@@ -39,6 +39,8 @@ struct credential {
39
39
char * path ;
40
40
char * username ;
41
41
char * password ;
42
+ char * password_expiry_utc ;
43
+ char * oauth_refresh_token ;
42
44
};
43
45
44
46
#define CREDENTIAL_INIT { 0 }
@@ -54,6 +56,25 @@ struct credential_operation {
54
56
55
57
/* ----------------- Secret Service functions ----------------- */
56
58
59
+ static const SecretSchema schema = {
60
+ "org.git.Password" ,
61
+ /* Ignore schema name during search for backwards compatibility */
62
+ SECRET_SCHEMA_DONT_MATCH_NAME ,
63
+ {
64
+ /*
65
+ * libsecret assumes attribute values are non-confidential and
66
+ * unchanging, so we can't include oauth_refresh_token or
67
+ * password_expiry_utc.
68
+ */
69
+ { "user" , SECRET_SCHEMA_ATTRIBUTE_STRING },
70
+ { "object" , SECRET_SCHEMA_ATTRIBUTE_STRING },
71
+ { "protocol" , SECRET_SCHEMA_ATTRIBUTE_STRING },
72
+ { "port" , SECRET_SCHEMA_ATTRIBUTE_INTEGER },
73
+ { "server" , SECRET_SCHEMA_ATTRIBUTE_STRING },
74
+ { NULL , 0 },
75
+ }
76
+ };
77
+
57
78
static char * make_label (struct credential * c )
58
79
{
59
80
if (c -> port )
@@ -101,7 +122,7 @@ static int keyring_get(struct credential *c)
101
122
102
123
attributes = make_attr_list (c );
103
124
items = secret_service_search_sync (service ,
104
- SECRET_SCHEMA_COMPAT_NETWORK ,
125
+ & schema ,
105
126
attributes ,
106
127
SECRET_SEARCH_LOAD_SECRETS | SECRET_SEARCH_UNLOCK ,
107
128
NULL ,
@@ -117,6 +138,7 @@ static int keyring_get(struct credential *c)
117
138
SecretItem * item ;
118
139
SecretValue * secret ;
119
140
const char * s ;
141
+ gchar * * parts ;
120
142
121
143
item = items -> data ;
122
144
secret = secret_item_get_secret (item );
@@ -130,8 +152,27 @@ static int keyring_get(struct credential *c)
130
152
131
153
s = secret_value_get_text (secret );
132
154
if (s ) {
133
- g_free (c -> password );
134
- c -> password = g_strdup (s );
155
+ /*
156
+ * Passwords and other attributes encoded in following format:
157
+ * hunter2
158
+ * password_expiry_utc=1684189401
159
+ * oauth_refresh_token=xyzzy
160
+ */
161
+ parts = g_strsplit (s , "\n" , 0 );
162
+ if (g_strv_length (parts ) >= 1 ) {
163
+ g_free (c -> password );
164
+ c -> password = g_strdup (parts [0 ]);
165
+ }
166
+ for (int i = 1 ; i < g_strv_length (parts ); i ++ ) {
167
+ if (g_str_has_prefix (parts [i ], "password_expiry_utc=" )) {
168
+ g_free (c -> password_expiry_utc );
169
+ c -> password_expiry_utc = g_strdup (& parts [i ][20 ]);
170
+ } else if (g_str_has_prefix (parts [i ], "oauth_refresh_token=" )) {
171
+ g_free (c -> oauth_refresh_token );
172
+ c -> oauth_refresh_token = g_strdup (& parts [i ][20 ]);
173
+ }
174
+ }
175
+ g_strfreev (parts );
135
176
}
136
177
137
178
g_hash_table_unref (attributes );
@@ -148,6 +189,7 @@ static int keyring_store(struct credential *c)
148
189
char * label = NULL ;
149
190
GHashTable * attributes = NULL ;
150
191
GError * error = NULL ;
192
+ GString * secret = NULL ;
151
193
152
194
/*
153
195
* Sanity check that what we are storing is actually sensible.
@@ -162,13 +204,23 @@ static int keyring_store(struct credential *c)
162
204
163
205
label = make_label (c );
164
206
attributes = make_attr_list (c );
165
- secret_password_storev_sync (SECRET_SCHEMA_COMPAT_NETWORK ,
207
+ secret = g_string_new (c -> password );
208
+ if (c -> password_expiry_utc ) {
209
+ g_string_append_printf (secret , "\npassword_expiry_utc=%s" ,
210
+ c -> password_expiry_utc );
211
+ }
212
+ if (c -> oauth_refresh_token ) {
213
+ g_string_append_printf (secret , "\noauth_refresh_token=%s" ,
214
+ c -> oauth_refresh_token );
215
+ }
216
+ secret_password_storev_sync (& schema ,
166
217
attributes ,
167
218
NULL ,
168
219
label ,
169
- c -> password ,
220
+ secret -> str ,
170
221
NULL ,
171
222
& error );
223
+ g_string_free (secret , TRUE);
172
224
g_free (label );
173
225
g_hash_table_unref (attributes );
174
226
@@ -198,7 +250,7 @@ static int keyring_erase(struct credential *c)
198
250
return EXIT_FAILURE ;
199
251
200
252
attributes = make_attr_list (c );
201
- secret_password_clearv_sync (SECRET_SCHEMA_COMPAT_NETWORK ,
253
+ secret_password_clearv_sync (& schema ,
202
254
attributes ,
203
255
NULL ,
204
256
& error );
@@ -238,6 +290,8 @@ static void credential_clear(struct credential *c)
238
290
g_free (c -> path );
239
291
g_free (c -> username );
240
292
g_free (c -> password );
293
+ g_free (c -> password_expiry_utc );
294
+ g_free (c -> oauth_refresh_token );
241
295
242
296
credential_init (c );
243
297
}
@@ -284,11 +338,19 @@ static int credential_read(struct credential *c)
284
338
} else if (!strcmp (key , "username" )) {
285
339
g_free (c -> username );
286
340
c -> username = g_strdup (value );
341
+ } else if (!strcmp (key , "password_expiry_utc" )) {
342
+ g_free (c -> password_expiry_utc );
343
+ c -> password_expiry_utc = g_strdup (value );
287
344
} else if (!strcmp (key , "password" )) {
288
345
g_free (c -> password );
289
346
c -> password = g_strdup (value );
290
347
while (* value )
291
348
* value ++ = '\0' ;
349
+ } else if (!strcmp (key , "oauth_refresh_token" )) {
350
+ g_free (c -> oauth_refresh_token );
351
+ c -> oauth_refresh_token = g_strdup (value );
352
+ while (* value )
353
+ * value ++ = '\0' ;
292
354
}
293
355
/*
294
356
* Ignore other lines; we don't know what they mean, but
@@ -314,6 +376,10 @@ static void credential_write(const struct credential *c)
314
376
/* only write username/password, if set */
315
377
credential_write_item (stdout , "username" , c -> username );
316
378
credential_write_item (stdout , "password" , c -> password );
379
+ credential_write_item (stdout , "password_expiry_utc" ,
380
+ c -> password_expiry_utc );
381
+ credential_write_item (stdout , "oauth_refresh_token" ,
382
+ c -> oauth_refresh_token );
317
383
}
318
384
319
385
static void usage (const char * name )
0 commit comments