• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

esl / MongooseIM / 16499779126

24 Jul 2025 02:03PM UTC coverage: 85.593% (-0.02%) from 85.614%
16499779126

Pull #4549

github

jacekwegr
Add TODO comments
Pull Request #4549: Support Erlang 28

50 of 68 new or added lines in 5 files covered. (73.53%)

289 existing lines in 7 files now uncovered.

28945 of 33817 relevant lines covered (85.59%)

51736.46 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

57.83
/src/auth/ejabberd_auth_rdbms.erl
1
%%%----------------------------------------------------------------------
2
%%% File    : ejabberd_auth_rdbms.erl
3
%%% Author  : Alexey Shchepin <alexey@process-one.net>
4
%%% Purpose : Authentification via RDBMS
5
%%% Created : 12 Dec 2004 by Alexey Shchepin <alexey@process-one.net>
6
%%%
7
%%%
8
%%% ejabberd, Copyright (C) 2002-2011   ProcessOne
9
%%%
10
%%% This program is free software; you can redistribute it and/or
11
%%% modify it under the terms of the GNU General Public License as
12
%%% published by the Free Software Foundation; either version 2 of the
13
%%% License, or (at your option) any later version.
14
%%%
15
%%% This program is distributed in the hope that it will be useful,
16
%%% but WITHOUT ANY WARRANTY; without even the implied warranty of
17
%%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18
%%% General Public License for more details.
19
%%%
20
%%% You should have received a copy of the GNU General Public License
21
%%% along with this program; if not, write to the Free Software
22
%%% Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
23
%%%
24
%%%----------------------------------------------------------------------
25

26
-module(ejabberd_auth_rdbms).
27
-author('alexey@process-one.net').
28

29
%% External exports
30
-behaviour(mongoose_gen_auth).
31

32
-export([start/1,
33
         stop/1,
34
         config_spec/0,
35
         authorize/1,
36
         set_password/4,
37
         try_register/4,
38
         get_registered_users/3,
39
         get_registered_users_number/3,
40
         get_password/3,
41
         get_password_s/3,
42
         does_user_exist/3,
43
         remove_user/3,
44
         remove_domain/2,
45
         supports_sasl_module/2,
46
         supported_features/0
47
        ]).
48

49
%% Internal
50
-export([check_password/4,
51
         check_password/6]).
52

53
-export([scram_passwords/2, scram_passwords/4]).
54

55
-ignore_xref([scram_passwords/2, scram_passwords/4]).
56

57
-import(mongoose_rdbms, [prepare/4, execute_successfully/3]).
58

59
-include("mongoose.hrl").
60
-include("mongoose_config_spec.hrl").
61

62
-define(DEFAULT_SCRAMMIFY_COUNT, 10000).
63
-define(DEFAULT_SCRAMMIFY_INTERVAL, 1000).
64

65

66
%%%----------------------------------------------------------------------
67
%%% Types
68
%%%----------------------------------------------------------------------
69

70
-type prepared_password() ::
71
        #{password := binary(),
72
          details => binary()}.
73

74
%%%----------------------------------------------------------------------
75
%%% API
76
%%%----------------------------------------------------------------------
77

78
-spec start(mongooseim:host_type()) -> ok.
79
start(HostType) ->
80
    prepare_queries(HostType),
1,860✔
81
    ok.
1,860✔
82

83
-spec stop(mongooseim:host_type()) -> ok.
84
stop(_HostType) ->
85
    ok.
8✔
86

87
-spec config_spec() -> mongoose_config_spec:config_section().
88
config_spec() ->
89
    #section{
15,224✔
90
       items = #{<<"users_number_estimate">> => #option{type = boolean}},
91
       defaults = #{<<"users_number_estimate">> => false}
92
      }.
93

94
-spec supports_sasl_module(mongooseim:host_type(), cyrsasl:sasl_module()) -> boolean().
95
supports_sasl_module(_HostType, cyrsasl_plain) -> true;
183,700✔
96
supports_sasl_module(HostType, cyrsasl_digest) -> not mongoose_scram:enabled(HostType);
56✔
97
supports_sasl_module(HostType, Mechanism) -> mongoose_scram:enabled(HostType, Mechanism).
2,709,987✔
98

