prompt: You will be provided with a partial code base and an issue statement explaining a problem to resolve.
  <issue>
  A suspicious user trying to log in results in a 500
  https://app.getsentry.com/gratipay/gratipay-com/group/32039756/
  
  <bountysource-plugin>
  
  ---
  
  Want to back this issue? **[Place a bounty on it!](https://www.bountysource.com/issues/4727299-a-suspicious-user-trying-to-log-in-results-in-a-500?utm_campaign=plugin&utm_content=tracker%2F85909&utm_medium=issues&utm_source=github)** We accept bounties via [Bountysource](https://www.bountysource.com/?utm_campaign=plugin&utm_content=tracker%2F85909&utm_medium=issues&utm_source=github).
  </bountysource-plugin>
  
  A suspicious user trying to log in results in a 500
  https://app.getsentry.com/gratipay/gratipay-com/group/32039756/
  
  <bountysource-plugin>
  
  ---
  
  Want to back this issue? **[Place a bounty on it!](https://www.bountysource.com/issues/4727299-a-suspicious-user-trying-to-log-in-results-in-a-500?utm_campaign=plugin&utm_content=tracker%2F85909&utm_medium=issues&utm_source=github)** We accept bounties via [Bountysource](https://www.bountysource.com/?utm_campaign=plugin&utm_content=tracker%2F85909&utm_medium=issues&utm_source=github).
  </bountysource-plugin>
  
  
  </issue>
  <code>
  [start of gratipay/security/user.py]
  1 
  2 from datetime import timedelta
  3 import uuid
  4 
  5 from aspen.utils import utcnow
  6 from gratipay.models.participant import Participant
  7 from gratipay.utils import set_cookie
  8 
  9 
  10 SESSION = b'session'
  11 SESSION_REFRESH = timedelta(hours=1)
  12 SESSION_TIMEOUT = timedelta(hours=6)
  13 
  14 
  15 class User(object):
  16     """Represent a user of our website.
  17     """
  18 
  19     participant = None
  20 
  21 
  22     # Constructors
  23     # ============
  24 
  25     @classmethod
  26     def from_session_token(cls, token):
  27         """Find a participant based on token and return a User.
  28         """
  29         self = cls()
  30         self.participant = Participant.from_session_token(token)
  31         return self
  32 
  33     @classmethod
  34     def from_api_key(cls, api_key):
  35         """Find a participant based on token and return a User.
  36         """
  37         self = cls()
  38         self.participant = Participant.from_api_key(api_key)
  39         return self
  40 
  41     @classmethod
  42     def from_username(cls, username):
  43         """Find a participant based on username and return a User.
  44         """
  45         self = cls()
  46         self.participant = Participant.from_username(username)
  47         return self
  48 
  49     def __str__(self):
  50         if self.participant is None:
  51             out = '<Anonymous>'
  52         else:
  53             out = '<User: %s>' % self.participant.username
  54         return out
  55     __repr__ = __str__
  56 
  57 
  58     # Authentication Helpers
  59     # ======================
  60 
  61     def sign_in(self, cookies):
  62         """Start a new session for the user.
  63         """
  64         token = uuid.uuid4().hex
  65         expires = utcnow() + SESSION_TIMEOUT
  66         self.participant.update_session(token, expires)
  67         set_cookie(cookies, SESSION, token, expires)
  68 
  69     def keep_signed_in(self, cookies):
  70         """Extend the user's current session.
  71         """
  72         new_expires = utcnow() + SESSION_TIMEOUT
  73         if new_expires - self.participant.session_expires > SESSION_REFRESH:
  74             self.participant.set_session_expires(new_expires)
  75             token = self.participant.session_token
  76             set_cookie(cookies, SESSION, token, expires=new_expires)
  77 
  78     def sign_out(self, cookies):
  79         """End the user's current session.
  80         """
  81         self.participant.update_session(None, None)
  82         self.participant = None
  83         set_cookie(cookies, SESSION, '')
  84 
  85 
  86     # Roles
  87     # =====
  88 
  89     @property
  90     def ADMIN(self):
  91         return not self.ANON and self.participant.is_admin
  92 
  93     @property
  94     def ANON(self):
  95         return self.participant is None or self.participant.is_suspicious is True
  96         # Append "is True" here because otherwise Python will return the result
  97         # of evaluating the right side of the or expression, which can be None.
  98 
  99     def get_highest_role(self, owner):
  100         """Return a string representing the highest role this user has.
  101 
  102         :param string owner: the username of the owner of the resource we're
  103             concerned with, or None
  104 
  105         """
  106         def is_owner():
  107             if self.participant is not None:
  108                 if owner is not None:
  109                     if self.participant.username == owner:
  110                         return True
  111             return False
  112 
  113         if self.ADMIN:
  114             return 'admin'
  115         elif is_owner():
  116             return 'owner'
  117         elif not self.ANON:
  118             return 'authenticated'
  119         else:
  120             return 'anonymous'
  121
  [end of gratipay/security/user.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/gratipay/security/user.py b/gratipay/security/user.py
  --- a/gratipay/security/user.py
  +++ b/gratipay/security/user.py
  @@ -92,9 +92,7 @@
   
       @property
       def ANON(self):
  -        return self.participant is None or self.participant.is_suspicious is True
  -        # Append "is True" here because otherwise Python will return the result
  -        # of evaluating the right side of the or expression, which can be None.
  +        return self.participant is None
   
       def get_highest_role(self, owner):
           """Return a string representing the highest role this user has.
  
verification_info: {"golden_diff": "diff --git a/gratipay/security/user.py b/gratipay/security/user.py\n--- a/gratipay/security/user.py\n+++ b/gratipay/security/user.py\n@@ -92,9 +92,7 @@\n \n     @property\n     def ANON(self):\n-        return self.participant is None or self.participant.is_suspicious is True\n-        # Append \"is True\" here because otherwise Python will return the result\n-        # of evaluating the right side of the or expression, which can be None.\n+        return self.participant is None\n \n     def get_highest_role(self, owner):\n         \"\"\"Return a string representing the highest role this user has.\n", "issue": "A suspicious user trying to log in results in a 500\nhttps://app.getsentry.com/gratipay/gratipay-com/group/32039756/\n\n<bountysource-plugin>\n\n---\n\nWant to back this issue? **[Place a bounty on it!](https://www.bountysource.com/issues/4727299-a-suspicious-user-trying-to-log-in-results-in-a-500?utm_campaign=plugin&utm_content=tracker%2F85909&utm_medium=issues&utm_source=github)** We accept bounties via [Bountysource](https://www.bountysource.com/?utm_campaign=plugin&utm_content=tracker%2F85909&utm_medium=issues&utm_source=github).\n</bountysource-plugin>\n\nA suspicious user trying to log in results in a 500\nhttps://app.getsentry.com/gratipay/gratipay-com/group/32039756/\n\n<bountysource-plugin>\n\n---\n\nWant to back this issue? **[Place a bounty on it!](https://www.bountysource.com/issues/4727299-a-suspicious-user-trying-to-log-in-results-in-a-500?utm_campaign=plugin&utm_content=tracker%2F85909&utm_medium=issues&utm_source=github)** We accept bounties via [Bountysource](https://www.bountysource.com/?utm_campaign=plugin&utm_content=tracker%2F85909&utm_medium=issues&utm_source=github).\n</bountysource-plugin>\n\n", "before_files": [{"content": "\nfrom datetime import timedelta\nimport uuid\n\nfrom aspen.utils import utcnow\nfrom gratipay.models.participant import Participant\nfrom gratipay.utils import set_cookie\n\n\nSESSION = b'session'\nSESSION_REFRESH = timedelta(hours=1)\nSESSION_TIMEOUT = timedelta(hours=6)\n\n\nclass User(object):\n    \"\"\"Represent a user of our website.\n    \"\"\"\n\n    participant = None\n\n\n    # Constructors\n    # ============\n\n    @classmethod\n    def from_session_token(cls, token):\n        \"\"\"Find a participant based on token and return a User.\n        \"\"\"\n        self = cls()\n        self.participant = Participant.from_session_token(token)\n        return self\n\n    @classmethod\n    def from_api_key(cls, api_key):\n        \"\"\"Find a participant based on token and return a User.\n        \"\"\"\n        self = cls()\n        self.participant = Participant.from_api_key(api_key)\n        return self\n\n    @classmethod\n    def from_username(cls, username):\n        \"\"\"Find a participant based on username and return a User.\n        \"\"\"\n        self = cls()\n        self.participant = Participant.from_username(username)\n        return self\n\n    def __str__(self):\n        if self.participant is None:\n            out = '<Anonymous>'\n        else:\n            out = '<User: %s>' % self.participant.username\n        return out\n    __repr__ = __str__\n\n\n    # Authentication Helpers\n    # ======================\n\n    def sign_in(self, cookies):\n        \"\"\"Start a new session for the user.\n        \"\"\"\n        token = uuid.uuid4().hex\n        expires = utcnow() + SESSION_TIMEOUT\n        self.participant.update_session(token, expires)\n        set_cookie(cookies, SESSION, token, expires)\n\n    def keep_signed_in(self, cookies):\n        \"\"\"Extend the user's current session.\n        \"\"\"\n        new_expires = utcnow() + SESSION_TIMEOUT\n        if new_expires - self.participant.session_expires > SESSION_REFRESH:\n            self.participant.set_session_expires(new_expires)\n            token = self.participant.session_token\n            set_cookie(cookies, SESSION, token, expires=new_expires)\n\n    def sign_out(self, cookies):\n        \"\"\"End the user's current session.\n        \"\"\"\n        self.participant.update_session(None, None)\n        self.participant = None\n        set_cookie(cookies, SESSION, '')\n\n\n    # Roles\n    # =====\n\n    @property\n    def ADMIN(self):\n        return not self.ANON and self.participant.is_admin\n\n    @property\n    def ANON(self):\n        return self.participant is None or self.participant.is_suspicious is True\n        # Append \"is True\" here because otherwise Python will return the result\n        # of evaluating the right side of the or expression, which can be None.\n\n    def get_highest_role(self, owner):\n        \"\"\"Return a string representing the highest role this user has.\n\n        :param string owner: the username of the owner of the resource we're\n            concerned with, or None\n\n        \"\"\"\n        def is_owner():\n            if self.participant is not None:\n                if owner is not None:\n                    if self.participant.username == owner:\n                        return True\n            return False\n\n        if self.ADMIN:\n            return 'admin'\n        elif is_owner():\n            return 'owner'\n        elif not self.ANON:\n            return 'authenticated'\n        else:\n            return 'anonymous'\n", "path": "gratipay/security/user.py"}]}