add TlsRpcCommand and TlsRawRpcCommand.

These act the same as the !tls versions of this code but they take a PEM
encoded certificate chain to be used to verify certificates (ca verified
certs could use /etc/ssl/certs.pem) and a parameter to skip cert
verification and will use https internally.
This commit is contained in:
Owain G. Ainsworth 2013-11-19 00:09:56 +00:00
parent 606262514b
commit e43c79c74d
3 changed files with 56 additions and 5 deletions

View file

@ -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.")
}

View file

@ -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

View file

@ -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.