diff --git a/internal_test.go b/internal_test.go index 12b8ad01..e5eefd05 100644 --- a/internal_test.go +++ b/internal_test.go @@ -51,7 +51,7 @@ func TestJsonRpcSend(t *testing.T) { password := "something" server := "invalid" var message []byte - _, err := jsonRpcSend(user, password, server, message) + _, err := jsonRpcSend(user, password, server, message, false, nil, false) if err == nil { t.Errorf("Should fail when it cannot connect.") } diff --git a/jsonapi.go b/jsonapi.go index 13e6e889..9ecd5b01 100644 --- a/jsonapi.go +++ b/jsonapi.go @@ -872,16 +872,32 @@ func JSONGetMethod(message []byte) (string, error) { return method, err } +// TlsRpcCommand takes a message generated from one of the routines above +// along with the login/server information and any relavent PEM encoded +// certificates chains. It sends the command via https and returns a go struct +// with the result. +func TlsRpcCommand(user string, password string, server string, message []byte, + certificates []byte, skipverify bool) (Reply, error) { + return rpcCommand(user, password, server, message, true, certificates, + skipverify) +} + // RpcCommand takes a message generated from one of the routines above // along with the login/server info, sends it, and gets a reply, returning // a go struct with the result. func RpcCommand(user string, password string, server string, message []byte) (Reply, error) { + return rpcCommand(user, password, server, message, false, nil, false) +} + +func rpcCommand(user string, password string, server string, message []byte, + https bool, certificates []byte, skipverify bool) (Reply, error) { var result Reply method, err := JSONGetMethod(message) if err != nil { return result, err } - body, err := RpcRawCommand(user, password, server, message) + body, err := rpcRawCommand(user, password, server, message, https, + certificates, skipverify) if err != nil { err := fmt.Errorf("Error getting json reply: %v", err) return result, err @@ -894,10 +910,26 @@ func RpcCommand(user string, password string, server string, message []byte) (Re return result, err } +// TlsRpcRawCommand takes a message generated from one of the routines above +// along with the login,server info and PEM encoded certificate chains for the +// server sends it, and gets a reply, returning +// the raw []byte response for use with ReadResultCmd. +func TlsRpcRawCommand(user string, password string, server string, + message []byte, certificates []byte, skipverify bool) ([]byte, error) { + return rpcRawCommand(user, password, server, message, true, + certificates, skipverify) +} + // RpcRawCommand takes a message generated from one of the routines above // along with the login/server info, sends it, and gets a reply, returning // the raw []byte response for use with ReadResultCmd. func RpcRawCommand(user string, password string, server string, message []byte) ([]byte, error) { + return rpcRawCommand(user, password, server, message, false, nil, false) +} + +// rpcRawCommand is a helper function for the above two functions. +func rpcRawCommand(user string, password string, server string, + message []byte, https bool, certificates []byte, skipverify bool) ([]byte, error) { var result []byte var msg interface{} err := json.Unmarshal(message, &msg) @@ -905,7 +937,8 @@ func RpcRawCommand(user string, password string, server string, message []byte) err := fmt.Errorf("Error, message does not appear to be valid json: %v", err) return result, err } - resp, err := jsonRpcSend(user, password, server, message) + resp, err := jsonRpcSend(user, password, server, message, https, + certificates, skipverify) if err != nil { err := fmt.Errorf("Error sending json message: " + err.Error()) return result, err diff --git a/jsonfxns.go b/jsonfxns.go index cc323879..f4479cf8 100644 --- a/jsonfxns.go +++ b/jsonfxns.go @@ -6,6 +6,9 @@ package btcjson import ( "bytes" + _ "crypto/sha512" + "crypto/tls" + "crypto/x509" "encoding/json" "fmt" "io" @@ -32,9 +35,24 @@ func MarshallAndSend(rawReply Reply, w io.Writer) (string, error) { // and ip/port and then send the supplied message. This uses net/http rather // than net/rpc/jsonrpc since that one doesn't support http connections and is // therefore useless. -func jsonRpcSend(user string, password string, server string, message []byte) (*http.Response, error) { +func jsonRpcSend(user string, password string, server string, message []byte, + https bool, certificates []byte, skipverify bool) (*http.Response, error) { + client := &http.Client{} + protocol := "http" + if https { + pool := x509.NewCertPool() + pool.AppendCertsFromPEM(certificates) + + config := &tls.Config{ + InsecureSkipVerify: skipverify, + RootCAs: pool, + } + transport := &http.Transport{TLSClientConfig: config} + client.Transport = transport + protocol = "https" + } credentials := user + ":" + password - resp, err := http.Post("http://"+credentials+"@"+server, + resp, err := client.Post(protocol+"://"+credentials+"@"+server, "application/json", bytes.NewBuffer(message)) if err != nil { // We do not want to log the username/password in the errors.