%%%------------------------------------------------------------------- %% @doc Cowboy handler for the read-only administration dashboard. %%%------------------------------------------------------------------- -module(vpn_dashboard_http). -export([init/2]). init(Req0, State) -> case cowboy_req:method(Req0) of <<"GET">> -> reply_dashboard(Req0, State); _Other -> Req = cowboy_req:reply( 405, #{<<"allow">> => <<"GET">>}, Req0), {ok, Req, State} end. reply_dashboard(Req0, State) -> try render(vpn_admin:summary_view()) of Html -> Req = cowboy_req:reply( 200, #{<<"content-type">> => <<"text/html; charset=utf-8">>}, Html, Req0), {ok, Req, State} catch _:_ -> Req = cowboy_req:reply( 500, #{<<"content-type">> => <<"text/html; charset=utf-8">>}, <<"VPN Dashboard Error" "

VPN Dashboard Error

">>, Req0), {ok, Req, State} end. render(Summary) -> Counts = maps:get(counts, Summary, #{}), Peers = maps:get(peers, Summary, []), iolist_to_binary([ <<"">>, <<"">>, <<"VPN Dashboard">>, style(), <<"
">>, <<"

VPN Dashboard

">>, actions(), counts(Counts), peers_table(Peers), <<"
">> ]). style() -> <<"">>. actions() -> <<"
" "" "
">>. counts(Counts) -> [ <<"
">>, count_card(<<"Configured Peers">>, maps:get(configured, Counts, 0)), count_card(<<"Running Peers">>, maps:get(running, Counts, 0)), count_card(<<"Stopped Peers">>, maps:get(stopped, Counts, 0)), count_card(<<"Certificates">>, maps:get(certificates, Counts, 0)), <<"
">> ]. count_card(Label, Value) -> [<<"
">>, html_escape(Label), <<"">>, html_escape(Value), <<"
">>]. peers_table(Peers) -> [ <<"">>, table_header(<<"Peer">>), table_header(<<"Running">>), table_header(<<"Mode">>), table_header(<<"IP">>), table_header(<<"Remote Peer">>), table_header(<<"Trusted">>), table_header(<<"Key Match">>), table_header(<<"Expires">>), table_header(<<"Crypto Failures">>), table_header(<<"Frames Rejected">>), table_header(<<"Actions">>), <<"">>, [peer_row(Peer) || Peer <- Peers], <<"
">> ]. table_header(Label) -> [<<"">>, html_escape(Label), <<"">>]. peer_row(Peer) -> Certificate = maps:get(certificate, Peer, #{}), [ <<"">>, table_cell(maps:get(id, Peer, null)), table_cell(yes_no(maps:get(running, Peer, false))), table_cell(maps:get(mode, Peer, null)), table_cell(maps:get(ip, Peer, null)), table_cell(maps:get(remote_peer_id, Peer, null)), table_cell(yes_no(maps:get(trusted, Certificate, false))), table_cell(yes_no(maps:get(key_match, Certificate, false))), table_cell(maps:get(not_after, Certificate, null)), table_cell(maps:get(crypto_failures, Peer, 0)), table_cell(maps:get(frames_rejected, Peer, 0)), table_cell_raw(peer_action(Peer)), <<"">> ]. table_cell(Value) -> [<<"">>, html_escape(Value), <<"">>]. table_cell_raw(Html) -> [<<"">>, Html, <<"">>]. peer_action(Peer) -> PeerId = maps:get(id, Peer, null), Running = maps:get(running, Peer, false), {Action, Label} = case Running of true -> {<<"stop">>, <<"Stop">>}; false -> {<<"start">>, <<"Start">>} end, [<<"
>, html_escape(PeerId), <<"/">>, Action, <<"\">
">>]. yes_no(true) -> <<"yes">>; yes_no(false) -> <<"no">>; yes_no(_Value) -> <<"no">>. html_escape(null) -> <<>>; html_escape(Value) when is_binary(Value) -> escape_binary(Value); html_escape(Value) when is_integer(Value) -> integer_to_binary(Value); html_escape(Value) when is_float(Value) -> float_to_binary(Value, [{decimals, 6}, compact]); html_escape(true) -> <<"true">>; html_escape(false) -> <<"false">>; html_escape(Value) when is_atom(Value) -> escape_binary(atom_to_binary(Value, utf8)); html_escape(Value) when is_list(Value) -> escape_binary(unicode:characters_to_binary(Value)); html_escape(_Value) -> <<>>. escape_binary(Value) -> escape_binary(Value, []). escape_binary(<<>>, Acc) -> iolist_to_binary(lists:reverse(Acc)); escape_binary(<<"&", Rest/binary>>, Acc) -> escape_binary(Rest, [<<"&">> | Acc]); escape_binary(<<"<", Rest/binary>>, Acc) -> escape_binary(Rest, [<<"<">> | Acc]); escape_binary(<<">", Rest/binary>>, Acc) -> escape_binary(Rest, [<<">">> | Acc]); escape_binary(<<"\"", Rest/binary>>, Acc) -> escape_binary(Rest, [<<""">> | Acc]); escape_binary(<<"'", Rest/binary>>, Acc) -> escape_binary(Rest, [<<"'">> | Acc]); escape_binary(<>, Acc) -> escape_binary(Rest, [<> | Acc]).