summaryrefslogtreecommitdiff
path: root/deps/rabbitmq_trust_store/src/rabbit_trust_store_file_provider.erl
diff options
context:
space:
mode:
Diffstat (limited to 'deps/rabbitmq_trust_store/src/rabbit_trust_store_file_provider.erl')
-rw-r--r--deps/rabbitmq_trust_store/src/rabbit_trust_store_file_provider.erl110
1 files changed, 110 insertions, 0 deletions
diff --git a/deps/rabbitmq_trust_store/src/rabbit_trust_store_file_provider.erl b/deps/rabbitmq_trust_store/src/rabbit_trust_store_file_provider.erl
new file mode 100644
index 0000000000..820ad550dd
--- /dev/null
+++ b/deps/rabbitmq_trust_store/src/rabbit_trust_store_file_provider.erl
@@ -0,0 +1,110 @@
+%% This Source Code Form is subject to the terms of the Mozilla Public
+%% License, v. 2.0. If a copy of the MPL was not distributed with this
+%% file, You can obtain one at https://mozilla.org/MPL/2.0/.
+%%
+%% Copyright (c) 2007-2020 VMware, Inc. or its affiliates. All rights reserved.
+%%
+
+-module(rabbit_trust_store_file_provider).
+
+-include_lib("kernel/include/file.hrl").
+
+-behaviour(rabbit_trust_store_certificate_provider).
+
+-export([list_certs/1, list_certs/2, load_cert/3]).
+
+-define(DIRECTORY_OR_FILE_NAME_EXISTS, eexist).
+
+-type cert_id() :: {FileName :: string(),
+ ChangeTime :: integer(),
+ Hash :: integer()}.
+
+-spec list_certs(Config :: list())
+ -> no_change | {ok, [{cert_id(), list()}], State}
+ when State :: nostate.
+list_certs(Config) ->
+ Path = directory_path(Config),
+ Certs = list_certs_0(Path),
+ {ok, Certs, nostate}.
+
+-spec list_certs(Config :: list(), State)
+ -> no_change | {ok, [{cert_id(), list()}], State}
+ when State :: nostate.
+list_certs(Config, _) ->
+ list_certs(Config).
+
+-spec load_cert(cert_id(), list(), Config :: list())
+ -> {ok, Cert :: public_key:der_encoded()}.
+load_cert({FileName, _, _}, _, Config) ->
+ Path = directory_path(Config),
+ Cert = extract_cert(Path, FileName),
+ rabbit_log:info(
+ "trust store: loading certificate '~s'", [FileName]),
+ {ok, Cert}.
+
+extract_cert(Path, FileName) ->
+ Absolute = filename:join(Path, FileName),
+ scan_then_parse(Absolute).
+
+scan_then_parse(Filename) when is_list(Filename) ->
+ {ok, Bin} = file:read_file(Filename),
+ [{'Certificate', Data, not_encrypted}] = public_key:pem_decode(Bin),
+ Data.
+
+list_certs_0(Path) ->
+ {ok, FileNames} = file:list_dir(Path),
+ lists:map(
+ fun(FileName) ->
+ AbsName = filename:absname(FileName, Path),
+ CertId = {FileName,
+ modification_time(AbsName),
+ file_content_hash(AbsName)},
+ {CertId, [{name, FileName}]}
+ end,
+ FileNames).
+
+modification_time(Path) ->
+ {ok, Info} = file:read_file_info(Path, [{time, posix}]),
+ Info#file_info.mtime.
+
+file_content_hash(Path) ->
+ {ok, Data} = file:read_file(Path),
+ erlang:phash2(Data).
+
+directory_path(Config) ->
+ directory_path(Config, default_directory()).
+
+directory_path(Config, Default) ->
+ Path = case proplists:get_value(directory, Config) of
+ undefined ->
+ Default;
+ V when is_binary(V) ->
+ binary_to_list(V);
+ V when is_list(V) ->
+ V
+ end,
+ ok = ensure_directory(Path),
+ Path.
+
+default_directory() ->
+ %% Dismantle the directory tree: first the table & meta-data
+ %% directory, then the Mesia database directory, finally the node
+ %% directory where we will place the default whitelist in `Full`.
+ Table = filename:split(rabbit_mnesia:dir()),
+ Node = lists:sublist(Table, length(Table) - 2),
+ Full = Node ++ ["trust_store", "whitelist"],
+ filename:join(Full).
+
+ensure_directory(Path) ->
+ ok = ensure_parent_directories(Path),
+ case file:make_dir(Path) of
+ {error, ?DIRECTORY_OR_FILE_NAME_EXISTS} ->
+ true = filelib:is_dir(Path),
+ ok;
+ ok ->
+ ok
+ end.
+
+ensure_parent_directories(Path) ->
+ filelib:ensure_dir(Path).
+