prototyping passport auth logic

This commit is contained in:
Mikayla Dobson
2022-11-21 10:57:37 -06:00
parent aaf71bc4f7
commit 1b08598799
10 changed files with 427 additions and 534 deletions

53
server/auth/index.ts Normal file
View File

@@ -0,0 +1,53 @@
import { IUser, IUserAuth } from "../schemas";
import { User } from "../models/user";
import createError from "http-errors";
import bcrypt from "bcrypt";
import { QueryResult } from "pg";
const UserInstance = new User();
export default class AuthService {
// methods for local strategies
async register(data: IUser): Promise<Array<keyof IUser>> {
const { email, password } = data;
try {
const user = await UserInstance.getOneByEmail(email);
if (user) throw createError('409', 'Email already in use');
let createdUser: IUser | null = null;
bcrypt.genSalt((err, salt) => {
if (err) throw err;
bcrypt.hash(password, salt, (err, hash) => {
if (err) throw err;
createdUser = {
...data,
password: hash
}
})
})
if (!createdUser) throw createError('400', 'Error creating user');
const result = await UserInstance.post(createdUser);
if (!result) throw createError('400', 'Error creating user');
return result;
} catch (e: any) {
throw new Error(e);
}
}
async login(data: IUserAuth): Promise<Array<keyof IUser>> {
return [];
}
// methods for Google OAuth
async googleRegister() {
}
async googleLogin() {
}
}

13
server/db/sessionStore.ts Normal file
View File

@@ -0,0 +1,13 @@
import connectPgSimple from 'connect-pg-simple';
import session from 'express-session';
import pool from ".";
export default function pgSessionStore(s: typeof session) {
const pgSession = connectPgSimple(s);
return new pgSession({
pool: pool,
tableName: "pgsessions",
createTableIfMissing: true
})
}

View File

@@ -1,7 +1,7 @@
import express from 'express';
import cors from 'cors';
import dotenv from 'dotenv';
dotenv.config({ path: './.env' });
dotenv.config();
import { loaders } from './loaders';

View File

@@ -1,13 +1,27 @@
import { Express } from 'express';
import cors from 'cors';
import bodyParser from 'body-parser';
import morgan from 'morgan';
import cors from 'cors';
import session from 'express-session';
import pgSessionStore from '../db/sessionStore';
export const expressLoader = (app: Express) => {
app.use(cors());
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
// app.use(session({}))
app.use(morgan('tiny'));
app.use(session({
secret: process.env.SESSIONSECRET || "",
cookie: {
maxAge: 8 * 60 * 60 * 1000,
secure: false
},
resave: false,
saveUninitialized: false,
store: pgSessionStore(session)
}))
return app;
}

View File

@@ -0,0 +1,34 @@
import { Strategy as LocalStrategy } from "passport-local";
import passport from "passport";
import { Express } from "express";
import AuthService from "../auth";
import { IUserAuth } from "../schemas";
const AuthInstance = new AuthService();
export const passportApp = (app: Express) => {
app.use(passport.initialize());
app.use(passport.session());
passport.serializeUser((user, done) => {
done(null, user);
})
passport.deserializeUser((user: IUserAuth, done) => {
process.nextTick(async () => {
const userData = await AuthInstance.login(user);
return userData ? done(null, userData) : done(null, false);
})
})
// sign in method with passport local strategy
passport.use(new LocalStrategy(async (email, password, done) => {
try {
const response = await AuthInstance.login({ email, password });
return done(null, response);
} catch (e: any) {
return done(e);
}
}))
return passport;
}

View File

@@ -28,6 +28,18 @@ export class User {
}
}
async getOneByEmail(email: string) {
try {
const statement = `SELECT * FROM recipin.appusers WHERE email = $1`;
const result = await pool.query(statement, [email]);
if (result.rows.length) return result.rows[0];
return null;
} catch (e: any) {
throw new Error(e);
}
}
async updateOneByID(id: string, data: IUser) {
try {
const statement = `
@@ -55,13 +67,13 @@ export class User {
}
async post(data: IUser) {
async post(data: IUser): Promise<Array<any> | null> {
const { firstname, lastname, handle, email, password, active } = data;
try {
const statement = `INSERT INTO recipin.appusers (firstname, lastname, handle, email, password, active) VALUES ($1, $2, $3, $4, $5, $6)`;
const params = [firstname, lastname, handle, email, password, active];
const result = await pool.query(statement, params);
if (result.rows.length) return result.rows;
if (result.rows.length) return result.rows as Array<keyof IUser>;
return null;
} catch (error: any) {
throw new Error(error);

810
server/package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -16,6 +16,7 @@
"dependencies": {
"bcrypt": "^5.1.0",
"body-parser": "^1.20.1",
"connect-pg-simple": "^8.0.0",
"cors": "^2.8.5",
"dotenv": "^16.0.3",
"express": "^4.18.2",
@@ -23,6 +24,7 @@
"helmet": "^6.0.0",
"http-errors": "^2.0.0",
"js-yaml": "^4.1.0",
"morgan": "^1.10.0",
"passport": "^0.6.0",
"passport-local": "^1.0.0",
"pg": "^8.8.0",
@@ -30,12 +32,18 @@
"swagger-ui-express": "^4.6.0"
},
"devDependencies": {
"@types/bcrypt": "^5.0.0",
"@types/connect-pg-simple": "^7.0.0",
"@types/cors": "^2.8.12",
"@types/dotenv": "^8.2.0",
"@types/express": "^4.17.14",
"@types/express-session": "^1.17.5",
"@types/http-errors": "^2.0.1",
"@types/js-yaml": "^4.0.5",
"@types/morgan": "^1.9.3",
"@types/node": "^18.11.9",
"@types/passport": "^1.0.11",
"@types/passport-local": "^1.0.34",
"@types/pg": "^8.6.5",
"@types/pg-promise": "^5.4.3",
"@types/swagger-ui-express": "^4.1.3",

View File

@@ -37,4 +37,9 @@ export interface IGroceryList {
recipes?: IRecipe["id"][]
active: boolean
ownerid: IUser["id"]
}
export interface IUserAuth {
email: string
password: string
}

View File

@@ -9,7 +9,7 @@
"strict": true,
"forceConsistentCasingInFileNames": true,
"outDir": "dist",
"baseUrl": ".",
"baseUrl": "./*",
"paths": {
"*": [
"node_modules/*"