Skip to content

Webinterface - Cloudflare Workers#7

Open
koljasagorski wants to merge 28 commits into
tayfun57:mainfrom
koljasagorski:main
Open

Webinterface - Cloudflare Workers#7
koljasagorski wants to merge 28 commits into
tayfun57:mainfrom
koljasagorski:main

Conversation

@koljasagorski

Copy link
Copy Markdown
Contributor

No description provided.

koljasagorski and others added 28 commits November 10, 2025 13:38
- Wrap api_client.logout() in try/except inside a finally block so
  failures don't mask earlier errors and don't leak unhandled exceptions
- Add InwxApiError exception and a _call() helper to deduplicate the
  repeated `code == 1000` API-response checks
- Make file paths (domains list, CSV output, log file) and the per-call
  API delay configurable via environment variables; rate-limit between
  domain checks to avoid hammering the INWX API
- Validate that the domains file exists before iterating
- Unify logging: file handler + warning-level console handler, set up
  inside main() so importing the module has no side effects
- Move logging.basicConfig out of module scope (was creating log.txt on
  import) and extract process_domain / print_summary helpers from main()
- Bump dependencies to current versions (requests 2.32, urllib3 2.2,
  python-dotenv 1.0, certifi 2024.7, idna 3.7, etc.)
- Move domains.txt to domains.txt.sample and gitignore the real file +
  generated artefacts (CSV, pycache, ruff/pytest caches)
- Add pytest suite (load_domains, write_csv, _call success/failure,
  InwxApiError) with a stubbed INWX SDK so tests run without network
- Add ruff + pytest configuration in pyproject.toml and a GitHub Actions
  CI workflow running on Python 3.10/3.11/3.12
- Flesh out README: start command, configuration table, dev setup

https://claude.ai/code/session_01KJj6SRqa7UBbtCpReVjaeB
…tion-Z8Q8M

Refactor INWX bot: robustness, configurability, tests + CI
Adds a TypeScript Cloudflare Worker variant of the INWX domain bot under
cloudflare-worker/, alongside the existing Python CLI script.

- Talks to the INWX JSON-RPC API directly via fetch (the requests-based
  Python SDK does not run on Workers); session cookie handled manually.
- Runs on a Cron Trigger; domain list and results stored in Workers KV.
- DRY_RUN defaults to "true" so it never registers domains until enabled.
- Token-protected HTTP endpoints to manage the list, trigger runs, and
  download JSON/CSV results.
- Optional 2FA (mobile TAN) via Web Crypto TOTP, verified against the
  RFC 6238 test vectors.
- Optional Slack/Discord webhook notifications for noteworthy runs.
- CI job added to typecheck the Worker; readme updated to describe both
  deployment options.

https://claude.ai/code/session_01KH9YazP7LmiLgvbA3NhW6Y
Add Cloudflare Worker deployment (scheduled, serverless)
Serves a self-contained dashboard at `/` that shows run status, per-domain
results, lets you edit the domain list, trigger a check, and download the
CSV. Data endpoints are reorganised under `/api/*`:

- GET /                -> dashboard HTML (strict nonce-based CSP, no external assets)
- GET /api/status      -> public status (dry-run mode, last run, last error)
- GET/PUT /api/domains -> read / replace the domain list (token protected)
- POST /api/run        -> trigger a run (token protected; ?async=true supported)
- GET /api/results.json|.csv -> last run results (token protected)

The dashboard prompts for ADMIN_TOKEN (kept in sessionStorage) and renders all
external data via safe DOM APIs (no innerHTML) to avoid XSS. README updated.

Verified: tsc typecheck, client-script syntax check, and end-to-end requests
against `wrangler dev` (HTML + CSP header, status, 401 without token, domain
save/list, run error path, CSV, 404).

https://claude.ai/code/session_01KH9YazP7LmiLgvbA3NhW6Y
Add web dashboard to the Cloudflare Worker
For every watched domain the bot now gathers registration metadata
(registered / expires / last changed / status / registrar) and shows it in
a new dashboard table. Expiry within 30 days is highlighted.

