Harden the server and add a Links page
Security headers, cross-site write refusal, atomic JSON writes, admin backup download, /healthz and Docker health check, OnlyOffice requires a JWT secret, npm test, CI audit, arm64 hub image. New Links tab for personal bookmarks, saved with per-person settings. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
b0d3aec811
commit
1f8c9493b7
16 files changed
+147
-25
No files matched your search
@@ -1,6 +1,7 @@
|
||||
// Tasks: a list stored in NE Hub, plus any iCloud reminder lists the account exposes over CalDAV.
|
||||
// (Apple hides Reminders lists that were upgraded for iOS 13+ from CalDAV, so iCloud lists may be absent; NE Hub lists always work.)
|
||||
const fs = require('fs');
|
||||
const atomicWrite = require('./atomic');
|
||||
const path = require('path');
|
||||
const crypto = require('crypto');
|
||||
const ics = require('./ics');
|
||||
@@ -10,7 +11,7 @@ const caldav = require('./caldav');
|
||||
const users = require('./users');
|
||||
const file = () => path.join(users.dir(), 'tasks.json'); // each person has their own
|
||||
const load = () => { try { return JSON.parse(fs.readFileSync(file(), 'utf8')); } catch { return { lists: [{ id: 'inbox', name: 'Tasks' }], tasks: [] }; } };
|
||||
const save = d => fs.writeFileSync(file(), JSON.stringify(d, null, 2), { mode: 0o600 });
|
||||
const save = d => atomicWrite(file(), JSON.stringify(d, null, 2), { mode: 0o600 });
|
||||
const readBody = req => new Promise((ok, no) => { const c = []; req.on('data', d => c.push(d)); req.on('end', () => ok(Buffer.concat(c).toString())); req.on('error', no); });
|
||||
const json = (res, code, obj) => { res.writeHead(code, { 'content-type': 'application/json' }); res.end(JSON.stringify(obj)); };
|
||||
const isLocal = id => String(id || '').startsWith('local:');
|
||||
|
||||
Reference in new issue
Block a user