Third round of Telegram support changes, can now edit messaging account (#4650)

Ylian Saint-Hilaire committed Oct 22, 2022 at 10:42 UTC c62bc9c962fd72edff34dac0b3e1730b619ec641
5 files changed +52 -11
meshcentral-config-schema.json
+1
@@ -527,6 +527,7 @@
527 "sms2factor": { "type": "boolean", "default": true, "description": "Set to false to disable SMS 2FA." },
528 "push2factor": { "type": "boolean", "default": true, "description": "Set to false to disable push notification 2FA." },
529 "otp2factor": { "type": "boolean", "default": true, "description": "Set to false to disable one-time-password 2FA." },
530 + "msg2factor": { "type": "boolean", "default": true, "description": "Set to false to disable user messaging 2FA." },
531 "backupcode2factor": { "type": "boolean", "default": true, "description": "Set to false to disable 2FA backup codes." },
532 "single2factorWarning": { "type": "boolean", "default": true, "description": "Set to false to disable single 2FA warning." },
533 "lock2factor": { "type": "boolean", "default": false, "description": "When set to true, prevents any changes to 2FA." },
meshuser.js
+21 -2
@@ -1387,6 +1387,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
1387 if (command.resetNextLogin === true) { chguser.passchange = -1; }
1388 if ((command.consent != null) && (typeof command.consent == 'number')) { if (command.consent == 0) { delete chguser.consent; } else { chguser.consent = command.consent; } change = 1; }
1389 if ((command.phone != null) && (typeof command.phone == 'string') && ((command.phone == '') || isPhoneNumber(command.phone))) { if (command.phone == '') { delete chguser.phone; } else { chguser.phone = command.phone; } change = 1; }
1390 + if ((command.msghandle != null) && (typeof command.msghandle == 'string')) { if (command.msghandle == '') { delete chguser.msghandle; } else { chguser.msghandle = command.msghandle; } change = 1; }
1391 if ((command.flags != null) && (typeof command.flags == 'number')) {
1392 // Flags: 1 = Account Image, 2 = Session Recording
1393 if ((command.flags == 0) && (chguser.flags != null)) { delete chguser.flags; change = 1; } else { if (command.flags !== chguser.flags) { chguser.flags = command.flags; change = 1; } }
@@ -5250,7 +5251,8 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
5251 'pong': serverCommandPong,
5252 'powertimeline': serverCommandPowerTimeline,
5253 'print': serverCommandPrint,
5253 - 'removePhone': serverCommandremovePhone,
5254 + 'removePhone': serverCommandRemovePhone,
5255 + 'removeMessaging': serverCommandRemoveMessaging,
5256 'removeuserfromusergroup': serverCommandRemoveUserFromUserGroup,
5257 'report': serverCommandReport,
5258 'serverclearerrorlog': serverCommandServerClearErrorLog,
@@ -6304,7 +6306,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
6306
6307 function serverCommandPrint(command) { console.log(command.value); }
6308
6307 - function serverCommandremovePhone(command) {
6309 + function serverCommandRemovePhone(command) {
6310 // Do not allow this command when logged in using a login token
6311 if (req.session.loginToken != null) return;
6312
@@ -6321,6 +6323,23 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
6323 parent.parent.DispatchEvent(['*', 'server-users', user._id], obj, event);
6324 }
6325
6326 + function serverCommandRemoveMessaging(command) {
6327 + // Do not allow this command when logged in using a login token
6328 + if (req.session.loginToken != null) return;
6329 +
6330 + if ((user.siteadmin != 0xFFFFFFFF) && ((user.siteadmin & 1024) != 0)) return; // If this account is settings locked, return here.
6331 + if (user.msghandle == null) return;
6332 +
6333 + // Clear the user's phone
6334 + delete user.msghandle;
6335 + db.SetUser(user);
6336 +
6337 + // Event the change
6338 + var event = { etype: 'user', userid: user._id, username: user.name, account: parent.CloneSafeUser(user), action: 'accountchange', msgid: 157, msgArgs: [user.name], msg: 'Removed messaging account of user ' + EscapeHtml(user.name), domain: domain.id };
6339 + 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.
6340 + parent.parent.DispatchEvent(['*', 'server-users', user._id], obj, event);
6341 + }
6342 +
6343 function serverCommandRemoveUserFromUserGroup(command) {
6344 var err = null;
6345 try {
public/images/messaging12.png
Binary files /dev/null and b/public/images/messaging12.png differ
public/images/messaging40.png
Binary files a/public/images/messaging40.png and b/public/images/messaging40.png differ
views/default.handlebars
+30 -9
@@ -11964,7 +11964,7 @@
11964 x = '<table style=width:100%><tr><td style=width:56px><img src="images/messaging40.png" style=padding:8px>';
11965 x += '<td style=text-align:center><div style=padding:6px>' + "Verified handle" + '</div><div style=font-size:20px>' + EscapeHtml(userinfo.msghandle) + '</div>';
11966 x += '<div style=margin:10px><label><input id=d2delPhone type=checkbox onclick=account_managePhoneRemoveValidate() />' + "Remove messaging" + '</label></div>';
11967 - setDialogMode(2, "Messaging Notifications", 3, account_managePhoneRemove, x);
11967 + setDialogMode(2, "Messaging Notifications", 3, account_manageMessagingRemove, x);
11968 account_managePhoneRemoveValidate();
11969 } else {
11970 x = '<table style=width:100%><tr><td style=width:56px;vertical-align:top><img src="images/messaging40.png" style=padding:8px>';
@@ -11985,6 +11985,7 @@
11985 function account_manageMessagingValidate(x) { var ok = (Q('d2handleinput').value.length > 0); QE('idx_dlgOkButton', ok); if ((x == 1) && ok) { dialogclose(1); } }
11986 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 }); }
11987 function account_manageMessagingConfirm(b, tag) { meshserver.send({ action: 'confirmMessaging', code: Q('d2phoneCodeInput').value, cookie: tag }); }
11988 + function account_manageMessagingRemove() { if (Q('d2delPhone').checked) { meshserver.send({ action: 'removeMessaging' }); } }
11989
11990 function account_manageAuthEmail() {
11991 if (xxdialogMode || ((features & 0x00800000) == 0)) return;
@@ -14616,6 +14617,7 @@
14617 if ((user.otpsecret > 0) || (user.otphkeys > 0) || ((user.otpekey == 1) && (features & 0x00800000)) || ((user.phone != null) && (features & 0x04000000))) { username += ' <img src="images/key12.png" height=12 width=11 title="' + "2nd factor authentication enabled" + '" style="margin-top:2px" />'; }
14618 if (user.phone != null) { username += ' <img src="images/phone12.png" height=12 width=7 title="' + "Verified phone number" + '" style="margin-top:2px" />'; }
14619 if ((user.siteadmin != null) && ((user.siteadmin & 32) != 0) && (user.siteadmin != 0xFFFFFFFF)) { username += ' <img src="images/padlock12.png" height=12 width=8 title="' + "Account is locked" + '" style="margin-top:2px" />'; }
14620 + if ((user.msghandle != null) && (features2 & 0x02000000)) { username += ' <img src="images/messaging12.png" height=12 width=12 title="' + "Verified messaging account" + '" style="margin-top:2px" />'; }
14621 x += '<tr tabindex=0 onmouseover=userMouseHover(this,1) onmouseout=userMouseHover(this,0) onkeypress="if (event.key==\'Enter\') gotoUser(\'' + encodeURIComponentEx(user._id) + '\')"><td>';
14622 x += '<div class=bar>';
14623 x += '<div class=baricon><input class=UserCheckbox value=' + encodeURIComponentEx(user._id) + ' onclick=p3updateInfo() type=checkbox' + ((user._id == userinfo._id)?' disabled':'') + '></div><div style=cursor:pointer onclick=gotoUser("' + encodeURIComponentEx(user._id) + '",false,event)>';
@@ -15686,7 +15688,7 @@
15688 }
15689
15690 if ((features2 & 0x02000000) || (user.msghandle != null)) { // If user messaging is enabled on the server or user has a messaging handle
15689 - x += addDeviceAttribute("Messaging", (user.msghandle?user.msghandle:('<i>' + "None" + '</i>')) + ' <img class=hoverButton style=cursor:pointer src="images/link5.png" onclick=p30editMessaging() />');
15691 + x += addDeviceAttribute("Messaging", '<img src="images/messaging12.png" height=12 width=12 title="' + "Messaging enabled" + '" style="margin-top:2px" /> ' + (user.msghandle?user.msghandle:('<i>' + "None" + '</i>')) + ' <img class=hoverButton style=cursor:pointer src="images/link5.png" onclick=p30editMessaging() />');
15692 }
15693
15694 // Display features
@@ -15757,6 +15759,7 @@
15759 if (user.otpkeys > 0) { factors.push("Backup Codes"); }
15760 if (user.otpdev > 0) { factors.push("Device Push"); }
15761 if ((user.phone != null) && (features & 0x04000000)) { factors.push("SMS"); }
15762 + if ((user.msghandle != null) && (features2 & 0x04000000)) { factors.push("Messaging"); }
15763 x += addDeviceAttribute("Security", '<img src="images/key12.png" height=12 width=11 title="' + "2nd factor authentication enabled" + '" style="margin-top:2px" /> ' + factors.join(', '));
15764 }
15765
@@ -15831,14 +15834,32 @@
15834 p30editPhoneValidate();
15835 }
15836
15834 - function p30editMessaging() { // TODO
15837 + function p30editMessaging() {
15838 if (xxdialogMode) return;
15836 - var x = '<table style=width:100%><tr><td style=width:56px><img src="images/phone80.png" style=padding:8px>';
15837 - x += '<td style=width:100%;text-align:center>' + "SMS capable phone number for this user." + '<br />' + "Leave blank for none.";
15838 - 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>';
15839 - setDialogMode(2, "Phone Notifications", 3, p30editPhoneEx, x, 'verifyPhone');
15840 - Q('d2phoneinput').focus();
15841 - p30editPhoneValidate();
15839 + var x = '<table style=width:100%><tr><td style=width:56px;vertical-align:top><img src="images/messaging40.png" style=padding:8px>';
15840 + x += '<td style=width:100%>' + "Messaging account for this user." + '<br />' + "Leave blank for none.";
15841 +
15842 + var y = '<select id=d2serviceselect style=width:160px;margin-left:8px>';
15843 + if ((serverinfo.userMsgProviders & 1) != 0) { y += '<option value=1>' + "Telegram" + '</option>'; }
15844 + if ((serverinfo.userMsgProviders & 2) != 0) { y += '<option value=2>' + "Signal Messenger" + '</option>'; }
15845 + y += '</select>';
15846 + x += '<table style=margin-top:12px><tr><td>' + "Service" + '<td>' + y;
15847 + x += '<tr><td>' + "Handle" + '<td><input maxlength=64 style=width:160px;margin-left:8px id=d2handleinput onKeyUp=p30editMessagingValidate() onkeypress="if (event.key==\'Enter\') p30editMessagingValidate(1)">';
15848 + x += '</table>';
15849 +
15850 + setDialogMode(2, "Messaging Notifications", 3, p30editMessagingEx, x, 'verifyMessaging');
15851 + Q('d2handleinput').focus();
15852 + p30editMessagingValidate();
15853 + }
15854 +
15855 + function p30editMessagingValidate(x) { if (x == 1) { dialogclose(1); } }
15856 +
15857 + // Send to the server the user's messaging account
15858 + function p30editMessagingEx() {
15859 + var handle = null;
15860 + if (Q('d2handleinput').value == '') { handle = ''; }
15861 + else if (Q('d2serviceselect').value == 1) { handle = 'telegram:@' + Q('d2handleinput').value; }
15862 + if (handle != null) { meshserver.send({ action: 'edituser', id: currentUser._id, msghandle: handle }); }
15863 }
15864
15865 function p20edituserfeatures() {