Skip to content

fix(ui-react): encode list filters as UTF-8 base64#6388

Merged
gustavosbarreto merged 1 commit into
masterfrom
fix/ui-react/utf-8-filter
May 29, 2026
Merged

fix(ui-react): encode list filters as UTF-8 base64#6388
gustavosbarreto merged 1 commit into
masterfrom
fix/ui-react/utf-8-filter

Conversation

@luizhf42
Copy link
Copy Markdown
Member

What

The filter encoder used on every list page (btoa(JSON.stringify(...))) throws InvalidCharacterError for any value containing characters above U+00FF, blocking searches and tag filters that include non-Latin-1 text. Replaced the inline encoder with a shared helper that goes through UTF-8 bytes first.

Why

Reproduced while stress-testing the Enterprise RC: filtering devices by a tag named 日本語タグ, or searching for a hostname containing Japanese characters, never sends the request — the browser throws at encode time and the UI looks broken even though the backend is fine. Affects every list page that builds a filter URL: namespace devices, admin devices, admin users, admin namespaces, public keys, containers, web endpoints, invitations.

Changes

  • utils/encoding.ts: new toBase64Json(value: unknown): string helper using Buffer.from(JSON.stringify(value), "utf-8").toString("base64"). Buffer is already polyfilled in the bundle via vite-plugin-node-polyfills and used elsewhere for byte-level work (ssh-keys.ts, TerminalInstance.tsx), so no new dependency surface.
  • 8 filter call sites: swapped btoa(JSON.stringify(x)) for toBase64Json(x). ASCII payloads serialize to the exact same bytes the old code produced, so the backend decoder (base64.StdEncoding.DecodeString then json.Unmarshal at pkg/api/query/filter.go:39) is unchanged.
  • Test coverage: ASCII round-trip pinned byte-for-byte against the legacy btoa output to lock in backward compatibility; Unicode round-trip guards the bug from regressing.

Testing

Reproducer needs non-Latin-1 data in the DB — any tag/device/namespace/user with characters above U+00FF.

  • Without the fix: dev tools shows InvalidCharacterError: Failed to execute 'btoa' on 'Window': The string to be encoded contains characters outside of the Latin1 range, and the request never leaves the browser.
  • With the fix: the list loads; the filter query param decodes (via atob then JSON.parse) to the expected clauses.
  • Regression check: existing ASCII filters produce the same network payload as before — toBase64Json(x) === btoa(JSON.stringify(x)) for ASCII input, locked by the unit test.

Pages to exercise: namespace devices, admin devices, admin users, admin namespaces, public keys, containers, web endpoints, invitations.

`btoa(JSON.stringify(...))` rejects characters above U+00FF, so any
filter value containing non-Latin-1 text (tag names, hostnames,
usernames, emails) throws `InvalidCharacterError` and the request
never goes out. Route filter encoding through a shared
`toBase64Json` helper that serializes via `Buffer.from(..., "utf-8")`.
ASCII payloads encode to the same bytes as before, so the backend
decode path (`base64.StdEncoding.DecodeString` then `json.Unmarshal`)
needs no change.
@luizhf42 luizhf42 requested a review from a team as a code owner May 29, 2026 14:50
@luizhf42 luizhf42 self-assigned this May 29, 2026
@luizhf42 luizhf42 added kind/bug Something isn't working area/ui javascript Pull requests that update Javascript code labels May 29, 2026
@github-actions
Copy link
Copy Markdown

github-actions Bot commented May 29, 2026

Claude finished @luizhf42's task in 15s —— View job


Code Review Complete

Reviewed 10 files across code quality, security, testing, language patterns, and architecture — no issues found. The code looks good as-is.

Highlights:

  • toBase64Json correctly handles UTF-8 by going through Buffer before base64, and the Buffer polyfill is already configured via vite-plugin-node-polyfills.
  • ASCII payloads produce byte-identical output to the old btoa path, confirmed by the unit test — no backend changes needed.
  • Go's base64.StdEncoding.DecodeStringjson.Unmarshal at pkg/api/query/filter.go natively handles UTF-8 JSON, so non-Latin-1 filter values will decode correctly server-side.
  • No cross-repo impact on cloud/ — the cloud filter code only consumes already-decoded filter structs.
  • Test coverage is solid: backward-compat pinning, Unicode round-trip, and stability for cache keys.

If you push additional changes and want a new review, tag @shellhub-io/admin and a team member can trigger it.

@gustavosbarreto gustavosbarreto merged commit 39ed6aa into master May 29, 2026
23 checks passed
@gustavosbarreto gustavosbarreto deleted the fix/ui-react/utf-8-filter branch May 29, 2026 17:15
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/ui javascript Pull requests that update Javascript code kind/bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants