Skip to content

Commit ef54442

Browse files
committed
Stop conditional creation after 5s
1 parent e7a06fa commit ef54442

File tree

8 files changed

+73
-23
lines changed

8 files changed

+73
-23
lines changed

packages/connect-react/src/components/append/AppendAfterErrorScreen.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ const AppendAfterErrorScreen = ({ attestationOptions }: { attestationOptions: st
2424

2525
setLoading(true);
2626
setErrorMessage(undefined);
27-
const res = await getConnectService().completeAppend(attestationOptions);
27+
const res = await getConnectService().completeAppend(attestationOptions, 'manual');
2828
if (res.err) {
2929
if (res.val.type === ConnectErrorType.ExcludeCredentialsMatch) {
3030
return handleSituation(AppendSituationCode.ClientExcludeCredentialsMatch, res.val);

packages/connect-react/src/components/append/AppendInitScreen.tsx

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import { StatefulLoader } from '../../utils/statefulLoader';
1212
import AppendBenefits from './append-init/AppendBenetifs';
1313
import AppendInitLoaded2 from './append-init/AppendInitLoaded2';
1414
import AppendInitLoading from './append-init/AppendInitLoading';
15+
import { AppendCompletionType } from '@corbado/web-core/dist/models/connect/append';
1516

1617
export enum AppendInitState {
1718
SilentLoading,
@@ -147,7 +148,7 @@ const AppendInitScreen = () => {
147148
statefulLoader.current.finish();
148149
if (startAppendRes.val.autoAppend || flags.hasSupportForAutomaticAppend()) {
149150
console.log('starting auto-append');
150-
await handleSubmit(startAppendRes.val.attestationOptions, false);
151+
await handleSubmit(startAppendRes.val.attestationOptions, 'auto');
151152
}
152153
};
153154

@@ -164,25 +165,25 @@ const AppendInitScreen = () => {
164165
}, []);
165166

166167
const handleSubmit = useCallback(
167-
async (attestationOptions: string, showErrorIfCancelled: boolean) => {
168+
async (attestationOptions: string, completionType: AppendCompletionType) => {
168169
if (appendLoading || skipping) {
169170
return;
170171
}
171172

172173
setAppendLoading(true);
173174
setErrorMessage(undefined);
174175

175-
const res = await getConnectService().completeAppend(attestationOptions);
176+
const res = await getConnectService().completeAppend(attestationOptions, completionType);
176177
if (res.err) {
177178
if (res.val.type === ConnectErrorType.ExcludeCredentialsMatch) {
178179
return handleSituation(AppendSituationCode.ClientExcludeCredentialsMatch, res.val);
179180
}
180181

181182
if (res.val.type === ConnectErrorType.Cancel) {
182-
if (showErrorIfCancelled) {
183-
return handleSituation(AppendSituationCode.ClientPasskeyOperationCancelled, res.val);
184-
} else {
183+
if (completionType === 'auto') {
185184
return handleSituation(AppendSituationCode.ClientPasskeyOperationCancelledSilent, res.val);
185+
} else {
186+
return handleSituation(AppendSituationCode.ClientPasskeyOperationCancelled, res.val);
186187
}
187188
}
188189

@@ -200,7 +201,7 @@ const AppendInitScreen = () => {
200201

201202
const handleConditionalCreate = useCallback(
202203
async (attestationOptions: string) => {
203-
const res = await getConnectService().completeAppend(attestationOptions, true);
204+
const res = await getConnectService().completeAppend(attestationOptions, 'conditional');
204205
if (res.err) {
205206
await handleSituation(AppendSituationCode.ClientPasskeyOperationErrorSilent, res.val);
206207
return false;
@@ -283,7 +284,14 @@ const AppendInitScreen = () => {
283284
void onReadMoreClick();
284285
setAppendInitState(AppendInitState.ShowBenefits);
285286
}}
286-
handleSubmit={() => void handleSubmit(attestationOptions, true)}
287+
handleSubmit={() => {
288+
let completionType: AppendCompletionType = 'manual';
289+
if (errorMessage) {
290+
completionType = 'manual-retry';
291+
}
292+
293+
void handleSubmit(attestationOptions, completionType);
294+
}}
287295
handleSkip={() => onSkip()}
288296
/>
289297
);

packages/connect-react/src/components/passkeyList/PasskeyListScreen.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,7 @@ const PasskeyListScreen = () => {
130130
return handleSituation(PasskeyListSituationCode.CboApiPasskeysNotSupported);
131131
}
132132

133-
const res = await getConnectService().completeAppend(startAppendRes.val.attestationOptions);
133+
const res = await getConnectService().completeAppend(startAppendRes.val.attestationOptions, 'manual');
134134
if (res.err) {
135135
if (res.val.type === ConnectErrorType.Cancel) {
136136
return handleSituation(PasskeyListSituationCode.ClientPasskeyOperationCancelled, res.val);

packages/web-core/openapi/spec_v2.yaml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1507,9 +1507,12 @@ components:
15071507
type: object
15081508
required:
15091509
- attestationResponse
1510+
- completionType
15101511
properties:
15111512
attestationResponse:
15121513
type: string
1514+
completionType:
1515+
$ref: "#/components/schemas/appendCompletionType"
15131516

15141517
connectAppendFinishRsp:
15151518
type: object
@@ -2376,6 +2379,10 @@ components:
23762379
error:
23772380
$ref: "#/components/schemas/requestError"
23782381

2382+
appendCompletionType:
2383+
type: string
2384+
enum: ["auto", "conditional", "manual", "manual-retry"]
2385+
23792386
responses:
23802387
"200":
23812388
description: Operation succeeded

packages/web-core/src/api/v2/api.ts

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,22 @@ export interface AaguidDetails {
4848
*/
4949
'iconDark': string;
5050
}
51+
/**
52+
*
53+
* @export
54+
* @enum {string}
55+
*/
56+
57+
export const AppendCompletionType = {
58+
Auto: 'auto',
59+
Conditional: 'conditional',
60+
Manual: 'manual',
61+
ManualRetry: 'manual-retry'
62+
} as const;
63+
64+
export type AppendCompletionType = typeof AppendCompletionType[keyof typeof AppendCompletionType];
65+
66+
5167
/**
5268
*
5369
* @export
@@ -299,7 +315,15 @@ export interface ConnectAppendFinishReq {
299315
* @memberof ConnectAppendFinishReq
300316
*/
301317
'attestationResponse': string;
318+
/**
319+
*
320+
* @type {AppendCompletionType}
321+
* @memberof ConnectAppendFinishReq
322+
*/
323+
'completionType': AppendCompletionType;
302324
}
325+
326+
303327
/**
304328
*
305329
* @export
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export type AppendCompletionType = 'manual' | 'manual-retry' | 'auto' | 'conditional';

packages/web-core/src/services/ConnectService.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ import { ConnectError, ConnectErrorType } from '../utils';
3838
import type { LastLogin } from './ClientStateService';
3939
import { ClientStateService } from './ClientStateService';
4040
import { WebAuthnService } from './WebAuthnService';
41+
import { AppendCompletionType } from '../models/connect/append';
4142

4243
const packageVersion = process.env.FE_LIBRARY_VERSION;
4344

@@ -434,20 +435,21 @@ export class ConnectService {
434435

435436
async completeAppend(
436437
attestationOptions: string,
437-
conditional = false,
438+
completionType: AppendCompletionType,
438439
): Promise<Result<ConnectAppendFinishRsp, ConnectError>> {
439440
const existingProcess = await this.#getExistingProcess(() => this.appendInit(new AbortController()));
440441
if (!existingProcess) {
441442
return Err(new ConnectError(ConnectErrorType.MissingInit));
442443
}
443444

445+
const conditional = completionType === 'conditional';
444446
const res = await this.#webAuthnCreatePasskey(attestationOptions, conditional);
445447
if (res.err) {
446448
return res;
447449
}
448450

449451
const finishRes = await this.wrapWithErr(() =>
450-
this.#connectApi.connectAppendFinish({ attestationResponse: res.val }),
452+
this.#connectApi.connectAppendFinish({ attestationResponse: res.val, completionType }),
451453
);
452454
if (finishRes.ok) {
453455
const latestLogin = finishRes.val.passkeyOperation as LastLogin;

packages/web-core/src/services/WebAuthnService.ts

Lines changed: 19 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -57,19 +57,27 @@ export class WebAuthnService {
5757
throw new Error('No publicKey in assertionOptions');
5858
}
5959

60-
let mediation: CredentialMediationRequirement | undefined;
60+
let credential: PublicKeyCredential;
6161
if (conditional) {
62-
mediation = 'conditional';
63-
}
64-
65-
const options = {
66-
publicKey,
67-
signal: abortController.signal,
68-
mediation,
69-
} as never;
62+
const p1 = await navigator.credentials.create({
63+
publicKey,
64+
signal: abortController.signal,
65+
mediation: 'conditional',
66+
} as never);
67+
const p2 = new Promise<null>(resolve => setTimeout(() => resolve(null), 5000));
68+
69+
const result = await Promise.race([p1, p2]);
70+
if (!result) {
71+
throw new Error('Timeout after 5000ms');
72+
}
7073

71-
console.log('create options', options);
72-
const credential = (await navigator.credentials.create(options)) as PublicKeyCredential;
74+
credential = result as PublicKeyCredential;
75+
} else {
76+
credential = (await navigator.credentials.create({
77+
publicKey,
78+
signal: abortController.signal,
79+
} as never)) as PublicKeyCredential;
80+
}
7381

7482
return {
7583
response: JSON.stringify(credential.toJSON()),

0 commit comments

Comments
 (0)