@passlock/client 0.9.17 → 0.9.21
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/dist/authentication/authenticate.d.ts +5 -4
- package/dist/authentication/authenticate.d.ts.map +1 -1
- package/dist/authentication/authenticate.fixture.d.ts +4 -5
- package/dist/authentication/authenticate.fixture.d.ts.map +1 -1
- package/dist/authentication/authenticate.fixture.js +2 -11
- package/dist/authentication/authenticate.fixture.js.map +1 -1
- package/dist/authentication/authenticate.js +4 -4
- package/dist/authentication/authenticate.js.map +1 -1
- package/dist/authentication/authenticate.test.js +5 -5
- package/dist/authentication/authenticate.test.js.map +1 -1
- package/dist/connection/connection.d.ts +4 -3
- package/dist/connection/connection.d.ts.map +1 -1
- package/dist/connection/connection.fixture.d.ts +3 -5
- package/dist/connection/connection.fixture.d.ts.map +1 -1
- package/dist/connection/connection.fixture.js +3 -15
- package/dist/connection/connection.fixture.js.map +1 -1
- package/dist/connection/connection.js +3 -3
- package/dist/connection/connection.js.map +1 -1
- package/dist/connection/connection.test.js +6 -5
- package/dist/connection/connection.test.js.map +1 -1
- package/dist/effect.d.ts +4 -4
- package/dist/effect.d.ts.map +1 -1
- package/dist/effect.js +17 -8
- package/dist/effect.js.map +1 -1
- package/dist/email/email.d.ts +5 -5
- package/dist/email/email.d.ts.map +1 -1
- package/dist/email/email.fixture.d.ts +3 -4
- package/dist/email/email.fixture.d.ts.map +1 -1
- package/dist/email/email.fixture.js +2 -10
- package/dist/email/email.fixture.js.map +1 -1
- package/dist/email/email.js +2 -3
- package/dist/email/email.js.map +1 -1
- package/dist/email/email.test.js +5 -5
- package/dist/email/email.test.js.map +1 -1
- package/dist/index.d.ts +13 -11
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/logging/eventLogger.d.ts.map +1 -1
- package/dist/logging/eventLogger.js +15 -9
- package/dist/logging/eventLogger.js.map +1 -1
- package/dist/logging/eventLogger.test.js.map +1 -1
- package/dist/registration/register.d.ts +6 -4
- package/dist/registration/register.d.ts.map +1 -1
- package/dist/registration/register.fixture.d.ts +4 -5
- package/dist/registration/register.fixture.d.ts.map +1 -1
- package/dist/registration/register.fixture.js +2 -12
- package/dist/registration/register.fixture.js.map +1 -1
- package/dist/registration/register.js +5 -4
- package/dist/registration/register.js.map +1 -1
- package/dist/registration/register.test.js +6 -6
- package/dist/registration/register.test.js.map +1 -1
- package/dist/rpc/authentication.d.ts +9 -0
- package/dist/rpc/authentication.d.ts.map +1 -0
- package/dist/rpc/authentication.js +15 -0
- package/dist/rpc/authentication.js.map +1 -0
- package/dist/rpc/client.d.ts +27 -0
- package/dist/rpc/client.d.ts.map +1 -0
- package/dist/rpc/client.js +92 -0
- package/dist/rpc/client.js.map +1 -0
- package/dist/rpc/config.d.ts +16 -0
- package/dist/rpc/config.d.ts.map +1 -0
- package/dist/rpc/config.js +6 -0
- package/dist/rpc/config.js.map +1 -0
- package/dist/rpc/connection.d.ts +9 -0
- package/dist/rpc/connection.d.ts.map +1 -0
- package/dist/rpc/connection.js +14 -0
- package/dist/rpc/connection.js.map +1 -0
- package/dist/rpc/registration.d.ts +9 -0
- package/dist/rpc/registration.d.ts.map +1 -0
- package/dist/rpc/registration.js +15 -0
- package/dist/rpc/registration.js.map +1 -0
- package/dist/rpc/social.d.ts +11 -0
- package/dist/rpc/social.d.ts.map +1 -0
- package/dist/rpc/social.js +17 -0
- package/dist/rpc/social.js.map +1 -0
- package/dist/rpc/user.d.ts +9 -0
- package/dist/rpc/user.d.ts.map +1 -0
- package/dist/rpc/user.js +18 -0
- package/dist/rpc/user.js.map +1 -0
- package/dist/social/social.d.ts +22 -13
- package/dist/social/social.d.ts.map +1 -1
- package/dist/social/social.fixture.d.ts +10 -10
- package/dist/social/social.fixture.d.ts.map +1 -1
- package/dist/social/social.fixture.js +21 -19
- package/dist/social/social.fixture.js.map +1 -1
- package/dist/social/social.js +12 -6
- package/dist/social/social.js.map +1 -1
- package/dist/social/social.test.js +15 -15
- package/dist/social/social.test.js.map +1 -1
- package/dist/storage/storage.d.ts +2 -2
- package/dist/storage/storage.d.ts.map +1 -1
- package/dist/storage/storage.js +1 -0
- package/dist/storage/storage.js.map +1 -1
- package/dist/test/fixtures.d.ts +1 -3
- package/dist/test/fixtures.d.ts.map +1 -1
- package/dist/test/fixtures.js +0 -2
- package/dist/test/fixtures.js.map +1 -1
- package/dist/user/user.d.ts +4 -4
- package/dist/user/user.d.ts.map +1 -1
- package/dist/user/user.fixture.d.ts +2 -3
- package/dist/user/user.fixture.d.ts.map +1 -1
- package/dist/user/user.fixture.js +2 -10
- package/dist/user/user.fixture.js.map +1 -1
- package/dist/user/user.js +3 -4
- package/dist/user/user.js.map +1 -1
- package/dist/user/user.test.js +5 -5
- package/dist/user/user.test.js.map +1 -1
- package/dist/version.d.ts +2 -0
- package/dist/version.d.ts.map +1 -0
- package/dist/version.js +2 -0
- package/dist/version.js.map +1 -0
- package/package.json +10 -11
- package/src/authentication/authenticate.fixture.ts +8 -16
- package/src/authentication/authenticate.test.ts +7 -7
- package/src/authentication/authenticate.ts +13 -14
- package/src/connection/connection.fixture.ts +4 -16
- package/src/connection/connection.test.ts +7 -6
- package/src/connection/connection.ts +5 -5
- package/src/effect.ts +22 -16
- package/src/email/email.fixture.ts +3 -11
- package/src/email/email.test.ts +7 -7
- package/src/email/email.ts +5 -6
- package/src/index.ts +10 -7
- package/src/logging/eventLogger.test.ts +1 -0
- package/src/logging/eventLogger.ts +16 -10
- package/src/registration/register.fixture.ts +9 -18
- package/src/registration/register.test.ts +9 -9
- package/src/registration/register.ts +12 -13
- package/src/social/social.fixture.ts +25 -21
- package/src/social/social.test.ts +21 -21
- package/src/social/social.ts +40 -19
- package/src/storage/storage.ts +3 -2
- package/src/test/fixtures.ts +1 -3
- package/src/user/user.fixture.ts +3 -11
- package/src/user/user.test.ts +7 -7
- package/src/user/user.ts +6 -7
- package/README.md +0 -116
|
@@ -2,21 +2,20 @@
|
|
|
2
2
|
* Passkey authentication effects
|
|
3
3
|
*/
|
|
4
4
|
import {
|
|
5
|
-
|
|
6
|
-
|
|
5
|
+
parseRequestOptionsFromJSON,
|
|
6
|
+
type CredentialRequestOptionsJSON,
|
|
7
7
|
} from '@github/webauthn-json/browser-ponyfill'
|
|
8
8
|
import {
|
|
9
|
-
|
|
10
|
-
|
|
9
|
+
InternalBrowserError,
|
|
10
|
+
type NotSupported,
|
|
11
11
|
} from '@passlock/shared/dist/error/error.js'
|
|
12
12
|
import type { OptionsErrors, VerificationErrors } from '@passlock/shared/dist/rpc/authentication.js'
|
|
13
|
-
import { OptionsReq, VerificationReq } from '@passlock/shared/dist/rpc/authentication.js'
|
|
14
|
-
import { RpcClient } from '@passlock/shared/dist/rpc/rpc.js'
|
|
13
|
+
import { AuthenticationClient, OptionsReq, VerificationReq } from '@passlock/shared/dist/rpc/authentication.js'
|
|
15
14
|
import type {
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
} from '@passlock/shared/dist/schema/
|
|
15
|
+
AuthenticationCredential,
|
|
16
|
+
UserVerification,
|
|
17
|
+
} from '@passlock/shared/dist/schema/passkey.js'
|
|
18
|
+
import { Principal } from '@passlock/shared/dist/schema/principal.js'
|
|
20
19
|
import { Context, Effect as E, Layer, flow, pipe } from 'effect'
|
|
21
20
|
import { Capabilities } from '../capabilities/capabilities.js'
|
|
22
21
|
import { StorageService } from '../storage/storage.js'
|
|
@@ -56,7 +55,7 @@ const fetchOptions = (request: OptionsReq) => {
|
|
|
56
55
|
return E.gen(function* (_) {
|
|
57
56
|
yield* _(E.logDebug('Making request'))
|
|
58
57
|
|
|
59
|
-
const rpcClient = yield* _(
|
|
58
|
+
const rpcClient = yield* _(AuthenticationClient)
|
|
60
59
|
const { publicKey, session } = yield* _(rpcClient.getAuthenticationOptions(request))
|
|
61
60
|
|
|
62
61
|
yield* _(E.logDebug('Converting Passlock options to CredentialRequestOptions'))
|
|
@@ -83,7 +82,7 @@ const verifyCredential = (request: VerificationReq) => {
|
|
|
83
82
|
return E.gen(function* (_) {
|
|
84
83
|
yield* _(E.logDebug('Making request'))
|
|
85
84
|
|
|
86
|
-
const rpcClient = yield* _(
|
|
85
|
+
const rpcClient = yield* _(AuthenticationClient)
|
|
87
86
|
const { principal } = yield* _(rpcClient.verifyAuthenticationCredential(request))
|
|
88
87
|
|
|
89
88
|
return principal
|
|
@@ -92,7 +91,7 @@ const verifyCredential = (request: VerificationReq) => {
|
|
|
92
91
|
|
|
93
92
|
/* Effects */
|
|
94
93
|
|
|
95
|
-
type Dependencies = GetCredential | Capabilities | StorageService |
|
|
94
|
+
type Dependencies = GetCredential | Capabilities | StorageService | AuthenticationClient
|
|
96
95
|
|
|
97
96
|
export const authenticatePasskey = (
|
|
98
97
|
request: AuthenticationRequest,
|
|
@@ -136,7 +135,7 @@ export const authenticatePasskey = (
|
|
|
136
135
|
export const AuthenticateServiceLive = Layer.effect(
|
|
137
136
|
AuthenticationService,
|
|
138
137
|
E.gen(function* (_) {
|
|
139
|
-
const context = yield* _(E.context<GetCredential |
|
|
138
|
+
const context = yield* _(E.context<GetCredential | AuthenticationClient | Capabilities | StorageService>())
|
|
140
139
|
|
|
141
140
|
return AuthenticationService.of({
|
|
142
141
|
authenticatePasskey: flow(authenticatePasskey, E.provide(context)),
|
|
@@ -1,24 +1,12 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { RpcClient } from '@passlock/shared/dist/rpc/rpc.js'
|
|
1
|
+
import { ConnectionClient, ConnectRes } from '@passlock/shared/dist/rpc/connection.js'
|
|
3
2
|
import { Effect as E, Layer as L } from 'effect'
|
|
4
|
-
import * as Fixtures from '../test/fixtures.js'
|
|
5
3
|
|
|
6
|
-
export const
|
|
7
|
-
export const preConnectRes = new PreConnectRes({ warmed: true })
|
|
4
|
+
export const preConnectRes = new ConnectRes({ warmed: true })
|
|
8
5
|
|
|
9
6
|
export const rpcClientTest = L.succeed(
|
|
10
|
-
|
|
11
|
-
|
|
7
|
+
ConnectionClient,
|
|
8
|
+
ConnectionClient.of({
|
|
12
9
|
preConnect: () => E.succeed(preConnectRes),
|
|
13
|
-
isExistingUser: () => E.fail(Fixtures.notImplemented),
|
|
14
|
-
verifyEmail: () => E.fail(Fixtures.notImplemented),
|
|
15
|
-
getRegistrationOptions: () => E.fail(Fixtures.notImplemented),
|
|
16
|
-
verifyRegistrationCredential: () => E.fail(Fixtures.notImplemented),
|
|
17
|
-
getAuthenticationOptions: () => E.fail(Fixtures.notImplemented),
|
|
18
|
-
verifyAuthenticationCredential: () => E.fail(Fixtures.notImplemented),
|
|
19
|
-
registerOidc: () => E.fail(Fixtures.notImplemented),
|
|
20
|
-
authenticateOidc: () => E.fail(Fixtures.notImplemented),
|
|
21
|
-
resendVerificationEmail: () => E.fail(Fixtures.notImplemented),
|
|
22
10
|
}),
|
|
23
11
|
)
|
|
24
12
|
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { RpcConfig } from '@passlock/shared/dist/rpc/config.js'
|
|
2
|
-
import {
|
|
2
|
+
import { ConnectionClient } from '@passlock/shared/dist/rpc/connection.js'
|
|
3
|
+
import { Dispatcher } from '@passlock/shared/dist/rpc/dispatcher.js'
|
|
3
4
|
import { Effect as E, Layer as L, Layer, LogLevel, Logger, pipe } from 'effect'
|
|
4
5
|
import { describe, expect, test } from 'vitest'
|
|
5
6
|
import { mock } from 'vitest-mock-extended'
|
|
@@ -12,17 +13,17 @@ describe('preConnect should', () => {
|
|
|
12
13
|
const service = yield* _(ConnectionService)
|
|
13
14
|
yield* _(service.preConnect())
|
|
14
15
|
|
|
15
|
-
const rpcClient = yield* _(
|
|
16
|
-
expect(rpcClient.preConnect).
|
|
16
|
+
const rpcClient = yield* _(ConnectionClient)
|
|
17
|
+
expect(rpcClient.preConnect).toBeCalled()
|
|
17
18
|
|
|
18
19
|
const dispatcher = yield* _(Dispatcher)
|
|
19
20
|
expect(dispatcher.get).toBeCalledWith(`/token/token?warm=true`)
|
|
20
21
|
})
|
|
21
22
|
|
|
22
23
|
const rpcClientTest = Layer.effect(
|
|
23
|
-
|
|
24
|
+
ConnectionClient,
|
|
24
25
|
E.sync(() => {
|
|
25
|
-
const rpcMock = mock<
|
|
26
|
+
const rpcMock = mock<ConnectionClient['Type']>()
|
|
26
27
|
|
|
27
28
|
rpcMock.preConnect.mockReturnValue(E.succeed(Fixture.preConnectRes))
|
|
28
29
|
|
|
@@ -37,7 +38,7 @@ describe('preConnect should', () => {
|
|
|
37
38
|
E.sync(() => {
|
|
38
39
|
const dispatcherMock = mock<Dispatcher['Type']>()
|
|
39
40
|
|
|
40
|
-
dispatcherMock.get.mockReturnValue(E.succeed({}))
|
|
41
|
+
dispatcherMock.get.mockReturnValue(E.succeed({ status: 200, body: {} }))
|
|
41
42
|
|
|
42
43
|
return dispatcherMock
|
|
43
44
|
}),
|
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
* Hits the rpc endpoint to warm up a lambda
|
|
3
3
|
*/
|
|
4
4
|
import type { RpcConfig } from '@passlock/shared/dist/rpc/config.js'
|
|
5
|
-
import {
|
|
6
|
-
import { Dispatcher
|
|
5
|
+
import { ConnectionClient } from '@passlock/shared/dist/rpc/connection.js'
|
|
6
|
+
import { Dispatcher } from '@passlock/shared/dist/rpc/dispatcher.js'
|
|
7
7
|
import { Context, Effect as E, Layer, flow, pipe } from 'effect'
|
|
8
8
|
|
|
9
9
|
/* Service */
|
|
@@ -26,8 +26,8 @@ const hitPrincipal = pipe(
|
|
|
26
26
|
|
|
27
27
|
const hitRpc = pipe(
|
|
28
28
|
E.logInfo('Pre-connecting to RPC endpoint'),
|
|
29
|
-
E.zipRight(
|
|
30
|
-
E.flatMap(rpcClient => rpcClient.preConnect(
|
|
29
|
+
E.zipRight(ConnectionClient),
|
|
30
|
+
E.flatMap(rpcClient => rpcClient.preConnect()),
|
|
31
31
|
E.asVoid,
|
|
32
32
|
)
|
|
33
33
|
|
|
@@ -39,7 +39,7 @@ export const preConnect = () => pipe(E.all([hitPrincipal, hitRpc], { concurrency
|
|
|
39
39
|
export const ConnectionServiceLive = Layer.effect(
|
|
40
40
|
ConnectionService,
|
|
41
41
|
E.gen(function* (_) {
|
|
42
|
-
const context = yield* _(E.context<
|
|
42
|
+
const context = yield* _(E.context<ConnectionClient | Dispatcher | RpcConfig>())
|
|
43
43
|
|
|
44
44
|
return ConnectionService.of({
|
|
45
45
|
preConnect: flow(preConnect, E.provide(context)),
|
package/src/effect.ts
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
import { create, get as getCredential } from '@github/webauthn-json/browser-ponyfill'
|
|
2
2
|
|
|
3
|
+
import { AuthenticationClientLive } from '@passlock/shared/dist/rpc/authentication.js'
|
|
4
|
+
import { ConnectionClientLive } from '@passlock/shared/dist/rpc/connection.js'
|
|
5
|
+
import { RegistrationClientLive } from '@passlock/shared/dist/rpc/registration.js'
|
|
6
|
+
import { SocialClientLive } from '@passlock/shared/dist/rpc/social.js'
|
|
7
|
+
import { UserClientLive } from '@passlock/shared/dist/rpc/user.js'
|
|
8
|
+
|
|
3
9
|
import {
|
|
4
10
|
Duplicate,
|
|
5
11
|
InternalBrowserError,
|
|
@@ -11,12 +17,7 @@ import {
|
|
|
11
17
|
type Unauthorized,
|
|
12
18
|
} from '@passlock/shared/dist/error/error.js'
|
|
13
19
|
|
|
14
|
-
import {
|
|
15
|
-
DispatcherLive,
|
|
16
|
-
RpcClientLive,
|
|
17
|
-
} from '@passlock/shared/dist/rpc/rpc.js'
|
|
18
|
-
|
|
19
|
-
import type { Principal } from '@passlock/shared/dist/schema/schema.js'
|
|
20
|
+
import type { Principal } from '@passlock/shared/dist/schema/principal.js'
|
|
20
21
|
|
|
21
22
|
import { Context, Effect as E, Layer as L, Layer, Schedule, pipe } from 'effect'
|
|
22
23
|
import type { NoSuchElementException } from 'effect/Cause'
|
|
@@ -48,7 +49,8 @@ import {
|
|
|
48
49
|
} from './storage/storage.js'
|
|
49
50
|
|
|
50
51
|
import { RetrySchedule, RpcConfig } from '@passlock/shared/dist/rpc/config.js'
|
|
51
|
-
import {
|
|
52
|
+
import { DispatcherLive } from '@passlock/shared/dist/rpc/dispatcher.js'
|
|
53
|
+
import { SocialService, SocialServiceLive, type RegisterOidcReq } from './social/social.js'
|
|
52
54
|
import { UserService, UserServiceLive, type Email } from './user/user.js'
|
|
53
55
|
|
|
54
56
|
/* Layers */
|
|
@@ -98,17 +100,21 @@ const schedule = Schedule.intersect(Schedule.recurs(3), Schedule.exponential('10
|
|
|
98
100
|
|
|
99
101
|
const retryScheduleLive = L.succeed(RetrySchedule, RetrySchedule.of({ schedule }))
|
|
100
102
|
|
|
103
|
+
/* RPC Clients */
|
|
101
104
|
const dispatcherLive = pipe(DispatcherLive, L.provide(retryScheduleLive))
|
|
102
|
-
|
|
103
|
-
const
|
|
105
|
+
const connectClientLive = pipe(ConnectionClientLive, L.provide(dispatcherLive))
|
|
106
|
+
const registerClientLive = pipe(RegistrationClientLive, L.provide(dispatcherLive))
|
|
107
|
+
const authenticateClientLive = pipe(AuthenticationClientLive, L.provide(dispatcherLive))
|
|
108
|
+
const socialClientLive = pipe(SocialClientLive, L.provide(dispatcherLive))
|
|
109
|
+
const userClientLive = pipe(UserClientLive, L.provide(dispatcherLive))
|
|
104
110
|
|
|
105
111
|
const storageServiceLive = StorageServiceLive
|
|
106
112
|
|
|
107
|
-
const userServiceLive = pipe(UserServiceLive, L.provide(
|
|
113
|
+
const userServiceLive = pipe(UserServiceLive, L.provide(userClientLive))
|
|
108
114
|
|
|
109
115
|
const registrationServiceLive = pipe(
|
|
110
116
|
RegistrationServiceLive,
|
|
111
|
-
L.provide(
|
|
117
|
+
L.provide(registerClientLive),
|
|
112
118
|
L.provide(userServiceLive),
|
|
113
119
|
L.provide(capabilitiesLive),
|
|
114
120
|
L.provide(createCredentialLive),
|
|
@@ -117,7 +123,7 @@ const registrationServiceLive = pipe(
|
|
|
117
123
|
|
|
118
124
|
const authenticationServiceLive = pipe(
|
|
119
125
|
AuthenticateServiceLive,
|
|
120
|
-
L.provide(
|
|
126
|
+
L.provide(authenticateClientLive),
|
|
121
127
|
L.provide(capabilitiesLive),
|
|
122
128
|
L.provide(getCredentialLive),
|
|
123
129
|
L.provide(storageServiceLive),
|
|
@@ -125,7 +131,7 @@ const authenticationServiceLive = pipe(
|
|
|
125
131
|
|
|
126
132
|
const connectionServiceLive = pipe(
|
|
127
133
|
ConnectionServiceLive,
|
|
128
|
-
L.provide(
|
|
134
|
+
L.provide(connectClientLive),
|
|
129
135
|
L.provide(dispatcherLive),
|
|
130
136
|
)
|
|
131
137
|
|
|
@@ -137,7 +143,7 @@ const urlQueryStringLive = Layer.succeed(
|
|
|
137
143
|
const emailServiceLive = pipe(
|
|
138
144
|
EmailServiceLive,
|
|
139
145
|
L.provide(urlQueryStringLive),
|
|
140
|
-
L.provide(
|
|
146
|
+
L.provide(userClientLive),
|
|
141
147
|
L.provide(capabilitiesLive),
|
|
142
148
|
L.provide(authenticationServiceLive),
|
|
143
149
|
L.provide(storageServiceLive),
|
|
@@ -145,7 +151,7 @@ const emailServiceLive = pipe(
|
|
|
145
151
|
|
|
146
152
|
const socialServiceLive = pipe(
|
|
147
153
|
SocialServiceLive,
|
|
148
|
-
L.provide(
|
|
154
|
+
L.provide(socialClientLive),
|
|
149
155
|
)
|
|
150
156
|
|
|
151
157
|
export const allRequirements = Layer.mergeAll(
|
|
@@ -271,7 +277,7 @@ export const clearExpiredTokens = (): E.Effect<void> =>
|
|
|
271
277
|
E.provide(storageLive),
|
|
272
278
|
)
|
|
273
279
|
|
|
274
|
-
export const authenticateOIDC = (request:
|
|
280
|
+
export const authenticateOIDC = (request: RegisterOidcReq) =>
|
|
275
281
|
pipe(
|
|
276
282
|
SocialService,
|
|
277
283
|
E.flatMap(service => service.registerOidc(request)),
|
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { VerifyEmailReq, VerifyEmailRes } from '@passlock/shared/dist/rpc/user.js'
|
|
1
|
+
import { UserClient, VerifyEmailReq, VerifyEmailRes } from '@passlock/shared/dist/rpc/user.js'
|
|
3
2
|
import { Effect as E, Layer as L } from 'effect'
|
|
4
3
|
import { AuthenticationService } from '../authentication/authenticate.js'
|
|
5
4
|
import * as Fixtures from '../test/fixtures.js'
|
|
@@ -27,17 +26,10 @@ export const rpcVerifyEmailReq = new VerifyEmailReq({ token, code })
|
|
|
27
26
|
export const rpcVerifyEmailRes = new VerifyEmailRes({ principal: Fixtures.principal })
|
|
28
27
|
|
|
29
28
|
export const rpcClientTest = L.succeed(
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
preConnect: () => E.succeed({ warmed: true }),
|
|
29
|
+
UserClient,
|
|
30
|
+
UserClient.of({
|
|
33
31
|
isExistingUser: () => E.succeed({ existingUser: true }),
|
|
34
32
|
verifyEmail: () => E.succeed(rpcVerifyEmailRes),
|
|
35
|
-
getRegistrationOptions: () => E.fail(Fixtures.notImplemented),
|
|
36
|
-
verifyRegistrationCredential: () => E.fail(Fixtures.notImplemented),
|
|
37
|
-
getAuthenticationOptions: () => E.fail(Fixtures.notImplemented),
|
|
38
|
-
verifyAuthenticationCredential: () => E.fail(Fixtures.notImplemented),
|
|
39
|
-
registerOidc: () => E.fail(Fixtures.notImplemented),
|
|
40
|
-
authenticateOidc: () => E.fail(Fixtures.notImplemented),
|
|
41
33
|
resendVerificationEmail: () => E.fail(Fixtures.notImplemented),
|
|
42
34
|
}),
|
|
43
35
|
)
|
package/src/email/email.test.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { UserClient } from '@passlock/shared/dist/rpc/user.js'
|
|
2
2
|
import { Effect as E, Layer as L, LogLevel, Logger, pipe } from 'effect'
|
|
3
3
|
import { NoSuchElementException } from 'effect/Cause'
|
|
4
4
|
import { describe, expect, test } from 'vitest'
|
|
@@ -116,14 +116,14 @@ describe('verifyEmailCode should', () => {
|
|
|
116
116
|
const service = yield* _(EmailService)
|
|
117
117
|
yield* _(service.verifyEmailCode({ code: Fixture.code }))
|
|
118
118
|
|
|
119
|
-
const rpcClient = yield* _(
|
|
119
|
+
const rpcClient = yield* _(UserClient)
|
|
120
120
|
expect(rpcClient.verifyEmail).toHaveBeenCalledWith(Fixture.rpcVerifyEmailReq)
|
|
121
121
|
})
|
|
122
122
|
|
|
123
123
|
const rpcClientTest = L.effect(
|
|
124
|
-
|
|
124
|
+
UserClient,
|
|
125
125
|
E.sync(() => {
|
|
126
|
-
const rpcMock = mock<
|
|
126
|
+
const rpcMock = mock<UserClient['Type']>()
|
|
127
127
|
|
|
128
128
|
rpcMock.verifyEmail.mockReturnValue(E.succeed(Fixture.rpcVerifyEmailRes))
|
|
129
129
|
|
|
@@ -154,14 +154,14 @@ describe('verifyEmailLink should', () => {
|
|
|
154
154
|
|
|
155
155
|
// LocationSearch return ?code=code
|
|
156
156
|
// and we expect rpcClient to be called with code
|
|
157
|
-
const rpcClient = yield* _(
|
|
157
|
+
const rpcClient = yield* _(UserClient)
|
|
158
158
|
expect(rpcClient.verifyEmail).toBeCalledWith(Fixture.rpcVerifyEmailReq)
|
|
159
159
|
})
|
|
160
160
|
|
|
161
161
|
const rpcClientTest = L.effect(
|
|
162
|
-
|
|
162
|
+
UserClient,
|
|
163
163
|
E.sync(() => {
|
|
164
|
-
const rpcMock = mock<
|
|
164
|
+
const rpcMock = mock<UserClient['Type']>()
|
|
165
165
|
|
|
166
166
|
rpcMock.verifyEmail.mockReturnValue(E.succeed(Fixture.rpcVerifyEmailRes))
|
|
167
167
|
|
package/src/email/email.ts
CHANGED
|
@@ -2,10 +2,9 @@
|
|
|
2
2
|
* Email verification effects
|
|
3
3
|
*/
|
|
4
4
|
import { BadRequest } from '@passlock/shared/dist/error/error.js'
|
|
5
|
-
import { RpcClient } from '@passlock/shared/dist/rpc/rpc.js'
|
|
6
5
|
import type { VerifyEmailErrors as RpcErrors } from '@passlock/shared/dist/rpc/user.js'
|
|
7
|
-
import { VerifyEmailReq } from '@passlock/shared/dist/rpc/user.js'
|
|
8
|
-
import type { Principal } from '@passlock/shared/dist/schema/
|
|
6
|
+
import { UserClient, VerifyEmailReq } from '@passlock/shared/dist/rpc/user.js'
|
|
7
|
+
import type { Principal } from '@passlock/shared/dist/schema/principal.js'
|
|
9
8
|
import { Context, Effect as E, Layer, Option as O, flow, identity, pipe } from 'effect'
|
|
10
9
|
import { AuthenticationService, type AuthenticationErrors } from '../authentication/authenticate.js'
|
|
11
10
|
import { StorageService } from '../storage/storage.js'
|
|
@@ -38,7 +37,7 @@ export const EmailService = Context.GenericTag<EmailService>('@services/EmailSer
|
|
|
38
37
|
|
|
39
38
|
/* Utils */
|
|
40
39
|
|
|
41
|
-
export type Dependencies = StorageService | AuthenticationService |
|
|
40
|
+
export type Dependencies = StorageService | AuthenticationService | UserClient
|
|
42
41
|
|
|
43
42
|
/**
|
|
44
43
|
* Check for existing token in sessionStorage,
|
|
@@ -101,7 +100,7 @@ export const verifyEmail = (
|
|
|
101
100
|
const { token } = yield* _(getToken())
|
|
102
101
|
|
|
103
102
|
yield* _(E.logDebug('Making request'))
|
|
104
|
-
const client = yield* _(
|
|
103
|
+
const client = yield* _(UserClient)
|
|
105
104
|
const { principal } = yield* _(
|
|
106
105
|
client.verifyEmail(new VerifyEmailReq({ token, code: request.code })),
|
|
107
106
|
)
|
|
@@ -128,7 +127,7 @@ export const EmailServiceLive = Layer.effect(
|
|
|
128
127
|
EmailService,
|
|
129
128
|
E.gen(function* (_) {
|
|
130
129
|
const context = yield* _(
|
|
131
|
-
E.context<
|
|
130
|
+
E.context<UserClient | AuthenticationService | StorageService | URLQueryString>(),
|
|
132
131
|
)
|
|
133
132
|
return EmailService.of({
|
|
134
133
|
verifyEmailCode: flow(verifyEmail, E.provide(context)),
|
package/src/index.ts
CHANGED
|
@@ -10,7 +10,7 @@ import type {
|
|
|
10
10
|
|
|
11
11
|
import { ErrorCode } from '@passlock/shared/dist/error/error.js'
|
|
12
12
|
import { RpcConfig } from '@passlock/shared/dist/rpc/config.js'
|
|
13
|
-
import type { Principal } from '@passlock/shared/dist/schema/
|
|
13
|
+
import type { Principal } from '@passlock/shared/dist/schema/principal.js'
|
|
14
14
|
import { Effect as E, Layer as L, Layer, Option, Runtime, Scope, pipe } from 'effect'
|
|
15
15
|
import { AuthenticationService, type AuthenticationRequest } from './authentication/authenticate.js'
|
|
16
16
|
import { Capabilities } from './capabilities/capabilities.js'
|
|
@@ -18,14 +18,17 @@ import { ConnectionService } from './connection/connection.js'
|
|
|
18
18
|
import { allRequirements } from './effect.js'
|
|
19
19
|
import { EmailService, type VerifyRequest } from './email/email.js'
|
|
20
20
|
import { RegistrationService, type RegistrationRequest } from './registration/register.js'
|
|
21
|
-
import { SocialService, type
|
|
21
|
+
import { SocialService, type AuthenticateOidcReq, type RegisterOidcReq } from './social/social.js'
|
|
22
22
|
import { Storage, StorageService, type AuthType, type StoredToken } from './storage/storage.js'
|
|
23
23
|
import { UserService, type Email, type ResendEmail } from './user/user.js'
|
|
24
24
|
|
|
25
25
|
/* Exports */
|
|
26
26
|
|
|
27
27
|
export type Options = { signal?: AbortSignal }
|
|
28
|
-
export type {
|
|
28
|
+
export type { VerifyEmail } from '@passlock/shared/dist/schema/email.js'
|
|
29
|
+
export type { UserVerification } from '@passlock/shared/dist/schema/passkey.js'
|
|
30
|
+
export type { Principal } from '@passlock/shared/dist/schema/principal.js'
|
|
31
|
+
|
|
29
32
|
export type { AuthenticationRequest } from './authentication/authenticate.js'
|
|
30
33
|
export type { VerifyRequest } from './email/email.js'
|
|
31
34
|
export type { RegistrationRequest } from './registration/register.js'
|
|
@@ -190,14 +193,14 @@ export class PasslockUnsafe {
|
|
|
190
193
|
effect => this.runPromise(effect, options),
|
|
191
194
|
)
|
|
192
195
|
|
|
193
|
-
registerOidc = (request:
|
|
196
|
+
registerOidc = (request: RegisterOidcReq, options?: Options) =>
|
|
194
197
|
pipe(
|
|
195
198
|
SocialService,
|
|
196
199
|
E.flatMap(service => service.registerOidc(request)),
|
|
197
200
|
effect => this.runPromise(effect, options),
|
|
198
201
|
)
|
|
199
202
|
|
|
200
|
-
authenticateOidc = (request:
|
|
203
|
+
authenticateOidc = (request: AuthenticateOidcReq, options?: Options) =>
|
|
201
204
|
pipe(
|
|
202
205
|
SocialService,
|
|
203
206
|
E.flatMap(service => service.authenticateOidc(request)),
|
|
@@ -297,14 +300,14 @@ export class Passlock {
|
|
|
297
300
|
effect => this.runPromise(effect, options),
|
|
298
301
|
)
|
|
299
302
|
|
|
300
|
-
registerOidc = (request:
|
|
303
|
+
registerOidc = (request: RegisterOidcReq, options?: Options) =>
|
|
301
304
|
pipe(
|
|
302
305
|
SocialService,
|
|
303
306
|
E.flatMap(service => service.registerOidc(request)),
|
|
304
307
|
effect => this.runPromise(effect, options),
|
|
305
308
|
)
|
|
306
309
|
|
|
307
|
-
authenticateOidc = (request:
|
|
310
|
+
authenticateOidc = (request: AuthenticateOidcReq, options?: Options) =>
|
|
308
311
|
pipe(
|
|
309
312
|
SocialService,
|
|
310
313
|
E.flatMap(service => service.authenticateOidc(request)),
|
|
@@ -79,6 +79,7 @@ describe('log', () => {
|
|
|
79
79
|
const withLogLevel = logStatement.pipe(Logger.withMinimumLogLevel(LogLevel.Warning))
|
|
80
80
|
|
|
81
81
|
const effect = E.provide(withLogLevel, eventLoggerLive)
|
|
82
|
+
|
|
82
83
|
E.runSync(effect)
|
|
83
84
|
|
|
84
85
|
const expectedEvent = new CustomEvent('PasslogDebugMessage', {
|
|
@@ -21,15 +21,21 @@ export const logRaw = <T>(message: T) => {
|
|
|
21
21
|
|
|
22
22
|
export const DebugMessage = 'PasslogDebugMessage'
|
|
23
23
|
|
|
24
|
+
const dispatch = (message: string) => {
|
|
25
|
+
try {
|
|
26
|
+
const evt = new CustomEvent(DebugMessage, { detail: message })
|
|
27
|
+
globalThis.dispatchEvent(evt)
|
|
28
|
+
} catch (e) {
|
|
29
|
+
globalThis.console.log('Unable to fire custom event')
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
24
33
|
export const eventLoggerLive = Logger.add(
|
|
25
|
-
Logger.make(
|
|
26
|
-
if (typeof
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
}),
|
|
34
|
+
Logger.make(({ logLevel, message }) => {
|
|
35
|
+
if (typeof message === 'string' && logLevel !== LogLevel.Debug) {
|
|
36
|
+
dispatch(message)
|
|
37
|
+
} else if (Array.isArray(message) && logLevel !== LogLevel.Debug) {
|
|
38
|
+
message.forEach(dispatch)
|
|
39
|
+
}
|
|
40
|
+
})
|
|
35
41
|
)
|
|
@@ -1,12 +1,11 @@
|
|
|
1
|
-
import { PreConnectRes } from '@passlock/shared/dist/rpc/connection.js'
|
|
2
1
|
import {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
2
|
+
OptionsReq,
|
|
3
|
+
OptionsRes,
|
|
4
|
+
RegistrationClient,
|
|
5
|
+
VerificationReq,
|
|
6
|
+
VerificationRes,
|
|
7
7
|
} from '@passlock/shared/dist/rpc/registration.js'
|
|
8
|
-
import {
|
|
9
|
-
import type { RegistrationCredential } from '@passlock/shared/dist/schema/schema.js'
|
|
8
|
+
import type { RegistrationCredential } from '@passlock/shared/dist/schema/passkey.js'
|
|
10
9
|
import { Effect as E, Layer as L } from 'effect'
|
|
11
10
|
import * as Fixtures from '../test/fixtures.js'
|
|
12
11
|
import { UserService } from '../user/user.js'
|
|
@@ -75,19 +74,11 @@ export const userServiceTest = L.succeed(
|
|
|
75
74
|
)
|
|
76
75
|
|
|
77
76
|
export const rpcClientTest = L.succeed(
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
preConnect: () => E.succeed(new PreConnectRes({ warmed: true })),
|
|
81
|
-
isExistingUser: () => E.fail(Fixtures.notImplemented),
|
|
82
|
-
verifyEmail: () => E.fail(Fixtures.notImplemented),
|
|
77
|
+
RegistrationClient,
|
|
78
|
+
RegistrationClient.of({
|
|
83
79
|
getRegistrationOptions: () => E.succeed(rpcOptionsRes),
|
|
84
80
|
verifyRegistrationCredential: () => E.succeed(rpcVerificationRes),
|
|
85
|
-
|
|
86
|
-
verifyAuthenticationCredential: () => E.fail(Fixtures.notImplemented),
|
|
87
|
-
registerOidc: () => E.fail(Fixtures.notImplemented),
|
|
88
|
-
authenticateOidc: () => E.fail(Fixtures.notImplemented),
|
|
89
|
-
resendVerificationEmail: () => E.fail(Fixtures.notImplemented),
|
|
90
|
-
}),
|
|
81
|
+
})
|
|
91
82
|
)
|
|
92
83
|
|
|
93
84
|
export const principal = Fixtures.principal
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Duplicate, InternalBrowserError } from '@passlock/shared/dist/error/error.js'
|
|
2
|
-
import {
|
|
2
|
+
import { RegistrationClient } from '@passlock/shared/dist/rpc/registration.js'
|
|
3
3
|
import { Effect as E, Layer as L, Layer, LogLevel, Logger, pipe } from 'effect'
|
|
4
4
|
import { describe, expect, test, vi } from 'vitest'
|
|
5
5
|
import { mock } from 'vitest-mock-extended'
|
|
@@ -33,14 +33,14 @@ describe('register should', () => {
|
|
|
33
33
|
const service = yield* _(RegistrationService)
|
|
34
34
|
yield* _(service.registerPasskey(Fixture.registrationRequest))
|
|
35
35
|
|
|
36
|
-
const rpcClient = yield* _(
|
|
36
|
+
const rpcClient = yield* _(RegistrationClient)
|
|
37
37
|
expect(rpcClient.getRegistrationOptions).toHaveBeenCalledWith(Fixture.rpcOptionsReq)
|
|
38
38
|
})
|
|
39
39
|
|
|
40
40
|
const rpcClientTest = L.effect(
|
|
41
|
-
|
|
41
|
+
RegistrationClient,
|
|
42
42
|
E.sync(() => {
|
|
43
|
-
const rpcMock = mock<
|
|
43
|
+
const rpcMock = mock<RegistrationClient['Type']>()
|
|
44
44
|
|
|
45
45
|
rpcMock.getRegistrationOptions.mockReturnValue(E.succeed(Fixture.rpcOptionsRes))
|
|
46
46
|
rpcMock.verifyRegistrationCredential.mockReturnValue(E.succeed(Fixture.rpcVerificationRes))
|
|
@@ -69,14 +69,14 @@ describe('register should', () => {
|
|
|
69
69
|
const service = yield* _(RegistrationService)
|
|
70
70
|
yield* _(service.registerPasskey(Fixture.registrationRequest))
|
|
71
71
|
|
|
72
|
-
const rpcClient = yield* _(
|
|
72
|
+
const rpcClient = yield* _(RegistrationClient)
|
|
73
73
|
expect(rpcClient.verifyRegistrationCredential).toHaveBeenCalledWith(Fixture.rpcVerificationReq)
|
|
74
74
|
})
|
|
75
75
|
|
|
76
76
|
const rpcClientTest = L.effect(
|
|
77
|
-
|
|
77
|
+
RegistrationClient,
|
|
78
78
|
E.sync(() => {
|
|
79
|
-
const rpcMock = mock<
|
|
79
|
+
const rpcMock = mock<RegistrationClient['Type']>()
|
|
80
80
|
|
|
81
81
|
rpcMock.getRegistrationOptions.mockReturnValue(E.succeed(Fixture.rpcOptionsRes))
|
|
82
82
|
rpcMock.verifyRegistrationCredential.mockReturnValue(E.succeed(Fixture.rpcVerificationRes))
|
|
@@ -110,9 +110,9 @@ describe('register should', () => {
|
|
|
110
110
|
})
|
|
111
111
|
|
|
112
112
|
const rpcClientTest = L.effect(
|
|
113
|
-
|
|
113
|
+
RegistrationClient,
|
|
114
114
|
E.sync(() => {
|
|
115
|
-
const rpcMock = mock<
|
|
115
|
+
const rpcMock = mock<RegistrationClient['Type']>()
|
|
116
116
|
|
|
117
117
|
rpcMock.getRegistrationOptions.mockReturnValue(E.fail(new Duplicate({ message: 'User already exists' })))
|
|
118
118
|
|
|
@@ -2,20 +2,19 @@
|
|
|
2
2
|
* User & passkey registration effects
|
|
3
3
|
*/
|
|
4
4
|
import {
|
|
5
|
-
|
|
6
|
-
|
|
5
|
+
parseCreationOptionsFromJSON,
|
|
6
|
+
type CredentialCreationOptionsJSON,
|
|
7
7
|
} from '@github/webauthn-json/browser-ponyfill'
|
|
8
8
|
import type { NotSupported } from '@passlock/shared/dist/error/error.js'
|
|
9
9
|
import { Duplicate, InternalBrowserError } from '@passlock/shared/dist/error/error.js'
|
|
10
10
|
import type { OptionsErrors, VerificationErrors } from '@passlock/shared/dist/rpc/registration.js'
|
|
11
|
-
import { OptionsReq, VerificationReq } from '@passlock/shared/dist/rpc/registration.js'
|
|
12
|
-
import {
|
|
11
|
+
import { OptionsReq, RegistrationClient, VerificationReq } from '@passlock/shared/dist/rpc/registration.js'
|
|
12
|
+
import { VerifyEmail } from '@passlock/shared/dist/schema/email.js'
|
|
13
13
|
import type {
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
} from '@passlock/shared/dist/schema/schema.js'
|
|
14
|
+
RegistrationCredential,
|
|
15
|
+
UserVerification,
|
|
16
|
+
} from '@passlock/shared/dist/schema/passkey.js'
|
|
17
|
+
import { Principal } from '@passlock/shared/dist/schema/principal.js'
|
|
19
18
|
import { Context, Effect as E, Layer, flow, pipe } from 'effect'
|
|
20
19
|
import { Capabilities } from '../capabilities/capabilities.js'
|
|
21
20
|
import { StorageService } from '../storage/storage.js'
|
|
@@ -59,7 +58,7 @@ const fetchOptions = (request: OptionsReq) => {
|
|
|
59
58
|
return E.gen(function* (_) {
|
|
60
59
|
yield* _(E.logDebug('Making request'))
|
|
61
60
|
|
|
62
|
-
const rpcClient = yield* _(
|
|
61
|
+
const rpcClient = yield* _(RegistrationClient)
|
|
63
62
|
const { publicKey, session } = yield* _(rpcClient.getRegistrationOptions(request))
|
|
64
63
|
|
|
65
64
|
yield* _(E.logDebug('Converting Passlock options to CredentialCreationOptions'))
|
|
@@ -86,7 +85,7 @@ const verifyCredential = (request: VerificationReq) => {
|
|
|
86
85
|
return E.gen(function* (_) {
|
|
87
86
|
yield* _(E.logDebug('Making request'))
|
|
88
87
|
|
|
89
|
-
const rpcClient = yield* _(
|
|
88
|
+
const rpcClient = yield* _(RegistrationClient)
|
|
90
89
|
const { principal } = yield* _(rpcClient.verifyRegistrationCredential(request))
|
|
91
90
|
|
|
92
91
|
return principal
|
|
@@ -95,7 +94,7 @@ const verifyCredential = (request: VerificationReq) => {
|
|
|
95
94
|
|
|
96
95
|
/* Effects */
|
|
97
96
|
|
|
98
|
-
type Dependencies = Capabilities | CreateCredential | StorageService | UserService |
|
|
97
|
+
type Dependencies = Capabilities | CreateCredential | StorageService | UserService | RegistrationClient
|
|
99
98
|
|
|
100
99
|
export const registerPasskey = (
|
|
101
100
|
request: RegistrationRequest,
|
|
@@ -146,7 +145,7 @@ export const RegistrationServiceLive = Layer.effect(
|
|
|
146
145
|
RegistrationService,
|
|
147
146
|
E.gen(function* (_) {
|
|
148
147
|
const context = yield* _(
|
|
149
|
-
E.context<CreateCredential |
|
|
148
|
+
E.context<CreateCredential | RegistrationClient | Capabilities | StorageService | UserService>(),
|
|
150
149
|
)
|
|
151
150
|
|
|
152
151
|
return RegistrationService.of({
|