starter.go 3.6 KB
Newer Older
1
2
3
package sign

import (
Caro Axel's avatar
Caro Axel committed
4
5
	"crypto/rsa"
	"crypto/x509"
6
7
8
	"errors"
	"fmt"
	"strconv"
Loïck Bonniot's avatar
Loïck Bonniot committed
9
	"time"
10

Caro Axel's avatar
Caro Axel committed
11
12
	"dfss"
	cAPI "dfss/dfssc/api"
13
	"dfss/dfssc/security"
Caro Axel's avatar
Caro Axel committed
14
	pAPI "dfss/dfssp/api"
15
16
17
	"dfss/dfssp/contract"
	"dfss/net"
	"golang.org/x/net/context"
Caro Axel's avatar
Caro Axel committed
18
	"google.golang.org/grpc"
19
20
21
22
23
24
25
)

// SignatureManager handles the signature of a contract.
type SignatureManager struct {
	auth      *security.AuthContainer
	localPort int
	contract  *contract.JSON
Caro Axel's avatar
Caro Axel committed
26
27
28
29
30
	platform  pAPI.PlatformClient
	peers     map[string]*cAPI.ClientClient
	cServer   *grpc.Server
	cert, ca  *x509.Certificate
	key       *rsa.PrivateKey
31
32
33
34
35
36
37
38
39
}

// NewSignatureManager populates a SignatureManager and connects to the platform.
func NewSignatureManager(fileCA, fileCert, fileKey, addrPort, passphrase string, port int, c *contract.JSON) (*SignatureManager, error) {
	m := &SignatureManager{
		auth:      security.NewAuthContainer(fileCA, fileCert, fileKey, addrPort, passphrase),
		localPort: port,
		contract:  c,
	}
Caro Axel's avatar
Caro Axel committed
40
41
	var err error
	m.ca, m.cert, m.key, err = m.auth.LoadFiles()
42
43
44
45
	if err != nil {
		return nil, err
	}

Caro Axel's avatar
Caro Axel committed
46
47
48
49
	m.cServer = m.GetServer()
	go func() { _ = net.Listen("0.0.0.0:"+strconv.Itoa(port), m.cServer) }()

	conn, err := net.Connect(m.auth.AddrPort, m.cert, m.key, m.ca)
50
51
52
53
	if err != nil {
		return nil, err
	}

Caro Axel's avatar
Caro Axel committed
54
	m.platform = pAPI.NewPlatformClient(conn)
55

Caro Axel's avatar
Caro Axel committed
56
	m.peers = make(map[string]*cAPI.ClientClient)
57
58
59
60
61
62
63
64
65
	for _, u := range c.Signers {
		m.peers[u.Email] = nil
	}

	return m, nil
}

// ConnectToPeers tries to fetch the list of users for this contract, and tries to establish a connection to each peer.
func (m *SignatureManager) ConnectToPeers() error {
Caro Axel's avatar
Caro Axel committed
66
	stream, err := m.platform.JoinSignature(context.Background(), &pAPI.JoinSignatureRequest{
67
68
69
70
71
72
73
74
75
76
77
78
79
		ContractUuid: m.contract.UUID,
		Port:         uint32(m.localPort),
	})
	if err != nil {
		return err
	}

	for {
		userConnected, err := stream.Recv()
		if err != nil {
			return err
		}
		errorCode := userConnected.GetErrorCode()
Caro Axel's avatar
Caro Axel committed
80
		if errorCode.Code != pAPI.ErrorCode_SUCCESS {
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
			return errors.New(errorCode.Message)
		}
		ready, err := m.addPeer(userConnected.User)
		if err != nil {
			return err
		}
		if ready {
			break
		}
	}

	return nil
}

// addPeer stores a peer from the platform and tries to establish a connection to this peer.
Caro Axel's avatar
Caro Axel committed
96
func (m *SignatureManager) addPeer(user *pAPI.User) (ready bool, err error) {
97
98
99
100
101
	if user == nil {
		err = errors.New("unexpected user format")
		return
	}

Caro Axel's avatar
Caro Axel committed
102
103
	addrPort := user.Ip + ":" + strconv.Itoa(int(user.Port))
	fmt.Println("Trying to connect with", user.Email, "/", addrPort)
104

Caro Axel's avatar
Caro Axel committed
105
106
107
108
109
110
111
112
113
114
115
116
117
118
	conn, err := net.Connect(addrPort, m.cert, m.key, m.ca)
	if err != nil {
		return false, err
	}

	// Sending Hello message
	client := cAPI.NewClientClient(conn)
	m.peers[user.Email] = &client
	msg, err := client.Discover(context.Background(), &cAPI.Hello{Version: dfss.Version})
	if err != nil {
		return false, err
	}
	// Printing answer: application version
	fmt.Println("Recieved:", msg.Version)
119
120
121
122

	// Check if we have any other peer to connect to
	for _, u := range m.peers {
		if u == nil {
Caro Axel's avatar
Caro Axel committed
123
			return false, nil
124
125
126
		}
	}

Caro Axel's avatar
Caro Axel committed
127
	return true, nil
128
}
Loïck Bonniot's avatar
Loïck Bonniot committed
129
130
131
132
133

// SendReadySign sends the READY signal to the platform, and wait (potentially a long time) for START signal.
func (m *SignatureManager) SendReadySign() (signatureUUID string, err error) {
	ctx, cancel := context.WithTimeout(context.Background(), 10 * time.Minute)
	defer cancel()
Loïck Bonniot's avatar
Loïck Bonniot committed
134
	launch, err := m.platform.ReadySign(ctx, &pAPI.ReadySignRequest{
Loïck Bonniot's avatar
Loïck Bonniot committed
135
136
137
138
139
140
141
		ContractUuid: m.contract.UUID,
	})
	if err != nil {
		return
	}

	errorCode := launch.GetErrorCode()
Loïck Bonniot's avatar
Loïck Bonniot committed
142
	if errorCode.Code != pAPI.ErrorCode_SUCCESS {
Loïck Bonniot's avatar
Loïck Bonniot committed
143
144
145
146
147
148
149
		err = errors.New(errorCode.Code.String() + " " + errorCode.Message)
		return
	}

	signatureUUID = launch.SignatureUuid
	return
}