diff --git a/Dockerfile b/Dockerfile deleted file mode 100644 index 31e17af..0000000 --- a/Dockerfile +++ /dev/null @@ -1,20 +0,0 @@ -FROM oven/bun - -ADD packages packages -ADD bun.lockb bun.lockb -ADD package.json package.json -ADD tsconfig.json tsconfig.json - -# install all deps -RUN bun install - -# client build -WORKDIR /home/bun/app/packages/client -RUN bun run build - -# move built client to server -RUN mv dist ../server/ -WORKDIR /home/bun/app/packages/server - -# start server -CMD bun run ./src/server.ts \ No newline at end of file diff --git a/README.md b/README.md index a5bc215..cac9fbf 100644 --- a/README.md +++ b/README.md @@ -14,13 +14,23 @@ bun run index.ts This project was created using `bun init` in bun v1.0.3. [Bun](https://bun.sh) is a fast all-in-one JavaScript runtime. +## Deployments + +They are configured to happen in gitea actions for CI/CD. If you need to deploy manually, it should be possible as long as you source the requisite envs first. + ## to deploy Doorman API / UI ```bash bun run deploy-serverless ``` -## homeassistant integration +## to deploy Doorman Buzzer client + +```bash +bun run deploy-buzzer-client +``` + +## homeassistant integration poller in configuration.yaml diff --git a/bun.lockb b/bun.lockb index 7e70e09..55ec619 100755 Binary files a/bun.lockb and b/bun.lockb differ diff --git a/docker-compose.yml b/docker-compose.yml deleted file mode 100644 index 646677f..0000000 --- a/docker-compose.yml +++ /dev/null @@ -1,14 +0,0 @@ -version: "3" - -services: - doorman: - container_name: doorman - image: gitea.chromart.dedyn.io/martin/doorman:latest - environment: - - CHALLENGE_EXPIRE_MS=105000 - - BASE_DOMAIN=gitea.chromart.dedyn.io - - REDIS_CONNECT_URL=redis://@redis:6379 - depends_on: - - redis - redis: - image: redis:latest \ No newline at end of file diff --git a/doorman.code-workspace b/doorman.code-workspace index 3b9c664..516e575 100644 --- a/doorman.code-workspace +++ b/doorman.code-workspace @@ -1,16 +1,20 @@ { "folders": [ { - "path": "packages/client" + "name": "doorman-ui", + "path": "packages/doorman-ui" }, { - "path": "packages/server" + "name": "doorman-api", + "path": "packages/doorman-api" }, { + "name": "doorman-client", + "path": "packages/doorman-client" + }, + { + "name": "doorman", "path": "." - }, - { - "path": "packages/serverless" } ], "settings": { diff --git a/package.json b/package.json index 35a5157..973cf63 100644 --- a/package.json +++ b/package.json @@ -7,9 +7,9 @@ "bun-types": "latest" }, "scripts": { - "prepare-client-serverless": "bun --filter 'doorman-client' build && rm -rf packages/serverless/assets/* && mkdir -p packages/serverless/assets/assets && cp -fr packages/client/dist/* packages/serverless/assets/ && cp -f packages/serverless/assets/index.html packages/serverless/assets/assets/index.html", - "deploy-serverless": "bun run prepare-client-serverless && bun --filter 'serverless' deploy", - "deploy-buzzer-client": "bun --filter 'buzzer-client' deploy" + "prepare-ui": "bun --filter 'doorman-ui' build && rm -rf packages/doorman-api/assets/* && mkdir -p packages/doorman-api/assets/assets && cp -fr packages/doorman-ui/dist/* packages/doorman-api/assets/ && cp -f packages/doorman-api/assets/index.html packages/doorman-api/assets/assets/index.html", + "deploy-serverless": "bun run prepare-ui && bun --filter 'doorman-api' deploy", + "deploy-buzzer-client": "bun --filter 'doorman-client' deploy" }, "peerDependencies": { "typescript": "^5.0.0" diff --git a/packages/serverless/.env.example b/packages/doorman-api/.env.example similarity index 100% rename from packages/serverless/.env.example rename to packages/doorman-api/.env.example diff --git a/packages/serverless/.gitignore b/packages/doorman-api/.gitignore similarity index 100% rename from packages/serverless/.gitignore rename to packages/doorman-api/.gitignore diff --git a/packages/buzzer-client/.nvmrc b/packages/doorman-api/.nvmrc similarity index 100% rename from packages/buzzer-client/.nvmrc rename to packages/doorman-api/.nvmrc diff --git a/packages/buzzer-client/.twilioserverlessrc b/packages/doorman-api/.twilioserverlessrc similarity index 100% rename from packages/buzzer-client/.twilioserverlessrc rename to packages/doorman-api/.twilioserverlessrc diff --git a/packages/serverless/README.md b/packages/doorman-api/README.md similarity index 72% rename from packages/serverless/README.md rename to packages/doorman-api/README.md index aa40868..fa24b87 100644 --- a/packages/serverless/README.md +++ b/packages/doorman-api/README.md @@ -2,8 +2,8 @@ this project deploys the UI and API to twilio functions https://doorman-6741-prod.twil.io -It uses a cloud redis cache +It uses DDB for the backend -After the twilio functions I have setup a cloudflare worker at https://doorman.chromart.workers.dev +After the twilio functions I have setup a cloudflare worker at https://doorman.chromart.cc to proxy the requests to the twilio lambda The cloudflare worker just proxies requests so the endpoint is a bit nicer diff --git a/packages/serverless/functions/api/door/auth.js b/packages/doorman-api/functions/api/door/auth.js similarity index 100% rename from packages/serverless/functions/api/door/auth.js rename to packages/doorman-api/functions/api/door/auth.js diff --git a/packages/serverless/functions/api/door/info.js b/packages/doorman-api/functions/api/door/info.js similarity index 100% rename from packages/serverless/functions/api/door/info.js rename to packages/doorman-api/functions/api/door/info.js diff --git a/packages/serverless/functions/api/door/status.js b/packages/doorman-api/functions/api/door/status.js similarity index 100% rename from packages/serverless/functions/api/door/status.js rename to packages/doorman-api/functions/api/door/status.js diff --git a/packages/serverless/functions/common/ddb.private.js b/packages/doorman-api/functions/common/ddb.private.js similarity index 100% rename from packages/serverless/functions/common/ddb.private.js rename to packages/doorman-api/functions/common/ddb.private.js diff --git a/packages/serverless/package.json b/packages/doorman-api/package.json similarity index 95% rename from packages/serverless/package.json rename to packages/doorman-api/package.json index 67c1249..15b4d70 100644 --- a/packages/serverless/package.json +++ b/packages/doorman-api/package.json @@ -1,5 +1,5 @@ { - "name": "serverless", + "name": "doorman-api", "version": "0.0.0", "private": true, "scripts": { diff --git a/packages/buzzer-client/.env.example b/packages/doorman-client/.env.example similarity index 100% rename from packages/buzzer-client/.env.example rename to packages/doorman-client/.env.example diff --git a/packages/buzzer-client/.gitignore b/packages/doorman-client/.gitignore similarity index 100% rename from packages/buzzer-client/.gitignore rename to packages/doorman-client/.gitignore diff --git a/packages/serverless/.nvmrc b/packages/doorman-client/.nvmrc similarity index 100% rename from packages/serverless/.nvmrc rename to packages/doorman-client/.nvmrc diff --git a/packages/serverless/.twilioserverlessrc b/packages/doorman-client/.twilioserverlessrc similarity index 100% rename from packages/serverless/.twilioserverlessrc rename to packages/doorman-client/.twilioserverlessrc diff --git a/packages/buzzer-client/.vscode/settings.json b/packages/doorman-client/.vscode/settings.json similarity index 100% rename from packages/buzzer-client/.vscode/settings.json rename to packages/doorman-client/.vscode/settings.json diff --git a/packages/buzzer-client/LICENSE b/packages/doorman-client/LICENSE similarity index 100% rename from packages/buzzer-client/LICENSE rename to packages/doorman-client/LICENSE diff --git a/packages/buzzer-client/README.md b/packages/doorman-client/README.md similarity index 100% rename from packages/buzzer-client/README.md rename to packages/doorman-client/README.md diff --git a/packages/buzzer-client/assets/buzzer_welcome_boosted.protected.mp3 b/packages/doorman-client/assets/buzzer_welcome_boosted.protected.mp3 similarity index 100% rename from packages/buzzer-client/assets/buzzer_welcome_boosted.protected.mp3 rename to packages/doorman-client/assets/buzzer_welcome_boosted.protected.mp3 diff --git a/packages/buzzer-client/assets/buzzer_welcome_boostedx2.protected.mp3 b/packages/doorman-client/assets/buzzer_welcome_boostedx2.protected.mp3 similarity index 100% rename from packages/buzzer-client/assets/buzzer_welcome_boostedx2.protected.mp3 rename to packages/doorman-client/assets/buzzer_welcome_boostedx2.protected.mp3 diff --git a/packages/buzzer-client/assets/buzzing_up_boosted.protected.mp3 b/packages/doorman-client/assets/buzzing_up_boosted.protected.mp3 similarity index 100% rename from packages/buzzer-client/assets/buzzing_up_boosted.protected.mp3 rename to packages/doorman-client/assets/buzzing_up_boosted.protected.mp3 diff --git a/packages/buzzer-client/bun.lockb b/packages/doorman-client/bun.lockb similarity index 100% rename from packages/buzzer-client/bun.lockb rename to packages/doorman-client/bun.lockb diff --git a/packages/buzzer-client/functions/buzzer-activated.js b/packages/doorman-client/functions/buzzer-activated.js similarity index 100% rename from packages/buzzer-client/functions/buzzer-activated.js rename to packages/doorman-client/functions/buzzer-activated.js diff --git a/packages/buzzer-client/functions/call-residents.js b/packages/doorman-client/functions/call-residents.js similarity index 100% rename from packages/buzzer-client/functions/call-residents.js rename to packages/doorman-client/functions/call-residents.js diff --git a/packages/buzzer-client/functions/door-open.js b/packages/doorman-client/functions/door-open.js similarity index 100% rename from packages/buzzer-client/functions/door-open.js rename to packages/doorman-client/functions/door-open.js diff --git a/packages/buzzer-client/functions/text-me.js b/packages/doorman-client/functions/text-me.js similarity index 100% rename from packages/buzzer-client/functions/text-me.js rename to packages/doorman-client/functions/text-me.js diff --git a/packages/buzzer-client/package-lock.json b/packages/doorman-client/package-lock.json similarity index 100% rename from packages/buzzer-client/package-lock.json rename to packages/doorman-client/package-lock.json diff --git a/packages/buzzer-client/package.json b/packages/doorman-client/package.json similarity index 95% rename from packages/buzzer-client/package.json rename to packages/doorman-client/package.json index f4310c6..75dd944 100644 --- a/packages/buzzer-client/package.json +++ b/packages/doorman-client/package.json @@ -1,5 +1,5 @@ { - "name": "buzzer-client", + "name": "doorman-client", "version": "0.0.0", "private": true, "scripts": { diff --git a/packages/client/README.md b/packages/doorman-ui/README.md similarity index 100% rename from packages/client/README.md rename to packages/doorman-ui/README.md diff --git a/packages/client/index.html b/packages/doorman-ui/index.html similarity index 100% rename from packages/client/index.html rename to packages/doorman-ui/index.html diff --git a/packages/client/package.json b/packages/doorman-ui/package.json similarity index 97% rename from packages/client/package.json rename to packages/doorman-ui/package.json index 94ac5fc..a160063 100644 --- a/packages/client/package.json +++ b/packages/doorman-ui/package.json @@ -1,5 +1,5 @@ { - "name": "doorman-client", + "name": "doorman-ui", "version": "0.1.0", "private": true, "dependencies": { diff --git a/packages/client/public/Insulin_Nation_Low_Kramer.gif b/packages/doorman-ui/public/Insulin_Nation_Low_Kramer.gif similarity index 100% rename from packages/client/public/Insulin_Nation_Low_Kramer.gif rename to packages/doorman-ui/public/Insulin_Nation_Low_Kramer.gif diff --git a/packages/client/public/global.css b/packages/doorman-ui/public/global.css similarity index 100% rename from packages/client/public/global.css rename to packages/doorman-ui/public/global.css diff --git a/packages/client/public/manifest.json b/packages/doorman-ui/public/manifest.json similarity index 100% rename from packages/client/public/manifest.json rename to packages/doorman-ui/public/manifest.json diff --git a/packages/client/public/robots.txt b/packages/doorman-ui/public/robots.txt similarity index 100% rename from packages/client/public/robots.txt rename to packages/doorman-ui/public/robots.txt diff --git a/packages/client/src/App.tsx b/packages/doorman-ui/src/App.tsx similarity index 100% rename from packages/client/src/App.tsx rename to packages/doorman-ui/src/App.tsx diff --git a/packages/client/src/components/AuthComponent.tsx b/packages/doorman-ui/src/components/AuthComponent.tsx similarity index 100% rename from packages/client/src/components/AuthComponent.tsx rename to packages/doorman-ui/src/components/AuthComponent.tsx diff --git a/packages/client/src/components/CountdownBar.tsx b/packages/doorman-ui/src/components/CountdownBar.tsx similarity index 100% rename from packages/client/src/components/CountdownBar.tsx rename to packages/doorman-ui/src/components/CountdownBar.tsx diff --git a/packages/client/src/index.tsx b/packages/doorman-ui/src/index.tsx similarity index 100% rename from packages/client/src/index.tsx rename to packages/doorman-ui/src/index.tsx diff --git a/packages/client/src/pages/DoorPage.tsx b/packages/doorman-ui/src/pages/DoorPage.tsx similarity index 100% rename from packages/client/src/pages/DoorPage.tsx rename to packages/doorman-ui/src/pages/DoorPage.tsx diff --git a/packages/client/src/types/Action.ts b/packages/doorman-ui/src/types/Action.ts similarity index 100% rename from packages/client/src/types/Action.ts rename to packages/doorman-ui/src/types/Action.ts diff --git a/packages/client/tsconfig.json b/packages/doorman-ui/tsconfig.json similarity index 100% rename from packages/client/tsconfig.json rename to packages/doorman-ui/tsconfig.json diff --git a/packages/client/vite-env.d.ts b/packages/doorman-ui/vite-env.d.ts similarity index 100% rename from packages/client/vite-env.d.ts rename to packages/doorman-ui/vite-env.d.ts diff --git a/packages/client/vite.config.ts b/packages/doorman-ui/vite.config.ts similarity index 100% rename from packages/client/vite.config.ts rename to packages/doorman-ui/vite.config.ts diff --git a/packages/server/package.json b/packages/server/package.json deleted file mode 100644 index ddeefff..0000000 --- a/packages/server/package.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "name": "doorman-server", - "version": "1.0.0", - "main": "index.js", - "license": "MIT", - "scripts": { - "start": "bun --hot run src/server.ts", - "build": "bun tsc" - }, - "dependencies": { - "express": "^4.18.2", - "express-fileupload": "^1.4.0", - "express-rate-limit": "^6.10.0", - "lnurl": "^0.25.1", - "qrcode": "^1.5.3", - "redis": "^4.6.8", - "ts-node": "^10.9.1", - "ts-node-dev": "^2.0.0", - "typescript": "^5.2.2" - }, - "devDependencies": { - "@types/express": "^4.17.17", - "@types/express-fileupload": "^1.4.1", - "@types/express-rate-limit": "^6.0.0", - "@types/node": "^20.6.4", - "@types/qrcode": "^1.5.2" - } -} diff --git a/packages/server/src/clients/db/AbstractDbClient.ts b/packages/server/src/clients/db/AbstractDbClient.ts deleted file mode 100644 index 1d7237f..0000000 --- a/packages/server/src/clients/db/AbstractDbClient.ts +++ /dev/null @@ -1,31 +0,0 @@ -import type { IAccessControl } from "../../types/IAccessControl"; - -export abstract class AbstractDbClient { - /** - * Checks if the given challenge already exists in the db - * @param challenge - challenge to check against db - * @returns true if challenge exists in DB - */ - public abstract doesChallengeExist(challenge: string): Promise; - - // access control methods - /** - * Set an entry in the DB to mark that a particular challenge was completed by a certain key. - * A future operation which presents this challenge will be authenticated by the key associated in this operation - * @param challenge - the challenge which was completed - * @param key - the key which was part of the authentication test - */ - public abstract markChallengeSuccess(challenge: string, key: string): Promise; - - /** - * Calls into the DB to see if a particular challege has been completed. If it has, return the relevant access control metadata. - * This method will also decrement the access count, and remove it if it falls below the number of remaining access tokens on this challenge - * @param challenge - 32 byte hex challenge - */ - public abstract accessFromChallenge(challenge: string): Promise; - - public abstract connect(): Promise; - - public abstract put(key: string, value: string): Promise; - public abstract exists(key: string): Promise; -} \ No newline at end of file diff --git a/packages/server/src/clients/db/RedisDbClient.ts b/packages/server/src/clients/db/RedisDbClient.ts deleted file mode 100644 index 9a738a2..0000000 --- a/packages/server/src/clients/db/RedisDbClient.ts +++ /dev/null @@ -1,69 +0,0 @@ -import type { RedisClientOptions, RedisClientType, RedisFunctions, RedisModules, RedisScripts } from "redis"; -import { createClient } from "redis"; -import type { IAccessControl } from "../../types/IAccessControl"; -import { AbstractDbClient } from "./AbstractDbClient"; -import { RedisKeys } from "../../types/RedisKeys"; - -export class RedisDbClient extends AbstractDbClient { - private client: RedisClientType; - - private timers: { [challenge: string]: NodeJS.Timeout } = {}; - - constructor(onError: (err: any) => void, options?: RedisClientOptions) { - super(); - this.client = createClient(options); - this.client.on("error", onError); - } - - public async connect(): Promise> { - return this.client.connect(); - } - - public doesChallengeExist(challenge: string): Promise { - return this.client.sIsMember(RedisKeys.CHALLENGES, challenge); - } - - public async removeChallenge(challenge: string): Promise { - let res: number = await this.client.sRem(RedisKeys.CHALLENGES, challenge); - clearTimeout(this.timers[challenge]); - delete this.timers[challenge]; - return res > 0; - } - - public async markChallengeSuccess(challenge: string, key: string): Promise { - await this.client.set(challenge, key); - } - - public async accessFromChallenge(challenge: string): Promise { - let key: string | null = await this.client.getDel(challenge); - - if (key == null) { - return null; - } - - return { - key, - remainingAccess: 0, - } - } - - public async put(key: string, value: string): Promise { - return this.client.set(key, value); - } - - public async exists(key: string): Promise { - return this.client.exists(key); - } - - public async get(key: string): Promise { - return this.client.get(key); - } - - public async remove(key: string): Promise { - return this.client.getDel(key); - } - - public getClient() { - return this.client; - } -} \ No newline at end of file diff --git a/packages/server/src/clients/db/RedisDbProvider.ts b/packages/server/src/clients/db/RedisDbProvider.ts deleted file mode 100644 index 7306b1b..0000000 --- a/packages/server/src/clients/db/RedisDbProvider.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { getEnv } from "../../util/EnvConfigUtil"; -import { RedisDbClient } from "./RedisDbClient"; - - -let client: RedisDbClient; - - -export async function getRedisClient(): Promise> { - if (!client) { - client = new RedisDbClient((err) => console.error(err), { url: getEnv("REDIS_CONNECT_URL") }); - await client.connect() - } - - return client; -} \ No newline at end of file diff --git a/packages/server/src/middlewares/DoorAuthModes.ts b/packages/server/src/middlewares/DoorAuthModes.ts deleted file mode 100644 index 235598a..0000000 --- a/packages/server/src/middlewares/DoorAuthModes.ts +++ /dev/null @@ -1,66 +0,0 @@ -import type { Request, RequestHandler } from "express"; -import { getRedisClient } from "../clients/db/RedisDbProvider"; -import { getAllDoorNames, getAuthModes, getDoorSettingString, getEnv } from "../util/EnvConfigUtil"; -import { IAuthMode } from "../types/IAuthMode"; -import { IDoorConfig } from "../types/IDoorConfig"; -import { doorRotatingKey } from "../types/RedisKeys"; -import crypto from "crypto"; -import fetch from "node-fetch"; - -const client = await getRedisClient(); - -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 checkAuth = async (mode: IAuthMode): Promise => { - switch(mode) { - case IAuthMode.FIXED_PIN: return handleFixedPinAuth(req) - case IAuthMode.RANDOM_ROTATING_KEY: return await handleRandomRotatingKeyAuth(req) - default: return false; - } - } - - const isAuthorized = (await Promise.all(authModes.map((mode) => checkAuth(mode)))).some(b => b); - - if (!isAuthorized) { - res.status(401).json({ msg: 'Unauthorized' }); - return; - } - - next(); -} - -const handleFixedPinAuth = (req: Request): boolean => { - const fixedPin = getDoorSettingString(req.params.id, IDoorConfig.FIXED_PIN); - return fixedPin !== undefined && req.query['key'] === fixedPin; -} - -const handleRandomRotatingKeyAuth = async (req: Request): Promise => { - 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: ${getEnv("BASE_DOMAIN")}/door/${door}?rotatingKey=${newKey}`; - console.log(message); - await fetch(getEnv("ROTATING_KEY_NTFY"), { method: "POST", body: message }); -} \ No newline at end of file diff --git a/packages/server/src/middlewares/TimeLockMiddleware.ts b/packages/server/src/middlewares/TimeLockMiddleware.ts deleted file mode 100644 index 78b8da8..0000000 --- a/packages/server/src/middlewares/TimeLockMiddleware.ts +++ /dev/null @@ -1,17 +0,0 @@ -import type { RequestHandler } from "express"; -import { getDoorSettingTimeLock } from "../util/EnvConfigUtil"; -import { IDoorStatus } from "../types/IDoorStatus"; - -export const TimeLockVerify: RequestHandler = async (req, res, next) => { - const timeLock = getDoorSettingTimeLock(req.params.id); - - const timeHr = (new Date()).getHours(); - - - if (timeHr >= timeLock[0] || timeHr <= timeLock[1]) { - res.status(410).json({ status: IDoorStatus.TIME_LOCK, msg: 'Sorry! This door is locked at this hour, try again later' }); - return; - } - - next(); -} \ No newline at end of file diff --git a/packages/server/src/routers/DoorRouter.ts b/packages/server/src/routers/DoorRouter.ts deleted file mode 100644 index f23229a..0000000 --- a/packages/server/src/routers/DoorRouter.ts +++ /dev/null @@ -1,65 +0,0 @@ -import express from "express"; -import { getRedisClient } from "../clients/db/RedisDbProvider"; -import { doorStatusKey } from "../types/RedisKeys"; -import { HandleAuthMode } from "../middlewares/DoorAuthModes"; -import { getAllDoorNames, getAuthModes, getDoorSettingNumber, getDoorSettingString, getEnv } from "../util/EnvConfigUtil"; -import { IDoorConfig } from "../types/IDoorConfig"; -import { TimeLockVerify } from "../middlewares/TimeLockMiddleware"; -import { IDoorStatus } from "../types/IDoorStatus"; - -const router = express.Router(); -const client = await getRedisClient(); - -router.get('/', async (req, res) => { - res.redirect(`/api/door/${getEnv("DEFAULT_DOOR") || getAllDoorNames()[0]}`); -}); - -router.get('/:id', async(req, res) => { - const doorId = req.params.id; - const authModes = getAuthModes(doorId); - const timeout = getDoorSettingNumber(doorId, IDoorConfig.OPEN_TIMEOUT)|| 60; - - if (authModes.length === 0) { - res.status(404).json({ msg: `Door ${doorId} not found` }); - return; - } - - const status = await client.get(doorStatusKey(doorId)) ? IDoorStatus.OPEN: IDoorStatus.CLOSED; - - res.status(200).json({ id: doorId, authModes, timeout, status }); -}); - -router.get('/:id/status', TimeLockVerify, async(req, res) => { - const isOpen = await client.get(doorStatusKey(req.params.id)); - - if (isOpen) { - const fingerprint = JSON.parse(isOpen); - res.status(200).json({ status: IDoorStatus.OPEN, fingerprint }); - - if (getDoorSettingString(req.params.id, IDoorConfig.CLOSE_AFTER_POLL)) { - await client.remove(doorStatusKey(req.params.id)); - } - return; - } - - res.status(401).json({ status: IDoorStatus.CLOSED }); -}); - -router.delete('/:id/status', async(req, res) => { - await client.remove(doorStatusKey(req.params.id)); - res.status(200).json({ msg: `Closed the door ${req.params.id}` }); -}); - -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, 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/server.ts b/packages/server/src/server.ts deleted file mode 100644 index df9594c..0000000 --- a/packages/server/src/server.ts +++ /dev/null @@ -1,34 +0,0 @@ -import express from "express"; -import DoorRouter from "./routers/DoorRouter"; -import { initializeRandomDoorPins } from "./middlewares/DoorAuthModes"; -import path from "path"; - -const Fingerprint = require('express-fingerprint'); -const app = express(); - -app.set('trust proxy', 1); - -app.use(Fingerprint({ - parameters: [ - Fingerprint.useragent, - Fingerprint.geoip - ] -})); - -app.use((req, res, next) => { - (req as any).fingerprint.ip = req.ip; - next(); -}); - -app.use(express.json()); -app.use(express.static("dist")); -app.use('/api/door', DoorRouter); - -app.get("*", (req, res) => { - res.sendFile(path.join(__dirname, "..", "dist", "index.html")); -}); - -app.listen(5000, async () => { - console.log("listening on port 5000"); - initializeRandomDoorPins(); -}); \ No newline at end of file diff --git a/packages/server/src/types/IAccessControl.ts b/packages/server/src/types/IAccessControl.ts deleted file mode 100644 index 17301c2..0000000 --- a/packages/server/src/types/IAccessControl.ts +++ /dev/null @@ -1,4 +0,0 @@ -export interface IAccessControl { - key: string; - remainingAccess?: number; -} \ No newline at end of file diff --git a/packages/server/src/types/IAuthCallbackQuery.ts b/packages/server/src/types/IAuthCallbackQuery.ts deleted file mode 100644 index b102b42..0000000 --- a/packages/server/src/types/IAuthCallbackQuery.ts +++ /dev/null @@ -1,7 +0,0 @@ -export default interface IAuthCallbackQuery { - action: string; - tag: string; - k1: string; - sig: string; - key: string -} \ No newline at end of file diff --git a/packages/server/src/types/IAuthMode.ts b/packages/server/src/types/IAuthMode.ts deleted file mode 100644 index 4d1ad2a..0000000 --- a/packages/server/src/types/IAuthMode.ts +++ /dev/null @@ -1,4 +0,0 @@ -export enum IAuthMode { - FIXED_PIN = "FIXED_PIN", - RANDOM_ROTATING_KEY = "RANDOM_ROTATING_KEY", -} \ No newline at end of file diff --git a/packages/server/src/types/IDoorConfig.ts b/packages/server/src/types/IDoorConfig.ts deleted file mode 100644 index 91acec9..0000000 --- a/packages/server/src/types/IDoorConfig.ts +++ /dev/null @@ -1,7 +0,0 @@ -export enum IDoorConfig { - AUTH_MODES = "AUTH_MODES", - OPEN_TIMEOUT = "OPEN_TIMEOUT", - FIXED_PIN = "FIXED_PIN", - CLOSE_AFTER_POLL="CLOSE_AFTER_POLL", - ALWAYS_LOCKED_TIME="ALWAYS_LOCKED_TIME", -} \ No newline at end of file diff --git a/packages/server/src/types/IDoorResponse.ts b/packages/server/src/types/IDoorResponse.ts deleted file mode 100644 index bd77640..0000000 --- a/packages/server/src/types/IDoorResponse.ts +++ /dev/null @@ -1,5 +0,0 @@ -export interface IDoorResponse { - id: string, - timeout: number; - buzzerCode: string; -}; diff --git a/packages/server/src/types/IDoorStatus.ts b/packages/server/src/types/IDoorStatus.ts deleted file mode 100644 index 5857a4e..0000000 --- a/packages/server/src/types/IDoorStatus.ts +++ /dev/null @@ -1,5 +0,0 @@ -export enum IDoorStatus { - OPEN="OPEN", - CLOSED="CLOSED", - TIME_LOCK="TIME_LOCK" -} \ No newline at end of file diff --git a/packages/server/src/types/RedisKeys.ts b/packages/server/src/types/RedisKeys.ts deleted file mode 100644 index 8da098d..0000000 --- a/packages/server/src/types/RedisKeys.ts +++ /dev/null @@ -1,16 +0,0 @@ -export enum RedisKeys { - CHALLENGES = "challenges", - DOORS = "doors" -} - -export function doorStatusKey(id: string) { - return concatKeys(RedisKeys.DOORS, id, 'open'); -} - -export function doorRotatingKey(id: string) { - return concatKeys(RedisKeys.DOORS, id, 'rotatingKey'); -} - -export function concatKeys(...keys: String[]) { - return keys.join(':'); -} \ No newline at end of file diff --git a/packages/server/src/util/EnvConfigUtil.ts b/packages/server/src/util/EnvConfigUtil.ts deleted file mode 100644 index 45cd1cc..0000000 --- a/packages/server/src/util/EnvConfigUtil.ts +++ /dev/null @@ -1,55 +0,0 @@ -import { IAuthMode } from "../types/IAuthMode"; -import { IDoorConfig } from "../types/IDoorConfig"; - -export const getEnv = (key: string): string => { - return process.env[key] || ""; -} - -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 getEnv(`${setting}_${doorToEnv(door)}`); -}; - -export const getDoorSettingNumber = (door: string, setting: IDoorConfig): number => { - return parseInt(getDoorSettingString(door, setting) || "0"); -}; - -export const getDoorSettingTimeLock = (door: string): number[] => { - const config = getDoorSettingString(door, IDoorConfig.ALWAYS_LOCKED_TIME); - - if (config) { - try { - return config.split(',').map(n => parseInt(n)); - } catch (e) { - console.warn(`Config ${IDoorConfig.ALWAYS_LOCKED_TIME} for door ${door} is invalid`); - } - } - - // never locked (always -1 < hr < 25) - return [25, -1]; -} - -export const getAllDoorNames = (): string[] => { - const names: string[] = []; - - Object.keys(process.env).forEach(key => { - if (key.startsWith(IDoorConfig.AUTH_MODES)) { - names.push(key.replace(IDoorConfig.AUTH_MODES + "_", "").toLowerCase()); - } - }); - - return names; -} \ No newline at end of file diff --git a/packages/server/src/util/RateLimits.ts b/packages/server/src/util/RateLimits.ts deleted file mode 100644 index 9cfd135..0000000 --- a/packages/server/src/util/RateLimits.ts +++ /dev/null @@ -1,14 +0,0 @@ -import rateLimit from "express-rate-limit"; - - -export const uploadDownloadLimiter = rateLimit({ - windowMs: 5 * 60 * 1000, - max: 5, - skipFailedRequests: true, -}); - -export const challengeLimiter = rateLimit({ - windowMs: 5 * 60 * 1000, - max: 10, - skipFailedRequests: true, -}); \ No newline at end of file diff --git a/packages/server/tsconfig.json b/packages/server/tsconfig.json deleted file mode 100644 index 8899e03..0000000 --- a/packages/server/tsconfig.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "compilerOptions": { - // Enable latest features - "lib": ["ESNext"], - "target": "ESNext", - "module": "ESNext", - "moduleDetection": "force", - "jsx": "react-jsx", - "allowJs": true, - "outDir": "build", - - // Bundler mode - "moduleResolution": "bundler", - // "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "noEmit": false, - - // Best practices - "strict": false, - "skipLibCheck": true, - "noFallthroughCasesInSwitch": true, - - // // Some stricter flags - // "noUnusedLocals": true, - // "noUnusedParameters": true, - // "noPropertyAccessFromIndexSignature": true - } -} \ No newline at end of file