mirror of
				https://github.com/Ylianst/MeshCentral.git
				synced 2025-03-09 15:40:18 +00:00 
			
		
		
		
	Second round of Telegram work, can now verify a user Telegram account (#4650)
This commit is contained in:
		
							parent
							
								
									68504f36ed
								
							
						
					
					
						commit
						0bd154a937
					
				
					 5 changed files with 163 additions and 12 deletions
				
			
		|  | @ -113,6 +113,7 @@ | |||
|     <Compile Include="meshdesktopmultiplex.js" /> | ||||
|     <Compile Include="meshipkvm.js" /> | ||||
|     <Compile Include="meshmail.js" /> | ||||
|     <Compile Include="meshmessaging.js" /> | ||||
|     <Compile Include="meshrelay.js" /> | ||||
|     <Compile Include="meshsms.js" /> | ||||
|     <Compile Include="meshscanner.js" /> | ||||
|  |  | |||
|  | @ -117,8 +117,8 @@ module.exports.CreateServer = function (parent) { | |||
|         return lines[templateNumber]; | ||||
|     } | ||||
| 
 | ||||
|     // Send phone number verification SMS
 | ||||
|     obj.sendPhoneCheck = function (domain, to, verificationCode, language, func) { | ||||
|     // Send messaging account verification
 | ||||
|     obj.sendMessagingCheck = function (domain, to, verificationCode, language, func) { | ||||
|         parent.debug('email', "Sending verification message to " + to); | ||||
| 
 | ||||
|         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('[[1]]').join(verificationCode); | ||||
| 
 | ||||
|         // Send the SMS
 | ||||
|         obj.sendSMS(to, sms, func); | ||||
|         // Send the message
 | ||||
|         obj.sendMessage(to, sms, func); | ||||
|     }; | ||||
| 
 | ||||
|     // Send phone number verification SMS
 | ||||
|     // Send 2FA verification
 | ||||
|     obj.sendToken = function (domain, to, verificationCode, language, func) { | ||||
|         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('[[1]]').join(verificationCode); | ||||
| 
 | ||||
|         // Send the SMS
 | ||||
|         obj.sendSMS(to, sms, func); | ||||
|         // Send the message
 | ||||
|         obj.sendMessage(to, sms, func); | ||||
|     }; | ||||
| 
 | ||||
|     return obj; | ||||
|  |  | |||
							
								
								
									
										78
									
								
								meshuser.js
									
										
									
									
									
								
							
							
						
						
									
										78
									
								
								meshuser.js
									
										
									
									
									
								
							|  | @ -5233,6 +5233,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use | |||
|         'changelang': serverCommandChangeLang, | ||||
|         'close': serverCommandClose, | ||||
|         'confirmPhone': serverCommandConfirmPhone, | ||||
|         'confirmMessaging': serverCommandConfirmMessaging, | ||||
|         'emailuser': serverCommandEmailUser, | ||||
|         'files': serverCommandFiles, | ||||
|         'getClip': serverCommandGetClip, | ||||
|  | @ -5261,6 +5262,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use | |||
|         'serverversion': serverCommandServerVersion, | ||||
|         'setClip': serverCommandSetClip, | ||||
|         'smsuser': serverCommandSmsUser, | ||||
|         'msguser': serverCommandMsgUser, | ||||
|         'trafficdelta': serverCommandTrafficDelta, | ||||
|         'trafficstats': serverCommandTrafficStats, | ||||
|         'updateAgents': serverCommandUpdateAgents, | ||||
|  | @ -5268,7 +5270,8 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use | |||
|         'urlargs': serverCommandUrlArgs, | ||||
|         'users': serverCommandUsers, | ||||
|         'verifyemail': serverCommandVerifyEmail, | ||||
|         'verifyPhone': serverCommandVerifyPhone | ||||
|         'verifyPhone': serverCommandVerifyPhone, | ||||
|         'verifyMessaging': serverCommandVerifyMessaging | ||||
|     }; | ||||
| 
 | ||||
|     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); | ||||
|     } | ||||
| 
 | ||||
