@onairos/react-native 3.0.1 → 3.0.2
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/lib/commonjs/api/index.js +105 -86
- package/lib/commonjs/api/index.js.map +1 -1
- package/lib/commonjs/components/OnairosButton.js +20 -12
- package/lib/commonjs/components/OnairosButton.js.map +1 -1
- package/lib/commonjs/components/UniversalOnboarding.js +18 -0
- package/lib/commonjs/components/UniversalOnboarding.js.map +1 -1
- package/lib/commonjs/index.js.map +1 -1
- package/lib/commonjs/utils/secureStorage.js +129 -42
- package/lib/commonjs/utils/secureStorage.js.map +1 -1
- package/lib/module/api/index.js +105 -86
- package/lib/module/api/index.js.map +1 -1
- package/lib/module/components/OnairosButton.js +21 -13
- package/lib/module/components/OnairosButton.js.map +1 -1
- package/lib/module/components/UniversalOnboarding.js +19 -1
- package/lib/module/components/UniversalOnboarding.js.map +1 -1
- package/lib/module/utils/secureStorage.js +129 -42
- package/lib/module/utils/secureStorage.js.map +1 -1
- package/package.json +1 -1
- package/src/api/index.ts +86 -101
- package/src/components/OnairosButton.tsx +22 -13
- package/src/components/UniversalOnboarding.tsx +13 -0
- package/src/index.ts +1 -2
- package/src/utils/secureStorage.ts +140 -57
|
@@ -1,41 +1,137 @@
|
|
|
1
|
+
import * as Keychain from 'react-native-keychain';
|
|
1
2
|
import { Platform } from 'react-native';
|
|
2
3
|
import { sha256 } from './crypto';
|
|
4
|
+
import { STORAGE_KEYS } from '../constants';
|
|
3
5
|
|
|
6
|
+
// Define OnairosCredentials interface locally to avoid circular dependencies
|
|
4
7
|
export interface OnairosCredentials {
|
|
5
8
|
username: string;
|
|
6
|
-
accessToken
|
|
9
|
+
accessToken?: string;
|
|
7
10
|
refreshToken?: string;
|
|
8
11
|
userPin?: string;
|
|
9
12
|
platforms?: {
|
|
10
|
-
instagram?: { token: string; username: string };
|
|
11
|
-
youtube?: { token: string; username: string };
|
|
12
|
-
pinterest?: { token: string; username: string };
|
|
13
|
-
reddit?: { token: string; username: string };
|
|
13
|
+
instagram?: { token: string; username: string; userId?: string };
|
|
14
|
+
youtube?: { token: string; username: string; userId?: string };
|
|
15
|
+
pinterest?: { token: string; username: string; userId?: string };
|
|
16
|
+
reddit?: { token: string; username: string; userId?: string };
|
|
14
17
|
};
|
|
15
18
|
createdAt: number;
|
|
16
19
|
}
|
|
17
20
|
|
|
18
21
|
export interface StorageOptions {
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
subtitle?: string;
|
|
23
|
-
};
|
|
22
|
+
service?: string;
|
|
23
|
+
accessControl?: Keychain.ACCESS_CONTROL;
|
|
24
|
+
accessible?: Keychain.ACCESSIBLE;
|
|
24
25
|
}
|
|
25
26
|
|
|
26
|
-
//
|
|
27
|
-
|
|
27
|
+
// Create a mock storage for environments without Keychain access (like Expo Go)
|
|
28
|
+
const mockStorage: Record<string, { username: string; password: string }> = {};
|
|
29
|
+
|
|
30
|
+
// Check if running in Expo Go or environments without native module access
|
|
31
|
+
const isKeychainAvailable = () => {
|
|
32
|
+
try {
|
|
33
|
+
return typeof Keychain.getGenericPassword === 'function';
|
|
34
|
+
} catch (e) {
|
|
35
|
+
return false;
|
|
36
|
+
}
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
// Wrapper for getGenericPassword that falls back to mock storage
|
|
40
|
+
const safeGetGenericPassword = async (options: Keychain.Options) => {
|
|
41
|
+
try {
|
|
42
|
+
if (isKeychainAvailable()) {
|
|
43
|
+
return await Keychain.getGenericPassword(options);
|
|
44
|
+
} else {
|
|
45
|
+
// Fall back to mock storage in memory
|
|
46
|
+
const key = options?.service || 'default';
|
|
47
|
+
return mockStorage[key] || null;
|
|
48
|
+
}
|
|
49
|
+
} catch (error) {
|
|
50
|
+
console.warn('Keychain access failed, using mock storage', error);
|
|
51
|
+
// Fall back to mock storage on error
|
|
52
|
+
const key = options?.service || 'default';
|
|
53
|
+
return mockStorage[key] || null;
|
|
54
|
+
}
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
// Wrapper for setGenericPassword that falls back to mock storage
|
|
58
|
+
const safeSetGenericPassword = async (
|
|
59
|
+
username: string,
|
|
60
|
+
password: string,
|
|
61
|
+
options?: Keychain.Options
|
|
62
|
+
) => {
|
|
63
|
+
try {
|
|
64
|
+
if (isKeychainAvailable()) {
|
|
65
|
+
return await Keychain.setGenericPassword(username, password, options);
|
|
66
|
+
} else {
|
|
67
|
+
// Fall back to mock storage in memory
|
|
68
|
+
const key = options?.service || 'default';
|
|
69
|
+
mockStorage[key] = { username, password };
|
|
70
|
+
return true;
|
|
71
|
+
}
|
|
72
|
+
} catch (error) {
|
|
73
|
+
console.warn('Keychain access failed, using mock storage', error);
|
|
74
|
+
// Fall back to mock storage on error
|
|
75
|
+
const key = options?.service || 'default';
|
|
76
|
+
mockStorage[key] = { username, password };
|
|
77
|
+
return true;
|
|
78
|
+
}
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
// Wrapper for resetGenericPassword that falls back to mock storage
|
|
82
|
+
const safeResetGenericPassword = async (options?: Keychain.Options) => {
|
|
83
|
+
try {
|
|
84
|
+
if (isKeychainAvailable()) {
|
|
85
|
+
return await Keychain.resetGenericPassword(options);
|
|
86
|
+
} else {
|
|
87
|
+
// Fall back to mock storage in memory
|
|
88
|
+
const key = options?.service || 'default';
|
|
89
|
+
delete mockStorage[key];
|
|
90
|
+
return true;
|
|
91
|
+
}
|
|
92
|
+
} catch (error) {
|
|
93
|
+
console.warn('Keychain access failed, using mock storage', error);
|
|
94
|
+
// Fall back to mock storage on error
|
|
95
|
+
const key = options?.service || 'default';
|
|
96
|
+
delete mockStorage[key];
|
|
97
|
+
return true;
|
|
98
|
+
}
|
|
99
|
+
};
|
|
28
100
|
|
|
29
101
|
/**
|
|
30
102
|
* Store credentials in memory (temporary solution)
|
|
31
103
|
*/
|
|
32
104
|
export const storeCredentials = async (
|
|
33
|
-
credentials: OnairosCredentials
|
|
34
|
-
options: StorageOptions = {}
|
|
105
|
+
credentials: Partial<OnairosCredentials>
|
|
35
106
|
): Promise<boolean> => {
|
|
36
107
|
try {
|
|
37
|
-
|
|
38
|
-
|
|
108
|
+
const existingCredentials = await getCredentials();
|
|
109
|
+
const updatedCredentials: OnairosCredentials = {
|
|
110
|
+
...existingCredentials,
|
|
111
|
+
...credentials,
|
|
112
|
+
createdAt: existingCredentials?.createdAt || Date.now(),
|
|
113
|
+
} as OnairosCredentials;
|
|
114
|
+
|
|
115
|
+
const username = updatedCredentials.username;
|
|
116
|
+
if (!username) {
|
|
117
|
+
throw new Error('Username is required for storing credentials');
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
const options: Keychain.Options = {
|
|
121
|
+
service: STORAGE_KEYS.credentials,
|
|
122
|
+
};
|
|
123
|
+
|
|
124
|
+
// Only use secure storage options on real devices
|
|
125
|
+
if (Platform.OS !== 'web' && isKeychainAvailable()) {
|
|
126
|
+
options.accessControl = Keychain.ACCESS_CONTROL.BIOMETRY_ANY_OR_DEVICE_PASSCODE;
|
|
127
|
+
options.accessible = Keychain.ACCESSIBLE.WHEN_UNLOCKED;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
await safeSetGenericPassword(
|
|
131
|
+
username,
|
|
132
|
+
JSON.stringify(updatedCredentials),
|
|
133
|
+
options
|
|
134
|
+
);
|
|
39
135
|
return true;
|
|
40
136
|
} catch (error) {
|
|
41
137
|
console.error('Error storing credentials:', error);
|
|
@@ -46,18 +142,17 @@ export const storeCredentials = async (
|
|
|
46
142
|
/**
|
|
47
143
|
* Retrieve credentials from memory (temporary solution)
|
|
48
144
|
*/
|
|
49
|
-
export const getCredentials = async (
|
|
50
|
-
options: StorageOptions = {}
|
|
51
|
-
): Promise<OnairosCredentials | null> => {
|
|
145
|
+
export const getCredentials = async (): Promise<OnairosCredentials | null> => {
|
|
52
146
|
try {
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
147
|
+
const credentials = await safeGetGenericPassword({
|
|
148
|
+
service: STORAGE_KEYS.credentials,
|
|
149
|
+
});
|
|
150
|
+
if (credentials) {
|
|
151
|
+
return JSON.parse(credentials.password);
|
|
57
152
|
}
|
|
58
|
-
return
|
|
153
|
+
return null;
|
|
59
154
|
} catch (error) {
|
|
60
|
-
console.error('Error
|
|
155
|
+
console.error('Error getting credentials:', error);
|
|
61
156
|
return null;
|
|
62
157
|
}
|
|
63
158
|
};
|
|
@@ -67,9 +162,12 @@ export const getCredentials = async (
|
|
|
67
162
|
*/
|
|
68
163
|
export const hasCredentials = async (): Promise<boolean> => {
|
|
69
164
|
try {
|
|
70
|
-
|
|
165
|
+
const credentials = await safeGetGenericPassword({
|
|
166
|
+
service: STORAGE_KEYS.credentials,
|
|
167
|
+
});
|
|
168
|
+
return !!credentials;
|
|
71
169
|
} catch (error) {
|
|
72
|
-
console.error('Error checking
|
|
170
|
+
console.error('Error checking credentials:', error);
|
|
73
171
|
return false;
|
|
74
172
|
}
|
|
75
173
|
};
|
|
@@ -79,7 +177,9 @@ export const hasCredentials = async (): Promise<boolean> => {
|
|
|
79
177
|
*/
|
|
80
178
|
export const deleteCredentials = async (): Promise<boolean> => {
|
|
81
179
|
try {
|
|
82
|
-
|
|
180
|
+
await safeResetGenericPassword({
|
|
181
|
+
service: STORAGE_KEYS.credentials,
|
|
182
|
+
});
|
|
83
183
|
return true;
|
|
84
184
|
} catch (error) {
|
|
85
185
|
console.error('Error deleting credentials:', error);
|
|
@@ -91,47 +191,30 @@ export const deleteCredentials = async (): Promise<boolean> => {
|
|
|
91
191
|
* Update specific fields in the stored credentials
|
|
92
192
|
*/
|
|
93
193
|
export const updateCredentials = async (
|
|
94
|
-
|
|
95
|
-
options: StorageOptions = {}
|
|
194
|
+
credentials: Partial<OnairosCredentials>
|
|
96
195
|
): Promise<boolean> => {
|
|
97
|
-
|
|
98
|
-
const currentCredentials = await getCredentials(options);
|
|
99
|
-
if (!currentCredentials) {
|
|
100
|
-
return false;
|
|
101
|
-
}
|
|
102
|
-
const updatedCredentials: OnairosCredentials = {
|
|
103
|
-
...currentCredentials,
|
|
104
|
-
...updates,
|
|
105
|
-
};
|
|
106
|
-
return await storeCredentials(updatedCredentials, options);
|
|
107
|
-
} catch (error) {
|
|
108
|
-
console.error('Error updating credentials:', error);
|
|
109
|
-
return false;
|
|
110
|
-
}
|
|
196
|
+
return storeCredentials(credentials);
|
|
111
197
|
};
|
|
112
198
|
|
|
113
199
|
/**
|
|
114
200
|
* Generate a device-specific unique username
|
|
115
201
|
*/
|
|
116
|
-
export const generateDeviceUsername =
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
const username = `onairos_${sha256(deviceInfo).substring(0, 10)}`;
|
|
120
|
-
return username;
|
|
121
|
-
} catch (error) {
|
|
122
|
-
console.error('Error generating device username:', error);
|
|
123
|
-
return `onairos_${Date.now().toString(36)}`;
|
|
124
|
-
}
|
|
202
|
+
export const generateDeviceUsername = (): string => {
|
|
203
|
+
const randomId = Math.random().toString(36).substring(2, 10);
|
|
204
|
+
return `dev_${randomId}`;
|
|
125
205
|
};
|
|
126
206
|
|
|
127
207
|
/**
|
|
128
208
|
* Verify credentials (temporary mock implementation)
|
|
129
209
|
*/
|
|
130
|
-
export const verifyCredentials = async (
|
|
131
|
-
credentials: OnairosCredentials
|
|
132
|
-
): Promise<boolean> => {
|
|
210
|
+
export const verifyCredentials = async (username: string): Promise<boolean> => {
|
|
133
211
|
try {
|
|
134
|
-
|
|
212
|
+
// For Expo Go or development, always return true
|
|
213
|
+
if (!isKeychainAvailable()) {
|
|
214
|
+
return true;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
// TODO: Implement actual verification with API
|
|
135
218
|
return true;
|
|
136
219
|
} catch (error) {
|
|
137
220
|
console.error('Error verifying credentials:', error);
|