leaky-ships/leaky-ships/pages/api/user/login.ts
2023-04-11 20:07:27 +02:00

94 lines
2.7 KiB
TypeScript

import checkPasswordIsValid from "@backend/components/checkPasswordIsValid"
import createTokenDB from "@backend/components/createTokenDB"
import getPlayerByNameDB from "@backend/components/getPlayerByNameDB"
import getUserFromBody from "@backend/components/getUserFromBody"
import sendError, { API } from "@backend/components/sendError"
import sendResponse from "@backend/components/sendResponse"
import logging from "@backend/logging"
import { rejectionErrors } from "@lib/backend/errors"
import prisma from "@lib/prisma"
import { setCookie } from "cookies-next"
import jwt from "jsonwebtoken"
import type { NextApiRequest, NextApiResponse } from "next"
interface Data {
loggedIn: boolean
}
export default async function login(
req: NextApiRequest,
res: NextApiResponse<Data>
) {
const context = { req, res }
return preCheck(context, () =>
getUserFromBody(context, (username, password) =>
getPlayerByNameDB(context, username, (player) => {
checkPasswordIsValid(context, player, password, () => {
createTokenDB(player, "REFRESH", (newToken, newTokenDB) => {
// Set login cookie
setCookie("token", newToken.value, {
req,
res,
maxAge: 172800,
httpOnly: true,
sameSite: true,
secure: true,
path: "/api",
})
sendResponse(context, {
message:
"User " +
player.id +
" logged in and generated Refresh-Token: " +
newTokenDB.id,
body: { loggedIn: true },
type: ["debug", "infoCyan"],
})
})
})
})
)
).catch((err) => sendError(context, err))
}
async function preCheck<T>(context: API<T>, next: () => void) {
const { req } = context
const oldRefreshToken = req.cookies.token
try {
if (!oldRefreshToken) return sendError(context, rejectionErrors.noCookie)
// Check for old cookie, if unused invalidate it
const tokenData = jwt.verify(
oldRefreshToken,
process.env.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: {
id: tokenData.id,
},
data: {
used: true,
},
})
await logging("Old login token has been invalidated.", ["debug"], req)
}
} catch (err) {
// err is expected if no correct cookie, just continue, otherwise it has been invalidated above
}
return next()
}