实现账号绑定、持久登录与跨设备对局恢复
CI / test (ubuntu-latest, node 22) (push) Failing after 33m10s
CI / test (ubuntu-latest, node 24) (push) Failing after 34m41s
CI / tooling (lint, imports, typecheck) (push) Failing after 36m11s
CI / test (windows-latest, node 22) (push) Canceled after 0s
CI / test (windows-latest, node 24) (push) Canceled after 0s
CI / test (ubuntu-latest, node 22) (push) Failing after 33m10s
CI / test (ubuntu-latest, node 24) (push) Failing after 34m41s
CI / tooling (lint, imports, typecheck) (push) Failing after 36m11s
CI / test (windows-latest, node 22) (push) Canceled after 0s
CI / test (windows-latest, node 24) (push) Canceled after 0s
This commit is contained in:
1 parent
488db49f11
commit
7c25c89992
62 files changed
+6855
-1005
No files matched your search
@@ -341,3 +341,68 @@ every vertex on a slab tile at its top or its foot; 战场#03 and #05(上半) ha
|
||||
`test/render/board3d-scene.test.js` (an official scene on 战场#03 keeps the slabs in the board material and nothing else of
|
||||
the procedural board; dropping the scene restores the board; act2 m02 adds no slab mesh). Screenshots of the five
|
||||
affected stages before / after / metal board were compared by hand. Golden: unchanged (client only).
|
||||
|
||||
### 31.12 Account binding before entry (fork integration, 2026-10-14)
|
||||
|
||||
Owner request: integrate the working account module at 博士代号, automatically use the bound role's nickname, retain
|
||||
Skland QR for official/Bilibili channels, and keep later upstream merges small. The callsign label and nickname are
|
||||
hidden until binding, then shown as plain text without an input; 绑定账号
|
||||
replaces 开始 until a named role is obtained, and returns after unbinding or an empty role list. Boot and local-match
|
||||
recovery recheck the binding before accepting a cached entry. The dialog, styles, entry policy and session resolver
|
||||
live in the module's own directories, with small title/boot/recovery hooks. Game-entry requests use the
|
||||
existing reconnect token and a reserved namespace; the independent diagnostic routes require an administrator key
|
||||
and cannot read or mutate these rows. No new WebSocket messages or simulation rules. Multiple roles select the default, retain a
|
||||
still-valid choice on refresh/reopen, and immediately update the callsign when switched. No manual callsign entry.
|
||||
The official account-page icons are referenced remotely; authorization redirects remain provider-operated.
|
||||
The nickname retains its person icon. Opening the scan tab automatically fetches a QR: replacement is every 10 s,
|
||||
switching to 60 s from the first status 101 (waiting for phone confirmation), with manual refresh retained. Refresh
|
||||
keeps the old QR visible until the new image is encoded, then replaces its source in place without a blank frame. Requests
|
||||
are serial and check confirmation before replacement; switching tabs or hiding the page pauses timers, and closing
|
||||
the dialog or binding stops them. The provider's 101 is exposed as `awaitingConfirmation` without changing `waiting`.
|
||||
|
||||
Persistent login uses a 30-day HS256 JWT in an HttpOnly, SameSite=Strict cookie (Secure over HTTPS), with signing
|
||||
key and revocable login/role records in the same SQLite database. New tabs and restarted servers restore the
|
||||
selected role without another provider login. The JWT contains no provider credentials. Account APIs derive
|
||||
ownership on the server, reject cross-site requests and foreign role selection, and default-close diagnostic access.
|
||||
The optional WebSocket account policy resolves hello and every room/game request to the owned role; a copied game
|
||||
reconnect token alone cannot claim it. UID plus server region determines stable game identity, allowing duplicate
|
||||
nicknames; optional `gameId` and name changes do not change that identity. Unbind clears credentials and revokes
|
||||
old JWTs/open-socket authority; late provider replies cannot restore a cancelled binding. Static/media/pack paths
|
||||
deny the configured database and its WAL/SHM files, including aliases and Windows casing. These changes follow the
|
||||
owner's explicit persistence/access-control request; rooms/matches remain memory-only.
|
||||
|
||||
Reference: [skland.md](../skland.md). Tests cover token rejection/player isolation, nickname selection, authenticated
|
||||
requests and the real title/modal in a browser with a stub account provider (QR, SMS and password/CAPTCHA continuation,
|
||||
landscape-phone layout, hidden/plain-text callsign with person icon, empty roles, unbinding, fresh-tab JWT restoration
|
||||
and cached-entry checks). Server tests cover forged JWT/claims, foreign roles, logout/replay, restart/expiry,
|
||||
protected database files, cancelled provider replies and same-name/different-UID/region identities.
|
||||
Deterministic timer tests cover automatic QR generation, exact 10/60 s boundaries, pause/resume, late responses,
|
||||
manual refresh versus confirmation and retry after failure. Golden: unchanged
|
||||
(no simulation changes).
|
||||
|
||||
### 31.13 Account-scoped cross-device recovery (fork integration, 2026-10-14)
|
||||
|
||||
Owner request: continue implementing recovery with the account across devices. The title now offers 恢复账号对局
|
||||
from authenticated server state, replacing the visible local-token recovery shortcuts. A device with no local save
|
||||
can sign in independently, select the same UID + provider region, inspect its retained seat and continue it. Login,
|
||||
cookie restoration and lookup alone do not disconnect another device; Start or recovery confirmation explicitly
|
||||
obtains the role's reconnect token. Only a successful welcome enters the UI, rotates the token and replaces the old
|
||||
socket. Old-device reloads and duplicated tabs cannot silently take the role back; the connection banner can still
|
||||
explicitly continue through checked account entry, and anonymous welcomes return to the title. The UI handles empty, loading,
|
||||
stale/error and refresh states and warns about taking over a live connection.
|
||||
|
||||
The server checks both credentials and the selected role, never a supplied player/name/UID/region. Public account
|
||||
ids encode 128 digest bits as base64url after a_ (24 characters): the previous full hexadecimal digest exceeded
|
||||
player-id and normal-field limits, rejecting watch/kick/battle-result messages. No wire limit needs to change. Recovery selectors
|
||||
belong to a particular room/match; stale or foreign selectors fail without minting a fresh game. Looking up a seat
|
||||
does not extend its lifetime. The normal lobby cleanup runs before an expired stable role id is reused, preventing
|
||||
an orphaned old match. The same Match/PlayerState is resumed, including funds, shop and lineup; no simulation rule,
|
||||
protocol message or generated data changes. Solo 24-hour/co-op 10-minute disconnect windows and waiting-room grace
|
||||
are unchanged. Matches remain memory-only: this is not save recovery after a server restart, nor synchronization of
|
||||
local preferences/statistics. These are owner-requested account policies, not deviations from official gameplay.
|
||||
|
||||
Normative updates: design/network.md §8 and its recovery note, design/client.md required-account entry, META.md §1.3;
|
||||
references: skland.md §5 and ARCHITECTURE.md / DEPLOY.md. Tests: test/skland/recovery.test.js exercises actual Match
|
||||
objects through independent HTTP/WS clients; test/skland/recovery.browser.test.js runs two isolated browser contexts
|
||||
with a stub provider, plus old-device and duplicated-tab checks and desktop/phone layout. Existing account, local
|
||||
identity, i18n and docs checks are rerun. Golden moves: none (no match/sim rules changed).
|
||||
Reference in new issue
Block a user