@@ -21,33 +21,96 @@ const { listGroups } = require('../../stores/group');
2121
2222const 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 .m e ) | ( t e l e g r a m .m e ) ) \/ \w + ( \/ [ A - Z a - z 0 - 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 .m e ) | ( t e l e g r a m .m e ) ) \/ / 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 = [
0 commit comments