@yielded/crypto 0.0.0-stage → 0.1.0-beta.20
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/LICENSE +21 -0
- package/README.md +39 -2
- package/THIRD_PARTY_NOTICES.md +378 -0
- package/dist/Aead.d.mts +34 -0
- package/dist/Aead.mjs +28 -0
- package/dist/Aead.mjs.map +1 -0
- package/dist/Errors.d.mts +20 -0
- package/dist/Errors.mjs +19 -0
- package/dist/Errors.mjs.map +1 -0
- package/dist/Hmac.d.mts +39 -0
- package/dist/Hmac.mjs +26 -0
- package/dist/Hmac.mjs.map +1 -0
- package/dist/Kdf.d.mts +54 -0
- package/dist/Kdf.mjs +78 -0
- package/dist/Kdf.mjs.map +1 -0
- package/dist/KdfAdmission.d.mts +24 -0
- package/dist/KdfAdmission.mjs +48 -0
- package/dist/KdfAdmission.mjs.map +1 -0
- package/dist/Portable.d.mts +11 -0
- package/dist/Portable.mjs +13 -0
- package/dist/Portable.mjs.map +1 -0
- package/dist/Signature.d.mts +70 -0
- package/dist/Signature.mjs +73 -0
- package/dist/Signature.mjs.map +1 -0
- package/dist/WebCrypto.d.mts +20 -0
- package/dist/WebCrypto.mjs +33 -0
- package/dist/WebCrypto.mjs.map +1 -0
- package/dist/index.d.mts +7 -0
- package/dist/index.mjs +7 -0
- package/dist/internal/aead.mjs +81 -0
- package/dist/internal/aead.mjs.map +1 -0
- package/dist/internal/argon2-core.mjs +293 -0
- package/dist/internal/argon2-core.mjs.map +1 -0
- package/dist/internal/argon2.mjs +16 -0
- package/dist/internal/argon2.mjs.map +1 -0
- package/dist/internal/blake2b.mjs +359 -0
- package/dist/internal/blake2b.mjs.map +1 -0
- package/dist/internal/common.mjs +20 -0
- package/dist/internal/common.mjs.map +1 -0
- package/dist/internal/hmac.mjs +68 -0
- package/dist/internal/hmac.mjs.map +1 -0
- package/dist/internal/kdf.mjs +99 -0
- package/dist/internal/kdf.mjs.map +1 -0
- package/dist/internal/layer.mjs +26 -0
- package/dist/internal/layer.mjs.map +1 -0
- package/dist/internal/node.d.mts +11 -0
- package/dist/internal/node.mjs +34 -0
- package/dist/internal/node.mjs.map +1 -0
- package/dist/internal/poly1305.mjs +247 -0
- package/dist/internal/poly1305.mjs.map +1 -0
- package/dist/internal/signature.mjs +140 -0
- package/dist/internal/signature.mjs.map +1 -0
- package/dist/internal/word64.mjs +25 -0
- package/dist/internal/word64.mjs.map +1 -0
- package/dist/internal/xchacha-core.mjs +285 -0
- package/dist/internal/xchacha-core.mjs.map +1 -0
- package/dist/internal/xchacha.mjs +21 -0
- package/dist/internal/xchacha.mjs.map +1 -0
- package/dist/platform-bun.d.mts +2 -0
- package/dist/platform-bun.mjs +2 -0
- package/dist/platform-node.d.mts +2 -0
- package/dist/platform-node.mjs +2 -0
- package/package.json +1 -6
- package/src/Aead.ts +39 -0
- package/src/Errors.ts +27 -0
- package/src/Hmac.ts +41 -0
- package/src/Kdf.ts +87 -0
- package/src/KdfAdmission.ts +87 -0
- package/src/Portable.ts +8 -0
- package/src/Signature.ts +87 -0
- package/src/WebCrypto.ts +46 -0
- package/src/index.ts +6 -0
- package/src/internal/aead.ts +119 -0
- package/src/internal/argon2-core.ts +470 -0
- package/src/internal/argon2.ts +23 -0
- package/src/internal/blake2b.ts +230 -0
- package/src/internal/common.ts +44 -0
- package/src/internal/hmac.ts +111 -0
- package/src/internal/kdf.ts +150 -0
- package/src/internal/layer.ts +32 -0
- package/src/internal/node.ts +46 -0
- package/src/internal/poly1305.ts +289 -0
- package/src/internal/signature.ts +188 -0
- package/src/internal/word64.ts +48 -0
- package/src/internal/xchacha-core.ts +397 -0
- package/src/internal/xchacha.ts +26 -0
- package/src/platform-bun.ts +2 -0
- package/src/platform-node.ts +2 -0
package/dist/Kdf.d.mts
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { KdfBusy, OperationError } from "./Errors.mjs";
|
|
2
|
+
import { Context, Effect, Redacted, Schema } from "effect";
|
|
3
|
+
//#region src/Kdf.d.ts
|
|
4
|
+
export declare const Argon2idInput: Schema.Struct<{
|
|
5
|
+
readonly password: Schema.Redacted<Schema.Uint8Array>;
|
|
6
|
+
readonly salt: Schema.Uint8Array;
|
|
7
|
+
readonly memoryKiB: Schema.Int;
|
|
8
|
+
readonly passes: Schema.Int;
|
|
9
|
+
readonly parallelism: Schema.Int;
|
|
10
|
+
readonly length: Schema.Int;
|
|
11
|
+
readonly secret: Schema.optionalKey<Schema.Redacted<Schema.Uint8Array>>;
|
|
12
|
+
readonly associatedData: Schema.optionalKey<Schema.Uint8Array>;
|
|
13
|
+
}>;
|
|
14
|
+
export type Argon2idInput = typeof Argon2idInput.Type;
|
|
15
|
+
export declare const Pbkdf2Input: Schema.Struct<{
|
|
16
|
+
readonly password: Schema.Redacted<Schema.Uint8Array>;
|
|
17
|
+
readonly salt: Schema.Uint8Array;
|
|
18
|
+
readonly iterations: Schema.Int;
|
|
19
|
+
readonly length: Schema.Int;
|
|
20
|
+
}>;
|
|
21
|
+
export type Pbkdf2Input = typeof Pbkdf2Input.Type;
|
|
22
|
+
export declare const HkdfInput: Schema.Struct<{
|
|
23
|
+
readonly key: Schema.Redacted<Schema.Uint8Array>;
|
|
24
|
+
readonly salt: Schema.Uint8Array;
|
|
25
|
+
readonly info: Schema.Uint8Array;
|
|
26
|
+
readonly length: Schema.Int;
|
|
27
|
+
}>;
|
|
28
|
+
export type HkdfInput = typeof HkdfInput.Type;
|
|
29
|
+
/** Resource ceilings, not a password-strength policy. Limits apply per permit. */
|
|
30
|
+
export declare const Limits: Schema.Struct<{
|
|
31
|
+
readonly maximumMemoryKiB: Schema.Int;
|
|
32
|
+
readonly maximumPasses: Schema.Int;
|
|
33
|
+
readonly maximumParallelism: Schema.Int;
|
|
34
|
+
readonly maximumMemoryPasses: Schema.Int;
|
|
35
|
+
readonly maximumIterations: Schema.Int;
|
|
36
|
+
readonly maximumInputBytes: Schema.Int;
|
|
37
|
+
readonly maximumOutputBytes: Schema.Int;
|
|
38
|
+
}>;
|
|
39
|
+
export type Limits = typeof Limits.Type;
|
|
40
|
+
export declare const defaultLimits: Limits;
|
|
41
|
+
declare const Kdf_base: Context.ServiceClass<Kdf, "@yielded/crypto/Kdf", {
|
|
42
|
+
readonly argon2id: (input: Argon2idInput) => Effect.Effect<Redacted.Redacted<Uint8Array>, OperationError | KdfBusy>;
|
|
43
|
+
readonly pbkdf2: (input: Pbkdf2Input) => Effect.Effect<Redacted.Redacted<Uint8Array>, OperationError | KdfBusy>;
|
|
44
|
+
readonly hkdf: (input: HkdfInput) => Effect.Effect<Redacted.Redacted<Uint8Array>, OperationError | KdfBusy>;
|
|
45
|
+
}>;
|
|
46
|
+
/**
|
|
47
|
+
* Byte-preserving derivation; no text normalization, PHC parsing or password policy.
|
|
48
|
+
* Argon2id uses version 19; PBKDF2 and HKDF use SHA-256. A backend captures shared
|
|
49
|
+
* KdfAdmission when its Layer is built and retains admission until work and cleanup
|
|
50
|
+
* finish, including when a native operation cannot be cancelled.
|
|
51
|
+
*/
|
|
52
|
+
export declare class Kdf extends Kdf_base {}
|
|
53
|
+
//#endregion
|
|
54
|
+
//# sourceMappingURL=Kdf.d.mts.map
|
package/dist/Kdf.mjs
ADDED
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { Context, Schema } from "effect";
|
|
2
|
+
//#region src/Kdf.ts
|
|
3
|
+
const positive = Schema.Int.check(Schema.isGreaterThan(0));
|
|
4
|
+
const uint32 = Schema.Int.check(Schema.isBetween({
|
|
5
|
+
minimum: 1,
|
|
6
|
+
maximum: 4294967295
|
|
7
|
+
}));
|
|
8
|
+
const bytes = Schema.Uint8Array;
|
|
9
|
+
const secret = Schema.Redacted(bytes, { disallowJsonEncode: true });
|
|
10
|
+
const argon2Bytes = bytes.check(Schema.isMaxLength(4294967295));
|
|
11
|
+
const argon2Secret = Schema.Redacted(argon2Bytes, { disallowJsonEncode: true });
|
|
12
|
+
const Argon2idInput = Schema.Struct({
|
|
13
|
+
password: argon2Secret,
|
|
14
|
+
salt: argon2Bytes.check(Schema.isMinLength(8)),
|
|
15
|
+
memoryKiB: uint32,
|
|
16
|
+
passes: uint32,
|
|
17
|
+
parallelism: Schema.Int.check(Schema.isBetween({
|
|
18
|
+
minimum: 1,
|
|
19
|
+
maximum: 16777215
|
|
20
|
+
})),
|
|
21
|
+
length: Schema.Int.check(Schema.isBetween({
|
|
22
|
+
minimum: 4,
|
|
23
|
+
maximum: 4294967295
|
|
24
|
+
})),
|
|
25
|
+
secret: Schema.optionalKey(argon2Secret),
|
|
26
|
+
associatedData: Schema.optionalKey(argon2Bytes)
|
|
27
|
+
});
|
|
28
|
+
const Pbkdf2Input = Schema.Struct({
|
|
29
|
+
password: secret,
|
|
30
|
+
salt: bytes,
|
|
31
|
+
iterations: Schema.Int.check(Schema.isBetween({
|
|
32
|
+
minimum: 1,
|
|
33
|
+
maximum: 2147483647
|
|
34
|
+
})),
|
|
35
|
+
length: Schema.Int.check(Schema.isBetween({
|
|
36
|
+
minimum: 1,
|
|
37
|
+
maximum: 536870911
|
|
38
|
+
}))
|
|
39
|
+
});
|
|
40
|
+
const HkdfInput = Schema.Struct({
|
|
41
|
+
key: secret,
|
|
42
|
+
salt: bytes,
|
|
43
|
+
info: bytes.check(Schema.isMaxLength(1024)),
|
|
44
|
+
length: Schema.Int.check(Schema.isBetween({
|
|
45
|
+
minimum: 1,
|
|
46
|
+
maximum: 8160
|
|
47
|
+
}))
|
|
48
|
+
});
|
|
49
|
+
/** Resource ceilings, not a password-strength policy. Limits apply per permit. */
|
|
50
|
+
const Limits = Schema.Struct({
|
|
51
|
+
maximumMemoryKiB: positive,
|
|
52
|
+
maximumPasses: positive,
|
|
53
|
+
maximumParallelism: positive,
|
|
54
|
+
maximumMemoryPasses: positive,
|
|
55
|
+
maximumIterations: positive,
|
|
56
|
+
maximumInputBytes: positive,
|
|
57
|
+
maximumOutputBytes: positive
|
|
58
|
+
});
|
|
59
|
+
const defaultLimits = Object.freeze({
|
|
60
|
+
maximumMemoryKiB: 65536,
|
|
61
|
+
maximumPasses: 6,
|
|
62
|
+
maximumParallelism: 4,
|
|
63
|
+
maximumMemoryPasses: 131072,
|
|
64
|
+
maximumIterations: 1e6,
|
|
65
|
+
maximumInputBytes: 65536,
|
|
66
|
+
maximumOutputBytes: 1024
|
|
67
|
+
});
|
|
68
|
+
/**
|
|
69
|
+
* Byte-preserving derivation; no text normalization, PHC parsing or password policy.
|
|
70
|
+
* Argon2id uses version 19; PBKDF2 and HKDF use SHA-256. A backend captures shared
|
|
71
|
+
* KdfAdmission when its Layer is built and retains admission until work and cleanup
|
|
72
|
+
* finish, including when a native operation cannot be cancelled.
|
|
73
|
+
*/
|
|
74
|
+
var Kdf = class extends Context.Service()("@yielded/crypto/Kdf") {};
|
|
75
|
+
//#endregion
|
|
76
|
+
export { Argon2idInput, HkdfInput, Kdf, Limits, Pbkdf2Input, defaultLimits };
|
|
77
|
+
|
|
78
|
+
//# sourceMappingURL=Kdf.mjs.map
|
package/dist/Kdf.mjs.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Kdf.mjs","names":[],"sources":["../src/Kdf.ts"],"sourcesContent":["import { Context, type Effect, type Redacted, Schema } from \"effect\";\n\nimport type { KdfBusy, OperationError } from \"./Errors\";\n\nconst positive = Schema.Int.check(Schema.isGreaterThan(0));\nconst uint32 = Schema.Int.check(Schema.isBetween({ minimum: 1, maximum: 0xffffffff }));\nconst bytes = Schema.Uint8Array;\nconst secret = Schema.Redacted(bytes, { disallowJsonEncode: true });\nconst argon2Bytes = bytes.check(Schema.isMaxLength(0xffffffff));\nconst argon2Secret = Schema.Redacted(argon2Bytes, { disallowJsonEncode: true });\n\nexport const Argon2idInput = Schema.Struct({\n password: argon2Secret,\n salt: argon2Bytes.check(Schema.isMinLength(8)),\n memoryKiB: uint32,\n passes: uint32,\n parallelism: Schema.Int.check(Schema.isBetween({ minimum: 1, maximum: 0xffffff })),\n length: Schema.Int.check(Schema.isBetween({ minimum: 4, maximum: 0xffffffff })),\n secret: Schema.optionalKey(argon2Secret),\n associatedData: Schema.optionalKey(argon2Bytes),\n});\n\nexport type Argon2idInput = typeof Argon2idInput.Type;\n\nexport const Pbkdf2Input = Schema.Struct({\n password: secret,\n salt: bytes,\n // Native Node/Bun PBKDF2 accepts a positive signed 32-bit iteration count.\n iterations: Schema.Int.check(Schema.isBetween({ minimum: 1, maximum: 0x7fffffff })),\n // WebCrypto takes an unsigned 32-bit bit count; this API takes whole bytes.\n length: Schema.Int.check(Schema.isBetween({ minimum: 1, maximum: 0x1fffffff })),\n});\n\nexport type Pbkdf2Input = typeof Pbkdf2Input.Type;\n\nexport const HkdfInput = Schema.Struct({\n key: secret,\n salt: bytes,\n info: bytes.check(Schema.isMaxLength(1024)),\n length: Schema.Int.check(Schema.isBetween({ minimum: 1, maximum: 255 * 32 })),\n});\n\nexport type HkdfInput = typeof HkdfInput.Type;\n\n/** Resource ceilings, not a password-strength policy. Limits apply per permit. */\nexport const Limits = Schema.Struct({\n maximumMemoryKiB: positive,\n maximumPasses: positive,\n maximumParallelism: positive,\n maximumMemoryPasses: positive,\n maximumIterations: positive,\n maximumInputBytes: positive,\n maximumOutputBytes: positive,\n});\n\nexport type Limits = typeof Limits.Type;\n\nexport const defaultLimits: Limits = Object.freeze({\n maximumMemoryKiB: 65536,\n maximumPasses: 6,\n maximumParallelism: 4,\n maximumMemoryPasses: 131072,\n maximumIterations: 1000000,\n maximumInputBytes: 65536,\n maximumOutputBytes: 1024,\n});\n\n/**\n * Byte-preserving derivation; no text normalization, PHC parsing or password policy.\n * Argon2id uses version 19; PBKDF2 and HKDF use SHA-256. A backend captures shared\n * KdfAdmission when its Layer is built and retains admission until work and cleanup\n * finish, including when a native operation cannot be cancelled.\n */\nexport class Kdf extends Context.Service<\n Kdf,\n {\n readonly argon2id: (\n input: Argon2idInput,\n ) => Effect.Effect<Redacted.Redacted<Uint8Array>, OperationError | KdfBusy>;\n readonly pbkdf2: (\n input: Pbkdf2Input,\n ) => Effect.Effect<Redacted.Redacted<Uint8Array>, OperationError | KdfBusy>;\n readonly hkdf: (\n input: HkdfInput,\n ) => Effect.Effect<Redacted.Redacted<Uint8Array>, OperationError | KdfBusy>;\n }\n>()(\"@yielded/crypto/Kdf\") {}\n"],"mappings":";;AAIA,MAAM,WAAW,OAAO,IAAI,MAAM,OAAO,cAAc,CAAC,CAAC;AACzD,MAAM,SAAS,OAAO,IAAI,MAAM,OAAO,UAAU;CAAE,SAAS;CAAG,SAAS;AAAW,CAAC,CAAC;AACrF,MAAM,QAAQ,OAAO;AACrB,MAAM,SAAS,OAAO,SAAS,OAAO,EAAE,oBAAoB,KAAK,CAAC;AAClE,MAAM,cAAc,MAAM,MAAM,OAAO,YAAY,UAAU,CAAC;AAC9D,MAAM,eAAe,OAAO,SAAS,aAAa,EAAE,oBAAoB,KAAK,CAAC;AAE9E,MAAa,gBAAgB,OAAO,OAAO;CACzC,UAAU;CACV,MAAM,YAAY,MAAM,OAAO,YAAY,CAAC,CAAC;CAC7C,WAAW;CACX,QAAQ;CACR,aAAa,OAAO,IAAI,MAAM,OAAO,UAAU;EAAE,SAAS;EAAG,SAAS;CAAS,CAAC,CAAC;CACjF,QAAQ,OAAO,IAAI,MAAM,OAAO,UAAU;EAAE,SAAS;EAAG,SAAS;CAAW,CAAC,CAAC;CAC9E,QAAQ,OAAO,YAAY,YAAY;CACvC,gBAAgB,OAAO,YAAY,WAAW;AAChD,CAAC;AAID,MAAa,cAAc,OAAO,OAAO;CACvC,UAAU;CACV,MAAM;CAEN,YAAY,OAAO,IAAI,MAAM,OAAO,UAAU;EAAE,SAAS;EAAG,SAAS;CAAW,CAAC,CAAC;CAElF,QAAQ,OAAO,IAAI,MAAM,OAAO,UAAU;EAAE,SAAS;EAAG,SAAS;CAAW,CAAC,CAAC;AAChF,CAAC;AAID,MAAa,YAAY,OAAO,OAAO;CACrC,KAAK;CACL,MAAM;CACN,MAAM,MAAM,MAAM,OAAO,YAAY,IAAI,CAAC;CAC1C,QAAQ,OAAO,IAAI,MAAM,OAAO,UAAU;EAAE,SAAS;EAAG,SAAS;CAAS,CAAC,CAAC;AAC9E,CAAC;;AAKD,MAAa,SAAS,OAAO,OAAO;CAClC,kBAAkB;CAClB,eAAe;CACf,oBAAoB;CACpB,qBAAqB;CACrB,mBAAmB;CACnB,mBAAmB;CACnB,oBAAoB;AACtB,CAAC;AAID,MAAa,gBAAwB,OAAO,OAAO;CACjD,kBAAkB;CAClB,eAAe;CACf,oBAAoB;CACpB,qBAAqB;CACrB,mBAAmB;CACnB,mBAAmB;CACnB,oBAAoB;AACtB,CAAC;;;;;;;AAQD,IAAa,MAAb,cAAyB,QAAQ,QAa/B,CAAC,CAAC,qBAAqB,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { InvalidInput, KdfBusy } from "./Errors.mjs";
|
|
2
|
+
import { Context, Effect, Layer } from "effect";
|
|
3
|
+
//#region src/KdfAdmission.d.ts
|
|
4
|
+
export interface Options {
|
|
5
|
+
readonly concurrency?: number;
|
|
6
|
+
readonly maxQueued?: number;
|
|
7
|
+
readonly maxWaitMilliseconds?: number;
|
|
8
|
+
}
|
|
9
|
+
declare const KdfAdmission_base: Context.ServiceClass<KdfAdmission, "@yielded/crypto/KdfAdmission", {
|
|
10
|
+
readonly run: <A, E, R>(work: Effect.Effect<A, E, R>) => Effect.Effect<A, E | KdfBusy, R>;
|
|
11
|
+
}>;
|
|
12
|
+
/** Share one Layer across all backend instances to bound actual KDF work. */
|
|
13
|
+
export declare class KdfAdmission extends KdfAdmission_base {}
|
|
14
|
+
/**
|
|
15
|
+
* Waiting is interruptible and bounded. The permit covers work and its cleanup;
|
|
16
|
+
* backends protect nonabortable native calls until actual completion. Owned
|
|
17
|
+
* interruptible work can stop and release its resources without finishing a KDF.
|
|
18
|
+
* Nested work in the same fiber shares its permit through scoped cleanup; forked
|
|
19
|
+
* fibers must acquire their own. This covers preparation and cleanup around a KDF.
|
|
20
|
+
* Defaults: one running derivation, sixteen waiting, five-second acquisition wait.
|
|
21
|
+
*/
|
|
22
|
+
export declare const layer: (options?: Options) => Layer.Layer<KdfAdmission, InvalidInput>;
|
|
23
|
+
//#endregion
|
|
24
|
+
//# sourceMappingURL=KdfAdmission.d.mts.map
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { InvalidInput, KdfBusy } from "./Errors.mjs";
|
|
2
|
+
import { Context, Effect, Layer, Option, Schema, Semaphore } from "effect";
|
|
3
|
+
//#region src/KdfAdmission.ts
|
|
4
|
+
/** Share one Layer across all backend instances to bound actual KDF work. */
|
|
5
|
+
var KdfAdmission = class extends Context.Service()("@yielded/crypto/KdfAdmission") {};
|
|
6
|
+
const Configuration = Schema.Struct({
|
|
7
|
+
concurrency: Schema.Int.check(Schema.isBetween({
|
|
8
|
+
minimum: 1,
|
|
9
|
+
maximum: 32
|
|
10
|
+
})),
|
|
11
|
+
maxQueued: Schema.Int.check(Schema.isGreaterThanOrEqualTo(0)),
|
|
12
|
+
maxWaitMilliseconds: Schema.Int.check(Schema.isGreaterThan(0))
|
|
13
|
+
});
|
|
14
|
+
/**
|
|
15
|
+
* Waiting is interruptible and bounded. The permit covers work and its cleanup;
|
|
16
|
+
* backends protect nonabortable native calls until actual completion. Owned
|
|
17
|
+
* interruptible work can stop and release its resources without finishing a KDF.
|
|
18
|
+
* Nested work in the same fiber shares its permit through scoped cleanup; forked
|
|
19
|
+
* fibers must acquire their own. This covers preparation and cleanup around a KDF.
|
|
20
|
+
* Defaults: one running derivation, sixteen waiting, five-second acquisition wait.
|
|
21
|
+
*/
|
|
22
|
+
const layer = (options = {}) => {
|
|
23
|
+
const snapshot = {
|
|
24
|
+
concurrency: options.concurrency ?? 1,
|
|
25
|
+
maxQueued: options.maxQueued ?? 16,
|
|
26
|
+
maxWaitMilliseconds: options.maxWaitMilliseconds ?? 5e3
|
|
27
|
+
};
|
|
28
|
+
return Layer.effect(KdfAdmission, Effect.gen(function* () {
|
|
29
|
+
const config = yield* Schema.decodeEffect(Configuration)(snapshot).pipe(Effect.mapError(() => InvalidInput.make({ reason: "parameters" })));
|
|
30
|
+
const capacity = yield* Schema.decodeEffect(Schema.Int)(config.concurrency + config.maxQueued).pipe(Effect.mapError(() => InvalidInput.make({ reason: "parameters" })));
|
|
31
|
+
const active = yield* Semaphore.make(config.concurrency);
|
|
32
|
+
const admitted = yield* Semaphore.make(capacity);
|
|
33
|
+
const owners = /* @__PURE__ */ new Set();
|
|
34
|
+
const acquire = Effect.acquireRelease(active.take(1), () => active.release(1), { interruptible: true }).pipe(Effect.timeoutOrElse({
|
|
35
|
+
duration: config.maxWaitMilliseconds,
|
|
36
|
+
orElse: () => Effect.fail(KdfBusy.make({}))
|
|
37
|
+
}));
|
|
38
|
+
return KdfAdmission.of({ run: (work) => Effect.withFiber((fiber) => {
|
|
39
|
+
if (owners.has(fiber.id)) return work;
|
|
40
|
+
const owned = Effect.acquireRelease(Effect.sync(() => owners.add(fiber.id)), () => Effect.sync(() => owners.delete(fiber.id))).pipe(Effect.andThen(work));
|
|
41
|
+
return admitted.withPermitsIfAvailable(1)(Effect.scoped(Effect.andThen(acquire, owned))).pipe(Effect.flatMap((result) => Option.isSome(result) ? Effect.succeed(result.value) : Effect.fail(KdfBusy.make({}))));
|
|
42
|
+
}) });
|
|
43
|
+
}));
|
|
44
|
+
};
|
|
45
|
+
//#endregion
|
|
46
|
+
export { KdfAdmission, layer };
|
|
47
|
+
|
|
48
|
+
//# sourceMappingURL=KdfAdmission.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"KdfAdmission.mjs","names":[],"sources":["../src/KdfAdmission.ts"],"sourcesContent":["import { Context, Effect, Layer, Option, Schema, Semaphore } from \"effect\";\n\nimport { InvalidInput, KdfBusy } from \"./Errors\";\n\nexport interface Options {\n readonly concurrency?: number;\n readonly maxQueued?: number;\n readonly maxWaitMilliseconds?: number;\n}\n\n/** Share one Layer across all backend instances to bound actual KDF work. */\nexport class KdfAdmission extends Context.Service<\n KdfAdmission,\n {\n readonly run: <A, E, R>(work: Effect.Effect<A, E, R>) => Effect.Effect<A, E | KdfBusy, R>;\n }\n>()(\"@yielded/crypto/KdfAdmission\") {}\n\nconst Configuration = Schema.Struct({\n concurrency: Schema.Int.check(Schema.isBetween({ minimum: 1, maximum: 32 })),\n maxQueued: Schema.Int.check(Schema.isGreaterThanOrEqualTo(0)),\n maxWaitMilliseconds: Schema.Int.check(Schema.isGreaterThan(0)),\n});\n\n/**\n * Waiting is interruptible and bounded. The permit covers work and its cleanup;\n * backends protect nonabortable native calls until actual completion. Owned\n * interruptible work can stop and release its resources without finishing a KDF.\n * Nested work in the same fiber shares its permit through scoped cleanup; forked\n * fibers must acquire their own. This covers preparation and cleanup around a KDF.\n * Defaults: one running derivation, sixteen waiting, five-second acquisition wait.\n */\nexport const layer = (options: Options = {}): Layer.Layer<KdfAdmission, InvalidInput> => {\n const snapshot = {\n concurrency: options.concurrency ?? 1,\n maxQueued: options.maxQueued ?? 16,\n maxWaitMilliseconds: options.maxWaitMilliseconds ?? 5000,\n };\n\n return Layer.effect(\n KdfAdmission,\n Effect.gen(function* () {\n const config = yield* Schema.decodeEffect(Configuration)(snapshot).pipe(\n Effect.mapError(() => InvalidInput.make({ reason: \"parameters\" })),\n );\n\n const capacity = yield* Schema.decodeEffect(Schema.Int)(\n config.concurrency + config.maxQueued,\n ).pipe(Effect.mapError(() => InvalidInput.make({ reason: \"parameters\" })));\n\n const active = yield* Semaphore.make(config.concurrency);\n const admitted = yield* Semaphore.make(capacity);\n const owners = new Set<number>();\n\n const acquire = Effect.acquireRelease(active.take(1), () => active.release(1), {\n interruptible: true,\n }).pipe(\n Effect.timeoutOrElse({\n duration: config.maxWaitMilliseconds,\n orElse: () => Effect.fail(KdfBusy.make({})),\n }),\n );\n\n return KdfAdmission.of({\n run: <A, E, R>(work: Effect.Effect<A, E, R>) =>\n Effect.withFiber((fiber) => {\n if (owners.has(fiber.id)) return work;\n\n const owned = Effect.acquireRelease(\n Effect.sync(() => owners.add(fiber.id)),\n () => Effect.sync(() => owners.delete(fiber.id)),\n ).pipe(Effect.andThen(work));\n\n return admitted\n .withPermitsIfAvailable(1)(Effect.scoped(Effect.andThen(acquire, owned)))\n .pipe(\n Effect.flatMap((result) =>\n Option.isSome(result)\n ? Effect.succeed(result.value)\n : Effect.fail(KdfBusy.make({})),\n ),\n );\n }),\n });\n }),\n );\n};\n"],"mappings":";;;;AAWA,IAAa,eAAb,cAAkC,QAAQ,QAKxC,CAAC,CAAC,8BAA8B,CAAC,CAAC,CAAC;AAErC,MAAM,gBAAgB,OAAO,OAAO;CAClC,aAAa,OAAO,IAAI,MAAM,OAAO,UAAU;EAAE,SAAS;EAAG,SAAS;CAAG,CAAC,CAAC;CAC3E,WAAW,OAAO,IAAI,MAAM,OAAO,uBAAuB,CAAC,CAAC;CAC5D,qBAAqB,OAAO,IAAI,MAAM,OAAO,cAAc,CAAC,CAAC;AAC/D,CAAC;;;;;;;;;AAUD,MAAa,SAAS,UAAmB,CAAC,MAA+C;CACvF,MAAM,WAAW;EACf,aAAa,QAAQ,eAAe;EACpC,WAAW,QAAQ,aAAa;EAChC,qBAAqB,QAAQ,uBAAuB;CACtD;CAEA,OAAO,MAAM,OACX,cACA,OAAO,IAAI,aAAa;EACtB,MAAM,SAAS,OAAO,OAAO,aAAa,aAAa,CAAC,CAAC,QAAQ,CAAC,CAAC,KACjE,OAAO,eAAe,aAAa,KAAK,EAAE,QAAQ,aAAa,CAAC,CAAC,CACnE;EAEA,MAAM,WAAW,OAAO,OAAO,aAAa,OAAO,GAAG,CAAC,CACrD,OAAO,cAAc,OAAO,SAC9B,CAAC,CAAC,KAAK,OAAO,eAAe,aAAa,KAAK,EAAE,QAAQ,aAAa,CAAC,CAAC,CAAC;EAEzE,MAAM,SAAS,OAAO,UAAU,KAAK,OAAO,WAAW;EACvD,MAAM,WAAW,OAAO,UAAU,KAAK,QAAQ;EAC/C,MAAM,yBAAS,IAAI,IAAY;EAE/B,MAAM,UAAU,OAAO,eAAe,OAAO,KAAK,CAAC,SAAS,OAAO,QAAQ,CAAC,GAAG,EAC7E,eAAe,KACjB,CAAC,CAAC,CAAC,KACD,OAAO,cAAc;GACnB,UAAU,OAAO;GACjB,cAAc,OAAO,KAAK,QAAQ,KAAK,CAAC,CAAC,CAAC;EAC5C,CAAC,CACH;EAEA,OAAO,aAAa,GAAG,EACrB,MAAe,SACb,OAAO,WAAW,UAAU;GAC1B,IAAI,OAAO,IAAI,MAAM,EAAE,GAAG,OAAO;GAEjC,MAAM,QAAQ,OAAO,eACnB,OAAO,WAAW,OAAO,IAAI,MAAM,EAAE,CAAC,SAChC,OAAO,WAAW,OAAO,OAAO,MAAM,EAAE,CAAC,CACjD,CAAC,CAAC,KAAK,OAAO,QAAQ,IAAI,CAAC;GAE3B,OAAO,SACJ,uBAAuB,CAAC,CAAC,CAAC,OAAO,OAAO,OAAO,QAAQ,SAAS,KAAK,CAAC,CAAC,CAAC,CACxE,KACC,OAAO,SAAS,WACd,OAAO,OAAO,MAAM,IAChB,OAAO,QAAQ,OAAO,KAAK,IAC3B,OAAO,KAAK,QAAQ,KAAK,CAAC,CAAC,CAAC,CAClC,CACF;EACJ,CAAC,EACL,CAAC;CACH,CAAC,CACH;AACF"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { InvalidInput } from "./Errors.mjs";
|
|
2
|
+
import { Aead } from "./Aead.mjs";
|
|
3
|
+
import { Hmac } from "./Hmac.mjs";
|
|
4
|
+
import { Kdf, Limits } from "./Kdf.mjs";
|
|
5
|
+
import { KdfAdmission } from "./KdfAdmission.mjs";
|
|
6
|
+
import { Signature } from "./Signature.mjs";
|
|
7
|
+
//#region src/Portable.d.ts
|
|
8
|
+
/** WebCrypto with owned, portable Argon2id and XChaCha20-Poly1305 implementations. */
|
|
9
|
+
export declare const layer: (subtle: SubtleCrypto, limits?: Partial<Limits>) => import("effect/Layer").Layer<Aead | Hmac | Kdf | Signature, InvalidInput, KdfAdmission>;
|
|
10
|
+
//#endregion
|
|
11
|
+
//# sourceMappingURL=Portable.d.mts.map
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { makeLayer } from "./internal/layer.mjs";
|
|
2
|
+
import { xchacha } from "./internal/xchacha.mjs";
|
|
3
|
+
import { argon2 } from "./internal/argon2.mjs";
|
|
4
|
+
//#region src/Portable.ts
|
|
5
|
+
/** WebCrypto with owned, portable Argon2id and XChaCha20-Poly1305 implementations. */
|
|
6
|
+
const layer = (subtle, limits = {}) => makeLayer(subtle, limits, {
|
|
7
|
+
argon2,
|
|
8
|
+
xchacha
|
|
9
|
+
});
|
|
10
|
+
//#endregion
|
|
11
|
+
export { layer };
|
|
12
|
+
|
|
13
|
+
//# sourceMappingURL=Portable.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Portable.mjs","names":[],"sources":["../src/Portable.ts"],"sourcesContent":["import { argon2 } from \"./internal/argon2\";\nimport { makeLayer } from \"./internal/layer\";\nimport { xchacha } from \"./internal/xchacha\";\nimport type { Limits } from \"./Kdf\";\n\n/** WebCrypto with owned, portable Argon2id and XChaCha20-Poly1305 implementations. */\nexport const layer = (subtle: SubtleCrypto, limits: Partial<Limits> = {}) =>\n makeLayer(subtle, limits, { argon2, xchacha });\n"],"mappings":";;;;;AAMA,MAAa,SAAS,QAAsB,SAA0B,CAAC,MACrE,UAAU,QAAQ,QAAQ;CAAE;CAAQ;AAAQ,CAAC"}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { OperationError } from "./Errors.mjs";
|
|
2
|
+
import { Context, Effect, Redacted, Schema } from "effect";
|
|
3
|
+
//#region src/Signature.d.ts
|
|
4
|
+
export declare const Algorithm: Schema.Literals<readonly ["ECDSA-P256-SHA256", "RSASSA-PKCS1-v1_5-SHA256", "RSA-PSS-SHA256", "Ed25519"]>;
|
|
5
|
+
export type Algorithm = typeof Algorithm.Type;
|
|
6
|
+
/**
|
|
7
|
+
* Unsigned big-endian components: 32-byte curve values and RSA components up to
|
|
8
|
+
* 1024 bytes. Native import validates the actual key, including RSA's minimum.
|
|
9
|
+
*/
|
|
10
|
+
export declare const PublicKeyParameters: Schema.Union<readonly [Schema.Struct<{
|
|
11
|
+
algorithm: Schema.Literal<"ECDSA-P256-SHA256">;
|
|
12
|
+
x: Schema.Uint8Array;
|
|
13
|
+
y: Schema.Uint8Array;
|
|
14
|
+
}>, Schema.Struct<{
|
|
15
|
+
algorithm: Schema.Literal<"Ed25519">;
|
|
16
|
+
x: Schema.Uint8Array;
|
|
17
|
+
}>, Schema.Struct<{
|
|
18
|
+
algorithm: Schema.Literals<readonly ["RSASSA-PKCS1-v1_5-SHA256", "RSA-PSS-SHA256"]>;
|
|
19
|
+
n: Schema.Uint8Array;
|
|
20
|
+
e: Schema.Uint8Array;
|
|
21
|
+
}>]>;
|
|
22
|
+
export type PublicKeyParameters = typeof PublicKeyParameters.Type;
|
|
23
|
+
export declare const PrivateKeyParameters: Schema.Union<readonly [Schema.Struct<{
|
|
24
|
+
readonly algorithm: Schema.Literal<"ECDSA-P256-SHA256">;
|
|
25
|
+
readonly x: Schema.Uint8Array;
|
|
26
|
+
readonly y: Schema.Uint8Array;
|
|
27
|
+
readonly d: Schema.Uint8Array;
|
|
28
|
+
}>, Schema.Struct<{
|
|
29
|
+
readonly algorithm: Schema.Literal<"Ed25519">;
|
|
30
|
+
readonly x: Schema.Uint8Array;
|
|
31
|
+
readonly d: Schema.Uint8Array;
|
|
32
|
+
}>, Schema.Struct<{
|
|
33
|
+
readonly algorithm: Schema.Literals<readonly ["RSASSA-PKCS1-v1_5-SHA256", "RSA-PSS-SHA256"]>;
|
|
34
|
+
readonly n: Schema.Uint8Array;
|
|
35
|
+
readonly e: Schema.Uint8Array;
|
|
36
|
+
readonly d: Schema.Uint8Array;
|
|
37
|
+
readonly p: Schema.Uint8Array;
|
|
38
|
+
readonly q: Schema.Uint8Array;
|
|
39
|
+
readonly dp: Schema.Uint8Array;
|
|
40
|
+
readonly dq: Schema.Uint8Array;
|
|
41
|
+
readonly qi: Schema.Uint8Array;
|
|
42
|
+
}>]>;
|
|
43
|
+
export type PrivateKeyParameters = typeof PrivateKeyParameters.Type;
|
|
44
|
+
export declare const SignInput: Schema.Struct<{
|
|
45
|
+
readonly algorithm: Schema.Literals<readonly ["ECDSA-P256-SHA256", "RSASSA-PKCS1-v1_5-SHA256", "RSA-PSS-SHA256", "Ed25519"]>;
|
|
46
|
+
readonly privateKey: Schema.Redacted<Schema.Uint8Array>;
|
|
47
|
+
readonly data: Schema.Uint8Array;
|
|
48
|
+
}>;
|
|
49
|
+
export type SignInput = typeof SignInput.Type;
|
|
50
|
+
export declare const VerifyInput: Schema.Struct<{
|
|
51
|
+
readonly algorithm: Schema.Literals<readonly ["ECDSA-P256-SHA256", "RSASSA-PKCS1-v1_5-SHA256", "RSA-PSS-SHA256", "Ed25519"]>;
|
|
52
|
+
readonly publicKey: Schema.Uint8Array;
|
|
53
|
+
readonly data: Schema.Uint8Array;
|
|
54
|
+
readonly signature: Schema.Uint8Array;
|
|
55
|
+
}>;
|
|
56
|
+
export type VerifyInput = typeof VerifyInput.Type;
|
|
57
|
+
declare const Signature_base: Context.ServiceClass<Signature, "@yielded/crypto/Signature", {
|
|
58
|
+
readonly encodePublicKey: (input: PublicKeyParameters) => Effect.Effect<Uint8Array, OperationError>;
|
|
59
|
+
readonly encodePrivateKey: (input: Redacted.Redacted<PrivateKeyParameters>) => Effect.Effect<Redacted.Redacted<Uint8Array>, OperationError>;
|
|
60
|
+
readonly sign: (input: SignInput) => Effect.Effect<Uint8Array, OperationError>;
|
|
61
|
+
readonly verify: (input: VerifyInput) => Effect.Effect<boolean, OperationError>;
|
|
62
|
+
}>;
|
|
63
|
+
/**
|
|
64
|
+
* Private keys are PKCS8 DER; public keys are SPKI DER. ECDSA signatures are
|
|
65
|
+
* 64-byte IEEE P1363 (r || s), not ASN.1 DER. RSA requires at least 2048 bits;
|
|
66
|
+
* PSS uses a 32-byte salt. Key serialization/selection and JOSE policy stay outside.
|
|
67
|
+
*/
|
|
68
|
+
export declare class Signature extends Signature_base {}
|
|
69
|
+
//#endregion
|
|
70
|
+
//# sourceMappingURL=Signature.d.mts.map
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { Context, Schema } from "effect";
|
|
2
|
+
//#region src/Signature.ts
|
|
3
|
+
const Algorithm = Schema.Literals([
|
|
4
|
+
"ECDSA-P256-SHA256",
|
|
5
|
+
"RSASSA-PKCS1-v1_5-SHA256",
|
|
6
|
+
"RSA-PSS-SHA256",
|
|
7
|
+
"Ed25519"
|
|
8
|
+
]);
|
|
9
|
+
const coordinate = Schema.Uint8Array.check(Schema.isMinLength(32), Schema.isMaxLength(32));
|
|
10
|
+
const integer = Schema.Uint8Array.check(Schema.isMinLength(1), Schema.isMaxLength(1024));
|
|
11
|
+
const ec = {
|
|
12
|
+
algorithm: Schema.Literal("ECDSA-P256-SHA256"),
|
|
13
|
+
x: coordinate,
|
|
14
|
+
y: coordinate
|
|
15
|
+
};
|
|
16
|
+
const ed = {
|
|
17
|
+
algorithm: Schema.Literal("Ed25519"),
|
|
18
|
+
x: coordinate
|
|
19
|
+
};
|
|
20
|
+
const rsa = {
|
|
21
|
+
algorithm: Schema.Literals(["RSASSA-PKCS1-v1_5-SHA256", "RSA-PSS-SHA256"]),
|
|
22
|
+
n: integer,
|
|
23
|
+
e: integer
|
|
24
|
+
};
|
|
25
|
+
/**
|
|
26
|
+
* Unsigned big-endian components: 32-byte curve values and RSA components up to
|
|
27
|
+
* 1024 bytes. Native import validates the actual key, including RSA's minimum.
|
|
28
|
+
*/
|
|
29
|
+
const PublicKeyParameters = Schema.Union([
|
|
30
|
+
Schema.Struct(ec),
|
|
31
|
+
Schema.Struct(ed),
|
|
32
|
+
Schema.Struct(rsa)
|
|
33
|
+
]);
|
|
34
|
+
const PrivateKeyParameters = Schema.Union([
|
|
35
|
+
Schema.Struct({
|
|
36
|
+
...ec,
|
|
37
|
+
d: coordinate
|
|
38
|
+
}),
|
|
39
|
+
Schema.Struct({
|
|
40
|
+
...ed,
|
|
41
|
+
d: coordinate
|
|
42
|
+
}),
|
|
43
|
+
Schema.Struct({
|
|
44
|
+
...rsa,
|
|
45
|
+
d: integer,
|
|
46
|
+
p: integer,
|
|
47
|
+
q: integer,
|
|
48
|
+
dp: integer,
|
|
49
|
+
dq: integer,
|
|
50
|
+
qi: integer
|
|
51
|
+
})
|
|
52
|
+
]);
|
|
53
|
+
const SignInput = Schema.Struct({
|
|
54
|
+
algorithm: Algorithm,
|
|
55
|
+
privateKey: Schema.Redacted(Schema.Uint8Array, { disallowJsonEncode: true }),
|
|
56
|
+
data: Schema.Uint8Array
|
|
57
|
+
});
|
|
58
|
+
const VerifyInput = Schema.Struct({
|
|
59
|
+
algorithm: Algorithm,
|
|
60
|
+
publicKey: Schema.Uint8Array,
|
|
61
|
+
data: Schema.Uint8Array,
|
|
62
|
+
signature: Schema.Uint8Array
|
|
63
|
+
});
|
|
64
|
+
/**
|
|
65
|
+
* Private keys are PKCS8 DER; public keys are SPKI DER. ECDSA signatures are
|
|
66
|
+
* 64-byte IEEE P1363 (r || s), not ASN.1 DER. RSA requires at least 2048 bits;
|
|
67
|
+
* PSS uses a 32-byte salt. Key serialization/selection and JOSE policy stay outside.
|
|
68
|
+
*/
|
|
69
|
+
var Signature = class extends Context.Service()("@yielded/crypto/Signature") {};
|
|
70
|
+
//#endregion
|
|
71
|
+
export { Algorithm, PrivateKeyParameters, PublicKeyParameters, SignInput, Signature, VerifyInput };
|
|
72
|
+
|
|
73
|
+
//# sourceMappingURL=Signature.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Signature.mjs","names":[],"sources":["../src/Signature.ts"],"sourcesContent":["import { Context, type Effect, type Redacted, Schema } from \"effect\";\n\nimport type { OperationError } from \"./Errors\";\n\nexport const Algorithm = Schema.Literals([\n \"ECDSA-P256-SHA256\",\n \"RSASSA-PKCS1-v1_5-SHA256\",\n \"RSA-PSS-SHA256\",\n \"Ed25519\",\n]);\n\nexport type Algorithm = typeof Algorithm.Type;\n\nconst coordinate = Schema.Uint8Array.check(Schema.isMinLength(32), Schema.isMaxLength(32));\nconst integer = Schema.Uint8Array.check(Schema.isMinLength(1), Schema.isMaxLength(1024));\nconst ec = { algorithm: Schema.Literal(\"ECDSA-P256-SHA256\"), x: coordinate, y: coordinate };\nconst ed = { algorithm: Schema.Literal(\"Ed25519\"), x: coordinate };\n\nconst rsa = {\n algorithm: Schema.Literals([\"RSASSA-PKCS1-v1_5-SHA256\", \"RSA-PSS-SHA256\"]),\n n: integer,\n e: integer,\n};\n\n/**\n * Unsigned big-endian components: 32-byte curve values and RSA components up to\n * 1024 bytes. Native import validates the actual key, including RSA's minimum.\n */\nexport const PublicKeyParameters = Schema.Union([\n Schema.Struct(ec),\n Schema.Struct(ed),\n Schema.Struct(rsa),\n]);\n\nexport type PublicKeyParameters = typeof PublicKeyParameters.Type;\n\nexport const PrivateKeyParameters = Schema.Union([\n Schema.Struct({ ...ec, d: coordinate }),\n Schema.Struct({ ...ed, d: coordinate }),\n Schema.Struct({\n ...rsa,\n d: integer,\n p: integer,\n q: integer,\n dp: integer,\n dq: integer,\n qi: integer,\n }),\n]);\n\nexport type PrivateKeyParameters = typeof PrivateKeyParameters.Type;\n\nexport const SignInput = Schema.Struct({\n algorithm: Algorithm,\n privateKey: Schema.Redacted(Schema.Uint8Array, { disallowJsonEncode: true }),\n data: Schema.Uint8Array,\n});\n\nexport type SignInput = typeof SignInput.Type;\n\nexport const VerifyInput = Schema.Struct({\n algorithm: Algorithm,\n publicKey: Schema.Uint8Array,\n data: Schema.Uint8Array,\n signature: Schema.Uint8Array,\n});\n\nexport type VerifyInput = typeof VerifyInput.Type;\n\n/**\n * Private keys are PKCS8 DER; public keys are SPKI DER. ECDSA signatures are\n * 64-byte IEEE P1363 (r || s), not ASN.1 DER. RSA requires at least 2048 bits;\n * PSS uses a 32-byte salt. Key serialization/selection and JOSE policy stay outside.\n */\nexport class Signature extends Context.Service<\n Signature,\n {\n readonly encodePublicKey: (\n input: PublicKeyParameters,\n ) => Effect.Effect<Uint8Array, OperationError>;\n readonly encodePrivateKey: (\n input: Redacted.Redacted<PrivateKeyParameters>,\n ) => Effect.Effect<Redacted.Redacted<Uint8Array>, OperationError>;\n readonly sign: (input: SignInput) => Effect.Effect<Uint8Array, OperationError>;\n readonly verify: (input: VerifyInput) => Effect.Effect<boolean, OperationError>;\n }\n>()(\"@yielded/crypto/Signature\") {}\n"],"mappings":";;AAIA,MAAa,YAAY,OAAO,SAAS;CACvC;CACA;CACA;CACA;AACF,CAAC;AAID,MAAM,aAAa,OAAO,WAAW,MAAM,OAAO,YAAY,EAAE,GAAG,OAAO,YAAY,EAAE,CAAC;AACzF,MAAM,UAAU,OAAO,WAAW,MAAM,OAAO,YAAY,CAAC,GAAG,OAAO,YAAY,IAAI,CAAC;AACvF,MAAM,KAAK;CAAE,WAAW,OAAO,QAAQ,mBAAmB;CAAG,GAAG;CAAY,GAAG;AAAW;AAC1F,MAAM,KAAK;CAAE,WAAW,OAAO,QAAQ,SAAS;CAAG,GAAG;AAAW;AAEjE,MAAM,MAAM;CACV,WAAW,OAAO,SAAS,CAAC,4BAA4B,gBAAgB,CAAC;CACzE,GAAG;CACH,GAAG;AACL;;;;;AAMA,MAAa,sBAAsB,OAAO,MAAM;CAC9C,OAAO,OAAO,EAAE;CAChB,OAAO,OAAO,EAAE;CAChB,OAAO,OAAO,GAAG;AACnB,CAAC;AAID,MAAa,uBAAuB,OAAO,MAAM;CAC/C,OAAO,OAAO;EAAE,GAAG;EAAI,GAAG;CAAW,CAAC;CACtC,OAAO,OAAO;EAAE,GAAG;EAAI,GAAG;CAAW,CAAC;CACtC,OAAO,OAAO;EACZ,GAAG;EACH,GAAG;EACH,GAAG;EACH,GAAG;EACH,IAAI;EACJ,IAAI;EACJ,IAAI;CACN,CAAC;AACH,CAAC;AAID,MAAa,YAAY,OAAO,OAAO;CACrC,WAAW;CACX,YAAY,OAAO,SAAS,OAAO,YAAY,EAAE,oBAAoB,KAAK,CAAC;CAC3E,MAAM,OAAO;AACf,CAAC;AAID,MAAa,cAAc,OAAO,OAAO;CACvC,WAAW;CACX,WAAW,OAAO;CAClB,MAAM,OAAO;CACb,WAAW,OAAO;AACpB,CAAC;;;;;;AASD,IAAa,YAAb,cAA+B,QAAQ,QAYrC,CAAC,CAAC,2BAA2B,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { InvalidInput } from "./Errors.mjs";
|
|
2
|
+
import { Aead } from "./Aead.mjs";
|
|
3
|
+
import { Hmac } from "./Hmac.mjs";
|
|
4
|
+
import { Kdf, Limits } from "./Kdf.mjs";
|
|
5
|
+
import { KdfAdmission } from "./KdfAdmission.mjs";
|
|
6
|
+
import { Signature } from "./Signature.mjs";
|
|
7
|
+
import { Crypto, Layer } from "effect";
|
|
8
|
+
//#region src/WebCrypto.d.ts
|
|
9
|
+
/** Supply the host capability explicitly; no implicit global backend selection. */
|
|
10
|
+
export declare const layer: (subtle: SubtleCrypto, limits?: Partial<Limits>) => Layer.Layer<Aead | Hmac | Kdf | Signature, InvalidInput, KdfAdmission>;
|
|
11
|
+
/** HMAC alone has no KDF admission requirement. */
|
|
12
|
+
export declare const layerHmac: (subtle: SubtleCrypto) => Layer.Layer<Hmac>;
|
|
13
|
+
/** Effect entropy and SHA digests from the host's global WebCrypto implementation. */
|
|
14
|
+
export declare const layerCryptoWeb: Layer.Layer<Crypto.Crypto>;
|
|
15
|
+
/** HMAC from global WebCrypto. Missing WebCrypto is a platform defect at Layer construction. */
|
|
16
|
+
export declare const layerHmacWeb: Layer.Layer<Hmac>;
|
|
17
|
+
/** Entropy, SHA digests and HMAC for sessions and proofs, without password derivation. */
|
|
18
|
+
export declare const layerWebCrypto: Layer.Layer<Crypto.Crypto | Hmac, never, never>;
|
|
19
|
+
//#endregion
|
|
20
|
+
//# sourceMappingURL=WebCrypto.d.mts.map
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { Hmac } from "./Hmac.mjs";
|
|
2
|
+
import { makeHmac } from "./internal/hmac.mjs";
|
|
3
|
+
import { makeLayer } from "./internal/layer.mjs";
|
|
4
|
+
import { Crypto, Effect, Layer, PlatformError } from "effect";
|
|
5
|
+
//#region src/WebCrypto.ts
|
|
6
|
+
/** Supply the host capability explicitly; no implicit global backend selection. */
|
|
7
|
+
const layer = (subtle, limits = {}) => makeLayer(subtle, limits);
|
|
8
|
+
/** HMAC alone has no KDF admission requirement. */
|
|
9
|
+
const layerHmac = (subtle) => Layer.sync(Hmac)(() => makeHmac(subtle));
|
|
10
|
+
/** Effect entropy and SHA digests from the host's global WebCrypto implementation. */
|
|
11
|
+
const layerCryptoWeb = Layer.sync(Crypto.Crypto)(() => Crypto.make({
|
|
12
|
+
randomBytes: (size) => globalThis.crypto.getRandomValues(new Uint8Array(size)),
|
|
13
|
+
digest: (algorithm, data) => Effect.tryPromise({
|
|
14
|
+
try: () => globalThis.crypto.subtle.digest(algorithm, new Uint8Array(data)),
|
|
15
|
+
catch: (cause) => PlatformError.systemError({
|
|
16
|
+
_tag: "Unknown",
|
|
17
|
+
module: "Crypto",
|
|
18
|
+
method: "digest",
|
|
19
|
+
cause
|
|
20
|
+
})
|
|
21
|
+
}).pipe(Effect.map((bytes) => new Uint8Array(bytes)))
|
|
22
|
+
}));
|
|
23
|
+
/** HMAC from global WebCrypto. Missing WebCrypto is a platform defect at Layer construction. */
|
|
24
|
+
const layerHmacWeb = Layer.effect(Hmac)(Effect.suspend(() => {
|
|
25
|
+
const subtle = globalThis.crypto?.subtle;
|
|
26
|
+
return subtle === void 0 ? Effect.die(/* @__PURE__ */ new Error("WebCrypto is unavailable in this runtime")) : Effect.succeed(makeHmac(subtle));
|
|
27
|
+
}));
|
|
28
|
+
/** Entropy, SHA digests and HMAC for sessions and proofs, without password derivation. */
|
|
29
|
+
const layerWebCrypto = Layer.merge(layerCryptoWeb, layerHmacWeb);
|
|
30
|
+
//#endregion
|
|
31
|
+
export { layer, layerCryptoWeb, layerHmac, layerHmacWeb, layerWebCrypto };
|
|
32
|
+
|
|
33
|
+
//# sourceMappingURL=WebCrypto.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"WebCrypto.mjs","names":[],"sources":["../src/WebCrypto.ts"],"sourcesContent":["import { Crypto, Effect, Layer, PlatformError } from \"effect\";\n\nimport { Hmac } from \"./Hmac\";\nimport { makeHmac } from \"./internal/hmac\";\nimport { makeLayer } from \"./internal/layer\";\nimport type { Limits } from \"./Kdf\";\n\n/** Supply the host capability explicitly; no implicit global backend selection. */\nexport const layer = (subtle: SubtleCrypto, limits: Partial<Limits> = {}) =>\n makeLayer(subtle, limits);\n\n/** HMAC alone has no KDF admission requirement. */\nexport const layerHmac = (subtle: SubtleCrypto): Layer.Layer<Hmac> =>\n Layer.sync(Hmac)(() => makeHmac(subtle));\n\n/** Effect entropy and SHA digests from the host's global WebCrypto implementation. */\nexport const layerCryptoWeb: Layer.Layer<Crypto.Crypto> = Layer.sync(Crypto.Crypto)(() =>\n Crypto.make({\n randomBytes: (size) => globalThis.crypto.getRandomValues(new Uint8Array(size)),\n digest: (algorithm, data) =>\n Effect.tryPromise({\n try: () => globalThis.crypto.subtle.digest(algorithm, new Uint8Array(data)),\n catch: (cause) =>\n PlatformError.systemError({\n _tag: \"Unknown\",\n module: \"Crypto\",\n method: \"digest\",\n cause,\n }),\n }).pipe(Effect.map((bytes) => new Uint8Array(bytes))),\n }),\n);\n\n/** HMAC from global WebCrypto. Missing WebCrypto is a platform defect at Layer construction. */\nexport const layerHmacWeb: Layer.Layer<Hmac> = Layer.effect(Hmac)(\n Effect.suspend(() => {\n const subtle = globalThis.crypto?.subtle;\n\n return subtle === undefined\n ? Effect.die(new Error(\"WebCrypto is unavailable in this runtime\"))\n : Effect.succeed(makeHmac(subtle));\n }),\n);\n\n/** Entropy, SHA digests and HMAC for sessions and proofs, without password derivation. */\nexport const layerWebCrypto = Layer.merge(layerCryptoWeb, layerHmacWeb);\n"],"mappings":";;;;;;AAQA,MAAa,SAAS,QAAsB,SAA0B,CAAC,MACrE,UAAU,QAAQ,MAAM;;AAG1B,MAAa,aAAa,WACxB,MAAM,KAAK,IAAI,CAAC,OAAO,SAAS,MAAM,CAAC;;AAGzC,MAAa,iBAA6C,MAAM,KAAK,OAAO,MAAM,CAAC,OACjF,OAAO,KAAK;CACV,cAAc,SAAS,WAAW,OAAO,gBAAgB,IAAI,WAAW,IAAI,CAAC;CAC7E,SAAS,WAAW,SAClB,OAAO,WAAW;EAChB,WAAW,WAAW,OAAO,OAAO,OAAO,WAAW,IAAI,WAAW,IAAI,CAAC;EAC1E,QAAQ,UACN,cAAc,YAAY;GACxB,MAAM;GACN,QAAQ;GACR,QAAQ;GACR;EACF,CAAC;CACL,CAAC,CAAC,CAAC,KAAK,OAAO,KAAK,UAAU,IAAI,WAAW,KAAK,CAAC,CAAC;AACxD,CAAC,CACH;;AAGA,MAAa,eAAkC,MAAM,OAAO,IAAI,CAAC,CAC/D,OAAO,cAAc;CACnB,MAAM,SAAS,WAAW,QAAQ;CAElC,OAAO,WAAW,KAAA,IACd,OAAO,oBAAI,IAAI,MAAM,0CAA0C,CAAC,IAChE,OAAO,QAAQ,SAAS,MAAM,CAAC;AACrC,CAAC,CACH;;AAGA,MAAa,iBAAiB,MAAM,MAAM,gBAAgB,YAAY"}
|
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import * as Aead from "./Aead.mjs";
|
|
2
|
+
import * as Errors from "./Errors.mjs";
|
|
3
|
+
import * as Hmac from "./Hmac.mjs";
|
|
4
|
+
import * as Kdf from "./Kdf.mjs";
|
|
5
|
+
import * as KdfAdmission from "./KdfAdmission.mjs";
|
|
6
|
+
import * as Signature from "./Signature.mjs";
|
|
7
|
+
export { Aead, Errors, Hmac, Kdf, KdfAdmission, Signature };
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import * as Aead from "./Aead.mjs";
|
|
2
|
+
import * as Errors from "./Errors.mjs";
|
|
3
|
+
import * as Hmac from "./Hmac.mjs";
|
|
4
|
+
import * as Kdf from "./Kdf.mjs";
|
|
5
|
+
import * as KdfAdmission from "./KdfAdmission.mjs";
|
|
6
|
+
import * as Signature from "./Signature.mjs";
|
|
7
|
+
export { Aead, Errors, Hmac, Kdf, KdfAdmission, Signature };
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { Aead, DecryptInput, EncryptInput } from "../Aead.mjs";
|
|
2
|
+
import { AuthenticationFailed, UnsupportedAlgorithm } from "../Errors.mjs";
|
|
3
|
+
import { copy, decode, importError, nativeError, nativeErrorName, withSecret } from "./common.mjs";
|
|
4
|
+
import { Effect, Redacted, Schema } from "effect";
|
|
5
|
+
//#region src/internal/aead.ts
|
|
6
|
+
const keyBytes = Schema.Uint8Array.check(Schema.isBetweenLength(32, 32));
|
|
7
|
+
const makeAead = (subtle, xchacha) => Aead.of({
|
|
8
|
+
encrypt: Effect.fnUntraced(function* (input) {
|
|
9
|
+
const value = yield* decode(EncryptInput, input, "data");
|
|
10
|
+
const nonceLength = value.algorithm === "AES-256-GCM" ? 12 : 24;
|
|
11
|
+
yield* decode(keyBytes, Redacted.value(value.key), "key");
|
|
12
|
+
yield* decode(Schema.Uint8Array.check(Schema.isBetweenLength(nonceLength, nonceLength)), value.nonce, "nonce");
|
|
13
|
+
if (value.algorithm === "XChaCha20-Poly1305" && xchacha === void 0) return yield* UnsupportedAlgorithm.make({});
|
|
14
|
+
const nonce = yield* copy(value.nonce);
|
|
15
|
+
const additionalData = yield* copy(value.additionalData ?? /* @__PURE__ */ new Uint8Array());
|
|
16
|
+
return yield* withSecret(value.key, (key) => withSecret(value.plaintext, (data) => {
|
|
17
|
+
if (value.algorithm === "XChaCha20-Poly1305") return xchacha === void 0 ? Effect.fail(UnsupportedAlgorithm.make({})) : xchacha.encrypt({
|
|
18
|
+
key,
|
|
19
|
+
nonce,
|
|
20
|
+
additionalData,
|
|
21
|
+
data
|
|
22
|
+
});
|
|
23
|
+
return Effect.gen(function* () {
|
|
24
|
+
const imported = yield* Effect.tryPromise({
|
|
25
|
+
try: () => subtle.importKey("raw", key, "AES-GCM", false, ["encrypt"]),
|
|
26
|
+
catch: importError
|
|
27
|
+
});
|
|
28
|
+
const encrypted = yield* Effect.tryPromise({
|
|
29
|
+
try: () => subtle.encrypt({
|
|
30
|
+
name: "AES-GCM",
|
|
31
|
+
iv: nonce,
|
|
32
|
+
additionalData,
|
|
33
|
+
tagLength: 128
|
|
34
|
+
}, imported, data),
|
|
35
|
+
catch: nativeError
|
|
36
|
+
});
|
|
37
|
+
return new Uint8Array(encrypted);
|
|
38
|
+
}).pipe(Effect.uninterruptible);
|
|
39
|
+
}));
|
|
40
|
+
}),
|
|
41
|
+
decrypt: Effect.fnUntraced(function* (input) {
|
|
42
|
+
const value = yield* decode(DecryptInput, input, "data");
|
|
43
|
+
const nonceLength = value.algorithm === "AES-256-GCM" ? 12 : 24;
|
|
44
|
+
yield* decode(keyBytes, Redacted.value(value.key), "key");
|
|
45
|
+
yield* decode(Schema.Uint8Array.check(Schema.isBetweenLength(nonceLength, nonceLength)), value.nonce, "nonce");
|
|
46
|
+
if (value.algorithm === "XChaCha20-Poly1305" && xchacha === void 0) return yield* UnsupportedAlgorithm.make({});
|
|
47
|
+
if (value.ciphertext.length < 16) return yield* AuthenticationFailed.make({});
|
|
48
|
+
const nonce = yield* copy(value.nonce);
|
|
49
|
+
const additionalData = yield* copy(value.additionalData ?? /* @__PURE__ */ new Uint8Array());
|
|
50
|
+
const data = yield* copy(value.ciphertext);
|
|
51
|
+
const plaintext = yield* withSecret(value.key, (key) => {
|
|
52
|
+
if (value.algorithm === "XChaCha20-Poly1305") return xchacha === void 0 ? Effect.fail(UnsupportedAlgorithm.make({})) : xchacha.decrypt({
|
|
53
|
+
key,
|
|
54
|
+
nonce,
|
|
55
|
+
additionalData,
|
|
56
|
+
data
|
|
57
|
+
});
|
|
58
|
+
return Effect.gen(function* () {
|
|
59
|
+
const imported = yield* Effect.tryPromise({
|
|
60
|
+
try: () => subtle.importKey("raw", key, "AES-GCM", false, ["decrypt"]),
|
|
61
|
+
catch: importError
|
|
62
|
+
});
|
|
63
|
+
const decrypted = yield* Effect.tryPromise({
|
|
64
|
+
try: () => subtle.decrypt({
|
|
65
|
+
name: "AES-GCM",
|
|
66
|
+
iv: nonce,
|
|
67
|
+
additionalData,
|
|
68
|
+
tagLength: 128
|
|
69
|
+
}, imported, data),
|
|
70
|
+
catch: (cause) => nativeErrorName(cause) === "OperationError" ? AuthenticationFailed.make({}) : nativeError(cause)
|
|
71
|
+
});
|
|
72
|
+
return new Uint8Array(decrypted);
|
|
73
|
+
}).pipe(Effect.uninterruptible);
|
|
74
|
+
});
|
|
75
|
+
return Redacted.make(plaintext);
|
|
76
|
+
})
|
|
77
|
+
});
|
|
78
|
+
//#endregion
|
|
79
|
+
export { makeAead };
|
|
80
|
+
|
|
81
|
+
//# sourceMappingURL=aead.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"aead.mjs","names":[],"sources":["../../src/internal/aead.ts"],"sourcesContent":["import { Effect, Redacted, Schema } from \"effect\";\n\nimport { Aead, DecryptInput, EncryptInput } from \"../Aead\";\nimport { AuthenticationFailed, type OperationError, UnsupportedAlgorithm } from \"../Errors\";\nimport { copy, decode, importError, nativeError, nativeErrorName, withSecret } from \"./common\";\n\ninterface CipherInput {\n readonly key: Uint8Array<ArrayBuffer>;\n readonly nonce: Uint8Array<ArrayBuffer>;\n readonly additionalData: Uint8Array<ArrayBuffer>;\n readonly data: Uint8Array<ArrayBuffer>;\n}\n\nexport interface XChaCha {\n readonly encrypt: (input: CipherInput) => Effect.Effect<Uint8Array, OperationError>;\n readonly decrypt: (\n input: CipherInput,\n ) => Effect.Effect<Uint8Array, OperationError | AuthenticationFailed>;\n}\n\nconst keyBytes = Schema.Uint8Array.check(Schema.isBetweenLength(32, 32));\n\nexport const makeAead = (subtle: SubtleCrypto, xchacha?: XChaCha): Aead[\"Service\"] =>\n Aead.of({\n encrypt: Effect.fnUntraced(function* (input) {\n const value = yield* decode(EncryptInput, input, \"data\");\n const nonceLength = value.algorithm === \"AES-256-GCM\" ? 12 : 24;\n\n yield* decode(keyBytes, Redacted.value(value.key), \"key\");\n yield* decode(\n Schema.Uint8Array.check(Schema.isBetweenLength(nonceLength, nonceLength)),\n value.nonce,\n \"nonce\",\n );\n if (value.algorithm === \"XChaCha20-Poly1305\" && xchacha === undefined)\n return yield* UnsupportedAlgorithm.make({});\n const nonce = yield* copy(value.nonce);\n const additionalData = yield* copy(value.additionalData ?? new Uint8Array());\n\n return yield* withSecret(value.key, (key) =>\n withSecret(value.plaintext, (data) => {\n if (value.algorithm === \"XChaCha20-Poly1305\") {\n return xchacha === undefined\n ? Effect.fail(UnsupportedAlgorithm.make({}))\n : xchacha.encrypt({ key, nonce, additionalData, data });\n }\n\n return Effect.gen(function* () {\n const imported = yield* Effect.tryPromise({\n try: () => subtle.importKey(\"raw\", key, \"AES-GCM\", false, [\"encrypt\"]),\n catch: importError,\n });\n\n const encrypted = yield* Effect.tryPromise({\n try: () =>\n subtle.encrypt(\n { name: \"AES-GCM\", iv: nonce, additionalData, tagLength: 128 },\n imported,\n data,\n ),\n catch: nativeError,\n });\n\n return new Uint8Array(encrypted);\n }).pipe(Effect.uninterruptible);\n }),\n );\n }),\n decrypt: Effect.fnUntraced(function* (input) {\n const value = yield* decode(DecryptInput, input, \"data\");\n const nonceLength = value.algorithm === \"AES-256-GCM\" ? 12 : 24;\n\n yield* decode(keyBytes, Redacted.value(value.key), \"key\");\n yield* decode(\n Schema.Uint8Array.check(Schema.isBetweenLength(nonceLength, nonceLength)),\n value.nonce,\n \"nonce\",\n );\n if (value.algorithm === \"XChaCha20-Poly1305\" && xchacha === undefined)\n return yield* UnsupportedAlgorithm.make({});\n if (value.ciphertext.length < 16) return yield* AuthenticationFailed.make({});\n const nonce = yield* copy(value.nonce);\n const additionalData = yield* copy(value.additionalData ?? new Uint8Array());\n const data = yield* copy(value.ciphertext);\n\n const plaintext = yield* withSecret(value.key, (key) => {\n if (value.algorithm === \"XChaCha20-Poly1305\") {\n return xchacha === undefined\n ? Effect.fail(UnsupportedAlgorithm.make({}))\n : xchacha.decrypt({ key, nonce, additionalData, data });\n }\n\n return Effect.gen(function* () {\n const imported = yield* Effect.tryPromise({\n try: () => subtle.importKey(\"raw\", key, \"AES-GCM\", false, [\"decrypt\"]),\n catch: importError,\n });\n\n const decrypted = yield* Effect.tryPromise({\n try: () =>\n subtle.decrypt(\n { name: \"AES-GCM\", iv: nonce, additionalData, tagLength: 128 },\n imported,\n data,\n ),\n // WebCrypto specifies OperationError for a rejected GCM tag.\n catch: (cause) =>\n nativeErrorName(cause) === \"OperationError\"\n ? AuthenticationFailed.make({})\n : nativeError(cause),\n });\n\n return new Uint8Array(decrypted);\n }).pipe(Effect.uninterruptible);\n });\n\n return Redacted.make(plaintext);\n }),\n });\n"],"mappings":";;;;;AAoBA,MAAM,WAAW,OAAO,WAAW,MAAM,OAAO,gBAAgB,IAAI,EAAE,CAAC;AAEvE,MAAa,YAAY,QAAsB,YAC7C,KAAK,GAAG;CACN,SAAS,OAAO,WAAW,WAAW,OAAO;EAC3C,MAAM,QAAQ,OAAO,OAAO,cAAc,OAAO,MAAM;EACvD,MAAM,cAAc,MAAM,cAAc,gBAAgB,KAAK;EAE7D,OAAO,OAAO,UAAU,SAAS,MAAM,MAAM,GAAG,GAAG,KAAK;EACxD,OAAO,OACL,OAAO,WAAW,MAAM,OAAO,gBAAgB,aAAa,WAAW,CAAC,GACxE,MAAM,OACN,OACF;EACA,IAAI,MAAM,cAAc,wBAAwB,YAAY,KAAA,GAC1D,OAAO,OAAO,qBAAqB,KAAK,CAAC,CAAC;EAC5C,MAAM,QAAQ,OAAO,KAAK,MAAM,KAAK;EACrC,MAAM,iBAAiB,OAAO,KAAK,MAAM,kCAAkB,IAAI,WAAW,CAAC;EAE3E,OAAO,OAAO,WAAW,MAAM,MAAM,QACnC,WAAW,MAAM,YAAY,SAAS;GACpC,IAAI,MAAM,cAAc,sBACtB,OAAO,YAAY,KAAA,IACf,OAAO,KAAK,qBAAqB,KAAK,CAAC,CAAC,CAAC,IACzC,QAAQ,QAAQ;IAAE;IAAK;IAAO;IAAgB;GAAK,CAAC;GAG1D,OAAO,OAAO,IAAI,aAAa;IAC7B,MAAM,WAAW,OAAO,OAAO,WAAW;KACxC,WAAW,OAAO,UAAU,OAAO,KAAK,WAAW,OAAO,CAAC,SAAS,CAAC;KACrE,OAAO;IACT,CAAC;IAED,MAAM,YAAY,OAAO,OAAO,WAAW;KACzC,WACE,OAAO,QACL;MAAE,MAAM;MAAW,IAAI;MAAO;MAAgB,WAAW;KAAI,GAC7D,UACA,IACF;KACF,OAAO;IACT,CAAC;IAED,OAAO,IAAI,WAAW,SAAS;GACjC,CAAC,CAAC,CAAC,KAAK,OAAO,eAAe;EAChC,CAAC,CACH;CACF,CAAC;CACD,SAAS,OAAO,WAAW,WAAW,OAAO;EAC3C,MAAM,QAAQ,OAAO,OAAO,cAAc,OAAO,MAAM;EACvD,MAAM,cAAc,MAAM,cAAc,gBAAgB,KAAK;EAE7D,OAAO,OAAO,UAAU,SAAS,MAAM,MAAM,GAAG,GAAG,KAAK;EACxD,OAAO,OACL,OAAO,WAAW,MAAM,OAAO,gBAAgB,aAAa,WAAW,CAAC,GACxE,MAAM,OACN,OACF;EACA,IAAI,MAAM,cAAc,wBAAwB,YAAY,KAAA,GAC1D,OAAO,OAAO,qBAAqB,KAAK,CAAC,CAAC;EAC5C,IAAI,MAAM,WAAW,SAAS,IAAI,OAAO,OAAO,qBAAqB,KAAK,CAAC,CAAC;EAC5E,MAAM,QAAQ,OAAO,KAAK,MAAM,KAAK;EACrC,MAAM,iBAAiB,OAAO,KAAK,MAAM,kCAAkB,IAAI,WAAW,CAAC;EAC3E,MAAM,OAAO,OAAO,KAAK,MAAM,UAAU;EAEzC,MAAM,YAAY,OAAO,WAAW,MAAM,MAAM,QAAQ;GACtD,IAAI,MAAM,cAAc,sBACtB,OAAO,YAAY,KAAA,IACf,OAAO,KAAK,qBAAqB,KAAK,CAAC,CAAC,CAAC,IACzC,QAAQ,QAAQ;IAAE;IAAK;IAAO;IAAgB;GAAK,CAAC;GAG1D,OAAO,OAAO,IAAI,aAAa;IAC7B,MAAM,WAAW,OAAO,OAAO,WAAW;KACxC,WAAW,OAAO,UAAU,OAAO,KAAK,WAAW,OAAO,CAAC,SAAS,CAAC;KACrE,OAAO;IACT,CAAC;IAED,MAAM,YAAY,OAAO,OAAO,WAAW;KACzC,WACE,OAAO,QACL;MAAE,MAAM;MAAW,IAAI;MAAO;MAAgB,WAAW;KAAI,GAC7D,UACA,IACF;KAEF,QAAQ,UACN,gBAAgB,KAAK,MAAM,mBACvB,qBAAqB,KAAK,CAAC,CAAC,IAC5B,YAAY,KAAK;IACzB,CAAC;IAED,OAAO,IAAI,WAAW,SAAS;GACjC,CAAC,CAAC,CAAC,KAAK,OAAO,eAAe;EAChC,CAAC;EAED,OAAO,SAAS,KAAK,SAAS;CAChC,CAAC;AACH,CAAC"}
|