94 lines
2.7 KiB
TypeScript
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()
|
|
}
|