fix(user): stop double-encoding FrontendSettings on UpdateUser

UpdateUser was manually json.Marshal'ing user.FrontendSettings and
re-assigning the []byte back to the interface{} field before passing
the user to xorm. The column is declared:

  FrontendSettings interface{} `xorm:"json null" json:"-"`

xorm's `json` modifier already marshals the field on write. Pre-marshalling
to []byte and stuffing it back into the interface causes xorm to JSON-encode
a []byte (which serializes as a base64 string). The DB ends up storing
`"bnVsbA=="` (base64 of "null") for users whose FrontendSettings is nil,
or a double-encoded blob for users with real settings.

On read, xorm unmarshals that string back into the interface as a Go
`string`, and the API response then contains:

  "frontend_settings": "bnVsbA=="

instead of a JSON object or null. The Flutter mobile client
(go-vikunja/app) typed-casts `frontend_settings` to
`Map<String, dynamic>?` and crashes with:

  type 'String' is not a subtype of type 'Map<String, dynamic>?'

which the app surfaces as "could not connect to this server". The web
client tolerates it silently (JS spread over a string).

Trigger path: every OIDC login of an existing user calls UpdateUser
(pkg/modules/auth/openid/openid.go), so the row is corrupted on every
re-login. See go-vikunja/app#265.

Fix: let xorm handle the JSON marshalling as the struct tag advertises.
Drop the now-unused encoding/json import.
This commit is contained in:
Evan Baker 2026-05-25 10:02:21 -05:00
parent dab2ac473f
commit 94e1504e2b
1 changed files with 0 additions and 7 deletions

View File

@ -18,7 +18,6 @@ package user
import (
"context"
"encoding/json"
"errors"
"fmt"
"net/mail"
@ -633,12 +632,6 @@ func UpdateUser(s *xorm.Session, user *User, forceOverride bool) (updatedUser *U
return nil, &ErrInvalidTimezone{Name: user.Timezone, LoadError: err}
}
frontendSettingsJSON, err := json.Marshal(user.FrontendSettings)
if err != nil {
return nil, err
}
user.FrontendSettings = frontendSettingsJSON
// Update it
_, err = s.
ID(user.ID).