/
contact.go
137 lines (115 loc) · 3.87 KB
/
contact.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
// Copyright (c) 2019 Laszlo Sari
//
// FileTribe is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// FileTribe is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
//
package common
import (
"bytes"
"context"
ethcommon "github.com/ethereum/go-ethereum/common"
"net"
"strings"
ethcrypto "github.com/ethereum/go-ethereum/crypto"
"github.com/golang/glog"
ma "github.com/multiformats/go-multiaddr"
"github.com/pkg/errors"
"github.com/aliras1/FileTribe/ipfs"
"github.com/aliras1/FileTribe/tribecrypto"
)
const (
// P2PProtocolName will be used by libp2p streams
P2PProtocolName = "ipfsShareP2P"
)
// Contact stores necessary information for P2P communication with a user
type Contact struct {
AccountAddress ethcommon.Address
EthAccountAddress ethcommon.Address
Name string
IpfsPeerID string
Boxer tribecrypto.AnonymPublicKey
conn *P2PConn
ipfs ipfs.IIpfs
}
// NewContact creates a new contact
func NewContact(
address ethcommon.Address,
accAddr ethcommon.Address,
name string,
ipfsPeerID string,
boxer tribecrypto.AnonymPublicKey,
ipfs ipfs.IIpfs) *Contact {
return &Contact{
AccountAddress: accAddr,
EthAccountAddress: address,
Name: name,
IpfsPeerID: ipfsPeerID,
Boxer: boxer,
ipfs: ipfs,
}
}
// Send sends a message to the given contact
func (contact *Contact) Send(data []byte) error {
if contact.conn == nil {
conn, err := contact.dialP2PConn(contact.ipfs)
if err != nil {
return errors.Wrap(err, "could not dial P2P connection")
}
contact.conn = conn
}
glog.Infof("sending P2P msg from %s to %s", contact.conn.RemoteAddr().String(), contact.conn.LocalAddr().String())
if _, err := contact.conn.Write(data); err != nil {
return errors.Wrap(err, "could not send data")
}
return nil
}
// VerifySignature verifies a signature if it really was made by the user
// this contact is representing
func (contact *Contact) VerifySignature(digest, signature []byte) bool {
pk, err := ethcrypto.SigToPub(digest, signature)
if err != nil {
glog.Warningf("could not get pk from sig: %s", err)
return false
}
otherAddress := ethcrypto.PubkeyToAddress(*pk)
return bytes.Equal(contact.EthAccountAddress.Bytes(), otherAddress.Bytes())
}
func (contact *Contact) dialP2PConn(ipfs ipfs.IIpfs) (*P2PConn, error) {
id, _ := ipfs.ID()
glog.Infof("user with ipfs %s is P2P dialing to %s", id.ID, contact.IpfsPeerID)
if contact.conn != nil {
return contact.conn, nil
}
stream, err := ipfs.P2PStreamDial(context.Background(), contact.IpfsPeerID, P2PProtocolName, "")
if err != nil {
return nil, errors.Wrapf(err, "could not dial to stream %s", contact.IpfsPeerID)
}
multiAddress := ma.StringCast(stream.Address)
var protocolValues []string
for _, protocol := range multiAddress.Protocols() {
value, _ := multiAddress.ValueForProtocol(protocol.Code)
protocolValues = append(protocolValues, value)
}
hostAddress := strings.Join(protocolValues, ":")
tcpAddr, err := net.ResolveTCPAddr("tcp", hostAddress)
conn, err := net.DialTCP("tcp", nil, tcpAddr)
if err != nil {
println("Dial failed:", err.Error())
return nil, errors.Wrap(err, "could not dial to tcp server")
}
if err := conn.SetKeepAlive(true); err != nil {
return nil, errors.Wrapf(err, "could not set keep alive to true")
}
contact.conn = (*P2PConn)(conn)
return contact.conn, nil
}