Skip to content

fix: escape layout key#1794

Merged
pedrolamas merged 3 commits intofluidd-core:developfrom
pedrolamas:pedrolamas/fix-1793
Feb 19, 2026
Merged

fix: escape layout key#1794
pedrolamas merged 3 commits intofluidd-core:developfrom
pedrolamas:pedrolamas/fix-1793

Conversation

@pedrolamas
Copy link
Member

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

Signed-off-by: Pedro Lamas <pedrolamas@gmail.com>
@pedrolamas pedrolamas added this to the 1.36.3 milestone Feb 19, 2026
@pedrolamas pedrolamas requested a review from Copilot February 19, 2026 17:50
@pedrolamas pedrolamas added the GH - Bug Something isn't working label Feb 19, 2026
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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

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
Copy link

Copilot AI Feb 19, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Suggested change
.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)

Copilot uses AI. Check for mistakes.
Comment on lines +75 to +78
const username = user.username
.replace(/[%.]/g, (m) => `%${m.charCodeAt(0).toString(16)}`) // encode . and % to avoid issues with localStorage keys

return `dashboard-${size}-${username}`
Copy link

Copilot AI Feb 19, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Suggested change
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

Copilot uses AI. Check for mistakes.
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This can't actually happen as it loads the data incorrectly, so we will ignore this.

Signed-off-by: Pedro Lamas <pedrolamas@gmail.com>
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated no new comments.

Signed-off-by: Pedro Lamas <pedrolamas@gmail.com>
@pedrolamas pedrolamas merged commit 2e0aba0 into fluidd-core:develop Feb 19, 2026
4 checks passed
@pedrolamas pedrolamas deleted the pedrolamas/fix-1793 branch February 19, 2026 18:37
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

GH - Bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Startup hang caused by malformed layout key for email username

2 participants