소스 검색

Adding ignored domains list to urlspamcog

main
Rocketsoup 3 달 전
부모
커밋
108de727d1
2개의 변경된 파일105개의 추가작업 그리고 52개의 파일을 삭제
  1. 1
    1
      README.md
  2. 104
    51
      rocketbot/cogs/urlspamcog.py

+ 1
- 1
README.md 파일 보기

4
 
4
 
5
 ## Requirements
5
 ## Requirements
6
 
6
 
7
-* Python 3.9
7
+* Python 3.10
8
 
8
 
9
 ## Setup
9
 ## Setup
10
 
10
 

+ 104
- 51
rocketbot/cogs/urlspamcog.py 파일 보기

5
 from datetime import timedelta
5
 from datetime import timedelta
6
 from typing import Literal
6
 from typing import Literal
7
 
7
 
8
-from discord import Member, Message
8
+from discord import Guild, Member, Message
9
 from discord import utils as discordutils
9
 from discord import utils as discordutils
10
 from discord.ext.commands import Cog
10
 from discord.ext.commands import Cog
11
 from discord.utils import escape_markdown
11
 from discord.utils import escape_markdown
69
 		enum_values={'nothing', 'modwarn', 'modwarndelete',
69
 		enum_values={'nothing', 'modwarn', 'modwarndelete',
70
 					 'chatwarn', 'chatwarndelete', 'delete', 'kick', 'ban'},
70
 					 'chatwarn', 'chatwarndelete', 'delete', 'kick', 'ban'},
71
 	)
71
 	)
72
+	SETTING_IGNORED_DOMAINS = CogSetting(
73
+		'ignoreddomains',
74
+		str,
75
+		default_value='tenor.com;giphy.com;imgur.com',
76
+		brief='List of allowed domains to exclude from detecting',
77
+		description='A semicolon-delimited list of domains that can be posted '
78
+					'without triggering a warning. E.g. GIF hosting sites.'
79
+	)
72
 
80
 
73
 	def __init__(self, bot):
81
 	def __init__(self, bot):
