Browse Source

Revert "fix(discord): Verify User Bot Installation Permission (#76360)"

This reverts commit 346d4829241d5f49cd13a1514abeb3ecfc1303f1.

Co-authored-by: iamrajjoshi <33237075+iamrajjoshi@users.noreply.github.com>
getsentry-bot 6 months ago
parent
commit
9ded21a2fc

+ 0 - 30
src/sentry/integrations/discord/client.py

@@ -12,7 +12,6 @@ from rest_framework import status
 from sentry import options
 from sentry.integrations.client import ApiClient
 from sentry.integrations.discord.message_builder.base.base import DiscordMessageBuilder
-from sentry.integrations.discord.types import DiscordPermissions
 from sentry.integrations.discord.utils.consts import DISCORD_ERROR_CODES, DISCORD_USER_ERRORS
 
 # to avoid a circular import
@@ -103,35 +102,6 @@ class DiscordClient(ApiClient):
         user_id = response["id"]  # type: ignore[index]
         return user_id
 
-    def check_user_bot_installation_permission(self, access_token: str, guild_id: str) -> bool:
-        headers = {"Authorization": f"Bearer {access_token}"}
-
-        # We only want information about guild_id so we filter everything else out
-        # Need to do this very convoluted way of getting the guild information because
-        # https://github.com/discord/discord-api-docs/discussions/6846
-        # TODO(iamrajjoshi): Eventually, we should use `/users/@me/guilds/{guild.id}/member`
-        params = {"before": str(int(guild_id) + 1), "after": str(int(guild_id) - 1), "limit": 1}
-
-        response = self.get("/users/@me/guilds", headers=headers, params=params)
-        if not response or not isinstance(response, list):
-            return False
-
-        # We will only get one guild back, so we can just grab the first one
-        guild_information = response[0]
-
-        if not guild_information:
-            return False
-
-        permissions = int(guild_information["permissions"])
-        can_manage_guild = (
-            permissions & DiscordPermissions.MANAGE_GUILD.value
-        ) == DiscordPermissions.MANAGE_GUILD.value
-        is_admin = (
-            permissions & DiscordPermissions.ADMINISTRATOR.value
-        ) == DiscordPermissions.ADMINISTRATOR.value
-
-        return can_manage_guild or is_admin
-
     def leave_guild(self, guild_id: str) -> None:
         """
         Leave the given guild_id, if the bot is currently a member.

+ 16 - 8
src/sentry/integrations/discord/integration.py

@@ -1,6 +1,7 @@
 from __future__ import annotations
 
 from collections.abc import Mapping, Sequence
+from enum import Enum
 from typing import Any
 from urllib.parse import urlencode
 
@@ -16,7 +17,6 @@ from sentry.integrations.base import (
     IntegrationProvider,
 )
 from sentry.integrations.discord.client import DiscordClient
-from sentry.integrations.discord.types import DiscordPermissions
 from sentry.integrations.models.integration import Integration
 from sentry.organizations.services.organization.model import RpcOrganizationSummary
 from sentry.pipeline.views.base import PipelineView
@@ -111,6 +111,19 @@ class DiscordIntegration(IntegrationInstallation):
             return
 
 
+class DiscordPermissions(Enum):
+    # https://discord.com/developers/docs/topics/permissions#permissions
+    VIEW_CHANNEL = 1 << 10
+    SEND_MESSAGES = 1 << 11
+    SEND_TTS_MESSAGES = 1 << 12
+    EMBED_LINKS = 1 << 14
+    ATTACH_FILES = 1 << 15
+    MANAGE_THREADS = 1 << 34
+    CREATE_PUBLIC_THREADS = 1 << 35
+    CREATE_PRIVATE_THREADS = 1 << 36
+    SEND_MESSAGES_IN_THREADS = 1 << 38
+
+
 class DiscordIntegrationProvider(IntegrationProvider):
     key = "discord"
     name = "Discord"
@@ -120,7 +133,6 @@ class DiscordIntegrationProvider(IntegrationProvider):
 
     # https://discord.com/developers/docs/topics/oauth2#shared-resources-oauth2-scopes
     oauth_scopes = frozenset(["applications.commands", "bot", "identify"])
-    access_token = ""
 
     bot_permissions = (
         DiscordPermissions.VIEW_CHANNEL.value
@@ -163,10 +175,6 @@ class DiscordIntegrationProvider(IntegrationProvider):
         auth_code = str(state.get("code"))
         if auth_code:
             discord_user_id = self._get_discord_user_id(auth_code, url)
-            if not self.client.check_user_bot_installation_permission(
-                access_token=self.access_token, guild_id=guild_id
-            ):
-                raise IntegrationError("User does not have permissions to install bot.")
         else:
             raise IntegrationError("Missing code from state.")
 
@@ -230,13 +238,13 @@ class DiscordIntegrationProvider(IntegrationProvider):
 
         """
         try:
