Completed /register and /login routes
This commit is contained in:
parent
07c0d955e4
commit
089009b7f4
21 changed files with 199 additions and 74 deletions
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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({
|
||||
|
|
|
|||
32
server/middleware/basicAuth.js
Normal file
32
server/middleware/basicAuth.js
Normal 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;
|
||||
0
server/middleware/tokenAuth.js
Normal file
0
server/middleware/tokenAuth.js
Normal 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,
|
||||
|
|
|
|||
|
|
@ -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
21
server/models/Token.js
Normal 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;
|
||||
|
|
@ -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 }
|
||||
);
|
||||
|
|
|
|||
|
|
@ -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 };
|
||||
|
|
|
|||
17
server/package-lock.json
generated
17
server/package-lock.json
generated
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,8 +0,0 @@
|
|||
body {
|
||||
padding: 50px;
|
||||
font: 14px "Lucida Grande", Helvetica, Arial, sans-serif;
|
||||
}
|
||||
|
||||
a {
|
||||
color: #00B7FF;
|
||||
}
|
||||
38
server/routes/auth/CreateUser.js
Normal file
38
server/routes/auth/CreateUser.js
Normal 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;
|
||||
17
server/routes/auth/Login.js
Normal file
17
server/routes/auth/Login.js
Normal 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;
|
||||
20
server/routes/authRouter.js
Normal file
20
server/routes/authRouter.js
Normal 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;
|
||||
|
|
@ -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
|
||||
|
|
@ -1,6 +0,0 @@
|
|||
extends layout
|
||||
|
||||
block content
|
||||
h1= message
|
||||
h2= error.status
|
||||
pre #{error.stack}
|
||||
|
|
@ -1,5 +0,0 @@
|
|||
extends layout
|
||||
|
||||
block content
|
||||
h1= title
|
||||
p Welcome to #{title}
|
||||
|
|
@ -1,7 +0,0 @@
|
|||
doctype html
|
||||
html
|
||||
head
|
||||
title= title
|
||||
link(rel='stylesheet', href='/stylesheets/style.css')
|
||||
body
|
||||
block content
|
||||
BIN
test_db.sqlite
BIN
test_db.sqlite
Binary file not shown.
Reference in a new issue