-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathpassport.js
114 lines (103 loc) · 3.45 KB
/
passport.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
const passport = require("passport");
const crypto = require("crypto");
const LocalStrategy = require("passport-local").Strategy;
const passportJWT = require("passport-jwt");
const db = require("./db/connection");
const {
updateIncorrectPasswordAttempts,
updateLastLoginAttempt,
} = require("./models/userModels");
const ExtractJWT = passportJWT.ExtractJwt;
const JWTStrategy = passportJWT.Strategy;
if (!process.env.JWT_SECRET) {
throw new Error("JWT_SECRET not set");
}
passport.use(
new LocalStrategy((username, password, done) => {
return db
.query(
`SELECT * FROM users JOIN security_policies USING (policy_id) WHERE username = $1`,
[username.toLowerCase()]
)
.then(({ rows, rowCount }) => {
if (!rowCount) {
return done(null, false, {
message: "Incorrect username or password",
});
}
const user = rows[0];
if (user.account_locked) {
return done(null, false, { message: "Account locked" });
}
return updateLastLoginAttempt(username, new Date()).then(() => {
if (user.incorrect_logins >= user.max_login_attempts) {
const lastLoginAttempt = new Date(user.last_login_attempt);
lastLoginAttempt.setSeconds(
lastLoginAttempt.getSeconds() + user.login_timeout_value
);
if (new Date() < lastLoginAttempt) {
return done(null, false, {
message: "Too many incorrect passwords",
});
}
}
const { hashedPassword } = passwordHasher(password, user.salt);
if (user.password === hashedPassword) {
updateIncorrectPasswordAttempts(username, 0).then(() => {
if (user.password_timeout_value) {
const passwordExpiryDate =
+new Date(user.last_password_set) +
(user.password_timeout_value ?? 0);
if (new Date() > passwordExpiryDate) {
return done(null, false, { message: "Password has expired" });
}
}
return done(null, user, { message: "Login successful" });
});
} else {
const newIncorrectLogins = user.incorrect_logins + 1;
updateIncorrectPasswordAttempts(username, newIncorrectLogins).then(
() =>
done(null, false, {
message: "Incorrect username or password",
})
);
}
});
});
})
);
passport.use(
new JWTStrategy(
{
jwtFromRequest: ExtractJWT.fromAuthHeaderAsBearerToken(),
secretOrKey: process.env.JWT_SECRET,
},
(jwtPayload, cb) => {
return db
.query(`SELECT account_locked FROM users WHERE username=$1;`, [
jwtPayload.username,
])
.then(({ rows, rowCount }) => {
if (!rowCount) {
return cb(null, false, { message: "Account no longer exists" });
}
const user = rows[0];
if (user.account_locked) {
return cb(null, false, { message: "Account locked" });
}
return cb(null, jwtPayload);
});
}
)
);
const passwordHasher = (
password,
salt = crypto.randomBytes(16).toString("hex")
) => {
const hashedPassword = crypto
.pbkdf2Sync(password, salt, 310000, 32, "sha256")
.toString("hex");
return { salt, hashedPassword };
};
module.exports = { passwordHasher };