Scope client management and config-apply per server (step 4)

Real per-server data isolation, the core ask behind the access-control
work: clients, config generation, and the client-management UI are now
scoped by server ID instead of implicitly operating on one global
"the server".

- util.DefaultServerID ("wg0") is the server every legacy bare route
  now resolves to, so old and new routes share one consistent identity
  instead of drifting apart.
- New /servers/:id/... routes (new-client, update-client, remove-client,
  set-status, download, api/clients, api/client/:cid, api/apply-wg-config)
  reuse the same handlers as the legacy routes via resolveServerID(c),
  gated by RequireServerAccess middleware. Cross-server edits/deletes on
  scoped routes are rejected (403) if a client belongs to a different
  server.
- Fixes a real data leak: ApplyServerConfig previously wrote ALL clients
  from ALL servers into whichever single wg.conf it targeted. It now
  filters clients by server ID before generating a config, and resolves
  each server's own ConfigFilePath/EndpointAddress via the new
  ServerSetting record instead of the app-wide GlobalSetting.
- WireGuardServerInterfaces/WireGuardServerKeyPair/GlobalSettingSubmit
  (the legacy /wg-server and /global-settings edit routes) now write
  through to the new per-server registry record for "wg0" in addition
  to the legacy collection, so the two stay in sync until the legacy
  routes are eventually retired.
- New templates/server_clients.html: per-server clone of clients.html
  wired to the scoped endpoints, with a server name/id heading.
- base.html's shared "New Client" and "Apply Config" actions (used by
  every page's nav buttons) now target the scoped route when a
  serverID is present on the page, instead of always hitting the
  legacy default-server endpoint regardless of which server's client
  page is open.

Legacy bare routes (/, /new-client, /wg-server, ...) are untouched and
still fully functional against the default "wg0" server - nothing was
removed yet, per the incremental-delivery approach for this project.
This commit is contained in:
sysops
2026-07-11 23:47:57 +02:00
parent e3534625c3
commit 74389a9d49
8 changed files with 1226 additions and 18 deletions
+9 -1
View File
@@ -254,7 +254,15 @@ func main() {
app.GET(util.BasePath+"/servers-settings", handler.ServersPage(), handler.ValidSession, handler.RefreshSession, handler.NeedsAdmin)
app.GET(util.BasePath+"/servers", handler.ListServers(db), handler.ValidSession)
app.POST(util.BasePath+"/servers", handler.CreateServer(db), handler.ValidSession, handler.ContentTypeJson, handler.NeedsAdmin)
app.GET(util.BasePath+"/servers/:id/clients", handler.GetServerClients(db), handler.ValidSession, handler.RequireServerAccess(db))
app.GET(util.BasePath+"/servers/:id/clients", handler.ServerClientsPage(db), handler.ValidSession, handler.RefreshSession, handler.RequireServerAccess(db))
app.GET(util.BasePath+"/servers/:id/api/clients", handler.GetServerClients(db), handler.ValidSession, handler.RequireServerAccess(db))
app.GET(util.BasePath+"/servers/:id/api/client/:cid", handler.GetServerClient(db), handler.ValidSession, handler.RequireServerAccess(db))
app.POST(util.BasePath+"/servers/:id/new-client", handler.NewClient(db), handler.ValidSession, handler.ContentTypeJson, handler.RequireServerAccess(db))
app.POST(util.BasePath+"/servers/:id/update-client", handler.UpdateClient(db), handler.ValidSession, handler.ContentTypeJson, handler.RequireServerAccess(db))
app.POST(util.BasePath+"/servers/:id/client/set-status", handler.SetClientStatus(db), handler.ValidSession, handler.ContentTypeJson, handler.RequireServerAccess(db))
app.POST(util.BasePath+"/servers/:id/remove-client", handler.RemoveClient(db), handler.ValidSession, handler.ContentTypeJson, handler.RequireServerAccess(db))
app.GET(util.BasePath+"/servers/:id/download", handler.DownloadClient(db), handler.ValidSession, handler.RequireServerAccess(db))
app.POST(util.BasePath+"/servers/:id/api/apply-wg-config", handler.ApplyServerConfig(db, tmplDir), handler.ValidSession, handler.ContentTypeJson, handler.RequireServerAccess(db))
app.GET(util.BasePath+"/api/clients", handler.GetClients(db), handler.ValidSession)
app.GET(util.BasePath+"/api/client/:id", handler.GetClient(db), handler.ValidSession)
app.GET(util.BasePath+"/api/machine-ips", handler.MachineIPAddresses(), handler.ValidSession)