Completed /register and /login routes

This commit is contained in:
Ceferino Patino 2022-03-05 00:25:50 -06:00
commit 089009b7f4
21 changed files with 199 additions and 74 deletions

View file

@ -4,7 +4,8 @@ var path = require('path');
var cookieParser = require('cookie-parser');
var logger = require('morgan');
var apiRouter = require('./routes/index');
var indexRouter = require('./routes/indexRouter');
var authRouter = require('./routes/authRouter');
var app = express();
@ -19,22 +20,12 @@ app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));
app.use('/', express.static(path.join(__dirname, '../client/build')));
app.use('/api', apiRouter);
app.use('/api', indexRouter);
app.use('/api/user', authRouter);
// catch 404 and forward to error handler
app.use(function (req, res, next) {
next(createError(404));
});
// error handler
app.use(function (err, req, res, next) {
// set locals, only providing error in development
res.locals.message = err.message;
res.locals.error = req.app.get('env') === 'development' ? err : {};
// render the error page
res.status(err.status || 500);
res.render('error');
});
module.exports = app;

View file

@ -85,8 +85,10 @@ function onError(error) {
async function onListening() {
initModels(db);
try {
await db.authenticate();
console.log('Connection has been established successfully.');
await db.authenticate({ logging: false });
console.log(
`[INFO]: Database connection to ${process.env.NODE_ENV} has been established successfully.`
);
} catch (error) {
console.error('Unable to connect to the database:', error);
}

View file

@ -1,7 +1,7 @@
var { Sequelize, Options } = require('sequelize');
var configs = require('./config/config.js');
const env = process.env.NODE_ENV || 'development';
const env = process.env.NODE_ENV;
const config = configs[env];
const db = new Sequelize({

View file

@ -0,0 +1,32 @@
const forge = require('node-forge');
const { User } = require('../models/index');
async function basicAuth(req, res, next) {
const email = req.body.email;
const password = req.body.password;
if (!email || !password) {
return res.status(400).send('Request lacking information');
}
const result = await User.findOne({ where: { email: email } });
if (!result) {
return res.status(400).send('Unauthorized user');
}
const hashedPassword = forge.md.sha512
.create()
.update(password)
.digest()
.toHex();
if (hashedPassword === result.password) {
req.user = result;
return next();
} else {
return res.status(400).send('Unauthorized user');
}
}
module.exports = basicAuth;

View file

View file

@ -1,3 +1,4 @@
const { v4: uuidv4 } = require('uuid');
const { DataTypes, Model } = require('sequelize');
class Group extends Model {
@ -7,6 +8,7 @@ class Group extends Model {
groupID: {
type: DataTypes.STRING,
primaryKey: true,
defaultValue: uuidv4,
},
groupName: {
type: DataTypes.STRING,

View file

@ -1,3 +1,4 @@
const { v4: uuidv4 } = require('uuid');
const { DataTypes, Model } = require('sequelize');
class Organization extends Model {
@ -7,6 +8,7 @@ class Organization extends Model {
orgID: {
type: DataTypes.STRING,
primaryKey: true,
defaultValue: uuidv4,
},
orgName: {
type: DataTypes.STRING,

21
server/models/Token.js Normal file
View file

@ -0,0 +1,21 @@
const { v4: uuidv4 } = require('uuid');
const { DataTypes, Model } = require('sequelize');
class Token extends Model {
static initModel(sequelize) {
Token.init(
{
tokenID: {
type: DataTypes.STRING,
primaryKey: true,
defaultValue: uuidv4,
},
},
{ sequelize }
);
return Token;
}
}
module.exports = Token;

View file

@ -1,3 +1,4 @@
const { v4: uuidv4 } = require('uuid');
const { DataTypes, Model } = require('sequelize');
class User extends Model {
@ -7,6 +8,7 @@ class User extends Model {
userID: {
type: DataTypes.STRING,
primaryKey: true,
defaultValue: uuidv4,
},
firstName: {
type: DataTypes.STRING,
@ -21,21 +23,19 @@ class User extends Model {
unique: true,
allowNull: false,
},
prounouns: {
password: {
type: DataTypes.STRING,
allowNull: false,
},
pronouns: {
type: DataTypes.STRING,
},
gender: {
type: DataTypes.STRING,
},
race: {
type: DataTypes.STRING,
},
ethnicity: {
type: DataTypes.STRING,
},
createdAt: {
type: DataTypes.DATE,
},
},
{ sequelize }
);

View file

@ -1,36 +1,52 @@
const User = require('./User');
const Group = require('./Group');
const Organization = require('./Organization');
const Token = require('./Token');
function initModels(sequelize) {
async function initModels(sequelize) {
User.initModel(sequelize);
Organization.initModel(sequelize);
Group.initModel(sequelize);
Token.initModel(sequelize);
User.hasMany(Group, { foreignKey: 'ownerID' });
User.hasMany(Group, { foreignKey: 'ownerID', onDelete: 'CASCADE' });
Group.belongsTo(User, { foreignKey: 'ownerID' });
User.hasOne(Organization, { foreignKey: 'ownerID' });
User.hasOne(Organization, { foreignKey: 'ownerID', onDelete: 'CASCADE' });
Organization.hasOne(Organization, { foreignKey: 'ownerID' });
Organization.hasMany(Group, { foreignKey: 'ownerID' });
Organization.hasMany(Group, { foreignKey: 'ownerID', onDelete: 'CASCADE' });
Group.belongsTo(Organization, { foreignKey: 'orgOwnerID' });
User.belongsToMany(Group, {
through: 'OrganizationUsers',
uniqueKey: 'userID',
User.hasOne(Token, { foreignKey: 'userID', onDelete: 'CASCADE' });
Token.belongsTo(User, { foreignKey: 'userID' });
User.belongsToMany(Organization, {
through: 'orgUsers',
foreignKey: 'userID',
});
Organization.belongsToMany(User, {
through: 'OrganizationUsers',
uniqueKey: 'organizationID',
through: 'orgUsers',
uniqueKey: 'orgID',
});
User.belongsToMany(Group, {
through: 'GroupUsers',
uniqueKey: 'userID',
through: 'groupUsers',
foreignKey: 'userID',
});
Group.belongsToMany(User, {
through: 'GroupUsers',
uniqueKey: 'groupID',
through: 'groupUsers',
foreignKey: 'groupID',
});
return { User, Group, Organization };
if (process.env.NODE_ENV == 'development') {
await sequelize.sync({ logging: false, force: true });
} else {
await sequelize.sync({ logging: false, alter: true });
}
return { User, Group, Organization, Token };
}
module.exports = { User, Organization, Group, initModels };
module.exports = { User, Organization, Group, Token, initModels };

View file

@ -15,9 +15,11 @@
"jade": "^0.29.0",
"morgan": "~1.9.1",
"mysql2": "^2.3.3",
"node-forge": "^1.2.1",
"nodemon": "^2.0.15",
"sequelize": "^6.17.0",
"sqlite3": "^5.0.2"
"sqlite3": "^5.0.2",
"uuid": "^8.3.2"
}
},
"node_modules/@sindresorhus/is": {
@ -1817,6 +1819,14 @@
"resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-3.2.1.tgz",
"integrity": "sha512-mmcei9JghVNDYydghQmeDX8KoAm0FAiYyIcUt/N4nhyAipB17pllZQDOJD2fotxABnt4Mdz+dKTO7eftLg4d0A=="
},
"node_modules/node-forge": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.2.1.tgz",
"integrity": "sha512-Fcvtbb+zBcZXbTTVwqGA5W+MKBj56UjVRevvchv5XrcyXbmNdesfZL37nlcWOfpgHhgmxApw3tQbTr4CqNmX4w==",
"engines": {
"node": ">= 6.13.0"
}
},
"node_modules/node-gyp": {
"version": "3.8.0",
"resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-3.8.0.tgz",
@ -4560,6 +4570,11 @@
"resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-3.2.1.tgz",
"integrity": "sha512-mmcei9JghVNDYydghQmeDX8KoAm0FAiYyIcUt/N4nhyAipB17pllZQDOJD2fotxABnt4Mdz+dKTO7eftLg4d0A=="
},
"node-forge": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.2.1.tgz",
"integrity": "sha512-Fcvtbb+zBcZXbTTVwqGA5W+MKBj56UjVRevvchv5XrcyXbmNdesfZL37nlcWOfpgHhgmxApw3tQbTr4CqNmX4w=="
},
"node-gyp": {
"version": "3.8.0",
"resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-3.8.0.tgz",

View file

@ -13,8 +13,10 @@
"jade": "^0.29.0",
"morgan": "~1.9.1",
"mysql2": "^2.3.3",
"node-forge": "^1.2.1",
"nodemon": "^2.0.15",
"sequelize": "^6.17.0",
"sqlite3": "^5.0.2"
"sqlite3": "^5.0.2",
"uuid": "^8.3.2"
}
}

View file

@ -1,8 +0,0 @@
body {
padding: 50px;
font: 14px "Lucida Grande", Helvetica, Arial, sans-serif;
}
a {
color: #00B7FF;
}

View file

@ -0,0 +1,38 @@
const forge = require('node-forge');
const { User } = require('../../models/index');
async function CreateUser(req, res, next) {
const body = req.body;
if (!body.firstName || !body.lastName || !body.email || !body.password) {
console.log(body);
return res.status(400).send('The request is missing required fields.');
}
const existingUsers = await User.findAll({
where: {
email: req.body.email,
},
});
if (existingUsers.length !== 0) {
return res.status(500).send('A user with that email already exists.');
}
try {
const passwordHash = forge.md.sha512
.create()
.update(body.password)
.digest()
.toHex();
const result = await User.create({ ...body, password: passwordHash });
return res.send(result);
} catch (e) {
console.log(e);
return res.status(500).send('Whoops, something went wrong!');
}
}
module.exports = CreateUser;

View file

@ -0,0 +1,17 @@
const forge = require('node-forge');
const { Token } = require('../../models/index');
async function Login(req, res, next) {
const token = forge.md.sha512
.create()
.update(`${new Date()}${req.user.email}`)
.digest()
.toHex();
await Token.destroy({ where: { userID: req.user.userID } });
const newToken = await Token.create({ userID: req.user.userID });
res.send(newToken.tokenID);
}
module.exports = Login;

View file

@ -0,0 +1,20 @@
var express = require('express');
var router = express.Router();
const basicAuth = require('../middleware/basicAuth');
const CreateUser = require('./auth/CreateUser');
const Login = require('./auth/Login');
router.post('/register', CreateUser);
router.post('/login', basicAuth, Login);
/*
User
- Change password
- User Login
- User Profile
- Modify user profile
*/
module.exports = router;

View file

@ -3,17 +3,10 @@ var router = express.Router();
/* GET home page. */
router.get('/', (req, res, next) => {
res.render('index', { title: 'Express' });
return res.render('index', { title: 'Express' });
});
/*
User
- Create user
- Change password
- User Login
- User Profile
- Modify user profile
/*
Organization
- Create organization
- Create organization account

View file

@ -1,6 +0,0 @@
extends layout
block content
h1= message
h2= error.status
pre #{error.stack}

View file

@ -1,5 +0,0 @@
extends layout
block content
h1= title
p Welcome to #{title}

View file

@ -1,7 +0,0 @@
doctype html
html
head
title= title
link(rel='stylesheet', href='/stylesheets/style.css')
body
block content

Binary file not shown.