Data sources (per domain, best first):
- INWX `domain.info` for domains in the account — authoritative dates for any
  TLD (including .de).
- RDAP (the JSON successor to WHOIS) for everything else. An explicit
  User-Agent is sent because some RDAP servers reject UA-less requests (403).
  Unregistered domains (RDAP 404) are reported as available.

New endpoints (token protected): `GET /api/whois` and
`POST /api/whois/refresh` (with `?async=true`). The data is stored in KV
(`whois:latest.json`), refreshed on each cron run and via a dashboard button.
`GET /api/status` now also reports `whoisLastRun`.

Verified: tsc, client-script syntax/structure checks, and end-to-end against
`wrangler dev` — RDAP returns real registration/expiry/updated data for a
registered domain and flags an unregistered one as available.

https://claude.ai/code/session_01KH9YazP7LmiLgvbA3NhW6Y
The committed wrangler.toml still carried the REPLACE_WITH_YOUR_KV_NAMESPACE_ID
placeholder, which made the Cloudflare Workers Build (Git integration) fail with
"KV namespace ... is not valid". Pin the real namespace id (an identifier, not a
secret) so automatic deploys work. Actual secrets stay out of the repo.

https://claude.ai/code/session_01KH9YazP7LmiLgvbA3NhW6Y
Add WHOIS / domain-status table to the dashboard
Monitoring smarts for the Worker (KV-based, no new infrastructure):

- Run history: each run is appended to a capped list (history:runs, last 50)
  and shown in a new dashboard "Verlauf" panel. New GET /api/history endpoint.
- Per-domain state (state:domains) tracks the last action so notifications fire
  only when a domain's status actually CHANGES (newly available / bought /
  failed), instead of on every run. Fatal run errors are de-duplicated too.
- Expiry alerts: as owned/registered domains approach renewal, a webhook alert
  is sent once per crossed threshold (EXPIRY_ALERT_DAYS, default 30,14,7,1),
  reset when the expiry date changes.
- Best-effort KV lock prevents a manual run/whois-refresh from overlapping the
  scheduled run; /api/run and /api/whois/refresh return 409 when busy.

Verified: tsc; unit tests of change-detection / threshold parsing / expiry
crossing; and end-to-end against `wrangler dev` with a webhook capture —
confirmed error-notify dedup (1 alert for 2 failing runs), an expiry alert
firing once and de-duplicating on repeat, and history growing correctly.

https://claude.ai/code/session_01KH9YazP7LmiLgvbA3NhW6Y
Monitoring smarts: run history, change-based + expiry alerts, run lock
Domain entries are now per-domain config objects ({domain, mode, maxPrice?,
tags?, notes?}) instead of plain strings (plain strings / newline lists stay
supported and default to mode "auto"):

- mode "watch" only reports availability; "auto" registers when free unless
  DRY_RUN is on.
- maxPrice skips an auto-purchase when the INWX price exceeds the budget;
  domain.check now also returns the price (best-effort). When a price cannot be
  determined and a budget is set, the purchase is skipped (safe default).
- POST /api/buy registers one available domain on explicit request; it ignores
  DRY_RUN and the watch/auto mode (explicit user action) and is lock-guarded.

Dashboard: the domain list is now an editable table (domain / mode / max price /
tags), and the results table has a per-row "Kaufen" button (with confirmation)
for available domains.

Verified: tsc; dashboard client-script syntax/structure checks; unit tests of
every processDomain decision branch (never buys on watch / dry-run / over-budget
/ unknown-price-with-budget; buys otherwise); and end-to-end against
`wrangler dev` — domain-config round-trip incl. backward-compatible string/text
input, and /api/buy validation (400 on empty, graceful error without creds).

https://claude.ai/code/session_01KH9YazP7LmiLgvbA3NhW6Y
Per-domain modes (watch/auto), budget guard, and on-demand buy
Quality and operations hardening for the Worker:

