98 lines
2.5 KiB
Go
98 lines
2.5 KiB
Go
package service
|
|
|
|
import (
|
|
"bytes"
|
|
"context"
|
|
"encoding/json"
|
|
"fmt"
|
|
"net/http"
|
|
"strconv"
|
|
|
|
"github.com/cortezaproject/corteza-server/federation/types"
|
|
)
|
|
|
|
type (
|
|
// HttpHandshake performs HTTP handshake with remote node
|
|
httpNodeHandshake struct {
|
|
httpClient httpNodeHandshaker
|
|
}
|
|
|
|
httpNodeHandshaker interface {
|
|
Do(*http.Request) (*http.Response, error)
|
|
}
|
|
)
|
|
|
|
func HttpHandshake(client httpNodeHandshaker) *httpNodeHandshake {
|
|
return &httpNodeHandshake{httpClient: client}
|
|
}
|
|
|
|
// Init calls handshake init on a remote node via HTTP
|
|
//
|
|
// Called from node.Pair() and sends POST request to remote Corteza
|
|
// There, it is handled with node.HandshakeInit
|
|
//
|
|
// Fn is not part of the node struct to allow injection
|
|
func (h httpNodeHandshake) Init(ctx context.Context, n *types.Node, authToken string) error {
|
|
var (
|
|
endpoint = fmt.Sprintf("%s/nodes/%d/handshake", n.BaseURL, n.SharedNodeID)
|
|
payload = map[string]string{
|
|
// Share pairing token, so we can authenticate ourselves
|
|
"pairToken": n.PairToken,
|
|
|
|
// Share auth token for the federation service user for this node
|
|
"authToken": authToken,
|
|
"sharedNodeID": strconv.FormatUint(n.SharedNodeID, 10),
|
|
}
|
|
)
|
|
|
|
return h.send(ctx, endpoint, payload)
|
|
}
|
|
|
|
// Confirm calls handshake init on a remote node via HTTP
|
|
//
|
|
// Called from node.Confirm and sends POST request to remote Corteza
|
|
// There, it's handled with node.HandshakeComplete
|
|
func (h httpNodeHandshake) Complete(ctx context.Context, n *types.Node, authToken string) error {
|
|
var (
|
|
endpoint = fmt.Sprintf("%s/nodes/%d/handshake-complete", n.BaseURL, n.SharedNodeID)
|
|
payload = map[string]string{
|
|
// Share auth token for the federation service user for this node
|
|
"authToken": authToken,
|
|
}
|
|
)
|
|
|
|
// use n.AuthToken in context
|
|
ctx = context.WithValue(ctx, "authToken", n.AuthToken)
|
|
|
|
return h.send(ctx, endpoint, payload)
|
|
}
|
|
|
|
func (h httpNodeHandshake) send(ctx context.Context, endpoint string, payload map[string]string) error {
|
|
body := bytes.NewBuffer(nil)
|
|
if err := json.NewEncoder(body).Encode(payload); err != nil {
|
|
return err
|
|
}
|
|
|
|
req, err := http.NewRequest(http.MethodPost, endpoint, body)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
req.Header.Set("Content-Type", "application/json")
|
|
|
|
if authToken := ctx.Value("authToken"); authToken != nil {
|
|
req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", authToken))
|
|
}
|
|
|
|
rsp, err := h.httpClient.Do(req.WithContext(ctx))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if rsp.StatusCode != http.StatusOK {
|
|
return fmt.Errorf("pairing failed, remote host retuned non-200 response")
|
|
}
|
|
|
|
return nil
|
|
}
|