Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 15 additions & 18 deletions server/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,7 @@ require('dotenv').config();

const express = require('express');
const cors = require('cors');
const cookieParser = require('cookie-parser');
const session = require('express-session');
const passport = require('passport');
const auth = require('./auth');
const session = require('express-session')
const fs = require('fs');
const https = require('https');
const http = require('http');
Expand All @@ -21,19 +18,6 @@ app.use(express.urlencoded({

app.use(express.json());

app.use(passport.initialize());
app.use(session({
name: 'session',
secret: process.env.KEY,
resave: false,
saveUninitialized: true,
}));
app.use(passport.authenticate('session'));
auth(passport);


app.use(cookieParser());

app.use(cors({
origin: function (origin, callback) {
if (allowedOrigins.indexOf(origin) !== -1) {
Expand All @@ -44,6 +28,20 @@ app.use(cors({
},
credentials: true,
}));
app.use(session({
secret: process.env.KEY,
resave: false,
saveUninitialized: true,
cookie: function(req) {
var match = req.url.match(/^\/([^/]+)/);
return {
path: match ? '/' + match[1] : '/',
httpOnly: true,
secure: req.secure || false,
maxAge: 60000
}
}
}));

app.use(require('./routes'));

Expand All @@ -67,5 +65,4 @@ if (fs.existsSync(private_key, fs.R_OK) && fs.existsSync(certificate, fs.R_OK))
server = http.createServer(app);
}


server.listen(port, () => console.log(`Listening on port ${port}!`));
59 changes: 36 additions & 23 deletions server/auth.js
Original file line number Diff line number Diff line change
@@ -1,29 +1,42 @@
// let GoogleStrategy = require('passport-google-oauth').OAuth2Strategy;
const GoogleStrategy = require('passport-google-oauth20').Strategy;
const { google } = require('googleapis');
const jwt = require('jsonwebtoken');

module.exports = (passport) => {
passport.serializeUser((user, done) => {
done(null, user);
});
const oauth2Client = new google.auth.OAuth2(
process.env.GOOGLE_CLIENT_ID,
process.env.GOOGLE_SECRET,
process.env.GOOGLE_CALLBACK_URL,
);

passport.deserializeUser((user, done) => {
done(null, user);
});
const scopes = [
'profile',
'email'
];

const authMiddleware = async (req, res, next) => {
const authHeader = req.get('Authorization');
if (!authHeader || !authHeader.startsWith('Bearer ')) {
res.status(400).json({ error: 'Token missing or malformed.' });
return;
}

const token = authHeader.substring(7);

passport.use(new GoogleStrategy({
clientID: process.env.GOOGLE_CLIENT_ID,
clientSecret: process.env.GOOGLE_SECRET,
callbackURL: process.env.GOOGLE_CALLBACK_URL,
passReqToCallback: true,
},
async (request, accessToken, refreshToken, profile, done) => {
try {
return done(null, {
profile: profile,
token: accessToken,
});
} catch (error) {
return done(error, null);
const verifiedToken = jwt.verify(token, process.env.KEY, {
algorithms: ['HS256'],
issuer: 'all.rit.edu'
});
req.userId = verifiedToken.sub;
next();
} catch {
res.status(401).json({ error: 'Unable to verify token.' });
return;
}
}));
};

module.exports = {
oauth2Client,
scopes,
authMiddleware
};

84 changes: 84 additions & 0 deletions server/controllers/AuthController.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
const db = require('../database');
const crypto = require('crypto');
const { oauth2Client, scopes } = require('../auth');
const jwt = require('jsonwebtoken');

const google = (req, res) => {
const state = crypto.randomBytes(32).toString('hex');
req.session.state = state;

const authorizationUrl = oauth2Client.generateAuthUrl({
access_type: 'offline',
scope: scopes,
include_granted_scopes: true,
state: state,
});

res.redirect(authorizationUrl)
};

const googleCallback = async (req, res) => {
if (req.query.error) {
res.status(400).json({ error: 'Error during Google consent screen authorization.' });
return;
}

if (req.query.state !== req.session.state) {
res.status(400).json({ error: 'Invalid state parameter. Aborting due to possible CSRF attack.' });
return;
}

let ticket;
try {
let { tokens } = await oauth2Client.getToken(req.query.code);

ticket = await oauth2Client.verifyIdToken({
idToken: tokens.id_token,
audience: oauth2Client._clientId,
});
} catch {
res.status(500).json({ error: 'Failed to exchange provided code for Google token.' });
}

let user = await db.Users.findOne({
where: {
googleAccountId: ticket.getUserId()
}
});

if (!user) {
user = await db.Users.create({
googleAccountId: ticket.getUserId(),
email: ticket.getPayload().email,
firstName: ticket.getPayload().given_name,
lastInitial: ticket.getPayload().family_name ? ticket.getPayload().family_name.charAt(0) : null,
pfp: ticket.getPayload().picture,
});
}

const iat = Math.floor(Date.now() / 1000);
const token = jwt.sign({
iss: 'all.rit.edu',
sub: user.id,
aud: user.id,
exp: iat + (60 * 60 * 24), // Token valid for 1 day
nbf: iat,
iat: iat,
googleAccountId: user.googleAccountId,
email: user.email,
firstName: user.firstName,
lastInitial: user.lastInitial,
pfp: user.pfp
}, process.env.KEY, {
algorithm: 'HS256'
});

return res.status(200).json({
token: token
});
};

module.exports = {
google,
googleCallback
}
119 changes: 62 additions & 57 deletions server/controllers/GroupController.js
Original file line number Diff line number Diff line change
@@ -1,38 +1,55 @@
const GroupService = require('../services/GroupService');

const getGroupLabs = async (req, res) => {
const createGroup = async (req, res) => {
try {
const data = await GroupService.getGroupLabs(req.params.groupID);
const data = await GroupService.createGroup(
req.userId,
req.body.groupName,
req.body.color,
);
res.status(200).json(data);
} catch (error) {
console.error('Error while fetching group labs', error);
res.status(500).json({ message: error.message });
console.error('Error while creating group', error);
res.status(500).json({ error: error.message });
}
};

const getGroupEnrolledStudents = async (req, res) => {
const updateGroup = async (req, res) => {
try {
const data = await GroupService.getGroupEnrolledStudents(req.params.groupID);
res.status(200).json(data);
const result = await GroupService.updateGroup(
req.params.groupId,
req.userId,
req.body.groupName,
req.body.groupColor,
);
if (result.status === 'failure') {
res.status(403).json(result);
} else {
res.status(200).send('Group name/color successfully updated!');
}
} catch (error) {
console.error('Error while getting students group', error);
res.status(500).json({ message: error.message });
console.error('Error in updating groupName:', error);
res.status(500).json({ error: error.message });
}
};

const getCompletedGroupLabs = async (req, res) => {
const deleteGroup = async (req, res) => {
try {
const data = await GroupService.getCompletedGroupLabs(req.params.userID, req.params.groupID);
res.status(200).json(data);
const result = await GroupService.deleteGroup(
req.params.groupId,
req.userId
);
res.status(result.status === 'failure' ? 403 : 200).json(result);
} catch (error) {
console.error('Error while getting completed group labs', error);
res.status(500).json({ message: error.message });
console.error('Error while deleting group:', error);
res.status(500).json({ error: error.message });
}
};


const enrollUserInGroup = (req, res) => {
GroupService.enrollUserInGroup(
req.body.userID,
req.userId,
req.body.inviteCode,
).then((response) => {
// todo: figure out how to send status code along with message,
Expand All @@ -52,87 +69,75 @@ const enrollUserInGroup = (req, res) => {
};

const unenrollUserFromGroup = (req, res) => {
GroupService.unenrollUserFromGroup({
userID: req.body.userID,
groupID: req.body.groupID,
}).then(() => {
GroupService.unenrollUserFromGroup(req.userId, req.params.groupId).then(() => {
res.sendStatus(200);
});
};

const createGroup = async (req, res) => {
const addGroupLab = async (req, res) => {
try {
const data = await GroupService.createGroup(
req.body.userID,
req.body.groupName,
req.body.color,
const groupLab = await GroupService.addGroupLab(
req.params.groupId,
req.userId,
req.body.labId,
);
res.status(200).json(data);
res.status(groupLab.status === 'failure' ? 403 : 200).json(groupLab);
} catch (error) {
console.error('Error while creating group', error);
console.error('Error while adding lab to group', error);
res.status(500).json({ error: error.message });
}
};

const addGroupLab = async (req, res) => {
const getGroupLabs = async (req, res) => {
try {
const lab = await GroupService.addGroupLab(
req.body.groupID,
req.body.labID,
);
res.status(200).json(lab);
const data = await GroupService.getGroupLabs(req.params.groupID);
res.status(200).json(data);
} catch (error) {
console.error('Error while adding lab to group', error);
res.status(500).json({ error: error.message });
console.error('Error while fetching group labs', error);
res.status(500).json({ message: error.message });
}
};

const deleteGroupLab = async (req, res) => {
const getGroupEnrolledStudents = async (req, res) => {
try {
await GroupService.deleteGroupLab(
req.body.groupID,
req.body.labID,
);
res.status(200).send('Lab successfully deleted!');
const data = await GroupService.getGroupEnrolledStudents(req.params.groupID);
res.status(200).json(data);
} catch (error) {
res.status(500).json({ error: error.message });
console.error('Error while getting students group', error);
res.status(500).json({ message: error.message });
}
};

const deleteGroup = async (req, res) => {
const getCompletedGroupLabs = async (req, res) => {
try {
const data = await GroupService.deleteGroup(
req.body.groupID,
);
const data = await GroupService.getCompletedGroupLabs(req.params.userID, req.params.groupID);
res.status(200).json(data);
} catch (error) {
console.error('Error while deleting group:', error);
res.status(500).json({ error: error.message });
console.error('Error while getting completed group labs', error);
res.status(500).json({ message: error.message });
}
};

const updateGroup = async (req, res) => {
const deleteGroupLab = async (req, res) => {
try {
await GroupService.updateGroup(
await GroupService.deleteGroupLab(
req.body.groupID,
req.body.groupName,
req.body.groupColor,
req.body.labID,
);
res.status(200).send('Group name successfully updated!');
res.status(200).send('Lab successfully deleted!');
} catch (error) {
console.error('Error in updating groupName:', error);
res.status(500).json({ error: error.message });
}
};

module.exports = {
createGroup,
updateGroup,
enrollUserInGroup,
unenrollUserFromGroup,
addGroupLab,
deleteGroup,
deleteGroupLab,
addGroupLab,
createGroup,
unenrollUserFromGroup,
enrollUserInGroup,
getCompletedGroupLabs,
getGroupEnrolledStudents,
getGroupLabs,
Expand Down
Loading
Loading