From 4c12273c3ce5f6930da6c9c3736a74ae7d227859 Mon Sep 17 00:00:00 2001 From: Ylian Saint-Hilaire Date: Thu, 14 May 2020 17:06:55 -0700 Subject: [PATCH] First working OAuth support for Twitter, Google, GitHub, Reddit. --- package.json | 2 +- public/styles/style.css | 2 +- sample-config.json | 4 +-- translate/translate.json | 48 ++++++++++++++++++--------------- views/default-mobile.handlebars | 21 ++++++++------- views/default.handlebars | 17 ++++++------ webserver.js | 39 ++++++++++++++++++--------- 7 files changed, 78 insertions(+), 55 deletions(-) diff --git a/package.json b/package.json index 14d3ab16..454ab0e8 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "meshcentral", - "version": "0.5.32", + "version": "0.5.33", "keywords": [ "Remote Management", "Intel AMT", diff --git a/public/styles/style.css b/public/styles/style.css index 697f5fde..129295bc 100644 --- a/public/styles/style.css +++ b/public/styles/style.css @@ -807,7 +807,7 @@ NoMeshesPanel img { text-align:center; position:absolute; right:20px; - top:140px; + top:125px; width:64px; height:64px; color:#FFF; diff --git a/sample-config.json b/sample-config.json index 9605c233..d033cd65 100644 --- a/sample-config.json +++ b/sample-config.json @@ -162,8 +162,8 @@ "__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", "twitter": { "__callbackurl": "https://server/auth-twitter-callback", - "apikey": "xxxxxxxxxxxxxxxxxxxxxxx", - "apisecret": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + "clientid": "xxxxxxxxxxxxxxxxxxxxxxx", + "clientsecret": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" }, "google": { "__callbackurl": "https://server/auth-google-callback", diff --git a/translate/translate.json b/translate/translate.json index a31c9c64..3fa4d770 100644 --- a/translate/translate.json +++ b/translate/translate.json @@ -1891,7 +1891,7 @@ "ru": "Действия учетной записи", "zh-chs": "帳戶動作", "xloc": [ - "default-mobile.handlebars->container->page_content->column_l->p3->p3info->1->p3AccountActions->3->0" + "default-mobile.handlebars->container->page_content->column_l->p3->p3info->1->p3AccountActions->p2AccountActions->1->0" ] }, { @@ -2800,7 +2800,7 @@ "ru": "Admin PowerShell", "zh-chs": "管理員PowerShell", "xloc": [ - "default.handlebars->termShellContextMenu->cxtermps", + "default.handlebars->termShellContextMenu->3", "xterm.handlebars->termShellContextMenu->cxtermps" ] }, @@ -2835,7 +2835,7 @@ "ru": "Admin Shell", "zh-chs": "管理員外殼", "xloc": [ - "default.handlebars->termShellContextMenu->cxtermnorm->0", + "default.handlebars->termShellContextMenu->1->0", "xterm.handlebars->termShellContextMenu->cxtermnorm->0" ] }, @@ -3346,7 +3346,7 @@ "ru": "Поменять порт", "zh-chs": "備用端口", "xloc": [ - "default.handlebars->altPortContextMenu->cxaltport->0" + "default.handlebars->altPortContextMenu->1" ] }, { @@ -4023,7 +4023,7 @@ "nl": "Vraag toestemming", "zh-chs": "询问同意", "xloc": [ - "default.handlebars->deskConnectContextMenu->cxdeskuc->0" + "default.handlebars->deskConnectContextMenu->3" ] }, { @@ -4037,7 +4037,7 @@ "nl": "Vraag toestemming + informatiebalk", "zh-chs": "询问同意+酒吧", "xloc": [ - "default.handlebars->deskConnectContextMenu->cxdeskuc->0" + "default.handlebars->deskConnectContextMenu->1" ] }, { @@ -5066,7 +5066,7 @@ "ru": "Смена email", "zh-chs": "更改電子郵件地址", "xloc": [ - "default-mobile.handlebars->container->page_content->column_l->p3->p3info->1->p3AccountActions->5->5->changeEmailId->0", + "default-mobile.handlebars->container->page_content->column_l->p3->p3info->1->p3AccountActions->p2AccountActions->3->5->changeEmailId->0", "default.handlebars->container->column_l->p2->p2info->p2AccountActions->3->p2AccountPassActions->accountChangeEmailAddressSpan->0" ] }, @@ -5084,7 +5084,7 @@ "ru": "Смена пароля", "zh-chs": "更改密碼", "xloc": [ - "default-mobile.handlebars->container->page_content->column_l->p3->p3info->1->p3AccountActions->5->7->0", + "default-mobile.handlebars->container->page_content->column_l->p3->p3info->1->p3AccountActions->p2AccountActions->3->7->0", "default.handlebars->container->column_l->p2->p2info->p2AccountActions->3->p2AccountPassActions->3" ] }, @@ -7440,7 +7440,7 @@ "default.handlebars->container->column_l->p13->p13toolbar->1->2->1->3", "default.handlebars->container->column_l->p5->p5toolbar->1->0->p5filehead->3", "default.handlebars->container->dialog->idx_dlgButtonBar->5", - "default.handlebars->filesContextMenu->cxfiledelete->0", + "default.handlebars->filesContextMenu->5", "player.handlebars->p11->dialog->idx_dlgButtonBar->5", "xterm.handlebars->p11->dialog->idx_dlgButtonBar->5" ] @@ -7630,7 +7630,7 @@ "ru": "Удалить учетную запись", "zh-chs": "刪除帳戶", "xloc": [ - "default-mobile.handlebars->container->page_content->column_l->p3->p3info->1->p3AccountActions->5->9->0", + "default-mobile.handlebars->container->page_content->column_l->p3->p3info->1->p3AccountActions->p2AccountActions->3->9->0", "default.handlebars->25->1442", "default.handlebars->container->column_l->p2->p2info->p2AccountActions->3->p2AccountPassActions->7" ] @@ -9502,7 +9502,7 @@ "zh-chs": "編輯", "xloc": [ "default.handlebars->container->column_l->p13->p13toolbar->1->2->1->3", - "default.handlebars->filesContextMenu->cxfileedit->0" + "default.handlebars->filesContextMenu->3" ] }, { @@ -15554,7 +15554,7 @@ "ru": "Вход в оболочку", "zh-chs": "登錄外殼", "xloc": [ - "default.handlebars->termShellContextMenuLinux->cxtermps", + "default.handlebars->termShellContextMenuLinux->5", "xterm.handlebars->termShellContextMenuLinux->cxtermps" ] }, @@ -16215,7 +16215,7 @@ "nl": "Beheer telefoonnummer", "zh-chs": "管理电话号码", "xloc": [ - "default-mobile.handlebars->container->page_content->column_l->p3->p3info->1->p3AccountActions->5->1->managePhoneNumber2->0", + "default-mobile.handlebars->container->page_content->column_l->p3->p3info->1->p3AccountActions->p2AccountActions->3->1->managePhoneNumber2->0", "default-mobile.handlebars->container->page_content->column_l->p3->p3info->1->p3AccountActions->p2AccountSecurity->3->managePhoneNumber1->0", "default.handlebars->container->column_l->p2->p2info->p2AccountActions->3->managePhoneNumber2->0", "default.handlebars->container->column_l->p2->p2info->p2AccountSecurity->3->managePhoneNumber1->1->0" @@ -19159,7 +19159,7 @@ "zh-chs": "打开播放器...", "xloc": [ "default.handlebars->container->column_l->p52->3->1->0->3->1", - "default.handlebars->deskPlayerContextMenu->cxopenplayer->0" + "default.handlebars->deskPlayerContextMenu->1" ] }, { @@ -20474,6 +20474,12 @@ "default.handlebars->25->137" ] }, + { + "en": "Privacy Bar", + "xloc": [ + "default.handlebars->deskConnectContextMenu->5" + ] + }, { "cs": "Správa procesů", "de": "Prozesskontrolle", @@ -21723,7 +21729,7 @@ "default.handlebars->25->756", "default.handlebars->container->column_l->p13->p13toolbar->1->2->1->3", "default.handlebars->container->column_l->p5->p5toolbar->1->0->p5filehead->3", - "default.handlebars->filesContextMenu->cxfilerename->0" + "default.handlebars->filesContextMenu->1" ] }, { @@ -22125,7 +22131,7 @@ "ru": "Root Shell", "zh-chs": "根殼", "xloc": [ - "default.handlebars->termShellContextMenuLinux->cxtermnorm->0", + "default.handlebars->termShellContextMenuLinux->1->0", "xterm.handlebars->termShellContextMenuLinux->cxtermnorm->0" ] }, @@ -27628,7 +27634,7 @@ "ru": "User PowerShell", "zh-chs": "用戶PowerShell", "xloc": [ - "default.handlebars->termShellContextMenu->cxtermups", + "default.handlebars->termShellContextMenu->7", "xterm.handlebars->termShellContextMenu->cxtermups" ] }, @@ -27663,8 +27669,8 @@ "ru": "User Shell", "zh-chs": "用戶外殼", "xloc": [ - "default.handlebars->termShellContextMenu->cxtermunorm", - "default.handlebars->termShellContextMenuLinux->cxtermps", + "default.handlebars->termShellContextMenu->5", + "default.handlebars->termShellContextMenuLinux->3", "xterm.handlebars->termShellContextMenu->cxtermunorm", "xterm.handlebars->termShellContextMenuLinux->cxtermps" ] @@ -28005,7 +28011,7 @@ "ru": "Подтвердить email", "zh-chs": "驗證郵件", "xloc": [ - "default-mobile.handlebars->container->page_content->column_l->p3->p3info->1->p3AccountActions->5->3->verifyEmailId->0", + "default-mobile.handlebars->container->page_content->column_l->p3->p3info->1->p3AccountActions->p2AccountActions->3->3->verifyEmailId->0", "default.handlebars->container->column_l->p2->p2info->p2AccountActions->3->verifyEmailId->0" ] }, @@ -31092,4 +31098,4 @@ ] } ] -} +} \ No newline at end of file diff --git a/views/default-mobile.handlebars b/views/default-mobile.handlebars index e99a809b..98691da2 100644 --- a/views/default-mobile.handlebars +++ b/views/default-mobile.handlebars @@ -296,7 +296,7 @@
-

Account Actions

-
-
-
-
-
Change password
-
Delete account
-
+
Device Groups ( New ) @@ -766,6 +768,7 @@ QV('authAppSetupCheck', userinfo.otpsecret == 1); //QV('authKeySetupCheck', userinfo.otphkeys > 0); QV('authCodesSetupCheck', userinfo.otpkeys > 0); + QV('p2AccountActions', ((features & 4) == 0) && (serverinfo.domainauth == false) && (userinfo != null) && (userinfo._id.split('/')[2].startsWith('~') == false)); // On the mobile app, don't allow group creation (for now). QV('p3createMeshLink1', false); diff --git a/views/default.handlebars b/views/default.handlebars index c4f32683..37711745 100644 --- a/views/default.handlebars +++ b/views/default.handlebars @@ -1664,7 +1664,7 @@ QV('managePhoneNumber1', (features & 0x02000000) && (features & 0x04000000)); QV('managePhoneNumber2', (features & 0x02000000) && !(features & 0x04000000)); QV('manageEmail2FA', features & 0x00800000); - QV('p2AccountPassActions', ((features & 4) == 0) && (serverinfo.domainauth == 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('p2ServerActions', siteRights & 21); QV('LeftMenuMyServer', siteRights & 21); // 16 + 4 + 1 @@ -1678,8 +1678,7 @@ if (currentNode != null) { gotoDevice(currentNode._id, xxcurrentView, true); } // Update user management state - if ((userinfo.siteadmin & 2) != 0) - { + if ((userinfo.siteadmin & 2) != 0) { // We are user administrator if (users == null) { meshserver.send({ action: 'users' }); } if (wssessions == null) { meshserver.send({ action: 'wssessioncount' }); } @@ -2368,7 +2367,7 @@ case 'accountremove': { // An account was removed if (users == null) break; - delete users['user/' + domain + '/' + message.event.username.toLowerCase()]; + delete users[message.event.userid]; masterUpdate(16384); break; } @@ -2657,10 +2656,10 @@ case 'wssessioncount': { // Update the active web socket session count for a user if (wssessions != null) { - if (message.event.count == 0 && wssessions['user/' + domain + '/' + message.event.username.toLowerCase()]) { - delete wssessions['user/' + domain + '/' + message.event.username.toLowerCase()]; + if (message.event.count == 0 && wssessions[message.event.userid]) { + delete wssessions[message.event.userid]; } else { - wssessions['user/' + domain + '/' + message.event.username.toLowerCase()] = message.event.count; + wssessions[message.event.userid] = message.event.count; } masterUpdate(16384); } @@ -2668,8 +2667,8 @@ } case 'login': { // Update the last login time - if (users != null && users['user/' + domain + '/' + message.event.username.toLowerCase()]) { - users['user/' + domain + '/' + message.event.username.toLowerCase()].login = Math.floor(new Date(message.event.time).getTime() / 1000); + if (users != null && users[message.event.userid]) { + users[message.event.userid].login = Math.floor(new Date(message.event.time).getTime() / 1000); } break; } diff --git a/webserver.js b/webserver.js index 47c4730e..b71d3510 100644 --- a/webserver.js +++ b/webserver.js @@ -1688,15 +1688,30 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) { const userid = req.user.id; var user = obj.users[userid]; if (user == null) { - // Create the user - parent.debug('web', 'handleStrategyLogin: creating new user: ' + userid); - user = { type: 'user', _id: userid, name: req.user.name, email: req.user.email, domain: domain.id }; - if (req.user.email != null) { user.email = req.user.email; user.emailVerified = true; } - obj.users[userid] = user; - obj.db.SetUser(user); - // TODO: Event user creation - req.session.userid = req.user.id; - req.session.domainid = domain.id; + if (domain.newaccounts == true) { + // Create the user + parent.debug('web', 'handleStrategyLogin: creating new user: ' + userid); + user = { type: 'user', _id: userid, name: req.user.name, email: req.user.email, creation: Math.floor(Date.now() / 1000), domain: domain.id }; + if (req.user.email != null) { user.email = req.user.email; user.emailVerified = true; } + obj.users[userid] = user; + obj.db.SetUser(user); + + // Event user creation + var targets = ['*', 'server-users']; + 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 }; + 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. + parent.DispatchEvent(targets, obj, event); + + req.session.userid = req.user.id; + req.session.domainid = domain.id; + } else { + // New users not allowed + parent.debug('web', 'handleStrategyLogin: Can\'t create new accounts'); + req.session.loginmode = '1'; + req.session.messageid = 100; // Unable to create account. + res.redirect(domain.url + getQueryPortion(req)); + return; + } } else { // Login success var userChange = false; @@ -2032,7 +2047,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) { // See what authentication strategies we have var authStrategies = []; if (typeof domain.authstrategies == 'object') { - if ((typeof domain.authstrategies.twitter == 'object') && (typeof domain.authstrategies.twitter.apikey == 'string') && (typeof domain.authstrategies.twitter.apisecret == 'string')) { authStrategies.push('twitter'); } + if ((typeof domain.authstrategies.twitter == 'object') && (typeof domain.authstrategies.twitter.clientid == 'string') && (typeof domain.authstrategies.twitter.clientsecret == 'string')) { authStrategies.push('twitter'); } if ((typeof domain.authstrategies.google == 'object') && (typeof domain.authstrategies.google.clientid == 'string') && (typeof domain.authstrategies.google.clientsecret == 'string')) { authStrategies.push('google'); } if ((typeof domain.authstrategies.github == 'object') && (typeof domain.authstrategies.github.clientid == 'string') && (typeof domain.authstrategies.github.clientsecret == 'string')) { authStrategies.push('github'); } 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) { //obj.app.use(passport.session()); // Twitter - if ((typeof domain.authstrategies.twitter == 'object') && (typeof domain.authstrategies.twitter.apikey == 'string') && (typeof domain.authstrategies.twitter.apisecret == 'string')) { + if ((typeof domain.authstrategies.twitter == 'object') && (typeof domain.authstrategies.twitter.clientid == 'string') && (typeof domain.authstrategies.twitter.clientsecret == 'string')) { const TwitterStrategy = require('passport-twitter'); - passport.use(new TwitterStrategy({ consumerKey: domain.authstrategies.twitter.apikey, consumerSecret: domain.authstrategies.twitter.apisecret, callbackURL: url + 'auth-twitter-callback' }, + passport.use(new TwitterStrategy({ consumerKey: domain.authstrategies.twitter.clientid, consumerSecret: domain.authstrategies.twitter.clientsecret, callbackURL: url + 'auth-twitter-callback' }, function (token, tokenSecret, profile, cb) { var user = { id: 'user/' + domain.id + '/~twitter:' + profile.id, name: profile.displayName }; if ((typeof profile.emails == 'object') && (profile.emails[0] != null) && (typeof profile.emails[0].value == 'string')) { user.email = profile.emails[0].value; }