Repository navigation
[Composite] Close 0.1.0 adoption gaps: desktop CORS, proxy docs, upload diagnostics #44
Description
Summary
Release 0.1.0 is functionally sound for server-side and curl checks, but several operability gaps block or confuse real ADAMANT clients (especially Electron/macOS), mislead operators about reverse-proxy settings, and surface opaque upload failures. This issue bundles hardening and documentation work only—no new product features.
Background
trustProxy: testnet vs mainnet
Both environments can run behind nginx on public HTTPS (for example port 44099 → 127.0.0.1:4000). The difference is configuration discipline, not “testnet works, mainnet wrong”:
| Situation | Typical behaviour on 0.1.0 |
|---|---|
Clients hit nginx HTTPS; Node sees X-Forwarded-For |
trustProxy must be set (hop count 1 or explicit proxy CIDR). false → startup warning and shared client IP for rate limits; can contribute to 429 storms and upload failures. |
trustProxy: true |
Rejected at startup (validation in src/security/trustProxy.ts). |
Direct access to :4000 without forwarded headers |
trustProxy: false is fine. |
Testnet nodes are not magically exempt: if they are behind nginx like mainnet, they need the same trustProxy tuning after upgrade to 0.1.0. Mainnet was explicitly corrected (trustProxy: 1) during rollout; testnet may still run older defaults until aligned.
Document this clearly so operators do not assume Docker-only or mainnet-only semantics.
Desktop clients and CORS (app://)
ADAMANT Electron (and similar custom-scheme desktops) load the UI from app://. Chromium sends:
Origin: app://.Health checks and uploads use axios/fetch from the renderer. The node’s CORS layer (src/security/cors.ts) only accepts http: / https: origins from cors.allowedOrigins. For Origin: app://. the API may return 200, but without Access-Control-Allow-Origin, so the renderer sees Network Error / Failed to fetch—nodes appear Offline in Settings even when curl succeeds.
PWA origins (for example https://msg.adamant.im under https://*.adamant.im) work; desktop does not until CORS or a documented client-side mitigation exists.
Reproduction (local): Electron with app:// + fetch('https://<ipfs-host>/api/node/info') fails; injecting Access-Control-Allow-Origin: app://. via webRequest.onHeadersReceived succeeds.
Proposed work
1. Code: allow desktop origins in CORS
- Extend
src/security/cors.ts(and validation insrc/security/config.ts) to support custom app schemes used by ADAMANT desktop builds, at minimumapp://.(and document any variants Electron sends). - Keep rejection of bare
*and unsafe patterns. - Add unit tests mirroring existing HTTP/HTTPS wildcard cases.
- Update
config.default.json5anddocker/config.example.json5with a commented example entry for self-hosters who run the official desktop against their node (operators opt in explicitly).
Security note: app:// is not a web origin arbitrary sites can forge; document the threat model (browser attackers vs desktop app).
2. Documentation (required public surface sync)
Update docs/guide/security.md, docs/guide/configuration.md, docs/guide/installation.md, docs/guide/docker.md, docs/operations/troubleshooting.md as needed:
trustProxybehind nginx: when to use hop count1vs explicit127.0.0.1/8/::1/128; relationship to Docker (publish 127.0.0.1:4000:4000+ host nginx) and bare pm2.- CORS checklist for ADAMANT deployments: PWA wildcards plus desktop
app://when serving official Electron users. - Monitoring: Zabbix/health probes without
Originvs browser/desktop withOrigin—why probes can be green while the app shows Offline. - Cross-link ADAMANT Messenger adopter page only as an example origin set, not as the product’s sole consumer.
3. Docker image and examples
| Artifact | Recommended change |
|---|---|
docker/config.example.json5 |
Comment block: behind reverse proxy set trustProxy: 1 (or CIDR list); expand cors.allowedOrigins beyond localhost for real deployments; mention desktop app://. |
Dockerfile |
No functional change required for CORS/trustProxy (runtime config). Optional: one-line comment in docker.md pointing to mounted config.json5—do not bake ADAMANT-specific origins into the image. |
scripts/docker-smoke-test.sh |
Keep trustProxy: false for direct probe; document why smoke test does not cover proxied CORS. |
4. Upload failures and client-visible errors
Research and improve actionable server behaviour where cheap (no new features):
User-reported pattern: IPFS node: Failed to upload file 10 times in a row (exact string not found in current adamant-im PWA sources; may come from native clients or aggregated retry logic—confirm source when implementing).
PWA path today (adamant-im):
- Upload:
POST /api/file/uploadviaIpfsClient→requestWithRetryacross nodes. - If all nodes look offline (often CORS/network), user gets
AllNodesOfflineError/ generic failure—not a clear “CORS/desktop” hint.
Node-side angles to investigate:
| Cause | Current behaviour | Possible improvement |
|---|---|---|
429 rate limit (rateLimits.upload, default 10 / 15 min per client IP) |
JSON Too many requests |
Document limits; ensure consistent JSON body and Retry-After / RateLimit headers; troubleshooting entry for shared IP when trustProxy: false. |
| Upload admission / disk reserve / memory pressure | Slow or hung uploads; ops saw multi-minute stalls before restart | Operations docs: memory limits, scan cadence; consider clearer 503/507 with stable error codes where already distinguishable in code. |
408 on GET /api/file/:cid (retrieval timeout) |
Reported on testnet cross-node fetch | Troubleshooting: replication lag, findFileTimeout, repair state—not an upload bug but same user perception (“IPFS broken”). |
| CORS on POST upload | Same as healthcheck for Electron | Fixed by section 1. |
Deliverables:
- Short troubleshooting section tying symptoms →
trustProxy, CORS, rate limits, healthdegraded, resource limits. - If code changes add stable
errorcodes in JSON for upload/read paths, updatedocs/openapi.yamlanddocs/reference/api.mdin the same change.
Out of scope
- New protocols, public DHT/gateway, uploader-signed deletion, peer discovery beyond static lists (existing open issues).
- Changing default rate limits globally without operator review.
Acceptance criteria
- Desktop origin (
app://.) can be configured and passes CORS forGET /api/node/infoandPOST /api/file/uploadin a browser-like test. - Documentation explains testnet and mainnet proxy/CORS requirements symmetrically.
- Docker guide and example config mention trustProxy + CORS for reverse-proxy deployments; Dockerfile change only if justified in PR description.
- Upload/rate-limit/CORS failure modes documented; any new response fields reflected in OpenAPI.
- Tests and
npm run lint,format,typecheckpass per AGENTS.md.
How to test
- Node with nginx TLS →
trustProxy: 1, CORS including PWA origin andapp://.. curland browser PWA fetch withOrigin: https://…→ ACAO present.- Electron (or minimal
app://fixture) healthcheck and small upload succeed. - Regression: existing wildcard HTTPS origins still match.
Related
- ADAMANT desktop client: separate tracking for
IpfsClientminVersionwiring and optional ElectronwebRequestfallback until all production nodes ship desktop CORS. - Messenger adopter deployments: mainnet mesh (2 nodes), Zabbix port 44099.
Metadata
Metadata
Assignees
Labels
Type
Projects
- StatusShow more project fieldsReleased IPFS node v0.1.0
Activity
metalisk commentedon Sep 28, 2026
Pull request: #45