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'
const tmpDir = path.join(os.tmpdir(), 'pear-git-test-vault-' + Date.now())
function vaultPath (name) {
return path.join(tmpDir, name + '.enc')
}
test('setup: create temp dir', async (t) => {
await fs.promises.mkdir(tmpDir, { recursive: true })
t.pass('temp dir created')
})
test('secure-storage: encrypt and decrypt roundtrip', async (t) => {
const vault = new SecureStorage(vaultPath('roundtrip'))
const plaintext = Buffer.from('abandon ability able about above absent')
const password = Buffer.from('test-password-123')
await vault.encrypt(plaintext, password)
t.ok(vault.exists(), 'vault file exists after encrypt')
const decrypted = await vault.decrypt(password)
t.alike(decrypted, plaintext, 'decrypted matches original plaintext')
})
test('secure-storage: wrong password throws', async (t) => {
const vault = new SecureStorage(vaultPath('wrongpw'))
const plaintext = Buffer.from('secret data here')
const password = Buffer.from('correct-password')
const wrongPassword = Buffer.from('wrong-password')
await vault.encrypt(plaintext, password)
try {
await vault.decrypt(wrongPassword)
t.fail('should have thrown')
} catch (err) {
t.ok(err.message.includes('wrong password'), 'throws on wrong password')
}
})
test('secure-storage: change password', async (t) => {
const vault = new SecureStorage(vaultPath('changepw'))
const plaintext = Buffer.from('mnemonic words here')
const oldPw = Buffer.from('old-password')
const newPw = Buffer.from('new-password')
await vault.encrypt(plaintext, oldPw)
await vault.changePassword(oldPw, newPw)
// Old password should fail
try {
await vault.decrypt(oldPw)
t.fail('old password should not work')
} catch {
t.pass('old password rejected after change')
}
// New password should work
const decrypted = await vault.decrypt(newPw)
t.alike(decrypted, plaintext, 'new password decrypts correctly')
})
test('secure-storage: exists() returns false for missing file', (t) => {
const vault = new SecureStorage(vaultPath('nonexistent'))
t.is(vault.exists(), false, 'exists() is false for missing file')
})
test('secure-storage: vault file has correct version', async (t) => {
const vault = new SecureStorage(vaultPath('version'))
await vault.encrypt(Buffer.from('data'), Buffer.from('pw'))
const raw = JSON.parse(await fs.promises.readFile(vaultPath('version'), 'utf-8'))
t.is(raw.version, 1, 'vault version is 1')
t.ok(raw.salt, 'salt present')
t.ok(raw.nonce, 'nonce present')
t.ok(raw.ciphertext, 'ciphertext present')
t.ok(raw.opslimit, 'opslimit present')
t.ok(raw.memlimit, 'memlimit present')
})
test('secure-storage: vault file has mode 0600', async (t) => {
const fp = vaultPath('perms')
const vault = new SecureStorage(fp)
await vault.encrypt(Buffer.from('data'), Buffer.from('pw'))
const stat = await fs.promises.stat(fp)
const mode = stat.mode & 0o777
t.is(mode, 0o600, 'vault file mode is 0600')
})
test('cleanup: remove temp dir', async (t) => {
await fs.promises.rm(tmpDir, { recursive: true, force: true })
t.pass('cleaned up')
})