99
-spec authorize(mongoose_credentials:t()) -> {ok, mongoose_credentials:t()}
100
                                           | {error, any()}.
101
authorize(Creds) ->
102
    ejabberd_auth:authorize_with_check_password(?MODULE, Creds).
59,511✔
103

104
-spec check_password(HostType :: mongooseim:host_type(),
105
                     LUser :: jid:luser(),
106
                     LServer :: jid:lserver(),
107
                     Password :: binary()) -> boolean().
108
check_password(HostType, LUser, LServer, Password) ->
109
    try execute_get_password(HostType, LServer, LUser) of
59,551✔
110
        {selected, [{Password, null}]} ->
111
            Password /= <<"">>; %% Password is correct, and not empty
72✔
112
        {selected, [{_Password2, null}]} ->
113
            false;
×
114
        {selected, [{_Password2, PassDetails}]} ->
115
            case mongoose_scram:deserialize(PassDetails) of
59,415✔
116
                {ok, Scram} ->
117
                    mongoose_scram:check_password(Password, Scram);
59,415✔
118
                {error, Reason} ->
119
                    ?LOG_WARNING(#{what => scram_serialisation_incorrect, reason => Reason,
×
120
                                   user => LUser, server => LServer}),
×
121
                    false %% Password is not correct
×
122
            end;
123
        {selected, []} ->
124
            false %% Account does not exist
64✔
125
    catch
126
        error:Reason:StackTrace ->
127
            ?LOG_ERROR(#{what => check_password_failed,
×
128
                         user => LUser, server => LServer,
129
                         class => error, reason => Reason, stacktrace => StackTrace}),
×
130
            false %% Database error
×
131
    end.
132

133
-spec check_password(HostType :: mongooseim:host_type(),
134
                     LUser :: jid:luser(),
135
                     LServer :: jid:lserver(),
136
                     Password :: binary(),
137
                     Digest :: binary(),
138
                     DigestGen :: fun()) -> boolean().
139

140
check_password(HostType, LUser, LServer, Password, Digest, DigestGen) ->
141
    try execute_get_password(HostType, LServer, LUser) of
8✔
142
        {selected, [{Passwd, null}]} ->
143
            ejabberd_auth:check_digest(Digest, DigestGen, Password, Passwd);
8✔
144
        {selected, [{_Passwd, PassDetails}]} ->
145
            case mongoose_scram:deserialize(PassDetails) of
×
146
                {ok, Scram} ->
147
                    mongoose_scram:check_digest(Scram, Digest, DigestGen, Password);
×
148
                {error, Reason} ->
149
                    ?LOG_WARNING(#{what => scram_serialisation_incorrect, reason => Reason,
×
150
                                   user => LUser, server => LServer}),
×
151
                    false
×
152
            end;
153
        {selected, []} ->
154
            false %% Account does not exist
×
155
    catch
156
        error:Reason:StackTrace ->
157
            ?LOG_ERROR(#{what => check_password_failed,
×
158
                         user => LUser, server => LServer,
159
                         class => error, reason => Reason, stacktrace => StackTrace}),
×
160
            false %% Database error
×
161
    end.
162

163
-spec set_password(HostType :: mongooseim:host_type(),
164
                   LUser :: jid:luser(),
165
                   LServer :: jid:lserver(),
166
                   Password :: binary()
167
                   ) -> ok | {error, not_allowed}.
168
set_password(HostType, LUser, LServer, Password) ->
169
    PreparedPass = prepare_password(HostType, Password),
88✔
170
    try
88✔
171
        execute_set_password(HostType, LServer, LUser, PreparedPass),
88✔
172
        ok
88✔
173
    catch
174
        error:Reason:StackTrace ->
175
            ?LOG_ERROR(#{what => set_password_failed,
×
176
                         user => LUser, server => LServer,
177
                         class => error, reason => Reason, stacktrace => StackTrace}),
