@explorins/pers-signer 1.0.27 → 1.0.31
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/browser.cjs.js +64 -38
- package/dist/browser.cjs.js.map +1 -1
- package/dist/browser.esm.js +64 -38
- package/dist/browser.esm.js.map +1 -1
- package/dist/index.cjs.js +75 -54
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.esm.js +75 -54
- package/dist/index.esm.js.map +1 -1
- package/dist/react-native.cjs.js +75 -54
- package/dist/react-native.cjs.js.map +1 -1
- package/dist/react-native.esm.js +75 -54
- package/dist/react-native.esm.js.map +1 -1
- package/package.json +1 -1
package/dist/index.esm.js
CHANGED
|
@@ -67,13 +67,11 @@ const SIGNER_CONFIG = {
|
|
|
67
67
|
* Used as fallback when production signer API is unavailable
|
|
68
68
|
*/
|
|
69
69
|
STAGING_SIGNER_API_URL: 'https://signer-api-staging.pers.ninja/v1',
|
|
70
|
-
// STAGING_SIGNER_API_URL: 'http://localhost:8080/v1',
|
|
71
70
|
/**
|
|
72
71
|
* PERS Platform API URLs
|
|
73
72
|
*/
|
|
74
73
|
DEFAULT_PERS_API_URL: 'https://api.pers.ninja/v2',
|
|
75
74
|
STAGING_PERS_API_URL: 'https://dev.api.pers.ninja/v2',
|
|
76
|
-
// STAGING_PERS_API_URL: 'https://explorins-loyalty.ngrok.io',
|
|
77
75
|
/**
|
|
78
76
|
* Default relying party name for WebAuthn operations
|
|
79
77
|
* This appears in the browser's authentication prompts
|
|
@@ -85,8 +83,31 @@ const SIGNER_CONFIG = {
|
|
|
85
83
|
*/
|
|
86
84
|
// Default fallback provider for Sepolia testnet (no API key required)
|
|
87
85
|
const DEFAULT_FALLBACK_PROVIDER = 'https://ethereum-sepolia.publicnode.com';
|
|
86
|
+
/**
|
|
87
|
+
* WebAuthn configuration constants
|
|
88
|
+
*/
|
|
89
|
+
const WEBAUTHN_CONFIG = {
|
|
90
|
+
/**
|
|
91
|
+
* Timeout for WebAuthn operations (in milliseconds)
|
|
92
|
+
*/
|
|
93
|
+
TIMEOUT: 60000,
|
|
94
|
+
/**
|
|
95
|
+
* User verification requirement
|
|
96
|
+
* 'preferred' - ask for verification if available
|
|
97
|
+
* 'required' - require verification
|
|
98
|
+
* 'discouraged' - don't ask for verification
|
|
99
|
+
*/
|
|
100
|
+
USER_VERIFICATION: 'preferred',
|
|
101
|
+
/**
|
|
102
|
+
* Resident key requirement (Passkeys)
|
|
103
|
+
*/
|
|
104
|
+
RESIDENT_KEY: 'required',
|
|
105
|
+
/**
|
|
106
|
+
* Authenticator attachment preference
|
|
107
|
+
*/
|
|
108
|
+
AUTHENTICATOR_ATTACHMENT: 'platform',
|
|
109
|
+
};
|
|
88
110
|
|
|
89
|
-
// import serviceState from '../core/ServiceState';
|
|
90
111
|
/**
|
|
91
112
|
* Detects the environment (Staging vs Production) based on the JWT token issuer.
|
|
92
113
|
* Updates the global service state accordingly.
|
|
@@ -100,16 +121,8 @@ function detectStagingEnvironmentFromToken(token) {
|
|
|
100
121
|
// Check if issuer matches staging URL
|
|
101
122
|
if (payload.iss === SIGNER_CONFIG.STAGING_PERS_API_URL
|
|
102
123
|
|| SIGNER_CONFIG.STAGING_PERS_API_URL.includes(payload.iss)
|
|
103
|
-
|| SIGNER_CONFIG.STAGING_SIGNER_API_URL.includes(payload.iss)
|
|
104
|
-
// Temporary additional checks for known staging issuers
|
|
105
|
-
// || 'https://signer-api-staging.pers.ninja'.includes(payload.iss)
|
|
106
|
-
// || 'https://dev.api.pers.ninja/v2'.includes(payload.iss)
|
|
107
|
-
) {
|
|
124
|
+
|| SIGNER_CONFIG.STAGING_SIGNER_API_URL.includes(payload.iss)) {
|
|
108
125
|
return true;
|
|
109
|
-
/* } else if (payload.iss === SIGNER_CONFIG.DEFAULT_PERS_API_URL ||
|
|
110
|
-
SIGNER_CONFIG.DEFAULT_PERS_API_URL.includes(payload.iss)) {
|
|
111
|
-
// Explicitly production
|
|
112
|
-
return false; */
|
|
113
126
|
}
|
|
114
127
|
}
|
|
115
128
|
return false;
|
|
@@ -1452,11 +1465,11 @@ class TransactionSigningService {
|
|
|
1452
1465
|
let provider;
|
|
1453
1466
|
try {
|
|
1454
1467
|
// Try primary provider first
|
|
1455
|
-
console.info(`[TransactionSigningService] Attempting to connect to primary provider: ${ethersProviderUrl}`);
|
|
1468
|
+
//console.info(`[TransactionSigningService] Attempting to connect to primary provider: ${ethersProviderUrl}`);
|
|
1456
1469
|
provider = new JsonRpcProvider(ethersProviderUrl);
|
|
1457
1470
|
// Test the connection with a simple call
|
|
1458
1471
|
await provider.getNetwork();
|
|
1459
|
-
console.info(`[TransactionSigningService] Successfully connected to primary provider`);
|
|
1472
|
+
//console.info(`[TransactionSigningService] Successfully connected to primary provider`);
|
|
1460
1473
|
}
|
|
1461
1474
|
catch (primaryError) {
|
|
1462
1475
|
console.warn(`[TransactionSigningService] Primary provider failed, falling back to: ${DEFAULT_FALLBACK_PROVIDER}`, primaryError);
|
|
@@ -1464,7 +1477,7 @@ class TransactionSigningService {
|
|
|
1464
1477
|
provider = new JsonRpcProvider(DEFAULT_FALLBACK_PROVIDER);
|
|
1465
1478
|
// Test the fallback connection
|
|
1466
1479
|
await provider.getNetwork();
|
|
1467
|
-
console.info(`[TransactionSigningService] Successfully connected to fallback provider`);
|
|
1480
|
+
//console.info(`[TransactionSigningService] Successfully connected to fallback provider`);
|
|
1468
1481
|
}
|
|
1469
1482
|
catch (fallbackError) {
|
|
1470
1483
|
console.error(`[TransactionSigningService] Both primary and fallback providers failed`, { primaryError, fallbackError });
|
|
@@ -1528,13 +1541,13 @@ class TransactionSigningService {
|
|
|
1528
1541
|
// Validate input parameters first using TransactionValidator
|
|
1529
1542
|
TransactionValidator.validateSigningParams(params);
|
|
1530
1543
|
const { transactionId, authTokens, ethersProviderUrl } = params;
|
|
1531
|
-
console.info(`[TransactionSigningService] Starting signature process for ${transactionId}`);
|
|
1544
|
+
// console.info(`[TransactionSigningService] Starting signature process for ${transactionId}`);
|
|
1532
1545
|
try {
|
|
1533
1546
|
// Step 2: Prepare wallet for signing
|
|
1534
1547
|
const wallet = await this.prepareWallet(authTokens, ethersProviderUrl);
|
|
1535
1548
|
// Step 3: Execute transaction signing
|
|
1536
1549
|
const signature = await this.executeTransactionSigning(wallet, signingData);
|
|
1537
|
-
console.info(`[TransactionSigningService] Completed signing successfully: ${transactionId}`);
|
|
1550
|
+
// console.info(`[TransactionSigningService] Completed signing successfully: ${transactionId}`);
|
|
1538
1551
|
return {
|
|
1539
1552
|
success: true,
|
|
1540
1553
|
transactionId,
|
|
@@ -1667,6 +1680,28 @@ function getServiceConfig() {
|
|
|
1667
1680
|
return getConfigProvider().getServiceConfig();
|
|
1668
1681
|
}
|
|
1669
1682
|
|
|
1683
|
+
/**
|
|
1684
|
+
* Get the WebAuthn configuration based on the current environment.
|
|
1685
|
+
* This logic is shared between browser and React Native implementations
|
|
1686
|
+
* to ensure consistent behavior while respecting platform differences.
|
|
1687
|
+
*/
|
|
1688
|
+
function getWebAuthnConfig() {
|
|
1689
|
+
// Check if running in a browser environment with window.location available
|
|
1690
|
+
// We use a safe check that won't crash in React Native
|
|
1691
|
+
const isBrowser = typeof window !== 'undefined' && !!window.location && !!window.location.hostname;
|
|
1692
|
+
return {
|
|
1693
|
+
relyingParty: {
|
|
1694
|
+
// In browser, prefer the actual hostname to avoid RP ID mismatch errors
|
|
1695
|
+
// In React Native, use the configured default RP ID
|
|
1696
|
+
id: isBrowser ? window.location.hostname : SIGNER_CONFIG.DEFAULT_RELYING_PARTY_ID,
|
|
1697
|
+
name: SIGNER_CONFIG.DEFAULT_RELYING_PARTY_NAME,
|
|
1698
|
+
// In browser, use the actual origin
|
|
1699
|
+
// In React Native, fallback to the default RP ID (or a configured origin if added later)
|
|
1700
|
+
origin: isBrowser ? window.location.origin : SIGNER_CONFIG.DEFAULT_RELYING_PARTY_ID,
|
|
1701
|
+
}
|
|
1702
|
+
};
|
|
1703
|
+
}
|
|
1704
|
+
|
|
1670
1705
|
/**
|
|
1671
1706
|
* Base64URL encoding/decoding utilities
|
|
1672
1707
|
* Used for WebAuthn credential ID and challenge handling
|
|
@@ -1739,9 +1774,8 @@ class BrowserWebAuthnProvider {
|
|
|
1739
1774
|
// 1. Prepare options for navigator.credentials.create
|
|
1740
1775
|
// We construct authenticatorSelection manually to ensure no conflicting legacy properties are present
|
|
1741
1776
|
const authenticatorSelection = {
|
|
1742
|
-
residentKey:
|
|
1743
|
-
|
|
1744
|
-
userVerification: challenge.authenticatorSelection?.userVerification || 'preferred',
|
|
1777
|
+
residentKey: WEBAUTHN_CONFIG.RESIDENT_KEY, // Force Passkey (discoverable credential)
|
|
1778
|
+
userVerification: challenge.authenticatorSelection?.userVerification || WEBAUTHN_CONFIG.USER_VERIFICATION,
|
|
1745
1779
|
};
|
|
1746
1780
|
const publicKey = {
|
|
1747
1781
|
challenge: base64UrlToBuffer(challenge.challenge),
|
|
@@ -1757,16 +1791,13 @@ class BrowserWebAuthnProvider {
|
|
|
1757
1791
|
pubKeyCredParams: challenge.pubKeyCredParams,
|
|
1758
1792
|
authenticatorSelection,
|
|
1759
1793
|
attestation: 'none',
|
|
1760
|
-
timeout: challenge.timeout ||
|
|
1794
|
+
timeout: challenge.timeout || WEBAUTHN_CONFIG.TIMEOUT,
|
|
1761
1795
|
excludeCredentials: challenge.excludeCredentials?.map((cred) => ({
|
|
1762
1796
|
id: base64UrlToBuffer(cred.id),
|
|
1763
1797
|
type: 'public-key',
|
|
1764
1798
|
transports: cred.transports,
|
|
1765
1799
|
})),
|
|
1766
1800
|
};
|
|
1767
|
-
// console.log('WebAuthn create options:', publicKey);
|
|
1768
|
-
// console.log('WebAuthn create challenge:', challenge);
|
|
1769
|
-
// console.log('this.config', this.config)
|
|
1770
1801
|
// 2. Call the browser's native WebAuthn API
|
|
1771
1802
|
const credential = await navigator.credentials.create({ publicKey });
|
|
1772
1803
|
if (!credential)
|
|
@@ -1790,8 +1821,8 @@ class BrowserWebAuthnProvider {
|
|
|
1790
1821
|
const publicKey = {
|
|
1791
1822
|
challenge: base64UrlToBuffer(challenge.challenge),
|
|
1792
1823
|
rpId: challenge.rpId || this.config.relyingParty.id,
|
|
1793
|
-
userVerification: challenge.userVerification ||
|
|
1794
|
-
timeout:
|
|
1824
|
+
userVerification: challenge.userVerification || WEBAUTHN_CONFIG.USER_VERIFICATION,
|
|
1825
|
+
timeout: WEBAUTHN_CONFIG.TIMEOUT,
|
|
1795
1826
|
allowCredentials: challenge.allowCredentials?.webauthn?.map((cred) => ({
|
|
1796
1827
|
id: base64UrlToBuffer(cred.id),
|
|
1797
1828
|
type: 'public-key',
|
|
@@ -1830,13 +1861,7 @@ class BrowserWebAuthnProvider {
|
|
|
1830
1861
|
* Get WebAuthn provider for browser environments
|
|
1831
1862
|
*/
|
|
1832
1863
|
async function getBrowserWebAuthnProvider() {
|
|
1833
|
-
const config =
|
|
1834
|
-
relyingParty: {
|
|
1835
|
-
id: typeof window !== 'undefined' ? window.location.hostname : SIGNER_CONFIG.DEFAULT_RELYING_PARTY_ID,
|
|
1836
|
-
name: SIGNER_CONFIG.DEFAULT_RELYING_PARTY_NAME,
|
|
1837
|
-
origin: typeof window !== 'undefined' ? window.location.origin : SIGNER_CONFIG.DEFAULT_RELYING_PARTY_ID,
|
|
1838
|
-
}
|
|
1839
|
-
};
|
|
1864
|
+
const config = getWebAuthnConfig();
|
|
1840
1865
|
return new BrowserWebAuthnProvider(config);
|
|
1841
1866
|
}
|
|
1842
1867
|
|
|
@@ -1852,13 +1877,18 @@ var WebAuthnProvider_browser = /*#__PURE__*/Object.freeze({
|
|
|
1852
1877
|
*/
|
|
1853
1878
|
class ReactNativeWebAuthnProvider {
|
|
1854
1879
|
constructor(config) {
|
|
1880
|
+
this.passkeyLibrary = null;
|
|
1855
1881
|
this.config = config;
|
|
1856
1882
|
}
|
|
1857
1883
|
async getPasskeyLibrary() {
|
|
1884
|
+
if (this.passkeyLibrary) {
|
|
1885
|
+
return this.passkeyLibrary;
|
|
1886
|
+
}
|
|
1858
1887
|
try {
|
|
1859
1888
|
// Dynamic import to avoid hard dependency
|
|
1860
1889
|
// @ts-ignore - Optional dependency
|
|
1861
1890
|
const { Passkey } = await import('react-native-passkey');
|
|
1891
|
+
this.passkeyLibrary = Passkey;
|
|
1862
1892
|
return Passkey;
|
|
1863
1893
|
}
|
|
1864
1894
|
catch (error) {
|
|
@@ -1874,7 +1904,6 @@ class ReactNativeWebAuthnProvider {
|
|
|
1874
1904
|
}
|
|
1875
1905
|
}
|
|
1876
1906
|
async handleWebFallback(operation, challenge) {
|
|
1877
|
-
console.log(`Falling back to browser WebAuthn for React Native Web (${operation})...`);
|
|
1878
1907
|
try {
|
|
1879
1908
|
// Import and use browser WebAuthn provider
|
|
1880
1909
|
const { getBrowserWebAuthnProvider } = await Promise.resolve().then(function () { return WebAuthnProvider_browser; });
|
|
@@ -1897,8 +1926,8 @@ class ReactNativeWebAuthnProvider {
|
|
|
1897
1926
|
// If it's a very long string, it might be an issue.
|
|
1898
1927
|
// But let's focus on aligning the authenticatorSelection first.
|
|
1899
1928
|
const authenticatorSelection = {
|
|
1900
|
-
residentKey:
|
|
1901
|
-
userVerification: challenge.authenticatorSelection?.userVerification ||
|
|
1929
|
+
residentKey: WEBAUTHN_CONFIG.RESIDENT_KEY, // Force Passkey (discoverable credential)
|
|
1930
|
+
userVerification: challenge.authenticatorSelection?.userVerification || WEBAUTHN_CONFIG.USER_VERIFICATION,
|
|
1902
1931
|
// Explicitly undefined to avoid issues, though JS objects don't usually include undefined keys in JSON
|
|
1903
1932
|
// But react-native-passkey might handle it differently.
|
|
1904
1933
|
};
|
|
@@ -1927,11 +1956,9 @@ class ReactNativeWebAuthnProvider {
|
|
|
1927
1956
|
transports: v.transports
|
|
1928
1957
|
})), // Cast to any to avoid strict type mismatch with react-native-passkey types
|
|
1929
1958
|
authenticatorSelection,
|
|
1930
|
-
timeout: challenge.timeout ||
|
|
1959
|
+
timeout: challenge.timeout || WEBAUTHN_CONFIG.TIMEOUT,
|
|
1931
1960
|
};
|
|
1932
|
-
console.log('[RNWebAuthn] Calling Passkey.create with:', JSON.stringify(request, null, 2));
|
|
1933
1961
|
const result = await Passkey.create(request);
|
|
1934
|
-
console.log('[RNWebAuthn] Passkey.create success:', JSON.stringify(result, null, 2));
|
|
1935
1962
|
return {
|
|
1936
1963
|
id: result.id,
|
|
1937
1964
|
clientDataJSON: result.response.clientDataJSON,
|
|
@@ -1959,12 +1986,10 @@ class ReactNativeWebAuthnProvider {
|
|
|
1959
1986
|
// transports: cred.transports,
|
|
1960
1987
|
})),
|
|
1961
1988
|
rpId: challenge.rpId || this.config.relyingParty.id,
|
|
1962
|
-
userVerification: challenge.userVerification ||
|
|
1963
|
-
timeout: challenge.timeout ||
|
|
1989
|
+
userVerification: challenge.userVerification || WEBAUTHN_CONFIG.USER_VERIFICATION,
|
|
1990
|
+
timeout: challenge.timeout || WEBAUTHN_CONFIG.TIMEOUT,
|
|
1964
1991
|
};
|
|
1965
|
-
console.log('[RNWebAuthn] Calling Passkey.get (sign) with:', JSON.stringify(request, null, 2));
|
|
1966
1992
|
const credential = await Passkey.get(request);
|
|
1967
|
-
console.log('[RNWebAuthn] Passkey.get success:', JSON.stringify(credential, null, 2));
|
|
1968
1993
|
return {
|
|
1969
1994
|
kind: 'Fido2',
|
|
1970
1995
|
credentialAssertion: {
|
|
@@ -1989,12 +2014,7 @@ class ReactNativeWebAuthnProvider {
|
|
|
1989
2014
|
* Get WebAuthn provider for React Native environments
|
|
1990
2015
|
*/
|
|
1991
2016
|
async function getReactNativeWebAuthnProvider() {
|
|
1992
|
-
const config =
|
|
1993
|
-
relyingParty: {
|
|
1994
|
-
id: SIGNER_CONFIG.DEFAULT_RELYING_PARTY_ID,
|
|
1995
|
-
name: SIGNER_CONFIG.DEFAULT_RELYING_PARTY_NAME,
|
|
1996
|
-
}
|
|
1997
|
-
};
|
|
2017
|
+
const config = getWebAuthnConfig();
|
|
1998
2018
|
return new ReactNativeWebAuthnProvider(config);
|
|
1999
2019
|
}
|
|
2000
2020
|
|
|
@@ -2126,7 +2146,6 @@ class PersSignerSDK {
|
|
|
2126
2146
|
* @throws {Error} If required configuration is missing
|
|
2127
2147
|
*/
|
|
2128
2148
|
constructor(config) {
|
|
2129
|
-
// console.log('DEBUG: v1.2.0')
|
|
2130
2149
|
this.config = config;
|
|
2131
2150
|
setConfigProvider(new WebConfigProvider({
|
|
2132
2151
|
apiUrl: config.apiUrl || SIGNER_CONFIG.DEFAULT_SIGNER_API_URL,
|
|
@@ -2335,10 +2354,12 @@ class PersSignerSDK {
|
|
|
2335
2354
|
authTokens,
|
|
2336
2355
|
ethersProviderUrl: this.config.ethersProviderUrl ?? DEFAULT_FALLBACK_PROVIDER
|
|
2337
2356
|
}, signingData);
|
|
2338
|
-
|
|
2339
|
-
|
|
2340
|
-
|
|
2341
|
-
|
|
2357
|
+
if (result.success) {
|
|
2358
|
+
this.triggerStatusUpdate(SigningStatus.COMPLETED, 'Transaction signed successfully', {
|
|
2359
|
+
transactionId: payload.transactionId,
|
|
2360
|
+
signature: result.signature
|
|
2361
|
+
}, statusCallback);
|
|
2362
|
+
}
|
|
2342
2363
|
return result;
|
|
2343
2364
|
}
|
|
2344
2365
|
catch (error) {
|