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)
|
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")
|
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 {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("cannot re-authenticate: %v", err)
|
return nil, fmt.Errorf("cannot re-authenticate: %v", err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -153,18 +153,27 @@ func main() {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
var twoFactorCode string
|
a, err = c.Auth(username, loginPassword, authInfo)
|
||||||
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)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
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
|
var mailboxPassword string
|
||||||
|
|
|
@ -16,12 +16,6 @@ type authInfoReq struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
type AuthInfo struct {
|
type AuthInfo struct {
|
||||||
TwoFactor int
|
|
||||||
TwoFactorInfo struct {
|
|
||||||
Enabled int
|
|
||||||
U2F interface{} // TODO
|
|
||||||
TOTP int
|
|
||||||
} `json:"2FA"`
|
|
||||||
version int
|
version int
|
||||||
modulus string
|
modulus string
|
||||||
serverEphemeral string
|
serverEphemeral string
|
||||||
|
@ -72,7 +66,6 @@ type authReq struct {
|
||||||
SRPSession string
|
SRPSession string
|
||||||
ClientEphemeral string
|
ClientEphemeral string
|
||||||
ClientProof string
|
ClientProof string
|
||||||
TwoFactorCode string
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type PasswordMode int
|
type PasswordMode int
|
||||||
|
@ -88,8 +81,14 @@ type Auth struct {
|
||||||
UID string
|
UID string
|
||||||
AccessToken string
|
AccessToken string
|
||||||
RefreshToken string
|
RefreshToken string
|
||||||
|
UserID string
|
||||||
EventID string
|
EventID string
|
||||||
PasswordMode PasswordMode
|
PasswordMode PasswordMode
|
||||||
|
TwoFactor struct {
|
||||||
|
Enabled int
|
||||||
|
U2F interface{} // TODO
|
||||||
|
TOTP int
|
||||||
|
} `json:"2FA"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type authResp struct {
|
type authResp struct {
|
||||||
|
@ -106,7 +105,7 @@ func (resp *authResp) auth() *Auth {
|
||||||
return 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 {
|
if info == nil {
|
||||||
var err error
|
var err error
|
||||||
if info, err = c.AuthInfo(username); err != nil {
|
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,
|
SRPSession: info.srpSession,
|
||||||
ClientEphemeral: base64.StdEncoding.EncodeToString(proofs.clientEphemeral),
|
ClientEphemeral: base64.StdEncoding.EncodeToString(proofs.clientEphemeral),
|
||||||
ClientProof: base64.StdEncoding.EncodeToString(proofs.clientProof),
|
ClientProof: base64.StdEncoding.EncodeToString(proofs.clientProof),
|
||||||
TwoFactorCode: twoFactorCode,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
req, err := c.newJSONRequest(http.MethodPost, "/auth", reqData)
|
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
|
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 {
|
type authRefreshReq struct {
|
||||||
UID string `json:"Uid"`
|
UID string `json:"Uid"`
|
||||||
RefreshToken string
|
RefreshToken string
|
||||||
|
|
|
@ -157,6 +157,8 @@ func (c *Client) doJSON(req *http.Request, respData interface{}) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//log.Printf("<< %v %v\n%#v", req.Method, req.URL.Path, respData)
|
||||||
|
|
||||||
if maybeError, ok := respData.(maybeError); ok {
|
if maybeError, ok := respData.(maybeError); ok {
|
||||||
if err := maybeError.Err(); err != nil {
|
if err := maybeError.Err(); err != nil {
|
||||||
log.Printf("request failed: %v %v: %v", req.Method, req.URL.String(), err)
|
log.Printf("request failed: %v %v: %v", req.Method, req.URL.String(), err)
|
||||||
|
|
Loading…
Reference in New Issue