Skip to content

Commit 88aebcd

Browse files
committed
now warns both channels/groups links and usernames
1 parent 8e4f01c commit 88aebcd

File tree

3 files changed

+121
-53
lines changed

3 files changed

+121
-53
lines changed

config.example.json

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,15 @@
22
"master": 123456789, // master admin ID as a number or username as astring.
33
"token": "", // bot token.
44
"plugins": [], // list of plugin names to be loaded
5+
56
"deleteCommands": "own", // which messages with commands should be deleted?
67
// valid options: "all", "own" (leave commands meant for other bots, this is the default), "none".
8+
79
"numberOfWarnsToBan": 3, // Number of warns that will get someone banned.
810
"groupsInlineKeyboard": [], // [[inlineButton]] -> inline keyboard to be added to reply to /groups
9-
"excludedChannels": [], // [String] -> list of channels usernames to be excluded from warnings, use "*" to disable this feature.
10-
"excludedGroups": [] // [String] -> list of groups links to be excluded from warnings, use "*" to disable this feature.
11+
12+
// [String] -> list of channels or groups links/usernames that you want to be excluded from warnings
13+
// use "*" to disable this feature.
14+
"excludedChannels": [],
15+
"excludedGroups": []
1116
}

handlers/messages/removeLinks.js

Lines changed: 88 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -21,33 +21,96 @@ const { listGroups } = require('../../stores/group');
2121

2222
const removeLinks = async ({ message, chat, reply, state }, next) => {
2323
const { isAdmin, user } = state;
24-
const groups = await listGroups();
25-
const groupLinks = excludedGroups !== '*' &&
26-
[
27-
...groups.map(group => group.link
28-
? group.link.split('/joinchat/')[1]
29-
: ''),
30-
...excludedGroups.map(group =>
31-
group.includes('/joinchat/')
32-
? group.split('/joinchat/')[1]
33-
: group)
34-
];
24+
const { entities, forward_from_chat, text } = message;
25+
const managedGroups = await listGroups();
26+
const shouldRemoveGroups = excludedGroups !== '*';
27+
const shouldRemoveChannels = excludedChannels !== '*';
28+
3529
if (
36-
message.forward_from_chat &&
37-
message.forward_from_chat.type !== 'private' &&
38-
excludedChannels !== '*' &&
39-
!excludedChannels.includes(message.forward_from_chat.username) ||
40-
message.text &&
41-
(message.text.includes('t.me') ||
42-
message.text.includes('telegram.me')) &&
43-
excludedGroups !== '*' &&
44-
!(excludedChannels.some(channel => message.text.includes(channel)) ||
45-
groupLinks.includes(message.text.split('/joinchat/')[1]))
46-
) {
47-
if (isAdmin) {
48-
return next();
30+
message.chat.type === 'private' ||
31+
isAdmin ||
32+
!shouldRemoveGroups &&
33+
!shouldRemoveChannels) {
34+
return next();
35+
}
36+
37+
// gather both managed groups and config excluded groups
38+
const knownGroups = [
39+
...managedGroups.map(group => group.link
40+
? group.link
41+
: ''),
42+
...excludedGroups
43+
];
44+
45+
// collect channels/supergroups usernames in the text
46+
let isChannelAd = false;
47+
let isGroupAd = false;
48+
const regexp = /(@\w+)|(((t.me)|(telegram.me))\/\w+(\/[A-Za-z0-9_-]+)?)/g;
49+
const usernames =
50+
text
51+
? text.match(regexp)
52+
: [];
53+
54+
await Promise.all(usernames.map(username => new Promise(async (resolve) => {
55+
// skip if already detected an ad
56+
if (isChannelAd || isGroupAd) return resolve();
57+
58+
// detect add if it's an invite link
59+
if (
60+
username.includes('/joinchat/') &&
61+
!knownGroups.some(group => group.includes(username))
62+
) {
63+
isGroupAd = true;
64+
return resolve();
4965
}
50-
const reason = 'Channel forward/link';
66+
67+
// detect if usernames are channels or public groups
68+
// and if they are ads
69+
username = username.replace(/.*((t.me)|(telegram.me))\//gi, '@');
70+
try {
71+
const { type } = await bot.telegram.getChat(username);
72+
if (!type) return resolve();
73+
if (
74+
type === 'channel' &&
75+
shouldRemoveChannels &&
76+
!excludedChannels
77+
.some(channel =>
78+
channel.includes(username.replace('@', '')))
79+
) {
80+
isChannelAd = true;
81+
return resolve();
82+
}
83+
if (
84+
type === 'supergroup' &&
85+
shouldRemoveGroups &&
86+
!knownGroups
87+
.some(group =>
88+
group.includes(username.replace('@', '')))
89+
) {
90+
isGroupAd = true;
91+
return resolve();
92+
}
93+
} catch (err) {
94+
return resolve();
95+
}
96+
return resolve();
97+
})));
98+
99+
if (
100+
// check if is forwarded from channel
101+
forward_from_chat &&
102+
forward_from_chat.type !== 'private' &&
103+
shouldRemoveChannels &&
104+
!excludedChannels.includes(forward_from_chat.username) ||
105+
106+
// check if text contains link/username of a channel or group
107+
text &&
108+
(text.includes('t.me') ||
109+
text.includes('telegram.me') ||
110+
entities && entities.some(entity => entity.type === 'mention')) &&
111+
(isChannelAd || isGroupAd)
112+
) {
113+
const reason = 'Forwarded or linked channels/groups';
51114
await warn(user, reason);
52115
const warnCount = await getWarns(user);
53116
const promises = [

package-lock.json

Lines changed: 26 additions & 26 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)