diff --git a/packages/server/src/middlewares/DoorAuthModes.ts b/packages/server/src/middlewares/DoorAuthModes.ts index 6e8fc95..b66dd96 100644 --- a/packages/server/src/middlewares/DoorAuthModes.ts +++ b/packages/server/src/middlewares/DoorAuthModes.ts @@ -1,13 +1,35 @@ -import { RequestHandler } from "express"; +import { Request, RequestHandler } from "express"; import { getRedisClient } from "../clients/db/RedisDbProvider"; +import { getAuthModes, getDoorSettingString } from "../util/EnvConfigUtil"; +import { IAuthMode } from "../types/IAuthMode"; +import { IDoorConfig } from "../types/IDoorConfig"; const client = await getRedisClient(); -export const ValidQueryParamAuth: RequestHandler = async (req, res, next) => { - if (req.query['key'] !== Bun.env.DOOR_FIXED_PIN) { - res.status(401).json({ msg: "Unauthorized" }); +export const HandleAuthMode: RequestHandler = async (req, res, next) => { + const authModes = getAuthModes(req.params.id); + + if (authModes.length === 0) { + res.status(404).json({ msg: `Unknown door ${req.params.id}` }); + return; + } + + const isAuthorized = authModes.some((mode) => { + switch(mode) { + case IAuthMode.FIXED_PIN: return handleFixedPinAuth(req) + default: return false; + } + }); + + if (!isAuthorized) { + res.status(401).json({ msg: 'Unauthorized' }); return; } next(); -}; \ No newline at end of file +} + +const handleFixedPinAuth = (req: Request): boolean => { + const fixedPin = getDoorSettingString(req.params.id, IDoorConfig.FIXED_PIN); + return fixedPin !== undefined && req.query['key'] === fixedPin; +} \ No newline at end of file diff --git a/packages/server/src/routers/DoorRouter.ts b/packages/server/src/routers/DoorRouter.ts index 4091d94..714f90a 100644 --- a/packages/server/src/routers/DoorRouter.ts +++ b/packages/server/src/routers/DoorRouter.ts @@ -1,7 +1,9 @@ import express from "express"; import { getRedisClient } from "../clients/db/RedisDbProvider"; import { doorStatusKey } from "../types/RedisKeys"; -import { ValidQueryParamAuth } from "../middlewares/DoorAuthModes"; +import { HandleAuthMode } from "../middlewares/DoorAuthModes"; +import { getDoorSettingNumber, getDoorSettingString } from "../util/EnvConfigUtil"; +import { IDoorConfig } from "../types/IDoorConfig"; const router = express.Router(); const client = await getRedisClient(); @@ -12,6 +14,10 @@ router.get('/:id/status', async(req, res) => { if (isOpen) { const fingerprint = JSON.parse(isOpen); res.status(200).json({ status: 'open', fingerprint }); + + if (getDoorSettingString(req.params.id, IDoorConfig.CLOSE_AFTER_POLL)) { + await client.remove(doorStatusKey(req.params.id)); + } return; } @@ -23,14 +29,16 @@ router.delete('/:id/status', async(req, res) => { res.status(200).json({ msg: `Closed the door ${req.params.id}` }); }); -router.all('/:id/auth', ValidQueryParamAuth, async(req, res) => { +router.all('/:id/auth', HandleAuthMode, async(req, res) => { const statusKey = doorStatusKey(req.params.id); const fingerprint = (req as any).fingerprint; + const timeout = getDoorSettingNumber(req.params.id, IDoorConfig.OPEN_TIMEOUT) || 60; + await client.put(statusKey, JSON.stringify(fingerprint)); - await client.getClient().expire(statusKey, Bun.env.DOOR_OPEN_TIMEOUT); - res.status(200).json({ msg: `Opened the door "${req.params.id}" for ${Bun.env.DOOR_OPEN_TIMEOUT}s` }); + await client.getClient().expire(statusKey, timeout); + res.status(200).json({ msg: `Opened the door "${req.params.id}" for ${timeout}s` }); }); export default router; \ No newline at end of file diff --git a/packages/server/src/types/IAuthMode.ts b/packages/server/src/types/IAuthMode.ts new file mode 100644 index 0000000..35612a8 --- /dev/null +++ b/packages/server/src/types/IAuthMode.ts @@ -0,0 +1,3 @@ +export enum IAuthMode { + FIXED_PIN = "FIXED_PIN", +} \ No newline at end of file diff --git a/packages/server/src/types/IDoorConfig.ts b/packages/server/src/types/IDoorConfig.ts new file mode 100644 index 0000000..99da2e0 --- /dev/null +++ b/packages/server/src/types/IDoorConfig.ts @@ -0,0 +1,6 @@ +export enum IDoorConfig { + AUTH_MODES = "AUTH_MODES", + OPEN_TIMEOUT = "OPEN_TIMEOUT", + FIXED_PIN = "FIXED_PIN", + CLOSE_AFTER_POLL="CLOSE_AFTER_POLL", +} \ No newline at end of file diff --git a/packages/server/src/util/EnvConfigUtil.ts b/packages/server/src/util/EnvConfigUtil.ts new file mode 100644 index 0000000..00a5eb4 --- /dev/null +++ b/packages/server/src/util/EnvConfigUtil.ts @@ -0,0 +1,24 @@ +import { IAuthMode } from "../types/IAuthMode"; +import { IDoorConfig } from "../types/IDoorConfig"; + +const doorToEnv = (door: string): string => { + return door.toUpperCase().replaceAll(' ', '_').replaceAll('-', '_'); +}; + +export const getAuthModes = (door: string): IAuthMode[] => { + const config = getDoorSettingString(door, IDoorConfig.AUTH_MODES); + + if (config) { + return JSON.parse(config); + } + + return []; +}; + +export const getDoorSettingString = (door: string, setting: IDoorConfig): string | undefined => { + return Bun.env[`${setting}_${doorToEnv(door)}`]; +}; + +export const getDoorSettingNumber = (door: string, setting: IDoorConfig): number => { + return parseInt(getDoorSettingString(door, setting) || "0"); +}; \ No newline at end of file