diff --git a/api/src/core/api.js b/api/src/core/api.js index 975e7da9..dc5c4ae1 100644 --- a/api/src/core/api.js +++ b/api/src/core/api.js @@ -257,7 +257,7 @@ export const runAPI = (express, app, __dirname) => { } }) - app.get('/tunnel', apiTunnelLimiter, (req, res) => { + app.get('/tunnel', apiTunnelLimiter, async (req, res) => { const id = String(req.query.id); const exp = String(req.query.exp); const sig = String(req.query.sig); @@ -276,7 +276,7 @@ export const runAPI = (express, app, __dirname) => { return res.status(200).end(); } - const streamInfo = verifyStream(id, sig, exp, sec, iv); + const streamInfo = await verifyStream(id, sig, exp, sec, iv); if (!streamInfo?.service) { return res.status(streamInfo.status).end(); } diff --git a/api/src/stream/manage.js b/api/src/stream/manage.js index 092232f6..2b03303c 100644 --- a/api/src/stream/manage.js +++ b/api/src/stream/manage.js @@ -1,4 +1,4 @@ -import NodeCache from "node-cache"; +import Store from "../store/store.js"; import { nanoid } from "nanoid"; import { randomBytes } from "crypto"; @@ -12,16 +12,7 @@ import { decryptStream, encryptStream, generateHmac } from "../misc/crypto.js"; // optional dependency const freebind = env.freebindCIDR && await import('freebind').catch(() => {}); -const streamCache = new NodeCache({ - stdTTL: env.streamLifespan, - checkperiod: 10, - deleteOnExpire: true, - useClones: false, -}) - -streamCache.on("expired", (key) => { - streamCache.del(key); -}) +const streamCache = new Store('streams'); const internalStreamCache = new Map(); const hmacSalt = randomBytes(64).toString('hex'); @@ -51,10 +42,14 @@ export function createStream(obj) { isHLS: obj.isHLS || false, }; + // FIXME: this is now a Promise, but it is not awaited + // here. it may happen that the stream is not + // stored in the Store before it is requested. streamCache.set( streamID, - encryptStream(streamData, iv, secret) - ) + encryptStream(streamData, iv, secret), + env.streamLifespan + ); let streamLink = new URL('/tunnel', env.apiURL); @@ -150,10 +145,10 @@ function wrapStream(streamInfo) { return streamInfo; } -export function verifyStream(id, hmac, exp, secret, iv) { +export async function verifyStream(id, hmac, exp, secret, iv) { try { const ghmac = generateHmac(`${id},${exp},${iv},${secret}`, hmacSalt); - const cache = streamCache.get(id.toString()); + const cache = await streamCache.get(id.toString()); if (ghmac !== String(hmac)) return { status: 401 }; if (!cache) return { status: 404 };