1 |
rakinar2 |
577 |
/** |
2 |
|
|
* This file is part of SudoBot. |
3 |
|
|
* |
4 |
|
|
* Copyright (C) 2021-2023 OSN Developers. |
5 |
|
|
* |
6 |
|
|
* SudoBot is free software; you can redistribute it and/or modify it |
7 |
|
|
* under the terms of the GNU Affero General Public License as published by |
8 |
|
|
* the Free Software Foundation, either version 3 of the License, or |
9 |
|
|
* (at your option) any later version. |
10 |
|
|
* |
11 |
|
|
* SudoBot is distributed in the hope that it will be useful, but |
12 |
|
|
* WITHOUT ANY WARRANTY; without even the implied warranty of |
13 |
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
14 |
|
|
* GNU Affero General Public License for more details. |
15 |
|
|
* |
16 |
|
|
* You should have received a copy of the GNU Affero General Public License |
17 |
|
|
* along with SudoBot. If not, see <https://www.gnu.org/licenses/>. |
18 |
|
|
*/ |
19 |
|
|
|
20 |
|
|
import { |
21 |
|
|
ChannelType, |
22 |
|
|
Guild, |
23 |
|
|
GuildBasedChannel, |
24 |
|
|
PermissionFlags, |
25 |
|
|
PermissionFlagsBits, |
26 |
|
|
PermissionOverwriteOptions, |
27 |
|
|
Snowflake, |
28 |
|
|
TextChannel, |
29 |
|
|
User |
30 |
|
|
} from "discord.js"; |
31 |
|
|
import Service from "../core/Service"; |
32 |
|
|
import { log, logError } from "../utils/Logger"; |
33 |
|
|
import { getChannelPermissionOverride } from "../utils/utils"; |
34 |
|
|
|
35 |
|
|
export const name = "channelLockManager"; |
36 |
|
|
|
37 |
|
|
type ChannelLockOptions = { |
38 |
|
|
channels?: Snowflake[]; |
39 |
|
|
channelMode?: "exclude" | "include"; |
40 |
|
|
ignorePrivateChannels?: boolean; |
41 |
|
|
moderator: User; |
42 |
|
|
reason?: string; |
43 |
|
|
}; |
44 |
|
|
|
45 |
|
|
export default class ChannelLockManager extends Service { |
46 |
|
|
async shouldLock(channels: Snowflake[], channel: GuildBasedChannel, channelMode: "exclude" | "include") { |
47 |
|
|
return ( |
48 |
|
|
channels.length === 0 || |
49 |
|
|
(channelMode === "include" && channels.includes(channel.id)) || |
50 |
|
|
(channelMode === "exclude" && !channels.includes(channel.id)) |
51 |
|
|
); |
52 |
|
|
} |
53 |
|
|
|
54 |
|
|
async lockGuild( |
55 |
|
|
guild: Guild, |
56 |
|
|
{ reason, moderator, channels = [], channelMode = "include", ignorePrivateChannels = true }: ChannelLockOptions |
57 |
|
|
) { |
58 |
|
|
let countSuccess = 0, |
59 |
|
|
countFailed = 0, |
60 |
|
|
countSkipped = 0, |
61 |
|
|
countInvalidChannel = 0; |
62 |
|
|
|
63 |
|
|
const originalPermissions = []; |
64 |
|
|
|
65 |
|
|
for (const [, channel] of guild.channels.cache) { |
66 |
|
|
log(channel.name); |
67 |
|
|
|
68 |
|
|
if ( |
69 |
|
|
!this.shouldLock(channels, channel, channelMode) || |
70 |
|
|
![ |
71 |
|
|
ChannelType.GuildAnnouncement, |
72 |
|
|
ChannelType.GuildCategory, |
73 |
|
|
ChannelType.GuildText, |
74 |
|
|
ChannelType.GuildVoice, |
75 |
|
|
ChannelType.GuildStageVoice, |
76 |
|
|
ChannelType.GuildForum |
77 |
|
|
].includes(channel.type) |
78 |
|
|
) { |
79 |
|
|
countInvalidChannel++; |
80 |
|
|
continue; |
81 |
|
|
} |
82 |
|
|
|
83 |
|
|
try { |
84 |
|
|
const permissionOverwrites = (channel as TextChannel).permissionOverwrites?.cache.get(guild.id); |
85 |
|
|
|
86 |
|
|
if (ignorePrivateChannels) { |
87 |
|
|
if (permissionOverwrites?.deny.has(PermissionFlagsBits.ViewChannel, true)) { |
88 |
|
|
log("Private channel, skipping lock"); |
89 |
|
|
countSkipped++; |
90 |
|
|
continue; |
91 |
|
|
} |
92 |
|
|
} |
93 |
|
|
|
94 |
|
|
if (permissionOverwrites?.deny.has(PermissionFlagsBits.SendMessages, true)) { |
95 |
|
|
log("Already locked channel, skipping lock"); |
96 |
|
|
countSkipped++; |
97 |
|
|
continue; |
98 |
|
|
} |
99 |
|
|
|
100 |
|
|
const permissionJson = { |
101 |
|
|
Connect: permissionOverwrites |
102 |
|
|
? getChannelPermissionOverride(PermissionFlagsBits.Connect, permissionOverwrites) |
103 |
|
|
: null, |
104 |
|
|
SendMessages: permissionOverwrites |
105 |
|
|
? getChannelPermissionOverride(PermissionFlagsBits.SendMessages, permissionOverwrites) |
106 |
|
|
: null, |
107 |
|
|
SendMessagesInThreads: permissionOverwrites |
108 |
|
|
? getChannelPermissionOverride(PermissionFlagsBits.SendMessagesInThreads, permissionOverwrites) |
109 |
|
|
: null, |
110 |
|
|
AddReactions: permissionOverwrites |
111 |
|
|
? getChannelPermissionOverride(PermissionFlagsBits.AddReactions, permissionOverwrites) |
112 |
|
|
: null |
113 |
|
|
}; |
114 |
|
|
|
115 |
|
|
originalPermissions.push({ |
116 |
|
|
channel_id: channel.id, |
117 |
|
|
guild_id: guild.id, |
118 |
|
|
permissions: permissionJson |
119 |
|
|
}); |
120 |
|
|
|
121 |
|
|
await (channel as TextChannel).permissionOverwrites?.edit(guild.id, { |
122 |
|
|
Connect: false, |
123 |
|
|
SendMessages: false, |
124 |
|
|
SendMessagesInThreads: false, |
125 |
|
|
AddReactions: false |
126 |
|
|
}); |
127 |
|
|
|
128 |
|
|
countSuccess++; |
129 |
|
|
} catch (e) { |
130 |
|
|
logError(e); |
131 |
|
|
countFailed++; |
132 |
|
|
} |
133 |
|
|
} |
134 |
|
|
|
135 |
|
|
await this.client.prisma.channelLock.createMany({ |
136 |
|
|
data: originalPermissions |
137 |
|
|
}); |
138 |
|
|
|
139 |
|
|
await this.client.loggerService.logServerLockOrUnlock({ |
140 |
|
|
guild, |
141 |
|
|
action: "Locked", |
142 |
|
|
moderator, |
143 |
|
|
countSuccess, |
144 |
|
|
countFailed, |
145 |
|
|
countInvalidChannel, |
146 |
|
|
countSkipped, |
147 |
|
|
reason |
148 |
|
|
}); |
149 |
|
|
|
150 |
|
|
return { |
151 |
|
|
countSuccess, |
152 |
|
|
countFailed, |
153 |
|
|
countInvalidChannel, |
154 |
|
|
countSkipped |
155 |
|
|
}; |
156 |
|
|
} |
157 |
|
|
|
158 |
|
|
async unlockGuild( |
159 |
|
|
guild: Guild, |
160 |
|
|
{ |
161 |
|
|
channels = [], |
162 |
|
|
channelMode = "include", |
163 |
|
|
ignorePrivateChannels = true, |
164 |
|
|
force, |
165 |
|
|
moderator, |
166 |
|
|
reason |
167 |
|
|
}: ChannelLockOptions & { force?: boolean } |
168 |
|
|
) { |
169 |
|
|
let countSuccess = 0, |
170 |
|
|
countFailed = 0, |
171 |
|
|
countSkipped = 0, |
172 |
|
|
countInvalidChannel = 0; |
173 |
|
|
|
174 |
|
|
const originalPermissions = force |
175 |
|
|
? guild.channels.cache.map(c => ({ channel_id: c.id, permissions: {}, id: 0 })) |
176 |
|
|
: await this.client.prisma.channelLock.findMany({ |
177 |
|
|
where: { |
178 |
|
|
guild_id: guild.id |
179 |
|
|
} |
180 |
|
|
}); |
181 |
|
|
|
182 |
|
|
for (const originalPermission of originalPermissions) { |
183 |
|
|
const channel = guild.channels.cache.get(originalPermission.channel_id); |
184 |
|
|
|
185 |
|
|
if (!channel) continue; |
186 |
|
|
|
187 |
|
|
if ( |
188 |
|
|
!this.shouldLock(channels, channel, channelMode) || |
189 |
|
|
![ |
190 |
|
|
ChannelType.GuildAnnouncement, |
191 |
|
|
ChannelType.GuildCategory, |
192 |
|
|
ChannelType.GuildText, |
193 |
|
|
ChannelType.GuildVoice, |
194 |
|
|
ChannelType.GuildStageVoice, |
195 |
|
|
ChannelType.GuildForum |
196 |
|
|
].includes(channel.type) |
197 |
|
|
) { |
198 |
|
|
countInvalidChannel++; |
199 |
|
|
continue; |
200 |
|
|
} |
201 |
|
|
|
202 |
|
|
try { |
203 |
|
|
const options = { |
204 |
|
|
Connect: force ? true : (originalPermission.permissions! as PermissionFlags).Connect, |
205 |
|
|
SendMessages: force ? true : (originalPermission.permissions! as PermissionFlags).SendMessages, |
206 |
|
|
SendMessagesInThreads: force |
207 |
|
|
? true |
208 |
|
|
: (originalPermission.permissions! as PermissionFlags).SendMessagesInThreads, |
209 |
|
|
AddReactions: force ? true : (originalPermission.permissions! as PermissionFlags).AddReactions |
210 |
|
|
}; |
211 |
|
|
|
212 |
|
|
const permissionOverwrites = (channel as TextChannel).permissionOverwrites?.cache.get(guild.id); |
213 |
|
|
|
214 |
|
|
if (ignorePrivateChannels && !force) { |
215 |
|
|
if (permissionOverwrites?.deny.has(PermissionFlagsBits.ViewChannel, true)) { |
216 |
|
|
log("Private channel, skipping lock"); |
217 |
|
|
countSkipped++; |
218 |
|
|
continue; |
219 |
|
|
} |
220 |
|
|
} |
221 |
|
|
|
222 |
|
|
if (permissionOverwrites) |
223 |
|
|
await (channel as TextChannel).permissionOverwrites?.edit(guild.id, options as PermissionOverwriteOptions); |
224 |
|
|
else await (channel as TextChannel).permissionOverwrites?.create(guild.id, options as PermissionOverwriteOptions); |
225 |
|
|
|
226 |
|
|
countSuccess++; |
227 |
|
|
} catch (e) { |
228 |
|
|
logError(e); |
229 |
|
|
countFailed++; |
230 |
|
|
} |
231 |
|
|
} |
232 |
|
|
|
233 |
|
|
log(originalPermissions); |
234 |
|
|
|
235 |
|
|
if (!force) |
236 |
|
|
await this.client.prisma.channelLock.deleteMany({ |
237 |
|
|
where: { |
238 |
|
|
id: { |
239 |
|
|
in: originalPermissions.map(permission => permission.id) |
240 |
|
|
} |
241 |
|
|
} |
242 |
|
|
}); |
243 |
|
|
|
244 |
|
|
await this.client.loggerService.logServerLockOrUnlock({ |
245 |
|
|
guild, |
246 |
|
|
action: "Unlocked", |
247 |
|
|
moderator, |
248 |
|
|
countSuccess, |
249 |
|
|
countFailed, |
250 |
|
|
countInvalidChannel, |
251 |
|
|
countSkipped, |
252 |
|
|
reason |
253 |
|
|
}); |
254 |
|
|
|
255 |
|
|
return { |
256 |
|
|
countSuccess, |
257 |
|
|
countFailed, |
258 |
|
|
countInvalidChannel, |
259 |
|
|
countSkipped |
260 |
|
|
}; |
261 |
|
|
} |
262 |
|
|
|
263 |
|
|
async lock(channel: TextChannel, moderator: User, reason?: string) { |
264 |
|
|
try { |
265 |
|
|
const options = { |
266 |
|
|
Connect: false, |
267 |
|
|
SendMessages: false, |
268 |
|
|
SendMessagesInThreads: false, |
269 |
|
|
AddReactions: false |
270 |
|
|
}; |
271 |
|
|
|
272 |
|
|
const permissionOverwrites = channel.permissionOverwrites?.cache.get(channel.guild.id); |
273 |
|
|
|
274 |
|
|
const permissionJson = { |
275 |
|
|
Connect: permissionOverwrites |
276 |
|
|
? getChannelPermissionOverride(PermissionFlagsBits.Connect, permissionOverwrites) |
277 |
|
|
: null, |
278 |
|
|
SendMessages: permissionOverwrites |
279 |
|
|
? getChannelPermissionOverride(PermissionFlagsBits.SendMessages, permissionOverwrites) |
280 |
|
|
: null, |
281 |
|
|
SendMessagesInThreads: permissionOverwrites |
282 |
|
|
? getChannelPermissionOverride(PermissionFlagsBits.SendMessagesInThreads, permissionOverwrites) |
283 |
|
|
: null, |
284 |
|
|
AddReactions: permissionOverwrites |
285 |
|
|
? getChannelPermissionOverride(PermissionFlagsBits.AddReactions, permissionOverwrites) |
286 |
|
|
: null |
287 |
|
|
}; |
288 |
|
|
|
289 |
|
|
if (permissionOverwrites) await channel.permissionOverwrites?.edit(channel.guild.id, options); |
290 |
|
|
else await channel.permissionOverwrites?.create(channel.guild.id, options); |
291 |
|
|
|
292 |
|
|
this.client.loggerService |
293 |
|
|
.logChannelLockOrUnlock({ |
294 |
|
|
guild: channel.guild, |
295 |
|
|
action: "Locked", |
296 |
|
|
channel, |
297 |
|
|
moderator, |
298 |
|
|
reason |
299 |
|
|
}) |
300 |
|
|
.catch(logError); |
301 |
|
|
|
302 |
|
|
return await this.client.prisma.channelLock.create({ |
303 |
|
|
data: { |
304 |
|
|
channel_id: channel.id, |
305 |
|
|
guild_id: channel.guild.id, |
306 |
|
|
permissions: permissionJson |
307 |
|
|
} |
308 |
|
|
}); |
309 |
|
|
} catch (e) { |
310 |
|
|
logError(e); |
311 |
|
|
return null; |
312 |
|
|
} |
313 |
|
|
} |
314 |
|
|
|
315 |
|
|
async unlock(channel: TextChannel, moderator: User, reason?: string, force?: boolean) { |
316 |
|
|
try { |
317 |
|
|
const channelLock = await this.client.prisma.channelLock.findFirst({ |
318 |
|
|
where: { |
319 |
|
|
channel_id: channel.id, |
320 |
|
|
guild_id: channel.guild.id |
321 |
|
|
} |
322 |
|
|
}); |
323 |
|
|
|
324 |
|
|
if (!channelLock) return null; |
325 |
|
|
|
326 |
|
|
const options = { |
327 |
|
|
Connect: force ? true : (channelLock.permissions as unknown as PermissionFlags).Connect, |
328 |
|
|
SendMessages: force ? true : (channelLock.permissions as unknown as PermissionFlags).SendMessages, |
329 |
|
|
SendMessagesInThreads: force |
330 |
|
|
? true |
331 |
|
|
: (channelLock.permissions as unknown as PermissionFlags).SendMessagesInThreads, |
332 |
|
|
AddReactions: force ? true : (channelLock.permissions as unknown as PermissionFlags).AddReactions |
333 |
|
|
}; |
334 |
|
|
|
335 |
|
|
const permissionOverwrites = channel.permissionOverwrites?.cache.get(channel.guild.id); |
336 |
|
|
|
337 |
|
|
if (permissionOverwrites) |
338 |
|
|
await channel.permissionOverwrites?.edit(channel.guild.id, options as PermissionOverwriteOptions); |
339 |
|
|
else await channel.permissionOverwrites?.create(channel.guild.id, options as PermissionOverwriteOptions); |
340 |
|
|
|
341 |
|
|
this.client.loggerService |
342 |
|
|
.logChannelLockOrUnlock({ |
343 |
|
|
guild: channel.guild, |
344 |
|
|
action: "Unlocked", |
345 |
|
|
channel, |
346 |
|
|
moderator, |
347 |
|
|
reason |
348 |
|
|
}) |
349 |
|
|
.catch(logError); |
350 |
|
|
|
351 |
|
|
return true; |
352 |
|
|
} catch (e) { |
353 |
|
|
logError(e); |
354 |
|
|
return false; |
355 |
|
|
} |
356 |
|
|
} |
357 |
|
|
} |