Základ zobrazování ověřených uživatelů

This commit is contained in:
2023-07-30 23:36:18 +02:00
parent 028186c8ea
commit 8a75c98c9a
6 changed files with 79 additions and 22 deletions

View File

@@ -4,9 +4,10 @@ import jwt from 'jsonwebtoken';
* Vygeneruje a vrátí podepsaný JWT token pro daný login.
*
* @param login přihlašovací jméno uživatele
* @param trusted příznak, zda se jedná o ověřeného uživatele
* @returns JWT token
*/
export function generateToken(login?: string): string {
export function generateToken(login?: string, trusted?: boolean): string {
if (!process.env.JWT_SECRET) {
throw Error("Není vyplněna proměnná prostředí JWT_SECRET");
}
@@ -16,7 +17,7 @@ export function generateToken(login?: string): string {
if (!login || login.trim().length === 0) {
throw Error("Nebyl předán login");
}
return jwt.sign({ login }, process.env.JWT_SECRET);
return jwt.sign({ login, trusted: trusted || false }, process.env.JWT_SECRET);
}
/**
@@ -50,4 +51,20 @@ export function getLogin(token?: string): string {
}
const payload: any = jwt.verify(token, process.env.JWT_SECRET);
return payload.login;
}
/**
* Vrátí zda je uživatel používající daný token ověřený, pokud je token platný.
*
* @param token JWT token
*/
export function getTrusted(token?: string): boolean {
if (!process.env.JWT_SECRET) {
throw Error("Není vyplněna proměnná prostředí JWT_SECRET");
}
if (!token) {
throw Error("Nebyl předán token");
}
const payload: any = jwt.verify(token, process.env.JWT_SECRET);
return payload.trusted || false;
}

View File

@@ -8,7 +8,7 @@ import dotenv from 'dotenv';
import path from 'path';
import { getMenuSladovnicka, getMenuTechTower, getMenuUMotliku } from "./restaurants";
import { getQr } from "./qr";
import { generateToken, getLogin, verify } from "./auth";
import { generateToken, getLogin, getTrusted, verify } from "./auth";
import { Locations, Restaurants } from "../../types";
const ENVIRONMENT = process.env.NODE_ENV || 'production';
@@ -62,7 +62,7 @@ app.post("/api/login", (req, res) => {
// Autentizace pomocí trusted headers
const remoteUser = req.header('remote-user');
if (remoteUser && remoteUser.length > 0) {
res.status(200).json(generateToken(remoteUser));
res.status(200).json(generateToken(remoteUser, true));
return;
}
// Klasická autentizace loginem
@@ -70,7 +70,7 @@ app.post("/api/login", (req, res) => {
throw Error("Nebyl předán login");
}
// TODO zavést podmínky pro délku loginu (min i max)
res.status(200).json(generateToken(req.body.login));
res.status(200).json(generateToken(req.body.login, false));
});
// TODO dočasné řešení - QR se zobrazuje přes <img>, nemáme sem jak dostat token
@@ -207,8 +207,9 @@ app.post("/api/finishDelivery", (req, res) => {
app.post("/api/addChoice", (req, res) => {
const login = getLogin(parseToken(req));
const trusted = getTrusted(parseToken(req));
if (req.body.locationIndex > -1) {
const data = addChoice(login, req.body.locationIndex, req.body.foodIndex);
const data = addChoice(login, trusted, req.body.locationIndex, req.body.foodIndex);
io.emit("message", data);
res.status(200).json(data);
}

View File

@@ -249,6 +249,7 @@ export function initIfNeeded() {
export function removeChoices(login: string, location: Locations) {
const today = formatDate(getToday());
let data: ClientData = db.get(today);
// TODO zajistit, že neověřený uživatel se stejným loginem nemůže mazat volby ověřeného
if (location in data.choices) {
if (login in data.choices[location]) {
delete data.choices[location][login]
@@ -273,11 +274,12 @@ export function removeChoices(login: string, location: Locations) {
export function removeChoice(login: string, location: Locations, foodIndex: number) {
const today = formatDate(getToday());
let data: ClientData = db.get(today);
// TODO řešit ověření uživatele
if (location in data.choices) {
if (login in data.choices[location]) {
const index = data.choices[location][login].indexOf(foodIndex);
const index = data.choices[location][login].options.indexOf(foodIndex);
if (index > -1) {
data.choices[location][login].splice(index, 1)
data.choices[location][login].options.splice(index, 1)
db.set(today, data);
}
}
@@ -309,24 +311,41 @@ function removeChoiceIfPresent(login: string) {
* @param login login uživatele
* @param location vybrané "umístění"
* @param foodIndex volitelný index jídla v daném umístění
* @param trusted příznak, zda se jedná o ověřeného uživatele
* @returns aktuální data
*/
export function addChoice(login: string, location: Locations, foodIndex?: number) {
export function addChoice(login: string, trusted: boolean, location: Locations, foodIndex?: number) {
initIfNeeded();
const today = formatDate(getToday());
let data: ClientData = db.get(today);
// Ověření, že se neověřený užívatel nepokouší přepsat údaje ověřeného
const locations = Object.values(data?.choices);
let found = false;
if (!trusted) {
for (const location of locations) {
if (Object.keys(location).includes(login) && location[login].trusted) {
found = true;
}
}
}
if (!trusted && found) {
throw Error("Nelze změnit volbu ověřeného uživatele");
}
// Pokud měníme pouze lokaci, mažeme případné předchozí
if (foodIndex == null) {
removeChoiceIfPresent(login);
}
const today = formatDate(getToday());
let data: ClientData = db.get(today);
if (!(location in data.choices)) {
data.choices[location] = {};
}
if (!(login in data.choices[location])) {
data.choices[location][login] = [];
data.choices[location][login] = {
trusted,
options: []
};
}
if (foodIndex != null && !data.choices[location][login].includes(foodIndex)) {
data.choices[location][login].push(foodIndex);
if (foodIndex != null && !data.choices[location][login].options.includes(foodIndex)) {
data.choices[location][login].options.push(foodIndex);
}
db.set(today, data);
return data;