@explorins/pers-sdk-react-native 1.5.28 → 1.5.30
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/README.md +22 -0
- package/dist/index.js +80 -24
- package/dist/index.js.map +1 -1
- package/dist/providers/PersSDKProvider.d.ts +1 -0
- package/dist/providers/PersSDKProvider.d.ts.map +1 -1
- package/dist/providers/PersSDKProvider.js +27 -14
- package/dist/providers/react-native-auth-provider.d.ts +5 -0
- package/dist/providers/react-native-auth-provider.d.ts.map +1 -1
- package/dist/providers/react-native-auth-provider.js +8 -2
- package/dist/storage/rn-secure-storage.d.ts.map +1 -1
- package/dist/storage/rn-secure-storage.js +46 -9
- package/package.json +2 -2
- package/src/providers/PersSDKProvider.tsx +32 -15
- package/src/providers/react-native-auth-provider.ts +15 -2
- package/src/storage/rn-secure-storage.ts +41 -8
package/README.md
CHANGED
|
@@ -376,6 +376,28 @@ function BlockchainRedemption() {
|
|
|
376
376
|
|
|
377
377
|
## Advanced Configuration
|
|
378
378
|
|
|
379
|
+
### SDK Initialization & DPoP
|
|
380
|
+
|
|
381
|
+
The `PersSDKProvider` accepts a `config` object allowing you to customize behavior, including **DPoP (Distributed Proof of Possession)**.
|
|
382
|
+
|
|
383
|
+
**DPoP Behavior:**
|
|
384
|
+
- **Enabled by Default**: Automatically active on iOS/Android using a high-performance C++ crypto bridge (`react-native-quick-crypto`).
|
|
385
|
+
- **Web Support**: Uses standard WebCrypto API.
|
|
386
|
+
- **Security**: Binds access tokens to the device, preventing replay attacks.
|
|
387
|
+
|
|
388
|
+
**Customizing Initialization:**
|
|
389
|
+
```typescript
|
|
390
|
+
<PersSDKProvider config={{
|
|
391
|
+
apiProjectKey: 'your-project-key',
|
|
392
|
+
// DPoP is enabled by default. To disable (not recommended):
|
|
393
|
+
dpop: {
|
|
394
|
+
enabled: false
|
|
395
|
+
}
|
|
396
|
+
}}>
|
|
397
|
+
<YourApp />
|
|
398
|
+
</PersSDKProvider>
|
|
399
|
+
```
|
|
400
|
+
|
|
379
401
|
### Custom Authentication Provider
|
|
380
402
|
|
|
381
403
|
The SDK automatically uses `ReactNativeSecureStorage` for React Native (iOS/Android) and `LocalStorageTokenStorage` for Web. You can customize this if needed:
|
package/dist/index.js
CHANGED
|
@@ -32078,8 +32078,20 @@ class ReactNativeSecureStorage {
|
|
|
32078
32078
|
// In runtime, 'key' is just a string, so this is safe.
|
|
32079
32079
|
if (this.SECURE_KEYS.has(key)) {
|
|
32080
32080
|
// Store in Keychain/Keystore
|
|
32081
|
-
|
|
32082
|
-
|
|
32081
|
+
try {
|
|
32082
|
+
if (Keychain) {
|
|
32083
|
+
// Service name acts as the key identifier in simple usage
|
|
32084
|
+
await Keychain.setGenericPassword(prefixedKey, stringValue, { service: prefixedKey });
|
|
32085
|
+
}
|
|
32086
|
+
else {
|
|
32087
|
+
throw new Error('RN Keychain not available');
|
|
32088
|
+
}
|
|
32089
|
+
}
|
|
32090
|
+
catch (e) {
|
|
32091
|
+
console.warn(`[ReactNativeSecureStorage] Keychain set failed for ${key}, falling back to AsyncStorage`, e);
|
|
32092
|
+
// Fallback to AsyncStorage if Keychain fails
|
|
32093
|
+
await AsyncStorage.setItem(prefixedKey, stringValue);
|
|
32094
|
+
}
|
|
32083
32095
|
}
|
|
32084
32096
|
else {
|
|
32085
32097
|
// Store standard config/metadata in AsyncStorage
|
|
@@ -32090,15 +32102,24 @@ class ReactNativeSecureStorage {
|
|
|
32090
32102
|
const prefixedKey = this.getKeyName(key);
|
|
32091
32103
|
if (this.SECURE_KEYS.has(key)) {
|
|
32092
32104
|
try {
|
|
32093
|
-
|
|
32094
|
-
|
|
32095
|
-
|
|
32105
|
+
if (Keychain) {
|
|
32106
|
+
const credentials = await Keychain.getGenericPassword({ service: prefixedKey });
|
|
32107
|
+
if (credentials) {
|
|
32108
|
+
return this.tryParse(credentials.password);
|
|
32109
|
+
}
|
|
32096
32110
|
}
|
|
32097
|
-
return null;
|
|
32098
32111
|
}
|
|
32099
32112
|
catch (e) {
|
|
32100
32113
|
console.warn(`[ReactNativeSecureStorage] Failed to access keychain for ${key}`, e);
|
|
32101
|
-
|
|
32114
|
+
// Continue to fallback check...
|
|
32115
|
+
}
|
|
32116
|
+
// Fallback: Check AsyncStorage if not found in Keychain or Keychain failed
|
|
32117
|
+
try {
|
|
32118
|
+
const val = await AsyncStorage.getItem(prefixedKey);
|
|
32119
|
+
return val ? this.tryParse(val) : null;
|
|
32120
|
+
}
|
|
32121
|
+
catch (e) {
|
|
32122
|
+
return null;
|
|
32102
32123
|
}
|
|
32103
32124
|
}
|
|
32104
32125
|
else {
|
|
@@ -32115,7 +32136,16 @@ class ReactNativeSecureStorage {
|
|
|
32115
32136
|
async remove(key) {
|
|
32116
32137
|
const prefixedKey = this.getKeyName(key);
|
|
32117
32138
|
if (this.SECURE_KEYS.has(key)) {
|
|
32118
|
-
|
|
32139
|
+
try {
|
|
32140
|
+
if (Keychain) {
|
|
32141
|
+
await Keychain.resetGenericPassword({ service: prefixedKey });
|
|
32142
|
+
}
|
|
32143
|
+
}
|
|
32144
|
+
catch (e) {
|
|
32145
|
+
console.warn(`[ReactNativeSecureStorage] Failed to reset keychain for ${key}`, e);
|
|
32146
|
+
}
|
|
32147
|
+
// Always remove from fallback storage too, just in case
|
|
32148
|
+
await AsyncStorage.removeItem(prefixedKey);
|
|
32119
32149
|
}
|
|
32120
32150
|
else {
|
|
32121
32151
|
await AsyncStorage.removeItem(prefixedKey);
|
|
@@ -32124,7 +32154,14 @@ class ReactNativeSecureStorage {
|
|
|
32124
32154
|
async clear() {
|
|
32125
32155
|
// Clear all known secure keys
|
|
32126
32156
|
for (const key of this.SECURE_KEYS) {
|
|
32127
|
-
|
|
32157
|
+
try {
|
|
32158
|
+
if (Keychain) {
|
|
32159
|
+
await Keychain.resetGenericPassword({ service: this.getKeyName(key) });
|
|
32160
|
+
}
|
|
32161
|
+
}
|
|
32162
|
+
catch (e) {
|
|
32163
|
+
console.warn(`[ReactNativeSecureStorage] Failed to clear keychain key ${key}`, e);
|
|
32164
|
+
}
|
|
32128
32165
|
}
|
|
32129
32166
|
// Clear AsyncStorage keys related to PERS
|
|
32130
32167
|
try {
|
|
@@ -32178,16 +32215,22 @@ function createReactNativeAuthProvider(projectKey, config = {}) {
|
|
|
32178
32215
|
if (!projectKey || typeof projectKey !== 'string') {
|
|
32179
32216
|
throw new Error('createReactNativeAuthProvider: projectKey is required and must be a string');
|
|
32180
32217
|
}
|
|
32181
|
-
const { keyPrefix = `pers_${projectKey.slice(0, 8)}_`, debug = false, customStorage, authType = 'user' } = config;
|
|
32218
|
+
const { keyPrefix = `pers_${projectKey.slice(0, 8)}_`, debug = false, customStorage, authType = 'user', dpop } = config;
|
|
32182
32219
|
// Platform-specific storage selection
|
|
32183
32220
|
const tokenStorage = customStorage || (isWebPlatform
|
|
32184
32221
|
? new LocalStorageTokenStorage()
|
|
32185
32222
|
: new ReactNativeSecureStorage(keyPrefix));
|
|
32223
|
+
// Prepare DPoP config ensuring enabled is boolean (default true)
|
|
32224
|
+
const dpopConfig = dpop ? {
|
|
32225
|
+
enabled: dpop.enabled ?? true,
|
|
32226
|
+
cryptoProvider: dpop.cryptoProvider
|
|
32227
|
+
} : undefined;
|
|
32186
32228
|
// Return DefaultAuthProvider configured with platform-appropriate storage
|
|
32187
32229
|
return new DefaultAuthProvider({
|
|
32188
32230
|
authType,
|
|
32189
32231
|
projectKey,
|
|
32190
|
-
storage: tokenStorage
|
|
32232
|
+
storage: tokenStorage,
|
|
32233
|
+
dpop: dpopConfig
|
|
32191
32234
|
});
|
|
32192
32235
|
}
|
|
32193
32236
|
|
|
@@ -32494,7 +32537,7 @@ class ReactNativeHttpClient {
|
|
|
32494
32537
|
// Create the context
|
|
32495
32538
|
const SDKContext = react.createContext(null);
|
|
32496
32539
|
// Provider component
|
|
32497
|
-
const PersSDKProvider = ({ children }) => {
|
|
32540
|
+
const PersSDKProvider = ({ children, config }) => {
|
|
32498
32541
|
const initializingRef = react.useRef(false);
|
|
32499
32542
|
const [sdk, setSdk] = react.useState(null);
|
|
32500
32543
|
const [authProvider, setAuthProvider] = react.useState(null);
|
|
@@ -32511,6 +32554,18 @@ const PersSDKProvider = ({ children }) => {
|
|
|
32511
32554
|
try {
|
|
32512
32555
|
// Create HTTP client
|
|
32513
32556
|
const httpClient = new ReactNativeHttpClient();
|
|
32557
|
+
// Ensure DPoP is enabled by default for all platforms
|
|
32558
|
+
const dpopConfig = config.dpop || {};
|
|
32559
|
+
const isDpopEnabled = dpopConfig.enabled ?? true;
|
|
32560
|
+
// Prepare DPoP settings for Auth Provider
|
|
32561
|
+
const dpopSettings = {
|
|
32562
|
+
enabled: isDpopEnabled,
|
|
32563
|
+
cryptoProvider: dpopConfig.cryptoProvider
|
|
32564
|
+
};
|
|
32565
|
+
// Inject Native DPoP Provider (crypto-based) for mobile platforms if not already provided
|
|
32566
|
+
if (reactNative.Platform.OS !== 'web' && isDpopEnabled && !dpopSettings.cryptoProvider) {
|
|
32567
|
+
dpopSettings.cryptoProvider = new ReactNativeDPoPProvider();
|
|
32568
|
+
}
|
|
32514
32569
|
// Create platform-aware auth provider if not provided
|
|
32515
32570
|
let authProvider;
|
|
32516
32571
|
if (config.authProvider) {
|
|
@@ -32519,23 +32574,16 @@ const PersSDKProvider = ({ children }) => {
|
|
|
32519
32574
|
else {
|
|
32520
32575
|
// Use our platform-aware auth provider that automatically selects LocalStorage (web) or AsyncStorage (mobile)
|
|
32521
32576
|
authProvider = createReactNativeAuthProvider(config.apiProjectKey || 'default-project', {
|
|
32522
|
-
debug: false
|
|
32577
|
+
debug: false,
|
|
32578
|
+
dpop: dpopSettings
|
|
32523
32579
|
});
|
|
32524
32580
|
}
|
|
32525
32581
|
// Enhanced config with platform-appropriate auth provider
|
|
32526
32582
|
const sdkConfig = {
|
|
32527
32583
|
...config,
|
|
32528
|
-
authProvider
|
|
32584
|
+
authProvider,
|
|
32585
|
+
dpop: dpopSettings
|
|
32529
32586
|
};
|
|
32530
|
-
// Inject Native DPoP Provider (crypto-based) for mobile platforms
|
|
32531
|
-
// Web platforms use built-in WebCrypto provider by default
|
|
32532
|
-
if (reactNative.Platform.OS !== 'web' && (!config.dpop?.cryptoProvider)) {
|
|
32533
|
-
sdkConfig.dpop = {
|
|
32534
|
-
...(config.dpop || {}),
|
|
32535
|
-
enabled: config.dpop?.enabled ?? true,
|
|
32536
|
-
cryptoProvider: new ReactNativeDPoPProvider()
|
|
32537
|
-
};
|
|
32538
|
-
}
|
|
32539
32587
|
// Initialize PersSDK with platform-aware auth provider
|
|
32540
32588
|
const sdkInstance = new PersSDK(httpClient, sdkConfig);
|
|
32541
32589
|
setAuthProvider(authProvider);
|
|
@@ -32550,7 +32598,15 @@ const PersSDKProvider = ({ children }) => {
|
|
|
32550
32598
|
finally {
|
|
32551
32599
|
initializingRef.current = false;
|
|
32552
32600
|
}
|
|
32553
|
-
}, []);
|
|
32601
|
+
}, [isInitialized]);
|
|
32602
|
+
// Auto-initialize if config is provided
|
|
32603
|
+
react.useEffect(() => {
|
|
32604
|
+
if (config && !isInitialized && !initializingRef.current) {
|
|
32605
|
+
initialize(config).catch(err => {
|
|
32606
|
+
console.error('Auto-initialization failed:', err);
|
|
32607
|
+
});
|
|
32608
|
+
}
|
|
32609
|
+
}, [config, isInitialized, initialize]);
|
|
32554
32610
|
const setAuthenticationState = react.useCallback((user, accountAddress, isAuthenticated) => {
|
|
32555
32611
|
setUser(user);
|
|
32556
32612
|
setAccountAddress(accountAddress);
|