First prisma integration step
This commit is contained in:
parent
6918729c45
commit
0507309ab1
21 changed files with 645 additions and 1 deletions
22
leaky-ships/lib/backend/components/checkPasswordIsValid.ts
Normal file
22
leaky-ships/lib/backend/components/checkPasswordIsValid.ts
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
import { Player } from "@prisma/client"
|
||||||
|
import bcrypt from "bcrypt"
|
||||||
|
|
||||||
|
export default async function checkPasswordIsValid<T>(payload: T & { player: Player, password: string }) {
|
||||||
|
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
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
28
leaky-ships/lib/backend/components/checkTokenIsValid.ts
Normal file
28
leaky-ships/lib/backend/components/checkTokenIsValid.ts
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
import { Token } from "@prisma/client"
|
||||||
|
import jwt from "jsonwebtoken"
|
||||||
|
import jwtVerifyCatch from "../jwtVerifyCatch"
|
||||||
|
|
||||||
|
async function checkTokenIsValid<T>(payload: T & { token: string, tokenType: Token['type'] }) {
|
||||||
|
const { token, tokenType } = payload
|
||||||
|
|
||||||
|
// Verify the token and get the payload
|
||||||
|
let tokenData: string | jwt.JwtPayload
|
||||||
|
try {
|
||||||
|
tokenData = jwt.verify(token, process.env.ACCESS_TOKEN_SECRET as string)
|
||||||
|
} catch (err: any) {
|
||||||
|
// Deal with the problem in more detail
|
||||||
|
return Promise.reject(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
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return { ...payload, tokenBody: token, tokenIsValid: true }
|
||||||
|
}
|
||||||
|
|
||||||
|
export default checkTokenIsValid
|
28
leaky-ships/lib/backend/components/createAnonymousDB.ts
Normal file
28
leaky-ships/lib/backend/components/createAnonymousDB.ts
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
import prisma from "../../prisma"
|
||||||
|
|
||||||
|
async function createAnonymousDB<T>(payload: T) {
|
||||||
|
const player = await prisma.player.create({
|
||||||
|
data: {
|
||||||
|
anonymous: true
|
||||||
|
}
|
||||||
|
})
|
||||||
|
// .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 { ...payload, player }
|
||||||
|
}
|
||||||
|
|
||||||
|
export default createAnonymousDB
|
34
leaky-ships/lib/backend/components/createPlayerDB.ts
Normal file
34
leaky-ships/lib/backend/components/createPlayerDB.ts
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
import bcrypt from "bcrypt"
|
||||||
|
import prisma from "../../prisma"
|
||||||
|
|
||||||
|
async function createPlayerDB<T>(payload: T & { username: string, password: string }) {
|
||||||
|
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
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export default createPlayerDB
|
36
leaky-ships/lib/backend/components/createTokenDB.ts
Normal file
36
leaky-ships/lib/backend/components/createTokenDB.ts
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
import { Player, Token } from "@prisma/client"
|
||||||
|
import jwt from "jsonwebtoken"
|
||||||
|
import { v4 as uuidv4 } from "uuid"
|
||||||
|
import prisma from "../../prisma"
|
||||||
|
|
||||||
|
const tokenLifetime = {
|
||||||
|
REFRESH: 172800,
|
||||||
|
ACCESS: 15
|
||||||
|
};
|
||||||
|
|
||||||
|
export default async function createTokenDB<T>(payload: T & { player: Player, newTokenType: Token['type'] }) {
|
||||||
|
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
|
||||||
|
const newTokenDB = await prisma.token.create({
|
||||||
|
data: {
|
||||||
|
token: newToken,
|
||||||
|
type: newTokenType,
|
||||||
|
expires: new Date(Date.now() + tokenLifetime[newTokenType] + '000'),
|
||||||
|
owner: {
|
||||||
|
connect: {
|
||||||
|
id: player.id
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
return {
|
||||||
|
...payload,
|
||||||
|
newToken,
|
||||||
|
newTokenDB
|
||||||
|
}
|
||||||
|
}
|
24
leaky-ships/lib/backend/components/getPlayerByIdDB.ts
Normal file
24
leaky-ships/lib/backend/components/getPlayerByIdDB.ts
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
import { Token } from "@prisma/client"
|
||||||
|
import prisma from "../../prisma"
|
||||||
|
|
||||||
|
export default async function getPlayerByIdDB<T>(payload: T & { tokenDB: Token }) {
|
||||||
|
const { tokenDB } = payload
|
||||||
|
// Find Host in DB if it still exists (just to make sure)
|
||||||
|
const player = await prisma.player.findUnique({
|
||||||
|
where: {
|
||||||
|
id: tokenDB.ownerId
|
||||||
|
}
|
||||||
|
})
|
||||||
|
if (!player) {
|
||||||
|
return Promise.reject({
|
||||||
|
message: 'Player not found in DB!',
|
||||||
|
statusCode: 401,
|
||||||
|
solved: false
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
...payload,
|
||||||
|
player
|
||||||
|
}
|
||||||
|
}
|
29
leaky-ships/lib/backend/components/getPlayerByNameDB.ts
Normal file
29
leaky-ships/lib/backend/components/getPlayerByNameDB.ts
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
import prisma from "../../prisma"
|
||||||
|
|
||||||
|
export default async function getPlayerByNameDB<T>(payload: T & { username: string }) {
|
||||||
|
const { username } = payload
|
||||||
|
// Find Player in DB if it still exists (just to make sure)
|
||||||
|
const player = await Promise.any([
|
||||||
|
prisma.player.findUnique({
|
||||||
|
where: {
|
||||||
|
username: username
|
||||||
|
}
|
||||||
|
}), prisma.player.findUnique({
|
||||||
|
where: {
|
||||||
|
email: username
|
||||||
|
}
|
||||||
|
})
|
||||||
|
])
|
||||||
|
if (!player) {
|
||||||
|
return Promise.reject({
|
||||||
|
message: 'Player not found in DB!',
|
||||||
|
statusCode: 401,
|
||||||
|
solved: false
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
...payload,
|
||||||
|
player
|
||||||
|
}
|
||||||
|
}
|
52
leaky-ships/lib/backend/components/getTokenDB.ts
Normal file
52
leaky-ships/lib/backend/components/getTokenDB.ts
Normal file
|
@ -0,0 +1,52 @@
|
||||||
|
import { NextApiRequest, NextApiResponse } from "next"
|
||||||
|
import prisma from "../../prisma"
|
||||||
|
|
||||||
|
async function getTokenDB<T>(payload: T & {
|
||||||
|
tokenBody: string
|
||||||
|
tokenIsValid: boolean,
|
||||||
|
req: NextApiRequest,
|
||||||
|
res: NextApiResponse<any>,
|
||||||
|
}) {
|
||||||
|
const { tokenBody } = payload
|
||||||
|
|
||||||
|
// Find refresh token in DB
|
||||||
|
const tokenDB = await prisma.token.findUnique({
|
||||||
|
where: {
|
||||||
|
token: tokenBody
|
||||||
|
}
|
||||||
|
})
|
||||||
|
if (!tokenDB) {
|
||||||
|
return Promise.reject({
|
||||||
|
message: 'Access-Token not found in DB!',
|
||||||
|
statusCode: 401,
|
||||||
|
solved: true,
|
||||||
|
type: 'warn'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tokenDB.used) {
|
||||||
|
return Promise.reject({
|
||||||
|
message: 'DBToken was already used!',
|
||||||
|
statusCode: 401,
|
||||||
|
solved: true
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
await prisma.token.update({
|
||||||
|
where: {
|
||||||
|
token: tokenBody
|
||||||
|
},
|
||||||
|
data: {
|
||||||
|
used: true
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// await logging('Old token has been invalidated.', ['debug'], req)
|
||||||
|
|
||||||
|
return {
|
||||||
|
...payload,
|
||||||
|
tokenDB
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default getTokenDB
|
19
leaky-ships/lib/backend/components/getTokenFromBody.ts
Normal file
19
leaky-ships/lib/backend/components/getTokenFromBody.ts
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
import { NextApiRequest } from "next"
|
||||||
|
|
||||||
|
async function getTokenFromBody<T>(payload: T & { req: NextApiRequest }) {
|
||||||
|
const { req } = payload
|
||||||
|
const token: string = req.body.token
|
||||||
|
|
||||||
|
// Checking for cookie presens, because it is necessary
|
||||||
|
if (!token) {
|
||||||
|
return Promise.reject({
|
||||||
|
message: 'Unauthorized. No Access-Token.',
|
||||||
|
statusCode: 401,
|
||||||
|
solved: true,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return { ...payload, token }
|
||||||
|
}
|
||||||
|
|
||||||
|
export default getTokenFromBody
|
20
leaky-ships/lib/backend/components/getTokenFromCookie.ts
Normal file
20
leaky-ships/lib/backend/components/getTokenFromCookie.ts
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
import { Token } from "@prisma/client"
|
||||||
|
import { NextApiRequest } from "next"
|
||||||
|
|
||||||
|
async function getTokenFromCookie<T>(payload: T & { req: NextApiRequest }) {
|
||||||
|
const { req } = payload
|
||||||
|
const token = req.cookies.token
|
||||||
|
|
||||||
|
// Checking for cookie presens, because it is necessary
|
||||||
|
if (!token) {
|
||||||
|
return Promise.reject({
|
||||||
|
message: 'Unauthorized. No cookie.',
|
||||||
|
statusCode: 401,
|
||||||
|
solved: true,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return { ...payload, token, tokenType: 'REFRESH' as Token['type'] }
|
||||||
|
}
|
||||||
|
|
||||||
|
export default getTokenFromCookie
|
15
leaky-ships/lib/backend/components/loginCheck.ts
Normal file
15
leaky-ships/lib/backend/components/loginCheck.ts
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
import { Token } from "@prisma/client"
|
||||||
|
import { Logging } from "../logging"
|
||||||
|
|
||||||
|
export default async function loginCheck<T>(payload: T & { loginCheck: boolean, tokenDB: Token, tokenType: 'REFRESH' }) {
|
||||||
|
const { loginCheck, tokenDB } = payload
|
||||||
|
// True login check response
|
||||||
|
if (loginCheck) {
|
||||||
|
return Promise.resolve({
|
||||||
|
message: 'loginCheck ' + loginCheck + ' of ' + tokenDB.id,
|
||||||
|
body: { loggedIn: true },
|
||||||
|
type: ['debug', 'info.cyan'] as Logging[]
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return payload
|
||||||
|
}
|
12
leaky-ships/lib/backend/components/sendError.ts
Normal file
12
leaky-ships/lib/backend/components/sendError.ts
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
import { NextApiRequest, NextApiResponse } from "next"
|
||||||
|
import logging from "../logging"
|
||||||
|
|
||||||
|
export default function sendError<T>(
|
||||||
|
req: NextApiRequest,
|
||||||
|
res: NextApiResponse<T>,
|
||||||
|
err: any
|
||||||
|
) {
|
||||||
|
// 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)
|
||||||
|
}
|
22
leaky-ships/lib/backend/components/sendResponse.ts
Normal file
22
leaky-ships/lib/backend/components/sendResponse.ts
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
import { NextApiRequest, NextApiResponse } from "next"
|
||||||
|
import logging, { Logging } from "../logging"
|
||||||
|
|
||||||
|
export interface Result<T> {
|
||||||
|
message: string,
|
||||||
|
statusCode?: number,
|
||||||
|
body?: T,
|
||||||
|
type?: Logging[],
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function sendResponse<T>(payload: {
|
||||||
|
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)
|
||||||
|
}
|
|
@ -1,5 +1,7 @@
|
||||||
|
import { Token } from "@prisma/client"
|
||||||
|
|
||||||
export default async function jwtVerifyCatch(
|
export default async function jwtVerifyCatch(
|
||||||
tokenType: 'refreshToken' | 'accessToken',
|
tokenType: Token['type'],
|
||||||
err: Error
|
err: Error
|
||||||
) {
|
) {
|
||||||
switch (err.message) {
|
switch (err.message) {
|
||||||
|
|
23
leaky-ships/lib/frontend/checkIsLoggedIn.ts
Normal file
23
leaky-ships/lib/frontend/checkIsLoggedIn.ts
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
import { GetServerSidePropsContext, PreviewData } from "next"
|
||||||
|
import { ParsedUrlQuery } from "querystring"
|
||||||
|
import getTokenFromCookie from "../backend/components/getTokenFromCookie"
|
||||||
|
import checkTokenIsValid from "../backend/components/checkTokenIsValid"
|
||||||
|
import getTokenDB from "../backend/components/getTokenDB"
|
||||||
|
import getPlayerByIdDB from "../backend/components/getPlayerByIdDB"
|
||||||
|
import logging from "../backend/logging"
|
||||||
|
|
||||||
|
export default async function checkIsLoggedIn(context: GetServerSidePropsContext<ParsedUrlQuery, PreviewData>) {
|
||||||
|
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)
|
||||||
|
|
||||||
|
logging('loginCheck ' + (isLoggedIn ? true : '-> loggedIn: ' + false), ['debug', 'info.cyan'], req)
|
||||||
|
|
||||||
|
return isLoggedIn
|
||||||
|
}
|
7
leaky-ships/lib/frontend/getAccessToken.ts
Normal file
7
leaky-ships/lib/frontend/getAccessToken.ts
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
export default function getAccessToken(): Promise<string> {
|
||||||
|
return fetch('/api/auth', {
|
||||||
|
method: 'GET',
|
||||||
|
})
|
||||||
|
.then(res => res.json())
|
||||||
|
.then(res => res.newAccessToken)
|
||||||
|
}
|
49
leaky-ships/pages/api/auth.ts
Normal file
49
leaky-ships/pages/api/auth.ts
Normal file
|
@ -0,0 +1,49 @@
|
||||||
|
import { NextApiRequest, NextApiResponse } from "next"
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
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))
|
||||||
|
}
|
||||||
|
|
||||||
|
async function authResponse<T>(payload: {
|
||||||
|
newToken: string,
|
||||||
|
newTokenDB: Token,
|
||||||
|
tokenDB: Token,
|
||||||
|
req: NextApiRequest,
|
||||||
|
res: NextApiResponse<T>
|
||||||
|
}) {
|
||||||
|
const { newToken, newTokenDB, tokenDB, req, res } = payload
|
||||||
|
|
||||||
|
// 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[]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
48
leaky-ships/pages/api/data.ts
Normal file
48
leaky-ships/pages/api/data.ts
Normal file
|
@ -0,0 +1,48 @@
|
||||||
|
import { NextApiRequest, NextApiResponse } from "next"
|
||||||
|
import getTokenFromBody from "../../lib/backend/components/getTokenFromBody"
|
||||||
|
import checkTokenIsValid from "../../lib/backend/components/checkTokenIsValid"
|
||||||
|
import getTokenDB from "../../lib/backend/components/getTokenDB"
|
||||||
|
import getPlayerByIdDB from "../../lib/backend/components/getPlayerByIdDB"
|
||||||
|
import sendResponse from "../../lib/backend/components/sendResponse"
|
||||||
|
import sendError from "../../lib/backend/components/sendError"
|
||||||
|
import { Logging } from "../../lib/backend/logging"
|
||||||
|
import { Game, Player, Token } from "@prisma/client"
|
||||||
|
|
||||||
|
interface Data {
|
||||||
|
games: Game[]
|
||||||
|
}
|
||||||
|
|
||||||
|
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))
|
||||||
|
}
|
||||||
|
|
||||||
|
async function dataResponse<T>(payload: {
|
||||||
|
player: Player,
|
||||||
|
tokenDB: Token,
|
||||||
|
// games: Game[],
|
||||||
|
req: NextApiRequest,
|
||||||
|
res: NextApiResponse<T>
|
||||||
|
}) {
|
||||||
|
const { player, tokenDB, req, res } = payload
|
||||||
|
|
||||||
|
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[]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
86
leaky-ships/pages/api/login.ts
Normal file
86
leaky-ships/pages/api/login.ts
Normal file
|
@ -0,0 +1,86 @@
|
||||||
|
import { NextApiRequest, NextApiResponse } from "next"
|
||||||
|
import logging, { Logging } from "../../lib/backend/logging"
|
||||||
|
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 { setCookie } from "cookies-next"
|
||||||
|
import { Player, Token } from "@prisma/client"
|
||||||
|
import prisma from "../../lib/prisma"
|
||||||
|
|
||||||
|
interface Data {
|
||||||
|
loggedIn: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
export default async function login(
|
||||||
|
req: NextApiRequest,
|
||||||
|
res: NextApiResponse<any>
|
||||||
|
) {
|
||||||
|
const { username, password } = req.body
|
||||||
|
return preCheck({ req, res, username, password, newTokenType: 'REFRESH' as Token['type'] })
|
||||||
|
.then(getPlayerByNameDB)
|
||||||
|
.then(checkPasswordIsValid)
|
||||||
|
.then(createTokenDB)
|
||||||
|
.then(loginResponse<Data>)
|
||||||
|
.then(sendResponse<Data>)
|
||||||
|
.catch(err => sendError(req, res, err))
|
||||||
|
}
|
||||||
|
|
||||||
|
async function preCheck<T>(payload: T & {
|
||||||
|
req: NextApiRequest,
|
||||||
|
res: NextApiResponse<T>
|
||||||
|
}) {
|
||||||
|
const { req } = 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
|
||||||
|
}
|
||||||
|
})
|
||||||
|
await logging('Old token has been invalidated.', ['debug'], req)
|
||||||
|
}
|
||||||
|
return { ...payload, noCookiePresent: true }
|
||||||
|
}
|
||||||
|
|
||||||
|
async function loginResponse<T>(payload: {
|
||||||
|
player: Player,
|
||||||
|
passwordIsValid: boolean,
|
||||||
|
refreshToken: string,
|
||||||
|
refreshTokenDB: Token,
|
||||||
|
req: NextApiRequest,
|
||||||
|
res: NextApiResponse<T>
|
||||||
|
}) {
|
||||||
|
const { player, refreshToken, refreshTokenDB, req, res } = payload
|
||||||
|
|
||||||
|
// Set login cookie
|
||||||
|
setCookie('token', refreshToken, {
|
||||||
|
req,
|
||||||
|
res,
|
||||||
|
maxAge: 172800000,
|
||||||
|
httpOnly: true,
|
||||||
|
sameSite: true,
|
||||||
|
secure: true,
|
||||||
|
})
|
||||||
|
|
||||||
|
// Successfull response
|
||||||
|
return {
|
||||||
|
req,
|
||||||
|
res,
|
||||||
|
result: {
|
||||||
|
message: 'User ' + player.id + ' logged in and generated Refresh-Token: ' + refreshTokenDB.id,
|
||||||
|
body: { loggedIn: true },
|
||||||
|
type: ['debug', 'info.cyan'] as Logging[]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
47
leaky-ships/pages/api/logout.ts
Normal file
47
leaky-ships/pages/api/logout.ts
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
import { NextApiRequest, NextApiResponse } from "next"
|
||||||
|
import checkTokenIsValid from "../../lib/backend/components/checkTokenIsValid"
|
||||||
|
import sendResponse from "../../lib/backend/components/sendResponse"
|
||||||
|
import sendError from "../../lib/backend/components/sendError"
|
||||||
|
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"
|
||||||
|
|
||||||
|
interface Data {
|
||||||
|
loggedOut: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
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))
|
||||||
|
}
|
||||||
|
|
||||||
|
async function logoutResponse<T>(payload: {
|
||||||
|
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[]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
41
leaky-ships/pages/api/register.ts
Normal file
41
leaky-ships/pages/api/register.ts
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
import { NextApiRequest, NextApiResponse } from "next"
|
||||||
|
import createPlayerDB from "../../lib/backend/components/createPlayerDB"
|
||||||
|
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"
|
||||||
|
|
||||||
|
interface Data {
|
||||||
|
registered: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
export default async function register(
|
||||||
|
req: NextApiRequest,
|
||||||
|
res: NextApiResponse<any>
|
||||||
|
) {
|
||||||
|
const { username, password } = req.body
|
||||||
|
return createPlayerDB({ req, res, username, password })
|
||||||
|
.then(registerResponse<Data>)
|
||||||
|
.then(sendResponse<Data>)
|
||||||
|
.catch(err => sendError(req, res, err))
|
||||||
|
}
|
||||||
|
|
||||||
|
async function registerResponse<T>(payload: {
|
||||||
|
player: Player,
|
||||||
|
req: NextApiRequest,
|
||||||
|
res: NextApiResponse<T>
|
||||||
|
}) {
|
||||||
|
const { player, req, res } = payload
|
||||||
|
|
||||||
|
// Successfull response
|
||||||
|
return {
|
||||||
|
req,
|
||||||
|
res,
|
||||||
|
result: {
|
||||||
|
message: 'Player created : ' + player.id,
|
||||||
|
statusCode: 201,
|
||||||
|
body: { registered: true },
|
||||||
|
type: ['debug', 'info.cyan'] as Logging[]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue