Přesun autentizace na server
This commit is contained in:
@@ -1,3 +1,6 @@
|
||||
# Secret pro podepisování JWT tokenů. Minimální délka 32 znaků.
|
||||
# JWT_SECRET='CHANGE_ME'
|
||||
|
||||
# Zapne režim mockování obědových menu.
|
||||
# Vhodné pro vývoj o víkendech, svátcích a dalších dnech, pro které podniky nenabízejí obědové menu.
|
||||
# V tomto režimu vrací server vždy falešné datum (pracovní den) a pevně nadefinovanou, smyšlenou nabídku jídel.
|
||||
|
||||
@@ -7,13 +7,13 @@ import jwt from 'jsonwebtoken';
|
||||
* @returns JWT token
|
||||
*/
|
||||
export function generateToken(login: string): string {
|
||||
if (!process.env.JWT_TOKEN) {
|
||||
throw Error("Není vyplněna proměnná prostředí JWT_TOKEN");
|
||||
if (!process.env.JWT_SECRET) {
|
||||
throw Error("Není vyplněna proměnná prostředí JWT_SECRET");
|
||||
}
|
||||
if (process.env.JWT_TOKEN.length < 32) {
|
||||
throw Error("Proměnná prostředí JWT_TOKEN musí být minimálně 32 znaků");
|
||||
if (process.env.JWT_SECRET.length < 32) {
|
||||
throw Error("Proměnná prostředí JWT_SECRET musí být minimálně 32 znaků");
|
||||
}
|
||||
return jwt.sign({ login }, process.env.JWT_TOKEN);
|
||||
return jwt.sign({ login }, process.env.JWT_SECRET);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -22,11 +22,11 @@ export function generateToken(login: string): string {
|
||||
* @param token JWT token
|
||||
*/
|
||||
export function verify(token: string): boolean {
|
||||
if (!process.env.JWT_TOKEN) {
|
||||
throw Error("Není vyplněna proměnná prostředí JWT_TOKEN");
|
||||
if (!process.env.JWT_SECRET) {
|
||||
throw Error("Není vyplněna proměnná prostředí JWT_SECRET");
|
||||
}
|
||||
try {
|
||||
jwt.verify(token, process.env.JWT_TOKEN);
|
||||
jwt.verify(token, process.env.JWT_SECRET);
|
||||
return true;
|
||||
} catch (err) {
|
||||
return false;
|
||||
@@ -38,10 +38,13 @@ export function verify(token: string): boolean {
|
||||
*
|
||||
* @param token JWT token
|
||||
*/
|
||||
export function getLogin(token: string): string {
|
||||
if (!process.env.JWT_TOKEN) {
|
||||
throw Error("Není vyplněna proměnná prostředí JWT_TOKEN");
|
||||
export function getLogin(token?: string): string {
|
||||
if (!process.env.JWT_SECRET) {
|
||||
throw Error("Není vyplněna proměnná prostředí JWT_SECRET");
|
||||
}
|
||||
const payload: any = jwt.verify(token, process.env.JWT_TOKEN);
|
||||
if (!token) {
|
||||
throw Error("Nebyl předán token");
|
||||
}
|
||||
const payload: any = jwt.verify(token, process.env.JWT_SECRET);
|
||||
return payload.login;
|
||||
}
|
||||
@@ -9,7 +9,7 @@ import path from 'path';
|
||||
import { getMenuSladovnicka, getMenuTechTower, getMenuUMotliku } from "./restaurants";
|
||||
import { getQr } from "./qr";
|
||||
import { Restaurants } from "./types";
|
||||
import { generateToken, verify } from "./auth";
|
||||
import { generateToken, getLogin, verify } from "./auth";
|
||||
|
||||
const ENVIRONMENT = process.env.NODE_ENV || 'production'
|
||||
dotenv.config({ path: path.resolve(__dirname, `../.env.${ENVIRONMENT}`) });
|
||||
@@ -30,6 +30,14 @@ app.use(cors({
|
||||
origin: '*'
|
||||
}));
|
||||
|
||||
const parseToken = (req: any) => {
|
||||
if (req?.headers?.authorization) {
|
||||
return req.headers.authorization.split(' ')[1];
|
||||
}
|
||||
}
|
||||
|
||||
// ----------- Metody nevyžadující token --------------
|
||||
|
||||
app.post("/api/login", (req, res) => {
|
||||
if (!req.body?.login) {
|
||||
throw Error("Nebyl předán login");
|
||||
@@ -39,14 +47,18 @@ app.post("/api/login", (req, res) => {
|
||||
res.status(200).json(token);
|
||||
});
|
||||
|
||||
app.post("/api/verify", (req, res) => {
|
||||
if (!req.body?.token) {
|
||||
res.status(401).send();
|
||||
} else if (verify(req.body.token)) {
|
||||
res.status(200).send();
|
||||
} else {
|
||||
res.status(403).send();
|
||||
// ----------------------------------------------------
|
||||
|
||||
/** Middleware ověřující JWT token */
|
||||
app.use((req, res, next) => {
|
||||
if (!req.headers.authorization) {
|
||||
return res.status(401).json({ error: 'Nebyl předán autentizační token' });
|
||||
}
|
||||
const token = req.headers.authorization.split(' ')[1];
|
||||
if (!verify(token)) {
|
||||
return res.status(403).json({ error: 'Neplatný autentizační token' });
|
||||
}
|
||||
next();
|
||||
});
|
||||
|
||||
/** Vrátí data pro aktuální den. */
|
||||
@@ -76,27 +88,21 @@ app.get("/api/pizza", (req, res) => {
|
||||
|
||||
/** Založí pizza day pro aktuální den, za předpokladu že dosud neexistuje. */
|
||||
app.post("/api/createPizzaDay", (req, res) => {
|
||||
if (!req.body?.creator) {
|
||||
throw Error("Nebyl předán název zakládajícího");
|
||||
}
|
||||
const data = createPizzaDay(req.body.creator);
|
||||
const login = getLogin(parseToken(req));
|
||||
const data = createPizzaDay(login);
|
||||
res.status(200).json(data);
|
||||
io.emit("message", data);
|
||||
});
|
||||
|
||||
/** Smaže pizza day pro aktuální den, za předpokladu že existuje. */
|
||||
app.post("/api/deletePizzaDay", (req, res) => {
|
||||
if (!req.body?.login) {
|
||||
throw Error("Nebyl předán login uživatele");
|
||||
}
|
||||
const data = deletePizzaDay(req.body.login);
|
||||
const login = getLogin(parseToken(req));
|
||||
const data = deletePizzaDay(login);
|
||||
io.emit("message", data);
|
||||
});
|
||||
|
||||
app.post("/api/addPizza", (req, res) => {
|
||||
if (!req.body?.login) {
|
||||
throw Error("Nebyl předán login");
|
||||
}
|
||||
const login = getLogin(parseToken(req));
|
||||
if (isNaN(req.body?.pizzaIndex)) {
|
||||
throw Error("Nebyl předán index pizzy");
|
||||
}
|
||||
@@ -112,74 +118,60 @@ app.post("/api/addPizza", (req, res) => {
|
||||
if (!pizzy[pizzaIndex].sizes[pizzaSizeIndex]) {
|
||||
throw Error("Neplatný index velikosti pizzy: " + pizzaSizeIndex);
|
||||
}
|
||||
const data = addPizzaOrder(req.body.login, pizzy[pizzaIndex], pizzy[pizzaIndex].sizes[pizzaSizeIndex]);
|
||||
const data = addPizzaOrder(login, pizzy[pizzaIndex], pizzy[pizzaIndex].sizes[pizzaSizeIndex]);
|
||||
io.emit("message", data);
|
||||
res.status(200).json({});
|
||||
})
|
||||
});
|
||||
|
||||
app.post("/api/removePizza", (req, res) => {
|
||||
if (!req.body?.login) {
|
||||
throw Error("Nebyl předán login");
|
||||
}
|
||||
const login = getLogin(parseToken(req));
|
||||
if (!req.body?.pizzaOrder) {
|
||||
throw Error("Nebyla předána objednávka");
|
||||
}
|
||||
const data = removePizzaOrder(req.body.login, req.body?.pizzaOrder);
|
||||
const data = removePizzaOrder(login, req.body?.pizzaOrder);
|
||||
io.emit("message", data);
|
||||
res.status(200).json({});
|
||||
});
|
||||
|
||||
app.post("/api/lockPizzaDay", (req, res) => {
|
||||
if (!req.body?.login) {
|
||||
throw Error("Nebyl předán login");
|
||||
}
|
||||
const data = lockPizzaDay(req.body.login);
|
||||
const login = getLogin(parseToken(req));
|
||||
const data = lockPizzaDay(login);
|
||||
io.emit("message", data);
|
||||
res.status(200).json({});
|
||||
});
|
||||
|
||||
app.post("/api/unlockPizzaDay", (req, res) => {
|
||||
if (!req.body?.login) {
|
||||
throw Error("Nebyl předán login");
|
||||
}
|
||||
const data = unlockPizzaDay(req.body.login);
|
||||
const login = getLogin(parseToken(req));
|
||||
const data = unlockPizzaDay(login);
|
||||
io.emit("message", data);
|
||||
res.status(200).json({});
|
||||
});
|
||||
|
||||
app.post("/api/finishOrder", (req, res) => {
|
||||
if (!req.body?.login) {
|
||||
throw Error("Nebyl předán login");
|
||||
}
|
||||
const data = finishPizzaOrder(req.body.login);
|
||||
const login = getLogin(parseToken(req));
|
||||
const data = finishPizzaOrder(login);
|
||||
io.emit("message", data);
|
||||
res.status(200).json({});
|
||||
});
|
||||
|
||||
app.post("/api/finishDelivery", (req, res) => {
|
||||
if (!req.body?.login) {
|
||||
throw Error("Nebyl předán login");
|
||||
}
|
||||
const data = finishPizzaDelivery(req.body.login, req.body.bankAccount, req.body.bankAccountHolder);
|
||||
const login = getLogin(parseToken(req));
|
||||
const data = finishPizzaDelivery(login, req.body.bankAccount, req.body.bankAccountHolder);
|
||||
io.emit("message", data);
|
||||
res.status(200).json({});
|
||||
});
|
||||
|
||||
app.post("/api/updateChoice", (req, res) => {
|
||||
if (!req.body.hasOwnProperty('name')) {
|
||||
res.status(400).json({});
|
||||
}
|
||||
const data = updateChoice(req.body.name, req.body.choice);
|
||||
const login = getLogin(parseToken(req));
|
||||
const data = updateChoice(login, req.body.choice);
|
||||
io.emit("message", data);
|
||||
res.status(200).json(data);
|
||||
});
|
||||
|
||||
app.get("/api/qr", (req, res) => {
|
||||
if (!req.query?.login || typeof req.query.login !== 'string') {
|
||||
throw Error("Nebyl předán login");
|
||||
}
|
||||
const img = getQr(req.query.login);
|
||||
const login = getLogin(parseToken(req));
|
||||
const img = getQr(login);
|
||||
res.writeHead(200, {
|
||||
'Content-Type': 'image/png',
|
||||
'Content-Length': img.length
|
||||
@@ -188,13 +180,11 @@ app.get("/api/qr", (req, res) => {
|
||||
});
|
||||
|
||||
app.post("/api/updateNote", (req, res) => {
|
||||
if (!req.body.login) {
|
||||
throw Error("Nebyl předán login");
|
||||
}
|
||||
const login = getLogin(parseToken(req));
|
||||
if (req.body.note && req.body.note.length > 100) {
|
||||
throw Error("Poznámka může mít maximálně 100 znaků");
|
||||
}
|
||||
const data = updateNote(req.body.login, req.body.note);
|
||||
const data = updateNote(login, req.body.note);
|
||||
io.emit("message", data);
|
||||
res.status(200).json(data);
|
||||
});
|
||||
|
||||
@@ -218,6 +218,7 @@ export function finishPizzaDelivery(login: string, bankAccount?: string, bankAcc
|
||||
clientData.pizzaDay.state = PizzaDayState.DELIVERED;
|
||||
|
||||
// Vygenerujeme QR kód, pokud k tomu máme data
|
||||
// TODO berka je potřeba počkat na resolve promises z generateQr a až poté volat save do DB
|
||||
if (bankAccount?.length && bankAccountHolder?.length) {
|
||||
for (const order of clientData.pizzaDay.orders) {
|
||||
if (order.customer !== login) { // zatím platí creator = objednávající, a pro toho nemá QR kód smysl
|
||||
|
||||
Reference in New Issue
Block a user