- Guest-safe legacy personal-root migration with state file and env gates - VFS guest deny for sensitive /.bare paths; warm-cache clear on identity switch - Optional acct/<hash>/ personal layout, guest scrub, vault exclude alignment - Shell session reset + errexit; fish history reload hook; replication metric - Audit NDJSON for migration/scrub; structured booter logging paths - Bump POSIX profile; getconf keys; syscall/socket contract + handbook/docs pass - Booter tests (Bare vs Node split for identity-session); release-checklist audit hook
96 lines
2.8 KiB
JavaScript
96 lines
2.8 KiB
JavaScript
/**
|
|
* bare-crypto loads only under Bare — run via brittle-bare (see package.json "test").
|
|
*/
|
|
import test from 'brittle'
|
|
import b4a from 'b4a'
|
|
import path from 'path'
|
|
import { mkdirSync, rmSync } from 'fs'
|
|
import { fileURLToPath } from 'url'
|
|
import Hyperdrive from 'hyperdrive'
|
|
import Corestore from 'corestore'
|
|
import {
|
|
encodeAccount,
|
|
decodeAccount,
|
|
encodeNewAccount,
|
|
ACCOUNT_MAGIC,
|
|
ACCOUNT_VERSION,
|
|
sealBytes,
|
|
openBytes,
|
|
vaultKeyFromSecret
|
|
} from './lib/identity-account.js'
|
|
import { createVfs } from './lib/vfs.js'
|
|
import { migrateLegacyPersonalHomeIfNeeded } from './lib/identity-session.js'
|
|
|
|
const __dirname = path.dirname(fileURLToPath(import.meta.url))
|
|
|
|
function testCorestoreDir(name) {
|
|
const dir = path.join(
|
|
__dirname,
|
|
'.test-data',
|
|
name + '-' + Date.now() + '-' + Math.random().toString(36).slice(2)
|
|
)
|
|
mkdirSync(path.dirname(dir), { recursive: true })
|
|
return dir
|
|
}
|
|
|
|
test('identity account encode/decode roundtrip', async (t) => {
|
|
const pass = 'unit-test-passphrase'
|
|
const blob = encodeNewAccount(pass)
|
|
t.ok(blob.length > 80)
|
|
t.is(blob[0], ACCOUNT_MAGIC[0])
|
|
t.is(blob[ACCOUNT_MAGIC.length], ACCOUNT_VERSION)
|
|
const { publicKey, secretKey } = decodeAccount(pass, blob)
|
|
t.is(publicKey.length, 32)
|
|
t.is(secretKey.length, 64)
|
|
const blob2 = encodeAccount(pass, publicKey, secretKey)
|
|
const again = decodeAccount(pass, blob2)
|
|
t.alike(publicKey, again.publicKey)
|
|
t.alike(secretKey, again.secretKey)
|
|
let bad = false
|
|
try {
|
|
decodeAccount('wrong-pass', blob)
|
|
} catch {
|
|
bad = true
|
|
}
|
|
t.ok(bad)
|
|
})
|
|
|
|
test('vault sealBytes/openBytes rejects tampered ciphertext', async (t) => {
|
|
const sk = new Uint8Array(64)
|
|
sk.fill(9)
|
|
const key = vaultKeyFromSecret(sk)
|
|
const sealed = sealBytes(key, b4a.from('vault-test'))
|
|
const bad = Uint8Array.from(sealed)
|
|
bad[bad.length - 1] ^= 0xff
|
|
let threw = false
|
|
try {
|
|
openBytes(key, bad)
|
|
} catch {
|
|
threw = true
|
|
}
|
|
t.ok(threw)
|
|
})
|
|
|
|
test('legacy root migration skips guest home when account blob exists', async (t) => {
|
|
const dir = testCorestoreDir('migguest')
|
|
const store = new Corestore(dir)
|
|
const sys = new Hyperdrive(store)
|
|
const personal = new Hyperdrive(store.namespace('pvmig'))
|
|
await sys.ready()
|
|
await personal.ready()
|
|
await personal.put('/legacy-root.txt', b4a.from('legacy'))
|
|
await personal.put('/.bare/account', b4a.from('acc'))
|
|
const env = { HOME: '/home/guest', PWD: '/home/guest', PATH: '/bin' }
|
|
const vfs = createVfs(sys, personal, env)
|
|
const ctx = {
|
|
personalDrive: personal,
|
|
vfs,
|
|
bareOsAuditLogAppendBatch: () => {}
|
|
}
|
|
await migrateLegacyPersonalHomeIfNeeded(ctx)
|
|
t.is(b4a.toString(await personal.get('/legacy-root.txt')), 'legacy')
|
|
t.is(await personal.get('/.bare-os/home/guest/legacy-root.txt'), null)
|
|
await store.close()
|
|
rmSync(dir, { recursive: true, force: true })
|
|
})
|