Pārlūkot izejas kodu

Adding autokick option to only kick users who go offline seconds after joining. Added presence permission to intents to get member status.

master
Rocketsoup 2 gadus atpakaļ
vecāks
revīzija
6292a00b59
2 mainītis faili ar 52 papildinājumiem un 2 dzēšanām
  1. 1
    0
      bot.py
  2. 51
    2
      rocketbot/cogs/autokickcog.py

+ 1
- 0
bot.py Parādīt failu

@@ -57,6 +57,7 @@ class Rocketbot(commands.Bot):
57 57
 intents = Intents.default()
58 58
 intents.messages = True  # pylint: disable=assigning-non-slot
59 59
 intents.members = True  # pylint: disable=assigning-non-slot
60
+intents.presences = True
60 61
 bot = Rocketbot(command_prefix=CONFIG['command_prefix'], intents=intents)
61 62
 
62 63
 # Core

+ 51
- 2
rocketbot/cogs/autokickcog.py Parādīt failu

@@ -1,12 +1,15 @@
1 1
 from datetime import datetime, timedelta
2
+from typing import cast
2 3
 
3
-from discord import Guild, Member
4
-from discord.ext import commands
4
+from discord import Guild, Member, Status
5
+from discord.ext import commands, tasks
6
+from discord.ext.tasks import Loop
5 7
 
6 8
 from config import CONFIG
7 9
 from rocketbot.cogs.basecog import BaseCog, BotMessage, CogSetting
8 10
 from rocketbot.collections import AgeBoundDict
9 11
 from rocketbot.storage import Storage
12
+from rocketbot.utils import bot_log
10 13
 
11 14
 class AutoKickContext:
12 15
 	"""
@@ -22,6 +25,11 @@ class AutoKickContext:
22 25
 		self.last_kick = time
23 26
 		self.kick_count += 1
24 27
 
28
+class StatusCheckContext:
29
+	def __init__(self, member: Member):
30
+		self.member = member
31
+		self.joined_at = datetime.now()
32
+
25 33
 class AutoKickCog(BaseCog, name='Auto Kick'):
26 34
 	"""
27 35
 	Cog for automatically kicking ALL new joins. For temporary use during join raids.
@@ -36,6 +44,13 @@ class AutoKickCog(BaseCog, name='Auto Kick'):
36 44
 					'disables this feature (only kick, never ban).',
37 45
 			usage='<count:int>',
38 46
 			min_value=0)
47
+	SETTING_OFFLINE_ONLY = CogSetting('offlineonly', bool,
48
+			brief='whether to only kick users whose status is offline',
49
+			description='Compromised accounts may have a status of offline. ' + \
50
+					'If this setting is enabled, the user\'s status will be ' + \
51
+					'checked a few seconds after joining. If it is offline ' + \
52
+					'they will be kicked.',
53
+			usage='<true|false>')
39 54
 
40 55
 	STATE_KEY_RECENT_KICKS = "AutoKickCog.recent_joins"
41 56
 
@@ -43,6 +58,10 @@ class AutoKickCog(BaseCog, name='Auto Kick'):
43 58
 		super().__init__(bot)
44 59
 		self.add_setting(AutoKickCog.SETTING_ENABLED)
45 60
 		self.add_setting(AutoKickCog.SETTING_BAN_COUNT)
61
+		self.add_setting(AutoKickCog.SETTING_OFFLINE_ONLY)
62
+		self.status_check_members = []
63
+		timer: Loop = cast(Loop, self.status_check_timer)
64
+		timer.start()
46 65
 
47 66
 	@commands.group(
48 67
 		brief='Automatically kicks all new users as soon as they join',
@@ -60,6 +79,36 @@ class AutoKickCog(BaseCog, name='Auto Kick'):
60 79
 		guild: Guild = member.guild
61 80
 		if not self.get_guild_setting(guild, self.SETTING_ENABLED):
62 81
 			return
82
+		if self.get_guild_setting(guild, self.SETTING_OFFLINE_ONLY):
83
+			self.log(guild, f'New member {member.name} status is {member.status}')
84
+			self.status_check_members.append(StatusCheckContext(member))
85
+			return
86
+		self.__kick_or_ban_if_needed(member)
87
+
88
+	@tasks.loop(seconds=5.0)
89
+	async def status_check_timer(self):
90
+		'Checks status of new members shortly after joining to see if they go offline'
91
+		contexts = self.status_check_members.copy()
92
+		self.status_check_members = []
93
+		now = datetime.now()
94
+		# bot_log(guild=None, cog_class=None, message=f'Found {len(contexts)} members to check')
95
+		for c in contexts:
96
+			context: StatusCheckContext = c
97
+			member: Member = context.member
98
+			guild: Guild = member.guild
99
+			if now - context.joined_at < timedelta(seconds=5.0):
100
+				# Too soon, check again later
101
+				self.status_check_members.append(context)
102
+				continue
103
+			if member.status != Status.offline:
104
+				# Online, ignore
105
+				self.log(guild, f'{member.name} status is {member.status}. Not kicking.')
106
+				continue
107
+			self.log(guild, f'{member.name} went offline 5s later')
108
+			await self.__kick_or_ban_if_needed(member)
109
+
110
+	async def __kick_or_ban_if_needed(self, member: Member):
111
+		guild: Guild = member.guild
63 112
 		recent_kicks: AgeBoundDict = Storage.get_state_value(guild, AutoKickCog.STATE_KEY_RECENT_KICKS)
64 113
 		if recent_kicks is None:
65 114
 			recent_kicks = AgeBoundDict(timedelta(seconds=3600), lambda i, context : context.last_kick)

Notiek ielāde…
Atcelt
Saglabāt