This repository has been archived on 2026-04-03. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
core/README.md
2026-02-28 21:55:13 +00:00

104 lines
3.4 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Hotfix Patches — v0.18.1 → v0.18.2
Priority order: apply top-to-bottom. All patches are independent
except 1 and 2 which must be applied together.
---
## Patch 1+2: Harden JSON scanning + SafeJSON (P0 — fixes broken chat list)
**Root cause:** Corrupt `\x02` byte in a channel's `settings` column.
`scanJSON` accepts it, Gin's `c.JSON()` starts writing 200 + headers,
`json.RawMessage.MarshalJSON()` hits the bad byte, aborts, browser
gets truncated body → "Unexpected end of JSON input" → 0 chats loaded.
**Files:**
1. **NEW:** `server/handlers/safe_json.go`
Copy `patches/server/handlers/safe_json.go` into your tree.
Contains: `SafeJSON()`, hardened `scanJSON()`, hardened `scanTags()`.
2. **NEW:** `server/handlers/safe_json_test.go`
Copy `patches/server/handlers/safe_json_test.go` into your tree.
3. **EDIT:** `server/handlers/channels.go`
Apply these three changes (or diff against `patches/server/handlers/channels.go`):
a. Remove the old `scanJSON` + `jsonScanner` + `scanTags` + `tagsScanner`
definitions (~lines 101155). Replace with a comment:
```go
// scanJSON, scanTags, SafeJSON → safe_json.go
```
b. Replace `c.JSON(http.StatusOK, paginatedResponse{` in ListChannels
with `SafeJSON(c, http.StatusOK, paginatedResponse{`
c. Replace `c.JSON(http.StatusCreated, ch)` at end of CreateChannel
with `SafeJSON(c, http.StatusCreated, ch)`
d. Replace `c.JSON(http.StatusOK, ch)` at end of GetChannel
with `SafeJSON(c, http.StatusOK, ch)`
**Verify:** `go build ./...` and `go test ./server/handlers/ -run TestScanJSON -v`
**Data fix:** Find and repair the corrupt row:
```sql
-- Find it
SELECT id, title, length(settings::text),
encode(substring(settings::bytea, 1, 20), 'hex') AS hex_preview
FROM channels
WHERE settings IS NOT NULL
AND settings::text ~ '[^\x20-\x7E\t\n\r]';
-- Fix it (reset to empty settings)
UPDATE channels SET settings = '{}'
WHERE settings IS NOT NULL
AND settings::text ~ '[^\x20-\x7E\t\n\r]';
```
---
## Patch 3: Service Worker scheme guard (P1 — console noise)
**Root cause:** SW fetch handler tries to cache `chrome-extension://`
URLs. `Cache.put()` rejects non-http(s) schemes.
**File:** `src/sw.js`
Add scheme guard after `const url = new URL(event.request.url);`:
```js
// Only handle http/https — ignore chrome-extension://, moz-extension://, etc.
if (url.protocol !== 'https:' && url.protocol !== 'http:') {
return;
}
```
Or copy `patches/src/sw.js`.
---
## Patch 4: Settings debounce (P2 — cosmetic waste)
Not included as a patch file — straightforward to implement:
- In `app.js` init sequence, debounce `API.updateSettings()` calls
- A 100ms `setTimeout` wrapper that coalesces multiple rapid saves
---
## Future work (not in this hotfix)
- Apply `SafeJSON` to extension list endpoints (lines 47, 115 of
extensions.go) — same vulnerability pattern, lower risk since
extension data is seeded from known-good JSON.
- Harden `JSONMap.Scan` in `models/models.go` to warn-and-default
instead of returning error. Currently it fails the whole query
which gives a clean 500, but it means one corrupt row blocks all
results in a list query.
- Startup JSON integrity check (design doc §17.1 Layer 4) — scan
all JSONB columns on boot, log warnings for corrupt data. Not
blocking for hotfix but valuable for post-upgrade diagnostics.
- JWT redaction in Gin log formatter for WebSocket URLs.