From bfc96768859f993bf4172ef3ea5c9e01d8f7737b Mon Sep 17 00:00:00 2001 From: Natsumi Date: Mon, 13 Feb 2023 01:45:41 +1300 Subject: [PATCH 1/2] Display 2FA dialog once --- html/src/app.js | 32 +++++++++++++++++++++++++++++++- html/src/repository/database.js | 2 +- 2 files changed, 32 insertions(+), 2 deletions(-) diff --git a/html/src/app.js b/html/src/app.js index d46903ec..245f9816 100644 --- a/html/src/app.js +++ b/html/src/app.js @@ -6540,7 +6540,17 @@ speechSynthesis.getVoices(); } }; + $app.data.twoFactorAuthDialogVisible = false; + + API.$on('LOGIN', function () { + $app.twoFactorAuthDialogVisible = false; + }); + $app.methods.promptTOTP = function () { + if (this.twoFactorAuthDialogVisible) { + return; + } + this.twoFactorAuthDialogVisible = true; this.$prompt($t('prompt.totp.description'), $t('prompt.totp.header'), { distinguishCancelAndClose: true, cancelButtonText: $t('prompt.totp.use_otp'), @@ -6564,11 +6574,19 @@ speechSynthesis.getVoices(); } else if (action === 'cancel') { this.promptOTP(); } + }, + beforeClose: (action, instance, done) => { + this.twoFactorAuthDialogVisible = false; + done(); } }); }; $app.methods.promptOTP = function () { + if (this.twoFactorAuthDialogVisible) { + return; + } + this.twoFactorAuthDialogVisible = true; this.$prompt($t('prompt.otp.description'), $t('prompt.otp.header'), { distinguishCancelAndClose: true, cancelButtonText: $t('prompt.otp.use_otp'), @@ -6592,11 +6610,19 @@ speechSynthesis.getVoices(); } else if (action === 'cancel') { this.promptTOTP(); } + }, + beforeClose: (action, instance, done) => { + this.twoFactorAuthDialogVisible = false; + done(); } }); }; $app.methods.promptEmailOTP = function () { + if (this.twoFactorAuthDialogVisible) { + return; + } + this.twoFactorAuthDialogVisible = true; this.$prompt( $t('prompt.email_otp.description'), $t('prompt.email_otp.header'), @@ -6621,6 +6647,10 @@ speechSynthesis.getVoices(); return args; }); } + }, + beforeClose: (action, instance, done) => { + this.twoFactorAuthDialogVisible = false; + done(); } } ); @@ -21955,7 +21985,7 @@ speechSynthesis.getVoices(); API.$on('LOGIN', async function () { $app.avatarHistory = new Set(); var historyArray = await database.getAvatarHistory(); - $app.avatarHistoryArray = historyArray.reverse(); + $app.avatarHistoryArray = historyArray; for (var i = 0; i < historyArray.length; i++) { $app.avatarHistory.add(historyArray[i].id); this.applyAvatar(historyArray[i]); diff --git a/html/src/repository/database.js b/html/src/repository/database.js index 04b71258..52422fb8 100644 --- a/html/src/repository/database.js +++ b/html/src/repository/database.js @@ -1583,7 +1583,7 @@ class Database { updated_at: dbRow[12], version: dbRow[13] }; - data.unshift(row); + data.push(row); }, `SELECT * FROM ${Database.userPrefix}_avatar_history INNER JOIN cache_avatar ON cache_avatar.id = ${Database.userPrefix}_avatar_history.avatar_id ORDER BY ${Database.userPrefix}_avatar_history.created_at DESC LIMIT 100`); return data; } From d7b9b8aa2c4e4010cd897e09c93a762eab56e72e Mon Sep 17 00:00:00 2001 From: Natsumi Date: Mon, 13 Feb 2023 08:29:50 +1300 Subject: [PATCH 2/2] Resend email button --- VRCX.csproj.DotSettings | 2 ++ html/src/app.js | 37 ++++++++++++++++++++++++--- html/src/localization/strings/en.json | 2 +- 3 files changed, 37 insertions(+), 4 deletions(-) create mode 100644 VRCX.csproj.DotSettings diff --git a/VRCX.csproj.DotSettings b/VRCX.csproj.DotSettings new file mode 100644 index 00000000..6e7fff86 --- /dev/null +++ b/VRCX.csproj.DotSettings @@ -0,0 +1,2 @@ + + No \ No newline at end of file diff --git a/html/src/app.js b/html/src/app.js index 245f9816..81a05755 100644 --- a/html/src/app.js +++ b/html/src/app.js @@ -6628,7 +6628,7 @@ speechSynthesis.getVoices(); $t('prompt.email_otp.header'), { distinguishCancelAndClose: true, - cancelButtonText: $t('prompt.email_otp.cancel'), + cancelButtonText: $t('prompt.email_otp.resend'), confirmButtonText: $t('prompt.email_otp.verify'), inputPlaceholder: $t('prompt.email_otp.input_placeholder'), inputPattern: /^[0-9]{6}$/, @@ -6646,6 +6646,8 @@ speechSynthesis.getVoices(); API.getCurrentUser(); return args; }); + } else if (action === 'cancel') { + this.resendEmail2fa(); } }, beforeClose: (action, instance, done) => { @@ -6656,6 +6658,30 @@ speechSynthesis.getVoices(); ); }; + $app.methods.resendEmail2fa = function () { + if (this.loginForm.lastUserLoggedIn) { + var user = + this.loginForm.savedCredentials[ + this.loginForm.lastUserLoggedIn + ]; + if (typeof user !== 'undefined') { + webApiService.clearCookies(); + this.relogin(user).then(() => { + new Noty({ + type: 'success', + text: 'Successfully relogged in.' + }).show(); + }); + return; + } + } + new Noty({ + type: 'error', + text: 'Cannot send 2FA email without saved credentials. Please login again.' + }).show(); + this.promptEmailOTP(); + }; + $app.methods.showExportFriendsListDialog = function () { var {friends} = API.currentUser; if (Array.isArray(friends) === false) { @@ -6764,6 +6790,8 @@ speechSynthesis.getVoices(); API.$on('LOGOUT', async function () { await $app.updateStoredUser(this.currentUser); webApiService.clearCookies(); + // eslint-disable-next-line require-atomic-updates + $app.loginForm.lastUserLoggedIn = ''; configRepository.remove('lastUserLoggedIn'); }); @@ -6931,7 +6959,9 @@ speechSynthesis.getVoices(); API.login({ username: loginParmas.username, password: pwd, - cipher: loginParmas.password + cipher: loginParmas.password, + endpoint: loginParmas.endpoint, + websocket: loginParmas.websocket }) .catch((err2) => { this.loginForm.loading = false; @@ -6964,9 +6994,10 @@ speechSynthesis.getVoices(); endpoint: loginParmas.endpoint, websocket: loginParmas.websocket }) - .catch(() => { + .catch((err2) => { this.loginForm.loading = false; API.logout(); + reject(err2); }) .then(() => { this.loginForm.loading = false; diff --git a/html/src/localization/strings/en.json b/html/src/localization/strings/en.json index b1dd3467..bbb75521 100644 --- a/html/src/localization/strings/en.json +++ b/html/src/localization/strings/en.json @@ -1065,7 +1065,7 @@ "email_otp": { "header": "Two-factor Authentication", "description": "Enter a numeric code that was sent to your email", - "cancel": "Cancel", + "resend": "Resend Email", "verify": "Verify", "input_placeholder": "Code", "input_error": "Invalid Code"