×
178
            {error, not_allowed}
×
179
    end.
180

181
-spec try_register(HostType :: mongooseim:host_type(),
182
                   LUser :: jid:luser(),
183
                   LServer :: jid:lserver(),
184
                   Password :: binary()
185
                   ) -> ok | {error, exists}.
186
try_register(HostType, LUser, LServer, Password) ->
187
    PreparedPass = prepare_password(HostType, Password),
53,644✔
188
    try execute_add_user(HostType, LServer, LUser, PreparedPass) of
53,644✔
189
        {updated, 1} ->
190
            ok;
53,644✔
191
        {updated, 0} ->
192
            {error, exists}
×
193
    catch
194
        error:Reason:StackTrace ->
195
            ?LOG_ERROR(#{what => registration_failed,
×
196
                         user => LUser, server => LServer,
197
                         class => error, reason => Reason, stacktrace => StackTrace}),
×
198
            {error, exists} %% XXX wrong error type - fix type in a separate PR
×
199
    end.
200

201
-spec get_registered_users(mongooseim:host_type(), jid:lserver(), Opts :: list()) ->
202
          [jid:simple_bare_jid()].
203
get_registered_users(HostType, LServer, Opts) ->
204
    try
2,082✔
205
        {selected, Res} = execute_list_users(HostType, LServer, maps:from_list(Opts)),
2,082✔
206
        [{U, LServer} || {U} <- Res]
2,082✔
207
    catch error:Reason:StackTrace ->
208
        ?LOG_ERROR(#{what => get_vh_registered_users_failed, server => LServer,
×
209
                     class => error, reason => Reason, stacktrace => StackTrace}),
×
210
        []
×
211
    end.
212

213
-spec get_registered_users_number(mongooseim:host_type(), jid:lserver(), Opts :: list()) ->
214
          non_neg_integer().
215
get_registered_users_number(HostType, LServer, Opts) ->
216
    try
55,518✔
217
        Selected = execute_count_users(HostType, LServer, maps:from_list(Opts)),
55,518✔
218
        mongoose_rdbms:selected_to_integer(Selected)
55,518✔
219
    catch error:Reason:StackTrace ->
220
        ?LOG_ERROR(#{what => get_vh_registered_users_numbers_failed, server => LServer,
×
221
                     class => error, reason => Reason, stacktrace => StackTrace}),
×
222
        0
×
223
    end.
224

225
-spec get_password(mongooseim:host_type(), jid:luser(), jid:lserver()) ->
226
          ejabberd_auth:passterm() | false.
227
get_password(HostType, LUser, LServer) ->
228
    try execute_get_password(HostType, LServer, LUser) of
752✔
229
        {selected, [{Password, null}]} ->
230
            Password; %% Plain password
280✔
231
        {selected, [{_Password, PassDetails}]} ->
232
            case mongoose_scram:deserialize(PassDetails) of
456✔
233
                {ok, Scram} ->
234
                    Scram;
456✔
235
                {error, Reason} ->
236
                    ?LOG_WARNING(#{what => scram_serialisation_incorrect, reason => Reason,
×
237
                                   user => LUser, server => LServer}),
×
238
                    false
×
239
            end;
240
        {selected, []} ->
241
            false
16✔
242
    catch
243
        error:Reason:StackTrace ->
244
            ?LOG_ERROR(#{what => get_password_failed,
×
245
                         user => LUser, server => LServer,
246
                         class => error, reason => Reason, stacktrace => StackTrace}),
×
247
            false
×
248
    end.
249

250

251
-spec get_password_s(mongooseim:host_type(), jid:luser(), jid:lserver()) -> binary().
252
get_password_s(HostType, LUser, LServer) ->
253
    try execute_get_password(HostType, LServer, LUser) of
136✔
254
        {selected, [{Password, _}]} ->
255
            Password;
120✔
256
        {selected, []} ->
257
            <<>>
16✔
258
    catch
259
        error:Reason:StackTrace ->
