# CHD Registration Domain Challenge (Concept) ## 1. Purpose Document a future hardening design for CHD installation registration that: 1. Keeps new cloud setup mostly automatic 2. Reduces abuse of open registration (`/api/sovereign/v1/install/register`) 3. Preserves backward compatibility with current connector behavior This is a design note only (not implemented yet). ## 2. Problem Current registration can be fully automatic, which is good for UX. Risk: 1. If registration is open (no registration token required), attackers can spam fake installations. 2. CHD may create registry/customer records for domains the caller does not control. 3. Abuse can pollute instance registry, create noise in support/admin tooling, and consume resources. ## 3. Goals 1. Prove caller controls the claimed public cloud domain. 2. Keep first-run setup simple for legitimate users. 3. Support both: - open registration mode (developer-friendly) - token-required registration mode (hardened production) 4. Allow phased rollout without breaking existing installs. ## 4. Non-goals (for this phase) 1. Proving Qortal address ownership cryptographically 2. Preventing all abuse without rate limits or moderation 3. Replacing CHD registration tokens entirely Qortal ownership proof can be added later as a higher-trust layer (for grants/high-risk actions). ## 5. Proposed model Use a two-step registration state: 1. `registered_unverified` 2. `domain_verified` Optional later: 3. `qortal_verified` 4. `billing_active` Registration may remain automatic, but higher-risk actions can require stronger state. ## 6. Domain challenge flow (proposed) ### 6.1 Step A: Initial registration request Cloud calls: 1. `POST /api/sovereign/v1/install/register` Payload includes (as it does today): 1. `instanceId` (optional client-supplied hint) 2. `nextcloudPublicUrl` 3. `adminEmail` (optional) 4. `adminQortalAddress` (optional but recommended/used) 5. mode/provider metadata CHD response returns: 1. normal instance credentials (`instanceId`, `instanceToken`, `instanceSecret`) 2. registration state = `registered_unverified` 3. a domain challenge object, e.g.: - `challengeId` - `challengeToken` - `expiresAt` - `verifyPath` (suggested URL path to expose) ### 6.2 Step B: Cloud proves domain control Cloud exposes challenge token at a deterministic public URL under the claimed domain. Examples: 1. `https:///.well-known/sovereign-chd/` 2. `https:///apps/qortal_integration/api/chd/verify` CHD verifies by fetching that URL over HTTPS and matching the challenge token. ### 6.3 Step C: Verification result If valid: 1. CHD marks instance `domain_verified` 2. CHD allows checkout issuance (recommended) 3. CHD can elevate trust for later automation flows If invalid/expired: 1. instance remains `registered_unverified` 2. CHD may allow only limited operations or block checkout ## 7. API sketch (proposed) ### 7.1 Registration response extension Existing response can be extended without breaking clients: ```json { "ok": true, "registration": { "instanceId": "sc-example", "instanceToken": "…", "instanceSecret": "…" }, "verification": { "state": "registered_unverified", "domainChallenge": { "required": true, "challengeId": "ch_123", "challengeToken": "abc123…", "verifyUrlPath": "/.well-known/sovereign-chd/sc-example", "expiresAt": "2026-02-24T00:00:00Z" } } } ``` ### 7.2 Optional explicit verify endpoint CHD can verify passively by fetch, or also expose: 1. `POST /api/sovereign/v1/install/verify-domain` Input: 1. `instanceId` 2. optional `challengeId` CHD performs fetch and returns status. This helps plugin/admin UI display clearer status. ## 8. Recommended policy gates To keep UX smooth while reducing abuse: 1. Registration: - allow open or token-required (configurable) 2. Entitlements sync: - allow for registered instances 3. Checkout link creation: - require `domain_verified` (recommended) 4. Grant workflows / higher trust operations: - later require `qortal_verified` and/or manual review ## 9. Connector hardening controls (independent of challenge) Domain challenge should be combined with basic anti-abuse controls: 1. Rate limit registration by IP 2. Rate limit by normalized domain 3. Cooldown for repeated attempts per domain 4. Expire unverified registrations (e.g. 15–60 minutes) 5. Reject localhost/private domains in production mode 6. Cap pending unverified instances per IP/day 7. Log registration + verification events ## 10. Backward compatibility / rollout ### Phase 1 (compatibility) 1. Add verification fields to registration response (optional) 2. CHD stores verification state but does not enforce 3. Existing plugins keep working unchanged ### Phase 2 (soft enforcement) 1. CHD warns on checkout when instance is not `domain_verified` 2. Admin UI surfaces verification status and remediation steps ### Phase 3 (policy enforcement) 1. CHD blocks checkout for `registered_unverified` (configurable) 2. Open registration remains possible but gated by verification ## 11. Future extension: Qortal ownership challenge Longer term, add a second proof layer for the admin Qortal address: 1. CHD issues a challenge tied to `adminQortalAddress` 2. Admin proves control via Qortal-capable signing/decryption flow 3. CHD marks instance `qortal_verified` This is better suited to a CHD admin plugin/admin cloud with Qortal tooling, not the connector alone. ## 12. Open questions 1. Which public challenge URL path is easiest and most stable for Nextcloud deployments? 2. Should checkout require `domain_verified` immediately or only in production mode? 3. Should verification use exact host match only, or allow canonical redirects? 4. How long should challenge tokens remain valid? 5. How should re-verification work when a cloud domain changes?