Skip to content

Commit d5b35bb

Browse files
Bo98gitster
authored andcommitted
osxkeychain: store new attributes
d208bfd (credential: new attribute password_expiry_utc, 2023-02-18) and a5c7656 (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 <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent e3cef40 commit d5b35bb

File tree

1 file changed

+62
-6
lines changed

1 file changed

+62
-6
lines changed

contrib/credential/osxkeychain/git-credential-osxkeychain.c

Lines changed: 62 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,17 +6,23 @@
66
#define ENCODING kCFStringEncodingUTF8
77
static CFStringRef protocol; /* Stores constant strings - not memory managed */
88
static CFStringRef host;
9+
static CFNumberRef port;
910
static CFStringRef path;
1011
static CFStringRef username;
1112
static CFDataRef password;
12-
static CFNumberRef port;
13+
static CFDataRef password_expiry_utc;
14+
static CFDataRef oauth_refresh_token;
1315

1416
static void clear_credential(void)
1517
{
1618
if (host) {
1719
CFRelease(host);
1820
host = NULL;
1921
}
22+
if (port) {
23+
CFRelease(port);
24+
port = NULL;
25+
}
2026
if (path) {
2127
CFRelease(path);
2228
path = NULL;
@@ -29,12 +35,18 @@ static void clear_credential(void)
2935
CFRelease(password);
3036
password = NULL;
3137
}
32-
if (port) {
33-
CFRelease(port);
34-
port = NULL;
38+
if (password_expiry_utc) {
39+
CFRelease(password_expiry_utc);
40+
password_expiry_utc = NULL;
41+
}
42+
if (oauth_refresh_token) {
43+
CFRelease(oauth_refresh_token);
44+
oauth_refresh_token = NULL;
3545
}
3646
}
3747

48+
#define STRING_WITH_LENGTH(s) s, sizeof(s) - 1
49+
3850
__attribute__((format (printf, 1, 2), __noreturn__))
3951
static void die(const char *err, ...)
4052
{
@@ -197,9 +209,27 @@ static OSStatus delete_ref(const void *itemRef)
197209
CFDictionarySetValue(query, kSecReturnData, kCFBooleanTrue);
198210
result = SecItemCopyMatching(query, (CFTypeRef *)&data);
199211
if (!result) {
200-
if (CFEqual(data, password))
212+
CFDataRef kc_password;
213+
const UInt8 *raw_data;
214+
const UInt8 *line;
215+
216+
/* Don't match appended metadata */
217+
raw_data = CFDataGetBytePtr(data);
218+
line = memchr(raw_data, '\n', CFDataGetLength(data));
219+
if (line)
220+
kc_password = CFDataCreateWithBytesNoCopy(
221+
kCFAllocatorDefault,
222+
raw_data,
223+
line - raw_data,
224+
kCFAllocatorNull);
225+
else
226+
kc_password = data;
227+
228+
if (CFEqual(kc_password, password))
201229
result = SecItemDelete(delete_query);
202230

231+
if (line)
232+
CFRelease(kc_password);
203233
CFRelease(data);
204234
}
205235

@@ -250,14 +280,31 @@ static OSStatus delete_internet_password(void)
250280

251281
static OSStatus add_internet_password(void)
252282
{
283+
CFMutableDataRef data;
253284
CFDictionaryRef attrs;
254285
OSStatus result;
255286

256287
/* Only store complete credentials */
257288
if (!protocol || !host || !username || !password)
258289
return -1;
259290

260-
attrs = CREATE_SEC_ATTRIBUTES(kSecValueData, password,
291+
data = CFDataCreateMutableCopy(kCFAllocatorDefault, 0, password);
292+
if (password_expiry_utc) {
293+
CFDataAppendBytes(data,
294+
(const UInt8 *)STRING_WITH_LENGTH("\npassword_expiry_utc="));
295+
CFDataAppendBytes(data,
296+
CFDataGetBytePtr(password_expiry_utc),
297+
CFDataGetLength(password_expiry_utc));
298+
}
299+
if (oauth_refresh_token) {
300+
CFDataAppendBytes(data,
301+
(const UInt8 *)STRING_WITH_LENGTH("\noauth_refresh_token="));
302+
CFDataAppendBytes(data,
303+
CFDataGetBytePtr(oauth_refresh_token),
304+
CFDataGetLength(oauth_refresh_token));
305+
}
306+
307+
attrs = CREATE_SEC_ATTRIBUTES(kSecValueData, data,
261308
NULL);
262309

263310
result = SecItemAdd(attrs, NULL);
@@ -268,6 +315,7 @@ static OSStatus add_internet_password(void)
268315
CFRelease(query);
269316
}
270317

318+
CFRelease(data);
271319
CFRelease(attrs);
272320

273321
return result;
@@ -339,6 +387,14 @@ static void read_credential(void)
339387
password = CFDataCreate(kCFAllocatorDefault,
340388
(UInt8 *)v,
341389
strlen(v));
390+
else if (!strcmp(buf, "password_expiry_utc"))
391+
password_expiry_utc = CFDataCreate(kCFAllocatorDefault,
392+
(UInt8 *)v,
393+
strlen(v));
394+
else if (!strcmp(buf, "oauth_refresh_token"))
395+
oauth_refresh_token = CFDataCreate(kCFAllocatorDefault,
396+
(UInt8 *)v,
397+
strlen(v));
342398
/*
343399
* Ignore other lines; we don't know what they mean, but
344400
* this future-proofs us when later versions of git do

0 commit comments

Comments
 (0)