-
Notifications
You must be signed in to change notification settings - Fork 0
/
index.js
156 lines (121 loc) · 4.28 KB
/
index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
require('dotenv').config();
const Telegraf = require('telegraf');
const bot = new Telegraf(process.env.TELEGRAM_BOT_TOKEN);
const TRUST_AGE = 6 * 60 * 60 * 1000; // 6h
const groups = {};
const messages = {
removed: (user, reason) => {
const name = user.first_name + (user.username ? ` (@${user.username})` : '');
return `☝️ Message from ${name} removed. Reason: ${reason}`;
},
};
const formatChatName = chat => {
const { id, title, username } = chat;
const user = username ? ` @${username}` : '';
return `${title} (${id}${user})`;
};
const formatUserName = member => {
const { id, first_name: name, username } = member;
const user = username ? `(@${username})` : '';
return `${name}[${id}] ${user}`;
};
const to = promise => promise
.then(r => [r, null])
.catch(e => [null, e]);
// Mark join times for new users
bot.use(async (ctx, next) => {
const now = Date.now();
const chatName = formatChatName(ctx.chat);
if (typeof groups[ctx.chat.id] === 'undefined') {
groups[ctx.chat.id] = { users: {}, admins: {}, lastUpdate: 0 };
console.log(`Chat ${chatName} was added to the group list`);
}
const { lastUpdate } = groups[ctx.chat.id];
const updateInterval = 3600 * 1000; // update one time per hour at most
if (now - lastUpdate > updateInterval) {
const [admins, error] = await to(ctx.getChatAdministrators());
if (error) {
console.log(`Failed to fetch chat admins: ${error.stack}`);
return; // give up on message
}
groups[ctx.chat.id].admins = admins.reduce((list, { user }) => {
const { id } = user;
const name = formatUserName(user);
return { ...list, [id]: { id, name } };
}, {});
groups[ctx.chat.id].lastUpdate = now;
console.log(`Admin list for ${chatName} was updated`);
}
if (!ctx.updateSubTypes.includes('new_chat_members')) {
return next();
}
ctx.message.new_chat_members.forEach(m => {
if (!groups[ctx.chat.id].users[m.id]) {
groups[ctx.chat.id].users[m.id] = {
since: Date.now(),
username: m.username,
};
const user = formatUserName(m);
console.log(`User ${user} joined ${chatName}. Marking as untrusted!`);
}
});
});
// Untrust kicked users
bot.use(async (ctx, next) => {
if (!ctx.updateSubTypes.includes('left_chat_member')) {
return next();
}
const member = ctx.message.left_chat_member;
if (ctx.from.id !== member.id) { // user was kicked/banned
delete groups[ctx.chat.id].users[member.id]; // untrust user
const fullName = formatUserName(member);
const chatName = formatChatName(ctx.chat);
console.log(`User ${fullName} is now untrusted in ${chatName}`);
}
});
// Check if the user is trusted
bot.use(async (ctx, next) => {
const { users, admins } = groups[ctx.chat.id];
const { id: uid } = ctx.from;
const fullName = formatUserName(ctx.from);
const chatName = formatChatName(ctx.chat);
if (typeof admins[uid] !== 'undefined') {
console.log(`Message from an admin ${fullName} in ${chatName}. Ignoring`);
return;
}
if (typeof users[uid] === 'undefined') {
console.log(`User ${fullName} join date in ${chatName} is unknown - will consider it trusted`);
users[uid] = { since: 0 };
}
if (Date.now() - users[uid].since >= TRUST_AGE) {
console.log(`User ${fullName} is trusted`);
return; // end call chain
}
next();
});
// detect url, animation, photo, document, voice, audio, video_note, sticker
bot.use(async (ctx, next) => {
const message = ctx.message || ctx.editedMessage;
const blacklist = ['animation', 'photo', 'document', 'voice', 'audio', 'video', 'sticker', 'video_note'];
const restrictedItems = ctx.updateSubTypes.filter(type => blacklist.includes(type));
const entities = message.entities || [];
const hasLinks = entities.reduce((acc, e) => (acc || e.type === 'url'), false);
if (hasLinks) {
restrictedItems.push('link');
}
if (restrictedItems.length) {
const reason = restrictedItems.join(', ');
const msg = messages.removed(ctx.from, 'new user + ' + reason);
const [, error] = await to(Promise.all([
ctx.deleteMessage(),
ctx.reply(msg),
]));
if (!error) {
console.error(`Action failed: ${error.stack}`);
}
console.log(`[failed] ${msg}`);
}
return next();
});
bot.startPolling();
console.log('Zatz started');