setting up auth system

This commit is contained in:
Mikayla Dobson
2023-01-31 19:06:15 -06:00
parent cfe4898ec9
commit 4c3a31c77f
12 changed files with 303 additions and 14 deletions

View File

@@ -0,0 +1,91 @@
const bcrypt = require('bcrypt');
const ControllerResponse = require('./ControllerResponse');
const User = require('../models/User');
module.exports = class AuthController {
static async getOne(id) {
const user = await User.getOne(id);
const ok = user !== null;
const data = ok ? user : ("No user found with id " + id);
const code = ok ? 200 : 404;
return new ControllerResponse(ok, data, code);
}
static async getOneByEmail(email) {
const user = await User.getOneByEmail(email);
const ok = user !== null;
const data = ok ? user : ("No user found with email" + email);
const code = ok ? 200 : 404;
return new ControllerResponse(ok, data, code);
}
static async getAll() {
const list = await User.getAll();
const ok = list.length > 0;
const data = ok ? list : "No user data found";
const code = ok ? 200 : 404;
return new ControllerResponse(ok, data, code);
}
static async create() {
}
/**
*
* @param {{ email: string, password: string }} userData - data to compare against encrypted DB entry
* @returns { ControllerResponse | null } controller response, or null failing all else
*/
static async login(userData) {
try {
const potentialUser = await AuthController.getOneByEmail(userData.email);
if (potentialUser.ok) {
const match = await bcrypt.compare(userData.password, potentialUser.data.password);
return new ControllerResponse(match, (match ? potentialUser : "Invalid credentials"), (match ? 200 : 403));
} else {
return new ControllerResponse(false, "No user found with these credentials", 404);
}
} catch (error) {
console.log(error);
}
return null;
}
static async logout() {
}
/**
* ## Register method
*
* @param {{ username: string, password: string, email: string }} data - provided user data
* @returns { ControllerResponse } controller response including status codes
*/
static async register(userData) {
try {
const potentialUser = await AuthController.getOneByEmail(userData.email);
if (potentialUser.ok) {
return new ControllerResponse(false, ("User already registered with email " + userData.email), 401);
}
const salt = await bcrypt.genSalt(12);
const hash = await bcrypt.hash(userData.password, salt);
const newUser = new User(userData.username, userData.email, hash);
const result = await User.create(newUser);
return new ControllerResponse(result.rows.length > 0, result, (result.rows.length > 0 ? 201 : 400));
} catch (error) {
console.log(error);
}
}
}

View File

@@ -0,0 +1,11 @@
module.exports = class ControllerResponse {
ok;
data;
code;
constructor(ok, data, code) {
this.ok = ok;
this.data = data;
this.code = code;
}
}

View File

@@ -0,0 +1,24 @@
const Item = require('../models/Item');
const ControllerResponse = require('./ControllerResponse');
module.exports = class ItemController {
static async getAll() {
const result = await Item.getAll();
const ok = result !== null;
const code = ok ? 200 : 404;
const data = ok ? result : "No items found";
return new ControllerResponse(ok, data, code);
}
static async getOne(id) {
const result = await Item.getOne(id);
const ok = result !== null;
const code = ok ? 200 : 404;
const data = ok ? result : ("No item found with ID " + id);
return new ControllerResponse(ok, data, code);
}
}

View File

