@effect-auth/core 0.1.0-alpha.0 → 0.1.0-alpha.2
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 +679 -36
- package/dist/AuditLog.d.ts +3 -0
- package/dist/AuditLog.d.ts.map +1 -1
- package/dist/AuditLog.js +6 -3
- package/dist/AuditLog.js.map +1 -1
- package/dist/AuthConfig.d.ts +51 -0
- package/dist/AuthConfig.d.ts.map +1 -0
- package/dist/AuthConfig.js +56 -0
- package/dist/AuthConfig.js.map +1 -0
- package/dist/AuthFlow.d.ts +295 -35
- package/dist/AuthFlow.d.ts.map +1 -1
- package/dist/AuthFlow.js +133 -6
- package/dist/AuthFlow.js.map +1 -1
- package/dist/AuthKernel.d.ts +3 -0
- package/dist/AuthKernel.d.ts.map +1 -0
- package/dist/AuthKernel.js +9 -0
- package/dist/AuthKernel.js.map +1 -0
- package/dist/Challenge.d.ts +22 -3
- package/dist/Challenge.d.ts.map +1 -1
- package/dist/Challenge.js +160 -1
- package/dist/Challenge.js.map +1 -1
- package/dist/Client.d.ts +36 -0
- package/dist/Client.d.ts.map +1 -0
- package/dist/Client.js +55 -0
- package/dist/Client.js.map +1 -0
- package/dist/Crypto.d.ts +9 -1
- package/dist/Crypto.d.ts.map +1 -1
- package/dist/Crypto.js +65 -1
- package/dist/Crypto.js.map +1 -1
- package/dist/D1Kysely.d.ts +43 -0
- package/dist/D1Kysely.d.ts.map +1 -0
- package/dist/D1Kysely.js +78 -0
- package/dist/D1Kysely.js.map +1 -0
- package/dist/EffectQbSqliteStorage.d.ts +183 -0
- package/dist/EffectQbSqliteStorage.d.ts.map +1 -0
- package/dist/EffectQbSqliteStorage.js +446 -0
- package/dist/EffectQbSqliteStorage.js.map +1 -0
- package/dist/EmailOtp.d.ts +117 -0
- package/dist/EmailOtp.d.ts.map +1 -0
- package/dist/EmailOtp.js +279 -0
- package/dist/EmailOtp.js.map +1 -0
- package/dist/EmailVerification.d.ts +121 -0
- package/dist/EmailVerification.d.ts.map +1 -0
- package/dist/EmailVerification.js +201 -0
- package/dist/EmailVerification.js.map +1 -0
- package/dist/HttpApi/Api.d.ts +175 -0
- package/dist/HttpApi/Api.d.ts.map +1 -0
- package/dist/HttpApi/Api.js +340 -0
- package/dist/HttpApi/Api.js.map +1 -0
- package/dist/HttpApi/Endpoints.d.ts +92 -0
- package/dist/HttpApi/Endpoints.d.ts.map +1 -0
- package/dist/HttpApi/Endpoints.js +48 -0
- package/dist/HttpApi/Endpoints.js.map +1 -0
- package/dist/HttpApi/Errors.d.ts +82 -0
- package/dist/HttpApi/Errors.d.ts.map +1 -0
- package/dist/HttpApi/Errors.js +184 -0
- package/dist/HttpApi/Errors.js.map +1 -0
- package/dist/HttpApi/Schemas.d.ts +86 -0
- package/dist/HttpApi/Schemas.d.ts.map +1 -0
- package/dist/HttpApi/Schemas.js +63 -0
- package/dist/HttpApi/Schemas.js.map +1 -0
- package/dist/HttpApi/Security.d.ts +147 -0
- package/dist/HttpApi/Security.d.ts.map +1 -0
- package/dist/HttpApi/Security.js +439 -0
- package/dist/HttpApi/Security.js.map +1 -0
- package/dist/HttpApi/Transport.d.ts +31 -0
- package/dist/HttpApi/Transport.d.ts.map +1 -0
- package/dist/HttpApi/Transport.js +169 -0
- package/dist/HttpApi/Transport.js.map +1 -0
- package/dist/HttpApi/index.d.ts +8 -0
- package/dist/HttpApi/index.d.ts.map +1 -0
- package/dist/HttpApi/index.js +7 -0
- package/dist/HttpApi/index.js.map +1 -0
- package/dist/HttpApi.d.ts +2 -0
- package/dist/HttpApi.d.ts.map +1 -0
- package/dist/HttpApi.js +2 -0
- package/dist/HttpApi.js.map +1 -0
- package/dist/Identifiers.d.ts.map +1 -1
- package/dist/Identifiers.js.map +1 -1
- package/dist/Internal.d.ts +7 -0
- package/dist/Internal.d.ts.map +1 -0
- package/dist/Internal.js +12 -0
- package/dist/Internal.js.map +1 -0
- package/dist/KyselyStorage.d.ts +67 -0
- package/dist/KyselyStorage.d.ts.map +1 -0
- package/dist/KyselyStorage.js +366 -0
- package/dist/KyselyStorage.js.map +1 -0
- package/dist/Mailer.d.ts +116 -0
- package/dist/Mailer.d.ts.map +1 -0
- package/dist/Mailer.js +101 -0
- package/dist/Mailer.js.map +1 -0
- package/dist/Password.d.ts +107 -0
- package/dist/Password.d.ts.map +1 -0
- package/dist/Password.js +252 -0
- package/dist/Password.js.map +1 -0
- package/dist/Policy.d.ts +7 -4
- package/dist/Policy.d.ts.map +1 -1
- package/dist/Policy.js +28 -5
- package/dist/Policy.js.map +1 -1
- package/dist/Privacy.d.ts +18 -0
- package/dist/Privacy.d.ts.map +1 -1
- package/dist/Privacy.js +63 -3
- package/dist/Privacy.js.map +1 -1
- package/dist/RateLimiter.d.ts +104 -0
- package/dist/RateLimiter.d.ts.map +1 -0
- package/dist/RateLimiter.js +118 -0
- package/dist/RateLimiter.js.map +1 -0
- package/dist/Sessions.d.ts +85 -11
- package/dist/Sessions.d.ts.map +1 -1
- package/dist/Sessions.js +424 -1
- package/dist/Sessions.js.map +1 -1
- package/dist/Storage.d.ts +162 -0
- package/dist/Storage.d.ts.map +1 -0
- package/dist/Storage.js +27 -0
- package/dist/Storage.js.map +1 -0
- package/dist/StorageMigrations.d.ts +8 -0
- package/dist/StorageMigrations.d.ts.map +1 -0
- package/dist/StorageMigrations.js +68 -0
- package/dist/StorageMigrations.js.map +1 -0
- package/dist/Testing.d.ts +9 -1
- package/dist/Testing.d.ts.map +1 -1
- package/dist/Testing.js +30 -2
- package/dist/Testing.js.map +1 -1
- package/dist/WaitUntil.d.ts +3 -0
- package/dist/WaitUntil.d.ts.map +1 -1
- package/dist/WaitUntil.js +6 -3
- package/dist/WaitUntil.js.map +1 -1
- package/dist/alchemy/cloudflare/RateLimitDurableObject.d.ts +34 -0
- package/dist/alchemy/cloudflare/RateLimitDurableObject.d.ts.map +1 -0
- package/dist/alchemy/cloudflare/RateLimitDurableObject.js +30 -0
- package/dist/alchemy/cloudflare/RateLimitDurableObject.js.map +1 -0
- package/dist/cloudflare/RateLimitDurableObject.d.ts +50 -0
- package/dist/cloudflare/RateLimitDurableObject.d.ts.map +1 -0
- package/dist/cloudflare/RateLimitDurableObject.js +51 -0
- package/dist/cloudflare/RateLimitDurableObject.js.map +1 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +7 -0
- package/dist/index.js.map +1 -1
- package/dist/internal/RateLimitDurableObject.d.ts +32 -0
- package/dist/internal/RateLimitDurableObject.d.ts.map +1 -0
- package/dist/internal/RateLimitDurableObject.js +80 -0
- package/dist/internal/RateLimitDurableObject.js.map +1 -0
- package/migrations/0001_auth_storage.sql +32 -0
- package/migrations/0002_auth_password.sql +25 -0
- package/package.json +97 -16
- package/LICENSE +0 -21
package/dist/AuthFlow.js
CHANGED
|
@@ -1,10 +1,137 @@
|
|
|
1
|
-
import { Context, Data, Effect } from "effect";
|
|
2
|
-
|
|
1
|
+
import { Context, Data, Effect, Layer } from "effect";
|
|
2
|
+
import { AuthEmailVerificationSessionPolicyConfig } from "./AuthConfig.js";
|
|
3
|
+
import { AuthFlowId } from "./Identifiers.js";
|
|
4
|
+
import { Sessions } from "./Sessions.js";
|
|
5
|
+
export class EmailVerificationSessionPolicy extends Context.Service()("auth/EmailVerificationSessionPolicy") {
|
|
6
|
+
}
|
|
7
|
+
(function (EmailVerificationSessionPolicy) {
|
|
8
|
+
EmailVerificationSessionPolicy.make = (service) => EmailVerificationSessionPolicy.of(service);
|
|
9
|
+
})(EmailVerificationSessionPolicy || (EmailVerificationSessionPolicy = {}));
|
|
10
|
+
const addEmailVerificationRequirement = (requirements) => requirements?.includes("email_verification") === true
|
|
11
|
+
? requirements
|
|
12
|
+
: [...(requirements ?? []), "email_verification"];
|
|
13
|
+
const removeEmailVerificationRequirement = (requirements) => requirements?.filter((requirement) => requirement !== "email_verification");
|
|
14
|
+
const withEmailVerified = (claims, emailVerified) => {
|
|
15
|
+
const requirements = emailVerified
|
|
16
|
+
? removeEmailVerificationRequirement(claims?.requirements)
|
|
17
|
+
: claims?.requirements;
|
|
18
|
+
return {
|
|
19
|
+
...claims,
|
|
20
|
+
emailVerified,
|
|
21
|
+
...(requirements === undefined ? {} : { requirements }),
|
|
22
|
+
};
|
|
23
|
+
};
|
|
24
|
+
const withEmailVerificationRequirement = (claims) => ({
|
|
25
|
+
...claims,
|
|
26
|
+
emailVerified: false,
|
|
27
|
+
requirements: addEmailVerificationRequirement(claims?.requirements),
|
|
28
|
+
});
|
|
29
|
+
export const makeEmailVerificationSessionPolicy = (options = {}) => {
|
|
30
|
+
const mode = options.mode ?? "allow-unverified";
|
|
31
|
+
return EmailVerificationSessionPolicy.make({
|
|
32
|
+
decide: Effect.fn("auth.email_verification_session_policy.decide")(function* (input) {
|
|
33
|
+
const emailVerified = input.claims?.emailVerified;
|
|
34
|
+
if (emailVerified !== false) {
|
|
35
|
+
return {
|
|
36
|
+
_tag: "CreateSession",
|
|
37
|
+
claims: emailVerified === true
|
|
38
|
+
? withEmailVerified(input.claims, true)
|
|
39
|
+
: input.claims,
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
switch (mode) {
|
|
43
|
+
case "allow-unverified": {
|
|
44
|
+
return {
|
|
45
|
+
_tag: "CreateSession",
|
|
46
|
+
claims: withEmailVerified(input.claims, false),
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
case "limited-session": {
|
|
50
|
+
return {
|
|
51
|
+
_tag: "CreateSession",
|
|
52
|
+
claims: withEmailVerificationRequirement(input.claims),
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
case "require-before-session": {
|
|
56
|
+
return { _tag: "RequiresEmailVerification" };
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}),
|
|
60
|
+
});
|
|
61
|
+
};
|
|
62
|
+
export const EmailVerificationSessionPolicyLive = (options) => Layer.succeed(EmailVerificationSessionPolicy)(makeEmailVerificationSessionPolicy(options));
|
|
63
|
+
export const AuthResult = Data.taggedEnum();
|
|
64
|
+
export class AuthFlowStateError extends Data.TaggedError("AuthFlowStateError") {
|
|
3
65
|
}
|
|
4
66
|
export class AuthFlow extends Context.Service()("auth/AuthFlow") {
|
|
5
67
|
}
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
68
|
+
(function (AuthFlow) {
|
|
69
|
+
AuthFlow.make = (service) => AuthFlow.of(service);
|
|
70
|
+
})(AuthFlow || (AuthFlow = {}));
|
|
71
|
+
export const makeAuthFlow = (dependencies) => {
|
|
72
|
+
const emailVerificationSessionPolicy = dependencies.emailVerificationSessionPolicy ??
|
|
73
|
+
makeEmailVerificationSessionPolicy();
|
|
74
|
+
const complete = Effect.fn("auth.auth_flow.complete")(function* (input) {
|
|
75
|
+
yield* Effect.annotateCurrentSpan({
|
|
76
|
+
"auth.method": input.method,
|
|
77
|
+
"auth.aal": input.aal,
|
|
78
|
+
"auth.amr_count": input.amr.length,
|
|
79
|
+
});
|
|
80
|
+
const session = yield* dependencies.sessions.create({
|
|
81
|
+
userId: input.userId,
|
|
82
|
+
method: input.method,
|
|
83
|
+
amr: input.amr,
|
|
84
|
+
aal: input.aal,
|
|
85
|
+
claims: input.claims,
|
|
86
|
+
});
|
|
87
|
+
yield* Effect.annotateCurrentSpan("auth.result", "Authenticated");
|
|
88
|
+
return AuthResult.Authenticated({ session });
|
|
89
|
+
});
|
|
90
|
+
const completePrimaryFactor = Effect.fn("auth.auth_flow.complete_primary_factor")(function* (input) {
|
|
91
|
+
const decision = yield* emailVerificationSessionPolicy.decide({
|
|
92
|
+
claims: input.claims,
|
|
93
|
+
});
|
|
94
|
+
if (decision._tag === "RequiresEmailVerification") {
|
|
95
|
+
yield* Effect.annotateCurrentSpan("auth.result", "RequiresEmailVerification");
|
|
96
|
+
return AuthResult.RequiresEmailVerification({
|
|
97
|
+
flowId: AuthFlowId("email-verification"),
|
|
98
|
+
...(input.email === undefined
|
|
99
|
+
? {}
|
|
100
|
+
: { userId: input.userId, email: input.email }),
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
return yield* complete({
|
|
104
|
+
userId: input.userId,
|
|
105
|
+
method: input.method,
|
|
106
|
+
amr: input.amr,
|
|
107
|
+
aal: input.aal,
|
|
108
|
+
claims: decision.claims,
|
|
109
|
+
});
|
|
110
|
+
});
|
|
111
|
+
return AuthFlow.make({
|
|
112
|
+
startPrimaryFactor: completePrimaryFactor,
|
|
113
|
+
completePrimaryFactor,
|
|
114
|
+
completeMfa: Effect.fn("auth.auth_flow.complete_mfa")(function* () {
|
|
115
|
+
return yield* new AuthFlowStateError({
|
|
116
|
+
message: "MFA flow state is not implemented yet",
|
|
117
|
+
});
|
|
118
|
+
}),
|
|
119
|
+
complete,
|
|
120
|
+
});
|
|
121
|
+
};
|
|
122
|
+
export const AuthFlowLive = Layer.effect(AuthFlow)(Effect.gen(function* () {
|
|
123
|
+
const sessions = yield* Sessions;
|
|
124
|
+
const emailVerificationSessionPolicyOptions = yield* AuthEmailVerificationSessionPolicyConfig;
|
|
125
|
+
return makeAuthFlow({
|
|
126
|
+
sessions,
|
|
127
|
+
emailVerificationSessionPolicy: makeEmailVerificationSessionPolicy(emailVerificationSessionPolicyOptions),
|
|
128
|
+
});
|
|
129
|
+
}));
|
|
130
|
+
export const AuthFlowLiveWithEmailVerificationPolicy = (options) => Layer.effect(AuthFlow)(Effect.gen(function* () {
|
|
131
|
+
const sessions = yield* Sessions;
|
|
132
|
+
return makeAuthFlow({
|
|
133
|
+
sessions,
|
|
134
|
+
emailVerificationSessionPolicy: makeEmailVerificationSessionPolicy(options),
|
|
135
|
+
});
|
|
136
|
+
}));
|
|
10
137
|
//# sourceMappingURL=AuthFlow.js.map
|
package/dist/AuthFlow.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AuthFlow.js","sourceRoot":"","sources":["../src/AuthFlow.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,QAAQ,
|
|
1
|
+
{"version":3,"file":"AuthFlow.js","sourceRoot":"","sources":["../src/AuthFlow.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import { Layer } from "effect";
|
|
2
|
+
export declare const AuthKernelLive: Layer.Layer<import("./Challenge.js").Challenge | import("./Sessions.js").Sessions | import("./Sessions.js").SessionCookie | import("./AuthFlow.js").AuthFlow | import("./Privacy.js").Privacy | import("./HttpApi/Transport.js").AuthHttp, never, import("./Crypto.js").Crypto | import("./Storage.js").VerificationStore | import("./AuthConfig.js").AuthSecrets | import("./Storage.js").SessionStore>;
|
|
3
|
+
//# sourceMappingURL=AuthKernel.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AuthKernel.d.ts","sourceRoot":"","sources":["../src/AuthKernel.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,QAAQ,CAAC;AAe/B,eAAO,MAAM,cAAc,0YAGyB,CAAC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { Layer } from "effect";
|
|
2
|
+
import { AuthFlowLive } from "./AuthFlow.js";
|
|
3
|
+
import { ChallengeLive } from "./Challenge.js";
|
|
4
|
+
import { AuthHttpTransportLive } from "./HttpApi/Transport.js";
|
|
5
|
+
import { PrivacyLive } from "./Privacy.js";
|
|
6
|
+
import { SessionCookieLive, SessionsLive } from "./Sessions.js";
|
|
7
|
+
const AuthKernelPrimitivesLive = Layer.mergeAll(SessionsLive(), SessionCookieLive(), ChallengeLive(), PrivacyLive());
|
|
8
|
+
export const AuthKernelLive = Layer.mergeAll(AuthFlowLive, AuthHttpTransportLive).pipe(Layer.provideMerge(AuthKernelPrimitivesLive));
|
|
9
|
+
//# sourceMappingURL=AuthKernel.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AuthKernel.js","sourceRoot":"","sources":["../src/AuthKernel.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,QAAQ,CAAC;AAE/B,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAC7C,OAAO,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAC/C,OAAO,EAAE,qBAAqB,EAAE,MAAM,wBAAwB,CAAC;AAC/D,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAC3C,OAAO,EAAE,iBAAiB,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAEhE,MAAM,wBAAwB,GAAG,KAAK,CAAC,QAAQ,CAC7C,YAAY,EAAE,EACd,iBAAiB,EAAE,EACnB,aAAa,EAAE,EACf,WAAW,EAAE,CACd,CAAC;AAEF,MAAM,CAAC,MAAM,cAAc,GAAG,KAAK,CAAC,QAAQ,CAC1C,YAAY,EACZ,qBAAqB,CACtB,CAAC,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,wBAAwB,CAAC,CAAC,CAAC"}
|
package/dist/Challenge.d.ts
CHANGED
|
@@ -1,6 +1,11 @@
|
|
|
1
|
-
import { Context, Effect, Redacted } from "effect";
|
|
2
|
-
import
|
|
3
|
-
import
|
|
1
|
+
import { Context, Duration, Effect, Layer, Redacted } from "effect";
|
|
2
|
+
import { AuthSecrets } from "./AuthConfig.js";
|
|
3
|
+
import { Crypto } from "./Crypto.js";
|
|
4
|
+
import type { CryptoKey, CryptoService } from "./Crypto.js";
|
|
5
|
+
import type { UnixMillis } from "./Identifiers.js";
|
|
6
|
+
import { ChallengeId } from "./Identifiers.js";
|
|
7
|
+
import { VerificationStore } from "./Storage.js";
|
|
8
|
+
import type { VerificationStoreService } from "./Storage.js";
|
|
4
9
|
export type ChallengeType = "email-otp" | "magic-link" | "passkey-authentication" | "reset-password" | "email-verification" | "oauth-state" | "mfa" | (string & {});
|
|
5
10
|
export interface ChallengeIssueInput {
|
|
6
11
|
readonly type: ChallengeType;
|
|
@@ -60,5 +65,19 @@ export interface ChallengeService {
|
|
|
60
65
|
declare const Challenge_base: Context.ServiceClass<Challenge, "auth/Challenge", ChallengeService>;
|
|
61
66
|
export declare class Challenge extends Challenge_base {
|
|
62
67
|
}
|
|
68
|
+
export declare namespace Challenge {
|
|
69
|
+
const make: (service: ChallengeService) => ChallengeService;
|
|
70
|
+
}
|
|
71
|
+
export interface ChallengeOptions {
|
|
72
|
+
readonly secret: CryptoKey;
|
|
73
|
+
readonly challengeIdBytes?: number;
|
|
74
|
+
}
|
|
75
|
+
export interface ChallengeDependencies extends ChallengeOptions {
|
|
76
|
+
readonly crypto: CryptoService;
|
|
77
|
+
readonly verificationStore: VerificationStoreService;
|
|
78
|
+
}
|
|
79
|
+
export declare const makeChallenge: (dependencies: ChallengeDependencies) => ChallengeService;
|
|
80
|
+
export declare function ChallengeLive(options: ChallengeOptions): Layer.Layer<Challenge, never, Crypto | VerificationStore>;
|
|
81
|
+
export declare function ChallengeLive(): Layer.Layer<Challenge, never, Crypto | VerificationStore | AuthSecrets>;
|
|
63
82
|
export {};
|
|
64
83
|
//# sourceMappingURL=Challenge.d.ts.map
|
package/dist/Challenge.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Challenge.d.ts","sourceRoot":"","sources":["../src/Challenge.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"Challenge.d.ts","sourceRoot":"","sources":["../src/Challenge.ts"],"names":[],"mappings":"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"}
|
package/dist/Challenge.js
CHANGED
|
@@ -1,4 +1,9 @@
|
|
|
1
|
-
import { Context, Data, Effect, Redacted } from "effect";
|
|
1
|
+
import { Context, Data, Duration, Effect, Layer, Option, Redacted, } from "effect";
|
|
2
|
+
import { AuthChallengeConfig, AuthSecrets } from "./AuthConfig.js";
|
|
3
|
+
import { Crypto } from "./Crypto.js";
|
|
4
|
+
import { ChallengeId } from "./Identifiers.js";
|
|
5
|
+
import { addMillis, currentUnixMillis, timingSafeEqualString, } from "./Internal.js";
|
|
6
|
+
import { VerificationStore } from "./Storage.js";
|
|
2
7
|
export class ChallengeIssueError extends Data.TaggedError("ChallengeIssueError") {
|
|
3
8
|
}
|
|
4
9
|
export class ChallengeVerifyError extends Data.TaggedError("ChallengeVerifyError") {
|
|
@@ -7,4 +12,158 @@ export class ChallengeConsumeError extends Data.TaggedError("ChallengeConsumeErr
|
|
|
7
12
|
}
|
|
8
13
|
export class Challenge extends Context.Service()("auth/Challenge") {
|
|
9
14
|
}
|
|
15
|
+
(function (Challenge) {
|
|
16
|
+
Challenge.make = (service) => Challenge.of(service);
|
|
17
|
+
})(Challenge || (Challenge = {}));
|
|
18
|
+
const ttlMillis = (ttl) => Duration.toMillis(ttl);
|
|
19
|
+
const hashChallengeSecret = (crypto, key, secret) => crypto.hmacSha256({ key, data: Redacted.value(secret) });
|
|
20
|
+
const verifiedFromRow = (row) => ({
|
|
21
|
+
id: row.id,
|
|
22
|
+
type: row.type,
|
|
23
|
+
subject: row.subject,
|
|
24
|
+
metadata: row.metadata,
|
|
25
|
+
});
|
|
26
|
+
export const makeChallenge = (dependencies) => {
|
|
27
|
+
const challengeIdBytes = dependencies.challengeIdBytes ?? 16;
|
|
28
|
+
return Challenge.make({
|
|
29
|
+
issue: Effect.fn("auth.challenge.issue")(function* (input) {
|
|
30
|
+
yield* Effect.annotateCurrentSpan("auth.challenge.type", input.type);
|
|
31
|
+
const ttl = ttlMillis(input.ttl);
|
|
32
|
+
if (!Number.isFinite(ttl) || ttl <= 0) {
|
|
33
|
+
return yield* new ChallengeIssueError({
|
|
34
|
+
message: "Challenge ttl must be a positive finite duration",
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
const now = yield* currentUnixMillis;
|
|
38
|
+
const id = ChallengeId(yield* dependencies.crypto.randomToken(challengeIdBytes).pipe(Effect.mapError((cause) => new ChallengeIssueError({
|
|
39
|
+
message: "Failed to generate challenge id",
|
|
40
|
+
cause,
|
|
41
|
+
}))));
|
|
42
|
+
const secretHash = input.secret === undefined
|
|
43
|
+
? undefined
|
|
44
|
+
: yield* hashChallengeSecret(dependencies.crypto, dependencies.secret, input.secret).pipe(Effect.mapError((cause) => new ChallengeIssueError({
|
|
45
|
+
message: "Failed to hash challenge secret",
|
|
46
|
+
cause,
|
|
47
|
+
})));
|
|
48
|
+
yield* dependencies.verificationStore
|
|
49
|
+
.insert({
|
|
50
|
+
id,
|
|
51
|
+
type: input.type,
|
|
52
|
+
subject: input.subject,
|
|
53
|
+
secretHash,
|
|
54
|
+
createdAt: now,
|
|
55
|
+
expiresAt: addMillis(now, ttl),
|
|
56
|
+
metadata: input.metadata,
|
|
57
|
+
})
|
|
58
|
+
.pipe(Effect.mapError((cause) => new ChallengeIssueError({
|
|
59
|
+
message: "Failed to store challenge",
|
|
60
|
+
cause,
|
|
61
|
+
})));
|
|
62
|
+
return {
|
|
63
|
+
id,
|
|
64
|
+
type: input.type,
|
|
65
|
+
subject: input.subject,
|
|
66
|
+
secret: input.secret,
|
|
67
|
+
expiresAt: addMillis(now, ttl),
|
|
68
|
+
};
|
|
69
|
+
}),
|
|
70
|
+
verify: Effect.fn("auth.challenge.verify")(function* (input) {
|
|
71
|
+
yield* Effect.annotateCurrentSpan("auth.challenge.type", input.type);
|
|
72
|
+
const now = yield* currentUnixMillis;
|
|
73
|
+
const rowOption = yield* dependencies.verificationStore
|
|
74
|
+
.findById(input.challengeId)
|
|
75
|
+
.pipe(Effect.mapError((cause) => new ChallengeVerifyError({
|
|
76
|
+
message: "Failed to load challenge",
|
|
77
|
+
cause,
|
|
78
|
+
})));
|
|
79
|
+
if (Option.isNone(rowOption)) {
|
|
80
|
+
return yield* new ChallengeVerifyError({
|
|
81
|
+
message: "Challenge not found",
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
const row = rowOption.value;
|
|
85
|
+
if (row.type !== input.type) {
|
|
86
|
+
return yield* new ChallengeVerifyError({
|
|
87
|
+
message: "Challenge type mismatch",
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
if (row.consumedAt !== undefined) {
|
|
91
|
+
return yield* new ChallengeVerifyError({
|
|
92
|
+
message: "Challenge already consumed",
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
if (Number(row.expiresAt) <= Number(now)) {
|
|
96
|
+
return yield* new ChallengeVerifyError({
|
|
97
|
+
message: "Challenge expired",
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
if (row.secretHash !== undefined) {
|
|
101
|
+
if (input.secret === undefined) {
|
|
102
|
+
return yield* new ChallengeVerifyError({
|
|
103
|
+
message: "Challenge secret is required",
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
const secretHash = yield* hashChallengeSecret(dependencies.crypto, dependencies.secret, input.secret).pipe(Effect.mapError((cause) => new ChallengeVerifyError({
|
|
107
|
+
message: "Failed to hash challenge secret",
|
|
108
|
+
cause,
|
|
109
|
+
})));
|
|
110
|
+
const secretMatches = yield* timingSafeEqualString(dependencies.crypto, secretHash, row.secretHash).pipe(Effect.mapError((cause) => new ChallengeVerifyError({
|
|
111
|
+
message: "Failed to compare challenge secret",
|
|
112
|
+
cause,
|
|
113
|
+
})));
|
|
114
|
+
if (!secretMatches) {
|
|
115
|
+
return yield* new ChallengeVerifyError({
|
|
116
|
+
message: "Invalid challenge secret",
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
const consumed = yield* dependencies.verificationStore
|
|
121
|
+
.consume({
|
|
122
|
+
id: input.challengeId,
|
|
123
|
+
type: input.type,
|
|
124
|
+
consumedAt: now,
|
|
125
|
+
})
|
|
126
|
+
.pipe(Effect.mapError((cause) => new ChallengeVerifyError({
|
|
127
|
+
message: "Failed to consume challenge",
|
|
128
|
+
cause,
|
|
129
|
+
})));
|
|
130
|
+
if (Option.isNone(consumed)) {
|
|
131
|
+
return yield* new ChallengeVerifyError({
|
|
132
|
+
message: "Challenge already consumed or expired",
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
return verifiedFromRow(consumed.value);
|
|
136
|
+
}),
|
|
137
|
+
consume: Effect.fn("auth.challenge.consume")(function* (id) {
|
|
138
|
+
const now = yield* currentUnixMillis;
|
|
139
|
+
const consumed = yield* dependencies.verificationStore
|
|
140
|
+
.consume({ id, consumedAt: now })
|
|
141
|
+
.pipe(Effect.mapError((cause) => new ChallengeConsumeError({
|
|
142
|
+
message: "Failed to consume challenge",
|
|
143
|
+
cause,
|
|
144
|
+
})));
|
|
145
|
+
if (Option.isNone(consumed)) {
|
|
146
|
+
return yield* new ChallengeConsumeError({
|
|
147
|
+
message: "Challenge not found, expired, or already consumed",
|
|
148
|
+
});
|
|
149
|
+
}
|
|
150
|
+
}),
|
|
151
|
+
});
|
|
152
|
+
};
|
|
153
|
+
export function ChallengeLive(options) {
|
|
154
|
+
return Layer.effect(Challenge)(Effect.gen(function* () {
|
|
155
|
+
const crypto = yield* Crypto;
|
|
156
|
+
const verificationStore = yield* VerificationStore;
|
|
157
|
+
const resolvedOptions = options ??
|
|
158
|
+
{
|
|
159
|
+
...(yield* AuthChallengeConfig),
|
|
160
|
+
secret: (yield* AuthSecrets).challenge,
|
|
161
|
+
};
|
|
162
|
+
return makeChallenge({
|
|
163
|
+
...resolvedOptions,
|
|
164
|
+
crypto,
|
|
165
|
+
verificationStore,
|
|
166
|
+
});
|
|
167
|
+
}));
|
|
168
|
+
}
|
|
10
169
|
//# sourceMappingURL=Challenge.js.map
|
package/dist/Challenge.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Challenge.js","sourceRoot":"","sources":["../src/Challenge.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"Challenge.js","sourceRoot":"","sources":["../src/Challenge.ts"],"names":[],"mappings":"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"}
|
package/dist/Client.d.ts
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { Schema } from "effect";
|
|
2
|
+
import { CurrentSessionHttpBody, EmailVerificationStartBody, EmailVerificationVerifyBody, PasswordAuthSuccess, PasswordSignInBody, PasswordSignUpBody } from "./HttpApi.js";
|
|
3
|
+
export type PasswordSignInRequest = Schema.Codec.Encoded<typeof PasswordSignInBody>;
|
|
4
|
+
export type PasswordSignUpRequest = Schema.Codec.Encoded<typeof PasswordSignUpBody>;
|
|
5
|
+
export type EmailVerificationStartRequest = Schema.Codec.Encoded<typeof EmailVerificationStartBody>;
|
|
6
|
+
export type EmailVerificationVerifyRequest = Schema.Codec.Encoded<typeof EmailVerificationVerifyBody>;
|
|
7
|
+
export type PasswordAuthResponse = Schema.Schema.Type<typeof PasswordAuthSuccess>;
|
|
8
|
+
export type CurrentSessionResponse = Schema.Schema.Type<typeof CurrentSessionHttpBody>;
|
|
9
|
+
export interface AuthClientRequestOptions {
|
|
10
|
+
readonly signal?: AbortSignal;
|
|
11
|
+
}
|
|
12
|
+
export interface AuthClientOptions {
|
|
13
|
+
readonly baseUrl?: URL | string;
|
|
14
|
+
readonly fetch?: typeof globalThis.fetch;
|
|
15
|
+
readonly requestInit?: RequestInit;
|
|
16
|
+
}
|
|
17
|
+
export interface AuthClient {
|
|
18
|
+
readonly password: {
|
|
19
|
+
readonly signIn: (input: PasswordSignInRequest, options?: AuthClientRequestOptions) => Promise<PasswordAuthResponse>;
|
|
20
|
+
readonly signUp: (input: PasswordSignUpRequest, options?: AuthClientRequestOptions) => Promise<PasswordAuthResponse>;
|
|
21
|
+
};
|
|
22
|
+
readonly session: {
|
|
23
|
+
readonly current: (options?: AuthClientRequestOptions) => Promise<CurrentSessionResponse>;
|
|
24
|
+
readonly currentOrUndefined: (options?: AuthClientRequestOptions) => Promise<CurrentSessionResponse | undefined>;
|
|
25
|
+
readonly refresh: (options?: AuthClientRequestOptions) => Promise<CurrentSessionResponse>;
|
|
26
|
+
readonly logout: (options?: AuthClientRequestOptions) => Promise<void>;
|
|
27
|
+
};
|
|
28
|
+
readonly emailVerification: {
|
|
29
|
+
readonly start: (input: EmailVerificationStartRequest, options?: AuthClientRequestOptions) => Promise<void>;
|
|
30
|
+
readonly verify: (input: EmailVerificationVerifyRequest, options?: AuthClientRequestOptions) => Promise<void>;
|
|
31
|
+
};
|
|
32
|
+
readonly dispose: () => Promise<void>;
|
|
33
|
+
}
|
|
34
|
+
export declare const authClientErrorMessage: (error: unknown) => string;
|
|
35
|
+
export declare const createAuthClient: (options?: AuthClientOptions) => AuthClient;
|
|
36
|
+
//# sourceMappingURL=Client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Client.d.ts","sourceRoot":"","sources":["../src/Client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAiC,MAAM,EAAE,MAAM,QAAQ,CAAC;AAI/D,OAAO,EAGL,sBAAsB,EACtB,0BAA0B,EAC1B,2BAA2B,EAC3B,mBAAmB,EACnB,kBAAkB,EAClB,kBAAkB,EACnB,MAAM,cAAc,CAAC;AAEtB,MAAM,MAAM,qBAAqB,GAAG,MAAM,CAAC,KAAK,CAAC,OAAO,CACtD,OAAO,kBAAkB,CAC1B,CAAC;AACF,MAAM,MAAM,qBAAqB,GAAG,MAAM,CAAC,KAAK,CAAC,OAAO,CACtD,OAAO,kBAAkB,CAC1B,CAAC;AACF,MAAM,MAAM,6BAA6B,GAAG,MAAM,CAAC,KAAK,CAAC,OAAO,CAC9D,OAAO,0BAA0B,CAClC,CAAC;AACF,MAAM,MAAM,8BAA8B,GAAG,MAAM,CAAC,KAAK,CAAC,OAAO,CAC/D,OAAO,2BAA2B,CACnC,CAAC;AACF,MAAM,MAAM,oBAAoB,GAAG,MAAM,CAAC,MAAM,CAAC,IAAI,CACnD,OAAO,mBAAmB,CAC3B,CAAC;AACF,MAAM,MAAM,sBAAsB,GAAG,MAAM,CAAC,MAAM,CAAC,IAAI,CACrD,OAAO,sBAAsB,CAC9B,CAAC;AAEF,MAAM,WAAW,wBAAwB;IACvC,QAAQ,CAAC,MAAM,CAAC,EAAE,WAAW,CAAC;CAC/B;AAED,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,OAAO,CAAC,EAAE,GAAG,GAAG,MAAM,CAAC;IAChC,QAAQ,CAAC,KAAK,CAAC,EAAE,OAAO,UAAU,CAAC,KAAK,CAAC;IACzC,QAAQ,CAAC,WAAW,CAAC,EAAE,WAAW,CAAC;CACpC;AAED,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,QAAQ,EAAE;QACjB,QAAQ,CAAC,MAAM,EAAE,CACf,KAAK,EAAE,qBAAqB,EAC5B,OAAO,CAAC,EAAE,wBAAwB,KAC/B,OAAO,CAAC,oBAAoB,CAAC,CAAC;QACnC,QAAQ,CAAC,MAAM,EAAE,CACf,KAAK,EAAE,qBAAqB,EAC5B,OAAO,CAAC,EAAE,wBAAwB,KAC/B,OAAO,CAAC,oBAAoB,CAAC,CAAC;KACpC,CAAC;IACF,QAAQ,CAAC,OAAO,EAAE;QAChB,QAAQ,CAAC,OAAO,EAAE,CAChB,OAAO,CAAC,EAAE,wBAAwB,KAC/B,OAAO,CAAC,sBAAsB,CAAC,CAAC;QACrC,QAAQ,CAAC,kBAAkB,EAAE,CAC3B,OAAO,CAAC,EAAE,wBAAwB,KAC/B,OAAO,CAAC,sBAAsB,GAAG,SAAS,CAAC,CAAC;QACjD,QAAQ,CAAC,OAAO,EAAE,CAChB,OAAO,CAAC,EAAE,wBAAwB,KAC/B,OAAO,CAAC,sBAAsB,CAAC,CAAC;QACrC,QAAQ,CAAC,MAAM,EAAE,CAAC,OAAO,CAAC,EAAE,wBAAwB,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;KACxE,CAAC;IACF,QAAQ,CAAC,iBAAiB,EAAE;QAC1B,QAAQ,CAAC,KAAK,EAAE,CACd,KAAK,EAAE,6BAA6B,EACpC,OAAO,CAAC,EAAE,wBAAwB,KAC/B,OAAO,CAAC,IAAI,CAAC,CAAC;QACnB,QAAQ,CAAC,MAAM,EAAE,CACf,KAAK,EAAE,8BAA8B,EACrC,OAAO,CAAC,EAAE,wBAAwB,KAC/B,OAAO,CAAC,IAAI,CAAC,CAAC;KACpB,CAAC;IACF,QAAQ,CAAC,OAAO,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CACvC;AASD,eAAO,MAAM,sBAAsB,GAAI,OAAO,OAAO,KAAG,MAYvD,CAAC;AAEF,eAAO,MAAM,gBAAgB,GAC3B,UAAS,iBAAsB,KAC9B,UA4FF,CAAC"}
|
package/dist/Client.js
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { Effect, Layer, ManagedRuntime, Schema } from "effect";
|
|
2
|
+
import { FetchHttpClient, HttpClient } from "effect/unstable/http";
|
|
3
|
+
import { HttpApiClient } from "effect/unstable/httpapi";
|
|
4
|
+
import { AuthApi, AuthUnauthenticatedError, CurrentSessionHttpBody, EmailVerificationStartBody, EmailVerificationVerifyBody, PasswordAuthSuccess, PasswordSignInBody, PasswordSignUpBody, } from "./HttpApi.js";
|
|
5
|
+
const defaultRequestInit = { credentials: "include" };
|
|
6
|
+
const authClientErrorShape = (error) => typeof error === "object" && error !== null
|
|
7
|
+
? error
|
|
8
|
+
: undefined;
|
|
9
|
+
export const authClientErrorMessage = (error) => {
|
|
10
|
+
const shape = authClientErrorShape(error);
|
|
11
|
+
if (typeof shape?.message === "string") {
|
|
12
|
+
return shape.message;
|
|
13
|
+
}
|
|
14
|
+
if (typeof shape?.code === "string") {
|
|
15
|
+
return shape.code;
|
|
16
|
+
}
|
|
17
|
+
return error instanceof Error ? error.message : "Request failed";
|
|
18
|
+
};
|
|
19
|
+
export const createAuthClient = (options = {}) => {
|
|
20
|
+
const requestInit = {
|
|
21
|
+
...defaultRequestInit,
|
|
22
|
+
...options.requestInit,
|
|
23
|
+
};
|
|
24
|
+
const fetchLayer = FetchHttpClient.layer.pipe(Layer.provide(Layer.succeed(FetchHttpClient.RequestInit, requestInit)), options.fetch === undefined
|
|
25
|
+
? (layer) => layer
|
|
26
|
+
: Layer.provide(Layer.succeed(FetchHttpClient.Fetch, options.fetch)));
|
|
27
|
+
const runtime = ManagedRuntime.make(fetchLayer);
|
|
28
|
+
const clientEffect = HttpApiClient.make(AuthApi, {
|
|
29
|
+
baseUrl: options.baseUrl,
|
|
30
|
+
});
|
|
31
|
+
const decodePasswordSignIn = Schema.decodeUnknownEffect(PasswordSignInBody);
|
|
32
|
+
const decodePasswordSignUp = Schema.decodeUnknownEffect(PasswordSignUpBody);
|
|
33
|
+
const decodeEmailVerificationStart = Schema.decodeUnknownEffect(EmailVerificationStartBody);
|
|
34
|
+
const decodeEmailVerificationVerify = Schema.decodeUnknownEffect(EmailVerificationVerifyBody);
|
|
35
|
+
const run = (effect, requestOptions = {}) => runtime.runPromise(effect, requestOptions);
|
|
36
|
+
const withClient = (effect, requestOptions) => run(Effect.flatMap(clientEffect, effect), requestOptions);
|
|
37
|
+
return {
|
|
38
|
+
password: {
|
|
39
|
+
signIn: (input, requestOptions) => withClient((client) => Effect.flatMap(decodePasswordSignIn(input), (payload) => client.password.signIn({ payload })), requestOptions),
|
|
40
|
+
signUp: (input, requestOptions) => withClient((client) => Effect.flatMap(decodePasswordSignUp(input), (payload) => client.password.signUp({ payload })), requestOptions),
|
|
41
|
+
},
|
|
42
|
+
session: {
|
|
43
|
+
current: (requestOptions) => withClient((client) => client.session.current(), requestOptions),
|
|
44
|
+
currentOrUndefined: (requestOptions) => withClient((client) => client.session.current().pipe(Effect.catchIf((error) => error instanceof AuthUnauthenticatedError, () => Effect.succeed(undefined))), requestOptions),
|
|
45
|
+
refresh: (requestOptions) => withClient((client) => client.session.refresh(), requestOptions),
|
|
46
|
+
logout: (requestOptions) => withClient((client) => client.session.logout(), requestOptions),
|
|
47
|
+
},
|
|
48
|
+
emailVerification: {
|
|
49
|
+
start: (input, requestOptions) => withClient((client) => Effect.flatMap(decodeEmailVerificationStart(input), (payload) => client.emailVerification.start({ payload })), requestOptions),
|
|
50
|
+
verify: (input, requestOptions) => withClient((client) => Effect.flatMap(decodeEmailVerificationVerify(input), (payload) => client.emailVerification.verify({ payload })), requestOptions),
|
|
51
|
+
},
|
|
52
|
+
dispose: () => runtime.dispose(),
|
|
53
|
+
};
|
|
54
|
+
};
|
|
55
|
+
//# sourceMappingURL=Client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Client.js","sourceRoot":"","sources":["../src/Client.ts"],"names":[],"mappings":"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"}
|
package/dist/Crypto.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Context, Effect, Redacted } from "effect";
|
|
1
|
+
import { Context, Effect, Layer, Redacted } from "effect";
|
|
2
2
|
export type CryptoOperation = "random-bytes" | "random-token" | "digest" | "hmac-sha256" | "timing-safe-equal";
|
|
3
3
|
declare const CryptoError_base: new <A extends Record<string, any> = {}>(args: import("effect/Types").VoidIfEmpty<{ readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }>) => import("effect/Cause").YieldableError & {
|
|
4
4
|
readonly _tag: "CryptoError";
|
|
@@ -31,5 +31,13 @@ export interface CryptoService {
|
|
|
31
31
|
declare const Crypto_base: Context.ServiceClass<Crypto, "auth/Crypto", CryptoService>;
|
|
32
32
|
export declare class Crypto extends Crypto_base {
|
|
33
33
|
}
|
|
34
|
+
export declare namespace Crypto {
|
|
35
|
+
const make: (service: CryptoService) => CryptoService;
|
|
36
|
+
}
|
|
37
|
+
export interface WebCryptoOptions {
|
|
38
|
+
readonly crypto?: typeof globalThis.crypto;
|
|
39
|
+
}
|
|
40
|
+
export declare const makeWebCrypto: (options?: WebCryptoOptions) => CryptoService;
|
|
41
|
+
export declare const WebCryptoLive: (options?: WebCryptoOptions) => Layer.Layer<Crypto, never, never>;
|
|
34
42
|
export {};
|
|
35
43
|
//# sourceMappingURL=Crypto.d.ts.map
|
package/dist/Crypto.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Crypto.d.ts","sourceRoot":"","sources":["../src/Crypto.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAQ,MAAM,EAAE,QAAQ,EAAE,MAAM,QAAQ,
|
|
1
|
+
{"version":3,"file":"Crypto.d.ts","sourceRoot":"","sources":["../src/Crypto.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAQ,MAAM,EAAY,KAAK,EAAE,QAAQ,EAAE,MAAM,QAAQ,CAAC;AAE1E,MAAM,MAAM,eAAe,GACvB,cAAc,GACd,cAAc,GACd,QAAQ,GACR,aAAa,GACb,mBAAmB,CAAC;;;;AAExB,qBAAa,WAAY,SAAQ,iBAAgC;IAC/D,QAAQ,CAAC,SAAS,EAAE,eAAe,CAAC;IACpC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,KAAK,CAAC,EAAE,OAAO,CAAC;CAC1B,CAAC;CAAG;AAEL,MAAM,MAAM,SAAS,GAAG,QAAQ,CAAC,QAAQ,CAAC,MAAM,CAAC,GAAG,UAAU,CAAC;AAE/D,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,GAAG,EAAE,SAAS,CAAC;IACxB,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,UAAU,CAAC;CACpC;AAED,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,UAAU,CAAC;CACpC;AAED,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAC;IAC1B,QAAQ,CAAC,KAAK,EAAE,UAAU,CAAC;CAC5B;AAED,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,WAAW,EAAE,CACpB,UAAU,EAAE,MAAM,KACf,MAAM,CAAC,MAAM,CAAC,UAAU,EAAE,WAAW,CAAC,CAAC;IAC5C,QAAQ,CAAC,WAAW,EAAE,CACpB,UAAU,CAAC,EAAE,MAAM,KAChB,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;IACxC,QAAQ,CAAC,YAAY,EAAE,CACrB,KAAK,EAAE,WAAW,KACf,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;IACxC,QAAQ,CAAC,UAAU,EAAE,CACnB,KAAK,EAAE,eAAe,KACnB,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;IACxC,QAAQ,CAAC,eAAe,EAAE,CACxB,KAAK,EAAE,oBAAoB,KACxB,MAAM,CAAC,MAAM,CAAC,OAAO,EAAE,WAAW,CAAC,CAAC;CAC1C;;AAED,qBAAa,MAAO,SAAQ,WAE3B;CAAG;AAEJ,yBAAiB,MAAM,CAAC;IACf,MAAM,IAAI,GAAI,SAAS,aAAa,KAAG,aAC1B,CAAC;CACtB;AAED,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,MAAM,CAAC,EAAE,OAAO,UAAU,CAAC,MAAM,CAAC;CAC5C;AA4CD,eAAO,MAAM,aAAa,GAAI,UAAU,gBAAgB,KAAG,aA2EvD,CAAC;AAEL,eAAO,MAAM,aAAa,GAAI,UAAU,gBAAgB,sCACT,CAAC"}
|
package/dist/Crypto.js
CHANGED
|
@@ -1,6 +1,70 @@
|
|
|
1
|
-
import { Context, Data, Effect, Redacted } from "effect";
|
|
1
|
+
import { Context, Data, Effect, Encoding, Layer, Redacted } from "effect";
|
|
2
2
|
export class CryptoError extends Data.TaggedError("CryptoError") {
|
|
3
3
|
}
|
|
4
4
|
export class Crypto extends Context.Service()("auth/Crypto") {
|
|
5
5
|
}
|
|
6
|
+
(function (Crypto) {
|
|
7
|
+
Crypto.make = (service) => Crypto.of(service);
|
|
8
|
+
})(Crypto || (Crypto = {}));
|
|
9
|
+
const textEncoder = new TextEncoder();
|
|
10
|
+
const cryptoError = (operation, message, cause) => new CryptoError({ operation, message, cause });
|
|
11
|
+
const getWebCrypto = (options, operation) => {
|
|
12
|
+
const crypto = options?.crypto ?? globalThis.crypto;
|
|
13
|
+
if (crypto === undefined) {
|
|
14
|
+
throw cryptoError(operation, "Web Crypto is not available");
|
|
15
|
+
}
|
|
16
|
+
return crypto;
|
|
17
|
+
};
|
|
18
|
+
const keyBytes = (key) => key instanceof Uint8Array ? key : textEncoder.encode(Redacted.value(key));
|
|
19
|
+
const valueBytes = (value) => typeof value === "string" ? textEncoder.encode(value) : value;
|
|
20
|
+
const randomBytesWith = (crypto, byteLength) => {
|
|
21
|
+
const bytes = new Uint8Array(byteLength);
|
|
22
|
+
for (let offset = 0; offset < bytes.length; offset += 65_536) {
|
|
23
|
+
crypto.getRandomValues(bytes.subarray(offset, Math.min(offset + 65_536, bytes.length)));
|
|
24
|
+
}
|
|
25
|
+
return bytes;
|
|
26
|
+
};
|
|
27
|
+
export const makeWebCrypto = (options) => Crypto.make({
|
|
28
|
+
randomBytes: (byteLength) => Effect.try({
|
|
29
|
+
try: () => {
|
|
30
|
+
if (!Number.isInteger(byteLength) || byteLength <= 0) {
|
|
31
|
+
throw new Error("byteLength must be a positive integer");
|
|
32
|
+
}
|
|
33
|
+
return randomBytesWith(getWebCrypto(options, "random-bytes"), byteLength);
|
|
34
|
+
},
|
|
35
|
+
catch: (cause) => cryptoError("random-bytes", "Failed to generate random bytes", cause),
|
|
36
|
+
}),
|
|
37
|
+
randomToken: (byteLength = 32) => Effect.try({
|
|
38
|
+
try: () => Encoding.encodeBase64Url(randomBytesWith(getWebCrypto(options, "random-token"), byteLength)),
|
|
39
|
+
catch: (cause) => cryptoError("random-token", "Failed to generate random token", cause),
|
|
40
|
+
}),
|
|
41
|
+
digestSha256: (input) => Effect.tryPromise({
|
|
42
|
+
try: async () => {
|
|
43
|
+
const digest = await getWebCrypto(options, "digest").subtle.digest("SHA-256", valueBytes(input.data));
|
|
44
|
+
return Encoding.encodeBase64Url(new Uint8Array(digest));
|
|
45
|
+
},
|
|
46
|
+
catch: (cause) => cryptoError("digest", "Failed to digest data", cause),
|
|
47
|
+
}),
|
|
48
|
+
hmacSha256: (input) => Effect.tryPromise({
|
|
49
|
+
try: async () => {
|
|
50
|
+
const crypto = getWebCrypto(options, "hmac-sha256");
|
|
51
|
+
const key = await crypto.subtle.importKey("raw", keyBytes(input.key), { name: "HMAC", hash: "SHA-256" }, false, ["sign"]);
|
|
52
|
+
const signature = await crypto.subtle.sign("HMAC", key, valueBytes(input.data));
|
|
53
|
+
return Encoding.encodeBase64Url(new Uint8Array(signature));
|
|
54
|
+
},
|
|
55
|
+
catch: (cause) => cryptoError("hmac-sha256", "Failed to calculate HMAC-SHA256", cause),
|
|
56
|
+
}),
|
|
57
|
+
timingSafeEqual: (input) => Effect.try({
|
|
58
|
+
try: () => {
|
|
59
|
+
const length = Math.max(input.left.length, input.right.length);
|
|
60
|
+
let diff = input.left.length ^ input.right.length;
|
|
61
|
+
for (let index = 0; index < length; index += 1) {
|
|
62
|
+
diff |= (input.left[index] ?? 0) ^ (input.right[index] ?? 0);
|
|
63
|
+
}
|
|
64
|
+
return diff === 0;
|
|
65
|
+
},
|
|
66
|
+
catch: (cause) => cryptoError("timing-safe-equal", "Failed to compare values", cause),
|
|
67
|
+
}),
|
|
68
|
+
});
|
|
69
|
+
export const WebCryptoLive = (options) => Layer.succeed(Crypto)(makeWebCrypto(options));
|
|
6
70
|
//# sourceMappingURL=Crypto.js.map
|