@oxyhq/services 5.15.9 → 5.16.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/core/OxyServices.js +0 -1
- package/lib/commonjs/core/OxyServices.js.map +1 -1
- package/lib/commonjs/core/mixins/OxyServices.auth.js +3 -6
- package/lib/commonjs/core/mixins/OxyServices.auth.js.map +1 -1
- package/lib/commonjs/core/mixins/OxyServices.devices.js +1 -1
- package/lib/commonjs/core/mixins/OxyServices.devices.js.map +1 -1
- package/lib/commonjs/core/mixins/index.js +11 -12
- package/lib/commonjs/core/mixins/index.js.map +1 -1
- package/lib/commonjs/crypto/signatureService.js +3 -2
- package/lib/commonjs/crypto/signatureService.js.map +1 -1
- package/lib/commonjs/i18n/locales/ar-SA.json +1 -9
- package/lib/commonjs/i18n/locales/ca-ES.json +1 -9
- package/lib/commonjs/i18n/locales/de-DE.json +1 -9
- package/lib/commonjs/i18n/locales/en-US.json +3 -21
- package/lib/commonjs/i18n/locales/es-ES.json +3 -21
- package/lib/commonjs/i18n/locales/fr-FR.json +1 -9
- package/lib/commonjs/i18n/locales/it-IT.json +1 -9
- package/lib/commonjs/i18n/locales/ja-JP.json +1 -9
- package/lib/commonjs/i18n/locales/ko-KR.json +1 -9
- package/lib/commonjs/i18n/locales/pt-PT.json +1 -9
- package/lib/commonjs/i18n/locales/zh-CN.json +1 -9
- package/lib/commonjs/ui/context/OxyContext.js +24 -4
- package/lib/commonjs/ui/context/OxyContext.js.map +1 -1
- package/lib/commonjs/ui/context/hooks/useAuthOperations.js +217 -100
- package/lib/commonjs/ui/context/hooks/useAuthOperations.js.map +1 -1
- package/lib/commonjs/ui/screens/AccountSettingsScreen.js +2 -319
- package/lib/commonjs/ui/screens/AccountSettingsScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/OxyAuthScreen.js +16 -7
- package/lib/commonjs/ui/screens/OxyAuthScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/PrivacySettingsScreen.js +0 -1
- package/lib/commonjs/ui/screens/PrivacySettingsScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/SessionManagementScreen.js +43 -29
- package/lib/commonjs/ui/screens/SessionManagementScreen.js.map +1 -1
- package/lib/commonjs/ui/stores/authStore.js +14 -1
- package/lib/commonjs/ui/stores/authStore.js.map +1 -1
- package/lib/module/core/OxyServices.js +0 -1
- package/lib/module/core/OxyServices.js.map +1 -1
- package/lib/module/core/mixins/OxyServices.auth.js +3 -6
- package/lib/module/core/mixins/OxyServices.auth.js.map +1 -1
- package/lib/module/core/mixins/OxyServices.devices.js +1 -1
- package/lib/module/core/mixins/OxyServices.devices.js.map +1 -1
- package/lib/module/core/mixins/index.js +1 -2
- package/lib/module/core/mixins/index.js.map +1 -1
- package/lib/module/crypto/signatureService.js +3 -2
- package/lib/module/crypto/signatureService.js.map +1 -1
- package/lib/module/i18n/locales/ar-SA.json +1 -9
- package/lib/module/i18n/locales/ca-ES.json +1 -9
- package/lib/module/i18n/locales/de-DE.json +1 -9
- package/lib/module/i18n/locales/en-US.json +3 -21
- package/lib/module/i18n/locales/es-ES.json +3 -21
- package/lib/module/i18n/locales/fr-FR.json +1 -9
- package/lib/module/i18n/locales/it-IT.json +1 -9
- package/lib/module/i18n/locales/ja-JP.json +1 -9
- package/lib/module/i18n/locales/ko-KR.json +1 -9
- package/lib/module/i18n/locales/pt-PT.json +1 -9
- package/lib/module/i18n/locales/zh-CN.json +1 -9
- package/lib/module/ui/context/OxyContext.js +24 -4
- package/lib/module/ui/context/OxyContext.js.map +1 -1
- package/lib/module/ui/context/hooks/useAuthOperations.js +217 -100
- package/lib/module/ui/context/hooks/useAuthOperations.js.map +1 -1
- package/lib/module/ui/screens/AccountSettingsScreen.js +2 -319
- package/lib/module/ui/screens/AccountSettingsScreen.js.map +1 -1
- package/lib/module/ui/screens/OxyAuthScreen.js +16 -7
- package/lib/module/ui/screens/OxyAuthScreen.js.map +1 -1
- package/lib/module/ui/screens/PrivacySettingsScreen.js +0 -1
- package/lib/module/ui/screens/PrivacySettingsScreen.js.map +1 -1
- package/lib/module/ui/screens/SessionManagementScreen.js +44 -29
- package/lib/module/ui/screens/SessionManagementScreen.js.map +1 -1
- package/lib/module/ui/stores/authStore.js +14 -1
- package/lib/module/ui/stores/authStore.js.map +1 -1
- package/lib/typescript/core/OxyServices.d.ts +0 -1
- package/lib/typescript/core/OxyServices.d.ts.map +1 -1
- package/lib/typescript/core/mixins/OxyServices.auth.d.ts +3 -4
- package/lib/typescript/core/mixins/OxyServices.auth.d.ts.map +1 -1
- package/lib/typescript/core/mixins/OxyServices.devices.d.ts +1 -4
- package/lib/typescript/core/mixins/OxyServices.devices.d.ts.map +1 -1
- package/lib/typescript/core/mixins/index.d.ts +1 -64
- package/lib/typescript/core/mixins/index.d.ts.map +1 -1
- package/lib/typescript/crypto/signatureService.d.ts +2 -1
- package/lib/typescript/crypto/signatureService.d.ts.map +1 -1
- package/lib/typescript/models/interfaces.d.ts +1 -1
- package/lib/typescript/models/interfaces.d.ts.map +1 -1
- package/lib/typescript/types/bip39.d.ts +1 -0
- package/lib/typescript/types/buffer.d.ts +1 -0
- package/lib/typescript/types/color.d.ts +1 -0
- package/lib/typescript/types/elliptic.d.ts +1 -0
- package/lib/typescript/types/expo-crypto.d.ts +1 -0
- package/lib/typescript/types/expo-secure-store.d.ts +1 -0
- package/lib/typescript/ui/context/OxyContext.d.ts +11 -3
- package/lib/typescript/ui/context/OxyContext.d.ts.map +1 -1
- package/lib/typescript/ui/context/hooks/useAuthOperations.d.ts +13 -5
- package/lib/typescript/ui/context/hooks/useAuthOperations.d.ts.map +1 -1
- package/lib/typescript/ui/screens/AccountSettingsScreen.d.ts.map +1 -1
- package/lib/typescript/ui/screens/OxyAuthScreen.d.ts.map +1 -1
- package/lib/typescript/ui/screens/PrivacySettingsScreen.d.ts.map +1 -1
- package/lib/typescript/ui/screens/SessionManagementScreen.d.ts.map +1 -1
- package/lib/typescript/ui/stores/authStore.d.ts +4 -0
- package/lib/typescript/ui/stores/authStore.d.ts.map +1 -1
- package/package.json +6 -5
- package/src/core/OxyServices.ts +0 -1
- package/src/core/mixins/OxyServices.auth.ts +3 -8
- package/src/core/mixins/OxyServices.devices.ts +1 -4
- package/src/core/mixins/index.ts +2 -5
- package/src/crypto/index.ts +1 -0
- package/src/crypto/keyManager.ts +1 -0
- package/src/crypto/polyfill.ts +1 -0
- package/src/crypto/recoveryPhrase.ts +1 -0
- package/src/crypto/signatureService.ts +4 -5
- package/src/i18n/locales/ar-SA.json +1 -9
- package/src/i18n/locales/ca-ES.json +1 -9
- package/src/i18n/locales/de-DE.json +1 -9
- package/src/i18n/locales/en-US.json +3 -21
- package/src/i18n/locales/es-ES.json +3 -21
- package/src/i18n/locales/fr-FR.json +1 -9
- package/src/i18n/locales/it-IT.json +1 -9
- package/src/i18n/locales/ja-JP.json +1 -9
- package/src/i18n/locales/ko-KR.json +1 -9
- package/src/i18n/locales/pt-PT.json +1 -9
- package/src/i18n/locales/zh-CN.json +1 -9
- package/src/models/interfaces.ts +1 -1
- package/src/types/bip39.d.ts +1 -0
- package/src/types/buffer.d.ts +1 -0
- package/src/types/color.d.ts +1 -0
- package/src/types/elliptic.d.ts +1 -0
- package/src/types/expo-crypto.d.ts +1 -0
- package/src/types/expo-secure-store.d.ts +1 -0
- package/src/ui/context/OxyContext.tsx +35 -3
- package/src/ui/context/hooks/useAuthOperations.ts +212 -98
- package/src/ui/screens/AccountSettingsScreen.tsx +1 -201
- package/src/ui/screens/OxyAuthScreen.tsx +16 -8
- package/src/ui/screens/PrivacySettingsScreen.tsx +0 -2
- package/src/ui/screens/SessionManagementScreen.tsx +43 -26
- package/src/ui/stores/authStore.ts +31 -2
- package/lib/commonjs/core/mixins/OxyServices.totp.js +0 -53
- package/lib/commonjs/core/mixins/OxyServices.totp.js.map +0 -1
- package/lib/commonjs/ui/components/profile/TwoFactorSetupModal.js +0 -467
- package/lib/commonjs/ui/components/profile/TwoFactorSetupModal.js.map +0 -1
- package/lib/module/core/mixins/OxyServices.totp.js +0 -49
- package/lib/module/core/mixins/OxyServices.totp.js.map +0 -1
- package/lib/module/ui/components/profile/TwoFactorSetupModal.js +0 -460
- package/lib/module/ui/components/profile/TwoFactorSetupModal.js.map +0 -1
- package/lib/typescript/core/mixins/OxyServices.totp.d.ts +0 -66
- package/lib/typescript/core/mixins/OxyServices.totp.d.ts.map +0 -1
- package/lib/typescript/ui/components/profile/TwoFactorSetupModal.d.ts +0 -11
- package/lib/typescript/ui/components/profile/TwoFactorSetupModal.d.ts.map +0 -1
- package/src/core/mixins/OxyServices.totp.ts +0 -36
- package/src/ui/components/profile/TwoFactorSetupModal.tsx +0 -442
|
@@ -36,10 +36,8 @@ import { EditEmailModal } from '../components/profile/EditEmailModal';
|
|
|
36
36
|
import { EditBioModal } from '../components/profile/EditBioModal';
|
|
37
37
|
import { EditLocationModal } from '../components/profile/EditLocationModal';
|
|
38
38
|
import { EditLinksModal } from '../components/profile/EditLinksModal';
|
|
39
|
-
import { TwoFactorSetupModal } from '../components/profile/TwoFactorSetupModal';
|
|
40
39
|
import { getDisplayName } from '../utils/user-utils';
|
|
41
40
|
import { TTLCache, registerCacheForCleanup } from '../../utils/cache';
|
|
42
|
-
import QRCode from 'react-native-qrcode-svg';
|
|
43
41
|
import { useOxy } from '../context/OxyContext';
|
|
44
42
|
import {
|
|
45
43
|
SCREEN_PADDING_HORIZONTAL,
|
|
@@ -102,13 +100,6 @@ const AccountSettingsScreen: React.FC<BaseScreenProps & { initialField?: string;
|
|
|
102
100
|
const [quickActionsSectionY, setQuickActionsSectionY] = useState<number | null>(null);
|
|
103
101
|
const [securitySectionY, setSecuritySectionY] = useState<number | null>(null);
|
|
104
102
|
|
|
105
|
-
// Two-Factor (TOTP) state
|
|
106
|
-
const [totpSetupUrl, setTotpSetupUrl] = useState<string | null>(null);
|
|
107
|
-
const [totpCode, setTotpCode] = useState('');
|
|
108
|
-
const [isTotpBusy, setIsTotpBusy] = useState(false);
|
|
109
|
-
const [showRecoveryModal, setShowRecoveryModal] = useState(false);
|
|
110
|
-
const [generatedBackupCodes, setGeneratedBackupCodes] = useState<string[] | null>(null);
|
|
111
|
-
const [generatedRecoveryKey, setGeneratedRecoveryKey] = useState<string | null>(null);
|
|
112
103
|
|
|
113
104
|
// Animation refs
|
|
114
105
|
const saveButtonScale = useRef(new Animated.Value(1)).current;
|
|
@@ -130,7 +121,6 @@ const AccountSettingsScreen: React.FC<BaseScreenProps & { initialField?: string;
|
|
|
130
121
|
const [showEditBioModal, setShowEditBioModal] = useState(false);
|
|
131
122
|
const [showEditLocationModal, setShowEditLocationModal] = useState(false);
|
|
132
123
|
const [showEditLinksModal, setShowEditLinksModal] = useState(false);
|
|
133
|
-
const [showTwoFactorModal, setShowTwoFactorModal] = useState(false);
|
|
134
124
|
|
|
135
125
|
// Location and links state (for display only - modals handle editing)
|
|
136
126
|
const [locations, setLocations] = useState<Array<{
|
|
@@ -342,9 +332,6 @@ const AccountSettingsScreen: React.FC<BaseScreenProps & { initialField?: string;
|
|
|
342
332
|
case 'links':
|
|
343
333
|
setTempLinksWithMetadata([...linksMetadata]);
|
|
344
334
|
break;
|
|
345
|
-
case 'twoFactor':
|
|
346
|
-
// No temp state needed for twoFactor
|
|
347
|
-
break;
|
|
348
335
|
}
|
|
349
336
|
}, [displayName, lastName, username, email, bio, locations, linksMetadata]);
|
|
350
337
|
|
|
@@ -423,8 +410,6 @@ const AccountSettingsScreen: React.FC<BaseScreenProps & { initialField?: string;
|
|
|
423
410
|
return bio;
|
|
424
411
|
case 'location':
|
|
425
412
|
case 'links':
|
|
426
|
-
case 'twoFactor':
|
|
427
|
-
return '';
|
|
428
413
|
default:
|
|
429
414
|
return '';
|
|
430
415
|
}
|
|
@@ -529,7 +514,6 @@ const AccountSettingsScreen: React.FC<BaseScreenProps & { initialField?: string;
|
|
|
529
514
|
const handleOpenBioModal = useCallback(() => setShowEditBioModal(true), []);
|
|
530
515
|
const handleOpenLocationModal = useCallback(() => setShowEditLocationModal(true), []);
|
|
531
516
|
const handleOpenLinksModal = useCallback(() => setShowEditLinksModal(true), []);
|
|
532
|
-
const handleOpenTwoFactorModal = useCallback(() => setShowTwoFactorModal(true), []);
|
|
533
517
|
|
|
534
518
|
// Handler to refresh data after modal saves
|
|
535
519
|
// Note: Access user directly from store when invoked to get latest value,
|
|
@@ -611,9 +595,6 @@ const AccountSettingsScreen: React.FC<BaseScreenProps & { initialField?: string;
|
|
|
611
595
|
case 'links':
|
|
612
596
|
setShowEditLinksModal(true);
|
|
613
597
|
break;
|
|
614
|
-
case 'twoFactor':
|
|
615
|
-
setShowTwoFactorModal(true);
|
|
616
|
-
break;
|
|
617
598
|
}
|
|
618
599
|
}, 300);
|
|
619
600
|
}
|
|
@@ -760,135 +741,9 @@ const AccountSettingsScreen: React.FC<BaseScreenProps & { initialField?: string;
|
|
|
760
741
|
// Memoize display name for avatar
|
|
761
742
|
const displayNameForAvatar = useMemo(() => getDisplayName(user), [user]);
|
|
762
743
|
|
|
763
|
-
// Legacy renderEditingField function (
|
|
744
|
+
// Legacy renderEditingField function (fallback)
|
|
764
745
|
const renderEditingField = (type: string | null) => {
|
|
765
746
|
if (!type) return null;
|
|
766
|
-
|
|
767
|
-
if (type === 'twoFactor') {
|
|
768
|
-
const enabled = !!user?.privacySettings?.twoFactorEnabled;
|
|
769
|
-
return (
|
|
770
|
-
<View style={[styles.editingFieldContainer, { backgroundColor: colors.background }]}>
|
|
771
|
-
<View style={styles.editingFieldContent}>
|
|
772
|
-
<View style={styles.newValueSection}>
|
|
773
|
-
<View style={styles.editingFieldHeader}>
|
|
774
|
-
<Text style={[styles.editingFieldLabel, { color: colors.text }]}>Two‑Factor Authentication (TOTP)</Text>
|
|
775
|
-
</View>
|
|
776
|
-
|
|
777
|
-
{!enabled ? (
|
|
778
|
-
<>
|
|
779
|
-
<Text style={styles.editingFieldDescription}>
|
|
780
|
-
Protect your account with a 6‑digit code from an authenticator app. Scan the QR code then enter the code to enable.
|
|
781
|
-
</Text>
|
|
782
|
-
{!totpSetupUrl ? (
|
|
783
|
-
<TouchableOpacity
|
|
784
|
-
style={[styles.primaryButton, { backgroundColor: colors.iconSecurity }]}
|
|
785
|
-
disabled={isTotpBusy}
|
|
786
|
-
onPress={async () => {
|
|
787
|
-
if (!activeSessionId) { toast.error(t('editProfile.toasts.noActiveSession') || 'No active session'); return; }
|
|
788
|
-
setIsTotpBusy(true);
|
|
789
|
-
try {
|
|
790
|
-
const { otpauthUrl } = await oxyServices.startTotpEnrollment(activeSessionId);
|
|
791
|
-
setTotpSetupUrl(otpauthUrl);
|
|
792
|
-
} catch (e: any) {
|
|
793
|
-
toast.error(e?.message || (t('editProfile.toasts.totpStartFailed') || 'Failed to start TOTP enrollment'));
|
|
794
|
-
} finally {
|
|
795
|
-
setIsTotpBusy(false);
|
|
796
|
-
}
|
|
797
|
-
}}
|
|
798
|
-
>
|
|
799
|
-
<Ionicons name="shield-checkmark" size={18} color="#fff" />
|
|
800
|
-
<Text style={styles.primaryButtonText}>Generate QR Code</Text>
|
|
801
|
-
</TouchableOpacity>
|
|
802
|
-
) : (
|
|
803
|
-
<View style={{ alignItems: 'center', gap: 16 }}>
|
|
804
|
-
<View style={{ padding: 16, backgroundColor: '#fff', borderRadius: 16 }}>
|
|
805
|
-
<QRCode value={totpSetupUrl} size={180} />
|
|
806
|
-
</View>
|
|
807
|
-
<View>
|
|
808
|
-
<Text style={styles.editingFieldLabel}>Enter 6‑digit code</Text>
|
|
809
|
-
<TextInput
|
|
810
|
-
style={styles.editingFieldInput}
|
|
811
|
-
keyboardType="number-pad"
|
|
812
|
-
placeholder="123456"
|
|
813
|
-
value={totpCode}
|
|
814
|
-
onChangeText={setTotpCode}
|
|
815
|
-
maxLength={6}
|
|
816
|
-
/>
|
|
817
|
-
</View>
|
|
818
|
-
<TouchableOpacity
|
|
819
|
-
style={[styles.primaryButton, { backgroundColor: colors.iconSecurity }]}
|
|
820
|
-
disabled={isTotpBusy || totpCode.length !== 6}
|
|
821
|
-
onPress={async () => {
|
|
822
|
-
if (!activeSessionId) { toast.error(t('editProfile.toasts.noActiveSession') || 'No active session'); return; }
|
|
823
|
-
setIsTotpBusy(true);
|
|
824
|
-
try {
|
|
825
|
-
const result = await oxyServices.verifyTotpEnrollment(activeSessionId, totpCode);
|
|
826
|
-
await updateUser({ privacySettings: { twoFactorEnabled: true } }, oxyServices);
|
|
827
|
-
if (result?.backupCodes || result?.recoveryKey) {
|
|
828
|
-
setGeneratedBackupCodes(result.backupCodes || null);
|
|
829
|
-
setGeneratedRecoveryKey(result.recoveryKey || null);
|
|
830
|
-
setShowRecoveryModal(true);
|
|
831
|
-
} else {
|
|
832
|
-
toast.success(t('editProfile.toasts.twoFactorEnabled') || 'Two‑Factor Authentication enabled');
|
|
833
|
-
setEditingField(null);
|
|
834
|
-
}
|
|
835
|
-
} catch (e: any) {
|
|
836
|
-
toast.error(e?.message || (t('editProfile.toasts.invalidCode') || 'Invalid code'));
|
|
837
|
-
} finally {
|
|
838
|
-
setIsTotpBusy(false);
|
|
839
|
-
}
|
|
840
|
-
}}
|
|
841
|
-
>
|
|
842
|
-
<Ionicons name="checkmark-circle" size={18} color="#fff" />
|
|
843
|
-
<Text style={styles.primaryButtonText}>Verify & Enable</Text>
|
|
844
|
-
</TouchableOpacity>
|
|
845
|
-
</View>
|
|
846
|
-
)}
|
|
847
|
-
</>
|
|
848
|
-
) : (
|
|
849
|
-
<>
|
|
850
|
-
<Text style={styles.editingFieldDescription}>
|
|
851
|
-
Two‑Factor Authentication is currently enabled. To disable, enter a code from your authenticator app.
|
|
852
|
-
</Text>
|
|
853
|
-
<View>
|
|
854
|
-
<Text style={styles.editingFieldLabel}>Enter 6‑digit code</Text>
|
|
855
|
-
<TextInput
|
|
856
|
-
style={styles.editingFieldInput}
|
|
857
|
-
keyboardType="number-pad"
|
|
858
|
-
placeholder="123456"
|
|
859
|
-
value={totpCode}
|
|
860
|
-
onChangeText={setTotpCode}
|
|
861
|
-
maxLength={6}
|
|
862
|
-
/>
|
|
863
|
-
</View>
|
|
864
|
-
<TouchableOpacity
|
|
865
|
-
style={[styles.primaryButton, { backgroundColor: colors.sidebarIconSharing }]}
|
|
866
|
-
disabled={isTotpBusy || totpCode.length !== 6}
|
|
867
|
-
onPress={async () => {
|
|
868
|
-
if (!activeSessionId) { toast.error(t('editProfile.toasts.noActiveSession') || 'No active session'); return; }
|
|
869
|
-
setIsTotpBusy(true);
|
|
870
|
-
try {
|
|
871
|
-
await oxyServices.disableTotp(activeSessionId, totpCode);
|
|
872
|
-
await updateUser({ privacySettings: { twoFactorEnabled: false } }, oxyServices);
|
|
873
|
-
toast.success(t('editProfile.toasts.twoFactorDisabled') || 'Two‑Factor Authentication disabled');
|
|
874
|
-
setEditingField(null);
|
|
875
|
-
} catch (e: any) {
|
|
876
|
-
toast.error(e?.message || t('editProfile.toasts.disableFailed') || 'Failed to disable');
|
|
877
|
-
} finally {
|
|
878
|
-
setIsTotpBusy(false);
|
|
879
|
-
}
|
|
880
|
-
}}
|
|
881
|
-
>
|
|
882
|
-
<Ionicons name="close-circle" size={18} color="#fff" />
|
|
883
|
-
<Text style={styles.primaryButtonText}>Disable 2FA</Text>
|
|
884
|
-
</TouchableOpacity>
|
|
885
|
-
</>
|
|
886
|
-
)}
|
|
887
|
-
</View>
|
|
888
|
-
</View>
|
|
889
|
-
</View>
|
|
890
|
-
);
|
|
891
|
-
}
|
|
892
747
|
if (type === 'displayName') {
|
|
893
748
|
return (
|
|
894
749
|
<View style={[styles.editingFieldContainer, { backgroundColor: colors.background }]}>
|
|
@@ -1368,41 +1223,6 @@ const AccountSettingsScreen: React.FC<BaseScreenProps & { initialField?: string;
|
|
|
1368
1223
|
</Text>
|
|
1369
1224
|
</View>
|
|
1370
1225
|
|
|
1371
|
-
{showRecoveryModal && (
|
|
1372
|
-
<View style={{ position: 'absolute', top: 0, left: 0, right: 0, bottom: 0, backgroundColor: 'rgba(0,0,0,0.6)', zIndex: 50, padding: 16, justifyContent: 'center' }}>
|
|
1373
|
-
<View style={{ backgroundColor: '#fff', borderRadius: 20, padding: 20, maxHeight: '80%' }}>
|
|
1374
|
-
<Text style={{ fontSize: 18, fontWeight: '700', marginBottom: 12 }}>Save These Codes Now</Text>
|
|
1375
|
-
<Text style={{ fontSize: 14, color: '#444', marginBottom: 12 }}>
|
|
1376
|
-
Backup codes and your Recovery Key are shown only once. Store them securely (paper or password manager).
|
|
1377
|
-
</Text>
|
|
1378
|
-
{generatedBackupCodes && generatedBackupCodes.length > 0 && (
|
|
1379
|
-
<View style={{ marginBottom: 12 }}>
|
|
1380
|
-
<Text style={{ fontSize: 16, fontWeight: '600', marginBottom: 8 }}>Backup Codes</Text>
|
|
1381
|
-
<View style={{ backgroundColor: '#F8F9FA', borderRadius: 12, padding: 12 }}>
|
|
1382
|
-
{generatedBackupCodes.map((c, idx) => (
|
|
1383
|
-
<Text key={idx} style={{ fontFamily: Platform.OS === 'web' ? 'monospace' as any : 'monospace', fontSize: 14, marginBottom: 4 }}>{c}</Text>
|
|
1384
|
-
))}
|
|
1385
|
-
</View>
|
|
1386
|
-
</View>
|
|
1387
|
-
)}
|
|
1388
|
-
{generatedRecoveryKey && (
|
|
1389
|
-
<View style={{ marginBottom: 12 }}>
|
|
1390
|
-
<Text style={{ fontSize: 16, fontWeight: '600', marginBottom: 8 }}>Recovery Key</Text>
|
|
1391
|
-
<View style={{ backgroundColor: '#F8F9FA', borderRadius: 12, padding: 12 }}>
|
|
1392
|
-
<Text style={{ fontFamily: Platform.OS === 'web' ? 'monospace' as any : 'monospace', fontSize: 14 }}>{generatedRecoveryKey}</Text>
|
|
1393
|
-
</View>
|
|
1394
|
-
</View>
|
|
1395
|
-
)}
|
|
1396
|
-
<TouchableOpacity
|
|
1397
|
-
style={[styles.primaryButton, { backgroundColor: colors.iconSecurity, alignSelf: 'flex-end', marginTop: 8 }]}
|
|
1398
|
-
onPress={() => { setShowRecoveryModal(false); setEditingField(null); toast.success(t('editProfile.toasts.twoFactorEnabled') || 'Two‑Factor Authentication enabled'); }}
|
|
1399
|
-
>
|
|
1400
|
-
<Ionicons name="checkmark" size={18} color="#fff" />
|
|
1401
|
-
<Text style={styles.primaryButtonText}>I saved them</Text>
|
|
1402
|
-
</TouchableOpacity>
|
|
1403
|
-
</View>
|
|
1404
|
-
</View>
|
|
1405
|
-
)}
|
|
1406
1226
|
{/* Profile Picture Section */}
|
|
1407
1227
|
<View
|
|
1408
1228
|
ref={(ref) => {
|
|
@@ -1634,20 +1454,6 @@ const AccountSettingsScreen: React.FC<BaseScreenProps & { initialField?: string;
|
|
|
1634
1454
|
{t('editProfile.sections.security') || 'SECURITY'}
|
|
1635
1455
|
</Text>
|
|
1636
1456
|
<View style={styles.groupedSectionWrapper}>
|
|
1637
|
-
<GroupedSection
|
|
1638
|
-
items={[
|
|
1639
|
-
{
|
|
1640
|
-
id: 'two-factor',
|
|
1641
|
-
icon: 'shield-lock',
|
|
1642
|
-
iconColor: colors.sidebarIconSecurity,
|
|
1643
|
-
title: t('editProfile.items.twoFactor.title') || 'Two‑Factor Authentication',
|
|
1644
|
-
subtitle: user?.privacySettings?.twoFactorEnabled
|
|
1645
|
-
? (t('editProfile.items.twoFactor.enabled') || 'Enabled')
|
|
1646
|
-
: (t('editProfile.items.twoFactor.disabled') || 'Disabled (recommended)'),
|
|
1647
|
-
onPress: handleOpenTwoFactorModal,
|
|
1648
|
-
},
|
|
1649
|
-
]}
|
|
1650
|
-
/>
|
|
1651
1457
|
</View>
|
|
1652
1458
|
</View>
|
|
1653
1459
|
</>
|
|
@@ -1698,12 +1504,6 @@ const AccountSettingsScreen: React.FC<BaseScreenProps & { initialField?: string;
|
|
|
1698
1504
|
theme={normalizedTheme}
|
|
1699
1505
|
onSave={handleModalSave}
|
|
1700
1506
|
/>
|
|
1701
|
-
<TwoFactorSetupModal
|
|
1702
|
-
visible={showTwoFactorModal}
|
|
1703
|
-
onClose={() => setShowTwoFactorModal(false)}
|
|
1704
|
-
isEnabled={!!user?.privacySettings?.twoFactorEnabled}
|
|
1705
|
-
theme={normalizedTheme}
|
|
1706
|
-
/>
|
|
1707
1507
|
</View>
|
|
1708
1508
|
);
|
|
1709
1509
|
};
|
|
@@ -60,7 +60,7 @@ const OxyAuthScreen: React.FC<BaseScreenProps> = ({
|
|
|
60
60
|
}) => {
|
|
61
61
|
const themeValue = (theme === 'light' || theme === 'dark') ? theme : 'light';
|
|
62
62
|
const colors = useThemeColors(themeValue);
|
|
63
|
-
const { oxyServices, signIn } = useOxy();
|
|
63
|
+
const { oxyServices, signIn, switchSession } = useOxy();
|
|
64
64
|
|
|
65
65
|
const [authSession, setAuthSession] = useState<AuthSession | null>(null);
|
|
66
66
|
const [isLoading, setIsLoading] = useState(true);
|
|
@@ -78,12 +78,19 @@ const OxyAuthScreen: React.FC<BaseScreenProps> = ({
|
|
|
78
78
|
isProcessingRef.current = true;
|
|
79
79
|
|
|
80
80
|
try {
|
|
81
|
-
//
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
81
|
+
// Switch to the new session (this will get token, user data, and update state)
|
|
82
|
+
if (switchSession) {
|
|
83
|
+
const user = await switchSession(sessionId);
|
|
84
|
+
if (onAuthenticated) {
|
|
85
|
+
onAuthenticated(user);
|
|
86
|
+
}
|
|
87
|
+
} else {
|
|
88
|
+
// Fallback if switchSession not available (shouldn't happen, but for safety)
|
|
89
|
+
await oxyServices.getTokenBySession(sessionId);
|
|
90
|
+
const user = await oxyServices.getUserBySession(sessionId);
|
|
91
|
+
if (onAuthenticated) {
|
|
92
|
+
onAuthenticated(user);
|
|
93
|
+
}
|
|
87
94
|
}
|
|
88
95
|
} catch (err) {
|
|
89
96
|
if (__DEV__) {
|
|
@@ -92,7 +99,7 @@ const OxyAuthScreen: React.FC<BaseScreenProps> = ({
|
|
|
92
99
|
setError('Authorization successful but failed to complete sign in. Please try again.');
|
|
93
100
|
isProcessingRef.current = false;
|
|
94
101
|
}
|
|
95
|
-
}, [oxyServices, onAuthenticated]);
|
|
102
|
+
}, [oxyServices, switchSession, onAuthenticated]);
|
|
96
103
|
|
|
97
104
|
// Connect to socket for real-time updates
|
|
98
105
|
const connectSocket = useCallback((sessionToken: string) => {
|
|
@@ -517,3 +524,4 @@ const styles = StyleSheet.create({
|
|
|
517
524
|
|
|
518
525
|
export default OxyAuthScreen;
|
|
519
526
|
|
|
527
|
+
|
|
@@ -21,7 +21,6 @@ interface PrivacySettings {
|
|
|
21
21
|
hideOnlineStatus: boolean;
|
|
22
22
|
hideLastSeen: boolean;
|
|
23
23
|
profileVisibility: boolean;
|
|
24
|
-
twoFactorEnabled: boolean;
|
|
25
24
|
loginAlerts: boolean;
|
|
26
25
|
blockScreenshots: boolean;
|
|
27
26
|
login: boolean;
|
|
@@ -52,7 +51,6 @@ const PrivacySettingsScreen: React.FC<BaseScreenProps> = ({
|
|
|
52
51
|
hideOnlineStatus: false,
|
|
53
52
|
hideLastSeen: false,
|
|
54
53
|
profileVisibility: true,
|
|
55
|
-
twoFactorEnabled: false,
|
|
56
54
|
loginAlerts: true,
|
|
57
55
|
blockScreenshots: false,
|
|
58
56
|
login: true,
|
|
@@ -21,6 +21,17 @@ import { useThemeStyles } from '../hooks/useThemeStyles';
|
|
|
21
21
|
import { normalizeTheme } from '../utils/themeUtils';
|
|
22
22
|
import { useOxy } from '../context/OxyContext';
|
|
23
23
|
|
|
24
|
+
// Button background colors for session actions
|
|
25
|
+
const SWITCH_BUTTON_BG = {
|
|
26
|
+
dark: '#1E2A38',
|
|
27
|
+
light: '#E6F2FF',
|
|
28
|
+
} as const;
|
|
29
|
+
|
|
30
|
+
const LOGOUT_BUTTON_BG = {
|
|
31
|
+
dark: '#3A1E1E',
|
|
32
|
+
light: '#FFEBEE',
|
|
33
|
+
} as const;
|
|
34
|
+
|
|
24
35
|
const SessionManagementScreen: React.FC<BaseScreenProps> = ({
|
|
25
36
|
onClose,
|
|
26
37
|
theme,
|
|
@@ -45,7 +56,7 @@ const SessionManagementScreen: React.FC<BaseScreenProps> = ({
|
|
|
45
56
|
const normalizedTheme = normalizeTheme(theme);
|
|
46
57
|
const themeStyles = useThemeStyles(normalizedTheme);
|
|
47
58
|
// Extract commonly used colors for readability
|
|
48
|
-
const { textColor, backgroundColor,
|
|
59
|
+
const { textColor, backgroundColor, borderColor, primaryColor, dangerColor, successColor, isDarkTheme } = themeStyles;
|
|
49
60
|
|
|
50
61
|
// Memoized load sessions function - prevents unnecessary re-renders
|
|
51
62
|
const loadSessions = useCallback(async (isRefresh = false) => {
|
|
@@ -92,9 +103,14 @@ const SessionManagementScreen: React.FC<BaseScreenProps> = ({
|
|
|
92
103
|
});
|
|
93
104
|
}, [logout, refreshSessions]);
|
|
94
105
|
|
|
106
|
+
// Memoized bulk action items - prevents unnecessary re-renders when dependencies haven't changed
|
|
107
|
+
const otherSessionsCount = useMemo(() =>
|
|
108
|
+
userSessions.filter(s => s.sessionId !== activeSessionId).length,
|
|
109
|
+
[userSessions, activeSessionId]
|
|
110
|
+
);
|
|
111
|
+
|
|
95
112
|
// Memoized logout other sessions handler - prevents unnecessary re-renders
|
|
96
113
|
const handleLogoutOtherSessions = useCallback(async () => {
|
|
97
|
-
const otherSessionsCount = userSessions.filter(s => s.sessionId !== activeSessionId).length;
|
|
98
114
|
if (otherSessionsCount === 0) {
|
|
99
115
|
toast.info('No other sessions to logout.');
|
|
100
116
|
return;
|
|
@@ -119,7 +135,7 @@ const SessionManagementScreen: React.FC<BaseScreenProps> = ({
|
|
|
119
135
|
}
|
|
120
136
|
}
|
|
121
137
|
);
|
|
122
|
-
}, [userSessions, activeSessionId, logout, refreshSessions]);
|
|
138
|
+
}, [otherSessionsCount, userSessions, activeSessionId, logout, refreshSessions]);
|
|
123
139
|
|
|
124
140
|
// Memoized logout all sessions handler - prevents unnecessary re-renders
|
|
125
141
|
const handleLogoutAllSessions = useCallback(async () => {
|
|
@@ -132,6 +148,7 @@ const SessionManagementScreen: React.FC<BaseScreenProps> = ({
|
|
|
132
148
|
} catch (error) {
|
|
133
149
|
console.error('Logout all sessions failed:', error);
|
|
134
150
|
toast.error('Failed to logout all sessions. Please try again.');
|
|
151
|
+
} finally {
|
|
135
152
|
setActionLoading(null);
|
|
136
153
|
}
|
|
137
154
|
}
|
|
@@ -171,22 +188,18 @@ const SessionManagementScreen: React.FC<BaseScreenProps> = ({
|
|
|
171
188
|
}
|
|
172
189
|
}, [activeSessionId, switchSession]);
|
|
173
190
|
|
|
191
|
+
// Memoized refresh handler for pull-to-refresh
|
|
192
|
+
const handleRefresh = useCallback(() => {
|
|
193
|
+
loadSessions(true);
|
|
194
|
+
}, [loadSessions]);
|
|
195
|
+
|
|
174
196
|
useEffect(() => {
|
|
175
197
|
loadSessions();
|
|
176
198
|
}, [loadSessions]);
|
|
177
199
|
|
|
178
|
-
if (loading) {
|
|
179
|
-
return (
|
|
180
|
-
<View style={[styles.container, styles.centerContent, { backgroundColor }]}>
|
|
181
|
-
<ActivityIndicator size="large" color={primaryColor} />
|
|
182
|
-
<Text style={[styles.loadingText, { color: textColor }]}>Loading sessions...</Text>
|
|
183
|
-
</View>
|
|
184
|
-
);
|
|
185
|
-
}
|
|
186
|
-
|
|
187
200
|
// Memoized session items - prevents unnecessary re-renders when dependencies haven't changed
|
|
188
201
|
const sessionItems = useMemo(() => {
|
|
189
|
-
return userSessions.map((session
|
|
202
|
+
return userSessions.map((session) => {
|
|
190
203
|
const isCurrent = session.sessionId === activeSessionId;
|
|
191
204
|
const subtitleParts: string[] = [];
|
|
192
205
|
if (session.deviceId) subtitleParts.push(`Device ${session.deviceId.substring(0, 10)}...`);
|
|
@@ -205,7 +218,7 @@ const SessionManagementScreen: React.FC<BaseScreenProps> = ({
|
|
|
205
218
|
<View style={styles.sessionActionsRow}>
|
|
206
219
|
<TouchableOpacity
|
|
207
220
|
onPress={() => handleSwitchSession(session.sessionId)}
|
|
208
|
-
style={[styles.sessionPillButton, { backgroundColor: isDarkTheme ?
|
|
221
|
+
style={[styles.sessionPillButton, { backgroundColor: isDarkTheme ? SWITCH_BUTTON_BG.dark : SWITCH_BUTTON_BG.light, borderColor: primaryColor }]}
|
|
209
222
|
disabled={switchLoading === session.sessionId || actionLoading === session.sessionId}
|
|
210
223
|
>
|
|
211
224
|
{switchLoading === session.sessionId ? (
|
|
@@ -216,7 +229,7 @@ const SessionManagementScreen: React.FC<BaseScreenProps> = ({
|
|
|
216
229
|
</TouchableOpacity>
|
|
217
230
|
<TouchableOpacity
|
|
218
231
|
onPress={() => handleLogoutSession(session.sessionId)}
|
|
219
|
-
style={[styles.sessionPillButton, { backgroundColor: isDarkTheme ?
|
|
232
|
+
style={[styles.sessionPillButton, { backgroundColor: isDarkTheme ? LOGOUT_BUTTON_BG.dark : LOGOUT_BUTTON_BG.light, borderColor: dangerColor }]}
|
|
220
233
|
disabled={actionLoading === session.sessionId || switchLoading === session.sessionId}
|
|
221
234
|
>
|
|
222
235
|
{actionLoading === session.sessionId ? (
|
|
@@ -237,12 +250,6 @@ const SessionManagementScreen: React.FC<BaseScreenProps> = ({
|
|
|
237
250
|
});
|
|
238
251
|
}, [userSessions, activeSessionId, formatRelative, successColor, primaryColor, isDarkTheme, switchLoading, actionLoading, handleSwitchSession, handleLogoutSession, dangerColor]);
|
|
239
252
|
|
|
240
|
-
// Memoized bulk action items - prevents unnecessary re-renders when dependencies haven't changed
|
|
241
|
-
const otherSessionsCount = useMemo(() =>
|
|
242
|
-
userSessions.filter(s => s.sessionId !== activeSessionId).length,
|
|
243
|
-
[userSessions, activeSessionId]
|
|
244
|
-
);
|
|
245
|
-
|
|
246
253
|
const bulkItems = useMemo(() => [
|
|
247
254
|
{
|
|
248
255
|
id: 'logout-others',
|
|
@@ -270,6 +277,15 @@ const SessionManagementScreen: React.FC<BaseScreenProps> = ({
|
|
|
270
277
|
},
|
|
271
278
|
], [otherSessionsCount, primaryColor, dangerColor, handleLogoutOtherSessions, handleLogoutAllSessions, actionLoading]);
|
|
272
279
|
|
|
280
|
+
if (loading) {
|
|
281
|
+
return (
|
|
282
|
+
<View style={[styles.container, styles.centerContent, { backgroundColor }]}>
|
|
283
|
+
<ActivityIndicator size="large" color={primaryColor} />
|
|
284
|
+
<Text style={[styles.loadingText, { color: textColor }]}>Loading sessions...</Text>
|
|
285
|
+
</View>
|
|
286
|
+
);
|
|
287
|
+
}
|
|
288
|
+
|
|
273
289
|
return (
|
|
274
290
|
<View style={[styles.container, { backgroundColor }]}>
|
|
275
291
|
<Header
|
|
@@ -285,7 +301,7 @@ const SessionManagementScreen: React.FC<BaseScreenProps> = ({
|
|
|
285
301
|
refreshControl={
|
|
286
302
|
<RefreshControl
|
|
287
303
|
refreshing={refreshing}
|
|
288
|
-
onRefresh={
|
|
304
|
+
onRefresh={handleRefresh}
|
|
289
305
|
tintColor={primaryColor}
|
|
290
306
|
/>
|
|
291
307
|
}
|
|
@@ -293,12 +309,12 @@ const SessionManagementScreen: React.FC<BaseScreenProps> = ({
|
|
|
293
309
|
{userSessions.length > 0 ? (
|
|
294
310
|
<>
|
|
295
311
|
{lastRefreshed && (
|
|
296
|
-
<Text style={[styles.metaText, { color:
|
|
312
|
+
<Text style={[styles.metaText, { color: '#777', marginBottom: 6 }]}>Last refreshed {formatRelative(lastRefreshed.toISOString())}</Text>
|
|
297
313
|
)}
|
|
298
314
|
<View style={styles.fullBleed}>
|
|
299
315
|
<GroupedSection items={sessionItems} />
|
|
300
316
|
</View>
|
|
301
|
-
<View style={
|
|
317
|
+
<View style={styles.sectionSpacer} />
|
|
302
318
|
<View style={styles.fullBleed}>
|
|
303
319
|
<GroupedSection items={bulkItems} />
|
|
304
320
|
</View>
|
|
@@ -326,8 +342,6 @@ const styles = StyleSheet.create({
|
|
|
326
342
|
justifyContent: 'center',
|
|
327
343
|
alignItems: 'center',
|
|
328
344
|
},
|
|
329
|
-
|
|
330
|
-
|
|
331
345
|
scrollView: {
|
|
332
346
|
flex: 1,
|
|
333
347
|
},
|
|
@@ -376,6 +390,9 @@ const styles = StyleSheet.create({
|
|
|
376
390
|
width: '100%',
|
|
377
391
|
alignSelf: 'stretch',
|
|
378
392
|
},
|
|
393
|
+
sectionSpacer: {
|
|
394
|
+
height: 12,
|
|
395
|
+
},
|
|
379
396
|
emptyState: {
|
|
380
397
|
alignItems: 'center',
|
|
381
398
|
paddingVertical: 40,
|
|
@@ -7,12 +7,21 @@ export interface AuthState {
|
|
|
7
7
|
isLoading: boolean;
|
|
8
8
|
error: string | null;
|
|
9
9
|
lastUserFetch: number | null; // Timestamp of last user fetch for caching
|
|
10
|
+
|
|
11
|
+
// Identity sync state (offline-first)
|
|
12
|
+
isIdentitySynced: boolean;
|
|
13
|
+
isSyncing: boolean;
|
|
14
|
+
|
|
10
15
|
loginSuccess: (user: User) => void;
|
|
11
16
|
loginFailure: (error: string) => void;
|
|
12
17
|
logout: () => void;
|
|
13
18
|
fetchUser: (oxyServices: { getCurrentUser: () => Promise<User> }, forceRefresh?: boolean) => Promise<void>;
|
|
14
19
|
updateUser: (updates: Partial<User>, oxyServices: { updateProfile: (updates: Partial<User>) => Promise<User>; getCurrentUser: () => Promise<User> }) => Promise<void>;
|
|
15
20
|
setUser: (user: User) => void; // Direct user setter for caching
|
|
21
|
+
|
|
22
|
+
// Identity sync actions
|
|
23
|
+
setIdentitySynced: (synced: boolean) => void;
|
|
24
|
+
setSyncing: (syncing: boolean) => void;
|
|
16
25
|
}
|
|
17
26
|
|
|
18
27
|
export const useAuthStore = create<AuthState>((set: (state: Partial<AuthState>) => void, get: () => AuthState) => ({
|
|
@@ -21,10 +30,30 @@ export const useAuthStore = create<AuthState>((set: (state: Partial<AuthState>)
|
|
|
21
30
|
isLoading: false,
|
|
22
31
|
error: null,
|
|
23
32
|
lastUserFetch: null,
|
|
24
|
-
|
|
33
|
+
|
|
34
|
+
// Identity sync state (offline-first)
|
|
35
|
+
isIdentitySynced: true, // Assume synced until proven otherwise
|
|
36
|
+
isSyncing: false,
|
|
37
|
+
|
|
38
|
+
loginSuccess: (user: User) => set({
|
|
39
|
+
isLoading: false,
|
|
40
|
+
isAuthenticated: true,
|
|
41
|
+
user,
|
|
42
|
+
lastUserFetch: Date.now(),
|
|
43
|
+
isIdentitySynced: true, // If login succeeded, identity is synced
|
|
44
|
+
}),
|
|
25
45
|
loginFailure: (error: string) => set({ isLoading: false, error }),
|
|
26
|
-
logout: () => set({
|
|
46
|
+
logout: () => set({
|
|
47
|
+
user: null,
|
|
48
|
+
isAuthenticated: false,
|
|
49
|
+
lastUserFetch: null,
|
|
50
|
+
// Keep identity sync state - user might still have local identity
|
|
51
|
+
}),
|
|
27
52
|
setUser: (user: User) => set({ user, lastUserFetch: Date.now() }),
|
|
53
|
+
|
|
54
|
+
// Identity sync actions
|
|
55
|
+
setIdentitySynced: (synced: boolean) => set({ isIdentitySynced: synced }),
|
|
56
|
+
setSyncing: (syncing: boolean) => set({ isSyncing: syncing }),
|
|
28
57
|
fetchUser: async (oxyServices, forceRefresh = false) => {
|
|
29
58
|
const state = get();
|
|
30
59
|
const now = Date.now();
|
|
@@ -1,53 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
Object.defineProperty(exports, "__esModule", {
|
|
4
|
-
value: true
|
|
5
|
-
});
|
|
6
|
-
exports.OxyServicesTotpMixin = OxyServicesTotpMixin;
|
|
7
|
-
/**
|
|
8
|
-
* TOTP Enrollment Methods Mixin
|
|
9
|
-
*/
|
|
10
|
-
|
|
11
|
-
function OxyServicesTotpMixin(Base) {
|
|
12
|
-
return class extends Base {
|
|
13
|
-
constructor(...args) {
|
|
14
|
-
super(...args);
|
|
15
|
-
}
|
|
16
|
-
async startTotpEnrollment(sessionId) {
|
|
17
|
-
try {
|
|
18
|
-
return await this.makeRequest('POST', '/api/auth/totp/enroll/start', {
|
|
19
|
-
sessionId
|
|
20
|
-
}, {
|
|
21
|
-
cache: false
|
|
22
|
-
});
|
|
23
|
-
} catch (error) {
|
|
24
|
-
throw this.handleError(error);
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
|
-
async verifyTotpEnrollment(sessionId, code) {
|
|
28
|
-
try {
|
|
29
|
-
return await this.makeRequest('POST', '/api/auth/totp/enroll/verify', {
|
|
30
|
-
sessionId,
|
|
31
|
-
code
|
|
32
|
-
}, {
|
|
33
|
-
cache: false
|
|
34
|
-
});
|
|
35
|
-
} catch (error) {
|
|
36
|
-
throw this.handleError(error);
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
async disableTotp(sessionId, code) {
|
|
40
|
-
try {
|
|
41
|
-
return await this.makeRequest('POST', '/api/auth/totp/disable', {
|
|
42
|
-
sessionId,
|
|
43
|
-
code
|
|
44
|
-
}, {
|
|
45
|
-
cache: false
|
|
46
|
-
});
|
|
47
|
-
} catch (error) {
|
|
48
|
-
throw this.handleError(error);
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
};
|
|
52
|
-
}
|
|
53
|
-
//# sourceMappingURL=OxyServices.totp.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"names":["OxyServicesTotpMixin","Base","constructor","args","startTotpEnrollment","sessionId","makeRequest","cache","error","handleError","verifyTotpEnrollment","code","disableTotp"],"sourceRoot":"../../../../src","sources":["core/mixins/OxyServices.totp.ts"],"mappings":";;;;;;AAAA;AACA;AACA;;AAGO,SAASA,oBAAoBA,CAAmCC,IAAO,EAAE;EAC9E,OAAO,cAAcA,IAAI,CAAC;IACxBC,WAAWA,CAAC,GAAGC,IAAW,EAAE;MAC1B,KAAK,CAAC,GAAIA,IAAc,CAAC;IAC3B;IACA,MAAMC,mBAAmBA,CAACC,SAAiB,EAAkF;MAC3H,IAAI;QACF,OAAO,MAAM,IAAI,CAACC,WAAW,CAAC,MAAM,EAAE,6BAA6B,EAAE;UAAED;QAAU,CAAC,EAAE;UAAEE,KAAK,EAAE;QAAM,CAAC,CAAC;MACvG,CAAC,CAAC,OAAOC,KAAK,EAAE;QACd,MAAM,IAAI,CAACC,WAAW,CAACD,KAAK,CAAC;MAC/B;IACF;IAEA,MAAME,oBAAoBA,CAACL,SAAiB,EAAEM,IAAY,EAA+E;MACvI,IAAI;QACF,OAAO,MAAM,IAAI,CAACL,WAAW,CAAC,MAAM,EAAE,8BAA8B,EAAE;UAAED,SAAS;UAAEM;QAAK,CAAC,EAAE;UAAEJ,KAAK,EAAE;QAAM,CAAC,CAAC;MAC9G,CAAC,CAAC,OAAOC,KAAK,EAAE;QACd,MAAM,IAAI,CAACC,WAAW,CAACD,KAAK,CAAC;MAC/B;IACF;IAEA,MAAMI,WAAWA,CAACP,SAAiB,EAAEM,IAAY,EAAkC;MACjF,IAAI;QACF,OAAO,MAAM,IAAI,CAACL,WAAW,CAAC,MAAM,EAAE,wBAAwB,EAAE;UAAED,SAAS;UAAEM;QAAK,CAAC,EAAE;UAAEJ,KAAK,EAAE;QAAM,CAAC,CAAC;MACxG,CAAC,CAAC,OAAOC,KAAK,EAAE;QACd,MAAM,IAAI,CAACC,WAAW,CAACD,KAAK,CAAC;MAC/B;IACF;EACF,CAAC;AACH","ignoreList":[]}
|