diff --git a/cmd/hydroxide/hydroxide.go b/cmd/hydroxide/hydroxide.go index a4367b1..bf847ce 100644 --- a/cmd/hydroxide/hydroxide.go +++ b/cmd/hydroxide/hydroxide.go @@ -2,6 +2,7 @@ package main import ( "bufio" + "encoding/json" "fmt" "log" "os" @@ -9,6 +10,30 @@ import ( "github.com/emersion/hydroxide/protonmail" ) +const authFile = "auth.json" + +func readCachedAuth() (*protonmail.Auth, error) { + f, err := os.Open(authFile) + if err != nil { + return nil, err + } + defer f.Close() + + auth := new(protonmail.Auth) + err = json.NewDecoder(f).Decode(auth) + return auth, err +} + +func saveAuth(auth *protonmail.Auth) error { + f, err := os.Create(authFile) + if err != nil { + return err + } + defer f.Close() + + return json.NewEncoder(f).Encode(auth) +} + func main() { c := &protonmail.Client{ RootURL: "https://dev.protonmail.com/api", @@ -19,41 +44,62 @@ func main() { scanner := bufio.NewScanner(os.Stdin) - fmt.Printf("Username: ") - scanner.Scan() - username := scanner.Text() + var password string + auth, err := readCachedAuth() + if err == nil { + passwordMode := auth.PasswordMode - fmt.Printf("Password: ") - scanner.Scan() - password := scanner.Text() + var err error + auth, err = c.AuthRefresh(auth.UID, auth.RefreshToken) + if err != nil { + log.Fatal(err) + } - authInfo, err := c.AuthInfo(username) - if err != nil { + auth.PasswordMode = passwordMode + } else if os.IsNotExist(err) { + fmt.Printf("Username: ") + scanner.Scan() + username := scanner.Text() + + fmt.Printf("Password: ") + scanner.Scan() + password = scanner.Text() + + authInfo, err := c.AuthInfo(username) + if err != nil { + log.Fatal(err) + } + + var twoFactorCode string + if authInfo.TwoFactor == 1 { + fmt.Printf("2FA code: ") + scanner.Scan() + twoFactorCode = scanner.Text() + } + + auth, err = c.Auth(username, password, twoFactorCode, authInfo) + if err != nil { + log.Fatal(err) + } + } else { log.Fatal(err) } - var twoFactorCode string - if authInfo.TwoFactor == 1 { - fmt.Printf("2FA code: ") - scanner.Scan() - twoFactorCode = scanner.Text() - } - - auth, err := c.Auth(username, password, twoFactorCode, authInfo) - if err != nil { + if err := saveAuth(auth); err != nil { log.Fatal(err) } - log.Println(auth) - - var mailboxPassword string - if auth.PasswordMode == protonmail.PasswordTwo { - fmt.Printf("Mailbox password: ") + if auth.PasswordMode == protonmail.PasswordTwo || password == "" { + if auth.PasswordMode == protonmail.PasswordTwo { + fmt.Printf("Mailbox password: ") + } else { + fmt.Printf("Password: ") + } scanner.Scan() - mailboxPassword = scanner.Text() + password = scanner.Text() } - _, err = c.Unlock(auth, mailboxPassword) + _, err = c.Unlock(auth, password) if err != nil { log.Fatal(err) } diff --git a/protonmail/auth.go b/protonmail/auth.go index b8e9dc8..24e7354 100644 --- a/protonmail/auth.go +++ b/protonmail/auth.go @@ -154,15 +154,19 @@ func (c *Client) Auth(username, password, twoFactorCode string, info *AuthInfo) type authRefreshReq struct { ClientID string - ClientSecret string UID string `json:"Uid"` RefreshToken string + + // Unused but required + ResponseType string + GrantType string + RedirectURI string + State string } func (c *Client) AuthRefresh(uid, refreshToken string) (*Auth, error) { reqData := &authRefreshReq{ ClientID: c.ClientID, - ClientSecret: c.ClientSecret, UID: uid, RefreshToken: refreshToken, }