Show authenticated daily operation records
This commit is contained in:
@@ -125,3 +125,39 @@ test('evolution is private, readable after login, and empty when absent', async
|
||||
const empty = await request('/api/evolution', { headers: { Cookie: cookie } });
|
||||
assert.equal(empty.status, 200); assert.deepEqual(await empty.json(), { schema_version: 1, events: [] });
|
||||
});
|
||||
|
||||
test('daily records require authentication, sort by date, validate input and remain read-only', async t => {
|
||||
const { directory, request, login } = await fixture(t);
|
||||
await mkdir(path.join(directory, 'daily'));
|
||||
const write = (name, value) => writeFile(path.join(directory, 'daily', name), value);
|
||||
await write('2026-11-02.json', JSON.stringify({ date: '2026-11-02', planned: ['<script>private</script>'], costs: ['未知'] }));
|
||||
await write('2026-11-03.json', JSON.stringify({ date: '2026-11-03', executed: ['完成'], evidence: ['证据'] }));
|
||||
await write('2026-11-04.json', '{broken');
|
||||
await write('2026-11-05.json', JSON.stringify({ date: '2026-11-05', planned: 'wrong type' }));
|
||||
await write('2026-02-30.json', JSON.stringify({ date: '2026-02-30' }));
|
||||
await write('ignored.json', 'bad');
|
||||
const anonymous = await request('/api/daily'); assert.equal(anonymous.status, 401); assert.doesNotMatch(await anonymous.text(), /private|完成/);
|
||||
assert.equal((await request('/daily/2026-11-02.json')).status, 404);
|
||||
const cookie = (await login()).headers.get('set-cookie').split(';')[0];
|
||||
const headers = { Cookie: cookie };
|
||||
const result = await request('/api/daily', { headers }); assert.equal(result.status, 200);
|
||||
const body = await result.json(); assert.equal(body.invalid_count, 3);
|
||||
assert.deepEqual(body.records.map(r => r.date), ['2026-11-03', '2026-11-02']);
|
||||
assert.deepEqual(body.records[0].planned, []); assert.deepEqual(body.records[0].executed, ['完成']);
|
||||
assert.deepEqual(body.records[1].costs, ['未知']);
|
||||
assert.equal((await request('/api/daily', { method: 'POST', headers: { ...headers, Origin: origin }, body: '{}' })).status, 404);
|
||||
await rm(path.join(directory, 'daily'), { recursive: true });
|
||||
assert.deepEqual(await (await request('/api/daily', { headers })).json(), { records: [], invalid_count: 0 });
|
||||
});
|
||||
|
||||
test('daily symlinks cannot disclose files outside DATA_DIR', async t => {
|
||||
const { directory, request, login } = await fixture(t);
|
||||
const outside = await mkdtemp(path.join(tmpdir(), 'pawplay-daily-outside-')); t.after(() => rm(outside, { recursive: true, force: true }));
|
||||
await mkdir(path.join(directory, 'daily'));
|
||||
await writeFile(path.join(outside, 'secret.json'), JSON.stringify({ date: '2026-11-03', executed: ['OUTSIDE-SECRET'] }));
|
||||
await symlink(path.join(outside, 'secret.json'), path.join(directory, 'daily/2026-11-03.json'));
|
||||
const cookie = (await login()).headers.get('set-cookie').split(';')[0];
|
||||
const response = await request('/api/daily', { headers: { Cookie: cookie } });
|
||||
assert.equal(response.status, 200); const text = await response.text(); assert.doesNotMatch(text, /OUTSIDE-SECRET/);
|
||||
assert.deepEqual(JSON.parse(text), { records: [], invalid_count: 1 });
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user