diff --git a/leaky-ships/lib/backend/components/checkTokenIsValid.ts b/leaky-ships/lib/backend/components/checkTokenIsValid.ts index d24d22e..e1a7e87 100644 --- a/leaky-ships/lib/backend/components/checkTokenIsValid.ts +++ b/leaky-ships/lib/backend/components/checkTokenIsValid.ts @@ -24,7 +24,7 @@ async function checkTokenIsValid( }) } - return { ...payload, tokenBody: token, tokenIsValid: true } + return { ...payload, tokenBody: tokenData, tokenIsValid: true } } export default checkTokenIsValid diff --git a/leaky-ships/lib/backend/components/createTokenDB.ts b/leaky-ships/lib/backend/components/createTokenDB.ts index 9ded9c4..2965ca8 100644 --- a/leaky-ships/lib/backend/components/createTokenDB.ts +++ b/leaky-ships/lib/backend/components/createTokenDB.ts @@ -1,6 +1,5 @@ import { Player, Token } from "@prisma/client" import jwt from "jsonwebtoken" -import { v4 as uuidv4 } from "uuid" import prisma from "../../prisma" const tokenLifetime = { @@ -13,19 +12,11 @@ export default async function createTokenDB( ) { const { player, newTokenType } = payload - // Sign a new access token - const newToken = jwt.sign( - { uuid: uuidv4(), user: player.id }, - process.env.ACCESS_TOKEN_SECRET as string, - { expiresIn: tokenLifetime[newTokenType] } - ) - - // Save token to DB + // Create token entry in DB const newTokenDB = await prisma.token.create({ data: { - token: newToken, type: newTokenType, - expires: new Date(Date.now() + tokenLifetime[newTokenType] + "000"), + // expires: new Date(Date.now() + tokenLifetime[newTokenType] + "000"), owner: { connect: { id: player.id, @@ -34,6 +25,13 @@ export default async function createTokenDB( }, }) + // Sign a new access token + const newToken = jwt.sign( + { id: newTokenDB.id }, + process.env.ACCESS_TOKEN_SECRET as string, + { expiresIn: tokenLifetime[newTokenType] } + ) + return { ...payload, newToken, diff --git a/leaky-ships/lib/backend/components/getPlayerByIdDB.ts b/leaky-ships/lib/backend/components/getPlayerByIdDB.ts index a3814cc..0fda890 100644 --- a/leaky-ships/lib/backend/components/getPlayerByIdDB.ts +++ b/leaky-ships/lib/backend/components/getPlayerByIdDB.ts @@ -13,7 +13,7 @@ export default async function getPlayerByIdDB( }) if (!player) { return Promise.reject({ - message: "Player not found in DB!", + message: "Player ID not found in DB!", statusCode: 401, solved: false, }) diff --git a/leaky-ships/lib/backend/components/getPlayerByNameDB.ts b/leaky-ships/lib/backend/components/getPlayerByNameDB.ts index 3de1a82..f587592 100644 --- a/leaky-ships/lib/backend/components/getPlayerByNameDB.ts +++ b/leaky-ships/lib/backend/components/getPlayerByNameDB.ts @@ -6,12 +6,12 @@ export default async function getPlayerByNameDB( const { username } = payload // Find Player in DB if it still exists (just to make sure) const player = await Promise.any([ - prisma.player.findUnique({ + prisma.player.findUniqueOrThrow({ where: { username: username, }, }), - prisma.player.findUnique({ + prisma.player.findUniqueOrThrow({ where: { email: username, }, @@ -19,7 +19,7 @@ export default async function getPlayerByNameDB( ]) if (!player) { return Promise.reject({ - message: "Player not found in DB!", + message: "Player name not found in DB!", statusCode: 401, solved: false, }) diff --git a/leaky-ships/lib/backend/components/getTokenDB.ts b/leaky-ships/lib/backend/components/getTokenDB.ts index 4c21da4..5d131b9 100644 --- a/leaky-ships/lib/backend/components/getTokenDB.ts +++ b/leaky-ships/lib/backend/components/getTokenDB.ts @@ -1,9 +1,10 @@ import { NextApiRequest, NextApiResponse } from "next" import prisma from "../../prisma" +import jwt from "jsonwebtoken" async function getTokenDB( payload: T & { - tokenBody: string + tokenBody: jwt.JwtPayload tokenIsValid: boolean req: NextApiRequest res: NextApiResponse @@ -14,7 +15,7 @@ async function getTokenDB( // Find refresh token in DB const tokenDB = await prisma.token.findUnique({ where: { - token: tokenBody, + id: tokenBody.id, }, }) if (!tokenDB) { @@ -36,7 +37,7 @@ async function getTokenDB( await prisma.token.update({ where: { - token: tokenBody, + id: tokenBody.id, }, data: { used: true, diff --git a/leaky-ships/lib/backend/components/sendError.ts b/leaky-ships/lib/backend/components/sendError.ts index 92db74c..f38c89f 100644 --- a/leaky-ships/lib/backend/components/sendError.ts +++ b/leaky-ships/lib/backend/components/sendError.ts @@ -9,4 +9,5 @@ export default function sendError( // If something went wrong, let the client know with status 500 res.status(err.statusCode ?? 500).end() logging(err.message, [err.type ?? (err.solved ? "debug" : "error")], req) + if (err.name) console.log(err) } diff --git a/leaky-ships/lib/backend/logging.ts b/leaky-ships/lib/backend/logging.ts index 2869641..4d38fa6 100644 --- a/leaky-ships/lib/backend/logging.ts +++ b/leaky-ships/lib/backend/logging.ts @@ -30,7 +30,7 @@ async function logStartup() { async function logging( message: string, types: Logging[], - req?: NextApiRequest | IncomingMessage + req?: NextApiRequest ) { if (!started) await logStartup() const messages = { console: message, file: message } @@ -49,8 +49,11 @@ async function logging( if (req) { const forwardedFor: any = req.headers["x-forwarded-for"] const ip = (forwardedFor || "127.0.0.1, 192.168.178.1").split(",") - messages.console = ip[0].yellow + " - " + messages.console - messages.file = ip[0] + " - " + messages.file + const route = req.url + messages.console = [ip[0].yellow, route?.green, messages.console].join( + " - " + ) + messages.file = [ip[0], route, messages.file].join(" - ") } await fs.promises.appendFile("log/log.txt", messages.file + "\n") console.log(messages.console) diff --git a/leaky-ships/lib/frontend/getAccessToken.ts b/leaky-ships/lib/frontend/getAccessToken.ts index 00105ea..90e3fd8 100644 --- a/leaky-ships/lib/frontend/getAccessToken.ts +++ b/leaky-ships/lib/frontend/getAccessToken.ts @@ -3,5 +3,5 @@ export default function getAccessToken(): Promise { method: "GET", }) .then((res) => res.json()) - .then((res) => res.newAccessToken) + .then((res) => res.token) } diff --git a/leaky-ships/pages/api/login.ts b/leaky-ships/pages/api/login.ts index 85bad8a..5c4492b 100644 --- a/leaky-ships/pages/api/login.ts +++ b/leaky-ships/pages/api/login.ts @@ -5,9 +5,10 @@ import checkPasswordIsValid from "../../lib/backend/components/checkPasswordIsVa import createTokenDB from "../../lib/backend/components/createTokenDB" import sendResponse from "../../lib/backend/components/sendResponse" import sendError from "../../lib/backend/components/sendError" -import { setCookie } from "cookies-next" +import { deleteCookie, setCookie } from "cookies-next" import { Player, Token } from "@prisma/client" import prisma from "../../lib/prisma" +import jwt from "jsonwebtoken" interface Data { loggedIn: boolean @@ -40,23 +41,36 @@ async function preCheck( res: NextApiResponse } ) { - const { req } = payload + const { req, res } = payload const oldRefreshToken = req.cookies.token // Check for old cookie, if unused invalidate it - const oldDBToken = await prisma.token.findUnique({ - where: { - token: oldRefreshToken, - }, - }) - if (oldDBToken?.used) { - await prisma.token.update({ - where: { - token: oldRefreshToken, - }, - data: { - used: true, - }, - }) + 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) return + if (!oldDBToken.used) + logging("Old token was used: " + oldDBToken.id, ["debug"], req) + else { + await prisma.token.update({ + where: { + id: tokenData.id, + }, + data: { + used: true, + }, + }) + } await logging("Old token has been invalidated.", ["debug"], req) } return { ...payload, noCookiePresent: true } @@ -65,15 +79,15 @@ async function preCheck( async function loginResponse(payload: { player: Player passwordIsValid: boolean - refreshToken: string - refreshTokenDB: Token + newToken: string + newTokenDB: Token req: NextApiRequest res: NextApiResponse }) { - const { player, refreshToken, refreshTokenDB, req, res } = payload + const { player, newToken, newTokenDB, req, res } = payload // Set login cookie - setCookie("token", refreshToken, { + setCookie("token", newToken, { req, res, maxAge: 172800000, @@ -91,7 +105,7 @@ async function loginResponse(payload: { "User " + player.id + " logged in and generated Refresh-Token: " + - refreshTokenDB.id, + newTokenDB.id, body: { loggedIn: true }, type: ["debug", "info.cyan"] as Logging[], }, diff --git a/leaky-ships/pages/api/logout.ts b/leaky-ships/pages/api/logout.ts index 98b010c..aed8cd2 100644 --- a/leaky-ships/pages/api/logout.ts +++ b/leaky-ships/pages/api/logout.ts @@ -6,7 +6,7 @@ import { deleteCookie } from "cookies-next" import { Token } from "@prisma/client" import getTokenDB from "../../lib/backend/components/getTokenDB" import getTokenFromCookie from "../../lib/backend/components/getTokenFromCookie" -import logging, { Logging } from "../../lib/backend/logging" +import { Logging } from "../../lib/backend/logging" interface Data { loggedOut: boolean