@oxyhq/services 5.16.40 → 5.16.42
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/adapters/expo/crypto.js +56 -0
- package/lib/commonjs/adapters/expo/crypto.js.map +1 -0
- package/lib/commonjs/adapters/expo/fetch.js +30 -0
- package/lib/commonjs/adapters/expo/fetch.js.map +1 -0
- package/lib/commonjs/adapters/expo/index.js +48 -0
- package/lib/commonjs/adapters/expo/index.js.map +1 -0
- package/lib/commonjs/adapters/expo/storage.js +201 -0
- package/lib/commonjs/adapters/expo/storage.js.map +1 -0
- package/lib/commonjs/adapters/index.js +50 -0
- package/lib/commonjs/adapters/index.js.map +1 -0
- package/lib/commonjs/adapters/node/crypto.js +40 -0
- package/lib/commonjs/adapters/node/crypto.js.map +1 -0
- package/lib/commonjs/adapters/node/fetch.js +62 -0
- package/lib/commonjs/adapters/node/fetch.js.map +1 -0
- package/lib/commonjs/adapters/node/index.js +34 -0
- package/lib/commonjs/adapters/node/index.js.map +1 -0
- package/lib/commonjs/adapters/node/storage.js +163 -0
- package/lib/commonjs/adapters/node/storage.js.map +1 -0
- package/lib/commonjs/core/identity-session/DeviceManager.js +237 -0
- package/lib/commonjs/core/identity-session/DeviceManager.js.map +1 -0
- package/lib/commonjs/core/identity-session/INTEGRATION_GUIDE.md +287 -0
- package/lib/commonjs/core/identity-session/IdentityManager.js +400 -0
- package/lib/commonjs/core/identity-session/IdentityManager.js.map +1 -0
- package/lib/commonjs/core/identity-session/IdentitySessionCore.js +394 -0
- package/lib/commonjs/core/identity-session/IdentitySessionCore.js.map +1 -0
- package/lib/commonjs/core/identity-session/RefreshManager.js +137 -0
- package/lib/commonjs/core/identity-session/RefreshManager.js.map +1 -0
- package/lib/commonjs/core/identity-session/SessionManager.js +427 -0
- package/lib/commonjs/core/identity-session/SessionManager.js.map +1 -0
- package/lib/commonjs/core/identity-session/createIdentitySessionCore.js +24 -0
- package/lib/commonjs/core/identity-session/createIdentitySessionCore.js.map +1 -0
- package/lib/commonjs/core/identity-session/errors.js +176 -0
- package/lib/commonjs/core/identity-session/errors.js.map +1 -0
- package/lib/commonjs/core/identity-session/index.js +80 -0
- package/lib/commonjs/core/identity-session/index.js.map +1 -0
- package/lib/commonjs/core/identity-session/types.js +2 -0
- package/lib/commonjs/core/identity-session/types.js.map +1 -0
- package/lib/commonjs/core/index.js +2 -21
- package/lib/commonjs/core/index.js.map +1 -1
- package/lib/commonjs/index.js +58 -8
- package/lib/commonjs/index.js.map +1 -1
- package/lib/commonjs/models/interfaces.js +7 -0
- package/lib/commonjs/models/interfaces.js.map +1 -1
- package/lib/commonjs/ui/context/OxyContext.js +434 -820
- package/lib/commonjs/ui/context/OxyContext.js.map +1 -1
- package/lib/commonjs/ui/hooks/useAvatarPicker.js +52 -0
- package/lib/commonjs/ui/hooks/useAvatarPicker.js.map +1 -0
- package/lib/commonjs/ui/hooks/useIdentityTransfer.js +125 -0
- package/lib/commonjs/ui/hooks/useIdentityTransfer.js.map +1 -0
- package/lib/commonjs/ui/hooks/useTransferCodesPersistence.js +81 -0
- package/lib/commonjs/ui/hooks/useTransferCodesPersistence.js.map +1 -0
- package/lib/commonjs/ui/screens/AccountCenterScreen.js +7 -2
- package/lib/commonjs/ui/screens/AccountCenterScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/AccountSettingsScreen.js +12 -5
- package/lib/commonjs/ui/screens/AccountSettingsScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/AccountSwitcherScreen.js +2 -2
- package/lib/commonjs/ui/screens/AccountSwitcherScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/ProfileScreen.js +6 -6
- package/lib/commonjs/ui/screens/ProfileScreen.js.map +1 -1
- package/lib/commonjs/ui/utils/sessionHelpers.js +7 -1
- package/lib/commonjs/ui/utils/sessionHelpers.js.map +1 -1
- package/lib/commonjs/utils/index.js +0 -7
- package/lib/commonjs/utils/index.js.map +1 -1
- package/lib/commonjs/utils/sessionUtils.js +8 -1
- package/lib/commonjs/utils/sessionUtils.js.map +1 -1
- package/lib/module/adapters/expo/crypto.js +51 -0
- package/lib/module/adapters/expo/crypto.js.map +1 -0
- package/lib/module/adapters/expo/fetch.js +26 -0
- package/lib/module/adapters/expo/fetch.js.map +1 -0
- package/lib/module/adapters/expo/index.js +45 -0
- package/lib/module/adapters/expo/index.js.map +1 -0
- package/lib/module/adapters/expo/storage.js +198 -0
- package/lib/module/adapters/expo/storage.js.map +1 -0
- package/lib/module/adapters/index.js +47 -0
- package/lib/module/adapters/index.js.map +1 -0
- package/lib/module/adapters/node/crypto.js +36 -0
- package/lib/module/adapters/node/crypto.js.map +1 -0
- package/lib/module/adapters/node/fetch.js +57 -0
- package/lib/module/adapters/node/fetch.js.map +1 -0
- package/lib/module/adapters/node/index.js +31 -0
- package/lib/module/adapters/node/index.js.map +1 -0
- package/lib/module/adapters/node/storage.js +159 -0
- package/lib/module/adapters/node/storage.js.map +1 -0
- package/lib/module/core/identity-session/DeviceManager.js +232 -0
- package/lib/module/core/identity-session/DeviceManager.js.map +1 -0
- package/lib/module/core/identity-session/INTEGRATION_GUIDE.md +287 -0
- package/lib/module/core/identity-session/IdentityManager.js +395 -0
- package/lib/module/core/identity-session/IdentityManager.js.map +1 -0
- package/lib/module/core/identity-session/IdentitySessionCore.js +390 -0
- package/lib/module/core/identity-session/IdentitySessionCore.js.map +1 -0
- package/lib/module/core/identity-session/RefreshManager.js +132 -0
- package/lib/module/core/identity-session/RefreshManager.js.map +1 -0
- package/lib/module/core/identity-session/SessionManager.js +422 -0
- package/lib/module/core/identity-session/SessionManager.js.map +1 -0
- package/lib/module/core/identity-session/createIdentitySessionCore.js +21 -0
- package/lib/module/core/identity-session/createIdentitySessionCore.js.map +1 -0
- package/lib/module/core/identity-session/errors.js +170 -0
- package/lib/module/core/identity-session/errors.js.map +1 -0
- package/lib/module/core/identity-session/index.js +17 -0
- package/lib/module/core/identity-session/index.js.map +1 -0
- package/lib/module/core/identity-session/types.js +2 -0
- package/lib/module/core/identity-session/types.js.map +1 -0
- package/lib/module/core/index.js +2 -3
- package/lib/module/core/index.js.map +1 -1
- package/lib/module/index.js +12 -2
- package/lib/module/index.js.map +1 -1
- package/lib/module/models/interfaces.js +7 -0
- package/lib/module/models/interfaces.js.map +1 -1
- package/lib/module/ui/context/OxyContext.js +436 -822
- package/lib/module/ui/context/OxyContext.js.map +1 -1
- package/lib/module/ui/hooks/useAvatarPicker.js +48 -0
- package/lib/module/ui/hooks/useAvatarPicker.js.map +1 -0
- package/lib/module/ui/hooks/useIdentityTransfer.js +121 -0
- package/lib/module/ui/hooks/useIdentityTransfer.js.map +1 -0
- package/lib/module/ui/hooks/useTransferCodesPersistence.js +77 -0
- package/lib/module/ui/hooks/useTransferCodesPersistence.js.map +1 -0
- package/lib/module/ui/screens/AccountCenterScreen.js +7 -2
- package/lib/module/ui/screens/AccountCenterScreen.js.map +1 -1
- package/lib/module/ui/screens/AccountSettingsScreen.js +12 -5
- package/lib/module/ui/screens/AccountSettingsScreen.js.map +1 -1
- package/lib/module/ui/screens/AccountSwitcherScreen.js +2 -2
- package/lib/module/ui/screens/AccountSwitcherScreen.js.map +1 -1
- package/lib/module/ui/screens/ProfileScreen.js +6 -6
- package/lib/module/ui/screens/ProfileScreen.js.map +1 -1
- package/lib/module/ui/utils/sessionHelpers.js +7 -1
- package/lib/module/ui/utils/sessionHelpers.js.map +1 -1
- package/lib/module/utils/index.js +2 -1
- package/lib/module/utils/index.js.map +1 -1
- package/lib/module/utils/sessionUtils.js +8 -1
- package/lib/module/utils/sessionUtils.js.map +1 -1
- package/lib/typescript/adapters/expo/crypto.d.ts +17 -0
- package/lib/typescript/adapters/expo/crypto.d.ts.map +1 -0
- package/lib/typescript/adapters/expo/fetch.d.ts +16 -0
- package/lib/typescript/adapters/expo/fetch.d.ts.map +1 -0
- package/lib/typescript/adapters/expo/index.d.ts +23 -0
- package/lib/typescript/adapters/expo/index.d.ts.map +1 -0
- package/lib/typescript/adapters/expo/storage.d.ts +23 -0
- package/lib/typescript/adapters/expo/storage.d.ts.map +1 -0
- package/lib/typescript/adapters/index.d.ts +19 -0
- package/lib/typescript/adapters/index.d.ts.map +1 -0
- package/lib/typescript/adapters/node/crypto.d.ts +17 -0
- package/lib/typescript/adapters/node/crypto.d.ts.map +1 -0
- package/lib/typescript/adapters/node/fetch.d.ts +16 -0
- package/lib/typescript/adapters/node/fetch.d.ts.map +1 -0
- package/lib/typescript/adapters/node/index.d.ts +23 -0
- package/lib/typescript/adapters/node/index.d.ts.map +1 -0
- package/lib/typescript/adapters/node/storage.d.ts +23 -0
- package/lib/typescript/adapters/node/storage.d.ts.map +1 -0
- package/lib/typescript/core/identity-session/DeviceManager.d.ts +64 -0
- package/lib/typescript/core/identity-session/DeviceManager.d.ts.map +1 -0
- package/lib/typescript/core/identity-session/IdentityManager.d.ts +88 -0
- package/lib/typescript/core/identity-session/IdentityManager.d.ts.map +1 -0
- package/lib/typescript/core/identity-session/IdentitySessionCore.d.ts +141 -0
- package/lib/typescript/core/identity-session/IdentitySessionCore.d.ts.map +1 -0
- package/lib/typescript/core/identity-session/RefreshManager.d.ts +36 -0
- package/lib/typescript/core/identity-session/RefreshManager.d.ts.map +1 -0
- package/lib/typescript/core/identity-session/SessionManager.d.ts +104 -0
- package/lib/typescript/core/identity-session/SessionManager.d.ts.map +1 -0
- package/lib/typescript/core/identity-session/createIdentitySessionCore.d.ts +11 -0
- package/lib/typescript/core/identity-session/createIdentitySessionCore.d.ts.map +1 -0
- package/lib/typescript/core/identity-session/errors.d.ts +63 -0
- package/lib/typescript/core/identity-session/errors.d.ts.map +1 -0
- package/lib/typescript/core/identity-session/index.d.ts +14 -0
- package/lib/typescript/core/identity-session/index.d.ts.map +1 -0
- package/lib/typescript/core/identity-session/types.d.ts +196 -0
- package/lib/typescript/core/identity-session/types.d.ts.map +1 -0
- package/lib/typescript/core/index.d.ts +1 -3
- package/lib/typescript/core/index.d.ts.map +1 -1
- package/lib/typescript/core/mixins/index.d.ts +2 -2
- package/lib/typescript/index.d.ts +3 -2
- package/lib/typescript/index.d.ts.map +1 -1
- package/lib/typescript/models/interfaces.d.ts +5 -36
- package/lib/typescript/models/interfaces.d.ts.map +1 -1
- package/lib/typescript/models/session.d.ts +3 -16
- package/lib/typescript/models/session.d.ts.map +1 -1
- package/lib/typescript/ui/context/OxyContext.d.ts +2 -25
- package/lib/typescript/ui/context/OxyContext.d.ts.map +1 -1
- package/lib/typescript/ui/hooks/mutations/useAccountMutations.d.ts +7 -8
- package/lib/typescript/ui/hooks/mutations/useAccountMutations.d.ts.map +1 -1
- package/lib/typescript/ui/hooks/mutations/useServicesMutations.d.ts +1 -1
- package/lib/typescript/ui/hooks/mutations/useServicesMutations.d.ts.map +1 -1
- package/lib/typescript/ui/hooks/queries/useAccountQueries.d.ts +5 -5
- package/lib/typescript/ui/hooks/queries/useAccountQueries.d.ts.map +1 -1
- package/lib/typescript/ui/hooks/useAvatarPicker.d.ts +18 -0
- package/lib/typescript/ui/hooks/useAvatarPicker.d.ts.map +1 -0
- package/lib/typescript/ui/hooks/useIdentityTransfer.d.ts +24 -0
- package/lib/typescript/ui/hooks/useIdentityTransfer.d.ts.map +1 -0
- package/lib/typescript/ui/hooks/useTransferCodesPersistence.d.ts +6 -0
- package/lib/typescript/ui/hooks/useTransferCodesPersistence.d.ts.map +1 -0
- package/lib/typescript/ui/screens/AccountCenterScreen.d.ts.map +1 -1
- package/lib/typescript/ui/screens/AccountSettingsScreen.d.ts.map +1 -1
- package/lib/typescript/ui/utils/sessionHelpers.d.ts +1 -0
- package/lib/typescript/ui/utils/sessionHelpers.d.ts.map +1 -1
- package/lib/typescript/utils/index.d.ts +0 -2
- package/lib/typescript/utils/index.d.ts.map +1 -1
- package/lib/typescript/utils/sessionUtils.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/adapters/expo/crypto.ts +55 -0
- package/src/adapters/expo/fetch.ts +28 -0
- package/src/adapters/expo/index.ts +51 -0
- package/src/adapters/expo/storage.ts +228 -0
- package/src/adapters/index.ts +47 -0
- package/src/adapters/node/crypto.ts +39 -0
- package/src/adapters/node/fetch.ts +59 -0
- package/src/adapters/node/index.ts +37 -0
- package/src/adapters/node/storage.ts +170 -0
- package/src/core/identity-session/DeviceManager.ts +273 -0
- package/src/core/identity-session/INTEGRATION_GUIDE.md +287 -0
- package/src/core/identity-session/IdentityManager.ts +474 -0
- package/src/core/identity-session/IdentitySessionCore.ts +464 -0
- package/src/core/identity-session/RefreshManager.ts +189 -0
- package/src/core/identity-session/SessionManager.ts +500 -0
- package/src/core/identity-session/createIdentitySessionCore.ts +19 -0
- package/src/core/identity-session/errors.ts +197 -0
- package/src/core/identity-session/index.ts +15 -0
- package/src/core/identity-session/types.ts +188 -0
- package/src/core/index.ts +3 -4
- package/src/index.ts +28 -3
- package/src/models/interfaces.ts +12 -39
- package/src/models/session.ts +6 -16
- package/src/ui/context/OxyContext.tsx +442 -871
- package/src/ui/hooks/auth/index.ts +1 -0
- package/src/ui/hooks/useAvatarPicker.ts +62 -0
- package/src/ui/hooks/useIdentityTransfer.ts +135 -0
- package/src/ui/hooks/useTransferCodesPersistence.ts +80 -0
- package/src/ui/screens/AccountCenterScreen.tsx +7 -2
- package/src/ui/screens/AccountSettingsScreen.tsx +15 -8
- package/src/ui/screens/AccountSwitcherScreen.tsx +2 -2
- package/src/ui/screens/ProfileScreen.tsx +10 -10
- package/src/ui/utils/sessionHelpers.ts +7 -0
- package/src/utils/index.ts +1 -2
- package/src/utils/sessionUtils.ts +8 -0
- package/lib/commonjs/ui/context/hooks/useAuthOperations.js +0 -732
- package/lib/commonjs/ui/context/hooks/useAuthOperations.js.map +0 -1
- package/lib/commonjs/ui/context/hooks/useDeviceManagement.js +0 -73
- package/lib/commonjs/ui/context/hooks/useDeviceManagement.js.map +0 -1
- package/lib/commonjs/ui/hooks/useDeviceManagement.js +0 -73
- package/lib/commonjs/ui/hooks/useDeviceManagement.js.map +0 -1
- package/lib/commonjs/ui/hooks/useSessionManagement.js +0 -281
- package/lib/commonjs/ui/hooks/useSessionManagement.js.map +0 -1
- package/lib/commonjs/utils/deviceManager.js +0 -177
- package/lib/commonjs/utils/deviceManager.js.map +0 -1
- package/lib/module/ui/context/hooks/useAuthOperations.js +0 -726
- package/lib/module/ui/context/hooks/useAuthOperations.js.map +0 -1
- package/lib/module/ui/context/hooks/useDeviceManagement.js +0 -68
- package/lib/module/ui/context/hooks/useDeviceManagement.js.map +0 -1
- package/lib/module/ui/hooks/useDeviceManagement.js +0 -68
- package/lib/module/ui/hooks/useDeviceManagement.js.map +0 -1
- package/lib/module/ui/hooks/useSessionManagement.js +0 -276
- package/lib/module/ui/hooks/useSessionManagement.js.map +0 -1
- package/lib/module/utils/deviceManager.js +0 -171
- package/lib/module/utils/deviceManager.js.map +0 -1
- package/lib/typescript/ui/context/hooks/useAuthOperations.d.ts +0 -59
- package/lib/typescript/ui/context/hooks/useAuthOperations.d.ts.map +0 -1
- package/lib/typescript/ui/context/hooks/useDeviceManagement.d.ts +0 -27
- package/lib/typescript/ui/context/hooks/useDeviceManagement.d.ts.map +0 -1
- package/lib/typescript/ui/hooks/useDeviceManagement.d.ts +0 -27
- package/lib/typescript/ui/hooks/useDeviceManagement.d.ts.map +0 -1
- package/lib/typescript/ui/hooks/useSessionManagement.d.ts +0 -41
- package/lib/typescript/ui/hooks/useSessionManagement.d.ts.map +0 -1
- package/lib/typescript/utils/deviceManager.d.ts +0 -66
- package/lib/typescript/utils/deviceManager.d.ts.map +0 -1
- package/src/ui/context/hooks/useAuthOperations.ts +0 -801
- package/src/ui/context/hooks/useDeviceManagement.ts +0 -108
- package/src/ui/hooks/useDeviceManagement.ts +0 -108
- package/src/ui/hooks/useSessionManagement.ts +0 -401
- package/src/utils/deviceManager.ts +0 -198
|
@@ -0,0 +1,474 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Identity Manager
|
|
3
|
+
*
|
|
4
|
+
* Manages cryptographic identity (OxyID) - SOLO NATIVE
|
|
5
|
+
* Handles key generation, storage, import, export, and signing operations.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { ec as EC } from 'elliptic';
|
|
9
|
+
import type { ECKeyPair } from 'elliptic';
|
|
10
|
+
import type { PlatformAdapter } from '../../adapters';
|
|
11
|
+
import type { Identity, BackupData } from './types';
|
|
12
|
+
import {
|
|
13
|
+
createIdentitySessionError,
|
|
14
|
+
IdentitySessionErrorCodes,
|
|
15
|
+
} from './errors';
|
|
16
|
+
import {
|
|
17
|
+
isValidPublicKey,
|
|
18
|
+
isValidPrivateKey,
|
|
19
|
+
derivePublicKey,
|
|
20
|
+
getEllipticCurve,
|
|
21
|
+
} from '../../crypto/core';
|
|
22
|
+
|
|
23
|
+
const ec = getEllipticCurve();
|
|
24
|
+
|
|
25
|
+
const STORAGE_KEYS = {
|
|
26
|
+
PRIVATE_KEY: 'oxy_identity_private_key',
|
|
27
|
+
PUBLIC_KEY: 'oxy_identity_public_key',
|
|
28
|
+
BACKUP_PRIVATE_KEY: 'oxy_identity_backup_private_key',
|
|
29
|
+
BACKUP_PUBLIC_KEY: 'oxy_identity_backup_public_key',
|
|
30
|
+
BACKUP_TIMESTAMP: 'oxy_identity_backup_timestamp',
|
|
31
|
+
} as const;
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Identity Manager Class
|
|
35
|
+
*/
|
|
36
|
+
export class IdentityManager {
|
|
37
|
+
private adapter: PlatformAdapter;
|
|
38
|
+
private cachedPublicKey: string | null = null;
|
|
39
|
+
private cachedHasIdentity: boolean | null = null;
|
|
40
|
+
|
|
41
|
+
constructor(adapter: PlatformAdapter) {
|
|
42
|
+
this.adapter = adapter;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Invalidate cached identity state
|
|
47
|
+
*/
|
|
48
|
+
invalidateCache(): void {
|
|
49
|
+
this.cachedPublicKey = null;
|
|
50
|
+
this.cachedHasIdentity = null;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Check if identity operations are available (only on native)
|
|
55
|
+
*/
|
|
56
|
+
private ensureNativePlatform(): void {
|
|
57
|
+
if (this.adapter.platform !== 'native') {
|
|
58
|
+
throw createIdentitySessionError(
|
|
59
|
+
IdentitySessionErrorCodes.IDENTITY_NOT_AVAILABLE_ON_WEB,
|
|
60
|
+
'Identity operations are only available on native platforms (iOS/Android)'
|
|
61
|
+
);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
if (!this.adapter.storage.isSecureStorageAvailable()) {
|
|
65
|
+
throw createIdentitySessionError(
|
|
66
|
+
IdentitySessionErrorCodes.SECURE_STORAGE_NOT_AVAILABLE,
|
|
67
|
+
'Secure storage is not available on this platform'
|
|
68
|
+
);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Convert Uint8Array to hexadecimal string
|
|
74
|
+
*/
|
|
75
|
+
private uint8ArrayToHex(bytes: Uint8Array): string {
|
|
76
|
+
return Array.from(bytes)
|
|
77
|
+
.map(b => b.toString(16).padStart(2, '0'))
|
|
78
|
+
.join('');
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Generate a new ECDSA secp256k1 key pair
|
|
83
|
+
*/
|
|
84
|
+
async generateKeyPair(): Promise<{ publicKey: string; privateKey: string }> {
|
|
85
|
+
this.ensureNativePlatform();
|
|
86
|
+
|
|
87
|
+
const randomBytes = await this.adapter.crypto.getRandomBytes(32);
|
|
88
|
+
const privateKeyHex = this.uint8ArrayToHex(randomBytes);
|
|
89
|
+
const keyPair = ec.keyFromPrivate(privateKeyHex);
|
|
90
|
+
|
|
91
|
+
return {
|
|
92
|
+
privateKey: keyPair.getPrivate('hex'),
|
|
93
|
+
publicKey: keyPair.getPublic('hex'),
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Create a new identity (generate and store key pair)
|
|
99
|
+
*/
|
|
100
|
+
async createIdentity(): Promise<string> {
|
|
101
|
+
this.ensureNativePlatform();
|
|
102
|
+
|
|
103
|
+
const { privateKey, publicKey } = await this.generateKeyPair();
|
|
104
|
+
|
|
105
|
+
await this.adapter.storage.secureSet(STORAGE_KEYS.PRIVATE_KEY, privateKey);
|
|
106
|
+
await this.adapter.storage.secureSet(STORAGE_KEYS.PUBLIC_KEY, publicKey);
|
|
107
|
+
|
|
108
|
+
// Update cache
|
|
109
|
+
this.cachedPublicKey = publicKey;
|
|
110
|
+
this.cachedHasIdentity = true;
|
|
111
|
+
|
|
112
|
+
return publicKey;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* Import an existing key pair (e.g., from backup file)
|
|
117
|
+
*/
|
|
118
|
+
async importKeyPair(privateKey: string): Promise<string> {
|
|
119
|
+
this.ensureNativePlatform();
|
|
120
|
+
|
|
121
|
+
if (!isValidPrivateKey(privateKey)) {
|
|
122
|
+
throw createIdentitySessionError(
|
|
123
|
+
IdentitySessionErrorCodes.INVALID_PRIVATE_KEY,
|
|
124
|
+
'Invalid private key format'
|
|
125
|
+
);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
const keyPair = ec.keyFromPrivate(privateKey);
|
|
129
|
+
const publicKey = keyPair.getPublic('hex');
|
|
130
|
+
|
|
131
|
+
if (!isValidPublicKey(publicKey)) {
|
|
132
|
+
throw createIdentitySessionError(
|
|
133
|
+
IdentitySessionErrorCodes.INVALID_PUBLIC_KEY,
|
|
134
|
+
'Failed to derive valid public key from private key'
|
|
135
|
+
);
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
await this.adapter.storage.secureSet(STORAGE_KEYS.PRIVATE_KEY, privateKey);
|
|
139
|
+
await this.adapter.storage.secureSet(STORAGE_KEYS.PUBLIC_KEY, publicKey);
|
|
140
|
+
|
|
141
|
+
// Update cache
|
|
142
|
+
this.cachedPublicKey = publicKey;
|
|
143
|
+
this.cachedHasIdentity = true;
|
|
144
|
+
|
|
145
|
+
return publicKey;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* Get the stored private key
|
|
150
|
+
* WARNING: Only use this for signing operations within the app
|
|
151
|
+
*/
|
|
152
|
+
async getPrivateKey(): Promise<string | null> {
|
|
153
|
+
this.ensureNativePlatform();
|
|
154
|
+
|
|
155
|
+
try {
|
|
156
|
+
return await this.adapter.storage.secureGet(STORAGE_KEYS.PRIVATE_KEY);
|
|
157
|
+
} catch (error) {
|
|
158
|
+
console.warn('[IdentityManager] Failed to access secure store:', error);
|
|
159
|
+
return null;
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
/**
|
|
164
|
+
* Get the stored public key (cached for performance)
|
|
165
|
+
*/
|
|
166
|
+
async getPublicKey(): Promise<string | null> {
|
|
167
|
+
if (this.adapter.platform !== 'native') {
|
|
168
|
+
return null; // Identity only exists on native
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
if (this.cachedPublicKey !== null) {
|
|
172
|
+
return this.cachedPublicKey;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
try {
|
|
176
|
+
const publicKey = await this.adapter.storage.secureGet(STORAGE_KEYS.PUBLIC_KEY);
|
|
177
|
+
|
|
178
|
+
// Cache result (null is a valid cache value meaning no identity)
|
|
179
|
+
this.cachedPublicKey = publicKey;
|
|
180
|
+
|
|
181
|
+
return publicKey;
|
|
182
|
+
} catch (error) {
|
|
183
|
+
// If secure store is not available, return null (no identity)
|
|
184
|
+
this.cachedPublicKey = null;
|
|
185
|
+
console.warn('[IdentityManager] Failed to access secure store:', error);
|
|
186
|
+
return null;
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
/**
|
|
191
|
+
* Check if an identity (key pair) exists on this device (cached for performance)
|
|
192
|
+
*/
|
|
193
|
+
async hasIdentity(): Promise<boolean> {
|
|
194
|
+
if (this.adapter.platform !== 'native') {
|
|
195
|
+
return false; // Identity only exists on native
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
if (this.cachedHasIdentity !== null) {
|
|
199
|
+
return this.cachedHasIdentity;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
try {
|
|
203
|
+
const privateKey = await this.getPrivateKey();
|
|
204
|
+
const hasIdentity = privateKey !== null;
|
|
205
|
+
|
|
206
|
+
// Cache result
|
|
207
|
+
this.cachedHasIdentity = hasIdentity;
|
|
208
|
+
|
|
209
|
+
return hasIdentity;
|
|
210
|
+
} catch (error) {
|
|
211
|
+
// If we can't check, assume no identity (safer default)
|
|
212
|
+
this.cachedHasIdentity = false;
|
|
213
|
+
console.warn('[IdentityManager] Failed to check identity:', error);
|
|
214
|
+
return false;
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
/**
|
|
219
|
+
* Delete the stored identity (both keys)
|
|
220
|
+
*/
|
|
221
|
+
async deleteIdentity(
|
|
222
|
+
skipBackup: boolean = false,
|
|
223
|
+
force: boolean = false,
|
|
224
|
+
userConfirmed: boolean = false
|
|
225
|
+
): Promise<void> {
|
|
226
|
+
this.ensureNativePlatform();
|
|
227
|
+
|
|
228
|
+
// CRITICAL SAFEGUARD: Require explicit user confirmation unless force is true
|
|
229
|
+
if (!force && !userConfirmed) {
|
|
230
|
+
throw createIdentitySessionError(
|
|
231
|
+
IdentitySessionErrorCodes.IDENTITY_DELETE_FAILED,
|
|
232
|
+
'Identity deletion requires explicit user confirmation'
|
|
233
|
+
);
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
if (!force) {
|
|
237
|
+
const hasIdentity = await this.hasIdentity();
|
|
238
|
+
if (!hasIdentity) {
|
|
239
|
+
return; // Nothing to delete
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
// ALWAYS create backup before deletion unless explicitly skipped
|
|
244
|
+
if (!skipBackup) {
|
|
245
|
+
try {
|
|
246
|
+
const backupSuccess = await this.backupIdentity();
|
|
247
|
+
if (!backupSuccess) {
|
|
248
|
+
console.warn('[IdentityManager] Failed to backup identity before deletion - proceeding anyway');
|
|
249
|
+
}
|
|
250
|
+
} catch (backupError) {
|
|
251
|
+
console.warn('[IdentityManager] Failed to backup identity before deletion:', backupError);
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
await this.adapter.storage.secureDelete(STORAGE_KEYS.PRIVATE_KEY);
|
|
256
|
+
await this.adapter.storage.secureDelete(STORAGE_KEYS.PUBLIC_KEY);
|
|
257
|
+
|
|
258
|
+
// Invalidate cache
|
|
259
|
+
this.invalidateCache();
|
|
260
|
+
|
|
261
|
+
// Also clear backup if force deletion
|
|
262
|
+
if (force) {
|
|
263
|
+
try {
|
|
264
|
+
await this.adapter.storage.secureDelete(STORAGE_KEYS.BACKUP_PRIVATE_KEY);
|
|
265
|
+
await this.adapter.storage.secureDelete(STORAGE_KEYS.BACKUP_PUBLIC_KEY);
|
|
266
|
+
await this.adapter.storage.remove(STORAGE_KEYS.BACKUP_TIMESTAMP);
|
|
267
|
+
} catch (error) {
|
|
268
|
+
// Ignore backup deletion errors
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
/**
|
|
274
|
+
* Backup identity to SecureStore (separate backup storage)
|
|
275
|
+
*/
|
|
276
|
+
async backupIdentity(): Promise<boolean> {
|
|
277
|
+
this.ensureNativePlatform();
|
|
278
|
+
|
|
279
|
+
try {
|
|
280
|
+
const privateKey = await this.getPrivateKey();
|
|
281
|
+
const publicKey = await this.getPublicKey();
|
|
282
|
+
|
|
283
|
+
if (!privateKey || !publicKey) {
|
|
284
|
+
return false; // Nothing to backup
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
// Store backup in SecureStore (still secure, but separate from primary storage)
|
|
288
|
+
await this.adapter.storage.secureSet(STORAGE_KEYS.BACKUP_PRIVATE_KEY, privateKey);
|
|
289
|
+
await this.adapter.storage.secureSet(STORAGE_KEYS.BACKUP_PUBLIC_KEY, publicKey);
|
|
290
|
+
await this.adapter.storage.set(STORAGE_KEYS.BACKUP_TIMESTAMP, Date.now().toString());
|
|
291
|
+
|
|
292
|
+
return true;
|
|
293
|
+
} catch (error) {
|
|
294
|
+
console.error('[IdentityManager] Failed to backup identity:', error);
|
|
295
|
+
return false;
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
/**
|
|
300
|
+
* Restore identity from backup if primary storage is corrupted
|
|
301
|
+
*/
|
|
302
|
+
async restoreIdentityFromBackup(): Promise<boolean> {
|
|
303
|
+
this.ensureNativePlatform();
|
|
304
|
+
|
|
305
|
+
try {
|
|
306
|
+
// Invalidate cache before restoring to ensure fresh state
|
|
307
|
+
this.invalidateCache();
|
|
308
|
+
|
|
309
|
+
// Check if backup exists
|
|
310
|
+
const backupPrivateKey = await this.adapter.storage.secureGet(STORAGE_KEYS.BACKUP_PRIVATE_KEY);
|
|
311
|
+
const backupPublicKey = await this.adapter.storage.secureGet(STORAGE_KEYS.BACKUP_PUBLIC_KEY);
|
|
312
|
+
|
|
313
|
+
if (!backupPrivateKey || !backupPublicKey) {
|
|
314
|
+
return false; // No backup available
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
// Verify backup integrity
|
|
318
|
+
if (!isValidPrivateKey(backupPrivateKey)) {
|
|
319
|
+
return false;
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
if (!isValidPublicKey(backupPublicKey)) {
|
|
323
|
+
return false;
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
// Verify keys match
|
|
327
|
+
const derivedPublicKey = derivePublicKey(backupPrivateKey);
|
|
328
|
+
if (derivedPublicKey !== backupPublicKey) {
|
|
329
|
+
return false; // Backup keys don't match
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
await this.adapter.storage.secureSet(STORAGE_KEYS.PRIVATE_KEY, backupPrivateKey);
|
|
333
|
+
await this.adapter.storage.secureSet(STORAGE_KEYS.PUBLIC_KEY, backupPublicKey);
|
|
334
|
+
|
|
335
|
+
const restored = await this.verifyIdentityIntegrity();
|
|
336
|
+
if (restored) {
|
|
337
|
+
// Update cache
|
|
338
|
+
this.cachedPublicKey = backupPublicKey;
|
|
339
|
+
this.cachedHasIdentity = true;
|
|
340
|
+
|
|
341
|
+
await this.adapter.storage.set(STORAGE_KEYS.BACKUP_TIMESTAMP, Date.now().toString());
|
|
342
|
+
return true;
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
return false;
|
|
346
|
+
} catch (error) {
|
|
347
|
+
console.error('[IdentityManager] Failed to restore identity from backup:', error);
|
|
348
|
+
return false;
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
/**
|
|
353
|
+
* Verify identity integrity - checks if keys are valid and accessible
|
|
354
|
+
*/
|
|
355
|
+
async verifyIdentityIntegrity(): Promise<boolean> {
|
|
356
|
+
this.ensureNativePlatform();
|
|
357
|
+
|
|
358
|
+
try {
|
|
359
|
+
const privateKey = await this.getPrivateKey();
|
|
360
|
+
const publicKey = await this.getPublicKey();
|
|
361
|
+
|
|
362
|
+
if (!privateKey || !publicKey) {
|
|
363
|
+
return false;
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
// Validate private key format
|
|
367
|
+
if (!isValidPrivateKey(privateKey)) {
|
|
368
|
+
return false;
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
// Validate public key format
|
|
372
|
+
if (!isValidPublicKey(publicKey)) {
|
|
373
|
+
return false;
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
// Verify public key can be derived from private key
|
|
377
|
+
const derivedPublicKey = derivePublicKey(privateKey);
|
|
378
|
+
if (derivedPublicKey !== publicKey) {
|
|
379
|
+
return false; // Keys don't match
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
// Verify we can create a key pair object (tests elliptic curve operations)
|
|
383
|
+
const keyPair = await this.getKeyPairObject();
|
|
384
|
+
if (!keyPair) {
|
|
385
|
+
return false;
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
return true;
|
|
389
|
+
} catch (error) {
|
|
390
|
+
console.error('[IdentityManager] Identity integrity check failed:', error);
|
|
391
|
+
return false;
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
/**
|
|
396
|
+
* Get the elliptic curve key object from the stored private key
|
|
397
|
+
* Used internally for signing operations
|
|
398
|
+
*/
|
|
399
|
+
async getKeyPairObject(): Promise<ECKeyPair | null> {
|
|
400
|
+
this.ensureNativePlatform();
|
|
401
|
+
|
|
402
|
+
const privateKey = await this.getPrivateKey();
|
|
403
|
+
if (!privateKey) return null;
|
|
404
|
+
|
|
405
|
+
return ec.keyFromPrivate(privateKey);
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
/**
|
|
409
|
+
* Decrypt backup data and import identity
|
|
410
|
+
*/
|
|
411
|
+
async decryptAndImportBackup(backupData: BackupData, password: string): Promise<string> {
|
|
412
|
+
this.ensureNativePlatform();
|
|
413
|
+
|
|
414
|
+
try {
|
|
415
|
+
// Convert hex strings to Uint8Array
|
|
416
|
+
const saltBytes = new Uint8Array(
|
|
417
|
+
backupData.salt.match(/.{1,2}/g)?.map(byte => parseInt(byte, 16)) || []
|
|
418
|
+
);
|
|
419
|
+
const ivBytes = new Uint8Array(
|
|
420
|
+
backupData.iv.match(/.{1,2}/g)?.map(byte => parseInt(byte, 16)) || []
|
|
421
|
+
);
|
|
422
|
+
|
|
423
|
+
// Derive key from password (same algorithm as EncryptedBackupGenerator)
|
|
424
|
+
const saltHex = Array.from(saltBytes).map(b => b.toString(16).padStart(2, '0')).join('');
|
|
425
|
+
let key = password + saltHex;
|
|
426
|
+
for (let i = 0; i < 10000; i++) {
|
|
427
|
+
key = await this.adapter.crypto.digestStringAsync('SHA256', key);
|
|
428
|
+
}
|
|
429
|
+
const keyBytes = new Uint8Array(32);
|
|
430
|
+
for (let i = 0; i < 64 && i < key.length; i += 2) {
|
|
431
|
+
keyBytes[i / 2] = parseInt(key.substring(i, i + 2), 16);
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
// Decrypt private key (XOR decryption - same as encryption)
|
|
435
|
+
const encryptedBytes = Buffer.from(backupData.encrypted, 'base64');
|
|
436
|
+
const decryptedBytes = new Uint8Array(encryptedBytes.length);
|
|
437
|
+
for (let i = 0; i < encryptedBytes.length; i++) {
|
|
438
|
+
decryptedBytes[i] = encryptedBytes[i] ^ keyBytes[i % keyBytes.length] ^ ivBytes[i % ivBytes.length];
|
|
439
|
+
}
|
|
440
|
+
const privateKey = new TextDecoder().decode(decryptedBytes);
|
|
441
|
+
|
|
442
|
+
// Import the key pair
|
|
443
|
+
return await this.importKeyPair(privateKey);
|
|
444
|
+
} catch (error) {
|
|
445
|
+
throw createIdentitySessionError(
|
|
446
|
+
IdentitySessionErrorCodes.BACKUP_DECRYPTION_FAILED,
|
|
447
|
+
`Failed to decrypt backup: ${error instanceof Error ? error.message : String(error)}`
|
|
448
|
+
);
|
|
449
|
+
}
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
/**
|
|
453
|
+
* Sign a challenge using the stored private key
|
|
454
|
+
*/
|
|
455
|
+
async signChallenge(challenge: string): Promise<string> {
|
|
456
|
+
this.ensureNativePlatform();
|
|
457
|
+
|
|
458
|
+
const keyPair = await this.getKeyPairObject();
|
|
459
|
+
if (!keyPair) {
|
|
460
|
+
throw createIdentitySessionError(
|
|
461
|
+
IdentitySessionErrorCodes.IDENTITY_NOT_FOUND,
|
|
462
|
+
'No identity found. Please create or import an identity first.'
|
|
463
|
+
);
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
// Hash the challenge
|
|
467
|
+
const messageHash = await this.adapter.crypto.digestStringAsync('SHA256', challenge);
|
|
468
|
+
|
|
469
|
+
// Sign the hash
|
|
470
|
+
const signature = keyPair.sign(messageHash);
|
|
471
|
+
return signature.toDER('hex');
|
|
472
|
+
}
|
|
473
|
+
}
|
|
474
|
+
|