Files
hop.noname.company/apps/server/test/owner-info.test.js

109 lines
4.0 KiB
JavaScript

import { test } from 'node:test';
import assert from 'node:assert/strict';
import { randomUUID } from 'node:crypto';
import { readFileSync, writeFileSync, existsSync } from 'node:fs';
import { eq } from 'drizzle-orm';
import { fixture } from './helpers.js';
import { visitorRegion } from '../src/ownerInfo.js';
import { loadConfig } from '../src/config.js';
import * as s from '../src/db/schema.js';
test('basic country and city use only trusted Cloudflare headers and ignore precise coordinates', () => {
const cfg = { ...loadConfig(), clientIpSource: 'cloudflare', trustedProxies: ['127.0.0.1'] };
const req = {
raw: { socket: { remoteAddress: '127.0.0.1' } },
headers: {
'cf-connecting-ip': '8.8.8.8',
'cf-ipcountry': 'KR',
'cf-region': 'Daejeon',
'cf-ipcity': Buffer.from('대전', 'utf8').toString('latin1'),
'cf-iplatitude': '37.123456',
'cf-iplongitude': '127.123456',
},
};
assert.deepEqual(visitorRegion(req, cfg), {
ip: '8.8.8.8',
countryCode: 'KR',
region: 'Daejeon',
city: '대전',
source: 'cloudflare',
});
for (const change of [{ trustedProxies: [] }, { clientIpSource: 'forwarded' }])
assert.deepEqual(visitorRegion(req, { ...cfg, ...change }), {
ip: null,
countryCode: null,
region: null,
city: null,
source: 'unavailable',
});
assert.equal(
visitorRegion({ ...req, headers: { ...req.headers, 'cf-ipcountry': 'XX' } }, cfg).countryCode,
null,
);
});
test('region records are NAS-only, deduplicated by request, bounded and cleaned with owner files', async () => {
const f = await fixture();
try {
const a = await f.create(),
b = await f.create();
await f.space(a, b);
f.cfg.clientIpSource = 'cloudflare';
const key = randomUUID(),
input = {
targetDeviceId: b.deviceId,
kind: 'file',
byteSize: 4,
count: 1,
files: [{ name: 'test.mp4', size: 4, type: 'video/mp4' }],
},
headers = {
'cf-connecting-ip': '8.8.8.8',
'cf-ipcountry': 'KR',
'cf-region': 'Daejeon',
'cf-ipcity': 'Daejeon',
'cf-iplatitude': '37.123456',
};
const result = await f.call(a, '/transfer-requests', 'POST', input, key, headers);
assert.equal(result.statusCode, 200);
const id = result.json().requestId,
row = f.service.storage.fileRows(id)[0],
owner = f.service.storage.layout.ownerInfo.details(row.storageKey);
const json = () => JSON.parse(readFileSync(owner.path, 'utf8'));
assert.equal(json().uploader.id, row.ownerGuestId);
assert.equal(json().recentLocations[0].city, 'Daejeon');
const serialized = readFileSync(owner.path, 'utf8');
assert.equal(json().recentLocations[0].ip, '8.8.8.8');
for (const secret of ['37.123456', a.csrf, a.cookie])
assert.equal(serialized.includes(secret), false);
await f.call(a, '/transfer-requests', 'POST', input, key, headers);
assert.equal(json().recentLocations.length, 1);
for (let i = 0; i < 30; i++)
f.service.storage.layout.ownerInfo.record(row, randomUUID(), {
countryCode: 'CN',
region: null,
city: null,
source: 'cloudflare',
});
assert.equal(json().recentLocations.length, 20);
const response = await f.app.inject({
url: '/uploads/originals/' + row.storageKey.split('/')[0] + '/owner-info.json',
});
assert.equal(
response.body.includes('recentLocations'),
false,
'metadata is not publicly served',
);
const expired = json();
for (const event of expired.recentLocations)
event.recordedAt = new Date(Date.now() - 8 * 86400000).toISOString();
writeFileSync(owner.path, JSON.stringify(expired));
await f.service.storage.layout.ownerInfo.cleanup();
assert.equal(json().recentLocations.length, 0);
f.service.db.update(s.files).set({ status: 'failed' }).where(eq(s.files.id, row.id)).run();
await f.service.storage.layout.ownerInfo.cleanup();
assert.equal(existsSync(owner.path), false);
} finally {
await f.close();
}
});