@owlmeans/server-iam 0.1.18-rc.6 → 0.1.18-rc.60
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 +13 -4
- package/agent-meta/manifest.json +2 -2
- package/agent-meta/skills/server-iam/SKILL.md +142 -16
- package/build/append.d.ts +1 -5
- package/build/append.d.ts.map +1 -1
- package/build/append.js.map +1 -1
- package/build/consts.local.d.ts +3 -0
- package/build/consts.local.d.ts.map +1 -0
- package/build/consts.local.js +3 -0
- package/build/consts.local.js.map +1 -0
- package/build/gate.d.ts +13 -14
- package/build/gate.d.ts.map +1 -1
- package/build/gate.js +128 -35
- package/build/gate.js.map +1 -1
- package/build/index.d.ts +6 -0
- package/build/index.d.ts.map +1 -1
- package/build/index.js +3 -0
- package/build/index.js.map +1 -1
- package/build/organization/types.d.ts +21 -0
- package/build/organization/types.d.ts.map +1 -0
- package/build/organization/types.js +2 -0
- package/build/organization/types.js.map +1 -0
- package/build/organization.d.ts +9 -0
- package/build/organization.d.ts.map +1 -0
- package/build/organization.js +30 -0
- package/build/organization.js.map +1 -0
- package/build/runtime.d.ts +15 -0
- package/build/runtime.d.ts.map +1 -0
- package/build/runtime.js +167 -0
- package/build/runtime.js.map +1 -0
- package/build/types.d.ts +42 -0
- package/build/types.d.ts.map +1 -0
- package/build/types.js +2 -0
- package/build/types.js.map +1 -0
- package/build/types.local.d.ts +16 -0
- package/build/types.local.d.ts.map +1 -0
- package/build/types.local.js +2 -0
- package/build/types.local.js.map +1 -0
- package/package.json +11 -9
- package/src/append.ts +1 -4
- package/src/consts.local.ts +2 -0
- package/src/gate.ts +157 -45
- package/src/index.ts +6 -0
- package/src/organization/types.ts +21 -0
- package/src/organization.ts +49 -0
- package/src/runtime.ts +193 -0
- package/src/types.local.ts +18 -0
- package/src/types.ts +43 -0
- package/tests/context.ts +100 -0
- package/tests/gate.spec.ts +132 -4
- package/tests/organization.spec.ts +52 -0
- package/tests/runtime.spec.ts +169 -0
- package/tests/tsconfig.json +12 -0
package/README.md
CHANGED
|
@@ -7,12 +7,14 @@ One-call OIDC RP wiring and IAM gate for OwlMeans servers — `appendIam()` and
|
|
|
7
7
|
- `appendIam(context)` — registers the OIDC client, wrapping service, and IAM gate in a single call, replacing verbose manual wiring
|
|
8
8
|
- `makeIamGate()` — produces a guard that asserts unscoped or resource-scoped permissions against the IAM backend (claims-first, UMA2 fallback)
|
|
9
9
|
- Re-exports `hasPermission` from `@owlmeans/iam` for inline permission checks
|
|
10
|
+
- `makeOrganizationScope(context, request)` — `.organizationOf(slug)` / `.organizationsOf()`: the organizations of a tenanted session, from its session record
|
|
11
|
+
- `makeIamRuntimeClient(context, request)` — a typed client of the provider's runtime IAM API, acting as the request's subject
|
|
10
12
|
- Designed for IAM consumers such as the viable target template backend
|
|
11
13
|
|
|
12
14
|
## Installation
|
|
13
15
|
|
|
14
16
|
```bash
|
|
15
|
-
bun add @owlmeans/server-iam
|
|
17
|
+
bun add @owlmeans/server-iam@^0.1.18-rc.60
|
|
16
18
|
```
|
|
17
19
|
|
|
18
20
|
## Usage
|
|
@@ -20,12 +22,19 @@ bun add @owlmeans/server-iam
|
|
|
20
22
|
```typescript
|
|
21
23
|
import { appendIam, makeIamGate } from '@owlmeans/server-iam'
|
|
22
24
|
import { IAM_GATE } from '@owlmeans/server-iam'
|
|
25
|
+
import { contract, protocol, typed } from '@owlmeans/entrypoint'
|
|
26
|
+
import { route } from '@owlmeans/route'
|
|
27
|
+
import { DEFAULT_GUARD } from '@owlmeans/auth-common'
|
|
23
28
|
|
|
24
29
|
// Wire IAM into a server context
|
|
25
30
|
appendIam(context)
|
|
26
31
|
|
|
27
|
-
// Gate a
|
|
28
|
-
|
|
32
|
+
// Gate a protocol with a permission check
|
|
33
|
+
protocol(
|
|
34
|
+
route('users', '/users'),
|
|
35
|
+
contract(typed<User[]>()),
|
|
36
|
+
{ guards: DEFAULT_GUARD, gate: { alias: IAM_GATE, params: ['manage-users@{entity}'] } },
|
|
37
|
+
)
|
|
29
38
|
```
|
|
30
39
|
|
|
31
40
|
Requires `@owlmeans/oidc` OIDC shared config and a running IAM provider configured via `@owlmeans/server-oidc-rp`.
|
|
@@ -38,7 +47,7 @@ This package ships embedded agent skills under `agent-meta/`. After installing y
|
|
|
38
47
|
your project's skill store (`.agents/skills/`):
|
|
39
48
|
|
|
40
49
|
```sh
|
|
41
|
-
npx @owlmeans/agent-skills
|
|
50
|
+
npx @owlmeans/agent-skills@^0.1.18-rc.53
|
|
42
51
|
```
|
|
43
52
|
|
|
44
53
|
The embedded files are version-matched to this package release. Do not edit them
|
package/agent-meta/manifest.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"schemaVersion": 2,
|
|
3
3
|
"package": "@owlmeans/server-iam",
|
|
4
|
-
"version": "0.1.18-rc.
|
|
5
|
-
"generatedAt": "2026-
|
|
4
|
+
"version": "0.1.18-rc.60",
|
|
5
|
+
"generatedAt": "2026-10-09T11:30:42.741Z",
|
|
6
6
|
"canonicalRepo": "https://github.com/owlmeans/common",
|
|
7
7
|
"entries": [
|
|
8
8
|
{
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: server-iam
|
|
3
|
-
description: "How to use @owlmeans/server-iam — one-call OIDC RP wiring (appendIam)
|
|
3
|
+
description: "How to use @owlmeans/server-iam — one-call OIDC RP wiring (appendIam), the IAM gate that asserts unbound, organization-bound and resource-scoped permissions (claims-first, UMA2 fallback), the session's organizations (makeOrganizationScope: organizationOf/organizationsOf), the request-bound runtime IAM client (makeIamRuntimeClient), plus the gate-param grammar it re-exports. Use when gating server endpoints, declaring gate params, acting in a tenanted client's organizations, managing members or grants from a target's server, or diagnosing a permission refusal. Applies to files matching **/owlmeans.ts, **/gate*.ts, **/auth-guard*.ts."
|
|
4
4
|
metadata:
|
|
5
5
|
applyTo: "**/owlmeans.ts, **/gate*.ts, **/auth-guard*.ts"
|
|
6
6
|
---
|
|
@@ -8,34 +8,91 @@ metadata:
|
|
|
8
8
|
|
|
9
9
|
# Using `@owlmeans/server-iam`
|
|
10
10
|
|
|
11
|
+
**Install:** `"@owlmeans/server-iam": "^0.1.18-rc.60"` in `dependencies`
|
|
12
|
+
|
|
11
13
|
Boilerplate-less server-side consumer of the OwlMeans IAM. One call wires the OIDC RP stack and the
|
|
12
|
-
IAM gate; the consumer never knows which IAM backend (Keycloak or integrated) is active.
|
|
14
|
+
IAM gate; the consumer never knows which IAM backend (Keycloak or integrated) is active. For a
|
|
15
|
+
tenanted client it also reads the session's organizations and calls the provider's runtime IAM API
|
|
16
|
+
as the signed-in subject.
|
|
13
17
|
|
|
14
18
|
## Public API surface
|
|
15
19
|
|
|
16
20
|
| Symbol | Kind | Purpose |
|
|
17
21
|
|--------|------|---------|
|
|
18
22
|
| `appendIam(context)` | fn | Registers `makeOidcClientService()`, `makeOidcWrappingService()`, `makeIamGate()` (under `OIDC_GATE`), and the OIDC guard |
|
|
19
|
-
| `makeIamGate(alias?)` | fn | The IAM `GateService` — claims-first assertion with UMA2 fallback |
|
|
20
|
-
| `
|
|
21
|
-
| `
|
|
23
|
+
| `makeIamGate(alias?, opts?)` | fn | The IAM `GateService` — claims-first assertion with UMA2 fallback |
|
|
24
|
+
| `IamGateOptions` | type | `{ strictResourceScope?: boolean }` — refuse a scoped param on the fallback path instead of widening it |
|
|
25
|
+
| `gateParamHelper` (`.parseGateParam` / `.parseGateSelector` / `.formatGateParam`) / `gateValidationHelper.validateGateParams` / `resolveGateResource` | helper / fn | Re-exports from `@owlmeans/iam`, which owns the grammar |
|
|
26
|
+
| `RESOURCE_PARAM_SEPARATOR` / `RESOURCE_SOURCE_SEPARATOR` / `RESOURCE_PATH_SEPARATOR` | const | `'@'`, `':'` and `'.'`, re-exported |
|
|
27
|
+
| `GateParamSource` / `GateParamErrorCode` / `GateResolutionFailure` | enum | Re-exported; the sources a selector may name, and why one failed |
|
|
22
28
|
| `hasPermission` | fn | Re-export from `@owlmeans/iam` |
|
|
29
|
+
| `makeOrganizationScope(context, request).organizationOf(entitySlug)` | scope | One organization of the request's subject as a `ResolvedEntity` (`{ id: entityKey, slug, iamKey: entityKey }`); one the subject is not in is `AuthForbidden(ORGANIZATION_REFUSAL)` |
|
|
30
|
+
| `makeOrganizationScope(context, request).organizationsOf()` | scope | Every organization of the request's subject, as `ResolvedEntity[]` |
|
|
31
|
+
| `makeIamRuntimeClient(context, request)` | fn | The request-bound `IamRuntimeClient` of the provider's runtime IAM API — see "The runtime IAM client" |
|
|
32
|
+
| `IamRuntimeClient` | type | `organizations.{list,create,update}`, `members.{list,add,update,remove}`, `permissions.list`, `grants.{list,assign,revoke}` |
|
|
33
|
+
| `ORGANIZATION_REFUSAL` / `ORGANIZATION_OWNER_REFUSAL` | const | Re-exported from `@owlmeans/oidc`: the `AuthForbidden` reasons of a non-member and of a non-owner |
|
|
34
|
+
| `SERVER_IAM_SERVICE` | const | `'server-iam-service'` — exported and referenced nowhere; the gate registers under `OIDC_GATE`, not under this |
|
|
35
|
+
| Every `@owlmeans/iam` type | type | Re-exported wholesale, so a server needs one IAM import |
|
|
36
|
+
|
|
37
|
+
The grammar lives in **`@owlmeans/iam`**, not here — the browser, both IAM adapters and
|
|
38
|
+
code-generation tooling all have to read the same rules. This package re-exports it because it is the
|
|
39
|
+
documented import path for a server, so one IAM import covers the gate and its grammar.
|
|
40
|
+
|
|
41
|
+
`appendIam` reads the provider configuration from `cfg.oidc.providers`, so populate that before
|
|
42
|
+
calling it. It is the IAM-flavoured replacement for wiring `@owlmeans/server-oidc-rp` by hand: the
|
|
43
|
+
one difference is the gate, which is `makeIamGate()` rather than `makeOidcGate()`.
|
|
23
44
|
|
|
24
45
|
## Gate-param syntax
|
|
25
46
|
|
|
26
47
|
```
|
|
27
|
-
<permission>
|
|
28
|
-
<permission>@<
|
|
48
|
+
<permission> → unscoped (project-wide): 'article--modify'
|
|
49
|
+
<permission>@<bareKey> → bare form: 'department--modify@departmentId'
|
|
50
|
+
<permission>@<source>:<path> → qualified form: 'order--modify@body:order.id'
|
|
29
51
|
```
|
|
30
52
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
53
|
+
Sources: `params`, `query`, `body`, `headers`, `auth`.
|
|
54
|
+
|
|
55
|
+
- **The bare form is lenient and flat**; the qualified form is strict and nested. `@a.b` in the bare
|
|
56
|
+
form is the literal key `"a.b"` — a query key may legally contain a dot, and splitting it would
|
|
57
|
+
change what already-deployed selectors mean. Dotted paths exist only after a `source:`.
|
|
58
|
+
- The separator is `:` and not a dot on purpose. With a dotted-only form, a route that gains a param
|
|
59
|
+
named like a source keyword silently changes a selector's meaning: `/report/:query` with
|
|
60
|
+
`@query.id` flips from "the route param named `query.id`" to "the query string's `id`" — an
|
|
61
|
+
authorization lookup redirected to attacker-supplied input by an unrelated route rename.
|
|
62
|
+
- The bare form searches `params` then `query`. That query fallback is legacy and deliberately kept:
|
|
63
|
+
removing it would silently deny deployed apps whose selector names a query key.
|
|
64
|
+
- `headers:` lowercases its first segment and unwraps a single-element array; a repeated header is
|
|
65
|
+
refused rather than silently narrowed to one of its values.
|
|
66
|
+
- `auth:` is the only source that is neither attacker-controlled nor subject to `removeAdditional`.
|
|
67
|
+
Prefer it whenever the rule is "bound to their own profile or entity".
|
|
68
|
+
- A resolved id must satisfy the grant's `resources[]` — **and a grant carrying no `resources` at all
|
|
69
|
+
covers every id**. That is the all-resources form of the same permission, not a separate one.
|
|
70
|
+
- Params are **any-of**: one granted param is enough. Which is why a malformed or unresolvable param
|
|
71
|
+
can only contribute `false` and never throw — otherwise one bad sibling would refuse a request the
|
|
72
|
+
subject is legitimately entitled to.
|
|
73
|
+
|
|
74
|
+
**The `@` belongs to the gate and nowhere else.** It is never part of a permission's stored NAME. A
|
|
75
|
+
definition or grant written as `enquiry--view@enquiryId` is a key nothing looks up, so the permission
|
|
76
|
+
reads as granted in every screen and every request is still refused, with nothing logged.
|
|
77
|
+
`ensurePermission` refuses such a name; `gateValidationHelper.validateGateParams` catches the mirror-image mistake at
|
|
78
|
+
generation time.
|
|
79
|
+
|
|
80
|
+
### `gateValidationHelper.validateGateParams(params, audit?)`
|
|
81
|
+
|
|
82
|
+
Reports what is provable from an entrypoint's own declaration: a selector naming a route param the
|
|
83
|
+
path does not carry, or a `body`/`query`/`headers` key the `Filter` does not declare **while that
|
|
84
|
+
schema sets `additionalProperties: false`**. That qualifier matters — the server's AJV runs
|
|
85
|
+
`removeAdditional`, which strips only what a schema closes, so without it the check would fire on
|
|
86
|
+
every unfiltered endpoint and be ignored within a week. It never decides a request; the gate runs it
|
|
87
|
+
once per alias and only logs.
|
|
88
|
+
|
|
89
|
+
The route half of the audit comes from `entrypoint.mount()`, which needs a service with a resolvable
|
|
90
|
+
address. An entrypoint that has none is still audited against its filter — the route-param check is
|
|
91
|
+
simply skipped rather than the whole audit being lost.
|
|
35
92
|
|
|
36
93
|
```ts
|
|
37
94
|
// module declaration
|
|
38
|
-
gate
|
|
95
|
+
{ gate: { alias: OIDC_GATE, params: ['department--modify@depId'] } }
|
|
39
96
|
|
|
40
97
|
// or imperative
|
|
41
98
|
await ctx.service<GateService>(OIDC_GATE).assert(req, res, ['article--modify'])
|
|
@@ -46,10 +103,76 @@ await ctx.service<GateService>(OIDC_GATE).assert(req, res, ['article--modify'])
|
|
|
46
103
|
1. `req.auth == null` → `AuthForbidden('auth')`.
|
|
47
104
|
2. **Claims mode** — when `req.auth.permissions` is a valid `PermissionSet[]` (minted into the id_token
|
|
48
105
|
by the integrated IAM provider and mapped into `Auth` by `@owlmeans/server-oidc-rp`), params are
|
|
49
|
-
asserted locally via `hasPermission
|
|
106
|
+
asserted locally via `hasPermission`, with `entitySlug: req.entity?.slug ?? authHelper.entitySlugOf(auth)` —
|
|
107
|
+
the organization the request acts in.
|
|
50
108
|
3. **Fallback** — otherwise `@…` suffixes are stripped and the check delegates to the UMA2 gate model
|
|
51
|
-
from `@owlmeans/server-oidc-rp` (`createGateModel().loadPermissions`) —
|
|
52
|
-
`makeOidcGate
|
|
109
|
+
from `@owlmeans/server-oidc-rp` (`createGateModel().loadPermissions`) — exactly the check
|
|
110
|
+
`makeOidcGate` performs, which is what a Keycloak-backed deployment gets.
|
|
111
|
+
|
|
112
|
+
In claims mode all four permission kinds (`iam` skill, "Permission kinds") are decided locally by
|
|
113
|
+
`hasPermission`; a bound set reaching the gate is a leak the relying party should have stripped, and
|
|
114
|
+
it counts only when the request acts in exactly its organization.
|
|
115
|
+
|
|
116
|
+
Which branch runs is decided per request by the token alone: a conforming `permissions` claim selects
|
|
117
|
+
claims mode, its absence selects the fallback. Nothing configures it, and there is no environment
|
|
118
|
+
variable behind it.
|
|
119
|
+
|
|
120
|
+
**The fallback path does not enforce resource scoping**, so one declaration means two different
|
|
121
|
+
things depending on which backend answered. It cannot be fixed by denying — a Keycloak-backed adapter
|
|
122
|
+
throws `IamUnsupported('resource-scoped-grant')`, so a scoped grant cannot exist there and denying
|
|
123
|
+
would lock every user out of every scoped endpoint. The gate logs each such param once per alias;
|
|
124
|
+
`makeIamGate(alias, { strictResourceScope: true })` opts into denial where the refusals are the
|
|
125
|
+
intended outcome.
|
|
126
|
+
|
|
127
|
+
A denial distinguishes its reasons in the log: a param that failed **structurally** (unparseable,
|
|
128
|
+
source absent, value not a scalar) is reported separately from one that resolved fine and simply was
|
|
129
|
+
not granted. The HTTP answer is identical — `AuthForbidden('permission')` either way — because the
|
|
130
|
+
caller must never learn which.
|
|
131
|
+
|
|
132
|
+
## `{entity}` in a permission name
|
|
133
|
+
|
|
134
|
+
A gate param may carry the literal `{entity}`, which is substituted at assertion time with the
|
|
135
|
+
organization entity's **stable id** — `req.entity.id`, resolved once at the server boundary — falling
|
|
136
|
+
back to the token's `entitySlug` and then to `-`. So `my-service-account-{entity}` asserts a
|
|
137
|
+
per-organization permission without the declaration knowing which organization it is for.
|
|
138
|
+
|
|
139
|
+
Grants are stored against the id wherever one is resolvable. The slug fallback exists for deployments
|
|
140
|
+
with no organization store of their own, where the slug *is* the identifier; a deployment that has a
|
|
141
|
+
store must not grant against slugs, because a rename would then orphan every grant.
|
|
142
|
+
|
|
143
|
+
## Organizations of the session
|
|
144
|
+
|
|
145
|
+
A relying party of a tenanted client has no organization registry of its own: the provider's
|
|
146
|
+
`organizations` claim, kept in the session record (`@owlmeans/server-oidc-rp`), is the only source,
|
|
147
|
+
re-read on every validation. `makeOrganizationScope(context, request).organizationsOf()` answers all of it and `.organizationOf(slug)` one entry by
|
|
148
|
+
slug, as `ResolvedEntity` values keyed by the frozen `entityKey` — use them for a handler that acts in
|
|
149
|
+
an organization its URL names rather than the session's acting one (which the guard already attaches
|
|
150
|
+
as `req.entity`). A session of a client without the scope acts in none and has none to offer; an
|
|
151
|
+
unauthenticated request or a session that is gone is `AuthorizationError` (401).
|
|
152
|
+
|
|
153
|
+
## The runtime IAM client
|
|
154
|
+
|
|
155
|
+
`makeIamRuntimeClient(context, request)` calls the provider's runtime IAM API (`makeIamRuntimeProtocols` in
|
|
156
|
+
`@owlmeans/iam`) as that request's subject:
|
|
157
|
+
|
|
158
|
+
- **Base** — the provider's discovery field `IAM_API_METADATA` (`owlmeans_iam_api`), read through
|
|
159
|
+
the OIDC client service's adapter `getMetadata()` for the session's client, and cached per context
|
|
160
|
+
and client; a failed lookup is forgotten. A provider that advertises none (Keycloak) is
|
|
161
|
+
`IamClientError('runtime-api:<client>')`.
|
|
162
|
+
- **Bearer** — the provider access token of the request's session record, read afresh on every call
|
|
163
|
+
so a token the guard just refreshed is the one sent. A record without one is
|
|
164
|
+
`AuthForbidden('record')`, and nothing is sent.
|
|
165
|
+
- **Transport** — plain `fetch` over `IAM_RUNTIME_ROUTES`: the API is another service's tree, and a
|
|
166
|
+
relying party binds none of it.
|
|
167
|
+
- **Refusals** — a development server's marshalled error is rebuilt into its class. A production body
|
|
168
|
+
is only an incident id, so the status and the route decide: a 403 from an owner route is
|
|
169
|
+
`AuthForbidden(ORGANIZATION_OWNER_REFUSAL)`, from any other route `AuthForbidden(ORGANIZATION_REFUSAL)`;
|
|
170
|
+
a 401 is `AuthorizationError('iam-runtime')`; anything else `IamError('runtime:status:<n>')`. The
|
|
171
|
+
incident id travels on the error.
|
|
172
|
+
|
|
173
|
+
`members.add` is find-or-create by e-mail and idempotent — that is the provider's job, so a caller
|
|
174
|
+
never checks for an existing member first. Owner and member rights are decided by the provider from
|
|
175
|
+
the token; nothing sent here can widen them.
|
|
53
176
|
|
|
54
177
|
## Rules
|
|
55
178
|
|
|
@@ -57,7 +180,10 @@ await ctx.service<GateService>(OIDC_GATE).assert(req, res, ['article--modify'])
|
|
|
57
180
|
`OIDC_GATE` alias and the IAM gate already covers the UMA2 path.
|
|
58
181
|
- Never branch on the IAM backend in consumer code — the gate's claims/fallback split is the only seam.
|
|
59
182
|
- The OIDC provider entry must request the `permissions` scope (`extraScopes`) for claims mode to
|
|
60
|
-
engage; without it the gate transparently uses the fallback.
|
|
183
|
+
engage; without it the gate transparently uses the fallback. A tenanted client also requests
|
|
184
|
+
`organizations`.
|
|
185
|
+
- Reach the runtime IAM API only through `makeIamRuntimeClient`; never forward the browser's wrapped token or
|
|
186
|
+
build a bearer from anything but the session record.
|
|
61
187
|
|
|
62
188
|
## Related instructions
|
|
63
189
|
|
package/build/append.d.ts
CHANGED
|
@@ -1,7 +1,4 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
import type { WithSharedConfig } from '@owlmeans/oidc';
|
|
3
|
-
type IamServerConfig = ServerConfig & WithSharedConfig;
|
|
4
|
-
type IamServerContext<C extends IamServerConfig = IamServerConfig> = ServerContext<C>;
|
|
1
|
+
import type { IamServerConfig, IamServerContext } from './types.local.js';
|
|
5
2
|
/**
|
|
6
3
|
* One-call OIDC RP setup for a server context.
|
|
7
4
|
*
|
|
@@ -15,5 +12,4 @@ type IamServerContext<C extends IamServerConfig = IamServerConfig> = ServerConte
|
|
|
15
12
|
* context.cfg.oidc.providers[] — populate it before calling appendIam().
|
|
16
13
|
*/
|
|
17
14
|
export declare const appendIam: <C extends IamServerConfig, T extends IamServerContext<C>>(context: T) => T;
|
|
18
|
-
export {};
|
|
19
15
|
//# sourceMappingURL=append.d.ts.map
|
package/build/append.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"append.d.ts","sourceRoot":"","sources":["../src/append.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"append.d.ts","sourceRoot":"","sources":["../src/append.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,eAAe,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAA;AAGzE;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,SAAS,GAAI,CAAC,SAAS,eAAe,EAAE,CAAC,SAAS,gBAAgB,CAAC,CAAC,CAAC,WACvE,CAAC,KACT,CAQF,CAAA"}
|
package/build/append.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"append.js","sourceRoot":"","sources":["../src/append.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"append.js","sourceRoot":"","sources":["../src/append.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,qBAAqB,EAAE,uBAAuB,EAAE,MAAM,0BAA0B,CAAA;AAC1G,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAA;AAIvC;;;;;;;;;;;GAWG;AACH,MAAM,CAAC,MAAM,SAAS,GAAG,CACvB,OAAU,EACP,EAAE;IACL,OAAO,CAAC,eAAe,CAAC,qBAAqB,EAAE,CAAC,CAAA;IAChD,OAAO,CAAC,eAAe,CAAC,uBAAuB,EAAE,CAAC,CAAA;IAClD,sEAAsE;IACtE,gEAAgE;IAChE,OAAO,CAAC,eAAe,CAAC,WAAW,EAAE,CAAC,CAAA;IACtC,eAAe,CAAO,OAAO,CAAC,CAAA;IAC9B,OAAO,OAAO,CAAA;AAChB,CAAC,CAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"consts.local.d.ts","sourceRoot":"","sources":["../src/consts.local.ts"],"names":[],"mappings":"AAAA,gGAAgG;AAChG,eAAO,MAAM,kBAAkB,kBAAkB,CAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"consts.local.js","sourceRoot":"","sources":["../src/consts.local.ts"],"names":[],"mappings":"AAAA,gGAAgG;AAChG,MAAM,CAAC,MAAM,kBAAkB,GAAG,eAAe,CAAA"}
|
package/build/gate.d.ts
CHANGED
|
@@ -1,27 +1,26 @@
|
|
|
1
1
|
import type { GateService } from '@owlmeans/entrypoint';
|
|
2
|
+
import type { IamGateOptions } from './types.js';
|
|
2
3
|
/**
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
* req.params[requestParam] ?? req.query[requestParam]
|
|
7
|
-
* and must be listed in the grant's resources[]
|
|
8
|
-
* '{entity}' substitution applies to the permission part in both forms.
|
|
4
|
+
* The gate-param grammar lives in `@owlmeans/iam` so the browser, the adapters and code-generation
|
|
5
|
+
* tooling can all read it. Re-exported here because this module was its home and is the documented
|
|
6
|
+
* import path.
|
|
9
7
|
*/
|
|
10
|
-
export
|
|
11
|
-
export
|
|
12
|
-
permission: string;
|
|
13
|
-
resourceParam?: string;
|
|
14
|
-
}
|
|
15
|
-
export declare const parseGateParam: (param: string) => ParsedGateParam;
|
|
8
|
+
export { RESOURCE_PARAM_SEPARATOR, RESOURCE_SOURCE_SEPARATOR, RESOURCE_PATH_SEPARATOR, GateParamSource, GateParamErrorCode, GateResolutionFailure, gateParamHelper, gateValidationHelper, resolveGateResource } from '@owlmeans/iam';
|
|
9
|
+
export type { ParsedGateParam, GateResourceSelector, GateParamAudit, GateParamHelper, GateValidationHelper } from '@owlmeans/iam';
|
|
16
10
|
/**
|
|
17
11
|
* IAM gate: claims-first with UMA2 fallback. Registered under the OIDC_GATE alias by
|
|
18
12
|
* appendIam() so target code never knows which IAM backend is active.
|
|
19
13
|
*
|
|
20
14
|
* 1. When the Auth carries a valid PermissionSet[] claim (integrated IAM mode),
|
|
21
|
-
* params are asserted locally against it — both unscoped and resource-scoped forms
|
|
15
|
+
* params are asserted locally against it — both unscoped and resource-scoped forms, and a set
|
|
16
|
+
* bound to an organization only for the organization the request acts in.
|
|
22
17
|
* 2. Otherwise (Keycloak mode — its tokens never produce a conforming claim) the
|
|
23
18
|
* @-suffixes are stripped and the check delegates to the UMA2 gate model from
|
|
24
19
|
* @owlmeans/server-oidc-rp, byte-equivalent to makeOidcGate.
|
|
20
|
+
*
|
|
21
|
+
* Params are OR'd: holding any one of them admits the request. That is why a malformed or
|
|
22
|
+
* unresolvable param can only contribute `false` and never throw — a sibling that would otherwise
|
|
23
|
+
* have passed must not be refused because of it.
|
|
25
24
|
*/
|
|
26
|
-
export declare const makeIamGate: (alias?: string) => GateService;
|
|
25
|
+
export declare const makeIamGate: (alias?: string, opts?: IamGateOptions) => GateService;
|
|
27
26
|
//# sourceMappingURL=gate.d.ts.map
|
package/build/gate.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"gate.d.ts","sourceRoot":"","sources":["../src/gate.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,
|
|
1
|
+
{"version":3,"file":"gate.d.ts","sourceRoot":"","sources":["../src/gate.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAqC,MAAM,sBAAsB,CAAA;AAM1F,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAA;AAEhD;;;;GAIG;AACH,OAAO,EACL,wBAAwB,EAAE,yBAAyB,EAAE,uBAAuB,EAC5E,eAAe,EAAE,kBAAkB,EAAE,qBAAqB,EAC1D,eAAe,EAAE,oBAAoB,EAAE,mBAAmB,EAC3D,MAAM,eAAe,CAAA;AACtB,YAAY,EAAE,eAAe,EAAE,oBAAoB,EAAE,cAAc,EAAE,eAAe,EAAE,oBAAoB,EAAE,MAAM,eAAe,CAAA;AAejI;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,WAAW,WAAW,MAAM,SAAqB,cAAc,KAAG,WAkK9E,CAAA"}
|
package/build/gate.js
CHANGED
|
@@ -1,73 +1,166 @@
|
|
|
1
1
|
import { createLazyService } from '@owlmeans/context';
|
|
2
|
+
import { authHelper, AuthForbidden } from '@owlmeans/auth';
|
|
2
3
|
import { OIDC_GATE } from '@owlmeans/oidc';
|
|
3
|
-
import { AuthForbidden } from '@owlmeans/auth';
|
|
4
4
|
import { createGateModel, extractPermissionSets } from '@owlmeans/server-oidc-rp';
|
|
5
|
-
import { hasPermission } from '@owlmeans/iam';
|
|
5
|
+
import { hasPermission, gateParamHelper, gateValidationHelper, resolveGateResource, GateResolutionFailure } from '@owlmeans/iam';
|
|
6
|
+
import { logger, logThrottle } from '@owlmeans/log';
|
|
6
7
|
/**
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
* req.params[requestParam] ?? req.query[requestParam]
|
|
11
|
-
* and must be listed in the grant's resources[]
|
|
12
|
-
* '{entity}' substitution applies to the permission part in both forms.
|
|
8
|
+
* The gate-param grammar lives in `@owlmeans/iam` so the browser, the adapters and code-generation
|
|
9
|
+
* tooling can all read it. Re-exported here because this module was its home and is the documented
|
|
10
|
+
* import path.
|
|
13
11
|
*/
|
|
14
|
-
export
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
const
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
const value = params?.[resourceParam] ?? query?.[resourceParam];
|
|
26
|
-
return value != null ? `${value}` : undefined;
|
|
27
|
-
};
|
|
12
|
+
export { RESOURCE_PARAM_SEPARATOR, RESOURCE_SOURCE_SEPARATOR, RESOURCE_PATH_SEPARATOR, GateParamSource, GateParamErrorCode, GateResolutionFailure, gateParamHelper, gateValidationHelper, resolveGateResource } from '@owlmeans/iam';
|
|
13
|
+
/**
|
|
14
|
+
* Structural faults are logged once per alias+param+reason.
|
|
15
|
+
*
|
|
16
|
+
* A gate on a hot endpoint runs on every request, and a misconfiguration is by definition permanent,
|
|
17
|
+
* so an un-deduplicated log turns one typo into the incident.
|
|
18
|
+
*/
|
|
19
|
+
const reported = new Set();
|
|
20
|
+
const log = logger('server-iam:gate');
|
|
21
|
+
/** Aliases whose declarations have already been checked. */
|
|
22
|
+
const audited = new Set();
|
|
28
23
|
/**
|
|
29
24
|
* IAM gate: claims-first with UMA2 fallback. Registered under the OIDC_GATE alias by
|
|
30
25
|
* appendIam() so target code never knows which IAM backend is active.
|
|
31
26
|
*
|
|
32
27
|
* 1. When the Auth carries a valid PermissionSet[] claim (integrated IAM mode),
|
|
33
|
-
* params are asserted locally against it — both unscoped and resource-scoped forms
|
|
28
|
+
* params are asserted locally against it — both unscoped and resource-scoped forms, and a set
|
|
29
|
+
* bound to an organization only for the organization the request acts in.
|
|
34
30
|
* 2. Otherwise (Keycloak mode — its tokens never produce a conforming claim) the
|
|
35
31
|
* @-suffixes are stripped and the check delegates to the UMA2 gate model from
|
|
36
32
|
* @owlmeans/server-oidc-rp, byte-equivalent to makeOidcGate.
|
|
33
|
+
*
|
|
34
|
+
* Params are OR'd: holding any one of them admits the request. That is why a malformed or
|
|
35
|
+
* unresolvable param can only contribute `false` and never throw — a sibling that would otherwise
|
|
36
|
+
* have passed must not be refused because of it.
|
|
37
37
|
*/
|
|
38
|
-
export const makeIamGate = (alias = OIDC_GATE) => {
|
|
38
|
+
export const makeIamGate = (alias = OIDC_GATE, opts) => {
|
|
39
|
+
const reportOnce = (key, message, data) => {
|
|
40
|
+
if (reported.has(key)) {
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
reported.add(key);
|
|
44
|
+
log.error(message, data);
|
|
45
|
+
};
|
|
46
|
+
/**
|
|
47
|
+
* A refusal of the gate. Logged once a minute per route, reason and subject — a hot endpoint
|
|
48
|
+
* refuses on every request, and one line per window says the same thing.
|
|
49
|
+
*/
|
|
50
|
+
const forbidden = (req, reason, params) => {
|
|
51
|
+
const auth = req.auth;
|
|
52
|
+
if (logThrottle(`access.forbidden\0${req.alias ?? ''}\0${reason}\0${auth?.userId ?? ''}`, 60_000)) {
|
|
53
|
+
log.warn('Access forbidden', {
|
|
54
|
+
alias: req.alias, reason, params, userId: auth?.userId, entitySlug: req.entity?.slug ?? (auth != null ? authHelper.entitySlugOf(auth) : undefined),
|
|
55
|
+
}, { event: 'access.forbidden' });
|
|
56
|
+
}
|
|
57
|
+
return new AuthForbidden(reason);
|
|
58
|
+
};
|
|
59
|
+
/**
|
|
60
|
+
* Check an entrypoint's gate params against what it declares, once, the first time it is reached.
|
|
61
|
+
*
|
|
62
|
+
* Structurally unable to affect the outcome: it only ever logs. A selector naming a key the
|
|
63
|
+
* entrypoint's filter does not declare is stripped by validation before the gate runs, so the
|
|
64
|
+
* endpoint denies every request with a clean build and nothing else to go on — this is the line that
|
|
65
|
+
* says why.
|
|
66
|
+
*/
|
|
67
|
+
const auditEntrypoint = (ctx, req, params) => {
|
|
68
|
+
if (req.alias == null || audited.has(req.alias)) {
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
audited.add(req.alias);
|
|
72
|
+
try {
|
|
73
|
+
const entrypoint = ctx.entrypoint(req.alias);
|
|
74
|
+
if (entrypoint == null) {
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
let routePath;
|
|
78
|
+
try {
|
|
79
|
+
routePath = entrypoint.mount();
|
|
80
|
+
}
|
|
81
|
+
catch {
|
|
82
|
+
// The mount needs a service with an address; an entrypoint that has none still has a filter
|
|
83
|
+
// worth auditing.
|
|
84
|
+
}
|
|
85
|
+
const audit = {
|
|
86
|
+
...(routePath != null ? { routePath } : {}),
|
|
87
|
+
...(entrypoint.filter != null ? { filter: entrypoint.filter } : {})
|
|
88
|
+
};
|
|
89
|
+
for (const issue of gateValidationHelper.validateGateParams(params, audit)) {
|
|
90
|
+
log.error('Gate param is misconfigured', {
|
|
91
|
+
param: issue.param, alias: req.alias, code: issue.code, detail: issue.detail,
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
catch {
|
|
96
|
+
// An entrypoint that cannot be looked up is not this gate's problem to report.
|
|
97
|
+
}
|
|
98
|
+
};
|
|
39
99
|
const service = createLazyService(alias, {
|
|
40
100
|
assert: async (req, _, params) => {
|
|
41
101
|
await service.ready();
|
|
42
102
|
const ctx = service.assertCtx();
|
|
43
103
|
if (req.auth == null) {
|
|
44
|
-
throw
|
|
104
|
+
throw forbidden(req, 'auth', params);
|
|
45
105
|
}
|
|
46
106
|
const auth = req.auth;
|
|
47
107
|
const sets = extractPermissionSets(auth.permissions);
|
|
48
108
|
if (sets != null) {
|
|
109
|
+
auditEntrypoint(ctx, req, params);
|
|
110
|
+
// Why a param failed, kept aside so a denial can say whether the gate was misconfigured or
|
|
111
|
+
// the subject simply lacks the grant. The two look identical from the outside and are
|
|
112
|
+
// repaired in completely different places.
|
|
113
|
+
const structural = [];
|
|
114
|
+
// The organization the request acts in. A relying party of a tenanted client attaches it
|
|
115
|
+
// through the guard; otherwise it is the token's. A set bound to any other organization
|
|
116
|
+
// never satisfies the check.
|
|
117
|
+
const entitySlug = req.entity?.slug ?? authHelper.entitySlugOf(auth);
|
|
49
118
|
const granted = params.some(param => {
|
|
50
|
-
const { permission,
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
119
|
+
const { permission, resource, error } = gateParamHelper.parseGateParam(param);
|
|
120
|
+
// Grants are stored against the entity's stable id wherever one is resolvable; the
|
|
121
|
+
// slug is only a fallback for deployments with no organization store of their own,
|
|
122
|
+
// where the slug IS the identifier.
|
|
123
|
+
const fixed = permission.replaceAll('{entity}', req.entity?.id ?? authHelper.entitySlugOf(auth) ?? '-');
|
|
124
|
+
if (error != null) {
|
|
125
|
+
structural.push(`"${param}" does not parse [${error.code}]: ${error.detail}`);
|
|
126
|
+
return false;
|
|
127
|
+
}
|
|
128
|
+
if (resource != null) {
|
|
129
|
+
const resolution = resolveGateResource(req, resource);
|
|
130
|
+
if (resolution.id == null) {
|
|
131
|
+
if (resolution.reason !== GateResolutionFailure.NotProvided) {
|
|
132
|
+
structural.push(`"${param}" resolved no resource id [${resolution.reason}]`
|
|
133
|
+
+ ` from ${resource.sources.join(', ')}`);
|
|
134
|
+
}
|
|
55
135
|
return false;
|
|
56
136
|
}
|
|
57
|
-
return hasPermission(auth, fixed, { resourceId });
|
|
137
|
+
return hasPermission(auth, fixed, { resourceId: resolution.id, entitySlug });
|
|
58
138
|
}
|
|
59
|
-
return hasPermission(auth, fixed);
|
|
139
|
+
return hasPermission(auth, fixed, { entitySlug });
|
|
60
140
|
});
|
|
61
141
|
if (!granted) {
|
|
62
|
-
|
|
142
|
+
structural.forEach(detail => reportOnce(`${req.alias}\0${detail}`, 'Gate refused a request it could not evaluate', { alias: req.alias, detail }));
|
|
143
|
+
throw forbidden(req, 'permission', params);
|
|
63
144
|
}
|
|
64
145
|
return;
|
|
65
146
|
}
|
|
66
|
-
|
|
147
|
+
// UMA2 fallback. Resource scoping is NOT enforced here: a Keycloak-backed deployment cannot
|
|
148
|
+
// store a resource-scoped grant, so a scoped param widens to a project-wide check and the same
|
|
149
|
+
// declaration means two different things depending on which backend is active.
|
|
150
|
+
const scoped = params.filter(param => gateParamHelper.parseGateParam(param).resource != null);
|
|
151
|
+
scoped.forEach(param => reportOnce(`uma2\0${req.alias}\0${param}`, 'Gate param is resource-scoped, but resource scoping is not enforced in UMA2 mode — it is checked as a '
|
|
152
|
+
+ 'project-wide permission', { param, alias: req.alias }));
|
|
153
|
+
const usable = opts?.strictResourceScope === true
|
|
154
|
+
? params.filter(param => gateParamHelper.parseGateParam(param).resource == null)
|
|
155
|
+
: params;
|
|
156
|
+
if (usable.length < 1) {
|
|
157
|
+
throw forbidden(req, 'permission', params);
|
|
158
|
+
}
|
|
159
|
+
const stripped = usable.map(param => gateParamHelper.parseGateParam(param).permission);
|
|
67
160
|
const model = createGateModel(ctx);
|
|
68
161
|
const permissions = await model.loadPermissions(auth, stripped);
|
|
69
162
|
if (permissions.length < 1) {
|
|
70
|
-
throw
|
|
163
|
+
throw forbidden(req, 'permission', params);
|
|
71
164
|
}
|
|
72
165
|
}
|
|
73
166
|
});
|
package/build/gate.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"gate.js","sourceRoot":"","sources":["../src/gate.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAA;AAErD,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"gate.js","sourceRoot":"","sources":["../src/gate.ts"],"names":[],"mappings":"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"}
|
package/build/index.d.ts
CHANGED
|
@@ -1,6 +1,12 @@
|
|
|
1
1
|
export type * from '@owlmeans/iam';
|
|
2
2
|
export { hasPermission } from '@owlmeans/iam';
|
|
3
|
+
export { ORGANIZATION_REFUSAL, ORGANIZATION_OWNER_REFUSAL } from '@owlmeans/oidc';
|
|
3
4
|
export * from './consts.js';
|
|
4
5
|
export * from './append.js';
|
|
5
6
|
export * from './gate.js';
|
|
7
|
+
export type * from './types.js';
|
|
8
|
+
export { makeOrganizationScope, organizationOf, organizationsOf } from './organization.js';
|
|
9
|
+
export type * from './organization/types.js';
|
|
10
|
+
export { makeIamRuntimeClient, iamRuntime } from './runtime.js';
|
|
11
|
+
export type { IamRuntimeClient } from './types.js';
|
|
6
12
|
//# sourceMappingURL=index.d.ts.map
|
package/build/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,mBAAmB,eAAe,CAAA;AAClC,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAA;AAC7C,cAAc,aAAa,CAAA;AAC3B,cAAc,aAAa,CAAA;AAC3B,cAAc,WAAW,CAAA"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,mBAAmB,eAAe,CAAA;AAClC,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAA;AAC7C,OAAO,EAAE,oBAAoB,EAAE,0BAA0B,EAAE,MAAM,gBAAgB,CAAA;AACjF,cAAc,aAAa,CAAA;AAC3B,cAAc,aAAa,CAAA;AAC3B,cAAc,WAAW,CAAA;AACzB,mBAAmB,YAAY,CAAA;AAC/B,OAAO,EAAE,qBAAqB,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAA;AAC1F,mBAAmB,yBAAyB,CAAA;AAC5C,OAAO,EAAE,oBAAoB,EAAE,UAAU,EAAE,MAAM,cAAc,CAAA;AAC/D,YAAY,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAA"}
|
package/build/index.js
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
export { hasPermission } from '@owlmeans/iam';
|
|
2
|
+
export { ORGANIZATION_REFUSAL, ORGANIZATION_OWNER_REFUSAL } from '@owlmeans/oidc';
|
|
2
3
|
export * from './consts.js';
|
|
3
4
|
export * from './append.js';
|
|
4
5
|
export * from './gate.js';
|
|
6
|
+
export { makeOrganizationScope, organizationOf, organizationsOf } from './organization.js';
|
|
7
|
+
export { makeIamRuntimeClient, iamRuntime } from './runtime.js';
|
|
5
8
|
//# sourceMappingURL=index.js.map
|
package/build/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAA;AAC7C,cAAc,aAAa,CAAA;AAC3B,cAAc,aAAa,CAAA;AAC3B,cAAc,WAAW,CAAA"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAA;AAC7C,OAAO,EAAE,oBAAoB,EAAE,0BAA0B,EAAE,MAAM,gBAAgB,CAAA;AACjF,cAAc,aAAa,CAAA;AAC3B,cAAc,aAAa,CAAA;AAC3B,cAAc,WAAW,CAAA;AAEzB,OAAO,EAAE,qBAAqB,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAA;AAE1F,OAAO,EAAE,oBAAoB,EAAE,UAAU,EAAE,MAAM,cAAc,CAAA"}
|