Repository: evennia/evennia

Issue:
[BUG] Error on connecting to a guest account twice
#### Describe the bug
My environment has an error occur when you connect to a guest account twice. The reason for this is that "webclient_authenticated_nonce" (from #2024) is set to `0` while a value of `None` is expected.

The actual value doesn't matter in this case, so the default value of the nonce can be safely considered `0` to prevent these issues.

#### To Reproduce
Steps to reproduce the behavior:
1. Login as a guest. A new guest Account is created for the duration of the session. `webclient_authenticated_nonce` is `None`.
2. Disconnect the webclient. The guest Account is deleted. `webclient_authenticated_nonce` is `None`, expected value is `None`: the value of `webclient_authenticated_uid` is reset to `None`. `webclient_authenticated_nonce` is reset to `0`.
3. Login as a guest for a second time. A new guest Account is created for the duration of the session. `webclient_authenticated_nonce` is `0`, but the internal value is stored as `None` because `webclient_authenticated_uid` is `None`.
4. Disconnect the webclient. The guest Account is deleted. `webclient_authenticated_nonce` is `0` and the expected value is `None`. Now, `webclient_authenticated_uid` is _not_ reset and points to a non-existent account ID.
5. Navigate to any page on the website, or try to open the webclient again.

You'll be confronted with an error message because line 57 of evennia/web/utils/middleware.py attempts to fetch the Account:

```
        elif webclient_uid:
            # Not logged into website, but logged into webclient
            if website_uid is None:
                csession["website_authenticated_uid"] = account.id
                account = AccountDB.objects.get(id=webclient_uid)  # this line raises an AccountDB.DoesNotExist error
                try:
                    # calls our custom authenticate, in web/utils/backend.py
                    authenticate(autologin=account)
                    login(request, account)
                except AttributeError:
                    logger.log_trace()
```

#### Expected behavior
I would have preferred if this was automatically corrected by the `website_authenticated_uid` being reset back to `None` if the database object doesn't exist. Unfortunately, this flexibility seems absent in this case.

#### Environment, Evennia version, OS etc
Evennia 1.0-dev (rev 43fd533) (rev 43fd533)
OS: nt
Python: 3.8.0
Twisted: 21.2.0
Django: 3.2.4

#### Additional context
I'll create a PR shortly referencing this issue, as I'm _accountable_ for this.
[BUG] Error on connecting to a guest account twice
#### Describe the bug
My environment has an error occur when you connect to a guest account twice. The reason for this is that "webclient_authenticated_nonce" (from #2024) is set to `0` while a value of `None` is expected.

The actual value doesn't matter in this case, so the default value of the nonce can be safely considered `0` to prevent these issues.

#### To Reproduce
Steps to reproduce the behavior:
1. Login as a guest. A new guest Account is created for the duration of the session. `webclient_authenticated_nonce` is `None`.
2. Disconnect the webclient. The guest Account is deleted. `webclient_authenticated_nonce` is `None`, expected value is `None`: the value of `webclient_authenticated_uid` is reset to `None`. `webclient_authenticated_nonce` is reset to `0`.
3. Login as a guest for a second time. A new guest Account is created for the duration of the session. `webclient_authenticated_nonce` is `0`, but the internal value is stored as `None` because `webclient_authenticated_uid` is `None`.
4. Disconnect the webclient. The guest Account is deleted. `webclient_authenticated_nonce` is `0` and the expected value is `None`. Now, `webclient_authenticated_uid` is _not_ reset and points to a non-existent account ID.
5. Navigate to any page on the website, or try to open the webclient again.

You'll be confronted with an error message because line 57 of evennia/web/utils/middleware.py attempts to fetch the Account:

```
        elif webclient_uid:
            # Not logged into website, but logged into webclient
            if website_uid is None:
                csession["website_authenticated_uid"] = account.id
                account = AccountDB.objects.get(id=webclient_uid)  # this line raises an AccountDB.DoesNotExist error
                try:
                    # calls our custom authenticate, in web/utils/backend.py
                    authenticate(autologin=account)
                    login(request, account)
                except AttributeError:
                    logger.log_trace()
```

#### Expected behavior
I would have preferred if this was automatically corrected by the `website_authenticated_uid` being reset back to `None` if the database object doesn't exist. Unfortunately, this flexibility seems absent in this case.

#### Environment, Evennia version, OS etc
Evennia 1.0-dev (rev 43fd533) (rev 43fd533)
OS: nt
Python: 3.8.0
Twisted: 21.2.0
Django: 3.2.4

#### Additional context
I'll create a PR shortly referencing this issue, as I'm _accountable_ for this.


Discussion:

Resolving patch:
diff --git a/evennia/server/portal/webclient.py b/evennia/server/portal/webclient.py
--- a/evennia/server/portal/webclient.py
+++ b/evennia/server/portal/webclient.py
@@ -49,7 +49,7 @@ class WebSocketClient(WebSocketServerProtocol, _BASE_SESSION_CLASS):
 
     # nonce value, used to prevent the webclient from erasing the
     # webclient_authenticated_uid value of csession on disconnect
-    nonce = None
+    nonce = 0
 
     def __init__(self, *args, **kwargs):
         super().__init__(*args, **kwargs)
@@ -143,7 +143,7 @@ def disconnect(self, reason=None):
             # set *before* this disconnect (disconnect called after a new client
             # connects, which occurs in some 'fast' browsers like Google Chrome
             # and Mobile Safari)
-            if csession.get("webclient_authenticated_nonce", None) == self.nonce:
+            if csession.get("webclient_authenticated_nonce", 0) == self.nonce:
                 csession["webclient_authenticated_uid"] = None
                 csession["webclient_authenticated_nonce"] = 0
                 csession.save()


Test patch: