mirror of
https://github.com/ancsemi/Haven.git
synced 2026-10-27 00:54:56 +00:00
78 lines
3.7 KiB
JavaScript
78 lines
3.7 KiB
JavaScript
'use strict';
|
|
|
|
// Copying a Discord import's pictures and files into Haven (#5811).
|
|
|
|
const assert = require('node:assert/strict');
|
|
const fs = require('node:fs');
|
|
const os = require('node:os');
|
|
const path = require('node:path');
|
|
const test = require('node:test');
|
|
|
|
process.env.HAVEN_DATA_DIR = fs.mkdtempSync(path.join(os.tmpdir(), 'haven-importfiles-'));
|
|
const { UPLOADS_DIR } = require('../src/paths');
|
|
const { copyAttachments, isDiscordFile } = require('../src/importFiles');
|
|
|
|
fs.mkdirSync(UPLOADS_DIR, { recursive: true });
|
|
const PNG = Buffer.from('89504e470d0a1a0a0000000d49484452', 'hex');
|
|
const CDN = 'https://cdn.discordapp.com/attachments/1/2/';
|
|
|
|
const fetched = [];
|
|
const fakeFetch = async (url) => {
|
|
fetched.push(url);
|
|
if (url.includes('gone')) return new Response('expired', { status: 404 });
|
|
if (url.includes('huge')) return new Response(Buffer.alloc(2048), { status: 200, headers: { 'content-length': '2048' } });
|
|
if (url.includes('sneaky')) return new Response(Buffer.alloc(4096), { status: 200 }); // no length given
|
|
const body = url.includes('.png') ? PNG : Buffer.from('%PDF-1.4 hello');
|
|
return new Response(body, { status: 200, headers: { 'content-length': String(body.length) } });
|
|
};
|
|
// The privacy pass is tested on its own; here it only has to move the file in.
|
|
const admit = async (tmp, rel) => {
|
|
const dest = path.join(UPLOADS_DIR, rel);
|
|
fs.renameSync(tmp, dest);
|
|
return { size: fs.statSync(dest).size };
|
|
};
|
|
const opts = (state = {}) => ({ capBytes: 1024, state, fetchImpl: fakeFetch, admit });
|
|
|
|
test('only Discord file links count', () => {
|
|
assert.equal(isDiscordFile(CDN + 'cat.png?ex=1'), true);
|
|
assert.equal(isDiscordFile('https://media.discordapp.net/attachments/1/2/cat.png'), true);
|
|
assert.equal(isDiscordFile('https://cdn.discordapp.com/avatars/1/2.png'), false);
|
|
assert.equal(isDiscordFile('http://cdn.discordapp.com/attachments/1/2/cat.png'), false);
|
|
assert.equal(isDiscordFile('https://127.0.0.1/attachments/x.png'), false);
|
|
assert.equal(isDiscordFile('not a link'), false);
|
|
});
|
|
|
|
test('a picture becomes a stored picture, a file a file line', async () => {
|
|
const state = {};
|
|
const out = await copyAttachments(`look\n📎 [cat.png](${CDN}cat.png?ex=1)\n📎 [notes.pdf](${CDN}notes.pdf)`, opts(state));
|
|
const [text, pic, file] = out.split('\n');
|
|
assert.equal(text, 'look');
|
|
assert.match(pic, /^\/uploads\/\d+-[0-9a-f]{16}\.png$/);
|
|
assert.ok(fs.existsSync(path.join(UPLOADS_DIR, path.basename(pic))));
|
|
assert.match(file, /^\[file:notes\.pdf\]\(\/uploads\/\d+-[0-9a-f]{16}\.pdf\|14 B\)$/);
|
|
assert.equal(state.copied, 2);
|
|
});
|
|
|
|
test('links anywhere else are never fetched', async () => {
|
|
fetched.length = 0;
|
|
const line = '📎 [x.png](https://192.168.1.10/attachments/x.png)';
|
|
assert.equal(await copyAttachments(line, opts()), line);
|
|
assert.equal(fetched.length, 0);
|
|
});
|
|
|
|
test('expired, too large or growing past the limit: the link stays', async () => {
|
|
const state = {};
|
|
const lines = [`📎 [a.png](${CDN}gone.png)`, `📎 [b.png](${CDN}huge.png)`, `📎 [c.png](${CDN}sneaky.png)`];
|
|
assert.equal(await copyAttachments(lines.join('\n'), opts(state)), lines.join('\n'));
|
|
assert.equal(state.skipped, 3);
|
|
assert.equal(state.copied, undefined);
|
|
assert.deepEqual(fs.readdirSync(path.join(process.env.HAVEN_DATA_DIR, 'unprocessed')).filter(f => f.startsWith('import-')), [], 'no half-written files left behind');
|
|
});
|
|
|
|
test('a forward keeps its quote, the file goes under it', async () => {
|
|
const out = await copyAttachments(`> *Forwarded*\n> look\n📎 [cat.png](${CDN}cat.png)`, opts());
|
|
assert.match(out, /^> \*Forwarded\*\n> look\n\/uploads\/\S+\.png$/);
|
|
});
|
|
|
|
test.after(() => fs.rmSync(process.env.HAVEN_DATA_DIR, { recursive: true, force: true }));
|