Fix 2FA support
The 2FA information is now returned after the /auth request instead of the /auth/info one. Closes: https://github.com/emersion/hydroxide/issues/76
This commit is contained in:
parent
1edc88fd5a
commit
80e0fa6f3e
|
@ -119,11 +119,11 @@ func authenticate(c *protonmail.Client, cachedAuth *CachedAuth, username string)
|
|||
return nil, fmt.Errorf("cannot re-authenticate: failed to get auth info: %v", err)
|
||||
}
|
||||
|
||||
if authInfo.TwoFactor == 1 {
|
||||
if cachedAuth.TwoFactor.Enabled == 1 {
|
||||
return nil, fmt.Errorf("cannot re-authenticate: two factor authentication enabled, please login manually")
|
||||
}
|
||||
|
||||
auth, err = c.Auth(username, cachedAuth.LoginPassword, "", authInfo)
|
||||
auth, err = c.Auth(username, cachedAuth.LoginPassword, authInfo)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("cannot re-authenticate: %v", err)
|
||||
}
|
||||
|
|
|
@ -153,18 +153,27 @@ func main() {
|
|||
log.Fatal(err)
|
||||
}
|
||||
|
||||
var twoFactorCode string
|
||||
if authInfo.TwoFactor == 1 {
|
||||
scanner := bufio.NewScanner(os.Stdin)
|
||||
fmt.Printf("2FA code: ")
|
||||
scanner.Scan()
|
||||
twoFactorCode = scanner.Text()
|
||||
}
|
||||
|
||||
a, err = c.Auth(username, loginPassword, twoFactorCode, authInfo)
|
||||
a, err = c.Auth(username, loginPassword, authInfo)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
if a.TwoFactor.Enabled == 1 {
|
||||
if a.TwoFactor.TOTP != 1 {
|
||||
log.Fatal("Only TOTP is supported as a 2FA method")
|
||||
}
|
||||
|
||||
scanner := bufio.NewScanner(os.Stdin)
|
||||
fmt.Printf("2FA TOTP code: ")
|
||||
scanner.Scan()
|
||||
code := scanner.Text()
|
||||
|
||||
scope, err := c.AuthTOTP(code)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
a.Scope = scope
|
||||
}
|
||||
}
|
||||
|
||||
var mailboxPassword string
|
||||
|
|
|
@ -16,12 +16,6 @@ type authInfoReq struct {
|
|||
}
|
||||
|
||||
type AuthInfo struct {
|
||||
TwoFactor int
|
||||
TwoFactorInfo struct {
|
||||
Enabled int
|
||||
U2F interface{} // TODO
|
||||
TOTP int
|
||||
} `json:"2FA"`
|
||||
version int
|
||||
modulus string
|
||||
serverEphemeral string
|
||||
|
@ -72,7 +66,6 @@ type authReq struct {
|
|||
SRPSession string
|
||||
ClientEphemeral string
|
||||
ClientProof string
|
||||
TwoFactorCode string
|
||||
}
|
||||
|
||||
type PasswordMode int
|
||||
|
@ -88,8 +81,14 @@ type Auth struct {
|
|||
UID string
|
||||
AccessToken string
|
||||
RefreshToken string
|
||||
UserID string
|
||||
EventID string
|
||||
PasswordMode PasswordMode
|
||||
TwoFactor struct {
|
||||
Enabled int
|
||||
U2F interface{} // TODO
|
||||
TOTP int
|
||||
} `json:"2FA"`
|
||||
}
|
||||
|
||||
type authResp struct {
|
||||
|
@ -106,7 +105,7 @@ func (resp *authResp) auth() *Auth {
|
|||
return auth
|
||||
}
|
||||
|
||||
func (c *Client) Auth(username, password, twoFactorCode string, info *AuthInfo) (*Auth, error) {
|
||||
func (c *Client) Auth(username, password string, info *AuthInfo) (*Auth, error) {
|
||||
if info == nil {
|
||||
var err error
|
||||
if info, err = c.AuthInfo(username); err != nil {
|
||||
|
@ -124,7 +123,6 @@ func (c *Client) Auth(username, password, twoFactorCode string, info *AuthInfo)
|
|||
SRPSession: info.srpSession,
|
||||
ClientEphemeral: base64.StdEncoding.EncodeToString(proofs.clientEphemeral),
|
||||
ClientProof: base64.StdEncoding.EncodeToString(proofs.clientProof),
|
||||
TwoFactorCode: twoFactorCode,
|
||||
}
|
||||
|
||||
req, err := c.newJSONRequest(http.MethodPost, "/auth", reqData)
|
||||
|
@ -147,6 +145,29 @@ func (c *Client) Auth(username, password, twoFactorCode string, info *AuthInfo)
|
|||
return auth, nil
|
||||
}
|
||||
|
||||
func (c *Client) AuthTOTP(code string) (scope string, err error) {
|
||||
reqData := struct {
|
||||
TwoFactorCode string
|
||||
}{
|
||||
TwoFactorCode: code,
|
||||
}
|
||||
|
||||
req, err := c.newJSONRequest(http.MethodPost, "/auth/2fa", reqData)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
respData := struct {
|
||||
resp
|
||||
Scope string
|
||||
}{}
|
||||
if err := c.doJSON(req, &respData); err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return respData.Scope, nil
|
||||
}
|
||||
|
||||
type authRefreshReq struct {
|
||||
UID string `json:"Uid"`
|
||||
RefreshToken string
|
||||
|
|
|
@ -157,6 +157,8 @@ func (c *Client) doJSON(req *http.Request, respData interface{}) error {
|
|||
return err
|
||||
}
|
||||
|
||||
//log.Printf("<< %v %v\n%#v", req.Method, req.URL.Path, respData)
|
||||
|
||||
if maybeError, ok := respData.(maybeError); ok {
|
||||
if err := maybeError.Err(); err != nil {
|
||||
log.Printf("request failed: %v %v: %v", req.Method, req.URL.String(), err)
|
||||
|
|
Loading…
Reference in New Issue