First working OAuth support for Twitter, Google, GitHub, Reddit.

Ylian Saint-Hilaire committed May 14, 2020 at 17:06 UTC 4c12273c3ce5f6930da6c9c3736a74ae7d227859
7 files changed +78 -55
package.json
+1 -1
@@ -1,6 +1,6 @@
1 {
2 "name": "meshcentral",
3 - "version": "0.5.32",
3 + "version": "0.5.33",
4 "keywords": [
5 "Remote Management",
6 "Intel AMT",
public/styles/style.css
+1 -1
@@ -807,7 +807,7 @@ NoMeshesPanel img {
807 text-align:center;
808 position:absolute;
809 right:20px;
810 - top:140px;
810 + top:125px;
811 width:64px;
812 height:64px;
813 color:#FFF;
sample-config.json
+2 -2
@@ -162,8 +162,8 @@
162 "__comment__" : "This section is used to allow users to login using other accounts. You will need to get an API key from the services and register callback URL's",
163 "twitter": {
164 "__callbackurl": "https://server/auth-twitter-callback",
165 - "apikey": "xxxxxxxxxxxxxxxxxxxxxxx",
166 - "apisecret": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
165 + "clientid": "xxxxxxxxxxxxxxxxxxxxxxx",
166 + "clientsecret": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
167 },
168 "google": {
169 "__callbackurl": "https://server/auth-google-callback",
translate/translate.json
+27 -21
@@ -1891,7 +1891,7 @@
1891 "ru": "Действия учетной записи",
1892 "zh-chs": "帳戶動作",
1893 "xloc": [
1894 - "default-mobile.handlebars->container->page_content->column_l->p3->p3info->1->p3AccountActions->3->0"
1894 + "default-mobile.handlebars->container->page_content->column_l->p3->p3info->1->p3AccountActions->p2AccountActions->1->0"
1895 ]
1896 },
1897 {
@@ -2800,7 +2800,7 @@
2800 "ru": "Admin PowerShell",
2801 "zh-chs": "管理員PowerShell",
2802 "xloc": [
2803 - "default.handlebars->termShellContextMenu->cxtermps",
2803 + "default.handlebars->termShellContextMenu->3",
2804 "xterm.handlebars->termShellContextMenu->cxtermps"
2805 ]
2806 },
@@ -2835,7 +2835,7 @@
2835 "ru": "Admin Shell",
2836 "zh-chs": "管理員外殼",
2837 "xloc": [
2838 - "default.handlebars->termShellContextMenu->cxtermnorm->0",
2838 + "default.handlebars->termShellContextMenu->1->0",
2839 "xterm.handlebars->termShellContextMenu->cxtermnorm->0"
2840 ]
2841 },
@@ -3346,7 +3346,7 @@
3346 "ru": "Поменять порт",
3347 "zh-chs": "備用端口",
3348 "xloc": [
3349 - "default.handlebars->altPortContextMenu->cxaltport->0"
3349 + "default.handlebars->altPortContextMenu->1"
3350 ]
3351 },
3352 {
@@ -4023,7 +4023,7 @@
4023 "nl": "Vraag toestemming",
4024 "zh-chs": "询问同意",
4025 "xloc": [
4026 - "default.handlebars->deskConnectContextMenu->cxdeskuc->0"
4026 + "default.handlebars->deskConnectContextMenu->3"
4027 ]
4028 },
4029 {
@@ -4037,7 +4037,7 @@
4037 "nl": "Vraag toestemming + informatiebalk",
4038 "zh-chs": "询问同意+酒吧",
4039 "xloc": [
4040 - "default.handlebars->deskConnectContextMenu->cxdeskuc->0"
4040 + "default.handlebars->deskConnectContextMenu->1"
4041 ]
4042 },
4043 {
@@ -5066,7 +5066,7 @@
5066 "ru": "Смена email",
5067 "zh-chs": "更改電子郵件地址",
5068 "xloc": [
5069 - "default-mobile.handlebars->container->page_content->column_l->p3->p3info->1->p3AccountActions->5->5->changeEmailId->0",
5069 + "default-mobile.handlebars->container->page_content->column_l->p3->p3info->1->p3AccountActions->p2AccountActions->3->5->changeEmailId->0",
5070 "default.handlebars->container->column_l->p2->p2info->p2AccountActions->3->p2AccountPassActions->accountChangeEmailAddressSpan->0"
5071 ]
5072 },
@@ -5084,7 +5084,7 @@
5084 "ru": "Смена пароля",
5085 "zh-chs": "更改密碼",
5086 "xloc": [
5087 - "default-mobile.handlebars->container->page_content->column_l->p3->p3info->1->p3AccountActions->5->7->0",
5087 + "default-mobile.handlebars->container->page_content->column_l->p3->p3info->1->p3AccountActions->p2AccountActions->3->7->0",
5088 "default.handlebars->container->column_l->p2->p2info->p2AccountActions->3->p2AccountPassActions->3"
5089 ]
5090 },
@@ -7440,7 +7440,7 @@
7440 "default.handlebars->container->column_l->p13->p13toolbar->1->2->1->3",
7441 "default.handlebars->container->column_l->p5->p5toolbar->1->0->p5filehead->3",
7442 "default.handlebars->container->dialog->idx_dlgButtonBar->5",
7443 - "default.handlebars->filesContextMenu->cxfiledelete->0",
7443 + "default.handlebars->filesContextMenu->5",
7444 "player.handlebars->p11->dialog->idx_dlgButtonBar->5",
7445 "xterm.handlebars->p11->dialog->idx_dlgButtonBar->5"
7446 ]
@@ -7630,7 +7630,7 @@
7630 "ru": "Удалить учетную запись",
7631 "zh-chs": "刪除帳戶",
7632 "xloc": [
7633 - "default-mobile.handlebars->container->page_content->column_l->p3->p3info->1->p3AccountActions->5->9->0",
7633 + "default-mobile.handlebars->container->page_content->column_l->p3->p3info->1->p3AccountActions->p2AccountActions->3->9->0",
7634 "default.handlebars->25->1442",
7635 "default.handlebars->container->column_l->p2->p2info->p2AccountActions->3->p2AccountPassActions->7"
7636 ]
@@ -9502,7 +9502,7 @@
9502 "zh-chs": "編輯",
9503 "xloc": [
9504 "default.handlebars->container->column_l->p13->p13toolbar->1->2->1->3",
9505 - "default.handlebars->filesContextMenu->cxfileedit->0"
9505 + "default.handlebars->filesContextMenu->3"
9506 ]
9507 },
9508 {
@@ -15554,7 +15554,7 @@
15554 "ru": "Вход в оболочку",
15555 "zh-chs": "登錄外殼",
15556 "xloc": [
15557 - "default.handlebars->termShellContextMenuLinux->cxtermps",
15557 + "default.handlebars->termShellContextMenuLinux->5",
15558 "xterm.handlebars->termShellContextMenuLinux->cxtermps"
15559 ]
15560 },
@@ -16215,7 +16215,7 @@
16215 "nl": "Beheer telefoonnummer",
16216 "zh-chs": "管理电话号码",
16217 "xloc": [
16218 - "default-mobile.handlebars->container->page_content->column_l->p3->p3info->1->p3AccountActions->5->1->managePhoneNumber2->0",
16218 + "default-mobile.handlebars->container->page_content->column_l->p3->p3info->1->p3AccountActions->p2AccountActions->3->1->managePhoneNumber2->0",
16219 "default-mobile.handlebars->container->page_content->column_l->p3->p3info->1->p3AccountActions->p2AccountSecurity->3->managePhoneNumber1->0",
16220 "default.handlebars->container->column_l->p2->p2info->p2AccountActions->3->managePhoneNumber2->0",
16221 "default.handlebars->container->column_l->p2->p2info->p2AccountSecurity->3->managePhoneNumber1->1->0"
@@ -19159,7 +19159,7 @@
19159 "zh-chs": "打开播放器...",
19160 "xloc": [
19161 "default.handlebars->container->column_l->p52->3->1->0->3->1",
19162 - "default.handlebars->deskPlayerContextMenu->cxopenplayer->0"
19162 + "default.handlebars->deskPlayerContextMenu->1"
19163 ]
19164 },
19165 {
@@ -20474,6 +20474,12 @@
20474 "default.handlebars->25->137"
20475 ]
20476 },
20477 + {
20478 + "en": "Privacy Bar",
20479 + "xloc": [
20480 + "default.handlebars->deskConnectContextMenu->5"
20481 + ]
20482 + },
20483 {
20484 "cs": "Správa procesů",
20485 "de": "Prozesskontrolle",
@@ -21723,7 +21729,7 @@
21729 "default.handlebars->25->756",
21730 "default.handlebars->container->column_l->p13->p13toolbar->1->2->1->3",
21731 "default.handlebars->container->column_l->p5->p5toolbar->1->0->p5filehead->3",
21726 - "default.handlebars->filesContextMenu->cxfilerename->0"
21732 + "default.handlebars->filesContextMenu->1"
21733 ]
21734 },
21735 {
@@ -22125,7 +22131,7 @@
22131 "ru": "Root Shell",
22132 "zh-chs": "根殼",
22133 "xloc": [
22128 - "default.handlebars->termShellContextMenuLinux->cxtermnorm->0",
22134 + "default.handlebars->termShellContextMenuLinux->1->0",
22135 "xterm.handlebars->termShellContextMenuLinux->cxtermnorm->0"
22136 ]
22137 },
@@ -27628,7 +27634,7 @@
27634 "ru": "User PowerShell",
27635 "zh-chs": "用戶PowerShell",
27636 "xloc": [
27631 - "default.handlebars->termShellContextMenu->cxtermups",
27637 + "default.handlebars->termShellContextMenu->7",
27638 "xterm.handlebars->termShellContextMenu->cxtermups"
27639 ]
27640 },
@@ -27663,8 +27669,8 @@
27669 "ru": "User Shell",
27670 "zh-chs": "用戶外殼",
27671 "xloc": [
27666 - "default.handlebars->termShellContextMenu->cxtermunorm",
27667 - "default.handlebars->termShellContextMenuLinux->cxtermps",
27672 + "default.handlebars->termShellContextMenu->5",
27673 + "default.handlebars->termShellContextMenuLinux->3",
27674 "xterm.handlebars->termShellContextMenu->cxtermunorm",
27675 "xterm.handlebars->termShellContextMenuLinux->cxtermps"
27676 ]
@@ -28005,7 +28011,7 @@
28011 "ru": "Подтвердить email",
28012 "zh-chs": "驗證郵件",
28013 "xloc": [
28008 - "default-mobile.handlebars->container->page_content->column_l->p3->p3info->1->p3AccountActions->5->3->verifyEmailId->0",
28014 + "default-mobile.handlebars->container->page_content->column_l->p3->p3info->1->p3AccountActions->p2AccountActions->3->3->verifyEmailId->0",
28015 "default.handlebars->container->column_l->p2->p2info->p2AccountActions->3->verifyEmailId->0"
28016 ]
28017 },
@@ -31092,4 +31098,4 @@
31098 ]
31099 }
31100 ]
31095 -}
31101 +}
\ No newline at end of file
views/default-mobile.handlebars
+12 -9
@@ -296,7 +296,7 @@
296 <div style="margin-left:8px">
297 <div id="p3AccountActions">
298 <div id="p2AccountSecurity" style="display:none">
299 - <p><strong>Account Security</strong></p>
299 + <p><strong>Account Security</strong></p>
300 <div style="margin-left:9px;margin-bottom:8px">
301 <div id="managePhoneNumber1" style="margin-top:5px;display:none"><a onclick="account_managePhone()" style="cursor:pointer">Manage phone number</a> <span id="authPhoneNumberCheck"><strong>&#x2713;</strong></span></div>
302 <div id="manageEmail2FA" style="margin-top:5px;display:none"><a onclick="account_manageAuthEmail()" style="cursor:pointer">Manage email authentication</a> <span id="authEmailSetupCheck"><strong>&#x2713;</strong></span></div>
@@ -304,15 +304,17 @@
304 <div id="manageOtp" style="margin-top:5px;display:none"><a onclick="account_manageOtp(0)" style="cursor:pointer">Manage backup codes</a> <span id="authCodesSetupCheck"><strong>&#x2713;</strong></span></div>
305 </div>
306 </div>
307 - <p><strong>Account Actions</strong></p>
308 - <div style="margin-left:9px;margin-bottom:8px">
309 - <div style="margin-top:5px"><span id="managePhoneNumber2" style="display:none"><a onclick="account_managePhone()" style="cursor:pointer">Manage phone number</a></span></div>
310 - <div style="margin-top:5px"><span id="verifyEmailId" style="display:none"><a onclick="account_showVerifyEmail()" style="cursor:pointer">Verify email</a></span></div>
311 - <div style="margin-top:5px"><span id="changeEmailId" style="display:none"><a onclick="account_showChangeEmail()" style="cursor:pointer">Change email address</a></span></div>
312 - <div style="margin-top:5px"><a onclick="account_showChangePassword()" style="cursor:pointer">Change password</a><span id="p2nextPasswordUpdateTime"></span></div>
313 - <div style="margin-top:5px"><a onclick="account_showDeleteAccount()" style="cursor:pointer">Delete account</a></div>
314 - </div>
307 + <div id="p2AccountActions" style="display:none">
308 + <p><strong>Account Actions</strong></p>
309 + <div style="margin-left:9px;margin-bottom:8px">
310 + <div style="margin-top:5px"><span id="managePhoneNumber2" style="display:none"><a onclick="account_managePhone()" style="cursor:pointer">Manage phone number</a></span></div>
311 + <div style="margin-top:5px"><span id="verifyEmailId" style="display:none"><a onclick="account_showVerifyEmail()" style="cursor:pointer">Verify email</a></span></div>
312 + <div style="margin-top:5px"><span id="changeEmailId" style="display:none"><a onclick="account_showChangeEmail()" style="cursor:pointer">Change email address</a></span></div>
313 + <div style="margin-top:5px"><a onclick="account_showChangePassword()" style="cursor:pointer">Change password</a><span id="p2nextPasswordUpdateTime"></span></div>
314 + <div style="margin-top:5px"><a onclick="account_showDeleteAccount()" style="cursor:pointer">Delete account</a></div>
315 + </div>
316 <br style=clear:both />
317 + </div>
318 </div>
319 <strong>Device Groups</strong>
320 <span id="p3createMeshLink1">( <a onclick=account_createMesh() style=cursor:pointer><img src="images/icon-addnew.png" width=12 height=12 border=0 /> New</a> )</span>
@@ -766,6 +768,7 @@
768 QV('authAppSetupCheck', userinfo.otpsecret == 1);
769 //QV('authKeySetupCheck', userinfo.otphkeys > 0);
770 QV('authCodesSetupCheck', userinfo.otpkeys > 0);
771 + QV('p2AccountActions', ((features & 4) == 0) && (serverinfo.domainauth == false) && (userinfo != null) && (userinfo._id.split('/')[2].startsWith('~') == false));
772
773 // On the mobile app, don't allow group creation (for now).
774 QV('p3createMeshLink1', false);
views/default.handlebars
+8 -9
@@ -1664,7 +1664,7 @@
1664 QV('managePhoneNumber1', (features & 0x02000000) && (features & 0x04000000));
1665 QV('managePhoneNumber2', (features & 0x02000000) && !(features & 0x04000000));
1666 QV('manageEmail2FA', features & 0x00800000);
1667 - QV('p2AccountPassActions', ((features & 4) == 0) && (serverinfo.domainauth == false)); // Hide Account Actions if in single user mode or domain authentication
1667 + 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
1668 //QV('p2AccountImage', ((features & 4) == 0) && (serverinfo.domainauth == false)); // If account actions are not visible, also remove the image on that panel
1669 QV('p2ServerActions', siteRights & 21);
1670 QV('LeftMenuMyServer', siteRights & 21); // 16 + 4 + 1
@@ -1678,8 +1678,7 @@
1678 if (currentNode != null) { gotoDevice(currentNode._id, xxcurrentView, true); }
1679
1680 // Update user management state
1681 - if ((userinfo.siteadmin & 2) != 0)
1682 - {
1681 + if ((userinfo.siteadmin & 2) != 0) {
1682 // We are user administrator
1683 if (users == null) { meshserver.send({ action: 'users' }); }
1684 if (wssessions == null) { meshserver.send({ action: 'wssessioncount' }); }
@@ -2368,7 +2367,7 @@
2367 case 'accountremove': {
2368 // An account was removed
2369 if (users == null) break;
2371 - delete users['user/' + domain + '/' + message.event.username.toLowerCase()];
2370 + delete users[message.event.userid];
2371 masterUpdate(16384);
2372 break;
2373 }
@@ -2657,10 +2656,10 @@
2656 case 'wssessioncount': {
2657 // Update the active web socket session count for a user
2658 if (wssessions != null) {
2660 - if (message.event.count == 0 && wssessions['user/' + domain + '/' + message.event.username.toLowerCase()]) {
2661 - delete wssessions['user/' + domain + '/' + message.event.username.toLowerCase()];
2659 + if (message.event.count == 0 && wssessions[message.event.userid]) {
2660 + delete wssessions[message.event.userid];
2661 } else {
2663 - wssessions['user/' + domain + '/' + message.event.username.toLowerCase()] = message.event.count;
2662 + wssessions[message.event.userid] = message.event.count;
2663 }
2664 masterUpdate(16384);
2665 }
@@ -2668,8 +2667,8 @@
2667 }
2668 case 'login': {
2669 // Update the last login time
2671 - if (users != null && users['user/' + domain + '/' + message.event.username.toLowerCase()]) {
2672 - users['user/' + domain + '/' + message.event.username.toLowerCase()].login = Math.floor(new Date(message.event.time).getTime() / 1000);
2670 + if (users != null && users[message.event.userid]) {
2671 + users[message.event.userid].login = Math.floor(new Date(message.event.time).getTime() / 1000);
2672 }
2673 break;
2674 }
webserver.js
+27 -12
@@ -1688,15 +1688,30 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
1688 const userid = req.user.id;
1689 var user = obj.users[userid];
1690 if (user == null) {
1691 - // Create the user
1692 - parent.debug('web', 'handleStrategyLogin: creating new user: ' + userid);
1693 - user = { type: 'user', _id: userid, name: req.user.name, email: req.user.email, domain: domain.id };
1694 - if (req.user.email != null) { user.email = req.user.email; user.emailVerified = true; }
1695 - obj.users[userid] = user;
1696 - obj.db.SetUser(user);
1697 - // TODO: Event user creation
1698 - req.session.userid = req.user.id;
1699 - req.session.domainid = domain.id;
1691 + if (domain.newaccounts == true) {
1692 + // Create the user
1693 + parent.debug('web', 'handleStrategyLogin: creating new user: ' + userid);
1694 + user = { type: 'user', _id: userid, name: req.user.name, email: req.user.email, creation: Math.floor(Date.now() / 1000), domain: domain.id };
1695 + if (req.user.email != null) { user.email = req.user.email; user.emailVerified = true; }
1696 + obj.users[userid] = user;
1697 + obj.db.SetUser(user);
1698 +
1699 + // Event user creation
1700 + var targets = ['*', 'server-users'];
1701 + var event = { etype: 'user', userid: user._id, username: user.name, account: obj.CloneSafeUser(user), action: 'accountcreate', msg: 'Account created, username is ' + user.name, domain: domain.id };
1702 + if (db.changeStream) { event.noact = 1; } // If DB change stream is active, don't use this event to create the user. Another event will come.
1703 + parent.DispatchEvent(targets, obj, event);
1704 +
1705 + req.session.userid = req.user.id;
1706 + req.session.domainid = domain.id;
1707 + } else {
1708 + // New users not allowed
1709 + parent.debug('web', 'handleStrategyLogin: Can\'t create new accounts');
1710 + req.session.loginmode = '1';
1711 + req.session.messageid = 100; // Unable to create account.
1712 + res.redirect(domain.url + getQueryPortion(req));
1713 + return;
1714 + }
1715 } else {
1716 // Login success
1717 var userChange = false;
@@ -2032,7 +2047,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
2047 // See what authentication strategies we have
2048 var authStrategies = [];
2049 if (typeof domain.authstrategies == 'object') {
2035 - if ((typeof domain.authstrategies.twitter == 'object') && (typeof domain.authstrategies.twitter.apikey == 'string') && (typeof domain.authstrategies.twitter.apisecret == 'string')) { authStrategies.push('twitter'); }
2050 + if ((typeof domain.authstrategies.twitter == 'object') && (typeof domain.authstrategies.twitter.clientid == 'string') && (typeof domain.authstrategies.twitter.clientsecret == 'string')) { authStrategies.push('twitter'); }
2051 if ((typeof domain.authstrategies.google == 'object') && (typeof domain.authstrategies.google.clientid == 'string') && (typeof domain.authstrategies.google.clientsecret == 'string')) { authStrategies.push('google'); }
2052 if ((typeof domain.authstrategies.github == 'object') && (typeof domain.authstrategies.github.clientid == 'string') && (typeof domain.authstrategies.github.clientsecret == 'string')) { authStrategies.push('github'); }
2053 if ((typeof domain.authstrategies.reddit == 'object') && (typeof domain.authstrategies.reddit.clientid == 'string') && (typeof domain.authstrategies.reddit.clientsecret == 'string')) { authStrategies.push('reddit'); }
@@ -4046,9 +4061,9 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
4061 //obj.app.use(passport.session());
4062
4063 // Twitter
4049 - if ((typeof domain.authstrategies.twitter == 'object') && (typeof domain.authstrategies.twitter.apikey == 'string') && (typeof domain.authstrategies.twitter.apisecret == 'string')) {
4064 + if ((typeof domain.authstrategies.twitter == 'object') && (typeof domain.authstrategies.twitter.clientid == 'string') && (typeof domain.authstrategies.twitter.clientsecret == 'string')) {
4065 const TwitterStrategy = require('passport-twitter');
4051 - passport.use(new TwitterStrategy({ consumerKey: domain.authstrategies.twitter.apikey, consumerSecret: domain.authstrategies.twitter.apisecret, callbackURL: url + 'auth-twitter-callback' },
4066 + passport.use(new TwitterStrategy({ consumerKey: domain.authstrategies.twitter.clientid, consumerSecret: domain.authstrategies.twitter.clientsecret, callbackURL: url + 'auth-twitter-callback' },
4067 function (token, tokenSecret, profile, cb) {
4068 var user = { id: 'user/' + domain.id + '/~twitter:' + profile.id, name: profile.displayName };
4069 if ((typeof profile.emails == 'object') && (profile.emails[0] != null) && (typeof profile.emails[0].value == 'string')) { user.email = profile.emails[0].value; }