mozilla / pontoon

Mozilla's Localization Platform

Home Page:https://pontoon.mozilla.org

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Cannot switch theme in Pontoon

MikkCZ opened this issue · comments

STR:

  1. Sign in to https://pontoon.mozilla.org/.
  2. Click the user avatar in top right corner.
  3. Under Choose appearance, click either Light or System.

Expected behavior:

  • Pontoon theme changes to the selected one.

Actual behavior:

  • A red error message briefly shows up with the following text {"status": false, "message": "Bad Request: Invalid theme"}, which is the response body of the POST https://pontoon.mozilla.org/api/v1/user/{some ID}/theme/ HTTP call.

obrazek

NOTE 1: The message shows really brifly, so it took me a while to take the screenshot successfully. Although I understand it disappear rather quickly because it hides actionable parts of the UI, it's still quite fast to be able to read it.

NOTE 2: The error message in the UI should be something human readable, not a JSON.

Thanks for filing, @MikkCZ!

I haven't reproduced the issue yet, so I wonder if you could inspect that POST request in the Network tab of your developer tools. Specifically, it'd be interested to see what value is sent for the key "theme".

I tried in Firefox and Chromium, to make sure it's not something in the browser, but with same outcome. Here is HAR info of the request from my Firefox. I redacted the cookies and CSRF token values, and some other staff that look potentially sensitive:

{
  "log": {
    "version": "1.2",
    "creator": {
      "name": "Firefox",
      "version": "122.0a1"
    },
    "browser": {
      "name": "Firefox",
      "version": "122.0a1"
    },
    "pages": [
      {
        "id": "page_1",
        "pageTimings": {
          "onContentLoad": -7985,
          "onLoad": -7638
        },
        "startedDateTime": "2023-12-03T14:19:36.144+01:00",
        "title": "https://pontoon.mozilla.org/cs/"
      }
    ],
    "entries": [
      {
        "startedDateTime": "2023-12-03T14:19:36.144+01:00",
        "request": {
          "bodySize": 96,
          "method": "POST",
          "url": "https://pontoon.mozilla.org/api/v1/user/jao8P-BzvE8uOS19Fx_iI89m8B8/theme/",
          "httpVersion": "HTTP/1.1",
          "headers": [
            {
              "name": "Host",
              "value": "pontoon.mozilla.org"
            },
            {
              "name": "User-Agent",
              "value": "Mozilla/5.0 (X11; Linux x86_64; rv:122.0) Gecko/20100101 Firefox/122.0"
            },
            {
              "name": "Accept",
              "value": "*/*"
            },
            {
              "name": "Accept-Language",
              "value": "cs,sk;q=0.8,en-US;q=0.5,en;q=0.3"
            },
            {
              "name": "Accept-Encoding",
              "value": "gzip, deflate, br"
            },
            {
              "name": "Referer",
              "value": "https://pontoon.mozilla.org/cs/"
            },
            {
              "name": "Content-Type",
              "value": "application/x-www-form-urlencoded; charset=UTF-8"
            },
            {
              "name": "X-Requested-With",
              "value": "XMLHttpRequest"
            },
            {
              "name": "Content-Length",
              "value": "96"
            },
            {
              "name": "Origin",
              "value": "https://pontoon.mozilla.org"
            },
            {
              "name": "DNT",
              "value": "1"
            },
            {
              "name": "Sec-GPC",
              "value": "1"
            },
            {
              "name": "Connection",
              "value": "keep-alive"
            },
            {
              "name": "Cookie",
              "value": "<REDACTED>"
            },
            {
              "name": "Sec-Fetch-Dest",
              "value": "empty"
            },
            {
              "name": "Sec-Fetch-Mode",
              "value": "cors"
            },
            {
              "name": "Sec-Fetch-Site",
              "value": "same-origin"
            },
            {
              "name": "Pragma",
              "value": "no-cache"
            },
            {
              "name": "Cache-Control",
              "value": "no-cache"
            }
          ],
          "cookies": [
            "<REDACTED>"
          ],
          "queryString": [],
          "headersSize": 915,
          "postData": {
            "mimeType": "application/x-www-form-urlencoded",
            "params": [
              {
                "name": "csrfmiddlewaretoken",
                "value": "<REDACTED>"
              },
              {
                "name": "theme",
                "value": "light"
              }
            ],
            "text": "csrfmiddlewaretoken=<REDACTED>&theme=light"
          }
        },
        "response": {
          "status": 400,
          "statusText": "Bad Request",
          "httpVersion": "HTTP/1.1",
          "headers": [
            {
              "name": "Report-To",
              "value": "<REDACTED>"
            },
            {
              "name": "Reporting-Endpoints",
              "value": "<REDACTED>"
            },
            {
              "name": "Nel",
              "value": "{\"report_to\":\"heroku-nel\",\"max_age\":3600,\"success_fraction\":0.005,\"failure_fraction\":0.05,\"response_headers\":[\"Via\"]}"
            },
            {
              "name": "Connection",
              "value": "keep-alive"
            },
            {
              "name": "Server",
              "value": "gunicorn/19.9.0"
            },
            {
              "name": "Date",
              "value": "Sun, 03 Dec 2023 13:19:36 GMT"
            },
            {
              "name": "Content-Type",
              "value": "application/json"
            },
            {
              "name": "Content-Security-Policy",
              "value": "font-src 'self'; script-src 'self' 'unsafe-eval' 'sha256-fDsgbzHC0sNuBdM4W91nXVccgFLwIDkl197QEca/Cl4=' 'sha256-G5/M3dBlZdlvno5Cibw42fbeLr2PTEGd1M909Z7vPZE=' https://www.google-analytics.com/analytics.js; img-src 'self' https: data: https://*.wp.com/pontoon.mozilla.org/ https://www.google-analytics.com https://www.gravatar.com/avatar/; frame-src https:; worker-src https:; default-src 'none'; connect-src 'self' https://bugzilla.mozilla.org/rest/bug; style-src 'self' 'unsafe-inline'"
            },
            {
              "name": "X-Frame-Options",
              "value": "DENY"
            },
            {
              "name": "Vary",
              "value": "Cookie"
            },
            {
              "name": "Content-Length",
              "value": "58"
            },
            {
              "name": "X-Content-Type-Options",
              "value": "nosniff"
            },
            {
              "name": "X-Xss-Protection",
              "value": "1; mode=block"
            },
            {
              "name": "Referrer-Policy",
              "value": "same-origin"
            },
            {
              "name": "Strict-Transport-Security",
              "value": "max-age=31536000"
            },
            {
              "name": "Via",
              "value": "1.1 vegur"
            }
          ],
          "cookies": [],
          "content": {
            "mimeType": "application/json",
            "size": 58,
            "text": "{\"status\": false, \"message\": \"Bad Request: Invalid theme\"}"
          },
          "redirectURL": "",
          "headersSize": 1376,
          "bodySize": 1434
        },
        "cache": {},
        "timings": {
          "blocked": 0,
          "dns": 0,
          "connect": 0,
          "ssl": 0,
          "send": 0,
          "wait": 152,
          "receive": 0
        },
        "time": 152,
        "_securityState": "secure",
        "serverIPAddress": "52.202.168.65",
        "connection": "443",
        "pageref": "page_1"
      }
    ]
  }
}