260
            ?LOG_ERROR(#{what => get_password_s_failed,
×
261
                         user => LUser, server => LServer,
262
                         class => error, reason => Reason, stacktrace => StackTrace}),
×
263
            <<>>
×
264
    end.
265

266

267
-spec does_user_exist(mongooseim:host_type(), jid:luser(), jid:lserver()) ->
268
          boolean() | {error, atom()}.
269
does_user_exist(HostType, LUser, LServer) ->
270
    try execute_get_password(HostType, LServer, LUser) of
142,268✔
271
        {selected, [{_Password, _}]} ->
272
            true; %% Account exists
81,857✔
273
        {selected, []} ->
274
            false %% Account does not exist
60,411✔
275
    catch
276
        error:Reason:StackTrace ->
277
            ?LOG_ERROR(#{what => does_user_exist_failed,
×
278
                         user => LUser, server => LServer,
279
                         class => error, reason => Reason, stacktrace => StackTrace}),
×
280
            {error, Reason} %% Database error
×
281

282
    end.
283

284

285
%% @doc Remove user.
286
%% Note: it may return ok even if there was some problem removing the user.
287
-spec remove_user(mongooseim:host_type(), jid:luser(), jid:lserver()) -> ok.
288
remove_user(HostType, LUser, LServer) ->
289
    try
53,334✔
290
        execute_delete_user(HostType, LServer, LUser)
53,334✔
291
    catch
292
        error:Reason:StackTrace ->
293
            ?LOG_ERROR(#{what => remove_user_failed,
×
294
                         user => LUser, server => LServer,
295
                         class => error, reason => Reason, stacktrace => StackTrace})
×
296
    end,
297
    ok.
53,334✔
298

299
-spec remove_domain(mongooseim:host_type(), jid:lserver()) -> ok.
300
remove_domain(HostType, Domain) ->
301
    execute_successfully(HostType, auth_remove_domain, [Domain]),
154✔
302
    ok.
154✔
303

304
-spec supported_features() -> [atom()].
305
supported_features() -> [dynamic_domains].
616✔
306

307
%%%------------------------------------------------------------------
308
%%% Scram
309
%%%------------------------------------------------------------------
310

311
-spec prepare_scrammed_password(HostType, Iterations, Password) -> prepared_password() when
312
        HostType :: mongooseim:host_type(),
313
        Iterations :: pos_integer(),
314
        Password :: binary().
315
prepare_scrammed_password(HostType, Iterations, Password) when is_integer(Iterations) ->
316
    Scram = mongoose_scram:password_to_scram(HostType, Password, Iterations),
53,476✔
317
    #{password => <<>>,
53,476✔
318
      details => mongoose_scram:serialize(Scram)}.
319

320
-spec prepare_password(HostType :: mongooseim:host_type(), Password :: binary()) ->
321
          prepared_password().
322
prepare_password(HostType, Password) ->
323
    case mongoose_scram:enabled(HostType) of
53,732✔
324
        true ->
325
            prepare_scrammed_password(HostType, mongoose_scram:iterations(HostType), Password);
53,476✔
326
        false ->
327
            #{password => Password}
256✔
328
    end.
329

330
-spec scram_passwords(Server, ScramIterationCount) -> ok | {error, atom()} when
331
    Server :: jid:lserver(),
332
    ScramIterationCount :: pos_integer().
333
scram_passwords(Server, ScramIterationCount) ->
334
    scram_passwords(Server, ?DEFAULT_SCRAMMIFY_COUNT,
×
335
                    ?DEFAULT_SCRAMMIFY_INTERVAL, ScramIterationCount).
336

337
-spec scram_passwords(Server, Count, Interval, ScramIterationCount) ->
338
    ok | {error, atom()} when
339
        Server :: jid:lserver(),
340
        Count :: pos_integer(),
341
        Interval :: pos_integer(),
342
        ScramIterationCount :: pos_integer().
343
scram_passwords(Server, Count, Interval, ScramIterationCount) ->
344
    LServer = jid:nameprep(Server),
×
345
    {ok, HostType} = mongoose_domain_api:get_domain_host_type(LServer),
