effect 4.1.0 → 4.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +30 -0
- package/THIRD_PARTY_NOTICES.md +62 -0
- package/dist/BigDecimal.d.ts +139 -7
- package/dist/BigDecimal.d.ts.map +1 -1
- package/dist/BigDecimal.js +83 -14
- package/dist/BigDecimal.js.map +1 -1
- package/dist/Equal.d.ts +2 -2
- package/dist/Equal.d.ts.map +1 -1
- package/dist/Equal.js +3 -3
- package/dist/Equal.js.map +1 -1
- package/dist/Hash.d.ts +3 -2
- package/dist/Hash.d.ts.map +1 -1
- package/dist/Hash.js +5 -4
- package/dist/Hash.js.map +1 -1
- package/dist/Iterable.d.ts.map +1 -1
- package/dist/Iterable.js +11 -8
- package/dist/Iterable.js.map +1 -1
- package/dist/Path.d.ts.map +1 -1
- package/dist/Path.js +5 -1
- package/dist/Path.js.map +1 -1
- package/dist/Pool.d.ts.map +1 -1
- package/dist/Pool.js +2 -1
- package/dist/Pool.js.map +1 -1
- package/dist/Schema.d.ts +2 -1
- package/dist/Schema.d.ts.map +1 -1
- package/dist/Schema.js +2 -1
- package/dist/Schema.js.map +1 -1
- package/dist/SchemaRepresentation.d.ts +4 -2
- package/dist/SchemaRepresentation.d.ts.map +1 -1
- package/dist/SchemaRepresentation.js +4 -2
- package/dist/SchemaRepresentation.js.map +1 -1
- package/dist/SchemaTransformation.d.ts +2 -2
- package/dist/SchemaTransformation.js +2 -2
- package/dist/ai/McpClient.d.ts +171 -19
- package/dist/ai/McpClient.d.ts.map +1 -1
- package/dist/ai/McpClient.js +277 -66
- package/dist/ai/McpClient.js.map +1 -1
- package/dist/ai/McpSchema.d.ts +108 -0
- package/dist/ai/McpSchema.d.ts.map +1 -1
- package/dist/ai/McpSchema.js +99 -0
- package/dist/ai/McpSchema.js.map +1 -1
- package/dist/ai/McpServer.d.ts +120 -6
- package/dist/ai/McpServer.d.ts.map +1 -1
- package/dist/ai/McpServer.js +215 -34
- package/dist/ai/McpServer.js.map +1 -1
- package/dist/ai/Prompt.d.ts.map +1 -1
- package/dist/ai/Prompt.js +20 -11
- package/dist/ai/Prompt.js.map +1 -1
- package/dist/ai/Tool.d.ts.map +1 -1
- package/dist/ai/Tool.js +5 -7
- package/dist/ai/Tool.js.map +1 -1
- package/dist/ai/internal/mcpCore.js +72 -3
- package/dist/ai/internal/mcpCore.js.map +1 -1
- package/dist/ai/internal/mcpProtocol/v2024_11_05.js +3 -1
- package/dist/ai/internal/mcpProtocol/v2024_11_05.js.map +1 -1
- package/dist/ai/internal/mcpProtocol/v2025_03_26.js +3 -1
- package/dist/ai/internal/mcpProtocol/v2025_03_26.js.map +1 -1
- package/dist/ai/internal/mcpProtocol/v2025_06_18.js +3 -1
- package/dist/ai/internal/mcpProtocol/v2025_06_18.js.map +1 -1
- package/dist/ai/internal/mcpProtocol/v2025_11_25.js +3 -1
- package/dist/ai/internal/mcpProtocol/v2025_11_25.js.map +1 -1
- package/dist/ai/internal/mcpProtocol/v2026_07_28.js +42 -7
- package/dist/ai/internal/mcpProtocol/v2026_07_28.js.map +1 -1
- package/dist/ai/internal/mcpProtocol.js +12 -0
- package/dist/ai/internal/mcpProtocol.js.map +1 -1
- package/dist/ai/internal/mcpRuntime.js +3 -3
- package/dist/ai/internal/mcpRuntime.js.map +1 -1
- package/dist/ai/internal/mcpSkills.d.ts +2 -0
- package/dist/ai/internal/mcpSkills.d.ts.map +1 -0
- package/dist/ai/internal/mcpSkills.js +428 -0
- package/dist/ai/internal/mcpSkills.js.map +1 -0
- package/dist/cluster/ClusterWorkflowEngine.d.ts.map +1 -1
- package/dist/cluster/ClusterWorkflowEngine.js +15 -5
- package/dist/cluster/ClusterWorkflowEngine.js.map +1 -1
- package/dist/cluster/Reply.d.ts +1 -1
- package/dist/cluster/Reply.d.ts.map +1 -1
- package/dist/cluster/Reply.js.map +1 -1
- package/dist/cluster/Sharding.d.ts.map +1 -1
- package/dist/cluster/Sharding.js +4 -1
- package/dist/cluster/Sharding.js.map +1 -1
- package/dist/cluster/internal/entityManager.js +15 -7
- package/dist/cluster/internal/entityManager.js.map +1 -1
- package/dist/crypto/Aead.d.ts +2 -1
- package/dist/crypto/Aead.d.ts.map +1 -1
- package/dist/crypto/Aead.js +2 -2
- package/dist/crypto/Aead.js.map +1 -1
- package/dist/crypto/Cipher.d.ts +2 -1
- package/dist/crypto/Cipher.d.ts.map +1 -1
- package/dist/crypto/Cipher.js +2 -2
- package/dist/crypto/Cipher.js.map +1 -1
- package/dist/crypto/KeyAgreement.d.ts +3 -2
- package/dist/crypto/KeyAgreement.d.ts.map +1 -1
- package/dist/crypto/KeyAgreement.js +2 -2
- package/dist/crypto/KeyAgreement.js.map +1 -1
- package/dist/crypto/KeyFormat.d.ts +33 -1
- package/dist/crypto/KeyFormat.d.ts.map +1 -1
- package/dist/crypto/KeyFormat.js.map +1 -1
- package/dist/crypto/KeyWrap.d.ts +4 -3
- package/dist/crypto/KeyWrap.d.ts.map +1 -1
- package/dist/crypto/KeyWrap.js +2 -2
- package/dist/crypto/KeyWrap.js.map +1 -1
- package/dist/crypto/Mac.d.ts +2 -1
- package/dist/crypto/Mac.d.ts.map +1 -1
- package/dist/crypto/Mac.js +2 -2
- package/dist/crypto/Mac.js.map +1 -1
- package/dist/crypto/Signature.d.ts +3 -2
- package/dist/crypto/Signature.d.ts.map +1 -1
- package/dist/crypto/Signature.js +2 -2
- package/dist/crypto/Signature.js.map +1 -1
- package/dist/crypto/WebCrypto.d.ts +19 -0
- package/dist/crypto/WebCrypto.d.ts.map +1 -1
- package/dist/crypto/WebCrypto.js.map +1 -1
- package/dist/crypto/internal/asymmetric.js.map +1 -1
- package/dist/crypto/internal/key.js +3 -2
- package/dist/crypto/internal/key.js.map +1 -1
- package/dist/encoding/Base64Url.d.ts.map +1 -1
- package/dist/encoding/Base64Url.js +26 -3
- package/dist/encoding/Base64Url.js.map +1 -1
- package/dist/encoding/Ndjson.d.ts +5 -4
- package/dist/encoding/Ndjson.d.ts.map +1 -1
- package/dist/encoding/Ndjson.js +6 -5
- package/dist/encoding/Ndjson.js.map +1 -1
- package/dist/encoding/Sse.d.ts +3 -1
- package/dist/encoding/Sse.d.ts.map +1 -1
- package/dist/encoding/Sse.js +5 -3
- package/dist/encoding/Sse.js.map +1 -1
- package/dist/eventlog/EventLog.d.ts +7 -0
- package/dist/eventlog/EventLog.d.ts.map +1 -1
- package/dist/eventlog/EventLog.js +7 -0
- package/dist/eventlog/EventLog.js.map +1 -1
- package/dist/eventlog/EventLogServer.d.ts +7 -1
- package/dist/eventlog/EventLogServer.d.ts.map +1 -1
- package/dist/eventlog/EventLogServer.js +27 -12
- package/dist/eventlog/EventLogServer.js.map +1 -1
- package/dist/eventlog/EventLogServerEncrypted.d.ts +10 -0
- package/dist/eventlog/EventLogServerEncrypted.d.ts.map +1 -1
- package/dist/eventlog/EventLogServerEncrypted.js.map +1 -1
- package/dist/eventlog/EventLogServerUnencrypted.d.ts +17 -0
- package/dist/eventlog/EventLogServerUnencrypted.d.ts.map +1 -1
- package/dist/eventlog/EventLogServerUnencrypted.js +14 -2
- package/dist/eventlog/EventLogServerUnencrypted.js.map +1 -1
- package/dist/eventlog/EventLogSessionAuth.d.ts +21 -0
- package/dist/eventlog/EventLogSessionAuth.d.ts.map +1 -1
- package/dist/eventlog/EventLogSessionAuth.js +22 -0
- package/dist/eventlog/EventLogSessionAuth.js.map +1 -1
- package/dist/graphql/GraphQLClient.d.ts +3 -1
- package/dist/graphql/GraphQLClient.d.ts.map +1 -1
- package/dist/graphql/GraphQLClient.js.map +1 -1
- package/dist/graphql/GraphQLClientError.d.ts +14 -9
- package/dist/graphql/GraphQLClientError.d.ts.map +1 -1
- package/dist/graphql/GraphQLClientError.js +14 -21
- package/dist/graphql/GraphQLClientError.js.map +1 -1
- package/dist/graphql/GraphQLProtocol.d.ts +12 -3
- package/dist/graphql/GraphQLProtocol.d.ts.map +1 -1
- package/dist/graphql/GraphQLProtocol.js +4 -1
- package/dist/graphql/GraphQLProtocol.js.map +1 -1
- package/dist/http/HttpClient.d.ts +189 -7
- package/dist/http/HttpClient.d.ts.map +1 -1
- package/dist/http/HttpClient.js +75 -2
- package/dist/http/HttpClient.js.map +1 -1
- package/dist/http/HttpServerRequest.d.ts.map +1 -1
- package/dist/http/HttpServerRequest.js +38 -22
- package/dist/http/HttpServerRequest.js.map +1 -1
- package/dist/http/internal/mimeTypes.d.ts +4 -1
- package/dist/http/internal/mimeTypes.d.ts.map +1 -1
- package/dist/http/internal/mimeTypes.js +4 -1
- package/dist/http/internal/mimeTypes.js.map +1 -1
- package/dist/http-api/HttpApiSchema.js +1 -1
- package/dist/http-api/HttpApiSchema.js.map +1 -1
- package/dist/internal/dateTime.js +49 -24
- package/dist/internal/dateTime.js.map +1 -1
- package/dist/internal/effect.js +10 -0
- package/dist/internal/effect.js.map +1 -1
- package/dist/internal/glob.js +234 -56
- package/dist/internal/glob.js.map +1 -1
- package/dist/internal/graphql.js +21 -7
- package/dist/internal/graphql.js.map +1 -1
- package/dist/internal/graphqlHeaders.d.ts +7 -0
- package/dist/internal/graphqlHeaders.d.ts.map +1 -1
- package/dist/internal/graphqlHeaders.js +11 -0
- package/dist/internal/graphqlHeaders.js.map +1 -1
- package/dist/internal/request.js +29 -42
- package/dist/internal/request.js.map +1 -1
- package/dist/internal/schema/fromJsonSchemaDocument.js +7 -8
- package/dist/internal/schema/fromJsonSchemaDocument.js.map +1 -1
- package/dist/internal/version.js +1 -1
- package/dist/jose/JoseError.d.ts +285 -0
- package/dist/jose/JoseError.d.ts.map +1 -0
- package/dist/jose/JoseError.js +269 -0
- package/dist/jose/JoseError.js.map +1 -0
- package/dist/jose/Jwe.d.ts +128 -0
- package/dist/jose/Jwe.d.ts.map +1 -0
- package/dist/jose/Jwe.js +134 -0
- package/dist/jose/Jwe.js.map +1 -0
- package/dist/jose/Jwk.d.ts +597 -0
- package/dist/jose/Jwk.d.ts.map +1 -0
- package/dist/jose/Jwk.js +503 -0
- package/dist/jose/Jwk.js.map +1 -0
- package/dist/jose/Jwks.d.ts +236 -0
- package/dist/jose/Jwks.d.ts.map +1 -0
- package/dist/jose/Jwks.js +306 -0
- package/dist/jose/Jwks.js.map +1 -0
- package/dist/jose/Jws.d.ts +177 -0
- package/dist/jose/Jws.d.ts.map +1 -0
- package/dist/jose/Jws.js +183 -0
- package/dist/jose/Jws.js.map +1 -0
- package/dist/jose/Jwt.d.ts +270 -0
- package/dist/jose/Jwt.d.ts.map +1 -0
- package/dist/jose/Jwt.js +293 -0
- package/dist/jose/Jwt.js.map +1 -0
- package/dist/jose/index.d.ts +51 -0
- package/dist/jose/index.d.ts.map +1 -0
- package/dist/jose/index.js +52 -0
- package/dist/jose/index.js.map +1 -0
- package/dist/jose/internal/compact.d.ts +2 -0
- package/dist/jose/internal/compact.d.ts.map +1 -0
- package/dist/jose/internal/compact.js +179 -0
- package/dist/jose/internal/compact.js.map +1 -0
- package/dist/net/Host.d.ts.map +1 -1
- package/dist/net/Host.js +5 -10
- package/dist/net/Host.js.map +1 -1
- package/dist/observability/OtlpSerialization.d.ts +1 -1
- package/dist/observability/OtlpSerialization.d.ts.map +1 -1
- package/dist/observability/OtlpSerialization.js +10 -4
- package/dist/observability/OtlpSerialization.js.map +1 -1
- package/dist/observability/internal/otlpProtobuf.js +3 -3
- package/dist/observability/internal/otlpProtobuf.js.map +1 -1
- package/dist/observability/internal/protobuf.js +6 -0
- package/dist/observability/internal/protobuf.js.map +1 -1
- package/dist/persistence/CircuitBreaker.d.ts +98 -38
- package/dist/persistence/CircuitBreaker.d.ts.map +1 -1
- package/dist/persistence/CircuitBreaker.js +67 -29
- package/dist/persistence/CircuitBreaker.js.map +1 -1
- package/dist/persistence/RateLimiter.d.ts +8 -0
- package/dist/persistence/RateLimiter.d.ts.map +1 -1
- package/dist/persistence/RateLimiter.js +63 -12
- package/dist/persistence/RateLimiter.js.map +1 -1
- package/dist/persistence/index.d.ts +1 -1
- package/dist/persistence/index.js +1 -1
- package/dist/reactivity/AtomRegistry.js +17 -7
- package/dist/reactivity/AtomRegistry.js.map +1 -1
- package/dist/rpc/Rpc.d.ts +1 -1
- package/dist/rpc/Rpc.d.ts.map +1 -1
- package/dist/rpc/Rpc.js.map +1 -1
- package/dist/rpc/RpcClient.d.ts +14 -2
- package/dist/rpc/RpcClient.d.ts.map +1 -1
- package/dist/rpc/RpcClient.js +38 -21
- package/dist/rpc/RpcClient.js.map +1 -1
- package/dist/rpc/RpcMessage.d.ts +3 -2
- package/dist/rpc/RpcMessage.d.ts.map +1 -1
- package/dist/rpc/RpcMessage.js.map +1 -1
- package/dist/sql/Migrator.d.ts +9 -1
- package/dist/sql/Migrator.d.ts.map +1 -1
- package/dist/sql/Migrator.js +18 -6
- package/dist/sql/Migrator.js.map +1 -1
- package/dist/sql/SqlClient.d.ts +38 -3
- package/dist/sql/SqlClient.d.ts.map +1 -1
- package/dist/sql/SqlClient.js +4 -3
- package/dist/sql/SqlClient.js.map +1 -1
- package/dist/sql/Statement.d.ts +41 -3
- package/dist/sql/Statement.d.ts.map +1 -1
- package/dist/sql/Statement.js +24 -20
- package/dist/sql/Statement.js.map +1 -1
- package/dist/workflow/Workflow.d.ts +4 -0
- package/dist/workflow/Workflow.d.ts.map +1 -1
- package/dist/workflow/Workflow.js.map +1 -1
- package/dist/workflow/WorkflowEngine.d.ts.map +1 -1
- package/dist/workflow/WorkflowEngine.js +5 -0
- package/dist/workflow/WorkflowEngine.js.map +1 -1
- package/package.json +5 -1
- package/src/BigDecimal.ts +170 -16
- package/src/Equal.ts +3 -3
- package/src/Hash.ts +5 -4
- package/src/Iterable.ts +8 -5
- package/src/Path.ts +6 -1
- package/src/Pool.ts +2 -1
- package/src/Schema.ts +3 -2
- package/src/SchemaRepresentation.ts +4 -2
- package/src/SchemaTransformation.ts +2 -2
- package/src/ai/McpClient.ts +488 -91
- package/src/ai/McpSchema.ts +119 -0
- package/src/ai/McpServer.ts +261 -38
- package/src/ai/Prompt.ts +16 -11
- package/src/ai/Tool.ts +5 -10
- package/src/ai/internal/mcpCore.ts +165 -12
- package/src/ai/internal/mcpProtocol/v2024_11_05.ts +3 -1
- package/src/ai/internal/mcpProtocol/v2025_03_26.ts +3 -1
- package/src/ai/internal/mcpProtocol/v2025_06_18.ts +3 -1
- package/src/ai/internal/mcpProtocol/v2025_11_25.ts +3 -1
- package/src/ai/internal/mcpProtocol/v2026_07_28.ts +41 -7
- package/src/ai/internal/mcpProtocol.ts +15 -0
- package/src/ai/internal/mcpRuntime.ts +6 -3
- package/src/ai/internal/mcpSkills.ts +480 -0
- package/src/cluster/ClusterWorkflowEngine.ts +22 -8
- package/src/cluster/Reply.ts +1 -1
- package/src/cluster/Sharding.ts +4 -1
- package/src/cluster/internal/entityManager.ts +24 -10
- package/src/crypto/Aead.ts +3 -3
- package/src/crypto/Cipher.ts +3 -3
- package/src/crypto/KeyAgreement.ts +4 -4
- package/src/crypto/KeyFormat.ts +30 -1
- package/src/crypto/KeyWrap.ts +6 -6
- package/src/crypto/Mac.ts +3 -3
- package/src/crypto/Signature.ts +4 -4
- package/src/crypto/WebCrypto.ts +20 -0
- package/src/crypto/internal/asymmetric.ts +2 -1
- package/src/crypto/internal/key.ts +12 -5
- package/src/encoding/Base64Url.ts +27 -3
- package/src/encoding/Ndjson.ts +6 -5
- package/src/encoding/Sse.ts +5 -3
- package/src/eventlog/EventLog.ts +7 -0
- package/src/eventlog/EventLogServer.ts +31 -12
- package/src/eventlog/EventLogServerEncrypted.ts +5 -0
- package/src/eventlog/EventLogServerUnencrypted.ts +19 -2
- package/src/eventlog/EventLogSessionAuth.ts +26 -0
- package/src/graphql/GraphQLClient.ts +3 -1
- package/src/graphql/GraphQLClientError.ts +15 -22
- package/src/graphql/GraphQLProtocol.ts +12 -3
- package/src/http/HttpClient.ts +210 -11
- package/src/http/HttpServerRequest.ts +61 -23
- package/src/http/internal/mimeTypes.ts +4 -1
- package/src/http-api/HttpApiSchema.ts +1 -1
- package/src/internal/dateTime.ts +54 -24
- package/src/internal/effect.ts +6 -0
- package/src/internal/glob.ts +279 -63
- package/src/internal/graphql.ts +27 -9
- package/src/internal/graphqlHeaders.ts +13 -0
- package/src/internal/request.ts +51 -58
- package/src/internal/schema/fromJsonSchemaDocument.ts +11 -10
- package/src/internal/version.ts +1 -1
- package/src/jose/JoseError.ts +329 -0
- package/src/jose/Jwe.ts +196 -0
- package/src/jose/Jwk.ts +777 -0
- package/src/jose/Jwks.ts +418 -0
- package/src/jose/Jws.ts +312 -0
- package/src/jose/Jwt.ts +493 -0
- package/src/jose/index.ts +58 -0
- package/src/jose/internal/compact.ts +195 -0
- package/src/net/Host.ts +5 -10
- package/src/observability/OtlpSerialization.ts +13 -5
- package/src/observability/internal/otlpProtobuf.ts +6 -6
- package/src/observability/internal/protobuf.ts +10 -0
- package/src/persistence/CircuitBreaker.ts +113 -48
- package/src/persistence/RateLimiter.ts +84 -15
- package/src/persistence/index.ts +1 -1
- package/src/reactivity/AtomRegistry.ts +19 -8
- package/src/rpc/Rpc.ts +3 -1
- package/src/rpc/RpcClient.ts +44 -24
- package/src/rpc/RpcMessage.ts +3 -2
- package/src/sql/Migrator.ts +35 -18
- package/src/sql/SqlClient.ts +43 -8
- package/src/sql/Statement.ts +52 -22
- package/src/workflow/Workflow.ts +4 -0
- package/src/workflow/WorkflowEngine.ts +5 -0
package/src/crypto/Cipher.ts
CHANGED
|
@@ -35,7 +35,7 @@ import * as CryptoError from "./CryptoError.ts"
|
|
|
35
35
|
import * as KeyModel from "./internal/key.ts"
|
|
36
36
|
import * as internal from "./internal/webCrypto.ts"
|
|
37
37
|
import * as SecureRandom from "./SecureRandom.ts"
|
|
38
|
-
import
|
|
38
|
+
import * as WebCrypto from "./WebCrypto.ts"
|
|
39
39
|
|
|
40
40
|
const TypeId = "~effect/crypto/Cipher/Key" as const
|
|
41
41
|
|
|
@@ -217,7 +217,7 @@ export const layerWebCrypto: Layer.Layer<Cipher, never, SecureRandom.SecureRando
|
|
|
217
217
|
Cipher,
|
|
218
218
|
Effect.gen(function*() {
|
|
219
219
|
const random = yield* SecureRandom.SecureRandom
|
|
220
|
-
const crypto = yield* WebCrypto
|
|
220
|
+
const crypto = yield* WebCrypto.WebCrypto
|
|
221
221
|
const cryptoKeyFor = KeyModel.makeCache((subtle, bytes, algorithm: Algorithm) =>
|
|
222
222
|
subtle.importKey("raw", bytes as BufferSource, algorithm.mode, false, ["encrypt", "decrypt"])
|
|
223
223
|
)
|
|
@@ -299,7 +299,7 @@ export const key = <A extends Algorithm>(
|
|
|
299
299
|
*/
|
|
300
300
|
export const fromCryptoKey = <A extends Algorithm>(
|
|
301
301
|
algorithm: A,
|
|
302
|
-
cryptoKey: CryptoKey
|
|
302
|
+
cryptoKey: WebCrypto.CryptoKey
|
|
303
303
|
): Effect.Effect<Key<A>, CryptoError.CryptoError> =>
|
|
304
304
|
KeyModel.fromCryptoKey("Cipher", "fromCryptoKey", KeyProto, algorithm, cryptoKey, {
|
|
305
305
|
type: "secret",
|
|
@@ -43,7 +43,7 @@ import * as Asymmetric from "./internal/asymmetric.ts"
|
|
|
43
43
|
import * as KeyModel from "./internal/key.ts"
|
|
44
44
|
import * as internal from "./internal/webCrypto.ts"
|
|
45
45
|
import * as SecureRandom from "./SecureRandom.ts"
|
|
46
|
-
import
|
|
46
|
+
import * as WebCrypto from "./WebCrypto.ts"
|
|
47
47
|
|
|
48
48
|
const PrivateKeyTypeId = "~effect/crypto/KeyAgreement/PrivateKey" as const
|
|
49
49
|
const PublicKeyTypeId = "~effect/crypto/KeyAgreement/PublicKey" as const
|
|
@@ -307,7 +307,7 @@ export const layerWebCrypto: Layer.Layer<KeyAgreement, never, SecureRandom.Secur
|
|
|
307
307
|
KeyAgreement,
|
|
308
308
|
Effect.gen(function*() {
|
|
309
309
|
const random = yield* SecureRandom.SecureRandom
|
|
310
|
-
const crypto = yield* WebCrypto
|
|
310
|
+
const crypto = yield* WebCrypto.WebCrypto
|
|
311
311
|
const caches = Asymmetric.makeCaches(family)
|
|
312
312
|
return KeyAgreement.of({
|
|
313
313
|
generateKeyPair: <A extends Algorithm>(algorithm: A) =>
|
|
@@ -447,7 +447,7 @@ export const publicKey = <A extends Algorithm>(
|
|
|
447
447
|
*/
|
|
448
448
|
export const privateKeyFromCryptoKey = <A extends Algorithm>(
|
|
449
449
|
algorithm: A,
|
|
450
|
-
cryptoKey: CryptoKey
|
|
450
|
+
cryptoKey: WebCrypto.CryptoKey
|
|
451
451
|
): Effect.Effect<PrivateKey<A>, CryptoError.CryptoError> =>
|
|
452
452
|
Asymmetric.fromCryptoKey(family, "privateKeyFromCryptoKey", algorithm, "private", cryptoKey)
|
|
453
453
|
|
|
@@ -467,7 +467,7 @@ export const privateKeyFromCryptoKey = <A extends Algorithm>(
|
|
|
467
467
|
*/
|
|
468
468
|
export const publicKeyFromCryptoKey = <A extends Algorithm>(
|
|
469
469
|
algorithm: A,
|
|
470
|
-
cryptoKey: CryptoKey
|
|
470
|
+
cryptoKey: WebCrypto.CryptoKey
|
|
471
471
|
): Effect.Effect<PublicKey<A>, CryptoError.CryptoError> =>
|
|
472
472
|
Asymmetric.fromCryptoKey(family, "publicKeyFromCryptoKey", algorithm, "public", cryptoKey)
|
|
473
473
|
|
package/src/crypto/KeyFormat.ts
CHANGED
|
@@ -76,6 +76,35 @@ export type Role = "public" | "private" | "secret"
|
|
|
76
76
|
*/
|
|
77
77
|
export type Direction = "decode" | "encode"
|
|
78
78
|
|
|
79
|
+
/**
|
|
80
|
+
* A JSON Web Key (RFC 7517) with the native Web Crypto field types and
|
|
81
|
+
* mutability, usable without DOM declarations.
|
|
82
|
+
*
|
|
83
|
+
* @stability unstable
|
|
84
|
+
* @category models
|
|
85
|
+
* @since 4.1.1
|
|
86
|
+
*/
|
|
87
|
+
export interface JsonWebKey {
|
|
88
|
+
alg?: string
|
|
89
|
+
crv?: string
|
|
90
|
+
d?: string
|
|
91
|
+
dp?: string
|
|
92
|
+
dq?: string
|
|
93
|
+
e?: string
|
|
94
|
+
ext?: boolean
|
|
95
|
+
k?: string
|
|
96
|
+
key_ops?: Array<string>
|
|
97
|
+
kty?: string
|
|
98
|
+
n?: string
|
|
99
|
+
oth?: Array<{ d?: string; r?: string; t?: string }>
|
|
100
|
+
p?: string
|
|
101
|
+
q?: string
|
|
102
|
+
qi?: string
|
|
103
|
+
use?: string
|
|
104
|
+
x?: string
|
|
105
|
+
y?: string
|
|
106
|
+
}
|
|
107
|
+
|
|
79
108
|
/**
|
|
80
109
|
* A key format, such as {@link spki} or `pem(pkcs8)`.
|
|
81
110
|
*
|
|
@@ -83,7 +112,7 @@ export type Direction = "decode" | "encode"
|
|
|
83
112
|
*
|
|
84
113
|
* `~tags` exists only in the types. It records the roles the format holds,
|
|
85
114
|
* whether it can be read and written, and the type of its data: `Uint8Array`
|
|
86
|
-
* for DER, `string` for PEM, and
|
|
115
|
+
* for DER, `string` for PEM, and {@link JsonWebKey} for JWK.
|
|
87
116
|
*
|
|
88
117
|
* @stability unstable
|
|
89
118
|
* @category models
|
package/src/crypto/KeyWrap.ts
CHANGED
|
@@ -44,7 +44,7 @@ import * as internal from "./internal/webCrypto.ts"
|
|
|
44
44
|
import type * as KeyFormat from "./KeyFormat.ts"
|
|
45
45
|
import * as Mac from "./Mac.ts"
|
|
46
46
|
import * as SecureRandom from "./SecureRandom.ts"
|
|
47
|
-
import
|
|
47
|
+
import * as WebCrypto from "./WebCrypto.ts"
|
|
48
48
|
|
|
49
49
|
const KeyTypeId = "~effect/crypto/KeyWrap/Key" as const
|
|
50
50
|
const PrivateKeyTypeId = "~effect/crypto/KeyWrap/PrivateKey" as const
|
|
@@ -417,7 +417,7 @@ export const layerWebCrypto: Layer.Layer<KeyWrap, never, SecureRandom.SecureRand
|
|
|
417
417
|
KeyWrap,
|
|
418
418
|
Effect.gen(function*() {
|
|
419
419
|
const random = yield* SecureRandom.SecureRandom
|
|
420
|
-
const crypto = yield* WebCrypto
|
|
420
|
+
const crypto = yield* WebCrypto.WebCrypto
|
|
421
421
|
const kwCryptoKey = KeyModel.makeCache((subtle, bytes) =>
|
|
422
422
|
subtle.importKey("raw", bytes as BufferSource, "AES-KW", false, ["wrapKey", "unwrapKey"])
|
|
423
423
|
)
|
|
@@ -553,7 +553,7 @@ export const key = <A extends AesKw>(
|
|
|
553
553
|
*/
|
|
554
554
|
export const fromCryptoKey = <A extends AesKw>(
|
|
555
555
|
algorithm: A,
|
|
556
|
-
cryptoKey: CryptoKey
|
|
556
|
+
cryptoKey: WebCrypto.CryptoKey
|
|
557
557
|
): Effect.Effect<Key<A>, CryptoError.CryptoError> =>
|
|
558
558
|
KeyModel.fromCryptoKey("KeyWrap", "fromCryptoKey", KeyProto, algorithm, cryptoKey, {
|
|
559
559
|
type: "secret",
|
|
@@ -570,7 +570,7 @@ const rsaFromCryptoKey = <K>(
|
|
|
570
570
|
proto: object,
|
|
571
571
|
algorithm: RsaOaep,
|
|
572
572
|
role: Asymmetric.Role,
|
|
573
|
-
cryptoKey: CryptoKey
|
|
573
|
+
cryptoKey: WebCrypto.CryptoKey
|
|
574
574
|
): Effect.Effect<K, CryptoError.CryptoError> =>
|
|
575
575
|
KeyModel.fromCryptoKey("KeyWrap", method, proto, algorithm, cryptoKey, {
|
|
576
576
|
type: role,
|
|
@@ -597,7 +597,7 @@ const rsaFromCryptoKey = <K>(
|
|
|
597
597
|
*/
|
|
598
598
|
export const privateKeyFromCryptoKey = <A extends RsaOaep>(
|
|
599
599
|
algorithm: A,
|
|
600
|
-
cryptoKey: CryptoKey
|
|
600
|
+
cryptoKey: WebCrypto.CryptoKey
|
|
601
601
|
): Effect.Effect<PrivateKey<A>, CryptoError.CryptoError> =>
|
|
602
602
|
rsaFromCryptoKey("privateKeyFromCryptoKey", PrivateKeyProto, algorithm, "private", cryptoKey)
|
|
603
603
|
|
|
@@ -617,7 +617,7 @@ export const privateKeyFromCryptoKey = <A extends RsaOaep>(
|
|
|
617
617
|
*/
|
|
618
618
|
export const publicKeyFromCryptoKey = <A extends RsaOaep>(
|
|
619
619
|
algorithm: A,
|
|
620
|
-
cryptoKey: CryptoKey
|
|
620
|
+
cryptoKey: WebCrypto.CryptoKey
|
|
621
621
|
): Effect.Effect<PublicKey<A>, CryptoError.CryptoError> =>
|
|
622
622
|
rsaFromCryptoKey("publicKeyFromCryptoKey", PublicKeyProto, algorithm, "public", cryptoKey)
|
|
623
623
|
|
package/src/crypto/Mac.ts
CHANGED
|
@@ -23,7 +23,7 @@ import * as Digest from "./Digest.ts"
|
|
|
23
23
|
import * as KeyModel from "./internal/key.ts"
|
|
24
24
|
import * as internal from "./internal/webCrypto.ts"
|
|
25
25
|
import * as SecureRandom from "./SecureRandom.ts"
|
|
26
|
-
import
|
|
26
|
+
import * as WebCrypto from "./WebCrypto.ts"
|
|
27
27
|
|
|
28
28
|
const TypeId = "~effect/crypto/Mac/Key" as const
|
|
29
29
|
|
|
@@ -215,7 +215,7 @@ export const layerWebCryptoWith = (options: {
|
|
|
215
215
|
Mac,
|
|
216
216
|
Effect.gen(function*() {
|
|
217
217
|
const random = yield* SecureRandom.SecureRandom
|
|
218
|
-
const crypto = yield* WebCrypto
|
|
218
|
+
const crypto = yield* WebCrypto.WebCrypto
|
|
219
219
|
const cryptoKeyFor = KeyModel.makeCache((subtle, bytes, algorithm: Algorithm) =>
|
|
220
220
|
subtle.importKey("raw", bytes as BufferSource, importParams(algorithm), false, ["sign", "verify"])
|
|
221
221
|
)
|
|
@@ -321,7 +321,7 @@ export const key = <A extends Algorithm>(
|
|
|
321
321
|
*/
|
|
322
322
|
export const fromCryptoKey = <A extends Algorithm>(
|
|
323
323
|
algorithm: A,
|
|
324
|
-
cryptoKey: CryptoKey
|
|
324
|
+
cryptoKey: WebCrypto.CryptoKey
|
|
325
325
|
): Effect.Effect<Key<A>, CryptoError.CryptoError> =>
|
|
326
326
|
KeyModel.fromCryptoKey("Mac", "fromCryptoKey", KeyProto, algorithm, cryptoKey, {
|
|
327
327
|
type: "secret",
|
package/src/crypto/Signature.ts
CHANGED
|
@@ -48,7 +48,7 @@ import * as Asymmetric from "./internal/asymmetric.ts"
|
|
|
48
48
|
import * as KeyModel from "./internal/key.ts"
|
|
49
49
|
import * as internal from "./internal/webCrypto.ts"
|
|
50
50
|
import * as SecureRandom from "./SecureRandom.ts"
|
|
51
|
-
import
|
|
51
|
+
import * as WebCrypto from "./WebCrypto.ts"
|
|
52
52
|
|
|
53
53
|
const PrivateKeyTypeId = "~effect/crypto/Signature/PrivateKey" as const
|
|
54
54
|
const PublicKeyTypeId = "~effect/crypto/Signature/PublicKey" as const
|
|
@@ -513,7 +513,7 @@ export const layerWebCrypto: Layer.Layer<Signature, never, SecureRandom.SecureRa
|
|
|
513
513
|
Signature,
|
|
514
514
|
Effect.gen(function*() {
|
|
515
515
|
const random = yield* SecureRandom.SecureRandom
|
|
516
|
-
const crypto = yield* WebCrypto
|
|
516
|
+
const crypto = yield* WebCrypto.WebCrypto
|
|
517
517
|
const caches = Asymmetric.makeCaches(family)
|
|
518
518
|
return Signature.of({
|
|
519
519
|
generateKeyPair: <A extends Algorithm>(algorithm: A) =>
|
|
@@ -630,7 +630,7 @@ export const publicKey = <
|
|
|
630
630
|
*/
|
|
631
631
|
export const privateKeyFromCryptoKey = <A extends Algorithm>(
|
|
632
632
|
algorithm: A,
|
|
633
|
-
cryptoKey: CryptoKey
|
|
633
|
+
cryptoKey: WebCrypto.CryptoKey
|
|
634
634
|
): Effect.Effect<PrivateKey<A>, CryptoError.CryptoError> =>
|
|
635
635
|
Asymmetric.fromCryptoKey(family, "privateKeyFromCryptoKey", algorithm, "private", cryptoKey)
|
|
636
636
|
|
|
@@ -650,7 +650,7 @@ export const privateKeyFromCryptoKey = <A extends Algorithm>(
|
|
|
650
650
|
*/
|
|
651
651
|
export const publicKeyFromCryptoKey = <A extends Algorithm>(
|
|
652
652
|
algorithm: A,
|
|
653
|
-
cryptoKey: CryptoKey
|
|
653
|
+
cryptoKey: WebCrypto.CryptoKey
|
|
654
654
|
): Effect.Effect<PublicKey<A>, CryptoError.CryptoError> =>
|
|
655
655
|
Asymmetric.fromCryptoKey(family, "publicKeyFromCryptoKey", algorithm, "public", cryptoKey)
|
|
656
656
|
|
package/src/crypto/WebCrypto.ts
CHANGED
|
@@ -20,6 +20,10 @@
|
|
|
20
20
|
import * as Context from "../Context.ts"
|
|
21
21
|
import * as Layer from "../Layer.ts"
|
|
22
22
|
|
|
23
|
+
// The type of `globalThis.crypto`, which, unlike the global `Crypto` type,
|
|
24
|
+
// every `@types/node` version declares.
|
|
25
|
+
type Crypto = typeof globalThis.crypto
|
|
26
|
+
|
|
23
27
|
/**
|
|
24
28
|
* Reference to the WebCrypto `Crypto` object, defaulting to
|
|
25
29
|
* `globalThis.crypto`.
|
|
@@ -62,3 +66,19 @@ export const WebCrypto: Context.Reference<Crypto> = Context.Reference<Crypto>("e
|
|
|
62
66
|
* @since 4.0.0
|
|
63
67
|
*/
|
|
64
68
|
export const layer = (crypto: Crypto): Layer.Layer<never> => Layer.succeed(WebCrypto, crypto)
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* A WebCrypto `CryptoKey`, declared structurally so the `effect` declarations
|
|
72
|
+
* type-check without the DOM library and with any `@types/node` version.
|
|
73
|
+
* Keys from `crypto.subtle` and Node's `webcrypto` are assignable to it.
|
|
74
|
+
*
|
|
75
|
+
* @stability unstable
|
|
76
|
+
* @category models
|
|
77
|
+
* @since 4.1.1
|
|
78
|
+
*/
|
|
79
|
+
export interface CryptoKey {
|
|
80
|
+
readonly algorithm: { readonly name: string }
|
|
81
|
+
readonly extractable: boolean
|
|
82
|
+
readonly type: "private" | "public" | "secret"
|
|
83
|
+
readonly usages: ReadonlyArray<string>
|
|
84
|
+
}
|
|
@@ -2,6 +2,7 @@ import * as Effect from "../../Effect.ts"
|
|
|
2
2
|
import * as Predicate from "../../Predicate.ts"
|
|
3
3
|
import * as CryptoError from "../CryptoError.ts"
|
|
4
4
|
import type * as SecureRandom from "../SecureRandom.ts"
|
|
5
|
+
import type * as WebCrypto from "../WebCrypto.ts"
|
|
5
6
|
import * as KeyModel from "./key.ts"
|
|
6
7
|
import * as internal from "./webCrypto.ts"
|
|
7
8
|
|
|
@@ -121,7 +122,7 @@ export const fromCryptoKey = <K>(
|
|
|
121
122
|
method: string,
|
|
122
123
|
algorithm: unknown,
|
|
123
124
|
role: Role,
|
|
124
|
-
cryptoKey: CryptoKey
|
|
125
|
+
cryptoKey: WebCrypto.CryptoKey
|
|
125
126
|
): Effect.Effect<K, CryptoError.CryptoError> => {
|
|
126
127
|
const spec = family.specOf(algorithm)
|
|
127
128
|
return KeyModel.fromCryptoKey(
|
|
@@ -4,6 +4,7 @@ import { format } from "../../Formatter.ts"
|
|
|
4
4
|
import { NodeInspectSymbol } from "../../Inspectable.ts"
|
|
5
5
|
import * as Predicate from "../../Predicate.ts"
|
|
6
6
|
import type * as CryptoError from "../CryptoError.ts"
|
|
7
|
+
import type * as WebCrypto from "../WebCrypto.ts"
|
|
7
8
|
import * as internal from "./webCrypto.ts"
|
|
8
9
|
|
|
9
10
|
/**
|
|
@@ -131,7 +132,7 @@ export const checkAesLength = (name: string, keyLength: number) => (algorithm: K
|
|
|
131
132
|
return length === keyLength * 8 ? undefined : `Expected a ${keyLength * 8}-bit ${name} key, not ${length} bits`
|
|
132
133
|
}
|
|
133
134
|
|
|
134
|
-
const checkCryptoKey = (cryptoKey: CryptoKey, expected: ExpectedCryptoKey): string | undefined => {
|
|
135
|
+
const checkCryptoKey = (cryptoKey: WebCrypto.CryptoKey, expected: ExpectedCryptoKey): string | undefined => {
|
|
135
136
|
if (
|
|
136
137
|
!Predicate.hasProperty(cryptoKey, "type") || !Predicate.hasProperty(cryptoKey, "algorithm") ||
|
|
137
138
|
!Predicate.hasProperty(cryptoKey, "usages") || !Array.isArray(cryptoKey.usages)
|
|
@@ -162,7 +163,7 @@ const checkCryptoKey = (cryptoKey: CryptoKey, expected: ExpectedCryptoKey): stri
|
|
|
162
163
|
*
|
|
163
164
|
* @internal
|
|
164
165
|
*/
|
|
165
|
-
export const importedAlgorithm = (algorithm: unknown, cryptoKey: CryptoKey): unknown => {
|
|
166
|
+
export const importedAlgorithm = (algorithm: unknown, cryptoKey: WebCrypto.CryptoKey): unknown => {
|
|
166
167
|
const modulusLength = (cryptoKey.algorithm as Partial<RsaKeyAlgorithm>).modulusLength
|
|
167
168
|
return Predicate.hasProperty(algorithm, "modulusLength") && modulusLength !== undefined &&
|
|
168
169
|
algorithm.modulusLength !== modulusLength
|
|
@@ -171,7 +172,8 @@ export const importedAlgorithm = (algorithm: unknown, cryptoKey: CryptoKey): unk
|
|
|
171
172
|
}
|
|
172
173
|
|
|
173
174
|
/**
|
|
174
|
-
* Synchronously validates and wraps a `CryptoKey`.
|
|
175
|
+
* Synchronously validates and wraps a `CryptoKey`. The structural key only
|
|
176
|
+
* becomes the native `CryptoKey` once it passes the check.
|
|
175
177
|
*
|
|
176
178
|
* @internal
|
|
177
179
|
*/
|
|
@@ -180,13 +182,18 @@ export const fromCryptoKey = <K>(
|
|
|
180
182
|
method: string,
|
|
181
183
|
proto: object,
|
|
182
184
|
algorithm: unknown,
|
|
183
|
-
cryptoKey: CryptoKey,
|
|
185
|
+
cryptoKey: WebCrypto.CryptoKey,
|
|
184
186
|
expected: ExpectedCryptoKey
|
|
185
187
|
): Effect.Effect<K, CryptoError.CryptoError> =>
|
|
186
188
|
Effect.suspend(() => {
|
|
187
189
|
const problem = checkCryptoKey(cryptoKey, expected)
|
|
188
190
|
return problem === undefined
|
|
189
|
-
? Effect.succeed(
|
|
191
|
+
? Effect.succeed(
|
|
192
|
+
make<K>(proto, importedAlgorithm(algorithm, cryptoKey), {
|
|
193
|
+
_tag: "CryptoKey",
|
|
194
|
+
cryptoKey: cryptoKey as CryptoKey
|
|
195
|
+
})
|
|
196
|
+
)
|
|
190
197
|
: internal.invalidKey(module, method, problem)
|
|
191
198
|
})
|
|
192
199
|
|
|
@@ -115,6 +115,7 @@ export const decode = (str: string): Result.Result<Uint8Array, EncodingError> =>
|
|
|
115
115
|
})
|
|
116
116
|
)
|
|
117
117
|
}
|
|
118
|
+
// Validating up front keeps failures as cheap as the scan, without allocating the output.
|
|
118
119
|
if (!/^[-_A-Z0-9]*?={0,2}$/i.test(stripped)) {
|
|
119
120
|
return Result.fail(
|
|
120
121
|
new EncodingError({
|
|
@@ -125,11 +126,34 @@ export const decode = (str: string): Result.Result<Uint8Array, EncodingError> =>
|
|
|
125
126
|
})
|
|
126
127
|
)
|
|
127
128
|
}
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
129
|
+
const end = !padded ? length : stripped.charCodeAt(length - 2) === 61 ? length - 2 : length - 1
|
|
130
|
+
const fullEnd = end & ~3
|
|
131
|
+
// Not `(end * 3) >> 2`: engines that allow strings over 2^31 / 3 characters would overflow int32.
|
|
132
|
+
const result = new Uint8Array(Math.floor(end * 3 / 4))
|
|
133
|
+
let j = 0
|
|
134
|
+
for (let i = 0; i < fullEnd; i += 4) {
|
|
135
|
+
const a = codes[stripped.charCodeAt(i)]
|
|
136
|
+
const b = codes[stripped.charCodeAt(i + 1)]
|
|
137
|
+
const c = codes[stripped.charCodeAt(i + 2)]
|
|
138
|
+
const d = codes[stripped.charCodeAt(i + 3)]
|
|
139
|
+
result[j++] = (a << 2) | (b >> 4)
|
|
140
|
+
result[j++] = (b << 4) | (c >> 2)
|
|
141
|
+
result[j++] = (c << 6) | d
|
|
142
|
+
}
|
|
143
|
+
// Non-zero trailing bits in the final character are ignored.
|
|
144
|
+
if (end > fullEnd) {
|
|
145
|
+
const a = codes[stripped.charCodeAt(fullEnd)]
|
|
146
|
+
const b = codes[stripped.charCodeAt(fullEnd + 1)]
|
|
147
|
+
result[j++] = (a << 2) | (b >> 4)
|
|
148
|
+
if (end - fullEnd === 3) result[j] = (b << 4) | (codes[stripped.charCodeAt(fullEnd + 2)] >> 2)
|
|
149
|
+
}
|
|
150
|
+
return Result.succeed(result)
|
|
131
151
|
}
|
|
132
152
|
|
|
153
|
+
const alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_"
|
|
154
|
+
const codes = new Uint8Array(128)
|
|
155
|
+
for (let i = 0; i < alphabet.length; i++) codes[alphabet.charCodeAt(i)] = i
|
|
156
|
+
|
|
133
157
|
/**
|
|
134
158
|
* Decodes a padded or unpadded URL-safe Base64 string into UTF-8 text safely.
|
|
135
159
|
*
|
package/src/encoding/Ndjson.ts
CHANGED
|
@@ -236,7 +236,7 @@ const parseLine = (
|
|
|
236
236
|
ignoreEmptyLines: boolean,
|
|
237
237
|
unterminated: boolean
|
|
238
238
|
): NdjsonError | undefined => {
|
|
239
|
-
if (ignoreEmptyLines && line
|
|
239
|
+
if (ignoreEmptyLines && /^[ \t]*$/.test(line)) return
|
|
240
240
|
try {
|
|
241
241
|
out.push(JSON.parse(line))
|
|
242
242
|
} catch (cause) {
|
|
@@ -262,8 +262,9 @@ const flushNothing = () => undefined
|
|
|
262
262
|
*
|
|
263
263
|
* **Gotchas**
|
|
264
264
|
*
|
|
265
|
-
* Set `ignoreEmptyLines` to skip
|
|
266
|
-
*
|
|
265
|
+
* Set `ignoreEmptyLines` to skip empty lines and lines containing only spaces
|
|
266
|
+
* or tabs before calling `JSON.parse`; otherwise these lines fail as invalid
|
|
267
|
+
* JSON.
|
|
267
268
|
*
|
|
268
269
|
* @stability unstable
|
|
269
270
|
* @category constructors
|
|
@@ -314,8 +315,8 @@ const emptyBytes = new Uint8Array(0)
|
|
|
314
315
|
* **Details**
|
|
315
316
|
*
|
|
316
317
|
* Lines may span input chunks. `\n`, `\r\n` and a bare `\r` end a line, and a
|
|
317
|
-
* leading UTF-8 BOM is skipped. `ignoreEmptyLines`
|
|
318
|
-
*
|
|
318
|
+
* leading UTF-8 BOM is skipped. `ignoreEmptyLines` skips empty lines and lines
|
|
319
|
+
* containing only spaces or tabs before JSON parsing.
|
|
319
320
|
*
|
|
320
321
|
* The first bad line fails the channel after the lines before it have been
|
|
321
322
|
* emitted. A line that is not valid UTF-8 fails with `reason: "InvalidUtf8"`
|
package/src/encoding/Sse.ts
CHANGED
|
@@ -667,7 +667,9 @@ export type AnyEvent = Event | Retry
|
|
|
667
667
|
* **Details**
|
|
668
668
|
*
|
|
669
669
|
* It renders `Event` values as `id`, `event`, and `data` lines and renders
|
|
670
|
-
* `Retry` values as `retry:` directives.
|
|
670
|
+
* `Retry` values as `retry:` directives. CR and LF are removed from `id` and
|
|
671
|
+
* `event`, and NUL is removed from `id`, so those values cannot inject fields
|
|
672
|
+
* or events.
|
|
671
673
|
*
|
|
672
674
|
* @stability unstable
|
|
673
675
|
* @category encoding
|
|
@@ -679,10 +681,10 @@ export const encoder: Encoder = {
|
|
|
679
681
|
case "Event": {
|
|
680
682
|
let data = ""
|
|
681
683
|
if (event.id !== undefined) {
|
|
682
|
-
data += `id: ${event.id}\n`
|
|
684
|
+
data += `id: ${event.id.replace(/[\r\n\0]/g, "")}\n`
|
|
683
685
|
}
|
|
684
686
|
if (event.event !== "message") {
|
|
685
|
-
data += `event: ${event.event}\n`
|
|
687
|
+
data += `event: ${event.event.replace(/[\r\n]/g, "")}\n`
|
|
686
688
|
}
|
|
687
689
|
data += `data: ${event.data.replace(/\r\n|\r|\n/g, "\ndata: ")}\n`
|
|
688
690
|
return data + "\n"
|
package/src/eventlog/EventLog.ts
CHANGED
|
@@ -303,6 +303,13 @@ export const layerRegistry = Layer.effect(
|
|
|
303
303
|
* The identity is used by remote replication for authentication and by the
|
|
304
304
|
* encryption service to derive signing and encryption keys.
|
|
305
305
|
*
|
|
306
|
+
* **Gotchas**
|
|
307
|
+
*
|
|
308
|
+
* `publicKey` identifies the identity but is not a secret, and nothing ties it
|
|
309
|
+
* to the signing key derived from `privateKey`. A server binds the first
|
|
310
|
+
* signing key that authenticates for a `publicKey`, unless its authorization
|
|
311
|
+
* checks the presented signing key.
|
|
312
|
+
*
|
|
306
313
|
* @stability unstable
|
|
307
314
|
* @category services
|
|
308
315
|
* @since 4.0.0
|
|
@@ -13,6 +13,7 @@ import type { NonEmptyReadonlyArray } from "../Array.ts"
|
|
|
13
13
|
import * as Arr from "../Array.ts"
|
|
14
14
|
import * as Cache from "../Cache.ts"
|
|
15
15
|
import * as Context from "../Context.ts"
|
|
16
|
+
import * as Mac from "../crypto/Mac.ts"
|
|
16
17
|
import * as Data from "../Data.ts"
|
|
17
18
|
import * as Duration from "../Duration.ts"
|
|
18
19
|
import * as Effect from "../Effect.ts"
|
|
@@ -76,6 +77,12 @@ export const layerAuthMiddleware: Layer.Layer<
|
|
|
76
77
|
* chunked writes, delegates write and change handling to the supplied callbacks,
|
|
77
78
|
* and frames large change payloads into chunks.
|
|
78
79
|
*
|
|
80
|
+
* `Authenticate` calls `authorizeIdentity` with the claimed public key and the
|
|
81
|
+
* presented signing public key, then verifies the signature against the
|
|
82
|
+
* presented key. Only a verified key is passed to
|
|
83
|
+
* `getOrCreateSessionAuthBinding`, and a key that differs from the identity's
|
|
84
|
+
* existing binding is rejected.
|
|
85
|
+
*
|
|
79
86
|
* Use the connection's `ConnectionWrites.track` in `onWrite` and
|
|
80
87
|
* `ConnectionWrites.filter` in `changes` to suppress its own write echoes.
|
|
81
88
|
* `compaction` sets `HelloResponse.compaction`, advertising that the server
|
|
@@ -89,7 +96,10 @@ export const layerRpcHandlers = (options: {
|
|
|
89
96
|
readonly remoteId: RemoteId
|
|
90
97
|
readonly firstSequence?: number | undefined
|
|
91
98
|
readonly compaction?: boolean | undefined
|
|
92
|
-
readonly authorizeIdentity?: (
|
|
99
|
+
readonly authorizeIdentity?: (
|
|
100
|
+
publicKey: string,
|
|
101
|
+
signingPublicKey: Uint8Array<ArrayBuffer>
|
|
102
|
+
) => Effect.Effect<void, EventLogProtocolError>
|
|
93
103
|
readonly getOrCreateSessionAuthBinding: (
|
|
94
104
|
publicKey: string,
|
|
95
105
|
signingPublicKey: Uint8Array<ArrayBuffer>
|
|
@@ -158,33 +168,40 @@ export const layerRpcHandlers = (options: {
|
|
|
158
168
|
}
|
|
159
169
|
yield* Cache.invalidate(clientChallenges, client.id)
|
|
160
170
|
if (options.authorizeIdentity) {
|
|
161
|
-
yield* options.authorizeIdentity(request.publicKey)
|
|
171
|
+
yield* options.authorizeIdentity(request.publicKey, request.signingPublicKey)
|
|
162
172
|
}
|
|
163
|
-
const signingPublicKey = yield* Cache.get(
|
|
164
|
-
persistedSigningPublicKeys,
|
|
165
|
-
new SessionAuthCacheKey({
|
|
166
|
-
publicKey: request.publicKey,
|
|
167
|
-
signingPublicKey: request.signingPublicKey
|
|
168
|
-
})
|
|
169
|
-
)
|
|
170
173
|
const verified = yield* EventLogSessionAuth.verifySessionAuthenticateRequest({
|
|
171
174
|
remoteId: options.remoteId,
|
|
172
175
|
challenge,
|
|
173
176
|
publicKey: request.publicKey,
|
|
174
|
-
signingPublicKey,
|
|
177
|
+
signingPublicKey: request.signingPublicKey,
|
|
175
178
|
signature: request.signature,
|
|
176
179
|
algorithm: request.algorithm
|
|
177
180
|
}).pipe(
|
|
178
181
|
Effect.catch(() => Effect.succeed(false))
|
|
179
182
|
)
|
|
180
183
|
|
|
181
|
-
|
|
182
|
-
|
|
184
|
+
const verificationFailed = () =>
|
|
185
|
+
new EventLogProtocolError({
|
|
183
186
|
requestTag: "Authenticate",
|
|
184
187
|
publicKey: request.publicKey,
|
|
185
188
|
code: "Forbidden",
|
|
186
189
|
message: "Session auth signature verification failed"
|
|
187
190
|
})
|
|
191
|
+
if (!verified) {
|
|
192
|
+
return yield* verificationFailed()
|
|
193
|
+
}
|
|
194
|
+
// Only a verified key reaches the binding. A key other than the
|
|
195
|
+
// identity's bound key is rejected like a bad signature.
|
|
196
|
+
const boundSigningPublicKey = yield* Cache.get(
|
|
197
|
+
persistedSigningPublicKeys,
|
|
198
|
+
new SessionAuthCacheKey({
|
|
199
|
+
publicKey: request.publicKey,
|
|
200
|
+
signingPublicKey: request.signingPublicKey
|
|
201
|
+
})
|
|
202
|
+
)
|
|
203
|
+
if (!Mac.timingSafeEqual(boundSigningPublicKey, request.signingPublicKey)) {
|
|
204
|
+
return yield* verificationFailed()
|
|
188
205
|
}
|
|
189
206
|
|
|
190
207
|
const authenticatedIdentities = new Set(
|
|
@@ -411,6 +428,8 @@ export class AuthenticatedIdentities extends Context.Service<AuthenticatedIdenti
|
|
|
411
428
|
"effect/eventlog/EventLogServer/AuthenticatedIdentities"
|
|
412
429
|
) {}
|
|
413
430
|
|
|
431
|
+
// Keyed by `publicKey` alone: the cache holds each identity's bound signing
|
|
432
|
+
// key, and `Authenticate` rejects any presented key that differs from it.
|
|
414
433
|
class SessionAuthCacheKey extends Data.Class<{
|
|
415
434
|
readonly publicKey: string
|
|
416
435
|
readonly signingPublicKey: Uint8Array<ArrayBuffer>
|
|
@@ -503,6 +503,11 @@ export class Storage extends Context.Service<Storage, {
|
|
|
503
503
|
* Lowest assigned sequence (default 0). Overestimating skips entries.
|
|
504
504
|
*/
|
|
505
505
|
readonly firstSequence?: number | undefined
|
|
506
|
+
/**
|
|
507
|
+
* Returns the signing key bound to `publicKey`, binding `signingPublicKey`
|
|
508
|
+
* when none is bound yet. The server only passes keys whose signature it
|
|
509
|
+
* has verified, and rejects a key that differs from the returned binding.
|
|
510
|
+
*/
|
|
506
511
|
readonly getOrCreateSessionAuthBinding: (
|
|
507
512
|
publicKey: string,
|
|
508
513
|
signingPublicKey: Uint8Array<ArrayBuffer>
|
|
@@ -165,8 +165,8 @@ export const layerRpcHandlers: Layer.Layer<
|
|
|
165
165
|
return EventLogServer.layerRpcHandlers({
|
|
166
166
|
remoteId,
|
|
167
167
|
firstSequence: storage.firstSequence,
|
|
168
|
-
authorizeIdentity: (publicKey) =>
|
|
169
|
-
auth.authorizeIdentity({ publicKey }).pipe(
|
|
168
|
+
authorizeIdentity: (publicKey, signingPublicKey) =>
|
|
169
|
+
auth.authorizeIdentity({ publicKey, signingPublicKey }).pipe(
|
|
170
170
|
Effect.mapError((error) =>
|
|
171
171
|
new EventLogProtocolError({
|
|
172
172
|
requestTag: "Authenticate",
|
|
@@ -318,6 +318,17 @@ export class EventLogServerAuthError extends Data.TaggedError("EventLogServerAut
|
|
|
318
318
|
* Use to provide authorization checks for plaintext event-log writes, reads,
|
|
319
319
|
* and identity authentication.
|
|
320
320
|
*
|
|
321
|
+
* **Gotchas**
|
|
322
|
+
*
|
|
323
|
+
* An identity's `publicKey` is an identifier, not a secret. The server binds
|
|
324
|
+
* the first signing key that authenticates for an identity and rejects any
|
|
325
|
+
* other key afterwards. `authorizeIdentity` also receives the presented
|
|
326
|
+
* `signingPublicKey`, so a deployment that records each identity's signing key
|
|
327
|
+
* at provisioning time, with `EventLogSessionAuth.deriveSigningPublicKey`, can
|
|
328
|
+
* reject every other key, including on first use. The server always supplies
|
|
329
|
+
* `signingPublicKey`; it is optional only so that existing callers keep
|
|
330
|
+
* compiling, and a policy that checks it should reject when it is missing.
|
|
331
|
+
*
|
|
321
332
|
* @stability unstable
|
|
322
333
|
* @category services
|
|
323
334
|
* @since 4.0.0
|
|
@@ -334,6 +345,7 @@ export class EventLogServerAuthorization extends Context.Service<EventLogServerA
|
|
|
334
345
|
}) => Effect.Effect<void, EventLogServerAuthError>
|
|
335
346
|
readonly authorizeIdentity: (options: {
|
|
336
347
|
readonly publicKey: string
|
|
348
|
+
readonly signingPublicKey?: Uint8Array<ArrayBuffer> | undefined
|
|
337
349
|
}) => Effect.Effect<void, EventLogServerAuthError>
|
|
338
350
|
}>()("effect/eventlog/EventLogServerUnencrypted/EventLogServerAuthorization") {}
|
|
339
351
|
|
|
@@ -422,6 +434,11 @@ export class Storage extends Context.Service<Storage, {
|
|
|
422
434
|
* Lowest assigned sequence (default 0). Overestimating skips entries.
|
|
423
435
|
*/
|
|
424
436
|
readonly firstSequence?: number | undefined
|
|
437
|
+
/**
|
|
438
|
+
* Returns the signing key bound to `publicKey`, binding `signingPublicKey`
|
|
439
|
+
* when none is bound yet. The server only passes keys whose signature it
|
|
440
|
+
* has verified, and rejects a key that differs from the returned binding.
|
|
441
|
+
*/
|
|
425
442
|
readonly getOrCreateSessionAuthBinding: (
|
|
426
443
|
publicKey: string,
|
|
427
444
|
signingPublicKey: Uint8Array<ArrayBuffer>
|
|
@@ -16,6 +16,8 @@ import { WebCrypto } from "../crypto/WebCrypto.ts"
|
|
|
16
16
|
import * as Data from "../Data.ts"
|
|
17
17
|
import * as Effect from "../Effect.ts"
|
|
18
18
|
import * as Layer from "../Layer.ts"
|
|
19
|
+
import type { Identity } from "./EventLog.ts"
|
|
20
|
+
import { makeGetIdentityRootSecretMaterial } from "./internal/identityRootSecretDerivation.ts"
|
|
19
21
|
|
|
20
22
|
const textEncoder = new TextEncoder()
|
|
21
23
|
const textDecoder = new TextDecoder("utf-8", { fatal: true })
|
|
@@ -524,3 +526,27 @@ export const verifySessionAuthenticateRequest = Effect.fnUntraced(function*(opti
|
|
|
524
526
|
signature: options.signature
|
|
525
527
|
})
|
|
526
528
|
})
|
|
529
|
+
|
|
530
|
+
const getIdentityRootSecretMaterial = makeGetIdentityRootSecretMaterial()
|
|
531
|
+
|
|
532
|
+
/**
|
|
533
|
+
* Derives the Ed25519 signing public key an identity presents during session
|
|
534
|
+
* authentication.
|
|
535
|
+
*
|
|
536
|
+
* **When to use**
|
|
537
|
+
*
|
|
538
|
+
* Use when provisioning an identity to record its signing key, so that server
|
|
539
|
+
* authorization can reject any other key presented for the identity's
|
|
540
|
+
* `publicKey`.
|
|
541
|
+
*
|
|
542
|
+
* **Details**
|
|
543
|
+
*
|
|
544
|
+
* The key is derived from the identity's private key on the `WebCrypto`
|
|
545
|
+
* reference.
|
|
546
|
+
*
|
|
547
|
+
* @stability unstable
|
|
548
|
+
* @category signing
|
|
549
|
+
* @since 4.1.1
|
|
550
|
+
*/
|
|
551
|
+
export const deriveSigningPublicKey = (identity: Identity["Service"]): Effect.Effect<Uint8Array<ArrayBuffer>> =>
|
|
552
|
+
Effect.map(getIdentityRootSecretMaterial(identity), (material) => material.signingPublicKey)
|
|
@@ -70,7 +70,9 @@ type ArgsWithOptions<Variables, Options> = {} extends Variables ? [variables: Va
|
|
|
70
70
|
* `partial: false`, it returns the decoded result and fails with a
|
|
71
71
|
* `ResponseError` on any `errors`. With `partial: true` it returns
|
|
72
72
|
* `{ data, errors }`. `partial` must be a literal `true` or `false`, not
|
|
73
|
-
* an arbitrary `boolean`.
|
|
73
|
+
* an arbitrary `boolean`. A non-2xx HTTP response never succeeds, even with
|
|
74
|
+
* `partial: true`: it fails with a `ResponseError` when it has `errors`, and
|
|
75
|
+
* with a `TransportError` otherwise.
|
|
74
76
|
*
|
|
75
77
|
* An operation without variables is called as `client.Viewer()` or, with
|
|
76
78
|
* options, `client.Viewer(undefined, { headers })`.
|