@toa.io/extensions.exposition 1.0.0-alpha.292 → 1.0.0-alpha.293
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/components/identity.basic/package.json +8 -0
- package/components/identity.federation/package.json +8 -0
- package/components/identity.passkeys/package.json +8 -0
- package/components/identity.tokens/package.json +10 -0
- package/package.json +24 -13
- package/transpiled/Endpoint.js +3 -0
- package/transpiled/Endpoint.js.map +1 -1
- package/transpiled/Introspection.d.ts +6 -0
- package/transpiled/Introspection.js +1 -0
- package/transpiled/Introspection.js.map +1 -1
- package/transpiled/MCP/schema.js +2 -2
- package/transpiled/Query.d.ts +2 -12
- package/transpiled/Query.js +2 -12
- package/transpiled/Query.js.map +1 -1
- package/transpiled/RTD/Endpoint.d.ts +2 -3
- package/ui/dist/_app/immutable/assets/0.Cu0AnR_8.css +2 -0
- package/ui/dist/_app/immutable/assets/2.BghF56l_.css +1 -0
- package/ui/dist/_app/immutable/assets/ui.C8aD6zzF.css +1 -0
- package/ui/dist/_app/immutable/chunks/B8GvXrmq.js +1 -0
- package/ui/dist/_app/immutable/chunks/BVDJTrf4.js +3 -0
- package/ui/dist/_app/immutable/chunks/D6q28_Ok.js +86 -0
- package/ui/dist/_app/immutable/chunks/{aLpTDmOc.js → DVlaUfVU.js} +1 -1
- package/ui/dist/_app/immutable/chunks/DpB73ZB6.js +6 -0
- package/ui/dist/_app/immutable/entry/app.CTava8yn.js +2 -0
- package/ui/dist/_app/immutable/entry/start.yWN0gSLA.js +1 -0
- package/ui/dist/_app/immutable/nodes/0.HKRDBYrC.js +1 -0
- package/ui/dist/_app/immutable/nodes/1.CLa0ydOi.js +1 -0
- package/ui/dist/_app/immutable/nodes/2.C9Kaym8C.js +8 -0
- package/ui/dist/_app/immutable/nodes/3.C1X4_rXZ.js +1 -0
- package/ui/dist/_app/immutable/nodes/4.DdzDIi9E.js +1 -0
- package/ui/dist/_app/immutable/nodes/5.DpbmCMdw.js +1 -0
- package/ui/dist/_app/version.json +1 -1
- package/ui/dist/index.html +12 -12
- package/CHANGELOG.md +0 -42
- package/components/identity.bans/tsconfig.tsbuildinfo +0 -1
- package/components/identity.basic/source/lib/credentials.test.ts +0 -18
- package/components/identity.basic/tsconfig.tsbuildinfo +0 -1
- package/components/identity.clients/source/lib/canonical.test.ts +0 -43
- package/components/identity.clients/source/lib/cimd.test.ts +0 -122
- package/components/identity.clients/source/lib/redirect.test.ts +0 -47
- package/components/identity.clients/tsconfig.tsbuildinfo +0 -1
- package/components/identity.credentials/source/list.test.ts +0 -70
- package/components/identity.credentials/tsconfig.tsbuildinfo +0 -1
- package/components/identity.federation/source/lib/discovery.test.ts +0 -60
- package/components/identity.federation/source/list.test.ts +0 -41
- package/components/identity.federation/tsconfig.tsbuildinfo +0 -1
- package/components/identity.grants/tsconfig.tsbuildinfo +0 -1
- package/components/identity.keys/tsconfig.tsbuildinfo +0 -1
- package/components/identity.otp/tsconfig.tsbuildinfo +0 -1
- package/components/identity.passkeys/source/errors.test.ts +0 -34
- package/components/identity.passkeys/source/webauthn.test.ts +0 -26
- package/components/identity.passkeys/tsconfig.tsbuildinfo +0 -1
- package/components/identity.roles/tsconfig.tsbuildinfo +0 -1
- package/components/identity.tokens/source/authenticate.test.ts +0 -112
- package/components/identity.tokens/source/decrypt.test.ts +0 -216
- package/components/identity.tokens/source/encrypt.test.ts +0 -150
- package/components/identity.tokens/source/issue.test.ts +0 -73
- package/components/identity.tokens/source/lib/form.test.ts +0 -25
- package/components/identity.tokens/source/lib/paseto.test.ts +0 -62
- package/components/identity.tokens/tsconfig.tsbuildinfo +0 -1
- package/context.toa.yaml +0 -31
- package/cucumber.mjs +0 -7
- package/documentation/.assets/ia3-dark.jpg +0 -0
- package/documentation/.assets/ia3-light.jpg +0 -0
- package/documentation/.assets/overview-dark.jpg +0 -0
- package/documentation/.assets/overview-light.jpg +0 -0
- package/documentation/.assets/role-scopes-dark.jpg +0 -0
- package/documentation/.assets/role-scopes-light.jpg +0 -0
- package/documentation/.assets/rtd-dark.jpg +0 -0
- package/documentation/.assets/rtd-light.jpg +0 -0
- package/documentation/access.md +0 -350
- package/documentation/authorities.md +0 -51
- package/documentation/cache.md +0 -72
- package/documentation/components.md +0 -472
- package/documentation/consent.md +0 -101
- package/documentation/credentials.md +0 -88
- package/documentation/dev.md +0 -30
- package/documentation/discovery.md +0 -81
- package/documentation/flow.md +0 -44
- package/documentation/help.md +0 -122
- package/documentation/identity.md +0 -304
- package/documentation/introspection.md +0 -123
- package/documentation/io.md +0 -167
- package/documentation/ip.md +0 -24
- package/documentation/map.md +0 -123
- package/documentation/mcp.md +0 -183
- package/documentation/notes/desync.jpg +0 -0
- package/documentation/notes/peers.md +0 -59
- package/documentation/notes/sse.md +0 -71
- package/documentation/notes/throttling.md +0 -122
- package/documentation/oauth.md +0 -180
- package/documentation/octets.md +0 -334
- package/documentation/passkeys.md +0 -11
- package/documentation/protocol.md +0 -120
- package/documentation/query.md +0 -324
- package/documentation/require.md +0 -15
- package/documentation/rpc.md +0 -154
- package/documentation/tracing.md +0 -70
- package/documentation/tree.md +0 -199
- package/features/access.feature +0 -596
- package/features/annotation.feature +0 -32
- package/features/auth.assert.feature +0 -55
- package/features/auth.bearer.feature +0 -120
- package/features/auth.claims.feature +0 -171
- package/features/auth.incept.feature +0 -166
- package/features/auth.input.feature +0 -59
- package/features/authorities.basic.feature +0 -141
- package/features/authorities.feature +0 -71
- package/features/authorities.federation.feature +0 -100
- package/features/authorities.tokens.feature +0 -117
- package/features/body.feature +0 -76
- package/features/cache.feature +0 -368
- package/features/configuration.feature +0 -206
- package/features/cors.feature +0 -127
- package/features/credentials.feature +0 -106
- package/features/debug.feature +0 -34
- package/features/dev.feature +0 -90
- package/features/directives.feature +0 -61
- package/features/discovery.feature +0 -213
- package/features/discovery.ui.feature +0 -213
- package/features/dynamic.feature +0 -192
- package/features/errors.feature +0 -258
- package/features/etag.feature +0 -239
- package/features/flow.feature +0 -148
- package/features/help.feature +0 -512
- package/features/identity.bans.feature +0 -200
- package/features/identity.basic.feature +0 -666
- package/features/identity.feature +0 -240
- package/features/identity.federation.feature +0 -396
- package/features/identity.otp.feature +0 -142
- package/features/identity.roles.feature +0 -568
- package/features/identity.tokens.custom.feature +0 -430
- package/features/identity.tokens.feature +0 -131
- package/features/interruptions.feature +0 -20
- package/features/introspection.feature +0 -565
- package/features/introspection.map.feature +0 -108
- package/features/io.feature +0 -204
- package/features/io.throttle.feature +0 -166
- package/features/map.feature +0 -360
- package/features/mcp.feature +0 -753
- package/features/methods.feature +0 -48
- package/features/oauth.clients.feature +0 -195
- package/features/oauth.discovery.feature +0 -164
- package/features/oauth.grants.feature +0 -301
- package/features/octets.cloudinary.feature +0 -233
- package/features/octets.download.feature +0 -194
- package/features/octets.entries.feature +0 -83
- package/features/octets.feature +0 -306
- package/features/octets.head.feature +0 -40
- package/features/octets.location.feature +0 -83
- package/features/octets.meta.feature +0 -117
- package/features/octets.workflows.feature +0 -565
- package/features/passkeys.feature +0 -66
- package/features/probes.feature +0 -18
- package/features/query.feature +0 -389
- package/features/realtime.feature +0 -34
- package/features/require.feature +0 -66
- package/features/response.feature +0 -103
- package/features/routes.feature +0 -224
- package/features/rpc.feature +0 -429
- package/features/server.feature +0 -21
- package/features/site/_app/immutable/asset.js +0 -1
- package/features/site/favicon.ico +0 -0
- package/features/site/index.html +0 -10
- package/features/steps/.env.example +0 -5
- package/features/steps/Captures.ts +0 -20
- package/features/steps/Cloudinary.ts +0 -12
- package/features/steps/Common.ts +0 -38
- package/features/steps/Components.ts +0 -115
- package/features/steps/Database.ts +0 -106
- package/features/steps/Gateway.ts +0 -239
- package/features/steps/HTTP.ts +0 -96
- package/features/steps/IDP.ts +0 -361
- package/features/steps/Identity.ts +0 -54
- package/features/steps/OTP.ts +0 -42
- package/features/steps/Parameters.ts +0 -162
- package/features/steps/Probe.ts +0 -38
- package/features/steps/Realtime.ts +0 -175
- package/features/steps/Workspace.ts +0 -48
- package/features/steps/components/audit/manifest.toa.yaml +0 -20
- package/features/steps/components/audit/operations/record.js +0 -5
- package/features/steps/components/echo/manifest.toa.yaml +0 -59
- package/features/steps/components/echo/operations/affect.js +0 -3
- package/features/steps/components/echo/operations/compute.js +0 -3
- package/features/steps/components/echo/operations/echo.js +0 -3
- package/features/steps/components/echo/operations/error.js +0 -7
- package/features/steps/components/echo/operations/identity.js +0 -3
- package/features/steps/components/echo/operations/parameters.js +0 -3
- package/features/steps/components/echo/operations/ping.js +0 -3
- package/features/steps/components/echo/operations/unwrap.js +0 -3
- package/features/steps/components/echo.beacon/manifest.toa.yaml +0 -2
- package/features/steps/components/echo.beacon/operations/hello.js +0 -3
- package/features/steps/components/greeter/manifest.toa.yaml +0 -5
- package/features/steps/components/greeter/operations/greet.js +0 -3
- package/features/steps/components/notify/manifest.toa.yaml +0 -20
- package/features/steps/components/notify/operations/send.js +0 -5
- package/features/steps/components/octets.tester/manifest.toa.yaml +0 -73
- package/features/steps/components/octets.tester/operations/authority.js +0 -3
- package/features/steps/components/octets.tester/operations/bar.js +0 -9
- package/features/steps/components/octets.tester/operations/baz.js +0 -9
- package/features/steps/components/octets.tester/operations/concat.js +0 -5
- package/features/steps/components/octets.tester/operations/echo.js +0 -5
- package/features/steps/components/octets.tester/operations/err.js +0 -14
- package/features/steps/components/octets.tester/operations/foo.js +0 -5
- package/features/steps/components/octets.tester/operations/id.js +0 -5
- package/features/steps/components/octets.tester/operations/identity.js +0 -5
- package/features/steps/components/octets.tester/operations/lenna.png +0 -0
- package/features/steps/components/octets.tester/operations/redirect.js +0 -17
- package/features/steps/components/octets.tester/operations/yex.js +0 -14
- package/features/steps/components/octets.tester/operations/yield.js +0 -11
- package/features/steps/components/orders/manifest.toa.yaml +0 -30
- package/features/steps/components/orders/operations/create.js +0 -7
- package/features/steps/components/pots/manifest.toa.yaml +0 -91
- package/features/steps/components/pots/migrations/0002-indexes.yaml +0 -4
- package/features/steps/components/pricing/manifest.toa.yaml +0 -13
- package/features/steps/components/pricing/operations/quote.js +0 -3
- package/features/steps/components/sequences/manifest.toa.yaml +0 -11
- package/features/steps/components/sequences/operations/numbers.js +0 -5
- package/features/steps/components/sequences/operations/tokens.js +0 -14
- package/features/steps/components/users/manifest.toa.yaml +0 -30
- package/features/steps/components/users/operations/create.js +0 -11
- package/features/steps/components/users.properties/manifest.toa.yaml +0 -22
- package/features/steps/map.ts +0 -30
- package/features/steps/tsconfig.json +0 -9
- package/features/streams.feature +0 -35
- package/features/timestamps.feature +0 -41
- package/features/timing.feature +0 -49
- package/features/tracing.feature +0 -123
- package/source/Branch.test.ts +0 -40
- package/source/Branch.ts +0 -44
- package/source/Composition.ts +0 -51
- package/source/Context.ts +0 -11
- package/source/Directive.test.ts +0 -199
- package/source/Directive.ts +0 -248
- package/source/Discovery/Explorer.ts +0 -34
- package/source/Discovery/Site.test.ts +0 -147
- package/source/Discovery/Site.ts +0 -202
- package/source/Discovery/index.ts +0 -3
- package/source/Discovery/tree.test.ts +0 -175
- package/source/Discovery/tree.ts +0 -77
- package/source/Discovery/trunk.ts +0 -33
- package/source/Endpoint.test.ts +0 -67
- package/source/Endpoint.ts +0 -157
- package/source/Factory.ts +0 -42
- package/source/Gateway.ts +0 -390
- package/source/HTTP/Context.ts +0 -143
- package/source/HTTP/Probe.ts +0 -99
- package/source/HTTP/Server.ts +0 -435
- package/source/HTTP/Timing.ts +0 -14
- package/source/HTTP/address.test.ts +0 -28
- package/source/HTTP/address.ts +0 -16
- package/source/HTTP/exceptions.ts +0 -99
- package/source/HTTP/formats/form.ts +0 -21
- package/source/HTTP/formats/index.ts +0 -36
- package/source/HTTP/formats/json.ts +0 -14
- package/source/HTTP/formats/msgpack.ts +0 -14
- package/source/HTTP/formats/text.ts +0 -10
- package/source/HTTP/formats/yaml.test.ts +0 -22
- package/source/HTTP/formats/yaml.ts +0 -40
- package/source/HTTP/index.ts +0 -6
- package/source/HTTP/messages.test.ts +0 -196
- package/source/HTTP/messages.ts +0 -186
- package/source/HTTP/types.ts +0 -39
- package/source/Interception.ts +0 -37
- package/source/Introspection.ts +0 -179
- package/source/MCP/Server.ts +0 -335
- package/source/MCP/discover.ts +0 -51
- package/source/MCP/errors.ts +0 -80
- package/source/MCP/index.ts +0 -1
- package/source/MCP/schema.test.ts +0 -91
- package/source/MCP/schema.ts +0 -94
- package/source/MCP/tools.ts +0 -144
- package/source/MCP/types.ts +0 -84
- package/source/Mapping.ts +0 -101
- package/source/Query.test.ts +0 -54
- package/source/Query.ts +0 -277
- package/source/RPC/Context.ts +0 -75
- package/source/RPC/Dispatcher.ts +0 -150
- package/source/RPC/errors.test.ts +0 -77
- package/source/RPC/errors.ts +0 -82
- package/source/RPC/index.ts +0 -1
- package/source/RPC/names.test.ts +0 -141
- package/source/RPC/names.ts +0 -176
- package/source/RPC/types.ts +0 -34
- package/source/RTD/Context.ts +0 -16
- package/source/RTD/Directives.ts +0 -126
- package/source/RTD/Endpoint.ts +0 -27
- package/source/RTD/Match.ts +0 -11
- package/source/RTD/Method.ts +0 -39
- package/source/RTD/Node.ts +0 -169
- package/source/RTD/Route.ts +0 -93
- package/source/RTD/Tree.ts +0 -137
- package/source/RTD/expiration.test.ts +0 -81
- package/source/RTD/factory.ts +0 -105
- package/source/RTD/index.ts +0 -8
- package/source/RTD/segment.test.ts +0 -35
- package/source/RTD/segment.ts +0 -51
- package/source/RTD/syntax/index.ts +0 -1
- package/source/RTD/walk.test.ts +0 -147
- package/source/Remotes.test.ts +0 -79
- package/source/Remotes.ts +0 -39
- package/source/Tenant.ts +0 -73
- package/source/directives/auth/Anonymous.test.ts +0 -70
- package/source/directives/auth/Anonymous.ts +0 -36
- package/source/directives/auth/Anyone.ts +0 -23
- package/source/directives/auth/Assert.ts +0 -43
- package/source/directives/auth/Authorization.test.ts +0 -24
- package/source/directives/auth/Authorization.ts +0 -388
- package/source/directives/auth/Delegate.test.ts +0 -36
- package/source/directives/auth/Delegate.ts +0 -54
- package/source/directives/auth/Echo.ts +0 -24
- package/source/directives/auth/Federation.ts +0 -104
- package/source/directives/auth/Id.ts +0 -37
- package/source/directives/auth/Incept.ts +0 -117
- package/source/directives/auth/Input.ts +0 -92
- package/source/directives/auth/Role.test.ts +0 -147
- package/source/directives/auth/Role.ts +0 -99
- package/source/directives/auth/Rule.ts +0 -59
- package/source/directives/auth/Scheme.ts +0 -31
- package/source/directives/auth/create.ts +0 -11
- package/source/directives/auth/index.ts +0 -3
- package/source/directives/auth/schemes.test.ts +0 -18
- package/source/directives/auth/schemes.ts +0 -39
- package/source/directives/auth/split.ts +0 -14
- package/source/directives/auth/types.ts +0 -75
- package/source/directives/cache/Cache.ts +0 -92
- package/source/directives/cache/Control.ts +0 -81
- package/source/directives/cache/Exact.ts +0 -7
- package/source/directives/cache/etag.ts +0 -38
- package/source/directives/cache/index.ts +0 -3
- package/source/directives/cache/types.ts +0 -9
- package/source/directives/cors/CORS.test.ts +0 -75
- package/source/directives/cors/CORS.ts +0 -88
- package/source/directives/cors/index.ts +0 -3
- package/source/directives/dev/Development.ts +0 -41
- package/source/directives/dev/Faulty.ts +0 -31
- package/source/directives/dev/Sleep.ts +0 -53
- package/source/directives/dev/Stub.ts +0 -14
- package/source/directives/dev/Throw.ts +0 -14
- package/source/directives/dev/index.ts +0 -3
- package/source/directives/dev/types.ts +0 -5
- package/source/directives/flow/Compose.ts +0 -98
- package/source/directives/flow/Fetch.ts +0 -86
- package/source/directives/flow/Flow.ts +0 -43
- package/source/directives/flow/index.ts +0 -3
- package/source/directives/flow/types.ts +0 -7
- package/source/directives/help/Family.ts +0 -122
- package/source/directives/help/Help.test.ts +0 -227
- package/source/directives/help/Help.ts +0 -47
- package/source/directives/help/Parameters.ts +0 -47
- package/source/directives/help/described.ts +0 -57
- package/source/directives/help/index.ts +0 -45
- package/source/directives/index.ts +0 -33
- package/source/directives/io/Directive.ts +0 -17
- package/source/directives/io/IO.ts +0 -118
- package/source/directives/io/Input.ts +0 -55
- package/source/directives/io/Message.ts +0 -1
- package/source/directives/io/Output.ts +0 -81
- package/source/directives/io/Status.test.ts +0 -88
- package/source/directives/io/Status.ts +0 -47
- package/source/directives/io/Throttle.ts +0 -30
- package/source/directives/io/index.ts +0 -3
- package/source/directives/io/lib/throttle/Configuration.test.ts +0 -72
- package/source/directives/io/lib/throttle/Configuration.ts +0 -68
- package/source/directives/io/lib/throttle/Keys.ts +0 -53
- package/source/directives/io/lib/throttle/Quotas.test.ts +0 -411
- package/source/directives/io/lib/throttle/Quotas.ts +0 -190
- package/source/directives/io/lib/throttle/Sync.test.ts +0 -163
- package/source/directives/io/lib/throttle/Sync.ts +0 -93
- package/source/directives/io/lib/throttle/Warning.test.ts +0 -32
- package/source/directives/io/lib/throttle/Warning.ts +0 -29
- package/source/directives/io/lib/throttle/components/Component.ts +0 -7
- package/source/directives/io/lib/throttle/components/IP.ts +0 -30
- package/source/directives/io/lib/throttle/components/Identity.ts +0 -19
- package/source/directives/io/lib/throttle/components/Path.ts +0 -8
- package/source/directives/io/lib/throttle/components/Route.ts +0 -19
- package/source/directives/io/lib/throttle/components/Segment.ts +0 -19
- package/source/directives/io/lib/throttle/components/index.ts +0 -19
- package/source/directives/io/lib/throttle/conditions/Condition.ts +0 -5
- package/source/directives/io/lib/throttle/conditions/Status.ts +0 -17
- package/source/directives/io/lib/throttle/conditions/index.ts +0 -11
- package/source/directives/io/lib/throttle/index.ts +0 -4
- package/source/directives/io/schemas.test.ts +0 -40
- package/source/directives/io/schemas.ts +0 -16
- package/source/directives/map/Authority.ts +0 -15
- package/source/directives/map/Buffer.ts +0 -15
- package/source/directives/map/Claims.ts +0 -63
- package/source/directives/map/Directive.ts +0 -4
- package/source/directives/map/Headers.ts +0 -60
- package/source/directives/map/Language.ts +0 -45
- package/source/directives/map/Languages.ts +0 -17
- package/source/directives/map/Map.ts +0 -85
- package/source/directives/map/Mapping.ts +0 -45
- package/source/directives/map/Properties.ts +0 -15
- package/source/directives/map/Segments.ts +0 -52
- package/source/directives/map/index.ts +0 -3
- package/source/directives/mcp/MCP.ts +0 -33
- package/source/directives/mcp/Tool.test.ts +0 -56
- package/source/directives/mcp/Tool.ts +0 -32
- package/source/directives/mcp/index.ts +0 -6
- package/source/directives/oauth/Discovery.ts +0 -66
- package/source/directives/oauth/documents.ts +0 -110
- package/source/directives/oauth/index.ts +0 -3
- package/source/directives/octets/Context.ts +0 -23
- package/source/directives/octets/Delete.ts +0 -96
- package/source/directives/octets/Directive.ts +0 -21
- package/source/directives/octets/Get.ts +0 -88
- package/source/directives/octets/Octets.ts +0 -82
- package/source/directives/octets/Put.ts +0 -186
- package/source/directives/octets/Workflow.ts +0 -60
- package/source/directives/octets/bytes.test.ts +0 -33
- package/source/directives/octets/bytes.ts +0 -18
- package/source/directives/octets/index.ts +0 -3
- package/source/directives/octets/schemas.test.ts +0 -20
- package/source/directives/octets/schemas.ts +0 -15
- package/source/directives/octets/types.ts +0 -9
- package/source/directives/octets/workflows/Execution.ts +0 -130
- package/source/directives/octets/workflows/Workflow.ts +0 -51
- package/source/directives/octets/workflows/index.ts +0 -1
- package/source/directives/require/Directive.ts +0 -5
- package/source/directives/require/Headers.ts +0 -19
- package/source/directives/require/Require.ts +0 -27
- package/source/directives/require/index.ts +0 -3
- package/source/discovery.ts +0 -1
- package/source/exceptions.ts +0 -47
- package/source/index.ts +0 -10
- package/source/io.ts +0 -4
- package/source/octets.d.ts +0 -17
- package/source/root.ts +0 -59
- package/source/service.ts +0 -95
- package/source/userland.ts +0 -47
- package/tsconfig.json +0 -13
- package/tsconfig.tsbuildinfo +0 -1
- package/ui/dist/_app/immutable/assets/0.Bl7vLmIK.css +0 -2
- package/ui/dist/_app/immutable/assets/2.BC0-Jhqu.css +0 -1
- package/ui/dist/_app/immutable/chunks/BaWe3aOV.js +0 -1
- package/ui/dist/_app/immutable/chunks/DjIYL2zC.js +0 -3
- package/ui/dist/_app/immutable/chunks/GZTfV0ks.js +0 -6
- package/ui/dist/_app/immutable/entry/app.D5v4JoUx.js +0 -2
- package/ui/dist/_app/immutable/entry/start.CWxFoIyZ.js +0 -1
- package/ui/dist/_app/immutable/nodes/0.DIh5T_5-.js +0 -1
- package/ui/dist/_app/immutable/nodes/1.CY-bFzHC.js +0 -1
- package/ui/dist/_app/immutable/nodes/2.6Ubd1ItY.js +0 -14
|
@@ -1,54 +0,0 @@
|
|
|
1
|
-
import { BadRequest } from '../../HTTP/index.js'
|
|
2
|
-
import { take } from '../../Introspection.js'
|
|
3
|
-
import { Role } from './Role.js'
|
|
4
|
-
import type { Introspection } from '../../Introspection.js'
|
|
5
|
-
import type { Context, Directive, Identity } from './types.js'
|
|
6
|
-
import type { Component } from '@toa.io/core'
|
|
7
|
-
|
|
8
|
-
export class Delegate implements Directive {
|
|
9
|
-
private readonly property: string
|
|
10
|
-
private readonly discovery: Promise<Component>
|
|
11
|
-
|
|
12
|
-
public constructor(property: string, discovery: Promise<Component>) {
|
|
13
|
-
this.property = property
|
|
14
|
-
this.discovery = discovery
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
public async authorize(identity: Identity | null, context: Context): Promise<boolean> {
|
|
18
|
-
if (identity === null) return false
|
|
19
|
-
|
|
20
|
-
identity.roles ??= await Role.get(identity, this.discovery)
|
|
21
|
-
context.pipelines.body.push((body) => this.embed(body, identity))
|
|
22
|
-
|
|
23
|
-
return true
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
/** It admits whoever there is, and embedding the identity is the request's business. */
|
|
27
|
-
public admits(identity: Identity | null): boolean {
|
|
28
|
-
return identity !== null
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
/**
|
|
32
|
-
* It takes an identity, and the property it embeds is that identity's — so a caller has
|
|
33
|
-
* nothing to put there.
|
|
34
|
-
*/
|
|
35
|
-
public describe(introspection: Introspection): Introspection {
|
|
36
|
-
take(introspection, this.property)
|
|
37
|
-
|
|
38
|
-
return { ...introspection, authenticated: true }
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
private embed(body: unknown, identity: Identity): Record<string, unknown> {
|
|
42
|
-
if (body === undefined) body = {}
|
|
43
|
-
|
|
44
|
-
check(body)
|
|
45
|
-
body[this.property] = structuredClone(identity)
|
|
46
|
-
|
|
47
|
-
return body
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
function check(body: unknown): asserts body is Record<string, unknown> {
|
|
52
|
-
if (typeof body !== 'object' || body === null)
|
|
53
|
-
throw new BadRequest('Invalid request body')
|
|
54
|
-
}
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
import { create } from './create.js'
|
|
2
|
-
import type { OutgoingMessage } from '../../HTTP/index.js'
|
|
3
|
-
import type { Directive, Identity, Context } from './types.js'
|
|
4
|
-
|
|
5
|
-
export class Echo implements Directive {
|
|
6
|
-
public authorize(identity: Identity | null, context: Context): boolean {
|
|
7
|
-
if (identity === null && 'authorization' in context.request.headers) return false
|
|
8
|
-
|
|
9
|
-
context.identity ??= create()
|
|
10
|
-
|
|
11
|
-
return true
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
/** What `authorize` answers, without inventing the identity it would go on to invent. */
|
|
15
|
-
public admits(identity: Identity | null, context: Context): boolean {
|
|
16
|
-
return !(identity === null && 'authorization' in context.request.headers)
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
public reply(context: Context): OutgoingMessage {
|
|
20
|
-
const body = context.identity!
|
|
21
|
-
|
|
22
|
-
return body.scheme === null ? { status: 201, body } : { body }
|
|
23
|
-
}
|
|
24
|
-
}
|
|
@@ -1,104 +0,0 @@
|
|
|
1
|
-
import assert from 'node:assert'
|
|
2
|
-
import type { Directive, Identity, Context } from './types.js'
|
|
3
|
-
import type { Introspection } from '../../Introspection.js'
|
|
4
|
-
import type { Parameter } from '../../RTD/index.js'
|
|
5
|
-
|
|
6
|
-
export class Federation implements Directive {
|
|
7
|
-
private readonly matchers: Array<[keyof Claims, Matcher]>
|
|
8
|
-
|
|
9
|
-
public constructor(options: Options) {
|
|
10
|
-
this.matchers = (Object.entries(options) as Array<[keyof Claims, string]>).map(
|
|
11
|
-
([key, value]) => [key, toMatcher(value)]
|
|
12
|
-
)
|
|
13
|
-
|
|
14
|
-
assert.ok(
|
|
15
|
-
this.matchers.length > 0,
|
|
16
|
-
'`auth:claims` requires at least one property defined'
|
|
17
|
-
)
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
/** Which claims it takes needs the request; that it takes an identity does not. */
|
|
21
|
-
public admits(identity: Identity | null): boolean | undefined {
|
|
22
|
-
return identity === null ? false : undefined
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
/** Which claims is the application's business; that it takes an identity is the caller's. */
|
|
26
|
-
public describe(introspection: Introspection): Introspection {
|
|
27
|
-
return { ...introspection, authenticated: true }
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
public authorize(
|
|
31
|
-
identity: Identity | null,
|
|
32
|
-
context: Context,
|
|
33
|
-
parameters: Parameter[]
|
|
34
|
-
): boolean {
|
|
35
|
-
if (identity === null || !('claims' in identity)) return false
|
|
36
|
-
|
|
37
|
-
const claims = (identity as FederatedIdentity).claims
|
|
38
|
-
|
|
39
|
-
for (const [key, match] of this.matchers)
|
|
40
|
-
if (!match(claims[key], context, parameters)) return false
|
|
41
|
-
|
|
42
|
-
return true
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
function toMatcher(expression: string): Matcher {
|
|
47
|
-
if (expression.startsWith(':')) {
|
|
48
|
-
const key = expression.slice(1) as 'authority'
|
|
49
|
-
|
|
50
|
-
if (key === 'authority') return (value, context) => matches(value, context[key])
|
|
51
|
-
|
|
52
|
-
if (key === 'domain')
|
|
53
|
-
return (value, context) => {
|
|
54
|
-
return Array.isArray(value)
|
|
55
|
-
? value.some((iss) => codomain(iss, context))
|
|
56
|
-
: codomain(value, context)
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
throw new Error('Unknown `auth:claims` syntax: ' + expression)
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
if (expression.startsWith('/:')) {
|
|
63
|
-
const name = expression.slice(2)
|
|
64
|
-
|
|
65
|
-
return (value, _, parameters) =>
|
|
66
|
-
parameters.some(
|
|
67
|
-
(parameter) => parameter.name === name && matches(value, parameter.value)
|
|
68
|
-
)
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
return (value) => matches(value, expression)
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
function matches(value: string | string[], reference: string): boolean {
|
|
75
|
-
return Array.isArray(value) ? value.includes(reference) : value === reference
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
function codomain(iss: string, context: Context): boolean {
|
|
79
|
-
const hostname = new URL(iss).hostname
|
|
80
|
-
const dot = hostname.indexOf('.')
|
|
81
|
-
const basename = dot === -1 ? hostname : hostname.slice(dot)
|
|
82
|
-
|
|
83
|
-
return context.authority.slice(-basename.length) === basename
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
type Matcher = (
|
|
87
|
-
value: string | string[],
|
|
88
|
-
context: Context,
|
|
89
|
-
parameters: Parameter[]
|
|
90
|
-
) => boolean
|
|
91
|
-
|
|
92
|
-
interface Claims {
|
|
93
|
-
iss: string
|
|
94
|
-
sub: string
|
|
95
|
-
aud: string | string[]
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
interface Options extends Partial<Claims> {
|
|
99
|
-
iss: string
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
interface FederatedIdentity extends Identity {
|
|
103
|
-
claims: Claims
|
|
104
|
-
}
|
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
import { type Parameter } from '../../RTD/index.js'
|
|
2
|
-
import { type Directive, type Identity } from './types.js'
|
|
3
|
-
import type { Introspection } from '../../Introspection.js'
|
|
4
|
-
|
|
5
|
-
export class Id implements Directive {
|
|
6
|
-
private readonly parameter: string
|
|
7
|
-
|
|
8
|
-
public constructor(parameter: string) {
|
|
9
|
-
this.parameter = parameter
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
/**
|
|
13
|
-
* Whether it is *this* identity's cannot be told from a description, which has no route
|
|
14
|
-
* variable to read — but that there must be an identity at all can, and a caller with
|
|
15
|
-
* none is refused whatever the value would have been.
|
|
16
|
-
*/
|
|
17
|
-
public admits(identity: Identity | null): boolean | undefined {
|
|
18
|
-
return identity === null ? false : undefined
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
/** Reaching it is being the identity it is about, which is what `private` says. */
|
|
22
|
-
public describe(introspection: Introspection): Introspection {
|
|
23
|
-
return { ...introspection, private: true }
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
public authorize(
|
|
27
|
-
identity: Identity | null,
|
|
28
|
-
_: unknown,
|
|
29
|
-
parameters: Parameter[]
|
|
30
|
-
): boolean {
|
|
31
|
-
if (identity === null) return false
|
|
32
|
-
|
|
33
|
-
const parameter = parameters.find((parameter) => parameter.name === this.parameter)
|
|
34
|
-
|
|
35
|
-
return parameter?.value === identity.id
|
|
36
|
-
}
|
|
37
|
-
}
|
|
@@ -1,117 +0,0 @@
|
|
|
1
|
-
import assert from 'node:assert'
|
|
2
|
-
import { console } from 'openspan'
|
|
3
|
-
import * as http from '../../HTTP/index.js'
|
|
4
|
-
import { split } from './split.js'
|
|
5
|
-
import { create } from './create.js'
|
|
6
|
-
import { INCEPTION, UNKNOWN, providers as providersOf } from './schemes.js'
|
|
7
|
-
import { Role } from './Role.js'
|
|
8
|
-
import type { Component } from '@toa.io/core'
|
|
9
|
-
import type { Maybe } from '@toa.io/core/types'
|
|
10
|
-
import type { Directive, Discovery, Identity, Context, Components, Ban } from './types.js'
|
|
11
|
-
|
|
12
|
-
export class Incept implements Directive {
|
|
13
|
-
private static readonly components: Components = {}
|
|
14
|
-
private static discovery: Discovery
|
|
15
|
-
private static bans: Component | null = null
|
|
16
|
-
|
|
17
|
-
private readonly property: string | null
|
|
18
|
-
|
|
19
|
-
public constructor(property: string, discovery: Discovery) {
|
|
20
|
-
assert.ok(
|
|
21
|
-
property === null || typeof property === 'string',
|
|
22
|
-
'`auth:incept` value must be a string or null'
|
|
23
|
-
)
|
|
24
|
-
|
|
25
|
-
this.property = property
|
|
26
|
-
Incept.discovery ??= discovery
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
public static async incept(context: Context, id: string): Promise<Identity> {
|
|
30
|
-
const [scheme, credentials] = split(context.request.headers.authorization!)
|
|
31
|
-
const candidates = providersOf(scheme)
|
|
32
|
-
|
|
33
|
-
if (candidates === undefined)
|
|
34
|
-
throw new http.BadRequest('Authentication scheme is not supported')
|
|
35
|
-
|
|
36
|
-
// a scheme several providers claim is incepted by the one that incepts; `Bearer`
|
|
37
|
-
// carries an access token this gateway issued, and an identity cannot be incepted
|
|
38
|
-
// from a credential it would itself have to exist to hold
|
|
39
|
-
const provider = candidates.find((candidate) => INCEPTION.includes(candidate))
|
|
40
|
-
|
|
41
|
-
if (provider === undefined) throw new http.Unauthorized()
|
|
42
|
-
|
|
43
|
-
Incept.bans ??= await Incept.discovery.bans
|
|
44
|
-
|
|
45
|
-
const ban = await Incept.bans.invoke<Ban>('observe', { query: { id } })
|
|
46
|
-
|
|
47
|
-
if (ban.banned) throw new http.Unauthorized()
|
|
48
|
-
|
|
49
|
-
Incept.components[provider] ??= await Incept.discovery[provider]
|
|
50
|
-
|
|
51
|
-
const identity = await Incept.components[provider]!.invoke<Maybe<Identity>>(
|
|
52
|
-
'incept',
|
|
53
|
-
{
|
|
54
|
-
input: {
|
|
55
|
-
scheme,
|
|
56
|
-
authority: context.authority,
|
|
57
|
-
id,
|
|
58
|
-
credentials
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
)
|
|
62
|
-
|
|
63
|
-
if (identity instanceof Error) throw new http.UnprocessableEntity(identity)
|
|
64
|
-
|
|
65
|
-
identity.scheme = scheme
|
|
66
|
-
|
|
67
|
-
// the roles are read where the token is minted: an Identity incepted as the principal
|
|
68
|
-
// has one already
|
|
69
|
-
return identity
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
/** Credentials that were rejected for any reason but being unknown are not incepted. */
|
|
73
|
-
public static acceptable(context: Context): boolean {
|
|
74
|
-
return (
|
|
75
|
-
context.request.headers.authorization === undefined || context.rejection === UNKNOWN
|
|
76
|
-
)
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
public authorize(identity: Identity | null, context: Context): boolean {
|
|
80
|
-
return identity === null && Incept.acceptable(context)
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
public reply(context: Context): http.OutgoingMessage | null {
|
|
84
|
-
if (this.property !== null) return null
|
|
85
|
-
|
|
86
|
-
const body = create(context.request.headers.authorization)
|
|
87
|
-
|
|
88
|
-
return { body }
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
public async settle(context: Context, response: http.OutgoingMessage): Promise<void> {
|
|
92
|
-
const id = response.body?.[this.property ?? 'id']
|
|
93
|
-
|
|
94
|
-
if (id === undefined) {
|
|
95
|
-
console.debug('Inception skipped: response does not contain expected property', {
|
|
96
|
-
property: this.property,
|
|
97
|
-
response
|
|
98
|
-
})
|
|
99
|
-
|
|
100
|
-
return
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
assert(
|
|
104
|
-
typeof id === 'string',
|
|
105
|
-
`Response body property "${this.property}" expected to be a string`
|
|
106
|
-
)
|
|
107
|
-
|
|
108
|
-
if (context.request.headers.authorization !== undefined)
|
|
109
|
-
context.identity = await Incept.incept(context, id)
|
|
110
|
-
else {
|
|
111
|
-
const identity = { id, scheme: null, refresh: true }
|
|
112
|
-
const roles = await Role.get(identity, Incept.discovery.roles)
|
|
113
|
-
|
|
114
|
-
context.identity = { ...identity, roles }
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
}
|
|
@@ -1,92 +0,0 @@
|
|
|
1
|
-
import { Forbidden } from '../../HTTP/index.js'
|
|
2
|
-
import type { Parameter } from '../../RTD/index.js'
|
|
3
|
-
import type { Context, Directive, Identity, Create } from './types.js'
|
|
4
|
-
|
|
5
|
-
export class Input implements Directive {
|
|
6
|
-
public priority = 0
|
|
7
|
-
private readonly statements: Statement[] = []
|
|
8
|
-
|
|
9
|
-
public constructor(declarations: Declaration[], create: Create) {
|
|
10
|
-
this.statements = declarations.map(
|
|
11
|
-
(declaration) => new Statement(declaration, create)
|
|
12
|
-
)
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
/** It admits nobody: it says what a body may carry, not who may send one. */
|
|
16
|
-
public admits(): boolean {
|
|
17
|
-
return false
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
public async authorize(
|
|
21
|
-
identity: Identity | null,
|
|
22
|
-
context: Context,
|
|
23
|
-
parameters: Parameter[]
|
|
24
|
-
): Promise<boolean> {
|
|
25
|
-
context.pipelines.body.push(async (body) =>
|
|
26
|
-
this.check(identity, context, parameters, body)
|
|
27
|
-
)
|
|
28
|
-
|
|
29
|
-
return false
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
// eslint-disable-next-line max-params
|
|
33
|
-
private async check(
|
|
34
|
-
identity: Identity | null,
|
|
35
|
-
context: Context,
|
|
36
|
-
parameters: Parameter[],
|
|
37
|
-
body: unknown
|
|
38
|
-
): Promise<unknown> {
|
|
39
|
-
if (body === undefined || body === null || body.constructor !== Object) return body
|
|
40
|
-
|
|
41
|
-
const settled = await Promise.allSettled(
|
|
42
|
-
this.statements.map(async (statement) =>
|
|
43
|
-
statement.check(identity, context, parameters, body as Body)
|
|
44
|
-
)
|
|
45
|
-
)
|
|
46
|
-
|
|
47
|
-
for (const result of settled) if (result.status === 'rejected') throw result.reason
|
|
48
|
-
|
|
49
|
-
return body
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
class Statement {
|
|
54
|
-
private readonly properties: string[]
|
|
55
|
-
private readonly directives: Directive[] = []
|
|
56
|
-
|
|
57
|
-
public constructor({ prop, ...directives }: Declaration, create: Create) {
|
|
58
|
-
this.properties = typeof prop === 'string' ? [prop] : prop
|
|
59
|
-
|
|
60
|
-
for (const [name, value] of Object.entries(directives)) {
|
|
61
|
-
const directive = create(name, value)
|
|
62
|
-
|
|
63
|
-
this.directives.push(directive)
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
// eslint-disable-next-line max-params
|
|
68
|
-
public async check(
|
|
69
|
-
identity: Identity | null,
|
|
70
|
-
context: Context,
|
|
71
|
-
parameters: Parameter[],
|
|
72
|
-
body: Body
|
|
73
|
-
): Promise<void> {
|
|
74
|
-
const match = this.properties.some((property) => property in body)
|
|
75
|
-
|
|
76
|
-
if (!match) return
|
|
77
|
-
|
|
78
|
-
for (const directive of this.directives) {
|
|
79
|
-
const authorized = await directive.authorize(identity, context, parameters)
|
|
80
|
-
|
|
81
|
-
if (!authorized) throw new Forbidden('Input property is not authorized')
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
export interface Declaration {
|
|
87
|
-
[key: Exclude<string, 'prop'>]: unknown
|
|
88
|
-
|
|
89
|
-
prop: string | string[]
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
type Body = Record<string, unknown>
|
|
@@ -1,147 +0,0 @@
|
|
|
1
|
-
import { it, beforeEach, mock } from 'node:test'
|
|
2
|
-
import assert from 'node:assert/strict'
|
|
3
|
-
import { isDeepStrictEqual } from 'node:util'
|
|
4
|
-
|
|
5
|
-
import { type Component } from '@toa.io/core'
|
|
6
|
-
import { generate } from 'randomstring'
|
|
7
|
-
import { Role } from './Role.js'
|
|
8
|
-
import { type Identity } from './types.js'
|
|
9
|
-
import type { Parameter } from '../../RTD/index.js'
|
|
10
|
-
|
|
11
|
-
const remote = {
|
|
12
|
-
invoke: mock.fn()
|
|
13
|
-
} as unknown as Component
|
|
14
|
-
|
|
15
|
-
const discovery = Promise.resolve(remote)
|
|
16
|
-
|
|
17
|
-
beforeEach(() => {
|
|
18
|
-
resetCalls()
|
|
19
|
-
})
|
|
20
|
-
|
|
21
|
-
it('should return false if not matched', async () => {
|
|
22
|
-
const roles = ['admin', 'user']
|
|
23
|
-
const directive = new Role(roles, discovery)
|
|
24
|
-
|
|
25
|
-
const identity: Identity = {
|
|
26
|
-
id: generate(),
|
|
27
|
-
scheme: '',
|
|
28
|
-
refresh: false
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
remote.invoke.mock.mockImplementationOnce(async () => ['guest'])
|
|
32
|
-
|
|
33
|
-
const result = await directive.authorize(identity, undefined, [])
|
|
34
|
-
|
|
35
|
-
assert.strictEqual(result, false)
|
|
36
|
-
|
|
37
|
-
assert.ok(
|
|
38
|
-
remote.invoke.mock.calls.some(
|
|
39
|
-
(call: any) =>
|
|
40
|
-
call.arguments.length === 2 &&
|
|
41
|
-
isDeepStrictEqual(call.arguments[0], 'list') &&
|
|
42
|
-
isDeepStrictEqual(call.arguments[1], {
|
|
43
|
-
query: {
|
|
44
|
-
criteria: `identity=="${identity.id}"`,
|
|
45
|
-
limit: 1024
|
|
46
|
-
}
|
|
47
|
-
})
|
|
48
|
-
)
|
|
49
|
-
)
|
|
50
|
-
})
|
|
51
|
-
|
|
52
|
-
it('should return true on exact match', async () => {
|
|
53
|
-
const result = await match(['admin', 'user'], ['user'])
|
|
54
|
-
|
|
55
|
-
assert.strictEqual(result, true)
|
|
56
|
-
})
|
|
57
|
-
|
|
58
|
-
it('should return true on scope match', async () => {
|
|
59
|
-
const result = await match(['system:identity:roles'], ['system'])
|
|
60
|
-
|
|
61
|
-
assert.strictEqual(result, true)
|
|
62
|
-
})
|
|
63
|
-
|
|
64
|
-
it('should return false on scope mismatch', async () => {
|
|
65
|
-
const result = await match(['system:identity'], ['system:identity:roles'])
|
|
66
|
-
|
|
67
|
-
assert.strictEqual(result, false)
|
|
68
|
-
})
|
|
69
|
-
|
|
70
|
-
it('should return false on non-scope substring match', async () => {
|
|
71
|
-
const result = await match(['system:identity'], ['system:iden'])
|
|
72
|
-
|
|
73
|
-
assert.strictEqual(result, false)
|
|
74
|
-
})
|
|
75
|
-
|
|
76
|
-
it('should return true on match with parameters', async () => {
|
|
77
|
-
const result = await match(
|
|
78
|
-
['app:{org}:reviews'],
|
|
79
|
-
['app:29e54ae1:reviews'],
|
|
80
|
-
[
|
|
81
|
-
{
|
|
82
|
-
name: 'org',
|
|
83
|
-
value: '29e54ae1'
|
|
84
|
-
}
|
|
85
|
-
]
|
|
86
|
-
)
|
|
87
|
-
|
|
88
|
-
assert.strictEqual(result, true)
|
|
89
|
-
})
|
|
90
|
-
|
|
91
|
-
it('should return true on match with parameters', async () => {
|
|
92
|
-
const result = await match(
|
|
93
|
-
['app:{org}:reviews'],
|
|
94
|
-
['app:29e54ae1:reviews'],
|
|
95
|
-
[
|
|
96
|
-
{
|
|
97
|
-
name: 'org',
|
|
98
|
-
value: '29e54ae1'
|
|
99
|
-
}
|
|
100
|
-
]
|
|
101
|
-
)
|
|
102
|
-
|
|
103
|
-
assert.strictEqual(result, true)
|
|
104
|
-
})
|
|
105
|
-
|
|
106
|
-
it('should return false on mismatch with parameters', async () => {
|
|
107
|
-
const result = await match(
|
|
108
|
-
['app:{org}:reviews'],
|
|
109
|
-
['app:29e54ae1:reviews'],
|
|
110
|
-
[
|
|
111
|
-
{
|
|
112
|
-
name: 'org',
|
|
113
|
-
value: '88584c9b'
|
|
114
|
-
}
|
|
115
|
-
]
|
|
116
|
-
)
|
|
117
|
-
|
|
118
|
-
assert.strictEqual(result, false)
|
|
119
|
-
})
|
|
120
|
-
|
|
121
|
-
async function match(
|
|
122
|
-
expected: string[],
|
|
123
|
-
actual: string[],
|
|
124
|
-
parameters: Parameter[] = []
|
|
125
|
-
): Promise<boolean> {
|
|
126
|
-
const directive = new Role(expected, discovery)
|
|
127
|
-
|
|
128
|
-
const identity: Identity = {
|
|
129
|
-
id: generate(),
|
|
130
|
-
scheme: '',
|
|
131
|
-
refresh: false
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
remote.invoke.mock.mockImplementationOnce(async () => actual)
|
|
135
|
-
|
|
136
|
-
return await directive.authorize(identity, undefined, parameters)
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
function resetCalls(target = [remote, discovery], seen = new Set()) {
|
|
140
|
-
if (target === null || typeof target !== 'object' || seen.has(target)) return
|
|
141
|
-
|
|
142
|
-
seen.add(target)
|
|
143
|
-
|
|
144
|
-
for (const value of Object.values(target))
|
|
145
|
-
if (typeof value === 'function' && value.mock !== undefined) value.mock.resetCalls()
|
|
146
|
-
else resetCalls(value, seen)
|
|
147
|
-
}
|
|
@@ -1,99 +0,0 @@
|
|
|
1
|
-
import assert from 'node:assert'
|
|
2
|
-
import { quote } from '@toa.io/generic'
|
|
3
|
-
import { type Component } from '@toa.io/core'
|
|
4
|
-
import type { Query } from '@toa.io/core/types'
|
|
5
|
-
import { type Directive, type Identity } from './types.js'
|
|
6
|
-
import type { Parameter } from '../../RTD/index.js'
|
|
7
|
-
import type { Introspection } from '../../Introspection.js'
|
|
8
|
-
|
|
9
|
-
export class Role implements Directive {
|
|
10
|
-
public static remote: Component | null = null
|
|
11
|
-
private readonly roles: string[]
|
|
12
|
-
private readonly discovery: Promise<Component>
|
|
13
|
-
private readonly dynamic: boolean
|
|
14
|
-
|
|
15
|
-
public constructor(roles: string | string[], discovery: Promise<Component>) {
|
|
16
|
-
this.roles = typeof roles === 'string' ? [roles] : roles
|
|
17
|
-
this.discovery = discovery
|
|
18
|
-
this.dynamic = this.roles.some((role) => role.includes('{'))
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
public static async get(
|
|
22
|
-
identity: Identity,
|
|
23
|
-
discovery: Promise<Component>
|
|
24
|
-
): Promise<string[]> {
|
|
25
|
-
this.remote ??= await discovery
|
|
26
|
-
|
|
27
|
-
const query: Query = {
|
|
28
|
-
criteria: `identity==${quote(identity.id)}`,
|
|
29
|
-
limit: 1024
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
return await this.remote.invoke('list', { query })
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
/**
|
|
36
|
-
* Reaching it takes a role, which is what `protected` says. A role of the `system` scope
|
|
37
|
-
* says so besides: what it guards is the machinery an application runs on rather than
|
|
38
|
-
* anything it serves, and a reader has no business being offered it as one.
|
|
39
|
-
*/
|
|
40
|
-
public describe(introspection: Introspection): Introspection {
|
|
41
|
-
const system = this.roles.some(
|
|
42
|
-
(role) => role === SYSTEM || role.startsWith(SYSTEM + ':')
|
|
43
|
-
)
|
|
44
|
-
|
|
45
|
-
return { ...introspection, protected: true, ...(system ? { system: true } : {}) }
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
public async authorize(
|
|
49
|
-
identity: Identity | null,
|
|
50
|
-
_: unknown,
|
|
51
|
-
parameters: Parameter[]
|
|
52
|
-
): Promise<boolean> {
|
|
53
|
-
if (identity === null) return false
|
|
54
|
-
|
|
55
|
-
identity.roles ??= await Role.get(identity, this.discovery)
|
|
56
|
-
|
|
57
|
-
return this.match(identity.roles, parameters)
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
/** A role naming a route variable cannot be told from a description, which has no values. */
|
|
61
|
-
public async admits(identity: Identity | null): Promise<boolean | undefined> {
|
|
62
|
-
if (this.dynamic) return undefined
|
|
63
|
-
|
|
64
|
-
if (identity === null) return false
|
|
65
|
-
|
|
66
|
-
identity.roles ??= await Role.get(identity, this.discovery)
|
|
67
|
-
|
|
68
|
-
return this.match(identity.roles, [])
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
private match(roles: string[], parameters: Parameter[]): boolean {
|
|
72
|
-
const required = this.dynamic ? this.substitute(parameters) : this.roles
|
|
73
|
-
|
|
74
|
-
for (const role of roles) {
|
|
75
|
-
const ok = required.some(
|
|
76
|
-
(expected) => expected === role || expected.startsWith(role + ':')
|
|
77
|
-
)
|
|
78
|
-
|
|
79
|
-
if (ok) return true
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
return false
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
private substitute(parameters: Parameter[]): string[] {
|
|
86
|
-
return this.roles.map((role) =>
|
|
87
|
-
role.replaceAll(/{(\w+)}/g, (_, key) => {
|
|
88
|
-
const value = parameters.find((parameter) => parameter.name === key)?.value
|
|
89
|
-
|
|
90
|
-
assert.ok(value !== undefined, `Role '${role}' requires '${key}' route parameter`)
|
|
91
|
-
|
|
92
|
-
return value
|
|
93
|
-
})
|
|
94
|
-
)
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
/** The scope of what an application runs on, as opposed to what it serves. */
|
|
99
|
-
const SYSTEM = 'system'
|