Skip to content

Commit

Permalink
Cleanup unused routes and convert auth response to string
Browse files Browse the repository at this point in the history
  • Loading branch information
sainak committed Aug 29, 2024
1 parent 02bec3f commit a1dd8e8
Show file tree
Hide file tree
Showing 15 changed files with 131 additions and 116 deletions.
4 changes: 2 additions & 2 deletions docker-compose.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ services:
# teleicu_middleware
teleicu_middleware:
restart: always
image: ghcr.io/coronasafe/teleicu_middleware:production-latest
image: ghcr.io/ohcnetwork/teleicu_middleware:production-latest
container_name: teleicu_middleware
depends_on:
- roverr_rtsp_stream
Expand All @@ -37,7 +37,7 @@ services:
# proxies requests to internal services
reverse-proxy:
restart: always
image: ghcr.io/coronasafe/teleicu_nginx/teleicu_nginx:latest
image: ghcr.io/ohcnetwork/teleicu_nginx/teleicu_nginx:latest
container_name: reverse-proxy
depends_on:
- teleicu_middleware
Expand Down
6 changes: 3 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@
"main": "src/index.ts",
"repository": {
"type": "git",
"url": "git+https://github.com/coronasafe/teleicu_middleware.git"
"url": "git+https://github.com/ohcnetwork/teleicu_middleware.git"
},
"keywords": [
"teleicu",
Expand All @@ -56,9 +56,9 @@
"author": "",
"license": "MIT",
"bugs": {
"url": "https://github.com/coronasafe/teleicu_middleware/issues"
"url": "https://github.com/ohcnetwork/teleicu_middleware/issues"
},
"homepage": "https://github.com/coronasafe/teleicu_middleware#readme",
"homepage": "https://github.com/ohcnetwork/teleicu_middleware#readme",
"devDependencies": {
"@trivago/prettier-plugin-sort-imports": "^4.3.0",
"@types/connect-flash": "^0.0.39",
Expand Down
4 changes: 2 additions & 2 deletions src/controller/AssetConfigController.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import dayjs from "dayjs";
import { Request, Response } from "express";

import prisma from "@/lib/prisma";
import { retrieveAssetConfig } from "@/cron/retrieveAssetConfig";
import prisma from "@/lib/prisma";

export class AssetConfigController {
static listAssets = async (req: Request, res: Response) => {
Expand Down Expand Up @@ -40,7 +40,7 @@ export class AssetConfigController {
static refreshAssets = async (req: Request, res: Response) => {
await retrieveAssetConfig();
res.redirect("/assets");
}
};

static createAssetForm = async (req: Request, res: Response) => {
res.render("pages/assets/form", {
Expand Down
18 changes: 0 additions & 18 deletions src/controller/CameraController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -353,24 +353,6 @@ export class CameraController {
});
});

/**
* @swagger
* /get_time:
* get:
* summary: "Get current time"
* description: ""
* tags:
* - BPL
* responses:
* "200":
* description: Return current time
*/
static getTime = catchAsync(async (req: Request, res: Response) => {
res.send({
time: new Date().toISOString(),
});
});

/**
* @swagger
* /preset:
Expand Down
2 changes: 1 addition & 1 deletion src/controller/ConfigController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ export class ConfigController {
res.render("pages/config", {
req,
csrfToken: res.locals.csrfToken,
hostname: "dev_middleware.coronasafe.live",
hostname: "dev_middleware.ohcnetwork.live",
});
};
}
29 changes: 0 additions & 29 deletions src/controller/ObservationController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -175,35 +175,6 @@ export class ObservationController {

static latestObservation = new ObservationsMap();

static getObservations(req: Request, res: Response) {
const limit = req.query?.limit || DEFAULT_LISTING_LIMIT;
const ip = req.query?.ip;

if (!ip) {
return res.json(staticObservations);
}
// console.log("Filtering");
const filtered = staticObservations.filter(
(observation) => observation.device_id === ip,
);
// Sort the observation by last updated time.
// .sort(
// (a, b) => new Date(a.lastObservationAt) - new Date(b.lastObservationAt)
// )
// // Limit the results
// .slice(0, limit);

return res.json(filtered ?? []);
}

static getLogData(req: Request, res: Response) {
return res.json(logData);
}

static getLastRequestData(req: Request, res: Response) {
return res.json(lastRequestData);
}

static updateObservations = (req: Request, res: Response) => {
// database logic
lastRequestData = req.body;
Expand Down
42 changes: 13 additions & 29 deletions src/controller/StreamAuthApiController.ts
Original file line number Diff line number Diff line change
@@ -1,23 +1,16 @@
import { Request, Response } from "express";

import { generateJWT, verifyJWT } from "@/lib/jose";
import { generateJWTWithKey, verifyJWTWithKey } from "@/lib/jose";

export class StreamAuthApiController {
static getVideoFeedStreamToken = async (req: Request, res: Response) => {
const { stream, ip, _duration } = req.body;
if (!stream || !ip) {
return res.status(400).json({ message: "stream and ip are required" });
const { stream_id } = req.body;
if (!stream_id) {
return res.status(400).json({ message: "stream_id is required" });
}

try {
const duration = parseInt(_duration ?? "5");
if (duration < 0 || duration > 60) {
return res
.status(400)
.json({ message: "duration must be between 0 and 60" });
}

const token = await generateJWT({ stream, ip }, `${duration}m`);
const token = await generateJWTWithKey({ stream:stream_id }, "60s");

return res.status(200).json({ token });
} catch (error: any) {
Expand All @@ -26,20 +19,13 @@ export class StreamAuthApiController {
};

static getVitalStreamToken = async (req: Request, res: Response) => {
const { asset_id, ip, _duration } = req.body;
const { asset_id, ip } = req.body;
if (!asset_id || !ip) {
return res.status(400).json({ message: "asset_id and ip are required" });
}

try {
const duration = parseInt(_duration ?? "5");
if (duration < 0 || duration > 60) {
return res
.status(400)
.json({ message: "duration must be between 0 and 60" });
}

const token = await generateJWT({ asset_id, ip }, `${duration}m`);
const token = await generateJWTWithKey({ asset_id, ip }, "60s");

return res.status(200).json({ token });
} catch (error: any) {
Expand All @@ -49,19 +35,17 @@ export class StreamAuthApiController {

static validateStreamToken = async (req: Request, res: Response) => {
const { token, ip, stream } = req.body;
if (!token || !ip || !stream) {
return res
.status(400)
.json({ message: "token, stream, and ip are required" });
if (!token || !stream) {
return res.status(400).json({ message: "token and stream are required" });
}

try {
const decoded = await verifyJWT(token);
if (decoded.ip === ip || decoded.stream === stream) {
return res.status(200).json({ status: 1 });
const decoded = await verifyJWTWithKey(token);
if (decoded.stream === stream) {
return res.status(200).json({ status: "1" });
}

return res.status(401).json({ status: 0 });
return res.status(401).json({ status: "0" });
} catch (error: any) {
return res.status(500).json({ message: error.message });
}
Expand Down
19 changes: 13 additions & 6 deletions src/cron/automatedDailyRounds.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,10 @@ import { randomUUID } from "crypto";
import fs from "fs";
import path from "path";



import { observationData, staticObservations } from "@/controller/ObservationController";
import {
observationData,
staticObservations,
} from "@/controller/ObservationController";
import prisma from "@/lib/prisma";
import { AssetBed } from "@/types/asset";
import { CameraParams } from "@/types/camera";
Expand All @@ -19,13 +20,19 @@ import { OCRV2Response } from "@/types/ocr";
import { CameraUtils } from "@/utils/CameraUtils";
import { isValid } from "@/utils/ObservationUtils";
import { generateHeaders } from "@/utils/assetUtils";
import { careApi, openaiApiKey, openaiApiVersion, openaiVisionModel, saveDailyRound, saveVitalsStat } from "@/utils/configs";
import {
careApi,
openaiApiKey,
openaiApiVersion,
openaiVisionModel,
saveDailyRound,
saveVitalsStat,
} from "@/utils/configs";
import { getPatientId } from "@/utils/dailyRoundUtils";
import { downloadImage } from "@/utils/downloadImageWithDigestRouter";
import { parseVitalsFromImage } from "@/utils/ocr";
import { Accuracy, calculateVitalsAccuracy } from "@/utils/vitalsAccuracy";


const UPDATE_INTERVAL = 60 * 60 * 1000;

export async function getMonitorPreset(bedId: string, assetId: string) {
Expand Down Expand Up @@ -499,4 +506,4 @@ export async function automatedDailyRounds() {
await fileAutomatedDailyRound(consultation_id, monitor.externalId, vitals);
console.log(`Daily round filed for the patient ${patient_id}`);
});
}
}
66 changes: 65 additions & 1 deletion src/lib/jose.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import * as jose from "jose";
import { v4 as uuidv4 } from "uuid";

import { randomString } from "@/lib/crypto";
import { careApi } from "@/utils/configs";
import { careApi, jwtSecret } from "@/utils/configs";

/**
* Default JSON Web Key (JWK) configuration.
Expand All @@ -29,6 +29,11 @@ let JWKs: jose.JSONWebKeySet | null = null;
*/
let careJWKs: jose.JSONWebKeySet | null = null;

/**
* JWT secret used to sign JWTs.
*/
let jwtSecretKey: Uint8Array | null = null;

/**
* Retrieves the private key used for encryption.
* If the private key is not already loaded, it attempts to load it from the "keys.json" file.
Expand Down Expand Up @@ -106,6 +111,19 @@ export async function getCareJWKs() {
return careJWKs;
}

/**
* Retrieves the JWT secret used to sign JWTs.
* If the JWT secret is not already loaded, it uses the value from the environment
* variable "
* @returns {Promise<Uint8Array>} The JWT secret used to sign JWTs.
*/
export async function getJWTSecret() {
if (!jwtSecretKey) {
jwtSecretKey = jwtSecret;
}
return jwtSecretKey;
}

/**
* Generates a new JSON Web Key (JWK) pair.
* @returns {Promise<jose.JWK>} The generated JWK pair.
Expand Down Expand Up @@ -151,6 +169,33 @@ export async function generateJWT(
.sign(privateKey);
}

/**
* Generates a JSON Web Token (JWT) with the provided claims and expiration time using the provided key.
* @param claims The payload of the JWT.
* @param expiresIn The expiration time of the JWT. Defaults to "2m" (2 minutes).
* @returns {Promise<string>} The generated JWT.
*/
export async function generateJWTWithKey(
claims: jose.JWTPayload,
expiresIn: string = "2m",
) {
const claimsWithDefaults: jose.JWTPayload = {
// iss: "teleicu-middleware",
// aud: "care",
jti: randomString(20),
...claims,
};

return new jose.SignJWT(claimsWithDefaults)
.setProtectedHeader({
alg: "HS256",
typ: "jwt",
})
.setIssuedAt()
.setExpirationTime(expiresIn)
.sign(await getJWTSecret());
}

/**
* Represents a function that validates a JSON Web Token (JWT).
* @param jwt The JWT to be validated.
Expand Down Expand Up @@ -182,6 +227,25 @@ export async function verifyJWT(
return payload;
}

/**
* Verifies a JSON Web Token (JWT) generated by this server using the provided options.
* @param jwt The JWT to verify.
* @param options The options for JWT verification.
* @returns {Promise<jose.JWTPayload>} The payload of the JWT.
*/
export async function verifyJWTWithKey(
jwt: string,
options: jose.JWTVerifyOptions = {},
) {
const { payload } = await jose.jwtVerify(jwt, await getJWTSecret(), {
// issuer: "teleicu-middleware",
// audience: "care",
...options,
});

return payload;
}

/**
* Verifies a JSON Web Token (JWT) generated by care backend using the provided options.
* @param jwt The JWT to verify.
Expand Down
Loading

0 comments on commit a1dd8e8

Please sign in to comment.