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

processone / ejabberd / 1296

19 Jan 2026 11:25AM UTC coverage: 33.562% (+0.09%) from 33.468%
1296

push

github

badlop
mod_conversejs: Cosmetic change: sort paths alphabetically

0 of 4 new or added lines in 1 file covered. (0.0%)

11245 existing lines in 174 files now uncovered.

15580 of 46421 relevant lines covered (33.56%)

1074.56 hits per line

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

29.27
/src/eldap_utils.erl
1
%%%----------------------------------------------------------------------
2
%%% File    : eldap_utils.erl
3
%%% Author  : Mickael Remond <mremond@process-one.net>
4
%%% Purpose : ejabberd LDAP helper functions
5
%%% Created : 12 Oct 2006 by Mickael Remond <mremond@process-one.net>
6
%%%
7
%%%
8
%%% ejabberd, Copyright (C) 2002-2026   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 along
21
%%% with this program; if not, write to the Free Software Foundation, Inc.,
22
%%% 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
23
%%%
24
%%%----------------------------------------------------------------------
25

26
-module(eldap_utils).
27

28
-author('mremond@process-one.net').
29

30
-export([generate_subfilter/1, find_ldap_attrs/2, check_filter/1,
31
         get_ldap_attr/2, get_user_part/2, make_filter/2,
32
         get_state/2, case_insensitive_match/2,
33
         decode_octet_string/3, uids_domain_subst/2]).
34

35
-include("logger.hrl").
36
-include("eldap.hrl").
37

38
%% Generate an 'or' LDAP query on one or several attributes
39
%% If there is only one attribute
40
generate_subfilter([UID]) ->
41
    subfilter(UID);
2✔
42
%% If there is several attributes
43
generate_subfilter(UIDs) ->
44
    iolist_to_binary(["(|", [subfilter(UID) || UID <- UIDs], ")"]).
×
45
%% Subfilter for a single attribute
46

47
subfilter({UIDAttr, UIDAttrFormat}) ->
48
%% The default UiDAttrFormat is %u
49
    <<$(, UIDAttr/binary, $=, UIDAttrFormat/binary, $)>>;
