diff --git a/vendor/easy-asterisk/easy-asterisk-v0.10.0.sh b/vendor/easy-asterisk/easy-asterisk-v0.10.0.sh index 958c8ce..3cd0981 100755 --- a/vendor/easy-asterisk/easy-asterisk-v0.10.0.sh +++ b/vendor/easy-asterisk/easy-asterisk-v0.10.0.sh @@ -4779,7 +4779,13 @@ qualify_frequency=30 subprocess.run(['chown', 'asterisk:asterisk', PJSIP_CONF], capture_output=True) subprocess.run(['/usr/local/bin/easy-asterisk', '--rebuild-dialplan'], capture_output=True) - return True, {'extension': extension, 'password': password, 'name': name} + return True, { + 'extension': extension, + 'password': password, + 'name': name, + 'transport': 'tls' if conn_type == 'fqdn' else 'udp', + 'port': 5061 if conn_type == 'fqdn' else 5060, + } def get_server_info(): """Get server configuration info including TURN/STUN details""" @@ -5099,7 +5105,9 @@ HTML_TEMPLATE = '''

Save these credentials - the password cannot be retrieved later

-
+
+ +
@@ -5702,24 +5710,49 @@ HTML_TEMPLATE = ''' if (result.success) { closeModal(); - let credHtml = ` -

Extension: ${result.data.extension}

-

Password: ${result.data.password}

-

Name: ${result.data.name}

- `; - // Fetch server info to show TURN details + const d = result.data; + const transportLabel = d.transport === 'tls' ? 'TLS' : 'UDP'; + + // Fetch server info for the domain and TURN details + let srv = {}; 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}

- `; - } + srv = await srvRes.json(); } catch(e) {} + const server = srv.domain || srv.server_ip || ''; + + // Everything a SIP client (e.g. Sipnetic) needs, kept in one + // object so both the display and the copy buttons read from + // the same source instead of re-parsing rendered HTML. + lastDeviceCreds = { + name: d.name, + server: server, + port: d.port, + transport: transportLabel, + username: d.extension, + password: d.password, + turnEnabled: !!(srv.turn_enabled && srv.turn_server), + turnServer: srv.turn_server || '', + turnUsername: srv.turn_username || '', + turnPassword: srv.turn_password || '' + }; + + let credHtml = ` +

Display Name: ${lastDeviceCreds.name}

+

Server: ${lastDeviceCreds.server}

+

Port: ${lastDeviceCreds.port}

+

Transport: ${lastDeviceCreds.transport}

+

Username: ${lastDeviceCreds.username}

+

Password: ${lastDeviceCreds.password}

+ `; + if (lastDeviceCreds.turnEnabled) { + credHtml += `
+

STUN/TURN (configure in app Network settings)

+

STUN/TURN server: ${lastDeviceCreds.turnServer}

+

TURN username: ${lastDeviceCreds.turnUsername}

+

TURN password: ${lastDeviceCreds.turnPassword}

+ `; + } document.getElementById('credentials-display').innerHTML = credHtml; document.getElementById('credentials-modal').classList.add('active'); } else { @@ -5730,6 +5763,57 @@ HTML_TEMPLATE = ''' } } + // Holds the most recently created device's credentials so the + // Copy All / Copy Password buttons don't need to re-parse the DOM. + let lastDeviceCreds = null; + + function copyToClipboard(text) { + if (navigator.clipboard && window.isSecureContext) { + return navigator.clipboard.writeText(text); + } + // Fallback for non-HTTPS/non-secure contexts where the Clipboard + // API is unavailable (e.g. plain-HTTP self-signed-cert access). + const ta = document.createElement('textarea'); + ta.value = text; + ta.style.position = 'fixed'; + ta.style.opacity = '0'; + document.body.appendChild(ta); + ta.focus(); + ta.select(); + try { + document.execCommand('copy'); + } finally { + document.body.removeChild(ta); + } + return Promise.resolve(); + } + + function copyAllCredentials() { + if (!lastDeviceCreds) return; + const c = lastDeviceCreds; + let text = `Display Name: ${c.name}\n` + + `Server: ${c.server}\n` + + `Port: ${c.port}\n` + + `Transport: ${c.transport}\n` + + `Username: ${c.username}\n` + + `Password: ${c.password}\n`; + if (c.turnEnabled) { + text += `STUN/TURN server: ${c.turnServer}\n` + + `TURN username: ${c.turnUsername}\n` + + `TURN password: ${c.turnPassword}\n`; + } + copyToClipboard(text) + .then(() => showAlert('All settings copied to clipboard', 'success')) + .catch(() => showAlert('Copy failed — select and copy manually', 'error')); + } + + function copyDevicePassword() { + if (!lastDeviceCreds) return; + copyToClipboard(lastDeviceCreds.password) + .then(() => showAlert('Password copied to clipboard', 'success')) + .catch(() => showAlert('Copy failed — select and copy manually', 'error')); + } + async function deleteDevice(ext, name) { if (!confirm(`Delete device ${ext} (${name})?`)) return;