@onairos/react-native 2.0.8 → 2.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.
- package/lib/commonjs/components/OnairosButton.js +60 -23
- package/lib/commonjs/components/OnairosButton.js.map +1 -1
- package/lib/commonjs/components/Overlay.js +37 -24
- package/lib/commonjs/components/Overlay.js.map +1 -1
- package/lib/commonjs/utils/secureStorage.js +14 -103
- package/lib/commonjs/utils/secureStorage.js.map +1 -1
- package/lib/module/components/OnairosButton.js +60 -23
- package/lib/module/components/OnairosButton.js.map +1 -1
- package/lib/module/components/Overlay.js +39 -24
- package/lib/module/components/Overlay.js.map +1 -1
- package/lib/module/index.js +8 -31
- package/lib/module/index.js.map +1 -1
- package/lib/module/utils/secureStorage.js +14 -102
- package/lib/module/utils/secureStorage.js.map +1 -1
- package/package.json +1 -1
- package/src/components/OnairosButton.tsx +78 -31
- package/src/components/Overlay.tsx +32 -19
- package/src/utils/secureStorage.ts +14 -104
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import React, { useState } from 'react';
|
|
2
|
-
import { TouchableOpacity, Text, StyleSheet, View, ViewStyle, TextStyle } from 'react-native';
|
|
2
|
+
import { TouchableOpacity, Text, StyleSheet, View, ViewStyle, TextStyle, Image } from 'react-native';
|
|
3
3
|
import { UniversalOnboarding } from './UniversalOnboarding';
|
|
4
|
+
import { Overlay } from './Overlay';
|
|
4
5
|
import { COLORS } from '../constants';
|
|
5
6
|
import type { OnairosButtonProps } from '../types';
|
|
7
|
+
import { hasCredentials, getCredentials } from '../utils/secureStorage';
|
|
6
8
|
|
|
7
9
|
export const OnairosButton: React.FC<OnairosButtonProps> = ({
|
|
8
10
|
returnLink,
|
|
@@ -10,9 +12,9 @@ export const OnairosButton: React.FC<OnairosButtonProps> = ({
|
|
|
10
12
|
AppName,
|
|
11
13
|
buttonType = 'normal',
|
|
12
14
|
requestData,
|
|
13
|
-
buttonWidth =
|
|
14
|
-
buttonHeight,
|
|
15
|
-
hasStroke =
|
|
15
|
+
buttonWidth = 240,
|
|
16
|
+
buttonHeight = 48,
|
|
17
|
+
hasStroke = true,
|
|
16
18
|
enabled = true,
|
|
17
19
|
buttonForm = 'default',
|
|
18
20
|
onRejection,
|
|
@@ -25,7 +27,11 @@ export const OnairosButton: React.FC<OnairosButtonProps> = ({
|
|
|
25
27
|
testMode = false,
|
|
26
28
|
}) => {
|
|
27
29
|
const [showOnboarding, setShowOnboarding] = useState(false);
|
|
30
|
+
const [showOverlay, setShowOverlay] = useState(false);
|
|
31
|
+
const [storedCredentials, setStoredCredentials] = useState<any>(null);
|
|
28
32
|
|
|
33
|
+
const isDarkMode = color === 'black' || (!color && !hasStroke);
|
|
34
|
+
|
|
29
35
|
const handlePress = async () => {
|
|
30
36
|
if (!enabled) return;
|
|
31
37
|
|
|
@@ -37,28 +43,48 @@ export const OnairosButton: React.FC<OnairosButtonProps> = ({
|
|
|
37
43
|
}
|
|
38
44
|
}
|
|
39
45
|
|
|
40
|
-
|
|
46
|
+
// Check if credentials exist
|
|
47
|
+
const hasStoredCreds = await hasCredentials();
|
|
48
|
+
|
|
49
|
+
if (hasStoredCreds) {
|
|
50
|
+
// If credentials exist, fetch them and display overlay
|
|
51
|
+
const credentials = await getCredentials();
|
|
52
|
+
setStoredCredentials(credentials);
|
|
53
|
+
setShowOverlay(true);
|
|
54
|
+
} else {
|
|
55
|
+
// If no credentials, show onboarding
|
|
56
|
+
setShowOnboarding(true);
|
|
57
|
+
}
|
|
41
58
|
};
|
|
42
59
|
|
|
43
60
|
const handleOnboardingComplete = (apiUrl: string, token: string, data: any) => {
|
|
44
61
|
setShowOnboarding(false);
|
|
45
62
|
onResolved?.(apiUrl, token, data);
|
|
46
63
|
};
|
|
64
|
+
|
|
65
|
+
const handleOverlayResolved = (apiUrl: string, token: string, data: any) => {
|
|
66
|
+
setShowOverlay(false);
|
|
67
|
+
onResolved?.(apiUrl, token, data);
|
|
68
|
+
};
|
|
47
69
|
|
|
70
|
+
// Calculate button styles based on props
|
|
48
71
|
const buttonStyle: ViewStyle[] = [
|
|
49
72
|
styles.button,
|
|
50
73
|
buttonType === 'pill' && styles.pillButton,
|
|
51
74
|
hasStroke && styles.strokedButton,
|
|
52
|
-
{
|
|
53
|
-
|
|
75
|
+
{
|
|
76
|
+
width: buttonWidth,
|
|
77
|
+
height: buttonHeight
|
|
78
|
+
},
|
|
54
79
|
color ? { backgroundColor: color } : null,
|
|
80
|
+
isDarkMode ? styles.darkButton : styles.lightButton,
|
|
55
81
|
swerv && styles.swervButton,
|
|
56
82
|
].filter(Boolean) as ViewStyle[];
|
|
57
83
|
|
|
84
|
+
// Calculate text styles based on props
|
|
58
85
|
const textStyle: TextStyle[] = [
|
|
59
86
|
styles.buttonText,
|
|
60
|
-
|
|
61
|
-
color ? styles.customColorText : null,
|
|
87
|
+
isDarkMode ? styles.lightText : styles.darkText,
|
|
62
88
|
].filter(Boolean) as TextStyle[];
|
|
63
89
|
|
|
64
90
|
return (
|
|
@@ -67,36 +93,49 @@ export const OnairosButton: React.FC<OnairosButtonProps> = ({
|
|
|
67
93
|
style={buttonStyle}
|
|
68
94
|
onPress={handlePress}
|
|
69
95
|
disabled={!enabled}
|
|
96
|
+
accessibilityLabel={`Sign in with Onairos`}
|
|
70
97
|
>
|
|
71
|
-
|
|
98
|
+
{/* Optional Onairos logo could be added here */}
|
|
99
|
+
<Text style={textStyle}>Sign in with Onairos</Text>
|
|
72
100
|
</TouchableOpacity>
|
|
73
101
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
102
|
+
{showOnboarding && (
|
|
103
|
+
<UniversalOnboarding
|
|
104
|
+
visible={showOnboarding}
|
|
105
|
+
onClose={() => setShowOnboarding(false)}
|
|
106
|
+
AppName={AppName}
|
|
107
|
+
requestData={requestData}
|
|
108
|
+
returnLink={returnLink}
|
|
109
|
+
onComplete={handleOnboardingComplete}
|
|
110
|
+
preferredPlatform={preferredPlatform}
|
|
111
|
+
debug={debug}
|
|
112
|
+
test={testMode}
|
|
113
|
+
/>
|
|
114
|
+
)}
|
|
115
|
+
|
|
116
|
+
{showOverlay && storedCredentials && (
|
|
117
|
+
<Overlay
|
|
118
|
+
data={requestData || {}}
|
|
119
|
+
username={storedCredentials.username}
|
|
120
|
+
modelKey={storedCredentials.userPin || ''}
|
|
121
|
+
onResolved={handleOverlayResolved}
|
|
122
|
+
/>
|
|
123
|
+
)}
|
|
85
124
|
</View>
|
|
86
125
|
);
|
|
87
126
|
};
|
|
88
127
|
|
|
89
128
|
const styles = StyleSheet.create({
|
|
90
129
|
button: {
|
|
91
|
-
|
|
92
|
-
paddingVertical: 12,
|
|
93
|
-
paddingHorizontal: 24,
|
|
94
|
-
borderRadius: 8,
|
|
130
|
+
flexDirection: 'row',
|
|
95
131
|
alignItems: 'center',
|
|
96
132
|
justifyContent: 'center',
|
|
133
|
+
paddingVertical: 12,
|
|
134
|
+
paddingHorizontal: 16,
|
|
135
|
+
borderRadius: 4,
|
|
97
136
|
},
|
|
98
137
|
pillButton: {
|
|
99
|
-
borderRadius:
|
|
138
|
+
borderRadius: 24,
|
|
100
139
|
},
|
|
101
140
|
strokedButton: {
|
|
102
141
|
backgroundColor: 'transparent',
|
|
@@ -106,15 +145,23 @@ const styles = StyleSheet.create({
|
|
|
106
145
|
swervButton: {
|
|
107
146
|
transform: [{ rotate: '-2deg' }],
|
|
108
147
|
},
|
|
148
|
+
darkButton: {
|
|
149
|
+
backgroundColor: '#000',
|
|
150
|
+
borderColor: '#000',
|
|
151
|
+
},
|
|
152
|
+
lightButton: {
|
|
153
|
+
backgroundColor: '#fff',
|
|
154
|
+
borderColor: '#000',
|
|
155
|
+
},
|
|
109
156
|
buttonText: {
|
|
110
|
-
color: '#fff',
|
|
111
157
|
fontSize: 16,
|
|
112
158
|
fontWeight: '600',
|
|
159
|
+
textAlign: 'center',
|
|
113
160
|
},
|
|
114
|
-
|
|
115
|
-
color: '#000',
|
|
116
|
-
},
|
|
117
|
-
customColorText: {
|
|
161
|
+
lightText: {
|
|
118
162
|
color: '#fff',
|
|
119
163
|
},
|
|
164
|
+
darkText: {
|
|
165
|
+
color: '#000',
|
|
166
|
+
},
|
|
120
167
|
});
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import React, { useState, useEffect } from 'react';
|
|
1
|
+
import React, { useState, useEffect, useRef } from 'react';
|
|
2
2
|
import {
|
|
3
3
|
View,
|
|
4
4
|
Text,
|
|
@@ -7,9 +7,10 @@ import {
|
|
|
7
7
|
ScrollView,
|
|
8
8
|
Alert,
|
|
9
9
|
Platform,
|
|
10
|
+
Dimensions,
|
|
10
11
|
} from 'react-native';
|
|
11
12
|
import { BottomSheetModal, BottomSheetBackdrop } from '@gorhom/bottom-sheet';
|
|
12
|
-
import DeviceInfo from 'react-native-device-info';
|
|
13
|
+
// import DeviceInfo from 'react-native-device-info'; // Comment out device info import
|
|
13
14
|
import { COLORS } from '../constants';
|
|
14
15
|
import { onairosApi } from '../api';
|
|
15
16
|
import { encryptModelKey, getServerPublicKey } from '../utils/encryption';
|
|
@@ -35,7 +36,8 @@ export const Overlay: React.FC<OverlayProps> = ({
|
|
|
35
36
|
}) => {
|
|
36
37
|
const [selections, setSelections] = useState<{ [key: string]: boolean }>({});
|
|
37
38
|
const [details, setDetails] = useState<string>('');
|
|
38
|
-
const bottomSheetRef =
|
|
39
|
+
const bottomSheetRef = useRef<BottomSheetModal>(null);
|
|
40
|
+
const snapPoints = ['60%']; // Set to 60% of screen height
|
|
39
41
|
|
|
40
42
|
useEffect(() => {
|
|
41
43
|
// Initialize selection state
|
|
@@ -45,6 +47,11 @@ export const Overlay: React.FC<OverlayProps> = ({
|
|
|
45
47
|
});
|
|
46
48
|
setSelections(initialSelections);
|
|
47
49
|
getDetails();
|
|
50
|
+
|
|
51
|
+
// Present the bottom sheet when component mounts
|
|
52
|
+
setTimeout(() => {
|
|
53
|
+
bottomSheetRef.current?.present();
|
|
54
|
+
}, 100);
|
|
48
55
|
}, []);
|
|
49
56
|
|
|
50
57
|
const getDetails = async () => {
|
|
@@ -66,17 +73,12 @@ export const Overlay: React.FC<OverlayProps> = ({
|
|
|
66
73
|
|
|
67
74
|
const confirmSelection = async () => {
|
|
68
75
|
try {
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
default: 'unknown'
|
|
76
|
-
});
|
|
77
|
-
} catch (e) {
|
|
78
|
-
console.warn('Failed to get app identifier:', e);
|
|
79
|
-
}
|
|
76
|
+
// Mock app identifier
|
|
77
|
+
const appId = Platform.select({
|
|
78
|
+
ios: 'com.onairos.mock',
|
|
79
|
+
android: 'com.onairos.mock',
|
|
80
|
+
default: 'unknown'
|
|
81
|
+
});
|
|
80
82
|
|
|
81
83
|
const serverPublicKey = await getServerPublicKey();
|
|
82
84
|
const encryptedModelKey = encryptModelKey(serverPublicKey, modelKey);
|
|
@@ -98,7 +100,7 @@ export const Overlay: React.FC<OverlayProps> = ({
|
|
|
98
100
|
closeOverlay();
|
|
99
101
|
}
|
|
100
102
|
} catch (e) {
|
|
101
|
-
console.error('Error
|
|
103
|
+
console.error('Error confirming selection:', e);
|
|
102
104
|
showErrorModal('Failed to confirm selection. Please try again.');
|
|
103
105
|
}
|
|
104
106
|
};
|
|
@@ -112,14 +114,19 @@ export const Overlay: React.FC<OverlayProps> = ({
|
|
|
112
114
|
return (
|
|
113
115
|
<BottomSheetModal
|
|
114
116
|
ref={bottomSheetRef}
|
|
115
|
-
snapPoints={
|
|
117
|
+
snapPoints={snapPoints}
|
|
118
|
+
handleIndicatorStyle={styles.handleIndicator}
|
|
116
119
|
backdropComponent={(props) => (
|
|
117
120
|
<BottomSheetBackdrop
|
|
118
121
|
{...props}
|
|
119
122
|
appearsOnIndex={0}
|
|
120
123
|
disappearsOnIndex={-1}
|
|
124
|
+
opacity={0.7}
|
|
121
125
|
/>
|
|
122
126
|
)}
|
|
127
|
+
enablePanDownToClose={true}
|
|
128
|
+
keyboardBehavior="interactive"
|
|
129
|
+
keyboardBlurBehavior="restore"
|
|
123
130
|
>
|
|
124
131
|
<View style={styles.container}>
|
|
125
132
|
<View style={styles.header}>
|
|
@@ -184,12 +191,18 @@ export const Overlay: React.FC<OverlayProps> = ({
|
|
|
184
191
|
);
|
|
185
192
|
};
|
|
186
193
|
|
|
194
|
+
const { width: SCREEN_WIDTH } = Dimensions.get('window');
|
|
195
|
+
|
|
187
196
|
const styles = StyleSheet.create({
|
|
188
197
|
container: {
|
|
189
198
|
flex: 1,
|
|
190
199
|
backgroundColor: COLORS.white,
|
|
191
|
-
|
|
192
|
-
|
|
200
|
+
width: SCREEN_WIDTH,
|
|
201
|
+
},
|
|
202
|
+
handleIndicator: {
|
|
203
|
+
backgroundColor: '#999',
|
|
204
|
+
width: 40,
|
|
205
|
+
height: 5,
|
|
193
206
|
},
|
|
194
207
|
header: {
|
|
195
208
|
flexDirection: 'row',
|
|
@@ -212,7 +225,7 @@ const styles = StyleSheet.create({
|
|
|
212
225
|
},
|
|
213
226
|
username: {
|
|
214
227
|
fontSize: 18,
|
|
215
|
-
color: COLORS.
|
|
228
|
+
color: COLORS.white,
|
|
216
229
|
},
|
|
217
230
|
content: {
|
|
218
231
|
flex: 1,
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import * as Keychain from 'react-native-keychain';
|
|
2
1
|
import { Platform } from 'react-native';
|
|
3
2
|
import { sha256 } from './crypto';
|
|
4
3
|
|
|
@@ -24,56 +23,19 @@ export interface StorageOptions {
|
|
|
24
23
|
};
|
|
25
24
|
}
|
|
26
25
|
|
|
27
|
-
|
|
26
|
+
// Temporary in-memory storage
|
|
27
|
+
let mockStorage: { [key: string]: string } = {};
|
|
28
28
|
|
|
29
29
|
/**
|
|
30
|
-
* Store credentials
|
|
30
|
+
* Store credentials in memory (temporary solution)
|
|
31
31
|
*/
|
|
32
32
|
export const storeCredentials = async (
|
|
33
33
|
credentials: OnairosCredentials,
|
|
34
34
|
options: StorageOptions = {}
|
|
35
35
|
): Promise<boolean> => {
|
|
36
36
|
try {
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
// Create a JSON string of the credentials
|
|
40
|
-
const credentialsString = JSON.stringify(credentials);
|
|
41
|
-
|
|
42
|
-
// Configure security options based on platform
|
|
43
|
-
const securityOptions: Keychain.Options = {
|
|
44
|
-
service: CREDENTIALS_KEY,
|
|
45
|
-
accessible: Keychain.ACCESSIBLE.WHEN_UNLOCKED_THIS_DEVICE_ONLY,
|
|
46
|
-
};
|
|
47
|
-
|
|
48
|
-
// Add biometric protection if requested
|
|
49
|
-
if (useBiometrics) {
|
|
50
|
-
// iOS specific options
|
|
51
|
-
if (Platform.OS === 'ios') {
|
|
52
|
-
securityOptions.accessControl = Keychain.ACCESS_CONTROL.BIOMETRY_ANY_OR_DEVICE_PASSCODE;
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
// Android specific options
|
|
56
|
-
if (Platform.OS === 'android') {
|
|
57
|
-
securityOptions.accessControl = Keychain.ACCESS_CONTROL.BIOMETRY_ANY;
|
|
58
|
-
if (biometricPrompt) {
|
|
59
|
-
securityOptions.authenticationType = Keychain.AUTHENTICATION_TYPE.BIOMETRIC;
|
|
60
|
-
securityOptions.authenticationPrompt = {
|
|
61
|
-
title: biometricPrompt.title || 'Biometric Authentication',
|
|
62
|
-
subtitle: biometricPrompt.subtitle,
|
|
63
|
-
description: 'Please authenticate to access your Onairos credentials',
|
|
64
|
-
cancel: 'Cancel',
|
|
65
|
-
};
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
// Store in the secure keychain
|
|
71
|
-
await Keychain.setGenericPassword(
|
|
72
|
-
credentials.username,
|
|
73
|
-
credentialsString,
|
|
74
|
-
securityOptions
|
|
75
|
-
);
|
|
76
|
-
|
|
37
|
+
console.log('[Mock] Storing credentials:', credentials.username);
|
|
38
|
+
mockStorage[credentials.username] = JSON.stringify(credentials);
|
|
77
39
|
return true;
|
|
78
40
|
} catch (error) {
|
|
79
41
|
console.error('Error storing credentials:', error);
|
|
@@ -82,39 +44,18 @@ export const storeCredentials = async (
|
|
|
82
44
|
};
|
|
83
45
|
|
|
84
46
|
/**
|
|
85
|
-
* Retrieve credentials from
|
|
47
|
+
* Retrieve credentials from memory (temporary solution)
|
|
86
48
|
*/
|
|
87
49
|
export const getCredentials = async (
|
|
88
50
|
options: StorageOptions = {}
|
|
89
51
|
): Promise<OnairosCredentials | null> => {
|
|
90
52
|
try {
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
const securityOptions: Keychain.Options = {
|
|
95
|
-
service: CREDENTIALS_KEY,
|
|
96
|
-
};
|
|
97
|
-
|
|
98
|
-
// Add biometric prompt if required
|
|
99
|
-
if (useBiometrics && biometricPrompt) {
|
|
100
|
-
securityOptions.authenticationPrompt = {
|
|
101
|
-
title: biometricPrompt.title || 'Biometric Authentication',
|
|
102
|
-
subtitle: biometricPrompt.subtitle,
|
|
103
|
-
description: 'Please authenticate to access your Onairos credentials',
|
|
104
|
-
cancel: 'Cancel',
|
|
105
|
-
};
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
// Retrieve from keychain
|
|
109
|
-
const result = await Keychain.getGenericPassword(securityOptions);
|
|
110
|
-
|
|
111
|
-
if (!result) {
|
|
53
|
+
// Get the first stored credential (temporary solution)
|
|
54
|
+
const storedCredential = Object.values(mockStorage)[0];
|
|
55
|
+
if (!storedCredential) {
|
|
112
56
|
return null;
|
|
113
57
|
}
|
|
114
|
-
|
|
115
|
-
// Parse the stored JSON
|
|
116
|
-
const credentials: OnairosCredentials = JSON.parse(result.password);
|
|
117
|
-
return credentials;
|
|
58
|
+
return JSON.parse(storedCredential);
|
|
118
59
|
} catch (error) {
|
|
119
60
|
console.error('Error retrieving credentials:', error);
|
|
120
61
|
return null;
|
|
@@ -126,11 +67,7 @@ export const getCredentials = async (
|
|
|
126
67
|
*/
|
|
127
68
|
export const hasCredentials = async (): Promise<boolean> => {
|
|
128
69
|
try {
|
|
129
|
-
|
|
130
|
-
service: CREDENTIALS_KEY,
|
|
131
|
-
});
|
|
132
|
-
|
|
133
|
-
return !!result;
|
|
70
|
+
return Object.keys(mockStorage).length > 0;
|
|
134
71
|
} catch (error) {
|
|
135
72
|
console.error('Error checking for credentials:', error);
|
|
136
73
|
return false;
|
|
@@ -142,7 +79,7 @@ export const hasCredentials = async (): Promise<boolean> => {
|
|
|
142
79
|
*/
|
|
143
80
|
export const deleteCredentials = async (): Promise<boolean> => {
|
|
144
81
|
try {
|
|
145
|
-
|
|
82
|
+
mockStorage = {};
|
|
146
83
|
return true;
|
|
147
84
|
} catch (error) {
|
|
148
85
|
console.error('Error deleting credentials:', error);
|
|
@@ -158,20 +95,14 @@ export const updateCredentials = async (
|
|
|
158
95
|
options: StorageOptions = {}
|
|
159
96
|
): Promise<boolean> => {
|
|
160
97
|
try {
|
|
161
|
-
// Get current credentials
|
|
162
98
|
const currentCredentials = await getCredentials(options);
|
|
163
|
-
|
|
164
99
|
if (!currentCredentials) {
|
|
165
100
|
return false;
|
|
166
101
|
}
|
|
167
|
-
|
|
168
|
-
// Merge updates with current credentials
|
|
169
102
|
const updatedCredentials: OnairosCredentials = {
|
|
170
103
|
...currentCredentials,
|
|
171
104
|
...updates,
|
|
172
105
|
};
|
|
173
|
-
|
|
174
|
-
// Store updated credentials
|
|
175
106
|
return await storeCredentials(updatedCredentials, options);
|
|
176
107
|
} catch (error) {
|
|
177
108
|
console.error('Error updating credentials:', error);
|
|
@@ -184,44 +115,23 @@ export const updateCredentials = async (
|
|
|
184
115
|
*/
|
|
185
116
|
export const generateDeviceUsername = async (): Promise<string> => {
|
|
186
117
|
try {
|
|
187
|
-
// Get a device-specific identifier that we can use
|
|
188
|
-
// This is a simplified example - in production you might want to use
|
|
189
|
-
// a more robust device identifier method
|
|
190
118
|
const deviceInfo = `${Platform.OS}-${Platform.Version}-${Date.now()}`;
|
|
191
|
-
|
|
192
|
-
// Hash it to create a unique identifier
|
|
193
119
|
const username = `onairos_${sha256(deviceInfo).substring(0, 10)}`;
|
|
194
|
-
|
|
195
120
|
return username;
|
|
196
121
|
} catch (error) {
|
|
197
122
|
console.error('Error generating device username:', error);
|
|
198
|
-
// Fallback to a timestamp-based username if there's an error
|
|
199
123
|
return `onairos_${Date.now().toString(36)}`;
|
|
200
124
|
}
|
|
201
125
|
};
|
|
202
126
|
|
|
203
127
|
/**
|
|
204
|
-
* Verify
|
|
128
|
+
* Verify credentials (temporary mock implementation)
|
|
205
129
|
*/
|
|
206
130
|
export const verifyCredentials = async (
|
|
207
131
|
credentials: OnairosCredentials
|
|
208
132
|
): Promise<boolean> => {
|
|
209
133
|
try {
|
|
210
|
-
|
|
211
|
-
if (!credentials || !credentials.accessToken || !credentials.username) {
|
|
212
|
-
return false;
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
// Check for expiration (example: credentials expire after 30 days)
|
|
216
|
-
const thirtyDaysMs = 30 * 24 * 60 * 60 * 1000;
|
|
217
|
-
const isExpired = Date.now() - credentials.createdAt > thirtyDaysMs;
|
|
218
|
-
|
|
219
|
-
if (isExpired) {
|
|
220
|
-
return false;
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
// Add any additional verification logic here
|
|
224
|
-
|
|
134
|
+
console.log('[Mock] Verifying credentials for:', credentials.username);
|
|
225
135
|
return true;
|
|
226
136
|
} catch (error) {
|
|
227
137
|
console.error('Error verifying credentials:', error);
|