./ct_report/coverage/mongoose_domain_api.COVER.html

1 %% Main module other parts of MongooseIM should use to access the domain
2 %% management.
3 -module(mongoose_domain_api).
4
5 -include("mongoose_logger.hrl").
6
7 -export([get_host_type/1]).
8
9 %% external domain API for GraphQL or REST handlers
10 -export([insert_domain/2,
11 delete_domain/2,
12 request_delete_domain/2,
13 disable_domain/1,
14 enable_domain/1,
15 get_domain_details/1,
16 check_host_type_and_get_domains/1]).
17
18 %% external domain admin API for GraphQL or REST handlers
19 -export([set_domain_password/2,
20 delete_domain_password/1]).
21
22 %% domain API
23 -export([get_domain_host_type/1,
24 get_all_static/0,
25 get_domains_by_host_type/1]).
26
27 %% domain admin API
28 -export([check_domain_password/2]).
29
30 %% subdomain API
31 -export([register_subdomain/3,
32 unregister_subdomain/2,
33 get_subdomain_host_type/1,
34 get_subdomain_info/1,
35 get_all_subdomains_for_domain/1]).
36
37 %% Helper for remove_domain
38 -export([remove_domain_wrapper/3,
39 do_delete_domain_in_progress/2]).
40
41 %% For testing
42 -export([get_all_dynamic/0]).
43
44 -ignore_xref([get_all_static/0]).
45 -ignore_xref([get_all_dynamic/0]).
46
47 -type status() :: enabled | disabled | deleting.
48 -type domain() :: jid:lserver().
49 -type host_type() :: mongooseim:host_type().
50 -type subdomain_pattern() :: mongoose_subdomain_utils:subdomain_pattern().
51 -type remove_domain_acc() :: #{failed := [module()]}.
52
53 -type domain_info() :: #{domain := domain(), host_type => host_type(), status => status()}.
54
55 -type insert_result() :: {ok, domain_info()} |
56 {static | unknown_host_type | duplicate, iodata()}.
57 -type delete_result() :: {ok, domain_info()} |
58 {static | unknown_host_type | not_found | wrong_host_type, iodata()}.
59 -type set_status_result() :: {ok, domain_info()} |
60 {static | unknown_host_type | not_found | deleted, iodata()}.
61 -type get_domains_result() :: {ok, [domain()]} | {unknown_host_type, iodata()}.
62 -type get_domain_details_result() :: {ok, domain_info()} | {static | not_found, iodata()}.
63
64 -export_type([status/0, remove_domain_acc/0]).
65
66 -spec insert_domain(domain(), host_type()) -> insert_result().
67 insert_domain(Domain, HostType) ->
68 89 M = #{domain => Domain, host_type => HostType},
69 89 fold(M, [fun check_domain/1, fun check_host_type/1,
70 fun do_insert_domain/1, fun force_check/1, fun return_domain/1]).
71
72 -spec delete_domain(domain(), host_type()) -> delete_result().
73 delete_domain(Domain, HostType) ->
74 33 delete_domain(Domain, HostType, sync).
75
76 -spec request_delete_domain(domain(), host_type()) -> delete_result().
77 request_delete_domain(Domain, HostType) ->
78 11 delete_domain(Domain, HostType, async).
79
80 -spec delete_domain(domain(), host_type(), sync | async) -> delete_result().
81 delete_domain(Domain, HostType, RequestType) ->
82 44 M = #{domain => Domain, host_type => HostType, request_type => RequestType},
83 44 fold(M, [fun check_domain/1, fun check_host_type/1, fun set_domain_for_deletion/1,
84 fun force_check/1, fun do_delete_domain/1, fun return_domain/1]).
85
86 -spec disable_domain(domain()) -> set_status_result().
87 disable_domain(Domain) ->
88 19 M = #{domain => Domain, status => disabled},
89 19 fold(M, [fun check_domain/1, fun set_status/1, fun force_check/1, fun return_domain/1]).
90
91 -spec enable_domain(domain()) -> set_status_result().
92 enable_domain(Domain) ->
93 19 M = #{domain => Domain, status => enabled},
94 19 fold(M, [fun check_domain/1, fun set_status/1, fun force_check/1, fun return_domain/1]).
95
96 -spec check_host_type_and_get_domains(host_type()) -> get_domains_result().
97 check_host_type_and_get_domains(HostType) ->
98 6 M = #{host_type => HostType},
99 6 fold(M, [fun check_host_type/1, fun get_domains/1]).
100
101 -spec get_domain_details(domain()) -> get_domain_details_result().
102 get_domain_details(Domain) ->
103 15 M = #{domain => Domain},
104 15 fold(M, [fun check_domain/1, fun select_domain/1, fun return_domain/1]).
105
106 check_domain(M = #{domain := Domain}) ->
107 186 case mongoose_domain_core:is_static(Domain) of
108 true ->
109 21 {static, <<"Domain is static">>};
110 false ->
111 165 M
112 end.
113
114 check_host_type(M = #{host_type := HostType}) ->
115 128 case mongoose_domain_core:is_host_type_allowed(HostType) of
116 true ->
117 118 M;
118 false ->
119 10 {unknown_host_type, <<"Unknown host type">>}
120 end.
121
122 select_domain(M = #{domain := Domain}) ->
123 13 case mongoose_domain_sql:select_domain(Domain) of
124 {ok, DomainDetails} ->
125 5 maps:merge(M, DomainDetails);
126 {error, not_found} ->
127 8 {not_found, <<"Given domain does not exist">>}
128 end.
129
130 do_insert_domain(M = #{domain := Domain, host_type := HostType}) ->
131 79 case mongoose_domain_sql:insert_domain(Domain, HostType) of
132 ok ->
133 71 M;
134 {error, duplicate} ->
135 6 {duplicate, <<"Domain already exists">>}
136 end.
137
138 set_domain_for_deletion(M = #{domain := Domain, host_type := HostType}) ->
139 35 case mongoose_domain_sql:set_domain_for_deletion(Domain, HostType) of
140 ok ->
141 22 M;
142 {error, wrong_host_type} ->
143 5 {wrong_host_type, <<"Wrong host type was provided">>};
144 {error, not_found} ->
145 8 {not_found, <<"Given domain does not exist">>}
146 end.
147
148 force_check(M) ->
149 110 service_domain_db:force_check_for_updates(),
150 110 M.
151
152 do_delete_domain(M = #{domain := Domain, host_type := HostType, request_type := RequestType}) ->
153 22 mongoose_domain_sql:delete_domain_admin(Domain),
154 22 case RequestType of
155 sync ->
156 17 do_delete_domain_in_progress(Domain, HostType),
157 15 M#{status => deleted};
158 async ->
159 5 mongoose_domain_db_cleaner:request_delete_domain(Domain, HostType),
160 5 M#{status => deleting}
161 end.
162
163 set_status(M = #{domain := Domain, status := Status}) ->
164 30 case mongoose_domain_sql:set_status(Domain, Status) of
165 {error, unknown_host_type} ->
166 2 {unknown_host_type, <<"Unknown host type">>};
167 {error, domain_deleted} ->
168 1 {deleted, <<"Domain has been deleted">>};
169 {error, not_found} ->
170 8 {not_found, <<"Given domain does not exist">>};
171 ok ->
172 17 M
173 end.
174
175 return_domain(M) ->
176 113 {ok, maps:with([domain, host_type, status], M)}.
177
178 get_domains(#{host_type := HostType}) ->
179 4 {ok, get_domains_by_host_type(HostType)}.
180
181 -spec do_delete_domain_in_progress(domain(), host_type()) -> ok.
182 do_delete_domain_in_progress(Domain, HostType) ->
183 22 #{failed := []} = mongoose_hooks:remove_domain(HostType, Domain),
184 22 ok = mongoose_domain_sql:delete_domain(Domain, HostType).
185
186 %% Domain should be nameprepped using `jid:nameprep'
187 -spec get_host_type(domain()) ->
188 {ok, host_type()} | {error, not_found}.
189 get_host_type(Domain) ->
190 61353 case get_domain_host_type(Domain) of
191 56034 {ok, HostType} -> {ok, HostType};
192 {error, not_found} ->
193 5319 get_subdomain_host_type(Domain)
194 end.
195
196 %% Domain should be nameprepped using `jid:nameprep'
197 -spec get_domain_host_type(domain()) ->
198 {ok, host_type()} | {error, not_found}.
199 get_domain_host_type(Domain) ->
200 132324 mongoose_domain_core:get_host_type(Domain).
201
202 %% Subdomain should be nameprepped using `jid:nameprep'
203 -spec get_subdomain_host_type(domain()) ->
204 {ok, host_type()} | {error, not_found}.
205 get_subdomain_host_type(Subdomain) ->
206 11697 mongoose_subdomain_core:get_host_type(Subdomain).
207
208 %% Subdomain should be nameprepped using `jid:nameprep'
209 -spec get_subdomain_info(domain()) ->
210 {ok, mongoose_subdomain_core:subdomain_info()} | {error, not_found}.
211 get_subdomain_info(Subdomain) ->
212 3663 mongoose_subdomain_core:get_subdomain_info(Subdomain).
213
214 %% Get the list of the host_types provided during initialisation
215 %% This has complexity N, where N is the number of online domains.
216 -spec get_all_static() -> [{domain(), host_type()}].
217 get_all_static() ->
218 2 mongoose_domain_core:get_all_static().
219
220 %% Get domains, loaded from DB to this node
221 -spec get_all_dynamic() -> [{domain(), host_type()}].
222 get_all_dynamic() ->
223 1 mongoose_domain_core:get_all_dynamic().
224
225 %% Get the list of the host_types provided during initialisation
226 %% This has complexity N, where N is the number of online domains.
227 -spec get_domains_by_host_type(host_type()) -> [domain()].
228 get_domains_by_host_type(HostType) ->
229 107 mongoose_domain_core:get_domains_by_host_type(HostType).
230
231 -type password() :: binary().
232
233 -spec check_domain_password(domain(), password()) -> ok | {error, wrong_password | not_found}.
234 check_domain_password(Domain, Password) ->
235 468 case mongoose_domain_sql:select_domain_admin(Domain) of
236 {ok, {Domain, PassDetails}} ->
237 467 case do_check_domain_password(Password, PassDetails) of
238 true ->
239 450 ok;
240 false ->
241 17 {error, wrong_password}
242 end;
243 {error, not_found} ->
244 1 {error, not_found}
245 end.
246
247 do_check_domain_password(Password, PassDetails) ->
248 467 case mongoose_scram:deserialize(PassDetails) of
249 {ok, Scram} ->
250 467 mongoose_scram:check_password(Password, Scram);
251 {error, _Reason} ->
252
:-(
false
253 end.
254
255 -spec set_domain_password(domain(), password()) -> {ok | not_found, iodata()}.
256 set_domain_password(Domain, Password) ->
257 34 case get_host_type(Domain) of
258 {ok, _} ->
259 31 ok = mongoose_domain_sql:set_domain_admin(Domain, Password),
260 31 {ok, <<"Domain password set successfully">>};
261 {error, not_found} ->
262 3 {not_found, <<"Given domain does not exist or is disabled">>}
263 end.
264
265 -spec delete_domain_password(domain()) -> {ok, iodata()}.
266 delete_domain_password(Domain) ->
267 9 case mongoose_domain_sql:delete_domain_admin(Domain) of
268 ok ->
269 5 {ok, <<"Domain password deleted successfully">>};
270 {error, not_found} ->
271 4 {not_found, <<"Domain password does not exist">>}
272 end.
273
274 -spec register_subdomain(host_type(), subdomain_pattern(),
275 mongoose_packet_handler:t()) ->
276 ok | {error, already_registered | subdomain_already_exists}.
277 register_subdomain(HostType, SubdomainPattern, PacketHandler) ->
278 595 mongoose_subdomain_core:register_subdomain(HostType, SubdomainPattern,
279 PacketHandler).
280
281 -spec unregister_subdomain(host_type(), subdomain_pattern()) -> ok.
282 unregister_subdomain(HostType, SubdomainPattern) ->
283 597 mongoose_subdomain_core:unregister_subdomain(HostType, SubdomainPattern).
284
285 -spec get_all_subdomains_for_domain(domain()) ->
286 [mongoose_subdomain_core:subdomain_info()].
287 get_all_subdomains_for_domain(Domain) ->
288 43 mongoose_subdomain_core:get_all_subdomains_for_domain(Domain).
289
290 -spec remove_domain_wrapper(remove_domain_acc(), fun(() -> remove_domain_acc()), module()) ->
291 {ok | stop, remove_domain_acc()}.
292 remove_domain_wrapper(Acc, F, Module) ->
293 44 try F() of
294 43 Acc -> {ok, Acc}
295 catch C:R:S ->
296 1 ?LOG_ERROR(#{what => hook_failed,
297 text => <<"Error running hook">>,
298 module => Module,
299
:-(
class => C, reason => R, stacktrace => S}),
300 1 {stop, Acc#{failed := [Module | maps:get(failed, Acc)]}}
301 end.
302
303 fold({_, _} = Result, _) ->
304 186 Result;
305 fold(M, [Step | Rest]) when is_map(M) ->
306 720 fold(Step(M), Rest).
Line Hits Source