-
Notifications
You must be signed in to change notification settings - Fork 212
/
identity.go
92 lines (83 loc) · 2.27 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
package p2p
import (
"crypto/rand"
"encoding/json"
"errors"
"fmt"
"io/fs"
"os"
"path/filepath"
"github.com/libp2p/go-libp2p/core/crypto"
"github.com/libp2p/go-libp2p/core/peer"
)
const keyFilename = "p2p.key"
type identityInfo struct {
Key []byte
ID peer.ID // this is needed only to simplify integration with some testing tools
}
func genIdentity() (crypto.PrivKey, error) {
pk, _, err := crypto.GenerateEd25519Key(rand.Reader)
if err != nil {
return nil, fmt.Errorf("generate ed25519 identity: %w", err)
}
return pk, nil
}
func identityInfoFromDir(dir string) (*identityInfo, error) {
path := filepath.Join(dir, keyFilename)
data, err := os.ReadFile(path)
if err != nil {
return nil, fmt.Errorf("read file %s: %w", path, err)
}
var info identityInfo
err = json.Unmarshal(data, &info)
if err != nil {
return nil, fmt.Errorf("unmarshal file content from %s into %+v: %w", path, info, err)
}
return &info, nil
}
// IdentityInfoFromDir returns a printable ID from a given identity directory.
func IdentityInfoFromDir(dir string) (string, error) {
identityInfo, err := identityInfoFromDir(dir)
return identityInfo.ID.String(), err
}
// EnsureIdentity generates an identity key file in given directory.
func EnsureIdentity(dir string) (crypto.PrivKey, error) {
// TODO add crc check
if err := os.MkdirAll(dir, 0o700); err != nil {
return nil, fmt.Errorf("ensure that directory %s exist: %w", dir, err)
}
info, err := identityInfoFromDir(dir)
switch {
case errors.Is(err, fs.ErrNotExist):
key, err := genIdentity()
if err != nil {
return nil, err
}
id, err := peer.IDFromPrivateKey(key)
if err != nil {
panic("generated key is malformed")
}
raw, err := crypto.MarshalPrivateKey(key)
if err != nil {
panic("generated key can't be marshaled to bytes")
}
data, err := json.Marshal(identityInfo{
Key: raw,
ID: id,
})
if err != nil {
return nil, err
}
if err := os.WriteFile(filepath.Join(dir, keyFilename), data, 0o600); err != nil {
return nil, fmt.Errorf("write identity data: %w", err)
}
return key, nil
case err != nil:
return nil, fmt.Errorf("read key from disk: %w", err)
}
pk, err := crypto.UnmarshalPrivateKey(info.Key)
if err != nil {
return nil, fmt.Errorf("unmarshal privkey: %w", err)
}
return pk, nil
}