prompt: You will be provided with a partial code base and an issue statement explaining a problem to resolve.
  <issue>
  Refuse account creation when using disposable email addresses.
  long term it makes no sense to accept accounts which use an email address which is disposable for managing legit packages. short/near term it opens an easy door for spammers to create accounts on PyPI.
  
  i've implemented blacklisting for account signup and email swaps which use the blacklist at https://github.com/martenson/disposable-email-domains for legacy pypi.
  
  
  </issue>
  <code>
  [start of warehouse/accounts/forms.py]
  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 import re
  13 
  14 import wtforms
  15 import wtforms.fields.html5
  16 
  17 from warehouse import forms, recaptcha
  18 
  19 
  20 class CredentialsMixin:
  21     username = wtforms.StringField(
  22         validators=[
  23             wtforms.validators.DataRequired(),
  24             wtforms.validators.Length(max=50),
  25         ],
  26     )
  27 
  28     password = wtforms.PasswordField(
  29         validators=[
  30             wtforms.validators.DataRequired(),
  31         ],
  32     )
  33 
  34     def __init__(self, *args, user_service, **kwargs):
  35         super().__init__(*args, **kwargs)
  36         self.user_service = user_service
  37 
  38 
  39 # XXX: This is a naive password strength validator, but something that can
  40 # easily be replicated in JS for client-side feedback.
  41 # see: https://github.com/pypa/warehouse/issues/6
  42 PWD_MIN_LEN = 8
  43 PWD_RE = re.compile(r"""
  44 ^                                                       # start
  45 (?=.*[A-Z]+.*)                                          # >= 1 upper case
  46 (?=.*[a-z]+.*)                                          # >= 1 lower case
  47 (?=.*[0-9]+.*)                                          # >= 1 number
  48 (?=.*[.*~`\!@#$%^&\*\(\)_+-={}|\[\]\\:";'<>?,\./]+.*)   # >= 1 special char
  49 .{""" + str(PWD_MIN_LEN) + """,}                        # >= 8 chars
  50 $                                                       # end
  51 """, re.X)
  52 
  53 
  54 class RegistrationForm(CredentialsMixin, forms.Form):
  55     password_confirm = wtforms.PasswordField(
  56         validators=[
  57             wtforms.validators.DataRequired(),
  58             wtforms.validators.EqualTo(
  59                 "password", "Passwords must match."
  60             ),
  61         ],
  62     )
  63 
  64     full_name = wtforms.StringField()
  65 
  66     email = wtforms.fields.html5.EmailField(
  67         validators=[
  68             wtforms.validators.DataRequired(),
  69             wtforms.validators.Email(),
  70         ],
  71     )
  72 
  73     g_recaptcha_response = wtforms.StringField()
  74 
  75     def __init__(self, *args, recaptcha_service, **kwargs):
  76         super().__init__(*args, **kwargs)
  77         self.recaptcha_service = recaptcha_service
  78 
  79     def validate_username(self, field):
  80         if self.user_service.find_userid(field.data) is not None:
  81             raise wtforms.validators.ValidationError(
  82                 "Username exists.")
  83 
  84     def validate_email(self, field):
  85         if self.user_service.find_userid_by_email(field.data) is not None:
  86             raise wtforms.validators.ValidationError("Email exists.")
  87 
  88     def validate_g_recaptcha_response(self, field):
  89         # do required data validation here due to enabled flag being required
  90         if self.recaptcha_service.enabled and not field.data:
  91             raise wtforms.validators.ValidationError("Recaptcha error.")
  92         try:
  93             self.recaptcha_service.verify_response(field.data)
  94         except recaptcha.RecaptchaError:
  95             # TODO: log error
  96             # don't want to provide the user with any detail
  97             raise wtforms.validators.ValidationError("Recaptcha error.")
  98 
  99     def validate_password(self, field):
  100         if not PWD_RE.match(field.data):
  101             raise wtforms.validators.ValidationError(
  102                 "Password must contain an upper case letter, a lower case "
  103                 "letter, a number, a special character and be at least "
  104                 "%d characters in length" % PWD_MIN_LEN
  105             )
  106 
  107 
  108 class LoginForm(CredentialsMixin, forms.Form):
  109     def validate_username(self, field):
  110         userid = self.user_service.find_userid(field.data)
  111 
  112         if userid is None:
  113             raise wtforms.validators.ValidationError("Invalid user.")
  114 
  115     def validate_password(self, field):
  116         userid = self.user_service.find_userid(self.username.data)
  117         if userid is not None:
  118             if not self.user_service.check_password(userid, field.data):
  119                 raise wtforms.validators.ValidationError("Invalid password.")
  120
  [end of warehouse/accounts/forms.py]
  </code>
  
  I need you to solve this issue by generating a single patch file that I can apply directly to this repository using git apply. Please respond with a single patch file in the following format.
  <patch>
  diff --git a/file.py b/file.py
  --- a/file.py
  +++ b/file.py
  @@ -1,27 +1,35 @@
   def euclidean(a, b):
  -    while b:
  -        a, b = b, a % b
  -    return a
  +    if b == 0:
  +        return a
  +    return euclidean(b, a % b)
   
   
   def bresenham(x0, y0, x1, y1):
       points = []
       dx = abs(x1 - x0)
       dy = abs(y1 - y0)
  -    sx = 1 if x0 < x1 else -1
  -    sy = 1 if y0 < y1 else -1
  -    err = dx - dy
  +    x, y = x0, y0
  +    sx = -1 if x0 > x1 else 1
  +    sy = -1 if y0 > y1 else 1
   
  -    while True:
  -        points.append((x0, y0))
  -        if x0 == x1 and y0 == y1:
  -            break
  -        e2 = 2 * err
  -        if e2 > -dy:
  -            err -= dy
  -            x0 += sx
  -        if e2 < dx:
  -            err += dx
  -            y0 += sy
  +    if dx > dy:
  +        err = dx / 2.0
  +        while x != x1:
  +            points.append((x, y))
  +            err -= dy
  +            if err < 0:
  +                y += sy
  +                err += dx
  +            x += sx
  +    else:
  +        err = dy / 2.0
  +        while y != y1:
  +            points.append((x, y))
  +            err -= dx
  +            if err < 0:
  +                x += sx
  +                err += dy
  +            y += sy
  +
  +    points.append((x, y))
       return points
  
  </patch>
