cmd/clef, signer: support removing stored keys (delpw + rules)

This commit is contained in:
Péter Szilágyi 2019-07-02 12:11:26 +03:00
parent 793db11483
commit 31c2781d49
No known key found for this signature in database
GPG key ID: E9AE538CEDF8293D
4 changed files with 82 additions and 12 deletions

View file

@ -93,7 +93,7 @@ var (
chainIdFlag = cli.Int64Flag{
Name: "chainid",
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{
Name: "rpcport",
@ -116,8 +116,7 @@ var (
}
ruleFlag = cli.StringFlag{
Name: "rules",
Usage: "Enable rule-engine",
Value: "",
Usage: "Path to the rule file to auto-authorize requests with",
}
stdiouiFlag = cli.BoolFlag{
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
Clef that the file is 'safe' to execute.`,
}
setCredentialCommand = cli.Command{
Action: utils.MigrateFlags(setCredential),
Name: "setpw",
@ -173,6 +171,19 @@ Clef that the file is 'safe' to execute.`,
},
Description: `
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{
Action: GenDoc,
@ -209,9 +220,9 @@ func init() {
advancedMode,
}
app.Action = signer
app.Commands = []cli.Command{initCommand, attestCommand, setCredentialCommand, gendocCommand}
app.Commands = []cli.Command{initCommand, attestCommand, setCredentialCommand, delCredentialCommand, gendocCommand}
}
func main() {
if err := app.Run(os.Args); err != nil {
fmt.Fprintln(os.Stderr, err)
@ -317,7 +328,6 @@ func setCredential(ctx *cli.Context) error {
if err := initialize(ctx); err != nil {
return err
}
addr := ctx.Args().First()
if !common.IsHexAddress(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]))
pwkey := crypto.Keccak256([]byte("credentials"), stretchedKey)
// Initialize the encrypted storages
pwStorage := storage.NewAESEncryptedStorage(filepath.Join(vaultLocation, "credentials.json"), pwkey)
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
}
@ -359,6 +397,10 @@ func initialize(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 {
return err
}

View file

@ -83,7 +83,12 @@ func (r *rulesetUI) execute(jsfunc string, jsarg interface{}) (otto.Value, error
vm.Set("storage", struct{}{})
storageObj, _ := vm.Get("storage")
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()
})
storageObj.Object().Set("get", func(call otto.FunctionCall) otto.Value {

View file

@ -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) {
if len(key) == 0 {
return
@ -99,6 +99,19 @@ func (s *AESEncryptedStorage) Get(key string) (string, error) {
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
func (s *AESEncryptedStorage) readEncryptedStorage() (map[string]storedCredential, error) {
creds := make(map[string]storedCredential)

View file

@ -28,12 +28,15 @@ var (
)
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)
// Get returns the previously stored value, or an error if the key is 0-length
// or unknown.
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
@ -43,6 +46,7 @@ type EphemeralStorage struct {
namespace string
}
// Put stores a value by key. 0-length keys results in noop.
func (s *EphemeralStorage) Put(key, value string) {
if len(key) == 0 {
return
@ -62,6 +66,11 @@ func (s *EphemeralStorage) Get(key string) (string, error) {
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 {
s := &EphemeralStorage{
data: make(map[string]string),
@ -73,6 +82,7 @@ func NewEphemeralStorage() Storage {
type NoStorage struct{}
func (s *NoStorage) Put(key, value string) {}
func (s *NoStorage) Del(key string) {}
func (s *NoStorage) Get(key string) (string, error) {
return "", errors.New("I forgot")
}