Merge pull request #9189 from lafirest/1003-add-a-sensitive-logger
fix(logger): add new macro `?LOG_SENSITIVE` and use it to replace some `?LOG` for security reason
This commit is contained in:
commit
6feaf1a8cf
|
@ -56,19 +56,7 @@ start(Module, Config) ->
|
||||||
{ok, Conn} ->
|
{ok, Conn} ->
|
||||||
{ok, Conn};
|
{ok, Conn};
|
||||||
{error, Reason} ->
|
{error, Reason} ->
|
||||||
Config1 = obfuscate(Config),
|
?LOG_SENSITIVE(error, "Failed to connect with module=~p\n"
|
||||||
?LOG(error, "Failed to connect with module=~p\n"
|
"config=~p\nreason:~p", [Module, Config, Reason]),
|
||||||
"config=~p\nreason:~p", [Module, Config1, Reason]),
|
|
||||||
{error, Reason}
|
{error, Reason}
|
||||||
end.
|
end.
|
||||||
|
|
||||||
obfuscate(Map) ->
|
|
||||||
maps:fold(fun(K, V, Acc) ->
|
|
||||||
case is_sensitive(K) of
|
|
||||||
true -> [{K, '***'} | Acc];
|
|
||||||
false -> [{K, V} | Acc]
|
|
||||||
end
|
|
||||||
end, [], Map).
|
|
||||||
|
|
||||||
is_sensitive(password) -> true;
|
|
||||||
is_sensitive(_) -> false.
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{application, emqx_bridge_mqtt,
|
{application, emqx_bridge_mqtt,
|
||||||
[{description, "EMQ X Bridge to MQTT Broker"},
|
[{description, "EMQ X Bridge to MQTT Broker"},
|
||||||
{vsn, "4.3.6"}, % strict semver, bump manually!
|
{vsn, "4.3.7"}, % strict semver, bump manually!
|
||||||
{modules, []},
|
{modules, []},
|
||||||
{registered, []},
|
{registered, []},
|
||||||
{applications, [kernel,stdlib,replayq,emqtt]},
|
{applications, [kernel,stdlib,replayq,emqtt]},
|
||||||
|
|
|
@ -1,29 +1,43 @@
|
||||||
%% -*- mode: erlang -*-
|
%% -*- mode: erlang -*-
|
||||||
%% Unless you know what you are doing, DO NOT edit manually!!
|
%% Unless you know what you are doing, DO NOT edit manually!!
|
||||||
{VSN,
|
{VSN,
|
||||||
[{<<"4\\.3\\.[4-5]">>,
|
[{"4.3.6",
|
||||||
[{load_module,emqx_bridge_mqtt_actions,brutal_purge,soft_purge,[]}]},
|
[{load_module,emqx_bridge_connect,brutal_purge,soft_purge,[]},
|
||||||
|
{load_module,emqx_bridge_mqtt_actions,brutal_purge,soft_purge,[]}]},
|
||||||
|
{<<"4\\.3\\.[4-5]">>,
|
||||||
|
[{load_module,emqx_bridge_connect,brutal_purge,soft_purge,[]},
|
||||||
|
{load_module,emqx_bridge_mqtt_actions,brutal_purge,soft_purge,[]}]},
|
||||||
{"4.3.3",
|
{"4.3.3",
|
||||||
[{load_module,emqx_bridge_mqtt_actions,brutal_purge,soft_purge,[]},
|
[{load_module,emqx_bridge_connect,brutal_purge,soft_purge,[]},
|
||||||
|
{load_module,emqx_bridge_mqtt_actions,brutal_purge,soft_purge,[]},
|
||||||
{load_module,emqx_bridge_mqtt,brutal_purge,soft_purge,[]}]},
|
{load_module,emqx_bridge_mqtt,brutal_purge,soft_purge,[]}]},
|
||||||
{<<"4\\.3\\.[1-2]">>,
|
{<<"4\\.3\\.[1-2]">>,
|
||||||
[{load_module,emqx_bridge_mqtt,brutal_purge,soft_purge,[]},
|
[{load_module,emqx_bridge_connect,brutal_purge,soft_purge,[]},
|
||||||
|
{load_module,emqx_bridge_mqtt,brutal_purge,soft_purge,[]},
|
||||||
{load_module,emqx_bridge_mqtt_actions,brutal_purge,soft_purge,[]}]},
|
{load_module,emqx_bridge_mqtt_actions,brutal_purge,soft_purge,[]}]},
|
||||||
{"4.3.0",
|
{"4.3.0",
|
||||||
[{load_module,emqx_bridge_mqtt,brutal_purge,soft_purge,[]},
|
[{load_module,emqx_bridge_connect,brutal_purge,soft_purge,[]},
|
||||||
|
{load_module,emqx_bridge_mqtt,brutal_purge,soft_purge,[]},
|
||||||
{load_module,emqx_bridge_worker,brutal_purge,soft_purge,[]},
|
{load_module,emqx_bridge_worker,brutal_purge,soft_purge,[]},
|
||||||
{load_module,emqx_bridge_mqtt_actions,brutal_purge,soft_purge,[]}]},
|
{load_module,emqx_bridge_mqtt_actions,brutal_purge,soft_purge,[]}]},
|
||||||
{<<".*">>,[]}],
|
{<<".*">>,[]}],
|
||||||
[{<<"4\\.3\\.[4-5]">>,
|
[{"4.3.6",
|
||||||
[{load_module,emqx_bridge_mqtt_actions,brutal_purge,soft_purge,[]}]},
|
[{load_module,emqx_bridge_connect,brutal_purge,soft_purge,[]},
|
||||||
|
{load_module,emqx_bridge_mqtt_actions,brutal_purge,soft_purge,[]}]},
|
||||||
|
{<<"4\\.3\\.[4-5]">>,
|
||||||
|
[{load_module,emqx_bridge_connect,brutal_purge,soft_purge,[]},
|
||||||
|
{load_module,emqx_bridge_mqtt_actions,brutal_purge,soft_purge,[]}]},
|
||||||
{"4.3.3",
|
{"4.3.3",
|
||||||
[{load_module,emqx_bridge_mqtt_actions,brutal_purge,soft_purge,[]},
|
[{load_module,emqx_bridge_connect,brutal_purge,soft_purge,[]},
|
||||||
|
{load_module,emqx_bridge_mqtt_actions,brutal_purge,soft_purge,[]},
|
||||||
{load_module,emqx_bridge_mqtt,brutal_purge,soft_purge,[]}]},
|
{load_module,emqx_bridge_mqtt,brutal_purge,soft_purge,[]}]},
|
||||||
{<<"4\\.3\\.[1-2]">>,
|
{<<"4\\.3\\.[1-2]">>,
|
||||||
[{load_module,emqx_bridge_mqtt,brutal_purge,soft_purge,[]},
|
[{load_module,emqx_bridge_connect,brutal_purge,soft_purge,[]},
|
||||||
|
{load_module,emqx_bridge_mqtt,brutal_purge,soft_purge,[]},
|
||||||
{load_module,emqx_bridge_mqtt_actions,brutal_purge,soft_purge,[]}]},
|
{load_module,emqx_bridge_mqtt_actions,brutal_purge,soft_purge,[]}]},
|
||||||
{"4.3.0",
|
{"4.3.0",
|
||||||
[{load_module,emqx_bridge_mqtt,brutal_purge,soft_purge,[]},
|
[{load_module,emqx_bridge_connect,brutal_purge,soft_purge,[]},
|
||||||
|
{load_module,emqx_bridge_mqtt,brutal_purge,soft_purge,[]},
|
||||||
{load_module,emqx_bridge_worker,brutal_purge,soft_purge,[]},
|
{load_module,emqx_bridge_worker,brutal_purge,soft_purge,[]},
|
||||||
{load_module,emqx_bridge_mqtt_actions,brutal_purge,soft_purge,[]}]},
|
{load_module,emqx_bridge_mqtt_actions,brutal_purge,soft_purge,[]}]},
|
||||||
{<<".*">>,[]}]}.
|
{<<".*">>,[]}]}.
|
||||||
|
|
|
@ -421,7 +421,7 @@ start_resource(ResId, PoolName, Options) ->
|
||||||
on_resource_destroy(ResId, #{<<"pool">> => PoolName}),
|
on_resource_destroy(ResId, #{<<"pool">> => PoolName}),
|
||||||
start_resource(ResId, PoolName, Options);
|
start_resource(ResId, PoolName, Options);
|
||||||
{error, Reason} ->
|
{error, Reason} ->
|
||||||
?LOG(error, "Initiate Resource ~p failed, ResId: ~p, ~p", [?RESOURCE_TYPE_MQTT, ResId, Reason]),
|
?LOG_SENSITIVE(error, "Initiate Resource ~p failed, ResId: ~p, ~p", [?RESOURCE_TYPE_MQTT, ResId, Reason]),
|
||||||
on_resource_destroy(ResId, #{<<"pool">> => PoolName}),
|
on_resource_destroy(ResId, #{<<"pool">> => PoolName}),
|
||||||
error({{?RESOURCE_TYPE_MQTT, ResId}, create_failed})
|
error({{?RESOURCE_TYPE_MQTT, ResId}, create_failed})
|
||||||
end.
|
end.
|
||||||
|
|
|
@ -309,7 +309,7 @@ check_and_update_resource(Id, NewParams) ->
|
||||||
do_check_and_update_resource(#{id => Id, config => Conifg, type => Type,
|
do_check_and_update_resource(#{id => Id, config => Conifg, type => Type,
|
||||||
description => Descr})
|
description => Descr})
|
||||||
catch Error:Reason:ST ->
|
catch Error:Reason:ST ->
|
||||||
?LOG(error, "check_and_update_resource failed: ~0p", [{Error, Reason, ST}]),
|
?LOG_SENSITIVE(error, "check_and_update_resource failed: ~0p", [{Error, Reason, ST}]),
|
||||||
{error, Reason}
|
{error, Reason}
|
||||||
end;
|
end;
|
||||||
_Other ->
|
_Other ->
|
||||||
|
@ -377,7 +377,7 @@ test_resource(#{type := Type} = Params) ->
|
||||||
{error, Reason}
|
{error, Reason}
|
||||||
end
|
end
|
||||||
catch E:R:S ->
|
catch E:R:S ->
|
||||||
?LOG(warning, "test resource failed, ~0p:~0p ~0p", [E, R, S]),
|
?LOG_SENSITIVE(warning, "test resource failed, ~0p:~0p ~0p", [E, R, S]),
|
||||||
{error, R}
|
{error, R}
|
||||||
after
|
after
|
||||||
_ = ?CLUSTER_CALL(ensure_resource_deleted, [ResId]),
|
_ = ?CLUSTER_CALL(ensure_resource_deleted, [ResId]),
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{application, emqx_web_hook,
|
{application, emqx_web_hook,
|
||||||
[{description, "EMQ X WebHook Plugin"},
|
[{description, "EMQ X WebHook Plugin"},
|
||||||
{vsn, "4.3.14"}, % strict semver, bump manually!
|
{vsn, "4.3.15"}, % strict semver, bump manually!
|
||||||
{modules, []},
|
{modules, []},
|
||||||
{registered, [emqx_web_hook_sup]},
|
{registered, [emqx_web_hook_sup]},
|
||||||
{applications, [kernel,stdlib,ehttpc]},
|
{applications, [kernel,stdlib,ehttpc]},
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
%% -*- mode: erlang -*-
|
%% -*- mode: erlang -*-
|
||||||
%% Unless you know what you are doing, DO NOT edit manually!!
|
%% Unless you know what you are doing, DO NOT edit manually!!
|
||||||
{VSN,
|
{VSN,
|
||||||
[{<<"4\\.3\\.[0-7]">>,
|
[{"4.3.14",[{load_module,emqx_web_hook_actions,brutal_purge,soft_purge,[]}]},
|
||||||
|
{<<"4\\.3\\.[0-7]">>,
|
||||||
[{apply,{application,stop,[emqx_web_hook]}},
|
[{apply,{application,stop,[emqx_web_hook]}},
|
||||||
{load_module,emqx_web_hook_app,brutal_purge,soft_purge,[]},
|
{load_module,emqx_web_hook_app,brutal_purge,soft_purge,[]},
|
||||||
{load_module,emqx_web_hook,brutal_purge,soft_purge,[]},
|
{load_module,emqx_web_hook,brutal_purge,soft_purge,[]},
|
||||||
|
@ -24,7 +25,8 @@
|
||||||
{<<"4\\.3\\.1[2-3]">>,
|
{<<"4\\.3\\.1[2-3]">>,
|
||||||
[{load_module,emqx_web_hook_actions,brutal_purge,soft_purge,[]}]},
|
[{load_module,emqx_web_hook_actions,brutal_purge,soft_purge,[]}]},
|
||||||
{<<".*">>,[]}],
|
{<<".*">>,[]}],
|
||||||
[{<<"4\\.3\\.[0-7]">>,
|
[{"4.3.14",[{load_module,emqx_web_hook_actions,brutal_purge,soft_purge,[]}]},
|
||||||
|
{<<"4\\.3\\.[0-7]">>,
|
||||||
[{apply,{application,stop,[emqx_web_hook]}},
|
[{apply,{application,stop,[emqx_web_hook]}},
|
||||||
{load_module,emqx_web_hook_app,brutal_purge,soft_purge,[]},
|
{load_module,emqx_web_hook_app,brutal_purge,soft_purge,[]},
|
||||||
{load_module,emqx_web_hook,brutal_purge,soft_purge,[]},
|
{load_module,emqx_web_hook,brutal_purge,soft_purge,[]},
|
||||||
|
|
|
@ -384,7 +384,7 @@ test_http_connect(Conf) ->
|
||||||
false
|
false
|
||||||
catch
|
catch
|
||||||
Err:Reason:ST ->
|
Err:Reason:ST ->
|
||||||
?LOG(error, "check http_connectivity failed: ~p, ~0p", [Conf, {Err, Reason, ST}]),
|
?LOG_SENSITIVE(error, "check http_connectivity failed: ~p, ~0p", [Conf, {Err, Reason, ST}]),
|
||||||
false
|
false
|
||||||
end.
|
end.
|
||||||
l2b(L) when is_list(L) -> iolist_to_binary(L);
|
l2b(L) when is_list(L) -> iolist_to_binary(L);
|
||||||
|
|
|
@ -10,6 +10,9 @@
|
||||||
|
|
||||||
- JWT ACL claim supports `all` action to imply the rules applie to both `pub` and `sub` [#9044](https://github.com/emqx/emqx/pull/9044).
|
- JWT ACL claim supports `all` action to imply the rules applie to both `pub` and `sub` [#9044](https://github.com/emqx/emqx/pull/9044).
|
||||||
|
|
||||||
|
- Added a log censor to avoid logging sensitive data [#9189](https://github.com/emqx/emqx/pull/9189).
|
||||||
|
If the data to be logged is a map or key-value list which contains sensitive key words such as `password`, the value is obfuscated as `******`.
|
||||||
|
|
||||||
## Bug fixes
|
## Bug fixes
|
||||||
|
|
||||||
- Fix that after uploading a backup file with an UTF8 filename, HTTP API `GET /data/export` fails with status code 500 [#9224](https://github.com/emqx/emqx/pull/9224).
|
- Fix that after uploading a backup file with an UTF8 filename, HTTP API `GET /data/export` fails with status code 500 [#9224](https://github.com/emqx/emqx/pull/9224).
|
||||||
|
|
|
@ -10,6 +10,9 @@
|
||||||
|
|
||||||
- 基于 JWT 的 ACL 支持 `all` 动作,指定同时适用于 `pub` 和 `sub` 两个动作的规则列表 [#9044](https://github.com/emqx/emqx/pull/9044)。
|
- 基于 JWT 的 ACL 支持 `all` 动作,指定同时适用于 `pub` 和 `sub` 两个动作的规则列表 [#9044](https://github.com/emqx/emqx/pull/9044)。
|
||||||
|
|
||||||
|
- 增强包含敏感数据的日志的安全性 [#9189](https://github.com/emqx/emqx/pull/9189)。
|
||||||
|
如果日志中包含敏感关键词,例如 `password`,那么关联的数据回被模糊化处理,替换成 `******`。
|
||||||
|
|
||||||
## 修复
|
## 修复
|
||||||
|
|
||||||
- 修复若上传的备份文件名中包含 UTF8 字符,`GET /data/export` HTTP 接口返回 500 错误 [#9224](https://github.com/emqx/emqx/pull/9224)。
|
- 修复若上传的备份文件名中包含 UTF8 字符,`GET /data/export` HTTP 接口返回 500 错误 [#9224](https://github.com/emqx/emqx/pull/9224)。
|
||||||
|
|
|
@ -48,3 +48,13 @@
|
||||||
line => ?LINE}))
|
line => ?LINE}))
|
||||||
end).
|
end).
|
||||||
|
|
||||||
|
%% Copy-paste to avoid changing the old macro which may cause beam md5 changes in a lot of modules
|
||||||
|
%% i.e. hot-upgrade hell
|
||||||
|
-define(LOG_SENSITIVE(Level, Format, Args),
|
||||||
|
begin
|
||||||
|
(logger:log(Level,#{},#{report_cb => fun(_) -> {'$logger_header'()++(Format), emqx_misc:redact(Args)} end,
|
||||||
|
mfa => {?MODULE, ?FUNCTION_NAME, ?FUNCTION_ARITY},
|
||||||
|
line => ?LINE,
|
||||||
|
is_sensitive => true
|
||||||
|
}))
|
||||||
|
end).
|
||||||
|
|
|
@ -2,7 +2,8 @@
|
||||||
%% Unless you know what you are doing, DO NOT edit manually!!
|
%% Unless you know what you are doing, DO NOT edit manually!!
|
||||||
{VSN,
|
{VSN,
|
||||||
[{"4.3.22",
|
[{"4.3.22",
|
||||||
[{load_module,emqx_cm,brutal_purge,soft_purge,[]},
|
[{load_module,emqx_misc,brutal_purge,soft_purge,[]},
|
||||||
|
{load_module,emqx_cm,brutal_purge,soft_purge,[]},
|
||||||
{load_module,emqx_ws_connection,brutal_purge,soft_purge,[]},
|
{load_module,emqx_ws_connection,brutal_purge,soft_purge,[]},
|
||||||
{load_module,emqx_connection,brutal_purge,soft_purge,[]},
|
{load_module,emqx_connection,brutal_purge,soft_purge,[]},
|
||||||
{load_module,emqx_channel,brutal_purge,soft_purge,[]},
|
{load_module,emqx_channel,brutal_purge,soft_purge,[]},
|
||||||
|
@ -869,7 +870,8 @@
|
||||||
{load_module,emqx_limiter,brutal_purge,soft_purge,[]}]},
|
{load_module,emqx_limiter,brutal_purge,soft_purge,[]}]},
|
||||||
{<<".*">>,[]}],
|
{<<".*">>,[]}],
|
||||||
[{"4.3.22",
|
[{"4.3.22",
|
||||||
[{load_module,emqx_cm,brutal_purge,soft_purge,[]},
|
[{load_module,emqx_misc,brutal_purge,soft_purge,[]},
|
||||||
|
{load_module,emqx_cm,brutal_purge,soft_purge,[]},
|
||||||
{load_module,emqx_ws_connection,brutal_purge,soft_purge,[]},
|
{load_module,emqx_ws_connection,brutal_purge,soft_purge,[]},
|
||||||
{load_module,emqx_connection,brutal_purge,soft_purge,[]},
|
{load_module,emqx_connection,brutal_purge,soft_purge,[]},
|
||||||
{load_module,emqx_channel,brutal_purge,soft_purge,[]},
|
{load_module,emqx_channel,brutal_purge,soft_purge,[]},
|
||||||
|
|
|
@ -217,6 +217,7 @@ json_key(Term) ->
|
||||||
throw({badkey, Term})
|
throw({badkey, Term})
|
||||||
end.
|
end.
|
||||||
|
|
||||||
|
|
||||||
-ifdef(TEST).
|
-ifdef(TEST).
|
||||||
-include_lib("proper/include/proper.hrl").
|
-include_lib("proper/include/proper.hrl").
|
||||||
-include_lib("eunit/include/eunit.hrl").
|
-include_lib("eunit/include/eunit.hrl").
|
||||||
|
|
|
@ -64,6 +64,8 @@
|
||||||
nolink_apply/2
|
nolink_apply/2
|
||||||
]).
|
]).
|
||||||
|
|
||||||
|
-export([redact/1]).
|
||||||
|
|
||||||
-define(VALID_STR_RE, "^[A-Za-z0-9]+[A-Za-z0-9-_]*$").
|
-define(VALID_STR_RE, "^[A-Za-z0-9]+[A-Za-z0-9-_]*$").
|
||||||
-define(DEFAULT_PMAP_TIMEOUT, 5000).
|
-define(DEFAULT_PMAP_TIMEOUT, 5000).
|
||||||
|
|
||||||
|
@ -466,6 +468,67 @@ maybe_mute_rpc_log(Node) ->
|
||||||
ok
|
ok
|
||||||
end.
|
end.
|
||||||
|
|
||||||
|
is_sensitive_key(token) -> true;
|
||||||
|
is_sensitive_key("token") -> true;
|
||||||
|
is_sensitive_key(<<"token">>) -> true;
|
||||||
|
is_sensitive_key(password) -> true;
|
||||||
|
is_sensitive_key("password") -> true;
|
||||||
|
is_sensitive_key(<<"password">>) -> true;
|
||||||
|
is_sensitive_key(secret) -> true;
|
||||||
|
is_sensitive_key("secret") -> true;
|
||||||
|
is_sensitive_key(<<"secret">>) -> true;
|
||||||
|
is_sensitive_key(passcode) -> true;
|
||||||
|
is_sensitive_key("passcode") -> true;
|
||||||
|
is_sensitive_key(<<"passcode">>) -> true;
|
||||||
|
is_sensitive_key(passphrase) -> true;
|
||||||
|
is_sensitive_key("passphrase") -> true;
|
||||||
|
is_sensitive_key(<<"passphrase">>) -> true;
|
||||||
|
is_sensitive_key(key) -> true;
|
||||||
|
is_sensitive_key("key") -> true;
|
||||||
|
is_sensitive_key(<<"key">>) -> true;
|
||||||
|
is_sensitive_key(aws_secret_access_key) -> true;
|
||||||
|
is_sensitive_key("aws_secret_access_key") -> true;
|
||||||
|
is_sensitive_key(<<"aws_secret_access_key">>) -> true;
|
||||||
|
is_sensitive_key(secret_key) -> true;
|
||||||
|
is_sensitive_key("secret_key") -> true;
|
||||||
|
is_sensitive_key(<<"secret_key">>) -> true;
|
||||||
|
is_sensitive_key(bind_password) -> true;
|
||||||
|
is_sensitive_key("bind_password") -> true;
|
||||||
|
is_sensitive_key(<<"bind_password">>) -> true;
|
||||||
|
is_sensitive_key(_) -> false.
|
||||||
|
|
||||||
|
redact(L) when is_list(L) ->
|
||||||
|
lists:map(fun redact/1, L);
|
||||||
|
redact(M) when is_map(M) ->
|
||||||
|
maps:map(fun(K, V) ->
|
||||||
|
redact(K, V)
|
||||||
|
end, M);
|
||||||
|
redact({Key, Value}) ->
|
||||||
|
case is_sensitive_key(Key) of
|
||||||
|
true ->
|
||||||
|
{Key, redact_v(Value)};
|
||||||
|
false ->
|
||||||
|
{redact(Key), redact(Value)}
|
||||||
|
end;
|
||||||
|
redact(T) when is_tuple(T) ->
|
||||||
|
Elements = erlang:tuple_to_list(T),
|
||||||
|
Redact = redact(Elements),
|
||||||
|
erlang:list_to_tuple(Redact);
|
||||||
|
redact(Any) ->
|
||||||
|
Any.
|
||||||
|
|
||||||
|
redact(K, V) ->
|
||||||
|
case is_sensitive_key(K) of
|
||||||
|
true ->
|
||||||
|
redact_v(V);
|
||||||
|
false ->
|
||||||
|
redact(V)
|
||||||
|
end.
|
||||||
|
|
||||||
|
-define(REDACT_VAL, "******").
|
||||||
|
redact_v(V) when is_binary(V) -> <<?REDACT_VAL>>;
|
||||||
|
redact_v(_V) -> ?REDACT_VAL.
|
||||||
|
|
||||||
-ifdef(TEST).
|
-ifdef(TEST).
|
||||||
-include_lib("eunit/include/eunit.hrl").
|
-include_lib("eunit/include/eunit.hrl").
|
||||||
|
|
||||||
|
@ -498,4 +561,53 @@ is_sane_id_test() ->
|
||||||
?assertMatch({error, _}, is_sane_id(list_to_binary(Bad))),
|
?assertMatch({error, _}, is_sane_id(list_to_binary(Bad))),
|
||||||
ok.
|
ok.
|
||||||
|
|
||||||
|
redact_test_() ->
|
||||||
|
Case = fun(Type, KeyT) ->
|
||||||
|
Key =
|
||||||
|
case Type of
|
||||||
|
atom -> KeyT;
|
||||||
|
string -> erlang:atom_to_list(KeyT);
|
||||||
|
binary -> erlang:atom_to_binary(KeyT)
|
||||||
|
end,
|
||||||
|
|
||||||
|
?assert(is_sensitive_key(Key)),
|
||||||
|
|
||||||
|
%% direct
|
||||||
|
?assertEqual({Key, ?REDACT_VAL}, redact({Key, foo})),
|
||||||
|
?assertEqual(#{Key => ?REDACT_VAL}, redact(#{Key => foo})),
|
||||||
|
?assertEqual({Key, Key, Key}, redact({Key, Key, Key})),
|
||||||
|
?assertEqual({[{Key, ?REDACT_VAL}], bar}, redact({[{Key, foo}], bar})),
|
||||||
|
|
||||||
|
%% 1 level nested
|
||||||
|
?assertEqual([{Key, ?REDACT_VAL}], redact([{Key, foo}])),
|
||||||
|
?assertEqual([#{Key => ?REDACT_VAL}], redact([#{Key => foo}])),
|
||||||
|
|
||||||
|
%% 2 level nested
|
||||||
|
?assertEqual(#{opts => [{Key, ?REDACT_VAL}]}, redact(#{opts => [{Key, foo}]})),
|
||||||
|
?assertEqual(#{opts => #{Key => ?REDACT_VAL}}, redact(#{opts => #{Key => foo}})),
|
||||||
|
?assertEqual({opts, [{Key, ?REDACT_VAL}]}, redact({opts, [{Key, foo}]})),
|
||||||
|
|
||||||
|
%% 3 level nested
|
||||||
|
?assertEqual([#{opts => [{Key, ?REDACT_VAL}]}], redact([#{opts => [{Key, foo}]}])),
|
||||||
|
?assertEqual([{opts, [{Key, ?REDACT_VAL}]}], redact([{opts, [{Key, foo}]}])),
|
||||||
|
?assertEqual([{opts, [#{Key => ?REDACT_VAL}]}], redact([{opts, [#{Key => foo}]}]))
|
||||||
|
end,
|
||||||
|
|
||||||
|
Types = [atom, string, binary],
|
||||||
|
Keys = [
|
||||||
|
token,
|
||||||
|
password,
|
||||||
|
secret,
|
||||||
|
passcode,
|
||||||
|
passphrase,
|
||||||
|
key,
|
||||||
|
aws_secret_access_key,
|
||||||
|
secret_key,
|
||||||
|
bind_password
|
||||||
|
],
|
||||||
|
[{case_name(Type, Key), fun() -> Case(Type, Key) end} || Key <- Keys, Type <- Types].
|
||||||
|
|
||||||
|
case_name(Type, Key) ->
|
||||||
|
lists:concat([Type, "-", Key]).
|
||||||
|
|
||||||
-endif.
|
-endif.
|
||||||
|
|
Loading…
Reference in New Issue