forked from ipfs-cluster/ipfs-cluster
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathidentity.go
193 lines (163 loc) · 4.34 KB
/
identity.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
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
package config
import (
"encoding/base64"
"encoding/json"
"errors"
"fmt"
"io/ioutil"
crypto "github.com/libp2p/go-libp2p-core/crypto"
peer "github.com/libp2p/go-libp2p-core/peer"
"github.com/kelseyhightower/envconfig"
)
const configKey = "cluster"
// Identity defaults
const (
DefaultConfigCrypto = crypto.Ed25519
DefaultConfigKeyLength = -1
)
// Identity represents identity of a cluster peer for communication,
// including the Consensus component.
type Identity struct {
ID peer.ID
PrivateKey crypto.PrivKey
}
// identityJSON represents a Cluster peer identity as it will look when it is
// saved using JSON.
type identityJSON struct {
ID string `json:"id"`
PrivateKey string `json:"private_key"`
}
// NewIdentity returns a new random identity.
func NewIdentity() (*Identity, error) {
ident := &Identity{}
err := ident.Default()
return ident, err
}
// Default generates a random keypair for this identity.
func (ident *Identity) Default() error {
// pid and private key generation
priv, pub, err := crypto.GenerateKeyPair(
DefaultConfigCrypto,
DefaultConfigKeyLength,
)
if err != nil {
return err
}
pid, err := peer.IDFromPublicKey(pub)
if err != nil {
return err
}
ident.ID = pid
ident.PrivateKey = priv
return nil
}
// ConfigKey returns a human-readable string to identify
// a cluster Identity.
func (ident *Identity) ConfigKey() string {
return configKey
}
// SaveJSON saves the JSON representation of the Identity to
// the given path.
func (ident *Identity) SaveJSON(path string) error {
logger.Info("Saving identity")
bs, err := ident.ToJSON()
if err != nil {
return err
}
return ioutil.WriteFile(path, bs, 0600)
}
// ToJSON generates a human-friendly version of Identity.
func (ident *Identity) ToJSON() (raw []byte, err error) {
jID, err := ident.toIdentityJSON()
if err != nil {
return
}
raw, err = json.MarshalIndent(jID, "", " ")
return
}
func (ident *Identity) toIdentityJSON() (jID *identityJSON, err error) {
jID = &identityJSON{}
// Private Key
pkeyBytes, err := crypto.MarshalPrivateKey(ident.PrivateKey)
if err != nil {
return
}
pKey := base64.StdEncoding.EncodeToString(pkeyBytes)
// Set all identity fields
jID.ID = ident.ID.Pretty()
jID.PrivateKey = pKey
return
}
// LoadJSON receives a raw json-formatted identity and
// sets the Config fields from it. Note that it should be JSON
// as generated by ToJSON().
func (ident *Identity) LoadJSON(raw []byte) error {
jID := &identityJSON{}
err := json.Unmarshal(raw, jID)
if err != nil {
logger.Error("Error unmarshaling cluster config")
return err
}
return ident.applyIdentityJSON(jID)
}
func (ident *Identity) applyIdentityJSON(jID *identityJSON) error {
pid, err := peer.Decode(jID.ID)
if err != nil {
err = fmt.Errorf("error decoding cluster ID: %s", err)
return err
}
ident.ID = pid
pkb, err := base64.StdEncoding.DecodeString(jID.PrivateKey)
if err != nil {
err = fmt.Errorf("error decoding private_key: %s", err)
return err
}
pKey, err := crypto.UnmarshalPrivateKey(pkb)
if err != nil {
err = fmt.Errorf("error parsing private_key ID: %s", err)
return err
}
ident.PrivateKey = pKey
return ident.Validate()
}
// Validate will check that the values of this identity
// seem to be working ones.
func (ident *Identity) Validate() error {
if ident.ID == "" {
return errors.New("identity ID not set")
}
if ident.PrivateKey == nil {
return errors.New("no identity private_key set")
}
if !ident.ID.MatchesPrivateKey(ident.PrivateKey) {
return errors.New("identity ID does not match the private_key")
}
return nil
}
// LoadJSONFromFile reads an Identity file from disk and parses
// it and return Identity.
func (ident *Identity) LoadJSONFromFile(path string) error {
file, err := ioutil.ReadFile(path)
if err != nil {
logger.Error("error reading the configuration file: ", err)
return err
}
return ident.LoadJSON(file)
}
// ApplyEnvVars fills in any Config fields found
// as environment variables.
func (ident *Identity) ApplyEnvVars() error {
jID, err := ident.toIdentityJSON()
if err != nil {
return err
}
err = envconfig.Process(ident.ConfigKey(), jID)
if err != nil {
return err
}
return ident.applyIdentityJSON(jID)
}
// Equals returns true if equal to provided identity.
func (ident *Identity) Equals(i *Identity) bool {
return ident.ID == i.ID && ident.PrivateKey.Equals(i.PrivateKey)
}