/** * Node.js secure memory implementation. * * When the optional native addon (nomyo-native) is installed and built, * this implementation provides true OS-level memory locking (mlock) and * secure zeroing via explicit_bzero / SecureZeroMemory. * * Without the native addon it falls back to pure-JS zeroing only. * * To build the native addon: * cd native && npm install && npm run build */ import { SecureMemory } from './secure'; import { ProtectionInfo } from '../../types/crypto'; interface NativeAddon { mlockBuffer(buf: Buffer): boolean; munlockBuffer(buf: Buffer): boolean; secureZeroBuffer(buf: Buffer): void; getPageSize(): number; } // Try to load the optional native addon once at module init time. let nativeAddon: NativeAddon | null = null; try { // eslint-disable-next-line @typescript-eslint/no-var-requires const loaded = require('nomyo-native') as NativeAddon | null; if (loaded && typeof loaded.mlockBuffer === 'function') { nativeAddon = loaded; } } catch (_e) { // Native addon not installed — degrade gracefully } export class NodeSecureMemory implements SecureMemory { private readonly hasNative: boolean; constructor() { this.hasNative = nativeAddon !== null; if (this.hasNative) { console.log('nomyo-native addon loaded: mlock + secure-zero available'); } } /** * Zero memory. * With native addon: uses explicit_bzero / SecureZeroMemory (not optimized away). * Without native addon: fills ArrayBuffer with zeros via Uint8Array (best effort). */ zeroMemory(data: ArrayBuffer): void { if (this.hasNative && nativeAddon) { // Buffer.from(arrayBuffer) shares the underlying memory (no copy) const buf = Buffer.from(data); nativeAddon.secureZeroBuffer(buf); } // Always also zero via JS for defence-in-depth const view = new Uint8Array(data); view.fill(0); } /** * Attempt to lock an ArrayBuffer in physical memory (prevent swapping). * Best-effort: fails gracefully without CAP_IPC_LOCK / elevated privileges. */ lockMemory(data: ArrayBuffer): boolean { if (!this.hasNative || !nativeAddon) return false; const buf = Buffer.from(data); return nativeAddon.mlockBuffer(buf); } /** * Unlock previously locked memory. */ unlockMemory(data: ArrayBuffer): boolean { if (!this.hasNative || !nativeAddon) return false; const buf = Buffer.from(data); return nativeAddon.munlockBuffer(buf); } /** * Get memory protection information. */ getProtectionInfo(): ProtectionInfo { if (this.hasNative) { return { canLock: true, isPlatformSecure: true, method: 'mlock', details: 'Node.js with nomyo-native addon: mlock + explicit_bzero/SecureZeroMemory available.', }; } return { canLock: false, isPlatformSecure: false, method: 'zero-only', details: 'Node.js (pure JS): memory locking not available without native addon. ' + 'Using immediate zeroing only. ' + 'Build the optional native addon for mlock support: cd native && npm install && npm run build', }; } }