@onairos/react-native 3.0.75 → 3.1.1

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.
Files changed (43) hide show
  1. package/lib/commonjs/components/EmailVerificationModal.js +7 -5
  2. package/lib/commonjs/components/EmailVerificationModal.js.map +1 -1
  3. package/lib/commonjs/index.js +18 -6
  4. package/lib/commonjs/index.js.map +1 -1
  5. package/lib/commonjs/services/apiKeyService.js +401 -27
  6. package/lib/commonjs/services/apiKeyService.js.map +1 -1
  7. package/lib/commonjs/services/platformAuthService.js +130 -299
  8. package/lib/commonjs/services/platformAuthService.js.map +1 -1
  9. package/lib/commonjs/utils/onairosApi.js +151 -71
  10. package/lib/commonjs/utils/onairosApi.js.map +1 -1
  11. package/lib/commonjs/utils/secureStorage.js +123 -1
  12. package/lib/commonjs/utils/secureStorage.js.map +1 -1
  13. package/lib/module/components/EmailVerificationModal.js +7 -5
  14. package/lib/module/components/EmailVerificationModal.js.map +1 -1
  15. package/lib/module/index.js +4 -2
  16. package/lib/module/index.js.map +1 -1
  17. package/lib/module/services/apiKeyService.js +384 -22
  18. package/lib/module/services/apiKeyService.js.map +1 -1
  19. package/lib/module/services/platformAuthService.js +127 -295
  20. package/lib/module/services/platformAuthService.js.map +1 -1
  21. package/lib/module/utils/onairosApi.js +147 -70
  22. package/lib/module/utils/onairosApi.js.map +1 -1
  23. package/lib/module/utils/secureStorage.js +116 -0
  24. package/lib/module/utils/secureStorage.js.map +1 -1
  25. package/lib/typescript/components/EmailVerificationModal.d.ts.map +1 -1
  26. package/lib/typescript/index.d.ts +2 -2
  27. package/lib/typescript/index.d.ts.map +1 -1
  28. package/lib/typescript/services/apiKeyService.d.ts +68 -2
  29. package/lib/typescript/services/apiKeyService.d.ts.map +1 -1
  30. package/lib/typescript/services/platformAuthService.d.ts +29 -14
  31. package/lib/typescript/services/platformAuthService.d.ts.map +1 -1
  32. package/lib/typescript/utils/onairosApi.d.ts +25 -10
  33. package/lib/typescript/utils/onairosApi.d.ts.map +1 -1
  34. package/lib/typescript/utils/secureStorage.d.ts +31 -0
  35. package/lib/typescript/utils/secureStorage.d.ts.map +1 -1
  36. package/package.json +1 -1
  37. package/src/components/EmailVerificationModal.tsx +9 -5
  38. package/src/index.ts +4 -1
  39. package/src/services/apiKeyService.ts +412 -18
  40. package/src/services/platformAuthService.ts +219 -421
  41. package/src/types/index.d.ts +11 -5
  42. package/src/utils/onairosApi.ts +162 -74
  43. 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 { makeAuthenticatedRequest, getApiConfig } from './apiKeyService';
4
+ import { makeDeveloperRequest, getApiConfig, storeJWT, extractUsernameFromJWT } from './apiKeyService';
5
5
 
