diff --git a/customize.dist/pages/login.js b/customize.dist/pages/login.js index 9234a447f..2ae732805 100644 --- a/customize.dist/pages/login.js +++ b/customize.dist/pages/login.js @@ -48,7 +48,7 @@ define([ ]), h('div.extra', [ (Config.restrictRegistration? - undefined: + h('div'): h('a#register', { href: "/register/", }, Msg.login_register) @@ -56,13 +56,14 @@ define([ h('button.login', Msg.login_login), ]), ]), + h('div.col-md-3'), h('div.col-md-3'+ssoEnabled), h('div#ssoForm.form-group.col-md-6'+ssoEnabled, [ h('div.cp-login-sso', Msg.sso_login_description) ]), - h('div.col-md-3') + h('div.col-md-3'+ssoEnabled), ]), - h('div.row', [ + h('div.row.cp-login-encryption', [ h('div.col-md-3'), h('div.col-md-6', Msg.register_warning_note), h('div.col-md-3'), diff --git a/customize.dist/pages/ssoauth.js b/customize.dist/pages/ssoauth.js index 691d18470..2b6297684 100644 --- a/customize.dist/pages/ssoauth.js +++ b/customize.dist/pages/ssoauth.js @@ -30,22 +30,21 @@ define([ return frame([ h('div.row', [ h('div.hidden.col-md-3'), - h('div#userForm.form-group.col-md-6', [ - h('div.cp-ssoauth-pw', [ - h('p.register', Msg.ssoauth_form_hint_register), - h('p.login', Msg.ssoauth_form_hint_login), - h('input.form-control#password', { - type: 'password', - placeholder: Msg.login_password, - }), - h('input.form-control.register#passwordconfirm', { - type: 'password', - placeholder: Msg.login_confirm, - }), - h('div.cp-ssoauth-button', - h('button.btn.btn-primary#cp-ssoauth-button', Msg.continue) - ) - ]), + h('div#userForm.form-group.col-md-6.cp-ssoauth-pw', [ + h('p.cp-isregister.cp-login-instance', Msg.ssoauth_form_hint_register), + h('p.cp-islogin.cp-login-instance', Msg.ssoauth_form_hint_login), + h('input.form-control#password', { + type: 'password', + placeholder: Msg.login_password, + }), + h('input.form-control.cp-isregister#passwordconfirm', { + type: 'password', + placeholder: Msg.login_confirm, + }), + h('div.cp-ssoauth-button.extra', + h('div'), + h('button.login#cp-ssoauth-button', Msg.continue) + ) ]), h('div.hidden.col-md-3'), ]) diff --git a/customize.dist/src/less2/include/login.less b/customize.dist/src/less2/include/login.less new file mode 100644 index 000000000..a47c1aabb --- /dev/null +++ b/customize.dist/src/less2/include/login.less @@ -0,0 +1,50 @@ +@import (reference) "../include/infopages.less"; +@import (reference) "../include/colortheme-all.less"; +@import (reference) "../include/alertify.less"; +@import (reference) "../include/forms.less"; + +.login_main() { + #userForm, #ssoForm { + .cp-shadow(); + background-color: @cp_static-card-bg; + padding: 10px; + margin: 0; + border-radius: @infopages-radius-L; + .cp-login-instance, .cp-login-sso-description { + margin-bottom: 5px; + } + .form-control { + border-radius: @infopages-radius; + color: @cryptpad_text_col; + background-color: @cp_forms-bg; + margin-bottom: 10px; + &:focus { + border-color: @cryptpad_color_brand; + } + .tools_placeholder-color(); + } + .checkbox-container { + color: @cryptpad_text_col; + } + } + #ssoForm { + margin-top: 10px; + button { + margin: 0 5px; + } + .cp-login-sso { + display: flex; + align-items: center; + } + } + .cp-default-label { + display: none; + } + .extra { + margin-top: 1em; + button.login { + margin-right: 0px; + } + } +} + diff --git a/customize.dist/src/less2/pages/page-login.less b/customize.dist/src/less2/pages/page-login.less index 655a418e5..1bf4042cd 100644 --- a/customize.dist/src/less2/pages/page-login.less +++ b/customize.dist/src/less2/pages/page-login.less @@ -3,6 +3,7 @@ @import (reference) "../include/alertify.less"; @import (reference) "../include/checkmark.less"; @import (reference) "../include/forms.less"; +@import (reference) "../include/login.less"; &.cp-page-login { .infopages_main(); @@ -22,47 +23,15 @@ .cp-hidden { display: none !important; } - #userForm, #ssoForm { - .cp-shadow(); - background-color: @cp_static-card-bg; - padding: 10px; - margin: 0 10px 10px 10px; - border-radius: @infopages-radius-L; - .cp-login-instance, .cp-login-sso-description { - margin-bottom: 5px; - } - .form-control { - border-radius: @infopages-radius; - color: @cryptpad_text_col; - background-color: @cp_forms-bg; - margin-bottom: 10px; - &:focus { - border-color: @cryptpad_color_brand; - } - .tools_placeholder-color(); - } - .checkbox-container { - color: @cryptpad_text_col; - } - } - #ssoForm { - button { - margin: 0 5px; - } - } + .login_main(); .align-items-center { box-shadow: 0 5px 15px @cp_shadow-color; background: @cryptpad_color_white; } - .extra { - margin-top: 1em; - button.login { - margin-right: 0px; - } - } - .cp-default-label { - display: none; - } + } + + .cp-login-encryption { + margin-top: 10px; } .cp-password-form { diff --git a/customize.dist/src/less2/pages/page-register.less b/customize.dist/src/less2/pages/page-register.less index 662a03381..481146253 100644 --- a/customize.dist/src/less2/pages/page-register.less +++ b/customize.dist/src/less2/pages/page-register.less @@ -3,6 +3,7 @@ @import (reference) "../include/alertify.less"; @import (reference) "../include/checkmark.less"; @import (reference) "../include/forms.less"; +@import (reference) "../include/login.less"; &.cp-page-register { .infopages_main(); @@ -88,37 +89,21 @@ .cp-hidden { display: none !important; } + .login_main(); #userForm, #ssoForm { - padding: 15px; - background-color: @cp_static-card-bg; position: relative; z-index: 2; - //margin-bottom: 100px; - border-radius: @infopages-radius-L; max-width: 100%; - .cp-shadow(); - .form-control { - border-radius: @infopages-radius; - color: @cryptpad_text_col; - background-color: @cp_forms-bg; - margin-bottom: 10px; - &:focus { - border-color: @cryptpad_color_brand; - } - .tools_placeholder-color(); - } + padding: 15px; .checkbox-container { margin-top: 0.5rem; - color: @cryptpad_text_col; } button#register { margin-top: 10px; } } #ssoForm { - button { - margin: 0 5px; - } + margin-top: 15px; } .cp-register-notes { diff --git a/customize.dist/src/less2/pages/page-ssoauth.less b/customize.dist/src/less2/pages/page-ssoauth.less index a2c0e0141..64d9511db 100644 --- a/customize.dist/src/less2/pages/page-ssoauth.less +++ b/customize.dist/src/less2/pages/page-ssoauth.less @@ -2,28 +2,47 @@ @import (reference) "../include/colortheme-all.less"; @import (reference) "../include/alertify.less"; @import (reference) "../include/forms.less"; +@import (reference) "../include/login.less"; &.cp-page-ssoauth { .infopages_main(); .forms_main(); - .alertify_main(); + .form-group { + .extra { + display: flex; + align-items: center; + justify-content: space-between; + width: 100%; + } + } + div.cp-ssoauth-pw { display: none; + width: 100%; } - &.cp-regsiter { - .login { + .cp-container { + .login_main(); + } + + &.cp-register { + .cp-islogin { display: none; } + #passwordconfirm { + margin-bottom: 0px !important; + } } &.cp-login { - .register { + .cp-isregister { display: none; } + #password { + margin-bottom: 0px !important; + } } - } diff --git a/lib/archive-account.js b/lib/archive-account.js index 31256336b..2e9217572 100644 --- a/lib/archive-account.js +++ b/lib/archive-account.js @@ -9,8 +9,9 @@ const Core = require("./commands/core"); const Metadata = require("./commands/metadata"); const Meta = require("./metadata"); const Logger = require("./log"); +const plugins = require("./plugin-manager"); -let SSOUtils; try { SSOUtils = require("./plugins/sso/sso-utils"); } catch (e) {} +let SSOUtils = plugins.SSO && plugins.SSO.utils; const Path = require("path"); const Fse = require("fs-extra"); diff --git a/lib/challenge-commands/totp.js b/lib/challenge-commands/totp.js index 8854d681f..9be38a1ed 100644 --- a/lib/challenge-commands/totp.js +++ b/lib/challenge-commands/totp.js @@ -10,8 +10,6 @@ const BlockStore = require("../storage/block"); const Block = require("../commands/block"); const config = require("../load-config"); -let SSOUtils; try { SSOUtils = require("../plugins/sso/sso-utils"); } catch (e) {} - const Commands = module.exports; var isString = s => typeof(s) === 'string'; @@ -66,6 +64,7 @@ var EXPIRATION = (config.otpSessionExpiration || 7 * 24) * 3600 * 1000; // Create a session with a token for the given public key const makeSession = (Env, publicKey, oldKey, ssoSession, cb) => { const sessionId = ssoSession || Sessions.randomId(); + let SSOUtils = Env.plugins && Env.plugins.SSO && Env.plugins.SSO.utils; // For password change, we need to get the sso session associated to the old block key // In other cases (login and totp_setup), the sso session is associated to the current block diff --git a/lib/commands/admin-rpc.js b/lib/commands/admin-rpc.js index 55f5b7a9d..a2c1686cb 100644 --- a/lib/commands/admin-rpc.js +++ b/lib/commands/admin-rpc.js @@ -15,8 +15,6 @@ const ArchiveAccount = require('../archive-account'); const { Worker } = require('node:worker_threads'); /* jshint ignore:end */ -let SSOUtils; try { SSOUtils = require("../plugins/sso/sso-utils"); } catch (e) {} - var Fs = require("fs"); var Admin = module.exports; @@ -724,6 +722,7 @@ var archiveBlock = function (Env, Server, cb, data) { }); cb(err); }); + let SSOUtils = Env.plugins && Env.plugins.SSO && Env.plugins.SSO.utils; if (SSOUtils) { SSOUtils.deleteAccount(Env, key, () => {}); } }; @@ -741,6 +740,7 @@ var restoreArchivedBlock = function (Env, Server, cb, data) { }); // Also restore SSO data + let SSOUtils = Env.plugins && Env.plugins.SSO && Env.plugins.SSO.utils; if (SSOUtils) { SSOUtils.restoreAccount(Env, key, () => {}); } cb(err); diff --git a/lib/commands/block.js b/lib/commands/block.js index 18e1d21a6..d7f33a295 100644 --- a/lib/commands/block.js +++ b/lib/commands/block.js @@ -6,8 +6,6 @@ const nThen = require("nthen"); const Util = require("../common-util"); const BlockStore = require("../storage/block"); -let SSOUtils; try { SSOUtils = require("../plugins/sso/sso-utils"); } catch (e) {} - var isString = s => typeof(s) === 'string'; Block.isValidBlockId = id => { return id && isString(id) && id.length === 44; @@ -191,6 +189,8 @@ Block.removeLoginBlock = function (Env, publicKey, reason, _cb) { // is already deleted anyway. // If this is NOT a password change, also delete sso user. + let SSOUtils = Env.plugins && Env.plugins.SSO && Env.plugins.SSO.utils; + if (!SSOUtils) { return; } if (reason !== 'PASSWORD_CHANGE') { SSOUtils.deleteAccount(Env, publicKey, () => {}); diff --git a/lib/env.js b/lib/env.js index 9907500e7..21cbea759 100644 --- a/lib/env.js +++ b/lib/env.js @@ -14,6 +14,8 @@ const Package = require("../package.json"); const Default = require("./defaults"); const Path = require("path"); +const plugins = require('./plugin-manager'); + const Nacl = require("tweetnacl/nacl-fast"); var canonicalizeOrigin = function (s) { @@ -79,6 +81,7 @@ module.exports.create = function (config) { const curve = Nacl.box.keyPair(); const Env = { + plugins: plugins, logFeedback: Boolean(config.logFeedback), mainPages: config.mainPages || Default.mainPages(), diff --git a/lib/http-commands.js b/lib/http-commands.js index dcac23421..f32c998fb 100644 --- a/lib/http-commands.js +++ b/lib/http-commands.js @@ -1,5 +1,6 @@ var Nacl = require("tweetnacl/nacl-fast"); var Util = require('./common-util.js'); +const plugins = require("./plugin-manager"); var Challenge = require("./storage/challenge.js"); // C.read(Env, id, cb) @@ -75,7 +76,7 @@ COMMANDS.TOTP_REMOVE_BLOCK = TOTP.TOTP_REMOVE_BLOCK; try { // SSO plugin may not be installed - const SSO = require("./plugins/sso/challenge.js"); + const SSO = plugins.SSO && plugins.SSO.challenge; COMMANDS.SSO_AUTH = SSO.SSO_AUTH; COMMANDS.SSO_AUTH_CB = SSO.SSO_AUTH_CB; COMMANDS.SSO_WRITE_BLOCK = SSO.SSO_WRITE_BLOCK; // Account creation only diff --git a/lib/http-worker.js b/lib/http-worker.js index 0bbe4593d..8ba24a712 100644 --- a/lib/http-worker.js +++ b/lib/http-worker.js @@ -13,13 +13,15 @@ const cookieParser = require("cookie-parser"); const bodyParser = require('body-parser'); const BlobStore = require("./storage/blob"); const BlockStore = require("./storage/block"); +const plugins = require("./plugin-manager"); const DEFAULT_QUERY_TIMEOUT = 5000; const PID = process.pid; -let SSOUtils; try { SSOUtils = require("./plugins/sso/sso-utils"); } catch (e) {} +let SSOUtils = plugins.SSO && plugins.SSO.utils; var Env = JSON.parse(process.env.Env); +Env.plugins = plugins; const response = Util.response(function (errLabel, info) { if (!Env.Log) { return; } Env.Log.error(errLabel, info); diff --git a/lib/plugin-manager.js b/lib/plugin-manager.js new file mode 100644 index 000000000..5326fb3f9 --- /dev/null +++ b/lib/plugin-manager.js @@ -0,0 +1,18 @@ +const fs = require('node:fs'); +const plugins = {}; + +try { + let pluginsDir = fs.readdirSync(__dirname + '/plugins'); + pluginsDir.forEach((name) => { + try { + let plugin = require(`./plugins/${name}/index`); + plugins[plugin.name] = plugin.modules; + } catch (err) { + console.error(err); + } + }); +} catch (err) { + if (err.code !== 'ENOENT') { console.error(err); } +} + +module.exports = plugins; diff --git a/www/login/main.js b/www/login/main.js index 3986edfac..c2f2aeef7 100644 --- a/www/login/main.js +++ b/www/login/main.js @@ -40,6 +40,10 @@ define([ return b; }); $sso.append(list); + + // Disable bfcache (back/forward cache) to prevent SSO button + // being disabled when using the browser "back" feature on the SSO page + $(window).on('unload', () => {}); } /* Log in UI */ diff --git a/www/register/main.js b/www/register/main.js index 174f0e8d7..302e2ebb7 100644 --- a/www/register/main.js +++ b/www/register/main.js @@ -70,6 +70,10 @@ define([ return b; }); $sso.append(list); + + // Disable bfcache (back/forward cache) to prevent SSO button + // being disabled when using the browser "back" feature on the SSO page + $(window).on('unload', () => {}); } var registerClick = function () {