@toa.io/extensions.exposition 1.0.0-alpha.4 → 1.0.0-alpha.40
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/context.toa.yaml +2 -2
- package/components/identity.bans/manifest.toa.yaml +15 -7
- package/components/identity.bans/operations/transit.d.ts +14 -0
- package/components/identity.bans/operations/transit.js +11 -0
- package/components/identity.bans/operations/transit.js.map +1 -0
- package/components/identity.bans/operations/tsconfig.tsbuildinfo +1 -0
- package/components/identity.bans/source/transit.ts +21 -0
- package/components/identity.bans/tsconfig.json +9 -0
- package/components/identity.basic/manifest.toa.yaml +22 -9
- package/components/identity.basic/operations/authenticate.d.ts +5 -1
- package/components/identity.basic/operations/authenticate.js +5 -2
- package/components/identity.basic/operations/authenticate.js.map +1 -1
- package/components/identity.basic/operations/incept.d.ts +12 -0
- package/components/identity.basic/operations/incept.js +26 -0
- package/components/identity.basic/operations/incept.js.map +1 -0
- package/components/identity.basic/operations/transit.d.ts +4 -4
- package/components/identity.basic/operations/transit.js +5 -3
- package/components/identity.basic/operations/transit.js.map +1 -1
- package/components/identity.basic/operations/tsconfig.tsbuildinfo +1 -1
- package/components/identity.basic/operations/types.d.ts +8 -4
- package/components/identity.basic/source/authenticate.ts +16 -5
- package/components/identity.basic/source/incept.ts +38 -0
- package/components/identity.basic/source/transit.ts +8 -6
- package/components/identity.basic/source/types.ts +8 -4
- package/components/identity.federation/manifest.toa.yaml +28 -22
- package/components/identity.federation/operations/authenticate.d.ts +2 -2
- package/components/identity.federation/operations/authenticate.js +3 -10
- package/components/identity.federation/operations/authenticate.js.map +1 -1
- package/components/identity.federation/operations/incept.d.ts +11 -0
- package/components/identity.federation/operations/{create.js → incept.js} +6 -7
- package/components/identity.federation/operations/incept.js.map +1 -0
- package/components/identity.federation/operations/lib/jwt.d.ts +4 -5
- package/components/identity.federation/operations/lib/jwt.js +3 -3
- package/components/identity.federation/operations/lib/jwt.js.map +1 -1
- package/components/identity.federation/operations/tsconfig.tsbuildinfo +1 -1
- package/components/identity.federation/operations/types/configuration.d.ts +14 -0
- package/components/identity.federation/operations/types/configuration.js +3 -0
- package/components/identity.federation/operations/types/configuration.js.map +1 -0
- package/components/identity.federation/operations/{types.d.ts → types/context.d.ts} +13 -6
- package/components/identity.federation/operations/types/context.js +3 -0
- package/components/identity.federation/operations/types/context.js.map +1 -0
- package/components/identity.federation/operations/types/entity.d.ts +6 -0
- package/components/identity.federation/operations/{types.js → types/entity.js} +1 -1
- package/components/identity.federation/operations/types/entity.js.map +1 -0
- package/components/identity.federation/operations/types/index.d.ts +3 -0
- package/components/identity.federation/operations/types/index.js +20 -0
- package/components/identity.federation/operations/types/index.js.map +1 -0
- package/components/identity.federation/source/authenticate.ts +5 -18
- package/components/identity.federation/source/{create.ts → incept.ts} +10 -9
- package/components/identity.federation/source/lib/jwt.test.ts +2 -2
- package/components/identity.federation/source/lib/jwt.ts +7 -8
- package/components/identity.federation/source/types/configuration.ts +15 -0
- package/components/identity.federation/source/{types.ts → types/context.ts} +15 -5
- package/components/identity.federation/source/types/entity.ts +6 -0
- package/components/identity.federation/source/types/index.ts +3 -0
- package/components/identity.federation/tsconfig.json +2 -2
- package/components/identity.roles/manifest.toa.yaml +18 -6
- package/components/identity.roles/operations/grant.d.ts +10 -0
- package/components/identity.roles/operations/grant.js +21 -0
- package/components/identity.roles/operations/grant.js.map +1 -0
- package/components/identity.roles/operations/lib/Entity.d.ts +5 -0
- package/components/identity.roles/operations/lib/Entity.js +3 -0
- package/components/identity.roles/operations/lib/Entity.js.map +1 -0
- package/components/identity.roles/operations/list.d.ts +1 -4
- package/components/identity.roles/operations/list.js.map +1 -1
- package/components/identity.roles/operations/principal.d.ts +4 -6
- package/components/identity.roles/operations/principal.js +6 -1
- package/components/identity.roles/operations/principal.js.map +1 -1
- package/components/identity.roles/operations/tsconfig.tsbuildinfo +1 -1
- package/components/identity.roles/source/grant.ts +32 -0
- package/components/identity.roles/source/lib/Entity.ts +5 -0
- package/components/identity.roles/source/list.ts +2 -4
- package/components/identity.roles/source/principal.ts +10 -8
- package/components/identity.tokens/manifest.toa.yaml +19 -5
- package/components/identity.tokens/operations/authenticate.d.ts +2 -2
- package/components/identity.tokens/operations/authenticate.js +10 -4
- package/components/identity.tokens/operations/authenticate.js.map +1 -1
- package/components/identity.tokens/operations/decrypt.js +1 -0
- package/components/identity.tokens/operations/decrypt.js.map +1 -1
- package/components/identity.tokens/operations/encrypt.js +5 -1
- package/components/identity.tokens/operations/encrypt.js.map +1 -1
- package/components/identity.tokens/operations/tsconfig.tsbuildinfo +1 -1
- package/components/identity.tokens/operations/types.d.ts +8 -2
- package/components/identity.tokens/receivers/identity.bans.created.js +3 -0
- package/components/identity.tokens/source/authenticate.test.ts +11 -4
- package/components/identity.tokens/source/authenticate.ts +12 -5
- package/components/identity.tokens/source/decrypt.test.ts +5 -3
- package/components/identity.tokens/source/decrypt.ts +9 -8
- package/components/identity.tokens/source/encrypt.test.ts +26 -2
- package/components/identity.tokens/source/encrypt.ts +5 -1
- package/components/identity.tokens/source/types.ts +9 -2
- package/components/octets.storage/manifest.toa.yaml +0 -7
- package/documentation/access.md +27 -16
- package/documentation/authorities.md +53 -0
- package/documentation/cache.md +8 -1
- package/documentation/components.md +47 -22
- package/documentation/identity.md +17 -22
- package/documentation/io.md +56 -0
- package/documentation/protocol.md +3 -0
- package/documentation/query.md +17 -11
- package/documentation/require.md +15 -0
- package/documentation/tree.md +22 -4
- package/documentation/vary.md +14 -14
- package/features/access.feature +89 -47
- package/features/annotation.feature +2 -0
- package/features/authorities.basic.feature +141 -0
- package/features/authorities.feature +32 -0
- package/features/authorities.federation.feature +99 -0
- package/features/authorities.tokens.feature +118 -0
- package/features/body.feature +4 -0
- package/features/cache.feature +112 -5
- package/features/cors.feature +7 -2
- package/features/debug.feature +34 -0
- package/features/directives.feature +5 -0
- package/features/dynamic.feature +18 -7
- package/features/errors.feature +18 -4
- package/features/etag.feature +18 -1
- package/features/identity.bans.feature +137 -0
- package/features/identity.basic.feature +142 -19
- package/features/identity.feature +7 -2
- package/features/identity.federation.feature +67 -14
- package/features/identity.roles.feature +220 -4
- package/features/identity.tokens.feature +57 -4
- package/features/io.feature +205 -0
- package/features/octets.entries.feature +10 -0
- package/features/octets.feature +60 -64
- package/features/octets.meta.feature +7 -3
- package/features/octets.workflows.feature +14 -0
- package/features/probes.feature +14 -0
- package/features/{queries.feature → query.feature} +50 -3
- package/features/require.feature +67 -0
- package/features/response.feature +12 -3
- package/features/routes.feature +25 -12
- package/features/steps/Database.ts +17 -10
- package/features/steps/Gateway.ts +23 -6
- package/features/steps/IdP.ts +28 -23
- package/features/steps/components/echo/manifest.toa.yaml +5 -1
- package/features/steps/components/echo/operations/identity.js +7 -0
- package/features/steps/components/pots/manifest.toa.yaml +2 -0
- package/features/steps/components/users.properties/manifest.toa.yaml +2 -1
- package/features/streams.feature +1 -0
- package/features/timing.feature +27 -1
- package/features/vary.feature +105 -3
- package/package.json +12 -11
- package/readme.md +19 -14
- package/schemas/annotation.cos.yaml +1 -1
- package/schemas/io/input.cos.yaml +3 -0
- package/schemas/io/message.cos.yaml +5 -0
- package/schemas/io/output.cos.yaml +5 -0
- package/source/Annotation.ts +3 -3
- package/source/Context.ts +6 -4
- package/source/Directive.test.ts +4 -4
- package/source/Directive.ts +11 -38
- package/source/Endpoint.ts +43 -8
- package/source/Factory.ts +11 -7
- package/source/Gateway.ts +16 -44
- package/source/HTTP/Context.ts +24 -2
- package/source/HTTP/Server.ts +56 -43
- package/source/HTTP/exceptions.ts +7 -1
- package/source/HTTP/messages.ts +1 -1
- package/source/Mapping.ts +6 -1
- package/source/Query.test.ts +1 -1
- package/source/Query.ts +35 -24
- package/source/RTD/Context.ts +7 -10
- package/source/RTD/Directives.ts +28 -4
- package/source/RTD/Endpoint.ts +6 -4
- package/source/RTD/Match.ts +2 -7
- package/source/RTD/Method.ts +7 -13
- package/source/RTD/Node.ts +13 -14
- package/source/RTD/Tree.ts +17 -16
- package/source/RTD/factory.ts +3 -6
- package/source/Tenant.ts +0 -8
- package/source/deployment.ts +32 -22
- package/source/directives/auth/Authorization.ts +38 -19
- package/source/directives/auth/Delegate.ts +42 -0
- package/source/directives/auth/Incept.ts +3 -2
- package/source/directives/auth/Role.test.ts +53 -6
- package/source/directives/auth/Role.ts +22 -14
- package/source/directives/auth/types.ts +1 -1
- package/source/directives/cache/Cache.ts +15 -8
- package/source/directives/cache/Control.ts +42 -16
- package/source/directives/cors/CORS.ts +13 -7
- package/source/directives/dev/Development.ts +4 -4
- package/source/directives/index.ts +6 -4
- package/source/directives/io/Directive.ts +11 -0
- package/source/directives/io/IO.ts +43 -0
- package/source/directives/io/Input.ts +50 -0
- package/source/directives/io/Message.ts +1 -0
- package/source/directives/io/Output.ts +69 -0
- package/source/directives/io/index.ts +3 -0
- package/source/directives/io/schemas.ts +12 -0
- package/source/directives/octets/Context.ts +4 -3
- package/source/directives/octets/Delete.ts +4 -2
- package/source/directives/octets/Directive.ts +10 -0
- package/source/directives/octets/Fetch.ts +4 -3
- package/source/directives/octets/List.ts +4 -2
- package/source/directives/octets/Octets.ts +6 -8
- package/source/directives/octets/Store.ts +12 -4
- package/source/directives/octets/Workflow.ts +10 -3
- package/source/directives/octets/types.ts +0 -7
- package/source/directives/require/Directive.ts +5 -0
- package/source/directives/require/Headers.ts +20 -0
- package/source/directives/require/Require.ts +28 -0
- package/source/directives/require/index.ts +3 -0
- package/source/directives/vary/Directive.ts +2 -1
- package/source/directives/vary/Embed.ts +14 -8
- package/source/directives/vary/Vary.ts +7 -5
- package/source/directives/vary/embeddings/Authority.ts +8 -0
- package/source/directives/vary/embeddings/Embedding.ts +2 -1
- package/source/directives/vary/embeddings/Header.ts +8 -6
- package/source/directives/vary/embeddings/Language.ts +1 -1
- package/source/directives/vary/embeddings/Parameter.ts +14 -0
- package/source/directives/vary/embeddings/index.ts +6 -4
- package/source/exceptions.ts +22 -11
- package/source/root.ts +5 -0
- package/source/schemas.ts +1 -1
- package/transpiled/Annotation.d.ts +3 -3
- package/transpiled/Context.d.ts +6 -4
- package/transpiled/Directive.d.ts +4 -17
- package/transpiled/Directive.js +4 -7
- package/transpiled/Directive.js.map +1 -1
- package/transpiled/Endpoint.d.ts +5 -3
- package/transpiled/Endpoint.js +30 -5
- package/transpiled/Endpoint.js.map +1 -1
- package/transpiled/Factory.js +9 -4
- package/transpiled/Factory.js.map +1 -1
- package/transpiled/Gateway.d.ts +1 -4
- package/transpiled/Gateway.js +10 -26
- package/transpiled/Gateway.js.map +1 -1
- package/transpiled/HTTP/Context.d.ts +8 -1
- package/transpiled/HTTP/Context.js +15 -2
- package/transpiled/HTTP/Context.js.map +1 -1
- package/transpiled/HTTP/Server.d.ts +13 -2
- package/transpiled/HTTP/Server.js +41 -35
- package/transpiled/HTTP/Server.js.map +1 -1
- package/transpiled/HTTP/exceptions.d.ts +4 -1
- package/transpiled/HTTP/exceptions.js +7 -1
- package/transpiled/HTTP/exceptions.js.map +1 -1
- package/transpiled/HTTP/messages.js +1 -1
- package/transpiled/HTTP/messages.js.map +1 -1
- package/transpiled/Mapping.js +4 -1
- package/transpiled/Mapping.js.map +1 -1
- package/transpiled/Query.d.ts +1 -0
- package/transpiled/Query.js +21 -20
- package/transpiled/Query.js.map +1 -1
- package/transpiled/RTD/Context.d.ts +7 -6
- package/transpiled/RTD/Directives.d.ts +19 -4
- package/transpiled/RTD/Endpoint.d.ts +6 -4
- package/transpiled/RTD/Match.d.ts +2 -4
- package/transpiled/RTD/Method.d.ts +7 -7
- package/transpiled/RTD/Method.js.map +1 -1
- package/transpiled/RTD/Node.d.ts +4 -6
- package/transpiled/RTD/Node.js +2 -1
- package/transpiled/RTD/Node.js.map +1 -1
- package/transpiled/RTD/Tree.d.ts +6 -6
- package/transpiled/RTD/Tree.js +4 -1
- package/transpiled/RTD/Tree.js.map +1 -1
- package/transpiled/RTD/factory.d.ts +2 -4
- package/transpiled/RTD/factory.js +1 -1
- package/transpiled/RTD/factory.js.map +1 -1
- package/transpiled/Tenant.d.ts +0 -1
- package/transpiled/Tenant.js +0 -6
- package/transpiled/Tenant.js.map +1 -1
- package/transpiled/deployment.d.ts +1 -1
- package/transpiled/deployment.js +28 -20
- package/transpiled/deployment.js.map +1 -1
- package/transpiled/directives/auth/Authorization.d.ts +2 -3
- package/transpiled/directives/auth/Authorization.js +26 -12
- package/transpiled/directives/auth/Authorization.js.map +1 -1
- package/transpiled/directives/auth/Delegate.d.ts +10 -0
- package/transpiled/directives/auth/Delegate.js +34 -0
- package/transpiled/directives/auth/Delegate.js.map +1 -0
- package/transpiled/directives/auth/Incept.js +3 -2
- package/transpiled/directives/auth/Incept.js.map +1 -1
- package/transpiled/directives/auth/Role.d.ts +4 -1
- package/transpiled/directives/auth/Role.js +20 -14
- package/transpiled/directives/auth/Role.js.map +1 -1
- package/transpiled/directives/cache/Cache.d.ts +5 -5
- package/transpiled/directives/cache/Cache.js +10 -4
- package/transpiled/directives/cache/Cache.js.map +1 -1
- package/transpiled/directives/cache/Control.d.ts +2 -1
- package/transpiled/directives/cache/Control.js +29 -12
- package/transpiled/directives/cache/Control.js.map +1 -1
- package/transpiled/directives/cors/CORS.d.ts +2 -3
- package/transpiled/directives/cors/CORS.js +13 -7
- package/transpiled/directives/cors/CORS.js.map +1 -1
- package/transpiled/directives/dev/Development.d.ts +3 -3
- package/transpiled/directives/dev/Development.js +1 -1
- package/transpiled/directives/dev/Development.js.map +1 -1
- package/transpiled/directives/index.d.ts +2 -2
- package/transpiled/directives/index.js +5 -3
- package/transpiled/directives/index.js.map +1 -1
- package/transpiled/directives/io/Directive.d.ts +8 -0
- package/transpiled/directives/io/Directive.js +3 -0
- package/transpiled/directives/io/Directive.js.map +1 -0
- package/transpiled/directives/io/IO.d.ts +9 -0
- package/transpiled/directives/io/IO.js +33 -0
- package/transpiled/directives/io/IO.js.map +1 -0
- package/transpiled/directives/io/Input.d.ts +11 -0
- package/transpiled/directives/{octets/Permute.js → io/Input.js} +33 -26
- package/transpiled/directives/io/Input.js.map +1 -0
- package/transpiled/directives/io/Message.d.ts +1 -0
- package/transpiled/directives/io/Message.js +3 -0
- package/transpiled/directives/io/Message.js.map +1 -0
- package/transpiled/directives/io/Output.d.ts +13 -0
- package/transpiled/directives/io/Output.js +76 -0
- package/transpiled/directives/io/Output.js.map +1 -0
- package/transpiled/directives/io/index.d.ts +2 -0
- package/transpiled/directives/io/index.js +6 -0
- package/transpiled/directives/io/index.js.map +1 -0
- package/transpiled/directives/io/schemas.d.ts +7 -0
- package/transpiled/directives/io/schemas.js +14 -0
- package/transpiled/directives/io/schemas.js.map +1 -0
- package/transpiled/directives/octets/Context.d.ts +3 -3
- package/transpiled/directives/octets/Context.js +4 -2
- package/transpiled/directives/octets/Context.js.map +1 -1
- package/transpiled/directives/octets/Delete.d.ts +3 -2
- package/transpiled/directives/octets/Delete.js +3 -1
- package/transpiled/directives/octets/Delete.js.map +1 -1
- package/transpiled/directives/octets/Directive.d.ts +8 -0
- package/transpiled/directives/octets/Directive.js +8 -0
- package/transpiled/directives/octets/Directive.js.map +1 -0
- package/transpiled/directives/octets/Fetch.d.ts +3 -2
- package/transpiled/directives/octets/Fetch.js +3 -1
- package/transpiled/directives/octets/Fetch.js.map +1 -1
- package/transpiled/directives/octets/List.d.ts +3 -2
- package/transpiled/directives/octets/List.js +3 -1
- package/transpiled/directives/octets/List.js.map +1 -1
- package/transpiled/directives/octets/Octets.d.ts +4 -4
- package/transpiled/directives/octets/Octets.js +2 -4
- package/transpiled/directives/octets/Octets.js.map +1 -1
- package/transpiled/directives/octets/Store.d.ts +3 -2
- package/transpiled/directives/octets/Store.js +10 -3
- package/transpiled/directives/octets/Store.js.map +1 -1
- package/transpiled/directives/octets/Workflow.d.ts +3 -2
- package/transpiled/directives/octets/Workflow.js +9 -2
- package/transpiled/directives/octets/Workflow.js.map +1 -1
- package/transpiled/directives/octets/types.d.ts +0 -5
- package/transpiled/directives/require/Directive.d.ts +4 -0
- package/transpiled/directives/require/Directive.js +3 -0
- package/transpiled/directives/require/Directive.js.map +1 -0
- package/transpiled/directives/require/Headers.d.ts +7 -0
- package/transpiled/directives/require/Headers.js +19 -0
- package/transpiled/directives/require/Headers.js.map +1 -0
- package/transpiled/directives/require/Require.d.ts +9 -0
- package/transpiled/directives/require/Require.js +27 -0
- package/transpiled/directives/require/Require.js.map +1 -0
- package/transpiled/directives/require/index.d.ts +2 -0
- package/transpiled/directives/require/index.js +6 -0
- package/transpiled/directives/require/index.js.map +1 -0
- package/transpiled/directives/vary/Directive.d.ts +2 -1
- package/transpiled/directives/vary/Embed.d.ts +2 -1
- package/transpiled/directives/vary/Embed.js +8 -6
- package/transpiled/directives/vary/Embed.js.map +1 -1
- package/transpiled/directives/vary/Vary.d.ts +3 -3
- package/transpiled/directives/vary/Vary.js +3 -3
- package/transpiled/directives/vary/Vary.js.map +1 -1
- package/transpiled/directives/vary/embeddings/Authority.d.ts +5 -0
- package/transpiled/directives/vary/embeddings/Authority.js +10 -0
- package/transpiled/directives/vary/embeddings/Authority.js.map +1 -0
- package/transpiled/directives/vary/embeddings/Embedding.d.ts +2 -1
- package/transpiled/directives/vary/embeddings/Header.js +8 -6
- package/transpiled/directives/vary/embeddings/Header.js.map +1 -1
- package/transpiled/directives/vary/embeddings/Language.js +1 -1
- package/transpiled/directives/vary/embeddings/Language.js.map +1 -1
- package/transpiled/directives/vary/embeddings/Parameter.d.ts +7 -0
- package/transpiled/directives/vary/embeddings/Parameter.js +14 -0
- package/transpiled/directives/vary/embeddings/Parameter.js.map +1 -0
- package/transpiled/directives/vary/embeddings/index.d.ts +2 -2
- package/transpiled/directives/vary/embeddings/index.js +8 -4
- package/transpiled/directives/vary/embeddings/index.js.map +1 -1
- package/transpiled/exceptions.d.ts +3 -2
- package/transpiled/exceptions.js +13 -7
- package/transpiled/exceptions.js.map +1 -1
- package/transpiled/root.js +5 -0
- package/transpiled/root.js.map +1 -1
- package/transpiled/schemas.d.ts +1 -1
- package/transpiled/schemas.js +2 -2
- package/transpiled/schemas.js.map +1 -1
- package/transpiled/tsconfig.tsbuildinfo +1 -1
- package/components/identity.basic/operations/create.d.ts +0 -10
- package/components/identity.basic/operations/create.js +0 -10
- package/components/identity.basic/operations/create.js.map +0 -1
- package/components/identity.basic/source/create.ts +0 -18
- package/components/identity.federation/operations/create.d.ts +0 -10
- package/components/identity.federation/operations/create.js.map +0 -1
- package/components/identity.federation/operations/schemas.d.ts +0 -59
- package/components/identity.federation/operations/schemas.js +0 -9
- package/components/identity.federation/operations/schemas.js.map +0 -1
- package/components/identity.federation/operations/types.js.map +0 -1
- package/components/identity.federation/source/schemas.ts +0 -61
- package/components/octets.storage/operations/permute.js +0 -7
- package/source/HTTP/Server.test.ts +0 -126
- package/source/directives/octets/Permute.ts +0 -43
- package/transpiled/directives/octets/Permute.d.ts +0 -10
- package/transpiled/directives/octets/Permute.js.map +0 -1
package/source/RTD/Node.ts
CHANGED
|
@@ -1,20 +1,15 @@
|
|
|
1
1
|
import { type Route } from './Route'
|
|
2
2
|
import { type Methods } from './Method'
|
|
3
3
|
import { type Match, type Parameter } from './Match'
|
|
4
|
-
import { type Directives } from './Directives'
|
|
5
|
-
import { type Endpoint } from './Endpoint'
|
|
6
4
|
|
|
7
|
-
export class Node
|
|
8
|
-
TEndpoint extends Endpoint<TEndpoint> = any,
|
|
9
|
-
TDirectives extends Directives<TDirectives> = any
|
|
10
|
-
> {
|
|
5
|
+
export class Node {
|
|
11
6
|
public intermediate: boolean
|
|
12
|
-
public methods: Methods
|
|
7
|
+
public methods: Methods
|
|
13
8
|
private readonly protected: boolean
|
|
14
9
|
private routes: Route[]
|
|
15
10
|
|
|
16
11
|
public constructor
|
|
17
|
-
(routes: Route[], methods: Methods
|
|
12
|
+
(routes: Route[], methods: Methods, properties: Properties) {
|
|
18
13
|
this.routes = routes
|
|
19
14
|
this.methods = methods
|
|
20
15
|
this.protected = properties.protected
|
|
@@ -34,26 +29,30 @@ export class Node<
|
|
|
34
29
|
return null
|
|
35
30
|
}
|
|
36
31
|
|
|
37
|
-
public merge (node: Node
|
|
32
|
+
public merge (node: Node): void {
|
|
38
33
|
this.intermediate = node.intermediate
|
|
39
34
|
|
|
40
|
-
if (!this.protected)
|
|
41
|
-
|
|
35
|
+
if (!this.protected)
|
|
36
|
+
this.replace(node)
|
|
37
|
+
else
|
|
38
|
+
this.append(node)
|
|
42
39
|
|
|
43
40
|
this.sort()
|
|
44
41
|
}
|
|
45
42
|
|
|
46
|
-
private replace (node: Node
|
|
43
|
+
private replace (node: Node): void {
|
|
47
44
|
const methods = Object.values(this.methods)
|
|
48
45
|
|
|
49
46
|
this.routes = node.routes
|
|
50
47
|
this.methods = node.methods
|
|
51
48
|
|
|
52
49
|
for (const method of methods)
|
|
53
|
-
void method.close()
|
|
50
|
+
void method.close()
|
|
51
|
+
|
|
52
|
+
// race condition is really unlikely
|
|
54
53
|
}
|
|
55
54
|
|
|
56
|
-
private append (node: Node
|
|
55
|
+
private append (node: Node): void {
|
|
57
56
|
for (const route of node.routes)
|
|
58
57
|
this.mergeRoute(route)
|
|
59
58
|
|
package/source/RTD/Tree.ts
CHANGED
|
@@ -1,32 +1,32 @@
|
|
|
1
|
-
import { type Node } from './Node'
|
|
2
1
|
import { createNode } from './factory'
|
|
3
2
|
import { fragment } from './segment'
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import
|
|
7
|
-
import
|
|
3
|
+
import type { Node } from './Node'
|
|
4
|
+
import type { Match } from './Match'
|
|
5
|
+
import type { Context } from './Context'
|
|
6
|
+
import type { DirectiveFactory } from './Directives'
|
|
7
|
+
import type { EndpointsFactory } from './Endpoint'
|
|
8
8
|
import type * as syntax from './syntax'
|
|
9
9
|
|
|
10
|
-
export class Tree
|
|
11
|
-
TEndpoint extends Endpoint<TEndpoint> = any,
|
|
12
|
-
TDirectives extends Directives<TDirectives> = any
|
|
13
|
-
> {
|
|
10
|
+
export class Tree {
|
|
14
11
|
private readonly root: syntax.Node
|
|
15
|
-
private readonly trunk: Node
|
|
16
|
-
private readonly endpoints: EndpointsFactory
|
|
17
|
-
private readonly directives:
|
|
12
|
+
private readonly trunk: Node
|
|
13
|
+
private readonly endpoints: EndpointsFactory
|
|
14
|
+
private readonly directives: DirectiveFactory
|
|
18
15
|
|
|
19
16
|
public constructor
|
|
20
|
-
(node: syntax.Node, endpoints: EndpointsFactory, directives:
|
|
17
|
+
(node: syntax.Node, endpoints: EndpointsFactory, directives: DirectiveFactory) {
|
|
21
18
|
this.endpoints = endpoints
|
|
22
19
|
this.directives = directives
|
|
23
20
|
this.trunk = this.createNode(node, PROTECTED)
|
|
24
21
|
this.root = node
|
|
25
22
|
}
|
|
26
23
|
|
|
27
|
-
public match (path: string): Match
|
|
24
|
+
public match (path: string): Match | null {
|
|
28
25
|
if (path === '/')
|
|
29
|
-
return {
|
|
26
|
+
return {
|
|
27
|
+
node: this.trunk,
|
|
28
|
+
parameters: []
|
|
29
|
+
}
|
|
30
30
|
|
|
31
31
|
const fragments = fragment(path)
|
|
32
32
|
|
|
@@ -39,7 +39,8 @@ export class Tree<
|
|
|
39
39
|
this.trunk.merge(branch)
|
|
40
40
|
}
|
|
41
41
|
|
|
42
|
-
private createNode
|
|
42
|
+
private createNode
|
|
43
|
+
(node: syntax.Node, protect: boolean, extension?: any): Node {
|
|
43
44
|
const context: Context = {
|
|
44
45
|
protected: protect,
|
|
45
46
|
endpoints: this.endpoints,
|
package/source/RTD/factory.ts
CHANGED
|
@@ -1,14 +1,11 @@
|
|
|
1
1
|
import { Node, type Properties } from './Node'
|
|
2
2
|
import { Route } from './Route'
|
|
3
|
-
import { type Context } from './Context'
|
|
4
3
|
import { segment } from './segment'
|
|
5
4
|
import { Method, type Methods } from './Method'
|
|
6
|
-
import {
|
|
7
|
-
import { type Directives } from './Directives'
|
|
5
|
+
import type { Context } from './Context'
|
|
8
6
|
import type * as syntax from './syntax'
|
|
9
7
|
|
|
10
|
-
export function createNode
|
|
11
|
-
(node: syntax.Node, context: Context): Node<TEndpoint, TDirectives> {
|
|
8
|
+
export function createNode (node: syntax.Node, context: Context): Node {
|
|
12
9
|
if (node.isolated === true)
|
|
13
10
|
context.directives.stack = node.directives
|
|
14
11
|
else
|
|
@@ -36,7 +33,7 @@ function createRoute (route: syntax.Route, context: Context): Route {
|
|
|
36
33
|
}
|
|
37
34
|
|
|
38
35
|
function createMethod (method: syntax.Method, context: Context): Method {
|
|
39
|
-
const stack =
|
|
36
|
+
const stack = method.directives.concat(context.directives.stack)
|
|
40
37
|
const directives = context.directives.factory.create(stack)
|
|
41
38
|
|
|
42
39
|
const endpoint = method.mapping?.endpoint === undefined
|
package/source/Tenant.ts
CHANGED
|
@@ -25,14 +25,6 @@ export class Tenant extends Connector {
|
|
|
25
25
|
public override async open (): Promise<void> {
|
|
26
26
|
await this.expose()
|
|
27
27
|
await this.broadcast.receive('ping', this.expose.bind(this))
|
|
28
|
-
|
|
29
|
-
console.info('Exposition Tenant for ' +
|
|
30
|
-
`'${this.branch.namespace}.${this.branch.component}' has started.`)
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
public override async dispose (): Promise<void> {
|
|
34
|
-
console.info('Exposition Tenant for ' +
|
|
35
|
-
`'${this.branch.namespace}.${this.branch.component}' has been stopped.`)
|
|
36
28
|
}
|
|
37
29
|
|
|
38
30
|
private async expose (): Promise<void> {
|
package/source/deployment.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import assert from 'node:assert'
|
|
1
2
|
import { type Dependency, type Service } from '@toa.io/operations'
|
|
2
3
|
import { encode } from '@toa.io/generic'
|
|
3
4
|
import { type Annotation } from './Annotation'
|
|
@@ -5,26 +6,29 @@ import * as schemas from './schemas'
|
|
|
5
6
|
import { shortcuts } from './Directive'
|
|
6
7
|
import { components } from './Composition'
|
|
7
8
|
import { parse } from './RTD/syntax'
|
|
9
|
+
import { DELAY, PORT } from './HTTP/Server'
|
|
10
|
+
|
|
11
|
+
export function deployment (_: unknown, annotation?: Annotation): Dependency {
|
|
12
|
+
assert.ok(annotation !== undefined, 'Exposition context annotation is required')
|
|
13
|
+
schemas.annotation.validate(annotation)
|
|
8
14
|
|
|
9
|
-
export function deployment (_: unknown, annotation: Annotation | undefined): Dependency {
|
|
10
15
|
const labels = components().labels
|
|
11
16
|
|
|
12
17
|
const service: Service = {
|
|
13
18
|
group: 'exposition',
|
|
14
19
|
name: 'gateway',
|
|
15
|
-
port:
|
|
20
|
+
port: PORT,
|
|
16
21
|
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
17
22
|
version: require('../package.json').version,
|
|
18
23
|
variables: [],
|
|
19
|
-
components: labels
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
class: annotation.class,
|
|
26
|
-
annotations: annotation.annotations
|
|
24
|
+
components: labels,
|
|
25
|
+
ingress: { hosts: [] },
|
|
26
|
+
probe: {
|
|
27
|
+
path: '/.ready',
|
|
28
|
+
port: PORT,
|
|
29
|
+
delay: DELAY
|
|
27
30
|
}
|
|
31
|
+
}
|
|
28
32
|
|
|
29
33
|
if (annotation?.['/'] !== undefined) {
|
|
30
34
|
const tree = parse(annotation['/'], shortcuts)
|
|
@@ -35,20 +39,26 @@ export function deployment (_: unknown, annotation: Annotation | undefined): Dep
|
|
|
35
39
|
})
|
|
36
40
|
}
|
|
37
41
|
|
|
38
|
-
|
|
39
|
-
service.variables.push({
|
|
40
|
-
name: 'TOA_EXPOSITION_DEBUG',
|
|
41
|
-
value: '1'
|
|
42
|
-
})
|
|
42
|
+
const { debug, trace, authorities } = annotation
|
|
43
43
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
44
|
+
service.ingress.hosts = Object.values(authorities)
|
|
45
|
+
service.ingress.class = annotation.class
|
|
46
|
+
service.ingress.annotations = annotation.annotations
|
|
47
|
+
|
|
48
|
+
const properties: Properties = { authorities }
|
|
49
49
|
|
|
50
|
-
if (
|
|
51
|
-
|
|
50
|
+
if (debug === true)
|
|
51
|
+
properties.debug = true
|
|
52
|
+
|
|
53
|
+
if (trace === true)
|
|
54
|
+
properties.trace = true
|
|
55
|
+
|
|
56
|
+
service.variables.push({
|
|
57
|
+
name: 'TOA_EXPOSITION_PROPERTIES',
|
|
58
|
+
value: encode(properties)
|
|
59
|
+
})
|
|
52
60
|
|
|
53
61
|
return { services: [service] }
|
|
54
62
|
}
|
|
63
|
+
|
|
64
|
+
type Properties = Pick<Annotation, 'authorities' | 'debug' | 'trace'>
|
|
@@ -7,14 +7,14 @@ import { Role } from './Role'
|
|
|
7
7
|
import { Rule } from './Rule'
|
|
8
8
|
import { Incept } from './Incept'
|
|
9
9
|
import { Echo } from './Echo'
|
|
10
|
-
import { split } from './split'
|
|
11
10
|
import { Scheme } from './Scheme'
|
|
11
|
+
import { Delegate } from './Delegate'
|
|
12
|
+
import { split } from './split'
|
|
12
13
|
import { PRIMARY, PROVIDERS } from './schemes'
|
|
13
14
|
import type { Output } from '../../io'
|
|
14
15
|
import type { Component } from '@toa.io/core'
|
|
15
16
|
import type { Remotes } from '../../Remotes'
|
|
16
|
-
import type {
|
|
17
|
-
import type { Parameter } from '../../RTD'
|
|
17
|
+
import type { Parameter, DirectiveFamily } from '../../RTD'
|
|
18
18
|
import type {
|
|
19
19
|
AuthenticationResult,
|
|
20
20
|
Ban,
|
|
@@ -27,7 +27,7 @@ import type {
|
|
|
27
27
|
Schemes
|
|
28
28
|
} from './types'
|
|
29
29
|
|
|
30
|
-
export class Authorization implements
|
|
30
|
+
export class Authorization implements DirectiveFamily<Directive, Extension> {
|
|
31
31
|
public readonly depends: string[] = ['Vary']
|
|
32
32
|
public readonly name: string = 'auth'
|
|
33
33
|
public readonly mandatory: boolean = true
|
|
@@ -38,10 +38,10 @@ export class Authorization implements Family<Directive, Extension> {
|
|
|
38
38
|
private bans: Component | null = null
|
|
39
39
|
|
|
40
40
|
public create (name: string, value: any, remotes: Remotes): Directive {
|
|
41
|
-
assert.ok(name in
|
|
42
|
-
`Directive '
|
|
41
|
+
assert.ok(name in constructors,
|
|
42
|
+
`Directive 'auth:${name}' is not implemented.`)
|
|
43
43
|
|
|
44
|
-
const Class =
|
|
44
|
+
const Class = constructors[name]
|
|
45
45
|
|
|
46
46
|
for (const name of REMOTES)
|
|
47
47
|
this.discovery[name] ??= remotes.discover('identity', name)
|
|
@@ -50,13 +50,22 @@ export class Authorization implements Family<Directive, Extension> {
|
|
|
50
50
|
Role, () => new Role(value as string | string[], this.discovery.roles),
|
|
51
51
|
Rule, () => new Rule(value as Record<string, string>, this.create.bind(this)),
|
|
52
52
|
Incept, () => new Incept(value as string, this.discovery),
|
|
53
|
+
Delegate, () => new Delegate(value as string, this.discovery.roles),
|
|
53
54
|
() => new Class(value))
|
|
54
55
|
}
|
|
55
56
|
|
|
56
57
|
public async preflight (directives: Directive[],
|
|
57
58
|
input: Input,
|
|
58
59
|
parameters: Parameter[]): Promise<Output> {
|
|
59
|
-
|
|
60
|
+
/**
|
|
61
|
+
* Some authentication scheme providers may create identity during authentication;
|
|
62
|
+
* therefore, we need to skip the authentication process if the Incept directive is present.
|
|
63
|
+
*
|
|
64
|
+
* If the provided credentials already exist,
|
|
65
|
+
* the inception will cause a unique constraint violation on the settle stage.
|
|
66
|
+
*/
|
|
67
|
+
const inception = directives.reduce((yes, directive) => yes || directive instanceof Incept, false)
|
|
68
|
+
const identity = inception ? null : await this.resolve(input.authority, input.request.headers.authorization)
|
|
60
69
|
|
|
61
70
|
input.identity = identity
|
|
62
71
|
|
|
@@ -80,25 +89,31 @@ export class Authorization implements Family<Directive, Extension> {
|
|
|
80
89
|
|
|
81
90
|
const identity = request.identity
|
|
82
91
|
|
|
83
|
-
if (identity === null)
|
|
92
|
+
if (identity === null)
|
|
93
|
+
return
|
|
84
94
|
|
|
85
|
-
if (identity.scheme === PRIMARY && !identity.refresh)
|
|
95
|
+
if (identity.scheme === PRIMARY && !identity.refresh)
|
|
96
|
+
return
|
|
86
97
|
|
|
87
98
|
// Role directive may have already set the value
|
|
88
|
-
if (identity.roles === undefined)
|
|
99
|
+
if (identity.roles === undefined)
|
|
100
|
+
await Role.set(identity, this.discovery.roles)
|
|
89
101
|
|
|
90
102
|
this.tokens ??= await this.discovery.tokens
|
|
91
103
|
|
|
92
|
-
const token = await this.tokens.invoke<string>('encrypt', {
|
|
93
|
-
|
|
104
|
+
const token = await this.tokens.invoke<string>('encrypt', {
|
|
105
|
+
input: { authority: request.authority, identity }
|
|
106
|
+
})
|
|
94
107
|
|
|
95
|
-
|
|
108
|
+
const authorization = `Token ${token}`
|
|
96
109
|
|
|
110
|
+
response.headers ??= new Headers()
|
|
97
111
|
response.headers.set('authorization', authorization)
|
|
98
112
|
}
|
|
99
113
|
|
|
100
|
-
private async resolve (authorization: string | undefined): Promise<Identity | null> {
|
|
101
|
-
if (authorization === undefined)
|
|
114
|
+
private async resolve (authority: string, authorization: string | undefined): Promise<Identity | null> {
|
|
115
|
+
if (authorization === undefined)
|
|
116
|
+
return null
|
|
102
117
|
|
|
103
118
|
const [scheme, credentials] = split(authorization)
|
|
104
119
|
const provider = PROVIDERS[scheme]
|
|
@@ -109,7 +124,10 @@ export class Authorization implements Family<Directive, Extension> {
|
|
|
109
124
|
this.schemes[scheme] ??= await this.discovery[provider]
|
|
110
125
|
|
|
111
126
|
const result = await this.schemes[scheme].invoke<AuthenticationResult>('authenticate', {
|
|
112
|
-
input:
|
|
127
|
+
input: {
|
|
128
|
+
authority,
|
|
129
|
+
credentials
|
|
130
|
+
}
|
|
113
131
|
})
|
|
114
132
|
|
|
115
133
|
if (result instanceof Error) return null
|
|
@@ -133,14 +151,15 @@ export class Authorization implements Family<Directive, Extension> {
|
|
|
133
151
|
}
|
|
134
152
|
}
|
|
135
153
|
|
|
136
|
-
const
|
|
154
|
+
const constructors: Record<string, new (value: any, argument?: any) => Directive> = {
|
|
137
155
|
anonymous: Anonymous,
|
|
138
156
|
id: Id,
|
|
139
157
|
role: Role,
|
|
140
158
|
rule: Rule,
|
|
141
159
|
incept: Incept,
|
|
142
160
|
scheme: Scheme,
|
|
143
|
-
echo: Echo
|
|
161
|
+
echo: Echo,
|
|
162
|
+
delegate: Delegate
|
|
144
163
|
}
|
|
145
164
|
|
|
146
165
|
const REMOTES: Remote[] = ['basic', 'federation', 'tokens', 'roles', 'bans']
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { BadRequest } from '../../HTTP'
|
|
2
|
+
import { type Directive, type Identity } from './types'
|
|
3
|
+
import { Role } from './Role'
|
|
4
|
+
import type { Component } from '@toa.io/core'
|
|
5
|
+
import type { Input } from '../../io'
|
|
6
|
+
|
|
7
|
+
export class Delegate implements Directive {
|
|
8
|
+
private readonly property: string
|
|
9
|
+
private readonly discovery: Promise<Component>
|
|
10
|
+
|
|
11
|
+
public constructor (property: string, discovery: Promise<Component>) {
|
|
12
|
+
this.property = property
|
|
13
|
+
this.discovery = discovery
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
public async authorize (identity: Identity | null, context: Input): Promise<boolean> {
|
|
17
|
+
if (identity === null)
|
|
18
|
+
return false
|
|
19
|
+
|
|
20
|
+
if (identity.roles === undefined)
|
|
21
|
+
await Role.set(identity, this.discovery)
|
|
22
|
+
|
|
23
|
+
context.pipelines.body.push((body) => this.embed(body, identity))
|
|
24
|
+
|
|
25
|
+
return true
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
private embed (body: unknown, identity: Identity): Record<string, unknown> {
|
|
29
|
+
if (body === undefined)
|
|
30
|
+
body = {}
|
|
31
|
+
|
|
32
|
+
check(body)
|
|
33
|
+
body[this.property] = structuredClone(identity)
|
|
34
|
+
|
|
35
|
+
return body
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function check (body: unknown): asserts body is Record<string, unknown> {
|
|
40
|
+
if (typeof body !== 'object' || body === null)
|
|
41
|
+
throw new BadRequest('Invalid request body')
|
|
42
|
+
}
|
|
@@ -31,15 +31,16 @@ export class Incept implements Directive {
|
|
|
31
31
|
this.schemes[scheme] ??= await this.discovery[provider]
|
|
32
32
|
|
|
33
33
|
const identity = await this.schemes[scheme]
|
|
34
|
-
.invoke<Maybe<Identity>>('
|
|
34
|
+
.invoke<Maybe<Identity>>('incept', {
|
|
35
35
|
input: {
|
|
36
|
+
authority: input.authority,
|
|
36
37
|
id,
|
|
37
38
|
credentials
|
|
38
39
|
}
|
|
39
40
|
})
|
|
40
41
|
|
|
41
42
|
if (identity instanceof Error)
|
|
42
|
-
throw new http.
|
|
43
|
+
throw new http.UnprocessableEntity(identity)
|
|
43
44
|
|
|
44
45
|
input.identity = identity
|
|
45
46
|
input.identity.scheme = scheme
|
|
@@ -2,6 +2,7 @@ import { type Component } from '@toa.io/core'
|
|
|
2
2
|
import { generate } from 'randomstring'
|
|
3
3
|
import { Role } from './Role'
|
|
4
4
|
import { type Identity } from './types'
|
|
5
|
+
import type { Parameter } from '../../RTD'
|
|
5
6
|
|
|
6
7
|
const remote = {
|
|
7
8
|
invoke: jest.fn()
|
|
@@ -16,16 +17,26 @@ beforeEach(() => {
|
|
|
16
17
|
it('should return false if not matched', async () => {
|
|
17
18
|
const roles = ['admin', 'user']
|
|
18
19
|
const directive = new Role(roles, discovery)
|
|
19
|
-
|
|
20
|
+
|
|
21
|
+
const identity: Identity = {
|
|
22
|
+
id: generate(),
|
|
23
|
+
scheme: '',
|
|
24
|
+
refresh: false
|
|
25
|
+
}
|
|
20
26
|
|
|
21
27
|
remote.invoke.mockResolvedValueOnce(['guest'])
|
|
22
28
|
|
|
23
|
-
const result = await directive.authorize(identity)
|
|
29
|
+
const result = await directive.authorize(identity, undefined, [])
|
|
24
30
|
|
|
25
31
|
expect(result).toBe(false)
|
|
26
32
|
|
|
27
33
|
expect(remote.invoke)
|
|
28
|
-
.toBeCalledWith('list', {
|
|
34
|
+
.toBeCalledWith('list', {
|
|
35
|
+
query: {
|
|
36
|
+
criteria: `identity==${identity.id}`,
|
|
37
|
+
limit: 1024
|
|
38
|
+
}
|
|
39
|
+
})
|
|
29
40
|
})
|
|
30
41
|
|
|
31
42
|
it('should return true on exact match', async () => {
|
|
@@ -52,11 +63,47 @@ it('should return false on non-scope substring match', async () => {
|
|
|
52
63
|
expect(result).toBe(false)
|
|
53
64
|
})
|
|
54
65
|
|
|
55
|
-
|
|
66
|
+
it('should return true on match with parameters', async () => {
|
|
67
|
+
const result = await match(['app:{org}:reviews'],
|
|
68
|
+
['app:29e54ae1:reviews'], [{
|
|
69
|
+
name: 'org',
|
|
70
|
+
value: '29e54ae1'
|
|
71
|
+
}])
|
|
72
|
+
|
|
73
|
+
expect(result).toBe(true)
|
|
74
|
+
})
|
|
75
|
+
|
|
76
|
+
it('should return true on match with parameters', async () => {
|
|
77
|
+
const result = await match(['app:{org}:reviews'],
|
|
78
|
+
['app:29e54ae1:reviews'], [{
|
|
79
|
+
name: 'org',
|
|
80
|
+
value: '29e54ae1'
|
|
81
|
+
}])
|
|
82
|
+
|
|
83
|
+
expect(result).toBe(true)
|
|
84
|
+
})
|
|
85
|
+
|
|
86
|
+
it('should return false on mismatch with parameters', async () => {
|
|
87
|
+
const result = await match(['app:{org}:reviews'],
|
|
88
|
+
['app:29e54ae1:reviews'], [{
|
|
89
|
+
name: 'org',
|
|
90
|
+
value: '88584c9b'
|
|
91
|
+
}])
|
|
92
|
+
|
|
93
|
+
expect(result).toBe(false)
|
|
94
|
+
})
|
|
95
|
+
|
|
96
|
+
async function match
|
|
97
|
+
(expected: string[], actual: string[], parameters: Parameter[] = []): Promise<boolean> {
|
|
56
98
|
const directive = new Role(expected, discovery)
|
|
57
|
-
|
|
99
|
+
|
|
100
|
+
const identity: Identity = {
|
|
101
|
+
id: generate(),
|
|
102
|
+
scheme: '',
|
|
103
|
+
refresh: false
|
|
104
|
+
}
|
|
58
105
|
|
|
59
106
|
remote.invoke.mockResolvedValueOnce(actual)
|
|
60
107
|
|
|
61
|
-
return await directive.authorize(identity)
|
|
108
|
+
return await directive.authorize(identity, undefined, parameters)
|
|
62
109
|
}
|
|
@@ -1,14 +1,18 @@
|
|
|
1
|
+
import assert from 'node:assert'
|
|
1
2
|
import { type Component, type Query } from '@toa.io/core'
|
|
2
3
|
import { type Directive, type Identity } from './types'
|
|
4
|
+
import type { Parameter } from '../../RTD'
|
|
3
5
|
|
|
4
6
|
export class Role implements Directive {
|
|
5
7
|
public static remote: Component | null = null
|
|
6
8
|
private readonly roles: string[]
|
|
7
9
|
private readonly discovery: Promise<Component>
|
|
10
|
+
private readonly dynamic: boolean
|
|
8
11
|
|
|
9
12
|
public constructor (roles: string | string[], discovery: Promise<Component>) {
|
|
10
13
|
this.roles = typeof roles === 'string' ? [roles] : roles
|
|
11
14
|
this.discovery = discovery
|
|
15
|
+
this.dynamic = this.roles.some((role) => role.includes('{'))
|
|
12
16
|
}
|
|
13
17
|
|
|
14
18
|
public static async set (identity: Identity, discovery: Promise<Component>): Promise<void> {
|
|
@@ -22,37 +26,41 @@ export class Role implements Directive {
|
|
|
22
26
|
identity.roles = await this.remote.invoke('list', { query })
|
|
23
27
|
}
|
|
24
28
|
|
|
25
|
-
public async authorize
|
|
29
|
+
public async authorize
|
|
30
|
+
(identity: Identity | null, _: unknown, parameters: Parameter[]): Promise<boolean> {
|
|
26
31
|
if (identity === null)
|
|
27
32
|
return false
|
|
28
33
|
|
|
29
34
|
await Role.set(identity, this.discovery)
|
|
30
35
|
|
|
31
|
-
if (identity.roles ===
|
|
36
|
+
if (identity.roles!.length === 0) // Role.set()
|
|
37
|
+
|
|
32
38
|
return false
|
|
33
39
|
|
|
34
|
-
return this.match(identity.roles)
|
|
40
|
+
return this.match(identity.roles!, parameters)
|
|
35
41
|
}
|
|
36
42
|
|
|
37
|
-
private match (roles: string[]): boolean {
|
|
43
|
+
private match (roles: string[], parameters: Parameter[]): boolean {
|
|
44
|
+
const required = this.dynamic ? this.substitute(parameters) : this.roles
|
|
45
|
+
|
|
38
46
|
for (const role of roles) {
|
|
39
|
-
const
|
|
47
|
+
const ok = required.some((expected) => expected === role || expected.startsWith(role + ':'))
|
|
40
48
|
|
|
41
|
-
if (
|
|
49
|
+
if (ok)
|
|
42
50
|
return true
|
|
43
51
|
}
|
|
44
52
|
|
|
45
53
|
return false
|
|
46
54
|
}
|
|
47
|
-
}
|
|
48
55
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
56
|
+
private substitute (parameters: Parameter[]): string[] {
|
|
57
|
+
return this.roles.map((role) => role.replaceAll(/{(\w+)}/g, (_, key) => {
|
|
58
|
+
const value = parameters.find((parameter) => parameter.name === key)?.value
|
|
52
59
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
return false
|
|
60
|
+
assert.ok(value !== undefined,
|
|
61
|
+
`Role '${role}' requires '${key}' route parameter.`)
|
|
56
62
|
|
|
57
|
-
|
|
63
|
+
return value
|
|
64
|
+
}))
|
|
65
|
+
}
|
|
58
66
|
}
|
|
@@ -1,19 +1,19 @@
|
|
|
1
1
|
import { Control } from './Control'
|
|
2
2
|
import { Exact } from './Exact'
|
|
3
|
-
import type {
|
|
4
|
-
import type { Directive } from './types'
|
|
5
|
-
import type {
|
|
3
|
+
import type { Output } from '../../io'
|
|
4
|
+
import type { AuthenticatedContext, Directive } from './types'
|
|
5
|
+
import type { DirectiveFamily } from '../../RTD'
|
|
6
6
|
import type * as http from '../../HTTP'
|
|
7
7
|
|
|
8
|
-
export class Cache implements
|
|
8
|
+
export class Cache implements DirectiveFamily<Directive> {
|
|
9
9
|
public readonly name: string = 'cache'
|
|
10
|
-
public readonly mandatory: boolean =
|
|
10
|
+
public readonly mandatory: boolean = true
|
|
11
11
|
|
|
12
12
|
public create (name: string, value: any): Directive {
|
|
13
13
|
const Class = constructors[name]
|
|
14
14
|
|
|
15
15
|
if (Class === undefined)
|
|
16
|
-
throw new Error(`Directive '
|
|
16
|
+
throw new Error(`Directive 'cache:${name}' is not implemented.`)
|
|
17
17
|
|
|
18
18
|
return new Class(value)
|
|
19
19
|
}
|
|
@@ -23,9 +23,16 @@ export class Cache implements Family<Directive> {
|
|
|
23
23
|
}
|
|
24
24
|
|
|
25
25
|
public async settle
|
|
26
|
-
(directives: Directive[],
|
|
26
|
+
(directives: Directive[], context: AuthenticatedContext, response: http.OutgoingMessage): Promise<void> {
|
|
27
|
+
const directive = directives[0]
|
|
28
|
+
|
|
27
29
|
response.headers ??= new Headers()
|
|
28
|
-
|
|
30
|
+
|
|
31
|
+
if (directive === undefined) {
|
|
32
|
+
if (context.identity !== null && !Control.disabled(response.headers))
|
|
33
|
+
response.headers.set('cache-control', 'private')
|
|
34
|
+
} else
|
|
35
|
+
directive.set(context, response.headers)
|
|
29
36
|
}
|
|
30
37
|
}
|
|
31
38
|
|