Skip to content

Commit f1d4074

Browse files
committed
github oauth almost complete, reorganize code for better structure
1 parent a12c2e6 commit f1d4074

File tree

13 files changed

+245
-101
lines changed

13 files changed

+245
-101
lines changed

main.js

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -94,8 +94,9 @@ const createWindow = () => {
9494
webPreferences: {
9595
zoomFactor: 0.7
9696
// for proper security measures, nodeIntegration should be set to false, but this results in a blank page when serving app
97-
//nodeIntegration: false,
98-
//preload: 'preload.js'
97+
// nodeIntegration: false,
98+
// preload: 'preload.js',
99+
// enableRemoteModule: false
99100
},
100101
show: false,
101102
icon: path.join(__dirname, '/src/public/icons/png/256x256.png'),

package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,8 @@
143143
"localforage": "^1.7.2",
144144
"lodash.throttle": "^4.1.1",
145145
"material-table": "^1.57.2",
146+
"passport": "^0.4.1",
147+
"passport-github2": "^0.1.12",
146148
"prettier": "^1.19.1",
147149
"prismjs": "^1.19.0",
148150
"prop-types": "^15.6.2",

server/controllers/cookieController.js

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,11 @@ const cookieController = {};
33
// setSSIDCookie - store the user id from database in cookie
44
cookieController.setSSIDCookie = (req, res, next) => {
55
// set cookie with key 'ssid' and value to user's id, also set http only
6+
console.log('Inside setSSIDCookie');
7+
68
res.cookie('ssid', res.locals.id, { maxAge: 3600000 });
7-
console.log('Successful setSSIDCookie');
9+
10+
console.log('Successful setSSIDCookie, ssid:', res.locals.id);
811
return next();
912
};
1013

server/controllers/sessionController.js

Lines changed: 41 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
1-
const Session = require('../models/sessionModel');
1+
const { Sessions } = require('../models/reactypeModels');
22
const sessionController = {};
33

44
// isLoggedIn finds appropriate session for this request in database, then verifies whether or not the session is still valid
55
sessionController.isLoggedIn = (req, res, next) => {
66
// find session from request session ID in mongodb
7-
Session.findOne({ cookieId: req.cookies.ssid }, (err, session) => {
7+
Sessions.findOne({ cookieId: req.cookies.ssid }, (err, session) => {
88
if (err) {
99
return next({
1010
log: `Error in sessionController.isLoggedIn: ${err}`,
@@ -26,7 +26,7 @@ sessionController.isLoggedIn = (req, res, next) => {
2626
sessionController.startSession = (req, res, next) => {
2727
console.log('Inside startSession');
2828
// first check if user is logged in already
29-
Session.findOne({ cookieId: res.locals.id }, (err, session) => {
29+
Sessions.findOne({ cookieId: res.locals.id }, (err, session) => {
3030
if (err) {
3131
return next({
3232
log: `Error in sessionController.startSession find session: ${err}`,
@@ -37,7 +37,7 @@ sessionController.startSession = (req, res, next) => {
3737
// if session doesn't exist, create a session
3838
// if valid user logged in/signed up, res.locals.id should be user's id generated from mongodb, which we will set as this session's cookieId
3939
} else if (!session) {
40-
Session.create({ cookieId: res.locals.id }, (err, session) => {
40+
Sessions.create({ cookieId: res.locals.id }, (err, session) => {
4141
if (err) {
4242
return next({
4343
log: `Error in sessionController.startSession create session: ${err}`,
@@ -59,4 +59,41 @@ sessionController.startSession = (req, res, next) => {
5959
}
6060
});
6161
};
62+
63+
// creates a session when logging in with github
64+
sessionController.githubSession = (req, res, next) => {
65+
// req.user is passed in from passport js -> serializeuser/deserializeuser
66+
console.log('github session req.user is', req.user);
67+
const cookieId = req.user._id;
68+
Sessions.findOne({ cookieId }, (err, session) => {
69+
if (err) {
70+
return next({
71+
log: `Error in sessionController.githubSession find session: ${err}`,
72+
message: {
73+
err: `Error in sessionController.githubSession find session, check server logs for details`
74+
}
75+
});
76+
} else if (!session) {
77+
Sessions.create({ cookieId }, (err, session) => {
78+
if (err) {
79+
return next({
80+
log: `Error in sessionController.githubSession create session: ${err}`,
81+
message: {
82+
err: `Error in sessionController.githubSession create session, check server logs for details`
83+
}
84+
});
85+
} else {
86+
console.log('Successful start githubSession');
87+
res.locals.id = session.cookieId;
88+
return next();
89+
}
90+
});
91+
} else {
92+
console.log('Github session exists, moving on');
93+
res.locals.id = session.cookieId;
94+
return next();
95+
}
96+
});
97+
};
98+
6299
module.exports = sessionController;

server/controllers/userController.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
// middleware functions create a new user and verify users
22

3-
const Users = require('../models/userModel');
3+
const { Users } = require('../models/reactypeModels');
44

55
const userController = {};
66
const bcrypt = require('bcryptjs');

server/models/reactypeModels.js

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
const mongoose = require('mongoose');
2+
require('dotenv').config();
3+
4+
// connect to mongo db
5+
mongoose
6+
.connect(process.env.MONGO_URI, {
7+
// options for the connect method to parse the URI
8+
useNewUrlParser: true,
9+
useUnifiedTopology: true,
10+
useCreateIndex: true,
11+
// stop deprecation warning for findOneAndUpdate and findOneAndDelete queries
12+
useFindAndModify: false,
13+
// sets the name of the DB that our collections are part of
14+
dbName: 'ReacType'
15+
})
16+
.then(() => console.log('Connected to Mongo DB.'))
17+
.catch(err => console.log(err));
18+
19+
const Schema = mongoose.Schema;
20+
21+
const userSchema = new Schema({
22+
username: { type: String, required: true, unique: true },
23+
email: { type: String, required: false, unique: true },
24+
password: { type: String, required: true },
25+
projects: { type: Array, default: [] }
26+
});
27+
28+
// salt will go through 10 rounds of hashing
29+
const SALT_WORK_FACTOR = 10;
30+
const bcrypt = require('bcryptjs');
31+
32+
// mongoose middleware that will run before the save to collection happens (user gets put into database)
33+
// cannot use arrow function here as context of 'this' is important
34+
userSchema.pre('save', function(next) {
35+
// within this context, 'this' refers to the document (new user) about to be saved, in our case, it should have properties username, password, and projects array
36+
bcrypt.hash(this.password, SALT_WORK_FACTOR, (err, hash) => {
37+
if (err) {
38+
return next({
39+
log: `bcrypt password hashing error: ${err}`,
40+
message: {
41+
err: `bcrypt hash error: check server logs for details`
42+
}
43+
});
44+
}
45+
this.password = hash;
46+
return next();
47+
});
48+
});
49+
50+
const sessionSchema = new Schema({
51+
cookieId: { type: String, required: true, unique: true },
52+
createdAt: { type: Date, expires: 3600, default: Date.now }
53+
});
54+
55+
const Users = mongoose.model('Users', userSchema);
56+
const Sessions = mongoose.model('Sessions', sessionSchema);
57+
58+
module.exports = { Users, Sessions };

server/models/sessionModel.js

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
1-
const mongoose = require('mongoose');
2-
const Schema = mongoose.Schema;
1+
// const mongoose = require('mongoose');
2+
// const Schema = mongoose.Schema;
33

4-
// Mongo has an automatic document expiration service that we can use via the 'expires' property in the schema. This sets it so each session can only last an hour
5-
const sessionSchema = new Schema({
6-
cookieId: { type: String, required: true, unique: true },
7-
createdAt: { type: Date, expires: 3600, default: Date.now }
8-
});
4+
// // Mongo has an automatic document expiration service that we can use via the 'expires' property in the schema. This sets it so each session can only last an hour
5+
// const sessionSchema = new Schema({
6+
// cookieId: { type: String, required: true, unique: true },
7+
// createdAt: { type: Date, expires: 3600, default: Date.now }
8+
// });
99

10-
module.exports = mongoose.model('Sessions', sessionSchema);
10+
// module.exports = mongoose.model('Sessions', sessionSchema);

server/models/userModel.js

Lines changed: 30 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,35 @@
1-
const mongoose = require('mongoose');
2-
require('dotenv').config();
1+
// const mongoose = require('mongoose');
2+
// require('dotenv').config();
33

4-
const Schema = mongoose.Schema;
4+
// const Schema = mongoose.Schema;
55

6-
const userSchema = new Schema({
7-
username: { type: String, required: true, unique: true },
8-
email: { type: String, required: true, unique: true },
9-
password: { type: String, required: true },
10-
projects: Array
11-
});
6+
// const userSchema = new Schema({
7+
// username: { type: String, required: true, unique: true },
8+
// email: { type: String, required: false, unique: true },
9+
// password: { type: String, required: true },
10+
// projects: Array
11+
// });
1212

13-
// salt will go through 10 rounds of hashing
14-
const SALT_WORK_FACTOR = 10;
15-
const bcrypt = require('bcryptjs');
13+
// // salt will go through 10 rounds of hashing
14+
// const SALT_WORK_FACTOR = 10;
15+
// const bcrypt = require('bcryptjs');
1616

17-
// mongoose middleware that will run before the save to collection happens (user gets put into database)
18-
// cannot use arrow function here as context of 'this' is important
19-
userSchema.pre('save', function(next) {
20-
// within this context, 'this' refers to the document (new user) about to be saved, in our case, it should have properties username, password, and projects array
21-
bcrypt.hash(this.password, SALT_WORK_FACTOR, (err, hash) => {
22-
if (err) {
23-
return next({
24-
log: `bcrypt password hashing error: ${err}`,
25-
message: {
26-
err: `bcrypt hash error: check server logs for details`
27-
}
28-
});
29-
}
30-
this.password = hash;
31-
return next();
32-
});
33-
});
17+
// // mongoose middleware that will run before the save to collection happens (user gets put into database)
18+
// // cannot use arrow function here as context of 'this' is important
19+
// userSchema.pre('save', function(next) {
20+
// // within this context, 'this' refers to the document (new user) about to be saved, in our case, it should have properties username, password, and projects array
21+
// bcrypt.hash(this.password, SALT_WORK_FACTOR, (err, hash) => {
22+
// if (err) {
23+
// return next({
24+
// log: `bcrypt password hashing error: ${err}`,
25+
// message: {
26+
// err: `bcrypt hash error: check server logs for details`
27+
// }
28+
// });
29+
// }
30+
// this.password = hash;
31+
// return next();
32+
// });
33+
// });
3434

35-
module.exports = mongoose.model('Users', userSchema);
35+
// module.exports = mongoose.model('Users', userSchema);

server/passport-setup.js

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
const passport = require('passport');
2+
const githubStrategy = require('passport-github2').Strategy;
3+
const { Users } = require('./models/reactypeModels');
4+
5+
passport.serializeUser((user, done) => {
6+
/*
7+
From the user take just the id (to minimize the cookie size) and just pass the id of the user
8+
to the done callback
9+
PS: You dont have to do it like this its just usually done like this
10+
*/
11+
done(null, user);
12+
});
13+
14+
passport.deserializeUser((user, done) => {
15+
/*
16+
Instead of user this function usually recives the id
17+
then you use the id to select the user from the db and pass the user obj to the done callback
18+
PS: You can later access this data in any routes in: req.user
19+
PS: For this project, the entire user was passed
20+
*/
21+
done(null, user);
22+
});
23+
24+
passport.use(
25+
new githubStrategy(
26+
{
27+
clientID: process.env.GITHUB_ID,
28+
clientSecret: process.env.GITHUB_SECRET,
29+
callbackURL: 'https://localhost:8080/github/callback',
30+
scope: ['user:email']
31+
},
32+
(accessToken, refreshToken, profile, next) => {
33+
const { username } = profile;
34+
const password = profile._json.node_id;
35+
const email = profile.emails[0].value;
36+
37+
console.log('Username, pw, email are', username, password, email);
38+
// check database to see if user exists
39+
Users.findOne({ username }, (err, user) => {
40+
console.log('Inside find User');
41+
if (!user) {
42+
console.log('User not found, creating new user in DB...');
43+
// if new user, create user account with following variables given to us from github oauth
44+
Users.create(
45+
{
46+
username,
47+
password: profile.id,
48+
email: profile.emails[0].value
49+
},
50+
(err, user) => {
51+
console.log('Creating user from github', user);
52+
return next(err, user);
53+
}
54+
);
55+
} else {
56+
console.log('User already in DB, moving on...');
57+
return next(err, user);
58+
}
59+
});
60+
}
61+
)
62+
);

server/server.js

Lines changed: 24 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,34 @@
11
const express = require('express');
22
const https = require('https');
33
const fs = require('fs');
4-
const mongoose = require('mongoose');
54
const path = require('path');
5+
const passport = require('passport');
6+
require('./passport-setup');
67
const cookieParser = require('cookie-parser');
78
const userController = require('./controllers/userController');
89
const cookieController = require('./controllers/cookieController');
910
const sessionController = require('./controllers/sessionController');
10-
const { session } = require('electron');
1111
const app = express();
12+
1213
const PORT = 8080;
1314

14-
// connect to mongo db
15-
mongoose
16-
.connect(process.env.MONGO_URI, {
17-
// options for the connect method to parse the URI
18-
useNewUrlParser: true,
19-
useUnifiedTopology: true,
20-
useCreateIndex: true,
21-
// stop deprecation warning for findOneAndUpdate and findOneAndDelete queries
22-
useFindAndModify: false,
23-
// sets the name of the DB that our collections are part of
24-
dbName: 'ReacType'
25-
})
26-
.then(() => console.log('Connected to Mongo DB.'))
27-
.catch(err => console.log(err));
15+
// initializes passport and passport sessions
16+
app.use(passport.initialize());
17+
app.use(passport.session());
18+
19+
// routes for initial github oauth and callback
20+
app.get('/github', passport.authenticate('github'));
21+
22+
app.get(
23+
'/github/callback',
24+
passport.authenticate('github', { failureRedirect: '/login' }),
25+
sessionController.githubSession,
26+
cookieController.setSSIDCookie,
27+
(req, res) => {
28+
console.log('At the end of github oauth process');
29+
return res.redirect('/');
30+
}
31+
);
2832

2933
// handle parsing request body
3034
app.use(express.json());
@@ -33,6 +37,10 @@ app.use(cookieParser());
3337

3438
// statically serve everything in build folder
3539
app.use('/', express.static(path.resolve(__dirname, '../build')));
40+
app.use(
41+
'/images',
42+
express.static(path.resolve(__dirname, '..src/public/images'))
43+
);
3644

3745
app.get('/', (req, res) => {
3846
res.status(200).sendFile(path.resolve(__dirname, '../build/index.html'));
@@ -76,10 +84,6 @@ app.get(
7684
}
7785
);
7886

79-
app.get('/github/callback', sessionController.startSession, (req, res) => {
80-
return res.status(200);
81-
});
82-
8387
// catch-all route handler
8488
app.use('*', (req, res) => {
8589
return res.status(404).send('Page not found');

0 commit comments

Comments
 (0)