6
- // 🔑 CRITICAL: Initialize API key service for authentication
7
- let isApiKeyInitialized = false;
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 API key service with the admin key for testing
11
- * This ensures all API requests include proper authentication headers
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
- // Import the initialization function
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('🔑 App already initialized with API key, using existing configuration');
28
- // Use the existing app's configuration instead of overriding
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
- // Only initialize with admin key if no app initialization exists
35
- const environment = __DEV__ ? 'development' : 'production';
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 makeAuthenticatedRequest(PLATFORM_AUTH_CONFIG[platform].authEndpoint, {
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 makeAuthenticatedRequest(PLATFORM_AUTH_CONFIG[platform].authEndpoint, {
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
- if (platform === 'youtube') {
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
- // Check if Google Sign-In package is available
355
- let GoogleSignin, statusCodes;
356
- try {
357
- const googleSignInModule = require('@react-native-google-signin/google-signin');
358
- GoogleSignin = googleSignInModule.GoogleSignin;
359
- statusCodes = googleSignInModule.statusCodes;
360
- } catch (importError) {
361
- console.error('❌ Google Sign-In package not available:', importError);
362
- throw new Error('Google Sign-In SDK not installed. Please install @react-native-google-signin/google-signin');
363
- }
364
-
365
- // Configure Google Sign-In with better error handling
366
- try {
367
- await GoogleSignin.configure({
368
- webClientId: '1030678346906-lovkuds2ouqmoc8eu5qpo98spa6edv4o.apps.googleusercontent.com',
369
- iosClientId: '1030678346906-lovkuds2ouqmoc8eu5qpo98spa6edv4o.apps.googleusercontent.com',
370
- scopes: ['https://www.googleapis.com/auth/youtube.readonly'],
371
- offlineAccess: true,
372
- hostedDomain: '',
373
- forceCodeForRefreshToken: true,
374
- accountName: '',
375
- });
376
- console.log('✅ Google Sign-In configured successfully');
377
- } catch (configError) {
378
- console.error('❌ Google Sign-In configuration failed:', configError);
379
- throw new Error(`Google Sign-In configuration failed: ${configError.message || configError}`);
380
- }
381
-
382
- // Check if Google Play Services are available (Android only)
383
- try {
384
- await GoogleSignin.hasPlayServices({ showPlayServicesUpdateDialog: true });
385
- console.log('✅ Google Play Services available');
386
- } catch (playServicesError) {
387
- console.error('❌ Google Play Services error:', playServicesError);
388
- throw new Error(`Google Play Services not available: ${playServicesError.message || playServicesError}`);
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
- // Sign in with Google
392
- let userInfo;
393
- try {
394
- userInfo = await GoogleSignin.signIn();
395
- console.log('Google Sign-In successful:', userInfo.user?.email);
396
- } catch (signInError) {
397
- console.error('Google Sign-In failed:', signInError);
398
-
399
- // Handle specific error codes
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
- const tokens = await GoogleSignin.getTokens();
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
- } catch (error: any) {
520
+ } catch (error: any) {
553
521
  console.error('❌ Google Sign-In error:', error);
554
522
 
555
- const { statusCodes: StatusCodes } = require('@react-native-google-signin/google-signin');
556
-
557
- if (error.code === StatusCodes.SIGN_IN_CANCELLED) {
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
- } else if (error.code === StatusCodes.IN_PROGRESS) {
527
+ } else if (error.code === StatusCodes.IN_PROGRESS) {
560
528
  console.log('Google Sign-In already in progress');
561
- } else if (error.code === StatusCodes.PLAY_SERVICES_NOT_AVAILABLE) {
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,243 @@ export const updateGoogleClientIds = (config: {
833
801
  };
834
802
 
835
803
  /**
836
- * 📧 EMAIL VERIFICATION FUNCTIONS
837
- * Using the correct Onairos email verification endpoints
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 (email: string, testMode = false): Promise<{
840
- success: boolean;
841
- message?: string;
842
- error?: string;
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
- // In test mode, always return success with mock request ID
857
- if (testMode) {
858
- console.log('🧪 Test mode: Always returning success with mock request ID');
859
- const mockRequestId = 'test-request-' + Date.now();
860
-
861
- // Store request info for tracking
862
- await AsyncStorage.setItem('email_verification_request_id', mockRequestId);
863
- await AsyncStorage.setItem('email_verification_request_email', email);
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: 'Email verification sent successfully (test mode)',
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: 'Network error while sending verification email',
837
+ error: data.error || 'Failed to send verification code'
913
838
  };
914
839
  }
915
840
  } catch (error) {
916
- console.error('❌ Email verification request error:', error);
841
+ console.error('❌ Error requesting email verification:', error);
917
842
  return {
918
843
  success: false,
919
- error: error instanceof Error ? error.message : 'Unknown error',
844
+ error: error instanceof Error ? error.message : 'Network error'
920
845
  };
921
846
  }
922
847
  };
923
848
 
924
- export const verifyEmailCode = async (email: string, code: string, testMode = false): Promise<{
925
- success: boolean;
926
- message?: string;
927
- error?: string;
928
- existingUser?: boolean;
929
- jwtToken?: string;
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
- if (!code || code.length < 4) {
944
- return {
945
- success: false,
946
- error: 'Valid verification code is required',
947
- };
948
- }
949
-
950
- // In test mode, always return success with mock JWT token
951
- if (testMode) {
952
- console.log('🧪 Test mode: Always returning success with mock JWT token');
953
- const mockToken = 'test-jwt-token-' + Date.now();
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 mock token for API requests
956
- await AsyncStorage.setItem('email_verification_token', mockToken);
957
- await AsyncStorage.setItem('onairos_jwt_token', mockToken);
958
- await AsyncStorage.setItem('email_verification_email', email);
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 verification successful (test mode)',
963
- existingUser: false,
964
- jwtToken: mockToken,
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: 'Network error during email verification',
896
+ error: data.error || 'Invalid verification code'
1021
897
  };
1022
898
  }
1023
899
  } catch (error) {
1024
- console.error('❌ Email verification error:', error);
900
+ console.error('❌ Error verifying email code:', error);
1025
901
  return {
1026
902
  success: false,
1027
- error: error instanceof Error ? error.message : 'Unknown error',
903
+ error: error instanceof Error ? error.message : 'Network error'
1028
904
  };
1029
905
  }
1030
906
  };
1031
907
 
1032
- export const checkEmailVerificationStatus = async (email: string, testMode = false): Promise<{
1033
- success: boolean;
1034
- isPending?: boolean;
1035
- message?: string;
1036
- error?: string;
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
- // In test mode, always return no pending verification
1043
- if (testMode) {
1044
- console.log('🧪 Test mode: Always returning no pending verification');
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: 'Network error while checking status',
939
+ error: data.error || 'Failed to check verification status'
1083
940
  };
1084
941
  }
1085
942
  } catch (error) {
1086
- console.error('❌ Email verification status error:', error);
943
+ console.error('❌ Error checking email verification status:', error);
1087
944
  return {
1088
945
  success: false,
1089
- error: error instanceof Error ? error.message : 'Unknown error',
946
+ error: error instanceof Error ? error.message : 'Network error'
1090
947
  };
1091
948
  }
1092
949
  };
1093
950
 
1094
951
  /**
1095
- * 🔌 UNIVERSAL PLATFORM DISCONNECTION
1096
- * Backend confirmed this endpoint is fully implemented
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 makeAuthenticatedRequest('/revoke', {
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 result = await response.json();
1123
- console.log('📡 Platform disconnect API response:', result);
1124
-
1125
- if (response.ok && result.success) {
1126
- console.log('✅ Platform disconnected successfully');
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('❌ Platform disconnect failed:', result.error);
976
+ console.error(`❌ Failed to disconnect ${platform}:`, data.error);
1133
977
  return {
1134
978
  success: false,
1135
- error: result.error || 'Failed to disconnect platform',
979
+ error: data.error || 'Failed to disconnect platform'
1136
980
  };
1137
981
  }
1138
982
  } catch (error) {
1139
- console.error('❌ Platform disconnect error:', error);
983
+ console.error(`❌ Error disconnecting ${platform}:`, error);
1140
984
  return {
1141
985
  success: false,
1142
- error: error instanceof Error ? error.message : 'Platform disconnect failed',
986
+ error: error instanceof Error ? error.message : 'Network error'
1143
987
  };
1144
988
  }
1145
989
  };
1146
990
 
1147
991
  /**
1148
- * 🔐 STORE PIN AFTER BIOMETRIC AUTHENTICATION
1149
- * Send PIN separately to /store-pin/web endpoint after biometric Face ID verification
992
+ * Store PIN for user (uses JWT authentication and extracts username from JWT)
993
+ * @param pin User PIN
994
+ * @param username Optional username (if not provided, extracts from JWT)
995
+ * @returns Promise with result
1150
996
  */
1151
- export const storePinAfterBiometric = async (username: string, pin: string, jwtToken?: string): Promise<{
1152
- success: boolean;
1153
- message?: string;
1154
- error?: string;
1155
- }> => {
997
+ export const storePIN = async (pin: string, username?: string): Promise<{ success: boolean; error?: string }> => {
1156
998
  try {
1157
- console.log('🔐 Storing PIN after biometric authentication for user:', username);
1158
- console.log('🔑 PIN length:', pin.length);
1159
- console.log('🎫 JWT token provided:', !!jwtToken);
999
+ // Extract username from JWT if not provided
1000
+ const userToStore = username || extractUsernameFromJWT();
1160
1001
 
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');
1002
+ if (!userToStore) {
1003
+ console.error('❌ No username available - either provide username or ensure JWT token is valid');
1186
1004
  return {
1187
1005
  success: false,
1188
- error: 'No authentication token available',
1006
+ error: 'No username available for PIN storage'
1189
1007
  };
1190
1008
  }
1009
+
1010
+ console.log('🔐 Storing PIN for user:', userToStore);
1191
1011
 
1192
- console.log('📤 Sending PIN to /store-pin/web endpoint');
1193
-
1194
- // Make authenticated request to store PIN
1195
- const response = await makeAuthenticatedRequest('/store-pin/web', {
1012
+ // Make authenticated request to store PIN (using developer API key for now)
1013
+ const response = await makeDeveloperRequest('/store-pin/web', {
1196
1014
  method: 'POST',
1197
1015
  headers: {
1198
- 'Authorization': `Bearer ${authToken}`,
1016
+ 'Content-Type': 'application/json',
1199
1017
  },
1200
1018
  body: JSON.stringify({
1201
- username,
1202
- pin,
1203
- }),
1019
+ username: userToStore,
1020
+ pin
1021
+ })
1204
1022
  });
1205
-
1206
- console.log('📡 PIN storage response status:', response.status);
1207
-
1208
- if (!response.ok) {
1209
- const errorText = await response.text();
1210
- console.error('❌ PIN storage failed:', errorText);
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
- };
1023
+
1024
+ const data = await response.json();
1025
+
1026
+ if (response.ok && data.success) {
1027
+ console.log('✅ PIN stored successfully for user:', userToStore);
1028
+ return { success: true };
1231
1029
  } else {
1232
- console.error('❌ PIN storage API returned error:', result.error);
1030
+ console.error('❌ Failed to store PIN:', data.error);
1233
1031
  return {
1234
1032
  success: false,
1235
- error: result.error || 'PIN storage failed',
1033
+ error: data.error || 'Failed to store PIN'
1236
1034
  };
1237
1035
  }
1238
1036
  } catch (error) {
1239
- console.error('❌ Error storing PIN after biometric authentication:', error);
1037
+ console.error('❌ Error storing PIN:', error);
1240
1038
  return {
1241
1039
  success: false,
1242
- error: error instanceof Error ? error.message : 'PIN storage failed',
1040
+ error: error instanceof Error ? error.message : 'Network error'
1243
1041
  };
1244
1042
  }
1245
1043
  };