2✔
50
%% The default UiDAttrFormat is <<"%u">>
51
subfilter({UIDAttr}) ->
52
    <<$(, UIDAttr/binary, $=, "%u)">>.
×
53

54
%% Not tail-recursive, but it is not very terribly.
55
%% It stops finding on the first not empty value.
56
-spec find_ldap_attrs([{binary()} | {binary(), binary()}],
57
                      [{binary(), [binary()]}]) -> <<>> | {binary(), binary()}.
58

59
find_ldap_attrs([{Attr} | Rest], Attributes) ->
60
    find_ldap_attrs([{Attr, <<"%u">>} | Rest], Attributes);
×
61
find_ldap_attrs([{Attr, Format} | Rest], Attributes) ->
UNCOV
62
    case get_ldap_attr(Attr, Attributes) of
×
63
        Value when is_binary(Value), Value /= <<>> ->
UNCOV
64
            {Value, Format};
×
65
        _ ->
66
            find_ldap_attrs(Rest, Attributes)
×
67
    end;
68
find_ldap_attrs([], _) ->
69
    <<>>.
×
70

71
-spec get_ldap_attr(binary(), [{binary(), [binary()]}]) -> binary().
72

73
get_ldap_attr(LDAPAttr, Attributes) ->
74
    Res = lists:filter(
23✔
75
            fun({Name, _}) ->
76
                    case_insensitive_match(Name, LDAPAttr)
63✔
77
            end, Attributes),
78
    case Res of
23✔
79
        [{_, [Value|_]}] -> Value;
6✔
80
        _ -> <<>>
17✔
81
    end.
82

83
-spec get_user_part(binary(), binary()) -> {ok, binary()} | {error, badmatch}.
84

85
get_user_part(String, Pattern) ->
86
    F = fun(S, P) ->
2✔
87
                First = str:str(P, <<"%u">>),
2✔
88
                TailLength = byte_size(P) - (First+1),
2✔
89
                str:sub_string(S, First, byte_size(S) - TailLength)
2✔
90
        end,
91
    case catch F(String, Pattern) of
2✔
92
        {'EXIT', _} ->
93
            {error, badmatch};
×
94
        Result ->
95
            case catch ejabberd_regexp:replace(Pattern, <<"%u">>, Result) of
2✔
96
                {'EXIT', _} ->
97
                    {error, badmatch};
×
98
                StringRes ->
99
                    case case_insensitive_match(StringRes, String) of
2✔
100
                        true ->
101
                            {ok, Result};
2✔
102
                        false ->
103
                            {error, badmatch}
×
104
                    end
105
            end
106
    end.
107

108
-spec make_filter([{binary(), [binary()]}], [{binary(), binary()}]) -> any().
109

110
make_filter(Data, UIDs) ->
111
    NewUIDs = [{U, eldap_filter:do_sub(
×
112
                     UF, [{<<"%u">>, <<"*%u*">>, 1}])} || {U, UF} <- UIDs],
×
113
    Filter = lists:flatmap(
×
114
               fun({Name, [Value | _]}) ->
115
                       case Name of
×
116
                           <<"%u">> when Value /= <<"">> ->
117
                               case eldap_filter:parse(
×
118
                                      generate_subfilter(NewUIDs),
119
                                      [{<<"%u">>, Value}]) of
120
                                   {ok, F} -> [F];
×
121
                                   _ -> []
×
122
                               end;
123
                           _ when Value /= <<"">> ->
124
                               [eldap:substrings(
×
125
                                  Name,
126
                                  [{any, Value}])];
127
                           _ ->
128
                               []
×
129
                       end
130
               end, Data),
131
    case Filter of
×
132
        [F] ->
133
            F;
×
134
        _ ->
135
            eldap:'and'(Filter)
×
136
    end.
137

138
check_filter(F) ->
139
    NewF = iolist_to_binary(F),
×
140
    {ok, _} = eldap_filter:parse(NewF),
×
141
    NewF.
×
142

143
-spec case_insensitive_match(binary(), binary()) -> boolean().
144

145
case_insensitive_match(X, Y) ->
146
    X1 = str:to_lower(X),
465✔
147
    Y1 = str:to_lower(Y),
465✔
148
    if
465✔
149
        X1 == Y1 -> true;
28✔
150
        true -> false
437✔
151
    end.
152

153
get_state(Server, Module) ->
154
    Proc = gen_mod:get_module_proc(Server, Module),
7✔
155
    gen_server:call(Proc, get_state).
7✔
156

157
%% From the list of uids attribute:
158
%% we look from alias domain (%d) and make the substitution
159
%% with the actual host domain
160
%% This help when you need to configure many virtual domains.
161
-spec uids_domain_subst(binary(), [{binary(), binary()}]) ->
162
                               [{binary(), binary()}].
163

164
uids_domain_subst(Host, UIDs) ->
165
    lists:map(fun({U,V}) ->
2✔
166
                      {U, eldap_filter:do_sub(V,[{<<"%d">>, Host}])};
2✔
167
                  (A) -> A
×
168
              end,
169
              UIDs).
170

171
%%----------------------------------------
172
%% Borrowed from asn1rt_ber_bin_v2.erl
173
%%----------------------------------------
174

175
%%% The tag-number for universal types
176
-define(N_BOOLEAN, 1).
177
-define(N_INTEGER, 2).
178
-define(N_BIT_STRING, 3).
179
-define(N_OCTET_STRING, 4).
180
-define(N_NULL, 5).
181
-define(N_OBJECT_IDENTIFIER, 6).
182
-define(N_OBJECT_DESCRIPTOR, 7).
183
-define(N_EXTERNAL, 8).
184
-define(N_REAL, 9).
185
-define(N_ENUMERATED, 10).
186
-define(N_EMBEDDED_PDV, 11).
187
-define(N_SEQUENCE, 16).
188
-define(N_SET, 17).
189
-define(N_NumericString, 18).
190
-define(N_PrintableString, 19).
191
-define(N_TeletexString, 20).
192
-define(N_VideotexString, 21).
193
-define(N_IA5String, 22).
194
-define(N_UTCTime, 23).
195
-define(N_GeneralizedTime, 24).
196
-define(N_GraphicString, 25).
197
-define(N_VisibleString, 26).
198
-define(N_GeneralString, 27).
199
-define(N_UniversalString, 28).
200
-define(N_BMPString, 30).
201

202
decode_octet_string(Buffer, Range, Tags) ->
203
%    NewTags = new_tags(HasTag,#tag{class=?UNIVERSAL,number=?N_OCTET_STRING}),
204
    decode_restricted_string(Buffer, Range, Tags).
×
205

206
decode_restricted_string(Tlv, Range, TagsIn) ->
207
    Val = match_tags(Tlv, TagsIn),
×
208
    Val2 =
×
209
        case Val of
210
            PartList = [_H|_T] -> % constructed val
211
                collect_parts(PartList);
×
212
            Bin ->
213
                Bin
×
214
        end,
215
    check_and_convert_restricted_string(Val2, Range).
×
216

217
check_and_convert_restricted_string(Val, Range) ->
218
    {StrLen,NewVal} = if is_binary(Val) ->
×
219
                              {size(Val), Val};
×
220
                         true ->
221
                              {length(Val), list_to_binary(Val)}
×
222
                      end,
223
    case Range of
×
224
        [] -> % No length constraint
225
            NewVal;
×
226
        {Lb,Ub} when StrLen >= Lb, Ub >= StrLen -> % variable length constraint
227
            NewVal;
×
228
        {{Lb,_Ub},[]} when StrLen >= Lb ->
229
            NewVal;
×
230
        {{Lb,_Ub},_Ext=[Min|_]} when StrLen >= Lb; StrLen >= Min ->
231
            NewVal;
×
232
        {{Lb1,Ub1},{Lb2,Ub2}} when StrLen >= Lb1, StrLen =< Ub1;
233
                                   StrLen =< Ub2, StrLen >= Lb2 ->
234
            NewVal;
×
235
        StrLen -> % fixed length constraint
236
            NewVal;
×
237
        {_,_} ->
238
            exit({error,{asn1,{length,Range,Val}}});
×
239
        _Len when is_integer(_Len) ->
240
            exit({error,{asn1,{length,Range,Val}}});
×
241
        _ -> % some strange constraint that we don't support yet
242
            NewVal
×
243
    end.
244

245
%%----------------------------------------
246
%% Decode the in buffer to bits
247
%%----------------------------------------
248
match_tags({T,V},[T]) ->
249
    V;
×
250
match_tags({T,V}, [T|Tt]) ->
251
    match_tags(V,Tt);
×
252
match_tags([{T,V}],[T|Tt]) ->
253
    match_tags(V, Tt);
×
254
match_tags(Vlist = [{T,_V}|_], [T]) ->
255
    Vlist;
×
256
match_tags(Tlv, []) ->
257
    Tlv;
×
258
match_tags({Tag,_V},[T|_Tt]) ->
259
    {error,{asn1,{wrong_tag,{Tag,T}}}}.
×
260

261
collect_parts(TlvList) ->
262
    collect_parts(TlvList,[]).
×
263

264
collect_parts([{_,L}|Rest],Acc) when is_list(L) ->
265
    collect_parts(Rest,[collect_parts(L)|Acc]);
×
266
collect_parts([{?N_BIT_STRING,<<Unused,Bits/binary>>}|Rest],_Acc) ->
267
    collect_parts_bit(Rest,[Bits],Unused);
×
268
collect_parts([{_T,V}|Rest],Acc) ->
269
    collect_parts(Rest,[V|Acc]);
×
270
collect_parts([],Acc) ->
271
    list_to_binary(lists:reverse(Acc)).
×
272

273
collect_parts_bit([{?N_BIT_STRING,<<Unused,Bits/binary>>}|Rest],Acc,Uacc) ->
274
    collect_parts_bit(Rest,[Bits|Acc],Unused+Uacc);
×
275
collect_parts_bit([],Acc,Uacc) ->
276
    list_to_binary([Uacc|lists:reverse(Acc)]).
×
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

© 2026 Coveralls, Inc