- Unit tests (vitest): 22 tests covering domain-config parsing, CSV escaping,
  run-change detection, expiry thresholds, RDAP parsing, and the RFC 6238 TOTP
  vectors. Pure helpers are re-exported from index.ts for testing. The CI
  "worker" job now runs `npm test` after the typecheck.
- Wrangler bumped to v4 (removes the out-of-date warning; matches the Cloudflare
  Workers Build environment). Config is unchanged and verified via dev + deploy
  dry-run.
- Telegram notifications: set TELEGRAM_BOT_TOKEN + TELEGRAM_CHAT_ID to receive
  alerts in Telegram in addition to (or instead of) the webhook. Notifications
  now fan out to every configured channel.
- Security headers: dashboard CSP gains `frame-ancestors 'none'`, and responses
  send `X-Content-Type-Options: nosniff` (+ `Referrer-Policy: no-referrer` on
  the dashboard).
- Dependabot config for npm (cloudflare-worker), pip, and github-actions.

Verified: `npm ci` + typecheck + 22 tests green; wrangler v4 dev serves the
dashboard with the new headers; notification fan-out confirmed against a local
webhook receiver (with correct de-duplication).

https://claude.ai/code/session_01KH9YazP7LmiLgvbA3NhW6Y
Quality & ops: unit tests + CI, Wrangler v4, Telegram, security headers, Dependabot
Final batch of the dashboard/ops UX:

- Runtime settings: dryRun / apiDelayMs / expiryAlertDays can be overridden via
  KV (settings:config) and edited in a dashboard panel — no redeploy needed.
  wrangler.toml [vars] remain the safe defaults; turning dry-run off prompts for
  confirmation. New GET/PUT /api/settings; the run, whois and status paths now
  read the effective settings.
- Ad-hoc quick check: POST /api/check ({domain} or {keyword,tlds[]}) and a
  dashboard form report availability + price without touching the watch list.
- Audit log: token-authenticated mutating actions (run, buy, domains.save,
  whois.refresh, settings.save, check) are recorded to a capped KV list
  (audit:log), exposed via GET /api/audit and shown in the dashboard.
- Login throttling: protected endpoints count failed token attempts per client
  IP and return 429 after a threshold (5-minute window); success clears the
  counter. Fail-open on KV errors.

Verified: tsc; 29 unit tests (incl. new mergeSettings / expandCheckTargets);
dashboard syntax/structure checks; and end-to-end against `wrangler dev` —
settings override flips DRY_RUN at runtime (reflected in /api/status), audit log
records actions with IP, /api/check validates input + degrades without creds,
and throttling returns 429 after 10 bad attempts (other IPs unaffected).

https://claude.ai/code/session_01KH9YazP7LmiLgvbA3NhW6Y
Settings UI, ad-hoc check, audit log, login throttling
Auto-sync per always-keep-GitHub-in-sync policy.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Polish and correctness fixes:

- Manual buy now: confirmation dialog shows the price, the result row flips to
  "purchased" immediately, a notification is sent, and the stored results/state
  are updated so a reload stays consistent (previously a manual buy was silent
  and the table kept showing "available").
- domain.check's price is surfaced on every DomainStatus and shown in a new
  "Preis" column.
- The per-domain "notes" field is now editable in the dashboard table (it
  existed in the model but was silently dropped by the UI).
- Settings can be reset to the wrangler.toml defaults (DELETE /api/settings +
  dashboard button), and the panel warns that overrides persist across deploys.
- Lock TTL raised 600s -> 1800s so a long run does not lose the lock mid-flight.
- Stop tracking the accidentally committed `.wrangler/` cache (account info /
  build cache) and gitignore `.wrangler/` + `node_modules/` at the repo root.

Verified: tsc; 29 unit tests; dashboard syntax/structure checks; and end-to-end
against `wrangler dev` — notes round-trip, settings override + reset (status
reflects the change and falls back to the env default), and audit logging.

