marius-wieschollek / passwords-webextension

The official browser extension for the Passwords app for Nextcloud.
GNU General Public License v3.0
109 stars 34 forks source link

[BUG]: Frequent Logout on Chrome Extension - "Too Many Requests" error #292

Open Be-Mann opened 3 weeks ago

Be-Mann commented 3 weeks ago

⚠️ This issue respects the following points: ⚠️

Server Information

Server1:
{
    "version": {
        "server": "30.0.1.2",
        "app": "2024.9.20",
        "lsr": false,
        "php": "8.3.12",
        "cronPhp": "8.3.13"
    },
    "environment": {
        "os": "Linux",
        "architecture": "x86_64",
        "bits": 64,
        "database": "mysql",
        "cron": "cron",
        "proxy": false,
        "sslProxy": true,
        "subdirectory": false
    },
    "services": {
        "images": "imagick",
        "favicons": "bi",
        "previews": "pageres",
        "security": "hibp",
        "words": "leipzig",
        "previewApi": false,
        "faviconApi": false
    },
    "status": {
        "autoBackupRestored": false
    },
    "settings": {
        "channel": "stable",
        "nightlies": false,
        "handbook": false,
        "performance": 5
    },
    "encryption": {
        "sse": {
            "SSEv1r1": false,
            "SSEv1r2": true,
            "SSEv2r1": true,
            "SSEv3r1": false,
            "none": true,
            "default": "none"
        },
        "cse": {
            "CSEv1r1": true,
            "none": true,
            "default": "CSEv1r1"
        }
    }
}

Server2:
{
    "version": {
        "server": "30.0.1.2",
        "app": "2024.9.20",
        "lsr": false,
        "php": "8.2.25",
        "cronPhp": "8.2.25"
    },
    "environment": {
        "os": "Linux",
        "architecture": "x86_64",
        "bits": 64,
        "database": "mysql",
        "cron": "cron",
        "proxy": false,
        "sslProxy": true,
        "subdirectory": false
    },
    "services": {
        "images": "imagick",
        "favicons": "bi",
        "previews": "ssl",
        "security": "hibp",
        "words": "auto",
        "previewApi": true,
        "faviconApi": false
    },
    "status": {
        "autoBackupRestored": false
    },
    "settings": {
        "channel": "stable",
        "nightlies": false,
        "handbook": false,
        "performance": 5
    },
    "encryption": {
        "sse": {
            "SSEv1r1": false,
            "SSEv1r2": true,
            "SSEv2r1": true,
            "SSEv3r1": false,
            "none": true,
            "default": "SSEv2r1"
        },
        "cse": {
            "CSEv1r1": true,
            "none": true,
            "default": "CSEv1r1"
        }
    }
}

Client Information

Browser and Version: Chrome 130.0.0.0 Client OS and Version: Windows 10 Pro 64bit, Version 19045.5073

Bug description

Recently I have been frequently logged out of the Password Manager extension (on both servers), sometimes immediately after logging in and sometimes only after 30 seconds or so. I am connected to two servers, one of which is connected via VPN.

The extension log shows "Too Many Requests" as an error message. Addendum: And it sometimes shows "Error: Could not establish connection" to one server.

But basically I am always logged out of both instead of just one.

Steps to reproduce

Open the Password Manager Chrome Extension. Log in to the account. Perform any action (e.g., access a stored password). After a short while (sometimes immediately), I am logged out, and the message "Too Many Requests" or "Error: Could not establish connection" appears in the log.

Expected behavior

