Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Modify password validation SLIC-4 #182

Open
wants to merge 6 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 2 additions & 0 deletions frontend/public/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:300,400,500">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<meta name="theme-color" content="#000000">
<meta http-equiv="Cache-control" content="no-cache, no-store, must-revalidate">
<meta http-equiv="Pragma" content="no-cache">
<link rel="manifest" href="%PUBLIC_URL%/manifest.json">
<title>SLIC Starter</title>
</head>
Expand Down
46 changes: 43 additions & 3 deletions frontend/src/components/ConfirmForgotPassword.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ const styles = (theme) => ({
marginTop: theme.spacing.unit
}
})
const PASSWORD_REGEX = /^(?=.*\d)(?=.*[\^$*.\[\]{}\(\)?\-\"!@#%&\/,><\':;|_~``=+-])(?=.*[a-z])(?=.*[A-Z]).{6,99}$/

class ConfirmForgotPassword extends Component {
state = {
Expand All @@ -38,7 +39,28 @@ class ConfirmForgotPassword extends Component {
newPassword: ''
};

validate = () => this.state.confirmationCode.length > 5 && this.state.newPassword.length > 5;
validate = () => {
const codeSent = this.state.confirmationCode.length > 5
const newPasswordValid = PASSWORD_REGEX.test(this.state.newPassword)

const result = {
valid: codeSent && newPasswordValid
}

result.confirmationCode = {
showError: !codeSent && this.state.confirmationCode.length > 0
}
result.newPassword = {
showError: !newPasswordValid && this.state.newPassword.length > 0
}
if (result.confirmationCode.showError) {
result.confirmationCode.message = 'Confirmation code is required'
}
if (result.newPassword.showError) {
result.newPassword.message = 'Password must contain at least one number, a special character, one lowercase and uppercase letter, and at least 6 characters'
}
return result
}

handleChange = ({ target: { id, value } }) => {
switch (id) {
Expand Down Expand Up @@ -70,10 +92,14 @@ class ConfirmForgotPassword extends Component {

const sendingPasswordSucccess = newPasswordSent ? (<Redirect to="/login" />) : null

const validation = this.validate()

const errorItem = newPasswordError
? (
<Grid item>
<ErrorMessage messageId={newPasswordError.id} />
<Typography className={classes.error}>
<ErrorMessage messageId={newPasswordError.id} />
</Typography>
</Grid>
)
: null
Expand Down Expand Up @@ -106,6 +132,13 @@ class ConfirmForgotPassword extends Component {
label="Confirmation Code"
onChange={this.handleChange}
className={classes.input}
error={validation.confirmationCode.showError}
helperText={validation.confirmationCode.message}
FormHelperTextProps={{
classes: {
root: classes.helperText
}
}}
/>
</Grid>

Expand All @@ -117,6 +150,13 @@ class ConfirmForgotPassword extends Component {
type="password"
autoComplete="new-password"
onChange={this.handleChange}
error={validation.newPassword.showError}
helperText={validation.newPassword.message}
FormHelperTextProps={{
classes: {
root: classes.helperText
}
}}
/>
{errorItem}
{sendingPasswordSucccess}
Expand All @@ -138,7 +178,7 @@ class ConfirmForgotPassword extends Component {
type="submit"
id='confirm-password-btn'
className={classes.button}
disabled={sendingNewPassword || !this.validate}
disabled={sendingNewPassword || !validation.valid}
>
{sendingNewPassword ? 'Resetting password...' : 'Reset Password'}
</Button>
Expand Down
71 changes: 62 additions & 9 deletions frontend/src/components/Signup.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,25 +21,60 @@ const styles = (theme) => ({
},
paper: {
minWidth: '340px',
maxWidth: '500px',
padding: theme.spacing.unit * 2
},
title: {
whiteSpace: 'nowrap'
},
input: {
width: '100%'
},
button: {
width: '100%',
marginTop: theme.spacing.unit
},
helperText: {
maxWidth: '275px'
}
})

/**
* TODO: Update this regular expression to check _exactly_ the password policy enforced by the Cognito User Pool
*/
const PASSWORD_REGEX = /^(?=.*\d)(?=.*[\^$*.\[\]{}\(\)?\-\"!@#%&\/,><\':;|_~``=+-])(?=.*[a-z])(?=.*[A-Z]).{6,99}$/

class Signup extends Component {
state = {
email: '',
password: ''
};

validate = () =>
this.state.email.length > 0 && this.state.password.length > 5;
validate = () => {
const emailValid = this.state.email.length > 3
const passwordValid = PASSWORD_REGEX.test(this.state.password)

const result = {
valid: emailValid && passwordValid
}

// Only provide field-specific errors if a value has been entered.
// We do not want to show any error if the user hasn't started typing yet
result.email = {
showError: !emailValid && this.state.email.length > 0
}
result.password = {
showError: !passwordValid && this.state.password.length > 0
}
if (result.email.showError) {
result.email.message = 'Email is required'
}
if (result.password.showError) {
result.password.message = 'Password must contain at least one number, a special character, one lowercase and uppercase letter, and at least 6 characters'
}

return result
}

handleChange = ({ target: { id, value } }) => this.setState({ [id]: value });

Expand All @@ -53,13 +88,17 @@ class Signup extends Component {

const { signingUp, signupError, signedUp, userConfirmed } = this.props.auth

// Perform client-side validation
const validation = this.validate()

// Render component for server-side errors if present
const errorItem = signupError
? (
<Grid item>
<Typography className={classes.error}>
<ErrorMessage messageId={signupError.id} />
</Typography>
</Grid>
<Grid item>
<Typography className={classes.error}>
<ErrorMessage messageId={signupError.id} />
</Typography>
</Grid>
)
: null

Expand All @@ -78,7 +117,7 @@ class Signup extends Component {
spacing={8}
>
<Grid item>
<Typography variant="h3">Sign Up</Typography>
<Typography variant="h3" className={classes.title}>Sign Up</Typography>
</Grid>
<Grid item>
<TextField
Expand All @@ -87,6 +126,13 @@ class Signup extends Component {
label="Email"
autoComplete="username"
onChange={this.handleChange}
error={validation.email.showError}
helperText={validation.email.message}
FormHelperTextProps={{
classes: {
root: classes.helperText
}
}}
/>
</Grid>
<Grid item>
Expand All @@ -97,6 +143,13 @@ class Signup extends Component {
type="password"
autoComplete="new-password"
onChange={this.handleChange}
error={validation.password.showError}
helperText={validation.password.message}
FormHelperTextProps={{
classes: {
root: classes.helperText
}
}}
/>
</Grid>
{errorItem}
Expand All @@ -107,7 +160,7 @@ class Signup extends Component {
color="secondary"
type="submit"
className={classes.button}
disabled={signingUp || !this.validate()}
disabled={signingUp || !validation.valid}
>
{signingUp ? 'Signing up...' : 'Sign Up'}
</Button>
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/errors.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ export const messages = {
[USER_NOT_CONFIRMED]: 'The user account has not been confirmed',
[USER_NOT_FOUND]: 'That user could not be found',
[UNKNOWN_AUTHENTICATION_ERROR]: 'An error occured',
[INVALID_PASSWORD]: 'Invalid password',
[INVALID_PASSWORD]: 'Password must contain at least one number and a special character, one lowercase and uppercase letter, and at least 6 or more characters',
[USER_ALREADY_EXISTS]: 'An account with that email already exists',
[UNKNOWN]: 'An unexpected error occurred',
[INVALID_EMAIL]: 'Invalid email format',
Expand Down