diff --git a/git-credential.go b/git-credential.go index 53ea8ec..aae47ac 100644 --- a/git-credential.go +++ b/git-credential.go @@ -23,11 +23,13 @@ import ( var Stdout io.Writer = os.Stdout type gitCredentials struct { - Protocol string - Host string - Path string - Username string - Password string + Protocol string + Host string + Path string + Username string + Password string + PasswordExpiryUTC string + OAuthRefreshToken string } // WriteTo writes the given credentials to the given io.Writer in the git-credential format. @@ -74,6 +76,22 @@ func (c *gitCredentials) WriteTo(w io.Writer) (int64, error) { } } + if c.PasswordExpiryUTC != "" { + i, err := io.WriteString(w, "password_expiry_utc="+c.PasswordExpiryUTC+"\n") + n += int64(i) + if err != nil { + return n, err + } + } + + if c.OAuthRefreshToken != "" { + i, err := io.WriteString(w, "oauth_refresh_token="+c.OAuthRefreshToken+"\n") + n += int64(i) + if err != nil { + return n, err + } + } + return n, nil } @@ -116,6 +134,10 @@ func parseGitCredentials(r io.Reader) (*gitCredentials, error) { c.Username = val case "password": c.Password = val + case "password_expiry_utc": + c.PasswordExpiryUTC = val + case "oauth_refresh_token": + c.OAuthRefreshToken = val } } } @@ -190,11 +212,23 @@ func (s *gc) Get(c *cli.Context) error { return err } - cred.Password = secret.Password() + payload := secret.Password() + lines := strings.Split(payload, "\n") + for i, line := range lines { + if i == 0 { + cred.Password = line + } + if i >= 1 && strings.HasPrefix(line, "oauth_refresh_token=") { + cred.OAuthRefreshToken = strings.TrimPrefix(line, "oauth_refresh_token=") + } + } if username, _ := secret.Get("login"); username != "" { // leave the username as is otherwise cred.Username = username } + if expiry, _ := secret.Get("password_expiry_utc"); expiry != "" { + cred.PasswordExpiryUTC = expiry + } _, err = cred.WriteTo(Stdout) if err != nil { @@ -225,10 +259,17 @@ func (s *gc) Store(c *cli.Context) error { return nil } secret := secrets.New() - secret.SetPassword(cred.Password) + payload := cred.Password + if cred.OAuthRefreshToken != "" { + payload += "\noauth_refresh_token=" + cred.OAuthRefreshToken + } + secret.SetPassword(payload) if cred.Username != "" { _ = secret.Set("login", cred.Username) } + if cred.PasswordExpiryUTC != "" { + _ = secret.Set("password_expiry_utc", cred.PasswordExpiryUTC) + } if err := s.gp.Set(ctx, path, secret); err != nil { fmt.Fprintf(os.Stderr, "gopass error: error while writing to store: %s\n", err) diff --git a/git-credential_test.go b/git-credential_test.go index 2ecfe8c..9803c17 100644 --- a/git-credential_test.go +++ b/git-credential_test.go @@ -30,6 +30,16 @@ func TestGitCredentialFormat(t *testing.T) { "path=test\n" + "password=secr3=t\n", ), + strings.NewReader("" + + "protocol=https\n" + + "host=example.com\n" + + "username=bob\n" + + "foo=bar\n" + + "path=test\n" + + "password=secr3=t\n" + + "password_expiry_utc=2000\n" + + "oauth_refresh_token=xyzzy\n", + ), strings.NewReader("" + "protocol=https\n" + "host=example.com\n" + @@ -56,11 +66,20 @@ func TestGitCredentialFormat(t *testing.T) { Protocol: "https", Username: "bob", }, + { + Host: "example.com", + Password: "secr3=t", + Path: "test", + Protocol: "https", + Username: "bob", + PasswordExpiryUTC: "2000", + OAuthRefreshToken: "xyzzy", + }, {}, {}, } - expectsErr := []bool{false, true, true} + expectsErr := []bool{false, false, true, true} for i := range data { result, err := parseGitCredentials(data[i]) if expectsErr[i] {