You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
CoreID/app/assets/app/auth/PasswordReset.component.js

169 lines
6.1 KiB

import { Component } from '../../lib/vues6/vues6.js'
import { session } from '../service/Session.service.js'
import { location_service } from '../service/Location.service.js'
import { password_service } from '../service/Password.service.js'
const template = `
<div class="coreid-auth-page col-lg-6 col-md-8 col-sm-10 col-xs-12 offset-lg-3 offset-md-2 offset-sm-1 offset-xs-0 text-left">
<div class="coreid-auth-page-inner">
<div class="coreid-header font-weight-light">{{ app_name }}</div>
<span v-if="step === 0">
<div class="coreid-message">
We're going to walk you through resetting your {{ app_name }} password.
<span v-if="has_mfa">
<br><br>
Note that this process will invalidate any existing app passwords you have created.
</span>
</div>
</span>
<span v-if="step === 1">
<div class="form-group">
<label for="coreid-password-reset-input-step-1">Please enter a new password for your account:</label>
<input
id="coreid-password-reset-input-step-1"
type="password"
v-model="password"
placeholder="New password"
class="form-control"
@keyup="on_key_up"
:disabled="loading"
name="password"
ref="input_1"
>
</div>
<div>
<div class="other-message" v-if="step_1_calc_time">This password would take {{ step_1_calc_time }} to crack.</div>
<div class="error-message" v-if="step_1_problem">{{ step_1_problem }}.</div>
</div>
</span>
<span v-if="step === 2">
<div class="form-group">
<label for="coreid-password-reset-input-step-1">Confirm the password:</label>
<input
id="coreid-password-reset-input-step-2"
type="password"
v-model="confirm_password"
placeholder="Confirm new password"
class="form-control"
@keyup="on_key_up"
:disabled="loading"
name="password_confirmation"
ref="input_2"
>
</div>
</span>
<div v-if="error_message" class="error-message">{{ error_message }}</div>
<div v-if="other_message" class="other-message">{{ other_message }}</div>
<div class="buttons text-right pad-top">
<button
type="button"
class="btn btn-primary"
@click="back_click"
:disabled="loading"
>Cancel</button>
<button
type="button"
class="btn btn-primary"
@click="continue_click"
:disabled="loading || (step === 1 && !step_1_valid) || (step === 2 && !step_2_valid)"
>{{ step === 2 ? 'Change Password' : 'Continue' }}</button>
</div>
<div class="coreid-loading-spinner" v-if="loading"><div class="inner"></div></div>
</div>
</div>
`
export default class PasswordResetComponent extends Component {
static get selector() { return 'coreid-password-reset-page' }
static get template() { return template }
static get props() { return ['app_name'] }
step = 0
loading = false
has_mfa = false
error_message = ''
other_message = ''
step_1_valid = false
step_1_calc_time = ''
step_1_problem = ''
step_2_valid = false
password = ''
confirm_password = ''
vue_on_create() {
this.has_mfa = !!session.get('user.has_mfa')
}
async back_click() {
this.loading = true
this.error_message = this.other_message = ''
if ( this.step === 0 ) {
await location_service.redirect('/dash/profile', 1500)
} else {
this.step -= 1
this.loading = false
}
}
async continue_click() {
this.loading = true
if ( this.step === 0 ) {
this.step += 1
this.error_message = this.other_message = ''
this.loading = false
this.$nextTick(() => {
this.$refs.input_1.focus()
})
} else if ( this.step === 1 ) {
if ( this.step_1_valid ) {
this.step += 1
this.error_message = this.other_message = ''
this.$nextTick(() => {
this.$refs.input_2.focus()
})
}
this.loading = false
} else if ( this.step === 2 ) {
if ( this.step_2_valid ) {
try {
await password_service.reset(this.password)
this.other_message = 'Your password was reset. For security reasons, you will be asked to sign-in again.'
await location_service.redirect('/dash/profile', 5000)
} catch (e) {
let message = 'An unknown error occurred while attempting to reset your password.'
if ( e.response && e.response.data && e.response.data.message ) {
message = e.response.data.message
}
this.error_message = message
this.loading = false
}
}
this.loading = false
}
}
on_key_up(event) {
if ( this.step === 1 ) {
const result = zxcvbn(this.password)
this.step_1_calc_time = result.crack_times_display.offline_slow_hashing_1e4_per_second
this.step_1_problem = result.feedback.warning
this.step_1_valid = result.score >= 3 // TODO make this configurable
} else if ( this.step === 2 ) {
this.step_2_valid = this.password === this.confirm_password
}
if ( event.keyCode === 13 ) {
// Enter was pressed
event.preventDefault()
event.stopPropagation()
return this.continue_click()
}
}
}