mirror of
https://github.com/PR0M3TH3AN/bitlogin.git
synced 2026-11-07 14:01:25 +00:00
Fix revoke-rebinds bug; correct the website's custody and revoke claims
The audit's most important finding was not a doc issue at all. In vaultSetBinding the identifier `origin` resolved to the WORKER GLOBAL self.origin rather than the intended value, so the dashboard's "Revoke app access" REBOUND the record to the calling page instead of clearing it -- the precise cross-origin adoption the binding guard exists to prevent, wearing the label of the button meant to prevent it. It typechecked because the DOM lib declares that global. I introduced this hours ago: a string replace intended for one call site silently matched two. Fixed, with the reasoning written where the next reader will hit it. Relay/account audit fixes: - Phrase recovery permanently tripped the rollback alarm. The mark is keyed by the everyday pubkey (unchanged by recovery) while recovery legitimately restarts at generation 0, and raiseHighWaterMark keeps the maximum -- so anyone who had ever rotated a password met "possibly revoked credentials" on EVERY later login, forever, with no way to clear it. The phrase is the master authority; it now resets the mark. - quorumMet counted TCP connections, not answers: a query timeout RESOLVED, so a connectable-but-silent relay counted as responding and every "not enough relays answered" guard was near-vacuous. Only EOSE is an answer now. - Relay responses were never checked against the address requested, so one junk event from one relay blocked registration, rotation, and recovery for every login name and password a user tried. Events must now match author, kind, and d-tag. Website honesty (the surface a stranger reads first, and the one that had drifted furthest from the spec): - docs.html and llms.txt still carried "private keys never leave the worker" -- false on its face, since the widget ships a reveal-nsec button. Both now state the same limit the README does. - "you revoke" became honest everywhere: removing a connection deletes the stored copy; spending authority is revoked at the wallet. - index.html dropped a pre-softening recovery claim, now says an account lives only while relays retain its capsule, and says "independently unaudited" out loud. - llms.txt gains the two warnings that were missing entirely: losing BOTH password and phrase is permanent, and removal is not revocation. - Stale headers: nwc-connections.md no longer claims "Not implemented", docs/README no longer says the authorization layer is unbuilt, the test count and spec version are current, and the demo domain points at bitlogin.network. Co-Authored-By: Claude Fable 5 <[email protected]> Claude-Session: https://claude.ai/code/session_01CMr9Yt8SYmZcfgrg3CV2G1
This commit is contained in:
1 parent
d040c2f5af
commit
efd994c4de
11 files changed
+129
-30
No files matched your search
@@ -333,7 +333,8 @@ async function handle(action: string, payload: unknown): Promise<unknown> {
|
||||
recovered: session.pendingRecovery,
|
||||
newLoginName: p.newLoginName,
|
||||
newPassword: p.newPassword,
|
||||
vaultRelayUrls
|
||||
vaultRelayUrls,
|
||||
store
|
||||
});
|
||||
session.activeCredentialEvent = result.credentialEvent;
|
||||
session.activeRecoveryEvent = result.refreshedRecoveryEvent;
|
||||
@@ -561,10 +562,21 @@ async function handle(action: string, payload: unknown): Promise<unknown> {
|
||||
}
|
||||
|
||||
case "vaultSetBinding": {
|
||||
// Two transitions only, and the difference is the whole feature:
|
||||
// origin === null is UNBIND (the dashboard's "Revoke app access"), and
|
||||
// anything else binds to THIS origin -- never a caller-named one, or a
|
||||
// host could adopt a wallet the user bound to another site.
|
||||
//
|
||||
// The bare identifier `origin` sat here and silently resolved to the
|
||||
// WORKER GLOBAL self.origin, so revoke rebound the record to the
|
||||
// calling page instead of clearing it -- the exact adoption this guard
|
||||
// exists to prevent, wearing the label of the button that prevents it.
|
||||
// It typechecked because the DOM lib declares that global.
|
||||
const p = payload as { connectionId: string; origin: string | null };
|
||||
const { vault, connection } = await findConnection(p.connectionId);
|
||||
const nextOrigin = p.origin === null ? null : selfOrigin();
|
||||
const { record, event } = await vault.updateConnection(connection, {
|
||||
application_binding: { origin, app_pubkey: null }
|
||||
application_binding: { origin: nextOrigin, app_pubkey: null }
|
||||
});
|
||||
const publish = await vault.publish({
|
||||
event,
|
||||
|
||||
Reference in new issue
Block a user