SMS support in mobile web app + UI fixes.

This commit is contained in:
Ylian Saint-Hilaire 2020-04-22 18:49:17 -07:00
parent bb3504363a
commit ed3a0c2eac
7 changed files with 446 additions and 371 deletions

View File

@ -1,2 +1,2 @@
[[0]] verification code is: [[1]] [[0]] verificatie code is: [[1]]
[[0]] access token is: [[1]] [[0]] Toegangs token is: [[1]]

View File

@ -2571,7 +2571,10 @@ function mainStart() {
// SMS support // SMS support
if ((config.sms != null) && (config.sms.provider == 'twilio')) { modules.push('twilio'); } if ((config.sms != null) && (config.sms.provider == 'twilio')) { modules.push('twilio'); }
if ((config.sms != null) && (config.sms.provider == 'plivo')) { modules.push('plivo'); } if ((config.sms != null) && (config.sms.provider == 'plivo')) {
const NodeJSVer = Number(process.version.match(/^v(\d+\.\d+)/)[1]);
if (NodeJSVer < 8) { console.log("SMS Plivo support requires Node v8 or above, current version is " + process.version + "."); } else { modules.push('plivo'); }
}
// Syslog support // Syslog support
if ((require('os').platform() != 'win32') && (config.settings.syslog || config.settings.syslogjson)) { modules.push('modern-syslog'); } if ((require('os').platform() != 'win32') && (config.settings.syslog || config.settings.syslogjson)) { modules.push('modern-syslog'); }

File diff suppressed because it is too large Load Diff

View File

@ -259,12 +259,14 @@
<div id="p3AccountActions"> <div id="p3AccountActions">
<p><strong>Account Security</strong></p> <p><strong>Account Security</strong></p>
<div style="margin-left:9px;margin-bottom:8px"> <div style="margin-left:9px;margin-bottom:8px">
<div id="managePhoneNumber1" style="margin-top:5px;display:none"><a onclick="account_managePhone()" style="cursor:pointer">Manage phone number</a></div>
<div id="manageEmail2FA" style="margin-top:5px;display:none"><a onclick="account_manageAuthEmail()" style="cursor:pointer">Manage email authentication</a></div> <div id="manageEmail2FA" style="margin-top:5px;display:none"><a onclick="account_manageAuthEmail()" style="cursor:pointer">Manage email authentication</a></div>
<div id="manageAuthApp" style="margin-top:5px;display:none"><a onclick="account_manageAuthApp()" style="cursor:pointer">Manage authenticator app</a></div> <div id="manageAuthApp" style="margin-top:5px;display:none"><a onclick="account_manageAuthApp()" style="cursor:pointer">Manage authenticator app</a></div>
<div id="manageOtp" style="margin-top:5px;display:none"><a onclick="account_manageOtp(0)" style="cursor:pointer">Manage backup codes</a></div> <div id="manageOtp" style="margin-top:5px;display:none"><a onclick="account_manageOtp(0)" style="cursor:pointer">Manage backup codes</a></div>
</div> </div>
<p><strong>Account Actions</strong></p> <p><strong>Account Actions</strong></p>
<div style="margin-left:9px;margin-bottom:8px"> <div style="margin-left:9px;margin-bottom:8px">
<div style="margin-top:5px"><span id="managePhoneNumber2" style="display:none"><a onclick="account_managePhone()" style="cursor:pointer">Manage phone number</a></span></div>
<div style="margin-top:5px"><span id="verifyEmailId" style="display:none"><a onclick="account_showVerifyEmail()" style="cursor:pointer">Verify email</a></span></div> <div style="margin-top:5px"><span id="verifyEmailId" style="display:none"><a onclick="account_showVerifyEmail()" style="cursor:pointer">Verify email</a></span></div>
<div style="margin-top:5px"><span id="changeEmailId" style="display:none"><a onclick="account_showChangeEmail()" style="cursor:pointer">Change email address</a></span></div> <div style="margin-top:5px"><span id="changeEmailId" style="display:none"><a onclick="account_showChangeEmail()" style="cursor:pointer">Change email address</a></span></div>
<div style="margin-top:5px"><a onclick="account_showChangePassword()" style="cursor:pointer">Change password</a><span id="p2nextPasswordUpdateTime"></span></div> <div style="margin-top:5px"><a onclick="account_showChangePassword()" style="cursor:pointer">Change password</a><span id="p2nextPasswordUpdateTime"></span></div>
@ -677,6 +679,8 @@
// Arrange the user interface // Arrange the user interface
QV('manageEmail2FA', features & 0x00800000); QV('manageEmail2FA', features & 0x00800000);
QV('managePhoneNumber1', (features & 0x02000000) && (features & 0x04000000));
QV('managePhoneNumber2', (features & 0x02000000) && !(features & 0x04000000));
} }
function onStateChanged(server, state, prevState, errorCode) { function onStateChanged(server, state, prevState, errorCode) {
@ -881,6 +885,16 @@
setDialogMode(2, "Manage Backup Codes", 8, null, x, 'otpauth-manage'); setDialogMode(2, "Manage Backup Codes", 8, null, x, 'otpauth-manage');
break; break;
} }
case 'verifyPhone': {
if (xxdialogMode && (xxdialogTag != 'verifyPhone')) return;
var x = '<table><tr><td><img src="images/phone80.png" style=padding:8px>';
x += '<td>Check your phone and enter the verification code.';
x += '<br /><br /><div style=width:100%;text-align:center>' + "Verification code:" + ' <input type=tel pattern="[0-9]" inputmode="number" maxlength=6 id=d2phoneCodeInput onKeyUp=account_managePhoneCodeValidate() onkeypress="if (event.key==\'Enter\') account_managePhoneCodeValidate(1)"></div></table>';
setDialogMode(2, "Phone Notifications", 3, account_managePhoneConfirm, x, message.cookie);
Q('d2phoneCodeInput').focus();
account_managePhoneCodeValidate();
break;
}
case 'event': { case 'event': {
/* /*
if (!message.event.nolog) { if (!message.event.nolog) {
@ -1236,6 +1250,33 @@
// MY ACCOUNT // MY ACCOUNT
// //
function account_managePhone() {
if (xxdialogMode || ((features & 0x02000000) == 0)) return;
var x;
if (userinfo.phone != null) {
x = '<table style=width:100%><tr><td style=width:56px><img src="images/phone80.png" style=padding:8px>';
x += '<td style=text-align:center><div style=padding:6px>' + "Verified phone number" + '</div><div style=font-size:20px>' + userinfo.phone + '</div>';
x += '<div style=margin:10px><label><input id=d2delPhone type=checkbox onclick=account_managePhoneRemoveValidate() />' + "Remove phone number" + '</label></div>';
setDialogMode(2, "Phone Notifications", 3, account_managePhoneRemove, x);
account_managePhoneRemoveValidate();
} else {
x = '<table style=width:100%><tr><td style=width:56px><img src="images/phone80.png" style=padding:8px>';
x += '<td>Enter your SMS capable phone number. Once verified, the number may be used for login verification and other notifications.';
x += '<br /><br /><div style=width:100%;text-align:center>' + "Phone number:" + ' <input type=tel pattern="[0-9]" autocomplete="tel" inputmode="tel" maxlength=18 id=d2phoneinput onKeyUp=account_managePhoneValidate() onkeypress="if (event.key==\'Enter\') account_managePhoneValidate(1)"></div></table>';
setDialogMode(2, "Phone Notifications", 3, account_managePhoneAdd, x, 'verifyPhone');
Q('d2phoneinput').focus();
account_managePhoneValidate();
}
}
function isPhoneNumber(x) { return x.match(/^\(?([0-9]{3,4})\)?[-. ]?([0-9]{3})[-. ]?([0-9]{4})$/) }
function account_managePhoneValidate(x) { var ok = isPhoneNumber(Q('d2phoneinput').value); QE('idx_dlgOkButton', ok); if ((x == 1) && ok) { dialogclose(1); } }
function account_managePhoneCodeValidate(x) { var ok = (Q('d2phoneCodeInput').value.length == 6) && Q('d2phoneCodeInput').value.match(/[0-9]/); QE('idx_dlgOkButton', ok); if ((x == 1) && ok) { dialogclose(1); } }
function account_managePhoneConfirm(b, tag) { meshserver.send({ action: 'confirmPhone', code: Q('d2phoneCodeInput').value, cookie: tag }); }
function account_managePhoneAdd() { if (isPhoneNumber(Q('d2phoneinput').value) == false) return; QE('d2phoneinput', false); meshserver.send({ action: 'verifyPhone', phone: Q('d2phoneinput').value }); }
function account_managePhoneRemove() { if (Q('d2delPhone').checked) { meshserver.send({ action: 'removePhone' }); } }
function account_managePhoneRemoveValidate() { QE('idx_dlgOkButton', Q('d2delPhone').checked); }
function account_manageAuthEmail() { function account_manageAuthEmail() {
if (xxdialogMode || ((features & 0x00800000) == 0)) return; if (xxdialogMode || ((features & 0x00800000) == 0)) return;
var emailU2Fenabled = ((userinfo.otpekey == 1) && (userinfo.email != null) && (userinfo.emailVerified == true)); var emailU2Fenabled = ((userinfo.otpekey == 1) && (userinfo.email != null) && (userinfo.emailVerified == true));

View File

@ -466,25 +466,27 @@
</div> </div>
</div> </div>
<div id=p10 style="display:none"> <div id=p10 style="display:none">
<table style="width:100%" cellpadding="0" cellspacing="0"> <div id=p10title>
<tr> <div id="p10BackButton"><div class="backButton" tabindex=0 onclick=goBack() title="Back" onkeypress="if (event.key == 'Enter') goBack()"><div class="backButtonEx"></div></div></div>
<td style=width:auto valign=top> <h1>General - <span id=p10deviceName></span></h1>
<div id=p10title> </div>
<div id="p10BackButton"><div class="backButton" tabindex=0 onclick=goBack() title="Back" onkeypress="if (event.key == 'Enter') goBack()"><div class="backButtonEx"></div></div></div> <div id=p10info style="overflow-y:auto">
<h1>General - <span id=p10deviceName></span></h1> <table style="width:100%" cellpadding="0" cellspacing="0">
</div> <tr>
<div id=p10html></div> <td style=width:auto valign=top>
</td> <div id=p10html></div>
<td style=width:20px></td> </td>
<td style=width:200px> <td style=width:20px></td>
<a href=# onclick=p10showiconselector()><img id=MainComputerImage></a> <td style=width:200px;vertical-align:top valign=top>
<div id=MainComputerState></div> <a href=# onclick=p10showiconselector()><img id=MainComputerImage></a>
</td> <div id=MainComputerState></div>
</tr> </td>
</table><br /> </tr>
<div id=p10html2></div> </table><br />
<div id=p10html3></div> <div id=p10html2></div>
<div id=p10html4></div> <div id=p10html3></div>
<div id=p10html4></div>
</div>
</div> </div>
<div id=p11 class="noselect" style="display:none"> <div id=p11 class="noselect" style="display:none">
<div id="p11title"> <div id="p11title">
@ -1442,6 +1444,8 @@
} }
QS('p43iframe')['height'] = 'calc(100vh - ' + (84 + xh) + 'px)'; QS('p43iframe')['height'] = 'calc(100vh - ' + (84 + xh) + 'px)';
QS('p43iframe')['max-height'] = 'calc(100vh - ' + (84 + xh) + 'px)'; QS('p43iframe')['max-height'] = 'calc(100vh - ' + (84 + xh) + 'px)';
QS('p10info')['height'] = 'calc(100vh - ' + (20 + xh + xh2) + 'px)';
QS('p10info')['max-height'] = 'calc(100vh - ' + (20 + xh + xh2) + 'px)';
QS('p17info')['height'] = 'calc(100vh - ' + (20 + xh + xh2) + 'px)'; QS('p17info')['height'] = 'calc(100vh - ' + (20 + xh + xh2) + 'px)';
QS('p17info')['max-height'] = 'calc(100vh - ' + (20 + xh + xh2) + 'px)'; QS('p17info')['max-height'] = 'calc(100vh - ' + (20 + xh + xh2) + 'px)';
QS('p16events')['height'] = 'calc(100vh - ' + (50 + xh + xh2) + 'px)'; QS('p16events')['height'] = 'calc(100vh - ' + (50 + xh + xh2) + 'px)';

View File

@ -167,6 +167,7 @@
<div style=float:right> <div style=float:right>
<input style="display:none;float:right" id=securityKeyButton type=button value="Use Security Key" onclick="useSecurityKey()" /> <input style="display:none;float:right" id=securityKeyButton type=button value="Use Security Key" onclick="useSecurityKey()" />
<input style="display:none;float:right" id=emailKeyButton type=button value="Email" onclick="useEmailToken()" /> <input style="display:none;float:right" id=emailKeyButton type=button value="Email" onclick="useEmailToken()" />
<input style="display:none;float:right" id=smsKeyButton type=button value="SMS" onclick="useSMSToken()" />
</div> </div>
</td> </td>
</tr> </tr>
@ -300,10 +301,11 @@
var publicKeyCredentialRequestOptions = null; var publicKeyCredentialRequestOptions = null;
var currentpanel = 0; var currentpanel = 0;
var otpemail = ('{{{otpemail}}}' === 'true'); var otpemail = ('{{{otpemail}}}' === 'true');
var otpsms = ('{{{otpsms}}}' === 'true');
// Display the right server message // Display the right server message
var messageid = parseInt('{{{messageid}}}'); var messageid = parseInt('{{{messageid}}}');
var okmessages = ['', "Hold on, reset mail sent.", "Email sent.", "Email verification required, check your mailbox and click the confirmation link."]; var okmessages = ['', "Hold on, reset mail sent.", "Email sent.", "Email verification required, check your mailbox and click the confirmation link.", "SMS sent."];
var failmessages = ["Unable to create account.", "Account limit reached.", "Existing account with this email address.", "Invalid account creation token.", "Username already exists.", "Password rejected, use a different one.", "Invalid email.", "Account not found.", "Invalid token, try again.", "Unable to sent email.", "Account locked.", "Access denied.", "Login failed, check username and password.", "Password change requested.", "IP address blocked, try again later."]; var failmessages = ["Unable to create account.", "Account limit reached.", "Existing account with this email address.", "Invalid account creation token.", "Username already exists.", "Password rejected, use a different one.", "Invalid email.", "Account not found.", "Invalid token, try again.", "Unable to sent email.", "Account locked.", "Access denied.", "Login failed, check username and password.", "Password change requested.", "IP address blocked, try again later."];
if (messageid > 0) { if (messageid > 0) {
var msg = ''; var msg = '';
@ -357,7 +359,8 @@
if (loginMode == '4') { if (loginMode == '4') {
try { if (hardwareKeyChallenge.length > 0) { hardwareKeyChallenge = JSON.parse(hardwareKeyChallenge); } else { hardwareKeyChallenge = null; } } catch (ex) { hardwareKeyChallenge = null } try { if (hardwareKeyChallenge.length > 0) { hardwareKeyChallenge = JSON.parse(hardwareKeyChallenge); } else { hardwareKeyChallenge = null; } } catch (ex) { hardwareKeyChallenge = null }
QV('securityKeyButton', (hardwareKeyChallenge != null) && (hardwareKeyChallenge.type == 'webAuthn')); QV('securityKeyButton', (hardwareKeyChallenge != null) && (hardwareKeyChallenge.type == 'webAuthn'));
QV('emailKeyButton', otpemail && (messageid != 2)); // TODO QV('emailKeyButton', otpemail && (messageid != 2) && (messageid != 4));
QV('smsKeyButton', otpsms && (messageid != 2) && (messageid != 4));
} }
if (loginMode == '5') { if (loginMode == '5') {
@ -436,6 +439,17 @@
Q('tokenOkButton').click(); Q('tokenOkButton').click();
} }
function useSMSToken() {
if (otpsms != true) return;
setDialogMode(1, "Secure Login", 3, useSMSTokenEx, "Send token to registed phone number?");
}
function useSMSTokenEx() {
Q('hwtokenInput').value = '**sms**';
QE('tokenOkButton', true);
Q('tokenOkButton').click();
}
function showPassHint() { function showPassHint() {
if (passRequirements.hint === true) { messagebox("Password Hint", passhint); } if (passRequirements.hint === true) { messagebox("Password Hint", passhint); }
} }

View File

@ -381,8 +381,8 @@
if (loginMode == '4') { if (loginMode == '4') {
try { if (hardwareKeyChallenge.length > 0) { hardwareKeyChallenge = JSON.parse(hardwareKeyChallenge); } else { hardwareKeyChallenge = null; } } catch (ex) { hardwareKeyChallenge = null } try { if (hardwareKeyChallenge.length > 0) { hardwareKeyChallenge = JSON.parse(hardwareKeyChallenge); } else { hardwareKeyChallenge = null; } } catch (ex) { hardwareKeyChallenge = null }
QV('securityKeyButton', (hardwareKeyChallenge != null) && (hardwareKeyChallenge.type == 'webAuthn')); QV('securityKeyButton', (hardwareKeyChallenge != null) && (hardwareKeyChallenge.type == 'webAuthn'));
QV('emailKeyButton', otpemail && (messageid != 2)); QV('emailKeyButton', otpemail && (messageid != 2) && (messageid != 4));
QV('smsKeyButton', otpsms && (messageid != 2)); QV('smsKeyButton', otpsms && (messageid != 2) && (messageid != 4));
} }
if (loginMode == '5') { if (loginMode == '5') {