Skip to content

Commit

Permalink
store password_expiry_utc and oauth_refresh_token attributes
Browse files Browse the repository at this point in the history
Git 2.40 and 2.41 introduced new credential attributes https://git-scm.com/docs/git-credential#IOFMT
  • Loading branch information
hickford committed May 27, 2023
1 parent acb9c9e commit fe1e249
Show file tree
Hide file tree
Showing 2 changed files with 68 additions and 8 deletions.
55 changes: 48 additions & 7 deletions git-credential.go
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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
}

Expand Down Expand Up @@ -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
}
}
}
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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)
Expand Down
21 changes: 20 additions & 1 deletion git-credential_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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" +
Expand All @@ -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] {
Expand Down

0 comments on commit fe1e249

Please sign in to comment.