Signer: support plain HTTP (no S) and a few cosmetic fixes
This commit is contained in:
parent
0bb12b0655
commit
7ad44a9af3
@ -59,7 +59,17 @@ let sign
|
|||||||
let public_key (cctxt : #Client_context.wallet) pkh =
|
let public_key (cctxt : #Client_context.wallet) pkh =
|
||||||
log "Request for public key %a"
|
log "Request for public key %a"
|
||||||
Signature.Public_key_hash.pp pkh >>= fun () ->
|
Signature.Public_key_hash.pp pkh >>= fun () ->
|
||||||
Client_keys.get_public_key cctxt pkh >>=? fun (name, pk) ->
|
Client_keys.list_keys cctxt >>=? fun all_keys ->
|
||||||
log "Found public key for hash %a (name: %s)"
|
match List.find (fun (_, h, _, _) -> Signature.Public_key_hash.equal h pkh) all_keys with
|
||||||
Signature.Public_key_hash.pp pkh name >>= fun () ->
|
| exception Not_found ->
|
||||||
return pk
|
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
|
||||||
|
66
src/bin_signer/http_daemon.ml
Normal file
66
src/bin_signer/http_daemon.ml
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
(**************************************************************************)
|
||||||
|
(* *)
|
||||||
|
(* Copyright (c) 2014 - 2018. *)
|
||||||
|
(* Dynamic Ledger Solutions, Inc. <contact@tezos.com> *)
|
||||||
|
(* *)
|
||||||
|
(* 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
|
@ -7,9 +7,16 @@
|
|||||||
(* *)
|
(* *)
|
||||||
(**************************************************************************)
|
(**************************************************************************)
|
||||||
|
|
||||||
val run:
|
val run_https:
|
||||||
#Client_context.io_wallet ->
|
#Client_context.io_wallet ->
|
||||||
host:string -> port:int -> cert:string -> key:string ->
|
host:string -> port:int -> cert:string -> key:string ->
|
||||||
?magic_bytes: int list ->
|
?magic_bytes: int list ->
|
||||||
require_auth: bool ->
|
require_auth: bool ->
|
||||||
'a tzresult Lwt.t
|
'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
|
@ -1,44 +0,0 @@
|
|||||||
(**************************************************************************)
|
|
||||||
(* *)
|
|
||||||
(* Copyright (c) 2014 - 2018. *)
|
|
||||||
(* Dynamic Ledger Solutions, Inc. <contact@tezos.com> *)
|
|
||||||
(* *)
|
|
||||||
(* 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))
|
|
@ -32,6 +32,16 @@ let default_https_port =
|
|||||||
| None -> "443"
|
| None -> "443"
|
||||||
| Some port -> port
|
| 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
|
open Clic
|
||||||
|
|
||||||
let group =
|
let group =
|
||||||
@ -98,6 +108,31 @@ let commands base_dir require_auth =
|
|||||||
(fun (magic_bytes, path) cctxt ->
|
(fun (magic_bytes, path) cctxt ->
|
||||||
Tezos_signer_backends.Encrypted.decrypt_all cctxt >>=? fun () ->
|
Tezos_signer_backends.Encrypted.decrypt_all cctxt >>=? fun () ->
|
||||||
Socket_daemon.run cctxt (Unix path) ?magic_bytes ~require_auth) ;
|
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
|
command ~group
|
||||||
~desc: "Launch a signer daemon over HTTPS."
|
~desc: "Launch a signer daemon over HTTPS."
|
||||||
(args3
|
(args3
|
||||||
@ -123,14 +158,22 @@ let commands base_dir require_auth =
|
|||||||
param
|
param
|
||||||
~name:"cert"
|
~name:"cert"
|
||||||
~desc: "path to th TLS certificate"
|
~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
|
param
|
||||||
~name:"key"
|
~name:"key"
|
||||||
~desc: "path to th TLS 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 ->
|
(fun (magic_bytes, host, port) cert key cctxt ->
|
||||||
Tezos_signer_backends.Encrypted.decrypt_all cctxt >>=? fun () ->
|
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
|
command ~group
|
||||||
~desc: "Authorize a given public key to perform signing requests."
|
~desc: "Authorize a given public key to perform signing requests."
|
||||||
(args1
|
(args1
|
||||||
|
@ -193,13 +193,13 @@ let raw_get_key (cctxt : #Client_context.wallet) pkh =
|
|||||||
let get_key cctxt pkh =
|
let get_key cctxt pkh =
|
||||||
raw_get_key cctxt pkh >>=? function
|
raw_get_key cctxt pkh >>=? function
|
||||||
| (pkh, Some pk, Some sk) -> return (pkh, pk, sk)
|
| (pkh, Some pk, Some sk) -> return (pkh, pk, sk)
|
||||||
| (_pkh, _pk, None) -> failwith "... FIXME ... E"
|
| (_pkh, _pk, None) -> failwith "Unknown secret key for %a" Signature.Public_key_hash.pp pkh
|
||||||
| (_pkh, None, _sk) -> failwith "... FIXME ... F"
|
| (_pkh, None, _sk) -> failwith "Unknown public key for %a" Signature.Public_key_hash.pp pkh
|
||||||
|
|
||||||
let get_public_key cctxt pkh =
|
let get_public_key cctxt pkh =
|
||||||
raw_get_key cctxt pkh >>=? function
|
raw_get_key cctxt pkh >>=? function
|
||||||
| (pkh, Some pk, _sk) -> return (pkh, pk)
|
| (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) =
|
let get_keys (cctxt : #Client_context.wallet) =
|
||||||
Secret_key.load cctxt >>=? fun sks ->
|
Secret_key.load cctxt >>=? fun sks ->
|
||||||
|
@ -110,7 +110,7 @@ let main select_commands =
|
|||||||
(module Tezos_signer_backends.Encrypted.Make(struct
|
(module Tezos_signer_backends.Encrypted.Make(struct
|
||||||
let cctxt = (client_config :> Client_context.prompter)
|
let cctxt = (client_config :> Client_context.prompter)
|
||||||
end)) ;
|
end)) ;
|
||||||
let module Remote_authenticator = struct
|
let module Remote_params = struct
|
||||||
let authenticate pkhs payload =
|
let authenticate pkhs payload =
|
||||||
Client_keys.list_keys client_config >>=? fun keys ->
|
Client_keys.list_keys client_config >>=? fun keys ->
|
||||||
match List.filter_map
|
match List.filter_map
|
||||||
@ -125,17 +125,20 @@ let main select_commands =
|
|||||||
| [] -> failwith
|
| [] -> failwith
|
||||||
"remote signer expects authentication signature, \
|
"remote signer expects authentication signature, \
|
||||||
but no authorized key was found in the wallet"
|
but no authorized key was found in the wallet"
|
||||||
|
let logger = rpc_config.logger
|
||||||
end in
|
end in
|
||||||
let module Https = Tezos_signer_backends.Https.Make(Remote_authenticator) in
|
let module Https = Tezos_signer_backends.Https.Make(Remote_params) in
|
||||||
let module Socket = Tezos_signer_backends.Socket.Make(Remote_authenticator) 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 Https) ;
|
||||||
|
Client_keys.register_signer (module Http) ;
|
||||||
Client_keys.register_signer (module Socket.Unix) ;
|
Client_keys.register_signer (module Socket.Unix) ;
|
||||||
Client_keys.register_signer (module Socket.Tcp) ;
|
Client_keys.register_signer (module Socket.Tcp) ;
|
||||||
Option.iter parsed_config_file.remote_signer ~f: begin fun signer ->
|
Option.iter parsed_config_file.remote_signer ~f: begin fun signer ->
|
||||||
Client_keys.register_signer
|
Client_keys.register_signer
|
||||||
(module Tezos_signer_backends.Remote.Make(struct
|
(module Tezos_signer_backends.Remote.Make(struct
|
||||||
let default = signer
|
let default = signer
|
||||||
include Remote_authenticator
|
include Remote_params
|
||||||
end))
|
end))
|
||||||
end ;
|
end ;
|
||||||
select_commands ctxt parsed_args >>=? fun commands ->
|
select_commands ctxt parsed_args >>=? fun commands ->
|
||||||
|
@ -41,7 +41,7 @@ module Raw = struct
|
|||||||
| None -> return None
|
| None -> return None
|
||||||
| Some bytes ->
|
| Some bytes ->
|
||||||
match Data_encoding.Binary.of_bytes Signature.Secret_key.encoding bytes with
|
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)
|
| Some sk -> return (Some sk)
|
||||||
|
|
||||||
end
|
end
|
||||||
@ -77,7 +77,7 @@ let rec noninteractice_decrypt_loop ~encrypted_sk = function
|
|||||||
|
|
||||||
let decrypt_payload cctxt ?name encrypted_sk =
|
let decrypt_payload cctxt ?name encrypted_sk =
|
||||||
match Base58.safe_decode encrypted_sk with
|
match Base58.safe_decode encrypted_sk with
|
||||||
| None -> failwith "... FIXME ... A"
|
| None -> failwith "Not a Base58 encoded encrypted key"
|
||||||
| Some encrypted_sk ->
|
| Some encrypted_sk ->
|
||||||
let encrypted_sk = MBytes.of_string encrypted_sk in
|
let encrypted_sk = MBytes.of_string encrypted_sk in
|
||||||
noninteractice_decrypt_loop ~encrypted_sk !passwords >>=? function
|
noninteractice_decrypt_loop ~encrypted_sk !passwords >>=? function
|
||||||
|
10
src/lib_signer_backends/http.ml
Normal file
10
src/lib_signer_backends/http.ml
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
(**************************************************************************)
|
||||||
|
(* *)
|
||||||
|
(* Copyright (c) 2014 - 2018. *)
|
||||||
|
(* Dynamic Ledger Solutions, Inc. <contact@tezos.com> *)
|
||||||
|
(* *)
|
||||||
|
(* All rights reserved. No warranty, explicit or implicit, provided. *)
|
||||||
|
(* *)
|
||||||
|
(**************************************************************************)
|
||||||
|
|
||||||
|
include Http_gen.Make(struct let scheme = "http" end)
|
16
src/lib_signer_backends/http.mli
Normal file
16
src/lib_signer_backends/http.mli
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
(**************************************************************************)
|
||||||
|
(* *)
|
||||||
|
(* Copyright (c) 2014 - 2018. *)
|
||||||
|
(* Dynamic Ledger Solutions, Inc. <contact@tezos.com> *)
|
||||||
|
(* *)
|
||||||
|
(* 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
|
91
src/lib_signer_backends/http_gen.ml
Normal file
91
src/lib_signer_backends/http_gen.ml
Normal file
@ -0,0 +1,91 @@
|
|||||||
|
(**************************************************************************)
|
||||||
|
(* *)
|
||||||
|
(* Copyright (c) 2014 - 2018. *)
|
||||||
|
(* Dynamic Ledger Solutions, Inc. <contact@tezos.com> *)
|
||||||
|
(* *)
|
||||||
|
(* 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
|
20
src/lib_signer_backends/http_gen.mli
Normal file
20
src/lib_signer_backends/http_gen.mli
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
(**************************************************************************)
|
||||||
|
(* *)
|
||||||
|
(* Copyright (c) 2014 - 2018. *)
|
||||||
|
(* Dynamic Ledger Solutions, Inc. <contact@tezos.com> *)
|
||||||
|
(* *)
|
||||||
|
(* 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
|
@ -7,77 +7,4 @@
|
|||||||
(* *)
|
(* *)
|
||||||
(**************************************************************************)
|
(**************************************************************************)
|
||||||
|
|
||||||
open Client_keys
|
include Http_gen.Make(struct let scheme = "https" end)
|
||||||
|
|
||||||
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 ()
|
|
||||||
|
@ -9,6 +9,7 @@
|
|||||||
|
|
||||||
module Make(P : sig
|
module Make(P : sig
|
||||||
val authenticate: Signature.Public_key_hash.t list -> MBytes.t -> Signature.t tzresult Lwt.t
|
val authenticate: Signature.Public_key_hash.t list -> MBytes.t -> Signature.t tzresult Lwt.t
|
||||||
|
val logger: RPC_client.logger
|
||||||
end)
|
end)
|
||||||
: Client_keys.SIGNER
|
: Client_keys.SIGNER
|
||||||
|
|
||||||
|
@ -14,6 +14,7 @@ let scheme = "remote"
|
|||||||
module Make(S : sig
|
module Make(S : sig
|
||||||
val default : Uri.t
|
val default : Uri.t
|
||||||
val authenticate: Signature.Public_key_hash.t list -> MBytes.t -> Signature.t tzresult Lwt.t
|
val authenticate: Signature.Public_key_hash.t list -> MBytes.t -> Signature.t tzresult Lwt.t
|
||||||
|
val logger: RPC_client.logger
|
||||||
end) = struct
|
end) = struct
|
||||||
|
|
||||||
let scheme = scheme
|
let scheme = scheme
|
||||||
@ -25,18 +26,21 @@ module Make(S : sig
|
|||||||
"Valid locators are of this form: remote://tz1...\n\
|
"Valid locators are of this form: remote://tz1...\n\
|
||||||
The key will be queried to current remote signer, which can be \
|
The key will be queried to current remote signer, which can be \
|
||||||
configured with the `--remote-signer` or `-R` options, \
|
configured with the `--remote-signer` or `-R` options, \
|
||||||
or by defining the following environment variables:\n \
|
or by defining the following environment variables:\n\
|
||||||
- $TEZOS_SIGNER_UNIX_PATH,\n\
|
\ - $TEZOS_SIGNER_UNIX_PATH,\n\
|
||||||
- $TEZOS_SIGNER_TCP_HOST and $TEZOS_SIGNER_TCP_PORT (default: 7732),\n\
|
\ - $TEZOS_SIGNER_TCP_HOST and $TEZOS_SIGNER_TCP_PORT (default: 7732),\n\
|
||||||
- $TEZOS_SIGNER_HTTPS_HOST and $TEZOS_SIGNER_HTTPS_PORT (default: 443)."
|
\ - $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 Socket = Socket.Make(S)
|
||||||
|
module Http = Http.Make(S)
|
||||||
module Https = Https.Make(S)
|
module Https = Https.Make(S)
|
||||||
|
|
||||||
let get_remote () =
|
let get_remote () =
|
||||||
match Uri.scheme S.default with
|
match Uri.scheme S.default with
|
||||||
| Some "unix" -> (module Socket.Unix : SIGNER)
|
| Some "unix" -> (module Socket.Unix : SIGNER)
|
||||||
| Some "tcp" -> (module Socket.Tcp : SIGNER)
|
| Some "tcp" -> (module Socket.Tcp : SIGNER)
|
||||||
|
| Some "http" -> (module Http : SIGNER)
|
||||||
| Some "https" -> (module Https : SIGNER)
|
| Some "https" -> (module Https : SIGNER)
|
||||||
| _ -> assert false
|
| _ -> assert false
|
||||||
|
|
||||||
@ -51,7 +55,7 @@ module Make(S : sig
|
|||||||
(fun uri ->
|
(fun uri ->
|
||||||
let key = Uri.path uri in
|
let key = Uri.path uri in
|
||||||
Uri.with_path S.default key)
|
Uri.with_path S.default key)
|
||||||
| Some "https" ->
|
| Some ("https" | "http") ->
|
||||||
(fun uri ->
|
(fun uri ->
|
||||||
let key = Uri.path uri in
|
let key = Uri.path uri in
|
||||||
match Uri.path S.default with
|
match Uri.path S.default with
|
||||||
@ -89,11 +93,12 @@ let make_pk pk =
|
|||||||
let read_base_uri_from_env () =
|
let read_base_uri_from_env () =
|
||||||
match Sys.getenv_opt "TEZOS_SIGNER_UNIX_PATH",
|
match Sys.getenv_opt "TEZOS_SIGNER_UNIX_PATH",
|
||||||
Sys.getenv_opt "TEZOS_SIGNER_TCP_HOST",
|
Sys.getenv_opt "TEZOS_SIGNER_TCP_HOST",
|
||||||
|
Sys.getenv_opt "TEZOS_SIGNER_HTTP_HOST",
|
||||||
Sys.getenv_opt "TEZOS_SIGNER_HTTPS_HOST" with
|
Sys.getenv_opt "TEZOS_SIGNER_HTTPS_HOST" with
|
||||||
| None, None, None -> return None
|
| None, None, None, None -> return None
|
||||||
| Some path, None, None ->
|
| Some path, None, None, None ->
|
||||||
return (Some (Socket.make_unix_base path))
|
return (Some (Socket.make_unix_base path))
|
||||||
| None, Some host, None -> begin
|
| None, Some host, None, None -> begin
|
||||||
try
|
try
|
||||||
let port =
|
let port =
|
||||||
match Sys.getenv_opt "TEZOS_SIGNER_TCP_PORT" with
|
match Sys.getenv_opt "TEZOS_SIGNER_TCP_PORT" with
|
||||||
@ -103,7 +108,17 @@ let read_base_uri_from_env () =
|
|||||||
with Invalid_argument _ ->
|
with Invalid_argument _ ->
|
||||||
failwith "Failed to parse TEZOS_SIGNER_TCP_PORT.@."
|
failwith "Failed to parse TEZOS_SIGNER_TCP_PORT.@."
|
||||||
end
|
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
|
try
|
||||||
let port =
|
let port =
|
||||||
match Sys.getenv_opt "TEZOS_SIGNER_HTTPS_PORT" with
|
match Sys.getenv_opt "TEZOS_SIGNER_HTTPS_PORT" with
|
||||||
@ -113,11 +128,12 @@ let read_base_uri_from_env () =
|
|||||||
with Invalid_argument _ ->
|
with Invalid_argument _ ->
|
||||||
failwith "Failed to parse TEZOS_SIGNER_HTTPS_PORT.@."
|
failwith "Failed to parse TEZOS_SIGNER_HTTPS_PORT.@."
|
||||||
end
|
end
|
||||||
| _, _, _ ->
|
| _, _, _, _ ->
|
||||||
failwith
|
failwith
|
||||||
"Only one the following environment variable must be defined: \
|
"Only one the following environment variable must be defined: \
|
||||||
TEZOS_SIGNER_UNIX_PATH, \
|
TEZOS_SIGNER_UNIX_PATH, \
|
||||||
TEZOS_SIGNER_TCP_HOST, \
|
TEZOS_SIGNER_TCP_HOST, \
|
||||||
|
TEZOS_SIGNER_HTTP_HOST, \
|
||||||
TEZOS_SIGNER_HTTPS_HOST@."
|
TEZOS_SIGNER_HTTPS_HOST@."
|
||||||
|
|
||||||
type error += Invalid_remote_signer of string
|
type error += Invalid_remote_signer of string
|
||||||
@ -130,7 +146,13 @@ let () =
|
|||||||
~description: "The provided remote signer is invalid."
|
~description: "The provided remote signer is invalid."
|
||||||
~pp:
|
~pp:
|
||||||
(fun ppf s ->
|
(fun ppf s ->
|
||||||
Format.fprintf ppf "Value '%s' is not a valid URI for a remote signer" s)
|
Format.fprintf ppf
|
||||||
|
"@[<v 0>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))
|
Data_encoding.(obj1 (req "uri" string))
|
||||||
(function Invalid_remote_signer s -> Some s | _ -> None)
|
(function Invalid_remote_signer s -> Some s | _ -> None)
|
||||||
(fun s -> Invalid_remote_signer s)
|
(fun s -> Invalid_remote_signer s)
|
||||||
@ -140,6 +162,7 @@ let parse_base_uri s =
|
|||||||
try
|
try
|
||||||
let uri = Uri.of_string s in
|
let uri = Uri.of_string s in
|
||||||
match Uri.scheme uri with
|
match Uri.scheme uri with
|
||||||
|
| Some "http" -> return uri
|
||||||
| Some "https" -> return uri
|
| Some "https" -> return uri
|
||||||
| Some "tcp" -> return uri
|
| Some "tcp" -> return uri
|
||||||
| Some "unix" -> return uri
|
| Some "unix" -> return uri
|
||||||
|
@ -10,6 +10,7 @@
|
|||||||
module Make(S : sig
|
module Make(S : sig
|
||||||
val default : Uri.t
|
val default : Uri.t
|
||||||
val authenticate: Signature.Public_key_hash.t list -> MBytes.t -> Signature.t tzresult Lwt.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
|
end) : Client_keys.SIGNER
|
||||||
|
|
||||||
val make_pk: Signature.public_key -> Client_keys.pk_uri
|
val make_pk: Signature.public_key -> Client_keys.pk_uri
|
||||||
|
@ -23,14 +23,14 @@ let sign =
|
|||||||
~query
|
~query
|
||||||
~input: Data_encoding.bytes
|
~input: Data_encoding.bytes
|
||||||
~output: Data_encoding.(obj1 (req "signature" Signature.encoding))
|
~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 =
|
let public_key =
|
||||||
RPC_service.get_service
|
RPC_service.get_service
|
||||||
~description: "Retrieve the public key of a given remote key"
|
~description: "Retrieve the public key of a given remote key"
|
||||||
~query: RPC_query.empty
|
~query: RPC_query.empty
|
||||||
~output: Data_encoding.(obj1 (req "public_key" Signature.Public_key.encoding))
|
~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 =
|
let authorized_keys =
|
||||||
RPC_service.get_service
|
RPC_service.get_service
|
||||||
|
Loading…
Reference in New Issue
Block a user