@passlock/client 0.9.30 → 2.0.0-beta.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.
Files changed (180) hide show
  1. package/README.md +14 -86
  2. package/README.template.md +16 -88
  3. package/dist/index.d.ts +4 -206
  4. package/dist/index.d.ts.map +1 -0
  5. package/dist/index.js +2 -158
  6. package/dist/index.js.map +1 -1
  7. package/dist/logger/index.d.ts +24 -0
  8. package/dist/logger/index.d.ts.map +1 -0
  9. package/dist/logger/index.js +47 -0
  10. package/dist/logger/index.js.map +1 -0
  11. package/dist/network.d.ts +39 -0
  12. package/dist/network.d.ts.map +1 -0
  13. package/dist/network.js +83 -0
  14. package/dist/network.js.map +1 -0
  15. package/dist/passkey/authentication/index.d.ts +21 -0
  16. package/dist/passkey/authentication/index.d.ts.map +1 -0
  17. package/dist/passkey/authentication/index.js +22 -0
  18. package/dist/passkey/authentication/index.js.map +1 -0
  19. package/dist/passkey/authentication/micro.d.ts +71 -0
  20. package/dist/passkey/authentication/micro.d.ts.map +1 -0
  21. package/dist/passkey/authentication/micro.js +107 -0
  22. package/dist/passkey/authentication/micro.js.map +1 -0
  23. package/dist/passkey/index.d.ts +7 -0
  24. package/dist/passkey/index.d.ts.map +1 -0
  25. package/dist/passkey/index.js +5 -0
  26. package/dist/passkey/index.js.map +1 -0
  27. package/dist/passkey/registration/index.d.ts +19 -0
  28. package/dist/passkey/registration/index.d.ts.map +1 -0
  29. package/dist/passkey/registration/index.js +20 -0
  30. package/dist/passkey/registration/index.js.map +1 -0
  31. package/dist/passkey/registration/micro.d.ts +101 -0
  32. package/dist/passkey/registration/micro.d.ts.map +1 -0
  33. package/dist/passkey/registration/micro.js +126 -0
  34. package/dist/passkey/registration/micro.js.map +1 -0
  35. package/dist/passkey/shared.d.ts +24 -0
  36. package/dist/passkey/shared.d.ts.map +1 -0
  37. package/dist/passkey/shared.js +10 -0
  38. package/dist/passkey/shared.js.map +1 -0
  39. package/dist/passkey/support.d.ts +3 -0
  40. package/dist/passkey/support.d.ts.map +1 -0
  41. package/dist/passkey/support.js +4 -0
  42. package/dist/passkey/support.js.map +1 -0
  43. package/dist/passkey/types.d.ts +26 -0
  44. package/dist/passkey/types.d.ts.map +1 -0
  45. package/dist/passkey/types.js +2 -0
  46. package/dist/passkey/types.js.map +1 -0
  47. package/dist/promise.d.ts +15 -0
  48. package/dist/promise.d.ts.map +1 -0
  49. package/dist/promise.js +46 -0
  50. package/dist/promise.js.map +1 -0
  51. package/dist/shared.d.ts +15 -0
  52. package/dist/shared.d.ts.map +1 -0
  53. package/dist/shared.js +2 -0
  54. package/dist/shared.js.map +1 -0
  55. package/dist/tenancy.d.ts +8 -0
  56. package/dist/tenancy.d.ts.map +1 -0
  57. package/dist/tenancy.js +4 -0
  58. package/dist/tenancy.js.map +1 -0
  59. package/package.json +52 -58
  60. package/LICENSE +0 -21
  61. package/dist/authentication/authenticate.d.ts +0 -24
  62. package/dist/authentication/authenticate.fixture.d.ts +0 -52
  63. package/dist/authentication/authenticate.fixture.js +0 -50
  64. package/dist/authentication/authenticate.fixture.js.map +0 -1
  65. package/dist/authentication/authenticate.js +0 -73
  66. package/dist/authentication/authenticate.js.map +0 -1
  67. package/dist/capabilities/capabilities.d.ts +0 -19
  68. package/dist/capabilities/capabilities.js +0 -37
  69. package/dist/capabilities/capabilities.js.map +0 -1
  70. package/dist/connection/connection.d.ts +0 -15
  71. package/dist/connection/connection.fixture.d.ts +0 -10
  72. package/dist/connection/connection.fixture.js +0 -13
  73. package/dist/connection/connection.fixture.js.map +0 -1
  74. package/dist/connection/connection.js +0 -23
  75. package/dist/connection/connection.js.map +0 -1
  76. package/dist/effect.d.ts +0 -26
  77. package/dist/effect.js +0 -78
  78. package/dist/effect.js.map +0 -1
  79. package/dist/email/email.d.ts +0 -70
  80. package/dist/email/email.fixture.d.ts +0 -46
  81. package/dist/email/email.fixture.js +0 -25
  82. package/dist/email/email.fixture.js.map +0 -1
  83. package/dist/email/email.js +0 -83
  84. package/dist/email/email.js.map +0 -1
  85. package/dist/event/event.d.ts +0 -8
  86. package/dist/event/event.js +0 -23
  87. package/dist/event/event.js.map +0 -1
  88. package/dist/logging/eventLogger.d.ts +0 -17
  89. package/dist/logging/eventLogger.js +0 -38
  90. package/dist/logging/eventLogger.js.map +0 -1
  91. package/dist/registration/register.d.ts +0 -27
  92. package/dist/registration/register.fixture.d.ts +0 -53
  93. package/dist/registration/register.fixture.js +0 -66
  94. package/dist/registration/register.fixture.js.map +0 -1
  95. package/dist/registration/register.js +0 -78
  96. package/dist/registration/register.js.map +0 -1
  97. package/dist/rpc/authentication.d.ts +0 -8
  98. package/dist/rpc/authentication.js +0 -16
  99. package/dist/rpc/authentication.js.map +0 -1
  100. package/dist/rpc/client.d.ts +0 -30
  101. package/dist/rpc/client.js +0 -101
  102. package/dist/rpc/client.js.map +0 -1
  103. package/dist/rpc/config.d.ts +0 -15
  104. package/dist/rpc/config.js +0 -6
  105. package/dist/rpc/config.js.map +0 -1
  106. package/dist/rpc/connection.d.ts +0 -8
  107. package/dist/rpc/connection.js +0 -15
  108. package/dist/rpc/connection.js.map +0 -1
  109. package/dist/rpc/registration.d.ts +0 -8
  110. package/dist/rpc/registration.js +0 -16
  111. package/dist/rpc/registration.js.map +0 -1
  112. package/dist/rpc/social.d.ts +0 -10
  113. package/dist/rpc/social.js +0 -18
  114. package/dist/rpc/social.js.map +0 -1
  115. package/dist/rpc/user.d.ts +0 -8
  116. package/dist/rpc/user.js +0 -19
  117. package/dist/rpc/user.js.map +0 -1
  118. package/dist/social/social.d.ts +0 -24
  119. package/dist/social/social.fixture.d.ts +0 -46
  120. package/dist/social/social.fixture.js +0 -31
  121. package/dist/social/social.fixture.js.map +0 -1
  122. package/dist/social/social.js +0 -39
  123. package/dist/social/social.js.map +0 -1
  124. package/dist/storage/storage.d.ts +0 -56
  125. package/dist/storage/storage.fixture.d.ts +0 -4
  126. package/dist/storage/storage.fixture.js +0 -10
  127. package/dist/storage/storage.fixture.js.map +0 -1
  128. package/dist/storage/storage.js +0 -111
  129. package/dist/storage/storage.js.map +0 -1
  130. package/dist/test/fixtures.d.ts +0 -15
  131. package/dist/test/fixtures.js +0 -56
  132. package/dist/test/fixtures.js.map +0 -1
  133. package/dist/tsconfig.tsbuildinfo +0 -1
  134. package/dist/user/user.d.ts +0 -25
  135. package/dist/user/user.fixture.d.ts +0 -12
  136. package/dist/user/user.fixture.js +0 -20
  137. package/dist/user/user.fixture.js.map +0 -1
  138. package/dist/user/user.js +0 -38
  139. package/dist/user/user.js.map +0 -1
  140. package/dist/version.d.ts +0 -1
  141. package/dist/version.js +0 -2
  142. package/dist/version.js.map +0 -1
  143. package/src/authentication/authenticate.fixture.ts +0 -73
  144. package/src/authentication/authenticate.test.ts +0 -249
  145. package/src/authentication/authenticate.ts +0 -149
  146. package/src/capabilities/capabilities.ts +0 -83
  147. package/src/connection/connection.fixture.ts +0 -20
  148. package/src/connection/connection.test.ts +0 -60
  149. package/src/connection/connection.ts +0 -51
  150. package/src/effect.ts +0 -280
  151. package/src/email/email.fixture.ts +0 -44
  152. package/src/email/email.test.ts +0 -186
  153. package/src/email/email.ts +0 -148
  154. package/src/event/event.node.test.ts +0 -21
  155. package/src/event/event.test.ts +0 -37
  156. package/src/event/event.ts +0 -25
  157. package/src/index.ts +0 -407
  158. package/src/logging/eventLogger.test.ts +0 -104
  159. package/src/logging/eventLogger.ts +0 -41
  160. package/src/registration/register.fixture.ts +0 -96
  161. package/src/registration/register.test.ts +0 -216
  162. package/src/registration/register.ts +0 -158
  163. package/src/rpc/authentication.ts +0 -43
  164. package/src/rpc/client.ts +0 -174
  165. package/src/rpc/config.ts +0 -18
  166. package/src/rpc/connection.ts +0 -30
  167. package/src/rpc/registration.ts +0 -41
  168. package/src/rpc/social.ts +0 -45
  169. package/src/rpc/user.ts +0 -57
  170. package/src/social/social.fixture.ts +0 -45
  171. package/src/social/social.test.ts +0 -179
  172. package/src/social/social.ts +0 -82
  173. package/src/storage/storage.fixture.ts +0 -16
  174. package/src/storage/storage.test.ts +0 -206
  175. package/src/storage/storage.ts +0 -168
  176. package/src/test/fixtures.ts +0 -70
  177. package/src/user/user.fixture.ts +0 -33
  178. package/src/user/user.test.ts +0 -84
  179. package/src/user/user.ts +0 -73
  180. package/src/version.ts +0 -1
