UNPKG

r2-streamer-js

Version:

Readium 2 'streamer' for NodeJS (TypeScript)

91 lines 3.76 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.verifyExpiringResourceURL = exports.signExpiringResourceURLs = exports.URL_SIGNED_EXPIRY_QUERY_PARAM_NAME = void 0; const debug_ = require("debug"); const crypto = require("crypto"); const JsonUtils_1 = require("r2-utils-js/dist/es7-es2016/src/_utils/JsonUtils"); const debug = debug_("r2:streamer#http/url-signed-expiry"); const DEFAULT_EXPIRE_SECONDS = 86400; exports.URL_SIGNED_EXPIRY_QUERY_PARAM_NAME = "r2tkn"; const computeHashSecret = () => { if (!process.env.R2_STREAMER_URL_EXPIRE_SECRET) { return undefined; } const checkSumSecret = crypto.createHash("sha256"); checkSumSecret.update(process.env.R2_STREAMER_URL_EXPIRE_SECRET); const hashSecret = checkSumSecret.digest("hex"); return hashSecret; }; const signExpiringResourceURLs = (rootUrl, pathBase64Str, jsonObj) => { const hashSecret = computeHashSecret(); if (!hashSecret) { return; } const timestamp = Date.now(); let expiry = DEFAULT_EXPIRE_SECONDS; if (process.env.R2_STREAMER_URL_EXPIRE_SECONDS) { try { expiry = parseInt(process.env.R2_STREAMER_URL_EXPIRE_SECONDS, 10); } catch (err) { debug(err); } } (0, JsonUtils_1.traverseJsonObjects)(jsonObj, (obj) => { if (obj.href && typeof obj.href === "string" && !/^https?:\/\//.test(obj.href) && !/^data:\/\//.test(obj.href)) { const publicationRootUrl = new URL(`${rootUrl}/`); const url = new URL(obj.href, publicationRootUrl); const resourcePath = url.pathname.replace(publicationRootUrl.pathname, ""); const checkSumData = crypto.createHash("sha256"); checkSumData.update(`${timestamp}_${hashSecret}_${resourcePath}_${expiry}_${pathBase64Str}`); const hashData = checkSumData.digest("hex"); const queryParamJson = { hash: hashData, timestamp, expiry, }; const queryParamValue = Buffer.from(JSON.stringify(queryParamJson)).toString("base64"); url.searchParams.append(exports.URL_SIGNED_EXPIRY_QUERY_PARAM_NAME, queryParamValue); obj.href = url.toString().replace(publicationRootUrl.toString(), ""); } }); }; exports.signExpiringResourceURLs = signExpiringResourceURLs; const verifyExpiringResourceURL = (queryParamValue, pathBase64Str, pathInZip) => { const hashSecret = computeHashSecret(); if (!hashSecret) { return true; } if (!queryParamValue) { return false; } try { const queryParamStr = Buffer.from(queryParamValue, "base64").toString("utf8"); const json = JSON.parse(queryParamStr); if (!json.hash || !json.timestamp || !json.expiry) { return false; } const resourcePath = pathInZip; const checkSumData = crypto.createHash("sha256"); checkSumData.update(`${json.timestamp}_${hashSecret}_${resourcePath}_${json.expiry}_${pathBase64Str}`); const hashData = checkSumData.digest("hex"); if (hashData !== json.hash) { debug(`HASH diff! ${hashData} !== ${json.hash} (${resourcePath})`); return false; } const timestamp = Date.now(); const timeDiff = timestamp - json.timestamp; if (timeDiff > (json.expiry * 1000)) { debug(`Resource EXPIRED! ${timeDiff} > ${json.expiry} (${resourcePath})`); return false; } return true; } catch (e) { debug(e); } return false; }; exports.verifyExpiringResourceURL = verifyExpiringResourceURL; //# sourceMappingURL=url-signed-expiry.js.map