I should stay logged in to the extension after logging in, without unexpected logout due to "Too many requests" or "Could not connect", (especially if it's only on a short timeout (1-2 seconds by vpn) and the connection is back afterwards.

Nextcloud Logs

[
  {
    "reqId": "UFj2OMQgaDu6PpJPrMpS",
    "level": 3,
    "time": "31.10.2024 18:47:59",
    "remoteAddr": "192.168.190.20",
    "user": "xxxx@xxxxxx.de",
    "app": "passwords",
    "method": "POST",
    "url": "/index.php/apps/passwords/api/1.0/session/open",
    "message": "Error \"Passphrase invalid\" in OCA\\Passwords\\Controller\\Api\\SessionApiController::open",
    "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36 OPR/114.0.0.0",
    "version": "30.0.1.2",
    "data": {
      "app": "passwords"
    }
  },
  {
    "reqId": "UFj2OMQgaDu6PpJPrMpS",
    "level": 4,
    "time": "31.10.2024 18:47:59",
    "remoteAddr": "192.168.190.20",
    "user": "xxxx@xxxxxx.de",
    "app": "passwords",
    "method": "POST",
    "url": "/index.php/apps/passwords/api/1.0/session/open",
    "message": "Passphrase invalid",
    "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36 OPR/114.0.0.0",
    "version": "30.0.1.2",
    "exception": {
      "Exception": "OCA\\Passwords\\Exception\\ApiException",
      "Message": "Passphrase invalid",
      "Code": 256,
      "Trace": [
        {
          "file": "/var/www/html/custom_apps/passwords/lib/Services/UserChallengeService.php",
          "line": 134,
          "function": "solveChallenge",
          "class": "OCA\\Passwords\\Helper\\Challenge\\ChallengeV1Helper",
          "type": "->",
          "args": [
            "*** sensitive parameters replaced ***"
          ]
        },
        {
          "file": "/var/www/html/custom_apps/passwords/lib/Controller/Api/SessionApiController.php",
          "line": 225,
          "function": "validateChallenge",
          "class": "OCA\\Passwords\\Services\\UserChallengeService",
          "type": "->",
          "args": [
            "*** sensitive parameters replaced ***"
          ]
        },
        {
          "file": "/var/www/html/custom_apps/passwords/lib/Controller/Api/SessionApiController.php",
          "line": 142,
          "function": "verifyChallenge",
          "class": "OCA\\Passwords\\Controller\\Api\\SessionApiController",
          "type": "->",
          "args": [
            "*** sensitive parameters replaced ***"
          ]
        },
        {
          "file": "/var/www/html/lib/private/AppFramework/Http/Dispatcher.php",
          "line": 208,
          "function": "open",
          "class": "OCA\\Passwords\\Controller\\Api\\SessionApiController",
          "type": "->",
          "args": []
        },
        {
          "file": "/var/www/html/lib/private/AppFramework/Http/Dispatcher.php",
          "line": 114,
          "function": "executeController",
          "class": "OC\\AppFramework\\Http\\Dispatcher",
          "type": "->",
          "args": [
            [
              "OCA\\Passwords\\Controller\\Api\\SessionApiController"
            ],
            "open"
          ]
        },
        {
          "file": "/var/www/html/lib/private/AppFramework/App.php",
          "line": 161,
          "function": "dispatch",
          "class": "OC\\AppFramework\\Http\\Dispatcher",
          "type": "->",
          "args": [
            [
              "OCA\\Passwords\\Controller\\Api\\SessionApiController"
            ],
            "open"
          ]
        },
        {
          "file": "/var/www/html/lib/private/Route/Router.php",
          "line": 302,
          "function": "main",
          "class": "OC\\AppFramework\\App",
          "type": "::",
          "args": [
            "SessionApiController",
            "open",
            [
              "OC\\AppFramework\\DependencyInjection\\DIContainer"
            ],
            [
              "passwords.session_api.open"
            ]
          ]
        },
        {
          "file": "/var/www/html/lib/base.php",
          "line": 1001,
          "function": "match",
          "class": "OC\\Route\\Router",
          "type": "->",
          "args": [
            "/apps/passwords/api/1.0/session/open"
          ]
        },
        {
          "file": "/var/www/html/index.php",
          "line": 24,
          "function": "handleRequest",
          "class": "OC",
          "type": "::",
          "args": []
        }
      ],
      "File": "/var/www/html/custom_apps/passwords/lib/Helper/Challenge/ChallengeV1Helper.php",
      "Line": 61,
      "Previous": {
        "Exception": "Exception",
        "Message": "HMAC does not match.",
        "Code": 0,
        "Trace": [
          {
            "file": "/var/www/html/lib/private/Security/Crypto.php",
            "line": 98,
            "function": "decryptWithoutSecret",
            "class": "OC\\Security\\Crypto",
            "type": "->",
            "args": [
              "*** sensitive parameters replaced ***"
            ]
          },
          {
            "file": "/var/www/html/custom_apps/passwords/lib/Helper/Challenge/ChallengeV1Helper.php",
            "line": 59,
            "function": "decrypt",
            "class": "OC\\Security\\Crypto",
            "type": "->",
            "args": [
              "*** sensitive parameters replaced ***"
            ]
          },
          {
            "file": "/var/www/html/custom_apps/passwords/lib/Services/UserChallengeService.php",
            "line": 134,
            "function": "solveChallenge",
            "class": "OCA\\Passwords\\Helper\\Challenge\\ChallengeV1Helper",
            "type": "->",
            "args": [
              "*** sensitive parameters replaced ***"
            ]
          },
          {
            "file": "/var/www/html/custom_apps/passwords/lib/Controller/Api/SessionApiController.php",
            "line": 225,
            "function": "validateChallenge",
            "class": "OCA\\Passwords\\Services\\UserChallengeService",
            "type": "->",
            "args": [
              "*** sensitive parameters replaced ***"
            ]
          },
          {
            "file": "/var/www/html/custom_apps/passwords/lib/Controller/Api/SessionApiController.php",
            "line": 142,
            "function": "verifyChallenge",
            "class": "OCA\\Passwords\\Controller\\Api\\SessionApiController",
            "type": "->",
            "args": [
              "*** sensitive parameters replaced ***"
            ]
          },
          {
            "file": "/var/www/html/lib/private/AppFramework/Http/Dispatcher.php",
            "line": 208,
            "function": "open",
            "class": "OCA\\Passwords\\Controller\\Api\\SessionApiController",
            "type": "->",
            "args": []
          },
          {
            "file": "/var/www/html/lib/private/AppFramework/Http/Dispatcher.php",
            "line": 114,
            "function": "executeController",
            "class": "OC\\AppFramework\\Http\\Dispatcher",
            "type": "->",
            "args": [
              [
                "OCA\\Passwords\\Controller\\Api\\SessionApiController"
              ],
              "open"
            ]
          },
          {
            "file": "/var/www/html/lib/private/AppFramework/App.php",
            "line": 161,
            "function": "dispatch",
            "class": "OC\\AppFramework\\Http\\Dispatcher",
            "type": "->",
            "args": [
              [
                "OCA\\Passwords\\Controller\\Api\\SessionApiController"
              ],
              "open"
            ]
          },
          {
            "file": "/var/www/html/lib/private/Route/Router.php",
            "line": 302,
            "function": "main",
            "class": "OC\\AppFramework\\App",
            "type": "::",
            "args": [
              "SessionApiController",
              "open",
              [
                "OC\\AppFramework\\DependencyInjection\\DIContainer"
              ],
              [
                "passwords.session_api.open"
              ]
            ]
          },
          {
            "file": "/var/www/html/lib/base.php",
            "line": 1001,
            "function": "match",
            "class": "OC\\Route\\Router",
            "type": "->",
            "args": [
              "/apps/passwords/api/1.0/session/open"
            ]
          },
          {
            "file": "/var/www/html/index.php",
            "line": 24,
            "function": "handleRequest",
            "class": "OC",
            "type": "::",
            "args": []
          }
        ],
        "File": "/var/www/html/lib/private/Security/Crypto.php",
        "Line": 137
      },
      "message": "Passphrase invalid",
      "exception": {},
      "CustomMessage": "Passphrase invalid"
    }
  }
]

Browser Logs

{
  "details": {
    "data": {
      "_response": {},
      "_status": 429
    },
    "message": "HTTP 429 - Too Many Requests",
    "stack": [
      "TooManyRequestsError: HTTP 429 - Too Many Requests",
      "    at f.getClass (chrome-extension://mhajlicjhgoofheldnmollgbgjheenbi/js/background.js:2:558803)",
      "    at _.getClass (chrome-extension://mhajlicjhgoofheldnmollgbgjheenbi/js/background.js:2:622342)",
      "    at O._getHttpError (chrome-extension://mhajlicjhgoofheldnmollgbgjheenbi/js/background.js:2:575959)",
      "    at O.send (chrome-extension://mhajlicjhgoofheldnmollgbgjheenbi/js/background.js:2:573668)",
      "    at async n.getFavicon (chrome-extension://mhajlicjhgoofheldnmollgbgjheenbi/js/background.js:2:608824)",
      "    at async chrome-extension://mhajlicjhgoofheldnmollgbgjheenbi/js/background.js:2:902052"
    ],
    "time": 1730897648057
  },
  "error": {
    "name": "TooManyRequestsError",
    "stack": [
      "TooManyRequestsError: HTTP 429 - Too Many Requests",
      "    at f.getClass (chrome-extension://mhajlicjhgoofheldnmollgbgjheenbi/js/background.js:2:558803)",
      "    at _.getClass (chrome-extension://mhajlicjhgoofheldnmollgbgjheenbi/js/background.js:2:622342)",
      "    at O._getHttpError (chrome-extension://mhajlicjhgoofheldnmollgbgjheenbi/js/background.js:2:575959)",
      "    at O.send (chrome-extension://mhajlicjhgoofheldnmollgbgjheenbi/js/background.js:2:573668)",
      "    at async n.getFavicon (chrome-extension://mhajlicjhgoofheldnmollgbgjheenbi/js/background.js:2:608824)",
      "    at async chrome-extension://mhajlicjhgoofheldnmollgbgjheenbi/js/background.js:2:902052"
    ],
    "string": "TooManyRequestsError: HTTP 429 - Too Many Requests",
    "message": "HTTP 429 - Too Many Requests",
    "_response": {},
    "_status": 429
  }
}

Addendum to the log:

{
  "details": {
    "data": {
      "id": "9a1f302a-f360-4704-8b8c-ac449cdcbc14",
      "tab": null,
      "type": "queue.items",
      "reply": null,
      "silent": false,
      "sender": "background",
      "channel": "runtime",
      "payload": {
        "name": "authorisation",
        "items": [
          {
            "id": "a0ceda2f-f32d-482c-8633-11bca268efb1",
            "task": {
              "server": "370c693e-3559-4695-b9b5-d399dd97b199",
              "label": "XXXXXX xxxx@xxxxxx.de",
              "password": true,
              "token": false,
              "providers": []
            },
            "result": {},
            "success": null,
            "accepted": false,
            "feedback": {}
          }
        ]
      },
      "receiver": null
    },
    "message": "Could not establish connection. Receiving end does not exist.",
    "stack": "Error: Could not establish connection. Receiving end does not exist.\n    at h (chrome-extension://mhajlicjhgoofheldnmollgbgjheenbi/js/background.js:2:776309)",
    "time": 1730920307930
  },
  "error": {
    "name": "Error",
    "stack": [
      "Error: Could not establish connection. Receiving end does not exist.",
      "    at h (chrome-extension://mhajlicjhgoofheldnmollgbgjheenbi/js/background.js:2:776309)"
    ],
    "string": "Error: Could not establish connection. Receiving end does not exist.",
    "message": "Could not establish connection. Receiving end does not exist."
  }
}
JonTabor commented 2 weeks ago

Just wanted to add that I'm seeing this as well on Brave browser (which uses Chrome extensions).

marius-wieschollek commented 2 weeks ago

Sounds like an extension issue to me so i'm moving this

Jackleboul commented 1 week ago

Yeah, it is becoming almost unusable. I am getting the same error and must log in every time I use the extension.

Screenshot 2024-11-21 at 10 45 06

marius-wieschollek commented 5 days ago

TLDR: Chrome reboots the extension every 30 seconds to be "more efficient".

So there seem to be a few errors mixed up here. The Error 429 - i have no clue currently where it comes from. I guess it's a side effect from the main issue. The "Could not establish connection" is a common error when tabs/popups or anything is closed while the extension communicates with them.

Here is how i understand what happens: Chrome "suspends" Manifest V3 extensions when not active. This seems to be done by just stopping the "service worker" and then starting it back up when needed. It seems that any context is not restored.

For the passwords extension that is a bit of an issue since the service worker (formerly the background page in Manifest V2) is where it keeps the local copy of the password database and the session with the Nextcloud server. Periodic events do not prevent Chrome from stopping and restarting the service worker. So tasks like the session keepalive check every minute don't help.

So simply put, the extension seems to be rebooted every 30 seconds which logs you out and also clears all local data, including the error log and local passwords.

My experience with Manifest V3 is limited, but looking online i found this stackoverflow answer archive which lists some workarounds for this genius new behavior.

I will release a nightly update soon with a workaround implemented and update this ticket.

marius-wieschollek commented 5 days ago

The development build with the update is released, would be great if you could give feedback if it works for you.

https://chromewebstore.google.com/detail/passw%C3%B6rter-f%C3%BCr-nextcloud/aipncmjoigmhooiiclcailmhiopachih?pli=1

Jackleboul commented 4 days ago

Hi Marius I have been using it for an hour, and it looks better. There has been no logout so far. I will let you know if any issues come up.

Appreciate your work. Jack

JonTabor commented 1 day ago

I concur, I've been using it all morning, and it's perfect. Thank you @marius-wieschollek!