@@ -1,25 +0,0 @@
1
- /**
2
- * Check for an existing user
3
- */
4
- import { Context, Effect as E, Layer } from 'effect';
5
- import type { BadRequest, Disabled, NotFound } from '@passlock/shared/dist/error/error.js';
6
- import type { VerifyEmail } from '@passlock/shared/dist/schema/email.js';
7
- import { UserClient } from '../rpc/user.js';
8
- export type Email = {
9
- email: string;
10
- };
11
- export type ResendEmail = VerifyEmail & {
12
- userId: string;
13
- };
14
- export type ResendEmailErrors = BadRequest | NotFound | Disabled;
15
- declare const UserService_base: Context.TagClass<UserService, "@services/UserService", {
16
- isExistingUser: (request: Email) => E.Effect<boolean, BadRequest>;
17
- resendVerificationEmail: (request: ResendEmail) => E.Effect<void, ResendEmailErrors>;
18
- }>;
19
- export declare class UserService extends UserService_base {
20
- }
21
- type Dependencies = UserClient;
22
- export declare const isExistingUser: (request: Email) => E.Effect<boolean, BadRequest, Dependencies>;
23
- export declare const resendVerificationEmail: (request: ResendEmail) => E.Effect<void, ResendEmailErrors, Dependencies>;
24
- export declare const UserServiceLive: Layer.Layer<UserService, never, UserClient>;
25
- export {};
@@ -1,12 +0,0 @@
1
- import { Layer as L } from 'effect';
2
- import { IsExistingUserReq, IsExistingUserRes, ResendEmailReq, ResendEmailRes, VerifyEmailRes } from '@passlock/shared/dist/rpc/user.js';
3
- import { UserClient } from '../rpc/user.js';
4
- import type { ResendEmail } from './user.js';
5
- export declare const email = "jdoe@gmail.com";
6
- export declare const isRegisteredReq: IsExistingUserReq;
7
- export declare const isRegisteredRes: IsExistingUserRes;
8
- export declare const verifyEmailRes: VerifyEmailRes;
9
- export declare const resendEmailReq: ResendEmail;
10
- export declare const rpcResendEmailReq: ResendEmailReq;
11
- export declare const rpcResendEmailRes: ResendEmailRes;
12
- export declare const rpcClientTest: L.Layer<UserClient, never, never>;
@@ -1,20 +0,0 @@
1
- import { Effect as E, Layer as L, Option as O } from 'effect';
2
- import { IsExistingUserReq, IsExistingUserRes, ResendEmailReq, ResendEmailRes, VerifyEmailRes, } from '@passlock/shared/dist/rpc/user.js';
3
- import * as Fixtures from '../test/fixtures.js';
4
- import { UserClient } from '../rpc/user.js';
5
- export const email = 'jdoe@gmail.com';
6
- export const isRegisteredReq = new IsExistingUserReq({ email });
7
- export const isRegisteredRes = new IsExistingUserRes({ existingUser: false, detail: O.none() });
8
- export const verifyEmailRes = new VerifyEmailRes({ principal: Fixtures.principal });
9
- export const resendEmailReq = { userId: '123', method: 'code' };
10
- export const rpcResendEmailReq = new ResendEmailReq({
11
- userId: '123',
12
- verifyEmail: { method: 'code' },
13
- });
14
- export const rpcResendEmailRes = new ResendEmailRes({});
15
- export const rpcClientTest = L.succeed(UserClient, UserClient.of({
16
- isExistingUser: () => E.succeed({ existingUser: true, detail: O.none() }),
17
- verifyEmail: () => E.succeed(verifyEmailRes),
18
- resendVerificationEmail: () => E.fail(Fixtures.notImplemented),
19
- }));
20
- //# sourceMappingURL=user.fixture.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"user.fixture.js","sourceRoot":"","sources":["../../src/user/user.fixture.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,IAAI,CAAC,EAAE,KAAK,IAAI,CAAC,EAAE,MAAM,IAAI,CAAC,EAAE,MAAM,QAAQ,CAAA;AAE7D,OAAO,EACL,iBAAiB,EACjB,iBAAiB,EACjB,cAAc,EACd,cAAc,EACd,cAAc,GACf,MAAM,mCAAmC,CAAA;AAE1C,OAAO,KAAK,QAAQ,MAAM,qBAAqB,CAAA;AAC/C,OAAO,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAA;AAG3C,MAAM,CAAC,MAAM,KAAK,GAAG,gBAAgB,CAAA;AACrC,MAAM,CAAC,MAAM,eAAe,GAAG,IAAI,iBAAiB,CAAC,EAAE,KAAK,EAAE,CAAC,CAAA;AAC/D,MAAM,CAAC,MAAM,eAAe,GAAG,IAAI,iBAAiB,CAAC,EAAE,YAAY,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAA;AAC/F,MAAM,CAAC,MAAM,cAAc,GAAG,IAAI,cAAc,CAAC,EAAE,SAAS,EAAE,QAAQ,CAAC,SAAS,EAAE,CAAC,CAAA;AACnF,MAAM,CAAC,MAAM,cAAc,GAAgB,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,CAAA;AAC5E,MAAM,CAAC,MAAM,iBAAiB,GAAG,IAAI,cAAc,CAAC;IAClD,MAAM,EAAE,KAAK;IACb,WAAW,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE;CAChC,CAAC,CAAA;AACF,MAAM,CAAC,MAAM,iBAAiB,GAAG,IAAI,cAAc,CAAC,EAAE,CAAC,CAAA;AAEvD,MAAM,CAAC,MAAM,aAAa,GAAG,CAAC,CAAC,OAAO,CACpC,UAAU,EACV,UAAU,CAAC,EAAE,CAAC;IACZ,cAAc,EAAE,GAAG,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,YAAY,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC;IACzE,WAAW,EAAE,GAAG,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,cAAc,CAAC;IAC5C,uBAAuB,EAAE,GAAG,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,cAAc,CAAC;CAC/D,CAAC,CACH,CAAA"}
package/dist/user/user.js DELETED
@@ -1,38 +0,0 @@
1
- /**
2
- * Check for an existing user
3
- */
4
- import { Context, Effect as E, Layer, flow } from 'effect';
5
- import { IsExistingUserReq, ResendEmailReq } from '@passlock/shared/dist/rpc/user.js';
6
- import { UserClient } from '../rpc/user.js';
7
- /* Service */
8
- export class UserService extends Context.Tag('@services/UserService')() {
9
- }
10
- export const isExistingUser = (request) => {
11
- return E.gen(function* (_) {
12
- yield* _(E.logInfo('Checking registration status'));
13
- const rpcClient = yield* _(UserClient);
14
- yield* _(E.logDebug('Making RPC request'));
15
- const { existingUser } = yield* _(rpcClient.isExistingUser(new IsExistingUserReq(request)));
16
- return existingUser;
17
- });
18
- };
19
- export const resendVerificationEmail = (request) => {
20
- return E.gen(function* (_) {
21
- yield* _(E.logInfo('Resending verification email'));
22
- const rpcClient = yield* _(UserClient);
23
- yield* _(E.logDebug('Making RPC request'));
24
- const { userId, ...verifyEmail } = request;
25
- yield* _(rpcClient.resendVerificationEmail(new ResendEmailReq({ userId, verifyEmail })));
26
- });
27
- };
28
- /* Live */
29
- /* v8 ignore start */
30
- export const UserServiceLive = Layer.effect(UserService, E.gen(function* (_) {
31
- const context = yield* _(E.context());
32
- return UserService.of({
33
- isExistingUser: flow(isExistingUser, E.provide(context)),
34
- resendVerificationEmail: flow(resendVerificationEmail, E.provide(context)),
35
- });
36
- }));
37
- /* v8 ignore stop */
38
- //# sourceMappingURL=user.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"user.js","sourceRoot":"","sources":["../../src/user/user.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,OAAO,EAAE,OAAO,EAAE,MAAM,IAAI,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAA;AAG1D,OAAO,EAAE,iBAAiB,EAAE,cAAc,EAAE,MAAM,mCAAmC,CAAA;AAGrF,OAAO,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAA;AAW3C,aAAa;AAEb,MAAM,OAAO,WAAY,SAAQ,OAAO,CAAC,GAAG,CAAC,uBAAuB,CAAC,EAMlE;CAAG;AAMN,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC,OAAc,EAA+C,EAAE;IAC5F,OAAO,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC;QACvB,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,8BAA8B,CAAC,CAAC,CAAA;QACnD,MAAM,SAAS,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,CAAA;QAEtC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,oBAAoB,CAAC,CAAC,CAAA;QAC1C,MAAM,EAAE,YAAY,EAAE,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,cAAc,CAAC,IAAI,iBAAiB,CAAC,OAAO,CAAC,CAAC,CAAC,CAAA;QAE3F,OAAO,YAAY,CAAA;IACrB,CAAC,CAAC,CAAA;AACJ,CAAC,CAAA;AAED,MAAM,CAAC,MAAM,uBAAuB,GAAG,CACrC,OAAoB,EAC6B,EAAE;IACnD,OAAO,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC;QACvB,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,8BAA8B,CAAC,CAAC,CAAA;QACnD,MAAM,SAAS,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,CAAA;QAEtC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,oBAAoB,CAAC,CAAC,CAAA;QAC1C,MAAM,EAAE,MAAM,EAAE,GAAG,WAAW,EAAE,GAAG,OAAO,CAAA;QAC1C,KAAK,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,uBAAuB,CAAC,IAAI,cAAc,CAAC,EAAE,MAAM,EAAE,WAAW,EAAE,CAAC,CAAC,CAAC,CAAA;IAC1F,CAAC,CAAC,CAAA;AACJ,CAAC,CAAA;AAED,UAAU;AAEV,qBAAqB;AACrB,MAAM,CAAC,MAAM,eAAe,GAAG,KAAK,CAAC,MAAM,CACzC,WAAW,EACX,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC;IAChB,MAAM,OAAO,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,EAAc,CAAC,CAAA;IACjD,OAAO,WAAW,CAAC,EAAE,CAAC;QACpB,cAAc,EAAE,IAAI,CAAC,cAAc,EAAE,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;QACxD,uBAAuB,EAAE,IAAI,CAAC,uBAAuB,EAAE,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;KAC3E,CAAC,CAAA;AACJ,CAAC,CAAC,CACH,CAAA;AACD,oBAAoB"}
package/dist/version.d.ts DELETED
@@ -1 +0,0 @@
1
- export declare const PASSLOCK_CLIENT_VERSION = "0.9.30";
package/dist/version.js DELETED
@@ -1,2 +0,0 @@
1
- export const PASSLOCK_CLIENT_VERSION = '0.9.30';
2
- //# sourceMappingURL=version.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"version.js","sourceRoot":"","sources":["../src/version.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,uBAAuB,GAAG,YAAY,CAAA"}
@@ -1,73 +0,0 @@
1
- import { Effect as E, Layer as L, Option as O } from 'effect'
2
-
3
- import {
4
- OptionsRes,
5
- VerificationReq,
6
- VerificationRes,
7
- } from '@passlock/shared/dist/rpc/authentication.js'
8
- import { IsExistingUserRes, VerifyEmailRes } from '@passlock/shared/dist/rpc/user.js'
9
- import type { AuthenticationCredential } from '@passlock/shared/dist/schema/passkey.js'
10
-
11
- import * as Fixtures from '../test/fixtures.js'
12
- import { AuthenticationClient } from '../rpc/authentication.js'
13
- import { type AuthenticationRequest, GetCredential } from './authenticate.js'
14
-
15
- export const session = 'session'
16
- export const token = 'token'
17
- export const code = 'code'
18
- export const authType = 'passkey'
19
- export const expireAt = Date.now() + 10000
20
-
21
- export const request: AuthenticationRequest = {
22
- userVerification: O.some('preferred'),
23
- email: O.none(),
24
- }
25
-
26
- export const rpcOptionsRes = new OptionsRes({
27
- session,
28
- publicKey: {
29
- rpId: 'passlock.dev',
30
- challenge: 'FKZSl_saKu5OXjLLwoq8eK3wlD8XgpGiS10SszW5RiE',
31
- timeout: 60000,
32
- userVerification: 'preferred',
33
- },
34
- })
35
-
36
- export const credential: AuthenticationCredential = {
37
- id: '1',
38
- type: 'public-key',
39
- rawId: 'id',
40
- response: {
41
- clientDataJSON: '',
42
- authenticatorData: '',
43
- signature: '',
44
- userHandle: null,
45
- },
46
- clientExtensionResults: {},
47
- authenticatorAttachment: null,
48
- }
49
-
50
- export const rpcVerificationReq = new VerificationReq({ session, credential })
51
-
52
- export const rpcVerificationRes = new VerificationRes({ principal: Fixtures.principal })
53
-
54
- export const rpcIsExistingUserRes = new IsExistingUserRes({ existingUser: true, detail: O.none() })
55
-
56
- export const rpcVerifyEmailRes = new VerifyEmailRes({ principal: Fixtures.principal })
57
-
58
- export const getCredentialTest = L.succeed(
59
- GetCredential,
60
- GetCredential.of({ getCredential: () => E.succeed(credential) }),
61
- )
62
-
63
- export const rpcClientTest = L.succeed(
64
- AuthenticationClient,
65
- AuthenticationClient.of({
66
- getAuthenticationOptions: () => E.succeed(rpcOptionsRes),
67
- verifyAuthenticationCredential: () => E.succeed(rpcVerificationRes),
68
- }),
69
- )
70
-
71
- export const principal = Fixtures.principal
72
- export const capabilitiesTest = Fixtures.capabilitiesTest
73
- export const storageServiceTest = Fixtures.storageServiceTest
@@ -1,249 +0,0 @@
1
- import { Effect as E, Layer as L, Layer, LogLevel, Logger, Option as O, pipe } from 'effect'
2
- import { describe, expect, test, vi } from 'vitest'
3
- import { mock } from 'vitest-mock-extended'
4
-
5
- import * as Fixture from './authenticate.fixture.js'
6
- import { AuthenticationClient } from '../rpc/authentication.js'
7
- import { StorageService } from '../storage/storage.js'
8
- import { AuthenticateServiceLive, AuthenticationService, GetCredential } from './authenticate.js'
9
-
10
- describe('authenticate should', () => {
11
- test('return a valid principal', async () => {
12
- const assertions = E.gen(function* (_) {
13
- const service = yield* _(AuthenticationService)
14
-
15
- const result = yield* _(
16
- service.authenticatePasskey({
17
- email: O.none(),
18
- userVerification: O.some('preferred'),
19
- }),
20
- )
21
-
22
- expect(result).toEqual(Fixture.principal)
23
- })
24
-
25
- const service = pipe(
26
- AuthenticateServiceLive,
27
- L.provide(Fixture.getCredentialTest),
28
- L.provide(Fixture.capabilitiesTest),
29
- L.provide(Fixture.storageServiceTest),
30
- L.provide(Fixture.rpcClientTest),
31
- )
32
-
33
- const effect = pipe(E.provide(assertions, service), Logger.withMinimumLogLevel(LogLevel.None))
34
-
35
- return E.runPromise(effect)
36
- })
37
-
38
- test('pass the authentication request to the backend', async () => {
39
- const assertions = E.gen(function* (_) {
40
- const service = yield* _(AuthenticationService)
41
-
42
- yield* _(
43
- service.authenticatePasskey({
44
- email: O.none(),
45
- userVerification: O.some('preferred'),
46
- }),
47
- )
48
-
49
- const rpcClient = yield* _(AuthenticationClient)
50
- expect(rpcClient.getAuthenticationOptions).toHaveBeenCalledOnce()
51
- expect(rpcClient.verifyAuthenticationCredential).toHaveBeenCalledOnce()
52
- })
53
-
54
- const rpcClientTest = L.effect(
55
- AuthenticationClient,
56
- E.sync(() => {
57
- const rpcMock = mock<AuthenticationClient['Type']>()
58
-
59
- rpcMock.getAuthenticationOptions.mockReturnValue(E.succeed(Fixture.rpcOptionsRes))
60
- rpcMock.verifyAuthenticationCredential.mockReturnValue(
61
- E.succeed(Fixture.rpcVerificationRes),
62
- )
63
-
64
- return rpcMock
65
- }),
66
- )
67
-
68
- const service = pipe(
69
- AuthenticateServiceLive,
70
- L.provide(Fixture.getCredentialTest),
71
- L.provide(Fixture.capabilitiesTest),
72
- L.provide(Fixture.storageServiceTest),
73
- L.provide(rpcClientTest),
74
- )
75
-
76
- const layers = Layer.merge(service, rpcClientTest)
77
- const effect = pipe(E.provide(assertions, layers), Logger.withMinimumLogLevel(LogLevel.None))
78
-
79
- return E.runPromise(effect)
80
- })
81
-
82
- test('send the credential to the backend', async () => {
83
- const assertions = E.gen(function* (_) {
84
- const service = yield* _(AuthenticationService)
85
-
86
- yield* _(
87
- service.authenticatePasskey({
88
- email: O.none(),
89
- userVerification: O.some('preferred'),
90
- }),
91
- )
92
-
93
- const rpcClient = yield* _(AuthenticationClient)
94
- expect(rpcClient.getAuthenticationOptions).toHaveBeenCalledOnce()
95
- expect(rpcClient.verifyAuthenticationCredential).toHaveBeenCalledWith(
96
- Fixture.rpcVerificationReq,
97
- )
98
- })
99
-
100
- const rpcClientTest = L.effect(
101
- AuthenticationClient,
102
- E.sync(() => {
103
- const rpcMock = mock<AuthenticationClient['Type']>()
104
-
105
- rpcMock.getAuthenticationOptions.mockReturnValue(E.succeed(Fixture.rpcOptionsRes))
106
- rpcMock.verifyAuthenticationCredential.mockReturnValue(
107
- E.succeed(Fixture.rpcVerificationRes),
108
- )
109
-
110
- return rpcMock
111
- }),
112
- )
113
-
114
- const service = pipe(
115
- AuthenticateServiceLive,
116
- L.provide(Fixture.getCredentialTest),
117
- L.provide(Fixture.capabilitiesTest),
118
- L.provide(Fixture.storageServiceTest),
119
- L.provide(rpcClientTest),
120
- )
121
-
122
- const layers = Layer.merge(service, rpcClientTest)
123
- const effect = pipe(E.provide(assertions, layers), Logger.withMinimumLogLevel(LogLevel.None))
124
-
125
- return E.runPromise(effect)
126
- })
127
-
128
- test('store the credential in local storage', async () => {
129
- const assertions = E.gen(function* (_) {
130
- const service = yield* _(AuthenticationService)
131
-
132
- yield* _(
133
- service.authenticatePasskey({
134
- email: O.none(),
135
- userVerification: O.some('preferred'),
136
- }),
137
- )
138
-
139
- const storageService = yield* _(StorageService)
140
- expect(storageService.storeToken).toHaveBeenCalledWith(Fixture.principal)
141
- })
142
-
143
- const storageServiceTest = L.effect(
144
- StorageService,
145
- E.sync(() => {
146
- const storageMock = mock<StorageService['Type']>()
147
-
148
- storageMock.storeToken.mockReturnValue(E.void)
149
- storageMock.clearExpiredToken.mockReturnValue(E.void)
150
-
151
- return storageMock
152
- }),
153
- )
154
-
155
- const service = pipe(
156
- AuthenticateServiceLive,
157
- L.provide(Fixture.getCredentialTest),
158
- L.provide(Fixture.capabilitiesTest),
159
- L.provide(Fixture.rpcClientTest),
160
- L.provide(storageServiceTest),
161
- )
162
-
163
- const layers = Layer.merge(service, storageServiceTest)
164
- const effect = pipe(E.provide(assertions, layers), Logger.withMinimumLogLevel(LogLevel.None))
165
-
166
- return E.runPromise(effect)
167
- })
168
-
169
- test('schedule deletion of the local token', async () => {
170
- const assertions = E.gen(function* (_) {
171
- const service = yield* _(AuthenticationService)
172
-
173
- yield* _(
174
- service.authenticatePasskey({
175
- email: O.none(),
176
- userVerification: O.some('preferred'),
177
- }),
178
- )
179
-
180
- const storageService = yield* _(StorageService)
181
- expect(storageService.clearExpiredToken).toHaveBeenCalledWith('passkey')
182
- })
183
-
184
- const storageServiceTest = L.effect(
185
- StorageService,
186
- E.sync(() => {
187
- const storageMock = mock<StorageService['Type']>()
188
-
189
- storageMock.storeToken.mockReturnValue(E.void)
190
- storageMock.clearExpiredToken.mockReturnValue(E.void)
191
-
192
- return storageMock
193
- }),
194
- )
195
-
196
- const service = pipe(
197
- AuthenticateServiceLive,
198
- L.provide(Fixture.getCredentialTest),
199
- L.provide(Fixture.capabilitiesTest),
200
- L.provide(Fixture.rpcClientTest),
201
- L.provide(storageServiceTest),
202
- )
203
-
204
- const layers = Layer.merge(service, storageServiceTest)
205
- const effect = pipe(E.provide(assertions, layers), Logger.withMinimumLogLevel(LogLevel.None))
206
-
207
- return E.runPromise(effect)
208
- })
209
-
210
- test("return an error if the browser can't create a credential", async () => {
211
- const assertions = E.gen(function* (_) {
212
- const service = yield* _(AuthenticationService)
213
-
214
- yield* _(
215
- service.authenticatePasskey({
216
- email: O.none(),
217
- userVerification: O.some('preferred'),
218
- }),
219
- )
220
-
221
- const { getCredential } = yield* _(GetCredential)
222
- expect(getCredential).toHaveBeenCalledOnce()
223
- })
224
-
225
- const getCredentialTest = L.effect(
226
- GetCredential,
227
- E.sync(() => {
228
- const getCredential = vi.fn()
229
-
230
- getCredential.mockReturnValue(E.succeed(Fixture.credential))
231
-
232
- return { getCredential }
233
- }),
234
- )
235
-
236
- const service = pipe(
237
- AuthenticateServiceLive,
238
- L.provide(Fixture.storageServiceTest),
239
- L.provide(Fixture.capabilitiesTest),
240
- L.provide(Fixture.rpcClientTest),
241
- L.provide(getCredentialTest),
242
- )
243
-
244
- const layers = Layer.merge(service, getCredentialTest)
245
- const effect = pipe(E.provide(assertions, layers), Logger.withMinimumLogLevel(LogLevel.None))
246
-
247
- return E.runPromise(effect)
248
- })
249
- })
@@ -1,149 +0,0 @@
1
- /**
2
- * Passkey authentication effects
3
- */
4
- import {
5
- type CredentialRequestOptionsJSON,
6
- parseRequestOptionsFromJSON,
7
- } from '@github/webauthn-json/browser-ponyfill'
8
- import { Context, Effect as E, Layer, flow, pipe } from 'effect'
9
-
10
- import { InternalBrowserError, type NotSupported } from '@passlock/shared/dist/error/error.js'
11
- import {
12
- type OptionsErrors,
13
- type OptionsReq,
14
- type VerificationErrors,
15
- VerificationReq,
16
- } from '@passlock/shared/dist/rpc/authentication.js'
17
- import type { AuthenticationCredential } from '@passlock/shared/dist/schema/passkey.js'
18
- import type { Principal } from '@passlock/shared/dist/schema/principal.js'
19
-
20
- import { Capabilities } from '../capabilities/capabilities.js'
21
- import { AuthenticationClient } from '../rpc/authentication.js'
22
- import { StorageService } from '../storage/storage.js'
23
-
24
- /* Requests */
25
-
26
- export type AuthenticationRequest = OptionsReq
27
- /* Errors */
28
-
29
- export type AuthenticationErrors = NotSupported | OptionsErrors | VerificationErrors
30
-
31
- /* Dependencies */
32
-
33
- export class GetCredential extends Context.Tag('@services/GetCredential')<
34
- GetCredential,
35
- {
36
- getCredential: (
37
- request: CredentialRequestOptions,
38
- ) => E.Effect<AuthenticationCredential, InternalBrowserError>
39
- }
40
- >() {}
41
-
42
- /* Service */
43
-
44
- export class AuthenticationService extends Context.Tag('@services/AuthenticationService')<
45
- AuthenticationService,
46
- {
47
- authenticatePasskey: (
48
- request: AuthenticationRequest,
49
- ) => E.Effect<Principal, AuthenticationErrors>
50
- }
51
- >() {}
52
-
53
- /* Utilities */
54
-
55
- const fetchOptions = (request: OptionsReq) => {
56
- return E.gen(function* (_) {
57
- yield* _(E.logDebug('Making request'))
58
-
59
- const rpcClient = yield* _(AuthenticationClient)
60
- const { publicKey, session } = yield* _(rpcClient.getAuthenticationOptions(request))
61
-
62
- yield* _(E.logDebug('Converting Passlock options to CredentialRequestOptions'))
63
- const options = yield* _(toRequestOptions({ publicKey }))
64
-
65
- return { options, session }
66
- })
67
- }
68
-
69
- const toRequestOptions = (request: CredentialRequestOptionsJSON) => {
70
- return pipe(
71
- E.try(() => parseRequestOptionsFromJSON(request)),
72
- E.mapError(
73
- error =>
74
- new InternalBrowserError({
75
- message: 'Browser was unable to create credential request options',
76
- detail: String(error.error),
77
- }),
78
- ),
79
- )
80
- }
81
-
82
- const verifyCredential = (request: VerificationReq) => {
83
- return E.gen(function* (_) {
84
- yield* _(E.logDebug('Making request'))
85
-
86
- const rpcClient = yield* _(AuthenticationClient)
87
- const { principal } = yield* _(rpcClient.verifyAuthenticationCredential(request))
88
-
89
- return principal
90
- })
91
- }
92
-
93
- /* Effects */
94
-
95
- type Dependencies = GetCredential | Capabilities | StorageService | AuthenticationClient
96
-
97
- export const authenticatePasskey = (
98
- request: AuthenticationRequest,
99
- ): E.Effect<Principal, AuthenticationErrors, Dependencies> => {
100
- const effect = E.gen(function* (_) {
101
- yield* _(E.logInfo('Checking if browser supports Passkeys'))
102
- const capabilities = yield* _(Capabilities)
103
- yield* _(capabilities.passkeySupport)
104
-
105
- yield* _(E.logInfo('Fetching authentication options from Passlock'))
106
-
107
- const { options, session } = yield* _(fetchOptions(request))
108
-
109
- yield* _(E.logInfo('Looking up credential'))
110
- const { getCredential } = yield* _(GetCredential)
111
- const credential = yield* _(getCredential(options))
112
-
113
- yield* _(E.logInfo('Verifying credential with Passlock'))
114
- const principal = yield* _(verifyCredential(new VerificationReq({ credential, session })))
115
-
116
- const storageService = yield* _(StorageService)
117
- yield* _(storageService.storeToken(principal))
118
- yield* _(E.logDebug('Stored token in local storage'))
119
-
120
- yield* _(E.logDebug('Defering local token deletion'))
121
- const delayedClearTokenE = pipe(
122
- storageService.clearExpiredToken('passkey'),
123
- E.delay('6 minutes'),
124
- E.fork,
125
- )
126
- yield* _(delayedClearTokenE)
127
-
128
- return principal
129
- })
130
-
131
- return E.catchTag(effect, 'InternalBrowserError', e => E.die(e))
132
- }
133
-
134
- /* Live */
135
-
136
- /* v8 ignore start */
137
- export const AuthenticateServiceLive = Layer.effect(
138
- AuthenticationService,
139
- E.gen(function* (_) {
140
- const context = yield* _(
141
- E.context<GetCredential | AuthenticationClient | Capabilities | StorageService>(),
142
- )
143
-
144
- return AuthenticationService.of({
145
- authenticatePasskey: flow(authenticatePasskey, E.provide(context)),
146
- })
147
- }),
148
- )
149
- /* v8 ignore stop */
@@ -1,83 +0,0 @@
1
- /**
2
- * Test if the browser supports passkeys, conditional UI etc
3
- */
4
- import { Context, Effect as E, Layer, identity, pipe } from 'effect'
5
-
6
- import { NotSupported } from '@passlock/shared/dist/error/error.js'
7
-
8
- /* Service */
9
-
10
- export class Capabilities extends Context.Tag('@services/Capabilities')<
11
- Capabilities,
12
- {
13
- passkeySupport: E.Effect<void, NotSupported>
14
- isPasskeySupport: E.Effect<boolean>
15
- autofillSupport: E.Effect<void, NotSupported>
16
- isAutofillSupport: E.Effect<boolean>
17
- }
18
- >() {}
19
-
20
- /* Effects */
21
-
22
- const hasWebAuthn = E.suspend(() =>
23
- typeof window.PublicKeyCredential === 'function'
24
- ? E.void
25
- : new NotSupported({ message: 'WebAuthn API is not supported on this device' }),
26
- )
27
-
28
- const hasPlatformAuth = pipe(
29
- E.tryPromise(() => window.PublicKeyCredential.isUserVerifyingPlatformAuthenticatorAvailable()),
30
- E.filterOrFail(
31
- identity,
32
- () => new NotSupported({ message: 'No platform authenticator available on this device' }),
33
- ),
34
- E.asVoid,
35
- )
36
-
37
- const hasConditionalUi = pipe(
38
- E.tryPromise({
39
- try: () => window.PublicKeyCredential.isConditionalMediationAvailable(),
40
- catch: () =>
41
- new NotSupported({ message: 'Conditional mediation not available on this device' }),
42
- }),
43
- E.filterOrFail(
44
- identity,
45
- () => new NotSupported({ message: 'Conditional mediation not available on this device' }),
46
- ),
47
- E.asVoid,
48
- )
49
-
50
- export const passkeySupport = pipe(
51
- hasWebAuthn,
52
- E.andThen(hasPlatformAuth),
53
- E.catchTag('UnknownException', e => E.die(e)),
54
- )
55
-
56
- export const isPasskeySupport = pipe(
57
- passkeySupport,
58
- E.match({
59
- onFailure: () => false,
60
- onSuccess: () => true,
61
- }),
62
- )
63
-
64
- export const autofillSupport = pipe(passkeySupport, E.andThen(hasConditionalUi))
65
-
66
- export const isAutofillSupport = pipe(
67
- autofillSupport,
68
- E.match({
69
- onFailure: () => false,
70
- onSuccess: () => true,
71
- }),
72
- )
73
-
74
- /* Live */
75
-
76
- /* v8 ignore start */
77
- export const capabilitiesLive = Layer.succeed(Capabilities, {
78
- passkeySupport,
79
- isPasskeySupport,
80
- autofillSupport,
81
- isAutofillSupport,
82
- })
83
- /* v8 ignore stop */