Initial Commit

This commit is contained in:
2026-05-27 23:47:53 +01:00
parent fbc70f96e6
commit 9b28db724f
18103 changed files with 1600554 additions and 0 deletions

View File

@@ -0,0 +1,240 @@
import { describe, expect, it } from "@suaveplan/testing/runner";
import * as fc from "fast-check";
import {
createEmptyContainer,
decryptContainer,
encryptContainer,
} from "../src/container/container.js";
import {
decryptField,
encryptField,
} from "../src/encryption/field-encryption.js";
import { VAULT_CODES } from "../src/errors/codes.js";
import { VaultError } from "../src/errors/vault-error.js";
import {
createManifest,
packManifest,
unpackManifest,
} from "../src/manifest/manifest.js";
import type {
DriveLike,
DriveSharingLike,
SyncDelegationResult,
SyncSnapshot,
VaultSyncLike,
} from "../src/types/adapters.js";
import type { VaultConfig } from "../src/types/types.js";
import { Vault } from "../src/vault/vault.js";
function vaultKey(): Uint8Array {
const key = new Uint8Array(32);
crypto.getRandomValues(key);
return key;
}
function memoryDrive(): DriveLike & { blobs: Map<string, Uint8Array> } {
const blobs = new Map<string, Uint8Array>();
return {
blobs,
async read(path) {
const v = blobs.get(path);
if (v === undefined) throw new Error(`missing ${path}`);
return v;
},
async write(path, data) {
blobs.set(path, new Uint8Array(data));
},
async delete(path) {
return blobs.delete(path);
},
async exists(path) {
return blobs.has(path);
},
};
}
function noopSharing(): DriveSharingLike {
return {
async createLink() {
return { id: "x", url: "https://x.example/x" };
},
async revokeLink() {},
async isActive() {
return true;
},
};
}
function noopSync(): VaultSyncLike {
let last: SyncSnapshot = { items: [], snapshotAt: 0 };
return {
hydrate(s) {
last = s;
},
async pull(): Promise<SyncDelegationResult> {
return { merged: [], conflicts: [], deleted: [], durationMs: 0 };
},
async push(): Promise<SyncDelegationResult> {
return { merged: [], conflicts: [], deleted: [], durationMs: 0 };
},
async sync(): Promise<SyncDelegationResult> {
return { merged: [], conflicts: [], deleted: [], durationMs: 0 };
},
currentSnapshot() {
return last;
},
};
}
function makeConfig(): VaultConfig {
return {
vaultId: "personal",
email: "u@example.com",
containerPath: "/v.bin",
attachmentsPrefix: "/att",
argon2id: {
memoryKB: 65536,
iterations: 3,
parallelism: 1,
outputLength: 32,
},
argon2idSalt: new Uint8Array(16),
drive: memoryDrive(),
driveSharing: noopSharing(),
sync: noopSync(),
};
}
describe("vault — property tests", () => {
it("encryptField + decryptField round-trip preserves arbitrary plaintexts", {
timeout: 30000,
}, () => {
const key = vaultKey();
fc.assert(
fc.property(fc.string({ maxLength: 256 }), (value) => {
const envelope = encryptField({
vaultKey: key,
itemId: "i1",
fieldName: "f",
value,
});
const recovered = decryptField({
vaultKey: key,
itemId: "i1",
fieldName: "f",
envelope,
});
return recovered === value;
}),
{ numRuns: 50 }
);
});
it("manifest pack/unpack round-trips for arbitrary parameter combinations", {
timeout: 30000,
}, () => {
fc.assert(
fc.property(
fc.integer({ min: 1, max: 0xff_ff_ff_ff }),
fc.integer({ min: 1, max: 0xff_ff }),
fc.integer({ min: 1, max: 0xff }),
fc.integer({ min: 0, max: 0xff_ff }),
(memoryKB, iterations, parallelism, schemaVersion) => {
const m = createManifest({
vaultId: "v",
argon2idMemoryKB: memoryKB,
argon2idIterations: iterations,
argon2idParallelism: parallelism,
schemaVersion,
now: 1_700_000_000_000,
});
const packed = packManifest(m);
const round = unpackManifest(packed);
return (
round.argon2idMemoryKB === memoryKB &&
round.argon2idIterations === iterations &&
round.argon2idParallelism === parallelism &&
round.schemaVersion === schemaVersion
);
}
),
{ numRuns: 30 }
);
});
it("container encrypt + decrypt round-trips arbitrary item ids", {
timeout: 30000,
}, () => {
const key = vaultKey();
fc.assert(
fc.property(
fc.string({ minLength: 1, maxLength: 32 }),
fc.string({ maxLength: 64 }),
(id, title) => {
const { manifest, state } = createEmptyContainer({
vaultId: "v",
argon2idMemoryKB: 65536,
argon2idIterations: 3,
argon2idParallelism: 4,
now: 1,
});
state.items.set(id, {
id,
createdAt: 1,
updatedAt: 1,
version: 1,
deleted: false,
title,
category: "x",
fieldsJson: "{}",
concealedFieldsJson: "{}",
tagsJson: "[]",
favorite: false,
});
const blob = encryptContainer({
manifest,
state,
vaultKey: key,
});
const round = decryptContainer(blob, key);
return round.state.items.get(id)?.title === title;
}
),
{ numRuns: 20 }
);
});
it("lock is idempotent across repeat calls", {
timeout: 30000,
}, async () => {
const vault = Vault.open(makeConfig());
await vault.lock();
await vault.lock();
await vault.lock();
expect(vault.isLocked).toBe(true);
});
it("every CRUD method on a locked vault throws VAULT.LOCKED", {
timeout: 30000,
}, () => {
const vault = Vault.open(makeConfig());
const ops: Array<() => unknown> = [
() => vault.items,
() => vault.search,
() => vault.attachments,
() => vault.shares,
() => vault.sync,
() => vault.currentManifest(),
];
for (const fn of ops) {
let captured: unknown = null;
try {
fn();
} catch (err) {
captured = err;
}
expect(VaultError.is(captured)).toBe(true);
expect((captured as VaultError).code).toBe(VAULT_CODES.LOCKED);
}
});
});