Skip to content

Commit f054285

Browse files
committed
Improved login and registration validation/messages.
1 parent bad9435 commit f054285

File tree

9 files changed

+568
-530
lines changed

9 files changed

+568
-530
lines changed

src/data/enums/UserLoginErrorCode.js

+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
const UserLoginErrorCode = {
2+
INCORRECT_PASSWORD: 'pw',
3+
INVALID_ID: 'invalid_id',
4+
LOGGED_IN: 'loggedin',
5+
LOGIN_UNSUCCESSFUL: 'unsuccessful',
6+
LOGIN_UPVOTE: 'up',
7+
USERNAME_TAKEN: 'id',
8+
};
9+
UserLoginErrorCode.messages = {
10+
[UserLoginErrorCode.INCORRECT_PASSWORD]: 'Incorrect password.',
11+
[UserLoginErrorCode.INVALID_ID]: 'User ID must be between 3 and 32 characters.',
12+
[UserLoginErrorCode.LOGGED_IN]: 'Logged in user must logout before logging in again.',
13+
[UserLoginErrorCode.LOGIN_UNSUCCESSFUL]: 'Login unsuccessful.',
14+
[UserLoginErrorCode.LOGIN_UPVOTE]: 'You have to be logged in to vote.',
15+
[UserLoginErrorCode.USERNAME_TAKEN]: 'Username is taken.',
16+
};
17+
18+
export default UserLoginErrorCode;

src/data/models/User.js

+22-12
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,15 @@ import {
88
import {
99
passwordIterations,
1010
} from '../../config';
11+
import {
12+
isValidUser,
13+
isValidNewUser,
14+
} from '../validation/User';
1115

1216
export default class User {
1317
constructor(props) {
1418
if (!props.id) throw new Error('Error instantiating User, id invalid: ', props.id);
19+
isValidUser(props);
1520

1621
this.id = props.id;
1722
this.about = props.about || '';
@@ -24,7 +29,7 @@ export default class User {
2429
this.lastName = props.lastName || null;
2530
this.likes = props.likes || [];
2631
this.posts = props.posts || [];
27-
this.password = props.password || undefined;
32+
this.hashedPassword = props.hashedPassword || undefined;
2833
this.passwordSalt = props.passwordSalt || undefined;
2934
}
3035

@@ -35,25 +40,30 @@ export default class User {
3540

3641
static validPassword = async (id, password) => {
3742
const user = cache.getUser(id);
38-
if (user) return await createHash(password, user.passwordSalt, passwordIterations) === user.password;
43+
if (user) return await createHash(password, user.passwordSalt, passwordIterations) === user.hashedPassword;
3944
return false;
4045
}
4146

42-
static registerUser = async ({ id, password }) => {
43-
if (id.length < 3 || id.length > 32) throw new Error('User ID must be between 3 and 32 characters.');
44-
if (password.length < 8 || password.length > 100) throw new Error('User password must be longer than 8 characters.');
45-
if (cache.getUser(id)) throw new Error('Username is taken.');
47+
static registerUser = async (user) => {
48+
// Check if user is valid
49+
isValidNewUser(user);
50+
51+
// Check if user already exists
52+
if (cache.getUser(user.id)) throw new Error('Username is taken.');
4653

54+
// Go ahead and create the new user
4755
const passwordSalt = createSalt();
48-
const hashedPassword = await createHash(password, passwordSalt, passwordIterations);
56+
const hashedPassword = await createHash(user.password, passwordSalt, passwordIterations);
4957

50-
const user = new User({
51-
id,
52-
password: hashedPassword,
58+
const newUser = new User({
59+
id: user.id,
60+
hashedPassword,
5361
passwordSalt,
5462
});
5563

56-
cache.setUser(user.id, user);
57-
return user;
64+
// Store the new user
65+
cache.setUser(user.id, newUser);
66+
67+
return newUser;
5868
}
5969
}

src/data/queries/meQuery.js

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import {
2+
gql,
3+
} from 'react-apollo';
4+
5+
export default gql`
6+
query User {
7+
me {
8+
id
9+
karma
10+
}
11+
}
12+
`;

src/data/validation/User.js

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import ValidationError from './ValidationError';
2+
3+
export function isValidUser({ id }) {
4+
if (id.length < 3 || id.length > 32) throw new ValidationError({ code: 'id', message: 'User ID must be between 3 and 32 characters.' });
5+
return true;
6+
}
7+
8+
export function isValidNewUser({ id, password }) {
9+
if (id.length < 3 || id.length > 32) throw new ValidationError({ code: 'id', message: 'User ID must be between 3 and 32 characters.' });
10+
if (password.length < 8 || password.length > 100) throw new ValidationError({ code: 'pw', message: 'User password must be longer than 8 characters.' });
11+
return true;
12+
}
13+
+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
export default class ValidationError extends Error {
2+
constructor(err) {
3+
super(err.message);
4+
this.code = err.code;
5+
Error.captureStackTrace(this, ValidationError);
6+
}
7+
}

src/layouts/Main.js

+1-10
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,11 @@ import PropTypes from 'prop-types';
33
import Head from 'next/head';
44
import {
55
graphql,
6-
gql,
76
} from 'react-apollo';
87

98
import Header from '../components/presentational/Header';
109
import Footer from '../components/presentational/Footer';
10+
import meQuery from '../data/queries/meQuery';
1111

1212

1313
const Main = props => (
@@ -58,15 +58,6 @@ Main.propTypes = {
5858
currentURL: PropTypes.string.isRequired,
5959
};
6060

61-
const meQuery = gql`
62-
query User {
63-
me {
64-
id
65-
karma
66-
}
67-
}
68-
`;
69-
7061
export default graphql(meQuery, {
7162
options: {
7263
// fetchPolicy: 'cache-and-network',

0 commit comments

Comments
 (0)