fix(7686): username 'false' / 'malformed color: false' for legacy settings.json#7688
Conversation
Settings.json files generated before December 2021 used `false` as the default for these two string options (commit 8c857a8 switched the template default to `null` and noted "this change has no effect due to a bug in how pad options are processed; that bug will be fixed in a future commit" — the follow-up never landed). pad.ts:getParams() then runs `false.toString()`, the resulting string "false" passes the `!== false` sentinel check at _afterHandshake, and notifyChangeName ships USERINFO_UPDATE with name="false" and colorId="false" (clobbered via clientVars.userColor). The server's hex regex rejects the colour and throws `malformed color: false`; the user sees their name as "false" and a white swatch. Defense in depth: - Server: Settings.ts::reloadSettings() coerces legacy boolean false to null for padOptions.userName / padOptions.userColor and warns the operator, matching the existing disableIPlogging shim pattern. - Client: the pad.ts userName / userColor callbacks reject the literal "false" string so URL params (?userName=false) and any other path that surfaces the sentinel as a string are also no-ops. - Backend regression test mirrors the shim and asserts it normalizes legacy false, leaves explicit values intact, leaves null untouched, does not coerce other padOptions keys, and does not coerce the string "false" (that path is the client guard's responsibility). Closes ether#7686 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
ⓘ You've reached your Qodo monthly free-tier limit. Reviews pause until next month — upgrade your plan to continue now, or link your paid account if you already have one. |
Review Summary by QodoFix legacy padOptions boolean false breaking user info updates
WalkthroughsDescription• Fix legacy padOptions.userName/userColor=false coercion to string "false" • Server-side shim normalizes boolean false to null in Settings.ts • Client-side guard rejects literal "false" string in pad.ts callbacks • Comprehensive regression test ensures legacy defaults are properly handled Diagramflowchart LR
A["Legacy settings.json<br/>userName/userColor=false"] -->|"getParams() coerces<br/>to string"| B["String 'false'<br/>propagates"]
B -->|"Fails sentinel check<br/>!== false"| C["USERINFO_UPDATE<br/>with name='false'"]
C -->|"Hex regex rejects"| D["Error: malformed color"]
E["Server shim:<br/>false → null"] -->|"Normalizes at boundary"| F["Downstream sees<br/>sentinel null"]
G["Client guard:<br/>rejects 'false' string"] -->|"URL params no-op"| F
F -->|"Prevents propagation"| H["Bug fixed"]
File Changes1. src/node/utils/Settings.ts
|
Code Review by Qodo
1.
|
Qodo flagged that storeSettings() will overwrite settings.padOptions raw with whatever settings.json supplies — including null, primitives, or arrays — which would make the new userName/userColor shim crash on property access. Add a shape guard so the shim is a no-op for malformed padOptions, and extend the regression test to cover null / primitive / array shapes. This doesn't change which configs work (Pad.ts also assumes padOptions is an object and would already crash on a null padOptions when a pad is opened) but it stops the shim from being the loud thing in the stack trace if someone hits it. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
@qodo-free-for-open-source-projects re: padOptions shim crash — Verified. Fixed in 2f875af: added a shape guard ( |
Summary
Closes #7686.
Settings.json files generated before December 2021 still ship
"userName": false/"userColor": falseforpadOptions. These two options are documented as strings, so the boolean was always meaningless — commit 8c857a85a switched the template default tonulland explicitly warned: "this change has no effect due to a bug in how pad options are processed; that bug will be fixed in a future commit." The follow-up never landed.The cascade:
clientVars.padOptions.userName === false(legacy) reachespad.ts:getParams().if (serverValue == null) continue;—false != null, doesn't skip.serverValue = serverValue.toString();→"false".settings.globalUserName = "false",clientVars.userColor = "false".pad.myUserInfo.colorId = clientVars.userColor→"false".if (settings.globalUserName !== false)→"false" !== falseistrue→notifyChangeName("false")ships USERINFO_UPDATE withname="false",colorId="false".Error: COLLABROOM: USERINFO_UPDATE: malformed color: false.The user sees their name as
falseand a white swatch.Fix (defense in depth)
Settings.ts::reloadSettings()coercespadOptions.userName === falseandpadOptions.userColor === falsetonulland warns once, matching the existingdisableIPloggingshim pattern.pad.tsuserName/userColorcallbacks reject empty / literal"false"so URL params like?userName=falseare also a no-op.tests/backend/specs/padOptionsLegacyDefaults.tsmirrors the shim and asserts it normalizes the legacy boolean, leaves explicit string/null values intact, doesn't touchshowChat: false/rtl: false/etc., and does not coerce the string"false"(that's the client guard's job).Test plan
pnpm exec tsc --noEmit— cleanpnpm exec mocha tests/backend/specs/padOptionsLegacyDefaults.ts— 8 passingpnpm exec mocha tests/backend/specs/settings.ts tests/backend/specs/ipLoggingSetting.ts tests/backend/specs/padOptionsLegacyDefaults.ts— 48 passing🤖 Generated with Claude Code