@onairos/react-native 3.0.71 โ 3.0.73
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/commonjs/components/Onairos.js +294 -155
- package/lib/commonjs/components/Onairos.js.map +1 -1
- package/lib/commonjs/components/OnairosButton.js +1 -1
- package/lib/commonjs/components/OnairosButton.js.map +1 -1
- package/lib/commonjs/components/UniversalOnboarding.js +6 -6
- package/lib/commonjs/components/UniversalOnboarding.js.map +1 -1
- package/lib/commonjs/components/onboarding/OAuthWebView.js +188 -52
- package/lib/commonjs/components/onboarding/OAuthWebView.js.map +1 -1
- package/lib/commonjs/index.js +25 -440
- package/lib/commonjs/index.js.map +1 -1
- package/lib/commonjs/services/apiKeyService.js +404 -0
- package/lib/commonjs/services/apiKeyService.js.map +1 -0
- package/lib/commonjs/services/platformAuthService.js +318 -113
- package/lib/commonjs/services/platformAuthService.js.map +1 -1
- package/lib/commonjs/types/index.js +4 -0
- package/lib/commonjs/types.js +12 -0
- package/lib/commonjs/types.js.map +1 -1
- package/lib/commonjs/utils/programmaticFlow.js +117 -0
- package/lib/commonjs/utils/programmaticFlow.js.map +1 -0
- package/lib/module/components/Onairos.js +297 -158
- package/lib/module/components/Onairos.js.map +1 -1
- package/lib/module/components/OnairosButton.js +1 -1
- package/lib/module/components/OnairosButton.js.map +1 -1
- package/lib/module/components/UniversalOnboarding.js +6 -6
- package/lib/module/components/UniversalOnboarding.js.map +1 -1
- package/lib/module/components/onboarding/OAuthWebView.js +188 -52
- package/lib/module/components/onboarding/OAuthWebView.js.map +1 -1
- package/lib/module/index.js +17 -61
- package/lib/module/index.js.map +1 -1
- package/lib/module/services/apiKeyService.js +389 -0
- package/lib/module/services/apiKeyService.js.map +1 -0
- package/lib/module/services/platformAuthService.js +311 -111
- package/lib/module/services/platformAuthService.js.map +1 -1
- package/lib/module/types/index.js +1 -1
- package/lib/module/types.js +8 -0
- package/lib/module/types.js.map +1 -1
- package/lib/module/utils/programmaticFlow.js +111 -0
- package/lib/module/utils/programmaticFlow.js.map +1 -0
- package/lib/typescript/components/Onairos.d.ts +2 -29
- package/lib/typescript/components/Onairos.d.ts.map +1 -1
- package/lib/typescript/components/onboarding/OAuthWebView.d.ts.map +1 -1
- package/lib/typescript/index.d.ts +10 -39
- package/lib/typescript/index.d.ts.map +1 -1
- package/lib/typescript/services/apiKeyService.d.ts +66 -0
- package/lib/typescript/services/apiKeyService.d.ts.map +1 -0
- package/lib/typescript/services/platformAuthService.d.ts +26 -0
- package/lib/typescript/services/platformAuthService.d.ts.map +1 -1
- package/lib/typescript/types/index.d.ts +144 -78
- package/lib/typescript/types/index.d.ts.map +1 -1
- package/lib/typescript/types.d.ts +92 -3
- package/lib/typescript/types.d.ts.map +1 -1
- package/lib/typescript/utils/programmaticFlow.d.ts +23 -0
- package/lib/typescript/utils/programmaticFlow.d.ts.map +1 -0
- package/package.json +1 -1
- package/src/components/Onairos.tsx +330 -207
- package/src/components/OnairosButton.tsx +1 -1
- package/src/components/UniversalOnboarding.tsx +6 -6
- package/src/components/onboarding/OAuthWebView.tsx +236 -71
- package/src/index.ts +25 -115
- package/src/services/apiKeyService.ts +401 -0
- package/src/services/platformAuthService.ts +363 -126
- package/src/types/index.d.ts +110 -0
- package/src/types/index.ts +148 -74
- package/src/types.ts +99 -3
- package/src/utils/programmaticFlow.ts +113 -0
|
@@ -1,29 +1,62 @@
|
|
|
1
1
|
import { Platform, Linking } from 'react-native';
|
|
2
2
|
import AsyncStorage from '@react-native-async-storage/async-storage';
|
|
3
|
+
import type { PlatformAuthConfig } from '../types';
|
|
4
|
+
import { makeAuthenticatedRequest, getApiConfig } from './apiKeyService';
|
|
3
5
|
|
|
4
|
-
//
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
6
|
+
// ๐ CRITICAL: Initialize API key service for authentication
|
|
7
|
+
let isApiKeyInitialized = false;
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Initialize the API key service with the admin key for testing
|
|
11
|
+
* This ensures all API requests include proper authentication headers
|
|
12
|
+
*/
|
|
13
|
+
export const initializePlatformAuthService = async (): Promise<void> => {
|
|
14
|
+
if (isApiKeyInitialized) {
|
|
15
|
+
console.log('๐ API key service already initialized');
|
|
16
|
+
return;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
try {
|
|
20
|
+
// Import the initialization function
|
|
21
|
+
const { initializeApiKey, ADMIN_API_KEY } = await import('./apiKeyService');
|
|
22
|
+
|
|
23
|
+
// Initialize with admin key for testing/development
|
|
24
|
+
await initializeApiKey({
|
|
25
|
+
apiKey: ADMIN_API_KEY, // 'OnairosIsAUnicorn2025'
|
|
26
|
+
environment: 'development',
|
|
27
|
+
enableLogging: true,
|
|
28
|
+
timeout: 30000,
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
isApiKeyInitialized = true;
|
|
32
|
+
console.log('โ
Platform auth service initialized with admin key');
|
|
33
|
+
} catch (error) {
|
|
34
|
+
console.error('โ Failed to initialize platform auth service:', error);
|
|
35
|
+
throw error;
|
|
36
|
+
}
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Ensure API key is initialized before making authenticated requests
|
|
41
|
+
*/
|
|
42
|
+
const ensureApiKeyInitialized = async (): Promise<void> => {
|
|
43
|
+
if (!isApiKeyInitialized) {
|
|
44
|
+
console.log('๐ API key not initialized, initializing now...');
|
|
45
|
+
await initializePlatformAuthService();
|
|
46
|
+
}
|
|
47
|
+
};
|
|
15
48
|
|
|
16
49
|
// Configuration for each platform's authentication
|
|
17
50
|
let PLATFORM_AUTH_CONFIG: Record<string, PlatformAuthConfig> = {
|
|
18
51
|
instagram: {
|
|
19
52
|
hasNativeSDK: false, // Instagram uses OAuth WebView flow
|
|
20
|
-
authEndpoint: '
|
|
53
|
+
authEndpoint: '/instagram/authorize',
|
|
21
54
|
color: '#E1306C',
|
|
22
55
|
},
|
|
23
56
|
youtube: {
|
|
24
57
|
hasNativeSDK: true, // Native Google Sign-In SDK enabled
|
|
25
58
|
nativeSDKPackage: '@react-native-google-signin/google-signin',
|
|
26
|
-
authEndpoint: '
|
|
59
|
+
authEndpoint: '/youtube/authorize',
|
|
27
60
|
color: '#FF0000',
|
|
28
61
|
clientId: '1030678346906-lovkuds2ouqmoc8eu5qpo98spa6edv4o.apps.googleusercontent.com',
|
|
29
62
|
redirectUri: 'onairosevents://auth/callback',
|
|
@@ -32,17 +65,17 @@ let PLATFORM_AUTH_CONFIG: Record<string, PlatformAuthConfig> = {
|
|
|
32
65
|
},
|
|
33
66
|
reddit: {
|
|
34
67
|
hasNativeSDK: false,
|
|
35
|
-
authEndpoint: '
|
|
68
|
+
authEndpoint: '/reddit/authorize',
|
|
36
69
|
color: '#FF4500',
|
|
37
70
|
},
|
|
38
71
|
pinterest: {
|
|
39
72
|
hasNativeSDK: false,
|
|
40
|
-
authEndpoint: '
|
|
73
|
+
authEndpoint: '/pinterest/authorize',
|
|
41
74
|
color: '#E60023',
|
|
42
75
|
},
|
|
43
76
|
email: {
|
|
44
77
|
hasNativeSDK: false,
|
|
45
|
-
authEndpoint: '
|
|
78
|
+
authEndpoint: '/gmail/authorize',
|
|
46
79
|
color: '#4285F4',
|
|
47
80
|
},
|
|
48
81
|
};
|
|
@@ -123,34 +156,12 @@ export const initiateOAuth = async (platform: string, username: string, appName?
|
|
|
123
156
|
|
|
124
157
|
console.log('๐ค Sending Instagram OAuth request:', jsonData);
|
|
125
158
|
|
|
126
|
-
const
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
try {
|
|
131
|
-
response = await fetch('https://api2.onairos.uk/instagram/authorize', {
|
|
132
|
-
method: 'POST',
|
|
133
|
-
headers: {
|
|
134
|
-
'Content-Type': 'application/json',
|
|
135
|
-
'User-Agent': 'OnairosReactNative/1.0',
|
|
136
|
-
},
|
|
137
|
-
body: JSON.stringify(jsonData),
|
|
138
|
-
signal: controller.signal,
|
|
139
|
-
});
|
|
140
|
-
} catch (fetchError) {
|
|
141
|
-
clearTimeout(timeoutId);
|
|
142
|
-
|
|
143
|
-
if (fetchError.name === 'AbortError') {
|
|
144
|
-
throw new Error(`Request timeout: Instagram OAuth server took too long to respond`);
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
throw new Error(`Network error: ${fetchError.message || 'Failed to connect to Instagram OAuth server'}`);
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
clearTimeout(timeoutId);
|
|
159
|
+
const response = await makeAuthenticatedRequest(PLATFORM_AUTH_CONFIG[platform].authEndpoint, {
|
|
160
|
+
method: 'POST',
|
|
161
|
+
body: JSON.stringify(jsonData),
|
|
162
|
+
});
|
|
151
163
|
|
|
152
164
|
console.log('๐ก Instagram OAuth response status:', response.status);
|
|
153
|
-
console.log('๐ก Instagram OAuth response headers:', response.headers);
|
|
154
165
|
|
|
155
166
|
if (!response.ok) {
|
|
156
167
|
const errorText = await response.text();
|
|
@@ -187,35 +198,13 @@ export const initiateOAuth = async (platform: string, username: string, appName?
|
|
|
187
198
|
|
|
188
199
|
console.log(`๐ค Sending ${platform} OAuth request:`, jsonData);
|
|
189
200
|
|
|
190
|
-
// Make the request to get the OAuth URL
|
|
191
|
-
const
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
try {
|
|
196
|
-
response = await fetch(PLATFORM_AUTH_CONFIG[platform].authEndpoint, {
|
|
197
|
-
method: 'POST',
|
|
198
|
-
headers: {
|
|
199
|
-
'Content-Type': 'application/json',
|
|
200
|
-
'User-Agent': 'OnairosReactNative/1.0',
|
|
201
|
-
},
|
|
202
|
-
body: JSON.stringify(jsonData),
|
|
203
|
-
signal: controller.signal,
|
|
204
|
-
});
|
|
205
|
-
} catch (fetchError) {
|
|
206
|
-
clearTimeout(timeoutId);
|
|
207
|
-
|
|
208
|
-
if (fetchError.name === 'AbortError') {
|
|
209
|
-
throw new Error(`Request timeout: ${platform} OAuth server took too long to respond`);
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
throw new Error(`Network error: ${fetchError.message || 'Failed to connect to OAuth server'}`);
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
clearTimeout(timeoutId);
|
|
201
|
+
// Make the authenticated request to get the OAuth URL
|
|
202
|
+
const response = await makeAuthenticatedRequest(PLATFORM_AUTH_CONFIG[platform].authEndpoint, {
|
|
203
|
+
method: 'POST',
|
|
204
|
+
body: JSON.stringify(jsonData),
|
|
205
|
+
});
|
|
216
206
|
|
|
217
207
|
console.log(`๐ก ${platform} OAuth response status:`, response.status);
|
|
218
|
-
console.log(`๐ก ${platform} OAuth response headers:`, response.headers);
|
|
219
208
|
|
|
220
209
|
if (!response.ok) {
|
|
221
210
|
const errorText = await response.text();
|
|
@@ -834,45 +823,83 @@ export const requestEmailVerification = async (email: string, testMode = false):
|
|
|
834
823
|
success: boolean;
|
|
835
824
|
message?: string;
|
|
836
825
|
error?: string;
|
|
826
|
+
requestId?: string;
|
|
837
827
|
}> => {
|
|
838
828
|
try {
|
|
839
829
|
console.log('๐ง Requesting email verification for:', email);
|
|
840
|
-
console.log('
|
|
841
|
-
|
|
842
|
-
// Use the correct endpoint: /email/verify
|
|
843
|
-
const response = await fetch('https://api2.onairos.uk/email/verify', {
|
|
844
|
-
method: 'POST',
|
|
845
|
-
headers: {
|
|
846
|
-
'Content-Type': 'application/json',
|
|
847
|
-
},
|
|
848
|
-
body: JSON.stringify({ email }),
|
|
849
|
-
});
|
|
830
|
+
console.log('๐งช Test mode:', testMode);
|
|
850
831
|
|
|
851
|
-
|
|
832
|
+
if (!email || !email.includes('@')) {
|
|
833
|
+
return {
|
|
834
|
+
success: false,
|
|
835
|
+
error: 'Valid email address is required',
|
|
836
|
+
};
|
|
837
|
+
}
|
|
852
838
|
|
|
853
|
-
|
|
854
|
-
|
|
839
|
+
// In test mode, always return success with mock request ID
|
|
840
|
+
if (testMode) {
|
|
841
|
+
console.log('๐งช Test mode: Always returning success with mock request ID');
|
|
842
|
+
const mockRequestId = 'test-request-' + Date.now();
|
|
855
843
|
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
844
|
+
// Store request info for tracking
|
|
845
|
+
await AsyncStorage.setItem('email_verification_request_id', mockRequestId);
|
|
846
|
+
await AsyncStorage.setItem('email_verification_request_email', email);
|
|
859
847
|
|
|
860
848
|
return {
|
|
861
849
|
success: true,
|
|
862
|
-
message,
|
|
850
|
+
message: 'Email verification sent successfully (test mode)',
|
|
851
|
+
requestId: mockRequestId,
|
|
863
852
|
};
|
|
864
|
-
}
|
|
865
|
-
|
|
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);
|
|
866
893
|
return {
|
|
867
894
|
success: false,
|
|
868
|
-
error:
|
|
895
|
+
error: 'Network error while sending verification email',
|
|
869
896
|
};
|
|
870
897
|
}
|
|
871
898
|
} catch (error) {
|
|
872
899
|
console.error('โ Email verification request error:', error);
|
|
873
900
|
return {
|
|
874
901
|
success: false,
|
|
875
|
-
error: error instanceof Error ? error.message : '
|
|
902
|
+
error: error instanceof Error ? error.message : 'Unknown error',
|
|
876
903
|
};
|
|
877
904
|
}
|
|
878
905
|
};
|
|
@@ -882,31 +909,57 @@ export const verifyEmailCode = async (email: string, code: string, testMode = fa
|
|
|
882
909
|
message?: string;
|
|
883
910
|
error?: string;
|
|
884
911
|
existingUser?: boolean;
|
|
912
|
+
jwtToken?: string;
|
|
885
913
|
}> => {
|
|
886
914
|
try {
|
|
887
915
|
console.log('๐ Verifying email code for:', email);
|
|
888
|
-
console.log('
|
|
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
|
+
}
|
|
889
925
|
|
|
890
|
-
|
|
926
|
+
if (!code || code.length < 4) {
|
|
927
|
+
return {
|
|
928
|
+
success: false,
|
|
929
|
+
error: 'Valid verification code is required',
|
|
930
|
+
};
|
|
931
|
+
}
|
|
932
|
+
|
|
933
|
+
// In test mode, always return success with mock JWT token
|
|
891
934
|
if (testMode) {
|
|
892
|
-
console.log('๐งช Test mode:
|
|
893
|
-
|
|
894
|
-
|
|
935
|
+
console.log('๐งช Test mode: Always returning success with mock JWT token');
|
|
936
|
+
const mockToken = 'test-jwt-token-' + Date.now();
|
|
937
|
+
|
|
938
|
+
// Store mock token for API requests
|
|
939
|
+
await AsyncStorage.setItem('email_verification_token', mockToken);
|
|
940
|
+
await AsyncStorage.setItem('onairos_jwt_token', mockToken);
|
|
941
|
+
await AsyncStorage.setItem('email_verification_email', email);
|
|
942
|
+
|
|
895
943
|
return {
|
|
896
944
|
success: true,
|
|
897
|
-
message: 'Email
|
|
898
|
-
existingUser:
|
|
945
|
+
message: 'Email verification successful (test mode)',
|
|
946
|
+
existingUser: false,
|
|
947
|
+
jwtToken: mockToken,
|
|
899
948
|
};
|
|
900
949
|
}
|
|
901
950
|
|
|
902
|
-
// Production mode: Make real API call with
|
|
951
|
+
// Production mode: Make real API call with API key authentication
|
|
903
952
|
try {
|
|
904
|
-
|
|
953
|
+
// ๐ Ensure API key is initialized before making authenticated requests
|
|
954
|
+
await ensureApiKeyInitialized();
|
|
955
|
+
|
|
956
|
+
const response = await makeAuthenticatedRequest('/email/verification', {
|
|
905
957
|
method: 'POST',
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
958
|
+
body: JSON.stringify({
|
|
959
|
+
email,
|
|
960
|
+
code,
|
|
961
|
+
action: 'verify',
|
|
962
|
+
}),
|
|
910
963
|
});
|
|
911
964
|
|
|
912
965
|
const result = await response.json();
|
|
@@ -914,23 +967,40 @@ export const verifyEmailCode = async (email: string, code: string, testMode = fa
|
|
|
914
967
|
|
|
915
968
|
if (response.ok && result.success) {
|
|
916
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
|
+
|
|
917
986
|
return {
|
|
918
987
|
success: true,
|
|
919
|
-
message: result.message || 'Email
|
|
920
|
-
existingUser: result.existingUser || false,
|
|
988
|
+
message: result.message || 'Email verification successful',
|
|
989
|
+
existingUser: result.existingUser || false,
|
|
990
|
+
jwtToken: jwtToken,
|
|
921
991
|
};
|
|
922
992
|
} else {
|
|
923
993
|
console.error('โ Email verification failed:', result.error);
|
|
924
994
|
return {
|
|
925
995
|
success: false,
|
|
926
|
-
error: result.error || '
|
|
996
|
+
error: result.error || 'Email verification failed',
|
|
927
997
|
};
|
|
928
998
|
}
|
|
929
999
|
} catch (apiError) {
|
|
930
1000
|
console.error('โ Email verification API call failed:', apiError);
|
|
931
1001
|
return {
|
|
932
1002
|
success: false,
|
|
933
|
-
error: 'Network error during verification',
|
|
1003
|
+
error: 'Network error during email verification',
|
|
934
1004
|
};
|
|
935
1005
|
}
|
|
936
1006
|
} catch (error) {
|
|
@@ -962,13 +1032,13 @@ export const checkEmailVerificationStatus = async (email: string, testMode = fal
|
|
|
962
1032
|
};
|
|
963
1033
|
}
|
|
964
1034
|
|
|
965
|
-
// Production mode: Make real API call
|
|
1035
|
+
// Production mode: Make real API call with API key authentication
|
|
966
1036
|
try {
|
|
967
|
-
|
|
1037
|
+
// ๐ Ensure API key is initialized before making authenticated requests
|
|
1038
|
+
await ensureApiKeyInitialized();
|
|
1039
|
+
|
|
1040
|
+
const response = await makeAuthenticatedRequest(`/email/verify/status/${encodeURIComponent(email)}`, {
|
|
968
1041
|
method: 'GET',
|
|
969
|
-
headers: {
|
|
970
|
-
'Content-Type': 'application/json',
|
|
971
|
-
},
|
|
972
1042
|
});
|
|
973
1043
|
|
|
974
1044
|
const result = await response.json();
|
|
@@ -1014,41 +1084,208 @@ export const disconnectPlatform = async (platform: string, username: string): Pr
|
|
|
1014
1084
|
error?: string;
|
|
1015
1085
|
}> => {
|
|
1016
1086
|
try {
|
|
1017
|
-
console.log(
|
|
1087
|
+
console.log('๐ Disconnecting platform:', platform, 'for user:', username);
|
|
1088
|
+
|
|
1089
|
+
if (!platform || !username) {
|
|
1090
|
+
return {
|
|
1091
|
+
success: false,
|
|
1092
|
+
error: 'Platform and username are required',
|
|
1093
|
+
};
|
|
1094
|
+
}
|
|
1095
|
+
|
|
1096
|
+
// Make authenticated API call to disconnect platform
|
|
1097
|
+
const response = await makeAuthenticatedRequest('/revoke', {
|
|
1098
|
+
method: 'POST',
|
|
1099
|
+
body: JSON.stringify({
|
|
1100
|
+
platform,
|
|
1101
|
+
username,
|
|
1102
|
+
}),
|
|
1103
|
+
});
|
|
1104
|
+
|
|
1105
|
+
const result = await response.json();
|
|
1106
|
+
console.log('๐ก Platform disconnect API response:', result);
|
|
1107
|
+
|
|
1108
|
+
if (response.ok && result.success) {
|
|
1109
|
+
console.log('โ
Platform disconnected successfully');
|
|
1110
|
+
return {
|
|
1111
|
+
success: true,
|
|
1112
|
+
message: result.message || 'Platform disconnected successfully',
|
|
1113
|
+
};
|
|
1114
|
+
} else {
|
|
1115
|
+
console.error('โ Platform disconnect failed:', result.error);
|
|
1116
|
+
return {
|
|
1117
|
+
success: false,
|
|
1118
|
+
error: result.error || 'Failed to disconnect platform',
|
|
1119
|
+
};
|
|
1120
|
+
}
|
|
1121
|
+
} catch (error) {
|
|
1122
|
+
console.error('โ Platform disconnect error:', error);
|
|
1123
|
+
return {
|
|
1124
|
+
success: false,
|
|
1125
|
+
error: error instanceof Error ? error.message : 'Platform disconnect failed',
|
|
1126
|
+
};
|
|
1127
|
+
}
|
|
1128
|
+
};
|
|
1129
|
+
|
|
1130
|
+
/**
|
|
1131
|
+
* ๐ STORE PIN AFTER BIOMETRIC AUTHENTICATION
|
|
1132
|
+
* Send PIN separately to /store-pin/web endpoint after biometric Face ID verification
|
|
1133
|
+
*/
|
|
1134
|
+
export const storePinAfterBiometric = async (username: string, pin: string, jwtToken?: string): Promise<{
|
|
1135
|
+
success: boolean;
|
|
1136
|
+
message?: string;
|
|
1137
|
+
error?: string;
|
|
1138
|
+
}> => {
|
|
1139
|
+
try {
|
|
1140
|
+
console.log('๐ Storing PIN after biometric authentication for user:', username);
|
|
1141
|
+
console.log('๐ PIN length:', pin.length);
|
|
1142
|
+
console.log('๐ซ JWT token provided:', !!jwtToken);
|
|
1143
|
+
|
|
1144
|
+
if (!username || !pin) {
|
|
1145
|
+
return {
|
|
1146
|
+
success: false,
|
|
1147
|
+
error: 'Username and PIN are required',
|
|
1148
|
+
};
|
|
1149
|
+
}
|
|
1150
|
+
|
|
1151
|
+
if (pin.length < 4) {
|
|
1152
|
+
return {
|
|
1153
|
+
success: false,
|
|
1154
|
+
error: 'PIN must be at least 4 digits',
|
|
1155
|
+
};
|
|
1156
|
+
}
|
|
1157
|
+
|
|
1158
|
+
// Get JWT token from storage if not provided
|
|
1159
|
+
let authToken = jwtToken;
|
|
1160
|
+
if (!authToken) {
|
|
1161
|
+
authToken = await AsyncStorage.getItem('onairos_jwt_token') ||
|
|
1162
|
+
await AsyncStorage.getItem('enoch_token') ||
|
|
1163
|
+
await AsyncStorage.getItem('auth_token') ||
|
|
1164
|
+
await AsyncStorage.getItem('email_verification_token');
|
|
1165
|
+
}
|
|
1166
|
+
|
|
1167
|
+
if (!authToken) {
|
|
1168
|
+
console.warn('โ ๏ธ No JWT token available for PIN storage');
|
|
1169
|
+
return {
|
|
1170
|
+
success: false,
|
|
1171
|
+
error: 'No authentication token available',
|
|
1172
|
+
};
|
|
1173
|
+
}
|
|
1174
|
+
|
|
1175
|
+
console.log('๐ค Sending PIN to /store-pin/web endpoint');
|
|
1018
1176
|
|
|
1019
|
-
|
|
1177
|
+
// Make authenticated request to store PIN
|
|
1178
|
+
const response = await makeAuthenticatedRequest('/store-pin/web', {
|
|
1020
1179
|
method: 'POST',
|
|
1021
1180
|
headers: {
|
|
1022
|
-
'
|
|
1181
|
+
'Authorization': `Bearer ${authToken}`,
|
|
1023
1182
|
},
|
|
1024
1183
|
body: JSON.stringify({
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
username: username,
|
|
1028
|
-
},
|
|
1184
|
+
username,
|
|
1185
|
+
pin,
|
|
1029
1186
|
}),
|
|
1030
1187
|
});
|
|
1031
1188
|
|
|
1189
|
+
console.log('๐ก PIN storage response status:', response.status);
|
|
1190
|
+
|
|
1191
|
+
if (!response.ok) {
|
|
1192
|
+
const errorText = await response.text();
|
|
1193
|
+
console.error('โ PIN storage failed:', errorText);
|
|
1194
|
+
return {
|
|
1195
|
+
success: false,
|
|
1196
|
+
error: `PIN storage failed: ${response.status} - ${errorText}`,
|
|
1197
|
+
};
|
|
1198
|
+
}
|
|
1199
|
+
|
|
1032
1200
|
const result = await response.json();
|
|
1201
|
+
console.log('๐ฅ PIN storage response:', result);
|
|
1033
1202
|
|
|
1034
|
-
if (
|
|
1035
|
-
console.log(
|
|
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
|
+
|
|
1036
1210
|
return {
|
|
1037
1211
|
success: true,
|
|
1038
|
-
message: result.message ||
|
|
1212
|
+
message: result.message || 'PIN stored successfully',
|
|
1039
1213
|
};
|
|
1040
1214
|
} else {
|
|
1041
|
-
console.error(
|
|
1215
|
+
console.error('โ PIN storage API returned error:', result.error);
|
|
1042
1216
|
return {
|
|
1043
1217
|
success: false,
|
|
1044
|
-
error: result.error ||
|
|
1218
|
+
error: result.error || 'PIN storage failed',
|
|
1045
1219
|
};
|
|
1046
1220
|
}
|
|
1047
1221
|
} catch (error) {
|
|
1048
|
-
console.error(
|
|
1222
|
+
console.error('โ Error storing PIN after biometric authentication:', error);
|
|
1049
1223
|
return {
|
|
1050
1224
|
success: false,
|
|
1051
|
-
error: error instanceof Error ? error.message : '
|
|
1225
|
+
error: error instanceof Error ? error.message : 'PIN storage failed',
|
|
1052
1226
|
};
|
|
1053
1227
|
}
|
|
1054
1228
|
};
|
|
1229
|
+
|
|
1230
|
+
/**
|
|
1231
|
+
* ๐ซ GET STORED JWT TOKEN
|
|
1232
|
+
* Helper function to retrieve stored JWT token from email verification or other sources
|
|
1233
|
+
*/
|
|
1234
|
+
export const getStoredJwtToken = async (): Promise<string | null> => {
|
|
1235
|
+
try {
|
|
1236
|
+
console.log('๐ซ Retrieving stored JWT token...');
|
|
1237
|
+
|
|
1238
|
+
// Try different storage keys in order of preference
|
|
1239
|
+
const tokenSources = [
|
|
1240
|
+
'email_verification_token',
|
|
1241
|
+
'onairos_jwt_token',
|
|
1242
|
+
'enoch_token',
|
|
1243
|
+
'auth_token',
|
|
1244
|
+
];
|
|
1245
|
+
|
|
1246
|
+
for (const source of tokenSources) {
|
|
1247
|
+
const token = await AsyncStorage.getItem(source);
|
|
1248
|
+
if (token && token.length > 20) {
|
|
1249
|
+
console.log(`โ
JWT token found in ${source}:`, token.substring(0, 20) + '...');
|
|
1250
|
+
return token;
|
|
1251
|
+
}
|
|
1252
|
+
}
|
|
1253
|
+
|
|
1254
|
+
console.warn('โ ๏ธ No JWT token found in storage');
|
|
1255
|
+
return null;
|
|
1256
|
+
} catch (error) {
|
|
1257
|
+
console.error('โ Error retrieving JWT token:', error);
|
|
1258
|
+
return null;
|
|
1259
|
+
}
|
|
1260
|
+
};
|
|
1261
|
+
|
|
1262
|
+
/**
|
|
1263
|
+
* ๐ซ CLEAR STORED TOKENS
|
|
1264
|
+
* Helper function to clear all stored tokens (useful for logout)
|
|
1265
|
+
*/
|
|
1266
|
+
export const clearStoredTokens = async (): Promise<void> => {
|
|
1267
|
+
try {
|
|
1268
|
+
console.log('๐งน Clearing all stored tokens...');
|
|
1269
|
+
|
|
1270
|
+
const tokenKeys = [
|
|
1271
|
+
'email_verification_token',
|
|
1272
|
+
'onairos_jwt_token',
|
|
1273
|
+
'enoch_token',
|
|
1274
|
+
'auth_token',
|
|
1275
|
+
'email_verification_email',
|
|
1276
|
+
'email_verification_request_id',
|
|
1277
|
+
'email_verification_request_email',
|
|
1278
|
+
'token_timestamp',
|
|
1279
|
+
'user_pin_stored',
|
|
1280
|
+
'pin_storage_timestamp',
|
|
1281
|
+
];
|
|
1282
|
+
|
|
1283
|
+
await Promise.all(
|
|
1284
|
+
tokenKeys.map(key => AsyncStorage.removeItem(key))
|
|
1285
|
+
);
|
|
1286
|
+
|
|
1287
|
+
console.log('โ
All tokens cleared successfully');
|
|
1288
|
+
} catch (error) {
|
|
1289
|
+
console.error('โ Error clearing tokens:', error);
|
|
1290
|
+
}
|
|
1291
|
+
};
|