Files
openhuman/app/src/utils/cryptoKeys.ts
T
777c98ef7c feat(skills): registry-based skill management + RPC state migration (#98)
* refactor(tauriCommands): streamline RPC method calls for skill management

- Simplified the syntax of RPC method calls in the `tauriCommands.ts` file by removing unnecessary line breaks, enhancing code readability.
- Updated descriptions in the `schemas.rs` file to maintain consistent formatting for RPC method descriptions, improving documentation clarity.

* chore(release): bump OpenHuman version to 0.49.23 in Cargo.lock

* feat(skills): add skill status management in desktopDeepLinkListener

- Introduced a new action `setSkillStatus` to manage the skill's connection status.
- Updated the OAuth deep link handling to dispatch the skill status as 'ready' upon successful connection, improving state management for skills.

* feat(screen_intelligence): implement capture mode for screenshots

- Added a `CaptureMode` enum to differentiate between windowed and fullscreen screenshot captures.
- Enhanced the `capture_screen_image_ref_for_context` function to determine capture mode based on window bounds, with fallback to fullscreen.
- Implemented logic to downscale screenshots exceeding size limits when captured in fullscreen mode.
- Introduced a new `parse_foreground_output` function to parse application context from AppleScript output, improving context retrieval for screenshots.

* chore(build): update Tauri configuration to remove updater artifacts creation

- Modified the TAURI_CONFIG_OVERRIDE to exclude the creation of updater artifacts during the build process, streamlining the build workflow.

* feat(accessibility): enhance accessibility state and add capture test functionality

- Introduced new properties `captureTestResult` and `isCaptureTestRunning` to the `AccessibilityState` interface for managing capture test states.
- Added `CaptureTestResult` and `CaptureTestContextInfo` interfaces to define the structure of capture test results.
- Implemented `openhumanScreenIntelligenceCaptureTest` function to initiate screen intelligence capture tests, improving accessibility features.

* feat(debug): add Screen Intelligence Debug Panel for enhanced diagnostics

- Introduced a new `ScreenIntelligenceDebugPanel` component to display accessibility status, session information, and capture test results.
- Integrated the debug panel into the existing `ScreenIntelligencePanel`, allowing users to expand and collapse the debug section.
- Updated accessibility state management to include `captureTestResult` and `isCaptureTestRunning` for improved testing feedback.
- Enhanced test setup to accommodate new debug functionalities.

* feat(screen_intelligence): implement custom hook for screen intelligence items

- Added `useScreenIntelligenceItems` hook to fetch and manage screen intelligence items from the accessibility state.
- Integrated the hook into the `Intelligence` component, combining items from both memory and screen intelligence sources.
- Enhanced loading state management to reflect the combined loading status of both data sources.

* test(screen_intelligence): add unit tests for useScreenIntelligenceItems mapping and confidenceToPriority functions

- Introduced tests for the mapping logic of AccessibilityVisionSummary to ActionableItem, ensuring correct transformation of properties.
- Added tests for confidenceToPriority function to validate priority assignment based on confidence levels.
- Included edge cases such as handling empty arrays, null app names, and long actionable notes truncation.

* feat(mnemonic): update mnemonic handling to support variable word counts

- Refactored mnemonic import logic to accommodate BIP39 phrase lengths (12, 15, 18, 21, 24 words).
- Updated state initialization and validation to dynamically adjust based on the allowed word counts.
- Enhanced user prompts to reflect the new word count options for recovery phrases.
- Adjusted focus handling for input fields to improve user experience during phrase entry.

* refactor(skills): migrate skill state management to RPC-based hooks

- Replaced Redux-based skill state management with RPC-backed hooks for improved performance and reactivity.
- Introduced `useSkillSnapshot` and `useAllSkillSnapshots` hooks to fetch skill states directly from the Rust core.
- Updated components to utilize the new hooks, enhancing the overall architecture and reducing dependency on Redux.
- Added event listeners to trigger state updates in response to skill state changes, ensuring real-time updates across the application.

* fix(lint): merge duplicate tauriCommands import in accessibilitySlice test

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* refactor(tests): remove eslint-disable comment from screen intelligence E2E test file

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-30 16:31:02 -07:00

74 lines
2.7 KiB
TypeScript

import { pbkdf2 } from '@noble/hashes/pbkdf2.js';
import { sha256 } from '@noble/hashes/sha2.js';
import { keccak_256 } from '@noble/hashes/sha3.js';
import { bytesToHex } from '@noble/hashes/utils.js';
import { getPublicKey } from '@noble/secp256k1';
import { HDKey } from '@scure/bip32';
import { generateMnemonic, mnemonicToSeedSync, validateMnemonic } from '@scure/bip39';
import { wordlist } from '@scure/bip39/wordlists/english.js';
/** Word count for newly generated recovery phrases (128-bit entropy, BIP39). */
export const MNEMONIC_GENERATE_WORD_COUNT = 12;
/**
* Generate a 12-word BIP39 mnemonic phrase (128-bit entropy).
*/
export function generateMnemonicPhrase(): string {
return generateMnemonic(wordlist, 128);
}
/**
* Validate a BIP39 mnemonic phrase.
*/
export function validateMnemonicPhrase(mnemonic: string): boolean {
return validateMnemonic(mnemonic, wordlist);
}
/**
* Derive a 256-bit AES encryption key from a mnemonic phrase.
* Uses BIP39 seed derivation followed by PBKDF2-SHA256.
* Returns the key as a hex string.
*/
export function deriveAesKeyFromMnemonic(mnemonic: string): string {
// Get the BIP39 seed (512-bit) from the mnemonic
const seed = mnemonicToSeedSync(mnemonic);
// Derive a 256-bit AES key using PBKDF2 with the seed
const salt = new TextEncoder().encode('openhuman-aes-key-v1');
const derivedKey = pbkdf2(sha256, seed, salt, { c: 100000, dkLen: 32 });
return bytesToHex(derivedKey);
}
/** BIP44 path for first Ethereum account: m/44'/60'/0'/0/0 */
const EVM_DERIVATION_PATH = "m/44'/60'/0'/0/0";
/**
* Derive the first EVM wallet address (Ethereum BIP44) from a mnemonic phrase.
* Uses path m/44'/60'/0'/0/0. Returns a checksummed 0x-prefixed address.
*/
export function deriveEvmAddressFromMnemonic(mnemonic: string): string {
const seed = mnemonicToSeedSync(mnemonic);
const hdkey = HDKey.fromMasterSeed(seed);
const derived = hdkey.derive(EVM_DERIVATION_PATH);
const privateKey = derived.privateKey;
if (!privateKey) throw new Error('Failed to derive private key');
// Ethereum address = keccak256(uncompressed public key without 0x04)[12:]
const pubKey = getPublicKey(privateKey, false); // uncompressed, 65 bytes
const hash = keccak_256(pubKey.slice(1));
const addressBytes = hash.slice(-20);
const hex = bytesToHex(addressBytes);
return toChecksumAddress('0x' + hex);
}
/** Simple checksum: lowercase with 0x, then capitalize by hash. */
function toChecksumAddress(address: string): string {
const a = address.replace(/^0x/i, '').toLowerCase();
const hash = bytesToHex(keccak_256(new TextEncoder().encode(a)));
let result = '0x';
for (let i = 0; i < 40; i++) {
result += parseInt(hash[i], 16) >= 8 ? a[i].toUpperCase() : a[i];
}
return result;
}