OverviewFilesCommitsIssuesDocsReleasesPeers

hyper-note / test / unit / secure-storage.test.js

84 lines · javascript ref:
import test from 'brittle'
import fs from 'bare-fs'
import path from 'bare-path'
import os from 'bare-os'
import { SecureStorage } from '../../lib/identity/secure-storage.js'

function tmpVaultPath() {
  const dir = path.join(os.tmpdir(), 'hypernote-test-' + Date.now() + '-' + Math.random().toString(36).slice(2))
  fs.mkdirSync(dir, { recursive: true })
  return path.join(dir, 'test-vault.enc')
}

test('SecureStorage - encrypt and decrypt round-trip', async (t) => {
  const vaultPath = tmpVaultPath()
  const storage = new SecureStorage(vaultPath)

  const plaintext = Buffer.from('my secret mnemonic words here')
  const password = Buffer.from('test-password-123')

  await storage.encrypt(plaintext, password)
  t.ok(storage.exists(), 'vault file exists after encrypt')

  const decrypted = await storage.decrypt(password)
  t.alike(decrypted, plaintext, 'decrypted matches original')

  // Cleanup
  fs.unlinkSync(vaultPath)
  fs.rmdirSync(path.dirname(vaultPath))
})

test('SecureStorage - wrong password fails', async (t) => {
  const vaultPath = tmpVaultPath()
  const storage = new SecureStorage(vaultPath)

  const plaintext = Buffer.from('secret data')
  const password = Buffer.from('correct-password')

  await storage.encrypt(plaintext, password)

  try {
    await storage.decrypt(Buffer.from('wrong-password'))
    t.fail('should have thrown')
  } catch (err) {
    t.ok(err.message.includes('wrong password') || err.message.includes('Decryption failed'), 'error indicates wrong password')
  }

  // Cleanup
  fs.unlinkSync(vaultPath)
  fs.rmdirSync(path.dirname(vaultPath))
})

test('SecureStorage - change password', async (t) => {
  const vaultPath = tmpVaultPath()
  const storage = new SecureStorage(vaultPath)

  const plaintext = Buffer.from('changeable secret')
  const oldPass = Buffer.from('old-password')
  const newPass = Buffer.from('new-password')

  await storage.encrypt(plaintext, oldPass)
  await storage.changePassword(oldPass, newPass)

  // Old password should fail
  try {
    await storage.decrypt(oldPass)
    t.fail('old password should fail')
  } catch {
    t.pass('old password correctly rejected')
  }

  // New password should work
  const decrypted = await storage.decrypt(newPass)
  t.alike(decrypted, plaintext, 'new password decrypts correctly')

  // Cleanup
  fs.unlinkSync(vaultPath)
  fs.rmdirSync(path.dirname(vaultPath))
})

test('SecureStorage - exists() returns false for missing file', (t) => {
  const storage = new SecureStorage('/tmp/nonexistent-vault-' + Date.now() + '.enc')
  t.absent(storage.exists(), 'returns false for missing file')
})