mirror of
https://github.com/HabitRPG/habitica.git
synced 2025-12-15 13:47:33 +01:00
* Revert "Revert "Minimum password length + Static Pages fixes (#11474)""
This reverts commit d1afbf4b92.
* add min length for reset password
This commit is contained in:
@@ -189,6 +189,28 @@ describe('POST /user/auth/reset-password-set-new-one', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('renders the error page if the password is too short', async () => {
|
||||||
|
const user = await generateUser();
|
||||||
|
|
||||||
|
const code = encrypt(JSON.stringify({
|
||||||
|
userId: user._id,
|
||||||
|
expiresAt: moment().add({ days: 1 }),
|
||||||
|
}));
|
||||||
|
await user.update({
|
||||||
|
'auth.local.passwordResetCode': code,
|
||||||
|
});
|
||||||
|
|
||||||
|
await expect(api.post(`${endpoint}`, {
|
||||||
|
newPassword: 'short',
|
||||||
|
confirmPassword: 'short',
|
||||||
|
code,
|
||||||
|
})).to.eventually.be.rejected.and.eql({
|
||||||
|
code: 400,
|
||||||
|
error: 'BadRequest',
|
||||||
|
message: t('invalidReqParams'),
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
it('renders the success page and save the user', async () => {
|
it('renders the success page and save the user', async () => {
|
||||||
const user = await generateUser();
|
const user = await generateUser();
|
||||||
|
|
||||||
|
|||||||
@@ -326,6 +326,24 @@ describe('POST /user/auth/local/register', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('requires minimum length for the password', async () => {
|
||||||
|
const username = generateRandomUserName();
|
||||||
|
const email = `${username}@example.com`;
|
||||||
|
const password = '1234567';
|
||||||
|
const confirmPassword = '1234567';
|
||||||
|
|
||||||
|
await expect(api.post('/user/auth/local/register', {
|
||||||
|
username,
|
||||||
|
email,
|
||||||
|
password,
|
||||||
|
confirmPassword,
|
||||||
|
})).to.eventually.be.rejected.and.eql({
|
||||||
|
code: 400,
|
||||||
|
error: 'BadRequest',
|
||||||
|
message: t('invalidReqParams'),
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
it('requires a username', async () => {
|
it('requires a username', async () => {
|
||||||
const email = `${generateRandomUserName()}@example.com`;
|
const email = `${generateRandomUserName()}@example.com`;
|
||||||
const password = 'password';
|
const password = 'password';
|
||||||
|
|||||||
@@ -82,6 +82,20 @@ describe('PUT /user/auth/update-password', async () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('returns an error when newPassword is too short', async () => {
|
||||||
|
const body = {
|
||||||
|
password,
|
||||||
|
newPassword: '1234567',
|
||||||
|
confirmPassword: '1234567',
|
||||||
|
};
|
||||||
|
|
||||||
|
await expect(user.put(ENDPOINT, body)).to.eventually.be.rejected.and.eql({
|
||||||
|
code: 400,
|
||||||
|
error: 'BadRequest',
|
||||||
|
message: t('invalidReqParams'),
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
it('returns an error when confirmPassword is missing', async () => {
|
it('returns an error when confirmPassword is missing', async () => {
|
||||||
const body = {
|
const body = {
|
||||||
password,
|
password,
|
||||||
|
|||||||
@@ -20,7 +20,7 @@
|
|||||||
@include btn-focus-hover-shadow();
|
@include btn-focus-hover-shadow();
|
||||||
}
|
}
|
||||||
|
|
||||||
&:hover:not(.btn-flat):not(.disabled) {
|
&:hover:not(.btn-flat):not(.disabled):not(:disabled) {
|
||||||
@include btn-focus-hover-shadow();
|
@include btn-focus-hover-shadow();
|
||||||
border-color: transparent;
|
border-color: transparent;
|
||||||
}
|
}
|
||||||
@@ -49,7 +49,7 @@
|
|||||||
background: $purple-200;
|
background: $purple-200;
|
||||||
}
|
}
|
||||||
|
|
||||||
&:hover:not(:disabled), &:active, &.active, &:focus {
|
&:hover:not(:disabled):not(.disabled), &:active:not(:disabled):not(.disabled), &.active:not(:disabled):not(.disabled), &:focus:not(:disabled):not(.disabled) {
|
||||||
background: #5d3b9c !important;
|
background: #5d3b9c !important;
|
||||||
color: $white;
|
color: $white;
|
||||||
}
|
}
|
||||||
@@ -59,7 +59,7 @@
|
|||||||
color: $gray-50;
|
color: $gray-50;
|
||||||
background: $white !important;
|
background: $white !important;
|
||||||
|
|
||||||
&:hover:not(:disabled):not(.disabled), &:active, &.active, &:focus {
|
&:hover:not(:disabled):not(.disabled), &:active:not(:disabled):not(.disabled), &.active:not(:disabled):not(.disabled), &:focus:not(:disabled):not(.disabled) {
|
||||||
color: $purple-200 !important;
|
color: $purple-200 !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -80,7 +80,7 @@
|
|||||||
background: $green-100;
|
background: $green-100;
|
||||||
}
|
}
|
||||||
|
|
||||||
&:hover:not(:disabled), &:active, &.active {
|
&:hover:not(:disabled):not(.disabled), &:active:not(:disabled):not(.disabled), &.active:not(:disabled):not(.disabled) {
|
||||||
background: $green-50;
|
background: $green-50;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -96,8 +96,12 @@
|
|||||||
background: $blue-50;
|
background: $blue-50;
|
||||||
}
|
}
|
||||||
|
|
||||||
&:hover:not(:disabled), &:active, &.active {
|
&:hover:not(:disabled):not(.disabled) {
|
||||||
background: $blue-100;
|
background-color: $blue-100;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:active:not(:disabled):not(.disabled), &.active:not(:disabled):not(.disabled) {
|
||||||
|
background: $blue-50;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -108,7 +112,11 @@
|
|||||||
background: $red-50;
|
background: $red-50;
|
||||||
}
|
}
|
||||||
|
|
||||||
&:hover:not(:disabled), &:active, &.active {
|
&:hover:not(:disabled):not(.disabled) {
|
||||||
|
background: $red-100;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:active:not(:disabled):not(.disabled), &.active:not(:disabled):not(.disabled) {
|
||||||
background: $red-100;
|
background: $red-100;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -65,6 +65,7 @@ input, textarea, input.form-control, textarea.form-control {
|
|||||||
padding-right: 40px;
|
padding-right: 40px;
|
||||||
background-image: url(~@/assets/svg/for-css/alert.svg);
|
background-image: url(~@/assets/svg/for-css/alert.svg);
|
||||||
background-size: 16px 16px;
|
background-size: 16px 16px;
|
||||||
|
border-color: $red-100 !important;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -276,3 +277,19 @@ $bg-disabled-control: #34303a;
|
|||||||
.toggle-switch-container.no-margin {
|
.toggle-switch-container.no-margin {
|
||||||
margin-top: 0 !important;
|
margin-top: 0 !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Disable default style Firefox for invalid elements.
|
||||||
|
// Selectors taken from view-source:resource://gre-resources/forms.css on Firefox
|
||||||
|
:not(output):-moz-ui-invalid {
|
||||||
|
box-shadow: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
:not(output):-moz-ui-invalid:-moz-focusring {
|
||||||
|
box-shadow: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
output:-moz-ui-invalid {
|
||||||
|
color: inherit;
|
||||||
|
}
|
||||||
|
|||||||
@@ -46,6 +46,13 @@
|
|||||||
:placeholder="$t('usernamePlaceholder')"
|
:placeholder="$t('usernamePlaceholder')"
|
||||||
:class="{'input-valid': usernameValid, 'input-invalid': usernameInvalid}"
|
:class="{'input-valid': usernameValid, 'input-invalid': usernameInvalid}"
|
||||||
>
|
>
|
||||||
|
<div
|
||||||
|
v-for="issue in usernameIssues"
|
||||||
|
:key="issue"
|
||||||
|
class="input-error"
|
||||||
|
>
|
||||||
|
{{ issue }}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
v-if="!registering"
|
v-if="!registering"
|
||||||
@@ -97,7 +104,17 @@
|
|||||||
class="form-control"
|
class="form-control"
|
||||||
type="password"
|
type="password"
|
||||||
:placeholder="$t(registering ? 'passwordPlaceholder' : 'password')"
|
:placeholder="$t(registering ? 'passwordPlaceholder' : 'password')"
|
||||||
|
:class="{
|
||||||
|
'input-valid': registering ? passwordValid : false,
|
||||||
|
'input-invalid': registering ? passwordInvalid: false,
|
||||||
|
}"
|
||||||
>
|
>
|
||||||
|
<div
|
||||||
|
v-if="passwordInvalid && registering"
|
||||||
|
class="input-error"
|
||||||
|
>
|
||||||
|
{{ $t('minPasswordLength') }}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
v-if="registering"
|
v-if="registering"
|
||||||
@@ -115,6 +132,12 @@
|
|||||||
:placeholder="$t('confirmPasswordPlaceholder')"
|
:placeholder="$t('confirmPasswordPlaceholder')"
|
||||||
:class="{'input-invalid': passwordConfirmInvalid, 'input-valid': passwordConfirmValid}"
|
:class="{'input-invalid': passwordConfirmInvalid, 'input-valid': passwordConfirmValid}"
|
||||||
>
|
>
|
||||||
|
<div
|
||||||
|
v-if="passwordConfirmInvalid"
|
||||||
|
class="input-error"
|
||||||
|
>
|
||||||
|
{{ $t('passwordConfirmationMatch') }}
|
||||||
|
</div>
|
||||||
<small
|
<small
|
||||||
v-once
|
v-once
|
||||||
class="form-text"
|
class="form-text"
|
||||||
@@ -183,8 +206,11 @@
|
|||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.input-valid {
|
.input-error {
|
||||||
color: #fff;
|
margin-top: 0.25em;
|
||||||
|
font-weight: normal;
|
||||||
|
font-size: 90%;
|
||||||
|
width: 100%;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
@@ -194,7 +220,7 @@ import hello from 'hellojs';
|
|||||||
import debounce from 'lodash/debounce';
|
import debounce from 'lodash/debounce';
|
||||||
import isEmail from 'validator/lib/isEmail';
|
import isEmail from 'validator/lib/isEmail';
|
||||||
import { setUpAxios } from '@/libs/auth';
|
import { setUpAxios } from '@/libs/auth';
|
||||||
|
import { MINIMUM_PASSWORD_LENGTH } from '@/../../common/script/constants';
|
||||||
import facebookSquareIcon from '@/assets/svg/facebook-square.svg';
|
import facebookSquareIcon from '@/assets/svg/facebook-square.svg';
|
||||||
import googleIcon from '@/assets/svg/google.svg';
|
import googleIcon from '@/assets/svg/google.svg';
|
||||||
|
|
||||||
@@ -223,6 +249,7 @@ export default {
|
|||||||
return isEmail(this.email);
|
return isEmail(this.email);
|
||||||
},
|
},
|
||||||
emailInvalid () {
|
emailInvalid () {
|
||||||
|
if (this.email.length <= 3) return false;
|
||||||
return !this.emailValid;
|
return !this.emailValid;
|
||||||
},
|
},
|
||||||
usernameValid () {
|
usernameValid () {
|
||||||
@@ -230,13 +257,23 @@ export default {
|
|||||||
return this.usernameIssues.length === 0;
|
return this.usernameIssues.length === 0;
|
||||||
},
|
},
|
||||||
usernameInvalid () {
|
usernameInvalid () {
|
||||||
|
if (this.username.length < 1) return false;
|
||||||
return !this.usernameValid;
|
return !this.usernameValid;
|
||||||
},
|
},
|
||||||
|
passwordValid () {
|
||||||
|
if (this.password.length <= 0) return false;
|
||||||
|
return this.password.length >= MINIMUM_PASSWORD_LENGTH;
|
||||||
|
},
|
||||||
|
passwordInvalid () {
|
||||||
|
if (this.password.length <= 0) return false;
|
||||||
|
return this.password.length < MINIMUM_PASSWORD_LENGTH;
|
||||||
|
},
|
||||||
passwordConfirmValid () {
|
passwordConfirmValid () {
|
||||||
if (this.passwordConfirm.length <= 3) return false;
|
if (this.passwordConfirm.length <= 3) return false;
|
||||||
return this.passwordConfirm === this.password;
|
return this.passwordConfirm === this.password;
|
||||||
},
|
},
|
||||||
passwordConfirmInvalid () {
|
passwordConfirmInvalid () {
|
||||||
|
if (this.passwordConfirm.length <= 3) return false;
|
||||||
return !this.passwordConfirmValid;
|
return !this.passwordConfirmValid;
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -6,8 +6,7 @@
|
|||||||
<form
|
<form
|
||||||
v-if="!forgotPassword && !resetPasswordSetNewOne"
|
v-if="!forgotPassword && !resetPasswordSetNewOne"
|
||||||
id="login-form"
|
id="login-form"
|
||||||
@submit.prevent="handleSubmit"
|
@submit.prevent.stop="handleSubmit"
|
||||||
@keyup.enter="handleSubmit"
|
|
||||||
>
|
>
|
||||||
<div class="text-center">
|
<div class="text-center">
|
||||||
<div>
|
<div>
|
||||||
@@ -69,7 +68,7 @@
|
|||||||
<input
|
<input
|
||||||
id="usernameInput"
|
id="usernameInput"
|
||||||
v-model="username"
|
v-model="username"
|
||||||
class="form-control"
|
class="form-control input-with-error"
|
||||||
type="text"
|
type="text"
|
||||||
:placeholder="$t('usernamePlaceholder')"
|
:placeholder="$t('usernamePlaceholder')"
|
||||||
:class="{'input-valid': usernameValid, 'input-invalid': usernameInvalid}"
|
:class="{'input-valid': usernameValid, 'input-invalid': usernameInvalid}"
|
||||||
@@ -132,7 +131,17 @@
|
|||||||
class="form-control"
|
class="form-control"
|
||||||
type="password"
|
type="password"
|
||||||
:placeholder="$t(registering ? 'passwordPlaceholder' : 'password')"
|
:placeholder="$t(registering ? 'passwordPlaceholder' : 'password')"
|
||||||
|
:class="{
|
||||||
|
'input-invalid input-with-error': registering && passwordInvalid,
|
||||||
|
'input-valid': registering && passwordValid
|
||||||
|
}"
|
||||||
>
|
>
|
||||||
|
<div
|
||||||
|
v-if="passwordInvalid && registering"
|
||||||
|
class="input-error"
|
||||||
|
>
|
||||||
|
{{ $t('minPasswordLength') }}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
v-if="registering"
|
v-if="registering"
|
||||||
@@ -145,11 +154,17 @@
|
|||||||
<input
|
<input
|
||||||
id="confirmPasswordInput"
|
id="confirmPasswordInput"
|
||||||
v-model="passwordConfirm"
|
v-model="passwordConfirm"
|
||||||
class="form-control"
|
class="form-control input-with-error"
|
||||||
type="password"
|
type="password"
|
||||||
:placeholder="$t('confirmPasswordPlaceholder')"
|
:placeholder="$t('confirmPasswordPlaceholder')"
|
||||||
:class="{'input-invalid': passwordConfirmInvalid, 'input-valid': passwordConfirmValid}"
|
:class="{'input-invalid': passwordConfirmInvalid, 'input-valid': passwordConfirmValid}"
|
||||||
>
|
>
|
||||||
|
<div
|
||||||
|
v-if="passwordConfirmInvalid"
|
||||||
|
class="input-error"
|
||||||
|
>
|
||||||
|
{{ $t('passwordConfirmationMatch') }}
|
||||||
|
</div>
|
||||||
<small
|
<small
|
||||||
v-once
|
v-once
|
||||||
class="form-text"
|
class="form-text"
|
||||||
@@ -157,22 +172,22 @@
|
|||||||
></small>
|
></small>
|
||||||
</div>
|
</div>
|
||||||
<div class="text-center">
|
<div class="text-center">
|
||||||
<div
|
<button
|
||||||
v-if="registering"
|
v-if="registering"
|
||||||
v-once
|
type="submit"
|
||||||
class="btn btn-info"
|
class="btn btn-info"
|
||||||
@click="register()"
|
:disabled="signupFormInvalid"
|
||||||
>
|
>
|
||||||
{{ $t('joinHabitica') }}
|
{{ $t('joinHabitica') }}
|
||||||
</div>
|
</button>
|
||||||
<div
|
<button
|
||||||
v-if="!registering"
|
v-if="!registering"
|
||||||
v-once
|
v-once
|
||||||
|
type="submit"
|
||||||
class="btn btn-info"
|
class="btn btn-info"
|
||||||
@click="login()"
|
|
||||||
>
|
>
|
||||||
{{ $t('login') }}
|
{{ $t('login') }}
|
||||||
</div>
|
</button>
|
||||||
<div class="toggle-links">
|
<div class="toggle-links">
|
||||||
<router-link
|
<router-link
|
||||||
v-if="registering"
|
v-if="registering"
|
||||||
@@ -275,10 +290,17 @@
|
|||||||
<input
|
<input
|
||||||
id="passwordInput"
|
id="passwordInput"
|
||||||
v-model="password"
|
v-model="password"
|
||||||
class="form-control"
|
class="form-control input-with-error"
|
||||||
type="password"
|
type="password"
|
||||||
:placeholder="$t('password')"
|
:placeholder="$t('password')"
|
||||||
|
:class="{'input-invalid': passwordInvalid, 'input-valid': passwordValid}"
|
||||||
>
|
>
|
||||||
|
<div
|
||||||
|
v-if="passwordInvalid"
|
||||||
|
class="input-error"
|
||||||
|
>
|
||||||
|
{{ $t('minPasswordLength') }}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label
|
<label
|
||||||
@@ -288,10 +310,17 @@
|
|||||||
<input
|
<input
|
||||||
id="confirmPasswordInput"
|
id="confirmPasswordInput"
|
||||||
v-model="passwordConfirm"
|
v-model="passwordConfirm"
|
||||||
class="form-control"
|
class="form-control input-with-error"
|
||||||
type="password"
|
type="password"
|
||||||
:placeholder="$t('confirmPasswordPlaceholder')"
|
:placeholder="$t('confirmPasswordPlaceholder')"
|
||||||
|
:class="{'input-invalid': passwordConfirmInvalid, 'input-valid': passwordConfirmValid}"
|
||||||
>
|
>
|
||||||
|
<div
|
||||||
|
v-if="passwordConfirmInvalid"
|
||||||
|
class="input-error"
|
||||||
|
>
|
||||||
|
{{ $t('passwordConfirmationMatch') }}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="text-center">
|
<div class="text-center">
|
||||||
<div
|
<div
|
||||||
@@ -426,10 +455,14 @@
|
|||||||
color: $white;
|
color: $white;
|
||||||
}
|
}
|
||||||
|
|
||||||
#usernameInput.input-invalid {
|
.input-with-error.input-invalid {
|
||||||
margin-bottom: 0.5em;
|
margin-bottom: 0.5em;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#confirmPasswordInput + .input-error {
|
||||||
|
margin-bottom: 2em;
|
||||||
|
}
|
||||||
|
|
||||||
.form-text {
|
.form-text {
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
color: $white;
|
color: $white;
|
||||||
@@ -480,7 +513,7 @@
|
|||||||
background-image: url('~@/assets/images/auth/seamless_mountains_demo.png');
|
background-image: url('~@/assets/images/auth/seamless_mountains_demo.png');
|
||||||
background-repeat: repeat-x;
|
background-repeat: repeat-x;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 500px;
|
height: 300px;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
z-index: 0;
|
z-index: 0;
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
@@ -512,7 +545,6 @@
|
|||||||
color: #fff;
|
color: #fff;
|
||||||
font-size: 90%;
|
font-size: 90%;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
text-align: center;
|
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
@@ -522,6 +554,7 @@ import hello from 'hellojs';
|
|||||||
import debounce from 'lodash/debounce';
|
import debounce from 'lodash/debounce';
|
||||||
import isEmail from 'validator/lib/isEmail';
|
import isEmail from 'validator/lib/isEmail';
|
||||||
|
|
||||||
|
import { MINIMUM_PASSWORD_LENGTH } from '@/../../common/script/constants';
|
||||||
import gryphon from '@/assets/svg/gryphon.svg';
|
import gryphon from '@/assets/svg/gryphon.svg';
|
||||||
import habiticaIcon from '@/assets/svg/habitica-logo.svg';
|
import habiticaIcon from '@/assets/svg/habitica-logo.svg';
|
||||||
import facebookSquareIcon from '@/assets/svg/facebook-square.svg';
|
import facebookSquareIcon from '@/assets/svg/facebook-square.svg';
|
||||||
@@ -580,6 +613,14 @@ export default {
|
|||||||
if (this.username.length < 1) return false;
|
if (this.username.length < 1) return false;
|
||||||
return !this.usernameValid;
|
return !this.usernameValid;
|
||||||
},
|
},
|
||||||
|
passwordValid () {
|
||||||
|
if (this.password.length <= 0) return false;
|
||||||
|
return this.password.length >= MINIMUM_PASSWORD_LENGTH;
|
||||||
|
},
|
||||||
|
passwordInvalid () {
|
||||||
|
if (this.password.length <= 0) return false;
|
||||||
|
return this.password.length < MINIMUM_PASSWORD_LENGTH;
|
||||||
|
},
|
||||||
passwordConfirmValid () {
|
passwordConfirmValid () {
|
||||||
if (this.passwordConfirm.length <= 3) return false;
|
if (this.passwordConfirm.length <= 3) return false;
|
||||||
return this.passwordConfirm === this.password;
|
return this.passwordConfirm === this.password;
|
||||||
@@ -588,6 +629,12 @@ export default {
|
|||||||
if (this.passwordConfirm.length <= 3) return false;
|
if (this.passwordConfirm.length <= 3) return false;
|
||||||
return !this.passwordConfirmValid;
|
return !this.passwordConfirmValid;
|
||||||
},
|
},
|
||||||
|
signupFormInvalid () {
|
||||||
|
return this.usernameInvalid
|
||||||
|
|| this.emailInvalid
|
||||||
|
|| this.passwordInvalid
|
||||||
|
|| this.passwordConfirmInvalid;
|
||||||
|
},
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
$route: {
|
$route: {
|
||||||
|
|||||||
@@ -53,9 +53,9 @@
|
|||||||
<div class="strike">
|
<div class="strike">
|
||||||
<span>{{ $t('or') }}</span>
|
<span>{{ $t('or') }}</span>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<form
|
||||||
class="form"
|
class="form"
|
||||||
@keyup.enter="register()"
|
@submit.prevent.stop="register()"
|
||||||
>
|
>
|
||||||
<p class="form-text">
|
<p class="form-text">
|
||||||
{{ $t('usernameLimitations') }}
|
{{ $t('usernameLimitations') }}
|
||||||
@@ -63,7 +63,7 @@
|
|||||||
<input
|
<input
|
||||||
id="usernameInput"
|
id="usernameInput"
|
||||||
v-model="username"
|
v-model="username"
|
||||||
class="form-control"
|
class="form-control input-with-error"
|
||||||
type="text"
|
type="text"
|
||||||
:placeholder="$t('username')"
|
:placeholder="$t('username')"
|
||||||
:class="{'input-valid': usernameValid, 'input-invalid': usernameInvalid}"
|
:class="{'input-valid': usernameValid, 'input-invalid': usernameInvalid}"
|
||||||
@@ -85,32 +85,49 @@
|
|||||||
>
|
>
|
||||||
<input
|
<input
|
||||||
v-model="password"
|
v-model="password"
|
||||||
class="form-control"
|
class="form-control input-with-error"
|
||||||
type="password"
|
type="password"
|
||||||
:placeholder="$t('password')"
|
:placeholder="$t('password')"
|
||||||
:class="{'input-valid': password.length > 3}"
|
:class="{
|
||||||
|
'input-valid': passwordValid,
|
||||||
|
'input-invalid': passwordInvalid,
|
||||||
|
}"
|
||||||
>
|
>
|
||||||
|
<div
|
||||||
|
v-if="passwordInvalid"
|
||||||
|
class="input-error"
|
||||||
|
>
|
||||||
|
{{ $t('minPasswordLength') }}
|
||||||
|
</div>
|
||||||
<input
|
<input
|
||||||
v-model="passwordConfirm"
|
v-model="passwordConfirm"
|
||||||
class="form-control"
|
class="form-control input-with-error"
|
||||||
type="password"
|
type="password"
|
||||||
:placeholder="$t('confirmPassword')"
|
:placeholder="$t('confirmPassword')"
|
||||||
:class="{
|
:class="{
|
||||||
'input-invalid': passwordConfirmInvalid,
|
'input-invalid': passwordConfirmInvalid,
|
||||||
'input-valid': passwordConfirmValid}"
|
'input-valid': passwordConfirmValid}"
|
||||||
>
|
>
|
||||||
|
<div
|
||||||
|
v-if="passwordConfirmInvalid"
|
||||||
|
class="input-error"
|
||||||
|
>
|
||||||
|
{{ $t('passwordConfirmationMatch') }}
|
||||||
|
</div>
|
||||||
<p
|
<p
|
||||||
v-once
|
v-once
|
||||||
class="form-text"
|
class="form-text"
|
||||||
v-html="$t('termsAndAgreement')"
|
v-html="$t('termsAndAgreement')"
|
||||||
></p>
|
></p>
|
||||||
<button
|
<button
|
||||||
class="sign-up"
|
class="btn btn-block btn-info sign-up"
|
||||||
|
:disabled="signupFormInvalid"
|
||||||
|
type="submit"
|
||||||
@click="register()"
|
@click="register()"
|
||||||
>
|
>
|
||||||
{{ $t('signup') }}
|
{{ $t('signup') }}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-12">
|
<div class="col-12">
|
||||||
<div
|
<div
|
||||||
@@ -519,7 +536,7 @@
|
|||||||
transition: border .5s, color .5s;
|
transition: border .5s, color .5s;
|
||||||
}
|
}
|
||||||
|
|
||||||
#usernameInput.input-invalid {
|
.input-invalid.input-with-error {
|
||||||
margin-bottom: 0.5em;
|
margin-bottom: 0.5em;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -537,21 +554,9 @@
|
|||||||
background-color: #36205d;
|
background-color: #36205d;
|
||||||
}
|
}
|
||||||
|
|
||||||
button.sign-up {
|
.sign-up {
|
||||||
width: 100%;
|
padding-top: 11px;
|
||||||
height: 48px;
|
padding-bottom: 11px;
|
||||||
color: #fff;
|
|
||||||
border: none;
|
|
||||||
border-radius: 2px;
|
|
||||||
background-color: #2995cd;
|
|
||||||
font-size: 16px;
|
|
||||||
transition: all .5s ease;
|
|
||||||
}
|
|
||||||
|
|
||||||
.sign-up:hover {
|
|
||||||
background-color: #50b5e9;
|
|
||||||
box-shadow: 0 4px 4px 0 rgba(26, 24, 29, 0.16), 0 1px 8px 0 rgba(26, 24, 29, 0.12);
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
::-webkit-input-placeholder { /* Chrome/Opera/Safari */
|
::-webkit-input-placeholder { /* Chrome/Opera/Safari */
|
||||||
@@ -769,7 +774,6 @@
|
|||||||
color: #fff;
|
color: #fff;
|
||||||
font-size: 90%;
|
font-size: 90%;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
text-align: center;
|
|
||||||
margin-bottom: 1em;
|
margin-bottom: 1em;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
@@ -796,6 +800,7 @@ import lifehacker from '@/assets/images/home/lifehacker.svg';
|
|||||||
import makeuseof from '@/assets/images/home/make-use-of.svg';
|
import makeuseof from '@/assets/images/home/make-use-of.svg';
|
||||||
import thenewyorktimes from '@/assets/images/home/the-new-york-times.svg';
|
import thenewyorktimes from '@/assets/images/home/the-new-york-times.svg';
|
||||||
import * as Analytics from '@/libs/analytics';
|
import * as Analytics from '@/libs/analytics';
|
||||||
|
import { MINIMUM_PASSWORD_LENGTH } from '@/../../common/script/constants';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
data () {
|
data () {
|
||||||
@@ -844,6 +849,14 @@ export default {
|
|||||||
if (this.username.length < 1) return false;
|
if (this.username.length < 1) return false;
|
||||||
return !this.usernameValid;
|
return !this.usernameValid;
|
||||||
},
|
},
|
||||||
|
passwordValid () {
|
||||||
|
if (this.password.length <= 0) return false;
|
||||||
|
return this.password.length >= MINIMUM_PASSWORD_LENGTH;
|
||||||
|
},
|
||||||
|
passwordInvalid () {
|
||||||
|
if (this.password.length <= 0) return false;
|
||||||
|
return this.password.length < MINIMUM_PASSWORD_LENGTH;
|
||||||
|
},
|
||||||
passwordConfirmValid () {
|
passwordConfirmValid () {
|
||||||
if (this.passwordConfirm.length <= 3) return false;
|
if (this.passwordConfirm.length <= 3) return false;
|
||||||
return this.passwordConfirm === this.password;
|
return this.passwordConfirm === this.password;
|
||||||
@@ -852,6 +865,12 @@ export default {
|
|||||||
if (this.passwordConfirm.length <= 3) return false;
|
if (this.passwordConfirm.length <= 3) return false;
|
||||||
return this.passwordConfirm !== this.password;
|
return this.passwordConfirm !== this.password;
|
||||||
},
|
},
|
||||||
|
signupFormInvalid () {
|
||||||
|
return this.usernameInvalid
|
||||||
|
|| this.emailInvalid
|
||||||
|
|| this.passwordInvalid
|
||||||
|
|| this.passwordConfirmInvalid;
|
||||||
|
},
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
username () {
|
username () {
|
||||||
|
|||||||
@@ -85,10 +85,6 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#bottom-wrap.purple-4 {
|
|
||||||
background-color: #271b3d;
|
|
||||||
}
|
|
||||||
|
|
||||||
#purple-footer {
|
#purple-footer {
|
||||||
background-color: #271b3d;
|
background-color: #271b3d;
|
||||||
|
|
||||||
@@ -115,33 +111,6 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#bottom-wrap {
|
|
||||||
padding-top: 10em;
|
|
||||||
}
|
|
||||||
|
|
||||||
#bottom-background {
|
|
||||||
position: relative;
|
|
||||||
|
|
||||||
.seamless_mountains_demo_repeat {
|
|
||||||
background-image: url('~@/assets/images/auth/seamless_mountains_demo.png');
|
|
||||||
background-repeat: repeat-x;
|
|
||||||
width: 100%;
|
|
||||||
height: 300px;
|
|
||||||
position: absolute;
|
|
||||||
z-index: 0;
|
|
||||||
bottom: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.midground_foreground_extended2 {
|
|
||||||
background-image: url('~@/assets/images/auth/midground_foreground_extended2.png');
|
|
||||||
position: relative;
|
|
||||||
width: 1500px;
|
|
||||||
max-width: 100%;
|
|
||||||
height: 150px;
|
|
||||||
margin: 0 auto;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.static-wrapper {
|
.static-wrapper {
|
||||||
.container-fluid {
|
.container-fluid {
|
||||||
margin: 5em 2em 2em 2em;
|
margin: 5em 2em 2em 2em;
|
||||||
@@ -171,6 +140,39 @@
|
|||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
#bottom-wrap.purple-4 {
|
||||||
|
background-color: #271b3d;
|
||||||
|
}
|
||||||
|
|
||||||
|
#bottom-wrap {
|
||||||
|
padding-top: 10em;
|
||||||
|
}
|
||||||
|
|
||||||
|
#bottom-background {
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
.seamless_mountains_demo_repeat {
|
||||||
|
background-image: url('~@/assets/images/auth/seamless_mountains_demo.png');
|
||||||
|
background-repeat: repeat-x;
|
||||||
|
width: 100%;
|
||||||
|
height: 300px;
|
||||||
|
position: absolute;
|
||||||
|
z-index: 0;
|
||||||
|
bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.midground_foreground_extended2 {
|
||||||
|
background-image: url('~@/assets/images/auth/midground_foreground_extended2.png');
|
||||||
|
position: relative;
|
||||||
|
width: 1500px;
|
||||||
|
max-width: 100%;
|
||||||
|
height: 150px;
|
||||||
|
margin: 0 auto;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import AppFooter from '@/components/appFooter';
|
import AppFooter from '@/components/appFooter';
|
||||||
import StaticHeader from './header.vue';
|
import StaticHeader from './header.vue';
|
||||||
|
|||||||
@@ -274,6 +274,7 @@
|
|||||||
"usernameTOSRequirements": "Usernames must conform to our <a href='/static/terms' target='_blank'>Terms of Service</a> and <a href='/static/community-guidelines' target='_blank'>Community Guidelines</a>. If you didn’t previously set a login name, your username was auto-generated.",
|
"usernameTOSRequirements": "Usernames must conform to our <a href='/static/terms' target='_blank'>Terms of Service</a> and <a href='/static/community-guidelines' target='_blank'>Community Guidelines</a>. If you didn’t previously set a login name, your username was auto-generated.",
|
||||||
"usernameTaken": "Username already taken.",
|
"usernameTaken": "Username already taken.",
|
||||||
"passwordConfirmationMatch": "Password confirmation doesn't match password.",
|
"passwordConfirmationMatch": "Password confirmation doesn't match password.",
|
||||||
|
"minPasswordLength": "Password must be 8 characters or more.",
|
||||||
"passwordResetPage": "Reset Password",
|
"passwordResetPage": "Reset Password",
|
||||||
"passwordReset": "If we have your email on file, instructions for setting a new password have been sent to your email.",
|
"passwordReset": "If we have your email on file, instructions for setting a new password have been sent to your email.",
|
||||||
"invalidLoginCredentialsLong": "Uh-oh - your email address / username or password is incorrect.\n- Make sure they are typed correctly. Your username and password are case-sensitive.\n- You may have signed up with Facebook or Google-sign-in, not email so double-check by trying them.\n- If you forgot your password, click \"Forgot Password\".",
|
"invalidLoginCredentialsLong": "Uh-oh - your email address / username or password is incorrect.\n- Make sure they are typed correctly. Your username and password are case-sensitive.\n- You may have signed up with Facebook or Google-sign-in, not email so double-check by trying them.\n- If you forgot your password, click \"Forgot Password\".",
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ export const GUILDS_PER_PAGE = 30; // number of guilds to return per page when u
|
|||||||
|
|
||||||
export const PARTY_LIMIT_MEMBERS = 30;
|
export const PARTY_LIMIT_MEMBERS = 30;
|
||||||
|
|
||||||
|
export const MINIMUM_PASSWORD_LENGTH = 8;
|
||||||
export const TRANSFORMATION_DEBUFFS_LIST = {
|
export const TRANSFORMATION_DEBUFFS_LIST = {
|
||||||
snowball: 'salt',
|
snowball: 'salt',
|
||||||
spookySparkles: 'opaquePotion',
|
spookySparkles: 'opaquePotion',
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ import {
|
|||||||
MAX_SUMMARY_SIZE_FOR_GUILDS,
|
MAX_SUMMARY_SIZE_FOR_GUILDS,
|
||||||
MIN_SHORTNAME_SIZE_FOR_CHALLENGES,
|
MIN_SHORTNAME_SIZE_FOR_CHALLENGES,
|
||||||
PARTY_LIMIT_MEMBERS,
|
PARTY_LIMIT_MEMBERS,
|
||||||
|
MINIMUM_PASSWORD_LENGTH,
|
||||||
SUPPORTED_SOCIAL_NETWORKS,
|
SUPPORTED_SOCIAL_NETWORKS,
|
||||||
TAVERN_ID,
|
TAVERN_ID,
|
||||||
} from './constants';
|
} from './constants';
|
||||||
@@ -106,6 +107,7 @@ api.constants = {
|
|||||||
CHAT_FLAG_LIMIT_FOR_HIDING,
|
CHAT_FLAG_LIMIT_FOR_HIDING,
|
||||||
CHAT_FLAG_FROM_MOD,
|
CHAT_FLAG_FROM_MOD,
|
||||||
CHAT_FLAG_FROM_SHADOW_MUTE,
|
CHAT_FLAG_FROM_SHADOW_MUTE,
|
||||||
|
MINIMUM_PASSWORD_LENGTH,
|
||||||
};
|
};
|
||||||
// TODO Move these under api.constants
|
// TODO Move these under api.constants
|
||||||
api.maxLevel = MAX_LEVEL;
|
api.maxLevel = MAX_LEVEL;
|
||||||
|
|||||||
@@ -245,6 +245,10 @@ api.updatePassword = {
|
|||||||
},
|
},
|
||||||
newPassword: {
|
newPassword: {
|
||||||
notEmpty: { errorMessage: res.t('missingNewPassword') },
|
notEmpty: { errorMessage: res.t('missingNewPassword') },
|
||||||
|
isLength: {
|
||||||
|
options: { min: common.constants.MINIMUM_PASSWORD_LENGTH },
|
||||||
|
errorMessage: res.t('minPasswordLength'),
|
||||||
|
},
|
||||||
},
|
},
|
||||||
confirmPassword: {
|
confirmPassword: {
|
||||||
notEmpty: { errorMessage: res.t('missingNewPassword') },
|
notEmpty: { errorMessage: res.t('missingNewPassword') },
|
||||||
@@ -387,13 +391,23 @@ api.resetPasswordSetNewOne = {
|
|||||||
|
|
||||||
if (!isValidCode) throw new NotAuthorized(res.t('invalidPasswordResetCode'));
|
if (!isValidCode) throw new NotAuthorized(res.t('invalidPasswordResetCode'));
|
||||||
|
|
||||||
req.checkBody('newPassword', res.t('missingNewPassword')).notEmpty();
|
req.checkBody({
|
||||||
req.checkBody('confirmPassword', res.t('missingNewPassword')).notEmpty();
|
newPassword: {
|
||||||
|
notEmpty: { errorMessage: res.t('missingNewPassword') },
|
||||||
|
isLength: {
|
||||||
|
options: { min: common.constants.MINIMUM_PASSWORD_LENGTH },
|
||||||
|
errorMessage: res.t('minPasswordLength'),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
confirmPassword: {
|
||||||
|
notEmpty: { errorMessage: res.t('missingNewPassword') },
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
const validationErrors = req.validationErrors();
|
const validationErrors = req.validationErrors();
|
||||||
if (validationErrors) throw validationErrors;
|
if (validationErrors) throw validationErrors;
|
||||||
|
|
||||||
const { newPassword } = req.body;
|
const { newPassword, confirmPassword } = req.body;
|
||||||
const { confirmPassword } = req.body;
|
|
||||||
|
|
||||||
if (newPassword !== confirmPassword) {
|
if (newPassword !== confirmPassword) {
|
||||||
throw new BadRequest(res.t('passwordConfirmationMatch'));
|
throw new BadRequest(res.t('passwordConfirmationMatch'));
|
||||||
|
|||||||
@@ -93,8 +93,13 @@ async function registerLocal (req, res, { isV3 = false }) {
|
|||||||
},
|
},
|
||||||
password: {
|
password: {
|
||||||
notEmpty: true,
|
notEmpty: true,
|
||||||
|
|
||||||
errorMessage: res.t('missingPassword'),
|
errorMessage: res.t('missingPassword'),
|
||||||
equals: { options: [req.body.confirmPassword], errorMessage: res.t('passwordConfirmationMatch') },
|
equals: { options: [req.body.confirmPassword], errorMessage: res.t('passwordConfirmationMatch') },
|
||||||
|
isLength: {
|
||||||
|
options: { min: common.constants.MINIMUM_PASSWORD_LENGTH },
|
||||||
|
errorMessage: res.t('minPasswordLength'),
|
||||||
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user