×
346
    ?LOG_INFO(#{what => scram_passwords, server => Server,
×
347
                text => <<"Converting the stored passwords into SCRAM bits">>}),
×
348
    Selected = execute_count_users_without_scram(HostType, LServer),
×
349
    ToConvertCount = mongoose_rdbms:selected_to_integer(Selected),
×
350

351
    ?LOG_INFO(#{what => scram_passwords, server => Server,
×
352
                convert_count => ToConvertCount,
353
                text => <<"Users to scrammify">>}),
×
354
    scram_passwords1(HostType, LServer, Count, Interval, ScramIterationCount).
×
355

356
-spec scram_passwords1(HostType, LServer, Count, Interval, ScramIterationCount) ->
357
    ok | {error, interrupted} when
358
        HostType :: mongooseim:host_type(),
359
        LServer :: jid:lserver(),
360
        Count :: pos_integer(),
361
        Interval :: pos_integer(),
362
        ScramIterationCount :: pos_integer().
363
scram_passwords1(HostType, LServer, Count, Interval, ScramIterationCount) ->
364
    case execute_list_users_without_scram(HostType, LServer, Count) of
×
365
        {selected, []} ->
366
            ?LOG_INFO(#{what => scram_passwords_completed,
×
367
                        text => <<"All users scrammed">>}),
×
368
            ok;
×
369
        {selected, Results} ->
370
            ?LOG_INFO(#{what => scram_passwords_progress,
×
371
                        user_count => length(Results),
372
                        text => <<"Scramming users in progress...">>}),
×
373
            lists:foreach(
×
374
              fun({Username, Password}) ->
375
                ScrammedPassword = prepare_scrammed_password(HostType,
×
376
                                                             ScramIterationCount,
377
                                                             Password),
378
                execute_set_password(HostType, LServer, Username, ScrammedPassword)
×
379
              end, Results),
380
            ?LOG_INFO(#{what => scram_passwords_progress,
×
381
                        user_count => length(Results), interval => Interval,
382
                        text => io_lib:format("Scrammed. Waiting for ~pms", [Interval])}),
×
383
            timer:sleep(Interval),
×
384
            scram_passwords1(HostType, LServer, Count, Interval, ScramIterationCount)
×
385
    end.
386

387
%%%------------------------------------------------------------------
388
%%% DB Queries
389
%%%------------------------------------------------------------------
390

391
-spec prepare_queries(mongooseim:host_type()) -> any().
392
prepare_queries(HostType) ->
393
    prepare(auth_get_password, users,
1,860✔
394
            [server, username],
395
            <<"SELECT password, pass_details FROM users "
396
              "WHERE server = ? AND username = ?">>),
397
    prepare(auth_set_password_scram, users,
1,860✔
398
            [password, pass_details, server, username],
399
            <<"UPDATE users SET password = ?, pass_details = ? "
400
              "WHERE server = ? AND username = ?">>),
401
    prepare(auth_set_password, users,
1,860✔
402
            [password, server, username],
403
            <<"UPDATE users SET password = ? WHERE server = ? AND username = ?">>),
404
    prepare(auth_add_user_scram, users,
1,860✔
405
            [server, username, password, pass_details],
406
            <<"INSERT INTO users(server, username, password, pass_details) VALUES (?, ?, ?, ?)">>),
407
    prepare(auth_add_user, users,
1,860✔
408
            [server, username, password],
409
            <<"INSERT INTO users(server, username, password) VALUES (?, ?, ?)">>),
410
    prepare(auth_delete_user, users,
1,860✔
411
            [server, username],
412
            <<"DELETE FROM users WHERE server = ? AND username = ?">>),
413
    prepare(auth_list_users, users, [server],
1,860✔
414
            <<"SELECT username FROM users WHERE server = ?">>),
415
    LimitOffset = rdbms_queries:limit_offset_sql(),
1,860✔
416
    prepare(auth_list_users_range, users,
1,860✔
417
            [server, limit, offset],
418
            <<"SELECT username FROM users WHERE server = ? ORDER BY username ",
419
              LimitOffset/binary>>),
420
    prepare(auth_list_users_prefix, users,
1,860✔
421
            [server, username],
422
            <<"SELECT username FROM users "
423
              "WHERE server = ? AND username LIKE ? ESCAPE '$' ORDER BY username">>),
424
    prepare(auth_list_users_prefix_range, users,
1,860✔
425
            [server, username, limit, offset],
426
            <<"SELECT username FROM users "
427
              "WHERE server = ? AND username LIKE ? ESCAPE '$' ORDER BY username ",
428
              LimitOffset/binary>>),
429
    {LimitSQL, LimitMSSQL} = rdbms_queries:get_db_specific_limits_binaries(),
1,860✔
430
    prepare(auth_list_users_without_scram, users,
1,860✔
431
            [server, limit],
432
            <<"SELECT ", LimitMSSQL/binary, " username, password FROM users "
433
              "WHERE server = ? AND pass_details is NULL ", LimitSQL/binary>>),
434
    prepare(auth_count_users_prefix, users,
1,860✔
435
            [server, username],
436
            <<"SELECT COUNT(*) FROM users WHERE server = ? AND username LIKE ? ESCAPE '$'">>),
437
    prepare_count_users(HostType),
1,860✔
438
    prepare(auth_count_users_without_scram, users, [server],
1,860✔
439
            <<"SELECT COUNT(*) FROM users WHERE server = ? AND pass_details is NULL">>),
440
    prepare(auth_remove_domain, users, [server],
1,860✔
441
            <<"DELETE FROM users WHERE server = ?">>).
442

443
prepare_count_users(HostType) ->
444
    case {mongoose_config:get_opt([{auth, HostType}, rdbms, users_number_estimate]),
1,860✔
445
          mongoose_rdbms:db_engine(HostType)} of
446
        {true, mysql} ->
447
            prepare(auth_count_users_estimate, 'information_schema.tables', [],
2✔
448
                    <<"SELECT table_rows FROM information_schema.tables "
449
                      "WHERE table_name = 'users'">>);
450
        {true, Driver} when Driver =:= pgsql; Driver =:= cockroachdb ->
451
            prepare_count_users(),
4✔
452
            prepare(auth_count_users_estimate, pg_class, [],
4✔
453
                    <<"SELECT reltuples::numeric FROM pg_class "
454
                      "WHERE oid = 'users'::regclass::oid">>);
455
        _ ->
456
            prepare_count_users()
1,854✔
457
    end.
458

459
prepare_count_users() ->
460
    prepare(auth_count_users, users, [server], <<"SELECT COUNT(*) FROM users WHERE server = ?">>).
1,858✔
461

462
-spec execute_get_password(mongooseim:host_type(), jid:lserver(), jid:luser()) ->
463
          mongoose_rdbms:query_result().
464
execute_get_password(HostType, LServer, LUser) ->
465
    execute_successfully(HostType, auth_get_password, [LServer, LUser]).
202,715✔
466

467
-spec execute_set_password(mongooseim:host_type(), jid:lserver(), jid:luser(),
468
                           prepared_password()) ->
469
          mongoose_rdbms:query_result().
470
execute_set_password(HostType, LServer, LUser, #{password := Pass, details := PassDetails}) ->
471
    execute_successfully(HostType, auth_set_password_scram, [Pass, PassDetails, LServer, LUser]);
88✔
472
execute_set_password(HostType, LServer, LUser, #{password := Pass}) ->
473
    execute_successfully(HostType, auth_set_password, [Pass, LServer, LUser]).
×
474

475
-spec execute_add_user(mongooseim:host_type(), jid:lserver(), jid:luser(), prepared_password()) ->
476
          mongoose_rdbms:query_result().
477
execute_add_user(HostType, LServer, LUser, #{password := Pass, details := PassDetails}) ->
478
    execute_successfully(HostType, auth_add_user_scram, [LServer, LUser, Pass, PassDetails]);
53,388✔
479
execute_add_user(HostType, LServer, LUser, #{password := Pass}) ->
480
    execute_successfully(HostType, auth_add_user, [LServer, LUser, Pass]).
256✔
481

482
-spec execute_delete_user(mongooseim:host_type(), jid:lserver(), jid:luser()) ->
483
          mongoose_rdbms:query_result().
484
execute_delete_user(HostType, LServer, LUser) ->
485
    execute_successfully(HostType, auth_delete_user, [LServer, LUser]).
53,334✔
486

487
-spec execute_list_users(mongooseim:host_type(), jid:lserver(), map()) ->
488
          mongoose_rdbms:query_result().
489
execute_list_users(HostType, LServer, #{from := Start, to := End} = OptMap) ->
490
    Map = maps:without([from, to], OptMap),
32✔
491
    execute_list_users(HostType, LServer, Map#{limit => End - Start + 1, offset => Start - 1});
32✔
492
execute_list_users(HostType, LServer, #{prefix := Prefix, limit := Limit, offset := Offset}) ->
493
    Args = [LServer, prefix_to_like(Prefix)] ++ rdbms_queries:limit_offset_args(Limit, Offset),
16✔
494
    execute_successfully(HostType, auth_list_users_prefix_range, Args);
16✔
495
execute_list_users(HostType, LServer, #{prefix := Prefix}) ->
496
    Args = [LServer, prefix_to_like(Prefix)],
8✔
497
    execute_successfully(HostType, auth_list_users_prefix, Args);
8✔
498
execute_list_users(HostType, LServer, #{limit := Limit, offset := Offset}) ->
499
    Args = [LServer] ++ rdbms_queries:limit_offset_args(Limit, Offset),
16✔
500
    execute_successfully(HostType, auth_list_users_range, Args);
16✔
501
execute_list_users(HostType, LServer, #{}) ->
502
    execute_successfully(HostType, auth_list_users, [LServer]).
2,042✔
503

504
-spec execute_list_users_without_scram(mongooseim:host_type(), jid:lserver(), non_neg_integer()) ->
505
          mongoose_rdbms:query_result().
506
execute_list_users_without_scram(HostType, LServer, Limit) ->
507
    execute_successfully(HostType, auth_list_users_without_scram, [LServer, Limit]).
×
508

509
-spec execute_count_users(mongooseim:host_type(), jid:lserver(), map()) ->
510
          mongoose_rdbms:query_result().
511
execute_count_users(HostType, LServer, #{prefix := Prefix}) ->
512
    Args = [LServer, prefix_to_like(Prefix)],
8✔
513
    execute_successfully(HostType, auth_count_users_prefix, Args);
8✔
514
execute_count_users(HostType, LServer, #{}) ->
515
    case {mongoose_config:get_opt([{auth, HostType}, rdbms, users_number_estimate]),
55,510✔
516
          mongoose_rdbms:db_engine(LServer)} of
517
        {true, mysql} ->
518
            execute_successfully(HostType, auth_count_users_estimate, []);
2✔
519
        {true, Driver} when Driver =:= pgsql; Driver =:= cockroachdb ->
520
            case execute_successfully(HostType, auth_count_users_estimate, []) of
4✔
521
                {selected,[{<<"-1">>}]} ->
522
                    execute_successfully(HostType, auth_count_users, [LServer]);
4✔
523
                Otherwise ->
UNCOV
524
                    Otherwise
×
525
            end;
526
        _ ->
527
            execute_successfully(HostType, auth_count_users, [LServer])
55,504✔
528
    end.
529

530
-spec execute_count_users_without_scram(mongooseim:host_type(), jid:lserver()) ->
531
          mongoose_rdbms:query_result().
532
execute_count_users_without_scram(HostType, LServer) ->
533
    execute_successfully(HostType, auth_count_users_without_scram, [LServer]).
×
534

535
-spec prefix_to_like(binary()) -> binary().
536
prefix_to_like(Prefix) ->
537
    EscapedPrefix = mongoose_rdbms:escape_prepared_like(Prefix),
32✔
538
    <<EscapedPrefix/binary, $%>>.
32✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc