From 168054f99a8a4d768eac5f313fc4b3fcd05ab2d4 Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 24 Feb 2026 23:58:10 +0000 Subject: [PATCH] Auto-provision STUN/TURN credentials to SIP clients MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Three provisioning touchpoints now include TURN/STUN configuration: 1. Linphone XML provisioning: ICE firewall policy, STUN server, and TURN credentials are auto-configured — no manual network setup needed 2. "Device Added" CLI output: Shows TURN server, username, and password for manual SIP apps (Sipnetic, Zoiper, etc.) 3. Web admin /api/server: Returns TURN details so the credentials modal shows STUN/TURN info alongside extension/password when creating devices https://claude.ai/code/session_01KWVtEt9MmZdywcu7WmgchX --- easy-asterisk-v0.10.0.sh | 64 ++++++++++++++++++++++++++++++++++++++-- 1 file changed, 61 insertions(+), 3 deletions(-) diff --git a/easy-asterisk-v0.10.0.sh b/easy-asterisk-v0.10.0.sh index a306c90..bc63904 100644 --- a/easy-asterisk-v0.10.0.sh +++ b/easy-asterisk-v0.10.0.sh @@ -944,6 +944,28 @@ EOF echo " Server Settings → Provisioning Manager → Create Baresip Config" echo "" echo "═══════════════════════════════════════════════════════════════" + + # Show TURN/STUN settings if enabled (for manual SIP app configuration) + if [[ "$TURN_ENABLED" == "y" && -n "$TURN_SERVER" ]]; then + echo "" + echo -e " ${BOLD}STUN/TURN SETTINGS (for NAT traversal)${NC}" + echo "═══════════════════════════════════════════════════════════════" + echo "" + echo " Configure these in your SIP app's Network/ICE settings:" + echo " ICE: Enabled" + echo " STUN server: ${TURN_SERVER}" + echo " TURN server: ${TURN_SERVER}" + echo " TURN username: ${TURN_USERNAME}" + echo " TURN password: ${TURN_PASSWORD}" + echo " TURN transport: UDP" + echo "" + echo " Linphone: Auto-provisioned via XML (no manual setup needed)" + echo " Sipnetic: Settings → Network → ICE/STUN/TURN" + echo " Olinuxino: Settings → Network → ICE/STUN/TURN" + echo "" + echo "═══════════════════════════════════════════════════════════════" + fi + echo "" echo " NOTE: These instructions work for most SIP apps (Zoiper," echo " sipnetic, etc.) - just use the same credentials." @@ -2015,11 +2037,20 @@ create_linphone_xml() {
1300 + + 3 + ${TURN_SERVER:-${domain}:3478}
EOF + # Add TURN credentials section if TURN is enabled + if [[ "$TURN_ENABLED" == "y" && -n "$TURN_SERVER" && -n "$TURN_USERNAME" && -n "$TURN_PASSWORD" ]]; then + # Insert TURN credentials into the net section before + sed -i "s|.*|${TURN_SERVER}\n 1\n ${TURN_USERNAME}\n ${TURN_PASSWORD}|" "$xml_file" + fi + chown asterisk:asterisk "$xml_file" chmod 644 "$xml_file" @@ -4747,20 +4778,33 @@ qualify_frequency=30 return True, {'extension': extension, 'password': password, 'name': name} def get_server_info(): - """Get server configuration info""" + """Get server configuration info including TURN/STUN details""" info = { 'domain': '', 'tls_enabled': False, - 'server_ip': '' + 'server_ip': '', + 'turn_enabled': False, + 'turn_server': '', + 'turn_username': '', + 'turn_password': '' } if os.path.exists(CONFIG_FILE): with open(CONFIG_FILE, 'r') as f: for line in f: + line = line.strip() if line.startswith('DOMAIN_NAME='): info['domain'] = line.split('=', 1)[1].strip().strip('"') elif line.startswith('ENABLE_TLS='): info['tls_enabled'] = 'y' in line.lower() + elif line.startswith('TURN_ENABLED='): + info['turn_enabled'] = 'y' in line.split('=', 1)[1].lower() + elif line.startswith('TURN_SERVER='): + info['turn_server'] = line.split('=', 1)[1].strip().strip('"') + elif line.startswith('TURN_USERNAME='): + info['turn_username'] = line.split('=', 1)[1].strip().strip('"') + elif line.startswith('TURN_PASSWORD='): + info['turn_password'] = line.split('=', 1)[1].strip().strip('"') try: result = subprocess.run(['hostname', '-I'], capture_output=True, text=True) @@ -5654,11 +5698,25 @@ HTML_TEMPLATE = ''' if (result.success) { closeModal(); - document.getElementById('credentials-display').innerHTML = ` + let credHtml = `

Extension: ${result.data.extension}

Password: ${result.data.password}

Name: ${result.data.name}

`; + // Fetch server info to show TURN details + try { + const srvRes = await fetch(API_BASE + '/server'); + const srv = await srvRes.json(); + if (srv.turn_enabled && srv.turn_server) { + credHtml += `
+

STUN/TURN (configure in app Network settings)

+

STUN/TURN server: ${srv.turn_server}

+

TURN username: ${srv.turn_username}

+

TURN password: ${srv.turn_password}

+ `; + } + } catch(e) {} + document.getElementById('credentials-display').innerHTML = credHtml; document.getElementById('credentials-modal').classList.add('active'); } else { showAlert(result.error || 'Failed to add device', 'error');