github.com/keybase/client/go@v0.0.0-20241007131713-f10651d043c8/service/account.go (about) 1 // Copyright 2015 Keybase, Inc. All rights reserved. Use of 2 // this source code is governed by the included BSD license. 3 4 package service 5 6 import ( 7 "errors" 8 "fmt" 9 "time" 10 11 "github.com/keybase/client/go/engine" 12 "github.com/keybase/client/go/libkb" 13 keybase1 "github.com/keybase/client/go/protocol/keybase1" 14 "github.com/keybase/go-framed-msgpack-rpc/rpc" 15 "golang.org/x/net/context" 16 ) 17 18 type AccountHandler struct { 19 *BaseHandler 20 libkb.Contextified 21 } 22 23 func NewAccountHandler(xp rpc.Transporter, g *libkb.GlobalContext) *AccountHandler { 24 return &AccountHandler{ 25 BaseHandler: NewBaseHandler(g, xp), 26 Contextified: libkb.NewContextified(g), 27 } 28 } 29 30 func (h *AccountHandler) getDelegateSecretUI(sessionID int) (ret libkb.SecretUI, err error) { 31 if h.G().UIRouter != nil { 32 return h.G().UIRouter.GetSecretUI(sessionID) 33 } 34 return nil, nil 35 } 36 37 func (h *AccountHandler) PassphraseChange(ctx context.Context, arg keybase1.PassphraseChangeArg) error { 38 eng := engine.NewPassphraseChange(h.G(), &arg) 39 uis := libkb.UIs{ 40 SecretUI: h.getSecretUI(arg.SessionID, h.G()), 41 SessionID: arg.SessionID, 42 } 43 m := libkb.NewMetaContext(ctx, h.G()).WithUIs(uis) 44 return engine.RunEngine2(m, eng) 45 } 46 47 func (h *AccountHandler) PassphrasePrompt(_ context.Context, arg keybase1.PassphrasePromptArg) (keybase1.GetPassphraseRes, error) { 48 ui := h.getSecretUI(arg.SessionID, h.G()) 49 if delegateUI, err := h.getDelegateSecretUI(arg.SessionID); err != nil { 50 return keybase1.GetPassphraseRes{}, err 51 } else if delegateUI != nil { 52 ui = delegateUI 53 h.G().Log.Debug("using delegate secret UI") 54 } 55 56 return ui.GetPassphrase(arg.GuiArg, nil) 57 } 58 59 func (h *AccountHandler) EmailChange(nctx context.Context, arg keybase1.EmailChangeArg) error { 60 uis := libkb.UIs{ 61 SessionID: arg.SessionID, 62 SecretUI: h.getSecretUI(arg.SessionID, h.G()), 63 } 64 m := libkb.NewMetaContext(nctx, h.G()).WithUIs(uis) 65 eng := engine.NewEmailChange(h.G(), &arg) 66 return engine.RunEngine2(m, eng) 67 } 68 69 func (h *AccountHandler) HasServerKeys(ctx context.Context, sessionID int) (res keybase1.HasServerKeysRes, err error) { 70 arg := keybase1.HasServerKeysArg{SessionID: sessionID} 71 eng := engine.NewHasServerKeys(h.G()) 72 m := libkb.NewMetaContext(ctx, h.G()).WithUIs(libkb.UIs{SessionID: arg.SessionID}) 73 err = engine.RunEngine2(m, eng) 74 if err != nil { 75 return res, err 76 } 77 return eng.GetResult(), nil 78 } 79 80 func (h *AccountHandler) ResetAccount(ctx context.Context, arg keybase1.ResetAccountArg) (err error) { 81 82 if h.G().Env.GetRunMode() != libkb.DevelRunMode { 83 return errors.New("ResetAccount only supported in devel run mode") 84 } 85 86 m := libkb.NewMetaContext(ctx, h.G()) 87 defer m.Trace("AccountHandler#ResetAccount", &err)() 88 89 username := h.G().GetEnv().GetUsername() 90 m.Debug("resetting account for %s", username.String()) 91 92 passphrase := arg.Passphrase 93 if passphrase == "" { 94 pparg := libkb.DefaultPassphrasePromptArg(m, username.String()) 95 secretUI := h.getSecretUI(arg.SessionID, h.G()) 96 res, err := secretUI.GetPassphrase(pparg, nil) 97 if err != nil { 98 return err 99 } 100 passphrase = res.Passphrase 101 } 102 103 err = libkb.ResetAccount(m, username, passphrase) 104 if err != nil { 105 return err 106 } 107 108 m.Debug("reset account succeeded, logging out.") 109 110 return m.LogoutKillSecrets() 111 } 112 113 type GetLockdownResponse struct { 114 libkb.AppStatusEmbed 115 Enabled bool `json:"enabled"` 116 History []keybase1.LockdownHistory `json:"history"` 117 } 118 119 func (h *AccountHandler) GetLockdownMode(ctx context.Context, sessionID int) (ret keybase1.GetLockdownResponse, err error) { 120 mctx := libkb.NewMetaContext(ctx, h.G()) 121 defer mctx.Trace("GetLockdownMode", &err)() 122 apiArg := libkb.APIArg{ 123 Endpoint: "account/lockdown", 124 SessionType: libkb.APISessionTypeREQUIRED, 125 } 126 var response GetLockdownResponse 127 err = mctx.G().API.GetDecode(mctx, apiArg, &response) 128 if err != nil { 129 return ret, err 130 } 131 132 upak, _, err := mctx.G().GetUPAKLoader().Load( 133 libkb.NewLoadUserArgWithMetaContext(mctx).WithPublicKeyOptional().WithUID(mctx.G().ActiveDevice.UID())) 134 if err != nil { 135 return ret, err 136 } 137 138 // Fill device names from ActiveDevices list. 139 for i, v := range response.History { 140 dev := upak.FindDevice(v.DeviceID) 141 if dev == nil { 142 mctx.Debug("GetLockdownMode: Could not find device in UserPlusAllKeys: %s", v.DeviceID) 143 continue 144 } 145 146 v.DeviceName = dev.DeviceDescription 147 response.History[i] = v 148 } 149 150 ret = keybase1.GetLockdownResponse{ 151 Status: response.Enabled, 152 History: response.History, 153 } 154 h.G().Log.CDebugf(ctx, "GetLockdownMode -> %v", ret.Status) 155 return ret, nil 156 } 157 158 func (h *AccountHandler) SetLockdownMode(ctx context.Context, arg keybase1.SetLockdownModeArg) (err error) { 159 mctx := libkb.NewMetaContext(ctx, h.G()) 160 defer mctx.Trace(fmt.Sprintf("SetLockdownMode(%v)", arg.Enabled), &err)() 161 apiArg := libkb.APIArg{ 162 Endpoint: "account/lockdown", 163 SessionType: libkb.APISessionTypeREQUIRED, 164 Args: libkb.HTTPArgs{ 165 "enabled": libkb.B{Val: arg.Enabled}, 166 }, 167 } 168 _, err = mctx.G().API.Post(mctx, apiArg) 169 return err 170 } 171 172 func (h *AccountHandler) PassphraseCheck(ctx context.Context, arg keybase1.PassphraseCheckArg) (ret bool, err error) { 173 mctx := libkb.NewMetaContext(ctx, h.G()) 174 defer mctx.Trace("PassphraseCheck", &err)() 175 eng := engine.NewPassphraseCheck(mctx.G(), &arg) 176 uis := libkb.UIs{ 177 SecretUI: h.getSecretUI(arg.SessionID, h.G()), 178 SessionID: arg.SessionID, 179 } 180 err = eng.Run(mctx.WithUIs(uis)) 181 return eng.GetResult(), err 182 } 183 184 func (h *AccountHandler) RecoverUsernameWithEmail(ctx context.Context, arg keybase1.RecoverUsernameWithEmailArg) (err error) { 185 mctx := libkb.NewMetaContext(ctx, h.G()) 186 defer mctx.Trace(fmt.Sprintf("RecoverUsernameWithEmail(%q)", arg.Email), &err)() 187 apiArg := libkb.APIArg{ 188 Endpoint: "account/recover_username", 189 SessionType: libkb.APISessionTypeNONE, 190 Args: libkb.HTTPArgs{ 191 "email": libkb.S{Val: arg.Email}, 192 }, 193 } 194 _, err = mctx.G().API.Post(mctx, apiArg) 195 return err 196 } 197 198 func (h *AccountHandler) RecoverUsernameWithPhone(ctx context.Context, arg keybase1.RecoverUsernameWithPhoneArg) (err error) { 199 mctx := libkb.NewMetaContext(ctx, h.G()) 200 defer mctx.Trace(fmt.Sprintf("RecoverUsernameWithPhone(%q)", arg.Phone), &err)() 201 if err = libkb.IsPossiblePhoneNumber(arg.Phone); err != nil { 202 return err 203 } 204 apiArg := libkb.APIArg{ 205 Endpoint: "account/recover_username", 206 SessionType: libkb.APISessionTypeNONE, 207 Args: libkb.HTTPArgs{ 208 "phone_number": libkb.S{Val: arg.Phone.String()}, 209 }, 210 } 211 _, err = mctx.G().API.Post(mctx, apiArg) 212 return err 213 } 214 215 // EnterPipeline allows a user to enter the reset pipeline. The user must 216 // verify ownership of the account via an email confirmation or their password. 217 // Resets are not allowed on a provisioned device. 218 func (h *AccountHandler) EnterResetPipeline(ctx context.Context, arg keybase1.EnterResetPipelineArg) (err error) { 219 mctx := libkb.NewMetaContext(ctx, h.G()) 220 defer mctx.Trace("EnterResetPipline", &err)() 221 uis := libkb.UIs{ 222 LoginUI: h.getLoginUI(arg.SessionID), 223 SecretUI: h.getSecretUI(arg.SessionID, h.G()), 224 LogUI: h.getLogUI(arg.SessionID), 225 SessionID: arg.SessionID, 226 } 227 eng := engine.NewAccountReset(h.G(), arg.UsernameOrEmail) 228 // In noninteractive mode, use this to set skipPassword 229 if arg.Passphrase != "" || !arg.Interactive { 230 eng.SetPassphrase(arg.Passphrase) 231 } 232 m := libkb.NewMetaContext(ctx, h.G()).WithUIs(uis) 233 return engine.RunEngine2(m, eng) 234 } 235 236 // CancelReset allows a user to cancel the reset process via an authenticated API call. 237 func (h *AccountHandler) CancelReset(ctx context.Context, sessionID int) (err error) { 238 mctx := libkb.NewMetaContext(ctx, h.G()) 239 defer mctx.Trace("CancelReset", &err)() 240 err = libkb.CancelResetPipeline(mctx) 241 if err != nil { 242 mctx.Debug("CancelResetPipeline failed with: %s", err) 243 mctx.Debug("Checking if we are not revoked") 244 err2 := mctx.LogoutAndDeprovisionIfRevoked() 245 if err2 != nil { 246 mctx.Error("LogoutAndDeprovisionIfRevoked failed in CancelReset check: %s", err2) 247 return libkb.CombineErrors(err, err2) 248 } 249 if mctx.CurrentUID().IsNil() { 250 // We got logged out. 251 return UserWasLoggedOutError{} 252 } 253 } 254 return err 255 } 256 257 // TimeTravelReset allows a user to move forward in the reset process via an API call [devel-only]. 258 func (h *AccountHandler) TimeTravelReset(ctx context.Context, arg keybase1.TimeTravelResetArg) error { 259 mctx := libkb.NewMetaContext(ctx, h.G()) 260 if arg.Username == "" { 261 current, _, err := mctx.G().GetAllUserNames() 262 if err != nil { 263 return err 264 } 265 arg.Username = current.String() 266 } 267 268 _, err := mctx.G().API.Post(mctx, libkb.APIArg{ 269 Endpoint: "autoreset/timetravel", 270 SessionType: libkb.APISessionTypeNONE, 271 Args: libkb.HTTPArgs{ 272 "username": libkb.S{Val: arg.Username}, 273 "duration_sec": libkb.I{Val: int(arg.Duration)}, 274 }, 275 }) 276 277 return err 278 } 279 280 func (h *AccountHandler) GuessCurrentLocation(ctx context.Context, arg keybase1.GuessCurrentLocationArg) (string, error) { 281 mctx := libkb.NewMetaContext(ctx, h.G()) 282 res, err := mctx.G().API.Get(mctx, libkb.APIArg{ 283 Endpoint: "account/location_suggest", 284 SessionType: libkb.APISessionTypeNONE, 285 InitialTimeout: 2500 * time.Millisecond, 286 RetryCount: 2, 287 }) 288 if err != nil { 289 mctx.Warning("Unable to retrieve the current location: %v", err) 290 return arg.DefaultCountry, nil 291 } 292 code, err := res.Body.AtKey("country_code").GetString() 293 if err != nil || code == "-" { 294 mctx.Warning("Unable to retrieve the current location: %v", err) 295 return arg.DefaultCountry, nil 296 } 297 mctx.Debug("Guessed this device's country to be %v", code) 298 return code, nil 299 } 300 301 func (h *AccountHandler) UserGetContactSettings(ctx context.Context) (res keybase1.ContactSettings, err error) { 302 mctx := libkb.NewMetaContext(ctx, h.G()) 303 defer mctx.Trace("AccountHandler#UserGetContactSettings", &err)() 304 return libkb.GetContactSettings(mctx) 305 } 306 307 func (h *AccountHandler) UserSetContactSettings(ctx context.Context, arg keybase1.ContactSettings) (err error) { 308 mctx := libkb.NewMetaContext(ctx, h.G()) 309 defer mctx.Trace("AccountHandler#UserSetContactSettings", &err)() 310 return libkb.SetContactSettings(mctx, arg) 311 }