@explorins/pers-sdk-react-native 1.5.27 → 1.5.29
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 +83 -32
- 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 +11 -3
- package/dist/providers/rn-dpop-provider.d.ts.map +1 -1
- package/dist/providers/rn-dpop-provider.js +18 -1
- package/dist/storage/rn-secure-storage.d.ts.map +1 -1
- package/dist/storage/rn-secure-storage.js +57 -10
- package/package.json +2 -2
- package/src/providers/PersSDKProvider.tsx +13 -3
- package/src/providers/rn-dpop-provider.ts +17 -1
- package/src/storage/rn-secure-storage.ts +52 -9
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PersSDKProvider.d.ts","sourceRoot":"","sources":["../../src/providers/PersSDKProvider.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,EAAuC,SAAS,
|
|
1
|
+
{"version":3,"file":"PersSDKProvider.d.ts","sourceRoot":"","sources":["../../src/providers/PersSDKProvider.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,EAAuC,SAAS,EAAkC,MAAM,OAAO,CAAC;AAE9G,OAAO,EAAE,OAAO,EAAE,UAAU,EAAE,mBAAmB,EAAsB,MAAM,0BAA0B,CAAC;AAIxG,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,wBAAwB,CAAC;AAG3D,OAAO,KAAK,EACV,WAAW,EACX,WAAW,EACX,YAAY,EACZ,eAAe,EACf,eAAe,EACf,iBAAiB,EACjB,kBAAkB,EAClB,eAAe,EACf,aAAa,EACb,gBAAgB,EAChB,eAAe,EAChB,MAAM,0BAA0B,CAAC;AAGlC,YAAY,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;AAE3D,MAAM,WAAW,cAAc;IAE7B,GAAG,EAAE,OAAO,GAAG,IAAI,CAAC;IAGpB,IAAI,EAAE,WAAW,GAAG,IAAI,CAAC;IACzB,KAAK,EAAE,WAAW,GAAG,IAAI,CAAC;IAC1B,MAAM,EAAE,YAAY,GAAG,IAAI,CAAC;IAC5B,UAAU,EAAE,eAAe,GAAG,IAAI,CAAC;IACnC,SAAS,EAAE,eAAe,GAAG,IAAI,CAAC;IAClC,WAAW,EAAE,iBAAiB,GAAG,IAAI,CAAC;IACtC,YAAY,EAAE,kBAAkB,GAAG,IAAI,CAAC;IACxC,SAAS,EAAE,eAAe,GAAG,IAAI,CAAC;IAClC,OAAO,EAAE,aAAa,GAAG,IAAI,CAAC;IAC9B,SAAS,EAAE,gBAAgB,GAAG,IAAI,CAAC;IACnC,SAAS,EAAE,eAAe,GAAG,IAAI,CAAC;IAGlC,QAAQ,EAAE,eAAe,GAAG,IAAI,CAAC;IAGjC,YAAY,EAAE,mBAAmB,GAAG,IAAI,CAAC;IAGzC,aAAa,EAAE,OAAO,CAAC;IACvB,eAAe,EAAE,OAAO,CAAC;IACzB,IAAI,EAAE,OAAO,GAAG,QAAQ,GAAG,IAAI,CAAC;IAChC,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;IAG9B,UAAU,EAAE,CAAC,MAAM,EAAE,UAAU,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAClD,sBAAsB,EAAE,CAAC,IAAI,EAAE,OAAO,GAAG,QAAQ,GAAG,IAAI,EAAE,cAAc,EAAE,MAAM,GAAG,IAAI,EAAE,eAAe,EAAE,OAAO,KAAK,IAAI,CAAC;IAC3H,eAAe,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CACtC;AAMD,eAAO,MAAM,eAAe,EAAE,KAAK,CAAC,EAAE,CAAC;IACrC,QAAQ,EAAE,SAAS,CAAC;IACpB,MAAM,CAAC,EAAE,UAAU,CAAC;CACrB,CAqIA,CAAC;AAGF,eAAO,MAAM,UAAU,QAAO,cAQ7B,CAAC"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
-
import { createContext, useContext, useState, useCallback, useRef } from 'react';
|
|
2
|
+
import { createContext, useContext, useState, useCallback, useRef, useEffect } from 'react';
|
|
3
3
|
import { Platform } from 'react-native';
|
|
4
4
|
import { PersSDK } from '@explorins/pers-sdk/core';
|
|
5
5
|
import { ReactNativeHttpClient } from './react-native-http-client';
|
|
@@ -8,7 +8,7 @@ import { ReactNativeDPoPProvider } from './rn-dpop-provider';
|
|
|
8
8
|
// Create the context
|
|
9
9
|
const SDKContext = createContext(null);
|
|
10
10
|
// Provider component
|
|
11
|
-
export const PersSDKProvider = ({ children }) => {
|
|
11
|
+
export const PersSDKProvider = ({ children, config }) => {
|
|
12
12
|
const initializingRef = useRef(false);
|
|
13
13
|
const [sdk, setSdk] = useState(null);
|
|
14
14
|
const [authProvider, setAuthProvider] = useState(null);
|
|
@@ -64,7 +64,15 @@ export const PersSDKProvider = ({ children }) => {
|
|
|
64
64
|
finally {
|
|
65
65
|
initializingRef.current = false;
|
|
66
66
|
}
|
|
67
|
-
}, []);
|
|
67
|
+
}, [isInitialized]);
|
|
68
|
+
// Auto-initialize if config is provided
|
|
69
|
+
useEffect(() => {
|
|
70
|
+
if (config && !isInitialized && !initializingRef.current) {
|
|
71
|
+
initialize(config).catch(err => {
|
|
72
|
+
console.error('Auto-initialization failed:', err);
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
}, [config, isInitialized, initialize]);
|
|
68
76
|
const setAuthenticationState = useCallback((user, accountAddress, isAuthenticated) => {
|
|
69
77
|
setUser(user);
|
|
70
78
|
setAccountAddress(accountAddress);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rn-dpop-provider.d.ts","sourceRoot":"","sources":["../../src/providers/rn-dpop-provider.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,kBAAkB,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;
|
|
1
|
+
{"version":3,"file":"rn-dpop-provider.d.ts","sourceRoot":"","sources":["../../src/providers/rn-dpop-provider.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,kBAAkB,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAkB3E,qBAAa,uBAAwB,YAAW,kBAAkB;IAChE;;;;;;;OAOG;IACG,eAAe,CAAC,OAAO,CAAC,EAAE;QAAE,WAAW,CAAC,EAAE,OAAO,CAAA;KAAE,GAAG,OAAO,CAAC,WAAW,CAAC;IAoB1E,SAAS,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAAE,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,MAAM,CAAC;IAmC9E,eAAe,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAO3D,OAAO,CAAC,SAAS;IAIjB,OAAO,CAAC,eAAe;CAQxB"}
|
|
@@ -1,5 +1,22 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { Platform } from 'react-native';
|
|
2
2
|
import { Buffer } from 'buffer';
|
|
3
|
+
// Conditionally require quick-crypto for Native platforms only
|
|
4
|
+
let crypto;
|
|
5
|
+
if (Platform.OS !== 'web') {
|
|
6
|
+
try {
|
|
7
|
+
crypto = require('react-native-quick-crypto').default || require('react-native-quick-crypto');
|
|
8
|
+
}
|
|
9
|
+
catch (e) {
|
|
10
|
+
console.warn('ReactNativeDPoPProvider: Failed to load react-native-quick-crypto', e);
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
else {
|
|
14
|
+
// on Web, we shouldn't be using this provider anyway (Core SDK has WebDPoPProvider)
|
|
15
|
+
// But to be safe, we can mock or throw
|
|
16
|
+
crypto = {
|
|
17
|
+
generateKeyPair: () => { throw new Error('ReactNativeDPoPProvider not supported on Web'); }
|
|
18
|
+
};
|
|
19
|
+
}
|
|
3
20
|
export class ReactNativeDPoPProvider {
|
|
4
21
|
/**
|
|
5
22
|
* Generates a new key pair (ES256 recommended)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rn-secure-storage.d.ts","sourceRoot":"","sources":["../../src/storage/rn-secure-storage.ts"],"names":[],"mappings":"AAEA,OAAO,EACL,YAAY,EAGb,MAAM,0BAA0B,CAAC;
|
|
1
|
+
{"version":3,"file":"rn-secure-storage.d.ts","sourceRoot":"","sources":["../../src/storage/rn-secure-storage.ts"],"names":[],"mappings":"AAEA,OAAO,EACL,YAAY,EAGb,MAAM,0BAA0B,CAAC;AAYlC;;;GAGG;AACH,qBAAa,wBAAyB,YAAW,YAAY;IAY/C,OAAO,CAAC,SAAS;IAV7B,QAAQ,CAAC,eAAe,SAAS;IAGjC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAKzB;gBAEiB,SAAS,GAAE,MAAuB;IAEhD,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC;IA0B/C,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,GAAG,IAAI,CAAC;IAkCzC,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAkBlC,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAwB5B,OAAO,CAAC,UAAU;IAOlB,OAAO,CAAC,QAAQ;CAOjB"}
|
|
@@ -1,6 +1,16 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { Platform } from 'react-native';
|
|
2
2
|
import AsyncStorage from '@react-native-async-storage/async-storage';
|
|
3
3
|
import { DPOP_STORAGE_KEYS, AUTH_STORAGE_KEYS } from '@explorins/pers-sdk/core';
|
|
4
|
+
// Conditionally require Keychain to avoid Web bundler errors
|
|
5
|
+
let Keychain;
|
|
6
|
+
if (Platform.OS !== 'web') {
|
|
7
|
+
try {
|
|
8
|
+
Keychain = require('react-native-keychain');
|
|
9
|
+
}
|
|
10
|
+
catch (e) {
|
|
11
|
+
console.warn('ReactNativeSecureStorage: Failed to load react-native-keychain', e);
|
|
12
|
+
}
|
|
13
|
+
}
|
|
4
14
|
/**
|
|
5
15
|
* Secure Storage implementation for React Native
|
|
6
16
|
* Uses Keychain/Keystore for sensitive data and AsyncStorage for non-sensitive data.
|
|
@@ -25,8 +35,20 @@ export class ReactNativeSecureStorage {
|
|
|
25
35
|
// In runtime, 'key' is just a string, so this is safe.
|
|
26
36
|
if (this.SECURE_KEYS.has(key)) {
|
|
27
37
|
// Store in Keychain/Keystore
|
|
28
|
-
|
|
29
|
-
|
|
38
|
+
try {
|
|
39
|
+
if (Keychain) {
|
|
40
|
+
// Service name acts as the key identifier in simple usage
|
|
41
|
+
await Keychain.setGenericPassword(prefixedKey, stringValue, { service: prefixedKey });
|
|
42
|
+
}
|
|
43
|
+
else {
|
|
44
|
+
throw new Error('RN Keychain not available');
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
catch (e) {
|
|
48
|
+
console.warn(`[ReactNativeSecureStorage] Keychain set failed for ${key}, falling back to AsyncStorage`, e);
|
|
49
|
+
// Fallback to AsyncStorage if Keychain fails
|
|
50
|
+
await AsyncStorage.setItem(prefixedKey, stringValue);
|
|
51
|
+
}
|
|
30
52
|
}
|
|
31
53
|
else {
|
|
32
54
|
// Store standard config/metadata in AsyncStorage
|
|
@@ -37,15 +59,24 @@ export class ReactNativeSecureStorage {
|
|
|
37
59
|
const prefixedKey = this.getKeyName(key);
|
|
38
60
|
if (this.SECURE_KEYS.has(key)) {
|
|
39
61
|
try {
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
62
|
+
if (Keychain) {
|
|
63
|
+
const credentials = await Keychain.getGenericPassword({ service: prefixedKey });
|
|
64
|
+
if (credentials) {
|
|
65
|
+
return this.tryParse(credentials.password);
|
|
66
|
+
}
|
|
43
67
|
}
|
|
44
|
-
return null;
|
|
45
68
|
}
|
|
46
69
|
catch (e) {
|
|
47
70
|
console.warn(`[ReactNativeSecureStorage] Failed to access keychain for ${key}`, e);
|
|
48
|
-
|
|
71
|
+
// Continue to fallback check...
|
|
72
|
+
}
|
|
73
|
+
// Fallback: Check AsyncStorage if not found in Keychain or Keychain failed
|
|
74
|
+
try {
|
|
75
|
+
const val = await AsyncStorage.getItem(prefixedKey);
|
|
76
|
+
return val ? this.tryParse(val) : null;
|
|
77
|
+
}
|
|
78
|
+
catch (e) {
|
|
79
|
+
return null;
|
|
49
80
|
}
|
|
50
81
|
}
|
|
51
82
|
else {
|
|
@@ -62,7 +93,16 @@ export class ReactNativeSecureStorage {
|
|
|
62
93
|
async remove(key) {
|
|
63
94
|
const prefixedKey = this.getKeyName(key);
|
|
64
95
|
if (this.SECURE_KEYS.has(key)) {
|
|
65
|
-
|
|
96
|
+
try {
|
|
97
|
+
if (Keychain) {
|
|
98
|
+
await Keychain.resetGenericPassword({ service: prefixedKey });
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
catch (e) {
|
|
102
|
+
console.warn(`[ReactNativeSecureStorage] Failed to reset keychain for ${key}`, e);
|
|
103
|
+
}
|
|
104
|
+
// Always remove from fallback storage too, just in case
|
|
105
|
+
await AsyncStorage.removeItem(prefixedKey);
|
|
66
106
|
}
|
|
67
107
|
else {
|
|
68
108
|
await AsyncStorage.removeItem(prefixedKey);
|
|
@@ -71,7 +111,14 @@ export class ReactNativeSecureStorage {
|
|
|
71
111
|
async clear() {
|
|
72
112
|
// Clear all known secure keys
|
|
73
113
|
for (const key of this.SECURE_KEYS) {
|
|
74
|
-
|
|
114
|
+
try {
|
|
115
|
+
if (Keychain) {
|
|
116
|
+
await Keychain.resetGenericPassword({ service: this.getKeyName(key) });
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
catch (e) {
|
|
120
|
+
console.warn(`[ReactNativeSecureStorage] Failed to clear keychain key ${key}`, e);
|
|
121
|
+
}
|
|
75
122
|
}
|
|
76
123
|
// Clear AsyncStorage keys related to PERS
|
|
77
124
|
try {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@explorins/pers-sdk-react-native",
|
|
3
|
-
"version": "1.5.
|
|
3
|
+
"version": "1.5.29",
|
|
4
4
|
"description": "React Native SDK for PERS Platform - Tourism Loyalty System with Blockchain Transaction Signing and WebAuthn Authentication",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -37,7 +37,7 @@
|
|
|
37
37
|
"author": "eXplorins",
|
|
38
38
|
"license": "MIT",
|
|
39
39
|
"dependencies": {
|
|
40
|
-
"@explorins/pers-sdk": "
|
|
40
|
+
"@explorins/pers-sdk": "^1.6.36",
|
|
41
41
|
"@explorins/pers-shared": "^2.1.52",
|
|
42
42
|
"@explorins/pers-signer": "^1.0.32",
|
|
43
43
|
"@explorins/web3-ts": "^0.3.75",
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import React, { createContext, useContext, useState, ReactNode, useCallback, useRef } from 'react';
|
|
1
|
+
import React, { createContext, useContext, useState, ReactNode, useCallback, useRef, useEffect } from 'react';
|
|
2
2
|
import { Platform } from 'react-native';
|
|
3
3
|
import { PersSDK, PersConfig, DefaultAuthProvider, DPoPCryptoProvider } from '@explorins/pers-sdk/core';
|
|
4
4
|
import { ReactNativeHttpClient } from './react-native-http-client';
|
|
@@ -65,7 +65,8 @@ const SDKContext = createContext<PersSDKContext | null>(null);
|
|
|
65
65
|
// Provider component
|
|
66
66
|
export const PersSDKProvider: React.FC<{
|
|
67
67
|
children: ReactNode;
|
|
68
|
-
|
|
68
|
+
config?: PersConfig;
|
|
69
|
+
}> = ({ children, config }) => {
|
|
69
70
|
const initializingRef = useRef(false);
|
|
70
71
|
const [sdk, setSdk] = useState<PersSDK | null>(null);
|
|
71
72
|
const [authProvider, setAuthProvider] = useState<DefaultAuthProvider | null>(null);
|
|
@@ -127,7 +128,16 @@ export const PersSDKProvider: React.FC<{
|
|
|
127
128
|
} finally {
|
|
128
129
|
initializingRef.current = false;
|
|
129
130
|
}
|
|
130
|
-
}, []);
|
|
131
|
+
}, [isInitialized]);
|
|
132
|
+
|
|
133
|
+
// Auto-initialize if config is provided
|
|
134
|
+
useEffect(() => {
|
|
135
|
+
if (config && !isInitialized && !initializingRef.current) {
|
|
136
|
+
initialize(config).catch(err => {
|
|
137
|
+
console.error('Auto-initialization failed:', err);
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
}, [config, isInitialized, initialize]);
|
|
131
141
|
|
|
132
142
|
const setAuthenticationState = useCallback((user: UserDTO | AdminDTO | null, accountAddress: string | null, isAuthenticated: boolean) => {
|
|
133
143
|
setUser(user);
|
|
@@ -1,7 +1,23 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { Platform } from 'react-native';
|
|
2
2
|
import { Buffer } from 'buffer';
|
|
3
3
|
import { DPoPCryptoProvider, DPoPKeyPair } from '@explorins/pers-sdk/core';
|
|
4
4
|
|
|
5
|
+
// Conditionally require quick-crypto for Native platforms only
|
|
6
|
+
let crypto: any;
|
|
7
|
+
if (Platform.OS !== 'web') {
|
|
8
|
+
try {
|
|
9
|
+
crypto = require('react-native-quick-crypto').default || require('react-native-quick-crypto');
|
|
10
|
+
} catch (e) {
|
|
11
|
+
console.warn('ReactNativeDPoPProvider: Failed to load react-native-quick-crypto', e);
|
|
12
|
+
}
|
|
13
|
+
} else {
|
|
14
|
+
// on Web, we shouldn't be using this provider anyway (Core SDK has WebDPoPProvider)
|
|
15
|
+
// But to be safe, we can mock or throw
|
|
16
|
+
crypto = {
|
|
17
|
+
generateKeyPair: () => { throw new Error('ReactNativeDPoPProvider not supported on Web'); }
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
|
|
5
21
|
export class ReactNativeDPoPProvider implements DPoPCryptoProvider {
|
|
6
22
|
/**
|
|
7
23
|
* Generates a new key pair (ES256 recommended)
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { Platform } from 'react-native';
|
|
2
2
|
import AsyncStorage from '@react-native-async-storage/async-storage';
|
|
3
3
|
import {
|
|
4
4
|
TokenStorage,
|
|
@@ -6,6 +6,16 @@ import {
|
|
|
6
6
|
AUTH_STORAGE_KEYS
|
|
7
7
|
} from '@explorins/pers-sdk/core';
|
|
8
8
|
|
|
9
|
+
// Conditionally require Keychain to avoid Web bundler errors
|
|
10
|
+
let Keychain: any;
|
|
11
|
+
if (Platform.OS !== 'web') {
|
|
12
|
+
try {
|
|
13
|
+
Keychain = require('react-native-keychain');
|
|
14
|
+
} catch (e) {
|
|
15
|
+
console.warn('ReactNativeSecureStorage: Failed to load react-native-keychain', e);
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
|
|
9
19
|
/**
|
|
10
20
|
* Secure Storage implementation for React Native
|
|
11
21
|
* Uses Keychain/Keystore for sensitive data and AsyncStorage for non-sensitive data.
|
|
@@ -32,8 +42,18 @@ export class ReactNativeSecureStorage implements TokenStorage {
|
|
|
32
42
|
// In runtime, 'key' is just a string, so this is safe.
|
|
33
43
|
if (this.SECURE_KEYS.has(key as any)) {
|
|
34
44
|
// Store in Keychain/Keystore
|
|
35
|
-
|
|
36
|
-
|
|
45
|
+
try {
|
|
46
|
+
if (Keychain) {
|
|
47
|
+
// Service name acts as the key identifier in simple usage
|
|
48
|
+
await Keychain.setGenericPassword(prefixedKey, stringValue, { service: prefixedKey });
|
|
49
|
+
} else {
|
|
50
|
+
throw new Error('RN Keychain not available');
|
|
51
|
+
}
|
|
52
|
+
} catch (e) {
|
|
53
|
+
console.warn(`[ReactNativeSecureStorage] Keychain set failed for ${key}, falling back to AsyncStorage`, e);
|
|
54
|
+
// Fallback to AsyncStorage if Keychain fails
|
|
55
|
+
await AsyncStorage.setItem(prefixedKey, stringValue);
|
|
56
|
+
}
|
|
37
57
|
} else {
|
|
38
58
|
// Store standard config/metadata in AsyncStorage
|
|
39
59
|
await AsyncStorage.setItem(prefixedKey, stringValue);
|
|
@@ -45,14 +65,23 @@ export class ReactNativeSecureStorage implements TokenStorage {
|
|
|
45
65
|
|
|
46
66
|
if (this.SECURE_KEYS.has(key as any)) {
|
|
47
67
|
try {
|
|
48
|
-
|
|
49
|
-
|
|
68
|
+
if (Keychain) {
|
|
69
|
+
const credentials = await Keychain.getGenericPassword({ service: prefixedKey });
|
|
70
|
+
if (credentials) {
|
|
50
71
|
return this.tryParse(credentials.password);
|
|
72
|
+
}
|
|
51
73
|
}
|
|
52
|
-
return null;
|
|
53
74
|
} catch (e) {
|
|
54
75
|
console.warn(`[ReactNativeSecureStorage] Failed to access keychain for ${key}`, e);
|
|
55
|
-
|
|
76
|
+
// Continue to fallback check...
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// Fallback: Check AsyncStorage if not found in Keychain or Keychain failed
|
|
80
|
+
try {
|
|
81
|
+
const val = await AsyncStorage.getItem(prefixedKey);
|
|
82
|
+
return val ? this.tryParse(val) : null;
|
|
83
|
+
} catch (e) {
|
|
84
|
+
return null;
|
|
56
85
|
}
|
|
57
86
|
} else {
|
|
58
87
|
try {
|
|
@@ -69,7 +98,15 @@ export class ReactNativeSecureStorage implements TokenStorage {
|
|
|
69
98
|
const prefixedKey = this.getKeyName(key);
|
|
70
99
|
|
|
71
100
|
if (this.SECURE_KEYS.has(key as any)) {
|
|
72
|
-
|
|
101
|
+
try {
|
|
102
|
+
if (Keychain) {
|
|
103
|
+
await Keychain.resetGenericPassword({ service: prefixedKey });
|
|
104
|
+
}
|
|
105
|
+
} catch (e) {
|
|
106
|
+
console.warn(`[ReactNativeSecureStorage] Failed to reset keychain for ${key}`, e);
|
|
107
|
+
}
|
|
108
|
+
// Always remove from fallback storage too, just in case
|
|
109
|
+
await AsyncStorage.removeItem(prefixedKey);
|
|
73
110
|
} else {
|
|
74
111
|
await AsyncStorage.removeItem(prefixedKey);
|
|
75
112
|
}
|
|
@@ -78,7 +115,13 @@ export class ReactNativeSecureStorage implements TokenStorage {
|
|
|
78
115
|
async clear(): Promise<void> {
|
|
79
116
|
// Clear all known secure keys
|
|
80
117
|
for (const key of this.SECURE_KEYS) {
|
|
81
|
-
|
|
118
|
+
try {
|
|
119
|
+
if (Keychain) {
|
|
120
|
+
await Keychain.resetGenericPassword({ service: this.getKeyName(key) });
|
|
121
|
+
}
|
|
122
|
+
} catch (e) {
|
|
123
|
+
console.warn(`[ReactNativeSecureStorage] Failed to clear keychain key ${key}`, e);
|
|
124
|
+
}
|
|
82
125
|
}
|
|
83
126
|
|
|
84
127
|
// Clear AsyncStorage keys related to PERS
|