-
Notifications
You must be signed in to change notification settings - Fork 1
/
auth.js
174 lines (140 loc) · 5.13 KB
/
auth.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
// What needs to be authenticated?
// -Users
//How?????
//-cookies or local storage with jwt
//What does authentication require?
//-valid user credentials from signing up or signing in
// What route to sign up?
// - .post('/users')
// What route to sign in?
// - I think it should be .post('/users/signin')
// When do we need to authenticate?
//- when user tries to do anything requiring authorization
//-user posts a comment
//-user posts a like
//-user post a song
// What/when do we need to authorize?
// -when user tries to get pages to edit song or user.
// - when user tries to edit song
// -when user tries to delete a song
// -when user tries to edit user
// -when user tries to delete user
//-user deletes a like
const jwt = require("jsonwebtoken");
const { jwtConfig } = require("./config");
const { secret, expiresIn } = jwtConfig;
const { User } = require("./db/models");
const generateUserToken = (user) => {
//DOES WHAT: generates a token for a user
//WHEN TO RUN: run it during account creation, login, or token refreshing.
//WHERE TO RUN IT: this should be ran in the signup and login routes. it can also be ran in a refresh middleware function.
const userDataForToken = {
id: user.id,
email: user.email,
username: user.username,
};
const token = jwt.sign({ data: userDataForToken }, secret, {
expiresIn: parseInt(expiresIn, 10),
});
return token;
};
const refreshValidToken = (req, res, next) => {
//DOES WHAT: refreshes a token if user has valid token already.
//WHEN TO RUN: This is an optional middleware. If we want user to have their token refreshed with each request, we should run this middleware.
//WHERE TO RUN IT: We would use this middleware on app.js; it is not route specific.
const { token } = req;
if (!token) {
next();
}
return jwt.verify(token, secret, null, async (err, jwtPayload) => {
if (err) {
err.status = 401;
return next(err);
}
const { id } = jwtPayload.data;
try {
const user = await User.findByPk(id);
} catch (err) {
return next(err);
}
const token = generateUserToken(user);
document.cookie = `NOISEWAVE_ACCESS_TOKEN=${token}`;
next();
});
};
const requireAuth = (req, res, next) => {
//DOES WHAT: this function checks to see if a user has is logged in (has a token). If yes, it will pass on their user instance to req. If not, it will direct the user to login.
//WHEN TO RUN: When it is necessary to have an authenticated, logged in user for a request.
//WHERE TO RUN IT: this is a middleware. run it before route.
const token = req.cookies.NOISEWAVE_ACCESS_TOKEN;
if (!token) {
//TODO this should be redirect or prompt modal popup for login
const error = new Error("You must be logged in to see this page");
res.status(401);
res.render("error", { error });
return;
}
return jwt.verify(token, secret, null, async (err, jwtPayload) => {
if (err) {
err.status = 401;
return next(err);
}
const { id } = jwtPayload.data;
try {
req.user = await User.findByPk(id);
} catch (err) {
return next(err);
}
if (!req.user) {
const error = new Error("You must be logged in to see this page");
res.status(401);
return res.render("error", error);
}
return next();
});
};
const loggedInUser = (req, res, next) => {
//DOES WHAT: this middleware checks if the user is logged in (has valid token). If they are, their instance is grabbed and passed in the req.
//WHEN TO RUN: this middleware should be ran when we want to determine how to render a frontend page from a get request. We check who is logged in, and if it matches the id of
// the get path for user or user songs we render it with extra stuff. For example, if a user visits a profile page or
//a user's songs page, we would run this and see if the person is logged in and the owner. if yes, we'd add links to edit account, or edit/add songs page(s).
//WHERE TO RUN IT: it's a middleware, run before rendering pug to see if we need to render certain options/links for user.
const token = req.cookies.NOISEWAVE_ACCESS_TOKEN;
if (!token) {
req.user = null;
next();
return;
}
return jwt.verify(token, secret, null, async (err, jwtPayload) => {
if (err) {
err.status = 405;
return next(err);
}
const { id } = jwtPayload.data;
try {
const user = await User.findByPk(id);
if (user !== null) {
req.user = user;
}
} catch (err) {
return next(err);
}
next();
});
};
const userIsAuthorized = (
authenticatedUserFromReqObject,
userSpecificiedByUrl
) => {
//DOES WHAT: tells us if user is authorized by comparing what user the route is selecting and what route is authenticated.
//WHEN TO RUN: Anytime specific authorization is required (see lines 16-29).
//WHERE TO RUN IT: this would always be ran from within a route. TBH the function itself is overkill, BUT it explains how we'd do authorization.
return authenticatedUserFromReqObject.id === userSpecificiedByUrl.id;
};
module.exports = {
generateUserToken,
requireAuth,
refreshValidToken,
loggedInUser,
userIsAuthorized,
};