@toa.io/extensions.exposition 1.0.0-alpha.278 → 1.0.0-alpha.282
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/CHANGELOG.md +31 -0
- package/components/identity.basic/events/principal.js +5 -1
- package/components/identity.basic/manifest.toa.yaml +11 -1
- package/components/identity.basic/operations/authenticate.js +9 -5
- package/components/identity.basic/operations/authenticate.js.map +1 -1
- package/components/identity.basic/operations/check.js +2 -1
- package/components/identity.basic/operations/check.js.map +1 -1
- package/components/identity.basic/operations/incept.js +4 -5
- package/components/identity.basic/operations/incept.js.map +1 -1
- package/components/identity.basic/operations/lib/credentials.d.ts +5 -0
- package/components/identity.basic/operations/lib/credentials.js +12 -0
- package/components/identity.basic/operations/lib/credentials.js.map +1 -0
- package/components/identity.basic/operations/transit.d.ts +2 -0
- package/components/identity.basic/operations/transit.js +12 -2
- package/components/identity.basic/operations/transit.js.map +1 -1
- package/components/identity.basic/operations/types.d.ts +11 -1
- package/components/identity.basic/source/authenticate.ts +11 -5
- package/components/identity.basic/source/check.ts +2 -1
- package/components/identity.basic/source/incept.ts +5 -5
- package/components/identity.basic/source/lib/credentials.test.ts +18 -0
- package/components/identity.basic/source/lib/credentials.ts +13 -0
- package/components/identity.basic/source/transit.ts +16 -4
- package/components/identity.basic/source/types.ts +13 -1
- package/components/identity.basic/tsconfig.tsbuildinfo +1 -1
- package/components/identity.federation/events/principal.js +1 -0
- package/components/identity.federation/manifest.toa.yaml +5 -1
- package/components/identity.federation/operations/authenticate.js +3 -3
- package/components/identity.federation/operations/authenticate.js.map +1 -1
- package/components/identity.federation/operations/create.js +5 -1
- package/components/identity.federation/operations/create.js.map +1 -1
- package/components/identity.federation/operations/lib/decode.js +5 -1
- package/components/identity.federation/operations/lib/decode.js.map +1 -1
- package/components/identity.federation/operations/lib/exchange.js +3 -3
- package/components/identity.federation/operations/lib/exchange.js.map +1 -1
- package/components/identity.federation/operations/list.js +2 -1
- package/components/identity.federation/operations/list.js.map +1 -1
- package/components/identity.federation/operations/types/configuration.d.ts +2 -1
- package/components/identity.federation/source/authenticate.ts +3 -3
- package/components/identity.federation/source/create.ts +5 -1
- package/components/identity.federation/source/lib/decode.ts +5 -1
- package/components/identity.federation/source/lib/exchange.ts +3 -3
- package/components/identity.federation/source/list.test.ts +1 -1
- package/components/identity.federation/source/list.ts +2 -1
- package/components/identity.federation/source/types/configuration.ts +2 -1
- package/components/identity.federation/tsconfig.tsbuildinfo +1 -1
- package/components/identity.keys/manifest.toa.yaml +18 -1
- package/components/identity.keys/operations/disable.d.ts +5 -0
- package/components/identity.keys/operations/disable.js +5 -0
- package/components/identity.keys/operations/disable.js.map +1 -0
- package/components/identity.keys/operations/revoke.d.ts +15 -0
- package/components/identity.keys/operations/revoke.js +12 -0
- package/components/identity.keys/operations/revoke.js.map +1 -0
- package/components/identity.keys/receivers/identity.bans.created.js +1 -0
- package/components/identity.keys/receivers/identity.bans.updated.js +1 -0
- package/components/identity.keys/receivers/identity.roles.deleted.js +1 -0
- package/components/identity.keys/source/disable.ts +9 -0
- package/components/identity.keys/source/revoke.ts +30 -0
- package/components/identity.keys/tsconfig.tsbuildinfo +1 -1
- package/components/identity.otp/manifest.toa.yaml +6 -0
- package/components/identity.otp/operations/authenticate.js +13 -1
- package/components/identity.otp/operations/authenticate.js.map +1 -1
- package/components/identity.otp/operations/issue.js +3 -2
- package/components/identity.otp/operations/issue.js.map +1 -1
- package/components/identity.otp/operations/lib/Context.d.ts +1 -0
- package/components/identity.otp/source/authenticate.ts +19 -1
- package/components/identity.otp/source/issue.ts +3 -2
- package/components/identity.otp/source/lib/Context.ts +1 -0
- package/components/identity.otp/tsconfig.tsbuildinfo +1 -1
- package/components/identity.passkeys/operations/authenticate.js +2 -1
- package/components/identity.passkeys/operations/authenticate.js.map +1 -1
- package/components/identity.passkeys/operations/challenge.js +3 -3
- package/components/identity.passkeys/operations/challenge.js.map +1 -1
- package/components/identity.passkeys/operations/delete.js +2 -1
- package/components/identity.passkeys/operations/delete.js.map +1 -1
- package/components/identity.passkeys/operations/list.js +2 -1
- package/components/identity.passkeys/operations/list.js.map +1 -1
- package/components/identity.passkeys/source/authenticate.ts +2 -1
- package/components/identity.passkeys/source/challenge.ts +3 -3
- package/components/identity.passkeys/source/delete.ts +2 -1
- package/components/identity.passkeys/source/list.ts +2 -1
- package/components/identity.passkeys/tsconfig.tsbuildinfo +1 -1
- package/components/identity.roles/manifest.toa.yaml +4 -0
- package/components/identity.roles/operations/grant.js +5 -2
- package/components/identity.roles/operations/grant.js.map +1 -1
- package/components/identity.roles/source/grant.ts +6 -2
- package/components/identity.roles/tsconfig.tsbuildinfo +1 -1
- package/components/identity.tokens/manifest.toa.yaml +3 -0
- package/components/identity.tokens/operations/authenticate.js +4 -3
- package/components/identity.tokens/operations/authenticate.js.map +1 -1
- package/components/identity.tokens/operations/decrypt.js +7 -1
- package/components/identity.tokens/operations/decrypt.js.map +1 -1
- package/components/identity.tokens/operations/encrypt.js +3 -2
- package/components/identity.tokens/operations/encrypt.js.map +1 -1
- package/components/identity.tokens/operations/issue.js +2 -1
- package/components/identity.tokens/operations/issue.js.map +1 -1
- package/components/identity.tokens/operations/lib/types.d.ts +3 -0
- package/components/identity.tokens/source/authenticate.test.ts +26 -2
- package/components/identity.tokens/source/authenticate.ts +4 -3
- package/components/identity.tokens/source/decrypt.test.ts +35 -1
- package/components/identity.tokens/source/decrypt.ts +10 -1
- package/components/identity.tokens/source/encrypt.test.ts +15 -0
- package/components/identity.tokens/source/encrypt.ts +4 -2
- package/components/identity.tokens/source/issue.ts +2 -1
- package/components/identity.tokens/source/lib/types.ts +4 -0
- package/components/identity.tokens/tsconfig.tsbuildinfo +1 -1
- package/documentation/authorities.md +3 -0
- package/documentation/components.md +31 -11
- package/documentation/identity.md +38 -6
- package/documentation/io.md +2 -2
- package/documentation/ip.md +24 -0
- package/documentation/passkeys.md +6 -0
- package/features/auth.assert.feature +2 -4
- package/features/auth.claims.feature +1 -0
- package/features/auth.incept.feature +46 -0
- package/features/authorities.feature +39 -0
- package/features/authorities.federation.feature +1 -0
- package/features/identity.bans.feature +63 -0
- package/features/identity.basic.feature +95 -3
- package/features/identity.feature +151 -0
- package/features/identity.federation.feature +5 -0
- package/features/identity.otp.feature +41 -0
- package/features/identity.roles.feature +252 -0
- package/features/identity.tokens.custom.feature +145 -0
- package/features/map.feature +2 -0
- package/features/steps/Gateway.ts +8 -2
- package/features/steps/Realtime.ts +1 -1
- package/package.json +5 -5
- package/readme.md +3 -0
- package/schemas/annotation.cos.yaml +16 -0
- package/source/Annotation.ts +14 -0
- package/source/Composition.ts +5 -5
- package/source/Directive.test.ts +3 -1
- package/source/Directive.ts +6 -2
- package/source/Endpoint.ts +4 -2
- package/source/Factory.ts +12 -9
- package/source/HTTP/Context.ts +12 -2
- package/source/HTTP/Server.ts +16 -3
- package/source/HTTP/address.test.ts +22 -0
- package/source/HTTP/address.ts +17 -0
- package/source/Query.test.ts +15 -1
- package/source/Query.ts +3 -1
- package/source/RTD/Directives.ts +10 -1
- package/source/Remotes.test.ts +7 -12
- package/source/Remotes.ts +5 -5
- package/source/const.ts +3 -0
- package/source/deployment.ts +7 -1
- package/source/directives/auth/Assert.ts +3 -0
- package/source/directives/auth/Authorization.test.ts +24 -0
- package/source/directives/auth/Authorization.ts +80 -11
- package/source/directives/auth/Incept.ts +9 -4
- package/source/directives/auth/Role.test.ts +1 -1
- package/source/directives/auth/Role.ts +2 -1
- package/source/directives/auth/schemes.test.ts +14 -0
- package/source/directives/auth/schemes.ts +14 -0
- package/source/directives/auth/types.ts +3 -0
- package/source/directives/io/IO.ts +10 -3
- package/source/directives/io/lib/throttle/Keys.ts +10 -3
- package/source/directives/io/lib/throttle/Quotas.test.ts +14 -4
- package/source/directives/io/lib/throttle/Quotas.ts +15 -2
- package/source/directives/io/lib/throttle/Sync.test.ts +7 -9
- package/source/directives/io/lib/throttle/Sync.ts +4 -7
- package/source/directives/io/lib/throttle/Warning.test.ts +32 -0
- package/source/directives/io/lib/throttle/Warning.ts +30 -0
- package/source/directives/io/lib/throttle/components/Component.ts +2 -1
- package/source/directives/io/lib/throttle/components/IP.ts +19 -28
- package/source/directives/io/lib/throttle/index.ts +1 -0
- package/source/redact.test.ts +27 -0
- package/source/redact.ts +21 -0
- package/source/schemas.test.ts +17 -0
- package/transpiled/Annotation.d.ts +10 -0
- package/transpiled/Composition.d.ts +3 -3
- package/transpiled/Composition.js +4 -4
- package/transpiled/Composition.js.map +1 -1
- package/transpiled/Directive.d.ts +3 -2
- package/transpiled/Directive.js +3 -1
- package/transpiled/Directive.js.map +1 -1
- package/transpiled/Endpoint.js +3 -2
- package/transpiled/Endpoint.js.map +1 -1
- package/transpiled/Factory.d.ts +3 -3
- package/transpiled/Factory.js +11 -8
- package/transpiled/Factory.js.map +1 -1
- package/transpiled/HTTP/Context.d.ts +4 -0
- package/transpiled/HTTP/Context.js +7 -2
- package/transpiled/HTTP/Context.js.map +1 -1
- package/transpiled/HTTP/Server.d.ts +5 -0
- package/transpiled/HTTP/Server.js +8 -3
- package/transpiled/HTTP/Server.js.map +1 -1
- package/transpiled/HTTP/address.d.ts +7 -0
- package/transpiled/HTTP/address.js +14 -0
- package/transpiled/HTTP/address.js.map +1 -0
- package/transpiled/Query.js +3 -1
- package/transpiled/Query.js.map +1 -1
- package/transpiled/RTD/Directives.d.ts +9 -1
- package/transpiled/Remotes.d.ts +3 -3
- package/transpiled/Remotes.js +4 -4
- package/transpiled/Remotes.js.map +1 -1
- package/transpiled/const.d.ts +2 -0
- package/transpiled/const.js +2 -0
- package/transpiled/const.js.map +1 -1
- package/transpiled/deployment.js +4 -0
- package/transpiled/deployment.js.map +1 -1
- package/transpiled/directives/auth/Assert.js +2 -0
- package/transpiled/directives/auth/Assert.js.map +1 -1
- package/transpiled/directives/auth/Authorization.d.ts +8 -0
- package/transpiled/directives/auth/Authorization.js +61 -11
- package/transpiled/directives/auth/Authorization.js.map +1 -1
- package/transpiled/directives/auth/Incept.d.ts +3 -1
- package/transpiled/directives/auth/Incept.js +8 -4
- package/transpiled/directives/auth/Incept.js.map +1 -1
- package/transpiled/directives/auth/Role.js +2 -1
- package/transpiled/directives/auth/Role.js.map +1 -1
- package/transpiled/directives/auth/schemes.d.ts +10 -0
- package/transpiled/directives/auth/schemes.js +12 -0
- package/transpiled/directives/auth/schemes.js.map +1 -1
- package/transpiled/directives/auth/types.d.ts +2 -0
- package/transpiled/directives/io/IO.d.ts +4 -1
- package/transpiled/directives/io/IO.js +7 -3
- package/transpiled/directives/io/IO.js.map +1 -1
- package/transpiled/directives/io/lib/throttle/Keys.d.ts +2 -1
- package/transpiled/directives/io/lib/throttle/Keys.js +7 -2
- package/transpiled/directives/io/lib/throttle/Keys.js.map +1 -1
- package/transpiled/directives/io/lib/throttle/Quotas.d.ts +3 -2
- package/transpiled/directives/io/lib/throttle/Quotas.js +8 -1
- package/transpiled/directives/io/lib/throttle/Quotas.js.map +1 -1
- package/transpiled/directives/io/lib/throttle/Sync.d.ts +2 -3
- package/transpiled/directives/io/lib/throttle/Sync.js +1 -3
- package/transpiled/directives/io/lib/throttle/Sync.js.map +1 -1
- package/transpiled/directives/io/lib/throttle/Warning.d.ts +11 -0
- package/transpiled/directives/io/lib/throttle/Warning.js +24 -0
- package/transpiled/directives/io/lib/throttle/Warning.js.map +1 -0
- package/transpiled/directives/io/lib/throttle/components/Component.d.ts +2 -1
- package/transpiled/directives/io/lib/throttle/components/IP.d.ts +10 -2
- package/transpiled/directives/io/lib/throttle/components/IP.js +18 -23
- package/transpiled/directives/io/lib/throttle/components/IP.js.map +1 -1
- package/transpiled/directives/io/lib/throttle/index.d.ts +1 -0
- package/transpiled/directives/io/lib/throttle/index.js +1 -0
- package/transpiled/directives/io/lib/throttle/index.js.map +1 -1
- package/transpiled/redact.d.ts +5 -0
- package/transpiled/redact.js +17 -0
- package/transpiled/redact.js.map +1 -0
- package/tsconfig.tsbuildinfo +1 -1
- package/components/exposition.atom/manifest.toa.yaml +0 -21
- package/components/exposition.atom/operations/meter.js +0 -5
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,37 @@
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
|
5
5
|
|
|
6
|
+
# [1.0.0-alpha.282](https://github.com/toa-io/toa/compare/v1.0.0-alpha.281...v1.0.0-alpha.282) (2026-09-03)
|
|
7
|
+
|
|
8
|
+
### Bug Fixes
|
|
9
|
+
|
|
10
|
+
* **exposition:** bouncer requires ip ([d470494](https://github.com/toa-io/toa/commit/d470494fdb42372a434d945205e93e27bca8880b))
|
|
11
|
+
* **exposition:** bound OTP guessing ([44b5a6a](https://github.com/toa-io/toa/commit/44b5a6a1f743cca4bd80b0b7e9f9691af83fb2ab))
|
|
12
|
+
* **exposition:** do not delegate the right to delegate ([cf1f83f](https://github.com/toa-io/toa/commit/cf1f83f6bb1051b8b399c632bb81f08a2fd9fb14))
|
|
13
|
+
* **exposition:** keep credentials out of the logs ([17a5529](https://github.com/toa-io/toa/commit/17a55296ec530b6f3c3a1d4e746499e52ef1c126))
|
|
14
|
+
* **exposition:** leave custom tokens unrefreshed ([ebec3d5](https://github.com/toa-io/toa/commit/ebec3d5ea421e8c780f7c7afd781c588851ef8fa))
|
|
15
|
+
* **exposition:** match token permissions on the routed path ([6c888f5](https://github.com/toa-io/toa/commit/6c888f5e51a379c0cdf46e8e3b3b0fa406328de6))
|
|
16
|
+
* **exposition:** name the client address header in the authentication annotation ([433ca3a](https://github.com/toa-io/toa/commit/433ca3ae19bc2c68fa26f6205e559ea7e652fcb9))
|
|
17
|
+
* **exposition:** never key on the connection address ([ad719af](https://github.com/toa-io/toa/commit/ad719afb89455a9cbdb97f144928b233aababb73))
|
|
18
|
+
* **exposition:** quote criteria values built from requests ([af3bf79](https://github.com/toa-io/toa/commit/af3bf794d8668a45a4390ad16ffa04aa4fe078e8))
|
|
19
|
+
* **exposition:** read roles again when a token is refreshed ([96c59ca](https://github.com/toa-io/toa/commit/96c59cae39a1b023e6b2b05720ea0682d4c746ad))
|
|
20
|
+
* **exposition:** read the client address from a header the deployment names ([216c2d8](https://github.com/toa-io/toa/commit/216c2d8f21bdb67c7d4387708c80f806f1c72360))
|
|
21
|
+
* **exposition:** refuse rejected credentials before inception ([48e76a8](https://github.com/toa-io/toa/commit/48e76a8f421b95492d256b5c7a9ca61f71f0d7fd))
|
|
22
|
+
* **exposition:** require the audience of a trusted issuer ([0d13604](https://github.com/toa-io/toa/commit/0d13604e3707ed2fcac01500beb27d992314c549))
|
|
23
|
+
* **exposition:** resolve an authentication scheme by its own name only ([ae116d1](https://github.com/toa-io/toa/commit/ae116d1813fc1e5a42b5263daedb752703eb08f0))
|
|
24
|
+
* **exposition:** resolve the client address once, into the request context ([2f36347](https://github.com/toa-io/toa/commit/2f36347d948bab0c421ff63105312549fffc660a))
|
|
25
|
+
* **exposition:** revoke custom tokens through their keys ([359d882](https://github.com/toa-io/toa/commit/359d8825315fce010ea8ac3700d2778b48362f72))
|
|
26
|
+
* **exposition:** revoke custom tokens when a role is revoked ([191a0c6](https://github.com/toa-io/toa/commit/191a0c603ef53dcab5ccd005dd7296d9c9bfaa0b))
|
|
27
|
+
* **exposition:** scope the principal to an authority ([98a0d36](https://github.com/toa-io/toa/commit/98a0d36267523eb1a1aa58742744cd39a21e94e9))
|
|
28
|
+
* **exposition:** split Basic credentials at the first colon ([596e5dc](https://github.com/toa-io/toa/commit/596e5dc2e6e589007dc7914374e1592ecc71c997))
|
|
29
|
+
* **exposition:** validate the request authority ([68686c9](https://github.com/toa-io/toa/commit/68686c9340effb148532607caa1abbaaa5dc0519))
|
|
30
|
+
|
|
31
|
+
### Features
|
|
32
|
+
|
|
33
|
+
* **core:** a Host for extensions ([6315eac](https://github.com/toa-io/toa/commit/6315eac1e9fb05be472272de06385c54ad5934ce))
|
|
34
|
+
* **exposition:** meter failed authentications per address ([98b07d3](https://github.com/toa-io/toa/commit/98b07d307815ee4a2a0f30f189cbcfc9d78a4d62))
|
|
35
|
+
|
|
36
|
+
|
|
6
37
|
# [1.0.0-alpha.278](https://github.com/toa-io/toa/compare/v1.0.0-alpha.277...v1.0.0-alpha.278) (2026-09-03)
|
|
7
38
|
|
|
8
39
|
**Note:** Version bump only for package @toa.io/extensions.exposition
|
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
export const condition = function (event, context) {
|
|
2
|
-
|
|
2
|
+
const principal = context.configuration.principal
|
|
3
|
+
|
|
4
|
+
return principal !== undefined &&
|
|
5
|
+
event.state.authority === principal.authority &&
|
|
6
|
+
event.state.username === principal.username
|
|
3
7
|
}
|
|
4
8
|
|
|
5
9
|
export const payload = function (event) {
|
|
@@ -172,7 +172,17 @@ configuration:
|
|
|
172
172
|
description: Hashing pepper, a secret
|
|
173
173
|
type: string
|
|
174
174
|
principal:
|
|
175
|
-
|
|
175
|
+
description: Basic credentials whose Identity is granted the `system` role
|
|
176
|
+
type: object
|
|
177
|
+
properties:
|
|
178
|
+
authority:
|
|
179
|
+
type: string
|
|
180
|
+
username:
|
|
181
|
+
type: string
|
|
182
|
+
required:
|
|
183
|
+
- authority
|
|
184
|
+
- username
|
|
185
|
+
additionalProperties: false
|
|
176
186
|
username:
|
|
177
187
|
type: array
|
|
178
188
|
items:
|
|
@@ -1,10 +1,14 @@
|
|
|
1
1
|
import { compare } from 'bcryptjs';
|
|
2
|
+
import { quote } from '@toa.io/generic';
|
|
3
|
+
import { split } from './lib/credentials.js';
|
|
2
4
|
export async function computation(input, context) {
|
|
3
|
-
const
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
const query = {
|
|
5
|
+
const pair = split(input.credentials);
|
|
6
|
+
if (pair === null)
|
|
7
|
+
return ERR_NOT_FOUND;
|
|
8
|
+
const [username, password] = pair;
|
|
9
|
+
const query = {
|
|
10
|
+
criteria: `authority==${quote(input.authority)};username==${quote(username)}`
|
|
11
|
+
};
|
|
8
12
|
const credentials = await context.local.observe({ query });
|
|
9
13
|
if (credentials instanceof Error)
|
|
10
14
|
return credentials;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"authenticate.js","sourceRoot":"","sources":["../source/authenticate.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,UAAU,CAAA;
|
|
1
|
+
{"version":3,"file":"authenticate.js","sourceRoot":"","sources":["../source/authenticate.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,UAAU,CAAA;AAClC,OAAO,EAAE,KAAK,EAAE,MAAM,iBAAiB,CAAA;AAEvC,OAAO,EAAE,KAAK,EAAE,MAAM,sBAAsB,CAAA;AAG5C,MAAM,CAAC,KAAK,UAAU,WAAW,CAAE,KAAY,EAAE,OAAgB;IAC/D,MAAM,IAAI,GAAG,KAAK,CAAC,KAAK,CAAC,WAAW,CAAC,CAAA;IAErC,IAAI,IAAI,KAAK,IAAI;QACf,OAAO,aAAa,CAAA;IAEtB,MAAM,CAAC,QAAQ,EAAE,QAAQ,CAAC,GAAG,IAAI,CAAA;IAEjC,MAAM,KAAK,GAAU;QACnB,QAAQ,EAAE,cAAc,KAAK,CAAC,KAAK,CAAC,SAAS,CAAC,cAAc,KAAK,CAAC,QAAQ,CAAC,EAAE;KAC9E,CAAA;IACD,MAAM,WAAW,GAAG,MAAM,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE,KAAK,EAAE,CAAC,CAAA;IAE1D,IAAI,WAAW,YAAY,KAAK;QAC9B,OAAO,WAAW,CAAA;IAEpB,IAAI,WAAW,KAAK,IAAI;QACtB,OAAO,aAAa,CAAA;IAEtB,MAAM,KAAK,GAAG,QAAQ,GAAG,CAAC,OAAO,CAAC,aAAa,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAA;IACvE,MAAM,KAAK,GAAG,MAAM,OAAO,CAAC,KAAK,EAAE,WAAW,CAAC,QAAQ,CAAC,CAAA;IAExD,IAAI,KAAK;QACP,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,EAAE,WAAW,CAAC,EAAE,EAAE,EAAE,CAAA;;QAE3C,OAAO,qBAAqB,CAAA;AAChC,CAAC;AAED,MAAM,aAAa,GAAG,IAAI,CAAC,MAAM,aAAc,SAAQ,KAAK;IAC1C,IAAI,GAAG,WAAW,CAAA;CACnC,CAAC,EAAE,CAAA;AAEJ,MAAM,qBAAqB,GAAG,IAAI,CAAC,MAAM,qBAAsB,SAAQ,KAAK;IAC1D,IAAI,GAAG,mBAAmB,CAAA;CAC3C,CAAC,EAAE,CAAA"}
|
|
@@ -1,7 +1,8 @@
|
|
|
1
|
+
import { quote } from '@toa.io/generic';
|
|
1
2
|
export async function computation(input, context) {
|
|
2
3
|
const username = Buffer.from(input.username, 'base64url').toString();
|
|
3
4
|
const found = await context.local.observe({
|
|
4
|
-
query: { criteria: `authority==${input.authority};username
|
|
5
|
+
query: { criteria: `authority==${quote(input.authority)};username==${quote(username)}` }
|
|
5
6
|
});
|
|
6
7
|
if (found instanceof Error)
|
|
7
8
|
return found;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"check.js","sourceRoot":"","sources":["../source/check.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"check.js","sourceRoot":"","sources":["../source/check.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,iBAAiB,CAAA;AAGvC,MAAM,CAAC,KAAK,UAAU,WAAW,CAAE,KAAY,EAAE,OAAgB;IAC/D,MAAM,QAAQ,GAAG,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,QAAQ,EAAE,WAAW,CAAC,CAAC,QAAQ,EAAE,CAAA;IAEpE,MAAM,KAAK,GAAG,MAAM,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC;QACxC,KAAK,EAAE,EAAE,QAAQ,EAAE,cAAc,KAAK,CAAC,KAAK,CAAC,SAAS,CAAC,cAAc,KAAK,CAAC,QAAQ,CAAC,EAAE,EAAE;KACzF,CAAC,CAAA;IAEF,IAAI,KAAK,YAAY,KAAK;QACxB,OAAO,KAAK,CAAA;IAEd,IAAI,KAAK,KAAK,IAAI;QAChB,OAAO,IAAI,CAAA;AACf,CAAC"}
|
|
@@ -1,10 +1,9 @@
|
|
|
1
|
+
import { split } from './lib/credentials.js';
|
|
1
2
|
export async function effect(input, context) {
|
|
2
|
-
const
|
|
3
|
-
|
|
4
|
-
.toString()
|
|
5
|
-
.split(':');
|
|
6
|
-
if (typeof password !== 'string')
|
|
3
|
+
const pair = split(input.credentials);
|
|
4
|
+
if (pair === null)
|
|
7
5
|
return INVALID_CREDENTIALS;
|
|
6
|
+
const [username, password] = pair;
|
|
8
7
|
const request = {
|
|
9
8
|
input: {
|
|
10
9
|
authority: input.authority,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"incept.js","sourceRoot":"","sources":["../source/incept.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"incept.js","sourceRoot":"","sources":["../source/incept.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,sBAAsB,CAAA;AAI5C,MAAM,CAAC,KAAK,UAAU,MAAM,CAAE,KAAY,EAAE,OAAgB;IAC1D,MAAM,IAAI,GAAG,KAAK,CAAC,KAAK,CAAC,WAAW,CAAC,CAAA;IAErC,IAAI,IAAI,KAAK,IAAI;QACf,OAAO,mBAAmB,CAAA;IAE5B,MAAM,CAAC,QAAQ,EAAE,QAAQ,CAAC,GAAG,IAAI,CAAA;IAEjC,MAAM,OAAO,GAAG;QACd,KAAK,EAAE;YACL,SAAS,EAAE,KAAK,CAAC,SAAS;YAC1B,QAAQ;YACR,QAAQ;SACT;QACD,KAAK,EAAE;YACL,EAAE,EAAE,KAAK,CAAC,EAAE;SACb;KACF,CAAA;IAED,OAAO,MAAM,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,CAAA;AAC7C,CAAC;AAED,MAAM,mBAAmB,GAAG,IAAI,CAAC,MAAM,uBAAwB,SAAQ,KAAK;IAC1D,IAAI,GAAG,qBAAqB,CAAA;CAC7C,CAAC,EAAE,CAAA"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The user-id and the password of Basic credentials. RFC 7617 forbids a colon in the
|
|
3
|
+
* user-id and allows any number of them in the password, so the split is at the first one.
|
|
4
|
+
*/
|
|
5
|
+
export function split(credentials) {
|
|
6
|
+
const decoded = Buffer.from(credentials, 'base64').toString();
|
|
7
|
+
const colon = decoded.indexOf(':');
|
|
8
|
+
if (colon === -1)
|
|
9
|
+
return null;
|
|
10
|
+
return [decoded.slice(0, colon), decoded.slice(colon + 1)];
|
|
11
|
+
}
|
|
12
|
+
//# sourceMappingURL=credentials.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"credentials.js","sourceRoot":"","sources":["../../source/lib/credentials.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,MAAM,UAAU,KAAK,CAAE,WAAmB;IACxC,MAAM,OAAO,GAAG,MAAM,CAAC,IAAI,CAAC,WAAW,EAAE,QAAQ,CAAC,CAAC,QAAQ,EAAE,CAAA;IAC7D,MAAM,KAAK,GAAG,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,CAAA;IAElC,IAAI,KAAK,KAAK,CAAC,CAAC;QACd,OAAO,IAAI,CAAA;IAEb,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,EAAE,OAAO,CAAC,KAAK,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,CAAA;AAC5D,CAAC"}
|
|
@@ -5,8 +5,10 @@ export declare class Transition implements Operation {
|
|
|
5
5
|
private pepper;
|
|
6
6
|
private principal?;
|
|
7
7
|
private tokens;
|
|
8
|
+
private keys;
|
|
8
9
|
private usernameRx;
|
|
9
10
|
private passwordRx;
|
|
10
11
|
mount(context: Context): void;
|
|
12
|
+
private locked;
|
|
11
13
|
execute(input: TransitInput, object: Entity): Promise<Maybe<IdOutput>>;
|
|
12
14
|
}
|
|
@@ -4,6 +4,7 @@ export class Transition {
|
|
|
4
4
|
pepper = '';
|
|
5
5
|
principal;
|
|
6
6
|
tokens = undefined;
|
|
7
|
+
keys = undefined;
|
|
7
8
|
usernameRx = [];
|
|
8
9
|
passwordRx = [];
|
|
9
10
|
mount(context) {
|
|
@@ -11,21 +12,30 @@ export class Transition {
|
|
|
11
12
|
this.pepper = context.configuration.pepper?.unwrap() ?? '';
|
|
12
13
|
this.principal = context.configuration.principal;
|
|
13
14
|
this.tokens = context.remote.identity.tokens;
|
|
15
|
+
this.keys = context.remote.identity.keys;
|
|
14
16
|
this.usernameRx = toRx(context.configuration.username);
|
|
15
17
|
this.passwordRx = toRx(context.configuration.password);
|
|
16
18
|
}
|
|
19
|
+
locked(object) {
|
|
20
|
+
return this.principal !== undefined &&
|
|
21
|
+
object.authority === this.principal.authority &&
|
|
22
|
+
object.username === this.principal.username;
|
|
23
|
+
}
|
|
17
24
|
async execute(input, object) {
|
|
18
25
|
const deleted = object._deleted !== undefined && object._deleted !== null;
|
|
19
26
|
const existent = object._version !== 0 && !deleted;
|
|
20
27
|
if (existent) {
|
|
21
28
|
if (input.inception === true)
|
|
22
29
|
return ERR_EXISTS;
|
|
23
|
-
await
|
|
30
|
+
await Promise.all([
|
|
31
|
+
this.tokens.revoke({ query: { id: object.id } }),
|
|
32
|
+
this.keys.revoke({ input: { identity: object.id } })
|
|
33
|
+
]);
|
|
24
34
|
}
|
|
25
35
|
else
|
|
26
36
|
object.authority = input.authority;
|
|
27
37
|
if (input.username !== undefined) {
|
|
28
|
-
if (existent &&
|
|
38
|
+
if (existent && this.locked(object))
|
|
29
39
|
return ERR_PRINCIPAL_LOCKED;
|
|
30
40
|
if (invalid(input.username, this.usernameRx))
|
|
31
41
|
return ERR_INVALID_USERNAME;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"transit.js","sourceRoot":"","sources":["../source/transit.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,UAAU,CAAA;AAIxC,MAAM,OAAO,UAAU;IACb,MAAM,GAAW,EAAE,CAAA;IACnB,MAAM,GAAW,EAAE,CAAA;IACnB,SAAS,
|
|
1
|
+
{"version":3,"file":"transit.js","sourceRoot":"","sources":["../source/transit.ts"],"names":[],"mappings":"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"}
|
|
@@ -11,16 +11,23 @@ export interface Context {
|
|
|
11
11
|
tokens: {
|
|
12
12
|
revoke: Call<void, IdentityTokensRevokeInput>;
|
|
13
13
|
};
|
|
14
|
+
keys: {
|
|
15
|
+
revoke: Call<void, IdentityKeysRevokeInput>;
|
|
16
|
+
};
|
|
14
17
|
};
|
|
15
18
|
};
|
|
16
19
|
configuration: {
|
|
17
20
|
readonly rounds: number;
|
|
18
21
|
readonly pepper?: Secret;
|
|
19
|
-
readonly principal?:
|
|
22
|
+
readonly principal?: Principal;
|
|
20
23
|
readonly username: string[];
|
|
21
24
|
readonly password: string[];
|
|
22
25
|
};
|
|
23
26
|
}
|
|
27
|
+
export interface Principal {
|
|
28
|
+
authority: string;
|
|
29
|
+
username: string;
|
|
30
|
+
}
|
|
24
31
|
export interface Entity {
|
|
25
32
|
id: string;
|
|
26
33
|
authority: string;
|
|
@@ -48,4 +55,7 @@ export interface IdOutput {
|
|
|
48
55
|
interface IdentityTokensRevokeInput {
|
|
49
56
|
query: Query;
|
|
50
57
|
}
|
|
58
|
+
interface IdentityKeysRevokeInput {
|
|
59
|
+
identity: string;
|
|
60
|
+
}
|
|
51
61
|
export {};
|
|
@@ -1,14 +1,20 @@
|
|
|
1
1
|
import { compare } from 'bcryptjs'
|
|
2
|
+
import { quote } from '@toa.io/generic'
|
|
2
3
|
import { type Query, type Maybe } from '@toa.io/types'
|
|
4
|
+
import { split } from './lib/credentials.js'
|
|
3
5
|
import { type Context } from './types.js'
|
|
4
6
|
|
|
5
7
|
export async function computation (input: Input, context: Context): Promise<Maybe<Output>> {
|
|
6
|
-
const
|
|
7
|
-
.from(input.credentials, 'base64')
|
|
8
|
-
.toString()
|
|
9
|
-
.split(':')
|
|
8
|
+
const pair = split(input.credentials)
|
|
10
9
|
|
|
11
|
-
|
|
10
|
+
if (pair === null)
|
|
11
|
+
return ERR_NOT_FOUND
|
|
12
|
+
|
|
13
|
+
const [username, password] = pair
|
|
14
|
+
|
|
15
|
+
const query: Query = {
|
|
16
|
+
criteria: `authority==${quote(input.authority)};username==${quote(username)}`
|
|
17
|
+
}
|
|
12
18
|
const credentials = await context.local.observe({ query })
|
|
13
19
|
|
|
14
20
|
if (credentials instanceof Error)
|
|
@@ -1,10 +1,11 @@
|
|
|
1
|
+
import { quote } from '@toa.io/generic'
|
|
1
2
|
import type { Context } from './types.js'
|
|
2
3
|
|
|
3
4
|
export async function computation (input: Input, context: Context): Promise<void | null | Error> {
|
|
4
5
|
const username = Buffer.from(input.username, 'base64url').toString()
|
|
5
6
|
|
|
6
7
|
const found = await context.local.observe({
|
|
7
|
-
query: { criteria: `authority==${input.authority};username
|
|
8
|
+
query: { criteria: `authority==${quote(input.authority)};username==${quote(username)}` }
|
|
8
9
|
})
|
|
9
10
|
|
|
10
11
|
if (found instanceof Error)
|
|
@@ -1,15 +1,15 @@
|
|
|
1
|
+
import { split } from './lib/credentials.js'
|
|
1
2
|
import type { Context } from './types.js'
|
|
2
3
|
import type { Maybe } from '@toa.io/types'
|
|
3
4
|
|
|
4
5
|
export async function effect (input: Input, context: Context): Promise<Maybe<Output>> {
|
|
5
|
-
const
|
|
6
|
-
.from(input.credentials, 'base64')
|
|
7
|
-
.toString()
|
|
8
|
-
.split(':')
|
|
6
|
+
const pair = split(input.credentials)
|
|
9
7
|
|
|
10
|
-
if (
|
|
8
|
+
if (pair === null)
|
|
11
9
|
return INVALID_CREDENTIALS
|
|
12
10
|
|
|
11
|
+
const [username, password] = pair
|
|
12
|
+
|
|
13
13
|
const request = {
|
|
14
14
|
input: {
|
|
15
15
|
authority: input.authority,
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { it } from 'node:test'
|
|
2
|
+
import assert from 'node:assert/strict'
|
|
3
|
+
|
|
4
|
+
import { split } from './credentials.js'
|
|
5
|
+
|
|
6
|
+
const encode = (value: string): string => Buffer.from(value).toString('base64')
|
|
7
|
+
|
|
8
|
+
it('should split at the first colon', () => {
|
|
9
|
+
assert.deepEqual(split(encode('user:pa:ss:word')), ['user', 'pa:ss:word'])
|
|
10
|
+
})
|
|
11
|
+
|
|
12
|
+
it('should accept an empty password', () => {
|
|
13
|
+
assert.deepEqual(split(encode('user:')), ['user', ''])
|
|
14
|
+
})
|
|
15
|
+
|
|
16
|
+
it('should refuse credentials without a colon', () => {
|
|
17
|
+
assert.equal(split(encode('user')), null)
|
|
18
|
+
})
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The user-id and the password of Basic credentials. RFC 7617 forbids a colon in the
|
|
3
|
+
* user-id and allows any number of them in the password, so the split is at the first one.
|
|
4
|
+
*/
|
|
5
|
+
export function split (credentials: string): [string, string] | null {
|
|
6
|
+
const decoded = Buffer.from(credentials, 'base64').toString()
|
|
7
|
+
const colon = decoded.indexOf(':')
|
|
8
|
+
|
|
9
|
+
if (colon === -1)
|
|
10
|
+
return null
|
|
11
|
+
|
|
12
|
+
return [decoded.slice(0, colon), decoded.slice(colon + 1)]
|
|
13
|
+
}
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import { genSalt, hash } from 'bcryptjs'
|
|
2
2
|
import type { Maybe, Operation } from '@toa.io/types'
|
|
3
|
-
import type { Context, Entity, TransitInput, IdOutput } from './types.js'
|
|
3
|
+
import type { Context, Entity, Principal, TransitInput, IdOutput } from './types.js'
|
|
4
4
|
|
|
5
5
|
export class Transition implements Operation {
|
|
6
6
|
private rounds: number = 10
|
|
7
7
|
private pepper: string = ''
|
|
8
|
-
private principal?:
|
|
8
|
+
private principal?: Principal
|
|
9
9
|
private tokens: Tokens = undefined as unknown as Tokens
|
|
10
|
+
private keys: Keys = undefined as unknown as Keys
|
|
10
11
|
private usernameRx: RegExp[] = []
|
|
11
12
|
private passwordRx: RegExp[] = []
|
|
12
13
|
|
|
@@ -15,11 +16,18 @@ export class Transition implements Operation {
|
|
|
15
16
|
this.pepper = context.configuration.pepper?.unwrap() ?? ''
|
|
16
17
|
this.principal = context.configuration.principal
|
|
17
18
|
this.tokens = context.remote.identity.tokens
|
|
19
|
+
this.keys = context.remote.identity.keys
|
|
18
20
|
|
|
19
21
|
this.usernameRx = toRx(context.configuration.username)
|
|
20
22
|
this.passwordRx = toRx(context.configuration.password)
|
|
21
23
|
}
|
|
22
24
|
|
|
25
|
+
private locked (object: Entity): boolean {
|
|
26
|
+
return this.principal !== undefined &&
|
|
27
|
+
object.authority === this.principal.authority &&
|
|
28
|
+
object.username === this.principal.username
|
|
29
|
+
}
|
|
30
|
+
|
|
23
31
|
public async execute (input: TransitInput, object: Entity): Promise<Maybe<IdOutput>> {
|
|
24
32
|
const deleted = object._deleted !== undefined && object._deleted !== null
|
|
25
33
|
const existent = object._version !== 0 && !deleted
|
|
@@ -28,12 +36,15 @@ export class Transition implements Operation {
|
|
|
28
36
|
if (input.inception === true)
|
|
29
37
|
return ERR_EXISTS
|
|
30
38
|
|
|
31
|
-
await
|
|
39
|
+
await Promise.all([
|
|
40
|
+
this.tokens.revoke({ query: { id: object.id } }),
|
|
41
|
+
this.keys.revoke({ input: { identity: object.id } })
|
|
42
|
+
])
|
|
32
43
|
} else
|
|
33
44
|
object.authority = input.authority
|
|
34
45
|
|
|
35
46
|
if (input.username !== undefined) {
|
|
36
|
-
if (existent &&
|
|
47
|
+
if (existent && this.locked(object))
|
|
37
48
|
return ERR_PRINCIPAL_LOCKED
|
|
38
49
|
|
|
39
50
|
if (invalid(input.username, this.usernameRx))
|
|
@@ -85,3 +96,4 @@ const ERR_EXISTS = new (class ExistsError extends Error {
|
|
|
85
96
|
})()
|
|
86
97
|
|
|
87
98
|
type Tokens = Context['remote']['identity']['tokens']
|
|
99
|
+
type Keys = Context['remote']['identity']['keys']
|
|
@@ -12,17 +12,25 @@ export interface Context {
|
|
|
12
12
|
tokens: {
|
|
13
13
|
revoke: Call<void, IdentityTokensRevokeInput>
|
|
14
14
|
}
|
|
15
|
+
keys: {
|
|
16
|
+
revoke: Call<void, IdentityKeysRevokeInput>
|
|
17
|
+
}
|
|
15
18
|
}
|
|
16
19
|
}
|
|
17
20
|
configuration: {
|
|
18
21
|
readonly rounds: number
|
|
19
22
|
readonly pepper?: Secret
|
|
20
|
-
readonly principal?:
|
|
23
|
+
readonly principal?: Principal
|
|
21
24
|
readonly username: string[]
|
|
22
25
|
readonly password: string[]
|
|
23
26
|
}
|
|
24
27
|
}
|
|
25
28
|
|
|
29
|
+
export interface Principal {
|
|
30
|
+
authority: string
|
|
31
|
+
username: string
|
|
32
|
+
}
|
|
33
|
+
|
|
26
34
|
export interface Entity {
|
|
27
35
|
id: string
|
|
28
36
|
authority: string
|
|
@@ -55,3 +63,7 @@ export interface IdOutput {
|
|
|
55
63
|
interface IdentityTokensRevokeInput {
|
|
56
64
|
query: Query
|
|
57
65
|
}
|
|
66
|
+
|
|
67
|
+
interface IdentityKeysRevokeInput {
|
|
68
|
+
identity: string
|
|
69
|
+
}
|