permdock 0.0.0 → 0.2.0
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 +327 -1
- package/dist/a2a/index.d.ts +169 -0
- package/dist/a2a/index.js +232 -0
- package/dist/adapter-context-mlWsVGGg.js +23 -0
- package/dist/ai-sdk/index.d.ts +95 -0
- package/dist/ai-sdk/index.js +154 -0
- package/dist/approval-required-TzNB9oQA.js +6 -0
- package/dist/approvals/index.d.ts +3 -0
- package/dist/approvals/index.js +5 -0
- package/dist/approvals-DbYAuNkG.js +224 -0
- package/dist/approvers-DT4AVyIg.js +52 -0
- package/dist/arazzo-BAgw9ap6.js +70 -0
- package/dist/arazzo-cmvX2jDe.js +54 -0
- package/dist/authzen/index.d.ts +39 -0
- package/dist/authzen/index.js +302 -0
- package/dist/better-auth/index.d.ts +109 -0
- package/dist/better-auth/index.js +344 -0
- package/dist/better-supabase/index.d.ts +206 -0
- package/dist/better-supabase/index.js +620 -0
- package/dist/bind-CVy3Espv.d.ts +25 -0
- package/dist/bind-VnYn2HKq.js +97 -0
- package/dist/boundary-BM8a_P6E.js +13 -0
- package/dist/boundary-BmHxVH1J.d.ts +15 -0
- package/dist/budget-JqcRqyhK.d.ts +11 -0
- package/dist/budget-NbEtbJC_.js +11 -0
- package/dist/canonical-json-DemiK4Vp.js +26 -0
- package/dist/capability-4qPdO9gk.js +173 -0
- package/dist/capability-Dq43tT1u.d.ts +99 -0
- package/dist/catalog/index.d.ts +12 -0
- package/dist/catalog/index.js +2 -0
- package/dist/catalog-BjZSovXQ.js +2 -0
- package/dist/catalog-doc-Dsc9y7sd.js +309 -0
- package/dist/catalog-h2tlKFkq.js +48 -0
- package/dist/catalog-path-CnI0XTFK.js +12 -0
- package/dist/catalog-z8q6bi_r.js +55 -0
- package/dist/claude-agent/index.d.ts +72 -0
- package/dist/claude-agent/index.js +77 -0
- package/dist/clerk/index.d.ts +65 -0
- package/dist/clerk/index.js +301 -0
- package/dist/cli/bin.d.ts +1 -0
- package/dist/cli/bin.js +20 -0
- package/dist/cli/index.d.ts +46 -0
- package/dist/cli/index.js +5 -0
- package/dist/clients-C7zLFuWT.d.ts +12 -0
- package/dist/clients-DjU5ABMy.js +23 -0
- package/dist/cloud/index.d.ts +90 -0
- package/dist/cloud/index.js +404 -0
- package/dist/cloud-BGhHS-lY.js +50 -0
- package/dist/cloud-Bo3e9Ak3.js +118 -0
- package/dist/collect-DDDv_ESs.js +502 -0
- package/dist/collect-DLlujdHC.js +83 -0
- package/dist/collect-rG2IQ3t0.js +2 -0
- package/dist/commands-DWOrSQic.js +97 -0
- package/dist/compact-y6vfu2_f.js +19 -0
- package/dist/compare-pfyVnBjE.js +12 -0
- package/dist/compile/index.d.ts +3 -0
- package/dist/compile/index.js +2 -0
- package/dist/compile-Ba4blROR.js +613 -0
- package/dist/compile-CNnl6uIt.d.ts +94 -0
- package/dist/config-BJiM-xAm.js +157 -0
- package/dist/config-Bn00Z3ks.js +36 -0
- package/dist/config-report-Dw_JcUqT.js +44 -0
- package/dist/connection-CU8MQxRi.js +194 -0
- package/dist/context-Ttp0ekMT.js +82 -0
- package/dist/convex/index.d.ts +45 -0
- package/dist/convex/index.js +65 -0
- package/dist/create-BWyx3jua.d.ts +245 -0
- package/dist/create-CPhDL6qx.js +253 -0
- package/dist/credential-8P81ff4u.js +306 -0
- package/dist/delegation-D8pUEuce.js +103 -0
- package/dist/describe-B_gVZEVi.js +94 -0
- package/dist/describe-PdoqESvg.d.ts +36 -0
- package/dist/diff-B8Tunc3o.js +451 -0
- package/dist/diff-CzqLxZ77.js +48 -0
- package/dist/digest-B3kc_PgQ.d.ts +19 -0
- package/dist/digest-BI-6aa6d.js +27 -0
- package/dist/doctor-WpvG6p4k.js +1194 -0
- package/dist/doctor-collect-ByfYlNv1.js +664 -0
- package/dist/doctor-rOr-4ZfS.js +53 -0
- package/dist/drizzle/index.d.ts +73 -0
- package/dist/drizzle/index.js +160 -0
- package/dist/duration-xK2jGFVc.js +25 -0
- package/dist/elysia/index.d.ts +49 -0
- package/dist/elysia/index.js +59 -0
- package/dist/errors-CWfoNg9N.js +47 -0
- package/dist/errors-Cz5zn0mW.js +123 -0
- package/dist/errors-DAqevpNk.d.ts +125 -0
- package/dist/errors-DRnGZHzF.js +30 -0
- package/dist/evaluation-items-CfCCejQd.js +40 -0
- package/dist/evaluations-tz6D9A2G.js +461 -0
- package/dist/eve/index.d.ts +86 -0
- package/dist/eve/index.js +176 -0
- package/dist/expiry-BoBJ8Tvc.js +7 -0
- package/dist/express/index.d.ts +23 -0
- package/dist/express/index.js +78 -0
- package/dist/fastify/index.d.ts +33 -0
- package/dist/fastify/index.js +92 -0
- package/dist/fields-BMl1RxoX.js +26 -0
- package/dist/files-DWUN9PzI.js +125 -0
- package/dist/fixtures-ht28Cplr.js +67 -0
- package/dist/freeze-CrU8nQeX.js +60 -0
- package/dist/from-snapshot-C3sHpZNS.js +569 -0
- package/dist/generate-CH7ThJ14.js +173 -0
- package/dist/grantee-Cv5Sogfv.js +602 -0
- package/dist/graph-sql-B-dsAT6j.d.ts +29 -0
- package/dist/headers-BZSDieNT.js +6 -0
- package/dist/headers-Cf-zWvsO.d.ts +6 -0
- package/dist/helpers-H_KARDVC.js +421 -0
- package/dist/hono/index.d.ts +48 -0
- package/dist/hono/index.js +99 -0
- package/dist/hosted-DJQw46hn.js +266 -0
- package/dist/http-BIhmLfCc.js +95 -0
- package/dist/http-DPuDaChb.d.ts +13 -0
- package/dist/http-SO7qGttf.js +44 -0
- package/dist/ids-DC4V4CFu.js +18 -0
- package/dist/index-A0YNL8jZ.d.ts +177 -0
- package/dist/index-CtE07CBF.d.ts +6 -0
- package/dist/index-D3vbkoSI.d.ts +483 -0
- package/dist/index-D6_cSa1z.d.ts +201 -0
- package/dist/index.d.ts +16 -0
- package/dist/index.js +26 -0
- package/dist/instance-options-BK_rNOSC.d.ts +11 -0
- package/dist/instance-options-Dhhcnm3y.js +22 -0
- package/dist/json-schema-BsAflUGW.js +106 -0
- package/dist/jwt/index.d.ts +91 -0
- package/dist/jwt/index.js +590 -0
- package/dist/kernel-GSQnMz3O.js +208 -0
- package/dist/kysely/index.d.ts +78 -0
- package/dist/kysely/index.js +129 -0
- package/dist/live-options-H2eG8dfJ.js +60 -0
- package/dist/load-DhWEB9P1.js +75 -0
- package/dist/load-DwJUafYN.js +2 -0
- package/dist/load-jose-BL6LH4bL.js +11 -0
- package/dist/lru-8q4WZjBV.js +28 -0
- package/dist/manifest-iaoBXHKc.js +783 -0
- package/dist/manifest-uDS9y5de.d.ts +206 -0
- package/dist/map-AcxK9o_D.js +147 -0
- package/dist/map-claims-Z4QZOiFF.js +369 -0
- package/dist/map-error-pgUWNNtG.js +23 -0
- package/dist/markers-B0hYLvMD.js +60 -0
- package/dist/may-use-DndQ5tQ-.js +77 -0
- package/dist/mcp/index.d.ts +159 -0
- package/dist/mcp/index.js +603 -0
- package/dist/nest/index.d.ts +75 -0
- package/dist/nest/index.js +261 -0
- package/dist/next/client.d.ts +23 -0
- package/dist/next/client.js +33 -0
- package/dist/next/index.d.ts +93 -0
- package/dist/next/index.js +180 -0
- package/dist/next/plugin.d.ts +14 -0
- package/dist/next/plugin.js +33 -0
- package/dist/node/index.d.ts +24 -0
- package/dist/node/index.js +34 -0
- package/dist/openai/index.d.ts +62 -0
- package/dist/openai/index.js +92 -0
- package/dist/openapi/index.d.ts +176 -0
- package/dist/openapi/index.js +3 -0
- package/dist/openapi-Bbg4wGVL.js +164 -0
- package/dist/openapi-BqRBvAng.js +538 -0
- package/dist/openapi-CqqEbHsL.js +250 -0
- package/dist/openapi-import-cmwetbzw.js +5959 -0
- package/dist/openapi-schema--ARjyfQr.js +6902 -0
- package/dist/orpc/index.d.ts +51 -0
- package/dist/orpc/index.js +145 -0
- package/dist/otel/index.d.ts +13 -0
- package/dist/otel/index.js +202 -0
- package/dist/package-root-zGkxO3oN.js +30 -0
- package/dist/parse-BuyjxhZV.js +53 -0
- package/dist/parse-local-manifest-BkGQNzAh.d.ts +10 -0
- package/dist/parse-local-manifest-BrMozJCo.js +36 -0
- package/dist/pdp/index.d.ts +22 -0
- package/dist/pdp/index.js +682 -0
- package/dist/peer-BOr_kJE1.js +31 -0
- package/dist/permdock-CzqXjCpU.js +3471 -0
- package/dist/permissions-CDgvKG5L.d.ts +52 -0
- package/dist/permissions-CpZrivYv.js +142 -0
- package/dist/permissions-DVoF6dMt.js +662 -0
- package/dist/permissions-DttnqqxC.d.ts +214 -0
- package/dist/pins-8ILTftC9.js +12 -0
- package/dist/policy-CFZAr_Al.d.ts +2252 -0
- package/dist/policy-D8UFyERw.d.ts +20 -0
- package/dist/policy-xyWg7QdR.js +1122 -0
- package/dist/powersync-A8x_Yyvh.js +2 -0
- package/dist/powersync-C7kLglqX.js +540 -0
- package/dist/powersync-yW1UUFzp.js +62 -0
- package/dist/prisma/index.d.ts +136 -0
- package/dist/prisma/index.js +455 -0
- package/dist/problem-B43ztKIm.js +191 -0
- package/dist/problem-details-CkL50EEf.d.ts +7 -0
- package/dist/problem-details-_AMOYz-w.js +144 -0
- package/dist/prompt-CXYhLfsS.js +32 -0
- package/dist/protected-CNsMzrVd.d.ts +27 -0
- package/dist/protected-Cs6kTaHo.js +100 -0
- package/dist/protected-bZs6rbT1.d.ts +40 -0
- package/dist/provider-Cjr62YMV.d.ts +6 -0
- package/dist/provider-DLzpb2Xz.js +52 -0
- package/dist/provider-store-DNyC1y48.js +43 -0
- package/dist/react/index.d.ts +8 -0
- package/dist/react/index.js +7 -0
- package/dist/react/provider-client.d.ts +2 -0
- package/dist/react/provider-client.js +3 -0
- package/dist/react-native/index.d.ts +198 -0
- package/dist/react-native/index.js +696 -0
- package/dist/refs-KYb4ntaz.js +91 -0
- package/dist/relations-cjOL01hZ.js +505 -0
- package/dist/replay-BsOyTrdV.js +28 -0
- package/dist/replay-sqBGMnNs.d.ts +5 -0
- package/dist/resource-ref-CaS9yVPi.js +20 -0
- package/dist/revocations-Bhr0aMIC.js +27 -0
- package/dist/revocations-Cy06JNx2.d.ts +21 -0
- package/dist/rls-BMNydpHk.js +2521 -0
- package/dist/rls-CEvs64Kj.js +238 -0
- package/dist/rls-fields-BMasREhR.js +3502 -0
- package/dist/rls-graph-pc9fuXYm.js +435 -0
- package/dist/rls-import-D8F7j35Q.js +943 -0
- package/dist/rls-migrate-7wikfrVI.js +367 -0
- package/dist/rls-ownership-B5Lkq62W.js +843 -0
- package/dist/rls-shared-aOQ4hGTO.js +493 -0
- package/dist/rls-verify-D8B7dOTh.js +745 -0
- package/dist/row-check-Dt35czLy.d.ts +40 -0
- package/dist/rpc-DOK54_CS.js +89 -0
- package/dist/run-YXCJDNYk.js +174 -0
- package/dist/runtime-CB8gQFvS.js +11 -0
- package/dist/saas-Bj_FFkjN.js +1203 -0
- package/dist/schema-D3MnDMxa.js +300 -0
- package/dist/scim/index.d.ts +2 -0
- package/dist/scim/index.js +2 -0
- package/dist/scim-BFGBBAqR.js +1445 -0
- package/dist/scopes-CVdPrWN-.js +239 -0
- package/dist/server/index.d.ts +134 -0
- package/dist/server/index.js +11 -0
- package/dist/server-DlZ28Oz5.js +268 -0
- package/dist/sha256-BO0swRXL.js +150 -0
- package/dist/shared-DRu8VFVM.js +123 -0
- package/dist/sink-Bd9PSyfq.js +141 -0
- package/dist/sink-Gs6TTVa-.d.ts +104 -0
- package/dist/skills-Biq5uup3.js +192 -0
- package/dist/skills-JaymNCdK.js +56 -0
- package/dist/snapshot-Enxd0n-s.js +975 -0
- package/dist/snapshot-cache-D6jLelln.js +44 -0
- package/dist/snapshot-cache-DwQH8ufx.d.ts +45 -0
- package/dist/solid/index.d.ts +93 -0
- package/dist/solid/index.js +188 -0
- package/dist/sources-B0UvrJ21.js +534 -0
- package/dist/sources-BcJgw0lt.d.ts +192 -0
- package/dist/sql-xdg5f4Fi.js +27 -0
- package/dist/src-CSbUiozF.js +568 -0
- package/dist/ssf/index.d.ts +4 -0
- package/dist/ssf/index.js +596 -0
- package/dist/store-DMAWwAJV.js +371 -0
- package/dist/store-D_pjn91-.d.ts +36 -0
- package/dist/store-options-yO0V6gRn.js +716 -0
- package/dist/stores-4_sqiOA1.js +87 -0
- package/dist/stores-DVR5NHLE.d.ts +52 -0
- package/dist/stream-DDpvynSB.js +66 -0
- package/dist/stream-DlvG2hs-.d.ts +12 -0
- package/dist/style-CTm1AXDT.js +22 -0
- package/dist/subject-C6dLxqHU.js +24 -0
- package/dist/subject-settings-BwBmCdTR.js +128 -0
- package/dist/supabase/index.d.ts +183 -0
- package/dist/supabase/index.js +5 -0
- package/dist/supabase/middleware.d.ts +82 -0
- package/dist/supabase/middleware.js +102 -0
- package/dist/supabase-CwafwxxF.js +83 -0
- package/dist/supabase-DTBaC20O.js +774 -0
- package/dist/supabase-config-Bs44dare.js +472 -0
- package/dist/supabase-hook-BuxLQLpU.js +1814 -0
- package/dist/supabase-hook-D5qVd_D8.js +2 -0
- package/dist/supautils-DYZnzRWV.js +91 -0
- package/dist/svelte/PermissionBoundary.svelte +37 -0
- package/dist/svelte/Protected.svelte +40 -0
- package/dist/svelte/index.d.ts +13 -0
- package/dist/svelte/index.js +107 -0
- package/dist/svelte/runtime.d.ts +7 -0
- package/dist/svelte/runtime.js +4 -0
- package/dist/svelte/source.d.ts +13 -0
- package/dist/svelte/source.js +11 -0
- package/dist/terminal/index.d.ts +163 -0
- package/dist/terminal/index.js +833 -0
- package/dist/testing/index.d.ts +745 -0
- package/dist/testing/index.js +3672 -0
- package/dist/testing/saas/index.d.ts +194 -0
- package/dist/testing/saas/index.js +3 -0
- package/dist/testing/saas/permissions.d.ts +2 -0
- package/dist/testing/saas/permissions.js +2 -0
- package/dist/text-diff-BdkkYSbi.js +15 -0
- package/dist/thenable-okc2xDsj.js +10 -0
- package/dist/timeout-D51niuQP.js +8 -0
- package/dist/token-CIWxJOCh.js +50 -0
- package/dist/trpc/index.d.ts +61 -0
- package/dist/trpc/index.js +122 -0
- package/dist/types-9AWO9EGt.d.ts +197 -0
- package/dist/types-BPxgszlT.d.ts +550 -0
- package/dist/types-BVyImy5I.d.ts +120 -0
- package/dist/types-Bvc4oWT6.d.ts +9 -0
- package/dist/types-C3s9xVJG.d.ts +48 -0
- package/dist/types-Dnemwd77.d.ts +183 -0
- package/dist/types-kxznc7cn.d.ts +52 -0
- package/dist/types-vKyAMtcX.d.ts +157 -0
- package/dist/types-vNSDF7Dq.d.ts +66 -0
- package/dist/types-yF5LmQVD.d.ts +306 -0
- package/dist/unplugin/index.d.ts +7 -0
- package/dist/unplugin/index.js +31 -0
- package/dist/usage-D07N9QJ3.js +42 -0
- package/dist/usage-D82l1CwK.js +2 -0
- package/dist/usage-DG1oeCca.js +693 -0
- package/dist/validation-error-CnjZ4t92.js +33 -0
- package/dist/validation-error-CtF23SrC.d.ts +26 -0
- package/dist/validity-uOp8UpYn.js +245 -0
- package/dist/verifier-BxBo6I44.js +466 -0
- package/dist/version-BvacVTZR.js +17 -0
- package/dist/views-Soe7bGSC.js +95 -0
- package/dist/vocabulary-DA8a8zif.d.ts +56 -0
- package/dist/vue/index.d.ts +79 -0
- package/dist/vue/index.js +196 -0
- package/dist/watch-Etoa_Mvr.js +2 -0
- package/dist/watch-UihESpsJ.js +128 -0
- package/dist/webmcp/index.d.ts +75 -0
- package/dist/webmcp/index.js +307 -0
- package/package.json +450 -5
- package/rulesets/permdock.yaml +29 -0
- package/schemas/approval-request-v1.json +175 -0
- package/schemas/catalog-v1.json +535 -0
- package/schemas/openapi/oas-3.1.json +1298 -0
- package/schemas/openapi/oas-3.2.json +1516 -0
- package/schemas/openapi/overlay-1.1.json +79 -0
- package/schemas/supabase-claims-v1.json +144 -0
- package/schemas/supabase-manifest-v1.json +361 -0
- package/skills/permdock/SKILL.md +66 -0
- package/skills/permdock-agents/SKILL.md +77 -0
- package/skills/permdock-agents/references/runtimes.md +213 -0
- package/skills/permdock-approvals/SKILL.md +80 -0
- package/skills/permdock-approvals/references/stores-and-resume.md +94 -0
- package/skills/permdock-audit/SKILL.md +67 -0
- package/skills/permdock-credentials/SKILL.md +55 -0
- package/skills/permdock-credentials/references/tokens-keys-links.md +132 -0
- package/skills/permdock-data/SKILL.md +57 -0
- package/skills/permdock-data/references/queries-and-rls.md +62 -0
- package/skills/permdock-data/references/relationships.md +67 -0
- package/skills/permdock-tenancy/SKILL.md +80 -0
- package/skills/permdock-tenancy/references/ownership-and-custom-roles.md +89 -0
- package/skills/permdock-wire/SKILL.md +116 -0
- package/skills/permdock-wire/references/adapters.md +492 -0
- package/skills/permdock-wire/references/policy-options.md +45 -0
|
@@ -0,0 +1,590 @@
|
|
|
1
|
+
import { t as compact } from "../compact-y6vfu2_f.js";
|
|
2
|
+
import { n as freezeDeep } from "../freeze-CrU8nQeX.js";
|
|
3
|
+
import { n as sha256, t as bytesToBase64Url } from "../sha256-BO0swRXL.js";
|
|
4
|
+
import { t as anonymousSubject } from "../subject-C6dLxqHU.js";
|
|
5
|
+
import { i as linkPolicyViolation, o as parseCapability, s as redeemerAllows, t as capabilitySubject } from "../capability-4qPdO9gk.js";
|
|
6
|
+
import { a as decodeHeader, i as issuerFromDiscovery, n as assertSubjectConfig, o as normalizeTyp, r as fail, t as joseTokenVerifier } from "../verifier-BxBo6I44.js";
|
|
7
|
+
import { t as loadJose } from "../load-jose-BL6LH4bL.js";
|
|
8
|
+
import { n as mapClaimsToSubject, r as validateCustomClaims, t as acceptMismatch } from "../map-claims-Z4QZOiFF.js";
|
|
9
|
+
import { t as memoryReplayStore } from "../replay-BsOyTrdV.js";
|
|
10
|
+
//#region src/jwt/capability.ts
|
|
11
|
+
function emit(options, reason, cause, token) {
|
|
12
|
+
if (options.onAuth === void 0) return;
|
|
13
|
+
const header = decodeHeader(token);
|
|
14
|
+
options.onAuth(compact({
|
|
15
|
+
reason,
|
|
16
|
+
cause,
|
|
17
|
+
source: "capability",
|
|
18
|
+
kid: header?.kid,
|
|
19
|
+
alg: header?.alg,
|
|
20
|
+
typ: header?.typ,
|
|
21
|
+
issuer: options.issuer,
|
|
22
|
+
requestId: options.requestId
|
|
23
|
+
}));
|
|
24
|
+
}
|
|
25
|
+
async function claimOnce(replay, key, expiresAt) {
|
|
26
|
+
if (replay.claim !== void 0) return replay.claim(key, expiresAt);
|
|
27
|
+
if (await replay.seen(key)) return false;
|
|
28
|
+
await replay.remember(key, expiresAt);
|
|
29
|
+
return true;
|
|
30
|
+
}
|
|
31
|
+
async function stores(options, capability, issuedAt, once) {
|
|
32
|
+
try {
|
|
33
|
+
const policy = await options.linkPolicy?.(capability);
|
|
34
|
+
if (policy !== void 0 && linkPolicyViolation(capability, policy, issuedAt) !== void 0) return "link-policy";
|
|
35
|
+
if (options.revoked !== void 0 && await options.revoked(capability.id)) return "capability-revoked";
|
|
36
|
+
const replay = options.replay;
|
|
37
|
+
if (once !== void 0 && (replay === void 0 || !await claimOnce(replay, once.key, once.expiresAt))) return "capability-replayed";
|
|
38
|
+
return { ok: true };
|
|
39
|
+
} catch {
|
|
40
|
+
return {
|
|
41
|
+
ok: false,
|
|
42
|
+
reason: "source-threw"
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Resolves a `permdock-capability+jwt` into the `link` subject it acts as.
|
|
48
|
+
* Every failure (signature, `typ`, `iss`, `aud`, expiry, a malformed claim,
|
|
49
|
+
* a revoked link, a replayed one-time token, a redeemer the viewer does not
|
|
50
|
+
* satisfy, a throwing store) is the anonymous subject, never a throw.
|
|
51
|
+
*/
|
|
52
|
+
async function subjectFromCapability(token, options) {
|
|
53
|
+
if (token === void 0 || token === null || token.length === 0) return anonymousSubject();
|
|
54
|
+
const deny = (cause, reason = "invalid-token") => {
|
|
55
|
+
emit(options, reason, cause, token);
|
|
56
|
+
return anonymousSubject();
|
|
57
|
+
};
|
|
58
|
+
if (typeof options.issuer !== "string" || options.issuer.length === 0) return deny("wrong-issuer");
|
|
59
|
+
if (options.audience === void 0 || options.audience.length === 0) return deny("wrong-audience");
|
|
60
|
+
let verifier;
|
|
61
|
+
try {
|
|
62
|
+
verifier = options.verifier ?? joseTokenVerifier({
|
|
63
|
+
...options,
|
|
64
|
+
typ: "permdock-capability+jwt"
|
|
65
|
+
});
|
|
66
|
+
} catch {
|
|
67
|
+
return deny("malformed");
|
|
68
|
+
}
|
|
69
|
+
let verified;
|
|
70
|
+
try {
|
|
71
|
+
verified = await verifier.verify(token, compact({
|
|
72
|
+
typ: "permdock-capability+jwt",
|
|
73
|
+
issuer: options.issuer,
|
|
74
|
+
audience: options.audience,
|
|
75
|
+
clockTolerance: options.clockTolerance
|
|
76
|
+
}));
|
|
77
|
+
} catch {
|
|
78
|
+
return deny("malformed");
|
|
79
|
+
}
|
|
80
|
+
if (!verified.ok) return deny(verified.cause);
|
|
81
|
+
if (normalizeTyp(verified.header.typ) !== "permdock-capability+jwt") return deny("wrong-token-type");
|
|
82
|
+
const parsed = parseCapability(verified.claims["capability"]);
|
|
83
|
+
const exp = verified.claims.exp;
|
|
84
|
+
if (parsed?.holder !== "link" || verified.claims.sub !== parsed.id || typeof exp !== "number") return deny("invalid-claims");
|
|
85
|
+
const capability = {
|
|
86
|
+
...parsed,
|
|
87
|
+
expiresAt: Math.min(parsed.expiresAt, exp)
|
|
88
|
+
};
|
|
89
|
+
const now = Date.now() / 1e3;
|
|
90
|
+
if (capability.expiresAt <= now) return deny("expired");
|
|
91
|
+
if (!redeemerAllows(capability.redeemer, options.viewer, now)) return deny("redeemer-mismatch");
|
|
92
|
+
const jti = verified.claims["jti"];
|
|
93
|
+
if (capability.once === true && (options.replay === void 0 || typeof jti !== "string" || jti === "")) return deny("invalid-claims");
|
|
94
|
+
const iat = verified.claims.iat;
|
|
95
|
+
const checked = await stores(options, capability, typeof iat === "number" ? iat : void 0, capability.once === true ? {
|
|
96
|
+
key: `capability\u0000${options.issuer}\u0000${String(jti)}`,
|
|
97
|
+
expiresAt: capability.expiresAt
|
|
98
|
+
} : void 0);
|
|
99
|
+
if (typeof checked === "string") return deny(checked);
|
|
100
|
+
if (!checked.ok) return deny(void 0, checked.reason);
|
|
101
|
+
return capabilitySubject(capability, { issuer: options.issuer });
|
|
102
|
+
}
|
|
103
|
+
//#endregion
|
|
104
|
+
//#region src/jwt/ci-oidc.ts
|
|
105
|
+
const PROVIDERS = {
|
|
106
|
+
github: {
|
|
107
|
+
issuer: "https://token.actions.githubusercontent.com",
|
|
108
|
+
jwks: "https://token.actions.githubusercontent.com/.well-known/jwks"
|
|
109
|
+
},
|
|
110
|
+
gitlab: {
|
|
111
|
+
issuer: "https://gitlab.com",
|
|
112
|
+
jwks: "https://gitlab.com/oauth/discovery/keys"
|
|
113
|
+
},
|
|
114
|
+
buildkite: {
|
|
115
|
+
issuer: "https://agent.buildkite.com",
|
|
116
|
+
jwks: "https://agent.buildkite.com/.well-known/jwks"
|
|
117
|
+
}
|
|
118
|
+
};
|
|
119
|
+
function text(claims, key) {
|
|
120
|
+
const value = Object.hasOwn(claims, key) ? claims[key] : void 0;
|
|
121
|
+
return typeof value === "string" && value !== "" ? value : void 0;
|
|
122
|
+
}
|
|
123
|
+
function fullRef(name, type) {
|
|
124
|
+
if (name === void 0) return;
|
|
125
|
+
if (name.startsWith("refs/")) return name;
|
|
126
|
+
return type === "tag" ? `refs/tags/${name}` : `refs/heads/${name}`;
|
|
127
|
+
}
|
|
128
|
+
function jobClaims(provider, claims) {
|
|
129
|
+
switch (provider) {
|
|
130
|
+
case "github": return compact({
|
|
131
|
+
repository: text(claims, "repository"),
|
|
132
|
+
ref: text(claims, "ref"),
|
|
133
|
+
environment: text(claims, "environment")
|
|
134
|
+
});
|
|
135
|
+
case "gitlab": return compact({
|
|
136
|
+
repository: text(claims, "project_path"),
|
|
137
|
+
ref: fullRef(text(claims, "ref"), text(claims, "ref_type") === "tag" ? "tag" : "branch"),
|
|
138
|
+
environment: text(claims, "environment")
|
|
139
|
+
});
|
|
140
|
+
case "buildkite": {
|
|
141
|
+
const organization = text(claims, "organization_slug");
|
|
142
|
+
const pipeline = text(claims, "pipeline_slug");
|
|
143
|
+
const tag = text(claims, "build_tag");
|
|
144
|
+
return compact({
|
|
145
|
+
repository: organization === void 0 || pipeline === void 0 ? void 0 : `${organization}/${pipeline}`,
|
|
146
|
+
ref: tag === void 0 ? fullRef(text(claims, "build_branch"), "branch") : fullRef(tag, "tag")
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
default: return provider;
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* Resolves a CI provider's OIDC token (GitHub Actions, GitLab CI, Buildkite)
|
|
154
|
+
* into a `workload` principal whose id is `sub`. Every failure (signature,
|
|
155
|
+
* issuer, audience, expiry, a missing `sub`, the `schema`) is the anonymous
|
|
156
|
+
* subject, never a throw and never a user.
|
|
157
|
+
*/
|
|
158
|
+
async function subjectFromCiOidc(token, options) {
|
|
159
|
+
if (token === void 0 || token === null || token.length === 0) return anonymousSubject();
|
|
160
|
+
const known = Object.hasOwn(PROVIDERS, options.provider) ? PROVIDERS[options.provider] : void 0;
|
|
161
|
+
const issuer = options.issuer ?? known?.issuer;
|
|
162
|
+
const deny = (cause) => {
|
|
163
|
+
const header = decodeHeader(token);
|
|
164
|
+
options.onAuth?.(compact({
|
|
165
|
+
reason: "invalid-token",
|
|
166
|
+
cause,
|
|
167
|
+
source: "ci-oidc",
|
|
168
|
+
kid: header?.kid,
|
|
169
|
+
alg: header?.alg,
|
|
170
|
+
typ: header?.typ,
|
|
171
|
+
issuer,
|
|
172
|
+
requestId: options.requestId
|
|
173
|
+
}));
|
|
174
|
+
return anonymousSubject();
|
|
175
|
+
};
|
|
176
|
+
if (known === void 0 || issuer === void 0) return deny("wrong-issuer");
|
|
177
|
+
if (options.audience === void 0 || options.audience.length === 0) return deny("wrong-audience");
|
|
178
|
+
let verifier;
|
|
179
|
+
try {
|
|
180
|
+
verifier = options.verifier ?? joseTokenVerifier(options.issuer === void 0 || options.jwks !== void 0 ? {
|
|
181
|
+
...options,
|
|
182
|
+
issuer,
|
|
183
|
+
jwks: options.jwks ?? known.jwks
|
|
184
|
+
} : {
|
|
185
|
+
...options,
|
|
186
|
+
issuer,
|
|
187
|
+
discovery: issuer
|
|
188
|
+
});
|
|
189
|
+
} catch {
|
|
190
|
+
return deny("malformed");
|
|
191
|
+
}
|
|
192
|
+
let verified;
|
|
193
|
+
try {
|
|
194
|
+
verified = await verifier.verify(token, compact({
|
|
195
|
+
typ: ["JWT"],
|
|
196
|
+
issuer,
|
|
197
|
+
audience: options.audience,
|
|
198
|
+
clockTolerance: options.clockTolerance
|
|
199
|
+
}));
|
|
200
|
+
} catch {
|
|
201
|
+
return deny("malformed");
|
|
202
|
+
}
|
|
203
|
+
if (!verified.ok) return deny(verified.cause);
|
|
204
|
+
const sub = text(verified.claims, "sub");
|
|
205
|
+
if (sub === void 0) return deny("invalid-claims");
|
|
206
|
+
if (options.schema !== void 0 && !validateCustomClaims(verified.claims, options.schema).ok) return deny("invalid-claims");
|
|
207
|
+
const principal = {
|
|
208
|
+
id: sub,
|
|
209
|
+
kind: "workload",
|
|
210
|
+
issuer,
|
|
211
|
+
provider: options.provider,
|
|
212
|
+
...jobClaims(options.provider, verified.claims)
|
|
213
|
+
};
|
|
214
|
+
return freezeDeep({
|
|
215
|
+
principal,
|
|
216
|
+
context: {}
|
|
217
|
+
});
|
|
218
|
+
}
|
|
219
|
+
//#endregion
|
|
220
|
+
//#region src/jwt/dpop.ts
|
|
221
|
+
const DPOP_WINDOW_SECONDS = 60;
|
|
222
|
+
const PROOF_ALGS = /* @__PURE__ */ new Set([
|
|
223
|
+
"ES256",
|
|
224
|
+
"PS256",
|
|
225
|
+
"Ed25519",
|
|
226
|
+
"EdDSA",
|
|
227
|
+
"RS256"
|
|
228
|
+
]);
|
|
229
|
+
const PRIVATE_MEMBERS = [
|
|
230
|
+
"d",
|
|
231
|
+
"p",
|
|
232
|
+
"q",
|
|
233
|
+
"dp",
|
|
234
|
+
"dq",
|
|
235
|
+
"qi",
|
|
236
|
+
"k"
|
|
237
|
+
];
|
|
238
|
+
function headerOf(request) {
|
|
239
|
+
return request.headers.get("DPoP") ?? request.headers.get("dpop");
|
|
240
|
+
}
|
|
241
|
+
function withoutQuery(value) {
|
|
242
|
+
if (typeof value !== "string" || !URL.canParse(value)) return null;
|
|
243
|
+
const url = new URL(value);
|
|
244
|
+
url.search = "";
|
|
245
|
+
url.hash = "";
|
|
246
|
+
return url.href;
|
|
247
|
+
}
|
|
248
|
+
async function claimJti(replay, key, expiresAt) {
|
|
249
|
+
if (replay.claim !== void 0) return replay.claim(key, expiresAt);
|
|
250
|
+
if (await replay.seen(key)) return false;
|
|
251
|
+
await replay.remember(key, expiresAt);
|
|
252
|
+
return true;
|
|
253
|
+
}
|
|
254
|
+
function verifyDpopProof(request, claims, accessToken, options = {}) {
|
|
255
|
+
return verify(request, claims, accessToken, options);
|
|
256
|
+
}
|
|
257
|
+
async function verify(request, claims, accessToken, options) {
|
|
258
|
+
const proof = headerOf(request);
|
|
259
|
+
if (proof === null || proof.length === 0) return {
|
|
260
|
+
ok: false,
|
|
261
|
+
cause: "dpop-proof-invalid"
|
|
262
|
+
};
|
|
263
|
+
const expectedJkt = claims["cnf"] !== null && typeof claims["cnf"] === "object" && !Array.isArray(claims["cnf"]) && typeof claims["cnf"].jkt === "string" ? claims["cnf"].jkt : void 0;
|
|
264
|
+
if (expectedJkt === void 0) return {
|
|
265
|
+
ok: false,
|
|
266
|
+
cause: "dpop-proof-invalid"
|
|
267
|
+
};
|
|
268
|
+
const header = decodeHeader(proof);
|
|
269
|
+
if (header?.typ?.toLowerCase() !== "dpop+jwt") return {
|
|
270
|
+
ok: false,
|
|
271
|
+
cause: "dpop-proof-invalid"
|
|
272
|
+
};
|
|
273
|
+
const jwk = header["jwk"];
|
|
274
|
+
if (!PROOF_ALGS.has(header.alg ?? "") || jwk === null || typeof jwk !== "object" || Array.isArray(jwk) || PRIVATE_MEMBERS.some((member) => member in jwk)) return {
|
|
275
|
+
ok: false,
|
|
276
|
+
cause: "dpop-proof-invalid"
|
|
277
|
+
};
|
|
278
|
+
try {
|
|
279
|
+
const jose = await loadJose();
|
|
280
|
+
const key = await jose.importJWK(jwk, header.alg);
|
|
281
|
+
const result = await jose.jwtVerify(proof, key, {
|
|
282
|
+
typ: "dpop+jwt",
|
|
283
|
+
maxTokenAge: DPOP_WINDOW_SECONDS
|
|
284
|
+
});
|
|
285
|
+
const jkt = await jose.calculateJwkThumbprint(jwk, "sha256");
|
|
286
|
+
if (jkt !== expectedJkt) return {
|
|
287
|
+
ok: false,
|
|
288
|
+
cause: "dpop-proof-invalid"
|
|
289
|
+
};
|
|
290
|
+
const htm = result.payload["htm"];
|
|
291
|
+
const htu = result.payload["htu"];
|
|
292
|
+
const expectedHtu = withoutQuery(request.url);
|
|
293
|
+
if (htm !== request.method || expectedHtu === null || withoutQuery(htu) !== expectedHtu) return {
|
|
294
|
+
ok: false,
|
|
295
|
+
cause: "dpop-proof-invalid"
|
|
296
|
+
};
|
|
297
|
+
if (accessToken !== void 0) {
|
|
298
|
+
const ath = bytesToBase64Url(sha256(accessToken));
|
|
299
|
+
if (result.payload["ath"] !== ath) return {
|
|
300
|
+
ok: false,
|
|
301
|
+
cause: "dpop-proof-invalid"
|
|
302
|
+
};
|
|
303
|
+
}
|
|
304
|
+
if (options.replay !== void 0) {
|
|
305
|
+
const jti = result.payload.jti;
|
|
306
|
+
const iat = result.payload.iat;
|
|
307
|
+
if (typeof jti !== "string" || jti === "" || typeof iat !== "number" || !await claimJti(options.replay, `dpop\u0000${jkt}\u0000${jti}`, iat + DPOP_WINDOW_SECONDS)) return {
|
|
308
|
+
ok: false,
|
|
309
|
+
cause: "dpop-proof-invalid"
|
|
310
|
+
};
|
|
311
|
+
}
|
|
312
|
+
return { ok: true };
|
|
313
|
+
} catch {
|
|
314
|
+
return {
|
|
315
|
+
ok: false,
|
|
316
|
+
cause: "dpop-proof-invalid"
|
|
317
|
+
};
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
//#endregion
|
|
321
|
+
//#region src/jwt/introspection.ts
|
|
322
|
+
function emitAuth$1(options, cause) {
|
|
323
|
+
if (options.onAuth === void 0) return;
|
|
324
|
+
options.onAuth(compact({
|
|
325
|
+
reason: "invalid-token",
|
|
326
|
+
cause,
|
|
327
|
+
source: "jwt",
|
|
328
|
+
issuer: options.issuer,
|
|
329
|
+
requestId: options.requestId
|
|
330
|
+
}));
|
|
331
|
+
}
|
|
332
|
+
function isRecord$1(value) {
|
|
333
|
+
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
334
|
+
}
|
|
335
|
+
function keyToCnf(key) {
|
|
336
|
+
if (!isRecord$1(key)) return;
|
|
337
|
+
if (isRecord$1(key["jwk"])) return { jwk: key["jwk"] };
|
|
338
|
+
return { jwk: key };
|
|
339
|
+
}
|
|
340
|
+
function introspectionToClaims(body) {
|
|
341
|
+
const cnf = keyToCnf(body["key"]);
|
|
342
|
+
return compact({
|
|
343
|
+
sub: typeof body["sub"] === "string" ? body["sub"] : void 0,
|
|
344
|
+
iss: typeof body["iss"] === "string" ? body["iss"] : void 0,
|
|
345
|
+
aud: body["aud"],
|
|
346
|
+
exp: typeof body["exp"] === "number" ? body["exp"] : void 0,
|
|
347
|
+
iat: typeof body["iat"] === "number" ? body["iat"] : void 0,
|
|
348
|
+
nbf: typeof body["nbf"] === "number" ? body["nbf"] : void 0,
|
|
349
|
+
jti: typeof body["jti"] === "string" ? body["jti"] : void 0,
|
|
350
|
+
scope: typeof body["scope"] === "string" ? body["scope"] : void 0,
|
|
351
|
+
authorization_details: body["authorization_details"],
|
|
352
|
+
access: body["access"],
|
|
353
|
+
client_id: typeof body["client_id"] === "string" ? body["client_id"] : void 0,
|
|
354
|
+
roles: body["roles"],
|
|
355
|
+
groups: body["groups"],
|
|
356
|
+
entitlements: body["entitlements"],
|
|
357
|
+
sid: typeof body["sid"] === "string" ? body["sid"] : void 0,
|
|
358
|
+
acr: typeof body["acr"] === "string" ? body["acr"] : void 0,
|
|
359
|
+
amr: body["amr"],
|
|
360
|
+
auth_time: body["auth_time"],
|
|
361
|
+
act: body["act"],
|
|
362
|
+
cnf
|
|
363
|
+
});
|
|
364
|
+
}
|
|
365
|
+
function instanceActor(body) {
|
|
366
|
+
const id = typeof body["instance_id"] === "string" ? body["instance_id"] : typeof body["client_id"] === "string" ? body["client_id"] : void 0;
|
|
367
|
+
if (id === void 0) return;
|
|
368
|
+
return {
|
|
369
|
+
id,
|
|
370
|
+
kind: "oauth-client"
|
|
371
|
+
};
|
|
372
|
+
}
|
|
373
|
+
function attachActor(subject, body, binding) {
|
|
374
|
+
if (subject.actor !== void 0) return subject;
|
|
375
|
+
const actor = instanceActor(body);
|
|
376
|
+
if (actor === void 0) return subject;
|
|
377
|
+
const principal = subject.principal;
|
|
378
|
+
if (principal === null) return subject;
|
|
379
|
+
return freezeDeep({
|
|
380
|
+
...subject,
|
|
381
|
+
principal: freezeDeep(compact({
|
|
382
|
+
...principal,
|
|
383
|
+
binding: void 0
|
|
384
|
+
})),
|
|
385
|
+
actor: freezeDeep(compact({
|
|
386
|
+
...actor,
|
|
387
|
+
binding
|
|
388
|
+
}))
|
|
389
|
+
});
|
|
390
|
+
}
|
|
391
|
+
/**
|
|
392
|
+
* RFC 7662 leaves `aud` and `iss` optional; a response that names another
|
|
393
|
+
* resource server or issuer than the one configured is not for this API.
|
|
394
|
+
*/
|
|
395
|
+
function boundToConfig(body, options) {
|
|
396
|
+
if (options.issuer !== void 0 && body["iss"] !== void 0 && body["iss"] !== options.issuer) return false;
|
|
397
|
+
if (options.audience === void 0) return true;
|
|
398
|
+
const expected = Array.isArray(options.audience) ? options.audience : [options.audience];
|
|
399
|
+
const aud = body["aud"];
|
|
400
|
+
return (typeof aud === "string" ? [aud] : Array.isArray(aud) ? aud : []).some((item) => expected.includes(item));
|
|
401
|
+
}
|
|
402
|
+
function subjectFromIntrospection(response, options = {}) {
|
|
403
|
+
try {
|
|
404
|
+
if (!isRecord$1(response) || response["active"] !== true || !boundToConfig(response, options)) return anonymousSubject();
|
|
405
|
+
const mapped = mapClaimsToSubject(introspectionToClaims(response), options);
|
|
406
|
+
if (mapped.invalidChain) {
|
|
407
|
+
emitAuth$1(options, "invalid-chain");
|
|
408
|
+
return anonymousSubject();
|
|
409
|
+
}
|
|
410
|
+
if (mapped.subject.principal === null) return anonymousSubject();
|
|
411
|
+
return attachActor(mapped.subject, response, mapped.subject.principal.binding);
|
|
412
|
+
} catch {
|
|
413
|
+
return anonymousSubject();
|
|
414
|
+
}
|
|
415
|
+
}
|
|
416
|
+
//#endregion
|
|
417
|
+
//#region src/jwt/signer.ts
|
|
418
|
+
const SIGNING_ALGS = /* @__PURE__ */ new Set([
|
|
419
|
+
"ES256",
|
|
420
|
+
"PS256",
|
|
421
|
+
"Ed25519",
|
|
422
|
+
"RS256"
|
|
423
|
+
]);
|
|
424
|
+
function isRecord(value) {
|
|
425
|
+
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
426
|
+
}
|
|
427
|
+
function publicJwk(key) {
|
|
428
|
+
const { d: _d, p: _p, q: _q, dp: _dp, dq: _dq, qi: _qi, k: _k, ...pub } = key;
|
|
429
|
+
return pub;
|
|
430
|
+
}
|
|
431
|
+
function joseTokenSigner(options) {
|
|
432
|
+
if (options.alg === "HS256" || options.alg === "EdDSA") throw new Error("PermDock: joseTokenSigner refuses HS* and polymorphic EdDSA on outputs.");
|
|
433
|
+
if (!SIGNING_ALGS.has(options.alg)) throw new Error(`PermDock: unsupported signing alg '${options.alg}'.`);
|
|
434
|
+
if (options.kid.length === 0) throw new Error("PermDock: joseTokenSigner requires kid.");
|
|
435
|
+
const importKey = async () => {
|
|
436
|
+
if (options.key instanceof Uint8Array) throw new TypeError("PermDock: HMAC keys cannot sign PermDock outputs.");
|
|
437
|
+
return (await loadJose()).importJWK(options.key, options.alg);
|
|
438
|
+
};
|
|
439
|
+
return {
|
|
440
|
+
kid: options.kid,
|
|
441
|
+
sign(payload, signOptions) {
|
|
442
|
+
return signJwt(payload, signOptions);
|
|
443
|
+
},
|
|
444
|
+
jwks() {
|
|
445
|
+
if (isRecord(options.key)) return Promise.resolve({ keys: [publicJwk(options.key)] });
|
|
446
|
+
return Promise.resolve({ keys: [] });
|
|
447
|
+
}
|
|
448
|
+
};
|
|
449
|
+
async function signJwt(payload, signOptions) {
|
|
450
|
+
const jose = await loadJose();
|
|
451
|
+
const key = await importKey();
|
|
452
|
+
const now = Math.floor(Date.now() / 1e3);
|
|
453
|
+
const jwt = new jose.SignJWT({ ...payload });
|
|
454
|
+
jwt.setProtectedHeader({
|
|
455
|
+
alg: options.alg,
|
|
456
|
+
kid: options.kid,
|
|
457
|
+
typ: signOptions.typ
|
|
458
|
+
});
|
|
459
|
+
jwt.setIssuedAt(now);
|
|
460
|
+
jwt.setJti(globalThis.crypto.randomUUID());
|
|
461
|
+
if (options.issuer !== void 0) jwt.setIssuer(options.issuer);
|
|
462
|
+
if (signOptions.audience !== void 0) jwt.setAudience(signOptions.audience);
|
|
463
|
+
jwt.setExpirationTime(signOptions.expiresAt ?? now + 3600);
|
|
464
|
+
return jwt.sign(key);
|
|
465
|
+
}
|
|
466
|
+
}
|
|
467
|
+
//#endregion
|
|
468
|
+
//#region src/jwt/subject.ts
|
|
469
|
+
function emitAuth(options, cause, token) {
|
|
470
|
+
if (options.onAuth === void 0) return;
|
|
471
|
+
const header = token === void 0 ? void 0 : decodeHeader(token);
|
|
472
|
+
options.onAuth(compact({
|
|
473
|
+
reason: "invalid-token",
|
|
474
|
+
cause,
|
|
475
|
+
source: "jwt",
|
|
476
|
+
kid: header?.kid,
|
|
477
|
+
alg: header?.alg,
|
|
478
|
+
typ: header?.typ,
|
|
479
|
+
issuer: options.issuer,
|
|
480
|
+
requestId: options.requestId
|
|
481
|
+
}));
|
|
482
|
+
}
|
|
483
|
+
function tokenInQuery(request) {
|
|
484
|
+
if (request === void 0) return false;
|
|
485
|
+
return new URL(request.url, "https://permdock.invalid").searchParams.has("access_token");
|
|
486
|
+
}
|
|
487
|
+
function mtlsThumbprint(claims) {
|
|
488
|
+
const cnf = claims["cnf"];
|
|
489
|
+
if (cnf === null || typeof cnf !== "object" || Array.isArray(cnf)) return;
|
|
490
|
+
const value = cnf["x5t#S256"];
|
|
491
|
+
return typeof value === "string" ? value : void 0;
|
|
492
|
+
}
|
|
493
|
+
async function extraMemberships(options, subject, tenant) {
|
|
494
|
+
if (options.memberships === void 0 || subject.principal === null) return subject;
|
|
495
|
+
try {
|
|
496
|
+
const extra = await options.memberships.membershipsFor(compact({
|
|
497
|
+
id: subject.principal.id,
|
|
498
|
+
kind: subject.principal.kind
|
|
499
|
+
}), compact({ tenant }));
|
|
500
|
+
if (extra.length === 0) return subject;
|
|
501
|
+
const merged = [...subject.principal.memberships ?? [], ...extra];
|
|
502
|
+
return freezeDeep({
|
|
503
|
+
...subject,
|
|
504
|
+
principal: {
|
|
505
|
+
...subject.principal,
|
|
506
|
+
memberships: merged
|
|
507
|
+
}
|
|
508
|
+
});
|
|
509
|
+
} catch {
|
|
510
|
+
return subject;
|
|
511
|
+
}
|
|
512
|
+
}
|
|
513
|
+
function subjectFromJwt(token, options, request) {
|
|
514
|
+
return resolveSubject(token, options, request);
|
|
515
|
+
}
|
|
516
|
+
function createJwtSubjectResolver(options) {
|
|
517
|
+
assertSubjectConfig(options);
|
|
518
|
+
const verifier = options.verifier ?? joseTokenVerifier(options);
|
|
519
|
+
return (token, request) => resolveSubject(token, {
|
|
520
|
+
...options,
|
|
521
|
+
verifier
|
|
522
|
+
}, request);
|
|
523
|
+
}
|
|
524
|
+
async function resolveSubject(token, options, request) {
|
|
525
|
+
if (options.verifier === void 0) assertSubjectConfig(options);
|
|
526
|
+
if (token === void 0 || token === null || token.length === 0) return anonymousSubject();
|
|
527
|
+
if (options.profile === "fapi2" && tokenInQuery(request)) {
|
|
528
|
+
emitAuth(options, "token-in-query", token);
|
|
529
|
+
return anonymousSubject();
|
|
530
|
+
}
|
|
531
|
+
const verifier = options.verifier ?? joseTokenVerifier(options);
|
|
532
|
+
const issuer = options.issuer ?? (options.discovery === void 0 ? void 0 : issuerFromDiscovery(options.discovery));
|
|
533
|
+
let verified;
|
|
534
|
+
try {
|
|
535
|
+
verified = await verifier.verify(token, compact({
|
|
536
|
+
audience: options.audience,
|
|
537
|
+
issuer,
|
|
538
|
+
clockTolerance: options.clockTolerance,
|
|
539
|
+
typ: options.accept === "id-token" ? ["JWT"] : options.profile === "fapi2" ? "at+jwt" : ["at+jwt", "JWT"]
|
|
540
|
+
}));
|
|
541
|
+
} catch {
|
|
542
|
+
verified = fail("malformed");
|
|
543
|
+
}
|
|
544
|
+
if (!verified.ok) {
|
|
545
|
+
emitAuth(options, verified.cause, token);
|
|
546
|
+
return anonymousSubject();
|
|
547
|
+
}
|
|
548
|
+
if (acceptMismatch(verified.claims, verified.header.typ, options, options.audience)) {
|
|
549
|
+
emitAuth(options, "wrong-token-type", token);
|
|
550
|
+
return anonymousSubject();
|
|
551
|
+
}
|
|
552
|
+
const sender = options.sender ?? (options.profile === "fapi2" ? "dpop" : "none");
|
|
553
|
+
const cnf = verified.claims["cnf"];
|
|
554
|
+
const hasCnf = cnf !== null && typeof cnf === "object";
|
|
555
|
+
if (options.profile === "fapi2" && !hasCnf) {
|
|
556
|
+
emitAuth(options, "sender-constraint-required", token);
|
|
557
|
+
return anonymousSubject();
|
|
558
|
+
}
|
|
559
|
+
if (sender === "dpop") {
|
|
560
|
+
const proof = request === void 0 ? {
|
|
561
|
+
ok: false,
|
|
562
|
+
cause: "dpop-proof-invalid"
|
|
563
|
+
} : await verifyDpopProof(request, verified.claims, token, compact({ replay: options.replay }));
|
|
564
|
+
if (!proof.ok) {
|
|
565
|
+
emitAuth(options, proof.cause, token);
|
|
566
|
+
return anonymousSubject();
|
|
567
|
+
}
|
|
568
|
+
}
|
|
569
|
+
if (sender === "mtls") {
|
|
570
|
+
const expected = options.certificateThumbprint;
|
|
571
|
+
const seen = mtlsThumbprint(verified.claims);
|
|
572
|
+
if (expected === void 0 || seen !== expected) {
|
|
573
|
+
emitAuth(options, "mtls-binding-mismatch", token);
|
|
574
|
+
return anonymousSubject();
|
|
575
|
+
}
|
|
576
|
+
}
|
|
577
|
+
const mapped = mapClaimsToSubject(verified.claims, options);
|
|
578
|
+
if (mapped.invalidChain) {
|
|
579
|
+
emitAuth(options, "invalid-chain", token);
|
|
580
|
+
return anonymousSubject();
|
|
581
|
+
}
|
|
582
|
+
if (mapped.subject.principal === null) {
|
|
583
|
+
emitAuth(options, "invalid-claims", token);
|
|
584
|
+
return anonymousSubject();
|
|
585
|
+
}
|
|
586
|
+
if (mapped.invalidClaims) emitAuth(options, "invalid-claims", token);
|
|
587
|
+
return extraMemberships(options, mapped.subject, mapped.subject.principal.tenant);
|
|
588
|
+
}
|
|
589
|
+
//#endregion
|
|
590
|
+
export { createJwtSubjectResolver, joseTokenSigner, joseTokenVerifier, memoryReplayStore, subjectFromCapability, subjectFromCiOidc, subjectFromIntrospection, subjectFromJwt, verifyDpopProof };
|