tinyrelayfile
tinyrelay/scripts/file-catalog.test.mjs/

scripts/file-catalog.test.mjs raw
1import test from "node:test";
2import assert from "node:assert/strict";
3import fs from "node:fs";
4import vm from "node:vm";
5
6const source = fs.readFileSync("tinyclient/file-catalog.js", "utf8");
7const pubkey = "a".repeat(64);
8const hash = "b".repeat(64);
9
10function setup({path = "/r/test/files", actor = pubkey} = {}) {
11 const values = new Map();
12 const rows = [];
13 const document = {
14 querySelector(selector) {
15 if (selector === "[data-pubkey]") return {getAttribute: () => actor};
16 if (selector === "#file-library") return {querySelectorAll: () => rows};
17 return null;
18 },
19 createElement() { return {textContent: "", append() {}}; }
20 };
21 const location = {href: "https://relay.test" + path, origin: "https://relay.test", pathname: path};
22 const history = {replaceState(_state, _title, value) { location.href = "https://relay.test" + value; location.pathname = new URL(location.href).pathname; location.hash = new URL(location.href).hash; }};
23 const context = {
24 location, history, document,
25 localStorage: {getItem: key => values.get(key) || null, setItem: (key, value) => values.set(key, value)},
26 URL, URLSearchParams, Date, Number, String, Array, Boolean, Object, RegExp, JSON,
27 globalThis: null, tiny: {localPath: value => "/r/test" + value}
28 };
29 context.globalThis = context;
30 vm.runInNewContext(source, context);
31 return {context, values, rows};
32}
33
34const link = () => `https://relay.test/r/test/file?hash=${hash}#key=${"c".repeat(64)}&iv=${"d".repeat(16)}&name=video.mp4&type=video%2Fmp4`;
35
36test("saves encrypted metadata per tenant and account and restores it after reload", () => {
37 const first = setup({path: "/r/test/file?hash=" + hash});
38 assert.equal(first.context.tiny.files.catalog.save({hash, link: link(), name: "video.mp4", type: "video/mp4", size: 104857600}, pubkey), true);
39 assert.equal(first.context.tiny.files.catalog.get(hash, pubkey).name, "video.mp4");
40 assert.equal(first.context.tiny.files.catalog.get(hash, "e".repeat(64)), null);
41 assert.equal(first.context.tiny.files.catalog.restore(pubkey).name, "video.mp4");
42 assert.match(first.context.location.href, /#key=/);
43});
44
45test("rejects unsafe links, names and cross-tenant links", () => {
46 const {context} = setup();
47 assert.equal(context.tiny.files.catalog.save({hash, link: "https://evil.test/r/test/file?hash=" + hash + "#key=x", name: "x"}, pubkey), false);
48 assert.equal(context.tiny.files.catalog.save({hash, link: link(), name: "../secret"}, pubkey), false);
49 assert.equal(context.tiny.files.catalog.save({hash, link: link().replace("/r/test/", "/r/other/"), name: "x"}, pubkey), false);
50});

About

ownerc01503e8035f
visibilitypublic
headd730679639bf

Maintainers

  • c01503e8035f owner
  • ba1b5beed5b5 agent hermes

Clone

  • https://012.run/npub1cq2s86qrtadf36eqq3epm38wmhdynrrcwxf84eldk3f94dkv7ttsrulrz5/tinyrelay.git

Refs