add rotating keys
This commit is contained in:
parent
f0ab000415
commit
d92305e504
@ -10,6 +10,8 @@
|
|||||||
"typescript": "^5.0.0"
|
"typescript": "^5.0.0"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"express-fingerprint": "^1.2.2"
|
"crypto": "^1.0.1",
|
||||||
|
"express-fingerprint": "^1.2.2",
|
||||||
|
"node-fetch": "^3.3.2"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,8 +1,11 @@
|
|||||||
import { Request, RequestHandler } from "express";
|
import { Request, RequestHandler } from "express";
|
||||||
import { getRedisClient } from "../clients/db/RedisDbProvider";
|
import { getRedisClient } from "../clients/db/RedisDbProvider";
|
||||||
import { getAuthModes, getDoorSettingString } from "../util/EnvConfigUtil";
|
import { getAllDoorNames, getAuthModes, getDoorSettingString } from "../util/EnvConfigUtil";
|
||||||
import { IAuthMode } from "../types/IAuthMode";
|
import { IAuthMode } from "../types/IAuthMode";
|
||||||
import { IDoorConfig } from "../types/IDoorConfig";
|
import { IDoorConfig } from "../types/IDoorConfig";
|
||||||
|
import { doorRotatingKey } from "../types/RedisKeys";
|
||||||
|
import crypto from "crypto";
|
||||||
|
import fetch from "node-fetch";
|
||||||
|
|
||||||
const client = await getRedisClient();
|
const client = await getRedisClient();
|
||||||
|
|
||||||
@ -14,12 +17,15 @@ export const HandleAuthMode: RequestHandler = async (req, res, next) => {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const isAuthorized = authModes.some((mode) => {
|
const checkAuth = async (mode: IAuthMode): Promise<boolean> => {
|
||||||
switch(mode) {
|
switch(mode) {
|
||||||
case IAuthMode.FIXED_PIN: return handleFixedPinAuth(req)
|
case IAuthMode.FIXED_PIN: return handleFixedPinAuth(req)
|
||||||
|
case IAuthMode.RANDOM_ROTATING_KEY: return await handleRandomRotatingKeyAuth(req)
|
||||||
default: return false;
|
default: return false;
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
|
|
||||||
|
const isAuthorized = (await Promise.all(authModes.map((mode) => checkAuth(mode)))).some(b => b);
|
||||||
|
|
||||||
if (!isAuthorized) {
|
if (!isAuthorized) {
|
||||||
res.status(401).json({ msg: 'Unauthorized' });
|
res.status(401).json({ msg: 'Unauthorized' });
|
||||||
@ -32,4 +38,28 @@ export const HandleAuthMode: RequestHandler = async (req, res, next) => {
|
|||||||
const handleFixedPinAuth = (req: Request): boolean => {
|
const handleFixedPinAuth = (req: Request): boolean => {
|
||||||
const fixedPin = getDoorSettingString(req.params.id, IDoorConfig.FIXED_PIN);
|
const fixedPin = getDoorSettingString(req.params.id, IDoorConfig.FIXED_PIN);
|
||||||
return fixedPin !== undefined && req.query['key'] === fixedPin;
|
return fixedPin !== undefined && req.query['key'] === fixedPin;
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleRandomRotatingKeyAuth = async (req: Request): Promise<boolean> => {
|
||||||
|
const currentPin = await client.get(doorRotatingKey(req.params.id));
|
||||||
|
|
||||||
|
if (currentPin === req.query['rotatingKey']) {
|
||||||
|
await replaceDoorRandomKey(req.params.id);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const initializeRandomDoorPins = () => {
|
||||||
|
const doors = getAllDoorNames();
|
||||||
|
doors.forEach(replaceDoorRandomKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
export const replaceDoorRandomKey = async (door: string) => {
|
||||||
|
const newKey = crypto.randomBytes(20).toString('hex');
|
||||||
|
|
||||||
|
await client.put(doorRotatingKey(door), newKey);
|
||||||
|
|
||||||
|
const message = `New key for door ${door}! Unlock link: ${Bun.env.BASE_DOMAIN}/api/door/${door}/auth?rotatingKey=${newKey}`;
|
||||||
|
await fetch(Bun.env.ROTATING_KEY_NTFY, { method: "POST", body: message });
|
||||||
}
|
}
|
||||||
@ -1,7 +1,11 @@
|
|||||||
import express from "express";
|
import express from "express";
|
||||||
import DoorRouter from "./routers/DoorRouter";
|
import DoorRouter from "./routers/DoorRouter";
|
||||||
|
import { getAllDoorNames } from "./util/EnvConfigUtil";
|
||||||
|
import { getRedisClient } from "./clients/db/RedisDbProvider";
|
||||||
|
import { initializeRandomDoorPins } from "./middlewares/DoorAuthModes";
|
||||||
|
|
||||||
const Fingerprint = require('express-fingerprint');
|
const Fingerprint = require('express-fingerprint');
|
||||||
|
const client = getRedisClient();
|
||||||
|
|
||||||
const app = express();
|
const app = express();
|
||||||
|
|
||||||
@ -25,4 +29,5 @@ app.use('/api/door', DoorRouter);
|
|||||||
|
|
||||||
app.listen(5000, async () => {
|
app.listen(5000, async () => {
|
||||||
console.log("listening on port 5000");
|
console.log("listening on port 5000");
|
||||||
|
initializeRandomDoorPins();
|
||||||
});
|
});
|
||||||
@ -5,5 +5,6 @@ declare module "bun" {
|
|||||||
REDIS_CONNECT_URL: string; // `redis[s]://[[username][:password]@][host][:port][/db-number]`
|
REDIS_CONNECT_URL: string; // `redis[s]://[[username][:password]@][host][:port][/db-number]`
|
||||||
DOOR_OPEN_TIMEOUT: number;
|
DOOR_OPEN_TIMEOUT: number;
|
||||||
DOOR_FIXED_PIN: string;
|
DOOR_FIXED_PIN: string;
|
||||||
|
ROTATING_KEY_NTFY: string;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1,3 +1,4 @@
|
|||||||
export enum IAuthMode {
|
export enum IAuthMode {
|
||||||
FIXED_PIN = "FIXED_PIN",
|
FIXED_PIN = "FIXED_PIN",
|
||||||
|
RANDOM_ROTATING_KEY = "RANDOM_ROTATING_KEY",
|
||||||
}
|
}
|
||||||
@ -7,6 +7,10 @@ export function doorStatusKey(id: string) {
|
|||||||
return concatKeys(RedisKeys.DOORS, id, 'open');
|
return concatKeys(RedisKeys.DOORS, id, 'open');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function doorRotatingKey(id: string) {
|
||||||
|
return concatKeys(RedisKeys.DOORS, id, 'rotatingKey');
|
||||||
|
}
|
||||||
|
|
||||||
export function concatKeys(...keys: String[]) {
|
export function concatKeys(...keys: String[]) {
|
||||||
return keys.join(':');
|
return keys.join(':');
|
||||||
}
|
}
|
||||||
@ -36,4 +36,16 @@ export const getDoorSettingTimeLock = (door: string): number[] => {
|
|||||||
|
|
||||||
// never locked (always -1 < hr < 25)
|
// never locked (always -1 < hr < 25)
|
||||||
return [25, -1];
|
return [25, -1];
|
||||||
|
}
|
||||||
|
|
||||||
|
export const getAllDoorNames = (): string[] => {
|
||||||
|
const names: string[] = [];
|
||||||
|
|
||||||
|
Object.keys(Bun.env).forEach(key => {
|
||||||
|
if (key.startsWith(IDoorConfig.AUTH_MODES)) {
|
||||||
|
names.push(key.replace(IDoorConfig.AUTH_MODES + "_", "").toLowerCase());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return names;
|
||||||
}
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user