/[sudobot]/branches/9.x-dev/extensions/urlfish/src/services/URLFishService.ts
ViewVC logotype

Contents of /branches/9.x-dev/extensions/urlfish/src/services/URLFishService.ts

Parent Directory Parent Directory | Revision Log Revision Log


Revision 577 - (show annotations)
Mon Jul 29 18:52:37 2024 UTC (8 months ago) by rakinar2
File MIME type: application/typescript
File size: 7793 byte(s)
chore: add old version archive branches (2.x to 9.x-dev)
1 import Service from "@sudobot/core/Service";
2 import FileSystem from "@sudobot/polyfills/FileSystem";
3 import { downloadFile } from "@sudobot/utils/download";
4 import { channelInfo, userInfo } from "@sudobot/utils/embed";
5 import { safeChannelFetch } from "@sudobot/utils/fetch";
6 import { sudoPrefix } from "@sudobot/utils/utils";
7 import { Colors, Message } from "discord.js";
8 import { ActionToTake, Config, GuildConfigWithExtension } from "src/types/config";
9
10 export const name = "urlfish";
11
12 export default class URLFishService extends Service {
13 private readonly domainListURL =
14 "https://raw.githubusercontent.com/mitchellkrogza/Phishing.Database/master/phishing-domains-ACTIVE.txt";
15 private _list: string[] = [];
16 private readonly patterns = [
17 /\[steamcommunity\.com\/gift\/([^\/]+)\]\(.+?\)/gim
18 ];
19
20 async boot() {
21 const urlfishDir = sudoPrefix("tmp/urlfish", true);
22 const dataFile = sudoPrefix("tmp/urlfish/LIST", false);
23
24 if (await FileSystem.exists(dataFile)) {
25 this.client.logger.debug("URLFishService", "Phishing domain list already exists", dataFile);
26 } else {
27 this.client.logger.debug("URLFishService", "Phishing domain list not found", dataFile);
28 this.client.logger.debug("URLFishService", "Downloading list", dataFile);
29
30 const url = this.domainListURL;
31 await downloadFile({
32 url,
33 name: "LIST",
34 path: urlfishDir
35 });
36 }
37
38 const data = (await FileSystem.readFileContents<string>(dataFile)).split("\n");
39 this.client.logger.debug("URLFishService", `Loaded ${data.length} entries from file`);
40 this._list = data;
41 }
42
43 get list() {
44 return this._list;
45 }
46
47 scanMessage(message: Message) {
48 const urls = message.content.toLowerCase().split(" ");
49 const phishingURLs: string[] = [];
50
51 for (const url of urls) {
52 const domain = url.startsWith("http") ? url.replace(/https?:\/?\/?/i, "") : url;
53
54 if (this.list.includes(domain)) {
55 phishingURLs.push(url);
56 }
57 }
58
59 return phishingURLs;
60 }
61
62 async verifyMessage(message: Message) {
63 const config = this.client.configManager.get<GuildConfigWithExtension>(message.guildId!)?.urlfish;
64
65 if (
66 !config?.enabled ||
67 (config.channels && "enabled_in" in config.channels && !config.channels.enabled_in.includes(message.channelId)) ||
68 (config.channels && "disabled_in" in config.channels && config.channels.disabled_in.includes(message.channelId)) ||
69 (await this.client.permissionManager.isImmuneToAutoMod(message.member!))
70 ) {
71 return;
72 }
73
74 for (const pattern of this.patterns) {
75 if (pattern.test(message.content)) {
76 await this.takeAction(message, config);
77 await this.logMessage(message, config, [pattern.toString()], config.action);
78 return;
79 }
80 }
81
82 const links = this.scanMessage(message);
83
84 if (links.length > 0) {
85 await this.takeAction(message, config);
86 await this.logMessage(message, config, links, config.action);
87 }
88 }
89
90 async takeAction(message: Message<boolean>, config: NonNullable<Config>) {
91 switch (config.action) {
92 case "delete":
93 if (message.deletable) {
94 await message.delete();
95 }
96
97 break;
98 case "warn":
99 await this.client.infractionManager.createMemberWarn(message.member!, {
100 guild: message.guild!,
101 reason:
102 config.infraction_reason ??
103 "We have detected phishing URLs in your message. Please refrain from posting these links.",
104 moderator: this.client.user!,
105 notifyUser: true,
106 sendLog: true
107 });
108
109 break;
110 case "mute":
111 await this.client.infractionManager.createMemberMute(message.member!, {
112 guild: message.guild!,
113 reason:
114 config.infraction_reason ??
115 "We have detected phishing URLs in your message. Please refrain from posting these links.",
116 moderator: this.client.user!,
117 notifyUser: true,
118 sendLog: true,
119 duration: config.mute_duration ?? 3_600_000, // 1 hour,
120 autoRemoveQueue: true
121 });
122
123 break;
124 case "kick":
125 await this.client.infractionManager.createMemberKick(message.member!, {
126 guild: message.guild!,
127 reason: config.infraction_reason ?? "We have detected phishing URLs in your message.",
128 moderator: this.client.user!,
129 notifyUser: true,
130 sendLog: true
131 });
132
133 break;
134 case "ban":
135 await this.client.infractionManager.createUserBan(message.author, {
136 guild: message.guild!,
137 reason: config.infraction_reason ?? "We have detected phishing URLs in your message.",
138 moderator: this.client.user!,
139 notifyUser: true,
140 sendLog: true,
141 deleteMessageSeconds: 604_800, // 7 days,
142 autoRemoveQueue: true
143 });
144
145 break;
146 }
147 }
148
149 async logMessage(message: Message<boolean>, config: Config, links: string[], action: ActionToTake) {
150 if (!config?.log_channel || !message.guild) {
151 return;
152 }
153
154 const logChannel = await safeChannelFetch(message.guild, config?.log_channel);
155
156 if (!logChannel?.isTextBased()) {
157 return;
158 }
159
160 const joinedLinks = links.join("\n");
161
162 await logChannel.send({
163 embeds: [
164 {
165 title: `Phishing URLs detected in ${message.url}`,
166 fields: [
167 {
168 name: "URLs",
169 value: joinedLinks.substring(0, 1020) + (joinedLinks.length > 1020 ? "..." : "")
170 },
171 {
172 name: "Channel",
173 value: channelInfo(message.channel),
174 inline: true
175 },
176 {
177 name: "User",
178 value: userInfo(message.author),
179 inline: true
180 },
181 {
182 name: "Action",
183 value:
184 action === "ban"
185 ? "Banned"
186 : action[0].toUpperCase() + action.substring(1) + (action.endsWith("e") ? "d" : "ed"),
187 inline: true
188 }
189 ],
190 description: message.content || "*No content*",
191 color: Colors.Red,
192 timestamp: message.createdAt.toISOString(),
193 author: {
194 name: message.author.username,
195 icon_url: message.author.displayAvatarURL()
196 },
197 footer: {
198 text: `Detected by URLFish`
199 }
200 }
201 ]
202 });
203 }
204 }

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26