mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-08-20 10:52:25 +00:00
cmd/clef, signer: support removing stored keys (delpw + rules)
This commit is contained in:
parent
793db11483
commit
31c2781d49
4 changed files with 82 additions and 12 deletions
|
|
@ -93,7 +93,7 @@ var (
|
||||||
chainIdFlag = cli.Int64Flag{
|
chainIdFlag = cli.Int64Flag{
|
||||||
Name: "chainid",
|
Name: "chainid",
|
||||||
Value: params.MainnetChainConfig.ChainID.Int64(),
|
Value: params.MainnetChainConfig.ChainID.Int64(),
|
||||||
Usage: "Chain id to use for signing (1=mainnet, 3=ropsten, 4=rinkeby, 5=Goerli)",
|
Usage: "Chain id to use for signing (1=mainnet, 3=Ropsten, 4=Rinkeby, 5=Goerli)",
|
||||||
}
|
}
|
||||||
rpcPortFlag = cli.IntFlag{
|
rpcPortFlag = cli.IntFlag{
|
||||||
Name: "rpcport",
|
Name: "rpcport",
|
||||||
|
|
@ -116,8 +116,7 @@ var (
|
||||||
}
|
}
|
||||||
ruleFlag = cli.StringFlag{
|
ruleFlag = cli.StringFlag{
|
||||||
Name: "rules",
|
Name: "rules",
|
||||||
Usage: "Enable rule-engine",
|
Usage: "Path to the rule file to auto-authorize requests with",
|
||||||
Value: "",
|
|
||||||
}
|
}
|
||||||
stdiouiFlag = cli.BoolFlag{
|
stdiouiFlag = cli.BoolFlag{
|
||||||
Name: "stdio-ui",
|
Name: "stdio-ui",
|
||||||
|
|
@ -160,7 +159,6 @@ incoming requests.
|
||||||
Whenever you make an edit to the rule file, you need to use attestation to tell
|
Whenever you make an edit to the rule file, you need to use attestation to tell
|
||||||
Clef that the file is 'safe' to execute.`,
|
Clef that the file is 'safe' to execute.`,
|
||||||
}
|
}
|
||||||
|
|
||||||
setCredentialCommand = cli.Command{
|
setCredentialCommand = cli.Command{
|
||||||
Action: utils.MigrateFlags(setCredential),
|
Action: utils.MigrateFlags(setCredential),
|
||||||
Name: "setpw",
|
Name: "setpw",
|
||||||
|
|
@ -173,6 +171,19 @@ Clef that the file is 'safe' to execute.`,
|
||||||
},
|
},
|
||||||
Description: `
|
Description: `
|
||||||
The setpw command stores a password for a given address (keyfile).
|
The setpw command stores a password for a given address (keyfile).
|
||||||
|
`}
|
||||||
|
delCredentialCommand = cli.Command{
|
||||||
|
Action: utils.MigrateFlags(removeCredential),
|
||||||
|
Name: "delpw",
|
||||||
|
Usage: "Remove a credential for a keystore file",
|
||||||
|
ArgsUsage: "<address>",
|
||||||
|
Flags: []cli.Flag{
|
||||||
|
logLevelFlag,
|
||||||
|
configdirFlag,
|
||||||
|
signerSecretFlag,
|
||||||
|
},
|
||||||
|
Description: `
|
||||||
|
The delpw command removes a password for a given address (keyfile).
|
||||||
`}
|
`}
|
||||||
gendocCommand = cli.Command{
|
gendocCommand = cli.Command{
|
||||||
Action: GenDoc,
|
Action: GenDoc,
|
||||||
|
|
@ -209,9 +220,9 @@ func init() {
|
||||||
advancedMode,
|
advancedMode,
|
||||||
}
|
}
|
||||||
app.Action = signer
|
app.Action = signer
|
||||||
app.Commands = []cli.Command{initCommand, attestCommand, setCredentialCommand, gendocCommand}
|
app.Commands = []cli.Command{initCommand, attestCommand, setCredentialCommand, delCredentialCommand, gendocCommand}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
if err := app.Run(os.Args); err != nil {
|
if err := app.Run(os.Args); err != nil {
|
||||||
fmt.Fprintln(os.Stderr, err)
|
fmt.Fprintln(os.Stderr, err)
|
||||||
|
|
@ -317,7 +328,6 @@ func setCredential(ctx *cli.Context) error {
|
||||||
if err := initialize(ctx); err != nil {
|
if err := initialize(ctx); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
addr := ctx.Args().First()
|
addr := ctx.Args().First()
|
||||||
if !common.IsHexAddress(addr) {
|
if !common.IsHexAddress(addr) {
|
||||||
utils.Fatalf("Invalid address specified: %s", addr)
|
utils.Fatalf("Invalid address specified: %s", addr)
|
||||||
|
|
@ -334,10 +344,38 @@ func setCredential(ctx *cli.Context) error {
|
||||||
vaultLocation := filepath.Join(configDir, common.Bytes2Hex(crypto.Keccak256([]byte("vault"), stretchedKey)[:10]))
|
vaultLocation := filepath.Join(configDir, common.Bytes2Hex(crypto.Keccak256([]byte("vault"), stretchedKey)[:10]))
|
||||||
pwkey := crypto.Keccak256([]byte("credentials"), stretchedKey)
|
pwkey := crypto.Keccak256([]byte("credentials"), stretchedKey)
|
||||||
|
|
||||||
// Initialize the encrypted storages
|
|
||||||
pwStorage := storage.NewAESEncryptedStorage(filepath.Join(vaultLocation, "credentials.json"), pwkey)
|
pwStorage := storage.NewAESEncryptedStorage(filepath.Join(vaultLocation, "credentials.json"), pwkey)
|
||||||
pwStorage.Put(address.Hex(), password)
|
pwStorage.Put(address.Hex(), password)
|
||||||
log.Info("Credential store updated", "key", address)
|
|
||||||
|
log.Info("Credential store updated", "set", address)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func removeCredential(ctx *cli.Context) error {
|
||||||
|
if len(ctx.Args()) < 1 {
|
||||||
|
utils.Fatalf("This command requires an address to be passed as an argument")
|
||||||
|
}
|
||||||
|
if err := initialize(ctx); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
addr := ctx.Args().First()
|
||||||
|
if !common.IsHexAddress(addr) {
|
||||||
|
utils.Fatalf("Invalid address specified: %s", addr)
|
||||||
|
}
|
||||||
|
address := common.HexToAddress(addr)
|
||||||
|
|
||||||
|
stretchedKey, err := readMasterKey(ctx, nil)
|
||||||
|
if err != nil {
|
||||||
|
utils.Fatalf(err.Error())
|
||||||
|
}
|
||||||
|
configDir := ctx.GlobalString(configdirFlag.Name)
|
||||||
|
vaultLocation := filepath.Join(configDir, common.Bytes2Hex(crypto.Keccak256([]byte("vault"), stretchedKey)[:10]))
|
||||||
|
pwkey := crypto.Keccak256([]byte("credentials"), stretchedKey)
|
||||||
|
|
||||||
|
pwStorage := storage.NewAESEncryptedStorage(filepath.Join(vaultLocation, "credentials.json"), pwkey)
|
||||||
|
pwStorage.Del(address.Hex())
|
||||||
|
|
||||||
|
log.Info("Credential store updated", "unset", address)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -359,6 +397,10 @@ func initialize(c *cli.Context) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
func signer(c *cli.Context) error {
|
func signer(c *cli.Context) error {
|
||||||
|
// If we have some unrecognized command, bail out
|
||||||
|
if args := c.Args(); len(args) > 0 {
|
||||||
|
return fmt.Errorf("invalid command: %q", args[0])
|
||||||
|
}
|
||||||
if err := initialize(c); err != nil {
|
if err := initialize(c); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -83,7 +83,12 @@ func (r *rulesetUI) execute(jsfunc string, jsarg interface{}) (otto.Value, error
|
||||||
vm.Set("storage", struct{}{})
|
vm.Set("storage", struct{}{})
|
||||||
storageObj, _ := vm.Get("storage")
|
storageObj, _ := vm.Get("storage")
|
||||||
storageObj.Object().Set("put", func(call otto.FunctionCall) otto.Value {
|
storageObj.Object().Set("put", func(call otto.FunctionCall) otto.Value {
|
||||||
r.storage.Put(call.Argument(0).String(), call.Argument(1).String())
|
key, val := call.Argument(0).String(), call.Argument(1).String()
|
||||||
|
if val == "" {
|
||||||
|
r.storage.Del(key)
|
||||||
|
} else {
|
||||||
|
r.storage.Put(key, val)
|
||||||
|
}
|
||||||
return otto.NullValue()
|
return otto.NullValue()
|
||||||
})
|
})
|
||||||
storageObj.Object().Set("get", func(call otto.FunctionCall) otto.Value {
|
storageObj.Object().Set("get", func(call otto.FunctionCall) otto.Value {
|
||||||
|
|
|
||||||
|
|
@ -53,7 +53,7 @@ func NewAESEncryptedStorage(filename string, key []byte) *AESEncryptedStorage {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Put stores a value by key. 0-length keys results in no-op
|
// Put stores a value by key. 0-length keys results in noop.
|
||||||
func (s *AESEncryptedStorage) Put(key, value string) {
|
func (s *AESEncryptedStorage) Put(key, value string) {
|
||||||
if len(key) == 0 {
|
if len(key) == 0 {
|
||||||
return
|
return
|
||||||
|
|
@ -99,6 +99,19 @@ func (s *AESEncryptedStorage) Get(key string) (string, error) {
|
||||||
return string(entry), nil
|
return string(entry), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Del removes a key-value pair. If the key doesn't exist, the method is a noop.
|
||||||
|
func (s *AESEncryptedStorage) Del(key string) {
|
||||||
|
data, err := s.readEncryptedStorage()
|
||||||
|
if err != nil {
|
||||||
|
log.Warn("Failed to read encrypted storage", "err", err, "file", s.filename)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
delete(data, key)
|
||||||
|
if err = s.writeEncryptedStorage(data); err != nil {
|
||||||
|
log.Warn("Failed to write entry", "err", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// readEncryptedStorage reads the file with encrypted creds
|
// readEncryptedStorage reads the file with encrypted creds
|
||||||
func (s *AESEncryptedStorage) readEncryptedStorage() (map[string]storedCredential, error) {
|
func (s *AESEncryptedStorage) readEncryptedStorage() (map[string]storedCredential, error) {
|
||||||
creds := make(map[string]storedCredential)
|
creds := make(map[string]storedCredential)
|
||||||
|
|
|
||||||
|
|
@ -28,12 +28,15 @@ var (
|
||||||
)
|
)
|
||||||
|
|
||||||
type Storage interface {
|
type Storage interface {
|
||||||
// Put stores a value by key. 0-length keys results in no-op
|
// Put stores a value by key. 0-length keys results in noop.
|
||||||
Put(key, value string)
|
Put(key, value string)
|
||||||
|
|
||||||
// Get returns the previously stored value, or an error if the key is 0-length
|
// Get returns the previously stored value, or an error if the key is 0-length
|
||||||
// or unknown.
|
// or unknown.
|
||||||
Get(key string) (string, error)
|
Get(key string) (string, error)
|
||||||
|
|
||||||
|
// Del removes a key-value pair. If the key doesn't exist, the method is a noop.
|
||||||
|
Del(key string)
|
||||||
}
|
}
|
||||||
|
|
||||||
// EphemeralStorage is an in-memory storage that does
|
// EphemeralStorage is an in-memory storage that does
|
||||||
|
|
@ -43,6 +46,7 @@ type EphemeralStorage struct {
|
||||||
namespace string
|
namespace string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Put stores a value by key. 0-length keys results in noop.
|
||||||
func (s *EphemeralStorage) Put(key, value string) {
|
func (s *EphemeralStorage) Put(key, value string) {
|
||||||
if len(key) == 0 {
|
if len(key) == 0 {
|
||||||
return
|
return
|
||||||
|
|
@ -62,6 +66,11 @@ func (s *EphemeralStorage) Get(key string) (string, error) {
|
||||||
return "", ErrNotFound
|
return "", ErrNotFound
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Del removes a key-value pair. If the key doesn't exist, the method is a noop.
|
||||||
|
func (s *EphemeralStorage) Del(key string) {
|
||||||
|
delete(s.data, key)
|
||||||
|
}
|
||||||
|
|
||||||
func NewEphemeralStorage() Storage {
|
func NewEphemeralStorage() Storage {
|
||||||
s := &EphemeralStorage{
|
s := &EphemeralStorage{
|
||||||
data: make(map[string]string),
|
data: make(map[string]string),
|
||||||
|
|
@ -73,6 +82,7 @@ func NewEphemeralStorage() Storage {
|
||||||
type NoStorage struct{}
|
type NoStorage struct{}
|
||||||
|
|
||||||
func (s *NoStorage) Put(key, value string) {}
|
func (s *NoStorage) Put(key, value string) {}
|
||||||
|
func (s *NoStorage) Del(key string) {}
|
||||||
func (s *NoStorage) Get(key string) (string, error) {
|
func (s *NoStorage) Get(key string) (string, error) {
|
||||||
return "", errors.New("I forgot")
|
return "", errors.New("I forgot")
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue