Second round of Telegram work, can now verify a user Telegram account (#4650)

This commit is contained in:
Ylian Saint-Hilaire 2022-10-22 09:20:00 -07:00
parent 68504f36ed
commit 0bd154a937
5 changed files with 163 additions and 12 deletions

View File

@ -113,6 +113,7 @@
<Compile Include="meshdesktopmultiplex.js" /> <Compile Include="meshdesktopmultiplex.js" />
<Compile Include="meshipkvm.js" /> <Compile Include="meshipkvm.js" />
<Compile Include="meshmail.js" /> <Compile Include="meshmail.js" />
<Compile Include="meshmessaging.js" />
<Compile Include="meshrelay.js" /> <Compile Include="meshrelay.js" />
<Compile Include="meshsms.js" /> <Compile Include="meshsms.js" />
<Compile Include="meshscanner.js" /> <Compile Include="meshscanner.js" />

View File

@ -117,8 +117,8 @@ module.exports.CreateServer = function (parent) {
return lines[templateNumber]; return lines[templateNumber];
} }
// Send phone number verification SMS // Send messaging account verification
obj.sendPhoneCheck = function (domain, to, verificationCode, language, func) { obj.sendMessagingCheck = function (domain, to, verificationCode, language, func) {
parent.debug('email', "Sending verification message to " + to); parent.debug('email', "Sending verification message to " + to);
var sms = getTemplate(0, domain, language); var sms = getTemplate(0, domain, language);
@ -128,11 +128,11 @@ module.exports.CreateServer = function (parent) {
sms = sms.split('[[0]]').join(domain.title ? domain.title : 'MeshCentral'); sms = sms.split('[[0]]').join(domain.title ? domain.title : 'MeshCentral');
sms = sms.split('[[1]]').join(verificationCode); sms = sms.split('[[1]]').join(verificationCode);
// Send the SMS // Send the message
obj.sendSMS(to, sms, func); obj.sendMessage(to, sms, func);
}; };
// Send phone number verification SMS // Send 2FA verification
obj.sendToken = function (domain, to, verificationCode, language, func) { obj.sendToken = function (domain, to, verificationCode, language, func) {
parent.debug('email', "Sending login token message to " + to); parent.debug('email', "Sending login token message to " + to);
@ -143,8 +143,8 @@ module.exports.CreateServer = function (parent) {
sms = sms.split('[[0]]').join(domain.title ? domain.title : 'MeshCentral'); sms = sms.split('[[0]]').join(domain.title ? domain.title : 'MeshCentral');
sms = sms.split('[[1]]').join(verificationCode); sms = sms.split('[[1]]').join(verificationCode);
// Send the SMS // Send the message
obj.sendSMS(to, sms, func); obj.sendMessage(to, sms, func);
}; };
return obj; return obj;

View File

@ -5233,6 +5233,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
'changelang': serverCommandChangeLang, 'changelang': serverCommandChangeLang,
'close': serverCommandClose, 'close': serverCommandClose,
'confirmPhone': serverCommandConfirmPhone, 'confirmPhone': serverCommandConfirmPhone,
'confirmMessaging': serverCommandConfirmMessaging,
'emailuser': serverCommandEmailUser, 'emailuser': serverCommandEmailUser,
'files': serverCommandFiles, 'files': serverCommandFiles,
'getClip': serverCommandGetClip, 'getClip': serverCommandGetClip,
@ -5261,6 +5262,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
'serverversion': serverCommandServerVersion, 'serverversion': serverCommandServerVersion,
'setClip': serverCommandSetClip, 'setClip': serverCommandSetClip,
'smsuser': serverCommandSmsUser, 'smsuser': serverCommandSmsUser,
'msguser': serverCommandMsgUser,
'trafficdelta': serverCommandTrafficDelta, 'trafficdelta': serverCommandTrafficDelta,
'trafficstats': serverCommandTrafficStats, 'trafficstats': serverCommandTrafficStats,
'updateAgents': serverCommandUpdateAgents, 'updateAgents': serverCommandUpdateAgents,
@ -5268,7 +5270,8 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
'urlargs': serverCommandUrlArgs, 'urlargs': serverCommandUrlArgs,
'users': serverCommandUsers, 'users': serverCommandUsers,
'verifyemail': serverCommandVerifyEmail, 'verifyemail': serverCommandVerifyEmail,
'verifyPhone': serverCommandVerifyPhone 'verifyPhone': serverCommandVerifyPhone,
'verifyMessaging': serverCommandVerifyMessaging
}; };
const serverUserCommands = { const serverUserCommands = {
@ -6026,6 +6029,35 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
parent.parent.DispatchEvent(['*', 'server-users', user._id], obj, event); parent.parent.DispatchEvent(['*', 'server-users', user._id], obj, event);
} }
function serverCommandConfirmMessaging(command) {
// Do not allow this command when logged in using a login token
if (req.session.loginToken != null) return;
if ((user.siteadmin != 0xFFFFFFFF) && ((user.siteadmin & 1024) != 0)) return; // If this account is settings locked, return here.
if ((parent.parent.msgserver == null) || (typeof command.cookie != 'string') || (typeof command.code != 'string') || (obj.failedMsgCookieCheck == 1)) return; // Input checks
var cookie = parent.parent.decodeCookie(command.cookie);
if (cookie == null) return; // Invalid cookie
if (cookie.s != ws.sessionId) return; // Invalid session
if (cookie.c != command.code) {
obj.failedMsgCookieCheck = 1;
// Code does not match, delay the response to limit how many guesses we can make and don't allow more than 1 guess at any given time.
setTimeout(function () {
ws.send(JSON.stringify({ action: 'verifyMessaging', cookie: command.cookie, success: true }));
delete obj.failedMsgCookieCheck;
}, 2000 + (parent.crypto.randomBytes(2).readUInt16BE(0) % 4095));
return;
}
// Set the user's messaging handle
user.msghandle = cookie.p;
db.SetUser(user);
// Event the change
var event = { etype: 'user', userid: user._id, username: user.name, account: parent.CloneSafeUser(user), action: 'accountchange', msgid: 156, msgArgs: [user.name], msg: 'Verified messaging account of user ' + EscapeHtml(user.name), domain: domain.id };
if (db.changeStream) { event.noact = 1; } // If DB change stream is active, don't use this event to change the user. Another event will come.
parent.parent.DispatchEvent(['*', 'server-users', user._id], obj, event);
}
function serverCommandEmailUser(command) { function serverCommandEmailUser(command) {
var errMsg = null, emailuser = null; var errMsg = null, emailuser = null;
if (domain.mailserver == null) { errMsg = 'Email server not enabled'; } if (domain.mailserver == null) { errMsg = 'Email server not enabled'; }
@ -6498,6 +6530,29 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
}); });
} }
function serverCommandMsgUser(command) {
var errMsg = null, msguser = null;
if ((parent.parent.msgserver == null) || (parent.parent.msgserver.providers == 0)) { errMsg = "Messaging server not enabled"; }
else if ((user.siteadmin & 2) == 0) { errMsg = "No user management rights"; }
else if (common.validateString(command.userid, 1, 2048) == false) { errMsg = "Invalid username"; }
else if (common.validateString(command.msg, 1, 160) == false) { errMsg = "Invalid message"; }
else {
msguser = parent.users[command.userid];
if (msguser == null) { errMsg = "Invalid username"; }
else if (msguser.msghandle == null) { errMsg = "No messaging service configured for this user"; }
}
if (errMsg != null) { displayNotificationMessage(errMsg); return; }
parent.parent.msgserver.sendMessage(msguser.msghandle, command.msg, function (success, msg) {
if (success) {
displayNotificationMessage("Message succesfuly sent.", null, null, null, 32);
} else {
if (typeof msg == 'string') { displayNotificationMessage("Messaging error: " + msg, null, null, null, 34, [msg]); } else { displayNotificationMessage("Messaging error", null, null, null, 33); }
}
});
}
function serverCommandTrafficDelta(command) { function serverCommandTrafficDelta(command) {
const stats = parent.getTrafficDelta(obj.trafficStats); const stats = parent.getTrafficDelta(obj.trafficStats);
obj.trafficStats = stats.current; obj.trafficStats = stats.current;
@ -6606,6 +6661,27 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
}); });
} }
function serverCommandVerifyMessaging(command) {
// Do not allow this command when logged in using a login token
if (req.session.loginToken != null) return;
if ((user.siteadmin != 0xFFFFFFFF) && ((user.siteadmin & 1024) != 0)) return; // If this account is settings locked, return here.
if (parent.parent.msgserver == null) return;
if (common.validateString(command.handle, 1, 64) == false) return; // Check handle length
// Setup the handle for the right messaging service
var handle = null;
if ((command.service == 1) && ((parent.parent.msgserver.providers & 1) != 0)) { handle = 'telegram:@' + command.handle; }
if (handle == null) return;
// Send a verification message
const code = common.zeroPad(getRandomSixDigitInteger(), 6);
const messagingCookie = parent.parent.encodeCookie({ a: 'verifyMessaging', c: code, p: handle, s: ws.sessionId });
parent.parent.msgserver.sendMessagingCheck(domain, handle, code, parent.getLanguageCodes(req), function (success) {
ws.send(JSON.stringify({ action: 'verifyMessaging', cookie: messagingCookie, success: success }));
});
}
function serverUserCommandHelp(cmdData) { function serverUserCommandHelp(cmdData) {
var fin = '', f = '', availcommands = []; var fin = '', f = '', availcommands = [];
for (var i in serverUserCommands) { availcommands.push(i); } for (var i in serverUserCommands) { availcommands.push(i); }

Binary file not shown.

After

Width:  |  Height:  |  Size: 895 B

View File

@ -425,6 +425,7 @@
<div id="manageHardwareOtp"><div class="p2AccountActions"><span id="authKeySetupCheck"><strong>&#x2713;</strong></span></div><span><a href=# onclick="return account_manageHardwareOtp(0)">Manage security keys</a><br /></span></div> <div id="manageHardwareOtp"><div class="p2AccountActions"><span id="authKeySetupCheck"><strong>&#x2713;</strong></span></div><span><a href=# onclick="return account_manageHardwareOtp(0)">Manage security keys</a><br /></span></div>
<div id="managePushAuthDev"><div class="p2AccountActions"><span id="authPushAuthDevCheck"><strong>&#x2713;</strong></span></div><span><a href=# onclick="return account_managePushAuthDev()">Manage push authentication</a><br /></span></div> <div id="managePushAuthDev"><div class="p2AccountActions"><span id="authPushAuthDevCheck"><strong>&#x2713;</strong></span></div><span><a href=# onclick="return account_managePushAuthDev()">Manage push authentication</a><br /></span></div>
<div id="manageOtp"><div class="p2AccountActions"><span id="authCodesSetupCheck"><strong>&#x2713;</strong></span></div><span><a href=# onclick="return account_manageOtp(0)">Manage backup codes</a><br /></span></div> <div id="manageOtp"><div class="p2AccountActions"><span id="authCodesSetupCheck"><strong>&#x2713;</strong></span></div><span><a href=# onclick="return account_manageOtp(0)">Manage backup codes</a><br /></span></div>
<div id="manageMessaging1"><div class="p2AccountActions"><span id="authMessagingCheck"><strong>&#x2713;</strong></span></div><span><a href=# onclick="return account_manageMessaging()">Manage messaging</a><br /></span></div>
<div class="p2AccountActions"></div><span><a href=# onclick="return account_viewPreviousLogins()">View previous logins</a><br /></span> <div class="p2AccountActions"></div><span><a href=# onclick="return account_viewPreviousLogins()">View previous logins</a><br /></span>
</div> </div>
</div> </div>
@ -432,6 +433,7 @@
<p><strong>Account actions</strong></p> <p><strong>Account actions</strong></p>
<p class="mL"> <p class="mL">
<span id="managePhoneNumber2" style="display:none"><a href=# onclick="return account_managePhone()">Manage phone number</a><br /></span> <span id="managePhoneNumber2" style="display:none"><a href=# onclick="return account_managePhone()">Manage phone number</a><br /></span>
<span id="manageMessaging2" style="display:none"><a href=# onclick="return account_manageMessaging()">Manage messaging</a><br /></span>
<span id="verifyEmailId" style="display:none"><a href=# onclick="return account_showVerifyEmail()">Verify email</a><br /></span> <span id="verifyEmailId" style="display:none"><a href=# onclick="return account_showVerifyEmail()">Verify email</a><br /></span>
<span id="accountEnableNotificationsSpan" style="display:none"><a href=# onclick="return account_enableNotifications()">Enable web notifications</a><br /></span> <span id="accountEnableNotificationsSpan" style="display:none"><a href=# onclick="return account_enableNotifications()">Enable web notifications</a><br /></span>
<a href=# onclick="return account_showLocalizationSettings()">Localization Settings</a><br /> <a href=# onclick="return account_showLocalizationSettings()">Localization Settings</a><br />
@ -2139,6 +2141,8 @@
QV('p2AccountActions', !accountSettingsLocked) QV('p2AccountActions', !accountSettingsLocked)
QV('managePhoneNumber1', (features & 0x02000000) && (features & 0x04000000) && (serverinfo.lock2factor != true)); QV('managePhoneNumber1', (features & 0x02000000) && (features & 0x04000000) && (serverinfo.lock2factor != true));
QV('managePhoneNumber2', (features & 0x02000000) && !(features & 0x04000000) && (serverinfo.lock2factor != true)); QV('managePhoneNumber2', (features & 0x02000000) && !(features & 0x04000000) && (serverinfo.lock2factor != true));
QV('manageMessaging1', (features2 & 0x02000000) && (features2 & 0x04000000) && (serverinfo.lock2factor != true));
QV('manageMessaging2', (features2 & 0x02000000) && !(features2 & 0x04000000) && (serverinfo.lock2factor != true));
QV('manageEmail2FA', (features & 0x00800000) && (serverinfo.lock2factor != true)); QV('manageEmail2FA', (features & 0x00800000) && (serverinfo.lock2factor != true));
QV('p2AccountPassActions', ((features & 4) == 0) && (serverinfo.domainauth == false) && (userinfo != null) && (userinfo._id.split('/')[2].startsWith('~') == false)); // Hide Account Actions if in single user mode or domain authentication QV('p2AccountPassActions', ((features & 4) == 0) && (serverinfo.domainauth == false) && (userinfo != null) && (userinfo._id.split('/')[2].startsWith('~') == false)); // Hide Account Actions if in single user mode or domain authentication
//QV('p2AccountImage', ((features & 4) == 0) && (serverinfo.domainauth == false)); // If account actions are not visible, also remove the image on that panel //QV('p2AccountImage', ((features & 4) == 0) && (serverinfo.domainauth == false)); // If account actions are not visible, also remove the image on that panel
@ -2238,6 +2242,7 @@
QV('verifyEmailId2', (userinfo.emailVerified !== true) && (userinfo.email != null) && (serverinfo.emailcheck == true) && (accountSettingsLocked == false)); QV('verifyEmailId2', (userinfo.emailVerified !== true) && (userinfo.email != null) && (serverinfo.emailcheck == true) && (accountSettingsLocked == false));
QV('manageOtp', (serverinfo.lock2factor != true) && (authFactorCount > 0) && ((features2 & 0x40000) == 0)); QV('manageOtp', (serverinfo.lock2factor != true) && (authFactorCount > 0) && ((features2 & 0x40000) == 0));
QV('authPhoneNumberCheck', (userinfo.phone != null)); QV('authPhoneNumberCheck', (userinfo.phone != null));
QV('authMessagingCheck', (userinfo.msghandle != null));
QV('authEmailSetupCheck', (userinfo.otpekey == 1) && (userinfo.email != null) && (userinfo.emailVerified == true)); QV('authEmailSetupCheck', (userinfo.otpekey == 1) && (userinfo.email != null) && (userinfo.emailVerified == true));
QV('authAppSetupCheck', userinfo.otpsecret == 1); QV('authAppSetupCheck', userinfo.otpsecret == 1);
QV('manageAuthApp', (serverinfo.lock2factor != true) && ((userinfo.otpsecret == 1) || ((features2 & 0x00020000) == 0))); QV('manageAuthApp', (serverinfo.lock2factor != true) && ((userinfo.otpsecret == 1) || ((features2 & 0x00020000) == 0)));
@ -2953,6 +2958,16 @@
account_managePhoneCodeValidate(); account_managePhoneCodeValidate();
break; break;
} }
case 'verifyMessaging': {
if (xxdialogMode && (xxdialogTag != 'verifyMessaging')) return;
var x = '<table><tr><td><img src="images/messaging40.png" style=padding:8px>';
x += '<td>' + "Check your messaging application 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, "Messaging Notifications", 3, account_manageMessagingConfirm, x, message.cookie);
Q('d2phoneCodeInput').focus();
account_managePhoneCodeValidate();
break;
}
case 'fileoperation': { case 'fileoperation': {
// View the file in the dialog box // View the file in the dialog box
var p5editSaveBack = function(b, tag) { var p5editSaveBack = function(b, tag) {
@ -11920,7 +11935,7 @@
var x; var x;
if (userinfo.phone != null) { if (userinfo.phone != null) {
x = '<table style=width:100%><tr><td style=width:56px><img src="images/phone80.png" style=padding:8px>'; 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 += '<td style=text-align:center><div style=padding:6px>' + "Verified phone number" + '</div><div style=font-size:20px>' + EscapeHtml(userinfo.phone) + '</div>';
x += '<div style=margin:10px><label><input id=d2delPhone type=checkbox onclick=account_managePhoneRemoveValidate() />' + "Remove phone number" + '</label></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); setDialogMode(2, "Phone Notifications", 3, account_managePhoneRemove, x);
account_managePhoneRemoveValidate(); account_managePhoneRemoveValidate();
@ -11942,6 +11957,35 @@
function account_managePhoneRemove() { if (Q('d2delPhone').checked) { meshserver.send({ action: 'removePhone' }); } } function account_managePhoneRemove() { if (Q('d2delPhone').checked) { meshserver.send({ action: 'removePhone' }); } }
function account_managePhoneRemoveValidate() { QE('idx_dlgOkButton', Q('d2delPhone').checked); } function account_managePhoneRemoveValidate() { QE('idx_dlgOkButton', Q('d2delPhone').checked); }
function account_manageMessaging() {
if (xxdialogMode || ((features2 & 0x02000000) == 0)) return;
var x;
if (userinfo.msghandle != null) {
x = '<table style=width:100%><tr><td style=width:56px><img src="images/messaging40.png" style=padding:8px>';
x += '<td style=text-align:center><div style=padding:6px>' + "Verified handle" + '</div><div style=font-size:20px>' + EscapeHtml(userinfo.msghandle) + '</div>';
x += '<div style=margin:10px><label><input id=d2delPhone type=checkbox onclick=account_managePhoneRemoveValidate() />' + "Remove messaging" + '</label></div>';
setDialogMode(2, "Messaging Notifications", 3, account_managePhoneRemove, x);
account_managePhoneRemoveValidate();
} else {
x = '<table style=width:100%><tr><td style=width:56px;vertical-align:top><img src="images/messaging40.png" style=padding:8px>';
x += '<td>' + "Enter your messaging service and handle. Once verified, this server can send you login verification and other notifications." + '<br /><br />';
var y = '<select id=d2serviceselect style=width:160px;margin-left:8px>';
if ((serverinfo.userMsgProviders & 1) != 0) { y += '<option value=1>' + "Telegram" + '</option>'; }
if ((serverinfo.userMsgProviders & 2) != 0) { y += '<option value=2>' + "Signal Messenger" + '</option>'; }
y += '</select>';
x += '<table><tr><td>' + "Service" + '<td>' + y;
x += '<tr><td>' + "Handle" + '<td><input maxlength=64 style=width:160px;margin-left:8px id=d2handleinput onKeyUp=account_manageMessagingValidate() onkeypress="if (event.key==\'Enter\') account_manageMessagingValidate(1)">';
x += '</table>';
setDialogMode(2, "Messaging Notifications", 3, account_manageMessagingAdd, x, 'verifyMessaging');
Q('d2handleinput').focus();
account_manageMessagingValidate();
}
}
function account_manageMessagingValidate(x) { var ok = (Q('d2handleinput').value.length > 0); QE('idx_dlgOkButton', ok); if ((x == 1) && ok) { dialogclose(1); } }
function account_manageMessagingAdd() { if (Q('d2handleinput').value.length == 0) return; QE('d2handleinput', false); meshserver.send({ action: 'verifyMessaging', service: Q('d2serviceselect').value, handle: Q('d2handleinput').value }); }
function account_manageMessagingConfirm(b, tag) { meshserver.send({ action: 'confirmMessaging', code: Q('d2phoneCodeInput').value, cookie: tag }); }
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));
@ -14279,7 +14323,9 @@
152: "No longer a relay for \"{0}\".", 152: "No longer a relay for \"{0}\".",
153: "Is a relay for \"{0}\".", 153: "Is a relay for \"{0}\".",
154: "Account changed to sync with LDAP data.", 154: "Account changed to sync with LDAP data.",
155: "Denied user login from {0}, {1}, {2}" 155: "Denied user login from {0}, {1}, {2}",
156: "Verified messaging account of user {0}",
157: "Removed messaging account of user {0}"
}; };
var eventsShortMessageId = { var eventsShortMessageId = {
@ -14723,6 +14769,15 @@
function showSendSMSValidate() { QE('idx_dlgOkButton', Q('d2smsText').value.length > 0); } function showSendSMSValidate() { QE('idx_dlgOkButton', Q('d2smsText').value.length > 0); }
function showSendSMSEx(b, tag) { if (Q('d2smsText').value.length > 0) { meshserver.send({ action: 'smsuser', userid: decodeURIComponent(tag), msg: Q('d2smsText').value }); } } function showSendSMSEx(b, tag) { if (Q('d2smsText').value.length > 0) { meshserver.send({ action: 'smsuser', userid: decodeURIComponent(tag), msg: Q('d2smsText').value }); } }
function showSendMessage(userid) {
if (xxdialogMode) return;
setDialogMode(2, "Send Message", 3, showSendMessageEx, '<textarea id=d2smsText maxlength=160 style=background-color:#fcf3cf;width:100%;height:100px;resize:none onKeyUp=showSendSMSValidate()></textarea><span style=font-size:10px><span>', userid);
Q('d2smsText').focus();
showSendSMSValidate();
}
function showSendMessageEx(b, tag) { if (Q('d2smsText').value.length > 0) { meshserver.send({ action: 'msguser', userid: decodeURIComponent(tag), msg: Q('d2smsText').value }); } }
function showSendEmail(userid) { function showSendEmail(userid) {
if (xxdialogMode) return; if (xxdialogMode) return;
var x = '<input id=d2emailSubject style=background-color:#fcf3cf;width:100% placeholder="' + "Subject" + '"></input>'; var x = '<input id=d2emailSubject style=background-color:#fcf3cf;width:100% placeholder="' + "Subject" + '"></input>';
@ -15630,6 +15685,10 @@
x += addDeviceAttribute("Phone Number", (user.phone?user.phone:('<i>' + "None" + '</i>')) + ' <img class=hoverButton style=cursor:pointer src="images/link5.png" onclick=p30editPhone() />'); x += addDeviceAttribute("Phone Number", (user.phone?user.phone:('<i>' + "None" + '</i>')) + ' <img class=hoverButton style=cursor:pointer src="images/link5.png" onclick=p30editPhone() />');
} }
if ((features2 & 0x02000000) || (user.msghandle != null)) { // If user messaging is enabled on the server or user has a messaging handle
x += addDeviceAttribute("Messaging", (user.msghandle?user.msghandle:('<i>' + "None" + '</i>')) + ' <img class=hoverButton style=cursor:pointer src="images/link5.png" onclick=p30editMessaging() />');
}
// Display features // Display features
var userFeatures = []; var userFeatures = [];
if ((serverinfo.usersSessionRecording == 1) && (user.flags) && (user.flags & 2)) { userFeatures.push("Record Sessions"); } if ((serverinfo.usersSessionRecording == 1) && (user.flags) && (user.flags & 2)) { userFeatures.push("Record Sessions"); }
@ -15706,6 +15765,7 @@
// Add action buttons // Add action buttons
x += '<input type=button value="' + "Notes" + '" title="' + "View notes about this user" + '" onclick=showNotes(false,"' + encodeURIComponentEx(user._id) + '") />'; x += '<input type=button value="' + "Notes" + '" title="' + "View notes about this user" + '" onclick=showNotes(false,"' + encodeURIComponentEx(user._id) + '") />';
if (user.phone && (features & 0x02000000)) { x += '<input type=button value="' + "SMS" + '" title="' + "Send a SMS message to this user" + '" onclick=showSendSMS("' + encodeURIComponentEx(user._id) + '") />'; } if (user.phone && (features & 0x02000000)) { x += '<input type=button value="' + "SMS" + '" title="' + "Send a SMS message to this user" + '" onclick=showSendSMS("' + encodeURIComponentEx(user._id) + '") />'; }
if (user.msghandle && (features2 & 0x02000000)) { x += '<input type=button value="' + "Message" + '" title="' + "Send a message to this user" + '" onclick=showSendMessage("' + encodeURIComponentEx(user._id) + '") />'; }
if ((typeof user.email == 'string') && (user.emailVerified === true) && (features & 0x00000040)) { x += '<input type=button value="' + "Email" + '" title="' + "Send a email message to this user" + '" onclick=showSendEmail("' + encodeURIComponentEx(user._id) + '") />'; } if ((typeof user.email == 'string') && (user.emailVerified === true) && (features & 0x00000040)) { x += '<input type=button value="' + "Email" + '" title="' + "Send a email message to this user" + '" onclick=showSendEmail("' + encodeURIComponentEx(user._id) + '") />'; }
if (!self && ((activeSessions > 0) || ((features2 & 8) && (user.webpush)))) { if (!self && ((activeSessions > 0) || ((features2 & 8) && (user.webpush)))) {
x += '<input type=button value="' + "Notify" + '" title="' + "Send user notification" + '" onclick=showUserAlertDialog(event,"' + encodeURIComponentEx(user._id) + '") />'; x += '<input type=button value="' + "Notify" + '" title="' + "Send user notification" + '" onclick=showUserAlertDialog(event,"' + encodeURIComponentEx(user._id) + '") />';
@ -15771,6 +15831,16 @@
p30editPhoneValidate(); p30editPhoneValidate();
} }
function p30editMessaging() { // TODO
if (xxdialogMode) return;
var x = '<table style=width:100%><tr><td style=width:56px><img src="images/phone80.png" style=padding:8px>';
x += '<td style=width:100%;text-align:center>' + "SMS capable phone number for this user." + '<br />' + "Leave blank for none.";
x += '<br /><br /><div style=width:100%;text-align:center>' + "Phone number:" + ' <input type=tel pattern="[0-9]" autocomplete="tel" value="' + (currentUser.phone?currentUser.phone:'') + '" inputmode="tel" maxlength=18 id=d2phoneinput onKeyUp=p30editPhoneValidate() onkeypress="if (event.key==\'Enter\') p30editPhoneValidate(1)"></div></table>';
setDialogMode(2, "Phone Notifications", 3, p30editPhoneEx, x, 'verifyPhone');
Q('d2phoneinput').focus();
p30editPhoneValidate();
}
function p20edituserfeatures() { function p20edituserfeatures() {
if (xxdialogMode) return; if (xxdialogMode) return;
var flags = (currentUser.flags)?currentUser.flags:0, x = ''; // Flags: 1 = Account Image, 2 = Session Recording var flags = (currentUser.flags)?currentUser.flags:0, x = ''; // Flags: 1 = Account Image, 2 = Session Recording
@ -16866,10 +16936,14 @@
"No user management rights", "No user management rights",
"Invalid SMS message", "Invalid SMS message",
"No phone number for this user", "No phone number for this user",
"SMS succesfuly sent.", "SMS succesfully sent.",
"SMS error", "SMS error",
"SMS error: {0}", "SMS error: {0}",
"Email domain \"{0}\" is not allowed. Only ({1}) are allowed" // 30 "Email domain \"{0}\" is not allowed. Only ({1}) are allowed", // 30,
"Invalid message",
"Message succesfully sent.",
"Message error",
"Message error: {0}"
]; ];
if (typeof n.titleid == 'number') { try { n.title = translatedTitles[n.titleid]; } catch (ex) {} } if (typeof n.titleid == 'number') { try { n.title = translatedTitles[n.titleid]; } catch (ex) {} }
if (typeof n.msgid == 'number') { try { n.text = translatedMessages[n.msgid]; if (Array.isArray(n.args)) { n.text = format(n.text, n.args[0], n.args[1], n.args[2], n.args[3], n.args[4], n.args[5]); } } catch (ex) { } } if (typeof n.msgid == 'number') { try { n.text = translatedMessages[n.msgid]; if (Array.isArray(n.args)) { n.text = format(n.text, n.args[0], n.args[1], n.args[2], n.args[3], n.args[4], n.args[5]); } } catch (ex) { } }