Client: add new password-file command line option
- add new global command line argument to the signer -f --password-file <filename>: Absolute path of the password file - add password_filename to wallet context
This commit is contained in:
parent
28238fce9e
commit
1c0561ee53
@ -259,10 +259,19 @@ let require_auth_arg () =
|
|||||||
~doc:"Require a signature from the caller to sign."
|
~doc:"Require a signature from the caller to sign."
|
||||||
()
|
()
|
||||||
|
|
||||||
|
let password_filename_arg () =
|
||||||
|
arg
|
||||||
|
~long:"password-file"
|
||||||
|
~short:'f'
|
||||||
|
~placeholder:"filename"
|
||||||
|
~doc:"Absolute path of the password file"
|
||||||
|
(string_parameter ())
|
||||||
|
|
||||||
let global_options () =
|
let global_options () =
|
||||||
args2
|
args3
|
||||||
(base_dir_arg ())
|
(base_dir_arg ())
|
||||||
(require_auth_arg ())
|
(require_auth_arg ())
|
||||||
|
(password_filename_arg ())
|
||||||
|
|
||||||
(* Main (lwt) entry *)
|
(* Main (lwt) entry *)
|
||||||
let main () =
|
let main () =
|
||||||
@ -286,12 +295,13 @@ let main () =
|
|||||||
begin
|
begin
|
||||||
begin
|
begin
|
||||||
parse_global_options
|
parse_global_options
|
||||||
(global_options ()) () original_args >>=? fun ((base_dir, require_auth), remaining) ->
|
(global_options ()) () original_args >>=?
|
||||||
|
fun ((base_dir, require_auth, password_filename), remaining) ->
|
||||||
let base_dir = Option.unopt ~default:default_base_dir base_dir in
|
let base_dir = Option.unopt ~default:default_base_dir base_dir in
|
||||||
let cctxt = object
|
let cctxt = object
|
||||||
inherit Client_context_unix.unix_logger ~base_dir
|
inherit Client_context_unix.unix_logger ~base_dir
|
||||||
inherit Client_context_unix.unix_prompter
|
inherit Client_context_unix.unix_prompter
|
||||||
inherit Client_context_unix.unix_wallet ~base_dir
|
inherit Client_context_unix.unix_wallet ~base_dir ~password_filename
|
||||||
end in
|
end in
|
||||||
Client_keys.register_signer
|
Client_keys.register_signer
|
||||||
(module Tezos_signer_backends.Encrypted.Make(struct
|
(module Tezos_signer_backends.Encrypted.Make(struct
|
||||||
|
@ -65,6 +65,7 @@ class simple_printer log =
|
|||||||
end
|
end
|
||||||
|
|
||||||
class type wallet = object
|
class type wallet = object
|
||||||
|
method password_filename : string option
|
||||||
method with_lock : (unit -> 'a Lwt.t) -> 'a Lwt.t
|
method with_lock : (unit -> 'a Lwt.t) -> 'a Lwt.t
|
||||||
method load : string -> default:'a -> 'a Data_encoding.encoding -> 'a tzresult Lwt.t
|
method load : string -> default:'a -> 'a Data_encoding.encoding -> 'a tzresult Lwt.t
|
||||||
method write : string -> 'a -> 'a Data_encoding.encoding -> unit tzresult Lwt.t
|
method write : string -> 'a -> 'a Data_encoding.encoding -> unit tzresult Lwt.t
|
||||||
@ -96,6 +97,7 @@ class type full = object
|
|||||||
end
|
end
|
||||||
|
|
||||||
class proxy_context (obj : full) = object
|
class proxy_context (obj : full) = object
|
||||||
|
method password_filename = obj#password_filename
|
||||||
method base = obj#base
|
method base = obj#base
|
||||||
method block = obj#block
|
method block = obj#block
|
||||||
method confirmations = obj#confirmations
|
method confirmations = obj#confirmations
|
||||||
|
@ -45,6 +45,7 @@ class type io = object
|
|||||||
end
|
end
|
||||||
|
|
||||||
class type wallet = object
|
class type wallet = object
|
||||||
|
method password_filename : string option
|
||||||
method with_lock : (unit -> 'a Lwt.t) -> 'a Lwt.t
|
method with_lock : (unit -> 'a Lwt.t) -> 'a Lwt.t
|
||||||
method load : string -> default:'a -> 'a Data_encoding.encoding -> 'a tzresult Lwt.t
|
method load : string -> default:'a -> 'a Data_encoding.encoding -> 'a tzresult Lwt.t
|
||||||
method write : string -> 'a -> 'a Data_encoding.encoding -> unit tzresult Lwt.t
|
method write : string -> 'a -> 'a Data_encoding.encoding -> unit tzresult Lwt.t
|
||||||
|
@ -106,6 +106,7 @@ module Cfg_file = struct
|
|||||||
web_port: int ;
|
web_port: int ;
|
||||||
remote_signer: Uri.t option ;
|
remote_signer: Uri.t option ;
|
||||||
confirmations: int option ;
|
confirmations: int option ;
|
||||||
|
password_filename: string option ;
|
||||||
}
|
}
|
||||||
|
|
||||||
let default = {
|
let default = {
|
||||||
@ -116,6 +117,7 @@ module Cfg_file = struct
|
|||||||
web_port = 8080 ;
|
web_port = 8080 ;
|
||||||
remote_signer = None ;
|
remote_signer = None ;
|
||||||
confirmations = Some 0 ;
|
confirmations = Some 0 ;
|
||||||
|
password_filename = None ;
|
||||||
}
|
}
|
||||||
|
|
||||||
open Data_encoding
|
open Data_encoding
|
||||||
@ -123,25 +125,27 @@ module Cfg_file = struct
|
|||||||
let encoding =
|
let encoding =
|
||||||
conv
|
conv
|
||||||
(fun { base_dir ; node_addr ; node_port ; tls ; web_port ;
|
(fun { base_dir ; node_addr ; node_port ; tls ; web_port ;
|
||||||
remote_signer ; confirmations } ->
|
remote_signer ; confirmations ; password_filename } ->
|
||||||
(base_dir, Some node_addr, Some node_port,
|
(base_dir, Some node_addr, Some node_port,
|
||||||
Some tls, Some web_port, remote_signer, confirmations))
|
Some tls, Some web_port, remote_signer, confirmations, password_filename ))
|
||||||
(fun (base_dir, node_addr, node_port, tls, web_port,
|
(fun (base_dir, node_addr, node_port, tls, web_port,
|
||||||
remote_signer, confirmations) ->
|
remote_signer, confirmations, password_filename) ->
|
||||||
let node_addr = Option.unopt ~default:default.node_addr node_addr in
|
let node_addr = Option.unopt ~default:default.node_addr node_addr in
|
||||||
let node_port = Option.unopt ~default:default.node_port node_port in
|
let node_port = Option.unopt ~default:default.node_port node_port in
|
||||||
let tls = Option.unopt ~default:default.tls tls in
|
let tls = Option.unopt ~default:default.tls tls in
|
||||||
let web_port = Option.unopt ~default:default.web_port web_port in
|
let web_port = Option.unopt ~default:default.web_port web_port in
|
||||||
{ base_dir ; node_addr ; node_port ; tls ; web_port ;
|
{ base_dir ; node_addr ; node_port ; tls ; web_port ;
|
||||||
remote_signer ; confirmations })
|
remote_signer ; confirmations ; password_filename })
|
||||||
(obj7
|
(obj8
|
||||||
(req "base_dir" string)
|
(req "base_dir" string)
|
||||||
(opt "node_addr" string)
|
(opt "node_addr" string)
|
||||||
(opt "node_port" int16)
|
(opt "node_port" int16)
|
||||||
(opt "tls" bool)
|
(opt "tls" bool)
|
||||||
(opt "web_port" int16)
|
(opt "web_port" int16)
|
||||||
(opt "remote_signer" RPC_client.uri_encoding)
|
(opt "remote_signer" RPC_client.uri_encoding)
|
||||||
(opt "confirmations" int8))
|
(opt "confirmations" int8)
|
||||||
|
(opt "password_filename" string)
|
||||||
|
)
|
||||||
|
|
||||||
let from_json json =
|
let from_json json =
|
||||||
Data_encoding.Json.destruct encoding json
|
Data_encoding.Json.destruct encoding json
|
||||||
@ -159,6 +163,7 @@ end
|
|||||||
type cli_args = {
|
type cli_args = {
|
||||||
block: Shell_services.block ;
|
block: Shell_services.block ;
|
||||||
confirmations: int option ;
|
confirmations: int option ;
|
||||||
|
password_filename: string option ;
|
||||||
protocol: Protocol_hash.t option ;
|
protocol: Protocol_hash.t option ;
|
||||||
print_timings: bool ;
|
print_timings: bool ;
|
||||||
log_requests: bool ;
|
log_requests: bool ;
|
||||||
@ -167,6 +172,7 @@ type cli_args = {
|
|||||||
let default_cli_args = {
|
let default_cli_args = {
|
||||||
block = default_block ;
|
block = default_block ;
|
||||||
confirmations = Some 0 ;
|
confirmations = Some 0 ;
|
||||||
|
password_filename = None ;
|
||||||
protocol = None ;
|
protocol = None ;
|
||||||
print_timings = false ;
|
print_timings = false ;
|
||||||
log_requests = false ;
|
log_requests = false ;
|
||||||
@ -298,6 +304,13 @@ let remote_signer_arg () =
|
|||||||
~doc:"URI of the remote signer"
|
~doc:"URI of the remote signer"
|
||||||
(parameter
|
(parameter
|
||||||
(fun _ x -> Tezos_signer_backends.Remote.parse_base_uri x))
|
(fun _ x -> Tezos_signer_backends.Remote.parse_base_uri x))
|
||||||
|
let password_filename_arg () =
|
||||||
|
arg
|
||||||
|
~long:"password-filename"
|
||||||
|
~short:'f'
|
||||||
|
~placeholder:"filename"
|
||||||
|
~doc:"path to the passowrd filename"
|
||||||
|
(string_parameter ())
|
||||||
|
|
||||||
let read_config_file config_file =
|
let read_config_file config_file =
|
||||||
Lwt_utils_unix.Json.read_file config_file >>=? fun cfg_json ->
|
Lwt_utils_unix.Json.read_file config_file >>=? fun cfg_json ->
|
||||||
@ -372,7 +385,7 @@ let commands config_file cfg =
|
|||||||
]
|
]
|
||||||
|
|
||||||
let global_options () =
|
let global_options () =
|
||||||
args11
|
args12
|
||||||
(base_dir_arg ())
|
(base_dir_arg ())
|
||||||
(config_file_arg ())
|
(config_file_arg ())
|
||||||
(timings_switch ())
|
(timings_switch ())
|
||||||
@ -384,6 +397,7 @@ let global_options () =
|
|||||||
(port_arg ())
|
(port_arg ())
|
||||||
(tls_switch ())
|
(tls_switch ())
|
||||||
(remote_signer_arg ())
|
(remote_signer_arg ())
|
||||||
|
(password_filename_arg ())
|
||||||
|
|
||||||
let parse_config_args (ctx : #Client_context.full) argv =
|
let parse_config_args (ctx : #Client_context.full) argv =
|
||||||
parse_global_options
|
parse_global_options
|
||||||
@ -400,7 +414,8 @@ let parse_config_args (ctx : #Client_context.full) argv =
|
|||||||
node_addr,
|
node_addr,
|
||||||
node_port,
|
node_port,
|
||||||
tls,
|
tls,
|
||||||
remote_signer), remaining) ->
|
remote_signer,
|
||||||
|
password_filename), remaining) ->
|
||||||
begin match base_dir with
|
begin match base_dir with
|
||||||
| None ->
|
| None ->
|
||||||
let base_dir = default_base_dir in
|
let base_dir = default_base_dir in
|
||||||
@ -443,7 +458,7 @@ let parse_config_args (ctx : #Client_context.full) argv =
|
|||||||
(Option.first_some remote_signer_env cfg.remote_signer) in
|
(Option.first_some remote_signer_env cfg.remote_signer) in
|
||||||
let confirmations = Option.unopt ~default:cfg.confirmations confirmations in
|
let confirmations = Option.unopt ~default:cfg.confirmations confirmations in
|
||||||
let cfg = { cfg with tls ; node_port ; node_addr ;
|
let cfg = { cfg with tls ; node_port ; node_addr ;
|
||||||
remote_signer ; confirmations } in
|
remote_signer ; confirmations ; password_filename } in
|
||||||
if Sys.file_exists base_dir && not (Sys.is_directory base_dir) then begin
|
if Sys.file_exists base_dir && not (Sys.is_directory base_dir) then begin
|
||||||
Format.eprintf "%s is not a directory.@." base_dir ;
|
Format.eprintf "%s is not a directory.@." base_dir ;
|
||||||
exit 1 ;
|
exit 1 ;
|
||||||
@ -455,6 +470,6 @@ let parse_config_args (ctx : #Client_context.full) argv =
|
|||||||
Lwt_utils_unix.create_dir config_dir >>= fun () ->
|
Lwt_utils_unix.create_dir config_dir >>= fun () ->
|
||||||
return
|
return
|
||||||
(cfg,
|
(cfg,
|
||||||
{ block ; confirmations ;
|
{ block ; confirmations ; password_filename ;
|
||||||
print_timings = timings ; log_requests ; protocol },
|
print_timings = timings ; log_requests ; protocol },
|
||||||
commands config_file cfg, remaining)
|
commands config_file cfg, remaining)
|
||||||
|
@ -28,7 +28,9 @@ include Tezos_stdlib.Logging.Make_semantic(struct let name = "client.context.uni
|
|||||||
|
|
||||||
let filename_tag = Tag.def ~doc:"Filename" "filename" Format.pp_print_string
|
let filename_tag = Tag.def ~doc:"Filename" "filename" Format.pp_print_string
|
||||||
|
|
||||||
class unix_wallet ~base_dir : wallet = object (self)
|
class unix_wallet ~base_dir ~password_filename : wallet = object (self)
|
||||||
|
|
||||||
|
method password_filename = password_filename
|
||||||
|
|
||||||
method private filename alias_name =
|
method private filename alias_name =
|
||||||
Filename.concat
|
Filename.concat
|
||||||
@ -130,11 +132,11 @@ class unix_logger ~base_dir =
|
|||||||
inherit Client_context.simple_printer log
|
inherit Client_context.simple_printer log
|
||||||
end
|
end
|
||||||
|
|
||||||
class unix_full ~base_dir ~block ~confirmations ~rpc_config : Client_context.full =
|
class unix_full ~base_dir ~block ~confirmations ~password_filename ~rpc_config : Client_context.full =
|
||||||
object
|
object
|
||||||
inherit unix_logger ~base_dir
|
inherit unix_logger ~base_dir
|
||||||
inherit unix_prompter
|
inherit unix_prompter
|
||||||
inherit unix_wallet ~base_dir
|
inherit unix_wallet ~base_dir ~password_filename
|
||||||
inherit RPC_client.http_ctxt rpc_config Media_type.all_media_types
|
inherit RPC_client.http_ctxt rpc_config Media_type.all_media_types
|
||||||
method block = block
|
method block = block
|
||||||
method confirmations = confirmations
|
method confirmations = confirmations
|
||||||
|
@ -25,6 +25,7 @@
|
|||||||
|
|
||||||
class unix_wallet :
|
class unix_wallet :
|
||||||
base_dir:string ->
|
base_dir:string ->
|
||||||
|
password_filename: string option ->
|
||||||
Client_context.wallet
|
Client_context.wallet
|
||||||
class unix_prompter :
|
class unix_prompter :
|
||||||
Client_context.prompter
|
Client_context.prompter
|
||||||
@ -35,5 +36,6 @@ class unix_full :
|
|||||||
base_dir:string ->
|
base_dir:string ->
|
||||||
block:Shell_services.block ->
|
block:Shell_services.block ->
|
||||||
confirmations:int option ->
|
confirmations:int option ->
|
||||||
|
password_filename: string option ->
|
||||||
rpc_config:RPC_client.config ->
|
rpc_config:RPC_client.config ->
|
||||||
Client_context.full
|
Client_context.full
|
||||||
|
@ -67,6 +67,7 @@ let main select_commands =
|
|||||||
(new unix_full
|
(new unix_full
|
||||||
~block:Client_config.default_block
|
~block:Client_config.default_block
|
||||||
~confirmations:None
|
~confirmations:None
|
||||||
|
~password_filename:None
|
||||||
~base_dir:Client_config.default_base_dir
|
~base_dir:Client_config.default_base_dir
|
||||||
~rpc_config:RPC_client.default_config)
|
~rpc_config:RPC_client.default_config)
|
||||||
original_args
|
original_args
|
||||||
@ -90,6 +91,7 @@ let main select_commands =
|
|||||||
new unix_full
|
new unix_full
|
||||||
~block:parsed_args.block
|
~block:parsed_args.block
|
||||||
~confirmations:parsed_args.confirmations
|
~confirmations:parsed_args.confirmations
|
||||||
|
~password_filename: parsed_args.password_filename
|
||||||
~base_dir:parsed_config_file.base_dir
|
~base_dir:parsed_config_file.base_dir
|
||||||
~rpc_config:rpc_config in
|
~rpc_config:rpc_config in
|
||||||
Client_keys.register_signer
|
Client_keys.register_signer
|
||||||
|
@ -132,6 +132,9 @@ module Encodings = struct
|
|||||||
end
|
end
|
||||||
|
|
||||||
let decrypted = Hashtbl.create 13
|
let decrypted = Hashtbl.create 13
|
||||||
|
|
||||||
|
(* we cache the password in this list to avoid
|
||||||
|
asking the user all the time *)
|
||||||
let passwords = ref []
|
let passwords = ref []
|
||||||
|
|
||||||
let rec interactive_decrypt_loop
|
let rec interactive_decrypt_loop
|
||||||
@ -152,6 +155,31 @@ let rec interactive_decrypt_loop
|
|||||||
| None ->
|
| None ->
|
||||||
interactive_decrypt_loop cctxt ?name ~encrypted_sk algo
|
interactive_decrypt_loop cctxt ?name ~encrypted_sk algo
|
||||||
|
|
||||||
|
(* FixMe : this could be done more elegantly *)
|
||||||
|
let read_all_lines filename =
|
||||||
|
let lines = ref [] in
|
||||||
|
let chan = open_in filename in
|
||||||
|
try
|
||||||
|
while true; do
|
||||||
|
lines := input_line chan :: !lines
|
||||||
|
done; !lines
|
||||||
|
with End_of_file ->
|
||||||
|
close_in chan;
|
||||||
|
List.rev !lines
|
||||||
|
|
||||||
|
(* add all passwords in [filename] to the list of known passwords *)
|
||||||
|
let password_file_load = function
|
||||||
|
|Some filename ->
|
||||||
|
if Sys.file_exists filename then begin
|
||||||
|
let l = read_all_lines filename in
|
||||||
|
let l = List.map MBytes.of_string l in
|
||||||
|
passwords := !passwords @ l ;
|
||||||
|
return_unit
|
||||||
|
end
|
||||||
|
else
|
||||||
|
return_unit
|
||||||
|
| None -> return_unit
|
||||||
|
|
||||||
let rec noninteractive_decrypt_loop algo ~encrypted_sk = function
|
let rec noninteractive_decrypt_loop algo ~encrypted_sk = function
|
||||||
| [] -> return_none
|
| [] -> return_none
|
||||||
| password :: passwords ->
|
| password :: passwords ->
|
||||||
@ -181,6 +209,7 @@ let decrypt (cctxt : #Client_context.prompter) ?name sk_uri =
|
|||||||
|
|
||||||
let decrypt_all (cctxt : #Client_context.io_wallet) =
|
let decrypt_all (cctxt : #Client_context.io_wallet) =
|
||||||
Secret_key.load cctxt >>=? fun sks ->
|
Secret_key.load cctxt >>=? fun sks ->
|
||||||
|
password_file_load cctxt#password_filename >>=? fun () ->
|
||||||
iter_s begin fun (name, sk_uri) ->
|
iter_s begin fun (name, sk_uri) ->
|
||||||
if Uri.scheme (sk_uri : sk_uri :> Uri.t) <> Some scheme then
|
if Uri.scheme (sk_uri : sk_uri :> Uri.t) <> Some scheme then
|
||||||
return_unit
|
return_unit
|
||||||
@ -191,6 +220,7 @@ let decrypt_all (cctxt : #Client_context.io_wallet) =
|
|||||||
|
|
||||||
let decrypt_list (cctxt : #Client_context.io_wallet) keys =
|
let decrypt_list (cctxt : #Client_context.io_wallet) keys =
|
||||||
Secret_key.load cctxt >>=? fun sks ->
|
Secret_key.load cctxt >>=? fun sks ->
|
||||||
|
password_file_load cctxt#password_filename >>=? fun () ->
|
||||||
iter_s begin fun (name, sk_uri) ->
|
iter_s begin fun (name, sk_uri) ->
|
||||||
if Uri.scheme (sk_uri : sk_uri :> Uri.t) = Some scheme &&
|
if Uri.scheme (sk_uri : sk_uri :> Uri.t) = Some scheme &&
|
||||||
(keys = [] || List.mem name keys) then
|
(keys = [] || List.mem name keys) then
|
||||||
|
@ -56,6 +56,7 @@ let no_write_context ?(block = `Head 0) config : #Client_context.full = object
|
|||||||
method with_lock : type a. (unit -> a Lwt.t) -> a Lwt.t = fun f -> f ()
|
method with_lock : type a. (unit -> a Lwt.t) -> a Lwt.t = fun f -> f ()
|
||||||
method block = block
|
method block = block
|
||||||
method confirmations = None
|
method confirmations = None
|
||||||
|
method password_filename = None
|
||||||
method prompt : type a. (a, string tzresult) Client_context.lwt_format -> a =
|
method prompt : type a. (a, string tzresult) Client_context.lwt_format -> a =
|
||||||
Format.kasprintf (fun _ -> return "")
|
Format.kasprintf (fun _ -> return "")
|
||||||
method prompt_password : type a. (a, MBytes.t tzresult) Client_context.lwt_format -> a =
|
method prompt_password : type a. (a, MBytes.t tzresult) Client_context.lwt_format -> a =
|
||||||
|
Loading…
Reference in New Issue
Block a user