Skip to content

Commit

Permalink
separated files
Browse files Browse the repository at this point in the history
  • Loading branch information
TeddyRoncin committed May 15, 2024
1 parent dcc9cad commit 5236810
Show file tree
Hide file tree
Showing 5 changed files with 233 additions and 213 deletions.
53 changes: 53 additions & 0 deletions web/src/apiRouter.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import {Request, Response, Router} from "express";
import {prisma} from "./prisma";
import logger from "./logger";
import {generateCode} from "./utils";

const apiRouter = Router();

apiRouter.post("/sesame", async (request: Request, response: Response) => {
const sesame: string | undefined = request.body.code;
if (!sesame) return response.status(400).send("Missing code");
if (
typeof sesame !== "string" ||
sesame.length !== (Number(process.env.SESAME_LENGTH) || 4)
)
return response.status(400).send("Invalid code");

const [opening] = await prisma.opening.findMany({
where: {
code: sesame,
date: null,
codeGeneratedAt: new Date(Date.now() - 1000 * 60 * 5),
},
select: {
return: {
select: {
returnOpeningId: true,
},
},
},
});

if (!opening) {
logger.info(`Invalid Sesame provided : ${sesame}`);
return response.status(403).send("Invalid sesame");
}

if (opening.return) {
const returnCode = await generateCode();
await prisma.opening.update({
where: {
id: opening.return.returnOpeningId,
},
data: {
code: returnCode,
codeGeneratedAt: new Date(),
},
});
}

return response.status(200).send("Sésame ouvre toi");
});

export default apiRouter;
216 changes: 3 additions & 213 deletions web/src/app.ts
Original file line number Diff line number Diff line change
@@ -1,224 +1,14 @@
import express, { Request, Response, Router } from "express";
import express from "express";
import dotenv from "dotenv";
import { PrismaClient } from "@prisma/client";
import path from "path";
import cookieParser from "cookie-parser";
import jwt from "jsonwebtoken";
import { XMLParser } from "fast-xml-parser";
import bodyParser from "body-parser";
import logger from "./logger";
import * as Sentry from "@sentry/node";
import webRouter from "./webRouter";
import apiRouter from "./apiRouter";

const prisma = new PrismaClient();
dotenv.config();
const app = express();

const webRouter = Router();

function authenticate(request: Request) {
if (!request.cookies["token"]) {
return null;
}
try {
return (
jwt.verify(request.cookies["token"], process.env.JWT_SECRET) as {
login: string;
}
).login;
} catch (e) {
return null;
}
}

const validOpening = {
codeGeneratedAt: { gte: new Date(Date.now() - 1000 * 60 * 5) },
};

const currentlyBorrowing = {
borrowOpening: { date: { not: null } },
returnOpening: { date: null },
};

async function generateCode() {
let code: string;
let found;
const ciffers = "0123456789";
do {
code =
ciffers[Math.floor(Math.random() * 10)] +
ciffers[Math.floor(Math.random() * 10)] +
ciffers[Math.floor(Math.random() * 10)] +
ciffers[Math.floor(Math.random() * 10)];
found = await prisma.opening.findFirst({ where: { code } });
} while (found);
return code;
}

async function getJoyconsLeft() {
const joyconBorrows = await prisma.borrow.findMany({where: {borrowOpening: {OR: [validOpening, {date: {not: null}}]}, returnOpening: {date: {not: null}}}});
return Number.parseInt(process.env.TOTAL_JOYCONS) - joyconBorrows.reduce((acc, borrow) => acc + borrow.joyconsTaken, 0);
}

webRouter.get("/", async (request: Request, response: Response) => {
const login = authenticate(request);
if (!login) {
return response.redirect("/login");
}
if (request.query['code']) {
return response.sendFile(path.join(__dirname, '../www/getCode.html'));
}
const borrow = await prisma.borrow.findFirst({
where: { user: { login }, ...currentlyBorrowing },
});
if (!borrow) {
return response.sendFile(path.join(__dirname, "../www/borrow.html"));
}
const code = await generateCode();
await prisma.borrow.update({where: {id: borrow.id}, data: {returnOpening: {upsert: {create: {code, codeGeneratedAt: new Date(Date.now())}, update: {code, codeGeneratedAt: new Date(Date.now())}}}}});
return response.redirect(`/?code=${code}`);
});

webRouter.get("/login", async (request: Request, response: Response) => {
if (authenticate(request)) {
return response.redirect("/");
}
if (request.query["ticket"]) {
const res = await fetch(
`https://cas.utt.fr/cas/serviceValidate?service=${encodeURI(
process.env.CAS_SERVICE
)}&ticket=${request.query["ticket"]}`
);
const resData: {
["cas:serviceResponse"]:
| {
["cas:authenticationSuccess"]: {
["cas:attributes"]: {
"cas:uid": string;
"cas:mail": string;
"cas:sn": string;
"cas:givenName": string;
};
};
}
| { "cas:authenticationFailure": unknown };
} = new XMLParser().parse(await res.text());
if ("cas:authenticationFailure" in resData["cas:serviceResponse"]) {
return { status: "invalid", token: "" };
}
const userData = {
login:
resData["cas:serviceResponse"]["cas:authenticationSuccess"][
"cas:attributes"
]["cas:uid"],
mail: resData["cas:serviceResponse"]["cas:authenticationSuccess"][
"cas:attributes"
]["cas:mail"],
lastName:
resData["cas:serviceResponse"]["cas:authenticationSuccess"][
"cas:attributes"
]["cas:sn"],
firstName:
resData["cas:serviceResponse"]["cas:authenticationSuccess"][
"cas:attributes"
]["cas:givenName"],
// TODO : fetch other infos from LDAP
};
let user = await prisma.user.findUnique({
where: { login: userData.login },
});
if (!user) {
await prisma.user.create({ data: userData });
}
const token = jwt.sign({ login: userData.login }, process.env.JWT_SECRET, {
expiresIn: process.env.JWT_EXPIRES_IN,
});
return response.cookie("token", token).redirect("/");
}
return response.sendFile(path.join(__dirname, "../www/login.html"));
});

webRouter.get("/login/cas", async (request: Request, response: Response) => {
return response.redirect(
`https://cas.utt.fr/cas/login?service=${encodeURI(process.env.CAS_SERVICE)}`
);
});

webRouter.post("/", async (request: Request, response: Response) => {
const login = authenticate(request);
if (!login) {
return response.redirect("/login");
}
const joycons = Number.parseInt(request.body.joycons);
const joyconsLeft = await getJoyconsLeft();
if (joycons < 0 || joycons > joyconsLeft) {
return response.send(
`Il ne reste plus que ${joyconsLeft} joycons disponibles`
);
}
const code = await generateCode();
await prisma.borrow.create({
data: {
joyconsTaken: joycons,
borrowOpening: {
create: {
code,
codeGeneratedAt: new Date(),
},
},
returnOpening: { create: {} },
user: { connect: { login } },
},
});
return response.redirect(`/?code=${code}`);
});

const apiRouter = Router();

apiRouter.post("/sesame", async (request: Request, response: Response) => {
const sesame: string | undefined = request.body.code;
if (!sesame) return response.status(400).send("Missing code");
if (
typeof sesame !== "string" ||
sesame.length !== (Number(process.env.SESAME_LENGTH) || 4)
)
return response.status(400).send("Invalid code");

const [opening] = await prisma.opening.findMany({
where: {
code: sesame,
date: null,
codeGeneratedAt: new Date(Date.now() - 1000 * 60 * 5),
},
select: {
return: {
select: {
returnOpeningId: true,
},
},
},
});

if (!opening) {
logger.info(`Invalid Sesame provided : ${sesame}`);
return response.status(403).send("Invalid sesame");
}

if (opening.return) {
const returnCode = await generateCode();
await prisma.opening.update({
where: {
id: opening.return.returnOpeningId,
},
data: {
code: returnCode,
codeGeneratedAt: new Date(),
},
});
}

return response.status(200).send("Sésame ouvre toi");
});

if (process.env.SENTRY_DSN) {
// Initiate Sentry
Sentry.init({
Expand Down
17 changes: 17 additions & 0 deletions web/src/prisma.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import {PrismaClient} from "@prisma/client";

export const prisma = new PrismaClient();

const validOpening = {
codeGeneratedAt: { gte: new Date(Date.now() - 1000 * 60 * 5) },
}

const currentlyBorrowing = {
borrowOpening: { date: { not: null } },
returnOpening: { date: null },
}

export const prismaUtils = {
validOpening,
currentlyBorrowing,
};
38 changes: 38 additions & 0 deletions web/src/utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import {Request} from "express";
import jwt from "jsonwebtoken";
import {prisma, prismaUtils} from "./prisma";

export function authenticate(request: Request) {
if (!request.cookies["token"]) {
return null;
}
try {
return (
jwt.verify(request.cookies["token"], process.env.JWT_SECRET) as {
login: string;
}
).login;
} catch (e) {
return null;
}
}

export async function generateCode() {
let code: string;
let found;
const ciffers = "0123456789";
do {
code =
ciffers[Math.floor(Math.random() * 10)] +
ciffers[Math.floor(Math.random() * 10)] +
ciffers[Math.floor(Math.random() * 10)] +
ciffers[Math.floor(Math.random() * 10)];
found = await prisma.opening.findFirst({ where: { code } });
} while (found);
return code;
}

export async function getJoyconsLeft() {
const joyconBorrows = await prisma.borrow.findMany({where: {borrowOpening: {OR: [prismaUtils.validOpening, {date: {not: null}}]}, returnOpening: {date: {not: null}}}});
return Number.parseInt(process.env.TOTAL_JOYCONS) - joyconBorrows.reduce((acc, borrow) => acc + borrow.joyconsTaken, 0);
}
Loading

0 comments on commit 5236810

Please sign in to comment.