https://claude.ai/code/session_01KH9YazP7LmiLgvbA3NhW6Y
Buy UX (price + notify + refresh), notes field, settings reset, cache cleanup
…rtbeat

Addresses the subrequest-limit ceiling and registration/liveness gaps:

- Availability is now checked in batches via a single domain.check call per
  ~30 domains (InwxClient.checkDomains) instead of one call per domain, so the
  run path stays well under Cloudflare's per-invocation subrequest limit. The
  ad-hoc /api/check uses the same batched path.
- The cron is split into two triggers — one for the availability run (06:00),
  one for the WHOIS refresh (06:30) — so each invocation gets its own
  subrequest budget. The scheduled handler routes by event.cron (unknown cron
  values run both as a fallback). wrangler.toml ships both crons.
- Registration options renewalMode / period / transferLock are applied to
  domain.create (defaults: AUTORENEW + transfer-locked), configurable via env
  vars, the dashboard settings panel, or PUT /api/settings.
- Optional HEARTBEAT_URL is pinged after every cron invocation as a
  dead-man's-switch so a stalled cron is detected externally.
- Lock TTL already raised in the previous PR; this keeps long batched runs safe.

Verified: tsc; 32 unit tests (added chunk + registration-merge coverage);
dashboard syntax/structure checks; and end-to-end against `wrangler dev
--test-scheduled` — the run cron updates lastRun, the WHOIS cron updates
whoisLastRun, each invocation pings the heartbeat, and the registration options
round-trip through /api/settings.

https://claude.ai/code/session_01KH9YazP7LmiLgvbA3NhW6Y
Scale runs: batch domain.check, split cron, registration options, heartbeat
Channels and comfort improvements:

- Email notifications via Resend: set RESEND_API_KEY + EMAIL_TO + EMAIL_FROM to
  also receive alerts by email. Notifications now fan out to every configured
  channel (webhook + Telegram + email), gated by a single hasNotifyChannel check.
- Backup: GET /api/export downloads a JSON bundle of the domain list + settings
  override (with a Content-Disposition filename); POST /api/import restores it.
  A "Backup herunterladen" button is added to the dashboard; imports are audited.
- Dashboard comfort: the results and WHOIS tables get a live filter input and
  click-to-sort column headers (numeric-aware), re-applied after each refresh.

Verified: tsc; 32 unit tests; dashboard syntax/structure checks; and end-to-end
against `wrangler dev` — export returns the bundle (+ download header), import
restores domains and settings (confirmed via the API), and the action is audited.

https://claude.ai/code/session_01KH9YazP7LmiLgvbA3NhW6Y
Email notifications, backup export/import, table filter + sort
For ccTLDs that rdap.org doesn't cover (e.g. .de), RDAP returns 404 — which the
WHOIS table previously misread as "available" for registered domains. Now:

- For such ccTLDs the table reports availability as *unknown* instead of falsely
  "available" (RDAP stays authoritative for gTLDs).
- Optional port-43 WHOIS fallback (WHOIS_PORT43="true", off by default) queries
  the registry over TCP (cloudflare:sockets) for the few mapped ccTLDs, parses
  registered/expires/updated/status, and detects "free" responses. It is
  time-boxed (5 s, with background socket close) so a blocked/non-responsive
  server can never stall the refresh — a hang found and fixed during testing.
  DENIC still never publishes registration/expiry; this mainly fills status +
  last-change, and many registries block datacenter IPs (then it yields nothing).

Verified: tsc; 35 unit tests (added parseWhoisText for gTLD + DENIC formats and
whoisServerFor); and end-to-end against `wrangler dev` — default keeps .de fast
and "unknown" (not "available"), and with the flag on the refresh returns in ~5s
(bounded by the timeout) instead of hanging.

https://claude.ai/code/session_01KH9YazP7LmiLgvbA3NhW6Y
Opt-in port-43 WHOIS fallback; fix .de false-"available"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants