./ct_report/coverage/mod_privacy_rdbms.COVER.html

1 %%%----------------------------------------------------------------------
2 %%% Copyright notice from original mod_privacy
3 %%%
4 %%% File : mod_privacy.erl
5 %%% Author : Alexey Shchepin <alexey@process-one.net>
6 %%% Purpose : jabber:iq:privacy support
7 %%% Created : 21 Jul 2003 by Alexey Shchepin <alexey@process-one.net>
8 %%%
9 %%%
10 %%% ejabberd, Copyright (C) 2002-2011 ProcessOne
11 %%%
12 %%% This program is free software; you can redistribute it and/or
13 %%% modify it under the terms of the GNU General Public License as
14 %%% published by the Free Software Foundation; either version 2 of the
15 %%% License, or (at your option) any later version.
16 %%%
17 %%% This program is distributed in the hope that it will be useful,
18 %%% but WITHOUT ANY WARRANTY; without even the implied warranty of
19 %%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 %%% General Public License for more details.
21 %%%
22 %%% You should have received a copy of the GNU General Public License
23 %%% along with this program; if not, write to the Free Software
24 %%% Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
25 %%%
26 %%%----------------------------------------------------------------------
27
28 -module(mod_privacy_rdbms).
29 -author('alexey@process-one.net').
30 -author('arcusfelis@gmail.com').
31 -behaviour(mod_privacy_backend).
32
33 -export([init/2,
34 get_default_list/3,
35 get_list_names/3,
36 get_privacy_list/4,
37 set_default_list/4,
38 forget_default_list/3,
39 remove_privacy_list/4,
40 replace_privacy_list/5,
41 remove_user/3,
42 remove_domain/2]).
43
44 -include("mongoose.hrl").
45 -include("jlib.hrl").
46 -include("mod_privacy.hrl").
47
48 init(HostType, _Opts) ->
49
:-(
prepare_queries(HostType),
50
:-(
ok.
51
52 prepare_queries(HostType) ->
53 %% Queries to privacy_list table
54
:-(
mongoose_rdbms:prepare(privacy_list_get_id, privacy_list, [server, username, name],
55 <<"SELECT id FROM privacy_list WHERE server=? AND username=? AND name=?">>),
56
:-(
mongoose_rdbms:prepare(privacy_list_get_names, privacy_list, [server, username],
57 <<"SELECT name FROM privacy_list WHERE server=? AND username=?">>),
58
:-(
mongoose_rdbms:prepare(privacy_list_delete_by_name, privacy_list, [server, username, name],
59 <<"DELETE FROM privacy_list WHERE server=? AND username=? AND name=?">>),
60
:-(
mongoose_rdbms:prepare(privacy_list_delete_multiple, privacy_list, [server, username],
61 <<"DELETE FROM privacy_list WHERE server=? AND username=?">>),
62
:-(
mongoose_rdbms:prepare(privacy_list_insert, privacy_list, [server, username, name],
63 <<"INSERT INTO privacy_list(server, username, name) VALUES (?, ?, ?)">>),
64 %% Queries to privacy_default_list table
65
:-(
mongoose_rdbms:prepare(privacy_default_get_name, privacy_default_list, [server, username],
66 <<"SELECT name FROM privacy_default_list WHERE server=? AND username=?">>),
67
:-(
mongoose_rdbms:prepare(privacy_default_delete, privacy_default_list, [server, username],
68 <<"DELETE from privacy_default_list WHERE server=? AND username=?">>),
69
:-(
prepare_default_list_upsert(HostType),
70 %% Queries to privacy_list_data table
71
:-(
mongoose_rdbms:prepare(privacy_data_get_by_id, privacy_list_data, [id],
72 <<"SELECT ord, t, value, action, match_all, match_iq, "
73 "match_message, match_presence_in, match_presence_out "
74 "FROM privacy_list_data "
75 "WHERE id=? ORDER BY ord">>),
76
:-(
mongoose_rdbms:prepare(delete_data_by_id, privacy_list_data, [id],
77 <<"DELETE FROM privacy_list_data WHERE id=?">>),
78
:-(
mongoose_rdbms:prepare(privacy_data_delete, privacy_list_data, [id, ord],
79 <<"DELETE FROM privacy_list_data WHERE id=? AND ord=?">>),
80
:-(
mongoose_rdbms:prepare(privacy_data_update, privacy_list_data,
81 [t, value, action, match_all, match_iq,
82 match_message, match_presence_in, match_presence_out, id, ord],
83 <<"UPDATE privacy_list_data SET "
84 "t=?, value=?, action=?, match_all=?, match_iq=?, "
85 "match_message=?, match_presence_in=?, match_presence_out=? "
86 " WHERE id=? AND ord=?">>),
87
:-(
mongoose_rdbms:prepare(privacy_data_insert, privacy_list_data,
88 [id, ord, t, value, action, match_all, match_iq,
89 match_message, match_presence_in, match_presence_out],
90 <<"INSERT INTO privacy_list_data("
91 "id, ord, t, value, action, match_all, match_iq, "
92 "match_message, match_presence_in, match_presence_out) "
93 "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)">>),
94 %% This query uses multiple tables
95
:-(
mongoose_rdbms:prepare(privacy_data_delete_user, privacy_list, [server, username],
96 <<"DELETE FROM privacy_list_data WHERE id IN "
97 "(SELECT id FROM privacy_list WHERE server=? AND username=?)">>),
98 %% delete domain queries
99
:-(
mongoose_rdbms:prepare(privacy_default_delete_domain, privacy_default_list, [server],
100 <<"DELETE from privacy_default_list WHERE server=?">>),
101
:-(
mongoose_rdbms:prepare(privacy_list_delete_domain, privacy_list, [server],
102 <<"DELETE FROM privacy_list WHERE server=?">>),
103
:-(
mongoose_rdbms:prepare(privacy_data_delete_domain, privacy_list, [server],
104 <<"DELETE FROM privacy_list_data WHERE id IN "
105 "(SELECT id FROM privacy_list WHERE server=?)">>),
106
:-(
ok.
107
108 prepare_default_list_upsert(HostType) ->
109
:-(
Fields = [<<"name">>],
110
:-(
Filter = [<<"server">>, <<"username">>],
111
:-(
rdbms_queries:prepare_upsert(HostType, privacy_default_upsert, privacy_default_list,
112 Filter ++ Fields, Fields, Filter).
113
114 default_list_upsert(HostType, LServer, LUser, Name) ->
115
:-(
InsertParams = [LServer, LUser, Name],
116
:-(
UpdateParams = [Name],
117
:-(
UniqueKeyValues = [LServer, LUser],
118
:-(
rdbms_queries:execute_upsert(HostType, privacy_default_upsert,
119 InsertParams, UpdateParams, UniqueKeyValues).
120
121 get_default_list(HostType, LUser, LServer) ->
122
:-(
case get_default_list_name(HostType, LUser, LServer) of
123 none ->
124
:-(
{error, not_found};
125 Default ->
126
:-(
case get_privacy_list(HostType, LUser, LServer, Default) of
127 {ok, List} ->
128
:-(
{ok, {Default, List}};
129 {error, Reason} ->
130
:-(
{error, Reason}
131 end
132 end.
133
134 get_list_names(HostType, LUser, LServer) ->
135
:-(
Default = get_default_list_name(HostType, LUser, LServer),
136
:-(
Names = get_list_names_only(HostType, LUser, LServer),
137
:-(
{ok, {Default, Names}}.
138
139 get_default_list_name(HostType, LUser, LServer) ->
140
:-(
try execute_privacy_default_get_name(HostType, LServer, LUser) of
141 {selected, []} ->
142
:-(
none;
143 {selected, [{DefName}]} ->
144
:-(
DefName;
145 Other ->
146
:-(
?LOG_ERROR(#{what => privacy_get_default_list_name_failed,
147
:-(
user => LUser, server => LServer, reason => Other}),
148
:-(
none
149 catch
150 Class:Reason:StackTrace ->
151
:-(
?LOG_ERROR(#{what => privacy_get_default_list_name_failed,
152 user => LUser, server => LServer,
153
:-(
class => Class, reason => Reason, stacktrace => StackTrace}),
154
:-(
none
155 end.
156
157 get_list_names_only(HostType, LUser, LServer) ->
158
:-(
try execute_privacy_list_get_names(HostType, LServer, LUser) of
159 {selected, Names} ->
160
:-(
[Name || {Name} <- Names];
161 Other ->
162
:-(
?LOG_ERROR(#{what => privacy_get_list_names_only_failed,
163
:-(
user => LUser, server => LServer, reason => Other}),
164
:-(
[]
165 catch
166 Class:Reason:StackTrace ->
167
:-(
?LOG_ERROR(#{what => privacy_get_list_names_only_failed,
168 user => LUser, server => LServer,
169
:-(
class => Class, reason => Reason, stacktrace => StackTrace}),
170
:-(
[]
171 end.
172
173 get_privacy_list(HostType, LUser, LServer, Name) ->
174
:-(
try execute_privacy_list_get_id(HostType, LServer, LUser, Name) of
175 {selected, []} ->
176
:-(
{error, not_found};
177 {selected, [{ID}]} ->
178
:-(
IntID = mongoose_rdbms:result_to_integer(ID),
179
:-(
get_privacy_list_by_id(HostType, LUser, LServer, Name, IntID, LServer);
180 Other ->
181
:-(
?LOG_ERROR(#{what => privacy_get_privacy_list_failed,
182 user => LUser, server => LServer, list_name => Name,
183
:-(
reason => Other}),
184
:-(
{error, Other}
185 catch
186 Class:Reason:StackTrace ->
187
:-(
?LOG_ERROR(#{what => privacy_get_privacy_list_failed,
188 user => LUser, server => LServer, list_name => Name,
189
:-(
class => Class, reason => Reason, stacktrace => StackTrace}),
190
:-(
{error, Reason}
191 end.
192
193 get_privacy_list_by_id(HostType, LUser, LServer, Name, ID, LServer) when is_integer(ID) ->
194
:-(
try execute_privacy_data_get_by_id(HostType, ID) of
195 {selected, Rows} ->
196
:-(
{ok, raw_to_items(Rows)};
197 Other ->
198
:-(
?LOG_ERROR(#{what => privacy_get_privacy_list_by_id_failed,
199 user => LUser, server => LServer, list_name => Name, list_id => ID,
200
:-(
reason => Other}),
201
:-(
{error, Other}
202 catch
203 Class:Reason:StackTrace ->
204
:-(
?LOG_ERROR(#{what => privacy_get_privacy_list_by_id_failed,
205 user => LUser, server => LServer, list_name => Name, list_id => ID,
206
:-(
class => Class, reason => Reason, stacktrace => StackTrace}),
207
:-(
{error, Reason}
208 end.
209
210 %% @doc Set no default list for user.
211 forget_default_list(HostType, LUser, LServer) ->
212
:-(
try execute_privacy_default_delete(HostType, LServer, LUser) of
213 {updated, _} ->
214
:-(
ok;
215 Other ->
216
:-(
?LOG_ERROR(#{what => privacy_forget_default_list_failed,
217
:-(
user => LUser, server => LServer, reason => Other}),
218
:-(
{error, Other}
219 catch
220 Class:Reason:StackTrace ->
221
:-(
?LOG_ERROR(#{what => privacy_forget_default_list_failed,
222 user => LUser, server => LServer,
223
:-(
class => Class, reason => Reason, stacktrace => StackTrace}),
224
:-(
{error, Reason}
225 end.
226
227 set_default_list(HostType, LUser, LServer, Name) ->
228
:-(
F = fun() -> set_default_list_t(HostType, LServer, LUser, Name) end,
229
:-(
case rdbms_queries:sql_transaction(HostType, F) of
230 {atomic, ok} ->
231
:-(
ok;
232 {atomic, {error, Reason}} ->
233
:-(
{error, Reason};
234 {aborted, Reason} ->
235
:-(
{error, {aborted, Reason}};
236 {error, Reason} ->
237
:-(
{error, Reason}
238 end.
239
240 set_default_list_t(HostType, LServer, LUser, Name) ->
241
:-(
case execute_privacy_list_get_names(HostType, LServer, LUser) of
242 {selected, []} ->
243
:-(
{error, not_found};
244 {selected, Names} ->
245
:-(
case lists:member({Name}, Names) of
246 true ->
247
:-(
default_list_upsert(HostType, LServer, LUser, Name),
248
:-(
ok;
249 false ->
250
:-(
{error, not_found}
251 end
252 end.
253
254 remove_privacy_list(HostType, LUser, LServer, Name) ->
255
:-(
F = fun() ->
256
:-(
case execute_privacy_default_get_name(HostType, LServer, LUser) of
257 {selected, [{Name}]} -> %% Matches Name variable
258
:-(
{error, conflict};
259 {selected, _} ->
260
:-(
execute_privacy_list_delete_by_name(HostType, LServer, LUser, Name),
261
:-(
ok
262 end
263 end,
264
:-(
case rdbms_queries:sql_transaction(HostType, F) of
265 {atomic, {error, _} = Error} ->
266
:-(
Error;
267 {atomic, ok} ->
268
:-(
ok;
269 {aborted, Reason} ->
270
:-(
{error, {aborted, Reason}};
271 {error, Reason} ->
272
:-(
{error, Reason}
273 end.
274
275 replace_privacy_list(HostType, LUser, LServer, Name, List) ->
276
:-(
Rows = lists:map(fun item_to_raw/1, List),
277
:-(
F = fun() ->
278
:-(
ResultID = case execute_privacy_list_get_id(HostType, LServer, LUser, Name) of
279 {selected, []} ->
280
:-(
execute_privacy_list_insert(HostType, LServer, LUser, Name),
281
:-(
{selected, [{I}]} = execute_privacy_list_get_id(HostType, LServer, LUser, Name),
282
:-(
I;
283 {selected, [{I}]} ->
284
:-(
I
285 end,
286
:-(
ID = mongoose_rdbms:result_to_integer(ResultID),
287
:-(
replace_data_rows(HostType, ID, Rows),
288
:-(
ok
289 end,
290
:-(
{atomic, ok} = mongoose_rdbms:transaction_with_delayed_retry(HostType, F, #{retries => 5, delay => 100}),
291
:-(
ok.
292
293 remove_domain(HostType, LServer) ->
294
:-(
F = fun() -> remove_domain_t(HostType, LServer) end,
295
:-(
rdbms_queries:sql_transaction(HostType, F).
296
297 remove_domain_t(HostType, LServer) ->
298
:-(
mongoose_rdbms:execute_successfully(HostType, privacy_data_delete_domain, [LServer]),
299
:-(
mongoose_rdbms:execute_successfully(HostType, privacy_list_delete_domain, [LServer]),
300
:-(
mongoose_rdbms:execute_successfully(HostType, privacy_default_delete_domain, [LServer]).
301
302 remove_user(HostType, LUser, LServer) ->
303
:-(
F = fun() -> remove_user_t(HostType, LUser, LServer) end,
304
:-(
rdbms_queries:sql_transaction(HostType, F).
305
306 remove_user_t(HostType, LUser, LServer) ->
307
:-(
mongoose_rdbms:execute_successfully(HostType, privacy_data_delete_user, [LServer, LUser]),
308
:-(
mongoose_rdbms:execute_successfully(HostType, privacy_list_delete_multiple, [LServer, LUser]),
309
:-(
execute_privacy_default_delete(HostType, LServer, LUser).
310
311 execute_privacy_list_get_id(HostType, LServer, LUser, Name) ->
312
:-(
mongoose_rdbms:execute_successfully(HostType, privacy_list_get_id, [LServer, LUser, Name]).
313
314 execute_privacy_default_get_name(HostType, LServer, LUser) ->
315
:-(
mongoose_rdbms:execute_successfully(HostType, privacy_default_get_name, [LServer, LUser]).
316
317 execute_privacy_list_get_names(HostType, LServer, LUser) ->
318
:-(
mongoose_rdbms:execute_successfully(HostType, privacy_list_get_names, [LServer, LUser]).
319
320 execute_privacy_data_get_by_id(HostType, ID) ->
321
:-(
mongoose_rdbms:execute_successfully(HostType, privacy_data_get_by_id, [ID]).
322
323 execute_privacy_default_delete(HostType, LServer, LUser) ->
324
:-(
mongoose_rdbms:execute_successfully(HostType, privacy_default_delete, [LServer, LUser]).
325
326 execute_privacy_list_delete_by_name(HostType, LServer, LUser, Name) ->
327
:-(
mongoose_rdbms:execute_successfully(HostType, privacy_list_delete_by_name, [LServer, LUser, Name]).
328
329 execute_privacy_list_insert(HostType, LServer, LUser, Name) ->
330
:-(
mongoose_rdbms:execute_successfully(HostType, privacy_list_insert, [LServer, LUser, Name]).
331
332 execute_delete_data_by_id(HostType, ID) ->
333
:-(
mongoose_rdbms:execute_successfully(HostType, delete_data_by_id, [ID]).
334
335 replace_data_rows(HostType, ID, []) when is_integer(ID) ->
336 %% Just remove the data, nothing should be inserted
337
:-(
execute_delete_data_by_id(HostType, ID);
338 replace_data_rows(HostType, ID, Rows) when is_integer(ID) ->
339
:-(
{selected, OldRows} = execute_privacy_data_get_by_id(HostType, ID),
340
:-(
New = lists:sort(Rows),
341
:-(
Old = lists:sort([tuple_to_list(Row) || Row <- OldRows]),
342
:-(
Diff = diff_rows(ID, New, Old, []),
343
:-(
F = fun({Q, Args}) -> mongoose_rdbms:execute_successfully(HostType, Q, Args) end,
344
:-(
lists:foreach(F, Diff),
345
:-(
ok.
346
347 %% We assume that there are no record duplicates with the same Order.
348 %% It's checked in the main module for the New argument.
349 %% It's checked by the database for the Old argument.
350 diff_rows(ID, [H|New], [H|Old], Ops) ->
351
:-(
diff_rows(ID, New, Old, Ops); %% Not modified
352 diff_rows(ID, [NewH|NewT] = New, [OldH|OldT] = Old, Ops) ->
353
:-(
NewOrder = hd(NewH),
354
:-(
OldOrder = hd(OldH),
355
:-(
if NewOrder =:= OldOrder ->
356
:-(
Op = {privacy_data_update, tl(NewH) ++ [ID, OldOrder]},
357
:-(
diff_rows(ID, NewT, OldT, [Op|Ops]);
358 NewOrder > OldOrder ->
359
:-(
Op = {privacy_data_delete, [ID, OldOrder]},
360
:-(
diff_rows(ID, New, OldT, [Op|Ops]);
361 true ->
362
:-(
Op = {privacy_data_insert, [ID|NewH]},
363
:-(
diff_rows(ID, NewT, Old, [Op|Ops])
364 end;
365 diff_rows(ID, [], [OldH|OldT], Ops) ->
366
:-(
OldOrder = hd(OldH),
367
:-(
Op = {privacy_data_delete, [ID, OldOrder]},
368
:-(
diff_rows(ID, [], OldT, [Op|Ops]);
369 diff_rows(ID, [NewH|NewT], [], Ops) ->
370
:-(
Op = {privacy_data_insert, [ID|NewH]},
371
:-(
diff_rows(ID, NewT, [], [Op|Ops]);
372 diff_rows(_ID, [], [], Ops) ->
373
:-(
Ops.
374
375 %% Encoding/decoding pure functions
376
377 raw_to_items(Rows) ->
378
:-(
[raw_to_item(Row) || Row <- Rows].
379
380 raw_to_item({ExtOrder, ExtType, ExtValue, ExtAction,
381 ExtMatchAll, ExtMatchIQ, ExtMatchMessage,
382 ExtMatchPresenceIn, ExtMatchPresenceOut}) ->
383
:-(
Type = decode_type(mongoose_rdbms:character_to_integer(ExtType)),
384
:-(
#listitem{type = Type,
385 value = decode_value(Type, ExtValue),
386 action = decode_action(mongoose_rdbms:character_to_integer(ExtAction)),
387 order = mongoose_rdbms:result_to_integer(ExtOrder),
388 match_all = mongoose_rdbms:to_bool(ExtMatchAll),
389 match_iq = mongoose_rdbms:to_bool(ExtMatchIQ),
390 match_message = mongoose_rdbms:to_bool(ExtMatchMessage),
391 match_presence_in = mongoose_rdbms:to_bool(ExtMatchPresenceIn),
392 match_presence_out = mongoose_rdbms:to_bool(ExtMatchPresenceOut)}.
393
394 %% Encodes for privacy_data_insert query (but without ID)
395 -spec item_to_raw(mod_privacy:list_item()) -> list(term()).
396 item_to_raw(#listitem{type = Type,
397 value = Value,
398 action = Action,
399 order = Order,
400 match_all = MatchAll,
401 match_iq = MatchIQ,
402 match_message = MatchMessage,
403 match_presence_in = MatchPresenceIn,
404 match_presence_out = MatchPresenceOut}) ->
405
:-(
ExtType = encode_type(Type),
406
:-(
ExtValue = encode_value(Type, Value),
407
:-(
ExtAction = encode_action(Action),
408
:-(
Bools = [MatchAll, MatchIQ, MatchMessage, MatchPresenceIn, MatchPresenceOut],
409
:-(
ExtBools = [encode_boolean(X) || X <- Bools],
410
:-(
[Order, ExtType, ExtValue, ExtAction | ExtBools].
411
412
:-(
encode_boolean(true) -> 1;
413
:-(
encode_boolean(false) -> 0.
414
415
:-(
encode_action(allow) -> <<"a">>;
416
:-(
encode_action(deny) -> <<"d">>;
417
:-(
encode_action(block) -> <<"b">>.
418
419
:-(
decode_action($a) -> allow;
420
:-(
decode_action($d) -> deny;
421
:-(
decode_action($b) -> block.
422
423
:-(
encode_subscription(none) -> <<"none">>;
424
:-(
encode_subscription(both) -> <<"both">>;
425
:-(
encode_subscription(from) -> <<"from">>;
426
:-(
encode_subscription(to) -> <<"to">>.
427
428
:-(
decode_subscription(<<"none">>) -> none;
429
:-(
decode_subscription(<<"both">>) -> both;
430
:-(
decode_subscription(<<"from">>) -> from;
431
:-(
decode_subscription(<<"to">>) -> to.
432
433
:-(
encode_type(none) -> <<"n">>;
434
:-(
encode_type(jid) -> <<"j">>;
435
:-(
encode_type(group) -> <<"g">>;
436
:-(
encode_type(subscription) -> <<"s">>.
437
438
:-(
decode_type($n) -> none;
439
:-(
decode_type($j) -> jid;
440
:-(
decode_type($g) -> group;
441
:-(
decode_type($s) -> subscription.
442
443
:-(
encode_value(none, _Value) -> <<>>;
444
:-(
encode_value(jid, Value) -> jid:to_binary(Value);
445
:-(
encode_value(group, Value) -> Value;
446
:-(
encode_value(subscription, Value) -> encode_subscription(Value).
447
448
:-(
decode_value(none, _) -> none;
449
:-(
decode_value(jid, BinJid) -> jid:to_lower(jid:from_binary(BinJid));
450
:-(
decode_value(group, Group) -> Group;
451
:-(
decode_value(subscription, ExtSub) -> decode_subscription(ExtSub).
Line Hits Source