1+ import { useNodeConfigStore } from '../store/nodeConfigStore' ;
2+ import { encryptField , decryptField } from '../lib/crypto/cryptoEngine' ;
3+ import { saveToIndexedDB , loadFromIndexedDB } from '../lib/storage/idb' ;
4+
5+ // Define layout schema metadata
6+ const CONFIG_SCHEMA : Record < string , { sensitive : boolean } > = {
7+ rpcEndpoint : { sensitive : true } ,
8+ apiKey : { sensitive : true } ,
9+ sshCredentials : { sensitive : true } ,
10+ nodeName : { sensitive : false } ,
11+ } ;
12+
13+ export function useNodeConfig ( getSessionKey : ( ) => CryptoKey , getSalt : ( ) => Uint8Array | null ) {
14+ const store = useNodeConfigStore ( ) ;
15+
16+ const loadConfig = async ( nodeId : string ) => {
17+ const rawPayload = await loadFromIndexedDB ( nodeId ) ;
18+ if ( ! rawPayload ) return null ;
19+
20+ const sessionKey = getSessionKey ( ) ;
21+ const decryptedConfig : Record < string , any > = { } ;
22+
23+ for ( const [ key , value ] of Object . entries ( rawPayload ) ) {
24+ if ( CONFIG_SCHEMA [ key ] ?. sensitive && value && typeof value === 'object' ) {
25+ decryptedConfig [ key ] = await decryptField ( value , sessionKey ) ;
26+ } else {
27+ decryptedConfig [ key ] = value ;
28+ }
29+ }
30+
31+ store . startEditing ( decryptedConfig ) ;
32+ } ;
33+
34+ const saveConfig = async ( nodeId : string ) => {
35+ if ( ! store . editingConfig ) return ;
36+
37+ const sessionKey = getSessionKey ( ) ;
38+ const salt = getSalt ( ) ;
39+ if ( ! salt ) throw new Error ( 'Salt configuration missing' ) ;
40+
41+ // Create shallow target object copy to execute transformations
42+ const payloadToPersist = { ...store . editingConfig } ;
43+
44+ for ( const [ key , value ] of Object . entries ( payloadToPersist ) ) {
45+ if ( CONFIG_SCHEMA [ key ] ?. sensitive && typeof value === 'string' ) {
46+ // 1. Encrypt field mutation
47+ payloadToPersist [ key ] = await encryptField ( value , sessionKey , salt ) ;
48+
49+ // 2. Strict Memory Hygiene: Purge plaintexts from the working copy immediately
50+ if ( store . editingConfig [ key ] ) {
51+ store . editingConfig [ key ] = null ;
52+ delete store . editingConfig [ key ] ;
53+ }
54+ }
55+ }
56+
57+ // Persist finalized structural envelope safely to DB
58+ await saveToIndexedDB ( nodeId , payloadToPersist ) ;
59+
60+ // Wipe out state trace fully
61+ store . clearEditor ( ) ;
62+ } ;
63+
64+ return {
65+ isEditorOpen : store . isEditorOpen ,
66+ editingConfig : store . editingConfig ,
67+ updateField : store . updateField ,
68+ loadConfig,
69+ saveConfig,
70+ cancelEditing : store . clearEditor ,
71+ } ;
72+ }
0 commit comments