diff --git a/go/client/cmd_update.go b/go/client/cmd_update.go index 1e9a23ab3d03..d9742371eb93 100644 --- a/go/client/cmd_update.go +++ b/go/client/cmd_update.go @@ -13,6 +13,7 @@ import ( "github.com/keybase/client/go/install" "github.com/keybase/client/go/libcmdline" "github.com/keybase/client/go/libkb" + "golang.org/x/net/context" ) // NewCmdUpdate are commands for supporting the updater @@ -26,6 +27,7 @@ func NewCmdUpdate(cl *libcmdline.CommandLine, g *libkb.GlobalContext) cli.Comman newCmdUpdateCheck(cl, g), // Deprecated newCmdUpdateCheckInUse(cl, g), newCmdUpdateNotify(cl, g), + newCmdUpdateSnooze(cl, g), }, } } @@ -167,3 +169,46 @@ func (v *cmdUpdateNotify) Run() error { return fmt.Errorf("Unrecognized event: %s", v.event) } } +func newCmdUpdateSnooze(cl *libcmdline.CommandLine, g *libkb.GlobalContext) cli.Command { + return cli.Command{ + Name: "snooze", + Usage: "Snooze update", + Action: func(c *cli.Context) { + cl.SetLogForward(libcmdline.LogForwardNone) + cl.SetForkCmd(libcmdline.NoFork) + cl.ChooseCommand(newCmdUpdateSnoozeRunner(g), "snooze", c) + }} +} + +type cmdUpdateSnooze struct { + libkb.Contextified +} + +func newCmdUpdateSnoozeRunner(g *libkb.GlobalContext) *cmdUpdateSnooze { + return &cmdUpdateSnooze{ + Contextified: libkb.NewContextified(g), + } +} + +func (v *cmdUpdateSnooze) GetUsage() libkb.Usage { + return libkb.Usage{ + API: true, + Config: true, + } +} + +func (v *cmdUpdateSnooze) ParseArgv(ctx *cli.Context) error { + return nil +} + +func (v *cmdUpdateSnooze) Run() error { + config, err := GetConfigClient(v.G()) + if err != nil { + return err + } + if err := config.SnoozeUpdate(context.Background()); err != nil { + v.G().Log.Errorf("Error snoozing: %s", err) + return err + } + return nil +} diff --git a/go/install/install_darwinwindows.go b/go/install/install_darwinwindows.go index 59c743a37d2b..c09a96d45e21 100644 --- a/go/install/install_darwinwindows.go +++ b/go/install/install_darwinwindows.go @@ -9,6 +9,8 @@ import ( "os/exec" "strconv" "strings" + + "github.com/keybase/client/go/libkb" ) // GetNeedUpdate returns true if updater says we have a new update available. @@ -29,3 +31,13 @@ func GetNeedUpdate() (bool, error) { } return needUpdate, nil } + +// SnoozeUpdate will snooze the new update (if there is one) for 24 hrs. +func SnoozeUpdate(mctx libkb.MetaContext) error { + updaterPath, err := UpdaterBinPath() + if err != nil { + return err + } + exec.Command(updaterPath, "snooze") + return nil +} diff --git a/go/install/install_unix.go b/go/install/install_unix.go index 2e466554005e..daf77a202070 100644 --- a/go/install/install_unix.go +++ b/go/install/install_unix.go @@ -180,3 +180,9 @@ func WatchdogLogPath(string) (string, error) { func SystemLogPath() string { return "" } + +// SnoozeUpdate will snooze all updates indefinitely +func SnoozeUpdate(mctx libkb.MetaContext) error { + mctx.G().Env.GetConfigWriter().SetSnoozeUpdates(true) + return nil +} diff --git a/go/libkb/config.go b/go/libkb/config.go index 84e1827f29ae..acac29f76d52 100644 --- a/go/libkb/config.go +++ b/go/libkb/config.go @@ -599,6 +599,12 @@ func (f *JSONConfigFile) GetRememberPassphrase(username NormalizedUsername) (boo } return f.GetTopLevelBool(legacyRememberPassphraseKey) } +func (f *JSONConfigFile) GetSnoozeUpdates() (bool, bool) { + return f.GetBoolAtPath("snooze_updates") +} +func (f *JSONConfigFile) SetSnoozeUpdates(snoozeUpdates bool) error { + return f.SetBoolAtPath("snooze_updates", snoozeUpdates) +} func (f *JSONConfigFile) GetStayLoggedOut() (bool, bool) { return f.GetBoolAtPath("stay_logged_out") } diff --git a/go/libkb/context.go b/go/libkb/context.go index 5eecd4912b3e..67e38bd0f23f 100644 --- a/go/libkb/context.go +++ b/go/libkb/context.go @@ -392,6 +392,8 @@ func (m MetaContext) switchUserNewConfig(u keybase1.UID, n NormalizedUsername, s return err } } + // TODO: do i need to do anything particular for snooze_updates when user + // switching? return g.ActiveDevice.SetOrClear(m, ad) } diff --git a/go/libkb/env.go b/go/libkb/env.go index d3842e92c1a6..363afbe4f8a7 100644 --- a/go/libkb/env.go +++ b/go/libkb/env.go @@ -77,6 +77,7 @@ func (n NullConfiguration) GetUsernameForUID(u keybase1.UID) NormalizedUsername func (n NullConfiguration) GetUIDForUsername(u NormalizedUsername) keybase1.UID { return keybase1.UID("") } +func (n NullConfiguration) GetSnoozeUpdates() (bool, bool) { return false, false } func (n NullConfiguration) GetStayLoggedOut() (bool, bool) { return false, false } func (n NullConfiguration) GetAutoFork() (bool, bool) { return false, false } func (n NullConfiguration) GetRunMode() (RunMode, error) { return NoRunMode, nil } @@ -1136,6 +1137,12 @@ func (e *Env) GetEmail() string { ) } +func (e *Env) GetSnoozeUpdates() bool { + return e.GetBool(false, + func() (bool, bool) { return e.GetConfig().GetSnoozeUpdates() }, + ) +} + func (e *Env) GetStayLoggedOut() bool { return e.GetBool(false, func() (bool, bool) { return e.GetConfig().GetStayLoggedOut() }, diff --git a/go/libkb/interfaces.go b/go/libkb/interfaces.go index 756ca478a134..8b9a10a5a064 100644 --- a/go/libkb/interfaces.go +++ b/go/libkb/interfaces.go @@ -207,6 +207,7 @@ type ConfigReader interface { GetProxyCACerts() ([]string, error) GetSecurityAccessGroupOverride() (bool, bool) GetBug3964RepairTime(NormalizedUsername) (time.Time, error) + GetSnoozeUpdates() (bool, bool) GetStayLoggedOut() (bool, bool) GetUpdatePreferenceAuto() (bool, bool) @@ -252,6 +253,7 @@ type ConfigWriter interface { SetBug3964RepairTime(NormalizedUsername, time.Time) error SetRememberPassphrase(NormalizedUsername, bool) error SetPassphraseState(keybase1.PassphraseState) error + SetSnoozeUpdates(bool) error SetStayLoggedOut(bool) error Reset() BeginTransaction() (ConfigWriterTransacter, error) diff --git a/go/protocol/keybase1/config.go b/go/protocol/keybase1/config.go index 221b7c9472c7..1b8b50ee0e6f 100644 --- a/go/protocol/keybase1/config.go +++ b/go/protocol/keybase1/config.go @@ -944,6 +944,9 @@ type GetUpdateInfoArg struct { type StartUpdateIfNeededArg struct { } +type SnoozeUpdateArg struct { +} + type WaitForClientArg struct { ClientType ClientType `codec:"clientType" json:"clientType"` Timeout DurationSec `codec:"timeout" json:"timeout"` @@ -1018,6 +1021,7 @@ type ConfigInterface interface { CheckAPIServerOutOfDateWarning(context.Context) (OutOfDateInfo, error) GetUpdateInfo(context.Context) (UpdateInfo, error) StartUpdateIfNeeded(context.Context) error + SnoozeUpdate(context.Context) error // Wait for client type to connect to service. WaitForClient(context.Context, WaitForClientArg) (bool, error) GetBootstrapStatus(context.Context, int) (BootstrapStatus, error) @@ -1339,6 +1343,16 @@ func ConfigProtocol(i ConfigInterface) rpc.Protocol { return }, }, + "snoozeUpdate": { + MakeArg: func() interface{} { + var ret [1]SnoozeUpdateArg + return &ret + }, + Handler: func(ctx context.Context, args interface{}) (ret interface{}, err error) { + err = i.SnoozeUpdate(ctx) + return + }, + }, "waitForClient": { MakeArg: func() interface{} { var ret [1]WaitForClientArg @@ -1633,6 +1647,11 @@ func (c ConfigClient) StartUpdateIfNeeded(ctx context.Context) (err error) { return } +func (c ConfigClient) SnoozeUpdate(ctx context.Context) (err error) { + err = c.Cli.Call(ctx, "keybase.1.config.snoozeUpdate", []interface{}{SnoozeUpdateArg{}}, nil, 0*time.Millisecond) + return +} + // Wait for client type to connect to service. func (c ConfigClient) WaitForClient(ctx context.Context, __arg WaitForClientArg) (res bool, err error) { err = c.Cli.Call(ctx, "keybase.1.config.waitForClient", []interface{}{__arg}, &res, 0*time.Millisecond) diff --git a/go/service/config.go b/go/service/config.go index a345c1de8a24..c8b1f8db2b5f 100644 --- a/go/service/config.go +++ b/go/service/config.go @@ -345,6 +345,11 @@ func (h ConfigHandler) StartUpdateIfNeeded(ctx context.Context) error { return install.StartUpdateIfNeeded(ctx, h.G().Log) } +func (h ConfigHandler) SnoozeUpdate(ctx context.Context) error { + m := libkb.NewMetaContext(ctx, h.G()) + return install.SnoozeUpdate(m) +} + func (h ConfigHandler) WaitForClient(_ context.Context, arg keybase1.WaitForClientArg) (bool, error) { return h.G().ConnectionManager.WaitForClientType(arg.ClientType, arg.Timeout.Duration()), nil } diff --git a/protocol/avdl/keybase1/config.avdl b/protocol/avdl/keybase1/config.avdl index 8d434d8d31e5..2185ab460dc5 100644 --- a/protocol/avdl/keybase1/config.avdl +++ b/protocol/avdl/keybase1/config.avdl @@ -258,6 +258,7 @@ protocol config { // Same as running `keybase update check` in CLI. void startUpdateIfNeeded(); + void snoozeUpdate(); /** Wait for client type to connect to service. diff --git a/protocol/json/keybase1/config.json b/protocol/json/keybase1/config.json index 1c4f6eb8df23..6dd903fd6f85 100644 --- a/protocol/json/keybase1/config.json +++ b/protocol/json/keybase1/config.json @@ -1049,6 +1049,10 @@ "request": [], "response": null }, + "snoozeUpdate": { + "request": [], + "response": null + }, "waitForClient": { "request": [ { diff --git a/shared/constants/types/rpc-gen.tsx b/shared/constants/types/rpc-gen.tsx index fd8c0cd85382..8cabbcc11089 100644 --- a/shared/constants/types/rpc-gen.tsx +++ b/shared/constants/types/rpc-gen.tsx @@ -3914,6 +3914,7 @@ export const wotDismissWotNotificationsRpcPromise = (params: MessageTypes['keyba // 'keybase.1.config.getValue' // 'keybase.1.config.guiClearValue' // 'keybase.1.config.checkAPIServerOutOfDateWarning' +// 'keybase.1.config.snoozeUpdate' // 'keybase.1.contacts.lookupContactList' // 'keybase.1.crypto.signED25519' // 'keybase.1.crypto.signED25519ForKBFS'