From 1f16684ba1f5ad3b56397abbdde3a8d34de27124 Mon Sep 17 00:00:00 2001 From: Akhil Date: Fri, 10 Apr 2026 18:53:14 +0530 Subject: [PATCH 01/13] feat: try to setup encryption at creation --- .codex | 0 package-lock.json | 40 ++++++++++++++++++++++++++++++++++++---- package.json | 3 ++- src/Signup.vue | 19 +++++++++++++++++++ 4 files changed, 57 insertions(+), 5 deletions(-) create mode 100644 .codex diff --git a/.codex b/.codex new file mode 100644 index 00000000..e69de29b diff --git a/package-lock.json b/package-lock.json index 3cd4fc6c..a383b436 100644 --- a/package-lock.json +++ b/package-lock.json @@ -15,6 +15,7 @@ "@nextcloud/l10n": "^3.1.0", "@nextcloud/router": "^3.0.1", "@nextcloud/vue": "^8.16.0", + "passwords-client": "1.0.0-alpha.5731", "vue": "^2.7.0", "vue-password-strength-meter": "^1.7.2" }, @@ -9325,6 +9326,21 @@ "node": ">= 0.8.0" } }, + "node_modules/libsodium": { + "version": "0.7.10", + "resolved": "https://registry.npmjs.org/libsodium/-/libsodium-0.7.10.tgz", + "integrity": "sha512-eY+z7hDrDKxkAK+QKZVNv92A5KYkxfvIshtBJkmg5TSiCnYqZP3i9OO9whE79Pwgm4jGaoHgkM4ao/b9Cyu4zQ==", + "license": "ISC" + }, + "node_modules/libsodium-wrappers": { + "version": "0.7.10", + "resolved": "https://registry.npmjs.org/libsodium-wrappers/-/libsodium-wrappers-0.7.10.tgz", + "integrity": "sha512-pO3F1Q9NPLB/MWIhehim42b/Fwb30JNScCNh8TcQ/kIc+qGLQch8ag8wb0keK3EP5kbGakk1H8Wwo7v+36rNQg==", + "license": "ISC", + "dependencies": { + "libsodium": "^0.7.0" + } + }, "node_modules/lines-and-columns": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", @@ -11130,6 +11146,26 @@ "node": ">= 0.8" } }, + "node_modules/passwords-client": { + "version": "1.0.0-alpha.5731", + "resolved": "https://registry.npmjs.org/passwords-client/-/passwords-client-1.0.0-alpha.5731.tgz", + "integrity": "sha512-Pl36mcHhUlbN9IjJAkPmcunXPvC5Rz/hVZZgUDKM+GOUIzVSsH8ltPliUJCN+2tugc0x/aINmO987CXNptWcYw==", + "license": "ISC", + "dependencies": { + "eventemitter3": "^3.1.2", + "libsodium": "0.7.10", + "libsodium-wrappers": "0.7.10", + "process": "^0.11.10", + "url-parse": "^1.5.3", + "uuid": "^8.3.2" + } + }, + "node_modules/passwords-client/node_modules/eventemitter3": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-3.1.2.tgz", + "integrity": "sha512-tvtQIeLVHjDkJYnzf2dgVMxfuSGJeM/7UCG17TT4EumTfNtF+0nebF/4zWOIkCreAbtNqhGEboB6BWrwqNaw4Q==", + "license": "MIT" + }, "node_modules/path-browserify": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-1.0.1.tgz", @@ -11566,8 +11602,6 @@ "version": "0.11.10", "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", "integrity": "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==", - "dev": true, - "peer": true, "engines": { "node": ">= 0.6.0" } @@ -14418,8 +14452,6 @@ "version": "8.3.2", "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", - "dev": true, - "peer": true, "bin": { "uuid": "dist/bin/uuid" } diff --git a/package.json b/package.json index 58337c9e..0337d171 100644 --- a/package.json +++ b/package.json @@ -26,7 +26,8 @@ "@nextcloud/router": "^3.0.1", "@nextcloud/vue": "^8.16.0", "vue": "^2.7.0", - "vue-password-strength-meter": "^1.7.2" + "vue-password-strength-meter": "^1.7.2", + "passwords-client": "1.0.0-alpha.5731" }, "browserslist": [ "extends @nextcloud/browserslist-config" diff --git a/src/Signup.vue b/src/Signup.vue index 9f0d163c..5dee00ef 100644 --- a/src/Signup.vue +++ b/src/Signup.vue @@ -30,6 +30,8 @@ import HCaptchaForm from './signup/HCaptchaForm.vue' import CaptchaForm from './signup/CaptchaForm.vue' import RecoveryEmailForm from './signup/RecoveryEmailForm.vue' import SuccessSection from './signup/SuccessSection.vue' +import PasswordsClient from "passwords-client"; +import {EnhancedApi} from 'passwords-client/legacy'; const APPLICATION_NAME = 'ecloud-accounts' @@ -107,7 +109,9 @@ export default { const url = generateUrl(`/apps/${this.appName}/accounts/create`) this.processingCreation = true await Axios.post(url, data) + await this.setupEncryption() + // If the execution reaches here, the response status is in the 2xx range this.showRegistrationForm = false this.showCaptchaForm = false @@ -125,6 +129,21 @@ export default { this.showMessage(errorMessage, 'error') } }, + async setupEncryption() { + const token = this.formData.password + const user = this.formData.username + let baseUrl = generateUrl('', [], {}) + if (baseUrl.indexOf(location.origin) === -1) { + baseUrl = new URL(location.origin + baseUrl).href + } + + const server = { baseUrl, user, token } + const client = new PasswordsClient(server, { baseUrl, user, token }) + const api = new EnhancedApi() + api.initialize(client, { cseMode: 'CSEv1r1' }) + + await api.setAccountChallenge(this.formData.password) + }, showMessage(message, type) { type === 'success' ? showSuccess(message) : showError(message) }, -- GitLab From b8e8747c39a3455a2315a3beed64e130e6a4b48d Mon Sep 17 00:00:00 2001 From: Akhil Date: Mon, 20 Apr 2026 18:05:19 +0530 Subject: [PATCH 02/13] fix: add required wrappers for passwords client to setup encryption --- .gitignore | 1 + lib/Controller/AccountController.php | 9 +++++-- src/Signup.vue | 32 ++++++++++++----------- src/passwords/ApiRequest.js | 22 ++++++++++++++++ src/passwords/ClientService.js | 39 ++++++++++++++++++++++++++++ src/passwords/LegacyPasswordsApi.js | 17 ++++++++++++ 6 files changed, 103 insertions(+), 17 deletions(-) create mode 100644 src/passwords/ApiRequest.js create mode 100644 src/passwords/ClientService.js create mode 100644 src/passwords/LegacyPasswordsApi.js diff --git a/.gitignore b/.gitignore index 25851242..fb33c3fa 100644 --- a/.gitignore +++ b/.gitignore @@ -19,3 +19,4 @@ translationtool.phar .php-cs-fixer.cache .phpunit.result.cache junit.xml +css/ diff --git a/lib/Controller/AccountController.php b/lib/Controller/AccountController.php index 54d316ac..c0fd27bf 100644 --- a/lib/Controller/AccountController.php +++ b/lib/Controller/AccountController.php @@ -113,18 +113,21 @@ class AccountController extends Controller { $captchaProvider = $this->getCaptchaProvider(); $this->initialState->provideInitialState('captchaProvider', $captchaProvider); + $csp = $response->getContentSecurityPolicy(); + $csp->allowEvalWasm(); + if ($captchaProvider === self::HCAPTCHA_PROVIDER) { - $csp = $response->getContentSecurityPolicy(); foreach (self::HCAPTCHA_DOMAINS as $domain) { $csp->addAllowedScriptDomain($domain); $csp->addAllowedFrameDomain($domain); $csp->addAllowedStyleDomain($domain); $csp->addAllowedConnectDomain($domain); } - $response->setContentSecurityPolicy($csp); $hcaptchaSiteKey = $this->config->getSystemValue(Application::APP_ID . '.hcaptcha_site_key'); $this->initialState->provideInitialState('hCaptchaSiteKey', $hcaptchaSiteKey); } + $response->setContentSecurityPolicy($csp); + return $response; } @@ -218,6 +221,8 @@ class AccountController extends Controller { $this->session->remove(self::SESSION_VERIFIED_DISPLAYNAME); $this->session->remove(self::CAPTCHA_VERIFIED_CHECK); + $user = $this->userService->getUser($username); + $this->userSession->setUser($user); $response->setStatus(200); $response->setData(['success' => true]); diff --git a/src/Signup.vue b/src/Signup.vue index 5dee00ef..dca01e32 100644 --- a/src/Signup.vue +++ b/src/Signup.vue @@ -30,8 +30,8 @@ import HCaptchaForm from './signup/HCaptchaForm.vue' import CaptchaForm from './signup/CaptchaForm.vue' import RecoveryEmailForm from './signup/RecoveryEmailForm.vue' import SuccessSection from './signup/SuccessSection.vue' -import PasswordsClient from "passwords-client"; -import {EnhancedApi} from 'passwords-client/legacy'; +import ClientService from './passwords/ClientService.js' +import LegacyPasswordsApi from './passwords/LegacyPasswordsApi.js' const APPLICATION_NAME = 'ecloud-accounts' @@ -91,7 +91,7 @@ export default { this.showRecoveryEmailForm = true } }, - submitRecoveryEmailForm(data) { + async submitRecoveryEmailForm(data) { if (data.isFormValid) { const data = { password: this.formData.password, @@ -99,9 +99,9 @@ export default { language: this.formData.selectedLanguage, newsletterEos: this.formData.newsletterEos, newsletterProduct: this.formData.newsletterProduct, - newsletterB2B: this.formData.newsletterB2B + newsletterB2B: this.formData.newsletterB2B, } - this.submitForm(data) + await this.submitForm(data) } }, async submitForm(data) { @@ -111,7 +111,6 @@ export default { await Axios.post(url, data) await this.setupEncryption() - // If the execution reaches here, the response status is in the 2xx range this.showRegistrationForm = false this.showCaptchaForm = false @@ -132,17 +131,20 @@ export default { async setupEncryption() { const token = this.formData.password const user = this.formData.username - let baseUrl = generateUrl('', [], {}) - if (baseUrl.indexOf(location.origin) === -1) { - baseUrl = new URL(location.origin + baseUrl).href + let baseUrl = new URL(generateUrl('/', [], {}), location.origin).href + if (baseUrl.indexOf('index.php') !== -1) { + baseUrl = baseUrl.substr(0, baseUrl.indexOf('index.php')) } - const server = { baseUrl, user, token } - const client = new PasswordsClient(server, { baseUrl, user, token }) - const api = new EnhancedApi() - api.initialize(client, { cseMode: 'CSEv1r1' }) - - await api.setAccountChallenge(this.formData.password) + ClientService.initialize(baseUrl, user, token, null, { cseMode: 'CSEv1r1' }) + const api = new LegacyPasswordsApi() + api.initialize(ClientService.getClient(), { cseMode: 'CSEv1r1' }) + try { + await api.setAccountChallenge(token) + } catch (error) { + console.error('[passwords] setAccountChallenge failed', error) + throw error + } }, showMessage(message, type) { type === 'success' ? showSuccess(message) : showError(message) diff --git a/src/passwords/ApiRequest.js b/src/passwords/ApiRequest.js new file mode 100644 index 00000000..d3439cf2 --- /dev/null +++ b/src/passwords/ApiRequest.js @@ -0,0 +1,22 @@ +import { ApiRequest as OriginalApiRequest } from 'passwords-client/http' + +export default class ApiRequest extends OriginalApiRequest { + + /** + * @param {string} url + * @param {object} options + * @return {Promise} + * @private + */ + async _executeRequest(url, options) { + try { + const request = new Request(url, options) + this._api.emit('request.before', request) + return await fetch(request, options) + } catch (e) { + this._api.emit('request.error', e) + throw e + } + } + +} diff --git a/src/passwords/ClientService.js b/src/passwords/ClientService.js new file mode 100644 index 00000000..d46bc042 --- /dev/null +++ b/src/passwords/ClientService.js @@ -0,0 +1,39 @@ +/* eslint-disable new-parens */ +/* eslint-disable padded-blocks */ +import EnhancedClassLoader from 'passwords-client/enhanced-class-loader' +import PasswordsClient from 'passwords-client' +import LegacyPasswordsApi from './LegacyPasswordsApi.js' +import ApiRequest from './ApiRequest.js' + +export default new class ClientService { + constructor() { + this._client = null + this._events = null + } + + initialize(baseUrl, user, token, events = null, legacyConfig = {}) { + const server = { baseUrl, user, token } + const config = { baseUrl, user, token } + + const classes = { + legacy: () => { + const client = new LegacyPasswordsApi() + client.initialize(this.getClient(), legacyConfig) + return client + }, + 'network.request': ApiRequest, + } + + const classLoader = new EnhancedClassLoader(classes) + this._client = new PasswordsClient(server, config, classLoader) + this._events = events + } + + getClient() { + return this._client + } + + getLegacyClient() { + return this.getClient().getInstance('legacy') + } +} diff --git a/src/passwords/LegacyPasswordsApi.js b/src/passwords/LegacyPasswordsApi.js new file mode 100644 index 00000000..aed85dbf --- /dev/null +++ b/src/passwords/LegacyPasswordsApi.js @@ -0,0 +1,17 @@ +import { EnhancedApi } from 'passwords-client/legacy' + +export default class LegacyPasswordsApi extends EnhancedApi { + + async _executeRequest(url, options) { + try { + const request = new Request(url, options) + this._config.events.emit('api.request.before', request) + return await fetch(request, options) + } catch (e) { + if (e.status === 401 && this._enabled) this._enabled = false + this._config.events.emit('api.request.error', e) + throw e + } + } + +} -- GitLab From a18d80fa37a146e9d71aa75a711535dc56695970 Mon Sep 17 00:00:00 2001 From: Akhil Date: Mon, 20 Apr 2026 18:08:07 +0530 Subject: [PATCH 03/13] chore: ignore .codex for now --- .codex | 0 .gitignore | 1 + 2 files changed, 1 insertion(+) delete mode 100644 .codex diff --git a/.codex b/.codex deleted file mode 100644 index e69de29b..00000000 diff --git a/.gitignore b/.gitignore index fb33c3fa..7cd2be0c 100644 --- a/.gitignore +++ b/.gitignore @@ -20,3 +20,4 @@ translationtool.phar .phpunit.result.cache junit.xml css/ +.codex -- GitLab From a24702e3c1d4fe99ba95e7795c1527aff4a2b99b Mon Sep 17 00:00:00 2001 From: Akhil Date: Mon, 20 Apr 2026 18:17:03 +0530 Subject: [PATCH 04/13] feat: add config flag to enable e2ee setup --- lib/Controller/AccountController.php | 20 ++++++++++++++++---- src/Signup.vue | 7 +++++-- 2 files changed, 21 insertions(+), 6 deletions(-) diff --git a/lib/Controller/AccountController.php b/lib/Controller/AccountController.php index c0fd27bf..4f84bb1e 100644 --- a/lib/Controller/AccountController.php +++ b/lib/Controller/AccountController.php @@ -14,6 +14,7 @@ use OCA\EcloudAccounts\Service\CaptchaService; use OCA\EcloudAccounts\Service\HCaptchaService; use OCA\EcloudAccounts\Service\NewsLetterService; use OCA\EcloudAccounts\Service\UserService; +use OCP\App\IAppManager; use OCP\AppFramework\Controller; use OCP\AppFramework\Http; use OCP\AppFramework\Http\DataResponse; @@ -52,7 +53,8 @@ class AccountController extends Controller { private const HCAPTCHA_PROVIDER = 'hcaptcha'; private const HCAPTCHA_DOMAINS = ['https://hcaptcha.com', 'https://*.hcaptcha.com']; private const BLACKLISTED_USERNAMES_FILE_NAME = 'blacklisted_usernames'; - + private const PASSWORDS_APP_ID = 'passwords'; + private LoggerInterface $logger; public function __construct( $AppName, @@ -66,6 +68,7 @@ class AccountController extends Controller { IURLGenerator $urlGenerator, ISession $session, IConfig $config, + private IAppManager $appManager, LoggerInterface $logger, IInitialState $initialState, IAppData $appData, @@ -114,7 +117,13 @@ class AccountController extends Controller { $this->initialState->provideInitialState('captchaProvider', $captchaProvider); $csp = $response->getContentSecurityPolicy(); - $csp->allowEvalWasm(); + $setupPasswordsE2ee = false; + + if ($this->appManager->isEnabledForUser(self::PASSWORDS_APP_ID) && $this->config->getAppValue(self::PASSWORDS_APP_ID, 'mandatoryEndToEndEncryption', false)) { + $setupPasswordsE2ee = true; + $csp->allowEvalWasm(); + } + $this->initialState->provideInitialState('setupPasswordsE2ee', $setupPasswordsE2ee); if ($captchaProvider === self::HCAPTCHA_PROVIDER) { foreach (self::HCAPTCHA_DOMAINS as $domain) { @@ -221,8 +230,11 @@ class AccountController extends Controller { $this->session->remove(self::SESSION_VERIFIED_DISPLAYNAME); $this->session->remove(self::CAPTCHA_VERIFIED_CHECK); - $user = $this->userService->getUser($username); - $this->userSession->setUser($user); + // Session needed for client to setup E2EE at passwords app via API calls + if ($this->appManager->isEnabledForUser(self::PASSWORDS_APP_ID) && $this->config->getAppValue(self::PASSWORDS_APP_ID, 'mandatoryEndToEndEncryption', false)) { + $user = $this->userService->getUser($username); + $this->userSession->setUser($user); + } $response->setStatus(200); $response->setData(['success' => true]); diff --git a/src/Signup.vue b/src/Signup.vue index dca01e32..f8b51bb5 100644 --- a/src/Signup.vue +++ b/src/Signup.vue @@ -109,7 +109,10 @@ export default { const url = generateUrl(`/apps/${this.appName}/accounts/create`) this.processingCreation = true await Axios.post(url, data) - await this.setupEncryption() + const setupPasswordsE2ee = loadState(APPLICATION_NAME, 'setupPasswordsE2ee') + if (setupPasswordsE2ee) { + await this.setupPasswordsE2ee() + } // If the execution reaches here, the response status is in the 2xx range this.showRegistrationForm = false @@ -128,7 +131,7 @@ export default { this.showMessage(errorMessage, 'error') } }, - async setupEncryption() { + async setupPasswordsE2ee() { const token = this.formData.password const user = this.formData.username let baseUrl = new URL(generateUrl('/', [], {}), location.origin).href -- GitLab From a14dfc2284b08b5ab0078a7c35a96af6bd07715a Mon Sep 17 00:00:00 2001 From: Akhil Date: Tue, 21 Apr 2026 16:04:49 +0530 Subject: [PATCH 05/13] fix: use a setting in the same app for setting up e2ee passwords --- lib/Controller/AccountController.php | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/lib/Controller/AccountController.php b/lib/Controller/AccountController.php index 4f84bb1e..dd40be95 100644 --- a/lib/Controller/AccountController.php +++ b/lib/Controller/AccountController.php @@ -119,7 +119,7 @@ class AccountController extends Controller { $csp = $response->getContentSecurityPolicy(); $setupPasswordsE2ee = false; - if ($this->appManager->isEnabledForUser(self::PASSWORDS_APP_ID) && $this->config->getAppValue(self::PASSWORDS_APP_ID, 'mandatoryEndToEndEncryption', false)) { + if ($this->shouldSetupPasswordsE2eeAtSignup()) { $setupPasswordsE2ee = true; $csp->allowEvalWasm(); } @@ -231,7 +231,7 @@ class AccountController extends Controller { $this->session->remove(self::CAPTCHA_VERIFIED_CHECK); // Session needed for client to setup E2EE at passwords app via API calls - if ($this->appManager->isEnabledForUser(self::PASSWORDS_APP_ID) && $this->config->getAppValue(self::PASSWORDS_APP_ID, 'mandatoryEndToEndEncryption', false)) { + if ($this->shouldSetupPasswordsE2eeAtSignup()) { $user = $this->userService->getUser($username); $this->userSession->setUser($user); } @@ -425,4 +425,8 @@ class AccountController extends Controller { return $captchaProvider; } + private function shouldSetupPasswordsE2eeAtSignup() : bool { + return $this->appManager->isEnabledForUser(self::PASSWORDS_APP_ID) && $this->config->getAppValue(Application::APP_ID, 'setupPasswordsE2eeAtSignup', false); + } + } -- GitLab From fcb8a13af339597a454921860df00e92737f29bd Mon Sep 17 00:00:00 2001 From: Akhil Date: Tue, 21 Apr 2026 17:05:21 +0530 Subject: [PATCH 06/13] feat: add compatibility warning if no crypto support --- lib/Controller/AccountController.php | 2 +- src/Signup.vue | 42 ++++++++++++++++++++++++++-- src/settings-user-security.js | 3 ++ src/signup/RegistrationForm.vue | 30 ++++++++++++++++---- 4 files changed, 67 insertions(+), 10 deletions(-) diff --git a/lib/Controller/AccountController.php b/lib/Controller/AccountController.php index dd40be95..76bc8043 100644 --- a/lib/Controller/AccountController.php +++ b/lib/Controller/AccountController.php @@ -123,7 +123,7 @@ class AccountController extends Controller { $setupPasswordsE2ee = true; $csp->allowEvalWasm(); } - $this->initialState->provideInitialState('setupPasswordsE2ee', $setupPasswordsE2ee); + $this->initialState->provideInitialState('shouldSetupPasswordsE2ee', $setupPasswordsE2ee); if ($captchaProvider === self::HCAPTCHA_PROVIDER) { foreach (self::HCAPTCHA_DOMAINS as $domain) { diff --git a/src/Signup.vue b/src/Signup.vue index f8b51bb5..a1996802 100644 --- a/src/Signup.vue +++ b/src/Signup.vue @@ -2,7 +2,10 @@
- + @@ -64,6 +67,9 @@ export default { showCaptchaForm: false, showRecoveryEmailForm: false, showSuccessSection: false, + shouldSetupPasswordsE2ee: loadState(APPLICATION_NAME, 'shouldSetupPasswordsE2ee'), + cryptoSupported: true, + cryptoSupportChecked: false, language: loadState(APPLICATION_NAME, 'lang'), processingCreation: false, } @@ -75,8 +81,39 @@ export default { // Set formData.email directly to recoveryEmail this.formData.email = recoveryEmail || '' + this.checkCryptoSupport() }, methods: { + async checkCryptoSupport() { + if (!this.shouldSetupPasswordsE2ee) { + this.cryptoSupportChecked = true + return + } + + try { + const hasWebCrypto = typeof window.crypto !== 'undefined' + && typeof window.crypto.subtle === 'object' + const hasTextEncoder = typeof window.TextEncoder !== 'undefined' + const hasWebAssembly = typeof window.WebAssembly !== 'undefined' + && typeof window.WebAssembly.instantiate === 'function' + + if (!hasWebCrypto || !hasTextEncoder || !hasWebAssembly) { + throw new Error('Required cryptography APIs are unavailable') + } + + this.cryptoSupported = true + } catch (error) { + this.cryptoSupported = false + const cryptoSupportError = t(this.appName, 'Your browser does not support the cryptography required to create an account. Please use a modern browser.') + this.showRegistrationForm = false + this.showCaptchaForm = false + this.showRecoveryEmailForm = false + this.showSuccessSection = false + this.showMessage(cryptoSupportError, 'error') + } finally { + this.cryptoSupportChecked = true + } + }, submitRegistrationForm(data) { if (data.isFormValid) { this.showRegistrationForm = false @@ -109,8 +146,7 @@ export default { const url = generateUrl(`/apps/${this.appName}/accounts/create`) this.processingCreation = true await Axios.post(url, data) - const setupPasswordsE2ee = loadState(APPLICATION_NAME, 'setupPasswordsE2ee') - if (setupPasswordsE2ee) { + if (this.shouldSetupPasswordsE2ee) { await this.setupPasswordsE2ee() } diff --git a/src/settings-user-security.js b/src/settings-user-security.js index 809e9cda..3160d192 100644 --- a/src/settings-user-security.js +++ b/src/settings-user-security.js @@ -1,6 +1,9 @@ (function() { const OriginalXhr = window.XMLHttpRequest + /** + * + */ function PatchedXhr() { const xhr = new OriginalXhr() diff --git a/src/signup/RegistrationForm.vue b/src/signup/RegistrationForm.vue index 15fad12d..610f52ff 100644 --- a/src/signup/RegistrationForm.vue +++ b/src/signup/RegistrationForm.vue @@ -1,7 +1,10 @@