Skip to content

Self-registration: +selfreg command + web/API endpoint with email verify #100

Description

@Aybook

Phase-8+ feature. Allow unregistered users (level 0) to self-register at level 20 (reg) without operator action. Two channels: in-hub command and web/API endpoint.

Why

Lowers the onboarding bottleneck for community hubs running reg_only = false. Today the only path is +reg via an operator (level 60+). For open hubs that's unnecessary friction.

Hard preconditions

  • reg_only = false (otherwise unregged can't connect at all to send +selfreg).
  • Default OFF: cfg flag selfreg_enabled = false so existing deployments are unchanged on upgrade.

Channels

A. Hub command +selfreg <password>

  • Available to level 0 (unreg) only; rejected for level >= 20.
  • Uses the connected user's already-claimed nick (the BINF nick).
  • Stores reg with level 20, marks email_verified = false until verify-link is clicked.
  • Reply: "Check <email> for the verification link, then reconnect."

B. REST endpoint POST /selfreg (depends on #82)

Email verification (mandatory, both channels)

New core/mail.lua (or plugin etc_mail.lua) wrapping LuaSocket SMTP:

  • cfg keys: mail_smtp_host, mail_smtp_port, mail_smtp_user, mail_smtp_pass, mail_from.
  • Verify token: 32 random bytes via adclib.random_bytes, base32 in URL.
  • Token stored in cfg/selfreg_pending.tbl (encrypted via cfg_secret, same Phase-7f channel as user.tbl).
  • Token TTL: cfg-tunable, default 1h.
  • Verify URL clicked -> sets email_verified = true, moves profile from pending to live _regusers.

Captcha (web channel only)

Pluggable: hCaptcha or reCAPTCHA via cfg-keyed site/secret. Hub-command path skips captcha (in-hub user is already past the per-IP connection cap from Phase 7c F-NET-1).

Per-IP rate limit (mandatory)

Sybil / squatting concerns

Audit logging (depends on #84)

Every self-reg attempt and outcome (success / verify-fail / rate-limit / squat-rejection) fires the audit event so operators can review onboarding patterns.

Sub-tasks (checklist)

  • Foundation: core/mail.lua SMTP wrapper + cfg keys + smoke test (loopback SMTP fake).
  • Foundation: encrypted selfreg_pending.tbl via cfg_secret.
  • Hub command +selfreg <password> (level-0 path).
  • Email verify token flow (URL click -> mark verified, promote to _regusers).
  • Per-IP rate-limit bucket via ratelimit v2: PM/INF/CTM/RCM coverage + per-userlevel limits #80.
  • Reserved-nicks cfg list with default sensible entries.
  • REST POST /selfreg endpoint (separate listener from Local HTTP API: read-only first, write-endpoints later #82).
  • Captcha integration (hCaptcha + reCAPTCHA cfg-pluggable).
  • Audit-log integration via Audit log for staff actions (core events + plugin writer) #84.
  • Invite-code mode (deferred to v2 of this feature; tracked here as checklist item but may split into its own issue when the rest lands).
  • Smoke harness: end-to-end test (+selfreg, capture verify URL from fake SMTP, click it, confirm reg promoted).
  • docs/SECURITY.md: threat-model section on self-reg + Sybil/squatting mitigations.

Out of scope for v1

  • OAuth / SSO / external identity providers.

Dependencies

Acceptance

  • +selfreg <password> rejects level >= 20, accepts level 0, sends verify mail.
  • Reconnect after verify succeeds at level 20 with the chosen password.
  • Without reg_only = false and selfreg_enabled = true, the command is unavailable.
  • REST endpoint passes captcha, sends mail, verify URL promotes profile.
  • Rate-limit kicks in after N attempts per IP per hour.
  • All Phase 7 invariants intact (user.tbl LDC1 magic, smoke 12+/12+ PASS).

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Fields

    No fields configured for Feature.

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions