From 23aa9e4e2f9e641c4d067ddfa3e215cbc41f0a65 Mon Sep 17 00:00:00 2001 From: Andreas Date: Mon, 12 Jun 2023 05:02:59 +0200 Subject: [PATCH] fixed api routes --- package-lock.json | 28 +++++++++ package.json | 2 + src/model/sequelize/User.ts | 39 +++++++++++++ src/pages/api/auth/index.ts | 111 +++++++++++++++++++++++------------- src/pages/api/user/index.ts | 44 ++++++++++++++ src/util/Auth.ts | 14 +++++ 6 files changed, 197 insertions(+), 41 deletions(-) create mode 100644 src/model/sequelize/User.ts create mode 100644 src/pages/api/user/index.ts create mode 100644 src/util/Auth.ts diff --git a/package-lock.json b/package-lock.json index c062cc8..8881381 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,11 +8,13 @@ "name": "portfolio2023", "version": "0.1.0", "dependencies": { + "@types/bcrypt": "^5.0.0", "@types/node": "20.1.7", "@types/react": "18.2.6", "@types/react-bootstrap": "^0.32.32", "@types/react-dom": "18.2.4", "autoprefixer": "10.4.14", + "bcrypt": "^5.1.0", "bootstrap": "^5.3.0", "eslint": "8.40.0", "eslint-config-next": "13.4.2", @@ -519,6 +521,14 @@ "node": ">= 6" } }, + "node_modules/@types/bcrypt": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@types/bcrypt/-/bcrypt-5.0.0.tgz", + "integrity": "sha512-agtcFKaruL8TmcvqbndlqHPSJgsolhf/qPWchFlgnW1gECTN/nKbFcoFnvKAQRFfKbh+BO6A3SWdJu9t+xF3Lw==", + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@types/debug": { "version": "4.1.8", "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.8.tgz", @@ -1009,6 +1019,24 @@ "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" }, + "node_modules/bcrypt": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/bcrypt/-/bcrypt-5.1.0.tgz", + "integrity": "sha512-RHBS7HI5N5tEnGTmtR/pppX0mmDSBpQ4aCBsj7CEQfYXDcO74A8sIBYcJMuCsis2E81zDxeENYhv66oZwLiA+Q==", + "hasInstallScript": true, + "dependencies": { + "@mapbox/node-pre-gyp": "^1.0.10", + "node-addon-api": "^5.0.0" + }, + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/bcrypt/node_modules/node-addon-api": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-5.1.0.tgz", + "integrity": "sha512-eh0GgfEkpnoWDq+VY8OyvYhFEzBk6jIYbRKdIlyTiAXIVJ8PyBaKb0rp7oDtoddbdoHWhq8wwr+XZ81F1rpNdA==" + }, "node_modules/big-integer": { "version": "1.6.51", "resolved": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.51.tgz", diff --git a/package.json b/package.json index 3d95284..df37877 100644 --- a/package.json +++ b/package.json @@ -9,11 +9,13 @@ "lint": "next lint" }, "dependencies": { + "@types/bcrypt": "^5.0.0", "@types/node": "20.1.7", "@types/react": "18.2.6", "@types/react-bootstrap": "^0.32.32", "@types/react-dom": "18.2.4", "autoprefixer": "10.4.14", + "bcrypt": "^5.1.0", "bootstrap": "^5.3.0", "eslint": "8.40.0", "eslint-config-next": "13.4.2", diff --git a/src/model/sequelize/User.ts b/src/model/sequelize/User.ts new file mode 100644 index 0000000..8c4a8fd --- /dev/null +++ b/src/model/sequelize/User.ts @@ -0,0 +1,39 @@ +import { Sequelize, DataTypes, Optional, Model } from 'sequelize'; +const sequelize = new Sequelize({ + dialect: 'sqlite', + storage: 'db.sqlite' +}); +interface UserAttributes{ + id: number; + username: string; + password: string; +}; +interface UserCreationAttributes extends Optional{}; +class UserModel extends Model{ + createdAt?: Date; + updatedAt?: Date; + username: string = ""; + password: string = ""; + id: undefined; + // declare title +} +export const MUser = sequelize.define( + 'User', + { + id: { + allowNull: false, + autoIncrement: true, + type: DataTypes.INTEGER, + primaryKey: true, + unique: true, + }, + username: { + allowNull: false, + type: DataTypes.STRING, + }, + password: { + allowNull: false, + type: DataTypes.STRING, + } + } +); \ No newline at end of file diff --git a/src/pages/api/auth/index.ts b/src/pages/api/auth/index.ts index 05b2b0a..5096ae6 100644 --- a/src/pages/api/auth/index.ts +++ b/src/pages/api/auth/index.ts @@ -3,50 +3,79 @@ import { getConnection } from "@/db"; import { Post, postPlaceholder } from "@/model/Models"; import { getPosts, IPost } from "@/controller/Post"; import { NextApiRequest, NextApiResponse } from "next"; -import { MPost, MUser, MAuth } from "@/model/Models" -import { Sequelize } from "sequelize"; -import { Elsie_Swash_Caps } from "next/font/google"; +// import { MPost, MUser, MAuth } from "@/model/Models" +import { MPost } from "@/model/sequelize/Post"; +import { MUser } from "@/model/sequelize/User"; +import { MAuth } from "@/model/sequelize/Auth"; -export default async function handler(req:NextApiRequest, res:NextApiResponse) { - await MUser.sync(); - await MAuth.sync(); - switch (req.method) { - case 'POST': - case 'GET': - const users = await MUser.findAll(); - // res.status(200).json(posts); - let username = req.body.username; - let password = req.body.password; - console.log(req.body ); - if(users.length == 0){ - MUser.create({ - username: "admin", - password: "changeme" - }) - } - users.forEach(user => async { - if(user.username == username && user.password == password){ - try{ - const authtoken = await MAuth.findOne({where : {user_id: user.id}}); - if(authtoken != null){ - res.status(200).json({"status":"correct"}); - console.log(authtoken); - } - else{ - res.status(200).json({"status":"no such auth token"}); - } - } catch(e){ - console.log(e); - } + +import { DataType, Model, Sequelize, UUID } from "sequelize"; +import { validatePassword, hashPassword } from "@/util/Auth"; + + +export default async function handler(req: NextApiRequest, res: NextApiResponse) { + if (req.method === 'GET') { + let auth; + try { + const authString = Buffer.from(req.headers.authorization.split(" ")[1], "base64").toString("utf8"); + auth = authString.split(":"); + } catch (error) { + res.status(500).json("Basic Auth is required"); + return; + } + console.log(auth); + const username = auth[0]; + const password = auth[1]; + // console.log(req.body); + await MUser.sync() + .then(async user => { + // console.log(user); + return await MAuth.sync(); + }) + .then(async auth => { + // console.log(auth); + return await MUser.findOne({ where: { username: username } }); + }) + .then(async user => { + // console.log(user); + if (user == undefined) { + throw "no such user exists"; } else{ - console.log(user.password); - res.status(200).json({"status":"incorrect"}); - + return user; } - }); - break; - default: - break; + }) + .then(async user => { + const passIsValid = await validatePassword(password, user.password); + return {passIsValid, user}; + }) + .then(async ({passIsValid, user})=>{ + if(passIsValid){ + const authtoken = await MAuth.findOne({ where: { user_id: user.id } }); + return {authtoken, user} + } + else{ + throw("invalid password"); + } + }) + .then(async ({authtoken, user}) => { + if (authtoken == null) { + if (typeof user.id === "number") { + // console.log("creating new auth token") + return await MAuth.create({ user_id: user.id }); + } + } + else { + return authtoken + } + }).then(authtoken => { + if (authtoken != null) { + // console.log(authtoken); + res.status(200).json(authtoken); + } + }) + .catch(error => { + res.status(500).json(error); + }); } } \ No newline at end of file diff --git a/src/pages/api/user/index.ts b/src/pages/api/user/index.ts new file mode 100644 index 0000000..b37be8a --- /dev/null +++ b/src/pages/api/user/index.ts @@ -0,0 +1,44 @@ +import mysql2, { Connection, RowDataPacket, OkPacket, QueryError } from "mysql2"; +import { getConnection } from "@/db"; +import { Post, postPlaceholder } from "@/model/Models"; +import { getPosts, IPost } from "@/controller/Post"; +import { NextApiRequest, NextApiResponse } from "next"; +// import { MPost, MUser, MAuth } from "@/model/Models" +import { MPost } from "@/model/sequelize/Post"; +import { MUser } from "@/model/sequelize/User"; +import { MAuth } from "@/model/sequelize/Auth"; + + +import { DataType, Model, Sequelize, UUID } from "sequelize"; +import { validatePassword, hashPassword } from "@/util/Auth"; + + +export default async function handler(req: NextApiRequest, res: NextApiResponse) { + if (req.method === 'POST') { + const username = req.body.username; + const password = req.body.password; + console.log(req.body); + const user = await MUser.sync() + .then(async f => { + return await MUser.findOne({ where: { username: username } }); + }) + .then(async user => { + if (user == undefined) { + const hash = await hashPassword(password) + return await MUser.create({ + username: username, + password: hash + }) + } + else{ + throw "User with that username already exists"; + } + }) + .then(user =>{ + res.status(200).json(user) + }) + .catch(error => { + res.status(500).json(error); + }); + } +} \ No newline at end of file diff --git a/src/util/Auth.ts b/src/util/Auth.ts new file mode 100644 index 0000000..9b1d00b --- /dev/null +++ b/src/util/Auth.ts @@ -0,0 +1,14 @@ +import { hash, compare } from "bcrypt"; + + +export async function validatePassword(password:string, hashString:string){ + const result = await compare(password, hashString); + return result; +} + +export async function hashPassword(password:string){ + const hashString = await hash(password, 10); + return hashString; +} + +export default { validatePassword, hashPassword }; \ No newline at end of file