2016-06-24 17:34:37 +02:00
|
|
|
-module(mod_pottymouth).
|
|
|
|
|
|
|
|
-behaviour(gen_mod).
|
|
|
|
|
2016-08-02 16:42:37 +02:00
|
|
|
-include("logger.hrl").
|
2017-07-26 18:56:58 +02:00
|
|
|
-include("xmpp.hrl").
|
2016-08-02 16:42:37 +02:00
|
|
|
|
2016-06-24 17:34:37 +02:00
|
|
|
-export([
|
|
|
|
start/2,
|
|
|
|
stop/1,
|
|
|
|
on_filter_packet/1,
|
2016-09-13 23:23:47 +02:00
|
|
|
mod_opt_type/1,
|
2017-07-26 18:56:58 +02:00
|
|
|
depends/2,
|
2018-07-11 10:46:45 +02:00
|
|
|
reload/3,
|
|
|
|
mod_options/1
|
2016-06-24 17:34:37 +02:00
|
|
|
]).
|
|
|
|
|
|
|
|
-import(bloom_gen_server, [start/0, stop/0, member/1]).
|
2016-07-19 23:34:04 +02:00
|
|
|
-import(nomalize_leet_gen_server, [normalize/1]).
|
2016-06-24 17:34:37 +02:00
|
|
|
|
2017-07-26 18:56:58 +02:00
|
|
|
getMessageLang(Msg) ->
|
|
|
|
LangAttr = xmpp:get_lang(Msg),
|
2016-06-24 17:34:37 +02:00
|
|
|
if
|
2017-07-26 18:56:58 +02:00
|
|
|
(LangAttr /= <<>>) ->
|
|
|
|
Lang = list_to_atom(binary_to_list(LangAttr));
|
2016-06-24 17:34:37 +02:00
|
|
|
true ->
|
2016-09-13 23:13:32 +02:00
|
|
|
Lang = default
|
2016-06-24 17:34:37 +02:00
|
|
|
end,
|
|
|
|
Lang.
|
|
|
|
|
2016-09-13 21:22:37 +02:00
|
|
|
censorWord({Lang, Word} = _MessageTerm) ->
|
|
|
|
% we need unicode characters to normlize the word
|
|
|
|
NormalizedWord = normalize_leet_gen_server:normalize({Lang, unicode:characters_to_list(list_to_binary(Word))}),
|
|
|
|
% we need bytewise format for bloom lookup
|
|
|
|
IsBadWord = bloom_gen_server:member({Lang, binary_to_list(unicode:characters_to_binary(NormalizedWord))}),
|
2016-06-24 17:34:37 +02:00
|
|
|
if
|
|
|
|
IsBadWord ->
|
|
|
|
"****";
|
|
|
|
true ->
|
|
|
|
Word
|
|
|
|
end.
|
|
|
|
|
|
|
|
filterWords(L) ->
|
|
|
|
lists:map(fun censorWord/1, L).
|
|
|
|
|
2017-07-26 18:56:58 +02:00
|
|
|
filterMessageText(Lang, MessageText) ->
|
2019-01-28 23:14:07 +01:00
|
|
|
try filterMessageText2(Lang, MessageText) of
|
|
|
|
R ->
|
|
|
|
R
|
|
|
|
catch exit:{noproc,{gen_server,call,[_,_]}} ->
|
|
|
|
?DEBUG("Blacklist of language '~p' not found, using 'default' list.", [Lang]),
|
|
|
|
filterMessageText2(default, MessageText)
|
|
|
|
end.
|
|
|
|
|
|
|
|
filterMessageText2(Lang, MessageText) ->
|
2016-09-13 21:22:37 +02:00
|
|
|
% we want to token-ize utf8 'words'
|
2016-08-02 16:42:37 +02:00
|
|
|
MessageWords = string:tokens(unicode:characters_to_list(MessageText, utf8), " "),
|
|
|
|
MessageTerms = [{Lang, Word} || Word <- MessageWords],
|
2016-09-13 21:22:37 +02:00
|
|
|
% we get back bytewise format terms (rather than utf8)
|
2016-09-30 18:55:33 +02:00
|
|
|
string:join(filterWords(MessageTerms), " ").
|
2016-08-02 16:42:37 +02:00
|
|
|
|
2016-06-24 17:34:37 +02:00
|
|
|
start(_Host, Opts) ->
|
|
|
|
Blacklists = gen_mod:get_opt(blacklists, Opts, fun(A) -> A end, []),
|
|
|
|
lists:map(fun bloom_gen_server:start/1, Blacklists),
|
2016-07-19 23:34:04 +02:00
|
|
|
CharMaps = gen_mod:get_opt(charmaps, Opts, fun(A) -> A end, []),
|
|
|
|
lists:map(fun normalize_leet_gen_server:start/1, CharMaps),
|
2016-06-24 17:34:37 +02:00
|
|
|
ejabberd_hooks:add(filter_packet, global, ?MODULE, on_filter_packet, 0),
|
|
|
|
ok.
|
|
|
|
|
|
|
|
stop(_Host) ->
|
|
|
|
bloom_gen_server:stop(),
|
2016-07-19 23:34:04 +02:00
|
|
|
normalize_leet_gen_server:stop(),
|
2016-06-24 17:34:37 +02:00
|
|
|
ejabberd_hooks:delete(filter_packet, global, ?MODULE, on_filter_packet, 0),
|
|
|
|
ok.
|
|
|
|
|
|
|
|
on_filter_packet(drop) ->
|
|
|
|
drop;
|
|
|
|
|
|
|
|
on_filter_packet(Msg) ->
|
2017-07-26 18:56:58 +02:00
|
|
|
Type = xmpp:get_type(Msg),
|
|
|
|
if
|
|
|
|
(Type == chat) orelse (Type == groupchat) ->
|
|
|
|
BodyText = xmpp:get_text(Msg#message.body),
|
|
|
|
if
|
|
|
|
(BodyText /= <<>>) ->
|
|
|
|
Lang = getMessageLang(Msg),
|
|
|
|
FilteredMessageWords = binary:list_to_bin(filterMessageText(Lang, binary:bin_to_list(BodyText))),
|
|
|
|
[BodyObject|_] = Msg#message.body,
|
|
|
|
NewBodyObject = setelement(3, BodyObject, FilteredMessageWords),
|
|
|
|
NewMsg = Msg#message{body = [NewBodyObject]},
|
|
|
|
NewMsg;
|
|
|
|
true ->
|
|
|
|
Msg
|
|
|
|
end;
|
|
|
|
true ->
|
|
|
|
Msg
|
|
|
|
end.
|
2016-06-24 17:34:37 +02:00
|
|
|
|
|
|
|
mod_opt_type(blacklists) -> fun (A) when is_list(A) -> A end;
|
2016-07-19 23:34:04 +02:00
|
|
|
mod_opt_type(charmaps) -> fun (A) when is_list(A) -> A end;
|
|
|
|
mod_opt_type(_) -> [blacklists, charmaps].
|
2016-09-13 23:23:47 +02:00
|
|
|
depends(_Host, _Opts) -> [].
|
2017-07-26 18:56:58 +02:00
|
|
|
reload(_Host, _NewOpts, _OldOpts) -> ok.
|
2018-07-11 10:46:45 +02:00
|
|
|
mod_options(_) ->
|
2018-07-13 16:17:59 +02:00
|
|
|
[{blacklists, []},{charmaps, []}].
|