Skip to content

feat(recover): stolen account recovery step 1#302

Open
ety001 wants to merge 12 commits into
nextfrom
feat/recover-account-step-1
Open

feat(recover): stolen account recovery step 1#302
ety001 wants to merge 12 commits into
nextfrom
feat/recover-account-step-1

Conversation

@ety001
Copy link
Copy Markdown
Member

@ety001 ety001 commented May 28, 2026

Summary

  • Add /recover_account_step_1 flow to start stolen account recovery.
  • Validate account + ensure owner key was changed recently.
  • Verify recent owner password/key against owner history.
  • Submit recovery request via email (shim endpoint for now).

Test plan

  • pnpm verify
  • Open /recover_account_step_1:
    • Enter account + recent owner password/key and proceed
    • Submit email and confirm success state

ety001 added 9 commits May 28, 2026 14:29
Port legacy step-1 UX: validate account, check owner history, then submit
recovery request email. Includes owner-history query API and recovery
request shim endpoint.
Add unit tests for owner-history + recovery request routes and client helpers to keep coverage threshold green.
- Add CSRF protection to /api/recovery/request route (verifyCSRF) and
  client (withCSRFHeader), matching legacy checkCSRF behavior
- Add CSRF fail test case in recover-request-route.test
- Remove unnecessary type assertion on last_owner_update (SteemAccount
  already has the field)
- Add es/zh translations for recoverAccountStep1Page namespace
- Add stale-check version counter in validateAccount to prevent
  onBlur race conditions
- Add console.info logging in recovery shim for debugging before
  backend is wired
- Add comment explaining JULY_14_HACK_MS (2016 Steem hack event)
- Define OwnerHistoryEntry type in types.ts; use it in server.ts,
  client.ts, and recover-account-step-1-page.tsx (replaces unknown[]
  and inline type assertions)
- Replace recovery shim with real DB persistence
- Add drizzle-orm, mysql2, and drizzle-kit
- Create schema src/lib/db/schema/index.ts (arecs table)
- Create connection module src/lib/db/index.ts with singleton pool
- Add drizzle.config.ts and migration files
- Update next.config.ts to externalize mysql2
- Add unit tests for recovery route with Drizzle mocks
- Remove stale recover-request-route.test.ts
…rmat

- Replace hardcoded timestamp in migration with CURRENT_TIMESTAMP /
  ON UPDATE CURRENT_TIMESTAMP so migration file is portable
- Add STM public key format validation (STM + 50+ base58 chars)
  in recovery request route
- Add test case for invalid owner_key format
- Update existing tests to use realistic-length public keys
- GET /api/recovery/verify/[code]: verify validation_code, return account_name
- POST /api/recovery/confirm: CSRF-protected, validates code + owner keys,
  updates arecs status to closed
- POST /api/broadcast/recover-account: server relay for signed recover_account tx
- RecoverAccountConfirmationPage: client-side component with old/new password form,
  owner history check, sign + broadcast flow
- SteemSigner.signRecoverAccount: derive owner keys, sign recover_account operation
- apiClient: add verifyRecoveryCode, confirmAccountRecovery, broadcastRecoverAccountTx
- i18n: en/es/zh translations for confirmation page
- Tests: 11 new test cases for verify and confirm routes (382 total passing)

Note: request_account_recovery (Conveyor step) is stubbed as TODO.
The client-side recover_account broadcast flow is complete.
- SteemService.requestAccountRecovery: call kingdom.recovery_account
  via steem.api.signedCallAsync (signed with conveyor account credentials)
- confirm route now calls requestAccountRecovery before updating arecs
- .env.example: add CONVEYOR_USERNAME and CONVEYOR_POSTING_WIF
- Test: mock SteemService.requestAccountRecovery in confirm route tests

Flow: confirm API -> kingdom.recovery_account -> arecs closed
      -> client signs recover_account locally -> server relay broadcasts
@ety001 ety001 force-pushed the feat/recover-account-step-1 branch from bd20c8e to c5f70c6 Compare May 28, 2026 16:27
ety001 added 3 commits May 29, 2026 00:33
P1.1: confirm route — atomic CAS update (confirmed→processing) prevents TOCTOU race
P1.2: confirmation page — useState→useEffect for mount-time side effect
P1.3: confirm route — processing state prevents kingdom/DB inconsistency
P2.1: broadcast route — validate operation body against DB record before relay
P2.2: verify route — add rate limiting (20 req/60s)
P2.3: request route — server-side email normalization (trim + lowercase)
P2.4: schema — add index on validation_code for verify/confirm lookups
P2.5: .env.example — add DATABASE_URL entry
P3.1: signRecoverAccount — correct return type from sync Promise to async
P3.2: owner_key regex — strict base58 character set (no 0/O/I/l)
P3.3: getDb() — retry on subsequent calls instead of permanent failure

Tests: 383/383 passing
S1: confirm route cross-validate old_owner_key vs DB ownerKey
S2: broadcast route reject null newOwnerKey
S3: request route account_name format validation + trim/lowercase
S4: signRecoverAccount add direct privateKey branch
C1: confirm route Step 3 WHERE clause add accountName
R2: request route account_name trim (merged into S3)
R3: docs document processing status cleanup requirement
T1: add broadcast/recover-account route tests (11 cases)
T2: add owner-history route tests (6 cases)
T3: steem-client-recover test verify request structure

403/403 tests passing
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.

1 participant