@swype-org/react-sdk 0.1.86 → 0.1.87
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/index.cjs +30 -4
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +13 -0
- package/dist/index.d.ts +13 -0
- package/dist/index.js +30 -4
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.cts
CHANGED
|
@@ -189,11 +189,13 @@ interface UserConfig {
|
|
|
189
189
|
passkey?: {
|
|
190
190
|
credentialId: string;
|
|
191
191
|
publicKey: string;
|
|
192
|
+
lastVerificationToken?: string | null;
|
|
192
193
|
} | null;
|
|
193
194
|
/** All registered WebAuthn passkey credentials for this user */
|
|
194
195
|
passkeys?: {
|
|
195
196
|
credentialId: string;
|
|
196
197
|
publicKey: string;
|
|
198
|
+
lastVerificationToken?: string | null;
|
|
197
199
|
}[];
|
|
198
200
|
}
|
|
199
201
|
/** Theme mode */
|
|
@@ -466,6 +468,12 @@ interface PasskeyVerifyPopupOptions {
|
|
|
466
468
|
rpId: string;
|
|
467
469
|
/** Populated by `findDevicePasskeyViaPopup`; not set by callers. */
|
|
468
470
|
channelId?: string;
|
|
471
|
+
/** Populated by `findDevicePasskeyViaPopup`; not set by callers. */
|
|
472
|
+
verificationToken?: string;
|
|
473
|
+
/** Privy JWT so the popup can report verification server-side. */
|
|
474
|
+
authToken?: string;
|
|
475
|
+
/** Core API base URL for server-side passkey activity reporting. */
|
|
476
|
+
apiBaseUrl?: string;
|
|
469
477
|
}
|
|
470
478
|
/**
|
|
471
479
|
* Opens a same-origin pop-up window on the Swype domain to check whether
|
|
@@ -475,6 +483,11 @@ interface PasskeyVerifyPopupOptions {
|
|
|
475
483
|
* inside a cross-origin iframe. The popup runs on the Swype domain where
|
|
476
484
|
* the rpId matches, so WebAuthn works.
|
|
477
485
|
*
|
|
486
|
+
* When `authToken` and `apiBaseUrl` are provided, the popup also writes a
|
|
487
|
+
* verification token to the backend. If Safari's ITP blocks both
|
|
488
|
+
* BroadcastChannel and window.opener.postMessage, the opener falls back to
|
|
489
|
+
* checking the server for the matching token after the popup closes.
|
|
490
|
+
*
|
|
478
491
|
* Must be called from a user-gesture handler (e.g. button click) to
|
|
479
492
|
* avoid the browser's pop-up blocker.
|
|
480
493
|
*
|
package/dist/index.d.ts
CHANGED
|
@@ -189,11 +189,13 @@ interface UserConfig {
|
|
|
189
189
|
passkey?: {
|
|
190
190
|
credentialId: string;
|
|
191
191
|
publicKey: string;
|
|
192
|
+
lastVerificationToken?: string | null;
|
|
192
193
|
} | null;
|
|
193
194
|
/** All registered WebAuthn passkey credentials for this user */
|
|
194
195
|
passkeys?: {
|
|
195
196
|
credentialId: string;
|
|
196
197
|
publicKey: string;
|
|
198
|
+
lastVerificationToken?: string | null;
|
|
197
199
|
}[];
|
|
198
200
|
}
|
|
199
201
|
/** Theme mode */
|
|
@@ -466,6 +468,12 @@ interface PasskeyVerifyPopupOptions {
|
|
|
466
468
|
rpId: string;
|
|
467
469
|
/** Populated by `findDevicePasskeyViaPopup`; not set by callers. */
|
|
468
470
|
channelId?: string;
|
|
471
|
+
/** Populated by `findDevicePasskeyViaPopup`; not set by callers. */
|
|
472
|
+
verificationToken?: string;
|
|
473
|
+
/** Privy JWT so the popup can report verification server-side. */
|
|
474
|
+
authToken?: string;
|
|
475
|
+
/** Core API base URL for server-side passkey activity reporting. */
|
|
476
|
+
apiBaseUrl?: string;
|
|
469
477
|
}
|
|
470
478
|
/**
|
|
471
479
|
* Opens a same-origin pop-up window on the Swype domain to check whether
|
|
@@ -475,6 +483,11 @@ interface PasskeyVerifyPopupOptions {
|
|
|
475
483
|
* inside a cross-origin iframe. The popup runs on the Swype domain where
|
|
476
484
|
* the rpId matches, so WebAuthn works.
|
|
477
485
|
*
|
|
486
|
+
* When `authToken` and `apiBaseUrl` are provided, the popup also writes a
|
|
487
|
+
* verification token to the backend. If Safari's ITP blocks both
|
|
488
|
+
* BroadcastChannel and window.opener.postMessage, the opener falls back to
|
|
489
|
+
* checking the server for the matching token after the popup closes.
|
|
490
|
+
*
|
|
478
491
|
* Must be called from a user-gesture handler (e.g. button click) to
|
|
479
492
|
* avoid the browser's pop-up blocker.
|
|
480
493
|
*
|
package/dist/index.js
CHANGED
|
@@ -801,7 +801,12 @@ var VERIFY_POPUP_TIMEOUT_MS = 6e4;
|
|
|
801
801
|
function findDevicePasskeyViaPopup(options) {
|
|
802
802
|
return new Promise((resolve, reject) => {
|
|
803
803
|
const channelId = `swype-pv-${Date.now()}-${Math.random().toString(36).slice(2)}`;
|
|
804
|
-
const
|
|
804
|
+
const verificationToken = crypto.randomUUID();
|
|
805
|
+
const payload = {
|
|
806
|
+
...options,
|
|
807
|
+
channelId,
|
|
808
|
+
verificationToken
|
|
809
|
+
};
|
|
805
810
|
const encoded = btoa(JSON.stringify(payload));
|
|
806
811
|
const popupUrl = `${window.location.origin}/passkey-verify#${encoded}`;
|
|
807
812
|
const popup = window.open(popupUrl, "swype-passkey-verify");
|
|
@@ -821,7 +826,15 @@ function findDevicePasskeyViaPopup(options) {
|
|
|
821
826
|
setTimeout(() => {
|
|
822
827
|
if (!settled) {
|
|
823
828
|
cleanup();
|
|
824
|
-
|
|
829
|
+
checkServerForVerifiedPasskey(
|
|
830
|
+
options.authToken,
|
|
831
|
+
options.apiBaseUrl,
|
|
832
|
+
verificationToken
|
|
833
|
+
).then((credentialId) => {
|
|
834
|
+
resolve(credentialId);
|
|
835
|
+
}).catch(() => {
|
|
836
|
+
resolve(null);
|
|
837
|
+
});
|
|
825
838
|
}
|
|
826
839
|
}, POPUP_CLOSED_GRACE_MS);
|
|
827
840
|
}
|
|
@@ -857,6 +870,17 @@ function findDevicePasskeyViaPopup(options) {
|
|
|
857
870
|
}
|
|
858
871
|
});
|
|
859
872
|
}
|
|
873
|
+
async function checkServerForVerifiedPasskey(authToken, apiBaseUrl, verificationToken) {
|
|
874
|
+
if (!authToken || !apiBaseUrl) return null;
|
|
875
|
+
const res = await fetch(`${apiBaseUrl}/v1/users/config`, {
|
|
876
|
+
headers: { Authorization: `Bearer ${authToken}` }
|
|
877
|
+
});
|
|
878
|
+
if (!res.ok) return null;
|
|
879
|
+
const body = await res.json();
|
|
880
|
+
const passkeys = body.config.passkeys ?? [];
|
|
881
|
+
const matched = passkeys.find((p) => p.lastVerificationToken === verificationToken);
|
|
882
|
+
return matched?.credentialId ?? null;
|
|
883
|
+
}
|
|
860
884
|
async function checkServerForNewPasskey(authToken, apiBaseUrl, existingCredentialIds) {
|
|
861
885
|
if (!authToken || !apiBaseUrl) return null;
|
|
862
886
|
const res = await fetch(`${apiBaseUrl}/v1/users/config`, {
|
|
@@ -5588,14 +5612,16 @@ function SwypePaymentInner({
|
|
|
5588
5612
|
setVerifyingPasskeyPopup(true);
|
|
5589
5613
|
setError(null);
|
|
5590
5614
|
try {
|
|
5615
|
+
const token = await getAccessToken();
|
|
5591
5616
|
const matched = await findDevicePasskeyViaPopup({
|
|
5592
5617
|
credentialIds: knownCredentialIds,
|
|
5593
|
-
rpId: resolvePasskeyRpId()
|
|
5618
|
+
rpId: resolvePasskeyRpId(),
|
|
5619
|
+
authToken: token ?? void 0,
|
|
5620
|
+
apiBaseUrl
|
|
5594
5621
|
});
|
|
5595
5622
|
if (matched) {
|
|
5596
5623
|
setActiveCredentialId(matched);
|
|
5597
5624
|
window.localStorage.setItem(ACTIVE_CREDENTIAL_STORAGE_KEY, matched);
|
|
5598
|
-
const token = await getAccessToken();
|
|
5599
5625
|
if (token) {
|
|
5600
5626
|
reportPasskeyActivity(apiBaseUrl, token, matched).catch(() => {
|
|
5601
5627
|
});
|