@pymthouse/builder-sdk 0.3.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/README.md +54 -28
- package/dist/{client-BHfjDvIe.d.ts → client-CauCfGa7.d.ts} +1 -1
- package/dist/{client-CvhJEhjV.d.cts → client-D1Xz-xlx.d.cts} +1 -1
- package/dist/config.cjs +0 -21
- package/dist/config.cjs.map +1 -1
- package/dist/config.d.cts +1 -5
- package/dist/config.d.ts +1 -5
- package/dist/config.js +1 -20
- package/dist/config.js.map +1 -1
- package/dist/device-initiate.cjs.map +1 -1
- package/dist/device-initiate.js.map +1 -1
- package/dist/device.cjs.map +1 -1
- package/dist/device.d.cts +1 -1
- package/dist/device.d.ts +1 -1
- package/dist/device.js.map +1 -1
- package/dist/env.cjs +13 -4
- package/dist/env.cjs.map +1 -1
- package/dist/env.d.cts +2 -2
- package/dist/env.d.ts +2 -2
- package/dist/env.js +13 -4
- package/dist/env.js.map +1 -1
- package/dist/index-B0ryx942.d.cts +66 -0
- package/dist/index-CvV5syf_.d.ts +66 -0
- package/dist/index.cjs +13 -4
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +29 -5
- package/dist/index.d.ts +29 -5
- package/dist/index.js +13 -4
- package/dist/index.js.map +1 -1
- package/dist/{ingest-DoKJTWU9.d.ts → proxy-JrT6raU_.d.cts} +5 -42
- package/dist/{ingest-B3Yi8Tb1.d.cts → proxy-U32DFNuj.d.ts} +5 -42
- package/dist/signer/server.cjs +799 -895
- package/dist/signer/server.cjs.map +1 -1
- package/dist/signer/server.d.cts +11 -15
- package/dist/signer/server.d.ts +11 -15
- package/dist/signer/server.js +799 -893
- package/dist/signer/server.js.map +1 -1
- package/dist/signer/webhook/adapters/api-key.cjs +82 -0
- package/dist/signer/webhook/adapters/api-key.cjs.map +1 -0
- package/dist/signer/webhook/adapters/api-key.d.cts +18 -0
- package/dist/signer/webhook/adapters/api-key.d.ts +18 -0
- package/dist/signer/webhook/adapters/api-key.js +80 -0
- package/dist/signer/webhook/adapters/api-key.js.map +1 -0
- package/dist/signer/webhook/adapters/composite.cjs +60 -0
- package/dist/signer/webhook/adapters/composite.cjs.map +1 -0
- package/dist/signer/webhook/adapters/composite.d.cts +5 -0
- package/dist/signer/webhook/adapters/composite.d.ts +5 -0
- package/dist/signer/webhook/adapters/composite.js +58 -0
- package/dist/signer/webhook/adapters/composite.js.map +1 -0
- package/dist/signer/webhook/adapters/oauth1.cjs +18 -0
- package/dist/signer/webhook/adapters/oauth1.cjs.map +1 -0
- package/dist/signer/webhook/adapters/oauth1.d.cts +19 -0
- package/dist/signer/webhook/adapters/oauth1.d.ts +19 -0
- package/dist/signer/webhook/adapters/oauth1.js +16 -0
- package/dist/signer/webhook/adapters/oauth1.js.map +1 -0
- package/dist/signer/webhook/adapters/oidc.cjs +533 -0
- package/dist/signer/webhook/adapters/oidc.cjs.map +1 -0
- package/dist/signer/webhook/adapters/oidc.d.cts +4 -0
- package/dist/signer/webhook/adapters/oidc.d.ts +4 -0
- package/dist/signer/webhook/adapters/oidc.js +526 -0
- package/dist/signer/webhook/adapters/oidc.js.map +1 -0
- package/dist/signer/webhook/adapters/trusted-headers.cjs +110 -0
- package/dist/signer/webhook/adapters/trusted-headers.cjs.map +1 -0
- package/dist/signer/webhook/adapters/trusted-headers.d.cts +18 -0
- package/dist/signer/webhook/adapters/trusted-headers.d.ts +18 -0
- package/dist/signer/webhook/adapters/trusted-headers.js +106 -0
- package/dist/signer/webhook/adapters/trusted-headers.js.map +1 -0
- package/dist/signer/webhook.cjs +759 -0
- package/dist/signer/webhook.cjs.map +1 -0
- package/dist/signer/webhook.d.cts +26 -0
- package/dist/signer/webhook.d.ts +26 -0
- package/dist/signer/webhook.js +732 -0
- package/dist/signer/webhook.js.map +1 -0
- package/dist/tokens.d.cts +1 -1
- package/dist/tokens.d.ts +1 -1
- package/dist/{types-_R1AwEZp.d.cts → types-BORaHW_x.d.cts} +5 -5
- package/dist/{types-_R1AwEZp.d.ts → types-BORaHW_x.d.ts} +5 -5
- package/dist/verifier-B-WFDMz6.d.cts +48 -0
- package/dist/verifier-B-WFDMz6.d.ts +48 -0
- package/dist/verify.cjs.map +1 -1
- package/dist/verify.d.cts +1 -1
- package/dist/verify.d.ts +1 -1
- package/dist/verify.js.map +1 -1
- package/package.json +30 -30
- package/dist/gateway/client/index.cjs +0 -492
- package/dist/gateway/client/index.cjs.map +0 -1
- package/dist/gateway/client/index.d.cts +0 -63
- package/dist/gateway/client/index.d.ts +0 -63
- package/dist/gateway/client/index.js +0 -489
- package/dist/gateway/client/index.js.map +0 -1
- package/dist/gateway/index.cjs +0 -16
- package/dist/gateway/index.cjs.map +0 -1
- package/dist/gateway/index.d.cts +0 -52
- package/dist/gateway/index.d.ts +0 -52
- package/dist/gateway/index.js +0 -10
- package/dist/gateway/index.js.map +0 -1
- package/dist/gateway/server/index.cjs +0 -1248
- package/dist/gateway/server/index.cjs.map +0 -1
- package/dist/gateway/server/index.d.cts +0 -31
- package/dist/gateway/server/index.d.ts +0 -31
- package/dist/gateway/server/index.js +0 -1233
- package/dist/gateway/server/index.js.map +0 -1
- package/gateway/proto/lp_rpc.proto +0 -542
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
// src/errors.ts
|
|
4
|
+
var PmtHouseError = class extends Error {
|
|
5
|
+
status;
|
|
6
|
+
code;
|
|
7
|
+
details;
|
|
8
|
+
constructor(message, {
|
|
9
|
+
status = 500,
|
|
10
|
+
code = "pymthouse_error",
|
|
11
|
+
details
|
|
12
|
+
} = {}) {
|
|
13
|
+
super(message);
|
|
14
|
+
this.name = "PmtHouseError";
|
|
15
|
+
this.status = status;
|
|
16
|
+
this.code = code;
|
|
17
|
+
this.details = details;
|
|
18
|
+
}
|
|
19
|
+
};
|
|
20
|
+
|
|
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
|
+
}
|
|
33
|
+
function headerValueFromWebhookPayload(headers, name) {
|
|
34
|
+
if (!headers) {
|
|
35
|
+
return "";
|
|
36
|
+
}
|
|
37
|
+
const direct = firstHeaderValue(headers[name]);
|
|
38
|
+
if (direct) {
|
|
39
|
+
return direct;
|
|
40
|
+
}
|
|
41
|
+
const target = name.toLowerCase();
|
|
42
|
+
for (const [key, values] of Object.entries(headers)) {
|
|
43
|
+
if (key.toLowerCase() === target) {
|
|
44
|
+
return firstHeaderValue(values);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
return "";
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// src/signer/webhook/adapters/trusted-headers/verifier.ts
|
|
51
|
+
var DEFAULT_DMZ_TRUSTED_HEADERS = {
|
|
52
|
+
issuer: "X-Livepeer-Usage-Issuer",
|
|
53
|
+
clientId: "X-Livepeer-Client-ID",
|
|
54
|
+
usageSubject: "X-Livepeer-Usage-Subject",
|
|
55
|
+
usageSubjectType: "X-Livepeer-Usage-Subject-Type"
|
|
56
|
+
};
|
|
57
|
+
function normalizeIssuer(value) {
|
|
58
|
+
let end = value.length;
|
|
59
|
+
while (end > 0 && value[end - 1] === "/") {
|
|
60
|
+
end -= 1;
|
|
61
|
+
}
|
|
62
|
+
return value.slice(0, end);
|
|
63
|
+
}
|
|
64
|
+
function identityFromTrustedHeaders(headers, config) {
|
|
65
|
+
const names = {
|
|
66
|
+
...DEFAULT_DMZ_TRUSTED_HEADERS,
|
|
67
|
+
...config.headerNames
|
|
68
|
+
};
|
|
69
|
+
const issuer = headerValueFromWebhookPayload(headers, names.issuer);
|
|
70
|
+
const clientId = headerValueFromWebhookPayload(headers, names.clientId);
|
|
71
|
+
const usageSubject = headerValueFromWebhookPayload(headers, names.usageSubject);
|
|
72
|
+
const usageSubjectType = headerValueFromWebhookPayload(headers, names.usageSubjectType) || "external_user_id";
|
|
73
|
+
if (!issuer || !clientId || !usageSubject) {
|
|
74
|
+
throw new PmtHouseError("missing trusted usage identity headers", {
|
|
75
|
+
status: 403,
|
|
76
|
+
code: "invalid_identity"
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
if (normalizeIssuer(issuer) !== normalizeIssuer(config.expectedIssuer.trim())) {
|
|
80
|
+
throw new PmtHouseError("trusted usage issuer mismatch", {
|
|
81
|
+
status: 403,
|
|
82
|
+
code: "invalid_identity"
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
return {
|
|
86
|
+
issuer,
|
|
87
|
+
client_id: clientId,
|
|
88
|
+
usage_subject: usageSubject,
|
|
89
|
+
usage_subject_type: usageSubjectType
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
function createTrustedHeadersEndUserVerifier(config) {
|
|
93
|
+
const expiryTtlSeconds = config.expiryTtlSeconds ?? 300;
|
|
94
|
+
return {
|
|
95
|
+
kind: "trusted_headers",
|
|
96
|
+
verify: async ({ payload }) => {
|
|
97
|
+
const identity = identityFromTrustedHeaders(payload.headers, config);
|
|
98
|
+
return {
|
|
99
|
+
identity,
|
|
100
|
+
expiry: Math.trunc(Date.now() / 1e3) + expiryTtlSeconds
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
exports.DEFAULT_DMZ_TRUSTED_HEADERS = DEFAULT_DMZ_TRUSTED_HEADERS;
|
|
107
|
+
exports.createTrustedHeadersEndUserVerifier = createTrustedHeadersEndUserVerifier;
|
|
108
|
+
exports.identityFromTrustedHeaders = identityFromTrustedHeaders;
|
|
109
|
+
//# sourceMappingURL=trusted-headers.cjs.map
|
|
110
|
+
//# sourceMappingURL=trusted-headers.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
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"]}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { E as EndUserAuthVerifier, U as UsageIdentity } from '../../../verifier-B-WFDMz6.cjs';
|
|
2
|
+
|
|
3
|
+
declare const DEFAULT_DMZ_TRUSTED_HEADERS: {
|
|
4
|
+
readonly issuer: "X-Livepeer-Usage-Issuer";
|
|
5
|
+
readonly clientId: "X-Livepeer-Client-ID";
|
|
6
|
+
readonly usageSubject: "X-Livepeer-Usage-Subject";
|
|
7
|
+
readonly usageSubjectType: "X-Livepeer-Usage-Subject-Type";
|
|
8
|
+
};
|
|
9
|
+
type TrustedHeadersEndUserAuthConfig = {
|
|
10
|
+
expectedIssuer: string;
|
|
11
|
+
headerNames?: Partial<typeof DEFAULT_DMZ_TRUSTED_HEADERS>;
|
|
12
|
+
/** Auth cache TTL returned to go-livepeer when headers are trusted. */
|
|
13
|
+
expiryTtlSeconds?: number;
|
|
14
|
+
};
|
|
15
|
+
declare function identityFromTrustedHeaders(headers: Record<string, string[]> | undefined, config: TrustedHeadersEndUserAuthConfig): UsageIdentity;
|
|
16
|
+
declare function createTrustedHeadersEndUserVerifier(config: TrustedHeadersEndUserAuthConfig): EndUserAuthVerifier;
|
|
17
|
+
|
|
18
|
+
export { DEFAULT_DMZ_TRUSTED_HEADERS, type TrustedHeadersEndUserAuthConfig, createTrustedHeadersEndUserVerifier, identityFromTrustedHeaders };
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { E as EndUserAuthVerifier, U as UsageIdentity } from '../../../verifier-B-WFDMz6.js';
|
|
2
|
+
|
|
3
|
+
declare const DEFAULT_DMZ_TRUSTED_HEADERS: {
|
|
4
|
+
readonly issuer: "X-Livepeer-Usage-Issuer";
|
|
5
|
+
readonly clientId: "X-Livepeer-Client-ID";
|
|
6
|
+
readonly usageSubject: "X-Livepeer-Usage-Subject";
|
|
7
|
+
readonly usageSubjectType: "X-Livepeer-Usage-Subject-Type";
|
|
8
|
+
};
|
|
9
|
+
type TrustedHeadersEndUserAuthConfig = {
|
|
10
|
+
expectedIssuer: string;
|
|
11
|
+
headerNames?: Partial<typeof DEFAULT_DMZ_TRUSTED_HEADERS>;
|
|
12
|
+
/** Auth cache TTL returned to go-livepeer when headers are trusted. */
|
|
13
|
+
expiryTtlSeconds?: number;
|
|
14
|
+
};
|
|
15
|
+
declare function identityFromTrustedHeaders(headers: Record<string, string[]> | undefined, config: TrustedHeadersEndUserAuthConfig): UsageIdentity;
|
|
16
|
+
declare function createTrustedHeadersEndUserVerifier(config: TrustedHeadersEndUserAuthConfig): EndUserAuthVerifier;
|
|
17
|
+
|
|
18
|
+
export { DEFAULT_DMZ_TRUSTED_HEADERS, type TrustedHeadersEndUserAuthConfig, createTrustedHeadersEndUserVerifier, identityFromTrustedHeaders };
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
// src/errors.ts
|
|
2
|
+
var PmtHouseError = class extends Error {
|
|
3
|
+
status;
|
|
4
|
+
code;
|
|
5
|
+
details;
|
|
6
|
+
constructor(message, {
|
|
7
|
+
status = 500,
|
|
8
|
+
code = "pymthouse_error",
|
|
9
|
+
details
|
|
10
|
+
} = {}) {
|
|
11
|
+
super(message);
|
|
12
|
+
this.name = "PmtHouseError";
|
|
13
|
+
this.status = status;
|
|
14
|
+
this.code = code;
|
|
15
|
+
this.details = details;
|
|
16
|
+
}
|
|
17
|
+
};
|
|
18
|
+
|
|
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
|
+
}
|
|
31
|
+
function headerValueFromWebhookPayload(headers, name) {
|
|
32
|
+
if (!headers) {
|
|
33
|
+
return "";
|
|
34
|
+
}
|
|
35
|
+
const direct = firstHeaderValue(headers[name]);
|
|
36
|
+
if (direct) {
|
|
37
|
+
return direct;
|
|
38
|
+
}
|
|
39
|
+
const target = name.toLowerCase();
|
|
40
|
+
for (const [key, values] of Object.entries(headers)) {
|
|
41
|
+
if (key.toLowerCase() === target) {
|
|
42
|
+
return firstHeaderValue(values);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
return "";
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// src/signer/webhook/adapters/trusted-headers/verifier.ts
|
|
49
|
+
var DEFAULT_DMZ_TRUSTED_HEADERS = {
|
|
50
|
+
issuer: "X-Livepeer-Usage-Issuer",
|
|
51
|
+
clientId: "X-Livepeer-Client-ID",
|
|
52
|
+
usageSubject: "X-Livepeer-Usage-Subject",
|
|
53
|
+
usageSubjectType: "X-Livepeer-Usage-Subject-Type"
|
|
54
|
+
};
|
|
55
|
+
function normalizeIssuer(value) {
|
|
56
|
+
let end = value.length;
|
|
57
|
+
while (end > 0 && value[end - 1] === "/") {
|
|
58
|
+
end -= 1;
|
|
59
|
+
}
|
|
60
|
+
return value.slice(0, end);
|
|
61
|
+
}
|
|
62
|
+
function identityFromTrustedHeaders(headers, config) {
|
|
63
|
+
const names = {
|
|
64
|
+
...DEFAULT_DMZ_TRUSTED_HEADERS,
|
|
65
|
+
...config.headerNames
|
|
66
|
+
};
|
|
67
|
+
const issuer = headerValueFromWebhookPayload(headers, names.issuer);
|
|
68
|
+
const clientId = headerValueFromWebhookPayload(headers, names.clientId);
|
|
69
|
+
const usageSubject = headerValueFromWebhookPayload(headers, names.usageSubject);
|
|
70
|
+
const usageSubjectType = headerValueFromWebhookPayload(headers, names.usageSubjectType) || "external_user_id";
|
|
71
|
+
if (!issuer || !clientId || !usageSubject) {
|
|
72
|
+
throw new PmtHouseError("missing trusted usage identity headers", {
|
|
73
|
+
status: 403,
|
|
74
|
+
code: "invalid_identity"
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
if (normalizeIssuer(issuer) !== normalizeIssuer(config.expectedIssuer.trim())) {
|
|
78
|
+
throw new PmtHouseError("trusted usage issuer mismatch", {
|
|
79
|
+
status: 403,
|
|
80
|
+
code: "invalid_identity"
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
return {
|
|
84
|
+
issuer,
|
|
85
|
+
client_id: clientId,
|
|
86
|
+
usage_subject: usageSubject,
|
|
87
|
+
usage_subject_type: usageSubjectType
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
function createTrustedHeadersEndUserVerifier(config) {
|
|
91
|
+
const expiryTtlSeconds = config.expiryTtlSeconds ?? 300;
|
|
92
|
+
return {
|
|
93
|
+
kind: "trusted_headers",
|
|
94
|
+
verify: async ({ payload }) => {
|
|
95
|
+
const identity = identityFromTrustedHeaders(payload.headers, config);
|
|
96
|
+
return {
|
|
97
|
+
identity,
|
|
98
|
+
expiry: Math.trunc(Date.now() / 1e3) + expiryTtlSeconds
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
export { DEFAULT_DMZ_TRUSTED_HEADERS, createTrustedHeadersEndUserVerifier, identityFromTrustedHeaders };
|
|
105
|
+
//# sourceMappingURL=trusted-headers.js.map
|
|
106
|
+
//# sourceMappingURL=trusted-headers.js.map
|
|
@@ -0,0 +1 @@
|
|
|
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"]}
|