fix: DDNS update token in body, webdav gating, regression tests
Unit Tests / test (push) Successful in 7m25s

- PicNgoDDNS.update(): send token in request body instead of Authorization
  header; DDNS server validates it from body (was returning HTTP 422 on
  every heartbeat, leaving IP record stale after fresh install)
- peers.py / Peers.jsx: webdav service_access only valid when 'files' store
  service is installed; was always shown even with no services, confusing
  users into thinking WebDAV was pre-installed
- 10 new regression tests: DDNS update body contract, Caddy always
  regenerates on startup with no services, peer role allowed on
  /api/services/active, webdav gating by installed services

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-06-07 16:56:12 -04:00
parent 962d137093
commit 69862331e7
7 changed files with 241 additions and 12 deletions
+8 -4
View File
@@ -6,7 +6,7 @@ import QRCode from 'qrcode';
const FULL_TUNNEL_IPS = '0.0.0.0/0, ::/0';
const emptyForm = (availableServiceKeys = ['webdav']) => ({
const emptyForm = (availableServiceKeys = []) => ({
name: '',
description: '',
public_key: '',
@@ -62,7 +62,7 @@ const ALL_SERVICES = [
function Peers() {
const { domain = 'cell' } = useConfig();
const [installedServiceKeys, setInstalledServiceKeys] = useState(['webdav']);
const [installedServiceKeys, setInstalledServiceKeys] = useState([]);
const SERVICES = ALL_SERVICES
.filter(s => installedServiceKeys.includes(s.key))
.map(s => ({ ...s, domain: `${s.key}.${domain}` }));
@@ -89,9 +89,13 @@ function Peers() {
cellLinkAPI.listConnections().then(r => setConnectedCells(r.data || [])).catch(() => {});
storeAPI.listInstalled().then(r => {
const installed = r.data?.installed || {};
const keys = ['webdav', ...Object.keys(installed)
// 'webdav' is part of the 'files' store service — show it only when files is installed
const mappedKeys = Object.keys(installed)
.map(id => STORE_ID_TO_ACCESS[id])
.filter(Boolean)];
.filter(Boolean);
const keys = 'files' in installed
? [...mappedKeys, 'webdav']
: mappedKeys;
setInstalledServiceKeys(keys);
}).catch(() => {});
}, []);