From 7ad44a9af3c8a9ee875596d67dd80d74bdbf9e9e Mon Sep 17 00:00:00 2001 From: Benjamin Canou Date: Wed, 13 Jun 2018 23:05:36 +0200 Subject: [PATCH] Signer: support plain HTTP (no S) and a few cosmetic fixes --- src/bin_signer/handler.ml | 18 +++- src/bin_signer/http_daemon.ml | 66 ++++++++++++++ .../{https_daemon.mli => http_daemon.mli} | 9 +- src/bin_signer/https_daemon.ml | 44 --------- src/bin_signer/main_signer.ml | 49 +++++++++- src/lib_client_base/client_keys.ml | 6 +- src/lib_client_base_unix/client_main_run.ml | 11 ++- src/lib_signer_backends/encrypted.ml | 4 +- src/lib_signer_backends/http.ml | 10 ++ src/lib_signer_backends/http.mli | 16 ++++ src/lib_signer_backends/http_gen.ml | 91 +++++++++++++++++++ src/lib_signer_backends/http_gen.mli | 20 ++++ src/lib_signer_backends/https.ml | 75 +-------------- src/lib_signer_backends/https.mli | 1 + src/lib_signer_backends/remote.ml | 45 ++++++--- src/lib_signer_backends/remote.mli | 1 + src/lib_signer_services/signer_services.ml | 4 +- 17 files changed, 322 insertions(+), 148 deletions(-) create mode 100644 src/bin_signer/http_daemon.ml rename src/bin_signer/{https_daemon.mli => http_daemon.mli} (82%) delete mode 100644 src/bin_signer/https_daemon.ml create mode 100644 src/lib_signer_backends/http.ml create mode 100644 src/lib_signer_backends/http.mli create mode 100644 src/lib_signer_backends/http_gen.ml create mode 100644 src/lib_signer_backends/http_gen.mli diff --git a/src/bin_signer/handler.ml b/src/bin_signer/handler.ml index 1f0849591..e953a1242 100644 --- a/src/bin_signer/handler.ml +++ b/src/bin_signer/handler.ml @@ -59,7 +59,17 @@ let sign let public_key (cctxt : #Client_context.wallet) pkh = log "Request for public key %a" Signature.Public_key_hash.pp pkh >>= fun () -> - Client_keys.get_public_key cctxt pkh >>=? fun (name, pk) -> - log "Found public key for hash %a (name: %s)" - Signature.Public_key_hash.pp pkh name >>= fun () -> - return pk + Client_keys.list_keys cctxt >>=? fun all_keys -> + match List.find (fun (_, h, _, _) -> Signature.Public_key_hash.equal h pkh) all_keys with + | exception Not_found -> + log "No public key found for hash %a" + Signature.Public_key_hash.pp pkh >>= fun () -> + Lwt.fail Not_found + | (_, _, None, _) -> + log "No public key found for hash %a" + Signature.Public_key_hash.pp pkh >>= fun () -> + Lwt.fail Not_found + | (name, _, Some pk, _) -> + log "Found public key for hash %a (name: %s)" + Signature.Public_key_hash.pp pkh name >>= fun () -> + return pk diff --git a/src/bin_signer/http_daemon.ml b/src/bin_signer/http_daemon.ml new file mode 100644 index 000000000..09ca54d4d --- /dev/null +++ b/src/bin_signer/http_daemon.ml @@ -0,0 +1,66 @@ +(**************************************************************************) +(* *) +(* Copyright (c) 2014 - 2018. *) +(* Dynamic Ledger Solutions, Inc. *) +(* *) +(* All rights reserved. No warranty, explicit or implicit, provided. *) +(* *) +(**************************************************************************) + +let log = Signer_logging.lwt_log_notice + +let run (cctxt : #Client_context.wallet) ~hosts ?magic_bytes ~require_auth mode = + let dir = RPC_directory.empty in + let dir = + RPC_directory.register1 dir Signer_services.sign begin fun pkh signature data -> + Handler.sign cctxt { pkh ; data ; signature } ?magic_bytes ~require_auth + end in + let dir = + RPC_directory.register1 dir Signer_services.public_key begin fun pkh () () -> + Handler.public_key cctxt pkh + end in + let dir = + RPC_directory.register0 dir Signer_services.authorized_keys begin fun () () -> + if require_auth then + return None + else + Handler.Authorized_key.load cctxt >>=? fun keys -> + return (Some (keys |> List.split |> snd |> List.map Signature.Public_key.hash)) + end in + Lwt.catch + (fun () -> + List.map + (fun host -> + let host = Ipaddr.V6.to_string host in + log "Listening on address %s" host >>= fun () -> + RPC_server.launch ~host mode dir + ~media_types:Media_type.all_media_types + >>= fun _server -> + fst (Lwt.wait ())) + hosts |> Lwt.choose) + (function + | Unix.Unix_error(Unix.EADDRINUSE, "bind","") -> + failwith "Port already in use." + | exn -> Lwt.return (error_exn exn)) + +let run_https (cctxt : #Client_context.wallet) ~host ~port ~cert ~key ?magic_bytes ~require_auth = + Lwt_utils_unix.getaddrinfo ~passive:true ~node:host ~service:(string_of_int port) >>= function + | []-> + failwith "Cannot resolve listening address: %S" host + | points -> + let hosts = fst (List.split points) in + log "Accepting HTTPS requests on port %d" port >>= fun () -> + let mode : Conduit_lwt_unix.server = + `TLS (`Crt_file_path cert, `Key_file_path key, `No_password, `Port port) in + run (cctxt : #Client_context.wallet) ~hosts ?magic_bytes ~require_auth mode + +let run_http (cctxt : #Client_context.wallet) ~host ~port ?magic_bytes ~require_auth = + Lwt_utils_unix.getaddrinfo ~passive:true ~node:host ~service:(string_of_int port) >>= function + | [] -> + failwith "Cannot resolve listening address: %S" host + | points -> + let hosts = fst (List.split points) in + log "Accepting HTTP requests on port %d" port >>= fun () -> + let mode : Conduit_lwt_unix.server = + `TCP (`Port port) in + run (cctxt : #Client_context.wallet) ~hosts ?magic_bytes ~require_auth mode diff --git a/src/bin_signer/https_daemon.mli b/src/bin_signer/http_daemon.mli similarity index 82% rename from src/bin_signer/https_daemon.mli rename to src/bin_signer/http_daemon.mli index 436ae30c0..2250f90be 100644 --- a/src/bin_signer/https_daemon.mli +++ b/src/bin_signer/http_daemon.mli @@ -7,9 +7,16 @@ (* *) (**************************************************************************) -val run: +val run_https: #Client_context.io_wallet -> host:string -> port:int -> cert:string -> key:string -> ?magic_bytes: int list -> require_auth: bool -> 'a tzresult Lwt.t + +val run_http: + #Client_context.io_wallet -> + host:string -> port:int -> + ?magic_bytes: int list -> + require_auth: bool -> + 'a tzresult Lwt.t diff --git a/src/bin_signer/https_daemon.ml b/src/bin_signer/https_daemon.ml deleted file mode 100644 index 6e40562eb..000000000 --- a/src/bin_signer/https_daemon.ml +++ /dev/null @@ -1,44 +0,0 @@ -(**************************************************************************) -(* *) -(* Copyright (c) 2014 - 2018. *) -(* Dynamic Ledger Solutions, Inc. *) -(* *) -(* All rights reserved. No warranty, explicit or implicit, provided. *) -(* *) -(**************************************************************************) - -let log = Signer_logging.lwt_log_notice - -let run (cctxt : #Client_context.wallet) ~host ~port ~cert ~key ?magic_bytes ~require_auth = - log "Accepting HTTPS requests on port %d" port >>= fun () -> - let mode : Conduit_lwt_unix.server = - `TLS (`Crt_file_path cert, `Key_file_path key, `No_password, `Port port) in - let dir = RPC_directory.empty in - let dir = - RPC_directory.register1 dir Signer_services.sign begin fun pkh signature data -> - Handler.sign cctxt { pkh ; data ; signature } ?magic_bytes ~require_auth - end in - let dir = - RPC_directory.register1 dir Signer_services.public_key begin fun pkh () () -> - Handler.public_key cctxt pkh - end in - let dir = - RPC_directory.register0 dir Signer_services.authorized_keys begin fun () () -> - if require_auth then - return None - else - Handler.Authorized_key.load cctxt >>=? fun keys -> - return (Some (keys |> List.split |> snd |> List.map Signature.Public_key.hash)) - end in - Lwt.catch - (fun () -> - RPC_server.launch ~host mode dir - ~media_types:Media_type.all_media_types - ~cors: { allowed_origins = [ "*" ] ; - allowed_headers = [ "Content-Type" ] } - >>= fun _server -> - fst (Lwt.wait ())) - (function - | Unix.Unix_error(Unix.EADDRINUSE, "bind","") -> - failwith "Port already in use." - | exn -> Lwt.return (error_exn exn)) diff --git a/src/bin_signer/main_signer.ml b/src/bin_signer/main_signer.ml index 6fc1ca829..98503400c 100644 --- a/src/bin_signer/main_signer.ml +++ b/src/bin_signer/main_signer.ml @@ -32,6 +32,16 @@ let default_https_port = | None -> "443" | Some port -> port +let default_http_host = + match Sys.getenv_opt "TEZOS_SIGNER_HTTP_HOST" with + | None -> "localhost" + | Some host -> host + +let default_http_port = + match Sys.getenv_opt "TEZOS_SIGNER_HTTP_PORT" with + | None -> "6732" + | Some port -> port + open Clic let group = @@ -98,6 +108,31 @@ let commands base_dir require_auth = (fun (magic_bytes, path) cctxt -> Tezos_signer_backends.Encrypted.decrypt_all cctxt >>=? fun () -> Socket_daemon.run cctxt (Unix path) ?magic_bytes ~require_auth) ; + command ~group + ~desc: "Launch a signer daemon over HTTP." + (args3 + magic_bytes_arg + (default_arg + ~doc: "listening address or host name" + ~short: 'a' + ~long: "address" + ~placeholder: "host|address" + ~default: default_http_host + (parameter (fun _ s -> return s))) + (default_arg + ~doc: "listening HTTP port" + ~short: 'p' + ~long: "port" + ~placeholder: "port number" + ~default: default_http_port + (parameter + (fun _ x -> + try return (int_of_string x) + with Failure _ -> failwith "Invalid port %s" x)))) + (prefixes [ "launch" ; "http" ; "signer" ] @@ stop) + (fun (magic_bytes, host, port) cctxt -> + Tezos_signer_backends.Encrypted.decrypt_all cctxt >>=? fun () -> + Http_daemon.run_http cctxt ~host ~port ?magic_bytes ~require_auth) ; command ~group ~desc: "Launch a signer daemon over HTTPS." (args3 @@ -123,14 +158,22 @@ let commands base_dir require_auth = param ~name:"cert" ~desc: "path to th TLS certificate" - (parameter (fun _ s -> return s)) @@ + (parameter (fun _ s -> + if not (Sys.file_exists s) then + failwith "No such TLS certificate file %s" s + else + return s)) @@ param ~name:"key" ~desc: "path to th TLS key" - (parameter (fun _ s -> return s)) @@ stop) + (parameter (fun _ s -> + if not (Sys.file_exists s) then + failwith "No such TLS key file %s" s + else + return s)) @@ stop) (fun (magic_bytes, host, port) cert key cctxt -> Tezos_signer_backends.Encrypted.decrypt_all cctxt >>=? fun () -> - Https_daemon.run cctxt ~host ~port ~cert ~key ?magic_bytes ~require_auth) ; + Http_daemon.run_https cctxt ~host ~port ~cert ~key ?magic_bytes ~require_auth) ; command ~group ~desc: "Authorize a given public key to perform signing requests." (args1 diff --git a/src/lib_client_base/client_keys.ml b/src/lib_client_base/client_keys.ml index 2768a8498..364c72fe8 100644 --- a/src/lib_client_base/client_keys.ml +++ b/src/lib_client_base/client_keys.ml @@ -193,13 +193,13 @@ let raw_get_key (cctxt : #Client_context.wallet) pkh = let get_key cctxt pkh = raw_get_key cctxt pkh >>=? function | (pkh, Some pk, Some sk) -> return (pkh, pk, sk) - | (_pkh, _pk, None) -> failwith "... FIXME ... E" - | (_pkh, None, _sk) -> failwith "... FIXME ... F" + | (_pkh, _pk, None) -> failwith "Unknown secret key for %a" Signature.Public_key_hash.pp pkh + | (_pkh, None, _sk) -> failwith "Unknown public key for %a" Signature.Public_key_hash.pp pkh let get_public_key cctxt pkh = raw_get_key cctxt pkh >>=? function | (pkh, Some pk, _sk) -> return (pkh, pk) - | (_pkh, None, _sk) -> failwith "... FIXME ... G" + | (_pkh, None, _sk) -> failwith "Unknown public key for %a" Signature.Public_key_hash.pp pkh let get_keys (cctxt : #Client_context.wallet) = Secret_key.load cctxt >>=? fun sks -> diff --git a/src/lib_client_base_unix/client_main_run.ml b/src/lib_client_base_unix/client_main_run.ml index 2c8d2a2e2..eefe33104 100644 --- a/src/lib_client_base_unix/client_main_run.ml +++ b/src/lib_client_base_unix/client_main_run.ml @@ -110,7 +110,7 @@ let main select_commands = (module Tezos_signer_backends.Encrypted.Make(struct let cctxt = (client_config :> Client_context.prompter) end)) ; - let module Remote_authenticator = struct + let module Remote_params = struct let authenticate pkhs payload = Client_keys.list_keys client_config >>=? fun keys -> match List.filter_map @@ -125,17 +125,20 @@ let main select_commands = | [] -> failwith "remote signer expects authentication signature, \ but no authorized key was found in the wallet" + let logger = rpc_config.logger end in - let module Https = Tezos_signer_backends.Https.Make(Remote_authenticator) in - let module Socket = Tezos_signer_backends.Socket.Make(Remote_authenticator) in + let module Https = Tezos_signer_backends.Https.Make(Remote_params) in + let module Http = Tezos_signer_backends.Http.Make(Remote_params) in + let module Socket = Tezos_signer_backends.Socket.Make(Remote_params) in Client_keys.register_signer (module Https) ; + Client_keys.register_signer (module Http) ; Client_keys.register_signer (module Socket.Unix) ; Client_keys.register_signer (module Socket.Tcp) ; Option.iter parsed_config_file.remote_signer ~f: begin fun signer -> Client_keys.register_signer (module Tezos_signer_backends.Remote.Make(struct let default = signer - include Remote_authenticator + include Remote_params end)) end ; select_commands ctxt parsed_args >>=? fun commands -> diff --git a/src/lib_signer_backends/encrypted.ml b/src/lib_signer_backends/encrypted.ml index 3ba295189..24583881f 100644 --- a/src/lib_signer_backends/encrypted.ml +++ b/src/lib_signer_backends/encrypted.ml @@ -41,7 +41,7 @@ module Raw = struct | None -> return None | Some bytes -> match Data_encoding.Binary.of_bytes Signature.Secret_key.encoding bytes with - | None -> failwith "... FIXME ... D" (* corrupted data *) + | None -> failwith "Corrupted wallet, deciphered key is invalid" | Some sk -> return (Some sk) end @@ -77,7 +77,7 @@ let rec noninteractice_decrypt_loop ~encrypted_sk = function let decrypt_payload cctxt ?name encrypted_sk = match Base58.safe_decode encrypted_sk with - | None -> failwith "... FIXME ... A" + | None -> failwith "Not a Base58 encoded encrypted key" | Some encrypted_sk -> let encrypted_sk = MBytes.of_string encrypted_sk in noninteractice_decrypt_loop ~encrypted_sk !passwords >>=? function diff --git a/src/lib_signer_backends/http.ml b/src/lib_signer_backends/http.ml new file mode 100644 index 000000000..13903789c --- /dev/null +++ b/src/lib_signer_backends/http.ml @@ -0,0 +1,10 @@ +(**************************************************************************) +(* *) +(* Copyright (c) 2014 - 2018. *) +(* Dynamic Ledger Solutions, Inc. *) +(* *) +(* All rights reserved. No warranty, explicit or implicit, provided. *) +(* *) +(**************************************************************************) + +include Http_gen.Make(struct let scheme = "http" end) diff --git a/src/lib_signer_backends/http.mli b/src/lib_signer_backends/http.mli new file mode 100644 index 000000000..fb77b83e5 --- /dev/null +++ b/src/lib_signer_backends/http.mli @@ -0,0 +1,16 @@ +(**************************************************************************) +(* *) +(* Copyright (c) 2014 - 2018. *) +(* Dynamic Ledger Solutions, Inc. *) +(* *) +(* All rights reserved. No warranty, explicit or implicit, provided. *) +(* *) +(**************************************************************************) + +module Make(P : sig + val authenticate: Signature.Public_key_hash.t list -> MBytes.t -> Signature.t tzresult Lwt.t + val logger: RPC_client.logger + end) + : Client_keys.SIGNER + +val make_base: string -> int -> Uri.t diff --git a/src/lib_signer_backends/http_gen.ml b/src/lib_signer_backends/http_gen.ml new file mode 100644 index 000000000..d5f1738ae --- /dev/null +++ b/src/lib_signer_backends/http_gen.ml @@ -0,0 +1,91 @@ +(**************************************************************************) +(* *) +(* Copyright (c) 2014 - 2018. *) +(* Dynamic Ledger Solutions, Inc. *) +(* *) +(* All rights reserved. No warranty, explicit or implicit, provided. *) +(* *) +(**************************************************************************) + +module Make(N : sig val scheme : string end) = struct + + open Client_keys + + let scheme = N.scheme + + module Make(P : sig + val authenticate: Signature.Public_key_hash.t list -> MBytes.t -> Signature.t tzresult Lwt.t + val logger: RPC_client.logger + end) = struct + + let scheme = scheme + + let title = + "Built-in tezos-signer using remote signer through hardcoded " ^ scheme ^ " requests." + + let description = + "Valid locators are of this form:\n" + ^ " - " ^ scheme ^ "://host/tz1...\n" + ^ " - " ^ scheme ^ "://host:port/path/to/service/tz1..." + + let parse uri = + (* extract `tz1..` from the last component of the path *) + assert (Uri.scheme uri = Some scheme) ; + let path = Uri.path uri in + begin match String.rindex_opt path '/' with + | None -> + failwith "Invalid locator %a" Uri.pp_hum uri + | Some i -> + let pkh = String.sub path (i + 1) (String.length path - i - 1) in + let path = String.sub path 0 i in + return (Uri.with_path uri path, pkh) + end >>=? fun (base, pkh) -> + Lwt.return (Signature.Public_key_hash.of_b58check pkh) >>=? fun pkh -> + return (base, pkh) + + let public_key uri = + parse (uri : pk_uri :> Uri.t) >>=? fun (base, pkh) -> + RPC_client.call_service + ~logger: P.logger + Media_type.all_media_types + ~base Signer_services.public_key ((), pkh) () () + + let neuterize uri = + return (Client_keys.make_pk_uri (uri : sk_uri :> Uri.t)) + + let public_key_hash uri = + public_key uri >>=? fun pk -> + return (Signature.Public_key.hash pk) + + let sign ?watermark uri msg = + parse (uri : sk_uri :> Uri.t) >>=? fun (base, pkh) -> + let msg = + match watermark with + | None -> msg + | Some watermark -> + MBytes.concat "" [ Signature.bytes_of_watermark watermark ; msg ] in + RPC_client.call_service + ~logger: P.logger + Media_type.all_media_types + ~base Signer_services.authorized_keys () () () >>=? fun authorized_keys -> + begin match authorized_keys with + | Some authorized_keys -> + P.authenticate + authorized_keys + (Signer_messages.Sign.Request.to_sign ~pkh ~data:msg) >>=? fun signature -> + return (Some signature) + | None -> return None + end >>=? fun signature -> + RPC_client.call_service + ~logger: P.logger + Media_type.all_media_types + ~base Signer_services.sign ((), pkh) + signature + msg + + end + + let make_base host port = + Uri.make ~scheme ~host ~port () + +end diff --git a/src/lib_signer_backends/http_gen.mli b/src/lib_signer_backends/http_gen.mli new file mode 100644 index 000000000..dcd5ab06d --- /dev/null +++ b/src/lib_signer_backends/http_gen.mli @@ -0,0 +1,20 @@ +(**************************************************************************) +(* *) +(* Copyright (c) 2014 - 2018. *) +(* Dynamic Ledger Solutions, Inc. *) +(* *) +(* All rights reserved. No warranty, explicit or implicit, provided. *) +(* *) +(**************************************************************************) + +module Make(N : sig val scheme : string end) : sig + + module Make(P : sig + val authenticate: Signature.Public_key_hash.t list -> MBytes.t -> Signature.t tzresult Lwt.t + val logger: RPC_client.logger + end) + : Client_keys.SIGNER + + val make_base: string -> int -> Uri.t + +end diff --git a/src/lib_signer_backends/https.ml b/src/lib_signer_backends/https.ml index 8ff78ea02..aff203cdd 100644 --- a/src/lib_signer_backends/https.ml +++ b/src/lib_signer_backends/https.ml @@ -7,77 +7,4 @@ (* *) (**************************************************************************) -open Client_keys - -let scheme = "https" - -module Make(P : sig - val authenticate: Signature.Public_key_hash.t list -> MBytes.t -> Signature.t tzresult Lwt.t - end) = struct - - let scheme = scheme - - let title = - "Built-in tezos-signer using remote signer through hardcoded https requests." - - let description = - "Valid locators are of this form:\n\ - \ - https://host/tz1...\n\ - \ - https://host:port/path/to/service/tz1...\n" - - let parse uri = - (* extract `tz1..` from the last component of the path *) - assert (Uri.scheme uri = Some scheme) ; - let path = Uri.path uri in - begin match String.rindex_opt path '/' with - | None -> - failwith "Invalid locator %a" Uri.pp_hum uri - | Some i -> - let pkh = String.sub path (i + 1) (String.length path - i - 1) in - let path = String.sub path 0 i in - return (Uri.with_path uri path, pkh) - end >>=? fun (base, pkh) -> - Lwt.return (Signature.Public_key_hash.of_b58check pkh) >>=? fun pkh -> - return (base, pkh) - - let public_key uri = - parse (uri : pk_uri :> Uri.t) >>=? fun (base, pkh) -> - RPC_client.call_service - Media_type.all_media_types - ~base Signer_services.public_key ((), pkh) () () - - let neuterize uri = - return (Client_keys.make_pk_uri (uri : sk_uri :> Uri.t)) - - let public_key_hash uri = - public_key uri >>=? fun pk -> - return (Signature.Public_key.hash pk) - - let sign ?watermark uri msg = - parse (uri : sk_uri :> Uri.t) >>=? fun (base, pkh) -> - let msg = - match watermark with - | None -> msg - | Some watermark -> - MBytes.concat "" [ Signature.bytes_of_watermark watermark ; msg ] in - RPC_client.call_service - Media_type.all_media_types - ~base Signer_services.authorized_keys () () () >>=? fun authorized_keys -> - begin match authorized_keys with - | Some authorized_keys -> - P.authenticate - authorized_keys - (Signer_messages.Sign.Request.to_sign ~pkh ~data:msg) >>=? fun signature -> - return (Some signature) - | None -> return None - end >>=? fun signature -> - RPC_client.call_service - Media_type.all_media_types - ~base Signer_services.sign ((), pkh) - signature - msg - -end - -let make_base host port = - Uri.make ~scheme ~host ~port () +include Http_gen.Make(struct let scheme = "https" end) diff --git a/src/lib_signer_backends/https.mli b/src/lib_signer_backends/https.mli index 978378073..fb77b83e5 100644 --- a/src/lib_signer_backends/https.mli +++ b/src/lib_signer_backends/https.mli @@ -9,6 +9,7 @@ module Make(P : sig val authenticate: Signature.Public_key_hash.t list -> MBytes.t -> Signature.t tzresult Lwt.t + val logger: RPC_client.logger end) : Client_keys.SIGNER diff --git a/src/lib_signer_backends/remote.ml b/src/lib_signer_backends/remote.ml index 7b95fef59..1bc75f9e2 100644 --- a/src/lib_signer_backends/remote.ml +++ b/src/lib_signer_backends/remote.ml @@ -14,6 +14,7 @@ let scheme = "remote" module Make(S : sig val default : Uri.t val authenticate: Signature.Public_key_hash.t list -> MBytes.t -> Signature.t tzresult Lwt.t + val logger: RPC_client.logger end) = struct let scheme = scheme @@ -25,18 +26,21 @@ module Make(S : sig "Valid locators are of this form: remote://tz1...\n\ The key will be queried to current remote signer, which can be \ configured with the `--remote-signer` or `-R` options, \ - or by defining the following environment variables:\n \ - - $TEZOS_SIGNER_UNIX_PATH,\n\ - - $TEZOS_SIGNER_TCP_HOST and $TEZOS_SIGNER_TCP_PORT (default: 7732),\n\ - - $TEZOS_SIGNER_HTTPS_HOST and $TEZOS_SIGNER_HTTPS_PORT (default: 443)." + or by defining the following environment variables:\n\ + \ - $TEZOS_SIGNER_UNIX_PATH,\n\ + \ - $TEZOS_SIGNER_TCP_HOST and $TEZOS_SIGNER_TCP_PORT (default: 7732),\n\ + \ - $TEZOS_SIGNER_HTTP_HOST and $TEZOS_SIGNER_HTTP_PORT (default: 6732),\n\ + \ - $TEZOS_SIGNER_HTTPS_HOST and $TEZOS_SIGNER_HTTPS_PORT (default: 443)." module Socket = Socket.Make(S) + module Http = Http.Make(S) module Https = Https.Make(S) let get_remote () = match Uri.scheme S.default with | Some "unix" -> (module Socket.Unix : SIGNER) | Some "tcp" -> (module Socket.Tcp : SIGNER) + | Some "http" -> (module Http : SIGNER) | Some "https" -> (module Https : SIGNER) | _ -> assert false @@ -51,7 +55,7 @@ module Make(S : sig (fun uri -> let key = Uri.path uri in Uri.with_path S.default key) - | Some "https" -> + | Some ("https" | "http") -> (fun uri -> let key = Uri.path uri in match Uri.path S.default with @@ -89,11 +93,12 @@ let make_pk pk = let read_base_uri_from_env () = match Sys.getenv_opt "TEZOS_SIGNER_UNIX_PATH", Sys.getenv_opt "TEZOS_SIGNER_TCP_HOST", + Sys.getenv_opt "TEZOS_SIGNER_HTTP_HOST", Sys.getenv_opt "TEZOS_SIGNER_HTTPS_HOST" with - | None, None, None -> return None - | Some path, None, None -> + | None, None, None, None -> return None + | Some path, None, None, None -> return (Some (Socket.make_unix_base path)) - | None, Some host, None -> begin + | None, Some host, None, None -> begin try let port = match Sys.getenv_opt "TEZOS_SIGNER_TCP_PORT" with @@ -103,7 +108,17 @@ let read_base_uri_from_env () = with Invalid_argument _ -> failwith "Failed to parse TEZOS_SIGNER_TCP_PORT.@." end - | None, None, Some host -> begin + | None, None, Some host, None -> begin + try + let port = + match Sys.getenv_opt "TEZOS_SIGNER_HTTP_PORT" with + | None -> 6732 + | Some port -> int_of_string port in + return (Some (Http.make_base host port)) + with Invalid_argument _ -> + failwith "Failed to parse TEZOS_SIGNER_HTTP_PORT.@." + end + | None, None, None, Some host -> begin try let port = match Sys.getenv_opt "TEZOS_SIGNER_HTTPS_PORT" with @@ -113,11 +128,12 @@ let read_base_uri_from_env () = with Invalid_argument _ -> failwith "Failed to parse TEZOS_SIGNER_HTTPS_PORT.@." end - | _, _, _ -> + | _, _, _, _ -> failwith "Only one the following environment variable must be defined: \ TEZOS_SIGNER_UNIX_PATH, \ TEZOS_SIGNER_TCP_HOST, \ + TEZOS_SIGNER_HTTP_HOST, \ TEZOS_SIGNER_HTTPS_HOST@." type error += Invalid_remote_signer of string @@ -130,7 +146,13 @@ let () = ~description: "The provided remote signer is invalid." ~pp: (fun ppf s -> - Format.fprintf ppf "Value '%s' is not a valid URI for a remote signer" s) + Format.fprintf ppf + "@[Value '%s' is not a valid URI for a remote signer.@,\ + Supported URIs for remote signers are of the form:@,\ + \ - unix:///path/to/socket/file@,\ + \ - tcp://host:port@,\ + \ - http://host[:port][/prefix]@,\ + \ - https://host[:port][/prefix]@]" s) Data_encoding.(obj1 (req "uri" string)) (function Invalid_remote_signer s -> Some s | _ -> None) (fun s -> Invalid_remote_signer s) @@ -140,6 +162,7 @@ let parse_base_uri s = try let uri = Uri.of_string s in match Uri.scheme uri with + | Some "http" -> return uri | Some "https" -> return uri | Some "tcp" -> return uri | Some "unix" -> return uri diff --git a/src/lib_signer_backends/remote.mli b/src/lib_signer_backends/remote.mli index 251150ed0..338f12655 100644 --- a/src/lib_signer_backends/remote.mli +++ b/src/lib_signer_backends/remote.mli @@ -10,6 +10,7 @@ module Make(S : sig val default : Uri.t val authenticate: Signature.Public_key_hash.t list -> MBytes.t -> Signature.t tzresult Lwt.t + val logger: RPC_client.logger end) : Client_keys.SIGNER val make_pk: Signature.public_key -> Client_keys.pk_uri diff --git a/src/lib_signer_services/signer_services.ml b/src/lib_signer_services/signer_services.ml index 8050b35c5..a4c74c24b 100644 --- a/src/lib_signer_services/signer_services.ml +++ b/src/lib_signer_services/signer_services.ml @@ -23,14 +23,14 @@ let sign = ~query ~input: Data_encoding.bytes ~output: Data_encoding.(obj1 (req "signature" Signature.encoding)) - RPC_path.(root /: Signature.Public_key_hash.rpc_arg) + RPC_path.(root / "keys" /: Signature.Public_key_hash.rpc_arg) let public_key = RPC_service.get_service ~description: "Retrieve the public key of a given remote key" ~query: RPC_query.empty ~output: Data_encoding.(obj1 (req "public_key" Signature.Public_key.encoding)) - RPC_path.(root /: Signature.Public_key_hash.rpc_arg) + RPC_path.(root / "keys" /: Signature.Public_key_hash.rpc_arg) let authorized_keys = RPC_service.get_service