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,477 @@
import {
getPublicKey,
randomPrivateKey,
} from "@suaveplan/crypto-curve/ed25519";
import { Drive } from "@suaveplan/drive";
import { MemoryStorage } from "@suaveplan/storage/memory";
import { describe, expect, it } from "@suaveplan/testing/runner";
import { parseChunk } from "./codec/chunk.js";
import { buildManifest } from "./manifest/build.js";
import { chunksPlugin } from "./plugin.js";
function createDriveStorage(id: string) {
return Object.assign(new MemoryStorage(), {
id,
}) as import("@suaveplan/drive").DriveStorage;
}
describe("CHUNKS-INVARIANT-01 — Store-as-is", () => {
it("putChunk persists raw bytes unchanged", { timeout: 5000 }, async () => {
const privKey = randomPrivateKey();
const pubKey = getPublicKey(privKey);
const storage = createDriveStorage("default");
const drive = new Drive(storage);
await drive.initialize();
const chunks = await drive.usePlugin(
chunksPlugin({
serverPrivKey: privKey,
serverPubKey: pubKey,
chunkSize: 1024,
})
);
await drive.write("test.txt", new TextEncoder().encode("hello world"));
const fileId = await chunks.ingest("test.txt");
const raw = await chunks.getChunk(fileId, 0);
expect(raw).toBeDefined();
const parsed = parseChunk(raw!);
expect(parsed.metadata.fileId).toEqual(fileId);
await drive.dispose();
});
});
describe("CHUNKS-VERIFY-01 — Sig-verify gate on receipt", () => {
it("putChunk rejects invalid signature before persist", {
timeout: 5000,
}, async () => {
const privKey = randomPrivateKey();
const _pubKey = getPublicKey(privKey);
const wrongPubKey = getPublicKey(randomPrivateKey());
const storage = createDriveStorage("default");
const drive = new Drive(storage);
await drive.initialize();
const chunks = await drive.usePlugin(
chunksPlugin({
serverPrivKey: privKey,
serverPubKey: wrongPubKey,
chunkSize: 1024,
})
);
await drive.write("test.txt", new TextEncoder().encode("hello world"));
const fileId = await chunks.ingest("test.txt");
const raw = await chunks.getChunk(fileId, 0);
expect(raw).toBeDefined();
// Now try to put the same chunk with a different pubKey (wrong signer)
const chunks2 = await drive.usePlugin(
chunksPlugin({
serverPrivKey: privKey,
serverPubKey: wrongPubKey,
chunkSize: 1024,
})
);
await expect(chunks2.putChunk(raw!)).rejects.toThrow();
try {
await chunks2.putChunk(raw!);
} catch (e) {
expect((e as { code?: string }).code).toBe("CHUNKS.SIG_INVALID");
}
await drive.dispose();
});
});
describe("CHUNKS-READ-01 — Read middleware reassembles", () => {
it("read returns original plaintext after ingest", {
timeout: 5000,
}, async () => {
const privKey = randomPrivateKey();
const pubKey = getPublicKey(privKey);
const storage = createDriveStorage("default");
const drive = new Drive(storage);
await drive.initialize();
const chunks = await drive.usePlugin(
chunksPlugin({
serverPrivKey: privKey,
serverPubKey: pubKey,
chunkSize: 1024,
})
);
const plaintext = new TextEncoder().encode(
"hello world from chunked drive"
);
await drive.write("test.txt", plaintext);
await chunks.ingest("test.txt");
const result = await drive.read("test.txt");
expect(result).toEqual(plaintext);
await drive.dispose();
});
it("throws when chunk is missing during reassembly", {
timeout: 5000,
}, async () => {
const privKey = randomPrivateKey();
const pubKey = getPublicKey(privKey);
const storage = createDriveStorage("default");
const drive = new Drive(storage);
await drive.initialize();
// Use chunk-keys layout so we can delete individual chunks
const chunks = await drive.usePlugin(
chunksPlugin({
serverPrivKey: privKey,
serverPubKey: pubKey,
chunkSize: 1024,
layout: "chunk-keys",
})
);
const plaintext = new TextEncoder().encode("x".repeat(2000));
await drive.write("test.txt", plaintext);
const fileId = await chunks.ingest("test.txt");
// Delete chunk 1 to simulate corruption
await storage.delete(
`chunks/${Array.from(fileId, (b) => b.toString(16).padStart(2, "0")).join("")}/1`
);
await expect(drive.read("test.txt")).rejects.toThrow();
try {
await drive.read("test.txt");
} catch (e) {
expect((e as { code?: string }).code).toBe("CHUNKS.FILE_NOT_FOUND");
}
await drive.dispose();
});
});
describe("CHUNKS-PLUGIN-INIT-01 — Storage resolution", () => {
it("throws when drive has no getStorage", { timeout: 5000 }, async () => {
const privKey = randomPrivateKey();
const pubKey = getPublicKey(privKey);
const fakeDrive = {
useMiddleware: () => {},
getStorage: () => {
throw new Error("no storage");
},
} as unknown as import("@suaveplan/drive").DriveLike;
const plugin = chunksPlugin({
serverPrivKey: privKey,
serverPubKey: pubKey,
});
await expect(plugin.install(fakeDrive)).rejects.toThrow();
try {
await plugin.install(fakeDrive);
} catch (e) {
expect((e as { code?: string }).code).toBe("CHUNKS.FILE_NOT_FOUND");
}
});
});
describe("CHUNKS-INGEST-01 — Edge cases", () => {
it("ingests empty file", { timeout: 5000 }, async () => {
const privKey = randomPrivateKey();
const pubKey = getPublicKey(privKey);
const storage = createDriveStorage("default");
const drive = new Drive(storage);
await drive.initialize();
const chunks = await drive.usePlugin(
chunksPlugin({
serverPrivKey: privKey,
serverPubKey: pubKey,
chunkSize: 1024,
})
);
await drive.write("empty.txt", new Uint8Array(0));
const fileId = await chunks.ingest("empty.txt");
// Empty file produces zero chunks, but manifest should exist
const manifestRaw = await storage.get(
`manifest:${Array.from(fileId, (b) => b.toString(16).padStart(2, "0")).join("")}`
);
expect(manifestRaw).toBeDefined();
await drive.dispose();
});
});
describe("CHUNKS-SOURCE-01 — ChunkSource interface", () => {
it("hasChunks and availableChunks reflect stored chunks", {
timeout: 5000,
}, async () => {
const privKey = randomPrivateKey();
const pubKey = getPublicKey(privKey);
const storage = createDriveStorage("default");
const drive = new Drive(storage);
await drive.initialize();
const chunks = await drive.usePlugin(
chunksPlugin({
serverPrivKey: privKey,
serverPubKey: pubKey,
chunkSize: 1024,
layout: "chunk-keys",
})
);
const plaintext = new TextEncoder().encode(
"hello world from chunked drive"
);
await drive.write("test.txt", plaintext);
const fileId = await chunks.ingest("test.txt");
const has = await chunks.hasChunks(fileId);
expect(has[0]).toBe(true);
const available = Array.from(await chunks.availableChunks(fileId));
expect(available).toEqual([0]);
await drive.dispose();
});
it("putChunk stores a valid chunk", { timeout: 5000 }, async () => {
const privKey = randomPrivateKey();
const pubKey = getPublicKey(privKey);
const storage = createDriveStorage("default");
const drive = new Drive(storage);
await drive.initialize();
const chunks = await drive.usePlugin(
chunksPlugin({
serverPrivKey: privKey,
serverPubKey: pubKey,
chunkSize: 1024,
layout: "chunk-keys",
})
);
const plaintext = new TextEncoder().encode(
"hello world from chunked drive"
);
await drive.write("test.txt", plaintext);
const fileId = await chunks.ingest("test.txt");
const raw = await chunks.getChunk(fileId, 0);
expect(raw).toBeDefined();
// Re-put the same chunk (valid signature)
await chunks.putChunk(raw!);
// Verify it was stored
const stored = await chunks.getChunk(fileId, 0);
expect(stored).toBeDefined();
expect(stored!).toEqual(raw!);
await drive.dispose();
});
it("exposes layout name", { timeout: 5000 }, async () => {
const privKey = randomPrivateKey();
const pubKey = getPublicKey(privKey);
const storage = createDriveStorage("default");
const drive = new Drive(storage);
await drive.initialize();
const chunks = await drive.usePlugin(
chunksPlugin({
serverPrivKey: privKey,
serverPubKey: pubKey,
chunkSize: 1024,
layout: "chunk-keys",
})
);
expect(chunks.layout).toBe("chunk-keys");
await drive.dispose();
});
it("uses default chunkSize when not specified", {
timeout: 5000,
}, async () => {
const privKey = randomPrivateKey();
const pubKey = getPublicKey(privKey);
const storage = createDriveStorage("default");
const drive = new Drive(storage);
await drive.initialize();
const chunks = await drive.usePlugin(
chunksPlugin({ serverPrivKey: privKey, serverPubKey: pubKey })
);
const plaintext = new TextEncoder().encode("hello world");
await drive.write("default-size.txt", plaintext);
const fileId = await chunks.ingest("default-size.txt");
expect(fileId).toBeDefined();
await drive.dispose();
});
it("uses explicit sparse-file layout", { timeout: 5000 }, async () => {
const privKey = randomPrivateKey();
const pubKey = getPublicKey(privKey);
const storage = createDriveStorage("default");
const drive = new Drive(storage);
await drive.initialize();
const chunks = await drive.usePlugin(
chunksPlugin({
serverPrivKey: privKey,
serverPubKey: pubKey,
layout: "sparse-file",
})
);
expect(chunks.layout).toBe("sparse-file");
const plaintext = new TextEncoder().encode("hello world");
await drive.write("sparse.txt", plaintext);
const fileId = await chunks.ingest("sparse.txt");
expect(fileId).toBeDefined();
await drive.dispose();
});
it("throws when drive.getStorage is missing", {
timeout: 5000,
}, async () => {
const privKey = randomPrivateKey();
const pubKey = getPublicKey(privKey);
const fakeDrive = {
useMiddleware: () => {},
} as unknown as import("@suaveplan/drive").DriveLike;
const plugin = chunksPlugin({
serverPrivKey: privKey,
serverPubKey: pubKey,
});
await expect(plugin.install(fakeDrive)).rejects.toThrow();
try {
await plugin.install(fakeDrive);
} catch (e) {
expect((e as { code?: string }).code).toBe("CHUNKS.FILE_NOT_FOUND");
}
});
});
describe("CHUNKS-MANIFEST-LOAD-01 — Manifest loading", () => {
it("throws when manifest is missing", { timeout: 5000 }, async () => {
const privKey = randomPrivateKey();
const pubKey = getPublicKey(privKey);
const storage = createDriveStorage("default");
const drive = new Drive(storage);
await drive.initialize();
const chunks = await drive.usePlugin(
chunksPlugin({
serverPrivKey: privKey,
serverPubKey: pubKey,
chunkSize: 1024,
})
);
const plaintext = new TextEncoder().encode("hello world");
await drive.write("test.txt", plaintext);
const fileId = await chunks.ingest("test.txt");
// Delete the manifest
await storage.delete(
`manifest:${Array.from(fileId, (b) => b.toString(16).padStart(2, "0")).join("")}`
);
await expect(drive.read("test.txt")).rejects.toThrow();
try {
await drive.read("test.txt");
} catch (e) {
expect((e as { code?: string }).code).toBe(
"CHUNKS.MANIFEST_NOT_FOUND"
);
}
await drive.dispose();
});
it("loads manifest from server when configured", {
timeout: 5000,
}, async () => {
const privKey = randomPrivateKey();
const pubKey = getPublicKey(privKey);
const storage = createDriveStorage("default");
const drive = new Drive(storage);
await drive.initialize();
const manifest = buildManifest({
fileId: new Uint8Array(32),
fileSize: 1n,
chunkSize: 65536,
totalChunks: 1,
encryption: {
algo: "xchacha20poly1305",
fileKeyWrapped: new Uint8Array(32),
baseNonce: new Uint8Array(24),
},
chunks: [{ chunkId: 0, hash: new Uint8Array(32), payloadLen: 1 }],
serverPrivKey: privKey,
});
const raw = new TextEncoder().encode(
JSON.stringify(manifest, (_k, v) => {
if (v instanceof Uint8Array)
return `base64:${btoa(String.fromCharCode(...v))}`;
if (typeof v === "bigint") return v.toString();
return v;
})
);
const originalFetch = globalThis.fetch;
// @ts-expect-error - mocking global fetch
globalThis.fetch = async () => ({
ok: true,
arrayBuffer: async () => raw.buffer,
});
try {
const chunks = await drive.usePlugin(
chunksPlugin({
serverPrivKey: privKey,
serverPubKey: pubKey,
chunkSize: 1024,
manifestSource: "server-only",
manifestServerUrl: "http://test-server",
})
);
const plaintext = new TextEncoder().encode("hello world");
await drive.write("server-test.txt", plaintext);
const fileId = await chunks.ingest("server-test.txt");
// Remove local manifest so server path is taken
await storage.delete(
`manifest:${Array.from(fileId, (b) => b.toString(16).padStart(2, "0")).join("")}`
);
// loadManifest should call the server
const loaded = await chunks.loadManifest(fileId);
expect(loaded.version).toBe(0x0001);
} finally {
globalThis.fetch = originalFetch;
}
await drive.dispose();
});
});