Skip to content
This repository has been archived by the owner on Apr 7, 2021. It is now read-only.

Commit

Permalink
Merge pull request #40 from ckanich-classrooms/dt/input-validation
Browse files Browse the repository at this point in the history
✨ Added Input Validation
  • Loading branch information
alexchomiak authored Mar 27, 2020
2 parents b2a70be + 49a91fe commit dcb3972
Show file tree
Hide file tree
Showing 5 changed files with 115 additions and 41 deletions.
35 changes: 27 additions & 8 deletions api/src/routes/auth/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@ import { isAuthenticated } from './passport'

const router = Router()

/* Remove data shouldn't be sent to client E.g. password */
const stripData = userData => {
const result = JSON.parse(JSON.stringify(userData))
// * Remove data shouldn't be sent to client
const stripData = data => {
const result = JSON.parse(JSON.stringify(data))
delete result['password']
return result
}
Expand Down Expand Up @@ -45,26 +45,45 @@ router.post('/signup', async (req: Request, res: Response) => {
// * Grab needed elements from request body
const { firstname, lastname, email, password } = req.body

// * Verify that the first and last name is valid
const nameRegex = /[^0-9\.\,\"\?\!\;\:\#\$\%\&\(\)\*\+\-\/\<\>\=\@\[\]\\\^\_\{\}\|\~]/
if (!nameRegex.test(firstname) || !nameRegex.test(lastname)) {
res.status(400).send('Name is invalid')
return
}

// * Verify that the email matches according to W3C standard
if (!/^[a-zA-Z0-9.!#$%&*+/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*$/.test(email)) {
res.status(400).send('Email is invalid')
return
}

// * Verify the the password is adhering to out standard
// * Length is atleast than 8
// * Has one lower case and upper case English letter
// * Has one digit and one special character
if (!/^(?=.*?[A-Z])(?=.*?[a-z])(?=.*?[0-9])(?=.*?[#?!@$%^&*-]).{8,}$/.test(password)) {
res.status(400).send('Password is not strong enough')
return
}

// * Check if user already exists
const test = await User.findOne({ email })
if (test) {
res.status(400).send('Email already exists!')
return
}

// * Hash password
const hashedPassword = await bcrypt.hash(password, 2)

// * Setup User
const user = new User({
firstname,
lastname,
email,
password: hashedPassword
// * Hashed Password
password: await bcrypt.hash(password, 2)
})

// * Save user
console.log(user)
await user.save()

// * Login User
Expand Down
10 changes: 5 additions & 5 deletions api/src/tests/auth.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ describe('Authentication Tests', () => {
firstname: 'Clark',
lastname: 'Chen',
email: 'schen237@uic.edu',
password: 'theRealClark'
password: 'theRealClark1$'
})

expect(response.status).toBe(200)
Expand All @@ -53,7 +53,7 @@ describe('Authentication Tests', () => {
firstname: 'Clark',
lastname: 'Chen',
email: 'schen237@uic.edu',
password: 'theRealClark'
password: 'theRealClark1$'
})

expect(response.status).toBe(400)
Expand All @@ -68,7 +68,7 @@ describe('Authentication Tests', () => {
it('Logs user in correctly using email, password', async () => {
const response = await client.post('login', {
email: 'schen237@uic.edu',
password: 'theRealClark'
password: 'theRealClark1$'
})

expect(response.status).toBe(200)
Expand All @@ -92,7 +92,7 @@ describe('Authentication Tests', () => {
it('Cannot login with incorrect email', async () => {
const response = await client.post('login', {
email: 'schen237@acm.cs.uic.edu',
password: 'theRealClark'
password: 'theRealClark1$'
})

expect(response.status).toBe(401)
Expand All @@ -101,7 +101,7 @@ describe('Authentication Tests', () => {
it('Cannot login with incorrect password', async () => {
const response = await client.post('login', {
email: 'schen237@uic.edu',
password: 'theFakeClark'
password: 'theFakeClark1$'
})

expect(response.status).toBe(401)
Expand Down
8 changes: 4 additions & 4 deletions api/src/tests/class.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,17 +47,17 @@ describe('Class Tests', () => {
const response = await client.post(`auth/signup`, {
firstname: 'Clark',
lastname: 'Chen',
email: 'schen2370@uic.edu',
password: 'theRealClark'
email: 'schen237@uic.edu',
password: 'theRealClark1$'
})

expect(response.status).toBe(200)
})

beforeEach(async () => {
const response = await client.post('auth/login', {
email: 'schen2370@uic.edu',
password: 'theRealClark'
email: 'schen237@uic.edu',
password: 'theRealClark1$'
})
})

Expand Down
101 changes: 78 additions & 23 deletions client/src/components/SignUp.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,43 @@ import { signUp } from '../utils/functions/authentication'

const SignUp = () => {
const [show, toggleShow] = useState(false)
const [validated, setValidated] = useState(false)

const [fName, setFName] = useState('')
const [lName, setLName] = useState('')
const [email, setEmail] = useState('')
const [password, setPassword] = useState('')

const handleClick = async () => {
setValidated(true)

const nameRegex = /[a-zA-Z]+[a-zA-Z0-9\s]+[a-zA-Z]/
if (!nameRegex.test(fName) || !nameRegex.test(lName)) {
return
}

// * Verify that the email matches according to W3C standard
if (!/^[a-zA-Z0-9.!#$%&*+/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*$/.test(email)) {
return
}

// * Verify the the password is adhering to out standard
// * Length is atleast than 8
// * Has one lower case and upper case English letter
// * Has one digit and one special character
if (!/^(?=.*?[A-Z])(?=.*?[a-z])(?=.*?[0-9])(?=.*?[#?!@$%^&*-]).{8,}$/.test(password)) {
return
}

toggleShow(false)
setFName('')
setLName('')
setEmail('')
setPassword('')

await signUp(fName, lName, email, password)
}

return (
<>
<span onClick={() => toggleShow(!show)}>Register</span>
Expand All @@ -21,75 +52,99 @@ const SignUp = () => {
<Modal.Title>Sign Up</Modal.Title>
</Modal.Header>
<Modal.Body>
<Form>
<Form.Group>
<Form validated={validated}>
<Form.Group controlId="validationFirstName">
<Form.Label>First Name</Form.Label>
<Form.Control
placeholder="Jon"
value={fName}
type="text"
required
pattern="[a-zA-Z]+[a-zA-Z0-9\s]+[a-zA-Z]"
onKeyDown={(e: React.KeyboardEvent<HTMLInputElement>) => {
if (e.key === ' ') {
e.preventDefault()
setFName(fName + ' ')
}
}}
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
console.log(e.target.value)
setFName(e.target.value)
}}
/>
<Form.Control.Feedback type="invalid">
Your firstname must start with a alphanumeric character and should
not contain any special characters.
</Form.Control.Feedback>
</Form.Group>

<Form.Group>
<Form.Group controlId="validationLastName">
<Form.Label>Last Name</Form.Label>
<Form.Control
placeholder="Doe"
value={lName}
required
pattern="[a-zA-Z]+[a-zA-Z0-9\s]+[a-zA-Z]"
onKeyDown={(e: React.KeyboardEvent<HTMLInputElement>) => {
if (e.key === ' ') {
e.preventDefault()
setLName(lName + ' ')
}
}}
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
setLName(e.target.value)
}}
/>
<Form.Control.Feedback type="invalid">
Your lastname must start with a alphanumeric character and should
not contain any special characters.
</Form.Control.Feedback>
</Form.Group>

<Form.Group>
<Form.Group controlId="validationEmail">
<Form.Label>Email address</Form.Label>
<Form.Control
type="email"
placeholder="Enter email"
required
value={email}
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
setEmail(e.target.value)
}}
/>
<Form.Control.Feedback type="invalid">
Please provide a valid email
</Form.Control.Feedback>
<Form.Text className="text-muted">
We'll never share your email with anyone else.
</Form.Text>
</Form.Group>

<Form.Group>
<Form.Group controlId="validationPassword">
<Form.Label>Password</Form.Label>
<Form.Control
type="password"
placeholder="Password"
required
pattern="(?=.*?[A-Z])(?=.*?[a-z])(?=.*?[0-9])(?=.*?[#?!@$%^&*-]).{8,}"
value={password}
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
setPassword(e.target.value)
}}
/>
<Form.Control.Feedback type="invalid">
Your password must be atleast 8 characters long and have a digit, a
special character, and an uppercase and lowercase English letter
</Form.Control.Feedback>
</Form.Group>

<Form.Group>
<Button variant="primary" onClick={handleClick}>
Sign Up
</Button>
</Form.Group>
</Form>
</Modal.Body>
<Modal.Footer>
<Button
variant="primary"
onClick={async (e: React.MouseEvent<HTMLButtonElement>) => {
e.preventDefault()

toggleShow(false)
setFName('')
setLName('')
setEmail('')
setPassword('')

await signUp(fName, lName, email, password)
}}
>
Sign Up
</Button>
</Modal.Footer>
</Modal>
</>
)
Expand Down
2 changes: 1 addition & 1 deletion client/src/utils/functions/authentication.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ export const signUp = async (fn: string, ln: string, em: string, pw: string) =>
else if (response.status === 400)
store.dispatch(
userSignUp(null, {
msg: 'Email already exist! Please login',
msg: response.data,
options: {
type: 'info'
}
Expand Down

0 comments on commit dcb3972

Please sign in to comment.