@onairos/react-native 3.0.72 โ 3.0.74
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/components/Onairos.js.map +1 -1
- package/lib/commonjs/index.js +23 -504
- package/lib/commonjs/index.js.map +1 -1
- package/lib/commonjs/services/apiKeyService.js +93 -14
- package/lib/commonjs/services/apiKeyService.js.map +1 -1
- package/lib/commonjs/services/platformAuthService.js +224 -9
- package/lib/commonjs/services/platformAuthService.js.map +1 -1
- package/lib/commonjs/types/index.js +4 -0
- package/lib/commonjs/types.js +12 -0
- package/lib/commonjs/types.js.map +1 -1
- package/lib/commonjs/utils/programmaticFlow.js +117 -0
- package/lib/commonjs/utils/programmaticFlow.js.map +1 -0
- package/lib/module/components/Onairos.js.map +1 -1
- package/lib/module/index.js +17 -64
- package/lib/module/index.js.map +1 -1
- package/lib/module/services/apiKeyService.js +90 -11
- package/lib/module/services/apiKeyService.js.map +1 -1
- package/lib/module/services/platformAuthService.js +218 -8
- package/lib/module/services/platformAuthService.js.map +1 -1
- package/lib/module/types/index.js +1 -1
- package/lib/module/types.js +8 -0
- package/lib/module/types.js.map +1 -1
- package/lib/module/utils/programmaticFlow.js +111 -0
- package/lib/module/utils/programmaticFlow.js.map +1 -0
- package/lib/typescript/components/Onairos.d.ts +1 -29
- package/lib/typescript/components/Onairos.d.ts.map +1 -1
- package/lib/typescript/index.d.ts +10 -40
- package/lib/typescript/index.d.ts.map +1 -1
- package/lib/typescript/services/apiKeyService.d.ts +18 -0
- package/lib/typescript/services/apiKeyService.d.ts.map +1 -1
- package/lib/typescript/services/platformAuthService.d.ts +26 -0
- package/lib/typescript/services/platformAuthService.d.ts.map +1 -1
- package/lib/typescript/types/index.d.ts +144 -78
- package/lib/typescript/types/index.d.ts.map +1 -1
- package/lib/typescript/types.d.ts +56 -0
- package/lib/typescript/types.d.ts.map +1 -1
- package/lib/typescript/utils/programmaticFlow.d.ts +23 -0
- package/lib/typescript/utils/programmaticFlow.d.ts.map +1 -0
- package/package.json +1 -1
- package/src/components/Onairos.tsx +1 -30
- package/src/index.ts +23 -132
- package/src/services/apiKeyService.ts +84 -8
- package/src/services/platformAuthService.ts +260 -4
- package/src/types/index.d.ts +110 -0
- package/src/types/index.ts +148 -74
- package/src/types.ts +59 -0
- package/src/utils/programmaticFlow.ts +113 -0
package/src/index.ts
CHANGED
|
@@ -1,156 +1,47 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Onairos React Native SDK
|
|
3
3
|
* A React Native implementation for Onairos personalized data integration
|
|
4
|
+
*
|
|
5
|
+
* PUBLIC API - Only expose what developers need
|
|
4
6
|
*/
|
|
5
7
|
|
|
6
|
-
//
|
|
8
|
+
// Essential Types Only
|
|
7
9
|
export type {
|
|
8
10
|
OnairosButtonProps,
|
|
11
|
+
OnairosProps,
|
|
9
12
|
DataTier,
|
|
10
|
-
UniversalOnboardingProps,
|
|
11
|
-
ConnectionStatus,
|
|
12
|
-
PlatformListProps,
|
|
13
|
-
PinInputProps,
|
|
14
|
-
TrainingModalProps,
|
|
15
|
-
OAuthWebViewProps,
|
|
16
|
-
PlatformConfig,
|
|
17
|
-
PlatformAuthConfig,
|
|
18
|
-
ApiResponse,
|
|
19
|
-
CredentialsResult,
|
|
20
|
-
OverlayProps,
|
|
21
|
-
BiometricOptions,
|
|
22
|
-
PinRequirements,
|
|
23
13
|
OnairosConfig,
|
|
24
|
-
ApiKeyConfig,
|
|
25
|
-
ApiKeyValidationResult,
|
|
26
14
|
TestModeOptions,
|
|
27
|
-
DataRequest,
|
|
28
15
|
} from './types';
|
|
29
16
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
export
|
|
33
|
-
export type { OAuthConfig } from './services/oauthService';
|
|
34
|
-
export type { ApiErrorType, ApiError } from './utils/onairosApi';
|
|
35
|
-
|
|
36
|
-
// Export constants
|
|
37
|
-
export { COLORS, PLATFORMS, API_ENDPOINTS, STORAGE_KEYS, PIN_REQUIREMENTS, DEEP_LINK_CONFIG } from './constants';
|
|
17
|
+
// Core Components
|
|
18
|
+
export { OnairosButton } from './components/OnairosButton';
|
|
19
|
+
export { Onairos } from './components/Onairos';
|
|
38
20
|
|
|
39
|
-
//
|
|
21
|
+
// SDK Initialization
|
|
40
22
|
export {
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
deleteCredentials,
|
|
45
|
-
updateCredentials,
|
|
46
|
-
generateDeviceUsername,
|
|
47
|
-
verifyCredentials,
|
|
48
|
-
} from './utils/secureStorage';
|
|
49
|
-
|
|
50
|
-
export {
|
|
51
|
-
validateCredentials,
|
|
52
|
-
createAccount,
|
|
53
|
-
authenticate,
|
|
54
|
-
refreshToken,
|
|
55
|
-
getPlatformData,
|
|
56
|
-
getUserProfile,
|
|
57
|
-
updatePlatformConnections,
|
|
58
|
-
} from './utils/onairosApi';
|
|
59
|
-
|
|
60
|
-
export {
|
|
61
|
-
rsaEncrypt,
|
|
62
|
-
sha256,
|
|
63
|
-
base64ToBuffer,
|
|
64
|
-
} from './utils/crypto';
|
|
65
|
-
|
|
66
|
-
export {
|
|
67
|
-
logDebug,
|
|
68
|
-
logError,
|
|
69
|
-
isDebugMode,
|
|
70
|
-
} from './utils/debugHelper';
|
|
71
|
-
|
|
72
|
-
// Export services
|
|
73
|
-
export {
|
|
74
|
-
connectPlatform,
|
|
75
|
-
initializeOAuthService,
|
|
76
|
-
cleanupOAuthService,
|
|
77
|
-
storePlatformConnection,
|
|
78
|
-
} from './services/oauthService';
|
|
23
|
+
initializeApiKey,
|
|
24
|
+
ADMIN_API_KEY,
|
|
25
|
+
} from './services/apiKeyService';
|
|
79
26
|
|
|
27
|
+
// Authentication & PIN Management
|
|
80
28
|
export {
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
testApiConnectivity,
|
|
29
|
+
storePinAfterBiometric,
|
|
30
|
+
getStoredJwtToken,
|
|
31
|
+
clearStoredTokens,
|
|
85
32
|
requestEmailVerification,
|
|
86
33
|
verifyEmailCode,
|
|
87
34
|
checkEmailVerificationStatus,
|
|
88
|
-
disconnectPlatform,
|
|
89
|
-
initiateOAuth,
|
|
90
35
|
} from './services/platformAuthService';
|
|
91
36
|
|
|
92
|
-
//
|
|
93
|
-
export {
|
|
94
|
-
initializeApiKey,
|
|
95
|
-
validateApiKey,
|
|
96
|
-
getApiConfig,
|
|
97
|
-
getApiKey,
|
|
98
|
-
isApiKeyInitialized,
|
|
99
|
-
resetApiKeyService,
|
|
100
|
-
getAuthHeaders,
|
|
101
|
-
makeAuthenticatedRequest,
|
|
102
|
-
} from './services/apiKeyService';
|
|
103
|
-
|
|
104
|
-
// Export API and Services
|
|
105
|
-
export { onairosApi } from './api';
|
|
106
|
-
export { OAuthService } from './services/oauthService';
|
|
107
|
-
export * from './utils/secureStorage';
|
|
108
|
-
export * from './utils/encryption';
|
|
109
|
-
|
|
110
|
-
// Export hooks
|
|
111
|
-
export { useCredentials } from './hooks/useCredentials';
|
|
112
|
-
export { useConnections } from './hooks/useConnections';
|
|
113
|
-
|
|
114
|
-
// Export Portal components
|
|
115
|
-
export { Portal, PortalHost } from './utils/Portal';
|
|
116
|
-
|
|
117
|
-
// Screen Components
|
|
118
|
-
export { ConnectorScreen } from './components/screens/ConnectorScreen';
|
|
119
|
-
export { PinCreationScreen } from './components/screens/PinCreationScreen';
|
|
120
|
-
export { LoadingScreen } from './components/screens/LoadingScreen';
|
|
121
|
-
|
|
122
|
-
// Onboarding Components
|
|
123
|
-
export { OAuthWebView } from './components/onboarding/OAuthWebView';
|
|
124
|
-
export { PlatformConnector } from './components/onboarding/PlatformConnector';
|
|
125
|
-
export { OnboardingHeader } from './components/onboarding/OnboardingHeader';
|
|
37
|
+
// Programmatic Function (for custom buttons)
|
|
38
|
+
export { executeOnairosFlow } from './utils/programmaticFlow';
|
|
126
39
|
|
|
127
|
-
//
|
|
128
|
-
export { PlatformList } from './components/PlatformList';
|
|
129
|
-
export { PinInput } from './components/PinInput';
|
|
130
|
-
export { TrainingModal } from './components/TrainingModal';
|
|
131
|
-
export { EmailVerificationModal } from './components/EmailVerificationModal';
|
|
132
|
-
export { DataRequestScreen } from './components/DataRequestScreen';
|
|
133
|
-
export { Overlay } from './components/Overlay';
|
|
134
|
-
export { UniversalOnboarding } from './components/UniversalOnboarding';
|
|
135
|
-
export { OnairosButton } from './components/OnairosButton';
|
|
136
|
-
export { Onairos } from './components/Onairos';
|
|
137
|
-
|
|
138
|
-
// Define the public components for default export
|
|
139
|
-
import * as React from 'react';
|
|
140
|
-
import { Onairos } from './components/Onairos';
|
|
40
|
+
// Default export for convenience
|
|
141
41
|
import { OnairosButton } from './components/OnairosButton';
|
|
142
|
-
import {
|
|
143
|
-
import { UniversalOnboarding } from './components/UniversalOnboarding';
|
|
144
|
-
import { PortalHost } from './utils/Portal';
|
|
145
|
-
|
|
146
|
-
// Simple default export object - main types are available through named exports
|
|
147
|
-
const components = {
|
|
148
|
-
Onairos: Onairos as any,
|
|
149
|
-
OnairosButton: OnairosButton as any,
|
|
150
|
-
OnairosOverlay: Overlay as any,
|
|
151
|
-
UniversalOnboarding: UniversalOnboarding as any,
|
|
152
|
-
PortalHost: PortalHost as any,
|
|
153
|
-
};
|
|
42
|
+
import { Onairos } from './components/Onairos';
|
|
154
43
|
|
|
155
|
-
|
|
156
|
-
|
|
44
|
+
export default {
|
|
45
|
+
OnairosButton,
|
|
46
|
+
Onairos,
|
|
47
|
+
};
|
|
@@ -1,5 +1,15 @@
|
|
|
1
1
|
import type { OnairosConfig, ApiKeyValidationResult } from '../types';
|
|
2
2
|
|
|
3
|
+
// Admin key for backend validation
|
|
4
|
+
export const ADMIN_API_KEY = 'OnairosIsAUnicorn2025';
|
|
5
|
+
|
|
6
|
+
// API key types
|
|
7
|
+
export enum ApiKeyType {
|
|
8
|
+
DEVELOPER = 'developer',
|
|
9
|
+
ADMIN = 'admin',
|
|
10
|
+
INVALID = 'invalid'
|
|
11
|
+
}
|
|
12
|
+
|
|
3
13
|
/**
|
|
4
14
|
* API Key Service for Onairos React Native SDK
|
|
5
15
|
*
|
|
@@ -12,6 +22,12 @@ import type { OnairosConfig, ApiKeyValidationResult } from '../types';
|
|
|
12
22
|
* 3. Cache validation results for performance
|
|
13
23
|
* 4. Include API key in all authenticated requests
|
|
14
24
|
* 5. Handle API key errors gracefully with developer-friendly messages
|
|
25
|
+
*
|
|
26
|
+
* Backend Integration:
|
|
27
|
+
* - All API requests include: Authorization: Bearer {apiKey}
|
|
28
|
+
* - Backend should validate API keys on each request
|
|
29
|
+
* - Admin key "OnairosIsAUnicorn2025" has full permissions
|
|
30
|
+
* - Developer keys have limited permissions based on validation response
|
|
15
31
|
*/
|
|
16
32
|
|
|
17
33
|
// Global configuration state
|
|
@@ -89,6 +105,33 @@ export const initializeApiKey = async (config: OnairosConfig): Promise<void> =>
|
|
|
89
105
|
}
|
|
90
106
|
};
|
|
91
107
|
|
|
108
|
+
/**
|
|
109
|
+
* Determine API key type
|
|
110
|
+
* @param apiKey The API key to check
|
|
111
|
+
* @returns The type of API key
|
|
112
|
+
*/
|
|
113
|
+
export const getApiKeyType = (apiKey: string): ApiKeyType => {
|
|
114
|
+
if (apiKey === ADMIN_API_KEY) {
|
|
115
|
+
return ApiKeyType.ADMIN;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// Developer keys should be at least 32 characters and start with specific prefix
|
|
119
|
+
if (apiKey.length >= 32 && (apiKey.startsWith('dev_') || apiKey.startsWith('pk_'))) {
|
|
120
|
+
return ApiKeyType.DEVELOPER;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
return ApiKeyType.INVALID;
|
|
124
|
+
};
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* Check if API key is admin key
|
|
128
|
+
* @param apiKey The API key to check
|
|
129
|
+
* @returns True if admin key
|
|
130
|
+
*/
|
|
131
|
+
export const isAdminKey = (apiKey: string): boolean => {
|
|
132
|
+
return apiKey === ADMIN_API_KEY;
|
|
133
|
+
};
|
|
134
|
+
|
|
92
135
|
/**
|
|
93
136
|
* Validate an API key with the Onairos backend
|
|
94
137
|
* @param apiKey The API key to validate
|
|
@@ -98,6 +141,30 @@ export const validateApiKey = async (apiKey: string): Promise<ApiKeyValidationRe
|
|
|
98
141
|
try {
|
|
99
142
|
console.log('๐ Validating API key...');
|
|
100
143
|
|
|
144
|
+
// Check if it's an admin key
|
|
145
|
+
if (isAdminKey(apiKey)) {
|
|
146
|
+
console.log('๐ Admin key detected - granting full permissions');
|
|
147
|
+
return {
|
|
148
|
+
isValid: true,
|
|
149
|
+
permissions: ['*'], // Full permissions for admin
|
|
150
|
+
rateLimits: {
|
|
151
|
+
remaining: 999999,
|
|
152
|
+
resetTime: Date.now() + 24 * 60 * 60 * 1000 // 24 hours
|
|
153
|
+
},
|
|
154
|
+
keyType: ApiKeyType.ADMIN
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
// Check basic format for developer keys
|
|
159
|
+
const keyType = getApiKeyType(apiKey);
|
|
160
|
+
if (keyType === ApiKeyType.INVALID) {
|
|
161
|
+
return {
|
|
162
|
+
isValid: false,
|
|
163
|
+
error: 'Invalid API key format. Developer keys must be at least 32 characters and start with "dev_" or "pk_"',
|
|
164
|
+
keyType: ApiKeyType.INVALID
|
|
165
|
+
};
|
|
166
|
+
}
|
|
167
|
+
|
|
101
168
|
// Check cache first
|
|
102
169
|
const cached = validationCache.get(apiKey);
|
|
103
170
|
if (cached && Date.now() - cached.timestamp < CACHE_DURATION) {
|
|
@@ -122,11 +189,14 @@ export const validateApiKey = async (apiKey: string): Promise<ApiKeyValidationRe
|
|
|
122
189
|
'Content-Type': 'application/json',
|
|
123
190
|
'Authorization': `Bearer ${apiKey}`,
|
|
124
191
|
'User-Agent': 'OnairosReactNative/1.0',
|
|
192
|
+
'X-API-Key-Type': keyType,
|
|
125
193
|
},
|
|
126
194
|
body: JSON.stringify({
|
|
127
195
|
environment,
|
|
128
|
-
sdk_version: '3.0.
|
|
196
|
+
sdk_version: '3.0.72',
|
|
129
197
|
platform: 'react-native',
|
|
198
|
+
keyType,
|
|
199
|
+
timestamp: new Date().toISOString(),
|
|
130
200
|
}),
|
|
131
201
|
signal: controller.signal,
|
|
132
202
|
});
|
|
@@ -140,6 +210,7 @@ export const validateApiKey = async (apiKey: string): Promise<ApiKeyValidationRe
|
|
|
140
210
|
isValid: true,
|
|
141
211
|
permissions: data.permissions || [],
|
|
142
212
|
rateLimits: data.rateLimits || null,
|
|
213
|
+
keyType: keyType,
|
|
143
214
|
};
|
|
144
215
|
|
|
145
216
|
// Cache the successful result
|
|
@@ -159,6 +230,7 @@ export const validateApiKey = async (apiKey: string): Promise<ApiKeyValidationRe
|
|
|
159
230
|
const result: ApiKeyValidationResult = {
|
|
160
231
|
isValid: false,
|
|
161
232
|
error: errorMessage,
|
|
233
|
+
keyType: keyType,
|
|
162
234
|
};
|
|
163
235
|
|
|
164
236
|
// Don't cache failed results
|
|
@@ -168,23 +240,23 @@ export const validateApiKey = async (apiKey: string): Promise<ApiKeyValidationRe
|
|
|
168
240
|
|
|
169
241
|
return result;
|
|
170
242
|
}
|
|
171
|
-
} catch (fetchError) {
|
|
243
|
+
} catch (fetchError: any) {
|
|
172
244
|
clearTimeout(timeoutId);
|
|
173
245
|
|
|
174
246
|
if (fetchError.name === 'AbortError') {
|
|
175
247
|
const errorMessage = 'API key validation timeout';
|
|
176
248
|
console.error('โฑ๏ธ API key validation timeout');
|
|
177
|
-
return { isValid: false, error: errorMessage };
|
|
249
|
+
return { isValid: false, error: errorMessage, keyType: keyType };
|
|
178
250
|
}
|
|
179
251
|
|
|
180
252
|
const errorMessage = `Network error during API key validation: ${fetchError.message}`;
|
|
181
253
|
console.error('๐ Network error during API key validation:', fetchError);
|
|
182
|
-
return { isValid: false, error: errorMessage };
|
|
254
|
+
return { isValid: false, error: errorMessage, keyType: keyType };
|
|
183
255
|
}
|
|
184
|
-
} catch (error) {
|
|
256
|
+
} catch (error: any) {
|
|
185
257
|
const errorMessage = `API key validation error: ${error.message}`;
|
|
186
258
|
console.error('โ API key validation error:', error);
|
|
187
|
-
return { isValid: false, error: errorMessage };
|
|
259
|
+
return { isValid: false, error: errorMessage, keyType: ApiKeyType.INVALID };
|
|
188
260
|
}
|
|
189
261
|
};
|
|
190
262
|
|
|
@@ -221,12 +293,16 @@ export const getAuthHeaders = (): Record<string, string> => {
|
|
|
221
293
|
throw new Error('SDK not initialized. Call initializeApiKey() first.');
|
|
222
294
|
}
|
|
223
295
|
|
|
296
|
+
const keyType = getApiKeyType(globalConfig.apiKey);
|
|
297
|
+
|
|
224
298
|
return {
|
|
225
299
|
'Content-Type': 'application/json',
|
|
226
300
|
'Authorization': `Bearer ${globalConfig.apiKey}`,
|
|
227
|
-
'User-Agent': 'OnairosReactNative/3.0.
|
|
228
|
-
'X-SDK-Version': '3.0.
|
|
301
|
+
'User-Agent': 'OnairosReactNative/3.0.72',
|
|
302
|
+
'X-SDK-Version': '3.0.72',
|
|
229
303
|
'X-SDK-Environment': globalConfig.environment || 'production',
|
|
304
|
+
'X-API-Key-Type': keyType,
|
|
305
|
+
'X-Timestamp': new Date().toISOString(),
|
|
230
306
|
};
|
|
231
307
|
};
|
|
232
308
|
|
|
@@ -3,6 +3,49 @@ import AsyncStorage from '@react-native-async-storage/async-storage';
|
|
|
3
3
|
import type { PlatformAuthConfig } from '../types';
|
|
4
4
|
import { makeAuthenticatedRequest, getApiConfig } from './apiKeyService';
|
|
5
5
|
|
|
6
|
+
// ๐ CRITICAL: Initialize API key service for authentication
|
|
7
|
+
let isApiKeyInitialized = false;
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Initialize the API key service with the admin key for testing
|
|
11
|
+
* This ensures all API requests include proper authentication headers
|
|
12
|
+
*/
|
|
13
|
+
export const initializePlatformAuthService = async (): Promise<void> => {
|
|
14
|
+
if (isApiKeyInitialized) {
|
|
15
|
+
console.log('๐ API key service already initialized');
|
|
16
|
+
return;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
try {
|
|
20
|
+
// Import the initialization function
|
|
21
|
+
const { initializeApiKey, ADMIN_API_KEY } = await import('./apiKeyService');
|
|
22
|
+
|
|
23
|
+
// Initialize with admin key for production email service
|
|
24
|
+
await initializeApiKey({
|
|
25
|
+
apiKey: ADMIN_API_KEY, // 'OnairosIsAUnicorn2025'
|
|
26
|
+
environment: 'production', // Use production for email verification
|
|
27
|
+
enableLogging: true,
|
|
28
|
+
timeout: 30000,
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
isApiKeyInitialized = true;
|
|
32
|
+
console.log('โ
Platform auth service initialized with admin key (production)');
|
|
33
|
+
} catch (error) {
|
|
34
|
+
console.error('โ Failed to initialize platform auth service:', error);
|
|
35
|
+
throw error;
|
|
36
|
+
}
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Ensure API key is initialized before making authenticated requests
|
|
41
|
+
*/
|
|
42
|
+
const ensureApiKeyInitialized = async (): Promise<void> => {
|
|
43
|
+
if (!isApiKeyInitialized) {
|
|
44
|
+
console.log('๐ API key not initialized, initializing now...');
|
|
45
|
+
await initializePlatformAuthService();
|
|
46
|
+
}
|
|
47
|
+
};
|
|
48
|
+
|
|
6
49
|
// Configuration for each platform's authentication
|
|
7
50
|
let PLATFORM_AUTH_CONFIG: Record<string, PlatformAuthConfig> = {
|
|
8
51
|
instagram: {
|
|
@@ -780,6 +823,7 @@ export const requestEmailVerification = async (email: string, testMode = false):
|
|
|
780
823
|
success: boolean;
|
|
781
824
|
message?: string;
|
|
782
825
|
error?: string;
|
|
826
|
+
requestId?: string;
|
|
783
827
|
}> => {
|
|
784
828
|
try {
|
|
785
829
|
console.log('๐ง Requesting email verification for:', email);
|
|
@@ -792,17 +836,27 @@ export const requestEmailVerification = async (email: string, testMode = false):
|
|
|
792
836
|
};
|
|
793
837
|
}
|
|
794
838
|
|
|
795
|
-
// In test mode, always return success
|
|
839
|
+
// In test mode, always return success with mock request ID
|
|
796
840
|
if (testMode) {
|
|
797
|
-
console.log('๐งช Test mode: Always returning success');
|
|
841
|
+
console.log('๐งช Test mode: Always returning success with mock request ID');
|
|
842
|
+
const mockRequestId = 'test-request-' + Date.now();
|
|
843
|
+
|
|
844
|
+
// Store request info for tracking
|
|
845
|
+
await AsyncStorage.setItem('email_verification_request_id', mockRequestId);
|
|
846
|
+
await AsyncStorage.setItem('email_verification_request_email', email);
|
|
847
|
+
|
|
798
848
|
return {
|
|
799
849
|
success: true,
|
|
800
850
|
message: 'Email verification sent successfully (test mode)',
|
|
851
|
+
requestId: mockRequestId,
|
|
801
852
|
};
|
|
802
853
|
}
|
|
803
854
|
|
|
804
855
|
// Production mode: Make real API call with API key authentication
|
|
805
856
|
try {
|
|
857
|
+
// ๐ Ensure API key is initialized before making authenticated requests
|
|
858
|
+
await ensureApiKeyInitialized();
|
|
859
|
+
|
|
806
860
|
const response = await makeAuthenticatedRequest('/email/verification', {
|
|
807
861
|
method: 'POST',
|
|
808
862
|
body: JSON.stringify({
|
|
@@ -816,9 +870,16 @@ export const requestEmailVerification = async (email: string, testMode = false):
|
|
|
816
870
|
|
|
817
871
|
if (response.ok && result.success) {
|
|
818
872
|
console.log('โ
Email verification request sent');
|
|
873
|
+
|
|
874
|
+
// Store request info for tracking
|
|
875
|
+
const requestId = result.requestId || result.id || ('req-' + Date.now());
|
|
876
|
+
await AsyncStorage.setItem('email_verification_request_id', requestId);
|
|
877
|
+
await AsyncStorage.setItem('email_verification_request_email', email);
|
|
878
|
+
|
|
819
879
|
return {
|
|
820
880
|
success: true,
|
|
821
881
|
message: result.message || 'Email verification sent successfully',
|
|
882
|
+
requestId: requestId,
|
|
822
883
|
};
|
|
823
884
|
} else {
|
|
824
885
|
console.error('โ Email verification request failed:', result.error);
|
|
@@ -848,6 +909,7 @@ export const verifyEmailCode = async (email: string, code: string, testMode = fa
|
|
|
848
909
|
message?: string;
|
|
849
910
|
error?: string;
|
|
850
911
|
existingUser?: boolean;
|
|
912
|
+
jwtToken?: string;
|
|
851
913
|
}> => {
|
|
852
914
|
try {
|
|
853
915
|
console.log('๐ Verifying email code for:', email);
|
|
@@ -868,18 +930,29 @@ export const verifyEmailCode = async (email: string, code: string, testMode = fa
|
|
|
868
930
|
};
|
|
869
931
|
}
|
|
870
932
|
|
|
871
|
-
// In test mode, always return success
|
|
933
|
+
// In test mode, always return success with mock JWT token
|
|
872
934
|
if (testMode) {
|
|
873
|
-
console.log('๐งช Test mode: Always returning success');
|
|
935
|
+
console.log('๐งช Test mode: Always returning success with mock JWT token');
|
|
936
|
+
const mockToken = 'test-jwt-token-' + Date.now();
|
|
937
|
+
|
|
938
|
+
// Store mock token for API requests
|
|
939
|
+
await AsyncStorage.setItem('email_verification_token', mockToken);
|
|
940
|
+
await AsyncStorage.setItem('onairos_jwt_token', mockToken);
|
|
941
|
+
await AsyncStorage.setItem('email_verification_email', email);
|
|
942
|
+
|
|
874
943
|
return {
|
|
875
944
|
success: true,
|
|
876
945
|
message: 'Email verification successful (test mode)',
|
|
877
946
|
existingUser: false,
|
|
947
|
+
jwtToken: mockToken,
|
|
878
948
|
};
|
|
879
949
|
}
|
|
880
950
|
|
|
881
951
|
// Production mode: Make real API call with API key authentication
|
|
882
952
|
try {
|
|
953
|
+
// ๐ Ensure API key is initialized before making authenticated requests
|
|
954
|
+
await ensureApiKeyInitialized();
|
|
955
|
+
|
|
883
956
|
const response = await makeAuthenticatedRequest('/email/verification', {
|
|
884
957
|
method: 'POST',
|
|
885
958
|
body: JSON.stringify({
|
|
@@ -894,10 +967,27 @@ export const verifyEmailCode = async (email: string, code: string, testMode = fa
|
|
|
894
967
|
|
|
895
968
|
if (response.ok && result.success) {
|
|
896
969
|
console.log('โ
Email verification successful');
|
|
970
|
+
|
|
971
|
+
// ๐ซ CRITICAL: Store JWT token from email verification response
|
|
972
|
+
const jwtToken = result.token || result.jwtToken || result.jwt || result.authToken;
|
|
973
|
+
|
|
974
|
+
if (jwtToken) {
|
|
975
|
+
console.log('๐ซ Storing JWT token from email verification response');
|
|
976
|
+
await AsyncStorage.setItem('email_verification_token', jwtToken);
|
|
977
|
+
await AsyncStorage.setItem('onairos_jwt_token', jwtToken);
|
|
978
|
+
await AsyncStorage.setItem('enoch_token', jwtToken);
|
|
979
|
+
await AsyncStorage.setItem('auth_token', jwtToken);
|
|
980
|
+
await AsyncStorage.setItem('email_verification_email', email);
|
|
981
|
+
await AsyncStorage.setItem('token_timestamp', Date.now().toString());
|
|
982
|
+
} else {
|
|
983
|
+
console.warn('โ ๏ธ No JWT token received from email verification API');
|
|
984
|
+
}
|
|
985
|
+
|
|
897
986
|
return {
|
|
898
987
|
success: true,
|
|
899
988
|
message: result.message || 'Email verification successful',
|
|
900
989
|
existingUser: result.existingUser || false,
|
|
990
|
+
jwtToken: jwtToken,
|
|
901
991
|
};
|
|
902
992
|
} else {
|
|
903
993
|
console.error('โ Email verification failed:', result.error);
|
|
@@ -944,6 +1034,9 @@ export const checkEmailVerificationStatus = async (email: string, testMode = fal
|
|
|
944
1034
|
|
|
945
1035
|
// Production mode: Make real API call with API key authentication
|
|
946
1036
|
try {
|
|
1037
|
+
// ๐ Ensure API key is initialized before making authenticated requests
|
|
1038
|
+
await ensureApiKeyInitialized();
|
|
1039
|
+
|
|
947
1040
|
const response = await makeAuthenticatedRequest(`/email/verify/status/${encodeURIComponent(email)}`, {
|
|
948
1041
|
method: 'GET',
|
|
949
1042
|
});
|
|
@@ -1033,3 +1126,166 @@ export const disconnectPlatform = async (platform: string, username: string): Pr
|
|
|
1033
1126
|
};
|
|
1034
1127
|
}
|
|
1035
1128
|
};
|
|
1129
|
+
|
|
1130
|
+
/**
|
|
1131
|
+
* ๐ STORE PIN AFTER BIOMETRIC AUTHENTICATION
|
|
1132
|
+
* Send PIN separately to /store-pin/web endpoint after biometric Face ID verification
|
|
1133
|
+
*/
|
|
1134
|
+
export const storePinAfterBiometric = async (username: string, pin: string, jwtToken?: string): Promise<{
|
|
1135
|
+
success: boolean;
|
|
1136
|
+
message?: string;
|
|
1137
|
+
error?: string;
|
|
1138
|
+
}> => {
|
|
1139
|
+
try {
|
|
1140
|
+
console.log('๐ Storing PIN after biometric authentication for user:', username);
|
|
1141
|
+
console.log('๐ PIN length:', pin.length);
|
|
1142
|
+
console.log('๐ซ JWT token provided:', !!jwtToken);
|
|
1143
|
+
|
|
1144
|
+
if (!username || !pin) {
|
|
1145
|
+
return {
|
|
1146
|
+
success: false,
|
|
1147
|
+
error: 'Username and PIN are required',
|
|
1148
|
+
};
|
|
1149
|
+
}
|
|
1150
|
+
|
|
1151
|
+
if (pin.length < 4) {
|
|
1152
|
+
return {
|
|
1153
|
+
success: false,
|
|
1154
|
+
error: 'PIN must be at least 4 digits',
|
|
1155
|
+
};
|
|
1156
|
+
}
|
|
1157
|
+
|
|
1158
|
+
// Get JWT token from storage if not provided
|
|
1159
|
+
let authToken = jwtToken;
|
|
1160
|
+
if (!authToken) {
|
|
1161
|
+
authToken = await AsyncStorage.getItem('onairos_jwt_token') ||
|
|
1162
|
+
await AsyncStorage.getItem('enoch_token') ||
|
|
1163
|
+
await AsyncStorage.getItem('auth_token') ||
|
|
1164
|
+
await AsyncStorage.getItem('email_verification_token');
|
|
1165
|
+
}
|
|
1166
|
+
|
|
1167
|
+
if (!authToken) {
|
|
1168
|
+
console.warn('โ ๏ธ No JWT token available for PIN storage');
|
|
1169
|
+
return {
|
|
1170
|
+
success: false,
|
|
1171
|
+
error: 'No authentication token available',
|
|
1172
|
+
};
|
|
1173
|
+
}
|
|
1174
|
+
|
|
1175
|
+
console.log('๐ค Sending PIN to /store-pin/web endpoint');
|
|
1176
|
+
|
|
1177
|
+
// Make authenticated request to store PIN
|
|
1178
|
+
const response = await makeAuthenticatedRequest('/store-pin/web', {
|
|
1179
|
+
method: 'POST',
|
|
1180
|
+
headers: {
|
|
1181
|
+
'Authorization': `Bearer ${authToken}`,
|
|
1182
|
+
},
|
|
1183
|
+
body: JSON.stringify({
|
|
1184
|
+
username,
|
|
1185
|
+
pin,
|
|
1186
|
+
}),
|
|
1187
|
+
});
|
|
1188
|
+
|
|
1189
|
+
console.log('๐ก PIN storage response status:', response.status);
|
|
1190
|
+
|
|
1191
|
+
if (!response.ok) {
|
|
1192
|
+
const errorText = await response.text();
|
|
1193
|
+
console.error('โ PIN storage failed:', errorText);
|
|
1194
|
+
return {
|
|
1195
|
+
success: false,
|
|
1196
|
+
error: `PIN storage failed: ${response.status} - ${errorText}`,
|
|
1197
|
+
};
|
|
1198
|
+
}
|
|
1199
|
+
|
|
1200
|
+
const result = await response.json();
|
|
1201
|
+
console.log('๐ฅ PIN storage response:', result);
|
|
1202
|
+
|
|
1203
|
+
if (result.success) {
|
|
1204
|
+
console.log('โ
PIN stored successfully after biometric authentication');
|
|
1205
|
+
|
|
1206
|
+
// Store PIN locally for future use
|
|
1207
|
+
await AsyncStorage.setItem('user_pin_stored', 'true');
|
|
1208
|
+
await AsyncStorage.setItem('pin_storage_timestamp', Date.now().toString());
|
|
1209
|
+
|
|
1210
|
+
return {
|
|
1211
|
+
success: true,
|
|
1212
|
+
message: result.message || 'PIN stored successfully',
|
|
1213
|
+
};
|
|
1214
|
+
} else {
|
|
1215
|
+
console.error('โ PIN storage API returned error:', result.error);
|
|
1216
|
+
return {
|
|
1217
|
+
success: false,
|
|
1218
|
+
error: result.error || 'PIN storage failed',
|
|
1219
|
+
};
|
|
1220
|
+
}
|
|
1221
|
+
} catch (error) {
|
|
1222
|
+
console.error('โ Error storing PIN after biometric authentication:', error);
|
|
1223
|
+
return {
|
|
1224
|
+
success: false,
|
|
1225
|
+
error: error instanceof Error ? error.message : 'PIN storage failed',
|
|
1226
|
+
};
|
|
1227
|
+
}
|
|
1228
|
+
};
|
|
1229
|
+
|
|
1230
|
+
/**
|
|
1231
|
+
* ๐ซ GET STORED JWT TOKEN
|
|
1232
|
+
* Helper function to retrieve stored JWT token from email verification or other sources
|
|
1233
|
+
*/
|
|
1234
|
+
export const getStoredJwtToken = async (): Promise<string | null> => {
|
|
1235
|
+
try {
|
|
1236
|
+
console.log('๐ซ Retrieving stored JWT token...');
|
|
1237
|
+
|
|
1238
|
+
// Try different storage keys in order of preference
|
|
1239
|
+
const tokenSources = [
|
|
1240
|
+
'email_verification_token',
|
|
1241
|
+
'onairos_jwt_token',
|
|
1242
|
+
'enoch_token',
|
|
1243
|
+
'auth_token',
|
|
1244
|
+
];
|
|
1245
|
+
|
|
1246
|
+
for (const source of tokenSources) {
|
|
1247
|
+
const token = await AsyncStorage.getItem(source);
|
|
1248
|
+
if (token && token.length > 20) {
|
|
1249
|
+
console.log(`โ
JWT token found in ${source}:`, token.substring(0, 20) + '...');
|
|
1250
|
+
return token;
|
|
1251
|
+
}
|
|
1252
|
+
}
|
|
1253
|
+
|
|
1254
|
+
console.warn('โ ๏ธ No JWT token found in storage');
|
|
1255
|
+
return null;
|
|
1256
|
+
} catch (error) {
|
|
1257
|
+
console.error('โ Error retrieving JWT token:', error);
|
|
1258
|
+
return null;
|
|
1259
|
+
}
|
|
1260
|
+
};
|
|
1261
|
+
|
|
1262
|
+
/**
|
|
1263
|
+
* ๐ซ CLEAR STORED TOKENS
|
|
1264
|
+
* Helper function to clear all stored tokens (useful for logout)
|
|
1265
|
+
*/
|
|
1266
|
+
export const clearStoredTokens = async (): Promise<void> => {
|
|
1267
|
+
try {
|
|
1268
|
+
console.log('๐งน Clearing all stored tokens...');
|
|
1269
|
+
|
|
1270
|
+
const tokenKeys = [
|
|
1271
|
+
'email_verification_token',
|
|
1272
|
+
'onairos_jwt_token',
|
|
1273
|
+
'enoch_token',
|
|
1274
|
+
'auth_token',
|
|
1275
|
+
'email_verification_email',
|
|
1276
|
+
'email_verification_request_id',
|
|
1277
|
+
'email_verification_request_email',
|
|
1278
|
+
'token_timestamp',
|
|
1279
|
+
'user_pin_stored',
|
|
1280
|
+
'pin_storage_timestamp',
|
|
1281
|
+
];
|
|
1282
|
+
|
|
1283
|
+
await Promise.all(
|
|
1284
|
+
tokenKeys.map(key => AsyncStorage.removeItem(key))
|
|
1285
|
+
);
|
|
1286
|
+
|
|
1287
|
+
console.log('โ
All tokens cleared successfully');
|
|
1288
|
+
} catch (error) {
|
|
1289
|
+
console.error('โ Error clearing tokens:', error);
|
|
1290
|
+
}
|
|
1291
|
+
};
|