./ct_report/coverage/mongoose_client_api.COVER.html

1 -module(mongoose_client_api).
2
3 -export([init/2]).
4 -export([content_types_provided/2]).
5 -export([is_authorized/2]).
6 -export([options/2]).
7 -export([allowed_methods/2]).
8 -export([to_json/2]).
9 -export([bad_request/2]).
10 -export([bad_request/3]).
11 -export([forbidden_request/2]).
12 -export([forbidden_request/3]).
13 -export([json_to_map/1]).
14
15 -ignore_xref([allowed_methods/2, content_types_provided/2, forbidden_request/3,
16 options/2, to_json/2]).
17
18 -include("mongoose.hrl").
19 -include("jlib.hrl").
20
21 init(Req, _Opts) ->
22 99 State = #{},
23 99 case cowboy_req:header(<<"origin">>, Req) of
24 undefined ->
25 99 {cowboy_rest, Req, State};
26 Origin ->
27
:-(
Req1 = set_cors_headers(Origin, Req),
28
:-(
{cowboy_rest, Req1, State}
29 end.
30
31 set_cors_headers(Origin, Req) ->
32 %% set CORS headers
33
:-(
Headers = [{<<"access-control-allow-origin">>, Origin},
34 {<<"access-control-allow-methods">>, <<"GET, OPTIONS">>},
35 {<<"access-control-allow-credentials">>, <<"true">>},
36 {<<"access-control-allow-headers">>, <<"authorization, content-type">>}
37 ],
38
39
:-(
lists:foldl(fun set_cors_header/2, Req, Headers).
40
41 set_cors_header({Header, Value}, Req) ->
42
:-(
cowboy_req:set_resp_header(Header, Value, Req).
43
44 allowed_methods(Req, State) ->
45
:-(
{[<<"OPTIONS">>, <<"GET">>], Req, State}.
46
47 content_types_provided(Req, State) ->
48
:-(
{[
49 {{<<"application">>, <<"json">>, '*'}, to_json}
50 ], Req, State}.
51
52 options(Req, State) ->
53
:-(
{ok, Req, State}.
54
55 to_json(Req, User) ->
56
:-(
{<<"{}">>, Req, User}.
57
58 bad_request(Req, State) ->
59 3 bad_request(Req, <<"Bad request. The details are unknown.">>, State).
60
61 bad_request(Req, Reason, State) ->
62 5 reply(400, Req, Reason, State).
63
64 forbidden_request(Req, State) ->
65 3 forbidden_request(Req, <<>>, State).
66
67 forbidden_request(Req, Reason, State) ->
68 3 reply(403, Req, Reason, State).
69
70 reply(StatusCode, Req, Body, State) ->
71 8 maybe_report_error(StatusCode, Req, Body),
72 8 Req1 = set_resp_body_if_missing(Body, Req),
73 8 Req2 = cowboy_req:reply(StatusCode, Req1),
74 8 {stop, Req2, State#{was_replied => true}}.
75
76 set_resp_body_if_missing(Body, Req) ->
77 8 case cowboy_req:has_resp_body(Req) of
78 true ->
79 3 Req;
80 false ->
81 5 cowboy_req:set_resp_body(Body, Req)
82 end.
83
84 maybe_report_error(StatusCode, Req, Body) when StatusCode >= 400 ->
85 8 ?LOG_WARNING(#{what => reply_error,
86 stacktrace => element(2, erlang:process_info(self(), current_stacktrace)),
87
:-(
code => StatusCode, req => Req, reply_body => Body});
88 maybe_report_error(_StatusCode, _Req, _Body) ->
89
:-(
ok.
90
91 %%--------------------------------------------------------------------
92 %% Authorization
93 %%--------------------------------------------------------------------
94
95 % @doc cowboy callback
96 is_authorized(Req, State) ->
97 99 HTTPMethod = cowboy_req:method(Req),
98 99 AuthDetails = mongoose_api_common:get_auth_details(Req),
99 99 case AuthDetails of
100 undefined ->
101 2 mongoose_api_common:make_unauthorized_response(Req, State);
102 {AuthMethod, User, Password} ->
103 97 authorize(AuthMethod, User, Password, HTTPMethod, Req, State)
104 end.
105
106 authorize(AuthMethod, User, Password, HTTPMethod, Req, State) ->
107 97 MaybeJID = jid:from_binary(User),
108 97 case do_authorize(AuthMethod, MaybeJID, Password, HTTPMethod) of
109 noauth ->
110
:-(
{true, Req, State};
111 {true, Creds} ->
112 97 {true, Req, State#{user => User, jid => MaybeJID, creds => Creds}};
113 false ->
114
:-(
mongoose_api_common:make_unauthorized_response(Req, State)
115 end.
116
117 do_authorize(AuthMethod, MaybeJID, Password, HTTPMethod) ->
118 97 case is_noauth_http_method(HTTPMethod) of
119 true ->
120
:-(
noauth;
121 false ->
122 97 mongoose_api_common:is_known_auth_method(AuthMethod) andalso
123 97 mongoose_api_common:check_password(MaybeJID, Password)
124 end.
125
126 % Constraints
127
:-(
is_noauth_http_method(<<"OPTIONS">>) -> true;
128 97 is_noauth_http_method(_) -> false.
129
130 %% -------------------------------------------------------------------
131 %% @doc
132 %% Decode JSON binary into map
133 %% @end
134 %% -------------------------------------------------------------------
135 -spec json_to_map(JsonBin :: binary()) -> {ok, Map :: maps:map()} | {error, invalid_json}.
136
137 json_to_map(JsonBin) ->
138 60 case catch jiffy:decode(JsonBin, [return_maps]) of
139 Map when is_map(Map) ->
140 59 {ok, Map};
141 _ ->
142 1 {error, invalid_json}
143 end.
Line Hits Source