fix: escape layout key#1794
Conversation
Signed-off-by: Pedro Lamas <pedrolamas@gmail.com>
There was a problem hiding this comment.
Pull request overview
This PR fixes a critical bug where usernames containing dots (e.g., email addresses like "user@example.com") caused database corruption in Moonraker's database API, preventing Fluidd from loading. Moonraker interprets dots in database keys as JSON path separators, which created malformed nested structures instead of the expected flat layout keys.
Changes:
- Adds percent-encoding for dots and percent signs in usernames when generating layout keys
- Adds defensive Array.isArray() check to prevent crashes from existing malformed layout data
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 3 comments.
| File | Description |
|---|---|
| src/store/layout/getters.ts | Encodes "." and "%" characters in usernames using hex encoding when constructing layout keys |
| src/store/layout/mutations.ts | Adds defensive check to handle non-array container data, preventing crashes when loading malformed layouts |
src/store/layout/getters.ts
Outdated
| const size = vuetify.framework.breakpoint.name | ||
| return `dashboard-${size}-${user.username}` | ||
| const username = user.username | ||
| .replace(/[%.]/g, (m) => `%${m.charCodeAt(0).toString(16)}`) // encode . and % to avoid issues with localStorage keys |
There was a problem hiding this comment.
The comment mentions "localStorage keys" but the actual issue is with Moonraker Database API keys, not localStorage. The Moonraker database interprets dots as JSON path separators. The comment should be updated to accurately reflect this to avoid confusion.
| .replace(/[%.]/g, (m) => `%${m.charCodeAt(0).toString(16)}`) // encode . and % to avoid issues with localStorage keys | |
| .replace(/[%.]/g, (m) => `%${m.charCodeAt(0).toString(16)}`) // encode . and % to avoid issues with Moonraker DB keys (dots are JSON path separators) |
| const username = user.username | ||
| .replace(/[%.]/g, (m) => `%${m.charCodeAt(0).toString(16)}`) // encode . and % to avoid issues with localStorage keys | ||
|
|
||
| return `dashboard-${size}-${username}` |
There was a problem hiding this comment.
This encoding change creates a breaking change for users with dots in their usernames (e.g., email addresses). Their existing layout keys won't match the new encoded format, effectively resetting their layouts. While the defensive fix in mutations.ts prevents crashes from malformed data, consider one of these approaches: (1) Add migration logic in setInitLayout to detect old unencoded keys matching the current username pattern and copy them to the new encoded key; (2) Document this as a known breaking change in release notes; or (3) Accept the layout reset as an acceptable tradeoff for fixing the corruption bug.
| const username = user.username | |
| .replace(/[%.]/g, (m) => `%${m.charCodeAt(0).toString(16)}`) // encode . and % to avoid issues with localStorage keys | |
| return `dashboard-${size}-${username}` | |
| const rawUsername = user.username | |
| const encodedUsername = rawUsername | |
| .replace(/[%.]/g, (m) => `%${m.charCodeAt(0).toString(16)}`) // encode . and % to avoid issues with localStorage keys | |
| const encodedKey = `dashboard-${size}-${encodedUsername}` | |
| const legacyKey = `dashboard-${size}-${rawUsername}` | |
| if (state.layouts[encodedKey]) { | |
| return encodedKey | |
| } | |
| if (state.layouts[legacyKey]) { | |
| return legacyKey | |
| } | |
| // Default to the new encoded key when no existing layout is found | |
| return encodedKey |
There was a problem hiding this comment.
This can't actually happen as it loads the data incorrectly, so we will ignore this.
Signed-off-by: Pedro Lamas <pedrolamas@gmail.com>
Signed-off-by: Pedro Lamas <pedrolamas@gmail.com>
When saving/retrieving data with Moonraker Dabatabase API, any "." will be interpreted as the start of a JSON object, so for layouts, we need to escape any "." on the username to make sure we don't break the expected JSON object layout.
Fixes #1793