@@ -9,6 +9,9 @@ const root = path.resolve(__dirname);
async function seed() {
console.clear();
await pool.query(`DROP TABLE IF EXISTS item`);
await pool.query(`DROP TABLE IF EXISTS appuser`);
const createUserTable = fs.readFileSync(root + "/sql/create/createUserTable.sql").toString();
const createItemTable = fs.readFileSync(root + "/sql/create/createItemTable.sql").toString();
const populateItemTable = fs.readFileSync(root + "/sql/populate/populateItemTable.sql").toString();

View File

@@ -3,6 +3,6 @@ CREATE TABLE IF NOT EXISTS appuser (
username VARCHAR NOT NULL,
email VARCHAR UNIQUE,
password VARCHAR NOT NULL,
created VARCHAR NOT NULL,
modified VARCHAR NOT NULL
created TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
modified TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP
);

View File

@@ -1,5 +1,6 @@
const passport = require('passport');
const { Strategy } = require('passport-local');
const AuthController = require('../controllers/authController');
async function passportLoader(app) {
app.use(passport.initialize());
@@ -13,13 +14,20 @@ async function passportLoader(app) {
done(null, user);
})
passport.use(new Strategy(async (email, password, done) => {
passport.use(new Strategy({ usernameField: "email", passwordField: "password" }, async (email, password, done) => {
try {
console.log(email, password);
const response = await AuthController.login({ email: email, password: password });
if (response && response.ok) {
return done(null, response.data.data);
} else {
return done(null, false);
}
} catch (error) {
return done(error);
}
}))
return passport;
}
module.exports = passportLoader;

View File

@@ -1,4 +1,6 @@
class Item {
const pool = require('../db');
module.exports = class Item {
name;
description;
created;
@@ -12,7 +14,23 @@ class Item {
this.modified = new Date(Date.now()).toDateString();
}
async getAll() {
static async getAll() {
const query = `SELECT * FROM item;`
const result = await pool.query(query);
if (result.rows.length) {
return result.rows;
}
return null;
}
static async getOne(id) {
const query = `SELECT * FROM item WHERE id = $1`;
const result = await pool.query(query, [id]);
if (result.rows.length) {
return result.rows[0];
}
return null;
}
}

View File

@@ -1,3 +1,5 @@
const pool = require('../db');
module.exports = class User {
username;
email;
@@ -12,4 +14,64 @@ module.exports = class User {
this.created = new Date(Date.now()).toDateString();
this.modified = new Date(Date.now()).toDateString();
}
presentAsArray() {
return [this.username, this.email, this.password];
}
static async getOne(id) {
const query = `SELECT * FROM appuser WHERE id = $1`;
const result = await pool.query(query, [id]);
if (result.rows.length) {
return result.rows[0];
}
return null;
}
static async getOneByEmail(email) {
const query = `SELECT * FROM appuser WHERE email = $1`;
const result = await pool.query(query, [email]);
if (result.rows.length) {
return result.rows[0];
}
return null;
}
static async getAll() {
const query = `SELECT * FROM appuser;`;
const result = await pool.query(query);
if (result.rows.length) {
return result.rows;
}
return null;
}
static async create(data) {
let result;
const query = `INSERT INTO appuser (username, email, password) VALUES ($1, $2, $3) RETURNING *`;
if (!data instanceof User) {
const newUser = new User(data.username, data.email, data.password);
result = await pool.query(query, newUser.presentAsArray());
} else {
result = await pool.query(query, data.presentAsArray());
}
return result.rows;
}
static async login() {
}
static async logout() {
}
static async register() {
}
}

View File

@@ -18,7 +18,7 @@
"dotenv": "^16.0.3",
"express": "^4.18.2",
"express-session": "^1.17.3",
"passport": "^0.6.0",
"passport": "^0.4.0",
"passport-local": "^1.0.0",
"pg": "^8.9.0"
},

View File

@@ -1,5 +1,55 @@
function authRoute(app, passport) {
const AuthController = require('../controllers/authController');
const router = require('express').Router();
async function authRoute(app, passport) {
router.post('/register', async (req, res) => {
try {
const data = req.body;
const response = await AuthController.register(data);
res.status(response.code).send(response.data);
} catch (error) {
console.log(error);
}
})
router.post('/login', async (req, res, next) => {
try {
const data = req.body;
const response = await AuthController.login(data);
if (!response || !response.ok) {
res.status(response.code || 400).send(response.data || "Something went wrong");
} else {
req.session.user = response.data;
req.session.save((err) => {
return next(err);
})
res.send(response.data);
}
} catch (error) {
next(error);
}
})
router.delete('/logout', async (req, res, next) => {
try {
req.session.destroy((err) => {
if (err) throw err;
req.logout((err) => {
if (err) return next(err);
})
})
res.status(204).send({ ok: true });
} catch (error) {
next(error);
}
})
return router;
}
module.exports = authRoute;

View File

@@ -1,5 +1,16 @@
async function routesLoader(app, passport) {
const authRoute = require("./auth");
const itemRoute = require("./item");
async function routesLoader(app, passport) {
const authRouter = await authRoute(app, passport);
const itemRouter = await itemRoute(app, passport);
app.get('/', (req, res) => {
res.send(req.session);
})
app.use('/auth', authRouter);
app.use('/app', passport.authenticate('local'), itemRouter);
}
module.exports = routesLoader;

View File

@@ -1,9 +1,20 @@
const router = require('express').Router();
const ItemController = require('../controllers/ItemController');
function itemRoute(app, passport) {
app.use('/app/items', router);
router.get('/', (req, res) => {
res.status(200).send('items');
router.get('/item', async (req, res) => {
const response = await ItemController.getAll();
const { data, code } = response;
res.status(code).send(data);
})
}
router.get('/item/:id', async (req, res) => {
const { id } = req.params;
const { data, code } = await ItemController.getOne(id);
res.status(code).send(data);
})
return router;
}
module.exports = itemRoute;