From 5a0f6c2b9fd208c6581cade92ee019730ec0b0aa Mon Sep 17 00:00:00 2001 From: djmaze Date: Thu, 22 Jul 2021 22:15:09 +0200 Subject: [PATCH 1/3] Translations for admin 2FA --- snappymail/v/0.0.0/app/localization/de-DE/admin.json | 1 + snappymail/v/0.0.0/app/localization/en/admin.json | 1 + snappymail/v/0.0.0/app/localization/es-ES/admin.json | 1 + snappymail/v/0.0.0/app/localization/fr-FR/admin.json | 1 + snappymail/v/0.0.0/app/localization/hu-HU/admin.json | 1 + snappymail/v/0.0.0/app/localization/nl-NL/admin.json | 1 + snappymail/v/0.0.0/app/localization/sv-SE/admin.json | 1 + snappymail/v/0.0.0/app/localization/zh-CN/admin.json | 1 + 8 files changed, 8 insertions(+) diff --git a/snappymail/v/0.0.0/app/localization/de-DE/admin.json b/snappymail/v/0.0.0/app/localization/de-DE/admin.json index b972fe5d8..8a9534d7e 100644 --- a/snappymail/v/0.0.0/app/localization/de-DE/admin.json +++ b/snappymail/v/0.0.0/app/localization/de-DE/admin.json @@ -2,6 +2,7 @@ "LOGIN": { "LABEL_LOGIN": "Benutzer", "LABEL_PASSWORD": "Passwort", + "LABEL_TOTP": "TOTP-Code", "BUTTON_LOGIN": "Im Adminpanel anmelden" }, "TOP_PANEL": { diff --git a/snappymail/v/0.0.0/app/localization/en/admin.json b/snappymail/v/0.0.0/app/localization/en/admin.json index 2cfb1efe9..7a7bed7ac 100644 --- a/snappymail/v/0.0.0/app/localization/en/admin.json +++ b/snappymail/v/0.0.0/app/localization/en/admin.json @@ -2,6 +2,7 @@ "LOGIN": { "LABEL_LOGIN": "Login", "LABEL_PASSWORD": "Password", + "LABEL_TOTP": "TOTP code", "BUTTON_LOGIN": "Log into the admin panel" }, "TOP_PANEL": { diff --git a/snappymail/v/0.0.0/app/localization/es-ES/admin.json b/snappymail/v/0.0.0/app/localization/es-ES/admin.json index bc6ddabab..9f4c24a55 100644 --- a/snappymail/v/0.0.0/app/localization/es-ES/admin.json +++ b/snappymail/v/0.0.0/app/localization/es-ES/admin.json @@ -2,6 +2,7 @@ "LOGIN": { "LABEL_LOGIN": "Ingresar", "LABEL_PASSWORD": "Contraseña", + "LABEL_TOTP": "Código TOTP", "BUTTON_LOGIN": "Ingresar al panel de control" }, "TOP_PANEL": { diff --git a/snappymail/v/0.0.0/app/localization/fr-FR/admin.json b/snappymail/v/0.0.0/app/localization/fr-FR/admin.json index 30562df0d..eb9307290 100644 --- a/snappymail/v/0.0.0/app/localization/fr-FR/admin.json +++ b/snappymail/v/0.0.0/app/localization/fr-FR/admin.json @@ -2,6 +2,7 @@ "LOGIN": { "LABEL_LOGIN": "Identifiant", "LABEL_PASSWORD": "Mot de passe", + "LABEL_TOTP": "Code TOTP", "BUTTON_LOGIN": "Se connecter au panneau d'administration" }, "TOP_PANEL": { diff --git a/snappymail/v/0.0.0/app/localization/hu-HU/admin.json b/snappymail/v/0.0.0/app/localization/hu-HU/admin.json index 9580417d8..bc71f177d 100644 --- a/snappymail/v/0.0.0/app/localization/hu-HU/admin.json +++ b/snappymail/v/0.0.0/app/localization/hu-HU/admin.json @@ -2,6 +2,7 @@ "LOGIN": { "LABEL_LOGIN": "Belépés", "LABEL_PASSWORD": "Jelszó", + "LABEL_TOTP": "TOTP kód", "BUTTON_LOGIN": "Bejelentkezés az admin felületre" }, "TOP_PANEL": { diff --git a/snappymail/v/0.0.0/app/localization/nl-NL/admin.json b/snappymail/v/0.0.0/app/localization/nl-NL/admin.json index 39e987c33..f303830d6 100644 --- a/snappymail/v/0.0.0/app/localization/nl-NL/admin.json +++ b/snappymail/v/0.0.0/app/localization/nl-NL/admin.json @@ -2,6 +2,7 @@ "LOGIN": { "LABEL_LOGIN": "Inlognaam", "LABEL_PASSWORD": "Wachtwoord", + "LABEL_TOTP": "TOTP-code", "BUTTON_LOGIN": "Aanmelden in het beheer paneel" }, "TOP_PANEL": { diff --git a/snappymail/v/0.0.0/app/localization/sv-SE/admin.json b/snappymail/v/0.0.0/app/localization/sv-SE/admin.json index f7e2a7c1a..d775f2924 100644 --- a/snappymail/v/0.0.0/app/localization/sv-SE/admin.json +++ b/snappymail/v/0.0.0/app/localization/sv-SE/admin.json @@ -2,6 +2,7 @@ "LOGIN": { "LABEL_LOGIN": "Logga in", "LABEL_PASSWORD": "Lösenord", + "LABEL_TOTP": "TOTP-kod", "BUTTON_LOGIN": "Logga in till admin-panelen" }, "TOP_PANEL": { diff --git a/snappymail/v/0.0.0/app/localization/zh-CN/admin.json b/snappymail/v/0.0.0/app/localization/zh-CN/admin.json index a13f46193..8a6c98c17 100644 --- a/snappymail/v/0.0.0/app/localization/zh-CN/admin.json +++ b/snappymail/v/0.0.0/app/localization/zh-CN/admin.json @@ -2,6 +2,7 @@ "LOGIN": { "LABEL_LOGIN": "登录", "LABEL_PASSWORD": "密码", + "LABEL_TOTP": "TOTP代碼", "BUTTON_LOGIN": "登录到控制面板" }, "TOP_PANEL": { From 0a69c6410d6e0a78839c0e0ba3ffe0abd38aef0d Mon Sep 17 00:00:00 2001 From: djmaze Date: Fri, 23 Jul 2021 11:40:03 +0200 Subject: [PATCH 2/3] Added support for JavaScript FormData As preparation for 2FA plugins and easier Fetch calls --- dev/Remote/AbstractFetch.js | 6 +++++- dev/Remote/User/Fetch.js | 16 +++------------- dev/View/User/Login.js | 17 ++++++++--------- dev/bootstrap.js | 14 ++++++++------ .../v/0.0.0/app/templates/Views/User/Login.html | 4 ++-- 5 files changed, 26 insertions(+), 31 deletions(-) diff --git a/dev/Remote/AbstractFetch.js b/dev/Remote/AbstractFetch.js index c92b8edc9..84a10ad64 100644 --- a/dev/Remote/AbstractFetch.js +++ b/dev/Remote/AbstractFetch.js @@ -47,7 +47,11 @@ abort = (sAction, bClearOnly) => { fetchJSON = (action, sGetAdd, params, timeout, jsonCallback) => { sGetAdd = pString(sGetAdd); params = params || {}; - params.Action = action; + if (params instanceof FormData) { + params.set('Action', action); + } else { + params.Action = action; + } let init = {}; if (window.AbortController) { abort(action); diff --git a/dev/Remote/User/Fetch.js b/dev/Remote/User/Fetch.js index fdc205072..cf125f1b0 100644 --- a/dev/Remote/User/Fetch.js +++ b/dev/Remote/User/Fetch.js @@ -50,20 +50,10 @@ class RemoteUserFetch extends AbstractFetchRemote { /** * @param {?Function} fCallback - * @param {string} sEmail - * @param {string} sLogin - * @param {string} sPassword - * @param {boolean} bSignMe - * @param {string=} sLanguage + * @param {FormData} oData */ - login(fCallback, sEmail, sPassword, bSignMe, sLanguage) { - this.defaultRequest(fCallback, 'Login', { - Email: sEmail, - Login: '', - Password: sPassword, - Language: sLanguage || '', - SignMe: bSignMe ? 1 : 0 - }); + login(fCallback, oData) { + this.defaultRequest(fCallback, 'Login', oData); } /** diff --git a/dev/View/User/Login.js b/dev/View/User/Login.js index 432f4dc22..4bdfcc4a6 100644 --- a/dev/View/User/Login.js +++ b/dev/View/User/Login.js @@ -104,17 +104,19 @@ class LoginUserView extends AbstractViewCenter { } submitCommand(self, event) { - let email = this.email().trim(), - valid = event.target.form.reportValidity() && email, - pass = this.password(); + let form = event.target.form, + data = new FormData(form), + email = this.email().trim(), + valid = form.reportValidity() && email; this.emailError(!email); - this.passwordError(!pass); + this.passwordError(!this.password()); this.formError(!valid); if (valid) { this.submitRequest(true); - + data.set('Language', this.bSendLanguage ? this.language() : ''); + data.set('SignMe', this.signMe() ? 1 : 0); Remote.login( (iError, oData) => { if (iError) { @@ -129,10 +131,7 @@ class LoginUserView extends AbstractViewCenter { rl.route.reload(); } }, - email, - pass, - !!this.signMe(), - this.bSendLanguage ? this.language() : '' + data ); Local.set(ClientSideKeyName.LastSignMe, this.signMe() ? '-1-' : '-0-'); diff --git a/dev/bootstrap.js b/dev/bootstrap.js index 9cb786364..8f76009f9 100644 --- a/dev/bootstrap.js +++ b/dev/bootstrap.js @@ -94,10 +94,7 @@ export default App => { if (postData) { init.method = 'POST'; init.headers['Content-Type'] = 'application/x-www-form-urlencoded; charset=UTF-8'; - postData.XToken = Settings.app('token'); -// init.body = JSON.stringify(postData); - const formData = new FormData(), - buildFormData = (formData, data, parentKey) => { + const buildFormData = (formData, data, parentKey) => { if (data && typeof data === 'object' && !(data instanceof Date || data instanceof File)) { Object.keys(data).forEach(key => buildFormData(formData, data[key], parentKey ? `${parentKey}[${key}]` : key) @@ -105,9 +102,14 @@ export default App => { } else { formData.set(parentKey, data == null ? '' : data); } + return formData; }; - buildFormData(formData, postData); - init.body = new URLSearchParams(formData); + postData = (postData instanceof FormData) + ? postData + : buildFormData(new FormData(), postData); + postData.set('XToken', Settings.app('token')); +// init.body = JSON.stringify(Object.fromEntries(postData)); + init.body = new URLSearchParams(postData); } return fetch(resource, init).then(response => { diff --git a/snappymail/v/0.0.0/app/templates/Views/User/Login.html b/snappymail/v/0.0.0/app/templates/Views/User/Login.html index c677637f4..7635440e1 100644 --- a/snappymail/v/0.0.0/app/templates/Views/User/Login.html +++ b/snappymail/v/0.0.0/app/templates/Views/User/Login.html @@ -9,7 +9,7 @@ data-bind="submit: submitForm, css: {'errorAnimated': formError, 'submitting': submitRequest()}">
- @@ -18,7 +18,7 @@
- From 56e8ea664db9c1288269837c32ce291f0f96f28b Mon Sep 17 00:00:00 2001 From: djmaze Date: Fri, 23 Jul 2021 11:57:45 +0200 Subject: [PATCH 3/3] Cleanup user login JavaScript code --- dev/View/User/Login.js | 45 +++++++++++++++--------------------------- 1 file changed, 16 insertions(+), 29 deletions(-) diff --git a/dev/View/User/Login.js b/dev/View/User/Login.js index 4bdfcc4a6..54b15e20d 100644 --- a/dev/View/User/Login.js +++ b/dev/View/User/Login.js @@ -16,18 +16,9 @@ import { AbstractViewCenter } from 'Knoin/AbstractViews'; import { LanguagesPopupView } from 'View/Popup/Languages'; -const - LoginSignMeType = { - DefaultOff: 0, - DefaultOn: 1, - Unused: 2 - }, - - LoginSignMeTypeAsString = { - DefaultOff: 'defaultoff', - DefaultOn: 'defaulton', - Unused: 'unused' - }; +const SignMeOff = 0, + SignMeOn = 1, + SignMeUnused = 2; class LoginUserView extends AbstractViewCenter { @@ -52,7 +43,7 @@ class LoginUserView extends AbstractViewCenter { langRequest: false, - signMeType: LoginSignMeType.Unused + signMeType: SignMeUnused }); this.formError = ko.observable(false).extend({ falseTimeout: 500 }); @@ -68,19 +59,17 @@ class LoginUserView extends AbstractViewCenter { languageFullName: () => convertLangName(this.language()), - signMeVisibility: () => LoginSignMeType.Unused !== this.signMeType() + signMeVisibility: () => SignMeUnused !== this.signMeType() }); this.addSubscribables({ - email: () => { - this.emailError(false); - }, + email: () => this.emailError(false), password: () => this.passwordError(false), submitError: value => value || this.submitErrorAddidional(''), - signMeType: iValue => this.signMe(LoginSignMeType.DefaultOn === iValue), + signMeType: iValue => this.signMe(SignMeOn === iValue), language: value => { this.langRequest(true); @@ -106,10 +95,9 @@ class LoginUserView extends AbstractViewCenter { submitCommand(self, event) { let form = event.target.form, data = new FormData(form), - email = this.email().trim(), - valid = form.reportValidity() && email; + valid = form.reportValidity(); - this.emailError(!email); + this.emailError(!this.email()); this.passwordError(!this.password()); this.formError(!valid); @@ -146,29 +134,28 @@ class LoginUserView extends AbstractViewCenter { onBuild() { const signMeLocal = Local.get(ClientSideKeyName.LastSignMe), - signMe = (SettingsGet('SignMe') || 'unused').toLowerCase(); + signMe = (SettingsGet('SignMe') || '').toLowerCase(); switch (signMe) { - case LoginSignMeTypeAsString.DefaultOff: - case LoginSignMeTypeAsString.DefaultOn: + case 'defaultoff': + case 'defaulton': this.signMeType( - LoginSignMeTypeAsString.DefaultOn === signMe ? LoginSignMeType.DefaultOn : LoginSignMeType.DefaultOff + 'defaulton' === signMe ? SignMeOn : SignMeOff ); switch (signMeLocal) { case '-1-': - this.signMeType(LoginSignMeType.DefaultOn); + this.signMeType(SignMeOn); break; case '-0-': - this.signMeType(LoginSignMeType.DefaultOff); + this.signMeType(SignMeOff); break; // no default } break; - case LoginSignMeTypeAsString.Unused: default: - this.signMeType(LoginSignMeType.Unused); + this.signMeType(SignMeUnused); break; } }