prompt: We are currently solving the following issue within our repository. Here is the issue text:
  --- BEGIN ISSUE ---
  WebAuthN user verification flag should be set to discouraged
  The current setting on the Pypi site is to ignore the UserVerificationOption setting in the `navigator.credentials.create()` call. Based on [this chromium documentation](https://chromium.googlesource.com/chromium/src/+/master/content/browser/webauth/uv_preferred.md), it appears to be set to "preferred" by default.
  
  TL:DR; it interrupts the login flow by popping up a pin entry dialog upon tapping my yubikey, then requires me to tap again after successful pin entry. This is not the recommended setting for second-factor credentials, only for passwordless [[1](https://developers.yubico.com/WebAuthn/WebAuthn_Developer_Guide/User_Presence_vs_User_Verification.html)].
  
  Please explicitly set this to [discouraged](https://w3c.github.io/webauthn/#enum-userVerificationRequirement) instead, so that I will no longer have PIN prompts on second-factor login.
  
  --- 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/utils/webauthn.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 base64
  14 import os
  15 
  16 import webauthn as pywebauthn
  17 
  18 from webauthn.webauthn import (
  19     AuthenticationRejectedException as _AuthenticationRejectedException,
  20     RegistrationRejectedException as _RegistrationRejectedException,
  21 )
  22 
  23 
  24 class AuthenticationRejectedException(Exception):
  25     pass
  26 
  27 
  28 class RegistrationRejectedException(Exception):
  29     pass
  30 
  31 
  32 WebAuthnCredential = pywebauthn.WebAuthnCredential
  33 
  34 
  35 def _get_webauthn_users(user, *, rp_id):
  36     """
  37     Returns a webauthn.WebAuthnUser instance corresponding
  38     to the given user model, with properties suitable for
  39     usage within the webauthn API.
  40     """
  41     return [
  42         pywebauthn.WebAuthnUser(
  43             str(user.id),
  44             user.username,
  45             user.name,
  46             None,
  47             credential.credential_id,
  48             credential.public_key,
  49             credential.sign_count,
  50             rp_id,
  51         )
  52         for credential in user.webauthn
  53     ]
  54 
  55 
  56 def _webauthn_b64decode(encoded):
  57     padding = "=" * (len(encoded) % 4)
  58     return base64.urlsafe_b64decode(encoded + padding)
  59 
  60 
  61 def _webauthn_b64encode(source):
  62     return base64.urlsafe_b64encode(source).rstrip(b"=")
  63 
  64 
  65 def generate_webauthn_challenge():
  66     """
  67     Returns a random challenge suitable for use within
  68     Webauthn's credential and configuration option objects.
  69 
  70     See: https://w3c.github.io/webauthn/#cryptographic-challenges
  71     """
  72     # NOTE: Webauthn recommends at least 16 bytes of entropy,
  73     # we go with 32 because it doesn't cost us anything.
  74     return _webauthn_b64encode(os.urandom(32)).decode()
  75 
  76 
  77 def get_credential_options(user, *, challenge, rp_name, rp_id):
  78     """
  79     Returns a dictionary of options for credential creation
  80     on the client side.
  81     """
  82     options = pywebauthn.WebAuthnMakeCredentialOptions(
  83         challenge, rp_name, rp_id, str(user.id), user.username, user.name, None
  84     )
  85 
  86     return options.registration_dict
  87 
  88 
  89 def get_assertion_options(user, *, challenge, rp_id):
  90     """
  91     Returns a dictionary of options for assertion retrieval
  92     on the client side.
  93     """
  94     options = pywebauthn.WebAuthnAssertionOptions(
  95         _get_webauthn_users(user, rp_id=rp_id), challenge
  96     )
  97 
  98     return options.assertion_dict
  99 
  100 
  101 def verify_registration_response(response, challenge, *, rp_id, origin):
  102     """
  103     Validates the challenge and attestation information
  104     sent from the client during device registration.
  105 
  106     Returns a WebAuthnCredential on success.
  107     Raises RegistrationRejectedException on failire.
  108     """
  109     # NOTE: We re-encode the challenge below, because our
  110     # response's clientData.challenge is encoded twice:
  111     # first for the entire clientData payload, and then again
  112     # for the individual challenge.
  113     encoded_challenge = _webauthn_b64encode(challenge.encode()).decode()
  114     response = pywebauthn.WebAuthnRegistrationResponse(
  115         rp_id, origin, response, encoded_challenge, self_attestation_permitted=True
  116     )
  117     try:
  118         return response.verify()
  119     except _RegistrationRejectedException as e:
  120         raise RegistrationRejectedException(str(e))
  121 
  122 
  123 def verify_assertion_response(assertion, *, challenge, user, origin, rp_id):
  124     """
  125     Validates the challenge and assertion information
  126     sent from the client during authentication.
  127 
  128     Returns an updated signage count on success.
  129     Raises AuthenticationRejectedException on failure.
  130     """
  131     webauthn_users = _get_webauthn_users(user, rp_id=rp_id)
  132     cred_ids = [cred.credential_id for cred in webauthn_users]
  133     encoded_challenge = _webauthn_b64encode(challenge.encode()).decode()
  134 
  135     for webauthn_user in webauthn_users:
  136         response = pywebauthn.WebAuthnAssertionResponse(
  137             webauthn_user,
  138             assertion,
  139             encoded_challenge,
  140             origin,
  141             allow_credentials=cred_ids,
  142         )
  143         try:
  144             return (webauthn_user.credential_id, response.verify())
  145         except _AuthenticationRejectedException:
  146             pass
  147 
  148     # If we exit the loop, then we've failed to verify the assertion against
  149     # any of the user's WebAuthn credentials. Fail.
  150     raise AuthenticationRejectedException("Invalid WebAuthn credential")
  151
  ```
  --- 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()
  
  ```
  
golden_diff: diff --git a/warehouse/utils/webauthn.py b/warehouse/utils/webauthn.py
  --- a/warehouse/utils/webauthn.py
  +++ b/warehouse/utils/webauthn.py
  @@ -80,7 +80,14 @@
       on the client side.
       """
       options = pywebauthn.WebAuthnMakeCredentialOptions(
  -        challenge, rp_name, rp_id, str(user.id), user.username, user.name, None
  +        challenge,
  +        rp_name,
  +        rp_id,
  +        str(user.id),
  +        user.username,
  +        user.name,
  +        None,
  +        user_verification="discouraged",
       )
   
       return options.registration_dict
  
verification_info: {"golden_diff": "diff --git a/warehouse/utils/webauthn.py b/warehouse/utils/webauthn.py\n--- a/warehouse/utils/webauthn.py\n+++ b/warehouse/utils/webauthn.py\n@@ -80,7 +80,14 @@\n     on the client side.\n     \"\"\"\n     options = pywebauthn.WebAuthnMakeCredentialOptions(\n-        challenge, rp_name, rp_id, str(user.id), user.username, user.name, None\n+        challenge,\n+        rp_name,\n+        rp_id,\n+        str(user.id),\n+        user.username,\n+        user.name,\n+        None,\n+        user_verification=\"discouraged\",\n     )\n \n     return options.registration_dict\n", "issue": "WebAuthN user verification flag should be set to discouraged\nThe current setting on the Pypi site is to ignore the UserVerificationOption setting in the `navigator.credentials.create()` call. Based on [this chromium documentation](https://chromium.googlesource.com/chromium/src/+/master/content/browser/webauth/uv_preferred.md), it appears to be set to \"preferred\" by default.\r\n\r\nTL:DR; it interrupts the login flow by popping up a pin entry dialog upon tapping my yubikey, then requires me to tap again after successful pin entry. This is not the recommended setting for second-factor credentials, only for passwordless [[1](https://developers.yubico.com/WebAuthn/WebAuthn_Developer_Guide/User_Presence_vs_User_Verification.html)].\r\n\r\nPlease explicitly set this to [discouraged](https://w3c.github.io/webauthn/#enum-userVerificationRequirement) instead, so that I will no longer have PIN prompts on second-factor login.\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 base64\nimport os\n\nimport webauthn as pywebauthn\n\nfrom webauthn.webauthn import (\n    AuthenticationRejectedException as _AuthenticationRejectedException,\n    RegistrationRejectedException as _RegistrationRejectedException,\n)\n\n\nclass AuthenticationRejectedException(Exception):\n    pass\n\n\nclass RegistrationRejectedException(Exception):\n    pass\n\n\nWebAuthnCredential = pywebauthn.WebAuthnCredential\n\n\ndef _get_webauthn_users(user, *, rp_id):\n    \"\"\"\n    Returns a webauthn.WebAuthnUser instance corresponding\n    to the given user model, with properties suitable for\n    usage within the webauthn API.\n    \"\"\"\n    return [\n        pywebauthn.WebAuthnUser(\n            str(user.id),\n            user.username,\n            user.name,\n            None,\n            credential.credential_id,\n            credential.public_key,\n            credential.sign_count,\n            rp_id,\n        )\n        for credential in user.webauthn\n    ]\n\n\ndef _webauthn_b64decode(encoded):\n    padding = \"=\" * (len(encoded) % 4)\n    return base64.urlsafe_b64decode(encoded + padding)\n\n\ndef _webauthn_b64encode(source):\n    return base64.urlsafe_b64encode(source).rstrip(b\"=\")\n\n\ndef generate_webauthn_challenge():\n    \"\"\"\n    Returns a random challenge suitable for use within\n    Webauthn's credential and configuration option objects.\n\n    See: https://w3c.github.io/webauthn/#cryptographic-challenges\n    \"\"\"\n    # NOTE: Webauthn recommends at least 16 bytes of entropy,\n    # we go with 32 because it doesn't cost us anything.\n    return _webauthn_b64encode(os.urandom(32)).decode()\n\n\ndef get_credential_options(user, *, challenge, rp_name, rp_id):\n    \"\"\"\n    Returns a dictionary of options for credential creation\n    on the client side.\n    \"\"\"\n    options = pywebauthn.WebAuthnMakeCredentialOptions(\n        challenge, rp_name, rp_id, str(user.id), user.username, user.name, None\n    )\n\n    return options.registration_dict\n\n\ndef get_assertion_options(user, *, challenge, rp_id):\n    \"\"\"\n    Returns a dictionary of options for assertion retrieval\n    on the client side.\n    \"\"\"\n    options = pywebauthn.WebAuthnAssertionOptions(\n        _get_webauthn_users(user, rp_id=rp_id), challenge\n    )\n\n    return options.assertion_dict\n\n\ndef verify_registration_response(response, challenge, *, rp_id, origin):\n    \"\"\"\n    Validates the challenge and attestation information\n    sent from the client during device registration.\n\n    Returns a WebAuthnCredential on success.\n    Raises RegistrationRejectedException on failire.\n    \"\"\"\n    # NOTE: We re-encode the challenge below, because our\n    # response's clientData.challenge is encoded twice:\n    # first for the entire clientData payload, and then again\n    # for the individual challenge.\n    encoded_challenge = _webauthn_b64encode(challenge.encode()).decode()\n    response = pywebauthn.WebAuthnRegistrationResponse(\n        rp_id, origin, response, encoded_challenge, self_attestation_permitted=True\n    )\n    try:\n        return response.verify()\n    except _RegistrationRejectedException as e:\n        raise RegistrationRejectedException(str(e))\n\n\ndef verify_assertion_response(assertion, *, challenge, user, origin, rp_id):\n    \"\"\"\n    Validates the challenge and assertion information\n    sent from the client during authentication.\n\n    Returns an updated signage count on success.\n    Raises AuthenticationRejectedException on failure.\n    \"\"\"\n    webauthn_users = _get_webauthn_users(user, rp_id=rp_id)\n    cred_ids = [cred.credential_id for cred in webauthn_users]\n    encoded_challenge = _webauthn_b64encode(challenge.encode()).decode()\n\n    for webauthn_user in webauthn_users:\n        response = pywebauthn.WebAuthnAssertionResponse(\n            webauthn_user,\n            assertion,\n            encoded_challenge,\n            origin,\n            allow_credentials=cred_ids,\n        )\n        try:\n            return (webauthn_user.credential_id, response.verify())\n        except _AuthenticationRejectedException:\n            pass\n\n    # If we exit the loop, then we've failed to verify the assertion against\n    # any of the user's WebAuthn credentials. Fail.\n    raise AuthenticationRejectedException(\"Invalid WebAuthn credential\")\n", "path": "warehouse/utils/webauthn.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 base64\nimport os\n\nimport webauthn as pywebauthn\n\nfrom webauthn.webauthn import (\n    AuthenticationRejectedException as _AuthenticationRejectedException,\n    RegistrationRejectedException as _RegistrationRejectedException,\n)\n\n\nclass AuthenticationRejectedException(Exception):\n    pass\n\n\nclass RegistrationRejectedException(Exception):\n    pass\n\n\nWebAuthnCredential = pywebauthn.WebAuthnCredential\n\n\ndef _get_webauthn_users(user, *, rp_id):\n    \"\"\"\n    Returns a webauthn.WebAuthnUser instance corresponding\n    to the given user model, with properties suitable for\n    usage within the webauthn API.\n    \"\"\"\n    return [\n        pywebauthn.WebAuthnUser(\n            str(user.id),\n            user.username,\n            user.name,\n            None,\n            credential.credential_id,\n            credential.public_key,\n            credential.sign_count,\n            rp_id,\n        )\n        for credential in user.webauthn\n    ]\n\n\ndef _webauthn_b64decode(encoded):\n    padding = \"=\" * (len(encoded) % 4)\n    return base64.urlsafe_b64decode(encoded + padding)\n\n\ndef _webauthn_b64encode(source):\n    return base64.urlsafe_b64encode(source).rstrip(b\"=\")\n\n\ndef generate_webauthn_challenge():\n    \"\"\"\n    Returns a random challenge suitable for use within\n    Webauthn's credential and configuration option objects.\n\n    See: https://w3c.github.io/webauthn/#cryptographic-challenges\n    \"\"\"\n    # NOTE: Webauthn recommends at least 16 bytes of entropy,\n    # we go with 32 because it doesn't cost us anything.\n    return _webauthn_b64encode(os.urandom(32)).decode()\n\n\ndef get_credential_options(user, *, challenge, rp_name, rp_id):\n    \"\"\"\n    Returns a dictionary of options for credential creation\n    on the client side.\n    \"\"\"\n    options = pywebauthn.WebAuthnMakeCredentialOptions(\n        challenge,\n        rp_name,\n        rp_id,\n        str(user.id),\n        user.username,\n        user.name,\n        None,\n        user_verification=\"discouraged\",\n    )\n\n    return options.registration_dict\n\n\ndef get_assertion_options(user, *, challenge, rp_id):\n    \"\"\"\n    Returns a dictionary of options for assertion retrieval\n    on the client side.\n    \"\"\"\n    options = pywebauthn.WebAuthnAssertionOptions(\n        _get_webauthn_users(user, rp_id=rp_id), challenge\n    )\n\n    return options.assertion_dict\n\n\ndef verify_registration_response(response, challenge, *, rp_id, origin):\n    \"\"\"\n    Validates the challenge and attestation information\n    sent from the client during device registration.\n\n    Returns a WebAuthnCredential on success.\n    Raises RegistrationRejectedException on failire.\n    \"\"\"\n    # NOTE: We re-encode the challenge below, because our\n    # response's clientData.challenge is encoded twice:\n    # first for the entire clientData payload, and then again\n    # for the individual challenge.\n    encoded_challenge = _webauthn_b64encode(challenge.encode()).decode()\n    response = pywebauthn.WebAuthnRegistrationResponse(\n        rp_id, origin, response, encoded_challenge, self_attestation_permitted=True\n    )\n    try:\n        return response.verify()\n    except _RegistrationRejectedException as e:\n        raise RegistrationRejectedException(str(e))\n\n\ndef verify_assertion_response(assertion, *, challenge, user, origin, rp_id):\n    \"\"\"\n    Validates the challenge and assertion information\n    sent from the client during authentication.\n\n    Returns an updated signage count on success.\n    Raises AuthenticationRejectedException on failure.\n    \"\"\"\n    webauthn_users = _get_webauthn_users(user, rp_id=rp_id)\n    cred_ids = [cred.credential_id for cred in webauthn_users]\n    encoded_challenge = _webauthn_b64encode(challenge.encode()).decode()\n\n    for webauthn_user in webauthn_users:\n        response = pywebauthn.WebAuthnAssertionResponse(\n            webauthn_user,\n            assertion,\n            encoded_challenge,\n            origin,\n            allow_credentials=cred_ids,\n        )\n        try:\n            return (webauthn_user.credential_id, response.verify())\n        except _AuthenticationRejectedException:\n            pass\n\n    # If we exit the loop, then we've failed to verify the assertion against\n    # any of the user's WebAuthn credentials. Fail.\n    raise AuthenticationRejectedException(\"Invalid WebAuthn credential\")\n", "path": "warehouse/utils/webauthn.py"}]}