-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathapp.js
157 lines (138 loc) · 5.28 KB
/
app.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
const express = require('express');
const bodyParser = require('body-parser');
const fs = require('fs');
const https = require('https');
const dotenv = require('dotenv').config();
const sequelize = require('./utilities/database');
const passport = require('passport');
const session = require('express-session');
const crypto = require('crypto');
const LocalStrategy = require('passport-local');
const MySQLStore = require('express-mysql-session')(session);
const { nextTick } = require('process');
// Database credentials (Used for session)
const db_options = {
host: process.env.DB_HOST,
user: process.env.DB_USER,
password: process.env.DB_PASSWORD,
database: process.env.DB_NAME,
};
// Required Models
const User = require('./models/user');
const Project = require('./models/project');
User.hasMany(Project);
Project.belongsTo(User);
// Require routes
const projectRoutes = require('./routes/projects');
// Initialize application
const app = express();
app.use((req, res, next) => {
res.setHeader('Access-Control-Allow-Origin', process.env.APP_URL); // * allows all, or you can limit by domain
res.setHeader('Access-Control-Allow-Methods', '*'); // Set which headers you want to allow
res.setHeader('Access-Control-Allow-Headers', 'Content-Type, Authorization'); // These 2 are recommended
res.setHeader('Access-Control-Expose-Headers', 'Set-Cookie'); // Required to allow the returned cookie to be set
res.setHeader('Access-Control-Allow-Credentials', 'true'); // Required to allow auth credentials
next();
});
// Parse the incoming data for use in middlewares (json format expected)
app.use(bodyParser.json());
app.use(session({
secret: 'keyboard cat',
resave: true,
saveUninitialized: false,
store: new MySQLStore(db_options),
cookie: {
path: "/",
httpOnly: false,
secure: true,
sameSite: 'none',
maxAge: 3600000 // Set cookie to last 1 hour
}
}));
app.use(passport.initialize());
app.use(passport.authenticate('session'));
/* -------------------------------------------------------------------------- */
/* User Serializer */
/* -------------------------------------------------------------------------- */
passport.serializeUser(function (user, cb) {
process.nextTick(function () {
cb(null, { id: user.id, username: user.username, firstname: user.firstname, lastname: user.lastname, email: user.email });
});
});
passport.deserializeUser(function (user, cb) {
process.nextTick(function () {
return cb(null, user);
});
});
// Local Strategy
passport.use(new LocalStrategy((username, password, callback) => {
User.findOne({where: { username: username}}).then(result => {
if (!result) { return callback(null, false, { message: 'Incorrect username or password.' }); }
crypto.pbkdf2(password, result.salt, 310000, 32, 'sha256', function (err, hashedPassword) {
if (err) { return callback(err); }
if (!crypto.timingSafeEqual(result.hashed_password, hashedPassword)) {
return callback(null, false, { message: 'Incorrect username or password.' });
}
return callback(null, result);
});
}).catch(err => nextTick(err));
}));
/* -------------------------------------------------------------------------- */
/* ROUTES */
/* -------------------------------------------------------------------------- */
// Prepare auth check for routes
const auth = function (req, res, next) {
if (req.isAuthenticated()) {
return next();
}
res.status(401).json("not authenticated!");
}
// Route for submitting login
app.post('/login', passport.authenticate('local', { failureRedirect: '/login', failureMessage: true }),
(req, res) => {
const user = {
id: req.user.id,
username: req.user.username,
firstname: req.user.firstname,
lastname: req.user.lastname,
email: req.user.email
};
return res.status(200).json({success: 'true', user: user});
});
// Route for creating a user
app.post('/signup', (req, res, next) => {
const salt = crypto.randomBytes(16);
crypto.pbkdf2(req.body.password, salt, 310000, 32, 'sha256', function (err, hashedPassword) {
if (err) { return next(err); }
User.create({username: req.body.username, hashed_password: hashedPassword, salt: salt, firstname: req.body.firstname, lastname: req.body.lastname, email: req.body.email}).then(result => {
let user = {
id: result.id,
username: result.username,
firstname: result.firstname,
lastname: result.lastname,
email: result.email
};
req.login(user, function (err) {
if (err) { return next(err); }
res.redirect('/home');
});
}).catch(err => console.log(err));
});
});
app.get('/logout', function(req, res, next) {
req.logout(function(err) {
if (err) { return next(err); }
req.session.destroy();
res.status(200).json({message: 'User logged out.'});
});
});
// Define routes
app.use('/projects',projectRoutes);
// Listen for requests
sequelize.sync().then(result => {
const httpsOptions = {
key: fs.readFileSync('key.pem'),
cert: fs.readFileSync('cert.pem')
}
const server = https.createServer(httpsOptions, app).listen(8080);
}).catch(err => console.log(err));