@onairos/react-native 3.0.74 → 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/components/UniversalOnboarding.js +10 -1
- package/lib/commonjs/components/UniversalOnboarding.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 +127 -290
- 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/components/UniversalOnboarding.js +11 -2
- package/lib/module/components/UniversalOnboarding.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 +125 -287
- 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/components/UniversalOnboarding.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/components/UniversalOnboarding.tsx +11 -1
- package/src/index.ts +1 -1
- package/src/services/apiKeyService.ts +282 -18
- package/src/services/platformAuthService.ts +216 -412
- package/src/types/index.d.ts +6 -5
- package/src/utils/onairosApi.ts +151 -74
- package/src/utils/secureStorage.ts +122 -0
|
@@ -1,51 +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
|
|
16
|
+
// Check if app is already initialized with API key
|
|
17
|
+
const existingConfig = getApiConfig();
|
|
22
18
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
console.log('✅ Platform auth service initialized with admin key (production)');
|
|
19
|
+
if (existingConfig && existingConfig.apiKey) {
|
|
20
|
+
console.log('🔑 Platform auth service using existing app configuration');
|
|
21
|
+
console.log(`✅ Environment: ${existingConfig.environment}`);
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
|
|
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.');
|
|
33
28
|
} catch (error) {
|
|
34
29
|
console.error('❌ Failed to initialize platform auth service:', error);
|
|
35
30
|
throw error;
|
|
36
31
|
}
|
|
37
32
|
};
|
|
38
33
|
|
|
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
|
-
|
|
49
34
|
// Configuration for each platform's authentication
|
|
50
35
|
let PLATFORM_AUTH_CONFIG: Record<string, PlatformAuthConfig> = {
|
|
51
36
|
instagram: {
|
|
@@ -156,7 +141,7 @@ export const initiateOAuth = async (platform: string, username: string, appName?
|
|
|
156
141
|
|
|
157
142
|
console.log('📤 Sending Instagram OAuth request:', jsonData);
|
|
158
143
|
|
|
159
|
-
const response = await
|
|
144
|
+
const response = await makeDeveloperRequest(PLATFORM_AUTH_CONFIG[platform].authEndpoint, {
|
|
160
145
|
method: 'POST',
|
|
161
146
|
body: JSON.stringify(jsonData),
|
|
162
147
|
});
|
|
@@ -199,7 +184,7 @@ export const initiateOAuth = async (platform: string, username: string, appName?
|
|
|
199
184
|
console.log(`📤 Sending ${platform} OAuth request:`, jsonData);
|
|
200
185
|
|
|
201
186
|
// Make the authenticated request to get the OAuth URL
|
|
202
|
-
const response = await
|
|
187
|
+
const response = await makeDeveloperRequest(PLATFORM_AUTH_CONFIG[platform].authEndpoint, {
|
|
203
188
|
method: 'POST',
|
|
204
189
|
body: JSON.stringify(jsonData),
|
|
205
190
|
});
|
|
@@ -331,68 +316,68 @@ const validateOAuthUrl = async (url: string): Promise<boolean> => {
|
|
|
331
316
|
* @returns A Promise that resolves to the authentication result
|
|
332
317
|
*/
|
|
333
318
|
export const initiateNativeAuth = async (platform: string, username?: string): Promise<boolean> => {
|
|
334
|
-
|
|
319
|
+
if (platform === 'youtube') {
|
|
335
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;
|
|
336
324
|
try {
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
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);
|
|
373
366
|
|
|
374
|
-
//
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
}
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
if (signInError.code === statusCodes.SIGN_IN_CANCELLED) {
|
|
384
|
-
throw new Error('Google Sign-In was cancelled by user');
|
|
385
|
-
} else if (signInError.code === statusCodes.IN_PROGRESS) {
|
|
386
|
-
throw new Error('Google Sign-In already in progress');
|
|
387
|
-
} else if (signInError.code === statusCodes.PLAY_SERVICES_NOT_AVAILABLE) {
|
|
388
|
-
throw new Error('Google Play Services not available or outdated');
|
|
389
|
-
} else {
|
|
390
|
-
throw new Error(`Google Sign-In failed: ${signInError.message || signInError}`);
|
|
391
|
-
}
|
|
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}`);
|
|
392
376
|
}
|
|
393
|
-
|
|
377
|
+
}
|
|
378
|
+
|
|
394
379
|
// Get access token for API calls
|
|
395
|
-
|
|
380
|
+
const tokens = await GoogleSignin.getTokens();
|
|
396
381
|
console.log('🔑 Got Google tokens');
|
|
397
382
|
|
|
398
383
|
// Get current user info with refresh token
|
|
@@ -532,22 +517,22 @@ export const initiateNativeAuth = async (platform: string, username?: string): P
|
|
|
532
517
|
return false;
|
|
533
518
|
}
|
|
534
519
|
|
|
535
|
-
|
|
520
|
+
} catch (error: any) {
|
|
536
521
|
console.error('❌ Google Sign-In error:', error);
|
|
537
522
|
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
523
|
+
const { statusCodes: StatusCodes } = require('@react-native-google-signin/google-signin');
|
|
524
|
+
|
|
525
|
+
if (error.code === StatusCodes.SIGN_IN_CANCELLED) {
|
|
541
526
|
console.log('User cancelled Google Sign-In');
|
|
542
|
-
|
|
527
|
+
} else if (error.code === StatusCodes.IN_PROGRESS) {
|
|
543
528
|
console.log('Google Sign-In already in progress');
|
|
544
|
-
|
|
529
|
+
} else if (error.code === StatusCodes.PLAY_SERVICES_NOT_AVAILABLE) {
|
|
545
530
|
console.log('Google Play Services not available');
|
|
546
|
-
}
|
|
547
|
-
|
|
548
|
-
return false;
|
|
549
531
|
}
|
|
532
|
+
|
|
533
|
+
return false;
|
|
550
534
|
}
|
|
535
|
+
}
|
|
551
536
|
|
|
552
537
|
return false;
|
|
553
538
|
};
|
|
@@ -816,413 +801,232 @@ export const updateGoogleClientIds = (config: {
|
|
|
816
801
|
};
|
|
817
802
|
|
|
818
803
|
/**
|
|
819
|
-
*
|
|
820
|
-
*
|
|
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
|
|
821
808
|
*/
|
|
822
|
-
export const requestEmailVerification = async (
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
requestId?: string;
|
|
827
|
-
}> => {
|
|
809
|
+
export const requestEmailVerification = async (
|
|
810
|
+
email: string,
|
|
811
|
+
testMode: boolean = false
|
|
812
|
+
): Promise<{ success: boolean; message?: string; error?: string }> => {
|
|
828
813
|
try {
|
|
829
814
|
console.log('📧 Requesting email verification for:', email);
|
|
830
|
-
console.log('🧪 Test mode:', testMode);
|
|
831
815
|
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
await AsyncStorage.setItem('email_verification_request_id', mockRequestId);
|
|
846
|
-
await AsyncStorage.setItem('email_verification_request_email', email);
|
|
847
|
-
|
|
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');
|
|
848
829
|
return {
|
|
849
830
|
success: true,
|
|
850
|
-
message: '
|
|
851
|
-
requestId: mockRequestId,
|
|
831
|
+
message: data.message || 'Verification code sent to your email'
|
|
852
832
|
};
|
|
853
|
-
}
|
|
854
|
-
|
|
855
|
-
// Production mode: Make real API call with API key authentication
|
|
856
|
-
try {
|
|
857
|
-
// 🔑 Ensure API key is initialized before making authenticated requests
|
|
858
|
-
await ensureApiKeyInitialized();
|
|
859
|
-
|
|
860
|
-
const response = await makeAuthenticatedRequest('/email/verification', {
|
|
861
|
-
method: 'POST',
|
|
862
|
-
body: JSON.stringify({
|
|
863
|
-
email,
|
|
864
|
-
action: 'request',
|
|
865
|
-
}),
|
|
866
|
-
});
|
|
867
|
-
|
|
868
|
-
const result = await response.json();
|
|
869
|
-
console.log('📡 Email verification API response:', result);
|
|
870
|
-
|
|
871
|
-
if (response.ok && result.success) {
|
|
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
|
-
|
|
879
|
-
return {
|
|
880
|
-
success: true,
|
|
881
|
-
message: result.message || 'Email verification sent successfully',
|
|
882
|
-
requestId: requestId,
|
|
883
|
-
};
|
|
884
|
-
} else {
|
|
885
|
-
console.error('❌ Email verification request failed:', result.error);
|
|
886
|
-
return {
|
|
887
|
-
success: false,
|
|
888
|
-
error: result.error || 'Failed to send verification email',
|
|
889
|
-
};
|
|
890
|
-
}
|
|
891
|
-
} catch (apiError) {
|
|
892
|
-
console.error('❌ Email verification API call failed:', apiError);
|
|
833
|
+
} else {
|
|
834
|
+
console.error('❌ Email verification request failed:', data.error);
|
|
893
835
|
return {
|
|
894
836
|
success: false,
|
|
895
|
-
error: '
|
|
837
|
+
error: data.error || 'Failed to send verification code'
|
|
896
838
|
};
|
|
897
839
|
}
|
|
898
840
|
} catch (error) {
|
|
899
|
-
console.error('❌
|
|
841
|
+
console.error('❌ Error requesting email verification:', error);
|
|
900
842
|
return {
|
|
901
843
|
success: false,
|
|
902
|
-
error: error instanceof Error ? error.message : '
|
|
844
|
+
error: error instanceof Error ? error.message : 'Network error'
|
|
903
845
|
};
|
|
904
846
|
}
|
|
905
847
|
};
|
|
906
848
|
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
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 }> => {
|
|
914
861
|
try {
|
|
915
862
|
console.log('🔍 Verifying email code for:', email);
|
|
916
|
-
console.log('🔑 Code length:', code.length);
|
|
917
|
-
console.log('🧪 Test mode:', testMode);
|
|
918
|
-
|
|
919
|
-
if (!email || !email.includes('@')) {
|
|
920
|
-
return {
|
|
921
|
-
success: false,
|
|
922
|
-
error: 'Valid email address is required',
|
|
923
|
-
};
|
|
924
|
-
}
|
|
925
863
|
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
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');
|
|
937
878
|
|
|
938
|
-
// Store
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
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
|
+
}
|
|
942
885
|
|
|
943
886
|
return {
|
|
944
887
|
success: true,
|
|
945
|
-
message: 'Email
|
|
946
|
-
existingUser: false,
|
|
947
|
-
|
|
888
|
+
message: data.message || 'Email verified successfully',
|
|
889
|
+
existingUser: data.existingUser || false,
|
|
890
|
+
token: data.token || data.jwtToken
|
|
948
891
|
};
|
|
949
|
-
}
|
|
950
|
-
|
|
951
|
-
// Production mode: Make real API call with API key authentication
|
|
952
|
-
try {
|
|
953
|
-
// 🔑 Ensure API key is initialized before making authenticated requests
|
|
954
|
-
await ensureApiKeyInitialized();
|
|
955
|
-
|
|
956
|
-
const response = await makeAuthenticatedRequest('/email/verification', {
|
|
957
|
-
method: 'POST',
|
|
958
|
-
body: JSON.stringify({
|
|
959
|
-
email,
|
|
960
|
-
code,
|
|
961
|
-
action: 'verify',
|
|
962
|
-
}),
|
|
963
|
-
});
|
|
964
|
-
|
|
965
|
-
const result = await response.json();
|
|
966
|
-
console.log('📡 Email verification API response:', result);
|
|
967
|
-
|
|
968
|
-
if (response.ok && result.success) {
|
|
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
|
-
|
|
986
|
-
return {
|
|
987
|
-
success: true,
|
|
988
|
-
message: result.message || 'Email verification successful',
|
|
989
|
-
existingUser: result.existingUser || false,
|
|
990
|
-
jwtToken: jwtToken,
|
|
991
|
-
};
|
|
992
|
-
} else {
|
|
993
|
-
console.error('❌ Email verification failed:', result.error);
|
|
994
|
-
return {
|
|
995
|
-
success: false,
|
|
996
|
-
error: result.error || 'Email verification failed',
|
|
997
|
-
};
|
|
998
|
-
}
|
|
999
|
-
} catch (apiError) {
|
|
1000
|
-
console.error('❌ Email verification API call failed:', apiError);
|
|
892
|
+
} else {
|
|
893
|
+
console.error('❌ Email verification failed:', data.error);
|
|
1001
894
|
return {
|
|
1002
895
|
success: false,
|
|
1003
|
-
error:
|
|
896
|
+
error: data.error || 'Invalid verification code'
|
|
1004
897
|
};
|
|
1005
898
|
}
|
|
1006
899
|
} catch (error) {
|
|
1007
|
-
console.error('❌
|
|
900
|
+
console.error('❌ Error verifying email code:', error);
|
|
1008
901
|
return {
|
|
1009
902
|
success: false,
|
|
1010
|
-
error: error instanceof Error ? error.message : '
|
|
903
|
+
error: error instanceof Error ? error.message : 'Network error'
|
|
1011
904
|
};
|
|
1012
905
|
}
|
|
1013
906
|
};
|
|
1014
907
|
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
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 }> => {
|
|
1021
918
|
try {
|
|
1022
919
|
console.log('🔍 Checking email verification status for:', email);
|
|
1023
|
-
console.log('🔍 Test mode:', testMode);
|
|
1024
920
|
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
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) {
|
|
1028
932
|
return {
|
|
1029
933
|
success: true,
|
|
1030
|
-
isPending: false
|
|
1031
|
-
message: 'Status retrieved successfully (test mode)',
|
|
934
|
+
isPending: data.isPending || false
|
|
1032
935
|
};
|
|
1033
|
-
}
|
|
1034
|
-
|
|
1035
|
-
// Production mode: Make real API call with API key authentication
|
|
1036
|
-
try {
|
|
1037
|
-
// 🔑 Ensure API key is initialized before making authenticated requests
|
|
1038
|
-
await ensureApiKeyInitialized();
|
|
1039
|
-
|
|
1040
|
-
const response = await makeAuthenticatedRequest(`/email/verify/status/${encodeURIComponent(email)}`, {
|
|
1041
|
-
method: 'GET',
|
|
1042
|
-
});
|
|
1043
|
-
|
|
1044
|
-
const result = await response.json();
|
|
1045
|
-
console.log('📡 Email verification status API response:', result);
|
|
1046
|
-
|
|
1047
|
-
if (response.ok && result.success) {
|
|
1048
|
-
console.log('✅ Email verification status retrieved');
|
|
1049
|
-
return {
|
|
1050
|
-
success: true,
|
|
1051
|
-
isPending: result.isPending || false,
|
|
1052
|
-
message: result.message || 'Status retrieved successfully',
|
|
1053
|
-
};
|
|
1054
|
-
} else {
|
|
1055
|
-
console.error('❌ Email verification status failed:', result.error);
|
|
1056
|
-
return {
|
|
1057
|
-
success: false,
|
|
1058
|
-
error: result.error || 'Failed to check verification status',
|
|
1059
|
-
};
|
|
1060
|
-
}
|
|
1061
|
-
} catch (apiError) {
|
|
1062
|
-
console.error('❌ Email verification status API call failed:', apiError);
|
|
936
|
+
} else {
|
|
1063
937
|
return {
|
|
1064
938
|
success: false,
|
|
1065
|
-
error: '
|
|
939
|
+
error: data.error || 'Failed to check verification status'
|
|
1066
940
|
};
|
|
1067
941
|
}
|
|
1068
942
|
} catch (error) {
|
|
1069
|
-
console.error('❌
|
|
943
|
+
console.error('❌ Error checking email verification status:', error);
|
|
1070
944
|
return {
|
|
1071
945
|
success: false,
|
|
1072
|
-
error: error instanceof Error ? error.message : '
|
|
946
|
+
error: error instanceof Error ? error.message : 'Network error'
|
|
1073
947
|
};
|
|
1074
948
|
}
|
|
1075
949
|
};
|
|
1076
950
|
|
|
1077
951
|
/**
|
|
1078
|
-
*
|
|
1079
|
-
*
|
|
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
|
|
1080
956
|
*/
|
|
1081
|
-
export const disconnectPlatform = async (platform: string, username: string): Promise<{
|
|
1082
|
-
success: boolean;
|
|
1083
|
-
message?: string;
|
|
1084
|
-
error?: string;
|
|
1085
|
-
}> => {
|
|
957
|
+
export const disconnectPlatform = async (platform: string, username: string): Promise<{ success: boolean; error?: string }> => {
|
|
1086
958
|
try {
|
|
1087
959
|
console.log('🔌 Disconnecting platform:', platform, 'for user:', username);
|
|
1088
960
|
|
|
1089
|
-
if (!platform || !username) {
|
|
1090
|
-
return {
|
|
1091
|
-
success: false,
|
|
1092
|
-
error: 'Platform and username are required',
|
|
1093
|
-
};
|
|
1094
|
-
}
|
|
1095
|
-
|
|
1096
961
|
// Make authenticated API call to disconnect platform
|
|
1097
|
-
const response = await
|
|
962
|
+
const response = await makeDeveloperRequest('/revoke', {
|
|
1098
963
|
method: 'POST',
|
|
1099
964
|
body: JSON.stringify({
|
|
1100
965
|
platform,
|
|
1101
|
-
username
|
|
1102
|
-
})
|
|
966
|
+
username
|
|
967
|
+
})
|
|
1103
968
|
});
|
|
1104
|
-
|
|
1105
|
-
const
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
return {
|
|
1111
|
-
success: true,
|
|
1112
|
-
message: result.message || 'Platform disconnected successfully',
|
|
1113
|
-
};
|
|
969
|
+
|
|
970
|
+
const data = await response.json();
|
|
971
|
+
|
|
972
|
+
if (response.ok && data.success) {
|
|
973
|
+
console.log(`✅ ${platform} disconnected successfully`);
|
|
974
|
+
return { success: true };
|
|
1114
975
|
} else {
|
|
1115
|
-
console.error(
|
|
976
|
+
console.error(`❌ Failed to disconnect ${platform}:`, data.error);
|
|
1116
977
|
return {
|
|
1117
978
|
success: false,
|
|
1118
|
-
error:
|
|
979
|
+
error: data.error || 'Failed to disconnect platform'
|
|
1119
980
|
};
|
|
1120
981
|
}
|
|
1121
982
|
} catch (error) {
|
|
1122
|
-
console.error(
|
|
983
|
+
console.error(`❌ Error disconnecting ${platform}:`, error);
|
|
1123
984
|
return {
|
|
1124
985
|
success: false,
|
|
1125
|
-
error: error instanceof Error ? error.message : '
|
|
986
|
+
error: error instanceof Error ? error.message : 'Network error'
|
|
1126
987
|
};
|
|
1127
988
|
}
|
|
1128
989
|
};
|
|
1129
990
|
|
|
1130
991
|
/**
|
|
1131
|
-
*
|
|
1132
|
-
*
|
|
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
|
|
1133
996
|
*/
|
|
1134
|
-
export const
|
|
1135
|
-
success: boolean;
|
|
1136
|
-
message?: string;
|
|
1137
|
-
error?: string;
|
|
1138
|
-
}> => {
|
|
997
|
+
export const storePIN = async (username: string, pin: string): Promise<{ success: boolean; error?: string }> => {
|
|
1139
998
|
try {
|
|
1140
|
-
console.log('🔐 Storing PIN
|
|
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');
|
|
999
|
+
console.log('🔐 Storing PIN for user:', username);
|
|
1176
1000
|
|
|
1177
1001
|
// Make authenticated request to store PIN
|
|
1178
|
-
const response = await
|
|
1002
|
+
const response = await makeDeveloperRequest('/store-pin/web', {
|
|
1179
1003
|
method: 'POST',
|
|
1180
1004
|
headers: {
|
|
1181
|
-
'
|
|
1005
|
+
'Content-Type': 'application/json',
|
|
1182
1006
|
},
|
|
1183
1007
|
body: JSON.stringify({
|
|
1184
1008
|
username,
|
|
1185
|
-
pin
|
|
1186
|
-
})
|
|
1009
|
+
pin
|
|
1010
|
+
})
|
|
1187
1011
|
});
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
if (
|
|
1192
|
-
|
|
1193
|
-
|
|
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
|
-
};
|
|
1012
|
+
|
|
1013
|
+
const data = await response.json();
|
|
1014
|
+
|
|
1015
|
+
if (response.ok && data.success) {
|
|
1016
|
+
console.log('✅ PIN stored successfully');
|
|
1017
|
+
return { success: true };
|
|
1214
1018
|
} else {
|
|
1215
|
-
console.error('❌
|
|
1019
|
+
console.error('❌ Failed to store PIN:', data.error);
|
|
1216
1020
|
return {
|
|
1217
1021
|
success: false,
|
|
1218
|
-
error:
|
|
1022
|
+
error: data.error || 'Failed to store PIN'
|
|
1219
1023
|
};
|
|
1220
1024
|
}
|
|
1221
1025
|
} catch (error) {
|
|
1222
|
-
console.error('❌ Error storing PIN
|
|
1026
|
+
console.error('❌ Error storing PIN:', error);
|
|
1223
1027
|
return {
|
|
1224
1028
|
success: false,
|
|
1225
|
-
error: error instanceof Error ? error.message : '
|
|
1029
|
+
error: error instanceof Error ? error.message : 'Network error'
|
|
1226
1030
|
};
|
|
1227
1031
|
}
|
|
1228
1032
|
};
|