mirror of
https://github.com/MewoLab/AquaDX.git
synced 2025-10-25 20:12:39 +00:00
fix: bug fixes to password reset (INCOMPLETE)
This commit is contained in:
parent
39ed8af840
commit
c01c40fe45
@ -53,6 +53,8 @@ export const EN_REF_Welcome = {
|
|||||||
'welcome.verify-state-0': 'You haven\'t verified your email. A verification email had been sent to your inbox less than a minute ago. Please check your inbox!',
|
'welcome.verify-state-0': 'You haven\'t verified your email. A verification email had been sent to your inbox less than a minute ago. Please check your inbox!',
|
||||||
'welcome.verify-state-1': 'You haven\'t verified your email. We\'ve already sent 3 emails over the last 24 hours so we\'ll not send another one. Please check your inbox!',
|
'welcome.verify-state-1': 'You haven\'t verified your email. We\'ve already sent 3 emails over the last 24 hours so we\'ll not send another one. Please check your inbox!',
|
||||||
'welcome.verify-state-2': 'You haven\'t verified your email. We just sent you another verification email. Please check your inbox!',
|
'welcome.verify-state-2': 'You haven\'t verified your email. We just sent you another verification email. Please check your inbox!',
|
||||||
|
'welcome.reset-state-0': 'A reset email had been sent to your inbox less than a minute ago. Please check your inbox!',
|
||||||
|
'welcome.reset-state-1': 'We\'ve already sent 3 emails over the last 24 hours so we\'ll not send another one. Please check your inbox!',
|
||||||
'welcome.verifying': 'Verifying your email... please wait.',
|
'welcome.verifying': 'Verifying your email... please wait.',
|
||||||
'welcome.verified': 'Your email has been verified! You can now log in now.',
|
'welcome.verified': 'Your email has been verified! You can now log in now.',
|
||||||
'welcome.verification-failed': 'Verification failed: ${message}. Please try again.',
|
'welcome.verification-failed': 'Verification failed: ${message}. Please try again.',
|
||||||
|
|||||||
@ -167,7 +167,7 @@ async function resetPassword(user: { email: string, turnstile: string }) {
|
|||||||
return await post('api/v2/user/reset-password', user)
|
return await post('api/v2/user/reset-password', user)
|
||||||
}
|
}
|
||||||
|
|
||||||
async function changePassword(user: { code: string, password: string }) {
|
async function changePassword(user: { token: string, password: string }) {
|
||||||
return await post('/api/v2/user/change-password', user)
|
return await post('/api/v2/user/change-password', user)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -20,20 +20,20 @@
|
|||||||
|
|
||||||
let error = ""
|
let error = ""
|
||||||
let verifyMsg = ""
|
let verifyMsg = ""
|
||||||
let code = ""
|
let token = ""
|
||||||
|
|
||||||
if (USER.isLoggedIn()) {
|
if (USER.isLoggedIn()) {
|
||||||
window.location.href = "/home"
|
window.location.href = "/home"
|
||||||
}
|
}
|
||||||
if (params.get('code')) {
|
if (params.get('code')) {
|
||||||
code = params.get('code')!
|
token = params.get('code')!
|
||||||
if (location.pathname === '/verify') {
|
if (location.pathname === '/verify') {
|
||||||
state = 'verify'
|
state = 'verify'
|
||||||
verifyMsg = t("welcome.verifying")
|
verifyMsg = t("welcome.verifying")
|
||||||
submitting = true
|
submitting = true
|
||||||
|
|
||||||
// Send request to server
|
// Send request to server
|
||||||
USER.confirmEmail(code)
|
USER.confirmEmail(token)
|
||||||
.then(() => {
|
.then(() => {
|
||||||
verifyMsg = t('welcome.verified')
|
verifyMsg = t('welcome.verified')
|
||||||
submitting = false
|
submitting = false
|
||||||
@ -104,7 +104,7 @@
|
|||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
error = e.message
|
error = e.message
|
||||||
submitting = false
|
submitting = false // unnecessary? see line 113, same for both reset functions
|
||||||
turnstileReset()
|
turnstileReset()
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@ -121,6 +121,12 @@
|
|||||||
return submitting = false
|
return submitting = false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (TURNSTILE_SITE_KEY && turnstile === "") {
|
||||||
|
// Sleep for 100ms to allow Turnstile to finish
|
||||||
|
error = t("welcome.waiting-turnstile")
|
||||||
|
return setTimeout(resetPassword, 100)
|
||||||
|
}
|
||||||
|
|
||||||
// Send request to server
|
// Send request to server
|
||||||
await USER.resetPassword({ email, turnstile })
|
await USER.resetPassword({ email, turnstile })
|
||||||
.then(() => {
|
.then(() => {
|
||||||
@ -129,12 +135,22 @@
|
|||||||
verifyMsg = t("welcome.reset-password-sent", { email })
|
verifyMsg = t("welcome.reset-password-sent", { email })
|
||||||
})
|
})
|
||||||
.catch(e => {
|
.catch(e => {
|
||||||
error = e.message
|
if (e.message === "Reset request rejected - STATE_0") {
|
||||||
submitting = false
|
state = 'verify'
|
||||||
turnstileReset()
|
verifyMsg = t("welcome.reset-state-0")
|
||||||
|
}
|
||||||
|
else if (e.message === "Reset request rejected - STATE_1") {
|
||||||
|
state = 'verify'
|
||||||
|
verifyMsg = t("welcome.reset-state-1")
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
error = e.message
|
||||||
|
submitting = false
|
||||||
|
turnstileReset()
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
submitting = false;
|
submitting = false
|
||||||
}
|
}
|
||||||
|
|
||||||
async function changePassword(): Promise<any> {
|
async function changePassword(): Promise<any> {
|
||||||
@ -145,9 +161,10 @@
|
|||||||
return submitting = false
|
return submitting = false
|
||||||
}
|
}
|
||||||
|
|
||||||
// Send request to server
|
// Send request to server
|
||||||
await USER.changePassword({ code, password })
|
await USER.changePassword({ token, password })
|
||||||
.then(() => {
|
.then(() => {
|
||||||
|
state = 'verify'
|
||||||
verifyMsg = t("welcome.password-reset-done")
|
verifyMsg = t("welcome.password-reset-done")
|
||||||
})
|
})
|
||||||
.catch(e => {
|
.catch(e => {
|
||||||
@ -174,11 +191,13 @@
|
|||||||
{#if error}
|
{#if error}
|
||||||
<span class="error">{error}</span>
|
<span class="error">{error}</span>
|
||||||
{/if}
|
{/if}
|
||||||
<div on:click={() => state = 'home'} on:keypress={() => state = 'home'}
|
{#if error != t("welcome.waiting-turnstile")}
|
||||||
role="button" tabindex="0" class="clickable">
|
<div on:click={() => state = 'home'} on:keypress={() => state = 'home'}
|
||||||
<Icon icon="line-md:chevron-small-left" />
|
role="button" tabindex="0" class="clickable">
|
||||||
<span>{t('back')}</span>
|
<Icon icon="line-md:chevron-small-left" />
|
||||||
</div>
|
<span>{t('back')}</span>
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
{#if isSignup}
|
{#if isSignup}
|
||||||
<input type="text" placeholder={t('username')} bind:value={username}>
|
<input type="text" placeholder={t('username')} bind:value={username}>
|
||||||
{/if}
|
{/if}
|
||||||
@ -191,7 +210,7 @@
|
|||||||
{isSignup ? t('welcome.btn-signup') : t('welcome.btn-login')}
|
{isSignup ? t('welcome.btn-signup') : t('welcome.btn-login')}
|
||||||
{/if}
|
{/if}
|
||||||
</button>
|
</button>
|
||||||
{#if !submitting}
|
{#if state === "login" && !submitting}
|
||||||
<button on:click={() => state = 'submitreset'}>{t('welcome.btn-reset-password')}</button>
|
<button on:click={() => state = 'submitreset'}>{t('welcome.btn-reset-password')}</button>
|
||||||
{/if}
|
{/if}
|
||||||
{#if TURNSTILE_SITE_KEY}
|
{#if TURNSTILE_SITE_KEY}
|
||||||
@ -207,11 +226,13 @@
|
|||||||
{#if error}
|
{#if error}
|
||||||
<span class="error">{error}</span>
|
<span class="error">{error}</span>
|
||||||
{/if}
|
{/if}
|
||||||
<div on:click={() => state = 'home'} on:keypress={() => state = 'home'}
|
{#if error != t("welcome.waiting-turnstile")}
|
||||||
role="button" tabindex="0" class="clickable">
|
<div on:click={() => state = 'login'} on:keypress={() => state = 'login'}
|
||||||
<Icon icon="line-md:chevron-small-left" />
|
role="button" tabindex="0" class="clickable">
|
||||||
<span>{t('back')}</span>
|
<Icon icon="line-md:chevron-small-left" />
|
||||||
</div>
|
<span>{t('back')}</span>
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
<input type="email" placeholder={t('email')} bind:value={email}>
|
<input type="email" placeholder={t('email')} bind:value={email}>
|
||||||
<button on:click={resetPassword}>
|
<button on:click={resetPassword}>
|
||||||
{#if submitting}
|
{#if submitting}
|
||||||
@ -236,7 +257,10 @@
|
|||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
{:else if state === "reset"}
|
{:else if state === "reset"}
|
||||||
<div class="login-form" transition:slide>
|
{#if error}
|
||||||
|
<span class="error">{error}</span>
|
||||||
|
{/if}
|
||||||
|
<div class="login-form" transition:slide>
|
||||||
<input type="password" placeholder={t('new-password')} bind:value={password}>
|
<input type="password" placeholder={t('new-password')} bind:value={password}>
|
||||||
<button on:click={changePassword}>
|
<button on:click={changePassword}>
|
||||||
{#if submitting}
|
{#if submitting}
|
||||||
|
|||||||
@ -59,7 +59,7 @@ Located at: [icu.samnyan.aqua.net.UserRegistrar](icu/samnyan/aqua/net/UserRegist
|
|||||||
* token: String
|
* token: String
|
||||||
* **Returns**: User information
|
* **Returns**: User information
|
||||||
|
|
||||||
**/user/login** : Login with email/username and password. This will also check if the email is verified and send another confirmation
|
**/user/login** : Login with email/username and password. This will also check if the email is verified and send another confirmation.
|
||||||
|
|
||||||
* email: String
|
* email: String
|
||||||
* password: String
|
* password: String
|
||||||
@ -74,6 +74,18 @@ Located at: [icu.samnyan.aqua.net.UserRegistrar](icu/samnyan/aqua/net/UserRegist
|
|||||||
* turnstile: String
|
* turnstile: String
|
||||||
* **Returns**: Success message
|
* **Returns**: Success message
|
||||||
|
|
||||||
|
**/user/reset-password** : Send the user a reset password email. This will also check if the email is verified or if many requests were sent recently.
|
||||||
|
|
||||||
|
* email: String
|
||||||
|
* turnstile: String
|
||||||
|
* **Returns** Success message
|
||||||
|
|
||||||
|
**/user/change-password** : Reset a user's password with a token sent through email to the user.
|
||||||
|
|
||||||
|
* token: String
|
||||||
|
* password: String
|
||||||
|
* **Returns** Success message
|
||||||
|
|
||||||
**/user/setting** : Validate and set a user setting field.
|
**/user/setting** : Validate and set a user setting field.
|
||||||
|
|
||||||
* token: String
|
* token: String
|
||||||
|
|||||||
@ -147,7 +147,7 @@ class UserRegistrar(
|
|||||||
}
|
}
|
||||||
|
|
||||||
@API("/reset-password")
|
@API("/reset-password")
|
||||||
@Doc("Reset password with a token sent through email to the user, if it exists.", "Success message") // wtf is the second param in this annotation?
|
@Doc("Reset password with a token sent through email to the user, if it exists.", "Success message")
|
||||||
suspend fun resetPassword(
|
suspend fun resetPassword(
|
||||||
@RP email: Str, @RP turnstile: Str,
|
@RP email: Str, @RP turnstile: Str,
|
||||||
request: HttpServletRequest
|
request: HttpServletRequest
|
||||||
@ -163,16 +163,28 @@ class UserRegistrar(
|
|||||||
?: return SUCCESS // obviously dont tell them if the email exists or not
|
?: return SUCCESS // obviously dont tell them if the email exists or not
|
||||||
|
|
||||||
// Check if email is verified
|
// Check if email is verified
|
||||||
if (!user.emailConfirmed && emailProps.enable) 400 - "Email not verified" // maybe similar logic to login here
|
if (!user.emailConfirmed && emailProps.enable) 400 - "Email not verified"
|
||||||
|
|
||||||
|
val resets = async { resetPasswordRepo.findByAquaNetUserAuId(user.auId) }
|
||||||
|
val lasReset = resets.maxByOrNull { it.createdAt }
|
||||||
|
|
||||||
|
if (lastReset?.createdAt?.plusSeconds(60)?.isAfter(Instant.now()) == true) {
|
||||||
|
400 - "Reset request rejected - STATE_0"
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if we have sent more than 3 confirmation emails in the last 24 hours
|
||||||
|
if (confirmations.count { it.createdAt.plusSeconds(60 * 60 * 24).isAfter(Instant.now()) } > 3) {
|
||||||
|
400 - "Reset request rejected- STATE_1"
|
||||||
|
}
|
||||||
|
|
||||||
// Send a password reset email
|
// Send a password reset email
|
||||||
emailService.sendPasswordReset(user)
|
emailService.sendPasswordReset(user)
|
||||||
|
|
||||||
return SUCCESS
|
return SUCCESS
|
||||||
}
|
}
|
||||||
|
|
||||||
@API("/change-password")
|
@API("/change-password")
|
||||||
@Doc("Change a user's password given a reset code", "Success message") // again have no idea what it is
|
@Doc("Change a user's password given a reset code", "Success message")
|
||||||
suspend fun changePassword(
|
suspend fun changePassword(
|
||||||
@RP token: Str, @RP password: Str,
|
@RP token: Str, @RP password: Str,
|
||||||
request: HttpServletRequest
|
request: HttpServletRequest
|
||||||
@ -188,7 +200,7 @@ class UserRegistrar(
|
|||||||
if (reset.createdAt.plusSeconds(60 * 60 * 24).isBefore(Instant.now())) 400 - "Token expired"
|
if (reset.createdAt.plusSeconds(60 * 60 * 24).isBefore(Instant.now())) 400 - "Token expired"
|
||||||
|
|
||||||
// Change the password
|
// Change the password
|
||||||
async { userRepo.save(reset.aquaNetUser.apply { pwHash = validator.checkPwHash(password) }) } // how...
|
async { userRepo.save(reset.aquaNetUser.apply { pwHash = validator.checkPwHash(password) }) }
|
||||||
|
|
||||||
return SUCCESS
|
return SUCCESS
|
||||||
}
|
}
|
||||||
|
|||||||
@ -84,6 +84,9 @@ class EmailService(
|
|||||||
.buildEmail()).thenRun { log.info("Verification email sent to ${user.email}") }
|
.buildEmail()).thenRun { log.info("Verification email sent to ${user.email}") }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send a reset password email to the user
|
||||||
|
*/
|
||||||
fun sendPasswordReset (user: AquaNetUser) {
|
fun sendPasswordReset (user: AquaNetUser) {
|
||||||
if (!props.enable) return
|
if (!props.enable) return
|
||||||
|
|
||||||
|
|||||||
@ -0,0 +1,8 @@
|
|||||||
|
CREATE TABLE aqua_net_email_password_reset
|
||||||
|
(
|
||||||
|
id BIGINT AUTO_INCREMENT NOT NULL,
|
||||||
|
token VARCHAR(255) NOT NULL,
|
||||||
|
created_at datetime NOT NULL,
|
||||||
|
au_id BIGINT NULL,
|
||||||
|
CONSTRAINT pk_email_password_reset PRIMARY KEY (id)
|
||||||
|
);
|
||||||
@ -202,7 +202,7 @@
|
|||||||
<table border="0" cellpadding="0" cellspacing="0" class="heading_block block-1" role="presentation" style="mso-table-lspace: 0pt; mso-table-rspace: 0pt;" width="100%">
|
<table border="0" cellpadding="0" cellspacing="0" class="heading_block block-1" role="presentation" style="mso-table-lspace: 0pt; mso-table-rspace: 0pt;" width="100%">
|
||||||
<tr>
|
<tr>
|
||||||
<td class="pad" style="padding-bottom:12px;text-align:center;width:100%;">
|
<td class="pad" style="padding-bottom:12px;text-align:center;width:100%;">
|
||||||
<h1 style="margin: 0; color: #292929; direction: ltr; font-family: 'Montserrat', 'Trebuchet MS', 'Lucida Grande', 'Lucida Sans Unicode', 'Lucida Sans', Tahoma, sans-serif; font-size: 32px; font-weight: 700; letter-spacing: normal; line-height: 120%; text-align: left; margin-top: 0; margin-bottom: 0; mso-line-height-alt: 38.4px;"><span class="tinyMce-placeholder">Verify your email!</span></h1>
|
<h1 style="margin: 0; color: #292929; direction: ltr; font-family: 'Montserrat', 'Trebuchet MS', 'Lucida Grande', 'Lucida Sans Unicode', 'Lucida Sans', Tahoma, sans-serif; font-size: 32px; font-weight: 700; letter-spacing: normal; line-height: 120%; text-align: left; margin-top: 0; margin-bottom: 0; mso-line-height-alt: 38.4px;"><span class="tinyMce-placeholder">Reset your password!</span></h1>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
@ -225,7 +225,7 @@
|
|||||||
<w:anchorlock/>
|
<w:anchorlock/>
|
||||||
<v:textbox inset="0px,0px,0px,0px">
|
<v:textbox inset="0px,0px,0px,0px">
|
||||||
<center style="color:#ffffff; font-family:'Trebuchet MS', Tahoma, sans-serif; font-size:16px">
|
<center style="color:#ffffff; font-family:'Trebuchet MS', Tahoma, sans-serif; font-size:16px">
|
||||||
<![endif]--><a href="{{url}}" style="text-decoration:none;display:inline-block;color:#ffffff;background-color:#646cff;border-radius:8px;width:auto;border-top:0px solid transparent;font-weight:400;border-right:0px solid transparent;border-bottom:0px solid transparent;border-left:0px solid transparent;padding-top:8px;padding-bottom:8px;font-family:'Montserrat', 'Trebuchet MS', 'Lucida Grande', 'Lucida Sans Unicode', 'Lucida Sans', Tahoma, sans-serif;font-size:16px;text-align:center;mso-border-alt:none;word-break:keep-all;" target="_blank"><span style="padding-left:16px;padding-right:16px;font-size:16px;display:inline-block;letter-spacing:normal;"><span style="word-break: break-word; line-height: 32px;">Verify email</span></span></a><!--[if mso]></center></v:textbox></v:roundrect><![endif]--></div>
|
<![endif]--><a href="{{url}}" style="text-decoration:none;display:inline-block;color:#ffffff;background-color:#646cff;border-radius:8px;width:auto;border-top:0px solid transparent;font-weight:400;border-right:0px solid transparent;border-bottom:0px solid transparent;border-left:0px solid transparent;padding-top:8px;padding-bottom:8px;font-family:'Montserrat', 'Trebuchet MS', 'Lucida Grande', 'Lucida Sans Unicode', 'Lucida Sans', Tahoma, sans-serif;font-size:16px;text-align:center;mso-border-alt:none;word-break:keep-all;" target="_blank"><span style="padding-left:16px;padding-right:16px;font-size:16px;display:inline-block;letter-spacing:normal;"><span style="word-break: break-word; line-height: 32px;">Reset password</span></span></a><!--[if mso]></center></v:textbox></v:roundrect><![endif]--></div>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user