We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN 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.  


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `src/sentry/api/bases/project.py`
Content:
```
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 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/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:

{"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"}], "after_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 Organization, 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            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=org,\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"}]}