diff --git a/meshcentral-config-schema.json b/meshcentral-config-schema.json index e7c9dc06a8..44e36fb793 100644 --- a/meshcentral-config-schema.json +++ b/meshcentral-config-schema.json @@ -527,6 +527,7 @@ "sms2factor": { "type": "boolean", "default": true, "description": "Set to false to disable SMS 2FA." }, "push2factor": { "type": "boolean", "default": true, "description": "Set to false to disable push notification 2FA." }, "otp2factor": { "type": "boolean", "default": true, "description": "Set to false to disable one-time-password 2FA." }, + "msg2factor": { "type": "boolean", "default": true, "description": "Set to false to disable user messaging 2FA." }, "backupcode2factor": { "type": "boolean", "default": true, "description": "Set to false to disable 2FA backup codes." }, "single2factorWarning": { "type": "boolean", "default": true, "description": "Set to false to disable single 2FA warning." }, "lock2factor": { "type": "boolean", "default": false, "description": "When set to true, prevents any changes to 2FA." }, diff --git a/meshuser.js b/meshuser.js index 7b855f8b14..e0f9666f9a 100644 --- a/meshuser.js +++ b/meshuser.js @@ -1387,6 +1387,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use if (command.resetNextLogin === true) { chguser.passchange = -1; } if ((command.consent != null) && (typeof command.consent == 'number')) { if (command.consent == 0) { delete chguser.consent; } else { chguser.consent = command.consent; } change = 1; } 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; } + if ((command.msghandle != null) && (typeof command.msghandle == 'string')) { if (command.msghandle == '') { delete chguser.msghandle; } else { chguser.msghandle = command.msghandle; } change = 1; } if ((command.flags != null) && (typeof command.flags == 'number')) { // Flags: 1 = Account Image, 2 = Session Recording 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 'pong': serverCommandPong, 'powertimeline': serverCommandPowerTimeline, 'print': serverCommandPrint, - 'removePhone': serverCommandremovePhone, + 'removePhone': serverCommandRemovePhone, + 'removeMessaging': serverCommandRemoveMessaging, 'removeuserfromusergroup': serverCommandRemoveUserFromUserGroup, 'report': serverCommandReport, 'serverclearerrorlog': serverCommandServerClearErrorLog, @@ -6304,7 +6306,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use function serverCommandPrint(command) { console.log(command.value); } - function serverCommandremovePhone(command) { + function serverCommandRemovePhone(command) { // Do not allow this command when logged in using a login token if (req.session.loginToken != null) return; @@ -6321,6 +6323,23 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use parent.parent.DispatchEvent(['*', 'server-users', user._id], obj, event); } + function serverCommandRemoveMessaging(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 (user.msghandle == null) return; + + // Clear the user's phone + delete user.msghandle; + db.SetUser(user); + + // Event the change + 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 }; + 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 serverCommandRemoveUserFromUserGroup(command) { var err = null; try { diff --git a/public/images/messaging12.png b/public/images/messaging12.png new file mode 100644 index 0000000000..9a5acfeec6 Binary files /dev/null and b/public/images/messaging12.png differ diff --git a/public/images/messaging40.png b/public/images/messaging40.png index a826e90052..f677154976 100644 Binary files a/public/images/messaging40.png and b/public/images/messaging40.png differ diff --git a/views/default.handlebars b/views/default.handlebars index ad714baf05..9b145db556 100644 --- a/views/default.handlebars +++ b/views/default.handlebars @@ -11964,7 +11964,7 @@ x = '
'; x += ' | ' + "Verified handle" + ' ' + EscapeHtml(userinfo.msghandle) + ' ';
x += '';
- setDialogMode(2, "Messaging Notifications", 3, account_managePhoneRemove, x);
+ setDialogMode(2, "Messaging Notifications", 3, account_manageMessagingRemove, x);
account_managePhoneRemoveValidate();
} else {
x = '
|