Complete backend rework

This commit is contained in:
aronmal 2023-04-08 16:56:03 +02:00
parent 53d4ab527a
commit eb09017dab
Signed by: aronmal
GPG key ID: 816B7707426FC612
25 changed files with 958 additions and 866 deletions

View file

@ -1,3 +1,5 @@
declare module globalThis {
import "@total-typescript/ts-reset"
declare global {
var prismaClient: PrismaClient
}

View file

@ -1,23 +1,19 @@
import { Player } from "@prisma/client"
import bcrypt from "bcrypt"
import errors from "../errors"
import sendError from "./sendError"
import { NextApiRequest, NextApiResponse } from "next"
export default async function checkPasswordIsValid<T>(
payload: T & { player: Player; password: string }
export default async function checkPasswordIsValid(
req: NextApiRequest,
res: NextApiResponse,
player: Player,
password: string,
next: () => void
) {
const { player, password } = payload
// Validate for correct password
return bcrypt.compare(password, player.passwordHash).then(async (result) => {
if (!result) {
return Promise.reject({
message: "Passwords do not match!",
statusCode: 401,
solved: true,
})
}
return {
...payload,
passwordIsValid: true,
}
})
const result = await bcrypt.compare(password, player.passwordHash)
if (!result) return sendError(req, res, errors.wrongPassword)
next()
}

View file

@ -1,30 +1,34 @@
import { Token } from "@prisma/client"
import { TokenType } from "@prisma/client"
import jwt from "jsonwebtoken"
import errors from "../errors"
import jwtVerifyCatch from "../jwtVerifyCatch"
import { NextApiRequest, NextApiResponse } from "next"
import sendError from "./sendError"
async function checkTokenIsValid<T>(
payload: T & { token: string; tokenType: Token["type"] }
async function checkTokenIsValid(
req: NextApiRequest,
res: NextApiResponse,
rawToken: [string, TokenType],
next: (tokenBody: jwt.JwtPayload) => void
) {
const { token, tokenType } = payload
const [tokenValue, tokenType] = rawToken
// Verify the token and get the payload
let tokenData: string | jwt.JwtPayload
try {
tokenData = jwt.verify(token, process.env.ACCESS_TOKEN_SECRET as string)
tokenData = jwt.verify(
tokenValue,
process.env.ACCESS_TOKEN_SECRET as string
)
} catch (err: any) {
// Deal with the problem in more detail
return Promise.reject(jwtVerifyCatch(tokenType, err))
return sendError(req, res, jwtVerifyCatch(tokenType, err))
}
// Making sure the token data is not a string (because it should be an object)
if (typeof tokenData === "string") {
return Promise.reject({
message: tokenType + "-Token data was a string. Token: " + token,
statusCode: 401,
solved: false,
})
}
if (typeof tokenData === "string")
return sendError(req, res, errors.tokenWasString(tokenType, tokenValue))
return { ...payload, tokenBody: tokenData, tokenIsValid: true }
return next(tokenData)
}
export default checkTokenIsValid

View file

@ -1,38 +1,19 @@
import { Player } from "@prisma/client"
import bcrypt from "bcrypt"
import prisma from "../../prisma"
async function createPlayerDB<T>(
payload: T & { username: string; password: string }
async function createPlayerDB(
username: string,
password: string,
next: (player: Player) => void
) {
const { username, password } = payload
return await prisma.player
.create({
data: {
username,
passwordHash: await bcrypt.hash(password, 10),
anonymous: false,
},
})
.then((player) => {
return { ...payload, player }
})
.catch((err: any) => {
if (err.code === 11000) {
return Promise.reject({
message: `Duplicate key error while creating Player in DB!`,
statusCode: 409,
solved: true,
type: "warn",
})
} else {
console.log(err)
return Promise.reject({
message: `Unknown error while creating Player in DB.`,
solved: false,
})
}
})
return await prisma.player.create({
data: {
username,
passwordHash: await bcrypt.hash(password, 10),
anonymous: false,
},
})
}
export default createPlayerDB

View file

@ -1,4 +1,4 @@
import { Player, Token } from "@prisma/client"
import { Player, Token, TokenType } from "@prisma/client"
import jwt from "jsonwebtoken"
import prisma from "../../prisma"
@ -7,11 +7,11 @@ const tokenLifetime = {
ACCESS: 15,
}
export default async function createTokenDB<T>(
payload: T & { player: Player; newTokenType: Token["type"] }
export default async function createTokenDB(
player: Player,
newTokenType: TokenType,
next: (token: [string, Token]) => void
) {
const { player, newTokenType } = payload
// Create token entry in DB
const newTokenDB = await prisma.token.create({
data: {
@ -28,13 +28,9 @@ export default async function createTokenDB<T>(
// Sign a new access token
const newToken = jwt.sign(
{ id: newTokenDB.id },
process.env.ACCESS_TOKEN_SECRET as string,
process.env.TOKEN_SECRET as string,
{ expiresIn: tokenLifetime[newTokenType] }
)
return {
...payload,
newToken,
newTokenDB,
}
return next([newToken, newTokenDB])
}

View file

@ -1,10 +1,15 @@
import { Token } from "@prisma/client"
import { Player, Token } from "@prisma/client"
import errors from "../errors"
import prisma from "../../prisma"
import { NextApiRequest, NextApiResponse } from "next"
import sendError from "./sendError"
export default async function getPlayerByIdDB<T>(
payload: T & { tokenDB: Token }
export default async function getPlayerByIdDB(
req: NextApiRequest,
res: NextApiResponse,
tokenDB: Token,
next: (player: Player) => void
) {
const { tokenDB } = payload
// Find Host in DB if it still exists (just to make sure)
const player = await prisma.player.findUnique({
where: {
@ -12,15 +17,8 @@ export default async function getPlayerByIdDB<T>(
},
})
if (!player) {
return Promise.reject({
message: "Player ID not found in DB!",
statusCode: 401,
solved: false,
})
return sendError(req, res, errors.playerNotFound)
}
return {
...payload,
player,
}
next(player)
}

View file

@ -1,9 +1,15 @@
import { Player } from "@prisma/client"
import errors from "../errors"
import prisma from "../../prisma"
import sendError from "./sendError"
import { NextApiRequest, NextApiResponse } from "next"
export default async function getPlayerByNameDB<T>(
payload: T & { username: string }
export default async function getPlayerByNameDB(
req: NextApiRequest,
res: NextApiResponse,
username: string,
next: (player: Player) => void
) {
const { username } = payload
// Find Player in DB if it still exists (just to make sure)
const player = await Promise.any([
prisma.player.findUniqueOrThrow({
@ -16,17 +22,8 @@ export default async function getPlayerByNameDB<T>(
email: username,
},
}),
])
if (!player) {
return Promise.reject({
message: "Player name not found in DB!",
statusCode: 401,
solved: false,
})
}
]).catch(() => null)
if (player === null) return sendError(req, res, errors.playerNotFound)
return {
...payload,
player,
}
next(player)
}

View file

@ -1,39 +1,26 @@
import { NextApiRequest, NextApiResponse } from "next"
import prisma from "../../prisma"
import jwt from "jsonwebtoken"
import { Token, TokenType } from "@prisma/client"
import errors from "../errors"
import sendError from "./sendError"
import { NextApiRequest, NextApiResponse } from "next"
async function getTokenDB<T>(
payload: T & {
tokenBody: jwt.JwtPayload
tokenIsValid: boolean
req: NextApiRequest
res: NextApiResponse<any>
}
async function getTokenDB(
req: NextApiRequest,
res: NextApiResponse,
tokenBody: jwt.JwtPayload,
tokenType: TokenType,
next: (tokenDB: Token) => void
) {
const { tokenBody } = payload
// Find refresh token in DB
const tokenDB = await prisma.token.findUnique({
where: {
id: tokenBody.id,
},
})
if (!tokenDB) {
return Promise.reject({
message: "Access-Token not found in DB!",
statusCode: 401,
solved: true,
type: "warn",
})
}
if (!tokenDB) return sendError(req, res, errors.tokenNotFound(tokenType))
if (tokenDB.used) {
return Promise.reject({
message: "DBToken was already used!",
statusCode: 401,
solved: true,
})
}
if (tokenDB.used) return sendError(req, res, errors.tokenUsed)
await prisma.token.update({
where: {
@ -46,10 +33,7 @@ async function getTokenDB<T>(
// await logging('Old token has been invalidated.', ['debug'], req)
return {
...payload,
tokenDB,
}
return next(tokenDB)
}
export default getTokenDB

View file

@ -1,19 +1,28 @@
import { NextApiRequest } from "next"
async function getTokenFromBody<T>(payload: T & { req: NextApiRequest }) {
const { req } = payload
const token: string = JSON.parse(req.body).token
import { TokenType } from "@prisma/client"
import { NextApiRequest, NextApiResponse } from "next"
import sendError from "./sendError"
async function getTokenFromBody(
req: NextApiRequest,
res: NextApiResponse,
next: (refreshToken: [string, TokenType]) => void
) {
const body = JSON.parse(req.body)
// Checking for cookie presens, because it is necessary
if (!token) {
return Promise.reject({
if (
typeof body !== "object" ||
!body ||
!("token" in body) ||
typeof body.token !== "string"
)
return sendError(req, res, {
message: "Unauthorized. No Access-Token.",
statusCode: 401,
solved: true,
})
}
const tokenValue = body.token
return { ...payload, token }
return next([tokenValue, "ACCESS"])
}
export default getTokenFromBody

View file

@ -1,20 +1,19 @@
import { Token } from "@prisma/client"
import { NextApiRequest } from "next"
import { TokenType } from "@prisma/client"
import { NextApiRequest, NextApiResponse } from "next"
import errors from "../errors"
import sendError from "./sendError"
async function getTokenFromCookie<T>(payload: T & { req: NextApiRequest }) {
const { req } = payload
const token = req.cookies.token
async function getTokenFromCookie(
req: NextApiRequest,
res: NextApiResponse,
next: (refreshToken: [string, TokenType]) => void
) {
const tokenValue = req.cookies.token
// Checking for cookie presens, because it is necessary
if (!token) {
return Promise.reject({
message: "Unauthorized. No cookie.",
statusCode: 401,
solved: true,
})
}
if (!tokenValue) return sendError(req, res, errors.noCookie)
return { ...payload, token, tokenType: "REFRESH" as Token["type"] }
return next([tokenValue, "REFRESH"])
}
export default getTokenFromCookie

View file

@ -0,0 +1,26 @@
import { NextApiRequest, NextApiResponse } from "next"
import sendError from "./sendError"
import errors from "../errors"
async function getUserFromBody(
req: NextApiRequest,
res: NextApiResponse,
next: (username: string, password: string) => void
) {
const body = JSON.parse(req.body)
if (
typeof body !== "object" ||
!body ||
!("username" in body) ||
typeof body.username !== "string"
)
return sendError(req, res, errors.noUsername)
const { username } = body
if (!("password" in body) || typeof body.password !== "string")
return sendError(req, res, errors.noPassword)
const { password } = body
return next(username, password)
}
export default getUserFromBody

View file

@ -1,9 +1,9 @@
import { NextApiRequest, NextApiResponse } from "next"
import logging from "../logging"
export default function sendError<T>(
export default function sendError(
req: NextApiRequest,
res: NextApiResponse<T>,
res: NextApiResponse,
err: any
) {
// If something went wrong, let the client know with status 500

View file

@ -8,12 +8,11 @@ export interface Result<T> {
type?: Logging[]
}
export default function sendResponse<T>(payload: {
req: NextApiRequest
res: NextApiResponse<T>
export default function sendResponse<T>(
req: NextApiRequest,
res: NextApiResponse<T>,
result: Result<T>
}) {
const { req, res, result } = payload
) {
res.status(result.statusCode ?? 200)
result.body ? res.json(result.body) : res.end()
logging(result.message, result.type ?? ["debug"], req)

View file

@ -0,0 +1,80 @@
import { TokenType } from "@prisma/client"
export interface rejectionError {
rejected?: boolean
message: string
statusCode: number
solved: boolean
}
export interface rejectionErrors {
[key: string]: rejectionError
}
const rejectionErrors = {
noCookie: {
rejected: true,
message: "Unauthorized. No cookie.",
statusCode: 401,
solved: true,
},
noBody: {
rejected: true,
message: "Unauthorized. No Body.",
statusCode: 401,
solved: true,
},
noUsername: {
rejected: true,
message: "No username in request body!",
statusCode: 401,
solved: true,
},
noPassword: {
rejected: true,
message: "No password in request body!",
statusCode: 401,
solved: true,
},
wrongPassword: {
message: "Passwords do not match!",
statusCode: 401,
solved: true,
},
playerNotFound: {
message: "Player name not found in DB!",
statusCode: 401,
solved: false,
},
tokenWasString(tokenType: TokenType, tokenValue: string) {
return {
rejected: true,
message: `${tokenType}-Token data was a string. Token: ${tokenValue}`,
statusCode: 401,
solved: false,
}
},
tokenNotFound(tokenType: TokenType) {
return {
rejected: true,
message: `${tokenType}-Token not found in DB!`,
statusCode: 401,
solved: true,
type: "warn",
}
},
tokenUsed: {
rejected: true,
message: "DBToken was already used!",
statusCode: 401,
solved: true,
},
noToken(tokenType: TokenType) {
return {
rejected: true,
message: `Unauthorized. No ${tokenType}-Token.`,
statusCode: 401,
solved: true,
}
},
}
export default rejectionErrors

View file

@ -1,9 +1,6 @@
import { Token } from "@prisma/client"
import { TokenType } from "@prisma/client"
export default async function jwtVerifyCatch(
tokenType: Token["type"],
err: Error
) {
export default async function jwtVerifyCatch(tokenType: TokenType, err: Error) {
switch (err.message) {
case "jwt expired":
return {

View file

@ -12,16 +12,17 @@ export default async function checkIsLoggedIn(
const req: any = context.req
const res: any = context.res
const isLoggedIn = await getTokenFromCookie({ req, res })
.then(checkTokenIsValid)
.then(getTokenDB)
.then(getPlayerByIdDB)
.then(({ player }) => !!player)
.catch(() => false)
const isLoggedIn = await getTokenFromCookie(req, res, (token) =>
checkTokenIsValid(req, res, token, (tokenBody) =>
getTokenDB(req, res, tokenBody, token[1], (tokenDB) =>
getPlayerByIdDB(req, res, tokenDB, (player) => !!player)
)
)
).catch(() => false)
logging(
"loginCheck " + (isLoggedIn ? true : "-> loggedIn: " + false),
["debug", "info.cyan"],
["debug", "infoCyan"],
req
)

View file

@ -1,7 +1,18 @@
export default function getAccessToken(): Promise<string> {
return fetch("/api/auth", {
async function getAccessToken() {
const response = await fetch("/api/auth", {
method: "GET",
})
.then((res) => res.json())
.then((res) => res.token)
const res = await response.json()
if (
typeof res === "object" &&
res &&
"token" in res &&
typeof res.token === "string"
)
return res.token
throw new Error("Access token not found")
}
export default getAccessToken

View file

@ -35,6 +35,7 @@
"typescript": "4.9.4"
},
"devDependencies": {
"@total-typescript/ts-reset": "^0.3.7",
"@types/bcrypt": "^5.0.0",
"@types/jsonwebtoken": "^9.0.1",
"@types/node": "^18.13.0",

View file

@ -1,13 +1,13 @@
import { NextApiRequest, NextApiResponse } from "next"
import { Logging } from "../../lib/backend/logging"
import { Token } from "@prisma/client"
import sendError from "../../lib/backend/components/sendError"
import getTokenFromCookie from "../../lib/backend/components/getTokenFromCookie"
import checkTokenIsValid from "../../lib/backend/components/checkTokenIsValid"
import getTokenDB from "../../lib/backend/components/getTokenDB"
import getPlayerByIdDB from "../../lib/backend/components/getPlayerByIdDB"
import createTokenDB from "../../lib/backend/components/createTokenDB"
import sendResponse from "../../lib/backend/components/sendResponse"
import sendError from "../../lib/backend/components/sendError"
import { Logging } from "../../lib/backend/logging"
import { Token } from "@prisma/client"
interface Data {
token: string
@ -17,41 +17,26 @@ export default async function auth(
req: NextApiRequest,
res: NextApiResponse<Data>
) {
return getTokenFromCookie({
req,
res,
newTokenType: "ACCESS" as Token["type"],
})
.then(checkTokenIsValid)
.then(getTokenDB)
.then(getPlayerByIdDB)
.then(createTokenDB)
.then(authResponse<Data>)
.then(sendResponse<Data>)
.catch((err) => sendError(req, res, err))
getTokenFromCookie(req, res, (token) => {
checkTokenIsValid(req, res, token, (tokenBody) => {
getTokenDB(req, res, tokenBody, token[1], (tokenDB) => {
getPlayerByIdDB(req, res, tokenDB, (player) => {
createTokenDB(player, "ACCESS", (newToken) => {
sendResponse(req, res, authResponse(newToken, tokenDB))
})
})
})
})
}).catch((err) => sendError(req, res, err))
}
async function authResponse<T>(payload: {
newToken: string
newTokenDB: Token
tokenDB: Token
req: NextApiRequest
res: NextApiResponse<T>
}) {
const { newToken, newTokenDB, tokenDB, req, res } = payload
function authResponse(newToken: [string, Token], tokenDB: Token) {
const [newTokenValue, newTokenDB] = newToken
// Successfull response
return {
req,
res,
result: {
message:
"Access-Token generated: " +
newTokenDB.id +
" with Refreshtoken-Token: " +
tokenDB.id,
body: { token: newToken },
type: ["debug", "info.cyan"] as Logging[],
},
message: `Access-Token generated: ${newTokenDB.id} with Refreshtoken-Token: ${tokenDB.id}`,
body: { token: newTokenValue },
type: ["debug", "info.cyan"] as Logging[],
}
}

View file

@ -16,37 +16,23 @@ export default async function data(
req: NextApiRequest,
res: NextApiResponse<Data>
) {
return getTokenFromBody({ req, res, tokenType: "ACCESS" as Token["type"] })
.then(checkTokenIsValid)
.then(getTokenDB)
.then(getPlayerByIdDB)
.then(dataResponse<Data>)
.then(sendResponse<Data>)
.catch((err) => sendError(req, res, err))
return getTokenFromBody(req, res, (token) => {
checkTokenIsValid(req, res, token, (tokenBody) => {
getTokenDB(req, res, tokenBody, token[1], (tokenDB) => {
getPlayerByIdDB(req, res, tokenDB, (player) => {
sendResponse(req, res, dataResponse(player, tokenDB))
})
})
})
}).catch((err) => sendError(req, res, err))
}
async function dataResponse<T>(payload: {
player: Player
tokenDB: Token
// games: Game[],
req: NextApiRequest
res: NextApiResponse<T>
}) {
const { player, tokenDB, req, res } = payload
function dataResponse<T>(player: Player, tokenDB: Token) {
const games: any = {}
// Successfull response
return {
req,
res,
result: {
message:
"Requested data of user: " +
player.id +
" with Access-Token: " +
tokenDB.id,
body: { games },
type: ["debug", "info.cyan"] as Logging[],
},
message: `Requested data of user: ${player.id} with Access-Token: ${tokenDB.id}`,
body: { games },
type: ["debug", "info.cyan"] as Logging[],
}
}

View file

@ -4,11 +4,13 @@ import getPlayerByNameDB from "../../lib/backend/components/getPlayerByNameDB"
import checkPasswordIsValid from "../../lib/backend/components/checkPasswordIsValid"
import createTokenDB from "../../lib/backend/components/createTokenDB"
import sendResponse from "../../lib/backend/components/sendResponse"
import sendError from "../../lib/backend/components/sendError"
import { deleteCookie, setCookie } from "cookies-next"
import { setCookie } from "cookies-next"
import { Player, Token } from "@prisma/client"
import prisma from "../../lib/prisma"
import jwt from "jsonwebtoken"
import errors from "../../lib/backend/errors"
import sendError from "../../lib/backend/components/sendError"
import getUserFromBody from "../../lib/backend/components/getUserFromBody"
interface Data {
loggedIn: boolean
@ -18,54 +20,44 @@ export default async function login(
req: NextApiRequest,
res: NextApiResponse<any>
) {
const { username, password } = JSON.parse(req.body)
const payload = {
req,
res,
username,
password,
newTokenType: "REFRESH" as Token["type"],
}
return preCheck(payload)
.then(getPlayerByNameDB)
.then(checkPasswordIsValid)
.then(createTokenDB)
.then(loginResponse<Data>)
.then(sendResponse<Data>)
.catch((err) => sendError(req, res, err))
return preCheck(req, res, () =>
getUserFromBody(req, res, (username, password) =>
getPlayerByNameDB(req, res, username, (player) => {
checkPasswordIsValid(req, res, player, password, () => {
createTokenDB(player, "REFRESH", (newToken) => {
sendResponse(req, res, loginResponse(player, newToken, req, res))
})
})
})
)
).catch((err) => sendError(req, res, err))
}
async function preCheck<T>(
payload: T & {
req: NextApiRequest
res: NextApiResponse<T>
}
async function preCheck(
req: NextApiRequest,
res: NextApiResponse,
next: () => void
) {
const { req, res } = payload
const oldRefreshToken = req.cookies.token
// Check for old cookie, if unused invalidate it
const tokenData =
oldRefreshToken &&
jwt.verify(oldRefreshToken, process.env.ACCESS_TOKEN_SECRET as string)
if (!tokenData || typeof tokenData === "string")
deleteCookie("token", { req, res })
else {
const oldDBToken =
oldRefreshToken &&
(await prisma.token.findUnique({
where: {
id: tokenData.id,
},
}))
if (!oldDBToken)
logging(
"Cookie could be verified but wasn't found in DB:" + tokenData,
["debug"],
req
)
else if (!oldDBToken.used)
logging("Old token was used: " + oldDBToken.id, ["debug"], req)
try {
if (!oldRefreshToken) return sendError(req, res, errors.noCookie)
// Check for old cookie, if unused invalidate it
const tokenData = jwt.verify(
oldRefreshToken,
process.env.ACCESS_TOKEN_SECRET as string
)
if (!tokenData || typeof tokenData === "string") return
const oldDBToken = await prisma.token.findUniqueOrThrow({
where: {
id: tokenData.id,
},
})
if (oldDBToken.used)
logging("Old login token was used: " + oldDBToken.id, ["debug"], req)
else {
await prisma.token.update({
where: {
@ -75,44 +67,52 @@ async function preCheck<T>(
used: true,
},
})
await logging("Old login token has been invalidated.", ["debug"], req)
}
await logging("Old token has been invalidated.", ["debug"], req)
} catch (err) {
// err is expected if no correct cookie, just continue, otherwise it has been invalidated above
}
return { ...payload, noCookiePresent: true }
return next()
}
async function loginResponse<T>(payload: {
player: Player
passwordIsValid: boolean
newToken: string
newTokenDB: Token
req: NextApiRequest
function loginResponse<T>(
player: Player,
newToken: [string, Token],
req: NextApiRequest,
res: NextApiResponse<T>
}) {
const { player, newToken, newTokenDB, req, res } = payload
) {
// const { player, req, res } = payload
const [newTokenValue, newTokenDB] = newToken
// Set login cookie
setCookie("token", newToken, {
setCookie("token", newTokenValue, {
req,
res,
maxAge: 172800000,
maxAge: 172800,
httpOnly: true,
sameSite: true,
secure: true,
path: "/api",
})
// deleteCookie("token", {
// req,
// res,
// httpOnly: true,
// sameSite: true,
// secure: true,
// path: "/api",
// })
// Successfull response
return {
req,
res,
result: {
message:
"User " +
player.id +
" logged in and generated Refresh-Token: " +
newTokenDB.id,
body: { loggedIn: true },
type: ["debug", "info.cyan"] as Logging[],
},
message:
"User " +
player.id +
" logged in and generated Refresh-Token: " +
newTokenDB.id,
body: { loggedIn: true },
type: ["debug", "info.cyan"] as Logging[],
}
}

View file

@ -16,32 +16,27 @@ export default async function logout(
req: NextApiRequest,
res: NextApiResponse<any>
) {
return getTokenFromCookie({ req, res })
.then(checkTokenIsValid)
.then(getTokenDB)
.then(logoutResponse<Data>)
.then(sendResponse<Data>)
.catch((err) => sendError(req, res, err))
return getTokenFromCookie(req, res, (token) => {
checkTokenIsValid(req, res, token, (tokenBody) => {
getTokenDB(req, res, tokenBody, token[1], (tokenDB) => {
sendResponse(req, res, logoutResponse(tokenDB, req, res))
})
})
}).catch((err) => sendError(req, res, err))
}
async function logoutResponse<T>(payload: {
tokenDB: Token
req: NextApiRequest
function logoutResponse<T>(
tokenDB: Token,
req: NextApiRequest,
res: NextApiResponse<T>
}) {
const { tokenDB, req, res } = payload
) {
// Set login cookie
deleteCookie("token", { req, res })
// Successfull response
return {
req,
res,
result: {
message: "User of Token " + tokenDB.id + " logged out.",
body: { loggedOut: true },
type: ["debug", "info.cyan"] as Logging[],
},
message: "User of Token " + tokenDB.id + " logged out.",
body: { loggedOut: true },
type: ["debug", "info.cyan"] as Logging[],
}
}

View file

@ -4,6 +4,7 @@ import sendError from "../../lib/backend/components/sendError"
import sendResponse from "../../lib/backend/components/sendResponse"
import { Logging } from "../../lib/backend/logging"
import { Player } from "@prisma/client"
import getUserFromBody from "../../lib/backend/components/getUserFromBody"
interface Data {
registered: boolean
@ -11,31 +12,21 @@ interface Data {
export default async function register(
req: NextApiRequest,
res: NextApiResponse<any>
res: NextApiResponse<Data>
) {
const { username, password } = JSON.parse(req.body)
return createPlayerDB({ req, res, username, password })
.then(registerResponse<Data>)
.then(sendResponse<Data>)
.catch((err) => sendError(req, res, err))
return getUserFromBody(req, res, (username, password) =>
createPlayerDB(username, password, (player) => {
sendResponse(req, res, registerResponse(player))
}).catch((err) => sendError(req, res, err))
)
}
async function registerResponse<T>(payload: {
player: Player
req: NextApiRequest
res: NextApiResponse<T>
}) {
const { player, req, res } = payload
function registerResponse<T>(player: Player) {
// Successfull response
return {
req,
res,
result: {
message: "Player created : " + player.id,
statusCode: 201,
body: { registered: true },
type: ["debug", "info.cyan"] as Logging[],
},
message: "Player created : " + player.id,
statusCode: 201,
body: { registered: true },
type: ["debug", "info.cyan"] as Logging[],
}
}

View file

@ -1,7 +1,7 @@
import type { NextApiRequest } from "next"
import { Server } from "socket.io"
import { NextApiResponseWithSocket } from "../../interfaces/NextApiSocket"
import checkTokenIsValid from "../../lib/backend/components/checkTokenIsValid"
import jwt from "jsonwebtoken"
import prisma from "../../lib/prisma"
export interface ServerToClientEvents {
@ -37,6 +37,21 @@ interface SocketData {
// next()
// }
async function checkTokenIsValid(rawToken: string) {
// Verify the token and get the payload
let tokenData: string | jwt.JwtPayload
try {
tokenData = jwt.verify(rawToken, process.env.ACCESS_TOKEN_SECRET as string)
} catch (err: any) {
// Deal with the problem in more detail
return Promise.reject()
}
// Making sure the token data is not a string (because it should be an object)
if (typeof tokenData === "string") return Promise.reject()
return tokenData
}
const SocketHandler = (req: NextApiRequest, res: NextApiResponseWithSocket) => {
if (res.socket.server.io) {
console.log("Socket is already running " + req.url)
@ -59,10 +74,7 @@ const SocketHandler = (req: NextApiRequest, res: NextApiResponseWithSocket) => {
})
socket.on("authenticate", (payload) => {
checkTokenIsValid({
token: payload.token,
tokenType: "ACCESS",
})
checkTokenIsValid(payload.token)
.then(async ({ tokenBody }) => {
const token = await prisma.token.findUnique({
where: { id: tokenBody.id },

File diff suppressed because it is too large Load diff