|     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) { | ||||
|         var errMsg = null, emailuser = null; | ||||
|         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) { | ||||
|         const stats = parent.getTrafficDelta(obj.trafficStats); | ||||
|         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) { | ||||
|         var fin = '', f = '', availcommands = []; | ||||
|         for (var i in serverUserCommands) { availcommands.push(i); } | ||||
|  |  | |||
							
								
								
									
										
											BIN
										
									
								
								public/images/messaging40.png
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								public/images/messaging40.png
									
										
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 895 B | 
|  | @ -425,6 +425,7 @@ | |||
|                             <div id="manageHardwareOtp"><div class="p2AccountActions"><span id="authKeySetupCheck"><strong>✓</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>✓</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>✓</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>✓</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> | ||||
|                     </div> | ||||
|  | @ -432,6 +433,7 @@ | |||
|                         <p><strong>Account actions</strong></p> | ||||
|                         <p class="mL"> | ||||
|                             <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="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 /> | ||||
|  | @ -2139,6 +2141,8 @@ | |||
|             QV('p2AccountActions', !accountSettingsLocked) | ||||
|             QV('managePhoneNumber1', (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('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 | ||||
|  | @ -2238,6 +2242,7 @@ | |||
|             QV('verifyEmailId2', (userinfo.emailVerified !== true) && (userinfo.email != null) && (serverinfo.emailcheck == true) && (accountSettingsLocked == false)); | ||||
|             QV('manageOtp', (serverinfo.lock2factor != true) && (authFactorCount > 0) && ((features2 & 0x40000) == 0)); | ||||
|             QV('authPhoneNumberCheck', (userinfo.phone != null)); | ||||
|             QV('authMessagingCheck', (userinfo.msghandle != null)); | ||||
|             QV('authEmailSetupCheck', (userinfo.otpekey == 1) && (userinfo.email != null) && (userinfo.emailVerified == true)); | ||||
|             QV('authAppSetupCheck', userinfo.otpsecret == 1); | ||||
|             QV('manageAuthApp', (serverinfo.lock2factor != true) && ((userinfo.otpsecret == 1) || ((features2 & 0x00020000) == 0)));  | ||||
|  | @ -2953,6 +2958,16 @@ | |||
|                     account_managePhoneCodeValidate(); | ||||
|                     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': { | ||||
|                     // View the file in the dialog box | ||||
|                     var p5editSaveBack = function(b, tag) { | ||||
|  | @ -11920,7 +11935,7 @@ | |||
|             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 += '<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>'; | ||||
|                 setDialogMode(2, "Phone Notifications", 3, account_managePhoneRemove, x); | ||||
|                 account_managePhoneRemoveValidate(); | ||||
|  | @ -11942,6 +11957,35 @@ | |||
|         function account_managePhoneRemove() { if (Q('d2delPhone').checked) { meshserver.send({ action: 'removePhone' }); } } | ||||
|         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() { | ||||
|             if (xxdialogMode || ((features & 0x00800000) == 0)) return; | ||||
|             var emailU2Fenabled = ((userinfo.otpekey == 1) && (userinfo.email != null) && (userinfo.emailVerified == true)); | ||||
|  | @ -14279,7 +14323,9 @@ | |||
|             152: "No longer a relay for \"{0}\".", | ||||
|             153: "Is a relay for \"{0}\".", | ||||
|             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 = { | ||||
|  | @ -14723,6 +14769,15 @@ | |||
|         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 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) { | ||||
|             if (xxdialogMode) return; | ||||
|             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() />'); | ||||
|             } | ||||
| 
 | ||||
|             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 | ||||
|             var userFeatures = []; | ||||
|             if ((serverinfo.usersSessionRecording == 1) && (user.flags) && (user.flags & 2)) { userFeatures.push("Record Sessions"); } | ||||
|  | @ -15706,6 +15765,7 @@ | |||
|             // Add action buttons | ||||
|             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.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 (!self && ((activeSessions > 0) || ((features2 & 8) && (user.webpush)))) { | ||||
|                 x += '<input type=button value="' + "Notify" + '" title="' + "Send user notification" + '" onclick=showUserAlertDialog(event,"' + encodeURIComponentEx(user._id) + '") />'; | ||||
|  | @ -15771,6 +15831,16 @@ | |||
|             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() { | ||||
|             if (xxdialogMode) return; | ||||
|             var flags = (currentUser.flags)?currentUser.flags:0, x = ''; // Flags: 1 = Account Image, 2 = Session Recording | ||||
|  | @ -16866,10 +16936,14 @@ | |||
|                 "No user management rights", | ||||
|                 "Invalid SMS message", | ||||
|                 "No phone number for this user", | ||||
|                 "SMS succesfuly sent.", | ||||
|                 "SMS succesfully sent.", | ||||
|                 "SMS error", | ||||
|                 "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.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) { } } | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue