We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Catch additional pymacaroons.Macaroon.deserialize exceptions
It appears that someone has [enumerated the various exceptions `pymacaroons.Macaroon.deserialize` might raise](https://github.com/ecordell/pymacaroons/issues/50). It'd be great if that were resolved, but we might want to further harden the work from #7424 to handle these other cases?

_Originally posted by @ewdurbin in https://github.com/pypa/warehouse/issues/7298#issuecomment-589957864_

---

**Good First Issue**: This issue is good for first time contributors. If you've already contributed to Warehouse, work on [another issue without this label](https://github.com/pypa/warehouse/issues?utf8=%E2%9C%93&q=is%3Aissue+is%3Aopen+-label%3A%22good+first+issue%22) instead. If there is not a corresponding pull request for this issue, it is up for grabs. For directions for getting set up, see our [Getting Started Guide](https://warehouse.pypa.io/development/getting-started/). If you are working on this issue and have questions, feel free to ask them here, [`#pypa-dev` on Freenode](https://webchat.freenode.net/?channels=%23pypa-dev), or the [pypa-dev mailing list](https://groups.google.com/forum/#!forum/pypa-dev).

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `warehouse/macaroons/services.py`
Content:
```
1 # Licensed under the Apache License, Version 2.0 (the "License");
2 # you may not use this file except in compliance with the License.
3 # You may obtain a copy of the License at
4 #
5 # http://www.apache.org/licenses/LICENSE-2.0
6 #
7 # Unless required by applicable law or agreed to in writing, software
8 # distributed under the License is distributed on an "AS IS" BASIS,
9 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10 # See the License for the specific language governing permissions and
11 # limitations under the License.
12 
13 import binascii
14 import datetime
15 import json
16 import uuid
17 
18 import pymacaroons
19 
20 from pymacaroons.exceptions import MacaroonDeserializationException
21 from sqlalchemy.orm import joinedload
22 from sqlalchemy.orm.exc import NoResultFound
23 from zope.interface import implementer
24 
25 from warehouse.accounts.models import User
26 from warehouse.macaroons.caveats import InvalidMacaroon, Verifier
27 from warehouse.macaroons.interfaces import IMacaroonService
28 from warehouse.macaroons.models import Macaroon
29 
30 
31 @implementer(IMacaroonService)
32 class DatabaseMacaroonService:
33     def __init__(self, db_session):
34         self.db = db_session
35 
36     def _extract_raw_macaroon(self, prefixed_macaroon):
37         """
38         Returns the base64-encoded macaroon component of a PyPI macaroon,
39         dropping the prefix.
40 
41         Returns None if the macaroon is None, has no prefix, or has the
42         wrong prefix.
43         """
44         if prefixed_macaroon is None:
45             return None
46 
47         prefix, _, raw_macaroon = prefixed_macaroon.partition("-")
48         if prefix != "pypi" or not raw_macaroon:
49             return None
50 
51         return raw_macaroon
52 
53     def find_macaroon(self, macaroon_id):
54         """
55         Returns a macaroon model from the DB by its identifier.
56         Returns None if no macaroon has the given ID.
57         """
58         try:
59             dm = (
60                 self.db.query(Macaroon)
61                 .options(joinedload("user"))
62                 .filter(Macaroon.id == uuid.UUID(macaroon_id))
63                 .one()
64             )
65         except NoResultFound:
66             return None
67 
68         return dm
69 
70     def find_userid(self, raw_macaroon):
71         """
72         Returns the id of the user associated with the given raw (serialized)
73         macaroon.
74         """
75         raw_macaroon = self._extract_raw_macaroon(raw_macaroon)
76         if raw_macaroon is None:
77             return None
78 
79         try:
80             m = pymacaroons.Macaroon.deserialize(raw_macaroon)
81         except binascii.Error:
82             return None
83         except MacaroonDeserializationException:
84             return None
85 
86         dm = self.find_macaroon(m.identifier.decode())
87 
88         if dm is None:
89             return None
90 
91         return dm.user.id
92 
93     def verify(self, raw_macaroon, context, principals, permission):
94         """
95         Returns True if the given raw (serialized) macaroon is
96         valid for the context, principals, and requested permission.
97 
98         Raises InvalidMacaroon if the macaroon is not valid.
99         """
100         raw_macaroon = self._extract_raw_macaroon(raw_macaroon)
101         if raw_macaroon is None:
102             raise InvalidMacaroon("malformed or nonexistent macaroon")
103 
104         try:
105             m = pymacaroons.Macaroon.deserialize(raw_macaroon)
106         except MacaroonDeserializationException:
107             raise InvalidMacaroon("malformed macaroon")
108 
109         dm = self.find_macaroon(m.identifier.decode())
110 
111         if dm is None:
112             raise InvalidMacaroon("deleted or nonexistent macaroon")
113 
114         verifier = Verifier(m, context, principals, permission)
115         if verifier.verify(dm.key):
116             dm.last_used = datetime.datetime.now()
117             return True
118 
119         raise InvalidMacaroon("invalid macaroon")
120 
121     def create_macaroon(self, location, user_id, description, caveats):
122         """
123         Returns a tuple of a new raw (serialized) macaroon and its DB model.
124         The description provided is not embedded into the macaroon, only stored
125         in the DB model.
126         """
127         user = self.db.query(User).filter(User.id == user_id).one()
128 
129         dm = Macaroon(user=user, description=description, caveats=caveats)
130         self.db.add(dm)
131         self.db.flush()
132 
133         m = pymacaroons.Macaroon(
134             location=location,
135             identifier=str(dm.id),
136             key=dm.key,
137             version=pymacaroons.MACAROON_V2,
138         )
139         m.add_first_party_caveat(json.dumps(caveats))
140         serialized_macaroon = f"pypi-{m.serialize()}"
141         return serialized_macaroon, dm
142 
143     def delete_macaroon(self, macaroon_id):
144         """
145         Deletes a macaroon from the DB by its identifier.
146         """
147         dm = self.find_macaroon(macaroon_id)
148         self.db.delete(dm)
149         self.db.flush()
150 
151     def get_macaroon_by_description(self, user_id, description):
152         """
153         Returns a macaroon model from the DB with the given description,
154         if one exists for the given user.
155 
156         Returns None if the user doesn't have a macaroon with this description.
157         """
158         try:
159             dm = (
160                 self.db.query(Macaroon)
161                 .options(joinedload("user"))
162                 .filter(Macaroon.description == description)
163                 .filter(Macaroon.user_id == user_id)
164                 .one()
165             )
166         except NoResultFound:
167             return None
168 
169         return dm
170 
171 
172 def database_macaroon_factory(context, request):
173     return DatabaseMacaroonService(request.db)
174
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/warehouse/macaroons/services.py b/warehouse/macaroons/services.py
--- a/warehouse/macaroons/services.py
+++ b/warehouse/macaroons/services.py
@@ -13,6 +13,7 @@
 import binascii
 import datetime
 import json
+import struct
 import uuid
 
 import pymacaroons
@@ -67,20 +68,32 @@
 
         return dm
 
+    def _deserialize_raw_macaroon(self, raw_macaroon):
+        raw_macaroon = self._extract_raw_macaroon(raw_macaroon)
+
+        if raw_macaroon is None:
+            raise InvalidMacaroon("malformed or nonexistent macaroon")
+
+        try:
+            return pymacaroons.Macaroon.deserialize(raw_macaroon)
+        except (
+            IndexError,
+            TypeError,
+            ValueError,
+            binascii.Error,
+            struct.error,
+            MacaroonDeserializationException,
+        ):
+            raise InvalidMacaroon("malformed macaroon")
+
     def find_userid(self, raw_macaroon):
         """
         Returns the id of the user associated with the given raw (serialized)
         macaroon.
         """
-        raw_macaroon = self._extract_raw_macaroon(raw_macaroon)
-        if raw_macaroon is None:
-            return None
-
         try:
-            m = pymacaroons.Macaroon.deserialize(raw_macaroon)
-        except binascii.Error:
-            return None
-        except MacaroonDeserializationException:
+            m = self._deserialize_raw_macaroon(raw_macaroon)
+        except InvalidMacaroon:
             return None
 
         dm = self.find_macaroon(m.identifier.decode())
@@ -97,15 +110,7 @@
 
         Raises InvalidMacaroon if the macaroon is not valid.
         """
-        raw_macaroon = self._extract_raw_macaroon(raw_macaroon)
-        if raw_macaroon is None:
-            raise InvalidMacaroon("malformed or nonexistent macaroon")
-
-        try:
-            m = pymacaroons.Macaroon.deserialize(raw_macaroon)
-        except MacaroonDeserializationException:
-            raise InvalidMacaroon("malformed macaroon")
-
+        m = self._deserialize_raw_macaroon(raw_macaroon)
         dm = self.find_macaroon(m.identifier.decode())
 
         if dm is None:

{"golden_diff": "diff --git a/warehouse/macaroons/services.py b/warehouse/macaroons/services.py\n--- a/warehouse/macaroons/services.py\n+++ b/warehouse/macaroons/services.py\n@@ -13,6 +13,7 @@\n import binascii\n import datetime\n import json\n+import struct\n import uuid\n \n import pymacaroons\n@@ -67,20 +68,32 @@\n \n         return dm\n \n+    def _deserialize_raw_macaroon(self, raw_macaroon):\n+        raw_macaroon = self._extract_raw_macaroon(raw_macaroon)\n+\n+        if raw_macaroon is None:\n+            raise InvalidMacaroon(\"malformed or nonexistent macaroon\")\n+\n+        try:\n+            return pymacaroons.Macaroon.deserialize(raw_macaroon)\n+        except (\n+            IndexError,\n+            TypeError,\n+            ValueError,\n+            binascii.Error,\n+            struct.error,\n+            MacaroonDeserializationException,\n+        ):\n+            raise InvalidMacaroon(\"malformed macaroon\")\n+\n     def find_userid(self, raw_macaroon):\n         \"\"\"\n         Returns the id of the user associated with the given raw (serialized)\n         macaroon.\n         \"\"\"\n-        raw_macaroon = self._extract_raw_macaroon(raw_macaroon)\n-        if raw_macaroon is None:\n-            return None\n-\n         try:\n-            m = pymacaroons.Macaroon.deserialize(raw_macaroon)\n-        except binascii.Error:\n-            return None\n-        except MacaroonDeserializationException:\n+            m = self._deserialize_raw_macaroon(raw_macaroon)\n+        except InvalidMacaroon:\n             return None\n \n         dm = self.find_macaroon(m.identifier.decode())\n@@ -97,15 +110,7 @@\n \n         Raises InvalidMacaroon if the macaroon is not valid.\n         \"\"\"\n-        raw_macaroon = self._extract_raw_macaroon(raw_macaroon)\n-        if raw_macaroon is None:\n-            raise InvalidMacaroon(\"malformed or nonexistent macaroon\")\n-\n-        try:\n-            m = pymacaroons.Macaroon.deserialize(raw_macaroon)\n-        except MacaroonDeserializationException:\n-            raise InvalidMacaroon(\"malformed macaroon\")\n-\n+        m = self._deserialize_raw_macaroon(raw_macaroon)\n         dm = self.find_macaroon(m.identifier.decode())\n \n         if dm is None:\n", "issue": "Catch additional pymacaroons.Macaroon.deserialize exceptions\nIt appears that someone has [enumerated the various exceptions `pymacaroons.Macaroon.deserialize` might raise](https://github.com/ecordell/pymacaroons/issues/50). It'd be great if that were resolved, but we might want to further harden the work from #7424 to handle these other cases?\r\n\r\n_Originally posted by @ewdurbin in https://github.com/pypa/warehouse/issues/7298#issuecomment-589957864_\r\n\r\n---\r\n\r\n**Good First Issue**: This issue is good for first time contributors. If you've already contributed to Warehouse, work on [another issue without this label](https://github.com/pypa/warehouse/issues?utf8=%E2%9C%93&q=is%3Aissue+is%3Aopen+-label%3A%22good+first+issue%22) instead. If there is not a corresponding pull request for this issue, it is up for grabs. For directions for getting set up, see our [Getting Started Guide](https://warehouse.pypa.io/development/getting-started/). If you are working on this issue and have questions, feel free to ask them here, [`#pypa-dev` on Freenode](https://webchat.freenode.net/?channels=%23pypa-dev), or the [pypa-dev mailing list](https://groups.google.com/forum/#!forum/pypa-dev).\n", "before_files": [{"content": "# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n# http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nimport binascii\nimport datetime\nimport json\nimport uuid\n\nimport pymacaroons\n\nfrom pymacaroons.exceptions import MacaroonDeserializationException\nfrom sqlalchemy.orm import joinedload\nfrom sqlalchemy.orm.exc import NoResultFound\nfrom zope.interface import implementer\n\nfrom warehouse.accounts.models import User\nfrom warehouse.macaroons.caveats import InvalidMacaroon, Verifier\nfrom warehouse.macaroons.interfaces import IMacaroonService\nfrom warehouse.macaroons.models import Macaroon\n\n\n@implementer(IMacaroonService)\nclass DatabaseMacaroonService:\n    def __init__(self, db_session):\n        self.db = db_session\n\n    def _extract_raw_macaroon(self, prefixed_macaroon):\n        \"\"\"\n        Returns the base64-encoded macaroon component of a PyPI macaroon,\n        dropping the prefix.\n\n        Returns None if the macaroon is None, has no prefix, or has the\n        wrong prefix.\n        \"\"\"\n        if prefixed_macaroon is None:\n            return None\n\n        prefix, _, raw_macaroon = prefixed_macaroon.partition(\"-\")\n        if prefix != \"pypi\" or not raw_macaroon:\n            return None\n\n        return raw_macaroon\n\n    def find_macaroon(self, macaroon_id):\n        \"\"\"\n        Returns a macaroon model from the DB by its identifier.\n        Returns None if no macaroon has the given ID.\n        \"\"\"\n        try:\n            dm = (\n                self.db.query(Macaroon)\n                .options(joinedload(\"user\"))\n                .filter(Macaroon.id == uuid.UUID(macaroon_id))\n                .one()\n            )\n        except NoResultFound:\n            return None\n\n        return dm\n\n    def find_userid(self, raw_macaroon):\n        \"\"\"\n        Returns the id of the user associated with the given raw (serialized)\n        macaroon.\n        \"\"\"\n        raw_macaroon = self._extract_raw_macaroon(raw_macaroon)\n        if raw_macaroon is None:\n            return None\n\n        try:\n            m = pymacaroons.Macaroon.deserialize(raw_macaroon)\n        except binascii.Error:\n            return None\n        except MacaroonDeserializationException:\n            return None\n\n        dm = self.find_macaroon(m.identifier.decode())\n\n        if dm is None:\n            return None\n\n        return dm.user.id\n\n    def verify(self, raw_macaroon, context, principals, permission):\n        \"\"\"\n        Returns True if the given raw (serialized) macaroon is\n        valid for the context, principals, and requested permission.\n\n        Raises InvalidMacaroon if the macaroon is not valid.\n        \"\"\"\n        raw_macaroon = self._extract_raw_macaroon(raw_macaroon)\n        if raw_macaroon is None:\n            raise InvalidMacaroon(\"malformed or nonexistent macaroon\")\n\n        try:\n            m = pymacaroons.Macaroon.deserialize(raw_macaroon)\n        except MacaroonDeserializationException:\n            raise InvalidMacaroon(\"malformed macaroon\")\n\n        dm = self.find_macaroon(m.identifier.decode())\n\n        if dm is None:\n            raise InvalidMacaroon(\"deleted or nonexistent macaroon\")\n\n        verifier = Verifier(m, context, principals, permission)\n        if verifier.verify(dm.key):\n            dm.last_used = datetime.datetime.now()\n            return True\n\n        raise InvalidMacaroon(\"invalid macaroon\")\n\n    def create_macaroon(self, location, user_id, description, caveats):\n        \"\"\"\n        Returns a tuple of a new raw (serialized) macaroon and its DB model.\n        The description provided is not embedded into the macaroon, only stored\n        in the DB model.\n        \"\"\"\n        user = self.db.query(User).filter(User.id == user_id).one()\n\n        dm = Macaroon(user=user, description=description, caveats=caveats)\n        self.db.add(dm)\n        self.db.flush()\n\n        m = pymacaroons.Macaroon(\n            location=location,\n            identifier=str(dm.id),\n            key=dm.key,\n            version=pymacaroons.MACAROON_V2,\n        )\n        m.add_first_party_caveat(json.dumps(caveats))\n        serialized_macaroon = f\"pypi-{m.serialize()}\"\n        return serialized_macaroon, dm\n\n    def delete_macaroon(self, macaroon_id):\n        \"\"\"\n        Deletes a macaroon from the DB by its identifier.\n        \"\"\"\n        dm = self.find_macaroon(macaroon_id)\n        self.db.delete(dm)\n        self.db.flush()\n\n    def get_macaroon_by_description(self, user_id, description):\n        \"\"\"\n        Returns a macaroon model from the DB with the given description,\n        if one exists for the given user.\n\n        Returns None if the user doesn't have a macaroon with this description.\n        \"\"\"\n        try:\n            dm = (\n                self.db.query(Macaroon)\n                .options(joinedload(\"user\"))\n                .filter(Macaroon.description == description)\n                .filter(Macaroon.user_id == user_id)\n                .one()\n            )\n        except NoResultFound:\n            return None\n\n        return dm\n\n\ndef database_macaroon_factory(context, request):\n    return DatabaseMacaroonService(request.db)\n", "path": "warehouse/macaroons/services.py"}], "after_files": [{"content": "# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n# http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nimport binascii\nimport datetime\nimport json\nimport struct\nimport uuid\n\nimport pymacaroons\n\nfrom pymacaroons.exceptions import MacaroonDeserializationException\nfrom sqlalchemy.orm import joinedload\nfrom sqlalchemy.orm.exc import NoResultFound\nfrom zope.interface import implementer\n\nfrom warehouse.accounts.models import User\nfrom warehouse.macaroons.caveats import InvalidMacaroon, Verifier\nfrom warehouse.macaroons.interfaces import IMacaroonService\nfrom warehouse.macaroons.models import Macaroon\n\n\n@implementer(IMacaroonService)\nclass DatabaseMacaroonService:\n    def __init__(self, db_session):\n        self.db = db_session\n\n    def _extract_raw_macaroon(self, prefixed_macaroon):\n        \"\"\"\n        Returns the base64-encoded macaroon component of a PyPI macaroon,\n        dropping the prefix.\n\n        Returns None if the macaroon is None, has no prefix, or has the\n        wrong prefix.\n        \"\"\"\n        if prefixed_macaroon is None:\n            return None\n\n        prefix, _, raw_macaroon = prefixed_macaroon.partition(\"-\")\n        if prefix != \"pypi\" or not raw_macaroon:\n            return None\n\n        return raw_macaroon\n\n    def find_macaroon(self, macaroon_id):\n        \"\"\"\n        Returns a macaroon model from the DB by its identifier.\n        Returns None if no macaroon has the given ID.\n        \"\"\"\n        try:\n            dm = (\n                self.db.query(Macaroon)\n                .options(joinedload(\"user\"))\n                .filter(Macaroon.id == uuid.UUID(macaroon_id))\n                .one()\n            )\n        except NoResultFound:\n            return None\n\n        return dm\n\n    def _deserialize_raw_macaroon(self, raw_macaroon):\n        raw_macaroon = self._extract_raw_macaroon(raw_macaroon)\n\n        if raw_macaroon is None:\n            raise InvalidMacaroon(\"malformed or nonexistent macaroon\")\n\n        try:\n            return pymacaroons.Macaroon.deserialize(raw_macaroon)\n        except (\n            IndexError,\n            TypeError,\n            ValueError,\n            binascii.Error,\n            struct.error,\n            MacaroonDeserializationException,\n        ):\n            raise InvalidMacaroon(\"malformed macaroon\")\n\n    def find_userid(self, raw_macaroon):\n        \"\"\"\n        Returns the id of the user associated with the given raw (serialized)\n        macaroon.\n        \"\"\"\n        try:\n            m = self._deserialize_raw_macaroon(raw_macaroon)\n        except InvalidMacaroon:\n            return None\n\n        dm = self.find_macaroon(m.identifier.decode())\n\n        if dm is None:\n            return None\n\n        return dm.user.id\n\n    def verify(self, raw_macaroon, context, principals, permission):\n        \"\"\"\n        Returns True if the given raw (serialized) macaroon is\n        valid for the context, principals, and requested permission.\n\n        Raises InvalidMacaroon if the macaroon is not valid.\n        \"\"\"\n        m = self._deserialize_raw_macaroon(raw_macaroon)\n        dm = self.find_macaroon(m.identifier.decode())\n\n        if dm is None:\n            raise InvalidMacaroon(\"deleted or nonexistent macaroon\")\n\n        verifier = Verifier(m, context, principals, permission)\n        if verifier.verify(dm.key):\n            dm.last_used = datetime.datetime.now()\n            return True\n\n        raise InvalidMacaroon(\"invalid macaroon\")\n\n    def create_macaroon(self, location, user_id, description, caveats):\n        \"\"\"\n        Returns a tuple of a new raw (serialized) macaroon and its DB model.\n        The description provided is not embedded into the macaroon, only stored\n        in the DB model.\n        \"\"\"\n        user = self.db.query(User).filter(User.id == user_id).one()\n\n        dm = Macaroon(user=user, description=description, caveats=caveats)\n        self.db.add(dm)\n        self.db.flush()\n\n        m = pymacaroons.Macaroon(\n            location=location,\n            identifier=str(dm.id),\n            key=dm.key,\n            version=pymacaroons.MACAROON_V2,\n        )\n        m.add_first_party_caveat(json.dumps(caveats))\n        serialized_macaroon = f\"pypi-{m.serialize()}\"\n        return serialized_macaroon, dm\n\n    def delete_macaroon(self, macaroon_id):\n        \"\"\"\n        Deletes a macaroon from the DB by its identifier.\n        \"\"\"\n        dm = self.find_macaroon(macaroon_id)\n        self.db.delete(dm)\n        self.db.flush()\n\n    def get_macaroon_by_description(self, user_id, description):\n        \"\"\"\n        Returns a macaroon model from the DB with the given description,\n        if one exists for the given user.\n\n        Returns None if the user doesn't have a macaroon with this description.\n        \"\"\"\n        try:\n            dm = (\n                self.db.query(Macaroon)\n                .options(joinedload(\"user\"))\n                .filter(Macaroon.description == description)\n                .filter(Macaroon.user_id == user_id)\n                .one()\n            )\n        except NoResultFound:\n            return None\n\n        return dm\n\n\ndef database_macaroon_factory(context, request):\n    return DatabaseMacaroonService(request.db)\n", "path": "warehouse/macaroons/services.py"}]}