UNPKG

@mft/moneyhub-api-client

Version:
169 lines 7.95 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.rewriteResourceServerResponseUrls = exports.inferCanonicalBaseFromLinkUrl = exports.getDiscoveryWithGatewayUrl = exports.getDiscovery = exports.rewriteDiscoveryDocForIdentityUrl = exports.rewriteDiscoveryUrls = exports.rewriteUrlsInObject = void 0; const got_1 = __importDefault(require("got")); /** * Rewrites any string value in a value (object, array, or primitive) that starts with * canonicalBase to use targetBase instead. Does not mutate the original. * Used for both OIDC discovery documents and resource server response bodies (e.g. links). * @param {*} value - Object, array or primitive to rewrite * @param {string} canonicalBase - Base URL to replace * @param {string} targetBase - Base URL to use instead * @returns {*} A copy of value with matching URLs rewritten */ function rewriteUrlsInObject(value, canonicalBase, targetBase) { if (canonicalBase === targetBase) return value; if (typeof value === "string") { if (value.startsWith(canonicalBase)) { return (targetBase + value.slice(canonicalBase.length)); } return value; } if (Array.isArray(value)) { return value.map((item) => rewriteUrlsInObject(item, canonicalBase, targetBase)); } if (value !== null && typeof value === "object") { const out = {}; for (const [k, v] of Object.entries(value)) { out[k] = rewriteUrlsInObject(v, canonicalBase, targetBase); } return out; } return value; } exports.rewriteUrlsInObject = rewriteUrlsInObject; /** * Rewrites URL fields in an OIDC discovery document so that endpoint URLs use the * target base. Leaves the discovery "issuer" field unchanged so that JWT iss claim * validation continues to work when the IdP still issues tokens with the canonical issuer. * @param {Object} doc - OIDC discovery document * @param {string} canonicalBase - Base URL to replace * @param {string} targetBase - Base URL to use instead * @returns {Object} Discovery document with endpoint URLs rewritten */ function rewriteDiscoveryUrls(doc, canonicalBase, targetBase) { if (canonicalBase === targetBase) return doc; const result = {}; for (const [key, val] of Object.entries(doc)) { if (key === "issuer" && typeof val === "string") { result[key] = val; continue; } result[key] = rewriteUrlsInObject(val, canonicalBase, targetBase); } return result; } exports.rewriteDiscoveryUrls = rewriteDiscoveryUrls; /** * Normalised OIDC base for the given identity service URL (no trailing slash). * @param {string} identityServiceUrl - Identity service base URL * @returns {string} OIDC base URL with no trailing slash */ const oidcBaseFromIdentityUrl = (identityServiceUrl) => (identityServiceUrl.replace(/\/oidc\/?$/, "") + "/oidc").replace(/\/$/, ""); /** * Rewrites a discovery document so endpoint URLs use the identity service base (e.g. gateway). * Single source of truth for canonical/target computation; used by both initial fetch and cache refresh. * @param {string} identityServiceUrl - Identity service base URL (e.g. gateway or https://identity.moneyhub.co.uk) * @param {Record<string, unknown>} doc - Raw OIDC discovery document * @returns {Record<string, unknown>} Discovery document with endpoint URLs rewritten (issuer unchanged) */ function rewriteDiscoveryDocForIdentityUrl(identityServiceUrl, doc) { const issuer = doc === null || doc === void 0 ? void 0 : doc.issuer; if (!issuer || typeof issuer !== "string") return doc; const canonicalBase = issuer.replace(/\/$/, ""); const targetBase = oidcBaseFromIdentityUrl(identityServiceUrl); return rewriteDiscoveryUrls(doc, canonicalBase, targetBase); } exports.rewriteDiscoveryDocForIdentityUrl = rewriteDiscoveryDocForIdentityUrl; /** * Fetches the raw OpenID discovery document from identityServiceUrl/oidc (no URL rewriting). * @param {string} identityServiceUrl - Identity service base URL * @param {DiscoveryOptions} options - Optional timeout, agent or mTLS settings * @returns {Promise<OpenIDDiscoveryMetadata>} Raw OpenID discovery metadata */ async function getDiscovery(identityServiceUrl, options = {}) { const base = oidcBaseFromIdentityUrl(identityServiceUrl); const url = `${base}/.well-known/openid-configuration`; const gotOpts = { timeout: options.timeout, responseType: "json", }; if (options.agent) { gotOpts.agent = options.agent; } if (options.mTLS) { gotOpts.https = { certificate: options.mTLS.cert, key: options.mTLS.key, }; } const doc = (await (0, got_1.default)(url, gotOpts).json()); return doc; } exports.getDiscovery = getDiscovery; /** * Fetches the OpenID discovery document from identityServiceUrl/oidc and rewrites * all endpoint URLs (but not the issuer field) to use the configured identity service url, so that * when used behind a gateway all OIDC traffic goes through the gateway. * @param {string} identityServiceUrl - Identity service URL (e.g. https://identity.moneyhub.co.uk) * @param {DiscoveryOptions} options - Optional timeout, agent or mTLS settings * @returns {Promise<OpenIDDiscoveryMetadata>} OpenID discovery metadata with URLs rewritten for the gateway */ async function getDiscoveryWithGatewayUrl(identityServiceUrl, options = {}) { const doc = (await getDiscovery(identityServiceUrl, options)); const rewritten = rewriteDiscoveryDocForIdentityUrl(identityServiceUrl, doc); return rewritten; } exports.getDiscoveryWithGatewayUrl = getDiscoveryWithGatewayUrl; /** * Infers the canonical API base from a response link URL (e.g. links.self) by taking * origin and path up to and including the version segment (e.g. /v3). * @param {string} linkUrl - Full link URL from a resource response * @returns {string|null} Canonical base URL or null if it cannot be inferred */ function inferCanonicalBaseFromLinkUrl(linkUrl) { try { const u = new URL(linkUrl); const pathParts = u.pathname.split("/").filter(Boolean); const versionIndex = pathParts.findIndex((p) => /^v\d+(\.\d+)?$/i.test(p)); if (versionIndex >= 0) { const versionPath = "/" + pathParts.slice(0, versionIndex + 1).join("/"); return `${u.origin}${versionPath}`; } return u.origin; } catch { return null; } } exports.inferCanonicalBaseFromLinkUrl = inferCanonicalBaseFromLinkUrl; /** * Rewrites URL strings in a resource server response body (e.g. links.self, links.next, * links.prev) so that any canonical API base is replaced with resourceServerUrl. * Returns the body unchanged if no links or no canonical base can be inferred. * @param {*} body - Resource server response body (typically with a links property) * @param {string} resourceServerUrl - Base URL for the resource server (e.g. gateway URL) * @returns {*} Body with link URLs rewritten to use resourceServerUrl */ function rewriteResourceServerResponseUrls(body, resourceServerUrl) { if (body === null || typeof body !== "object") return body; const targetBase = resourceServerUrl.replace(/\/$/, ""); const links = body.links; if (!links || typeof links.self !== "string") return body; const canonicalBase = inferCanonicalBaseFromLinkUrl(links.self); if (!canonicalBase || canonicalBase === targetBase) return body; const result = { ...body }; result.links = rewriteUrlsInObject(links, canonicalBase, targetBase); return result; } exports.rewriteResourceServerResponseUrls = rewriteResourceServerResponseUrls; //# sourceMappingURL=discovery.js.map