1 |
|
%%%------------------------------------------------------------------- |
2 |
|
%%% @author bartek <bartlomiej.gorny@erlang-solutions.com> |
3 |
|
%%% @copyright (C) 2017, Erlang Solutions sp. z o.o. |
4 |
|
%%% @doc Generic functions for checking packet against privacy rules. Works by |
5 |
|
%%% calling 'privacy_check_packet' hooks to which various handlers might be attached. |
6 |
|
%%% |
7 |
|
%%% @end |
8 |
|
%%% Created : 06. Feb 2017 11:37 |
9 |
|
%%%------------------------------------------------------------------- |
10 |
|
-module(mongoose_privacy). |
11 |
|
-author("bartek"). |
12 |
|
|
13 |
|
-include("jlib.hrl"). |
14 |
|
-include("mod_privacy.hrl"). |
15 |
|
|
16 |
|
%% API |
17 |
|
-export([privacy_check_packet/5, privacy_check_packet/6]). |
18 |
|
|
19 |
|
-type direction() :: in | out. |
20 |
|
-type decision() :: allow | deny | block. |
21 |
|
-type userlist() :: #userlist{}. |
22 |
|
-export_type([direction/0, decision/0, userlist/0]). |
23 |
|
|
24 |
|
%%% API %%% |
25 |
|
|
26 |
|
%% @doc abbreviated version - in most cases we have 'from' in Acc, but sometimes |
27 |
|
%% the caller wants something different (e.g. mod_last which swaps addresses) |
28 |
|
%% the first arg can be accumulator, if we are checking its element, or a tuple |
29 |
|
%% {Acc, El} for cases where one acc triggers sending many messages which have to be checked |
30 |
|
-spec privacy_check_packet(Acc :: mongoose_acc:t() | {mongoose_acc:t(), exml:element()}, |
31 |
|
JID :: jid:jid(), |
32 |
|
PrivacyList :: userlist(), |
33 |
|
To :: jid:jid(), |
34 |
|
Dir :: direction()) -> {decision(), mongoose_acc:t()}. |
35 |
|
privacy_check_packet(Acc0, JID, PrivacyList, To, Dir) -> |
36 |
3567 |
Acc1 = case Acc0 of |
37 |
:-( |
{Acc, #xmlel{}} -> Acc; |
38 |
3567 |
_ -> Acc0 |
39 |
|
end, |
40 |
3567 |
From = mongoose_acc:from_jid(Acc1), |
41 |
3567 |
privacy_check_packet(Acc0, JID, PrivacyList, From, To, Dir). |
42 |
|
|
43 |
|
%% @doc check packet, store result in accumulator, return acc and result for quick check |
44 |
|
%% Acc can be either a single argument (an Accumulator) or a tuple of {Acc, Stanza} |
45 |
|
%% in the latter case name and type to check against privacy lists are taken from the Stanza |
46 |
|
-spec privacy_check_packet(Acc :: mongoose_acc:t() | {mongoose_acc:t(), exml:element()}, |
47 |
|
JID :: jid:jid(), |
48 |
|
PrivacyList :: userlist(), |
49 |
|
From :: jid:jid(), |
50 |
|
To :: jid:jid(), |
51 |
|
Dir :: direction()) -> {decision(), mongoose_acc:t()}. |
52 |
|
privacy_check_packet(Acc0, #jid{luser = LUser, lserver = LServer} = JID, |
53 |
|
PrivacyList, From, To, Dir) -> |
54 |
|
% see if we have just Acc or also stanza to check - may have different name/type |
55 |
3570 |
{Acc, Name, Type} = case Acc0 of |
56 |
|
{A, #xmlel{name = SName} = Stanza} -> |
57 |
:-( |
SType = exml_query:attr(Stanza, <<"type">>, undefined), |
58 |
:-( |
{A, SName, SType}; |
59 |
|
_ -> |
60 |
3570 |
{Acc0, mongoose_acc:stanza_name(Acc0), mongoose_acc:stanza_type(Acc0)} |
61 |
|
end, |
62 |
|
% check if it is there, if not then set default and run a hook |
63 |
3570 |
Key = {cached_check, LServer, LUser, From, To, Name, Type, Dir}, |
64 |
3570 |
case mongoose_acc:get(privacy, Key, undefined, Acc) of |
65 |
|
undefined -> |
66 |
3570 |
Acc1 = mongoose_hooks:privacy_check_packet(Acc, JID, PrivacyList, |
67 |
|
{From, To, Name, Type}, Dir), |
68 |
3570 |
Res = mongoose_acc:get(hook, result, Acc1), |
69 |
3570 |
{Res, mongoose_acc:set(privacy, Key, Res, Acc1)}; |
70 |
|
Res -> |
71 |
:-( |
{Res, Acc} |
72 |
|
end. |