74
 		super().__init__(
82
 		super().__init__(
80
 		self.add_setting(URLSpamCog.SETTING_ACTION)
88
 		self.add_setting(URLSpamCog.SETTING_ACTION)
81
 		self.add_setting(URLSpamCog.SETTING_JOIN_AGE)
89
 		self.add_setting(URLSpamCog.SETTING_JOIN_AGE)
82
 		self.add_setting(URLSpamCog.SETTING_DECEPTIVE_ACTION)
90
 		self.add_setting(URLSpamCog.SETTING_DECEPTIVE_ACTION)
91
+		self.add_setting(URLSpamCog.SETTING_IGNORED_DOMAINS)
83
 
92
 
84
 	@Cog.listener()
93
 	@Cog.listener()
85
 	async def on_message(self, message: Message):
94
 	async def on_message(self, message: Message):
86
 		"""Event listener"""
95
 		"""Event listener"""
87
 		if message.author is None or \
96
 		if message.author is None or \
88
-				message.author.bot or \
89
 				message.guild is None or \
97
 				message.guild is None or \
90
 				message.channel is None or \
98
 				message.channel is None or \
91
 				message.content is None:
99
 				message.content is None:
100
+			self.__trace("Missing message data")
101
+			return
102
+		if message.author.bot:
103
+			self.__trace("Message from bot")
104
+			return
105
+		if message.channel.permissions_for(message.author).ban_members:
106
+			self.__trace("User exempt")
92
 			return
107
 			return
93
 		if not self.get_guild_setting(message.guild, self.SETTING_ENABLED):
108
 		if not self.get_guild_setting(message.guild, self.SETTING_ENABLED):
109
+			self.__trace("Cog disabled")
110
+			return
111
+		urls = self.__find_urls(message.content)
112
+		if len(urls) == 0:
113
+			self.__trace("Contains no URLs")
114
+			return
115
+		if self.__all_ignored_domains(message.guild, urls):
116
+			self.__trace("All URLs are ignored domains")
94
 			return
117
 			return
95
 		await self.check_message_recency(message)
118
 		await self.check_message_recency(message)
96
 		await self.check_deceptive_links(message)
119
 		await self.check_deceptive_links(message)
97
 
120
 
121
+	def __all_ignored_domains(self, guild: Guild, urls: list[str]) -> bool:
122
+		domain_list: str = self.get_guild_setting(guild, self.SETTING_IGNORED_DOMAINS)
123
+		self.__trace(f"Domain list is {domain_list}")
124
+		domains = domain_list.split(';')
125
+		self.__trace(f"Split into {len(domains)} domains")
126
+		for url in urls:
127
+			if not self.__is_ignored_url(url, domains):
128
+				return False
129
+		return True
130
+
131
+	def __is_ignored_url(self, url: str, ignored_domains: list[str]) -> bool:
132
+		p = re.compile(r'https?://([\w\.]+)')
133
+		domain = re.search(p, url).group(1)
134
+		for ignored_domain in ignored_domains:
135
+			if domain.endswith(ignored_domain.strip()):
136
+				self.__trace(f"URL {url} matches ignored domain {ignored_domain}")
137
+				return True
138
+		self.__trace("URL {url} not ignored")
139
+		return False
140
+
98
 	async def check_message_recency(self, message: Message):
141
 	async def check_message_recency(self, message: Message):
99
 		"""Checks if the message was sent too recently by a new user"""
142
 		"""Checks if the message was sent too recently by a new user"""
100
 		action = self.get_guild_setting(message.guild, self.SETTING_ACTION)
143
 		action = self.get_guild_setting(message.guild, self.SETTING_ACTION)
101
 		join_seconds = self.get_guild_setting(message.guild, self.SETTING_JOIN_AGE)
144
 		join_seconds = self.get_guild_setting(message.guild, self.SETTING_JOIN_AGE)
102
 		min_join_age = timedelta(seconds=join_seconds)
145
 		min_join_age = timedelta(seconds=join_seconds)
103
 		if action == 'nothing':
146
 		if action == 'nothing':
104
-			return
105
-		if not self.__contains_url(message.content):
147
+			self.__trace("Configured action is nothing")
106
 			return
148
 			return
107
 		join_age = message.created_at - message.author.joined_at
149
 		join_age = message.created_at - message.author.joined_at
108
 		join_age_str = describe_timedelta(join_age)
150
 		join_age_str = describe_timedelta(join_age)
109
-		if join_age < min_join_age:
110
-			context = URLSpamContext(message)
111
-			needs_attention = False
112
-			if action == 'modwarn':
113
-				needs_attention = not self.was_warned_recently(message.author)
114
-				self.log(message.guild, f'New user {message.author.name} ' + \
115
-					f'({message.author.id}) posted URL {join_age_str} after ' + \
116
-					'joining.' + (' Mods alerted.' if needs_attention else ''))
117
-			elif action == 'delete':
118
-				await message.delete()
119
-				context.is_deleted = True
120
-				self.log(message.guild, f'New user {message.author.name} ' + \
121
-					f'({message.author.id}) posted URL {join_age_str} after ' + \
122
-					'joining. Message deleted.')
123
-			elif action == 'kick':
124
-				await message.delete()
125
-				context.is_deleted = True
126
-				await message.author.kick(
127
-					reason=f'Rocketbot: Posted a link {join_age_str} after joining')
128
-				context.is_kicked = True
129
-				self.log(message.guild, f'New user {message.author.name} ' + \
130
-					f'({message.author.id}) posted URL {join_age_str} after ' + \
131
-					'joining. User kicked.')
132
-			elif action == 'ban':
133
-				await message.author.ban(
134
-					reason=f'Rocketbot: User posted a link {join_age_str} after joining',
135
-					delete_message_days=1)
136
-				context.is_deleted = True
137
-				context.is_kicked = True
138
-				context.is_banned = True
139
-				self.log(message.guild, f'New user {message.author.name} ' + \
140
-					f'({message.author.id}) posted URL {join_age_str} after ' + \
141
-					'joining. User banned.')
142
-			bm = BotMessage(
143
-					message.guild,
144
-					f'User {message.author.mention} posted a URL ' + \
145
-					f'{join_age_str} after joining: {message.jump_url}',
146
-					type = BotMessage.TYPE_MOD_WARNING if needs_attention else BotMessage.TYPE_INFO,
147
-					context = context)
148
-			bm.quote = discordutils.remove_markdown(message.clean_content)
149
-			await bm.set_reactions(BotMessageReaction.standard_set(
150
-				did_delete=context.is_deleted,
151
-				did_kick=context.is_kicked,
152
-				did_ban=context.is_banned))
153
-			await self.post_message(bm)
154
-			if needs_attention:
155
-				self.record_warning(message.author)
151
+		if join_age > min_join_age:
152
+			self.__trace("User has been member long enough")
153
+			return
154
+		context = URLSpamContext(message)
155
+		needs_attention = False
156
+		if action == 'modwarn':
157
+			needs_attention = not self.was_warned_recently(message.author)
158
+			self.log(message.guild, f'New user {message.author.name} ' + \
159
+				f'({message.author.id}) posted URL {join_age_str} after ' + \
160
+				'joining.' + (' Mods alerted.' if needs_attention else ''))
161
+		elif action == 'delete':
162
+			await message.delete()
163
+			context.is_deleted = True
164
+			self.log(message.guild, f'New user {message.author.name} ' + \
165
+				f'({message.author.id}) posted URL {join_age_str} after ' + \
166
+				'joining. Message deleted.')
167
+		elif action == 'kick':
168
+			await message.delete()
169
+			context.is_deleted = True
170
+			await message.author.kick(
171
+				reason=f'Rocketbot: Posted a link {join_age_str} after joining')
172
+			context.is_kicked = True
173
+			self.log(message.guild, f'New user {message.author.name} ' + \
174
+				f'({message.author.id}) posted URL {join_age_str} after ' + \
175
+				'joining. User kicked.')
176
+		elif action == 'ban':
177
+			await message.author.ban(
178
+				reason=f'Rocketbot: User posted a link {join_age_str} after joining',
179
+				delete_message_days=1)
180
+			context.is_deleted = True
181
+			context.is_kicked = True
182
+			context.is_banned = True
183
+			self.log(message.guild, f'New user {message.author.name} ' + \
184
+				f'({message.author.id}) posted URL {join_age_str} after ' + \
185
+				'joining. User banned.')
186
+		bm = BotMessage(
187
+				message.guild,
188
+				f'User {message.author.mention} posted a URL ' + \
189
+				f'{join_age_str} after joining: {message.jump_url}',
190
+				type = BotMessage.TYPE_MOD_WARNING if needs_attention else BotMessage.TYPE_INFO,
191
+				context = context)
192
+		bm.quote = discordutils.remove_markdown(message.clean_content)
193
+		await bm.set_reactions(BotMessageReaction.standard_set(
194
+			did_delete=context.is_deleted,
195
+			did_kick=context.is_kicked,
196
+			did_ban=context.is_banned))
197
+		await self.post_message(bm)
198
+		if needs_attention:
199
+			self.record_warning(message.author)
156
 
200
 
157
 	async def check_deceptive_links(self, message: Message):
201
 	async def check_deceptive_links(self, message: Message):
158
 		"""
202
 		"""
302
 			did_kick=context.is_kicked,
346
 			did_kick=context.is_kicked,
303
 			did_ban=context.is_banned))
347
 			did_ban=context.is_banned))
304
 
348
 
349
+	def __trace(self, message: str):
350
+		# print(f'URLSpamCog: {message}')
351
+		pass
352
+
305
 	@classmethod
353
 	@classmethod
306
 	def __contains_url(cls, text: str) -> bool:
354
 	def __contains_url(cls, text: str) -> bool:
307
 		p = re.compile(r'https?://\S+')
355
 		p = re.compile(r'https?://\S+')
308
 		return p.search(text) is not None
356
 		return p.search(text) is not None
357
+
358
+	@classmethod
359
+	def __find_urls(cls, text: str) -> list[str]:
360
+		p = re.compile(r'https?://\S+')
361
+		return re.findall(p, text)

Loading…
취소
저장