@onairos/react-native 3.1.0 → 3.1.2
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/UniversalOnboarding.js +22 -4
- package/lib/commonjs/components/UniversalOnboarding.js.map +1 -1
- package/lib/commonjs/index.js +13 -35
- package/lib/commonjs/index.js.map +1 -1
- package/lib/commonjs/services/apiKeyService.js +133 -10
- package/lib/commonjs/services/apiKeyService.js.map +1 -1
- package/lib/commonjs/services/platformAuthService.js +26 -11
- package/lib/commonjs/services/platformAuthService.js.map +1 -1
- package/lib/commonjs/types.js.map +1 -1
- package/lib/commonjs/utils/onairosApi.js +14 -6
- package/lib/commonjs/utils/onairosApi.js.map +1 -1
- package/lib/module/components/UniversalOnboarding.js +22 -4
- package/lib/module/components/UniversalOnboarding.js.map +1 -1
- package/lib/module/index.js +1 -1
- package/lib/module/index.js.map +1 -1
- package/lib/module/services/apiKeyService.js +128 -8
- package/lib/module/services/apiKeyService.js.map +1 -1
- package/lib/module/services/platformAuthService.js +27 -12
- package/lib/module/services/platformAuthService.js.map +1 -1
- package/lib/module/types.js.map +1 -1
- package/lib/module/utils/onairosApi.js +15 -7
- package/lib/module/utils/onairosApi.js.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 +18 -0
- package/lib/typescript/services/apiKeyService.d.ts.map +1 -1
- package/lib/typescript/services/platformAuthService.d.ts +3 -3
- package/lib/typescript/services/platformAuthService.d.ts.map +1 -1
- package/lib/typescript/types/index.d.ts +1 -0
- package/lib/typescript/types/index.d.ts.map +1 -1
- package/lib/typescript/types.d.ts +2 -0
- package/lib/typescript/types.d.ts.map +1 -1
- package/lib/typescript/utils/onairosApi.d.ts +4 -3
- package/lib/typescript/utils/onairosApi.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/components/UniversalOnboarding.tsx +23 -4
- package/src/index.ts +3 -0
- package/src/services/apiKeyService.ts +130 -0
- package/src/services/platformAuthService.ts +29 -11
- package/src/types/index.d.ts +5 -0
- package/src/types/index.ts +1 -0
- package/src/types.ts +2 -0
- package/src/utils/onairosApi.ts +17 -6
package/src/index.ts
CHANGED
|
@@ -352,6 +352,136 @@ export const clearJWT = async (): Promise<void> => {
|
|
|
352
352
|
}
|
|
353
353
|
};
|
|
354
354
|
|
|
355
|
+
/**
|
|
356
|
+
* React Native compatible base64 decoder
|
|
357
|
+
* @param str Base64 encoded string
|
|
358
|
+
* @returns Decoded string
|
|
359
|
+
*/
|
|
360
|
+
const base64Decode = (str: string): string => {
|
|
361
|
+
// Simple base64 decoding for React Native
|
|
362
|
+
const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
|
|
363
|
+
let result = '';
|
|
364
|
+
let i = 0;
|
|
365
|
+
|
|
366
|
+
str = str.replace(/[^A-Za-z0-9+/]/g, '');
|
|
367
|
+
|
|
368
|
+
while (i < str.length) {
|
|
369
|
+
const a = chars.indexOf(str.charAt(i++));
|
|
370
|
+
const b = chars.indexOf(str.charAt(i++));
|
|
371
|
+
const c = chars.indexOf(str.charAt(i++));
|
|
372
|
+
const d = chars.indexOf(str.charAt(i++));
|
|
373
|
+
|
|
374
|
+
const bitmap = (a << 18) | (b << 12) | (c << 6) | d;
|
|
375
|
+
|
|
376
|
+
result += String.fromCharCode((bitmap >> 16) & 255);
|
|
377
|
+
if (c !== 64) result += String.fromCharCode((bitmap >> 8) & 255);
|
|
378
|
+
if (d !== 64) result += String.fromCharCode(bitmap & 255);
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
return result;
|
|
382
|
+
};
|
|
383
|
+
|
|
384
|
+
/**
|
|
385
|
+
* Decode JWT token payload (React Native compatible)
|
|
386
|
+
* @param token JWT token string
|
|
387
|
+
* @returns Decoded payload or null if invalid
|
|
388
|
+
*/
|
|
389
|
+
export const decodeJWTPayload = (token: string): any => {
|
|
390
|
+
try {
|
|
391
|
+
// Split JWT token (header.payload.signature)
|
|
392
|
+
const parts = token.split('.');
|
|
393
|
+
if (parts.length !== 3) {
|
|
394
|
+
console.error('❌ Invalid JWT token format');
|
|
395
|
+
return null;
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
// Decode payload (base64url to base64)
|
|
399
|
+
const payload = parts[1];
|
|
400
|
+
const base64 = payload.replace(/-/g, '+').replace(/_/g, '/');
|
|
401
|
+
|
|
402
|
+
// Add padding if needed
|
|
403
|
+
const padded = base64.padEnd(Math.ceil(base64.length / 4) * 4, '=');
|
|
404
|
+
|
|
405
|
+
// Decode base64 to JSON using React Native compatible decoder
|
|
406
|
+
const decoded = base64Decode(padded);
|
|
407
|
+
return JSON.parse(decoded);
|
|
408
|
+
} catch (error) {
|
|
409
|
+
console.error('❌ Failed to decode JWT token:', error);
|
|
410
|
+
return null;
|
|
411
|
+
}
|
|
412
|
+
};
|
|
413
|
+
|
|
414
|
+
/**
|
|
415
|
+
* Extract username from JWT token
|
|
416
|
+
* @param token JWT token (optional, uses stored token if not provided)
|
|
417
|
+
* @returns Username or null if not found
|
|
418
|
+
*/
|
|
419
|
+
export const extractUsernameFromJWT = (token?: string): string | null => {
|
|
420
|
+
try {
|
|
421
|
+
const jwtToken = token || userToken;
|
|
422
|
+
if (!jwtToken) {
|
|
423
|
+
console.warn('⚠️ No JWT token available for username extraction');
|
|
424
|
+
return null;
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
const payload = decodeJWTPayload(jwtToken);
|
|
428
|
+
if (!payload) {
|
|
429
|
+
return null;
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
// Try different possible username fields in order of preference
|
|
433
|
+
const username = payload.userName || payload.username || payload.userId || payload.email;
|
|
434
|
+
|
|
435
|
+
if (globalConfig?.enableLogging) {
|
|
436
|
+
console.log('👤 Extracted username from JWT:', username);
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
return username || null;
|
|
440
|
+
} catch (error) {
|
|
441
|
+
console.error('❌ Failed to extract username from JWT:', error);
|
|
442
|
+
return null;
|
|
443
|
+
}
|
|
444
|
+
};
|
|
445
|
+
|
|
446
|
+
/**
|
|
447
|
+
* Extract user data from JWT token
|
|
448
|
+
* @param token JWT token (optional, uses stored token if not provided)
|
|
449
|
+
* @returns User data object or null if not found
|
|
450
|
+
*/
|
|
451
|
+
export const extractUserDataFromJWT = (token?: string): any => {
|
|
452
|
+
try {
|
|
453
|
+
const jwtToken = token || userToken;
|
|
454
|
+
if (!jwtToken) {
|
|
455
|
+
console.warn('⚠️ No JWT token available for user data extraction');
|
|
456
|
+
return null;
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
const payload = decodeJWTPayload(jwtToken);
|
|
460
|
+
if (!payload) {
|
|
461
|
+
return null;
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
const userData = {
|
|
465
|
+
id: payload.id,
|
|
466
|
+
email: payload.email,
|
|
467
|
+
userId: payload.userId,
|
|
468
|
+
userName: payload.userName || payload.username,
|
|
469
|
+
verified: payload.verified,
|
|
470
|
+
iat: payload.iat,
|
|
471
|
+
exp: payload.exp
|
|
472
|
+
};
|
|
473
|
+
|
|
474
|
+
if (globalConfig?.enableLogging) {
|
|
475
|
+
console.log('👤 Extracted user data from JWT:', userData);
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
return userData;
|
|
479
|
+
} catch (error) {
|
|
480
|
+
console.error('❌ Failed to extract user data from JWT:', error);
|
|
481
|
+
return null;
|
|
482
|
+
}
|
|
483
|
+
};
|
|
484
|
+
|
|
355
485
|
/**
|
|
356
486
|
* Check if user is authenticated with JWT token
|
|
357
487
|
* @returns True if user has valid JWT token
|
|
@@ -1,7 +1,7 @@
|
|
|
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 { makeDeveloperRequest, getApiConfig, storeJWT } from './apiKeyService';
|
|
4
|
+
import { makeDeveloperRequest, getApiConfig, storeJWT, extractUsernameFromJWT } from './apiKeyService';
|
|
5
5
|
|
|
6
6
|
// 🔑 CRITICAL: Use two-tier authentication system
|
|
7
7
|
// - Developer API key for email verification requests
|
|
@@ -332,16 +332,20 @@ export const initiateNativeAuth = async (platform: string, username?: string): P
|
|
|
332
332
|
|
|
333
333
|
// Configure Google Sign-In with better error handling
|
|
334
334
|
try {
|
|
335
|
+
const youtubeConfig = PLATFORM_AUTH_CONFIG.youtube;
|
|
336
|
+
const webClientId = youtubeConfig.clientId || '1030678346906-lovkuds2ouqmoc8eu5qpo98spa6edv4o.apps.googleusercontent.com';
|
|
337
|
+
const iosClientId = youtubeConfig.iosClientId || webClientId;
|
|
338
|
+
|
|
335
339
|
await GoogleSignin.configure({
|
|
336
|
-
webClientId:
|
|
337
|
-
iosClientId:
|
|
340
|
+
webClientId: webClientId,
|
|
341
|
+
iosClientId: iosClientId,
|
|
338
342
|
scopes: ['https://www.googleapis.com/auth/youtube.readonly'],
|
|
339
343
|
offlineAccess: true,
|
|
340
344
|
hostedDomain: '',
|
|
341
345
|
forceCodeForRefreshToken: true,
|
|
342
346
|
accountName: '',
|
|
343
347
|
});
|
|
344
|
-
console.log('✅ Google Sign-In configured successfully');
|
|
348
|
+
console.log('✅ Google Sign-In configured successfully with client ID:', webClientId.substring(0, 20) + '...');
|
|
345
349
|
} catch (configError) {
|
|
346
350
|
console.error('❌ Google Sign-In configuration failed:', configError);
|
|
347
351
|
throw new Error(`Google Sign-In configuration failed: ${configError.message || configError}`);
|
|
@@ -794,9 +798,12 @@ export const updateGoogleClientIds = (config: {
|
|
|
794
798
|
PLATFORM_AUTH_CONFIG.youtube = {
|
|
795
799
|
...PLATFORM_AUTH_CONFIG.youtube,
|
|
796
800
|
clientId: config.webClientId || PLATFORM_AUTH_CONFIG.youtube.clientId,
|
|
801
|
+
iosClientId: config.iosClientId || PLATFORM_AUTH_CONFIG.youtube.iosClientId,
|
|
797
802
|
};
|
|
798
803
|
|
|
799
804
|
console.log('✅ Google client IDs updated successfully');
|
|
805
|
+
console.log(' - Web Client ID:', config.webClientId ? config.webClientId.substring(0, 20) + '...' : 'not provided');
|
|
806
|
+
console.log(' - iOS Client ID:', config.iosClientId ? config.iosClientId.substring(0, 20) + '...' : 'not provided');
|
|
800
807
|
}
|
|
801
808
|
};
|
|
802
809
|
|
|
@@ -989,23 +996,34 @@ export const disconnectPlatform = async (platform: string, username: string): Pr
|
|
|
989
996
|
};
|
|
990
997
|
|
|
991
998
|
/**
|
|
992
|
-
* Store PIN for user (uses
|
|
993
|
-
* @param username Username
|
|
999
|
+
* Store PIN for user (uses JWT authentication and extracts username from JWT)
|
|
994
1000
|
* @param pin User PIN
|
|
1001
|
+
* @param username Optional username (if not provided, extracts from JWT)
|
|
995
1002
|
* @returns Promise with result
|
|
996
1003
|
*/
|
|
997
|
-
export const storePIN = async (
|
|
1004
|
+
export const storePIN = async (pin: string, username?: string): Promise<{ success: boolean; error?: string }> => {
|
|
998
1005
|
try {
|
|
999
|
-
|
|
1006
|
+
// Extract username from JWT if not provided
|
|
1007
|
+
const userToStore = username || extractUsernameFromJWT();
|
|
1008
|
+
|
|
1009
|
+
if (!userToStore) {
|
|
1010
|
+
console.error('❌ No username available - either provide username or ensure JWT token is valid');
|
|
1011
|
+
return {
|
|
1012
|
+
success: false,
|
|
1013
|
+
error: 'No username available for PIN storage'
|
|
1014
|
+
};
|
|
1015
|
+
}
|
|
1016
|
+
|
|
1017
|
+
console.log('🔐 Storing PIN for user:', userToStore);
|
|
1000
1018
|
|
|
1001
|
-
// Make authenticated request to store PIN
|
|
1019
|
+
// Make authenticated request to store PIN (using developer API key for now)
|
|
1002
1020
|
const response = await makeDeveloperRequest('/store-pin/web', {
|
|
1003
1021
|
method: 'POST',
|
|
1004
1022
|
headers: {
|
|
1005
1023
|
'Content-Type': 'application/json',
|
|
1006
1024
|
},
|
|
1007
1025
|
body: JSON.stringify({
|
|
1008
|
-
username,
|
|
1026
|
+
username: userToStore,
|
|
1009
1027
|
pin
|
|
1010
1028
|
})
|
|
1011
1029
|
});
|
|
@@ -1013,7 +1031,7 @@ export const storePIN = async (username: string, pin: string): Promise<{ success
|
|
|
1013
1031
|
const data = await response.json();
|
|
1014
1032
|
|
|
1015
1033
|
if (response.ok && data.success) {
|
|
1016
|
-
console.log('✅ PIN stored successfully');
|
|
1034
|
+
console.log('✅ PIN stored successfully for user:', userToStore);
|
|
1017
1035
|
return { success: true };
|
|
1018
1036
|
} else {
|
|
1019
1037
|
console.error('❌ Failed to store PIN:', data.error);
|
package/src/types/index.d.ts
CHANGED
|
@@ -243,6 +243,11 @@ declare module '@onairos/react-native' {
|
|
|
243
243
|
// SDK Initialization Functions
|
|
244
244
|
export function initializeApiKey(config: any): Promise<void>;
|
|
245
245
|
export const ADMIN_API_KEY: string;
|
|
246
|
+
|
|
247
|
+
// JWT Token Functions
|
|
248
|
+
export function extractUsernameFromJWT(token?: string): string | null;
|
|
249
|
+
export function extractUserDataFromJWT(token?: string): any;
|
|
250
|
+
export function decodeJWTPayload(token: string): any;
|
|
246
251
|
|
|
247
252
|
// Programmatic Flow
|
|
248
253
|
export function executeOnairosFlow(config: any): Promise<any>;
|
package/src/types/index.ts
CHANGED
package/src/types.ts
CHANGED
|
@@ -18,6 +18,7 @@ export interface TestModeOptions {
|
|
|
18
18
|
// Optional tweaks
|
|
19
19
|
fastTraining?: boolean; // Speed up training simulation
|
|
20
20
|
skipRealConnections?: boolean; // Allow mock platform connections
|
|
21
|
+
skipApiCalls?: boolean; // Skip API calls entirely (for pure UI testing)
|
|
21
22
|
}
|
|
22
23
|
|
|
23
24
|
export interface ApiKeyConfig {
|
|
@@ -239,6 +240,7 @@ export interface PlatformAuthConfig {
|
|
|
239
240
|
authEndpoint: string;
|
|
240
241
|
color: string;
|
|
241
242
|
clientId?: string;
|
|
243
|
+
iosClientId?: string;
|
|
242
244
|
redirectUri?: string;
|
|
243
245
|
scope?: string;
|
|
244
246
|
responseType?: string;
|
package/src/utils/onairosApi.ts
CHANGED
|
@@ -2,7 +2,7 @@ import { Platform } from 'react-native';
|
|
|
2
2
|
import NetInfo from '@react-native-community/netinfo';
|
|
3
3
|
import { OnairosCredentials } from './secureStorage';
|
|
4
4
|
import { logDebug } from './debugHelper';
|
|
5
|
-
import { getJWT, makeUserRequest, makeDeveloperRequest, isUserAuthenticated } from '../services/apiKeyService';
|
|
5
|
+
import { getJWT, makeUserRequest, makeDeveloperRequest, isUserAuthenticated, extractUsernameFromJWT } from '../services/apiKeyService';
|
|
6
6
|
|
|
7
7
|
// API response types
|
|
8
8
|
export interface ApiResponse<T = any> {
|
|
@@ -352,16 +352,27 @@ export const updatePlatformConnections = async (
|
|
|
352
352
|
};
|
|
353
353
|
|
|
354
354
|
/**
|
|
355
|
-
* Store user PIN (uses JWT)
|
|
355
|
+
* Store user PIN (uses JWT and extracts username from JWT)
|
|
356
356
|
*/
|
|
357
357
|
export const storePIN = async (
|
|
358
|
-
username: string,
|
|
359
358
|
pin: string,
|
|
360
|
-
options
|
|
359
|
+
options: { debug?: boolean; username?: string } = {}
|
|
361
360
|
): Promise<ApiResponse<any>> => {
|
|
361
|
+
const { debug = false, username } = options;
|
|
362
|
+
|
|
363
|
+
// Extract username from JWT if not provided
|
|
364
|
+
const userToStore = username || extractUsernameFromJWT();
|
|
365
|
+
|
|
366
|
+
if (!userToStore) {
|
|
367
|
+
throw new ApiError(
|
|
368
|
+
'No username available - either provide username or ensure JWT token is valid',
|
|
369
|
+
'auth_error'
|
|
370
|
+
);
|
|
371
|
+
}
|
|
372
|
+
|
|
362
373
|
return makeUserApiRequest('store-pin/mobile', 'POST', {
|
|
363
|
-
data: { username, pin },
|
|
364
|
-
debug
|
|
374
|
+
data: { username: userToStore, pin },
|
|
375
|
+
debug,
|
|
365
376
|
});
|
|
366
377
|
};
|
|
367
378
|
|