The theme value is either light or system, depending on which button I click.

What I noticed now though is that the CSRF token included in that POST request is then used before in a previous POST to https://pontoon.mozilla.org/log-ux-action/ (action type Render:+Unread+notifications+icon).

So although the error says the problem is the theme value, it might actually be the CSRF token?

Thanks for digging into it! I'm still unable to reproduce the problem and we have about 100 users that are currently using the light theme or the system theme, so they must have been able to switch.

I was also able to change the theme for you via Django admin (I changed it back to the default value).

Are you able to change the theme in the translate view?

Would you be willing to review #3042?

Looking at the differences with my own request, there are some additional fields in Michal's query

{
    "name": "Sec-GPC",
    "value": "1"
}

{
    "name": "Pragma",
    "value": "no-cache"
}

{
    "name": "Cache-Control",
    "value": "no-cache"
}

Not sure how useful this can be.

EDIT: tried enabling privacy.globalprivacycontrol.enabled in Nightly to get the Sec-GPC header, but the theme switcher still works fine.

It works for me now. Not sure what you did, @mathjazz. Could have been my profile was somehow "dirty" and it was not possible to load and save it, not related to the theme value?

Well, I can still reproduce in staging. I did so now.

In staging there is still the version that returns the error in the JSON response. I get

{
  "status": false,
  "message": "User profile validation error: {'visibility_email': [\"Value 'Logged in users' is not a valid choice.\"]}"
}

My settings page https://mozilla-pontoon-staging.herokuapp.com/settings/ corresponds with that - the preference is not loaded correctly.

obrazek

We renamed the "Logged in users" visibility_email value to "Logged-in users":
d8696c9#diff-4ebc5e9888b2962aecd470dd76f7d410b4e246f2d8323df57ed7dd0c8d5e3adeL1678

But we didn't add a data migration to migrate users with the old value to the new one.

I'll add it to #3042.

Sounds like it should have been an enum-like value that is decoupled between database, code, API and the UI. ;)

Anyway, this issue is fixed now, at least for me. Feel free to close it when you deem fit.

Yeah, the actual value (that gets stored) and the human-readable value are the same, which isn't ideal, as proven here. :)

Thank you for debugging, that error message on stage was the key.

I'll close the bug when we merge the PR. There are 27 other users with broken profiles, still. :)