@pymthouse/builder-sdk 0.4.1-rc.1 → 0.4.1-rc.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{index-BixH4VIG.d.cts → index-B0ryx942.d.cts} +3 -1
- package/dist/{index-BTDKEorK.d.ts → index-CvV5syf_.d.ts} +3 -1
- package/dist/signer/server.cjs +3 -3
- package/dist/signer/server.cjs.map +1 -1
- package/dist/signer/server.d.cts +2 -2
- package/dist/signer/server.d.ts +2 -2
- package/dist/signer/server.js +3 -3
- package/dist/signer/server.js.map +1 -1
- package/dist/signer/webhook/adapters/api-key.cjs +14 -10
- package/dist/signer/webhook/adapters/api-key.cjs.map +1 -1
- package/dist/signer/webhook/adapters/api-key.js +14 -10
- package/dist/signer/webhook/adapters/api-key.js.map +1 -1
- package/dist/signer/webhook/adapters/oidc.cjs +33 -22
- package/dist/signer/webhook/adapters/oidc.cjs.map +1 -1
- package/dist/signer/webhook/adapters/oidc.d.cts +1 -1
- package/dist/signer/webhook/adapters/oidc.d.ts +1 -1
- package/dist/signer/webhook/adapters/oidc.js +33 -22
- package/dist/signer/webhook/adapters/oidc.js.map +1 -1
- package/dist/signer/webhook/adapters/trusted-headers.cjs +17 -10
- package/dist/signer/webhook/adapters/trusted-headers.cjs.map +1 -1
- package/dist/signer/webhook/adapters/trusted-headers.js +17 -10
- package/dist/signer/webhook/adapters/trusted-headers.js.map +1 -1
- package/dist/signer/webhook.cjs +41 -29
- package/dist/signer/webhook.cjs.map +1 -1
- package/dist/signer/webhook.d.cts +2 -2
- package/dist/signer/webhook.d.ts +2 -2
- package/dist/signer/webhook.js +41 -30
- package/dist/signer/webhook.js.map +1 -1
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../src/signer/webhook/bearer.ts","../../../../src/errors.ts","../../../../src/string-utils.ts","../../../../src/discovery.ts","../../../../src/oauth-map.ts","../../../../src/verify.ts","../../../../src/signer/webhook/payload.ts","../../../../src/signer/webhook/authorize.ts","../../../../src/signer/webhook/identity.ts","../../../../src/signer/webhook/adapters/oidc/verifier.ts","../../../../src/signer/webhook/adapters/composite/verifier.ts","../../../../src/signer/webhook/adapters/trusted-headers/verifier.ts","../../../../src/signer/webhook/adapters/oidc/config.ts"],"names":["customFetch","allowInsecureRequests"],"mappings":"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","file":"oidc.js","sourcesContent":["export function bearerTokenFromAuthorization(authorization: string): string {\n const trimmed = authorization.trim();\n if (!trimmed) {\n throw new Error(\"missing authorization\");\n }\n const prefix = \"Bearer \";\n if (!trimmed.startsWith(prefix)) {\n throw new Error(\"authorization must be Bearer token\");\n }\n const token = trimmed.slice(prefix.length).trim();\n if (!token) {\n throw new Error(\"empty bearer token\");\n }\n return token;\n}\n","export class PmtHouseError extends Error {\n readonly status: number;\n readonly code: string;\n readonly details?: unknown;\n\n constructor(\n message: string,\n {\n status = 500,\n code = \"pymthouse_error\",\n details,\n }: {\n status?: number;\n code?: string;\n details?: unknown;\n } = {},\n ) {\n super(message);\n this.name = \"PmtHouseError\";\n this.status = status;\n this.code = code;\n this.details = details;\n }\n}\n\nexport function toPmtHouseError(\n error: unknown,\n fallbackMessage: string,\n): PmtHouseError {\n if (error instanceof PmtHouseError) {\n return error;\n }\n\n if (error instanceof Error) {\n return new PmtHouseError(error.message || fallbackMessage, {\n code: \"unexpected_error\",\n status: 500,\n });\n }\n\n return new PmtHouseError(fallbackMessage, {\n code: \"unexpected_error\",\n status: 500,\n });\n}\n","/** Removes trailing `/` without regex (linear time). */\nexport function stripTrailingSlashes(value: string): string {\n let end = value.length;\n while (end > 0 && (value.codePointAt(end - 1) ?? 0) === 47) {\n end--;\n }\n return value.slice(0, end);\n}\n\nfunction endsWithIgnoreCase(value: string, suffix: string): boolean {\n if (suffix.length > value.length) {\n return false;\n }\n const start = value.length - suffix.length;\n for (let i = 0; i < suffix.length; i++) {\n const a = value.codePointAt(start + i) ?? 0;\n const b = suffix.codePointAt(i) ?? 0;\n if (a !== b && (a | 32) !== (b | 32)) {\n return false;\n }\n }\n return true;\n}\n\nfunction stripSuffixIgnoreCase(value: string, suffix: string): string {\n return endsWithIgnoreCase(value, suffix)\n ? value.slice(0, value.length - suffix.length)\n : value;\n}\n\n/** Issuer URL (`…/oidc`) → Builder API base (`…/api/v1`). Linear-time; no regex. */\nexport function stripOidcPathSuffix(issuerUrl: string): string {\n let base = stripTrailingSlashes(issuerUrl.trim());\n base = stripSuffixIgnoreCase(base, \"/oidc\");\n return stripTrailingSlashes(base);\n}\n\n/** Issuer URL (`…/api/v1/oidc`) → host origin for signer/API-key routes. Linear-time; no regex. */\nexport function stripIssuerOriginFromOidcUrl(issuerUrl: string): string {\n let base = stripTrailingSlashes(issuerUrl.trim());\n base = stripSuffixIgnoreCase(base, \"/api/v1/oidc\");\n base = stripSuffixIgnoreCase(base, \"/oidc\");\n return stripTrailingSlashes(base);\n}\n\n/** Parse and validate an http(s) facade origin (no path). */\nexport function parseHttpOrigin(raw: string | undefined, fallback: string): string {\n const trimmed = (raw ?? fallback).trim();\n let parsed: URL;\n try {\n parsed = new URL(trimmed);\n } catch {\n throw new TypeError(\"Origin must be a valid http(s) URL\");\n }\n if (parsed.protocol !== \"http:\" && parsed.protocol !== \"https:\") {\n throw new TypeError(\"Origin must use http or https\");\n }\n return parsed.origin;\n}\n\n","import {\n allowInsecureRequests,\n customFetch,\n discoveryRequest,\n processDiscoveryResponse,\n type AuthorizationServer,\n} from \"oauth4webapi\";\nimport { PmtHouseError } from \"./errors.js\";\nimport { stripTrailingSlashes } from \"./string-utils.js\";\nimport type { FetchLike, OidcDiscoveryDocument } from \"./types.js\";\n\nexport function authorizationServerToOidcDocument(as: AuthorizationServer): OidcDiscoveryDocument {\n const tokenEndpoint = as.token_endpoint;\n const jwksUri = as.jwks_uri;\n if (!tokenEndpoint || !jwksUri) {\n throw new PmtHouseError(\"OIDC discovery document is missing token_endpoint or jwks_uri\", {\n status: 500,\n code: \"oidc_discovery_invalid\",\n });\n }\n return {\n issuer: as.issuer,\n authorization_endpoint: as.authorization_endpoint ?? \"\",\n token_endpoint: tokenEndpoint,\n jwks_uri: jwksUri,\n userinfo_endpoint: as.userinfo_endpoint,\n device_authorization_endpoint: as.device_authorization_endpoint,\n };\n}\n\nconst CACHE_TTL_MS = 5 * 60 * 1000;\n\ntype CacheEntry = {\n as: AuthorizationServer;\n fetchedAt: number;\n};\n\nconst discoveryCache = new Map<string, CacheEntry>();\n\nfunction normalizedIssuerKey(issuerUrl: string): string {\n return stripTrailingSlashes(issuerUrl);\n}\n\nexport interface LoadAuthorizationServerOptions {\n force?: boolean;\n allowInsecureHttp?: boolean;\n}\n\n/**\n * Loads OIDC discovery metadata via oauth4webapi (RFC 8414 / OIDC Discovery), with a 5-minute cache.\n */\nexport async function loadAuthorizationServer(\n issuerUrl: string,\n fetchImpl: FetchLike,\n options: LoadAuthorizationServerOptions = {},\n): Promise<AuthorizationServer> {\n const key = normalizedIssuerKey(issuerUrl);\n const now = Date.now();\n const cached = discoveryCache.get(key);\n\n if (!options.force && cached && now - cached.fetchedAt < CACHE_TTL_MS) {\n return cached.as;\n }\n\n const issuerIdentifier = new URL(key);\n const discoveryOpts: Parameters<typeof discoveryRequest>[1] = {\n algorithm: \"oidc\",\n [customFetch]: fetchImpl,\n };\n if (options.allowInsecureHttp) {\n discoveryOpts[allowInsecureRequests] = true;\n }\n\n let response: Response;\n try {\n response = await discoveryRequest(issuerIdentifier, discoveryOpts);\n } catch (e) {\n throw mapDiscoveryNetworkError(e);\n }\n\n let as: AuthorizationServer;\n try {\n as = await processDiscoveryResponse(issuerIdentifier, response);\n } catch (e) {\n throw mapOAuthDiscoveryError(e);\n }\n\n discoveryCache.set(key, { as, fetchedAt: now });\n return as;\n}\n\nexport async function fetchDiscoveryDocument(\n issuerUrl: string,\n fetchImpl: FetchLike,\n options: LoadAuthorizationServerOptions = {},\n): Promise<OidcDiscoveryDocument> {\n const as = await loadAuthorizationServer(issuerUrl, fetchImpl, options);\n return authorizationServerToOidcDocument(as);\n}\n\nexport function clearDiscoveryCache(issuerUrl?: string): void {\n if (!issuerUrl) {\n discoveryCache.clear();\n return;\n }\n discoveryCache.delete(normalizedIssuerKey(issuerUrl));\n}\n\nfunction mapOAuthDiscoveryError(error: unknown): PmtHouseError {\n if (error instanceof PmtHouseError) {\n return error;\n }\n if (error instanceof Error) {\n return new PmtHouseError(error.message, {\n status: 500,\n code: \"oidc_discovery_invalid\",\n details: { cause: error.cause },\n });\n }\n return new PmtHouseError(\"OIDC discovery failed\", {\n status: 500,\n code: \"oidc_discovery_invalid\",\n });\n}\n\nfunction mapDiscoveryNetworkError(error: unknown): PmtHouseError {\n if (error instanceof PmtHouseError) {\n return error;\n }\n if (error instanceof Error) {\n return new PmtHouseError(`Failed to load OIDC discovery: ${error.message}`, {\n status: 502,\n code: \"oidc_discovery_failed\",\n });\n }\n return new PmtHouseError(\"Failed to load OIDC discovery\", {\n status: 502,\n code: \"oidc_discovery_failed\",\n });\n}\n","import { type Client, OperationProcessingError, ResponseBodyError } from \"oauth4webapi\";\nimport { PmtHouseError } from \"./errors.js\";\nimport type { ClientCredentialsTokenResponse, TokenExchangeResponse } from \"./types.js\";\n\nconst ACCEPTED_ISSUED_TOKEN_TYPES = new Set([\n \"urn:ietf:params:oauth:token-type:access_token\",\n \"urn:pmth:token-type:remote-signer-session\",\n]);\n\nexport function mapOAuthError(error: unknown): PmtHouseError {\n if (error instanceof PmtHouseError) {\n return error;\n }\n\n if (error instanceof ResponseBodyError) {\n const cause = error.cause as Record<string, unknown>;\n const description =\n typeof error.error_description === \"string\"\n ? error.error_description\n : error.message;\n const details: Record<string, unknown> = { ...cause };\n if (typeof cause.error_uri === \"string\") {\n details.error_uri = cause.error_uri;\n }\n return new PmtHouseError(description, {\n status: error.status,\n code: error.error,\n details,\n });\n }\n\n if (error instanceof OperationProcessingError) {\n return new PmtHouseError(error.message, {\n status: 502,\n code: error.code ?? \"oauth_processing_error\",\n details: { cause: error.cause },\n });\n }\n\n if (error instanceof Error) {\n return new PmtHouseError(error.message, {\n status: 500,\n code: \"unexpected_error\",\n });\n }\n\n return new PmtHouseError(\"Unexpected error\", {\n status: 500,\n code: \"unexpected_error\",\n });\n}\n\nexport function tokenEndpointResponseToExchange(\n tr: import(\"oauth4webapi\").TokenEndpointResponse,\n): TokenExchangeResponse {\n const issued = tr.issued_token_type;\n if (typeof issued !== \"string\" || !ACCEPTED_ISSUED_TOKEN_TYPES.has(issued)) {\n throw new PmtHouseError(\"Token exchange returned an unexpected issued_token_type\", {\n status: 502,\n code: \"invalid_token_response\",\n details: { issued_token_type: issued },\n });\n }\n\n const tt = tr.token_type;\n if (typeof tt !== \"string\" || tt.toLowerCase() !== \"bearer\") {\n throw new PmtHouseError(\"Token endpoint returned a non-Bearer token_type\", {\n status: 502,\n code: \"invalid_token_response\",\n details: { token_type: tt },\n });\n }\n\n const expiresIn = tr.expires_in;\n if (typeof expiresIn !== \"number\") {\n throw new PmtHouseError(\"Token response missing expires_in\", {\n status: 502,\n code: \"invalid_token_response\",\n });\n }\n\n const scope = typeof tr.scope === \"string\" ? tr.scope : \"\";\n\n return {\n access_token: tr.access_token,\n token_type: \"Bearer\",\n expires_in: expiresIn,\n scope,\n issued_token_type: issued,\n };\n}\n\nexport function tokenEndpointResponseToClientCredentials(\n tr: import(\"oauth4webapi\").TokenEndpointResponse,\n): ClientCredentialsTokenResponse {\n const tt = tr.token_type;\n if (typeof tt !== \"string\" || tt.toLowerCase() !== \"bearer\") {\n throw new PmtHouseError(\"Token endpoint returned a non-Bearer token_type\", {\n status: 502,\n code: \"invalid_token_response\",\n details: { token_type: tt },\n });\n }\n\n return {\n access_token: tr.access_token,\n token_type: \"Bearer\",\n expires_in: tr.expires_in,\n scope: typeof tr.scope === \"string\" ? tr.scope : undefined,\n };\n}\n\nexport function m2mClient(clientId: string): Client {\n return { client_id: clientId };\n}\n","import {\n allowInsecureRequests,\n customFetch,\n validateJwtAccessToken,\n type JWTAccessTokenClaims,\n} from \"oauth4webapi\";\nimport { loadAuthorizationServer } from \"./discovery.js\";\nimport { PmtHouseError } from \"./errors.js\";\nimport { mapOAuthError } from \"./oauth-map.js\";\nimport type { FetchLike } from \"./types.js\";\n\nexport interface VerifyJwtOptions {\n issuerUrl: string;\n /** Expected JWT `aud` (resource identifier). */\n audience: string;\n fetch?: FetchLike;\n allowInsecureHttp?: boolean;\n /** If set, every scope here must appear in the token's `scope` claim (space-separated). */\n requiredScopes?: string[];\n}\n\n/**\n * RFC 9068 / RFC 6750: validate a JWT access token using issuer JWKS via oauth4webapi.\n */\nexport async function verifyJwt(\n token: string,\n options: VerifyJwtOptions,\n): Promise<JWTAccessTokenClaims> {\n const fetchImpl = options.fetch ?? fetch;\n const as = await loadAuthorizationServer(options.issuerUrl, fetchImpl, {\n allowInsecureHttp: options.allowInsecureHttp,\n });\n\n const request = new Request(\"https://resource.invalid/\", {\n headers: {\n Authorization: `Bearer ${token}`,\n },\n });\n\n const httpOpts: Record<symbol, unknown> = {\n [customFetch]: fetchImpl,\n };\n if (options.allowInsecureHttp) {\n httpOpts[allowInsecureRequests] = true;\n }\n\n try {\n const claims = await validateJwtAccessToken(\n as,\n request,\n options.audience,\n httpOpts as import(\"oauth4webapi\").ValidateJWTAccessTokenOptions,\n );\n\n if (options.requiredScopes?.length) {\n const scopeStr = typeof claims.scope === \"string\" ? claims.scope : \"\";\n const have = new Set(scopeStr.split(/\\s+/).filter(Boolean));\n for (const s of options.requiredScopes) {\n if (!have.has(s)) {\n throw new PmtHouseError(`Missing required scope: ${s}`, {\n status: 403,\n code: \"insufficient_scope\",\n });\n }\n }\n }\n\n return claims;\n } catch (e) {\n throw mapOAuthError(e);\n }\n}\n","import type { PaymentWebhookRequest } from \"./types.js\";\n\nexport function headerValueFromWebhookPayload(\n headers: Record<string, string[]> | undefined,\n name: string,\n): string {\n if (!headers) {\n return \"\";\n }\n const target = name.toLowerCase();\n for (const [key, values] of Object.entries(headers)) {\n if (key.toLowerCase() !== target) {\n continue;\n }\n if (!Array.isArray(values)) {\n continue;\n }\n for (const value of values) {\n if (typeof value === \"string\" && value.trim()) {\n return value.trim();\n }\n }\n }\n return \"\";\n}\n\n/** End-user Authorization from go-livepeer webhook body (headers map or legacy field). */\nexport function authorizationFromWebhookPayload(\n payload: PaymentWebhookRequest,\n): string {\n const fromHeaders = headerValueFromWebhookPayload(\n payload.headers,\n \"Authorization\",\n );\n if (fromHeaders) {\n return fromHeaders;\n }\n return payload.authorization?.trim() ?? \"\";\n}\n","import { timingSafeEqual } from \"node:crypto\";\nimport { PmtHouseError } from \"../../errors.js\";\nimport { authorizationFromWebhookPayload } from \"./payload.js\";\nimport type { PaymentWebhookRequest, PaymentWebhookResponse } from \"./types.js\";\nimport type { EndUserAuthVerifier, VerifiedEndUserAuth } from \"./verifier.js\";\n\nexport type {\n EndUserAuthVerifier,\n EndUserAuthVerifyContext,\n VerifiedEndUserAuth,\n WebhookAdminRoute,\n} from \"./verifier.js\";\n\nexport type WebhookAuthorizeContext = {\n authorization: string;\n payload: PaymentWebhookRequest;\n request: Request;\n verified: VerifiedEndUserAuth;\n identity: VerifiedEndUserAuth[\"identity\"];\n};\n\nexport type RemoteSignerWebhookConfig = {\n webhookSecret: string;\n endUserAuth: EndUserAuthVerifier;\n afterVerify?: (context: WebhookAuthorizeContext) => Promise<void>;\n};\n\nfunction authIdFromIdentity(identity: VerifiedEndUserAuth[\"identity\"]): string {\n return `${identity.client_id}:${identity.usage_subject}`;\n}\n\nfunction timingSafeEqualStrings(a: string, b: string): boolean {\n const aBuffer = Buffer.from(a);\n const bBuffer = Buffer.from(b);\n if (aBuffer.length !== bBuffer.length) {\n return false;\n }\n return timingSafeEqual(aBuffer, bBuffer);\n}\n\nexport function authenticateWebhookCaller(request: Request, secret: string): boolean {\n if (!secret.trim()) {\n return false;\n }\n const trimmed = secret.trim();\n const auth = request.headers.get(\"authorization\")?.trim() ?? \"\";\n if (auth === `Bearer ${trimmed}`) {\n return true;\n }\n const apiKey = request.headers.get(\"x-api-key\")?.trim() ?? \"\";\n if (apiKey && timingSafeEqualStrings(apiKey, trimmed)) {\n return true;\n }\n const legacySecret = request.headers.get(\"x-webhook-secret\")?.trim() ?? \"\";\n if (legacySecret && timingSafeEqualStrings(legacySecret, trimmed)) {\n return true;\n }\n return false;\n}\n\nfunction paymentWebhookJson(\n httpStatus: number,\n body: PaymentWebhookResponse,\n): Response {\n return new Response(JSON.stringify(body), {\n status: httpStatus,\n headers: { \"Content-Type\": \"application/json\" },\n });\n}\n\nfunction rejectStatusFromError(err: unknown): { status: number; reason: string } {\n if (err instanceof PmtHouseError) {\n return {\n status: err.status >= 400 && err.status < 600 ? err.status : 403,\n reason: err.message,\n };\n }\n const reason = err instanceof Error ? err.message : \"authorization rejected\";\n return { status: 403, reason };\n}\n\nexport async function handleRemoteSignerAuthorize(\n request: Request,\n config: RemoteSignerWebhookConfig,\n): Promise<Response> {\n if (!authenticateWebhookCaller(request, config.webhookSecret)) {\n return paymentWebhookJson(401, {\n status: 401,\n reason: \"unauthorized webhook caller\",\n });\n }\n\n let payload: PaymentWebhookRequest;\n try {\n payload = (await request.json()) as PaymentWebhookRequest;\n } catch {\n return paymentWebhookJson(400, {\n status: 400,\n reason: \"invalid request json\",\n });\n }\n\n const authorization = authorizationFromWebhookPayload(payload) ?? \"\";\n\n try {\n const verified = await config.endUserAuth.verify({\n authorization,\n payload,\n request,\n });\n\n if (config.afterVerify) {\n await config.afterVerify({\n authorization,\n payload,\n request,\n verified,\n identity: verified.identity,\n });\n }\n\n return paymentWebhookJson(200, {\n status: 200,\n expiry: verified.expiry,\n auth_id: authIdFromIdentity(verified.identity),\n identity: verified.identity,\n });\n } catch (err) {\n const { status, reason } = rejectStatusFromError(err);\n return paymentWebhookJson(200, {\n status,\n reason,\n });\n }\n}\n\nexport function createRemoteSignerAuthorizeHandler(\n config: RemoteSignerWebhookConfig,\n): (request: Request) => Promise<Response> {\n return (request) => handleRemoteSignerAuthorize(request, config);\n}\n\nexport async function routeRemoteSignerWebhookRequest(\n request: Request,\n config: RemoteSignerWebhookConfig,\n): Promise<Response | null> {\n const url = new URL(request.url);\n if (request.method === \"POST\" && url.pathname === \"/authorize\") {\n return handleRemoteSignerAuthorize(request, config);\n }\n\n const adminRoutes = config.endUserAuth.adminRoutes ?? [];\n for (const route of adminRoutes) {\n if (request.method === route.method && url.pathname === route.pathname) {\n return route.handler(request);\n }\n }\n\n return null;\n}\n","import { PmtHouseError } from \"../../errors.js\";\nimport type { UsageIdentity } from \"./types.js\";\n\nexport type WebhookIdentityClaimMapping = {\n claimClientId: string;\n claimUsageSubject: string;\n usageSubjectType: string;\n};\n\nexport const DEFAULT_WEBHOOK_IDENTITY_CLAIMS: WebhookIdentityClaimMapping = {\n claimClientId: \"client_id\",\n claimUsageSubject: \"sub\",\n usageSubjectType: \"external_user_id\",\n};\n\nfunction readClaim(payload: Record<string, unknown>, key: string): string {\n const value = payload[key];\n if (typeof value === \"string\" && value.trim()) {\n return value.trim();\n }\n if (\n typeof value === \"number\" ||\n typeof value === \"boolean\" ||\n typeof value === \"bigint\"\n ) {\n return value.toString().trim();\n }\n return \"\";\n}\n\nexport function identityFromWebhookClaims(\n claims: Record<string, unknown>,\n mapping: Partial<WebhookIdentityClaimMapping> = {},\n): UsageIdentity {\n const claimClientId =\n mapping.claimClientId ?? DEFAULT_WEBHOOK_IDENTITY_CLAIMS.claimClientId;\n const claimUsageSubject =\n mapping.claimUsageSubject ?? DEFAULT_WEBHOOK_IDENTITY_CLAIMS.claimUsageSubject;\n const defaultUsageSubjectType =\n mapping.usageSubjectType ?? DEFAULT_WEBHOOK_IDENTITY_CLAIMS.usageSubjectType;\n\n let clientId = readClaim(claims, claimClientId);\n if (!clientId) {\n clientId = readClaim(claims, \"azp\");\n }\n\n const usageSubject = readClaim(claims, claimUsageSubject);\n let usageSubjectType = defaultUsageSubjectType;\n const claimUsageSubjectType = readClaim(claims, \"usage_subject_type\");\n if (claimUsageSubjectType) {\n usageSubjectType = claimUsageSubjectType;\n }\n\n const identity: UsageIdentity = {\n issuer: readClaim(claims, \"iss\"),\n client_id: clientId,\n usage_subject: usageSubject,\n usage_subject_type: usageSubjectType,\n };\n\n if (!identity.issuer || !identity.client_id || !identity.usage_subject) {\n throw new PmtHouseError(\"JWT missing required identity claims\", {\n status: 403,\n code: \"invalid_identity\",\n });\n }\n\n return identity;\n}\n\nexport function claimExpirySeconds(\n claims: Record<string, unknown>,\n fallbackTtlSeconds = 300,\n): number {\n const exp = claims.exp;\n if (typeof exp === \"number\" && Number.isFinite(exp)) {\n return Math.trunc(exp);\n }\n if (typeof exp === \"string\" && exp.trim()) {\n const parsed = Number(exp);\n if (Number.isFinite(parsed)) {\n return Math.trunc(parsed);\n }\n }\n return Math.trunc(Date.now() / 1000) + fallbackTtlSeconds;\n}\n","import { loadAuthorizationServer } from \"../../../../discovery.js\";\nimport { verifyJwt } from \"../../../../verify.js\";\nimport type { FetchLike } from \"../../../../types.js\";\nimport { authenticateWebhookCaller } from \"../../authorize.js\";\nimport {\n claimExpirySeconds,\n DEFAULT_WEBHOOK_IDENTITY_CLAIMS,\n identityFromWebhookClaims,\n type WebhookIdentityClaimMapping,\n} from \"../../identity.js\";\nimport { bearerTokenFromAuthorization } from \"../../bearer.js\";\nimport type { EndUserAuthVerifier } from \"../../verifier.js\";\n\nexport type OidcEndUserAuthConfig = {\n jwtIssuer: string;\n jwtAudience: string;\n claimMapping?: Partial<WebhookIdentityClaimMapping>;\n allowInsecureHttp?: boolean;\n fetch?: FetchLike;\n requiredScopes?: string[];\n webhookSecret: string;\n};\n\nexport async function handleRemoteSignerRefreshJwks(\n request: Request,\n config: Pick<\n OidcEndUserAuthConfig,\n \"webhookSecret\" | \"jwtIssuer\" | \"fetch\" | \"allowInsecureHttp\"\n >,\n): Promise<Response> {\n if (!authenticateWebhookCaller(request, config.webhookSecret)) {\n return new Response(\"unauthorized\", { status: 401 });\n }\n\n try {\n await loadAuthorizationServer(config.jwtIssuer, config.fetch ?? fetch, {\n force: true,\n allowInsecureHttp: config.allowInsecureHttp,\n });\n return new Response(JSON.stringify({ status: \"ok\" }), {\n status: 200,\n headers: { \"Content-Type\": \"application/json\" },\n });\n } catch (err) {\n const message = err instanceof Error ? err.message : \"jwks refresh failed\";\n return new Response(message, { status: 500 });\n }\n}\n\nexport function createOidcEndUserVerifier(\n config: OidcEndUserAuthConfig,\n): EndUserAuthVerifier {\n const claimMapping = {\n ...DEFAULT_WEBHOOK_IDENTITY_CLAIMS,\n ...config.claimMapping,\n };\n\n return {\n kind: \"oidc\",\n verify: async ({ authorization }) => {\n const token = bearerTokenFromAuthorization(authorization);\n const audience = config.jwtAudience.trim();\n if (!audience) {\n throw new Error(\"jwt audience is required for webhook verification\");\n }\n\n const claims = await verifyJwt(token, {\n issuerUrl: config.jwtIssuer,\n audience,\n fetch: config.fetch,\n allowInsecureHttp: config.allowInsecureHttp,\n requiredScopes: config.requiredScopes,\n });\n\n const claimsRecord = claims as unknown as Record<string, unknown>;\n const identity = identityFromWebhookClaims(claimsRecord, claimMapping);\n\n return {\n identity,\n expiry: claimExpirySeconds(claimsRecord),\n raw: claimsRecord,\n };\n },\n adminRoutes: [\n {\n method: \"POST\",\n pathname: \"/admin/refresh-jwks\",\n handler: (request) => handleRemoteSignerRefreshJwks(request, config),\n },\n ],\n };\n}\n","import { PmtHouseError } from \"../../../../errors.js\";\nimport type { EndUserAuthVerifier } from \"../../verifier.js\";\n\nexport function createFirstMatchEndUserVerifier(\n verifiers: EndUserAuthVerifier[],\n): EndUserAuthVerifier {\n if (verifiers.length === 0) {\n throw new PmtHouseError(\"at least one verifier is required\", {\n status: 500,\n code: \"invalid_verifier_config\",\n });\n }\n\n return {\n kind: \"custom\",\n verify: async (context) => {\n let lastError: unknown;\n for (const verifier of verifiers) {\n try {\n return await verifier.verify(context);\n } catch (err) {\n lastError = err;\n }\n }\n\n if (lastError instanceof PmtHouseError) {\n throw lastError;\n }\n if (lastError instanceof Error) {\n throw new PmtHouseError(lastError.message, {\n status: 401,\n code: \"invalid_credentials\",\n });\n }\n throw new PmtHouseError(\"invalid credentials\", {\n status: 401,\n code: \"invalid_credentials\",\n });\n },\n adminRoutes: verifiers.flatMap((verifier) => verifier.adminRoutes ?? []),\n };\n}\n","import { PmtHouseError } from \"../../../../errors.js\";\nimport { headerValueFromWebhookPayload } from \"../../payload.js\";\nimport type { EndUserAuthVerifier } from \"../../verifier.js\";\nimport type { UsageIdentity } from \"../../types.js\";\n\nexport const DEFAULT_DMZ_TRUSTED_HEADERS = {\n issuer: \"X-Livepeer-Usage-Issuer\",\n clientId: \"X-Livepeer-Client-ID\",\n usageSubject: \"X-Livepeer-Usage-Subject\",\n usageSubjectType: \"X-Livepeer-Usage-Subject-Type\",\n} as const;\n\nexport type TrustedHeadersEndUserAuthConfig = {\n expectedIssuer: string;\n headerNames?: Partial<typeof DEFAULT_DMZ_TRUSTED_HEADERS>;\n /** Auth cache TTL returned to go-livepeer when headers are trusted. */\n expiryTtlSeconds?: number;\n};\n\nfunction normalizeIssuer(value: string): string {\n let end = value.length;\n while (end > 0 && value[end - 1] === \"/\") {\n end -= 1;\n }\n return value.slice(0, end);\n}\n\nexport function identityFromTrustedHeaders(\n headers: Record<string, string[]> | undefined,\n config: TrustedHeadersEndUserAuthConfig,\n): UsageIdentity {\n const names = {\n ...DEFAULT_DMZ_TRUSTED_HEADERS,\n ...config.headerNames,\n };\n const issuer = headerValueFromWebhookPayload(headers, names.issuer);\n const clientId = headerValueFromWebhookPayload(headers, names.clientId);\n const usageSubject = headerValueFromWebhookPayload(headers, names.usageSubject);\n const usageSubjectType =\n headerValueFromWebhookPayload(headers, names.usageSubjectType) ||\n \"external_user_id\";\n\n if (!issuer || !clientId || !usageSubject) {\n throw new PmtHouseError(\"missing trusted usage identity headers\", {\n status: 403,\n code: \"invalid_identity\",\n });\n }\n\n if (\n normalizeIssuer(issuer) !== normalizeIssuer(config.expectedIssuer.trim())\n ) {\n throw new PmtHouseError(\"trusted usage issuer mismatch\", {\n status: 403,\n code: \"invalid_identity\",\n });\n }\n\n return {\n issuer,\n client_id: clientId,\n usage_subject: usageSubject,\n usage_subject_type: usageSubjectType,\n };\n}\n\nexport function createTrustedHeadersEndUserVerifier(\n config: TrustedHeadersEndUserAuthConfig,\n): EndUserAuthVerifier {\n const expiryTtlSeconds = config.expiryTtlSeconds ?? 300;\n\n return {\n kind: \"trusted_headers\",\n verify: async ({ payload }) => {\n const identity = identityFromTrustedHeaders(payload.headers, config);\n return {\n identity,\n expiry: Math.trunc(Date.now() / 1000) + expiryTtlSeconds,\n };\n },\n };\n}\n","import type {\n RemoteSignerWebhookConfig,\n WebhookAuthorizeContext,\n} from \"../../authorize.js\";\nimport { createFirstMatchEndUserVerifier } from \"../composite/verifier.js\";\nimport {\n createTrustedHeadersEndUserVerifier,\n type TrustedHeadersEndUserAuthConfig,\n} from \"../trusted-headers/verifier.js\";\nimport {\n createOidcEndUserVerifier,\n type OidcEndUserAuthConfig,\n} from \"./verifier.js\";\n\nfunction envTrim(env: NodeJS.ProcessEnv, key: string): string | undefined {\n const value = env[key]?.trim();\n return value || undefined;\n}\n\nexport type OidcRemoteSignerWebhookConfigInput = OidcEndUserAuthConfig & {\n afterVerify?: (context: WebhookAuthorizeContext) => Promise<void>;\n};\n\nexport type SignerDmzRemoteSignerWebhookConfigInput =\n OidcRemoteSignerWebhookConfigInput & {\n /** When true (default), accept Apache DMZ X-Livepeer-* identity headers. */\n dmzTrustedHeaders?: boolean;\n trustedHeaders?: Omit<TrustedHeadersEndUserAuthConfig, \"expectedIssuer\">;\n };\n\nexport function createOidcRemoteSignerWebhookConfig(\n input: OidcRemoteSignerWebhookConfigInput,\n): RemoteSignerWebhookConfig {\n const { afterVerify, ...oidcConfig } = input;\n return {\n webhookSecret: oidcConfig.webhookSecret,\n endUserAuth: createOidcEndUserVerifier(oidcConfig),\n afterVerify,\n };\n}\n\n/**\n * PymtHouse signer-dmz: Apache validates the end-user JWT (iss/aud = issuer), injects\n * X-Livepeer-* headers, and go-livepeer forwards those headers to this webhook per\n * go-livepeer remote-signer.md. Falls back to Bearer JWT verification when present.\n */\nexport function createSignerDmzRemoteSignerWebhookConfig(\n input: SignerDmzRemoteSignerWebhookConfigInput,\n): RemoteSignerWebhookConfig {\n const {\n afterVerify,\n dmzTrustedHeaders = true,\n trustedHeaders,\n ...oidcConfig\n } = input;\n const oidcVerifier = createOidcEndUserVerifier(oidcConfig);\n const endUserAuth =\n dmzTrustedHeaders === false\n ? oidcVerifier\n : createFirstMatchEndUserVerifier([\n createTrustedHeadersEndUserVerifier({\n expectedIssuer: oidcConfig.jwtIssuer,\n ...trustedHeaders,\n }),\n oidcVerifier,\n ]);\n\n return {\n webhookSecret: oidcConfig.webhookSecret,\n endUserAuth,\n afterVerify,\n };\n}\n\nexport function readOidcRemoteSignerWebhookConfigFromEnv(\n env: NodeJS.ProcessEnv = process.env,\n): RemoteSignerWebhookConfig {\n const webhookSecret = envTrim(env, \"WEBHOOK_SECRET\");\n const jwtIssuer = envTrim(env, \"JWT_ISSUER\");\n const jwtAudience = envTrim(env, \"JWT_AUDIENCE\") ?? jwtIssuer;\n\n if (!webhookSecret) {\n throw new Error(\"WEBHOOK_SECRET is required\");\n }\n if (!jwtIssuer) {\n throw new Error(\"JWT_ISSUER is required\");\n }\n if (!jwtAudience) {\n throw new Error(\"JWT_AUDIENCE is required\");\n }\n\n return createSignerDmzRemoteSignerWebhookConfig({\n webhookSecret,\n jwtIssuer,\n jwtAudience,\n claimMapping: {\n claimClientId: envTrim(env, \"CLAIM_CLIENT_ID\") ?? \"client_id\",\n claimUsageSubject: envTrim(env, \"CLAIM_USAGE_SUBJECT\") ?? \"sub\",\n usageSubjectType: envTrim(env, \"USAGE_SUBJECT_TYPE\") ?? \"external_user_id\",\n },\n allowInsecureHttp: envTrim(env, \"ALLOW_INSECURE_HTTP\") === \"1\",\n });\n}\n\n/** @deprecated Use readOidcRemoteSignerWebhookConfigFromEnv */\nexport const readRemoteSignerWebhookConfigFromEnv =\n readOidcRemoteSignerWebhookConfigFromEnv;\n"]}
|
|
1
|
+
{"version":3,"sources":["../../../../src/signer/webhook/bearer.ts","../../../../src/errors.ts","../../../../src/string-utils.ts","../../../../src/discovery.ts","../../../../src/oauth-map.ts","../../../../src/verify.ts","../../../../src/signer/webhook/payload.ts","../../../../src/signer/webhook/authorize.ts","../../../../src/signer/webhook/identity.ts","../../../../src/signer/webhook/adapters/oidc/verifier.ts","../../../../src/signer/webhook/adapters/composite/verifier.ts","../../../../src/signer/webhook/adapters/trusted-headers/verifier.ts","../../../../src/signer/webhook/adapters/oidc/config.ts"],"names":["customFetch","allowInsecureRequests"],"mappings":"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","file":"oidc.js","sourcesContent":["const BEARER_PREFIX = \"Bearer \";\n\n/** Returns the token after `Bearer `, or null when the header is missing or not Bearer. */\nexport function optionalBearerToken(authorization: string): string | null {\n const trimmed = authorization.trim();\n if (!trimmed.startsWith(BEARER_PREFIX)) {\n return null;\n }\n const token = trimmed.slice(BEARER_PREFIX.length).trim();\n return token || null;\n}\n\nexport function bearerTokenFromAuthorization(authorization: string): string {\n const token = optionalBearerToken(authorization);\n if (token) {\n return token;\n }\n if (!authorization.trim()) {\n throw new Error(\"missing authorization\");\n }\n throw new Error(\"authorization must be Bearer token\");\n}\n","export class PmtHouseError extends Error {\n readonly status: number;\n readonly code: string;\n readonly details?: unknown;\n\n constructor(\n message: string,\n {\n status = 500,\n code = \"pymthouse_error\",\n details,\n }: {\n status?: number;\n code?: string;\n details?: unknown;\n } = {},\n ) {\n super(message);\n this.name = \"PmtHouseError\";\n this.status = status;\n this.code = code;\n this.details = details;\n }\n}\n\nexport function toPmtHouseError(\n error: unknown,\n fallbackMessage: string,\n): PmtHouseError {\n if (error instanceof PmtHouseError) {\n return error;\n }\n\n if (error instanceof Error) {\n return new PmtHouseError(error.message || fallbackMessage, {\n code: \"unexpected_error\",\n status: 500,\n });\n }\n\n return new PmtHouseError(fallbackMessage, {\n code: \"unexpected_error\",\n status: 500,\n });\n}\n","/** Removes trailing `/` without regex (linear time). */\nexport function stripTrailingSlashes(value: string): string {\n let end = value.length;\n while (end > 0 && (value.codePointAt(end - 1) ?? 0) === 47) {\n end--;\n }\n return value.slice(0, end);\n}\n\nfunction endsWithIgnoreCase(value: string, suffix: string): boolean {\n if (suffix.length > value.length) {\n return false;\n }\n const start = value.length - suffix.length;\n for (let i = 0; i < suffix.length; i++) {\n const a = value.codePointAt(start + i) ?? 0;\n const b = suffix.codePointAt(i) ?? 0;\n if (a !== b && (a | 32) !== (b | 32)) {\n return false;\n }\n }\n return true;\n}\n\nfunction stripSuffixIgnoreCase(value: string, suffix: string): string {\n return endsWithIgnoreCase(value, suffix)\n ? value.slice(0, value.length - suffix.length)\n : value;\n}\n\n/** Issuer URL (`…/oidc`) → Builder API base (`…/api/v1`). Linear-time; no regex. */\nexport function stripOidcPathSuffix(issuerUrl: string): string {\n let base = stripTrailingSlashes(issuerUrl.trim());\n base = stripSuffixIgnoreCase(base, \"/oidc\");\n return stripTrailingSlashes(base);\n}\n\n/** Issuer URL (`…/api/v1/oidc`) → host origin for signer/API-key routes. Linear-time; no regex. */\nexport function stripIssuerOriginFromOidcUrl(issuerUrl: string): string {\n let base = stripTrailingSlashes(issuerUrl.trim());\n base = stripSuffixIgnoreCase(base, \"/api/v1/oidc\");\n base = stripSuffixIgnoreCase(base, \"/oidc\");\n return stripTrailingSlashes(base);\n}\n\n/** Parse and validate an http(s) facade origin (no path). */\nexport function parseHttpOrigin(raw: string | undefined, fallback: string): string {\n const trimmed = (raw ?? fallback).trim();\n let parsed: URL;\n try {\n parsed = new URL(trimmed);\n } catch {\n throw new TypeError(\"Origin must be a valid http(s) URL\");\n }\n if (parsed.protocol !== \"http:\" && parsed.protocol !== \"https:\") {\n throw new TypeError(\"Origin must use http or https\");\n }\n return parsed.origin;\n}\n\n","import {\n allowInsecureRequests,\n customFetch,\n discoveryRequest,\n processDiscoveryResponse,\n type AuthorizationServer,\n} from \"oauth4webapi\";\nimport { PmtHouseError } from \"./errors.js\";\nimport { stripTrailingSlashes } from \"./string-utils.js\";\nimport type { FetchLike, OidcDiscoveryDocument } from \"./types.js\";\n\nexport function authorizationServerToOidcDocument(as: AuthorizationServer): OidcDiscoveryDocument {\n const tokenEndpoint = as.token_endpoint;\n const jwksUri = as.jwks_uri;\n if (!tokenEndpoint || !jwksUri) {\n throw new PmtHouseError(\"OIDC discovery document is missing token_endpoint or jwks_uri\", {\n status: 500,\n code: \"oidc_discovery_invalid\",\n });\n }\n return {\n issuer: as.issuer,\n authorization_endpoint: as.authorization_endpoint ?? \"\",\n token_endpoint: tokenEndpoint,\n jwks_uri: jwksUri,\n userinfo_endpoint: as.userinfo_endpoint,\n device_authorization_endpoint: as.device_authorization_endpoint,\n };\n}\n\nconst CACHE_TTL_MS = 5 * 60 * 1000;\n\ntype CacheEntry = {\n as: AuthorizationServer;\n fetchedAt: number;\n};\n\nconst discoveryCache = new Map<string, CacheEntry>();\n\nfunction normalizedIssuerKey(issuerUrl: string): string {\n return stripTrailingSlashes(issuerUrl);\n}\n\nexport interface LoadAuthorizationServerOptions {\n force?: boolean;\n allowInsecureHttp?: boolean;\n}\n\n/**\n * Loads OIDC discovery metadata via oauth4webapi (RFC 8414 / OIDC Discovery), with a 5-minute cache.\n */\nexport async function loadAuthorizationServer(\n issuerUrl: string,\n fetchImpl: FetchLike,\n options: LoadAuthorizationServerOptions = {},\n): Promise<AuthorizationServer> {\n const key = normalizedIssuerKey(issuerUrl);\n const now = Date.now();\n const cached = discoveryCache.get(key);\n\n if (!options.force && cached && now - cached.fetchedAt < CACHE_TTL_MS) {\n return cached.as;\n }\n\n const issuerIdentifier = new URL(key);\n const discoveryOpts: Parameters<typeof discoveryRequest>[1] = {\n algorithm: \"oidc\",\n [customFetch]: fetchImpl,\n };\n if (options.allowInsecureHttp) {\n discoveryOpts[allowInsecureRequests] = true;\n }\n\n let response: Response;\n try {\n response = await discoveryRequest(issuerIdentifier, discoveryOpts);\n } catch (e) {\n throw mapDiscoveryNetworkError(e);\n }\n\n let as: AuthorizationServer;\n try {\n as = await processDiscoveryResponse(issuerIdentifier, response);\n } catch (e) {\n throw mapOAuthDiscoveryError(e);\n }\n\n discoveryCache.set(key, { as, fetchedAt: now });\n return as;\n}\n\nexport async function fetchDiscoveryDocument(\n issuerUrl: string,\n fetchImpl: FetchLike,\n options: LoadAuthorizationServerOptions = {},\n): Promise<OidcDiscoveryDocument> {\n const as = await loadAuthorizationServer(issuerUrl, fetchImpl, options);\n return authorizationServerToOidcDocument(as);\n}\n\nexport function clearDiscoveryCache(issuerUrl?: string): void {\n if (!issuerUrl) {\n discoveryCache.clear();\n return;\n }\n discoveryCache.delete(normalizedIssuerKey(issuerUrl));\n}\n\nfunction mapOAuthDiscoveryError(error: unknown): PmtHouseError {\n if (error instanceof PmtHouseError) {\n return error;\n }\n if (error instanceof Error) {\n return new PmtHouseError(error.message, {\n status: 500,\n code: \"oidc_discovery_invalid\",\n details: { cause: error.cause },\n });\n }\n return new PmtHouseError(\"OIDC discovery failed\", {\n status: 500,\n code: \"oidc_discovery_invalid\",\n });\n}\n\nfunction mapDiscoveryNetworkError(error: unknown): PmtHouseError {\n if (error instanceof PmtHouseError) {\n return error;\n }\n if (error instanceof Error) {\n return new PmtHouseError(`Failed to load OIDC discovery: ${error.message}`, {\n status: 502,\n code: \"oidc_discovery_failed\",\n });\n }\n return new PmtHouseError(\"Failed to load OIDC discovery\", {\n status: 502,\n code: \"oidc_discovery_failed\",\n });\n}\n","import { type Client, OperationProcessingError, ResponseBodyError } from \"oauth4webapi\";\nimport { PmtHouseError } from \"./errors.js\";\nimport type { ClientCredentialsTokenResponse, TokenExchangeResponse } from \"./types.js\";\n\nconst ACCEPTED_ISSUED_TOKEN_TYPES = new Set([\n \"urn:ietf:params:oauth:token-type:access_token\",\n \"urn:pmth:token-type:remote-signer-session\",\n]);\n\nexport function mapOAuthError(error: unknown): PmtHouseError {\n if (error instanceof PmtHouseError) {\n return error;\n }\n\n if (error instanceof ResponseBodyError) {\n const cause = error.cause as Record<string, unknown>;\n const description =\n typeof error.error_description === \"string\"\n ? error.error_description\n : error.message;\n const details: Record<string, unknown> = { ...cause };\n if (typeof cause.error_uri === \"string\") {\n details.error_uri = cause.error_uri;\n }\n return new PmtHouseError(description, {\n status: error.status,\n code: error.error,\n details,\n });\n }\n\n if (error instanceof OperationProcessingError) {\n return new PmtHouseError(error.message, {\n status: 502,\n code: error.code ?? \"oauth_processing_error\",\n details: { cause: error.cause },\n });\n }\n\n if (error instanceof Error) {\n return new PmtHouseError(error.message, {\n status: 500,\n code: \"unexpected_error\",\n });\n }\n\n return new PmtHouseError(\"Unexpected error\", {\n status: 500,\n code: \"unexpected_error\",\n });\n}\n\nexport function tokenEndpointResponseToExchange(\n tr: import(\"oauth4webapi\").TokenEndpointResponse,\n): TokenExchangeResponse {\n const issued = tr.issued_token_type;\n if (typeof issued !== \"string\" || !ACCEPTED_ISSUED_TOKEN_TYPES.has(issued)) {\n throw new PmtHouseError(\"Token exchange returned an unexpected issued_token_type\", {\n status: 502,\n code: \"invalid_token_response\",\n details: { issued_token_type: issued },\n });\n }\n\n const tt = tr.token_type;\n if (typeof tt !== \"string\" || tt.toLowerCase() !== \"bearer\") {\n throw new PmtHouseError(\"Token endpoint returned a non-Bearer token_type\", {\n status: 502,\n code: \"invalid_token_response\",\n details: { token_type: tt },\n });\n }\n\n const expiresIn = tr.expires_in;\n if (typeof expiresIn !== \"number\") {\n throw new PmtHouseError(\"Token response missing expires_in\", {\n status: 502,\n code: \"invalid_token_response\",\n });\n }\n\n const scope = typeof tr.scope === \"string\" ? tr.scope : \"\";\n\n return {\n access_token: tr.access_token,\n token_type: \"Bearer\",\n expires_in: expiresIn,\n scope,\n issued_token_type: issued,\n };\n}\n\nexport function tokenEndpointResponseToClientCredentials(\n tr: import(\"oauth4webapi\").TokenEndpointResponse,\n): ClientCredentialsTokenResponse {\n const tt = tr.token_type;\n if (typeof tt !== \"string\" || tt.toLowerCase() !== \"bearer\") {\n throw new PmtHouseError(\"Token endpoint returned a non-Bearer token_type\", {\n status: 502,\n code: \"invalid_token_response\",\n details: { token_type: tt },\n });\n }\n\n return {\n access_token: tr.access_token,\n token_type: \"Bearer\",\n expires_in: tr.expires_in,\n scope: typeof tr.scope === \"string\" ? tr.scope : undefined,\n };\n}\n\nexport function m2mClient(clientId: string): Client {\n return { client_id: clientId };\n}\n","import {\n allowInsecureRequests,\n customFetch,\n validateJwtAccessToken,\n type JWTAccessTokenClaims,\n} from \"oauth4webapi\";\nimport { loadAuthorizationServer } from \"./discovery.js\";\nimport { PmtHouseError } from \"./errors.js\";\nimport { mapOAuthError } from \"./oauth-map.js\";\nimport type { FetchLike } from \"./types.js\";\n\nexport interface VerifyJwtOptions {\n issuerUrl: string;\n /** Expected JWT `aud` (resource identifier). */\n audience: string;\n fetch?: FetchLike;\n allowInsecureHttp?: boolean;\n /** If set, every scope here must appear in the token's `scope` claim (space-separated). */\n requiredScopes?: string[];\n}\n\n/**\n * RFC 9068 / RFC 6750: validate a JWT access token using issuer JWKS via oauth4webapi.\n */\nexport async function verifyJwt(\n token: string,\n options: VerifyJwtOptions,\n): Promise<JWTAccessTokenClaims> {\n const fetchImpl = options.fetch ?? fetch;\n const as = await loadAuthorizationServer(options.issuerUrl, fetchImpl, {\n allowInsecureHttp: options.allowInsecureHttp,\n });\n\n const request = new Request(\"https://resource.invalid/\", {\n headers: {\n Authorization: `Bearer ${token}`,\n },\n });\n\n const httpOpts: Record<symbol, unknown> = {\n [customFetch]: fetchImpl,\n };\n if (options.allowInsecureHttp) {\n httpOpts[allowInsecureRequests] = true;\n }\n\n try {\n const claims = await validateJwtAccessToken(\n as,\n request,\n options.audience,\n httpOpts as import(\"oauth4webapi\").ValidateJWTAccessTokenOptions,\n );\n\n if (options.requiredScopes?.length) {\n const scopeStr = typeof claims.scope === \"string\" ? claims.scope : \"\";\n const have = new Set(scopeStr.split(/\\s+/).filter(Boolean));\n for (const s of options.requiredScopes) {\n if (!have.has(s)) {\n throw new PmtHouseError(`Missing required scope: ${s}`, {\n status: 403,\n code: \"insufficient_scope\",\n });\n }\n }\n }\n\n return claims;\n } catch (e) {\n throw mapOAuthError(e);\n }\n}\n","import type { PaymentWebhookRequest } from \"./types.js\";\n\nfunction firstHeaderValue(values: string[] | undefined): string {\n if (!Array.isArray(values)) {\n return \"\";\n }\n for (const value of values) {\n if (typeof value === \"string\" && value.trim()) {\n return value.trim();\n }\n }\n return \"\";\n}\n\nexport function headerValueFromWebhookPayload(\n headers: Record<string, string[]> | undefined,\n name: string,\n): string {\n if (!headers) {\n return \"\";\n }\n const direct = firstHeaderValue(headers[name]);\n if (direct) {\n return direct;\n }\n const target = name.toLowerCase();\n for (const [key, values] of Object.entries(headers)) {\n if (key.toLowerCase() === target) {\n return firstHeaderValue(values);\n }\n }\n return \"\";\n}\n\n/** End-user Authorization from go-livepeer webhook body (headers map or legacy field). */\nexport function authorizationFromWebhookPayload(\n payload: PaymentWebhookRequest,\n): string {\n const fromHeaders = headerValueFromWebhookPayload(\n payload.headers,\n \"Authorization\",\n );\n if (fromHeaders) {\n return fromHeaders;\n }\n return payload.authorization?.trim() ?? \"\";\n}\n","import { timingSafeEqual } from \"node:crypto\";\nimport { PmtHouseError } from \"../../errors.js\";\nimport { optionalBearerToken } from \"./bearer.js\";\nimport { authorizationFromWebhookPayload } from \"./payload.js\";\nimport type { PaymentWebhookRequest, PaymentWebhookResponse } from \"./types.js\";\nimport type { EndUserAuthVerifier, VerifiedEndUserAuth } from \"./verifier.js\";\n\nexport type {\n EndUserAuthVerifier,\n EndUserAuthVerifyContext,\n VerifiedEndUserAuth,\n WebhookAdminRoute,\n} from \"./verifier.js\";\n\nexport type WebhookAuthorizeContext = {\n authorization: string;\n payload: PaymentWebhookRequest;\n request: Request;\n verified: VerifiedEndUserAuth;\n identity: VerifiedEndUserAuth[\"identity\"];\n};\n\nexport type RemoteSignerWebhookConfig = {\n webhookSecret: string;\n endUserAuth: EndUserAuthVerifier;\n afterVerify?: (context: WebhookAuthorizeContext) => Promise<void>;\n};\n\nfunction authIdFromIdentity(identity: VerifiedEndUserAuth[\"identity\"]): string {\n return `${identity.client_id}:${identity.usage_subject}`;\n}\n\nfunction timingSafeEqualStrings(a: string, b: string): boolean {\n const aBuffer = Buffer.from(a);\n const bBuffer = Buffer.from(b);\n if (aBuffer.length !== bBuffer.length) {\n return false;\n }\n return timingSafeEqual(aBuffer, bBuffer);\n}\n\nexport function authenticateWebhookCaller(request: Request, secret: string): boolean {\n if (!secret.trim()) {\n return false;\n }\n const trimmed = secret.trim();\n const bearer = optionalBearerToken(request.headers.get(\"authorization\") ?? \"\");\n if (bearer && timingSafeEqualStrings(bearer, trimmed)) {\n return true;\n }\n const apiKey = request.headers.get(\"x-api-key\")?.trim() ?? \"\";\n if (apiKey && timingSafeEqualStrings(apiKey, trimmed)) {\n return true;\n }\n const legacySecret = request.headers.get(\"x-webhook-secret\")?.trim() ?? \"\";\n if (legacySecret && timingSafeEqualStrings(legacySecret, trimmed)) {\n return true;\n }\n return false;\n}\n\nfunction paymentWebhookJson(\n httpStatus: number,\n body: PaymentWebhookResponse,\n): Response {\n return new Response(JSON.stringify(body), {\n status: httpStatus,\n headers: { \"Content-Type\": \"application/json\" },\n });\n}\n\nfunction rejectStatusFromError(err: unknown): { status: number; reason: string } {\n if (err instanceof PmtHouseError) {\n return {\n status: err.status >= 400 && err.status < 600 ? err.status : 403,\n reason: err.message,\n };\n }\n const reason = err instanceof Error ? err.message : \"authorization rejected\";\n return { status: 403, reason };\n}\n\nexport async function handleRemoteSignerAuthorize(\n request: Request,\n config: RemoteSignerWebhookConfig,\n): Promise<Response> {\n if (!authenticateWebhookCaller(request, config.webhookSecret)) {\n return paymentWebhookJson(401, {\n status: 401,\n reason: \"unauthorized webhook caller\",\n });\n }\n\n let payload: PaymentWebhookRequest;\n try {\n payload = (await request.json()) as PaymentWebhookRequest;\n } catch {\n return paymentWebhookJson(400, {\n status: 400,\n reason: \"invalid request json\",\n });\n }\n\n const authorization = authorizationFromWebhookPayload(payload) ?? \"\";\n\n try {\n const verified = await config.endUserAuth.verify({\n authorization,\n payload,\n request,\n });\n\n if (config.afterVerify) {\n await config.afterVerify({\n authorization,\n payload,\n request,\n verified,\n identity: verified.identity,\n });\n }\n\n return paymentWebhookJson(200, {\n status: 200,\n expiry: verified.expiry,\n auth_id: authIdFromIdentity(verified.identity),\n identity: verified.identity,\n });\n } catch (err) {\n const { status, reason } = rejectStatusFromError(err);\n return paymentWebhookJson(200, {\n status,\n reason,\n });\n }\n}\n\nexport function createRemoteSignerAuthorizeHandler(\n config: RemoteSignerWebhookConfig,\n): (request: Request) => Promise<Response> {\n return (request) => handleRemoteSignerAuthorize(request, config);\n}\n\nexport async function routeRemoteSignerWebhookRequest(\n request: Request,\n config: RemoteSignerWebhookConfig,\n): Promise<Response | null> {\n const url = new URL(request.url);\n if (request.method === \"POST\" && url.pathname === \"/authorize\") {\n return handleRemoteSignerAuthorize(request, config);\n }\n\n const adminRoutes = config.endUserAuth.adminRoutes ?? [];\n for (const route of adminRoutes) {\n if (request.method === route.method && url.pathname === route.pathname) {\n return route.handler(request);\n }\n }\n\n return null;\n}\n","import { PmtHouseError } from \"../../errors.js\";\nimport type { UsageIdentity } from \"./types.js\";\n\nexport type WebhookIdentityClaimMapping = {\n claimClientId: string;\n claimUsageSubject: string;\n usageSubjectType: string;\n};\n\nexport const DEFAULT_WEBHOOK_IDENTITY_CLAIMS: WebhookIdentityClaimMapping = {\n claimClientId: \"client_id\",\n claimUsageSubject: \"sub\",\n usageSubjectType: \"external_user_id\",\n};\n\nfunction readClaim(payload: Record<string, unknown>, key: string): string {\n const value = payload[key];\n if (typeof value === \"string\" && value.trim()) {\n return value.trim();\n }\n if (\n typeof value === \"number\" ||\n typeof value === \"boolean\" ||\n typeof value === \"bigint\"\n ) {\n return value.toString().trim();\n }\n return \"\";\n}\n\nexport function identityFromWebhookClaims(\n claims: Record<string, unknown>,\n mapping: Partial<WebhookIdentityClaimMapping> = {},\n): UsageIdentity {\n const claimClientId =\n mapping.claimClientId ?? DEFAULT_WEBHOOK_IDENTITY_CLAIMS.claimClientId;\n const claimUsageSubject =\n mapping.claimUsageSubject ?? DEFAULT_WEBHOOK_IDENTITY_CLAIMS.claimUsageSubject;\n const defaultUsageSubjectType =\n mapping.usageSubjectType ?? DEFAULT_WEBHOOK_IDENTITY_CLAIMS.usageSubjectType;\n\n let clientId = readClaim(claims, claimClientId);\n if (!clientId) {\n clientId = readClaim(claims, \"azp\");\n }\n\n const usageSubject = readClaim(claims, claimUsageSubject);\n let usageSubjectType = defaultUsageSubjectType;\n const claimUsageSubjectType = readClaim(claims, \"usage_subject_type\");\n if (claimUsageSubjectType) {\n usageSubjectType = claimUsageSubjectType;\n }\n\n const identity: UsageIdentity = {\n issuer: readClaim(claims, \"iss\"),\n client_id: clientId,\n usage_subject: usageSubject,\n usage_subject_type: usageSubjectType,\n };\n\n if (!identity.issuer || !identity.client_id || !identity.usage_subject) {\n throw new PmtHouseError(\"JWT missing required identity claims\", {\n status: 403,\n code: \"invalid_identity\",\n });\n }\n\n return identity;\n}\n\nexport function claimExpirySeconds(\n claims: Record<string, unknown>,\n fallbackTtlSeconds = 300,\n): number {\n const exp = claims.exp;\n if (typeof exp === \"number\" && Number.isFinite(exp)) {\n return Math.trunc(exp);\n }\n if (typeof exp === \"string\" && exp.trim()) {\n const parsed = Number(exp);\n if (Number.isFinite(parsed)) {\n return Math.trunc(parsed);\n }\n }\n return Math.trunc(Date.now() / 1000) + fallbackTtlSeconds;\n}\n","import { loadAuthorizationServer } from \"../../../../discovery.js\";\nimport { verifyJwt } from \"../../../../verify.js\";\nimport type { FetchLike } from \"../../../../types.js\";\nimport { authenticateWebhookCaller } from \"../../authorize.js\";\nimport {\n claimExpirySeconds,\n DEFAULT_WEBHOOK_IDENTITY_CLAIMS,\n identityFromWebhookClaims,\n type WebhookIdentityClaimMapping,\n} from \"../../identity.js\";\nimport { bearerTokenFromAuthorization } from \"../../bearer.js\";\nimport type { EndUserAuthVerifier } from \"../../verifier.js\";\n\nexport type OidcEndUserAuthConfig = {\n jwtIssuer: string;\n jwtAudience: string;\n claimMapping?: Partial<WebhookIdentityClaimMapping>;\n allowInsecureHttp?: boolean;\n fetch?: FetchLike;\n requiredScopes?: string[];\n webhookSecret: string;\n};\n\nexport async function handleRemoteSignerRefreshJwks(\n request: Request,\n config: Pick<\n OidcEndUserAuthConfig,\n \"webhookSecret\" | \"jwtIssuer\" | \"fetch\" | \"allowInsecureHttp\"\n >,\n): Promise<Response> {\n if (!authenticateWebhookCaller(request, config.webhookSecret)) {\n return new Response(\"unauthorized\", { status: 401 });\n }\n\n try {\n await loadAuthorizationServer(config.jwtIssuer, config.fetch ?? fetch, {\n force: true,\n allowInsecureHttp: config.allowInsecureHttp,\n });\n return new Response(JSON.stringify({ status: \"ok\" }), {\n status: 200,\n headers: { \"Content-Type\": \"application/json\" },\n });\n } catch (err) {\n const message = err instanceof Error ? err.message : \"jwks refresh failed\";\n return new Response(message, { status: 500 });\n }\n}\n\nexport function createOidcEndUserVerifier(\n config: OidcEndUserAuthConfig,\n): EndUserAuthVerifier {\n const claimMapping = {\n ...DEFAULT_WEBHOOK_IDENTITY_CLAIMS,\n ...config.claimMapping,\n };\n\n return {\n kind: \"oidc\",\n verify: async ({ authorization }) => {\n const token = bearerTokenFromAuthorization(authorization);\n const audience = config.jwtAudience.trim();\n if (!audience) {\n throw new Error(\"jwt audience is required for webhook verification\");\n }\n\n const claims = await verifyJwt(token, {\n issuerUrl: config.jwtIssuer,\n audience,\n fetch: config.fetch,\n allowInsecureHttp: config.allowInsecureHttp,\n requiredScopes: config.requiredScopes,\n });\n\n const claimsRecord = claims as unknown as Record<string, unknown>;\n const identity = identityFromWebhookClaims(claimsRecord, claimMapping);\n\n return {\n identity,\n expiry: claimExpirySeconds(claimsRecord),\n raw: claimsRecord,\n };\n },\n adminRoutes: [\n {\n method: \"POST\",\n pathname: \"/admin/refresh-jwks\",\n handler: (request) => handleRemoteSignerRefreshJwks(request, config),\n },\n ],\n };\n}\n","import { PmtHouseError } from \"../../../../errors.js\";\nimport type { EndUserAuthVerifier } from \"../../verifier.js\";\n\nexport function createFirstMatchEndUserVerifier(\n verifiers: EndUserAuthVerifier[],\n): EndUserAuthVerifier {\n if (verifiers.length === 0) {\n throw new PmtHouseError(\"at least one verifier is required\", {\n status: 500,\n code: \"invalid_verifier_config\",\n });\n }\n\n return {\n kind: \"custom\",\n verify: async (context) => {\n let lastError: unknown;\n for (const verifier of verifiers) {\n try {\n return await verifier.verify(context);\n } catch (err) {\n lastError = err;\n }\n }\n\n if (lastError instanceof PmtHouseError) {\n throw lastError;\n }\n if (lastError instanceof Error) {\n throw new PmtHouseError(lastError.message, {\n status: 401,\n code: \"invalid_credentials\",\n });\n }\n throw new PmtHouseError(\"invalid credentials\", {\n status: 401,\n code: \"invalid_credentials\",\n });\n },\n adminRoutes: verifiers.flatMap((verifier) => verifier.adminRoutes ?? []),\n };\n}\n","import { PmtHouseError } from \"../../../../errors.js\";\nimport { headerValueFromWebhookPayload } from \"../../payload.js\";\nimport type { EndUserAuthVerifier } from \"../../verifier.js\";\nimport type { UsageIdentity } from \"../../types.js\";\n\nexport const DEFAULT_DMZ_TRUSTED_HEADERS = {\n issuer: \"X-Livepeer-Usage-Issuer\",\n clientId: \"X-Livepeer-Client-ID\",\n usageSubject: \"X-Livepeer-Usage-Subject\",\n usageSubjectType: \"X-Livepeer-Usage-Subject-Type\",\n} as const;\n\nexport type TrustedHeadersEndUserAuthConfig = {\n expectedIssuer: string;\n headerNames?: Partial<typeof DEFAULT_DMZ_TRUSTED_HEADERS>;\n /** Auth cache TTL returned to go-livepeer when headers are trusted. */\n expiryTtlSeconds?: number;\n};\n\nfunction normalizeIssuer(value: string): string {\n let end = value.length;\n while (end > 0 && value[end - 1] === \"/\") {\n end -= 1;\n }\n return value.slice(0, end);\n}\n\nexport function identityFromTrustedHeaders(\n headers: Record<string, string[]> | undefined,\n config: TrustedHeadersEndUserAuthConfig,\n): UsageIdentity {\n const names = {\n ...DEFAULT_DMZ_TRUSTED_HEADERS,\n ...config.headerNames,\n };\n const issuer = headerValueFromWebhookPayload(headers, names.issuer);\n const clientId = headerValueFromWebhookPayload(headers, names.clientId);\n const usageSubject = headerValueFromWebhookPayload(headers, names.usageSubject);\n const usageSubjectType =\n headerValueFromWebhookPayload(headers, names.usageSubjectType) ||\n \"external_user_id\";\n\n if (!issuer || !clientId || !usageSubject) {\n throw new PmtHouseError(\"missing trusted usage identity headers\", {\n status: 403,\n code: \"invalid_identity\",\n });\n }\n\n if (\n normalizeIssuer(issuer) !== normalizeIssuer(config.expectedIssuer.trim())\n ) {\n throw new PmtHouseError(\"trusted usage issuer mismatch\", {\n status: 403,\n code: \"invalid_identity\",\n });\n }\n\n return {\n issuer,\n client_id: clientId,\n usage_subject: usageSubject,\n usage_subject_type: usageSubjectType,\n };\n}\n\nexport function createTrustedHeadersEndUserVerifier(\n config: TrustedHeadersEndUserAuthConfig,\n): EndUserAuthVerifier {\n const expiryTtlSeconds = config.expiryTtlSeconds ?? 300;\n\n return {\n kind: \"trusted_headers\",\n verify: async ({ payload }) => {\n const identity = identityFromTrustedHeaders(payload.headers, config);\n return {\n identity,\n expiry: Math.trunc(Date.now() / 1000) + expiryTtlSeconds,\n };\n },\n };\n}\n","import type {\n RemoteSignerWebhookConfig,\n WebhookAuthorizeContext,\n} from \"../../authorize.js\";\nimport { createFirstMatchEndUserVerifier } from \"../composite/verifier.js\";\nimport {\n createTrustedHeadersEndUserVerifier,\n type TrustedHeadersEndUserAuthConfig,\n} from \"../trusted-headers/verifier.js\";\nimport {\n createOidcEndUserVerifier,\n type OidcEndUserAuthConfig,\n} from \"./verifier.js\";\n\nfunction envTrim(env: NodeJS.ProcessEnv, key: string): string | undefined {\n const value = env[key]?.trim();\n return value || undefined;\n}\n\nexport type OidcRemoteSignerWebhookConfigInput = OidcEndUserAuthConfig & {\n afterVerify?: (context: WebhookAuthorizeContext) => Promise<void>;\n};\n\nexport type SignerDmzRemoteSignerWebhookConfigInput =\n OidcRemoteSignerWebhookConfigInput & {\n /** When true (default), accept Apache DMZ X-Livepeer-* identity headers. */\n dmzTrustedHeaders?: boolean;\n trustedHeaders?: Omit<TrustedHeadersEndUserAuthConfig, \"expectedIssuer\">;\n };\n\nexport function createOidcRemoteSignerWebhookConfig(\n input: OidcRemoteSignerWebhookConfigInput,\n): RemoteSignerWebhookConfig {\n const { afterVerify, ...oidcConfig } = input;\n return {\n webhookSecret: oidcConfig.webhookSecret,\n endUserAuth: createOidcEndUserVerifier(oidcConfig),\n afterVerify,\n };\n}\n\n/**\n * PymtHouse signer-dmz: Apache validates the end-user JWT (iss/aud = issuer), injects\n * X-Livepeer-* headers, and go-livepeer forwards those headers to this webhook per\n * go-livepeer remote-signer.md. Falls back to Bearer JWT verification when present.\n */\nexport function createSignerDmzRemoteSignerWebhookConfig(\n input: SignerDmzRemoteSignerWebhookConfigInput,\n): RemoteSignerWebhookConfig {\n const {\n afterVerify,\n dmzTrustedHeaders = true,\n trustedHeaders,\n ...oidcConfig\n } = input;\n const oidcVerifier = createOidcEndUserVerifier(oidcConfig);\n const endUserAuth =\n dmzTrustedHeaders === false\n ? oidcVerifier\n : createFirstMatchEndUserVerifier([\n createTrustedHeadersEndUserVerifier({\n expectedIssuer: oidcConfig.jwtIssuer,\n ...trustedHeaders,\n }),\n oidcVerifier,\n ]);\n\n return {\n webhookSecret: oidcConfig.webhookSecret,\n endUserAuth,\n afterVerify,\n };\n}\n\nexport function readOidcRemoteSignerWebhookConfigFromEnv(\n env: NodeJS.ProcessEnv = process.env,\n): RemoteSignerWebhookConfig {\n const webhookSecret = envTrim(env, \"WEBHOOK_SECRET\");\n const jwtIssuer = envTrim(env, \"JWT_ISSUER\");\n const jwtAudience = envTrim(env, \"JWT_AUDIENCE\") ?? jwtIssuer;\n\n if (!webhookSecret) {\n throw new Error(\"WEBHOOK_SECRET is required\");\n }\n if (!jwtIssuer) {\n throw new Error(\"JWT_ISSUER is required\");\n }\n if (!jwtAudience) {\n throw new Error(\"JWT_AUDIENCE is required\");\n }\n\n return createSignerDmzRemoteSignerWebhookConfig({\n webhookSecret,\n jwtIssuer,\n jwtAudience,\n claimMapping: {\n claimClientId: envTrim(env, \"CLAIM_CLIENT_ID\") ?? \"client_id\",\n claimUsageSubject: envTrim(env, \"CLAIM_USAGE_SUBJECT\") ?? \"sub\",\n usageSubjectType: envTrim(env, \"USAGE_SUBJECT_TYPE\") ?? \"external_user_id\",\n },\n allowInsecureHttp: envTrim(env, \"ALLOW_INSECURE_HTTP\") === \"1\",\n });\n}\n\n/** @deprecated Use readOidcRemoteSignerWebhookConfigFromEnv */\nexport const readRemoteSignerWebhookConfigFromEnv =\n readOidcRemoteSignerWebhookConfigFromEnv;\n"]}
|
|
@@ -19,22 +19,29 @@ var PmtHouseError = class extends Error {
|
|
|
19
19
|
};
|
|
20
20
|
|
|
21
21
|
// src/signer/webhook/payload.ts
|
|
22
|
+
function firstHeaderValue(values) {
|
|
23
|
+
if (!Array.isArray(values)) {
|
|
24
|
+
return "";
|
|
25
|
+
}
|
|
26
|
+
for (const value of values) {
|
|
27
|
+
if (typeof value === "string" && value.trim()) {
|
|
28
|
+
return value.trim();
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
return "";
|
|
32
|
+
}
|
|
22
33
|
function headerValueFromWebhookPayload(headers, name) {
|
|
23
34
|
if (!headers) {
|
|
24
35
|
return "";
|
|
25
36
|
}
|
|
37
|
+
const direct = firstHeaderValue(headers[name]);
|
|
38
|
+
if (direct) {
|
|
39
|
+
return direct;
|
|
40
|
+
}
|
|
26
41
|
const target = name.toLowerCase();
|
|
27
42
|
for (const [key, values] of Object.entries(headers)) {
|
|
28
|
-
if (key.toLowerCase()
|
|
29
|
-
|
|
30
|
-
}
|
|
31
|
-
if (!Array.isArray(values)) {
|
|
32
|
-
continue;
|
|
33
|
-
}
|
|
34
|
-
for (const value of values) {
|
|
35
|
-
if (typeof value === "string" && value.trim()) {
|
|
36
|
-
return value.trim();
|
|
37
|
-
}
|
|
43
|
+
if (key.toLowerCase() === target) {
|
|
44
|
+
return firstHeaderValue(values);
|
|
38
45
|
}
|
|
39
46
|
}
|
|
40
47
|
return "";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../src/errors.ts","../../../../src/signer/webhook/payload.ts","../../../../src/signer/webhook/adapters/trusted-headers/verifier.ts"],"names":[],"mappings":";;;AAAO,IAAM,aAAA,GAAN,cAA4B,KAAA,CAAM;AAAA,EAC9B,MAAA;AAAA,EACA,IAAA;AAAA,EACA,OAAA;AAAA,EAET,YACE,OAAA,EACA;AAAA,IACE,MAAA,GAAS,GAAA;AAAA,IACT,IAAA,GAAO,iBAAA;AAAA,IACP;AAAA,GACF,GAII,EAAC,EACL;AACA,IAAA,KAAA,CAAM,OAAO,CAAA;AACb,IAAA,IAAA,CAAK,IAAA,GAAO,eAAA;AACZ,IAAA,IAAA,CAAK,MAAA,GAAS,MAAA;AACd,IAAA,IAAA,CAAK,IAAA,GAAO,IAAA;AACZ,IAAA,IAAA,CAAK,OAAA,GAAU,OAAA;AAAA,EACjB;AACF,CAAA;;;
|
|
1
|
+
{"version":3,"sources":["../../../../src/errors.ts","../../../../src/signer/webhook/payload.ts","../../../../src/signer/webhook/adapters/trusted-headers/verifier.ts"],"names":[],"mappings":"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","file":"trusted-headers.cjs","sourcesContent":["export class PmtHouseError extends Error {\n readonly status: number;\n readonly code: string;\n readonly details?: unknown;\n\n constructor(\n message: string,\n {\n status = 500,\n code = \"pymthouse_error\",\n details,\n }: {\n status?: number;\n code?: string;\n details?: unknown;\n } = {},\n ) {\n super(message);\n this.name = \"PmtHouseError\";\n this.status = status;\n this.code = code;\n this.details = details;\n }\n}\n\nexport function toPmtHouseError(\n error: unknown,\n fallbackMessage: string,\n): PmtHouseError {\n if (error instanceof PmtHouseError) {\n return error;\n }\n\n if (error instanceof Error) {\n return new PmtHouseError(error.message || fallbackMessage, {\n code: \"unexpected_error\",\n status: 500,\n });\n }\n\n return new PmtHouseError(fallbackMessage, {\n code: \"unexpected_error\",\n status: 500,\n });\n}\n","import type { PaymentWebhookRequest } from \"./types.js\";\n\nfunction firstHeaderValue(values: string[] | undefined): string {\n if (!Array.isArray(values)) {\n return \"\";\n }\n for (const value of values) {\n if (typeof value === \"string\" && value.trim()) {\n return value.trim();\n }\n }\n return \"\";\n}\n\nexport function headerValueFromWebhookPayload(\n headers: Record<string, string[]> | undefined,\n name: string,\n): string {\n if (!headers) {\n return \"\";\n }\n const direct = firstHeaderValue(headers[name]);\n if (direct) {\n return direct;\n }\n const target = name.toLowerCase();\n for (const [key, values] of Object.entries(headers)) {\n if (key.toLowerCase() === target) {\n return firstHeaderValue(values);\n }\n }\n return \"\";\n}\n\n/** End-user Authorization from go-livepeer webhook body (headers map or legacy field). */\nexport function authorizationFromWebhookPayload(\n payload: PaymentWebhookRequest,\n): string {\n const fromHeaders = headerValueFromWebhookPayload(\n payload.headers,\n \"Authorization\",\n );\n if (fromHeaders) {\n return fromHeaders;\n }\n return payload.authorization?.trim() ?? \"\";\n}\n","import { PmtHouseError } from \"../../../../errors.js\";\nimport { headerValueFromWebhookPayload } from \"../../payload.js\";\nimport type { EndUserAuthVerifier } from \"../../verifier.js\";\nimport type { UsageIdentity } from \"../../types.js\";\n\nexport const DEFAULT_DMZ_TRUSTED_HEADERS = {\n issuer: \"X-Livepeer-Usage-Issuer\",\n clientId: \"X-Livepeer-Client-ID\",\n usageSubject: \"X-Livepeer-Usage-Subject\",\n usageSubjectType: \"X-Livepeer-Usage-Subject-Type\",\n} as const;\n\nexport type TrustedHeadersEndUserAuthConfig = {\n expectedIssuer: string;\n headerNames?: Partial<typeof DEFAULT_DMZ_TRUSTED_HEADERS>;\n /** Auth cache TTL returned to go-livepeer when headers are trusted. */\n expiryTtlSeconds?: number;\n};\n\nfunction normalizeIssuer(value: string): string {\n let end = value.length;\n while (end > 0 && value[end - 1] === \"/\") {\n end -= 1;\n }\n return value.slice(0, end);\n}\n\nexport function identityFromTrustedHeaders(\n headers: Record<string, string[]> | undefined,\n config: TrustedHeadersEndUserAuthConfig,\n): UsageIdentity {\n const names = {\n ...DEFAULT_DMZ_TRUSTED_HEADERS,\n ...config.headerNames,\n };\n const issuer = headerValueFromWebhookPayload(headers, names.issuer);\n const clientId = headerValueFromWebhookPayload(headers, names.clientId);\n const usageSubject = headerValueFromWebhookPayload(headers, names.usageSubject);\n const usageSubjectType =\n headerValueFromWebhookPayload(headers, names.usageSubjectType) ||\n \"external_user_id\";\n\n if (!issuer || !clientId || !usageSubject) {\n throw new PmtHouseError(\"missing trusted usage identity headers\", {\n status: 403,\n code: \"invalid_identity\",\n });\n }\n\n if (\n normalizeIssuer(issuer) !== normalizeIssuer(config.expectedIssuer.trim())\n ) {\n throw new PmtHouseError(\"trusted usage issuer mismatch\", {\n status: 403,\n code: \"invalid_identity\",\n });\n }\n\n return {\n issuer,\n client_id: clientId,\n usage_subject: usageSubject,\n usage_subject_type: usageSubjectType,\n };\n}\n\nexport function createTrustedHeadersEndUserVerifier(\n config: TrustedHeadersEndUserAuthConfig,\n): EndUserAuthVerifier {\n const expiryTtlSeconds = config.expiryTtlSeconds ?? 300;\n\n return {\n kind: \"trusted_headers\",\n verify: async ({ payload }) => {\n const identity = identityFromTrustedHeaders(payload.headers, config);\n return {\n identity,\n expiry: Math.trunc(Date.now() / 1000) + expiryTtlSeconds,\n };\n },\n };\n}\n"]}
|
|
@@ -17,22 +17,29 @@ var PmtHouseError = class extends Error {
|
|
|
17
17
|
};
|
|
18
18
|
|
|
19
19
|
// src/signer/webhook/payload.ts
|
|
20
|
+
function firstHeaderValue(values) {
|
|
21
|
+
if (!Array.isArray(values)) {
|
|
22
|
+
return "";
|
|
23
|
+
}
|
|
24
|
+
for (const value of values) {
|
|
25
|
+
if (typeof value === "string" && value.trim()) {
|
|
26
|
+
return value.trim();
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
return "";
|
|
30
|
+
}
|
|
20
31
|
function headerValueFromWebhookPayload(headers, name) {
|
|
21
32
|
if (!headers) {
|
|
22
33
|
return "";
|
|
23
34
|
}
|
|
35
|
+
const direct = firstHeaderValue(headers[name]);
|
|
36
|
+
if (direct) {
|
|
37
|
+
return direct;
|
|
38
|
+
}
|
|
24
39
|
const target = name.toLowerCase();
|
|
25
40
|
for (const [key, values] of Object.entries(headers)) {
|
|
26
|
-
if (key.toLowerCase()
|
|
27
|
-
|
|
28
|
-
}
|
|
29
|
-
if (!Array.isArray(values)) {
|
|
30
|
-
continue;
|
|
31
|
-
}
|
|
32
|
-
for (const value of values) {
|
|
33
|
-
if (typeof value === "string" && value.trim()) {
|
|
34
|
-
return value.trim();
|
|
35
|
-
}
|
|
41
|
+
if (key.toLowerCase() === target) {
|
|
42
|
+
return firstHeaderValue(values);
|
|
36
43
|
}
|
|
37
44
|
}
|
|
38
45
|
return "";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../src/errors.ts","../../../../src/signer/webhook/payload.ts","../../../../src/signer/webhook/adapters/trusted-headers/verifier.ts"],"names":[],"mappings":";AAAO,IAAM,aAAA,GAAN,cAA4B,KAAA,CAAM;AAAA,EAC9B,MAAA;AAAA,EACA,IAAA;AAAA,EACA,OAAA;AAAA,EAET,YACE,OAAA,EACA;AAAA,IACE,MAAA,GAAS,GAAA;AAAA,IACT,IAAA,GAAO,iBAAA;AAAA,IACP;AAAA,GACF,GAII,EAAC,EACL;AACA,IAAA,KAAA,CAAM,OAAO,CAAA;AACb,IAAA,IAAA,CAAK,IAAA,GAAO,eAAA;AACZ,IAAA,IAAA,CAAK,MAAA,GAAS,MAAA;AACd,IAAA,IAAA,CAAK,IAAA,GAAO,IAAA;AACZ,IAAA,IAAA,CAAK,OAAA,GAAU,OAAA;AAAA,EACjB;AACF,CAAA;;;
|
|
1
|
+
{"version":3,"sources":["../../../../src/errors.ts","../../../../src/signer/webhook/payload.ts","../../../../src/signer/webhook/adapters/trusted-headers/verifier.ts"],"names":[],"mappings":"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","file":"trusted-headers.js","sourcesContent":["export class PmtHouseError extends Error {\n readonly status: number;\n readonly code: string;\n readonly details?: unknown;\n\n constructor(\n message: string,\n {\n status = 500,\n code = \"pymthouse_error\",\n details,\n }: {\n status?: number;\n code?: string;\n details?: unknown;\n } = {},\n ) {\n super(message);\n this.name = \"PmtHouseError\";\n this.status = status;\n this.code = code;\n this.details = details;\n }\n}\n\nexport function toPmtHouseError(\n error: unknown,\n fallbackMessage: string,\n): PmtHouseError {\n if (error instanceof PmtHouseError) {\n return error;\n }\n\n if (error instanceof Error) {\n return new PmtHouseError(error.message || fallbackMessage, {\n code: \"unexpected_error\",\n status: 500,\n });\n }\n\n return new PmtHouseError(fallbackMessage, {\n code: \"unexpected_error\",\n status: 500,\n });\n}\n","import type { PaymentWebhookRequest } from \"./types.js\";\n\nfunction firstHeaderValue(values: string[] | undefined): string {\n if (!Array.isArray(values)) {\n return \"\";\n }\n for (const value of values) {\n if (typeof value === \"string\" && value.trim()) {\n return value.trim();\n }\n }\n return \"\";\n}\n\nexport function headerValueFromWebhookPayload(\n headers: Record<string, string[]> | undefined,\n name: string,\n): string {\n if (!headers) {\n return \"\";\n }\n const direct = firstHeaderValue(headers[name]);\n if (direct) {\n return direct;\n }\n const target = name.toLowerCase();\n for (const [key, values] of Object.entries(headers)) {\n if (key.toLowerCase() === target) {\n return firstHeaderValue(values);\n }\n }\n return \"\";\n}\n\n/** End-user Authorization from go-livepeer webhook body (headers map or legacy field). */\nexport function authorizationFromWebhookPayload(\n payload: PaymentWebhookRequest,\n): string {\n const fromHeaders = headerValueFromWebhookPayload(\n payload.headers,\n \"Authorization\",\n );\n if (fromHeaders) {\n return fromHeaders;\n }\n return payload.authorization?.trim() ?? \"\";\n}\n","import { PmtHouseError } from \"../../../../errors.js\";\nimport { headerValueFromWebhookPayload } from \"../../payload.js\";\nimport type { EndUserAuthVerifier } from \"../../verifier.js\";\nimport type { UsageIdentity } from \"../../types.js\";\n\nexport const DEFAULT_DMZ_TRUSTED_HEADERS = {\n issuer: \"X-Livepeer-Usage-Issuer\",\n clientId: \"X-Livepeer-Client-ID\",\n usageSubject: \"X-Livepeer-Usage-Subject\",\n usageSubjectType: \"X-Livepeer-Usage-Subject-Type\",\n} as const;\n\nexport type TrustedHeadersEndUserAuthConfig = {\n expectedIssuer: string;\n headerNames?: Partial<typeof DEFAULT_DMZ_TRUSTED_HEADERS>;\n /** Auth cache TTL returned to go-livepeer when headers are trusted. */\n expiryTtlSeconds?: number;\n};\n\nfunction normalizeIssuer(value: string): string {\n let end = value.length;\n while (end > 0 && value[end - 1] === \"/\") {\n end -= 1;\n }\n return value.slice(0, end);\n}\n\nexport function identityFromTrustedHeaders(\n headers: Record<string, string[]> | undefined,\n config: TrustedHeadersEndUserAuthConfig,\n): UsageIdentity {\n const names = {\n ...DEFAULT_DMZ_TRUSTED_HEADERS,\n ...config.headerNames,\n };\n const issuer = headerValueFromWebhookPayload(headers, names.issuer);\n const clientId = headerValueFromWebhookPayload(headers, names.clientId);\n const usageSubject = headerValueFromWebhookPayload(headers, names.usageSubject);\n const usageSubjectType =\n headerValueFromWebhookPayload(headers, names.usageSubjectType) ||\n \"external_user_id\";\n\n if (!issuer || !clientId || !usageSubject) {\n throw new PmtHouseError(\"missing trusted usage identity headers\", {\n status: 403,\n code: \"invalid_identity\",\n });\n }\n\n if (\n normalizeIssuer(issuer) !== normalizeIssuer(config.expectedIssuer.trim())\n ) {\n throw new PmtHouseError(\"trusted usage issuer mismatch\", {\n status: 403,\n code: \"invalid_identity\",\n });\n }\n\n return {\n issuer,\n client_id: clientId,\n usage_subject: usageSubject,\n usage_subject_type: usageSubjectType,\n };\n}\n\nexport function createTrustedHeadersEndUserVerifier(\n config: TrustedHeadersEndUserAuthConfig,\n): EndUserAuthVerifier {\n const expiryTtlSeconds = config.expiryTtlSeconds ?? 300;\n\n return {\n kind: \"trusted_headers\",\n verify: async ({ payload }) => {\n const identity = identityFromTrustedHeaders(payload.headers, config);\n return {\n identity,\n expiry: Math.trunc(Date.now() / 1000) + expiryTtlSeconds,\n };\n },\n };\n}\n"]}
|
package/dist/signer/webhook.cjs
CHANGED
|
@@ -87,23 +87,51 @@ function claimExpirySeconds(claims, fallbackTtlSeconds = 300) {
|
|
|
87
87
|
return Math.trunc(Date.now() / 1e3) + fallbackTtlSeconds;
|
|
88
88
|
}
|
|
89
89
|
|
|
90
|
+
// src/signer/webhook/bearer.ts
|
|
91
|
+
var BEARER_PREFIX = "Bearer ";
|
|
92
|
+
function optionalBearerToken(authorization) {
|
|
93
|
+
const trimmed = authorization.trim();
|
|
94
|
+
if (!trimmed.startsWith(BEARER_PREFIX)) {
|
|
95
|
+
return null;
|
|
96
|
+
}
|
|
97
|
+
const token = trimmed.slice(BEARER_PREFIX.length).trim();
|
|
98
|
+
return token || null;
|
|
99
|
+
}
|
|
100
|
+
function bearerTokenFromAuthorization(authorization) {
|
|
101
|
+
const token = optionalBearerToken(authorization);
|
|
102
|
+
if (token) {
|
|
103
|
+
return token;
|
|
104
|
+
}
|
|
105
|
+
if (!authorization.trim()) {
|
|
106
|
+
throw new Error("missing authorization");
|
|
107
|
+
}
|
|
108
|
+
throw new Error("authorization must be Bearer token");
|
|
109
|
+
}
|
|
110
|
+
|
|
90
111
|
// src/signer/webhook/payload.ts
|
|
112
|
+
function firstHeaderValue(values) {
|
|
113
|
+
if (!Array.isArray(values)) {
|
|
114
|
+
return "";
|
|
115
|
+
}
|
|
116
|
+
for (const value of values) {
|
|
117
|
+
if (typeof value === "string" && value.trim()) {
|
|
118
|
+
return value.trim();
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
return "";
|
|
122
|
+
}
|
|
91
123
|
function headerValueFromWebhookPayload(headers, name) {
|
|
92
124
|
if (!headers) {
|
|
93
125
|
return "";
|
|
94
126
|
}
|
|
127
|
+
const direct = firstHeaderValue(headers[name]);
|
|
128
|
+
if (direct) {
|
|
129
|
+
return direct;
|
|
130
|
+
}
|
|
95
131
|
const target = name.toLowerCase();
|
|
96
132
|
for (const [key, values] of Object.entries(headers)) {
|
|
97
|
-
if (key.toLowerCase()
|
|
98
|
-
|
|
99
|
-
}
|
|
100
|
-
if (!Array.isArray(values)) {
|
|
101
|
-
continue;
|
|
102
|
-
}
|
|
103
|
-
for (const value of values) {
|
|
104
|
-
if (typeof value === "string" && value.trim()) {
|
|
105
|
-
return value.trim();
|
|
106
|
-
}
|
|
133
|
+
if (key.toLowerCase() === target) {
|
|
134
|
+
return firstHeaderValue(values);
|
|
107
135
|
}
|
|
108
136
|
}
|
|
109
137
|
return "";
|
|
@@ -136,8 +164,8 @@ function authenticateWebhookCaller(request, secret) {
|
|
|
136
164
|
return false;
|
|
137
165
|
}
|
|
138
166
|
const trimmed = secret.trim();
|
|
139
|
-
const
|
|
140
|
-
if (
|
|
167
|
+
const bearer = optionalBearerToken(request.headers.get("authorization") ?? "");
|
|
168
|
+
if (bearer && timingSafeEqualStrings(bearer, trimmed)) {
|
|
141
169
|
return true;
|
|
142
170
|
}
|
|
143
171
|
const apiKey = request.headers.get("x-api-key")?.trim() ?? "";
|
|
@@ -229,23 +257,6 @@ async function routeRemoteSignerWebhookRequest(request, config) {
|
|
|
229
257
|
return null;
|
|
230
258
|
}
|
|
231
259
|
|
|
232
|
-
// src/signer/webhook/bearer.ts
|
|
233
|
-
function bearerTokenFromAuthorization(authorization) {
|
|
234
|
-
const trimmed = authorization.trim();
|
|
235
|
-
if (!trimmed) {
|
|
236
|
-
throw new Error("missing authorization");
|
|
237
|
-
}
|
|
238
|
-
const prefix = "Bearer ";
|
|
239
|
-
if (!trimmed.startsWith(prefix)) {
|
|
240
|
-
throw new Error("authorization must be Bearer token");
|
|
241
|
-
}
|
|
242
|
-
const token = trimmed.slice(prefix.length).trim();
|
|
243
|
-
if (!token) {
|
|
244
|
-
throw new Error("empty bearer token");
|
|
245
|
-
}
|
|
246
|
-
return token;
|
|
247
|
-
}
|
|
248
|
-
|
|
249
260
|
// src/signer/webhook/adapters/api-key/verifier.ts
|
|
250
261
|
function createApiKeyEndUserVerifier(config) {
|
|
251
262
|
const prefix = config.apiKeyPrefix ?? "sk_";
|
|
@@ -739,6 +750,7 @@ exports.headerValueFromWebhookPayload = headerValueFromWebhookPayload;
|
|
|
739
750
|
exports.identityFromTrustedHeaders = identityFromTrustedHeaders;
|
|
740
751
|
exports.identityFromWebhookClaims = identityFromWebhookClaims;
|
|
741
752
|
exports.isValidUsageIdentity = isValidUsageIdentity;
|
|
753
|
+
exports.optionalBearerToken = optionalBearerToken;
|
|
742
754
|
exports.readOidcRemoteSignerWebhookConfigFromEnv = readOidcRemoteSignerWebhookConfigFromEnv;
|
|
743
755
|
exports.readRemoteSignerWebhookConfigFromEnv = readRemoteSignerWebhookConfigFromEnv;
|
|
744
756
|
exports.routeRemoteSignerWebhookRequest = routeRemoteSignerWebhookRequest;
|