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 formatter(), do: RabbitMQ.CLI.Formatters.Erlang
|
||||||
|
|
||||||
def banner(_, _) do
|
def banner(_, _) do
|
||||||
"Decrypting value..."
|
"Decrypting an advanced.config (Erlang term) value..."
|
||||||
end
|
end
|
||||||
|
|
||||||
def usage,
|
def usage,
|
||||||
|
|
@ -125,7 +125,7 @@ defmodule RabbitMQ.CLI.Ctl.Commands.DecodeCommand do
|
||||||
|
|
||||||
def usage_additional() 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"],
|
["<passphrase>", "passphrase to use with the config value encryption key"],
|
||||||
["--cipher <cipher>", "cipher suite to use"],
|
["--cipher <cipher>", "cipher suite to use"],
|
||||||
["--hash <hash>", "hashing function 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 help_section(), do: :configuration
|
||||||
|
|
||||||
def description(), do: "Decrypts an encrypted configuration value"
|
def description(), do: "Decrypts an encrypted advanced.config value"
|
||||||
|
|
||||||
#
|
#
|
||||||
# Implementation
|
# 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
|
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"],
|
["<passphrase>", "passphrase to use with the config value encryption key"],
|
||||||
["--cipher <cipher>", "cipher suite to use"],
|
["--cipher <cipher>", "cipher suite to use"],
|
||||||
["--hash <hash>", "hashing function 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
|
## 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/.
|
## 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
|
defmodule RabbitMQ.CLI.Ctl.Commands.EncryptConfValueCommand do
|
||||||
alias RabbitMQ.CLI.Core.{DocGuide, Helpers, Input}
|
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