golden_diff: diff --git a/warehouse/accounts/forms.py b/warehouse/accounts/forms.py
  --- a/warehouse/accounts/forms.py
  +++ b/warehouse/accounts/forms.py
  @@ -11,6 +11,7 @@
   # limitations under the License.
   import re
   
  +import disposable_email_domains
   import wtforms
   import wtforms.fields.html5
   
  @@ -84,6 +85,9 @@
       def validate_email(self, field):
           if self.user_service.find_userid_by_email(field.data) is not None:
               raise wtforms.validators.ValidationError("Email exists.")
  +        domain = field.data.split('@')[-1]
  +        if domain in disposable_email_domains.blacklist:
  +            raise wtforms.validators.ValidationError("Disposable email.")
   
       def validate_g_recaptcha_response(self, field):
           # do required data validation here due to enabled flag being required
  
verification_info: {"golden_diff": "diff --git a/warehouse/accounts/forms.py b/warehouse/accounts/forms.py\n--- a/warehouse/accounts/forms.py\n+++ b/warehouse/accounts/forms.py\n@@ -11,6 +11,7 @@\n # limitations under the License.\n import re\n \n+import disposable_email_domains\n import wtforms\n import wtforms.fields.html5\n \n@@ -84,6 +85,9 @@\n     def validate_email(self, field):\n         if self.user_service.find_userid_by_email(field.data) is not None:\n             raise wtforms.validators.ValidationError(\"Email exists.\")\n+        domain = field.data.split('@')[-1]\n+        if domain in disposable_email_domains.blacklist:\n+            raise wtforms.validators.ValidationError(\"Disposable email.\")\n \n     def validate_g_recaptcha_response(self, field):\n         # do required data validation here due to enabled flag being required\n", "issue": "Refuse account creation when using disposable email addresses.\nlong term it makes no sense to accept accounts which use an email address which is disposable for managing legit packages. short/near term it opens an easy door for spammers to create accounts on PyPI.\n\ni've implemented blacklisting for account signup and email swaps which use the blacklist at https://github.com/martenson/disposable-email-domains for legacy pypi.\n\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.\nimport re\n\nimport wtforms\nimport wtforms.fields.html5\n\nfrom warehouse import forms, recaptcha\n\n\nclass CredentialsMixin:\n    username = wtforms.StringField(\n        validators=[\n            wtforms.validators.DataRequired(),\n            wtforms.validators.Length(max=50),\n        ],\n    )\n\n    password = wtforms.PasswordField(\n        validators=[\n            wtforms.validators.DataRequired(),\n        ],\n    )\n\n    def __init__(self, *args, user_service, **kwargs):\n        super().__init__(*args, **kwargs)\n        self.user_service = user_service\n\n\n# XXX: This is a naive password strength validator, but something that can\n# easily be replicated in JS for client-side feedback.\n# see: https://github.com/pypa/warehouse/issues/6\nPWD_MIN_LEN = 8\nPWD_RE = re.compile(r\"\"\"\n^                                                       # start\n(?=.*[A-Z]+.*)                                          # >= 1 upper case\n(?=.*[a-z]+.*)                                          # >= 1 lower case\n(?=.*[0-9]+.*)                                          # >= 1 number\n(?=.*[.*~`\\!@#$%^&\\*\\(\\)_+-={}|\\[\\]\\\\:\";'<>?,\\./]+.*)   # >= 1 special char\n.{\"\"\" + str(PWD_MIN_LEN) + \"\"\",}                        # >= 8 chars\n$                                                       # end\n\"\"\", re.X)\n\n\nclass RegistrationForm(CredentialsMixin, forms.Form):\n    password_confirm = wtforms.PasswordField(\n        validators=[\n            wtforms.validators.DataRequired(),\n            wtforms.validators.EqualTo(\n                \"password\", \"Passwords must match.\"\n            ),\n        ],\n    )\n\n    full_name = wtforms.StringField()\n\n    email = wtforms.fields.html5.EmailField(\n        validators=[\n            wtforms.validators.DataRequired(),\n            wtforms.validators.Email(),\n        ],\n    )\n\n    g_recaptcha_response = wtforms.StringField()\n\n    def __init__(self, *args, recaptcha_service, **kwargs):\n        super().__init__(*args, **kwargs)\n        self.recaptcha_service = recaptcha_service\n\n    def validate_username(self, field):\n        if self.user_service.find_userid(field.data) is not None:\n            raise wtforms.validators.ValidationError(\n                \"Username exists.\")\n\n    def validate_email(self, field):\n        if self.user_service.find_userid_by_email(field.data) is not None:\n            raise wtforms.validators.ValidationError(\"Email exists.\")\n\n    def validate_g_recaptcha_response(self, field):\n        # do required data validation here due to enabled flag being required\n        if self.recaptcha_service.enabled and not field.data:\n            raise wtforms.validators.ValidationError(\"Recaptcha error.\")\n        try:\n            self.recaptcha_service.verify_response(field.data)\n        except recaptcha.RecaptchaError:\n            # TODO: log error\n            # don't want to provide the user with any detail\n            raise wtforms.validators.ValidationError(\"Recaptcha error.\")\n\n    def validate_password(self, field):\n        if not PWD_RE.match(field.data):\n            raise wtforms.validators.ValidationError(\n                \"Password must contain an upper case letter, a lower case \"\n                \"letter, a number, a special character and be at least \"\n                \"%d characters in length\" % PWD_MIN_LEN\n            )\n\n\nclass LoginForm(CredentialsMixin, forms.Form):\n    def validate_username(self, field):\n        userid = self.user_service.find_userid(field.data)\n\n        if userid is None:\n            raise wtforms.validators.ValidationError(\"Invalid user.\")\n\n    def validate_password(self, field):\n        userid = self.user_service.find_userid(self.username.data)\n        if userid is not None:\n            if not self.user_service.check_password(userid, field.data):\n                raise wtforms.validators.ValidationError(\"Invalid password.\")\n", "path": "warehouse/accounts/forms.py"}]}