diff --git a/client/client.go b/client/client.go index e8031f1..19564ee 100644 --- a/client/client.go +++ b/client/client.go @@ -387,3 +387,20 @@ func (c *RemoteServer) Status(req core.StatusRequest) (*core.ResponseData, error return unmarshalResponseData(respBytes) } + +// Restore issues a restore request to the server. Note that a restore +// request is the same as a delegation request, except that the user +// and label lists are ignored. +func (c *RemoteServer) Restore(req core.DelegateRequest) (*core.ResponseData, error) { + reqBytes, err := json.Marshal(req) + if err != nil { + return nil, err + } + + respBytes, err := c.doAction("restore", reqBytes) + if err != nil { + return nil, err + } + + return unmarshalResponseData(respBytes) +} diff --git a/cmd/ro/main.go b/cmd/ro/main.go index 7929d5a..57ebbd8 100644 --- a/cmd/ro/main.go +++ b/cmd/ro/main.go @@ -45,6 +45,7 @@ var commandSet = map[string]command{ "order": command{Run: runOrder, Desc: "place an order for delegations"}, "owners": command{Run: runOwner, Desc: "show owners list"}, "status": command{Run: runStatus, Desc: "show Red October persistent delegation state"}, + "restore": command{Run: runRestore, Desc: "perform a restore delegation"}, } func registerFlags() { @@ -132,6 +133,29 @@ func runDelegate() { fmt.Println(resp.Status) } +func runRestore() { + req := core.DelegateRequest{ + Name: user, + Password: pswd, + Uses: uses, + Time: duration, + } + + resp, err := roServer.Restore(req) + processError(err) + + if resp.Status != "ok" { + fmt.Fprintf(os.Stderr, "failed: %s\n", resp.Status) + os.Exit(1) + } + + var st core.StatusData + err = json.Unmarshal(resp.Response, &st) + processError(err) + + fmt.Println("Restore delegation complete; persistence is now", st.Status) +} + // TODO: summary response needs better formatting func runSummary() { req := core.SummaryRequest{ diff --git a/cryptor/cryptor.go b/cryptor/cryptor.go index 9cd35aa..4d9b945 100644 --- a/cryptor/cryptor.go +++ b/cryptor/cryptor.go @@ -742,6 +742,11 @@ var ErrRestoreDelegations = errors.New("cryptor: need more delegations") // enough delegations are present to restore the cache, the current // Red October key cache is replaced with the persisted one. func (c *Cryptor) Restore(name, password string, uses int, slot, durationString string) error { + // If the persistence store is already active, don't proceed. + if st := c.persist.Status(); st != nil && st.State == persist.Active { + return nil + } + record, ok := c.records.GetRecord(name) if !ok { return errors.New("Missing user on disk") @@ -774,6 +779,7 @@ func (c *Cryptor) Restore(name, password string, uses int, slot, durationString c.cache = keycache.NewFrom(uk) c.persist.Persist() + c.persist.Cache().Flush() return nil } diff --git a/redoctober.go b/redoctober.go index cad520b..27a2f7c 100644 --- a/redoctober.go +++ b/redoctober.go @@ -304,6 +304,9 @@ func main() { } if vaultPath == "" || !cfg.Valid() { + if !cfg.Valid() { + fmt.Fprintf(os.Stderr, "Invalid config.\n") + } fmt.Fprint(os.Stderr, usage) flag.PrintDefaults() os.Exit(2)