prompt: You will be provided with a partial code base and an issue statement explaining a problem to resolve.
  <issue>
  Tokens are able to enumerate project names regardless of organization membership.
  We respond with 404s when there are missing project names, but 403s when there is an existing project. Probably should just check for organization membership before even going into the project fetching.
  # Original HackerOne Report
  
  Title:  Project Enumeration of Other Teams
  Types:  Information Disclosure
  Link:   https://hackerone.com/reports/154048
  Date:   2016-07-26 05:25:05 -0700
  By:     vagg-a-bond
  
  Details:
  Hello,
  
  It is possible for any valid user of @sentry to enumerate project names in other team by comparing errors. 
  
  For example, if user user accesses `GET /api/0/projects/sumne/project_sumne_001/` which is not of his/her, then error will be `403 FORBIDDEN` and for  `GET /api/0/projects/sumne/project_sumne_001_not_there/` application responds with `404 NOT FOUND`
  
  So an attacker can enumerate all the projects available in a team by automating the process to request `GET /api/0/projects/TARGET_TEAM_NAME/PROJECT_NAME/`. 
  
  **Vulnerable Endpoint:**
  
  > GET /api/0/projects/sumne/project_sumne_001/*
  
  **Recommended Fix:**
  Respond with `404 NOT FOUND` for both.  
  
  
  </issue>
  <code>
  [start of src/sentry/api/bases/project.py]
  1 from __future__ import absolute_import
  2 
  3 from sentry.auth import access
  4 from sentry.api.base import Endpoint
  5 from sentry.api.exceptions import ResourceDoesNotExist
  6 from sentry.api.permissions import ScopedPermission
  7 from sentry.models import Project, ProjectStatus
  8 from sentry.models.apikey import ROOT_KEY
  9 
  10 
  11 class ProjectPermission(ScopedPermission):
  12     scope_map = {
  13         'GET': ['project:read', 'project:write', 'project:delete'],
  14         'POST': ['project:write', 'project:delete'],
  15         'PUT': ['project:write', 'project:delete'],
  16         'DELETE': ['project:delete'],
  17     }
  18 
  19     def has_object_permission(self, request, view, project):
  20         if request.user and request.user.is_authenticated() and request.auth:
  21             request.access = access.from_request(
  22                 request, project.organization, scopes=request.auth.get_scopes(),
  23             )
  24 
  25         elif request.auth:
  26             if request.auth is ROOT_KEY:
  27                 return True
  28             return request.auth.organization_id == project.organization_id
  29 
  30         else:
  31             request.access = access.from_request(request, project.organization)
  32 
  33         allowed_scopes = set(self.scope_map.get(request.method, []))
  34         return any(
  35             request.access.has_team_scope(project.team, s)
  36             for s in allowed_scopes
  37         )
  38 
  39 
  40 class ProjectReleasePermission(ProjectPermission):
  41     scope_map = {
  42         'GET': ['project:read', 'project:write', 'project:delete', 'project:releases'],
  43         'POST': ['project:write', 'project:delete', 'project:releases'],
  44         'PUT': ['project:write', 'project:delete', 'project:releases'],
  45         'DELETE': ['project:delete', 'project:releases'],
  46     }
  47 
  48 
  49 class ProjectEventPermission(ProjectPermission):
  50     scope_map = {
  51         'GET': ['event:read', 'event:write', 'event:delete'],
  52         'POST': ['event:write', 'event:delete'],
  53         'PUT': ['event:write', 'event:delete'],
  54         'DELETE': ['event:delete'],
  55     }
  56 
  57 
  58 class ProjectEndpoint(Endpoint):
  59     permission_classes = (ProjectPermission,)
  60 
  61     def convert_args(self, request, organization_slug, project_slug, *args, **kwargs):
  62         try:
  63             project = Project.objects.get_from_cache(
  64                 organization__slug=organization_slug,
  65                 slug=project_slug,
  66             )
  67         except Project.DoesNotExist:
  68             raise ResourceDoesNotExist
  69 
  70         if project.status != ProjectStatus.VISIBLE:
  71             raise ResourceDoesNotExist
  72 
  73         self.check_object_permissions(request, project)
  74 
  75         kwargs['project'] = project
  76         return (args, kwargs)
  77
  [end of src/sentry/api/bases/project.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/src/sentry/api/bases/project.py b/src/sentry/api/bases/project.py
  --- a/src/sentry/api/bases/project.py
  +++ b/src/sentry/api/bases/project.py
  @@ -4,7 +4,7 @@
   from sentry.api.base import Endpoint
   from sentry.api.exceptions import ResourceDoesNotExist
   from sentry.api.permissions import ScopedPermission
  -from sentry.models import Project, ProjectStatus
  +from sentry.models import Organization, Project, ProjectStatus
   from sentry.models.apikey import ROOT_KEY
   
   
  @@ -59,9 +59,21 @@
       permission_classes = (ProjectPermission,)
   
       def convert_args(self, request, organization_slug, project_slug, *args, **kwargs):
  +        try:
  +            org = Organization.objects.get_from_cache(slug=organization_slug)
  +            if request.user:
  +                can_access_org = any(access.from_request(request, org).memberships)
  +            if request.auth:
  +                can_access_org = request.auth.organization_id == org.id
  +            if not can_access_org:
  +                raise ResourceDoesNotExist
  +
  +        except Organization.DoesNotExist:
  +            raise ResourceDoesNotExist
  +
           try:
               project = Project.objects.get_from_cache(
  -                organization__slug=organization_slug,
  +                organization=org,
                   slug=project_slug,
               )
           except Project.DoesNotExist:
  
verification_info: {"golden_diff": "diff --git a/src/sentry/api/bases/project.py b/src/sentry/api/bases/project.py\n--- a/src/sentry/api/bases/project.py\n+++ b/src/sentry/api/bases/project.py\n@@ -4,7 +4,7 @@\n from sentry.api.base import Endpoint\n from sentry.api.exceptions import ResourceDoesNotExist\n from sentry.api.permissions import ScopedPermission\n-from sentry.models import Project, ProjectStatus\n+from sentry.models import Organization, Project, ProjectStatus\n from sentry.models.apikey import ROOT_KEY\n \n \n@@ -59,9 +59,21 @@\n     permission_classes = (ProjectPermission,)\n \n     def convert_args(self, request, organization_slug, project_slug, *args, **kwargs):\n+        try:\n+            org = Organization.objects.get_from_cache(slug=organization_slug)\n+            if request.user:\n+                can_access_org = any(access.from_request(request, org).memberships)\n+            if request.auth:\n+                can_access_org = request.auth.organization_id == org.id\n+            if not can_access_org:\n+                raise ResourceDoesNotExist\n+\n+        except Organization.DoesNotExist:\n+            raise ResourceDoesNotExist\n+\n         try:\n             project = Project.objects.get_from_cache(\n-                organization__slug=organization_slug,\n+                organization=org,\n                 slug=project_slug,\n             )\n         except Project.DoesNotExist:\n", "issue": "Tokens are able to enumerate project names regardless of organization membership.\nWe respond with 404s when there are missing project names, but 403s when there is an existing project. Probably should just check for organization membership before even going into the project fetching.\n# Original HackerOne Report\n\nTitle:  Project Enumeration of Other Teams\nTypes:  Information Disclosure\nLink:   https://hackerone.com/reports/154048\nDate:   2016-07-26 05:25:05 -0700\nBy:     vagg-a-bond\n\nDetails:\nHello,\n\nIt is possible for any valid user of @sentry to enumerate project names in other team by comparing errors. \n\nFor example, if user user accesses `GET /api/0/projects/sumne/project_sumne_001/` which is not of his/her, then error will be `403 FORBIDDEN` and for  `GET /api/0/projects/sumne/project_sumne_001_not_there/` application responds with `404 NOT FOUND`\n\nSo an attacker can enumerate all the projects available in a team by automating the process to request `GET /api/0/projects/TARGET_TEAM_NAME/PROJECT_NAME/`. \n\n**Vulnerable Endpoint:**\n\n> GET /api/0/projects/sumne/project_sumne_001/*\n\n**Recommended Fix:**\nRespond with `404 NOT FOUND` for both.  \n\n", "before_files": [{"content": "from __future__ import absolute_import\n\nfrom sentry.auth import access\nfrom sentry.api.base import Endpoint\nfrom sentry.api.exceptions import ResourceDoesNotExist\nfrom sentry.api.permissions import ScopedPermission\nfrom sentry.models import Project, ProjectStatus\nfrom sentry.models.apikey import ROOT_KEY\n\n\nclass ProjectPermission(ScopedPermission):\n    scope_map = {\n        'GET': ['project:read', 'project:write', 'project:delete'],\n        'POST': ['project:write', 'project:delete'],\n        'PUT': ['project:write', 'project:delete'],\n        'DELETE': ['project:delete'],\n    }\n\n    def has_object_permission(self, request, view, project):\n        if request.user and request.user.is_authenticated() and request.auth:\n            request.access = access.from_request(\n                request, project.organization, scopes=request.auth.get_scopes(),\n            )\n\n        elif request.auth:\n            if request.auth is ROOT_KEY:\n                return True\n            return request.auth.organization_id == project.organization_id\n\n        else:\n            request.access = access.from_request(request, project.organization)\n\n        allowed_scopes = set(self.scope_map.get(request.method, []))\n        return any(\n            request.access.has_team_scope(project.team, s)\n            for s in allowed_scopes\n        )\n\n\nclass ProjectReleasePermission(ProjectPermission):\n    scope_map = {\n        'GET': ['project:read', 'project:write', 'project:delete', 'project:releases'],\n        'POST': ['project:write', 'project:delete', 'project:releases'],\n        'PUT': ['project:write', 'project:delete', 'project:releases'],\n        'DELETE': ['project:delete', 'project:releases'],\n    }\n\n\nclass ProjectEventPermission(ProjectPermission):\n    scope_map = {\n        'GET': ['event:read', 'event:write', 'event:delete'],\n        'POST': ['event:write', 'event:delete'],\n        'PUT': ['event:write', 'event:delete'],\n        'DELETE': ['event:delete'],\n    }\n\n\nclass ProjectEndpoint(Endpoint):\n    permission_classes = (ProjectPermission,)\n\n    def convert_args(self, request, organization_slug, project_slug, *args, **kwargs):\n        try:\n            project = Project.objects.get_from_cache(\n                organization__slug=organization_slug,\n                slug=project_slug,\n            )\n        except Project.DoesNotExist:\n            raise ResourceDoesNotExist\n\n        if project.status != ProjectStatus.VISIBLE:\n            raise ResourceDoesNotExist\n\n        self.check_object_permissions(request, project)\n\n        kwargs['project'] = project\n        return (args, kwargs)\n", "path": "src/sentry/api/bases/project.py"}]}