-            self.access_token = self.client.get_access_token(auth_code, url)
+            access_token = self.client.get_access_token(auth_code, url)
         except ApiError:
             raise IntegrationError("Failed to get Discord access token from API.")
         except KeyError:
             raise IntegrationError("Failed to get Discord access token from key.")
         try:
-            user_id = self.client.get_user_id(self.access_token)
+            user_id = self.client.get_user_id(access_token)
         except ApiError:
             raise IntegrationError("Failed to get Discord user ID from API.")
         except KeyError:

+ 0 - 17
src/sentry/integrations/discord/types.py

@@ -1,17 +0,0 @@
-from enum import Enum
-
-
-class DiscordPermissions(Enum):
-    # https://discord.com/developers/docs/topics/permissions#permissions
-    VIEW_CHANNEL = 1 << 10
-    SEND_MESSAGES = 1 << 11
-    SEND_TTS_MESSAGES = 1 << 12
-    EMBED_LINKS = 1 << 14
-    ATTACH_FILES = 1 << 15
-    MANAGE_THREADS = 1 << 34
-    CREATE_PUBLIC_THREADS = 1 << 35
-    CREATE_PRIVATE_THREADS = 1 << 36
-    SEND_MESSAGES_IN_THREADS = 1 << 38
-
-    MANAGE_GUILD = 1 << 5
-    ADMINISTRATOR = 1 << 3

+ 22 - 80
tests/sentry/integrations/discord/test_integration.py

@@ -9,7 +9,6 @@ from sentry import audit_log, options
 from sentry.api.client import ApiError
 from sentry.integrations.discord.client import APPLICATION_COMMANDS_URL, GUILD_URL, DiscordClient
 from sentry.integrations.discord.integration import COMMANDS, DiscordIntegrationProvider
-from sentry.integrations.discord.types import DiscordPermissions
 from sentry.integrations.models.integration import Integration
 from sentry.models.auditlogentry import AuditLogEntry
 from sentry.shared_integrations.exceptions import IntegrationError
@@ -73,12 +72,6 @@ class DiscordSetupTestCase(IntegrationTestCase):
             json=[] if command_response_empty else COMMANDS,
         )
 
-        responses.add(
-            responses.GET,
-            url=f"{DiscordClient.base_url}/users/@me/guilds",
-            json=[{"id": guild_id, "permissions": str(DiscordPermissions.MANAGE_GUILD.value)}],
-        )
-
         if command_response_empty:
             for command in COMMANDS:
                 responses.add(
@@ -167,13 +160,6 @@ class DiscordSetupTestCase(IntegrationTestCase):
                 "access_token": "access_token",
             },
         )
-
-        responses.add(
-            responses.GET,
-            url=f"{DiscordClient.base_url}/users/@me/guilds",
-            json=[{"id": guild_id, "permissions": str(DiscordPermissions.MANAGE_GUILD.value)}],
-        )
-
         responses.add(
             responses.GET, url=f"{DiscordClient.base_url}/users/@me", json={"id": "user_1234"}
         )
@@ -251,22 +237,19 @@ class DiscordSetupIntegrationTest(DiscordSetupTestCase):
 
 
 class DiscordIntegrationTest(DiscordSetupTestCase):
-    def setUp(self):
-        super().setUp()
-        self.user_id = "user1234"
-        self.guild_id = "12345"
-        self.guild_name = "guild_name"
-
     @responses.activate
     def test_get_guild_name(self):
         provider = self.provider()
+        user_id = "user1234"
+        guild_id = "guild_id"
+        guild_name = "guild_name"
         responses.add(
             responses.GET,
-            url=f"{DiscordClient.base_url}{GUILD_URL.format(guild_id=self.guild_id)}",
+            url=f"{DiscordClient.base_url}{GUILD_URL.format(guild_id=guild_id)}",
             match=[header_matcher({"Authorization": f"Bot {self.bot_token}"})],
             json={
-                "id": self.guild_id,
-                "name": self.guild_name,
+                "id": guild_id,
+                "name": guild_name,
             },
         )
         responses.add(
@@ -279,26 +262,21 @@ class DiscordIntegrationTest(DiscordSetupTestCase):
         responses.add(
             responses.GET, url=f"{DiscordClient.base_url}/users/@me", json={"id": "user_1234"}
         )
-
-        responses.add(
-            responses.GET,
-            url=f"{DiscordClient.base_url}/users/@me/guilds",
-            json=[{"id": self.guild_id, "permissions": str(DiscordPermissions.MANAGE_GUILD.value)}],
-        )
-
-        result = provider.build_integration({"guild_id": self.guild_id, "code": self.user_id})
-        assert result["name"] == self.guild_name
+        result = provider.build_integration({"guild_id": "guild_id", "code": user_id})
+        assert result["name"] == guild_name
 
     @responses.activate
     def test_build_integration_no_code_in_state(self):
         provider = self.provider()
+        guild_id = "guild_id"
+        guild_name = "guild_name"
         responses.add(
             responses.GET,
-            url=f"{DiscordClient.base_url}{GUILD_URL.format(guild_id=self.guild_id)}",
+            url=f"{DiscordClient.base_url}{GUILD_URL.format(guild_id=guild_id)}",
             match=[header_matcher({"Authorization": f"Bot {self.bot_token}"})],
             json={
-                "id": self.guild_id,
-                "name": self.guild_name,
+                "id": guild_id,
+                "name": guild_name,
             },
         )
         with pytest.raises(IntegrationError):
@@ -307,40 +285,9 @@ class DiscordIntegrationTest(DiscordSetupTestCase):
     @responses.activate
     def test_get_guild_name_failure(self):
         provider = self.provider()
-
-        responses.add(responses.GET, "https://discord.com/api/v10/guilds/guild_name", status=500),
-        responses.add(
-            responses.POST,
-            url="https://discord.com/api/v10/oauth2/token",
-            json={
-                "access_token": "access_token",
-            },
-        )
-        responses.add(
-            responses.GET, url=f"{DiscordClient.base_url}/users/@me", json={"id": self.user_id}
-        )
-        responses.add(
-            responses.GET,
-            url=f"{DiscordClient.base_url}/users/@me/guilds",
-            json=[{"id": self.guild_id, "permissions": str(DiscordPermissions.MANAGE_GUILD.value)}],
-        )
-
-        result = provider.build_integration({"guild_id": self.guild_id, "code": self.user_id})
-        assert result["name"] == self.guild_id
-
-    @responses.activate
-    def test_get_user_insufficient_permission(self):
-        provider = self.provider()
-
-        responses.add(
-            responses.GET,
-            url=f"{DiscordClient.base_url}{GUILD_URL.format(guild_id=self.guild_id)}",
-            match=[header_matcher({"Authorization": f"Bot {self.bot_token}"})],
-            json={
-                "id": self.guild_id,
-                "name": self.guild_name,
-            },
-        )
+        user_id = "user1234"
+        guild_id = "guild_id"
+        responses.add(responses.GET, "https://discord.com/api/v10/guilds/guild_name", status=500)
         responses.add(
             responses.POST,
             url="https://discord.com/api/v10/oauth2/token",
@@ -349,20 +296,15 @@ class DiscordIntegrationTest(DiscordSetupTestCase):
             },
         )
         responses.add(
-            responses.GET, url=f"{DiscordClient.base_url}/users/@me", json={"id": self.user_id}
-        )
-        responses.add(
-            responses.GET,
-            url=f"{DiscordClient.base_url}/users/@me/guilds",
-            json=[{"id": self.guild_id, "permissions": str(DiscordPermissions.VIEW_CHANNEL.value)}],
+            responses.GET, url=f"{DiscordClient.base_url}/users/@me", json={"id": user_id}
         )
-
-        with pytest.raises(IntegrationError):
-            provider.build_integration({"guild_id": self.guild_id, "code": self.user_id})
+        result = provider.build_integration({"guild_id": guild_id, "code": user_id})
+        assert result["name"] == guild_id
 
     @responses.activate
     def test_get_discord_user_id(self):
         provider = self.provider()
+        user_id = "user1234"
 
         responses.add(
             responses.POST,
@@ -372,12 +314,12 @@ class DiscordIntegrationTest(DiscordSetupTestCase):
             },
         )
         responses.add(
-            responses.GET, url=f"{DiscordClient.base_url}/users/@me", json={"id": self.user_id}
+            responses.GET, url=f"{DiscordClient.base_url}/users/@me", json={"id": user_id}
         )
 
         result = provider._get_discord_user_id("auth_code", "1")
 
-        assert result == self.user_id
+        assert result == user_id
 
     @responses.activate
     def test_get_discord_user_id_oauth_failure(self):