@onairos/react-native 3.0.75 → 3.1.0
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/EmailVerificationModal.js +7 -5
- package/lib/commonjs/components/EmailVerificationModal.js.map +1 -1
- package/lib/commonjs/index.js +0 -6
- package/lib/commonjs/index.js.map +1 -1
- package/lib/commonjs/services/apiKeyService.js +278 -27
- package/lib/commonjs/services/apiKeyService.js.map +1 -1
- package/lib/commonjs/services/platformAuthService.js +123 -301
- package/lib/commonjs/services/platformAuthService.js.map +1 -1
- package/lib/commonjs/utils/onairosApi.js +143 -71
- package/lib/commonjs/utils/onairosApi.js.map +1 -1
- package/lib/commonjs/utils/secureStorage.js +123 -1
- package/lib/commonjs/utils/secureStorage.js.map +1 -1
- package/lib/module/components/EmailVerificationModal.js +7 -5
- package/lib/module/components/EmailVerificationModal.js.map +1 -1
- package/lib/module/index.js +3 -1
- package/lib/module/index.js.map +1 -1
- package/lib/module/services/apiKeyService.js +264 -22
- package/lib/module/services/apiKeyService.js.map +1 -1
- package/lib/module/services/platformAuthService.js +120 -297
- package/lib/module/services/platformAuthService.js.map +1 -1
- package/lib/module/utils/onairosApi.js +139 -70
- package/lib/module/utils/onairosApi.js.map +1 -1
- package/lib/module/utils/secureStorage.js +116 -0
- package/lib/module/utils/secureStorage.js.map +1 -1
- package/lib/typescript/components/EmailVerificationModal.d.ts.map +1 -1
- package/lib/typescript/index.d.ts +1 -1
- package/lib/typescript/index.d.ts.map +1 -1
- package/lib/typescript/services/apiKeyService.d.ts +50 -2
- package/lib/typescript/services/apiKeyService.d.ts.map +1 -1
- package/lib/typescript/services/platformAuthService.d.ts +29 -14
- package/lib/typescript/services/platformAuthService.d.ts.map +1 -1
- package/lib/typescript/utils/onairosApi.d.ts +24 -10
- package/lib/typescript/utils/onairosApi.d.ts.map +1 -1
- package/lib/typescript/utils/secureStorage.d.ts +31 -0
- package/lib/typescript/utils/secureStorage.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/components/EmailVerificationModal.tsx +9 -5
- package/src/index.ts +1 -1
- package/src/services/apiKeyService.ts +282 -18
- package/src/services/platformAuthService.ts +211 -424
- package/src/types/index.d.ts +6 -5
- package/src/utils/onairosApi.ts +151 -74
- package/src/utils/secureStorage.ts +122 -0
|
@@ -1,68 +1,36 @@
|
|
|
1
1
|
import { Platform, Linking } from 'react-native';
|
|
2
2
|
import AsyncStorage from '@react-native-async-storage/async-storage';
|
|
3
3
|
import type { PlatformAuthConfig } from '../types';
|
|
4
|
-
import {
|
|
4
|
+
import { makeDeveloperRequest, getApiConfig, storeJWT } from './apiKeyService';
|
|
5
5
|
|
|
6
|
-
// 🔑 CRITICAL:
|
|
7
|
-
|
|
6
|
+
// 🔑 CRITICAL: Use two-tier authentication system
|
|
7
|
+
// - Developer API key for email verification requests
|
|
8
|
+
// - JWT tokens for user-authenticated requests after email verification
|
|
8
9
|
|
|
9
10
|
/**
|
|
10
|
-
* Initialize the
|
|
11
|
-
* This
|
|
11
|
+
* Initialize the platform auth service
|
|
12
|
+
* This service now uses the two-tier authentication system
|
|
12
13
|
*/
|
|
13
14
|
export const initializePlatformAuthService = async (): Promise<void> => {
|
|
14
|
-
if (isApiKeyInitialized) {
|
|
15
|
-
console.log('🔑 API key service already initialized');
|
|
16
|
-
return;
|
|
17
|
-
}
|
|
18
|
-
|
|
19
15
|
try {
|
|
20
|
-
//
|
|
21
|
-
const { initializeApiKey, ADMIN_API_KEY, getApiConfig } = await import('./apiKeyService');
|
|
22
|
-
|
|
23
|
-
// Check if there's already an app initialization
|
|
16
|
+
// Check if app is already initialized with API key
|
|
24
17
|
const existingConfig = getApiConfig();
|
|
25
18
|
|
|
26
19
|
if (existingConfig && existingConfig.apiKey) {
|
|
27
|
-
console.log('🔑
|
|
28
|
-
|
|
29
|
-
isApiKeyInitialized = true;
|
|
30
|
-
console.log(`✅ Platform auth service using existing app configuration (${existingConfig.environment})`);
|
|
20
|
+
console.log('🔑 Platform auth service using existing app configuration');
|
|
21
|
+
console.log(`✅ Environment: ${existingConfig.environment}`);
|
|
31
22
|
return;
|
|
32
23
|
}
|
|
33
24
|
|
|
34
|
-
//
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
console.log('🔑 No app initialization found, initializing platform auth service with admin key');
|
|
38
|
-
console.log('🔑 Environment:', environment);
|
|
39
|
-
|
|
40
|
-
// Initialize with admin key as fallback
|
|
41
|
-
await initializeApiKey({
|
|
42
|
-
apiKey: ADMIN_API_KEY, // 'OnairosIsAUnicorn2025'
|
|
43
|
-
environment: environment,
|
|
44
|
-
enableLogging: true,
|
|
45
|
-
timeout: 30000,
|
|
46
|
-
});
|
|
47
|
-
|
|
48
|
-
isApiKeyInitialized = true;
|
|
49
|
-
console.log(`✅ Platform auth service initialized with admin key (${environment})`);
|
|
25
|
+
// If no app initialization, we can't proceed
|
|
26
|
+
console.error('❌ Platform auth service requires app-level API key initialization');
|
|
27
|
+
throw new Error('Platform auth service requires app-level API key initialization. Please call initializeApiKey() first.');
|
|
50
28
|
} catch (error) {
|
|
51
29
|
console.error('❌ Failed to initialize platform auth service:', error);
|
|
52
30
|
throw error;
|
|
53
31
|
}
|
|
54
32
|
};
|
|
55
33
|
|
|
56
|
-
/**
|
|
57
|
-
* Ensure API key is initialized before making authenticated requests
|
|
58
|
-
*/
|
|
59
|
-
const ensureApiKeyInitialized = async (): Promise<void> => {
|
|
60
|
-
if (!isApiKeyInitialized) {
|
|
61
|
-
console.log('🔑 API key not initialized, initializing now...');
|
|
62
|
-
await initializePlatformAuthService();
|
|
63
|
-
}
|
|
64
|
-
};
|
|
65
|
-
|
|
66
34
|
// Configuration for each platform's authentication
|
|
67
35
|
let PLATFORM_AUTH_CONFIG: Record<string, PlatformAuthConfig> = {
|
|
68
36
|
instagram: {
|
|
@@ -173,7 +141,7 @@ export const initiateOAuth = async (platform: string, username: string, appName?
|
|
|
173
141
|
|
|
174
142
|
console.log('📤 Sending Instagram OAuth request:', jsonData);
|
|
175
143
|
|
|
176
|
-
const response = await
|
|
144
|
+
const response = await makeDeveloperRequest(PLATFORM_AUTH_CONFIG[platform].authEndpoint, {
|
|
177
145
|
method: 'POST',
|
|
178
146
|
body: JSON.stringify(jsonData),
|
|
179
147
|
});
|
|
@@ -216,7 +184,7 @@ export const initiateOAuth = async (platform: string, username: string, appName?
|
|
|
216
184
|
console.log(`📤 Sending ${platform} OAuth request:`, jsonData);
|
|
217
185
|
|
|
218
186
|
// Make the authenticated request to get the OAuth URL
|
|
219
|
-
const response = await
|
|
187
|
+
const response = await makeDeveloperRequest(PLATFORM_AUTH_CONFIG[platform].authEndpoint, {
|
|
220
188
|
method: 'POST',
|
|
221
189
|
body: JSON.stringify(jsonData),
|
|
222
190
|
});
|
|
@@ -348,68 +316,68 @@ const validateOAuthUrl = async (url: string): Promise<boolean> => {
|
|
|
348
316
|
* @returns A Promise that resolves to the authentication result
|
|
349
317
|
*/
|
|
350
318
|
export const initiateNativeAuth = async (platform: string, username?: string): Promise<boolean> => {
|
|
351
|
-
|
|
319
|
+
if (platform === 'youtube') {
|
|
352
320
|
console.log('🔗 Initiating native Google Sign-In for YouTube');
|
|
321
|
+
try {
|
|
322
|
+
// Check if Google Sign-In package is available
|
|
323
|
+
let GoogleSignin, statusCodes;
|
|
353
324
|
try {
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
325
|
+
const googleSignInModule = require('@react-native-google-signin/google-signin');
|
|
326
|
+
GoogleSignin = googleSignInModule.GoogleSignin;
|
|
327
|
+
statusCodes = googleSignInModule.statusCodes;
|
|
328
|
+
} catch (importError) {
|
|
329
|
+
console.error('❌ Google Sign-In package not available:', importError);
|
|
330
|
+
throw new Error('Google Sign-In SDK not installed. Please install @react-native-google-signin/google-signin');
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
// Configure Google Sign-In with better error handling
|
|
334
|
+
try {
|
|
335
|
+
await GoogleSignin.configure({
|
|
336
|
+
webClientId: '1030678346906-lovkuds2ouqmoc8eu5qpo98spa6edv4o.apps.googleusercontent.com',
|
|
337
|
+
iosClientId: '1030678346906-lovkuds2ouqmoc8eu5qpo98spa6edv4o.apps.googleusercontent.com',
|
|
338
|
+
scopes: ['https://www.googleapis.com/auth/youtube.readonly'],
|
|
339
|
+
offlineAccess: true,
|
|
340
|
+
hostedDomain: '',
|
|
341
|
+
forceCodeForRefreshToken: true,
|
|
342
|
+
accountName: '',
|
|
343
|
+
});
|
|
344
|
+
console.log('✅ Google Sign-In configured successfully');
|
|
345
|
+
} catch (configError) {
|
|
346
|
+
console.error('❌ Google Sign-In configuration failed:', configError);
|
|
347
|
+
throw new Error(`Google Sign-In configuration failed: ${configError.message || configError}`);
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
// Check if Google Play Services are available (Android only)
|
|
351
|
+
try {
|
|
352
|
+
await GoogleSignin.hasPlayServices({ showPlayServicesUpdateDialog: true });
|
|
353
|
+
console.log('✅ Google Play Services available');
|
|
354
|
+
} catch (playServicesError) {
|
|
355
|
+
console.error('❌ Google Play Services error:', playServicesError);
|
|
356
|
+
throw new Error(`Google Play Services not available: ${playServicesError.message || playServicesError}`);
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
// Sign in with Google
|
|
360
|
+
let userInfo;
|
|
361
|
+
try {
|
|
362
|
+
userInfo = await GoogleSignin.signIn();
|
|
363
|
+
console.log('✅ Google Sign-In successful:', userInfo.user?.email);
|
|
364
|
+
} catch (signInError) {
|
|
365
|
+
console.error('❌ Google Sign-In failed:', signInError);
|
|
390
366
|
|
|
391
|
-
//
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
}
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
if (signInError.code === statusCodes.SIGN_IN_CANCELLED) {
|
|
401
|
-
throw new Error('Google Sign-In was cancelled by user');
|
|
402
|
-
} else if (signInError.code === statusCodes.IN_PROGRESS) {
|
|
403
|
-
throw new Error('Google Sign-In already in progress');
|
|
404
|
-
} else if (signInError.code === statusCodes.PLAY_SERVICES_NOT_AVAILABLE) {
|
|
405
|
-
throw new Error('Google Play Services not available or outdated');
|
|
406
|
-
} else {
|
|
407
|
-
throw new Error(`Google Sign-In failed: ${signInError.message || signInError}`);
|
|
408
|
-
}
|
|
367
|
+
// Handle specific error codes
|
|
368
|
+
if (signInError.code === statusCodes.SIGN_IN_CANCELLED) {
|
|
369
|
+
throw new Error('Google Sign-In was cancelled by user');
|
|
370
|
+
} else if (signInError.code === statusCodes.IN_PROGRESS) {
|
|
371
|
+
throw new Error('Google Sign-In already in progress');
|
|
372
|
+
} else if (signInError.code === statusCodes.PLAY_SERVICES_NOT_AVAILABLE) {
|
|
373
|
+
throw new Error('Google Play Services not available or outdated');
|
|
374
|
+
} else {
|
|
375
|
+
throw new Error(`Google Sign-In failed: ${signInError.message || signInError}`);
|
|
409
376
|
}
|
|
410
|
-
|
|
377
|
+
}
|
|
378
|
+
|
|
411
379
|
// Get access token for API calls
|
|
412
|
-
|
|
380
|
+
const tokens = await GoogleSignin.getTokens();
|
|
413
381
|
console.log('🔑 Got Google tokens');
|
|
414
382
|
|
|
415
383
|
// Get current user info with refresh token
|
|
@@ -549,22 +517,22 @@ export const initiateNativeAuth = async (platform: string, username?: string): P
|
|
|
549
517
|
return false;
|
|
550
518
|
}
|
|
551
519
|
|
|
552
|
-
|
|
520
|
+
} catch (error: any) {
|
|
553
521
|
console.error('❌ Google Sign-In error:', error);
|
|
554
522
|
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
523
|
+
const { statusCodes: StatusCodes } = require('@react-native-google-signin/google-signin');
|
|
524
|
+
|
|
525
|
+
if (error.code === StatusCodes.SIGN_IN_CANCELLED) {
|
|
558
526
|
console.log('User cancelled Google Sign-In');
|
|
559
|
-
|
|
527
|
+
} else if (error.code === StatusCodes.IN_PROGRESS) {
|
|
560
528
|
console.log('Google Sign-In already in progress');
|
|
561
|
-
|
|
529
|
+
} else if (error.code === StatusCodes.PLAY_SERVICES_NOT_AVAILABLE) {
|
|
562
530
|
console.log('Google Play Services not available');
|
|
563
|
-
}
|
|
564
|
-
|
|
565
|
-
return false;
|
|
566
531
|
}
|
|
532
|
+
|
|
533
|
+
return false;
|
|
567
534
|
}
|
|
535
|
+
}
|
|
568
536
|
|
|
569
537
|
return false;
|
|
570
538
|
};
|
|
@@ -833,413 +801,232 @@ export const updateGoogleClientIds = (config: {
|
|
|
833
801
|
};
|
|
834
802
|
|
|
835
803
|
/**
|
|
836
|
-
*
|
|
837
|
-
*
|
|
804
|
+
* Request email verification using developer API key
|
|
805
|
+
* @param email Email address to verify
|
|
806
|
+
* @param testMode Whether to use test mode
|
|
807
|
+
* @returns Promise with verification result
|
|
838
808
|
*/
|
|
839
|
-
export const requestEmailVerification = async (
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
requestId?: string;
|
|
844
|
-
}> => {
|
|
809
|
+
export const requestEmailVerification = async (
|
|
810
|
+
email: string,
|
|
811
|
+
testMode: boolean = false
|
|
812
|
+
): Promise<{ success: boolean; message?: string; error?: string }> => {
|
|
845
813
|
try {
|
|
846
814
|
console.log('📧 Requesting email verification for:', email);
|
|
847
|
-
console.log('🧪 Test mode:', testMode);
|
|
848
|
-
|
|
849
|
-
if (!email || !email.includes('@')) {
|
|
850
|
-
return {
|
|
851
|
-
success: false,
|
|
852
|
-
error: 'Valid email address is required',
|
|
853
|
-
};
|
|
854
|
-
}
|
|
855
815
|
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
816
|
+
const response = await makeDeveloperRequest('/email/verification', {
|
|
817
|
+
method: 'POST',
|
|
818
|
+
body: JSON.stringify({
|
|
819
|
+
email,
|
|
820
|
+
action: 'request',
|
|
821
|
+
testMode
|
|
822
|
+
})
|
|
823
|
+
});
|
|
824
|
+
|
|
825
|
+
const data = await response.json();
|
|
826
|
+
|
|
827
|
+
if (response.ok && data.success) {
|
|
828
|
+
console.log('✅ Email verification requested successfully');
|
|
865
829
|
return {
|
|
866
830
|
success: true,
|
|
867
|
-
message: '
|
|
868
|
-
requestId: mockRequestId,
|
|
831
|
+
message: data.message || 'Verification code sent to your email'
|
|
869
832
|
};
|
|
870
|
-
}
|
|
871
|
-
|
|
872
|
-
// Production mode: Make real API call with API key authentication
|
|
873
|
-
try {
|
|
874
|
-
// 🔑 Ensure API key is initialized before making authenticated requests
|
|
875
|
-
await ensureApiKeyInitialized();
|
|
876
|
-
|
|
877
|
-
const response = await makeAuthenticatedRequest('/email/verification', {
|
|
878
|
-
method: 'POST',
|
|
879
|
-
body: JSON.stringify({
|
|
880
|
-
email,
|
|
881
|
-
action: 'request',
|
|
882
|
-
}),
|
|
883
|
-
});
|
|
884
|
-
|
|
885
|
-
const result = await response.json();
|
|
886
|
-
console.log('📡 Email verification API response:', result);
|
|
887
|
-
|
|
888
|
-
if (response.ok && result.success) {
|
|
889
|
-
console.log('✅ Email verification request sent');
|
|
890
|
-
|
|
891
|
-
// Store request info for tracking
|
|
892
|
-
const requestId = result.requestId || result.id || ('req-' + Date.now());
|
|
893
|
-
await AsyncStorage.setItem('email_verification_request_id', requestId);
|
|
894
|
-
await AsyncStorage.setItem('email_verification_request_email', email);
|
|
895
|
-
|
|
896
|
-
return {
|
|
897
|
-
success: true,
|
|
898
|
-
message: result.message || 'Email verification sent successfully',
|
|
899
|
-
requestId: requestId,
|
|
900
|
-
};
|
|
901
|
-
} else {
|
|
902
|
-
console.error('❌ Email verification request failed:', result.error);
|
|
903
|
-
return {
|
|
904
|
-
success: false,
|
|
905
|
-
error: result.error || 'Failed to send verification email',
|
|
906
|
-
};
|
|
907
|
-
}
|
|
908
|
-
} catch (apiError) {
|
|
909
|
-
console.error('❌ Email verification API call failed:', apiError);
|
|
833
|
+
} else {
|
|
834
|
+
console.error('❌ Email verification request failed:', data.error);
|
|
910
835
|
return {
|
|
911
836
|
success: false,
|
|
912
|
-
error: '
|
|
837
|
+
error: data.error || 'Failed to send verification code'
|
|
913
838
|
};
|
|
914
839
|
}
|
|
915
840
|
} catch (error) {
|
|
916
|
-
console.error('❌
|
|
841
|
+
console.error('❌ Error requesting email verification:', error);
|
|
917
842
|
return {
|
|
918
843
|
success: false,
|
|
919
|
-
error: error instanceof Error ? error.message : '
|
|
844
|
+
error: error instanceof Error ? error.message : 'Network error'
|
|
920
845
|
};
|
|
921
846
|
}
|
|
922
847
|
};
|
|
923
848
|
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
849
|
+
/**
|
|
850
|
+
* Verify email code and store JWT token
|
|
851
|
+
* @param email Email address
|
|
852
|
+
* @param code Verification code
|
|
853
|
+
* @param testMode Whether to use test mode
|
|
854
|
+
* @returns Promise with verification result and JWT token
|
|
855
|
+
*/
|
|
856
|
+
export const verifyEmailCode = async (
|
|
857
|
+
email: string,
|
|
858
|
+
code: string,
|
|
859
|
+
testMode: boolean = false
|
|
860
|
+
): Promise<{ success: boolean; message?: string; error?: string; existingUser?: boolean; token?: string }> => {
|
|
931
861
|
try {
|
|
932
862
|
console.log('🔍 Verifying email code for:', email);
|
|
933
|
-
console.log('🔑 Code length:', code.length);
|
|
934
|
-
console.log('🧪 Test mode:', testMode);
|
|
935
|
-
|
|
936
|
-
if (!email || !email.includes('@')) {
|
|
937
|
-
return {
|
|
938
|
-
success: false,
|
|
939
|
-
error: 'Valid email address is required',
|
|
940
|
-
};
|
|
941
|
-
}
|
|
942
863
|
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
864
|
+
const response = await makeDeveloperRequest('/email/verification', {
|
|
865
|
+
method: 'POST',
|
|
866
|
+
body: JSON.stringify({
|
|
867
|
+
email,
|
|
868
|
+
action: 'verify',
|
|
869
|
+
code,
|
|
870
|
+
testMode
|
|
871
|
+
})
|
|
872
|
+
});
|
|
873
|
+
|
|
874
|
+
const data = await response.json();
|
|
875
|
+
|
|
876
|
+
if (response.ok && data.success) {
|
|
877
|
+
console.log('✅ Email verification successful');
|
|
954
878
|
|
|
955
|
-
// Store
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
879
|
+
// Store JWT token if received
|
|
880
|
+
if (data.token || data.jwtToken) {
|
|
881
|
+
const jwtToken = data.token || data.jwtToken;
|
|
882
|
+
await storeJWT(jwtToken);
|
|
883
|
+
console.log('🎫 JWT token stored successfully');
|
|
884
|
+
}
|
|
959
885
|
|
|
960
886
|
return {
|
|
961
887
|
success: true,
|
|
962
|
-
message: 'Email
|
|
963
|
-
existingUser: false,
|
|
964
|
-
|
|
888
|
+
message: data.message || 'Email verified successfully',
|
|
889
|
+
existingUser: data.existingUser || false,
|
|
890
|
+
token: data.token || data.jwtToken
|
|
965
891
|
};
|
|
966
|
-
}
|
|
967
|
-
|
|
968
|
-
// Production mode: Make real API call with API key authentication
|
|
969
|
-
try {
|
|
970
|
-
// 🔑 Ensure API key is initialized before making authenticated requests
|
|
971
|
-
await ensureApiKeyInitialized();
|
|
972
|
-
|
|
973
|
-
const response = await makeAuthenticatedRequest('/email/verification', {
|
|
974
|
-
method: 'POST',
|
|
975
|
-
body: JSON.stringify({
|
|
976
|
-
email,
|
|
977
|
-
code,
|
|
978
|
-
action: 'verify',
|
|
979
|
-
}),
|
|
980
|
-
});
|
|
981
|
-
|
|
982
|
-
const result = await response.json();
|
|
983
|
-
console.log('📡 Email verification API response:', result);
|
|
984
|
-
|
|
985
|
-
if (response.ok && result.success) {
|
|
986
|
-
console.log('✅ Email verification successful');
|
|
987
|
-
|
|
988
|
-
// 🎫 CRITICAL: Store JWT token from email verification response
|
|
989
|
-
const jwtToken = result.token || result.jwtToken || result.jwt || result.authToken;
|
|
990
|
-
|
|
991
|
-
if (jwtToken) {
|
|
992
|
-
console.log('🎫 Storing JWT token from email verification response');
|
|
993
|
-
await AsyncStorage.setItem('email_verification_token', jwtToken);
|
|
994
|
-
await AsyncStorage.setItem('onairos_jwt_token', jwtToken);
|
|
995
|
-
await AsyncStorage.setItem('enoch_token', jwtToken);
|
|
996
|
-
await AsyncStorage.setItem('auth_token', jwtToken);
|
|
997
|
-
await AsyncStorage.setItem('email_verification_email', email);
|
|
998
|
-
await AsyncStorage.setItem('token_timestamp', Date.now().toString());
|
|
999
|
-
} else {
|
|
1000
|
-
console.warn('⚠️ No JWT token received from email verification API');
|
|
1001
|
-
}
|
|
1002
|
-
|
|
1003
|
-
return {
|
|
1004
|
-
success: true,
|
|
1005
|
-
message: result.message || 'Email verification successful',
|
|
1006
|
-
existingUser: result.existingUser || false,
|
|
1007
|
-
jwtToken: jwtToken,
|
|
1008
|
-
};
|
|
1009
|
-
} else {
|
|
1010
|
-
console.error('❌ Email verification failed:', result.error);
|
|
1011
|
-
return {
|
|
1012
|
-
success: false,
|
|
1013
|
-
error: result.error || 'Email verification failed',
|
|
1014
|
-
};
|
|
1015
|
-
}
|
|
1016
|
-
} catch (apiError) {
|
|
1017
|
-
console.error('❌ Email verification API call failed:', apiError);
|
|
892
|
+
} else {
|
|
893
|
+
console.error('❌ Email verification failed:', data.error);
|
|
1018
894
|
return {
|
|
1019
895
|
success: false,
|
|
1020
|
-
error:
|
|
896
|
+
error: data.error || 'Invalid verification code'
|
|
1021
897
|
};
|
|
1022
898
|
}
|
|
1023
899
|
} catch (error) {
|
|
1024
|
-
console.error('❌
|
|
900
|
+
console.error('❌ Error verifying email code:', error);
|
|
1025
901
|
return {
|
|
1026
902
|
success: false,
|
|
1027
|
-
error: error instanceof Error ? error.message : '
|
|
903
|
+
error: error instanceof Error ? error.message : 'Network error'
|
|
1028
904
|
};
|
|
1029
905
|
}
|
|
1030
906
|
};
|
|
1031
907
|
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
908
|
+
/**
|
|
909
|
+
* Check email verification status
|
|
910
|
+
* @param email Email address
|
|
911
|
+
* @param testMode Whether to use test mode
|
|
912
|
+
* @returns Promise with status result
|
|
913
|
+
*/
|
|
914
|
+
export const checkEmailVerificationStatus = async (
|
|
915
|
+
email: string,
|
|
916
|
+
testMode: boolean = false
|
|
917
|
+
): Promise<{ success: boolean; isPending?: boolean; error?: string }> => {
|
|
1038
918
|
try {
|
|
1039
919
|
console.log('🔍 Checking email verification status for:', email);
|
|
1040
|
-
console.log('🔍 Test mode:', testMode);
|
|
1041
920
|
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
921
|
+
const response = await makeDeveloperRequest('/email/verification/status', {
|
|
922
|
+
method: 'POST',
|
|
923
|
+
body: JSON.stringify({
|
|
924
|
+
email,
|
|
925
|
+
testMode
|
|
926
|
+
})
|
|
927
|
+
});
|
|
928
|
+
|
|
929
|
+
const data = await response.json();
|
|
930
|
+
|
|
931
|
+
if (response.ok && data.success) {
|
|
1045
932
|
return {
|
|
1046
933
|
success: true,
|
|
1047
|
-
isPending: false
|
|
1048
|
-
message: 'Status retrieved successfully (test mode)',
|
|
934
|
+
isPending: data.isPending || false
|
|
1049
935
|
};
|
|
1050
|
-
}
|
|
1051
|
-
|
|
1052
|
-
// Production mode: Make real API call with API key authentication
|
|
1053
|
-
try {
|
|
1054
|
-
// 🔑 Ensure API key is initialized before making authenticated requests
|
|
1055
|
-
await ensureApiKeyInitialized();
|
|
1056
|
-
|
|
1057
|
-
const response = await makeAuthenticatedRequest(`/email/verify/status/${encodeURIComponent(email)}`, {
|
|
1058
|
-
method: 'GET',
|
|
1059
|
-
});
|
|
1060
|
-
|
|
1061
|
-
const result = await response.json();
|
|
1062
|
-
console.log('📡 Email verification status API response:', result);
|
|
1063
|
-
|
|
1064
|
-
if (response.ok && result.success) {
|
|
1065
|
-
console.log('✅ Email verification status retrieved');
|
|
1066
|
-
return {
|
|
1067
|
-
success: true,
|
|
1068
|
-
isPending: result.isPending || false,
|
|
1069
|
-
message: result.message || 'Status retrieved successfully',
|
|
1070
|
-
};
|
|
1071
|
-
} else {
|
|
1072
|
-
console.error('❌ Email verification status failed:', result.error);
|
|
1073
|
-
return {
|
|
1074
|
-
success: false,
|
|
1075
|
-
error: result.error || 'Failed to check verification status',
|
|
1076
|
-
};
|
|
1077
|
-
}
|
|
1078
|
-
} catch (apiError) {
|
|
1079
|
-
console.error('❌ Email verification status API call failed:', apiError);
|
|
936
|
+
} else {
|
|
1080
937
|
return {
|
|
1081
938
|
success: false,
|
|
1082
|
-
error: '
|
|
939
|
+
error: data.error || 'Failed to check verification status'
|
|
1083
940
|
};
|
|
1084
941
|
}
|
|
1085
942
|
} catch (error) {
|
|
1086
|
-
console.error('❌
|
|
943
|
+
console.error('❌ Error checking email verification status:', error);
|
|
1087
944
|
return {
|
|
1088
945
|
success: false,
|
|
1089
|
-
error: error instanceof Error ? error.message : '
|
|
946
|
+
error: error instanceof Error ? error.message : 'Network error'
|
|
1090
947
|
};
|
|
1091
948
|
}
|
|
1092
949
|
};
|
|
1093
950
|
|
|
1094
951
|
/**
|
|
1095
|
-
*
|
|
1096
|
-
*
|
|
952
|
+
* Disconnect a platform (uses developer API key)
|
|
953
|
+
* @param platform Platform to disconnect
|
|
954
|
+
* @param username Username associated with the platform
|
|
955
|
+
* @returns Promise with disconnect result
|
|
1097
956
|
*/
|
|
1098
|
-
export const disconnectPlatform = async (platform: string, username: string): Promise<{
|
|
1099
|
-
success: boolean;
|
|
1100
|
-
message?: string;
|
|
1101
|
-
error?: string;
|
|
1102
|
-
}> => {
|
|
957
|
+
export const disconnectPlatform = async (platform: string, username: string): Promise<{ success: boolean; error?: string }> => {
|
|
1103
958
|
try {
|
|
1104
959
|
console.log('🔌 Disconnecting platform:', platform, 'for user:', username);
|
|
1105
960
|
|
|
1106
|
-
if (!platform || !username) {
|
|
1107
|
-
return {
|
|
1108
|
-
success: false,
|
|
1109
|
-
error: 'Platform and username are required',
|
|
1110
|
-
};
|
|
1111
|
-
}
|
|
1112
|
-
|
|
1113
961
|
// Make authenticated API call to disconnect platform
|
|
1114
|
-
const response = await
|
|
962
|
+
const response = await makeDeveloperRequest('/revoke', {
|
|
1115
963
|
method: 'POST',
|
|
1116
964
|
body: JSON.stringify({
|
|
1117
965
|
platform,
|
|
1118
|
-
username
|
|
1119
|
-
})
|
|
966
|
+
username
|
|
967
|
+
})
|
|
1120
968
|
});
|
|
1121
|
-
|
|
1122
|
-
const
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
return {
|
|
1128
|
-
success: true,
|
|
1129
|
-
message: result.message || 'Platform disconnected successfully',
|
|
1130
|
-
};
|
|
969
|
+
|
|
970
|
+
const data = await response.json();
|
|
971
|
+
|
|
972
|
+
if (response.ok && data.success) {
|
|
973
|
+
console.log(`✅ ${platform} disconnected successfully`);
|
|
974
|
+
return { success: true };
|
|
1131
975
|
} else {
|
|
1132
|
-
console.error(
|
|
976
|
+
console.error(`❌ Failed to disconnect ${platform}:`, data.error);
|
|
1133
977
|
return {
|
|
1134
978
|
success: false,
|
|
1135
|
-
error:
|
|
979
|
+
error: data.error || 'Failed to disconnect platform'
|
|
1136
980
|
};
|
|
1137
981
|
}
|
|
1138
982
|
} catch (error) {
|
|
1139
|
-
console.error(
|
|
983
|
+
console.error(`❌ Error disconnecting ${platform}:`, error);
|
|
1140
984
|
return {
|
|
1141
985
|
success: false,
|
|
1142
|
-
error: error instanceof Error ? error.message : '
|
|
986
|
+
error: error instanceof Error ? error.message : 'Network error'
|
|
1143
987
|
};
|
|
1144
988
|
}
|
|
1145
989
|
};
|
|
1146
990
|
|
|
1147
991
|
/**
|
|
1148
|
-
*
|
|
1149
|
-
*
|
|
992
|
+
* Store PIN for user (uses developer API key for now, should be JWT in future)
|
|
993
|
+
* @param username Username
|
|
994
|
+
* @param pin User PIN
|
|
995
|
+
* @returns Promise with result
|
|
1150
996
|
*/
|
|
1151
|
-
export const
|
|
1152
|
-
success: boolean;
|
|
1153
|
-
message?: string;
|
|
1154
|
-
error?: string;
|
|
1155
|
-
}> => {
|
|
997
|
+
export const storePIN = async (username: string, pin: string): Promise<{ success: boolean; error?: string }> => {
|
|
1156
998
|
try {
|
|
1157
|
-
console.log('🔐 Storing PIN
|
|
1158
|
-
console.log('🔑 PIN length:', pin.length);
|
|
1159
|
-
console.log('🎫 JWT token provided:', !!jwtToken);
|
|
1160
|
-
|
|
1161
|
-
if (!username || !pin) {
|
|
1162
|
-
return {
|
|
1163
|
-
success: false,
|
|
1164
|
-
error: 'Username and PIN are required',
|
|
1165
|
-
};
|
|
1166
|
-
}
|
|
1167
|
-
|
|
1168
|
-
if (pin.length < 4) {
|
|
1169
|
-
return {
|
|
1170
|
-
success: false,
|
|
1171
|
-
error: 'PIN must be at least 4 digits',
|
|
1172
|
-
};
|
|
1173
|
-
}
|
|
1174
|
-
|
|
1175
|
-
// Get JWT token from storage if not provided
|
|
1176
|
-
let authToken = jwtToken;
|
|
1177
|
-
if (!authToken) {
|
|
1178
|
-
authToken = await AsyncStorage.getItem('onairos_jwt_token') ||
|
|
1179
|
-
await AsyncStorage.getItem('enoch_token') ||
|
|
1180
|
-
await AsyncStorage.getItem('auth_token') ||
|
|
1181
|
-
await AsyncStorage.getItem('email_verification_token');
|
|
1182
|
-
}
|
|
1183
|
-
|
|
1184
|
-
if (!authToken) {
|
|
1185
|
-
console.warn('⚠️ No JWT token available for PIN storage');
|
|
1186
|
-
return {
|
|
1187
|
-
success: false,
|
|
1188
|
-
error: 'No authentication token available',
|
|
1189
|
-
};
|
|
1190
|
-
}
|
|
1191
|
-
|
|
1192
|
-
console.log('📤 Sending PIN to /store-pin/web endpoint');
|
|
999
|
+
console.log('🔐 Storing PIN for user:', username);
|
|
1193
1000
|
|
|
1194
1001
|
// Make authenticated request to store PIN
|
|
1195
|
-
const response = await
|
|
1002
|
+
const response = await makeDeveloperRequest('/store-pin/web', {
|
|
1196
1003
|
method: 'POST',
|
|
1197
1004
|
headers: {
|
|
1198
|
-
'
|
|
1005
|
+
'Content-Type': 'application/json',
|
|
1199
1006
|
},
|
|
1200
1007
|
body: JSON.stringify({
|
|
1201
1008
|
username,
|
|
1202
|
-
pin
|
|
1203
|
-
})
|
|
1009
|
+
pin
|
|
1010
|
+
})
|
|
1204
1011
|
});
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
if (
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
return {
|
|
1212
|
-
success: false,
|
|
1213
|
-
error: `PIN storage failed: ${response.status} - ${errorText}`,
|
|
1214
|
-
};
|
|
1215
|
-
}
|
|
1216
|
-
|
|
1217
|
-
const result = await response.json();
|
|
1218
|
-
console.log('📥 PIN storage response:', result);
|
|
1219
|
-
|
|
1220
|
-
if (result.success) {
|
|
1221
|
-
console.log('✅ PIN stored successfully after biometric authentication');
|
|
1222
|
-
|
|
1223
|
-
// Store PIN locally for future use
|
|
1224
|
-
await AsyncStorage.setItem('user_pin_stored', 'true');
|
|
1225
|
-
await AsyncStorage.setItem('pin_storage_timestamp', Date.now().toString());
|
|
1226
|
-
|
|
1227
|
-
return {
|
|
1228
|
-
success: true,
|
|
1229
|
-
message: result.message || 'PIN stored successfully',
|
|
1230
|
-
};
|
|
1012
|
+
|
|
1013
|
+
const data = await response.json();
|
|
1014
|
+
|
|
1015
|
+
if (response.ok && data.success) {
|
|
1016
|
+
console.log('✅ PIN stored successfully');
|
|
1017
|
+
return { success: true };
|
|
1231
1018
|
} else {
|
|
1232
|
-
console.error('❌
|
|
1019
|
+
console.error('❌ Failed to store PIN:', data.error);
|
|
1233
1020
|
return {
|
|
1234
1021
|
success: false,
|
|
1235
|
-
error:
|
|
1022
|
+
error: data.error || 'Failed to store PIN'
|
|
1236
1023
|
};
|
|
1237
1024
|
}
|
|
1238
1025
|
} catch (error) {
|
|
1239
|
-
console.error('❌ Error storing PIN
|
|
1026
|
+
console.error('❌ Error storing PIN:', error);
|
|
1240
1027
|
return {
|
|
1241
1028
|
success: false,
|
|
1242
|
-
error: error instanceof Error ? error.message : '
|
|
1029
|
+
error: error instanceof Error ? error.message : 'Network error'
|
|
1243
1030
|
};
|
|
1244
1031
|
}
|
|
1245
1032
|
};
|