forked from gnolang/gno
-
Notifications
You must be signed in to change notification settings - Fork 0
/
secrets_init.go
209 lines (171 loc) · 5.7 KB
/
secrets_init.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
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
package main
import (
"context"
"errors"
"flag"
"fmt"
"os"
"path/filepath"
"github.com/gnolang/gno/tm2/pkg/bft/privval"
"github.com/gnolang/gno/tm2/pkg/commands"
"github.com/gnolang/gno/tm2/pkg/crypto/ed25519"
osm "github.com/gnolang/gno/tm2/pkg/os"
"github.com/gnolang/gno/tm2/pkg/p2p"
)
var errOverwriteNotEnabled = errors.New("overwrite not enabled")
type secretsInitCfg struct {
commonAllCfg
forceOverwrite bool
}
// newSecretsInitCmd creates the secrets init command
func newSecretsInitCmd(io commands.IO) *commands.Command {
cfg := &secretsInitCfg{}
return commands.NewCommand(
commands.Metadata{
Name: "init",
ShortUsage: "secrets init [flags] [<key>]",
ShortHelp: "initializes required Gno secrets in a common directory",
LongHelp: fmt.Sprintf(
"initializes the validator private key, the node p2p key and the validator's last sign state. "+
"If a key is provided, it initializes the specified key. Available keys: %s",
getAvailableSecretsKeys(),
),
},
cfg,
func(_ context.Context, args []string) error {
return execSecretsInit(cfg, args, io)
},
)
}
func (c *secretsInitCfg) RegisterFlags(fs *flag.FlagSet) {
c.commonAllCfg.RegisterFlags(fs)
fs.BoolVar(
&c.forceOverwrite,
"force",
false,
"overwrite existing secrets, if any",
)
}
func execSecretsInit(cfg *secretsInitCfg, args []string, io commands.IO) error {
// Check the data output directory path
if cfg.dataDir == "" {
return errInvalidDataDir
}
// Verify the secrets key
if err := verifySecretsKey(args); err != nil {
return err
}
var key string
if len(args) > 0 {
key = args[0]
}
// Make sure the directory is there
if err := os.MkdirAll(cfg.dataDir, 0o755); err != nil {
return fmt.Errorf("unable to create secrets dir, %w", err)
}
// Construct the paths
var (
validatorKeyPath = filepath.Join(cfg.dataDir, defaultValidatorKeyName)
validatorStatePath = filepath.Join(cfg.dataDir, defaultValidatorStateName)
nodeKeyPath = filepath.Join(cfg.dataDir, defaultNodeKeyName)
)
switch key {
case validatorPrivateKeyKey:
if osm.FileExists(validatorKeyPath) && !cfg.forceOverwrite {
return fmt.Errorf("unable to overwrite validator key, %w", errOverwriteNotEnabled)
}
// Initialize and save the validator's private key
return initAndSaveValidatorKey(validatorKeyPath, io)
case nodeIDKey:
if osm.FileExists(nodeKeyPath) && !cfg.forceOverwrite {
return fmt.Errorf("unable to overwrite the node' p2p key, %w", errOverwriteNotEnabled)
}
// Initialize and save the node's p2p key
return initAndSaveNodeKey(nodeKeyPath, io)
case validatorStateKey:
if osm.FileExists(validatorStatePath) && !cfg.forceOverwrite {
return fmt.Errorf("unable to overwrite validator last sign state, %w", errOverwriteNotEnabled)
}
// Initialize and save the validator's last sign state
return initAndSaveValidatorState(validatorStatePath, io)
default:
// No key provided, initialize everything
return errors.Join(
overwriteGuard(validatorKeyPath, initAndSaveValidatorKey, cfg.forceOverwrite, io),
overwriteGuard(validatorStatePath, initAndSaveValidatorState, cfg.forceOverwrite, io),
overwriteGuard(nodeKeyPath, initAndSaveNodeKey, cfg.forceOverwrite, io),
)
}
}
// overwriteGuard guards against unwanted secret overwrites,
// and executes the secret initialization if the secret is not present
func overwriteGuard(
path string,
initFn func(string, commands.IO) error,
overwriteEnabled bool,
io commands.IO,
) error {
// Check if the secret already exists
if osm.FileExists(path) && !overwriteEnabled {
return fmt.Errorf(
"unable to overwrite secret at %q, %w",
path,
errOverwriteNotEnabled,
)
}
// Secret doesn't exist, initialize it
return initFn(path, io)
}
// initAndSaveValidatorKey generates a validator private key and saves it to the given path
func initAndSaveValidatorKey(path string, io commands.IO) error {
// Initialize the validator's private key
privateKey := generateValidatorPrivateKey()
// Save the key
if err := saveSecretData(privateKey, path); err != nil {
return fmt.Errorf("unable to save validator key, %w", err)
}
io.Printfln("Validator private key saved at %s", path)
return nil
}
// initAndSaveValidatorState generates an empty last validator sign state and saves it to the given path
func initAndSaveValidatorState(path string, io commands.IO) error {
// Initialize the validator's last sign state
validatorState := generateLastSignValidatorState()
// Save the last sign state
if err := saveSecretData(validatorState, path); err != nil {
return fmt.Errorf("unable to save last validator sign state, %w", err)
}
io.Printfln("Validator last sign state saved at %s", path)
return nil
}
// initAndSaveNodeKey generates a node p2p key and saves it to the given path
func initAndSaveNodeKey(path string, io commands.IO) error {
// Initialize the node's p2p key
nodeKey := generateNodeKey()
// Save the node key
if err := saveSecretData(nodeKey, path); err != nil {
return fmt.Errorf("unable to save node p2p key, %w", err)
}
io.Printfln("Node key saved at %s", path)
return nil
}
// generateValidatorPrivateKey generates the validator's private key
func generateValidatorPrivateKey() *privval.FilePVKey {
privKey := ed25519.GenPrivKey()
return &privval.FilePVKey{
Address: privKey.PubKey().Address(),
PubKey: privKey.PubKey(),
PrivKey: privKey,
}
}
// generateLastSignValidatorState generates the empty last sign state
func generateLastSignValidatorState() *privval.FilePVLastSignState {
return &privval.FilePVLastSignState{} // Empty last sign state
}
// generateNodeKey generates the p2p node key
func generateNodeKey() *p2p.NodeKey {
privKey := ed25519.GenPrivKey()
return &p2p.NodeKey{
PrivKey: privKey,
}
}