# P2NS Admin Backend API The P2NS (Peer-to-Peer Name System) admin backend API, hosted at `https://p2ns.admin`, provides endpoints for managing the decentralized DNS system programmatically. These endpoints, implemented in `admin.js`, allow interaction with domains, Holesail servers and clients, local DNS records, certificates, virtual interfaces, logs, settings, and system status. All endpoints are accessible via HTTP/HTTPS and do not require authentication (since the domain is local). Responses are typically JSON or plain text, with errors returned as plain text messages. Real-time updates are broadcast via WebSocket at `wss://p2ns.admin/ws`. ## Base URL `https://p2ns.admin` ## WebSocket Endpoint - **URL**: `wss://p2ns.admin/ws` - **Description**: Establishes a WebSocket connection for real-time updates from the server. - **Client → server messages**: - `subscribe-stats` / `unsubscribe-stats` / `request-stats-snapshot` — Stats tab live data. - `subscribe-log` — `{ "type": "subscribe-log", "channel": "core", "lines": 1000 }` (channels: `core`, `proxy`, `httpProxy`, `dns`, `plugins`, `holesail`). - `unsubscribe-log` — Stop log tail. - `request-domains` — Refresh domains list (server replies with `domains-list`). - **Server → client messages**: - `stats-snapshot` — Full stats page payload (`stats`, `historical`, `health`, `status`, `minutes`). Includes `stats.core` (invite RPC diagnostics) and `stats.pluginRpc` / `stats.peerChannels` (plugin RPC metrics). - `update-stats` — Notifies stats subscribers to apply their latest snapshot (does not embed metrics itself). - `update-health` — Health payload for Diagnostics tab subscribers. - `file-log` — `{ "type": "file-log", "channel": "dns", "level": "info", "message": "" }` (live log tail). - `log-snapshot` — Initial tail after `subscribe-log`: `{ "type": "log-snapshot", "channel": "core", "lines": ["..."] }`. - `log` — **Legacy**; may still map to core. Prefer `file-log` + `subscribe-log`. - `holesail-log` — Holesail child process logs (`id`, `level`, `message`). - `plugin-log` — Per-plugin logs (`domain`, `level`, `component`, `message`). - `domains-list` — Resolved domains array. - `update-database`, `update-peers`, `update-certs`, `update-interfaces`, `update-local-dns`, `update-holesail`, `update-holesail-clients`, `update-settings`, `update-plugins`, `update-plugin-settings` — Tab refresh hints. - `system-reset` — Client should reload. - **Example (`file-log`)**: ```json { "type": "file-log", "channel": "core", "level": "info", "message": "2026-05-28T12:00:00.000Z [INFO] [Main] Starting..." } ``` ## Endpoints ### 1. GET / - **Description**: Serves the admin panel HTML (`includes/admin/admin-frontend/index.html`). - **Response**: HTML content. - **Status Codes**: - `200`: Success. - `500`: Failed to load admin panel. - **Example**: ```bash curl -X GET \ https://p2ns.admin/ ``` ### 2. GET /styles.css - **Description**: Serves the admin panel stylesheet (`includes/admin/admin-frontend/styles.css`). - **Response**: CSS content. - **Status Codes**: - `200`: Success. - `500`: Failed to load styles. - **Example**: ```bash curl -X GET \ https://p2ns.admin/styles.css ``` ### 3. GET /admin.js - **Description**: Serves the admin panel JavaScript (`includes/admin/admin-frontend/admin.js`). - **Response**: JavaScript content. - **Status Codes**: - `200`: Success. - `500`: Failed to load script. - **Example**: ```bash curl -X GET \ https://p2ns.admin/admin.js ``` ### 4. GET /api/resolved-domains - **Description**: Retrieves a list of resolved domains with their hashes, local status, ownership, consensus information, and available services. - **Response**: JSON array of objects with: - `domain` (string): Domain name - `hash` (string): Holesail hash or `"internal"` for internal domains - `isLocal` (boolean): Whether the local writer has a claim for this domain - `isOwner` (boolean): Whether the local writer is the resolved claimant (owner) of this domain - `consensusState` (object): Detailed consensus information including status, vote counts, quorum status, etc. - `consensusStatus` (string): Simplified status that may include `"conflict"` for domains where local peer has a claim but another claimant won - `services` (array): Array of service objects with `serviceName`, `key`, `port`, and `protocol` fields - **Status Codes**: - `200`: Success. - `500`: Failed to fetch domains. - **Example**: ```bash curl -X GET \ https://p2ns.admin/api/resolved-domains ``` ```json [ { "domain": "example.tld", "hash": "hs://s00084bf...", "isLocal": true, "isOwner": true, "consensusState": { "status": "resolved", "hash": "hs://s00084bf...", "resolvedClaimant": "a6a6d7ebcc1df8f33410067bf96ad2cc30d5276516f758bb0f34195e914c451f", "voteCounts": { "a6a6d7ebcc1df8f33410067bf96ad2cc30d5276516f758bb0f34195e914c451f": 8 }, "activePeers": 5, "quorumMet": true, "minVotes": 2, "totalVotes": 8, "lastResolution": 1766780982538 }, "consensusStatus": "resolved", "services": [ { "serviceName": "web", "key": "hs://s00084bf...", "port": 8080, "protocol": "tcp" } ] }, { "domain": "bm.git", "hash": "hs://s000f44fb5cfe3fa7f37e9070ea14975a8dbf1e2156689638bc92458118df7a4987b", "isLocal": true, "isOwner": false, "consensusState": { "status": "resolved", "hash": "hs://s000f44fb5cfe3fa7f37e9070ea14975a8dbf1e2156689638bc92458118df7a4987b", "resolvedClaimant": "acbb3b69ee810f4fbe54927a5742530e4cf76b7b462a4c37ddfe27ba5c3060b6", "voteCounts": { "a6a6d7ebcc1df8f33410067bf96ad2cc30d5276516f758bb0f34195e914c451f": 1, "acbb3b69ee810f4fbe54927a5742530e4cf76b7b462a4c37ddfe27ba5c3060b6": 7 }, "activePeers": 5, "quorumMet": true, "minVotes": 2, "totalVotes": 8, "lastResolution": 1766780982538 }, "consensusStatus": "conflict", "services": [] }, { "domain": "peer.directory", "hash": "internal", "isLocal": true, "isOwner": true, "consensusStatus": "internal", "services": [] } ] ``` ### 5. GET /api/entries - **Description**: Retrieves all Autopass ledger entries (claims and votes). - **Response**: JSON array of objects with `key` (string) and `value` (string). - **Status Codes**: - `200`: Success. - `500`: Failed to fetch entries. - **Example**: ```bash curl -X GET \ https://p2ns.admin/api/entries ``` ```json [ { "key": "claim:example.tld:abc123", "value": "hs://s00084bf..." }, { "key": "vote:example.tld:abc123:def456", "value": "1" } ] ``` ### 6. GET /api/peers - **Description**: Lists connected peers (public keys). - **Response**: JSON array of peer public keys (strings). - **Status Codes**: - `200`: Success. - `500`: Failed to fetch peers. - **Example**: ```bash curl -X GET \ https://p2ns.admin/api/peers ``` ```json ["def456", "ghi789"] ``` ### 7. GET /api/certs - **Description**: Lists domains with generated certificates. - **Response**: JSON array of domain names (strings). - **Status Codes**: - `200`: Success. - `500`: Failed to fetch certs. - **Example**: ```bash curl -X GET \ https://p2ns.admin/api/certs ``` ```json ["example.tld", "peer.directory"] ``` ### 8. GET /api/cert-details?domain= - **Description**: Retrieves the certificate content for a specified domain. - **Query Parameters**: - `domain`: The domain name (e.g., `example.tld`). - **Response**: Plain text certificate content (PEM format). - **Status Codes**: - `200`: Success. - `500`: Failed to fetch cert details. - **Example**: ```bash curl -X GET \ https://p2ns.admin/api/cert-details?domain=example.tld ``` ```text -----BEGIN CERTIFICATE----- MIID... -----END CERTIFICATE----- ``` ### 9. GET /api/interfaces - **Description**: Lists virtual interfaces with domain-to-IP mappings. - **Response**: JSON array of objects with `domain` (string) and `ip` (string). - **Status Codes**: - `200`: Success. - `500`: Failed to fetch interfaces. - **Example**: ```bash curl -X GET \ https://p2ns.admin/api/interfaces ``` ```json [ { "domain": "example.tld", "ip": "192.168.3.2" }, { "domain": "peer.directory", "ip": "192.168.3.3" } ] ``` ### 10. GET /api/local-dns - **Description**: Retrieves custom local DNS records and conflicting domains (domains with both P2P and public records). - **Response**: JSON object with: - `records`: Array of DNS records with `index` (number), `name` (string), `type` (string), `ttl` (number), `class` (string, usually "IN"), and type-specific fields (e.g., `data` for A, `preference` and `exchange` for MX). - `conflicts`: Array of objects with `domain` (string), `version` (p2p/public), and `publicIP` (string). - **Status Codes**: - `200`: Success. - `500`: Failed to fetch local DNS and conflicts. - **Example**: ```bash curl -X GET \ https://p2ns.admin/api/local-dns ``` ```json { "records": [ { "index": 0, "name": "local.example", "type": "A", "class": "IN", "ttl": 3600, "data": "192.168.1.100" }, { "index": 1, "name": "mail.example", "type": "MX", "class": "IN", "ttl": 3600, "preference": 10, "exchange": "mx.example.com" }, { "index": 2, "name": "_service._tcp.example", "type": "SRV", "class": "IN", "ttl": 3600, "priority": 0, "weight": 5, "port": 8080, "target": "server.example.com" } ], "conflicts": [ { "domain": "myspace.com", "version": "public", "publicIP": "151.101.1.195" }, { "domain": "example.com", "version": "p2p", "publicIP": "93.184.216.34" } ] } ``` ### 11. GET /api/selector-cache - **Description**: Retrieves DNS version preferences for domains with both P2P and public records. - **Response**: JSON object mapping domains to `p2p` or `public`. - **Status Codes**: - `200`: Success. - `500`: Failed to fetch selector cache. - **Example**: ```bash curl -X GET \ https://p2ns.admin/api/selector-cache ``` ```json { "myspace.com": "public", "example.com": "p2p" } ``` ### 12. GET /api/status - **Description**: Retrieves system status, including master/joiner mode and peer count. - **Response**: JSON object with `isMaster` (boolean), `isConnected` (boolean), and `peersCount` (number). - **Status Codes**: - `200`: Success. - `500`: Failed to fetch status. - **Example**: ```bash curl -X GET \ https://p2ns.admin/api/status ``` ```json { "isMaster": true, "isConnected": true, "peersCount": 5 } ``` ### 13. GET /api/holesail-servers - **Description**: Lists all Holesail servers with their configurations and status. - **Response**: JSON array of objects with `id` (string), `opts` (configuration object), and `info` (object including `state`: running/stopped). - **Status Codes**: - `200`: Success. - `500`: Failed to fetch Holesail servers. - **Example**: ```bash curl -X GET \ https://p2ns.admin/api/holesail-servers ``` ```json [ { "id": "abc123", "opts": { "name": "server1", "port": 8080, "host": "0.0.0.0", "secure": true, "log": 1 }, "info": { "state": "running", "url": "hs://s00084bf..." } } ] ``` ### 14. GET /api/holesail-clients - **Description**: Lists all Holesail clients with their configurations and status. - **Response**: JSON array of objects with `id` (string), `opts` (configuration object), and `info` (object including `state`: running/starting/stopped/error). - **Status Codes**: - `200`: Success. - `500`: Failed to fetch Holesail clients. - **Example**: ```bash curl -X GET \ https://p2ns.admin/api/holesail-clients ``` ```json [ { "id": "def456", "opts": { "domain": "example.tld", "key": "hs://s00084bf...", "port": 8080, "protocol": "tcp" }, "info": { "state": "running" } } ] ``` ### 15. GET /api/settings - **Description**: Retrieves environment settings (whitelisted variables). Note: `SUBNETS`, `SUBNET_BASE`, and `INITIAL_IP_INDEX` are managed separately via the subnet configurator (see `/api/subnets`). - **Response**: JSON object with `settings` (object mapping whitelisted keys to values) and `metadata` (object with setting metadata including types, descriptions, and categories). - **Status Codes**: - `200`: Success. - `500`: Failed to fetch settings. - **Example**: ```bash curl -X GET \ https://p2ns.admin/api/settings ``` ```json { "settings": { "LOG_LEVEL": "1", "INTERNAL_DOMAINS": "Note: Internal domains are now automatically discovered from plugin-sites/{domain}/config.json files" }, "metadata": { "LOG_LEVEL": { "type": "number", "category": "Logging & Debugging", "label": "Log Level", "description": "...", "default": "0" } } } ``` ### 16. POST /api/add-domain - **Description**: Adds a domain with its Holesail hash to the P2P network and `domains.json`. Assigns an IP if needed and triggers auto-voting. **Note: Internal domains (automatically discovered from `plugin-sites/{domain}/config.json` files, including `p2ns.admin`) cannot be claimed and will return an error.** - **Request Body**: JSON with `domain` (string), `hash` (string, e.g., `hs://`), and optionally `ssl` (boolean). The `ssl` field indicates if the Holesail connection uses SSL/TLS. When `true`, proxy connections will use HTTPS/WSS instead of HTTP/WS. Defaults to `false` if not provided. - **Response**: Plain text `OK` on success, error message on failure. - **Status Codes**: - `200`: Success. - `500`: Failed to add domain. - **WebSocket Broadcast**: `update-database`. - **Example**: ```bash curl -X POST \ -H "Content-Type: application/json" \ -d '{"domain":"example.tld","hash":"hs://s00084bf...","ssl":true}' \ https://p2ns.admin/api/add-domain ``` ```text OK ``` ### 17. POST /api/remove-domain - **Description**: Removes a domain. Behavior depends on consensus status: - **Resolved Claimant**: Performs full cleanup removing all claims and votes for the domain, broadcasts `consensus.removeDomain` RPC to trigger other peers to clean up - **Conflict Claim**: Removes only your own claim and votes, broadcasts `removeConflictDomainClaim:` notification (other peers preserve their claims) - **Request Body**: JSON with `domain` (string). - **Response**: Plain text `OK` on success, error message on failure. - **Status Codes**: - `200`: Success. - `403`: No claim found for domain or peer not initialized. - `500`: Failed to remove domain. - **WebSocket Broadcast**: `update-database`, `update-holesail-clients`, `update-local-dns`. - **Note**: Only the peer that created a claim can remove it. Ownership is strictly validated before removal. - **Example**: ```bash curl -X POST \ -H "Content-Type: application/json" \ -d '{"domain":"example.tld"}' \ https://p2ns.admin/api/remove-domain ``` ```text OK ``` ### 18. POST /api/regenerate-ca - **Description**: Regenerates the root CA certificate. - **Request Body**: None. - **Response**: Plain text `OK` on success, error message on failure. - **Status Codes**: - `200`: Success. - `500`: Failed to regenerate CA. - **WebSocket Broadcast**: `update-certs`. - **Example**: ```bash curl -X POST \ https://p2ns.admin/api/regenerate-ca ``` ```text OK ``` ### 19. POST /api/install-ca - **Description**: Installs the root CA to the system trust store. - **Request Body**: None. - **Response**: Plain text `OK` on success, error message on failure. - **Status Codes**: - `200`: Success. - `500`: Failed to install CA. - **Example**: ```bash curl -X POST \ https://p2ns.admin/api/install-ca ``` ```text OK ``` ### 20. POST /api/generate-cert - **Description**: Generates a certificate for a specified domain, assigning an IP if needed. - **Request Body**: JSON with `domain` (string). - **Response**: Plain text `OK` on success, error message on failure. - **Status Codes**: - `200`: Success. - `500`: Failed to generate cert. - **WebSocket Broadcast**: `update-certs`. - **Example**: ```bash curl -X POST \ -H "Content-Type: application/json" \ -d '{"domain":"example.tld"}' \ https://p2ns.admin/api/generate-cert ``` ```text OK ``` ### 21. POST /api/delete-cert - **Description**: Deletes the certificate for a specified domain. - **Request Body**: JSON with `domain` (string). - **Response**: Plain text `OK` on success, error message on failure. - **Status Codes**: - `200`: Success. - `500`: Failed to delete cert. - **WebSocket Broadcast**: `update-certs`. - **Example**: ```bash curl -X POST \ -H "Content-Type: application/json" \ -d '{"domain":"example.tld"}' \ https://p2ns.admin/api/delete-cert ``` ```text OK ``` ### 22. POST /api/regenerate-cert - **Description**: Regenerates the certificate for a specified domain, assigning an IP if needed. - **Request Body**: JSON with `domain` (string). - **Response**: Plain text `OK` on success, error message on failure. - **Status Codes**: - `200`: Success. - `500`: Failed to regenerate cert. - **WebSocket Broadcast**: `update-certs`. - **Example**: ```bash curl -X POST \ -H "Content-Type: application/json" \ -d '{"domain":"example.tld"}' \ https://p2ns.admin/api/regenerate-cert ``` ```text OK ``` ### 23. POST /api/cleanup-interfaces - **Description**: Cleans up unused virtual interfaces. - **Note**: This endpoint is available via the API but is not exposed in the admin UI interface. - **Request Body**: None. - **Response**: Plain text `OK` on success, error message on failure. - **Status Codes**: - `200`: Success. - `500`: Failed to cleanup interfaces. - **WebSocket Broadcast**: `update-interfaces`. - **Example**: ```bash curl -X POST \ https://p2ns.admin/api/cleanup-interfaces ``` ```text OK ``` ### 24. POST /api/add-local-dns - **Description**: Adds a custom DNS record to `local_dns.json`. Supports all DNS record types (e.g., A, AAAA, CNAME, MX, TXT, SRV, SOA, CAA, NS, PTR, OTHER) with flexible fields. - **Request Body**: JSON object with `name` (string), `type` (string), `ttl` (number), `class` (string, optional, defaults to "IN"), and type-specific fields (e.g., `data` for A, `preference` and `exchange` for MX). - **Response**: Plain text `OK` on success, error message on failure. - **Status Codes**: - `200`: Success. - `500`: Failed to add local DNS record. - **WebSocket Broadcast**: `update-local-dns`. - **Example** (A record): ```bash curl -X POST \ -H "Content-Type: application/json" \ -d '{"name":"local.example","type":"A","ttl":3600,"data":"192.168.1.100"}' \ https://p2ns.admin/api/add-local-dns ``` ```text OK ``` - **Example** (SRV record): ```bash curl -X POST \ -H "Content-Type: application/json" \ -d '{"name":"_service._tcp.example","type":"SRV","ttl":3600,"priority":0,"weight":5,"port":8080,"target":"server.example.com"}' \ https://p2ns.admin/api/add-local-dns ``` ```text OK ``` ### 25. POST /api/update-local-dns - **Description**: Updates an existing custom DNS record in `local_dns.json` by index. Supports all DNS record types. - **Request Body**: JSON object with `index` (number) and `record` (object with `name`, `type`, `ttl`, `class` (optional), and type-specific fields). - **Response**: Plain text `OK` on success, error message on failure. - **Status Codes**: - `200`: Success. - `400`: Invalid index. - `500`: Failed to update local DNS record. - **WebSocket Broadcast**: `update-local-dns`. - **Example**: ```bash curl -X POST \ -H "Content-Type: application/json" \ -d '{"index":0,"record":{"name":"local.example","type":"A","ttl":7200,"data":"192.168.1.101"}}' \ https://p2ns.admin/api/update-local-dns ``` ```text OK ``` ### 26. POST /api/delete-local-dns - **Description**: Deletes a custom DNS record from `local_dns.json` by index. - **Request Body**: JSON with `index` (number). - **Response**: Plain text `OK` on success, error message on failure. - **Status Codes**: - `200`: Success. - `400`: Invalid index. - `500`: Failed to delete local DNS record. - **WebSocket Broadcast**: `update-local-dns`. - **Example**: ```bash curl -X POST \ -H "Content-Type: application/json" \ -d '{"index":0}' \ https://p2ns.admin/api/delete-local-dns ``` ```text OK ``` ### 27. POST /api/update-version-preference - **Description**: Updates the DNS version preference (p2p or public) for a domain with both P2P and public records, stored in `selector_cache.json`. - **Request Body**: JSON with `domain` (string) and `version` (string: `p2p` or `public`). - **Response**: Plain text `OK` on success, error message on failure. - **Status Codes**: - `200`: Success. - `400`: Invalid version. - `500`: Failed to update version preference. - **WebSocket Broadcast**: `update-local-dns`. - **Example**: ```bash curl -X POST \ -H "Content-Type: application/json" \ -d '{"domain":"myspace.com","version":"public"}' \ https://p2ns.admin/api/update-version-preference ``` ```text OK ``` ### 28. GET /api/p2p-domain-conflicts - **Description**: Retrieves domains with P2P consensus conflicts where the user has a local claim but another claimant won consensus. Used for the P2P Domain Conflicts management interface. - **Response**: JSON object with `conflicts` array containing objects with: - `domain` (string): Domain name - `localHash` (string): User's local claim hash - `resolvedHash` (string): Consensus-resolved hash - `resolvedClaimant` (string): Public key of consensus winner - `localClaimant` (string): User's public key - `consensusStatus` (string): Current consensus status - `hashPreference` (string): User's hash preference ('local' or 'resolved') - **Status Codes**: - `200`: Success. - `500`: Failed to fetch P2P domain conflicts. - **WebSocket Broadcast**: None. - **Example**: ```bash curl -X GET \ https://p2ns.admin/api/p2p-domain-conflicts ``` ```json { "conflicts": [ { "domain": "example.com", "localHash": "hs://s0001abc...", "resolvedHash": "hs://s0001def...", "resolvedClaimant": "abc123...", "localClaimant": "def456...", "consensusStatus": "resolved", "hashPreference": "resolved" } ] } ``` ### 29. POST /api/update-hash-preference - **Description**: Updates the hash preference ('local' or 'resolved') for a domain with P2P consensus conflicts, stored in `selector_cache.json`. When changed, automatically restarts any active Holesail clients for the domain to use the new hash. - **Request Body**: JSON with `domain` (string) and `preference` (string: `local` or `resolved`). - **Response**: Plain text `OK` on success, error message on failure. - **Status Codes**: - `200`: Success. - `400`: Invalid preference. - `500`: Failed to update hash preference. - **WebSocket Broadcast**: `update-local-dns`. - **Example**: ```bash curl -X POST \ -H "Content-Type: application/json" \ -d '{"domain":"example.com","preference":"local"}' \ https://p2ns.admin/api/update-hash-preference ``` ```text OK ``` ### 30. POST /api/clear-dns-cache - **Description**: Clears DNS resolution cache entries for a specific domain to force fresh hash resolution on next DNS query. - **Request Body**: JSON with `domain` (string). - **Response**: Plain text `OK` on success, error message on failure. - **Status Codes**: - `200`: Success. - `500`: Failed to clear DNS cache. - **WebSocket Broadcast**: None. - **Example**: ```bash curl -X POST \ -H "Content-Type: application/json" \ -d '{"domain":"example.com"}' \ https://p2ns.admin/api/clear-dns-cache ``` ```text OK ``` ### 31. POST /api/restart-holesail-clients-for-domain - **Description**: Restarts all Holesail clients (both admin-managed and DNS-triggered) for a specific domain to use updated hash preferences. Closes existing connections and creates new ones with correct hashes. Ensures IP assignment exists before creating clients. - **Request Body**: JSON with `domain` (string). - **Response**: Plain text `OK` on success, error message on failure. - **Status Codes**: - `200`: Success. - `500`: Failed to restart clients or resolve hash. - `500`: Failed to restart Holesail clients. - **WebSocket Broadcast**: `update-holesail-clients`. - **Example**: ```bash curl -X POST \ -H "Content-Type: application/json" \ -d '{"domain":"example.com"}' \ https://p2ns.admin/api/restart-holesail-clients-for-domain ``` ```text OK ``` ### 32. POST /api/holesail-create - **Description**: Creates a new Holesail server, optionally assigning it to a domain. Persists to `holesail_servers.json`. - **Request Body**: JSON with `name` (string, optional), `port` (number), `host` (string, optional), `key` (string, optional), `domain` (string, optional), `secure` (boolean), `udp` (boolean), `log` (number). - **Response**: JSON with `id` (string) on success, error message on failure. - **Status Codes**: - `200`: Success. - `500`: Failed to create Holesail server. - **WebSocket Broadcast**: `update-holesail`, `update-database` (if domain assigned). - **Example**: ```bash curl -X POST \ -H "Content-Type: application/json" \ -d '{"name":"server1","port":8080,"host":"0.0.0.0","secure":true,"udp":false,"log":1,"domain":"example.tld"}' \ https://p2ns.admin/api/holesail-create ``` ```json {"id":"abc123"} ``` ### 33. POST /api/holesail-delete - **Description**: Deletes a Holesail server by ID and removes it from `holesail_servers.json`. - **Request Body**: JSON with `id` (string). - **Response**: Plain text `OK` on success, error message on failure. - **Status Codes**: - `200`: Success. - `500`: Failed to delete Holesail server. - **WebSocket Broadcast**: `update-holesail`. - **Example**: ```bash curl -X POST \ -H "Content-Type: application/json" \ -d '{"id":"abc123"}' \ https://p2ns.admin/api/holesail-delete ``` ```text OK ``` ### 34. POST /api/holesail-restart - **Description**: Restarts a Holesail server by ID, optionally reassigning its domain. Persists to `holesail_servers.json`. - **Request Body**: JSON with `id` (string). - **Response**: Plain text `OK` on success, error message on failure. - **Status Codes**: - `200`: Success. - `500`: Failed to restart Holesail server. - **WebSocket Broadcast**: `update-holesail`, `update-database` (if domain assigned). - **Example**: ```bash curl -X POST \ -H "Content-Type: application/json" \ -d '{"id":"abc123"}' \ https://p2ns.admin/api/holesail-restart ``` ```text OK ``` ### 35. POST /api/holesail-client-create - **Description**: Creates a new Holesail client for a domain and port. Persists to `holesail_clients.json`. If `serviceName` is provided, the client ID will be `domain_servicename`; otherwise, a generated ID is used. The client is also added to the domain's claim record `clients` array. - **Request Body**: JSON with: - `domain` (string, required): Domain name (must be owned by local writer) - `key` (string, required): Holesail connection hash (e.g., `hs://s00084bf...`) - `port` (number, required): Port number - `serviceName` (string, optional): Service name for naming the client (format: `domain_servicename`) - `protocol` (string, optional): Protocol type (`tcp` or `udp`, default: `tcp`) - **Response**: JSON with `id` (string) on success, error message on failure. - **Status Codes**: - `200`: Success. - `400`: Invalid request (missing required fields or domain not owned). - `500`: Failed to create Holesail client. - **WebSocket Broadcast**: `update-holesail-clients`. - **Example**: ```bash curl -X POST \ -H "Content-Type: application/json" \ -d '{"domain":"example.tld","key":"hs://s00084bf...","port":8080,"serviceName":"web","protocol":"tcp"}' \ https://p2ns.admin/api/holesail-client-create ``` ```json {"id":"example.tld_web"} ``` ### 36. POST /api/holesail-client-delete - **Description**: Deletes a Holesail client by ID, closing connections and removing it from `holesail_clients.json`. - **Request Body**: JSON with `id` (string). - **Response**: Plain text `OK` on success, error message on failure. - **Status Codes**: - `200`: Success. - `500`: Failed to delete Holesail client. - **WebSocket Broadcast**: `update-holesail-clients`. - **Example**: ```bash curl -X POST \ -H "Content-Type: application/json" \ -d '{"id":"def456"}' \ https://p2ns.admin/api/holesail-client-delete ``` ```text OK ``` ### 37. POST /api/holesail-client-restart - **Description**: Restarts a Holesail client by ID, ensuring the port is free and connections are closed. - **Request Body**: JSON with `id` (string). - **Response**: Plain text `OK` on success, error message on failure. - **Status Codes**: - `200`: Success. - `500`: Failed to restart Holesail client. - **WebSocket Broadcast**: `update-holesail-clients`. - **Example**: ```bash curl -X POST \ -H "Content-Type: application/json" \ -d '{"id":"def456"}' \ https://p2ns.admin/api/holesail-client-restart ``` ```text OK ``` ### 38. POST /api/update-settings - **Description**: Updates environment settings (whitelisted variables) and persists them to `.env`. Note: `SUBNETS` can be updated here, but it's recommended to use `/api/subnets` for subnet management. `SUBNET_BASE` and `INITIAL_IP_INDEX` are deprecated in favor of the subnet configurator. - **Request Body**: JSON with `settings` (object mapping whitelisted keys to values). For `SUBNETS`, provide a JSON array string. - **Response**: JSON object with `message` (string), `restartRequired` (boolean), and optionally `restartRequiredSettings` (array of strings). - **Status Codes**: - `200`: Success. - `400`: Validation failed (includes `errors` array). - `500`: Failed to update settings. - **WebSocket Broadcast**: `update-settings`. - **Example**: ```bash curl -X POST \ -H "Content-Type: application/json" \ -d '{"settings":{"LOG_LEVEL":"1"}}' \ https://p2ns.admin/api/update-settings ``` ```json { "message": "Settings saved and applied successfully.", "restartRequired": false } ``` ### 39. GET /api/network-interfaces - **Description**: Retrieves a list of available network interfaces on the system. Used by the admin interface to populate the Subnet Interface Name dropdown setting. - **Response**: JSON object with `interfaces` (array of interface objects). Each interface object contains: - `value` (string): Interface name (e.g., "lo0", "lo", "eth0") - `label` (string): Display label for the interface (may include "(default)" for OS default) - **Status Codes**: - `200`: Success. - `500`: Failed to fetch network interfaces. - **Example**: ```bash curl -X GET \ https://p2ns.admin/api/network-interfaces ``` ```json { "interfaces": [ { "value": "lo0", "label": "lo0" }, { "value": "en0", "label": "en0" }, { "value": "eth0", "label": "eth0" } ] } ``` - **Note**: Interfaces are sorted with loopback interfaces (lo, lo0) and OS-specific defaults (lo0 on macOS, lo on Linux, Loopback Pseudo-Interface 1 on Windows) prioritized first. ### 40. GET /api/subnets - **Description**: Retrieves all configured subnets with capacity information. Returns default subnet from `SUBNET_BASE` if no subnets are configured. - **Response**: JSON object with `subnets` (array of subnet objects). Each subnet object contains: - `base` (string): Network base IP address (e.g., "192.168.3.0") - `cidr` (number): CIDR notation (1-32, e.g., 24) - `startIndex` (number): First usable IP index (1-254) - `name` (string): Subnet name/description - `index` (number): Subnet index in array - `available` (number): Total available IPs in subnet - `used` (number): Currently used IPs - `remaining` (number): Remaining available IPs - **Status Codes**: - `200`: Success. - `500`: Failed to fetch subnets. - **Example**: ```bash curl -X GET \ https://p2ns.admin/api/subnets ``` ```json { "subnets": [ { "base": "192.168.3.0", "cidr": 24, "startIndex": 2, "name": "Primary Subnet", "index": 0, "available": 253, "used": 5, "remaining": 248 }, { "base": "10.0.0.0", "cidr": 24, "startIndex": 2, "name": "Secondary Subnet", "index": 1, "available": 253, "used": 0, "remaining": 253 } ] } ``` ### 41. POST /api/subnets - **Description**: Updates subnet configuration. Replaces all existing subnets with the provided array. Changes require a system restart to fully take effect. - **Request Body**: JSON object with `subnets` (array of subnet objects). Each subnet object must contain: - `base` (string, required): Network base IP address (e.g., "192.168.3.0") - `cidr` (number, required): CIDR notation (1-32, typically 24) - `startIndex` (number, required): First usable IP index (1-254, typically 2) - `name` (string, optional): Subnet name/description (defaults to "Subnet N" if not provided) - **Response**: JSON object with `message` (string) and `restartRequired` (boolean, always true). - **Status Codes**: - `200`: Success. - `400`: Validation failed (includes `error` string and `errors` array). - `500`: Failed to update subnets. - **WebSocket Broadcast**: `update-settings`. - **Example**: ```bash curl -X POST \ -H "Content-Type: application/json" \ -d '{"subnets":[{"base":"192.168.3.0","cidr":24,"startIndex":2,"name":"Primary Subnet"},{"base":"10.0.0.0","cidr":24,"startIndex":2,"name":"Secondary Subnet"}]}' \ https://p2ns.admin/api/subnets ``` ```json { "message": "Subnets updated. Restart required to fully apply changes.", "restartRequired": true } ``` - **Validation Rules**: - `base` must be a valid IPv4 address (e.g., "192.168.3.0") - `cidr` must be between 1 and 32 - `startIndex` must be between 1 and 254 (or up to subnet size - 2) - Subnets must not overlap with each other ### 42. GET /api/health - **Description**: Health check endpoint supporting liveness and readiness probes. - **Query Parameters**: - `probe`: Type of health probe (`liveness` or `readiness`, default: `liveness`). - **Response**: JSON object with `status` (healthy/degraded/not_ready), `timestamp`, `uptime`, `probe`, `services` (object with DNS, proxy, swarm status), and `dependencies` (object with corestore, hyperswarm status). - **Status Codes**: - `200`: System is healthy. - `503`: System is degraded or not ready. - **Example**: ```bash curl -X GET \ https://p2ns.admin/api/health ``` ```json { "status": "healthy", "timestamp": "2024-01-01T00:00:00.000Z", "uptime": 3600000, "probe": "liveness", "services": { "dns": { "enabled": true, "healthy": true, "initialized": true }, "proxy": { "enabled": true, "healthy": true }, "swarm": { "healthy": true } }, "dependencies": { "corestore": { "healthy": true }, "hyperswarm": { "healthy": true } } } ``` ### 43. GET /api/stats - **Description**: Retrieves a one-shot system metrics snapshot (same data shape as `stats-snapshot` over WebSocket). The admin UI loads this once, then uses `subscribe-stats` for live updates. - **Response**: JSON object including: - Request statistics (total, success rate, average response time, failed requests) - Holesail children (servers, clients, P2P domain connections) with status, PID, uptime, CPU/memory usage - `core` — Core control-plane / invite RPC diagnostics (`diagnoseInviteIssues`) - `pluginRpc` and `peerChannels` — Per-plugin protomux-rpc protocol stats (`transport: 'rpc'`, methods, `rpcOpen` counts) - HyperDB / Hyperdrive sections when available - **Status Codes**: - `200`: Success. - `500`: Failed to fetch stats. - **Example**: ```bash curl -X GET \ https://p2ns.admin/api/stats ``` ```json { "requests": { "total": 1000, "successful": 950, "failed": 50, "successRate": 0.95, "avgResponseTime": 45 }, "holesailChildren": [ { "id": "abc123", "type": "server", "status": "running", "pid": 12345, "uptime": 3600000, "cpuUsage": { "percentage": 2.5 }, "memoryUsage": { "rss": 52428800 } } ] } ``` ### 44. GET /api/logs - **Description**: Lists available split log channels written under `LOG_DIR` (default `./logs/`). - **Response**: `{ "channels": [ { "id": "core", "label": "Core", "file": "core.log" }, ... ] }` - **Status Codes**: `200`, `500` - **Example**: ```bash curl -k https://p2ns.admin/api/logs ``` ### 45. GET /api/logs/:channel - **Description**: Returns the tail of a log file (in-memory buffer with file fallback). - **Path**: `channel` — `core`, `proxy`, `httpProxy`, `dns`, `plugins`, or `holesail` - **Query**: `lines` — max lines (default `500`, max `5000`) - **Response**: `{ "channel": "dns", "lines": ["..."] }` - **Example**: ```bash curl -k "https://p2ns.admin/api/logs/dns?lines=200" ``` ### 46. GET /api/stats/historical - **Description**: Retrieves historical metrics data for a specified time range. - **Query Parameters**: - `minutes`: Time range in minutes (1-1440, default: 60). - **Response**: JSON object with historical metrics data including request trends, connection statistics, and system performance over time. - **Status Codes**: - `200`: Success. - `500`: Failed to fetch historical data. - **Example**: ```bash curl -X GET \ "https://p2ns.admin/api/stats/historical?minutes=1440" ``` ### 47. GET /api/backups - **Description**: Lists all available backups with metadata including name, timestamp, size, and file count. - **Response**: JSON array of backup objects with `name`, `timestamp`, `size`, `sizeFormatted`, and `fileCount`. - **Status Codes**: - `200`: Success. - `500`: Failed to list backups. - **Example**: ```bash curl -X GET \ https://p2ns.admin/api/backups ``` ```json [ { "name": "backup-20240101-000000", "timestamp": "2024-01-01T00:00:00.000Z", "size": 1048576, "sizeFormatted": "1.00 MB", "fileCount": 15 } ] ``` ### 48. POST /api/backups/create - **Description**: Creates a manual backup of configuration files, certificates, and cache data. Automatic cleanup of old backups is performed before creation. - **Request Body**: None. - **Response**: JSON object with `success` (boolean) and `path` (string, backup file path). - **Status Codes**: - `200`: Success. - `500`: Failed to create backup. - **Example**: ```bash curl -X POST \ https://p2ns.admin/api/backups/create ``` ```json { "success": true, "path": "./backups/backup-20240101-000000.tar.gz" } ``` ### 49. POST /api/backups/restore - **Description**: Restores system configuration from a backup. Replaces current configuration files and certificates. - **Request Body**: JSON with `backupName` (string, backup name to restore). - **Response**: JSON object with `success` (boolean) and `message` (string). - **Status Codes**: - `200`: Success. - `400`: Invalid request (missing backupName). - `500`: Failed to restore backup. - **Example**: ```bash curl -X POST \ -H "Content-Type: application/json" \ -d '{"backupName":"backup-20240101-000000"}' \ https://p2ns.admin/api/backups/restore ``` ```json { "success": true, "message": "Backup restored successfully" } ``` ### 50. DELETE /api/backups/:id - **Description**: Deletes a backup by name. Supports both directory and tar.gz formats. - **Path Parameters**: - `id`: Backup name (e.g., `backup-20240101-000000` or `backup-20240101-000000.tar.gz`). - **Response**: JSON object with `success` (boolean) and `message` (string). - **Status Codes**: - `200`: Success. - `400`: Invalid backup name. - `500`: Failed to delete backup. - **Example**: ```bash curl -X DELETE \ https://p2ns.admin/api/backups/backup-20240101-000000 ``` ### 51. GET /api/backups/:id/metadata - **Description**: Retrieves detailed metadata for a backup including file list, sizes, and timestamps. - **Path Parameters**: - `id`: Backup name. - **Response**: JSON object with backup metadata including `timestamp`, `files` (array with name, size, sizeFormatted, modified), and other metadata. - **Status Codes**: - `200`: Success. - `404`: Backup not found. - `500`: Failed to get backup metadata. - **Example**: ```bash curl -X GET \ https://p2ns.admin/api/backups/backup-20240101-000000/metadata ``` ### 52. POST /api/diagnostics/dns-lookup - **Description**: Performs DNS lookup for a domain with specified record type. - **Request Body**: JSON with `domain` (string, required) and `type` (string, optional, default: `A`). Supported types: A, AAAA, MX, TXT, NS, CNAME, SRV, PTR, SOA. - **Response**: JSON object with `success` (boolean), `domain`, `type`, `results` (array), and `responseTime` (number). - **Status Codes**: - `200`: Success (includes both successful and failed lookups). - `400`: Invalid request (missing domain). - `500`: Server error. - **Example**: ```bash curl -X POST \ -H "Content-Type: application/json" \ -d '{"domain":"example.com","type":"A"}' \ https://p2ns.admin/api/diagnostics/dns-lookup ``` ```json { "success": true, "domain": "example.com", "type": "A", "results": ["93.184.216.34"], "responseTime": 25 } ``` ### 53. POST /api/diagnostics/ping - **Description**: Tests network connectivity using ping. Supports both streaming and non-streaming modes. - **Request Body**: JSON with `target` (string, required), `count` (number, optional, default: 4), and `stream` (boolean, optional, default: false). - **Response**: - **Non-streaming**: JSON object with `success`, `target`, `count`, `output`, `error`, and `responseTime`. - **Streaming**: NDJSON stream with `type` (output/error/complete), `data`, `timestamp`, and completion status. - **Status Codes**: - `200`: Success. - `400`: Invalid request (missing target). - `500`: Server error. - **Example** (non-streaming): ```bash curl -X POST \ -H "Content-Type: application/json" \ -d '{"target":"8.8.8.8","count":4}' \ https://p2ns.admin/api/diagnostics/ping ``` - **Example** (streaming): ```bash curl -X POST \ -H "Content-Type: application/json" \ -d '{"target":"8.8.8.8","count":4,"stream":true}' \ https://p2ns.admin/api/diagnostics/ping ``` ### 54. POST /api/diagnostics/traceroute - **Description**: Traces network path to a target. Supports both streaming and non-streaming modes. - **Request Body**: JSON with `target` (string, required) and `stream` (boolean, optional, default: false). - **Response**: - **Non-streaming**: JSON object with `success`, `target`, `output`, `error`, and `responseTime`. - **Streaming**: NDJSON stream with `type` (output/error/complete), `data`, `timestamp`, and completion status. - **Status Codes**: - `200`: Success. - `400`: Invalid request (missing target). - `500`: Server error. - **Example**: ```bash curl -X POST \ -H "Content-Type: application/json" \ -d '{"target":"8.8.8.8","stream":true}' \ https://p2ns.admin/api/diagnostics/traceroute ``` ### 55. POST /api/diagnostics/connection-test - **Description**: Tests TCP connectivity to a domain and port combination. - **Request Body**: JSON with `domain` (string, required) and `port` (number, required). - **Response**: JSON object with `success` (boolean), `domain`, `ip` (resolved IP), `port`, `latency` (if successful), `error` (if failed), and `responseTime`. - **Status Codes**: - `200`: Success (includes both successful and failed tests). - `400`: Invalid request (missing domain or port). - `500`: Server error. - **Example**: ```bash curl -X POST \ -H "Content-Type: application/json" \ -d '{"domain":"example.com","port":443}' \ https://p2ns.admin/api/diagnostics/connection-test ``` ```json { "success": true, "domain": "example.com", "ip": "93.184.216.34", "port": 443, "latency": 45, "responseTime": 50 } ``` ### 56. GET /api/diagnostics/bandwidth - **Description**: Network interface information and configuration. Real-time throughput stats are not available via Node.js; response is interface layout only. - **Response**: JSON with `interfaces`, optional `note`, `responseTime`. - **Status Codes**: `200`, `500` - **Example**: ```bash curl -k https://p2ns.admin/api/diagnostics/bandwidth ``` ### 57. GET /api/diagnostics/invites - **Description**: Core invite / control-plane diagnostics over `p2ns.core-request-rpc` (`invite.request`, `invite.deliver`, `invite.ack`, `core.status`). Used by the Stats **Core** section and Invite Diagnostics UI. - **Response**: JSON with `summary` (dnsPass, rpcOpen, requestChannelOpen, failed peers, …), `peers`, `recommendations`, `connectionIssues`, etc. - **Status Codes**: `200`, `503` (still initializing), `500` - **Example**: ```bash curl -k https://p2ns.admin/api/diagnostics/invites ``` ### 58. GET / - **Description**: Redirects to the admin panel with the specified tab (e.g., `/domains`, `/host`, `/local-dns`) open. - **Path Parameters**: - `tab`: One of `domains`, `host`, `local-dns`, `entries`, `peers`, `certs`, `interfaces`, `logs`, `settings`. - **Response**: HTTP redirect to `/#`. - **Status Codes**: - `302`: Redirect. - **Example**: ```bash curl -X GET \ -L \ https://p2ns.admin/domains ``` ### 59. GET /favicon.ico - **Description**: Returns a 404 response (favicon not implemented). - **Response**: Plain text `Not Found`. - **Status Codes**: - `404`: Not found. - **Example**: ```bash curl -X GET \ https://p2ns.admin/favicon.ico ``` ```text Not Found ``` ## Consensus Endpoints ### 60. GET /api/consensus/:domain - **Description**: Retrieves the consensus state for a specific domain, including vote counts, quorum status, and resolution information. - **Path Parameters**: - `domain`: The domain name (e.g., `example.tld`). - **Response**: JSON object with: - `status` (string): Consensus status (`resolved`, `insufficient_quorum`, `tie`, `no_claims`, `error`). - `hash` (string|null): Resolved Holesail hash if status is `resolved`, otherwise `null`. - `resolvedClaimant` (string|null): Public key of the winning claimant if resolved, otherwise `null`. - `voteCounts` (object): Mapping of claimant public keys to their vote counts. - `activePeers` (number): Number of active peers in the network (including local node). - `quorumMet` (boolean): Whether the quorum threshold has been met. - `minVotes` (number): Minimum votes required to meet quorum. - `totalVotes` (number): Total number of votes cast for all claimants. - `lastResolution` (number|null): Timestamp of last resolution, or `null` if never resolved. - **Status Codes**: - `200`: Success. - `500`: Failed to get consensus state. - **Example**: ```bash curl -X GET \ https://p2ns.admin/api/consensus/example.tld ``` ```json { "status": "resolved", "hash": "hs://s00084bf87dfa89a3048fb081c0e6207eb5a", "resolvedClaimant": "abc123def456...", "voteCounts": { "abc123def456...": 3, "ghi789jkl012...": 1 }, "activePeers": 5, "quorumMet": true, "minVotes": 3, "totalVotes": 4, "lastResolution": 1704067200000 } ``` ### GET /api/consensus/status - **Description**: Returns health and progress of the consensus Autobase sidecar (the sole read path for `getConsensusState`). - **Response**: JSON object with: - `open` (boolean): Whether the sidecar Autobase instance is open. - `ready` (boolean): Whether the sidecar has completed opening. - `writable` (boolean): Whether this node can append sidecar events. - `bootstrapComplete` (boolean): Whether bootstrap or hydration from dnsPass has finished. - `eventCount` (number): Total events applied to the in-memory view. - `domainCount` (number): Domains present in the apply view. - `lastApplyAt` (number|null): Timestamp of the last applied event. - `indexedLength` (number): Autobase indexed length. - `length` (number): Autobase length. - `key` (string|null): Sidecar public key (hex). - **Status Codes**: - `200`: Success. - `500`: Failed to get consensus status. - **Example**: ```bash curl -X GET \ https://p2ns.admin/api/consensus/status ``` ```json { "open": true, "ready": true, "writable": true, "bootstrapComplete": true, "eventCount": 142, "domainCount": 12, "lastApplyAt": 1704067200000, "indexedLength": 142, "length": 142, "key": "a1b2c3..." } ``` ### 61. GET /api/consensus/metrics - **Description**: Retrieves overall consensus metrics including resolution statistics, quorum failures, ties, validation failures, and sidecar health. - **Response**: JSON object with: - `resolutions` (number): Total number of successful domain resolutions. - `quorumFailures` (number): Number of times quorum was not met. - `ties` (number): Number of ties that required tie-breaking. - `validationFailures` (number): Number of invalid votes that were rejected. - `totalVotes` (number): Total number of votes cast across all domains. - `avgVotesPerDomain` (number): Average number of votes per domain. - `domainResolutions` (array): Per-domain resolution statistics with `domain`, `resolved` count, and `failed` count. - `sidecar` (object): Same fields as `GET /api/consensus/status`. - `bootstrapComplete` (boolean): Whether sidecar bootstrap/hydration is complete. - **Status Codes**: - `200`: Success. - `500`: Failed to get consensus metrics. - **Example**: ```bash curl -X GET \ https://p2ns.admin/api/consensus/metrics ``` ```json { "resolutions": 42, "quorumFailures": 3, "ties": 2, "validationFailures": 1, "totalVotes": 156, "avgVotesPerDomain": 3.71, "domainResolutions": [ { "domain": "example.tld", "resolved": 5, "failed": 0 }, { "domain": "another.tld", "resolved": 3, "failed": 1 } ], "sidecar": { "open": true, "ready": true, "writable": true, "bootstrapComplete": true, "eventCount": 142, "domainCount": 12, "lastApplyAt": 1704067200000, "indexedLength": 142, "length": 142, "key": "a1b2c3..." }, "bootstrapComplete": true } ``` ### 62. POST /api/consensus/recalculate - **Description**: Forces a consensus recalculation for all domains. Invalidates the consensus cache and triggers auto-voting checks. - **Request Body**: None. - **Response**: JSON object with `success` (boolean) and `message` (string). - **Status Codes**: - `200`: Success. - `500`: Failed to recalculate consensus. - **WebSocket Broadcast**: `update-database` (triggers refresh of domains and entries). - **Example**: ```bash curl -X POST \ https://p2ns.admin/api/consensus/recalculate ``` ```json { "success": true, "message": "Consensus recalculation triggered" } ``` ### 63. POST /api/consensus/recalculate/:domain - **Description**: Forces a consensus recalculation for a specific domain. Invalidates the consensus cache for that domain and triggers auto-voting. - **Path Parameters**: - `domain`: The domain name (e.g., `example.tld`). - **Request Body**: None. - **Response**: JSON object with `success` (boolean) and `message` (string). - **Status Codes**: - `200`: Success. - `500`: Failed to recalculate consensus for domain. - **WebSocket Broadcast**: `update-database` (triggers refresh of domains and entries). - **Example**: ```bash curl -X POST \ https://p2ns.admin/api/consensus/recalculate/example.tld ``` ```json { "success": true, "message": "Consensus recalculation triggered for example.tld" } ``` ## Service Subscription Endpoints ### 64. GET /api/domain-services - **Description**: Retrieves all services configured for a specific domain from its claim record. - **Query Parameters**: - `domain` (string, required): The domain name to query services for. - **Response**: JSON array of service objects, each containing: - `serviceName` (string): Service identifier - `key` (string): Holesail connection hash - `port` (number): Port number - `protocol` (string): Protocol type (`tcp` or `udp`) - **Status Codes**: - `200`: Success (returns empty array if domain has no services or is not resolved). - `400`: Missing domain parameter. - `500`: Failed to fetch domain services. - **Example**: ```bash curl -X GET \ "https://p2ns.admin/api/domain-services?domain=example.tld" ``` ```json [ { "serviceName": "web", "key": "hs://s00084bf87dfa89a3048fb081c0e6207eb5a", "port": 8080, "protocol": "tcp" }, { "serviceName": "api", "key": "hs://s000bcc379b38f6d3a5cb4cfde23fa52392d", "port": 9090, "protocol": "tcp" } ] ``` ### 65. GET /api/service-subscriptions - **Description**: Lists all service subscriptions configured on this node. - **Response**: JSON array of subscription objects, each containing: - `domain` (string): Domain name - `serviceName` (string): Service identifier - `key` (string): Holesail connection hash - `port` (number): Port number - `protocol` (string): Protocol type (`tcp` or `udp`) - **Status Codes**: - `200`: Success. - `500`: Failed to fetch subscriptions. - **Example**: ```bash curl -X GET \ https://p2ns.admin/api/service-subscriptions ``` ```json [ { "domain": "example.tld", "serviceName": "web", "key": "hs://s00084bf87dfa89a3048fb081c0e6207eb5a", "port": 8080, "protocol": "tcp" } ] ``` ### 66. GET /api/subscribe-all-domains - **Description**: Lists all domains for which "subscribe all" is enabled. When enabled, the system automatically subscribes to all services for that domain, including newly added services. - **Response**: JSON array of domain names (strings). - **Status Codes**: - `200`: Success. - `500`: Failed to fetch subscribe-all domains. - **Example**: ```bash curl -X GET \ https://p2ns.admin/api/subscribe-all-domains ``` ```json ["example.tld", "another.tld"] ``` ### 67. POST /api/service-subscribe - **Description**: Subscribes to a specific service from a domain. Creates a Holesail client automatically with ID `domain_servicename` and persists the subscription to `subscriptions.json`. - **Request Body**: JSON with: - `domain` (string, required): Domain name - `serviceName` (string, required): Service identifier - `key` (string, required): Holesail connection hash - `port` (number, required): Port number - `protocol` (string, optional): Protocol type (`tcp` or `udp`, default: `tcp`) - **Response**: JSON with `success` (boolean) on success, error message on failure. - **Status Codes**: - `200`: Success. - `400`: Missing required fields. - `409`: Already subscribed to this service. - `500`: Failed to subscribe. - **WebSocket Broadcast**: `update-holesail-clients`. - **Example**: ```bash curl -X POST \ -H "Content-Type: application/json" \ -d '{"domain":"example.tld","serviceName":"web","key":"hs://s00084bf...","port":8080,"protocol":"tcp"}' \ https://p2ns.admin/api/service-subscribe ``` ```json {"success": true} ``` ### 68. POST /api/service-unsubscribe - **Description**: Unsubscribes from a specific service. Deletes the associated Holesail client and removes the subscription from `subscriptions.json`. - **Request Body**: JSON with: - `domain` (string, required): Domain name - `serviceName` (string, required): Service identifier - **Response**: JSON with `success` (boolean) on success, error message on failure. - **Status Codes**: - `200`: Success. - `400`: Missing required fields. - `404`: Subscription not found. - `500`: Failed to unsubscribe. - **WebSocket Broadcast**: `update-holesail-clients`. - **Example**: ```bash curl -X POST \ -H "Content-Type: application/json" \ -d '{"domain":"example.tld","serviceName":"web"}' \ https://p2ns.admin/api/service-unsubscribe ``` ```json {"success": true} ``` ### 69. POST /api/subscribe-all - **Description**: Enables "subscribe all" for a domain. This automatically subscribes to all current services for that domain and will automatically subscribe to any new services added in the future. Creates Holesail clients for all existing services. - **Request Body**: JSON with: - `domain` (string, required): Domain name - **Response**: JSON with `success` (boolean) on success, error message on failure. - **Status Codes**: - `200`: Success. - `400`: Missing domain field. - `500`: Failed to set subscribe-all. - **WebSocket Broadcast**: `update-holesail-clients`. - **Example**: ```bash curl -X POST \ -H "Content-Type: application/json" \ -d '{"domain":"example.tld"}' \ https://p2ns.admin/api/subscribe-all ``` ```json {"success": true} ``` ### 70. POST /api/unsubscribe-all - **Description**: Disables "subscribe all" for a domain and unsubscribes from all services for that domain. Deletes all associated Holesail clients. - **Request Body**: JSON with: - `domain` (string, required): Domain name - **Response**: JSON with `success` (boolean) on success, error message on failure. - **Status Codes**: - `200`: Success. - `400`: Missing domain field. - `500`: Failed to clear subscribe-all. - **WebSocket Broadcast**: `update-holesail-clients`. - **Example**: ```bash curl -X POST \ -H "Content-Type: application/json" \ -d '{"domain":"example.tld"}' \ https://p2ns.admin/api/unsubscribe-all ``` ```json {"success": true} ``` ## Plugin Management Endpoints **Note:** For detailed information about the plugin system, see [plugins/README.md](plugins/README.md) and [plugins/PLUGIN_SDK.md](plugins/PLUGIN_SDK.md). ### 71. GET /api/plugins - **Description**: Lists all plugins with their information, status, actions, and settings. Includes both loaded and stopped plugins. - **Response**: JSON object with `plugins` (array of plugin objects). Each plugin object contains: - `domain` (string): Plugin domain name - `name` (string): Plugin name from config.json - `version` (string): Plugin version - `description` (string): Plugin description - `author` (string): Plugin author - `homepage` (string): Plugin homepage URL - `license` (string): Plugin license - `status` (string): Plugin status (`loaded`, `stopped`, or `static`) - `hasHandler` (boolean): Whether plugin has a handler function - `hasWww` (boolean): Whether plugin has a www directory - `hasDatabase` (boolean): Whether plugin has HyperDB configured - `actions` (array): Array of registered action objects - `settings` (object): Map of registered settings with their current values - **Status Codes**: - `200`: Success. - `500`: Failed to list plugins. - **Example**: ```bash curl -X GET \ https://p2ns.admin/api/plugins ``` ```json { "plugins": [ { "domain": "example.plugin", "name": "Example Plugin", "version": "1.0.0", "description": "A template plugin", "author": "P2NS", "homepage": "https://example.com", "license": "MIT", "status": "loaded", "hasHandler": true, "hasWww": true, "hasDatabase": false, "actions": [ { "name": "testAction", "label": "Test Action", "description": "A test action", "icon": "🧪" } ], "settings": { "maxItems": { "type": "number", "label": "Maximum Items", "description": "Maximum number of items", "default": 100, "value": 100 } } } ] } ``` ### 72. GET /api/plugins/:domain - **Description**: Retrieves detailed information for a specific plugin. - **Path Parameters**: - `domain`: The plugin domain name (e.g., `example.plugin`). - **Response**: JSON object with plugin information (same structure as plugin object in GET /api/plugins). - **Status Codes**: - `200`: Success. - `404`: Plugin not found. - `500`: Failed to get plugin info. - **Example**: ```bash curl -X GET \ https://p2ns.admin/api/plugins/example.plugin ``` ### 73. POST /api/plugins/:domain/start - **Description**: Starts a stopped plugin. Loads the plugin handler and initializes resources. - **Path Parameters**: - `domain`: The plugin domain name (e.g., `example.plugin`). - **Request Body**: None. - **Response**: JSON object with `success` (boolean), `message` (string), and `domain` (string). - **Status Codes**: - `200`: Success. - `400`: Invalid domain parameter. - `500`: Failed to start plugin. - **WebSocket Broadcast**: `update-plugins`. - **Example**: ```bash curl -X POST \ https://p2ns.admin/api/plugins/example.plugin/start ``` ```json { "success": true, "message": "Plugin example.plugin started successfully", "domain": "example.plugin" } ``` ### 74. POST /api/plugins/:domain/stop - **Description**: Stops a running plugin. Unloads the plugin handler and cleans up resources. - **Path Parameters**: - `domain`: The plugin domain name (e.g., `example.plugin`). - **Request Body**: None. - **Response**: JSON object with `success` (boolean), `message` (string), and `domain` (string). - **Status Codes**: - `200`: Success. - `400`: Invalid domain parameter. - `500`: Failed to stop plugin. - **WebSocket Broadcast**: `update-plugins`. - **Example**: ```bash curl -X POST \ https://p2ns.admin/api/plugins/example.plugin/stop ``` ```json { "success": true, "message": "Plugin example.plugin stopped successfully", "domain": "example.plugin" } ``` ### 75. POST /api/plugins/:domain/reload - **Description**: Reloads a plugin. Stops the plugin, clears the module cache, and starts it again. Useful for applying code changes without restarting P2NS. - **Path Parameters**: - `domain`: The plugin domain name (e.g., `example.plugin`). - **Request Body**: None. - **Response**: JSON object with `success` (boolean), `message` (string), and `domain` (string). - **Status Codes**: - `200`: Success. - `400`: Invalid domain parameter. - `500`: Failed to reload plugin. - **WebSocket Broadcast**: `update-plugins`. - **Example**: ```bash curl -X POST \ https://p2ns.admin/api/plugins/example.plugin/reload ``` ```json { "success": true, "message": "Plugin example.plugin reloaded successfully", "domain": "example.plugin" } ``` ### 76. POST /api/plugins/:domain/actions/:actionName - **Description**: Executes a registered plugin action. The action handler is called with the provided parameters. - **Path Parameters**: - `domain`: The plugin domain name (e.g., `example.plugin`). - `actionName`: The action name (e.g., `testAction`). - **Request Body**: JSON object with action parameters (optional). - **Response**: JSON object with `success` (boolean) and `result` (any) containing the action handler's return value. - **Status Codes**: - `200`: Success. - `400`: Invalid request path. - `404`: Plugin or action not found. - `500`: Action execution failed. - **Example**: ```bash curl -X POST \ -H "Content-Type: application/json" \ -d '{"value": 10}' \ https://p2ns.admin/api/plugins/example.plugin/actions/testAction ``` ```json { "success": true, "result": { "success": true, "message": "Test action executed successfully!", "timestamp": "2025-12-12T10:00:00.000Z" } } ``` ### 77. POST /api/plugins/:domain/settings - **Description**: Updates plugin settings. Saves settings to `cache/plugin-settings/{domain}.json` and persists them across plugin restarts. - **Path Parameters**: - `domain`: The plugin domain name (e.g., `example.plugin`). - **Request Body**: JSON object mapping setting keys to values. - **Response**: JSON object with `success` (boolean) and `message` (string). - **Status Codes**: - `200`: Success. - `400`: Invalid domain parameter. - `500`: Failed to update settings. - **WebSocket Broadcast**: `update-plugin-settings`. - **Example**: ```bash curl -X POST \ -H "Content-Type: application/json" \ -d '{"maxItems": 200, "enableFeature": true}' \ https://p2ns.admin/api/plugins/example.plugin/settings ``` ```json { "success": true, "message": "Settings updated for plugin example.plugin" } ``` ### 78. GET /api/token - **Description**: Generates a signed Ed25519 authentication token for plugin authentication. Available to all plugins globally. - **Request Headers**: None required. - **Response**: JSON object with `token` (string), `expiresAt` (number), and `peerId` (string). - **Status Codes**: - `200`: Success. - `500`: Failed to generate token. - **Example**: ```bash curl -X GET \ https://global.profile/api/token ``` ```json { "token": "eyJwZWVySWQiOiIxMjM0NTY3ODkwYWJjZGVmZ2hpamsuLi4iLCJ0aW1lc3RhbXAiOjE2ODk...", "expiresAt": 1689123456789, "peerId": "1234567890abcdef..." } ``` - **Notes**: - Tokens expire after 1 hour (3600 seconds) by default. - Tokens are signed with Ed25519 using the local peer's private key. - Use the token in the `Authorization: Bearer ` header for authenticated requests. - The `X-Auth-Token` header is also supported as an alternative. ## Authentication Plugin write operations (POST, PUT, DELETE, PATCH) require authentication using Ed25519-signed tokens. ### Authentication Headers **Authorization Header (Preferred):** ``` Authorization: Bearer ``` **Alternative Header:** ``` X-Auth-Token: ``` ### Error Responses **401 Unauthorized:** ```json { "error": "Authentication required", "message": "Invalid or missing authentication token" } ``` **403 Forbidden:** ```json { "error": "Forbidden", "message": "Only the local peer can perform this operation" } ``` ### Token Format Tokens are base64-encoded JSON objects containing: - `peerId`: The public key (hex string) of the authenticated peer - `timestamp`: Token creation timestamp (milliseconds) - `expiresAt`: Token expiration timestamp (milliseconds) - `signature`: Ed25519 signature (hex string) of the token payload ### Frontend Integration Include the authentication utilities script: ```html ``` Use `authenticatedFetch()` for write operations: ```javascript const response = await authenticatedFetch('/api/data', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ data: 'value' }) }); ``` See [plugins/PLUGIN_SDK.md](plugins/PLUGIN_SDK.md#authentication-and-authorization) for complete authentication API documentation. ## Security Notes - **Plugin Authentication**: Write operations in plugins require Ed25519-signed tokens. See [Authentication](#authentication) section above. - **No Authentication**: Admin endpoints are unauthenticated, so restrict access to trusted networks or users in production. - **HTTPS**: Use HTTPS to protect data in transit. - **Input Validation**: Ensure inputs (e.g., domain names, DNS record fields) are sanitized to prevent injection attacks. - **Permissions**: `selector_cache.json`, `domains.json`, `local_dns.json`, `holesail_servers.json`, `holesail_clients.json`, and `subscriptions.json` should have restricted permissions to prevent unauthorized modifications. ## Testing - Use tools like `curl` or Postman to test endpoints. - Verify WebSocket updates using a WebSocket client (e.g., `wscat`). - Test DNS record creation with various types (e.g., SRV, SOA) and check `local_dns.json`. - Monitor logs in the admin **Logs** tab (`subscribe-log` per channel) or `GET /api/logs/:channel`; plugin logs use `plugin-log` WebSocket messages.