diff --git a/config/jwtConfig.mjs b/config/jwtConfig.mjs new file mode 100644 index 0000000..b6d6415 --- /dev/null +++ b/config/jwtConfig.mjs @@ -0,0 +1,3 @@ +export default { + secret: "jwt-secret", +}; diff --git a/config/passport.mjs b/config/passport.mjs new file mode 100644 index 0000000..cb83ff2 --- /dev/null +++ b/config/passport.mjs @@ -0,0 +1,117 @@ +import bcrypt from "bcrypt"; +import jwtSecret from "./jwtConfig"; + +const BCRYPT_SALT_ROUNDS = 12; + +const passport = require("passport"); +const LocalStrategy = require("passport-local").Strategy; +const JWTstrategy = require("passport-jwt").Strategy; +const ExtractJWT = require("passport-jwt").ExtractJwt; +const User = require("../sequelize"); + +passport.use( + "register", + new LocalStrategy( + { + usernameField: "username", + passwordField: "password", + passReqToCallback: true, + session: false, + }, + (req, username, password, done) => { + try { + User.findOne({ + where: { + [Op.or]: [ + { + username, + }, + { email: req.body.email }, + ], + }, + }).then((user) => { + if (user != null) { + console.log("username or email already taken"); + return done(null, false, { + message: "username or email already taken", + }); + } + bcrypt.hash(password, BCRYPT_SALT_ROUNDS).then((hashedPassword) => { + User.create({ + username, + password: hashedPassword, + email: req.body.email, + }).then((user) => { + console.log("user created"); + return done(null, user); + }); + }); + }); + } catch (err) { + return done(err); + } + }, + ), +); + +passport.use( + "login", + new LocalStrategy( + { + usernameField: "username", + passwordField: "password", + session: false, + }, + (username, password, done) => { + try { + User.findOne({ + where: { + username, + }, + }).then((user) => { + if (user === null) { + return done(null, false, { message: "bad username" }); + } + bcrypt.compare(password, user.password).then((response) => { + if (response !== true) { + console.log("passwords do not match"); + return done(null, false, { message: "passwords do not match" }); + } + console.log("user found & authenticated"); + return done(null, user); + }); + }); + } catch (err) { + done(err); + } + }, + ), +); + +const opts = { + jwtFromRequest: ExtractJWT.fromAuthHeaderWithScheme("JWT"), + secretOrKey: jwtSecret.secret, +}; + +passport.use( + "jwt", + new JWTstrategy(opts, (jwt_payload, done) => { + try { + User.findOne({ + where: { + id: jwt_payload.id, + }, + }).then((user) => { + if (user) { + console.log("user found in db in passport"); + done(null, user); + } else { + console.log("user not found in db"); + done(null, false); + } + }); + } catch (err) { + done(err); + } + }), +); diff --git a/objects/Endpoints.mjs b/objects/Endpoints.mjs index eea59c5..df5e741 100644 --- a/objects/Endpoints.mjs +++ b/objects/Endpoints.mjs @@ -1,85 +1,75 @@ import express from "express"; import logger from "../logger.mjs"; -import Story from "./Story.mjs" -import Publication from "./Publication.mjs" +import Story from "./Story.mjs"; +import Publication from "./Publication.mjs"; import Submission from "./Submission.mjs"; - - - - - +import passport from "passport"; export const getEndpoints = (dbObject) => { - const router = express.Router() + const router = express.Router(); - router.get('/stories', (req,res)=>{ - res.statusCode=200 - res.send(dbObject.stories) - return - }) - - router.get('/publications', (req,res)=>{ - res.statusCode=200 - res.send(dbObject.publications) - return - }) - - router.get('/submissions', (req,res)=>{ - res.statusCode=200 - res.send(dbObject.submissions) - return - }) - router.get('/responses', (req,res)=>{ - res.statusCode=200 - res.send(dbObject.responses) - return - }) - router.get('/genres', (req,res)=>{ - res.statusCode=200 - res.send(dbObject.genres) - return - }) + router.get("/stories", (_, res) => { + res.statusCode = 200; + res.send(dbObject.stories); + return; + }); - return router -} - -export const postEndpoints = (db,data) => { - const router = express.Router() - endpoint(router,Story,'create','insert',db,data) - endpoint(router,Story,'edit','update',db,data) - endpoint(router,Story,'delete','update',db,data) - endpoint(router,Submission,'create','insert',db,data) - endpoint(router,Submission,'edit','update',db,data) - endpoint(router,Submission,'delete','update',db,data) - endpoint(router,Publication,'create','insert',db,data) - endpoint(router,Publication,'edit','update',db,data) - endpoint(router,Publication,'delete','del',db,data) - return router -} - - - - const endpoint = (router,Entity,path,method,db,data) =>{ - router.post(`/${Entity.name.toLowerCase()}/${path}`, async (req,res) => { - try { - logger.trace({data:req.body},"POST request received") - const entity = new Entity(req.body) - await entity[method](db,data) - res.sendStatus(200) - data.init() - return - } catch (error) { - logger.error(error) - if(error instanceof TypeError){ - res.sendStatus(400) - return - } - res.sendStatus(500) - return - } - }) -} + router.get("/publications", (_, res) => { + res.statusCode = 200; + res.send(dbObject.publications); + return; + }); + router.get("/submissions", (_, res) => { + res.statusCode = 200; + res.send(dbObject.submissions); + return; + }); + router.get("/responses", (_, res) => { + res.statusCode = 200; + res.send(dbObject.responses); + return; + }); + router.get("/genres", (_, res) => { + res.statusCode = 200; + res.send(dbObject.genres); + return; + }); + return router; +}; +export const postEndpoints = (db, data) => { + const router = express.Router(); + endpoint(router, Story, "create", "insert", db, data); + endpoint(router, Story, "edit", "update", db, data); + endpoint(router, Story, "delete", "update", db, data); + endpoint(router, Submission, "create", "insert", db, data); + endpoint(router, Submission, "edit", "update", db, data); + endpoint(router, Submission, "delete", "update", db, data); + endpoint(router, Publication, "create", "insert", db, data); + endpoint(router, Publication, "edit", "update", db, data); + endpoint(router, Publication, "delete", "del", db, data); + return router; +}; +const endpoint = (router, Entity, path, method, db, data) => { + router.post(`/${Entity.name.toLowerCase()}/${path}`, async (req, res) => { + try { + logger.trace({ data: req.body }, "POST request received"); + const entity = new Entity(req.body); + await entity[method](db, data); + res.sendStatus(200); + data.init(); + return; + } catch (error) { + logger.error(error); + if (error instanceof TypeError) { + res.sendStatus(400); + return; + } + res.sendStatus(500); + return; + } + }); +}; diff --git a/package.json b/package.json index ea9d513..e4953be 100644 --- a/package.json +++ b/package.json @@ -14,16 +14,20 @@ "chai-as-promised": "^7.1.1", "chai-http": "^4.4.0", "cors": "^2.8.5", + "eslint": "^8.57.0", "express": "^4.18.2", + "jsonwebtoken": "^9.0.2", "knex": "^2.5.1", "lodash": "^4.17.21", "luxon": "^3.4.3", "mocha": "^10.2.0", + "mongodb": "^6.5.0", + "mongoose": "^8.2.2", + "passport": "^0.7.0", + "passport-jwt": "^4.0.1", + "passport-local": "^1.0.0", "pino": "^8.15.0", "pino-http": "^8.5.0", "sqlite3": "^5.1.6" - }, - "devDependencies": { - "eslint": "^8.57.0" } } diff --git a/server.mjs b/server.mjs index 7cd5093..ec753d6 100644 --- a/server.mjs +++ b/server.mjs @@ -1,36 +1,35 @@ -import express from "express" -import pinoHTTP from 'pino-http' +import express from "express"; +import pinoHTTP from "pino-http"; import logger from "./logger.mjs"; import bodyParser from "body-parser"; import { Data } from "./objects/Data.mjs"; import { db } from "./db.mjs"; import { getEndpoints, postEndpoints } from "./objects/Endpoints.mjs"; -import cors from 'cors' +import cors from "cors"; -const app = express() -const port = 4000 -const corsOptions={ - origin: ['http://localhost:5173'] -} -app.use(cors()) -app.use(pinoHTTP({logger})) -app.use(bodyParser.json()) - +const app = express(); +const port = 4000; +const corsOptions = { + origin: ["http://localhost:5173"], +}; +app.use(cors()); +app.use(pinoHTTP({ logger })); +app.use(bodyParser.json()); +// app.use(bodyParser.urlencoded({ extended: false })); +// app.use(helmet()); +// app.use(passport.initialize()); +const data = new Data(db); +await data.init(); -const data = new Data(db) -await data.init() - - -app.use('/api',getEndpoints(data)) -app.use('/api',postEndpoints(db,data) ) - - +app.use("/api", getEndpoints(data)); +app.use("/api", postEndpoints(db, data)); app.listen(port, (err) => { - if (err) logger.error(err); - logger.info("Server listening on PORT " + port) - }) + if (err) logger.error(err); + logger.info("Server listening on PORT " + port); +}); + +export default app; - export default app \ No newline at end of file