More CLI commands for tagged values
This commit is contained in:
parent
c2fdd73c4b
commit
e1490c6d9c
|
|
@ -117,7 +117,7 @@ defmodule RabbitMQ.CLI.Ctl.Commands.DecodeCommand do
|
|||
def formatter(), do: RabbitMQ.CLI.Formatters.Erlang
|
||||
|
||||
def banner(_, _) do
|
||||
"Decrypting value..."
|
||||
"Decrypting an advanced.config (Erlang term) value..."
|
||||
end
|
||||
|
||||
def usage,
|
||||
|
|
@ -125,7 +125,7 @@ defmodule RabbitMQ.CLI.Ctl.Commands.DecodeCommand do
|
|||
|
||||
def usage_additional() do
|
||||
[
|
||||
["<value>", "config value to decode"],
|
||||
["<value>", "advanced.config (Erlang term) value to decode"],
|
||||
["<passphrase>", "passphrase to use with the config value encryption key"],
|
||||
["--cipher <cipher>", "cipher suite to use"],
|
||||
["--hash <hash>", "hashing function to use"],
|
||||
|
|
@ -141,7 +141,7 @@ defmodule RabbitMQ.CLI.Ctl.Commands.DecodeCommand do
|
|||
|
||||
def help_section(), do: :configuration
|
||||
|
||||
def description(), do: "Decrypts an encrypted configuration value"
|
||||
def description(), do: "Decrypts an encrypted advanced.config value"
|
||||
|
||||
#
|
||||
# Implementation
|
||||
|
|
|
|||
172
deps/rabbitmq_cli/lib/rabbitmq/cli/ctl/commands/decrypt_conf_value_command.ex
vendored
Normal file
172
deps/rabbitmq_cli/lib/rabbitmq/cli/ctl/commands/decrypt_conf_value_command.ex
vendored
Normal file
|
|
@ -0,0 +1,172 @@
|
|||
## 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-2023 Broadcom. All Rights Reserved. The term “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. All rights reserved.
|
||||
|
||||
alias RabbitMQ.CLI.Core.Helpers
|
||||
|
||||
defmodule RabbitMQ.CLI.Ctl.Commands.DecryptConfValueCommand do
|
||||
alias RabbitMQ.CLI.Core.{DocGuide, Input}
|
||||
|
||||
@behaviour RabbitMQ.CLI.CommandBehaviour
|
||||
use RabbitMQ.CLI.DefaultOutput
|
||||
|
||||
def switches() do
|
||||
[
|
||||
cipher: :string,
|
||||
hash: :string,
|
||||
iterations: :integer
|
||||
]
|
||||
end
|
||||
|
||||
@atomized_keys [:cipher, :hash]
|
||||
@prefix "encrypted:"
|
||||
|
||||
def distribution(_), do: :none
|
||||
|
||||
def merge_defaults(args, opts) do
|
||||
with_defaults =
|
||||
Map.merge(
|
||||
%{
|
||||
cipher: :rabbit_pbe.default_cipher(),
|
||||
hash: :rabbit_pbe.default_hash(),
|
||||
iterations: :rabbit_pbe.default_iterations()
|
||||
},
|
||||
opts
|
||||
)
|
||||
|
||||
{args, Helpers.atomize_values(with_defaults, @atomized_keys)}
|
||||
end
|
||||
|
||||
def validate(args, _) when length(args) < 1 do
|
||||
{:validation_failure, {:not_enough_args, "Please provide a value to decode and a passphrase"}}
|
||||
end
|
||||
|
||||
def validate(args, _) when length(args) > 2 do
|
||||
{:validation_failure, :too_many_args}
|
||||
end
|
||||
|
||||
def validate(_args, opts) do
|
||||
case {supports_cipher(opts.cipher), supports_hash(opts.hash), opts.iterations > 0} do
|
||||
{false, _, _} ->
|
||||
{:validation_failure, {:bad_argument, "The requested cipher is not supported"}}
|
||||
|
||||
{_, false, _} ->
|
||||
{:validation_failure, {:bad_argument, "The requested hash is not supported"}}
|
||||
|
||||
{_, _, false} ->
|
||||
{:validation_failure,
|
||||
{:bad_argument,
|
||||
"The requested number of iterations is incorrect (must be a positive integer)"}}
|
||||
|
||||
{true, true, true} ->
|
||||
:ok
|
||||
end
|
||||
end
|
||||
|
||||
def run([value], %{cipher: cipher, hash: hash, iterations: iterations} = opts) do
|
||||
case Input.consume_single_line_string_with_prompt("Passphrase: ", opts) do
|
||||
:eof ->
|
||||
{:error, :not_enough_args}
|
||||
|
||||
passphrase ->
|
||||
try do
|
||||
term_value = Helpers.evaluate_input_as_term(value)
|
||||
|
||||
term_to_decrypt =
|
||||
case term_value do
|
||||
prefixed_val when is_bitstring(prefixed_val) or is_list(prefixed_val) ->
|
||||
tag_input_value_with_encrypted(prefixed_val)
|
||||
|
||||
{:encrypted, _} = encrypted ->
|
||||
encrypted
|
||||
|
||||
_ ->
|
||||
{:encrypted, term_value}
|
||||
end
|
||||
|
||||
result = :rabbit_pbe.decrypt_term(cipher, hash, iterations, passphrase, term_to_decrypt)
|
||||
{:ok, result}
|
||||
catch
|
||||
_, _ ->
|
||||
IO.inspect(__STACKTRACE__)
|
||||
{:error,
|
||||
"Failed to decrypt the value. Things to check: is the passphrase correct? Are the cipher and hash algorithms the same as those used for encryption?"}
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def run([value, passphrase], %{cipher: cipher, hash: hash, iterations: iterations}) do
|
||||
try do
|
||||
term_value = Helpers.evaluate_input_as_term(value)
|
||||
|
||||
term_to_decrypt =
|
||||
case term_value do
|
||||
prefixed_val when is_bitstring(prefixed_val) or is_list(prefixed_val) ->
|
||||
tag_input_value_with_encrypted(prefixed_val)
|
||||
|
||||
{:encrypted, _} = encrypted ->
|
||||
encrypted
|
||||
|
||||
_ ->
|
||||
{:encrypted, term_value}
|
||||
end
|
||||
|
||||
result = :rabbit_pbe.decrypt_term(cipher, hash, iterations, passphrase, term_to_decrypt)
|
||||
{:ok, result}
|
||||
catch
|
||||
_, _ ->
|
||||
IO.inspect(__STACKTRACE__)
|
||||
{:error,
|
||||
"Failed to decrypt the value. Things to check: is the passphrase correct? Are the cipher and hash algorithms the same as those used for encryption?"}
|
||||
end
|
||||
end
|
||||
|
||||
def formatter(), do: RabbitMQ.CLI.Formatters.Erlang
|
||||
|
||||
def banner(_, _) do
|
||||
"Decrypting a rabbitmq.conf string value..."
|
||||
end
|
||||
|
||||
def usage,
|
||||
do: "decrypt_conf_value value passphrase [--cipher <cipher>] [--hash <hash>] [--iterations <iterations>]"
|
||||
|
||||
def usage_additional() do
|
||||
[
|
||||
["<value>", "a double-quoted rabbitmq.conf string value to decode"],
|
||||
["<passphrase>", "passphrase to use with the config value encryption key"],
|
||||
["--cipher <cipher>", "cipher suite to use"],
|
||||
["--hash <hash>", "hashing function to use"],
|
||||
["--iterations <iterations>", "number of iteration to apply"]
|
||||
]
|
||||
end
|
||||
|
||||
def usage_doc_guides() do
|
||||
[
|
||||
DocGuide.configuration()
|
||||
]
|
||||
end
|
||||
|
||||
def help_section(), do: :configuration
|
||||
|
||||
def description(), do: "Decrypts an encrypted configuration value"
|
||||
|
||||
#
|
||||
# Implementation
|
||||
#
|
||||
|
||||
defp supports_cipher(cipher), do: Enum.member?(:rabbit_pbe.supported_ciphers(), cipher)
|
||||
|
||||
defp supports_hash(hash), do: Enum.member?(:rabbit_pbe.supported_hashes(), hash)
|
||||
|
||||
defp tag_input_value_with_encrypted(value) when is_bitstring(value) or is_list(value) do
|
||||
bin_val = :rabbit_data_coercion.to_binary(value)
|
||||
untagged_val = String.replace_prefix(bin_val, @prefix, "")
|
||||
|
||||
{:encrypted, untagged_val}
|
||||
end
|
||||
defp tag_input_value_with_encrypted(value) do
|
||||
{:encrypted, value}
|
||||
end
|
||||
end
|
||||
|
|
@ -130,7 +130,7 @@ defmodule RabbitMQ.CLI.Ctl.Commands.EncodeCommand do
|
|||
|
||||
def usage_additional() do
|
||||
[
|
||||
["<value>", "config value to encode"],
|
||||
["<value>", "value to encode, to be used in advanced.config"],
|
||||
["<passphrase>", "passphrase to use with the config value encryption key"],
|
||||
["--cipher <cipher>", "cipher suite to use"],
|
||||
["--hash <hash>", "hashing function to use"],
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
## 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-2023 Broadcom. All Rights Reserved. The term “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. All rights reserved.
|
||||
## Copyright (c) 2007-2024 Broadcom. All Rights Reserved. The term “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. All rights reserved.
|
||||
|
||||
defmodule RabbitMQ.CLI.Ctl.Commands.EncryptConfValueCommand do
|
||||
alias RabbitMQ.CLI.Core.{DocGuide, Helpers, Input}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,78 @@
|
|||
## 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-2024 Broadcom. All Rights Reserved. The term “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. All rights reserved.
|
||||
|
||||
defmodule EncryptConfValueCommandTest do
|
||||
use ExUnit.Case, async: false
|
||||
|
||||
@command RabbitMQ.CLI.Ctl.Commands.EncryptConfValueCommand
|
||||
|
||||
setup _context do
|
||||
{:ok,
|
||||
opts: %{
|
||||
cipher: :rabbit_pbe.default_cipher(),
|
||||
hash: :rabbit_pbe.default_hash(),
|
||||
iterations: :rabbit_pbe.default_iterations()
|
||||
}}
|
||||
end
|
||||
|
||||
test "validate: providing exactly 2 positional arguments passes", context do
|
||||
assert :ok == @command.validate(["value", "secret"], context[:opts])
|
||||
end
|
||||
|
||||
test "validate: providing zero or one positional argument passes", context do
|
||||
assert :ok == @command.validate([], context[:opts])
|
||||
assert :ok == @command.validate(["value"], context[:opts])
|
||||
end
|
||||
|
||||
test "validate: providing three or more positional argument fails", context do
|
||||
assert match?(
|
||||
{:validation_failure, :too_many_args},
|
||||
@command.validate(["value", "secret", "incorrect"], context[:opts])
|
||||
)
|
||||
end
|
||||
|
||||
test "validate: hash and cipher must be supported", context do
|
||||
assert match?(
|
||||
{:validation_failure, {:bad_argument, _}},
|
||||
@command.validate(
|
||||
["value", "secret"],
|
||||
Map.merge(context[:opts], %{cipher: :funny_cipher})
|
||||
)
|
||||
)
|
||||
|
||||
assert match?(
|
||||
{:validation_failure, {:bad_argument, _}},
|
||||
@command.validate(
|
||||
["value", "secret"],
|
||||
Map.merge(context[:opts], %{hash: :funny_hash})
|
||||
)
|
||||
)
|
||||
|
||||
assert match?(
|
||||
{:validation_failure, {:bad_argument, _}},
|
||||
@command.validate(
|
||||
["value", "secret"],
|
||||
Map.merge(context[:opts], %{cipher: :funny_cipher, hash: :funny_hash})
|
||||
)
|
||||
)
|
||||
|
||||
assert :ok == @command.validate(["value", "secret"], context[:opts])
|
||||
end
|
||||
|
||||
test "validate: number of iterations must greater than 0", context do
|
||||
assert match?(
|
||||
{:validation_failure, {:bad_argument, _}},
|
||||
@command.validate(["value", "secret"], Map.merge(context[:opts], %{iterations: 0}))
|
||||
)
|
||||
|
||||
assert match?(
|
||||
{:validation_failure, {:bad_argument, _}},
|
||||
@command.validate(["value", "secret"], Map.merge(context[:opts], %{iterations: -1}))
|
||||
)
|
||||
|
||||
assert :ok == @command.validate(["value", "secret"], context[:opts])
|
||||
end
|
||||
end
|
||||
Loading…
Reference in New Issue