diff options
author | Bo Anderson <mail@boanderson.me> | 2024-02-17 23:34:56 +0000 |
---|---|---|
committer | Junio C Hamano <gitster@pobox.com> | 2024-04-01 15:38:20 -0700 |
commit | d5b35bba86e6fdf0484ea71bf5b8ef1167f14015 (patch) | |
tree | 4a19453fdf7ff5f956df0fa092d7a46a1e7b451a | |
parent | e3cef40db89f5a7c91f4e9d6c4959ca1e41f4647 (diff) | |
download | git-d5b35bba86e6fdf0484ea71bf5b8ef1167f14015.tar.gz |
osxkeychain: store new attributes
d208bfdfef (credential: new attribute password_expiry_utc, 2023-02-18)
and a5c76569e7 (credential: new attribute oauth_refresh_token,
2023-04-21) introduced new credential attributes but support was missing
from git-credential-osxkeychain.
Support these attributes by appending the data to the password in the
keychain, separated by line breaks. Line breaks cannot appear in a git
credential password so it is an appropriate separator.
Fixes the remaining test failures with osxkeychain:
18 - helper (osxkeychain) gets password_expiry_utc
19 - helper (osxkeychain) overwrites when password_expiry_utc
changes
21 - helper (osxkeychain) gets oauth_refresh_token
Signed-off-by: Bo Anderson <mail@boanderson.me>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
-rw-r--r-- | contrib/credential/osxkeychain/git-credential-osxkeychain.c | 68 |
1 files changed, 62 insertions, 6 deletions
diff --git a/contrib/credential/osxkeychain/git-credential-osxkeychain.c b/contrib/credential/osxkeychain/git-credential-osxkeychain.c index 9e74279633..6a40917b1e 100644 --- a/contrib/credential/osxkeychain/git-credential-osxkeychain.c +++ b/contrib/credential/osxkeychain/git-credential-osxkeychain.c @@ -6,10 +6,12 @@ #define ENCODING kCFStringEncodingUTF8 static CFStringRef protocol; /* Stores constant strings - not memory managed */ static CFStringRef host; +static CFNumberRef port; static CFStringRef path; static CFStringRef username; static CFDataRef password; -static CFNumberRef port; +static CFDataRef password_expiry_utc; +static CFDataRef oauth_refresh_token; static void clear_credential(void) { @@ -17,6 +19,10 @@ static void clear_credential(void) CFRelease(host); host = NULL; } + if (port) { + CFRelease(port); + port = NULL; + } if (path) { CFRelease(path); path = NULL; @@ -29,12 +35,18 @@ static void clear_credential(void) CFRelease(password); password = NULL; } - if (port) { - CFRelease(port); - port = NULL; + if (password_expiry_utc) { + CFRelease(password_expiry_utc); + password_expiry_utc = NULL; + } + if (oauth_refresh_token) { + CFRelease(oauth_refresh_token); + oauth_refresh_token = NULL; } } +#define STRING_WITH_LENGTH(s) s, sizeof(s) - 1 + __attribute__((format (printf, 1, 2), __noreturn__)) static void die(const char *err, ...) { @@ -197,9 +209,27 @@ static OSStatus delete_ref(const void *itemRef) CFDictionarySetValue(query, kSecReturnData, kCFBooleanTrue); result = SecItemCopyMatching(query, (CFTypeRef *)&data); if (!result) { - if (CFEqual(data, password)) + CFDataRef kc_password; + const UInt8 *raw_data; + const UInt8 *line; + + /* Don't match appended metadata */ + raw_data = CFDataGetBytePtr(data); + line = memchr(raw_data, '\n', CFDataGetLength(data)); + if (line) + kc_password = CFDataCreateWithBytesNoCopy( + kCFAllocatorDefault, + raw_data, + line - raw_data, + kCFAllocatorNull); + else + kc_password = data; + + if (CFEqual(kc_password, password)) result = SecItemDelete(delete_query); + if (line) + CFRelease(kc_password); CFRelease(data); } @@ -250,6 +280,7 @@ static OSStatus delete_internet_password(void) static OSStatus add_internet_password(void) { + CFMutableDataRef data; CFDictionaryRef attrs; OSStatus result; @@ -257,7 +288,23 @@ static OSStatus add_internet_password(void) if (!protocol || !host || !username || !password) return -1; - attrs = CREATE_SEC_ATTRIBUTES(kSecValueData, password, + data = CFDataCreateMutableCopy(kCFAllocatorDefault, 0, password); + if (password_expiry_utc) { + CFDataAppendBytes(data, + (const UInt8 *)STRING_WITH_LENGTH("\npassword_expiry_utc=")); + CFDataAppendBytes(data, + CFDataGetBytePtr(password_expiry_utc), + CFDataGetLength(password_expiry_utc)); + } + if (oauth_refresh_token) { + CFDataAppendBytes(data, + (const UInt8 *)STRING_WITH_LENGTH("\noauth_refresh_token=")); + CFDataAppendBytes(data, + CFDataGetBytePtr(oauth_refresh_token), + CFDataGetLength(oauth_refresh_token)); + } + + attrs = CREATE_SEC_ATTRIBUTES(kSecValueData, data, NULL); result = SecItemAdd(attrs, NULL); @@ -268,6 +315,7 @@ static OSStatus add_internet_password(void) CFRelease(query); } + CFRelease(data); CFRelease(attrs); return result; @@ -339,6 +387,14 @@ static void read_credential(void) password = CFDataCreate(kCFAllocatorDefault, (UInt8 *)v, strlen(v)); + else if (!strcmp(buf, "password_expiry_utc")) + password_expiry_utc = CFDataCreate(kCFAllocatorDefault, + (UInt8 *)v, + strlen(v)); + else if (!strcmp(buf, "oauth_refresh_token")) + oauth_refresh_token = CFDataCreate(kCFAllocatorDefault, + (UInt8 *)v, + strlen(v)); /* * Ignore other lines; we don't know what they mean, but * this future-proofs us when later versions of git do |