DC-140: network provider abstraction (src/network/) + tailscale provider + registry + tests
This commit is contained in:
7 files changed
+1308
No files matched your search
@@ -0,0 +1,75 @@
|
||||
/**
|
||||
* NetworkProvider interface — the documented contract for DashCaddy
|
||||
* Private Network providers (DC-140, specs/PRIVATE-NETWORK-SPEC.md §3).
|
||||
*
|
||||
* Everything above the provider (people, groups, resources, access map,
|
||||
* forward_auth, Technitium names, the CA, the UI) is shared and talks to
|
||||
* the network ONLY through this contract — never to a provider module
|
||||
* directly. Resolution goes through src/network/registry.js.
|
||||
*
|
||||
* ## Capability flags
|
||||
*
|
||||
* `capabilities()` returns:
|
||||
* - invites provider can mint invite URLs itself (TS user-invites /
|
||||
* WG one-time token). When false, DashCaddy mints its own.
|
||||
* - splitDnsApi provider exposes a split-DNS API (Tailscale does;
|
||||
* WireGuard writes Technitium directly instead).
|
||||
* - perPeerFirewall provider enforces per-peer rules natively (WG nftables;
|
||||
* Tailscale relies on ACLs, so false).
|
||||
* - selfHosted no outside control-plane dependency (WG true, TS false).
|
||||
*
|
||||
* Feature modules MUST check capabilities and degrade cleanly.
|
||||
*
|
||||
* ## Methods (all async, all return plain JSON, all validated)
|
||||
*
|
||||
* id() → 'tailscale' | 'wireguard'
|
||||
* capabilities() → { invites, splitDnsApi, perPeerFirewall, selfHosted }
|
||||
* getStatus() → provider health/summary (TS: local `tailscale status`;
|
||||
* WG: `wg show dump` + iface state)
|
||||
* listDevices() → device list merged with local online state
|
||||
* listPeople() → provider users projected to
|
||||
* { id, displayName, email, createdAt }
|
||||
* createInvite({ role, email? }) → { inviteUrl, id } — email is OPTIONAL;
|
||||
* when omitted, the provider returns a link without sending
|
||||
* (link-first, DC-085 pattern; never log inviteUrl raw)
|
||||
* revokeInvite(id) → { revoked: true }
|
||||
* blockPerson(userId) → reversible network-level block (TS: expire every
|
||||
* device key owned by the user; WG: drop peer + deny set)
|
||||
* unblockPerson(userId) → reverse of blockPerson (TS: no-op at provider
|
||||
* level, DashCaddy re-grants via syncAccess)
|
||||
* removePerson(userId) → delete provider devices + revoke invites
|
||||
* revokeDevice(deviceId) → expire/remove a single device's access
|
||||
* syncAccess(accessMap, resources) → compile + dry-run + push provider
|
||||
* rules (hash-guarded). Injected per provider in later DCs
|
||||
* (TS ACL compiler = DC-148; WG nftables = DC-150).
|
||||
* whois(ip) → which person owns the connecting device
|
||||
* configureDns({ zone, server }) → split-DNS setup when splitDnsApi
|
||||
*
|
||||
* ## Error contract
|
||||
*
|
||||
* All failures throw ProviderError (src/network/errors.js) with a `code`
|
||||
* and `retryable` hint. Providers map their native errors at the boundary
|
||||
* so no provider-specific error type ever escapes this package.
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
module.exports = {
|
||||
/** Method names every provider must implement (documented contract). */
|
||||
CONTRACT_METHODS: [
|
||||
'id',
|
||||
'capabilities',
|
||||
'getStatus',
|
||||
'listDevices',
|
||||
'listPeople',
|
||||
'createInvite',
|
||||
'revokeInvite',
|
||||
'blockPerson',
|
||||
'unblockPerson',
|
||||
'removePerson',
|
||||
'revokeDevice',
|
||||
'syncAccess',
|
||||
'whois',
|
||||
'configureDns',
|
||||
],
|
||||
};
|
||||
Reference in new issue
Block a user