@@ -7,7 +7,8 @@ const HOSTS_KEY = 'hosts';
7
7
const CREDENTIAL_SERVICE = 'vscode-pull-request-github' ;
8
8
9
9
export class VSCodeConfiguration extends Configuration {
10
- private _hosts : Map < string , IHostConfiguration > ;
10
+ private _hosts : Map < string , IHostConfiguration > = new Map < string , IHostConfiguration > ( ) ;
11
+ private _hostTokensInKeychain : Set < string > = new Set < string > ( ) ;
11
12
12
13
constructor ( ) {
13
14
super ( undefined ) ;
@@ -63,14 +64,34 @@ export class VSCodeConfiguration extends Configuration {
63
64
this . saveConfiguration ( ) ;
64
65
}
65
66
66
- public async update ( username : string | undefined , token : string | undefined , raiseEvent : boolean = true ) : Promise < void > {
67
- super . update ( username , token , raiseEvent ) ;
68
- await keychain . setPassword ( CREDENTIAL_SERVICE , this . host , token ) ;
69
- this . saveConfiguration ( ) ;
67
+ public async update ( username : string | undefined , token : string | undefined , raiseEvent : boolean = true ) : Promise < boolean > {
68
+ const key = this . host ;
69
+ try {
70
+ // this might fail. if it does, fallback to saving the token in the user settings file
71
+ await keychain . setPassword ( CREDENTIAL_SERVICE , key , token ) ;
72
+ if ( ! this . _hostTokensInKeychain . has ( key ) ) {
73
+ this . _hostTokensInKeychain . add ( key ) ;
74
+ }
75
+ } catch ( e ) {
76
+ if ( this . _hostTokensInKeychain . has ( key ) ) {
77
+ this . _hostTokensInKeychain . delete ( key ) ;
78
+ }
79
+ }
80
+ return super . update ( username , token , false ) . then ( hasChanged => {
81
+ if ( hasChanged ) {
82
+ this . saveConfiguration ( ) ;
83
+ // raise changed events only after the host list has been roundtripped to disk
84
+ if ( raiseEvent ) {
85
+ this . raiseChangedEvent ( ) ;
86
+ }
87
+ }
88
+ return hasChanged ;
89
+ } ) ;
70
90
}
71
91
72
92
private reset ( ) : void {
73
- this . _hosts = new Map < string , IHostConfiguration > ( ) ;
93
+ this . _hosts . clear ( ) ;
94
+ this . _hostTokensInKeychain . clear ( ) ;
74
95
}
75
96
76
97
public async loadConfiguration ( ) : Promise < void > {
@@ -84,12 +105,16 @@ export class VSCodeConfiguration extends Configuration {
84
105
return Promise . all ( configHosts . map ( async c => {
85
106
// if the token is not in the user settings file, load it from the system credential manager
86
107
if ( c . token === 'system' ) {
87
- c . token = await keychain . getPassword ( CREDENTIAL_SERVICE , c . host ) || undefined ;
108
+ try {
109
+ c . token = await keychain . getPassword ( CREDENTIAL_SERVICE , c . host ) || undefined ;
110
+ if ( c . token ) {
111
+ this . _hostTokensInKeychain . add ( c . host ) ;
112
+ this . _hosts . set ( c . host , c ) ;
113
+ }
114
+ } catch { } // only load the host if we can read the token, otherwise there's no point
88
115
} else {
89
- // the token might have been filled out in the settings file, load it from there if so
90
- await keychain . setPassword ( CREDENTIAL_SERVICE , c . host , c . token ) ;
116
+ this . _hosts . set ( c . host , c ) ;
91
117
}
92
- this . _hosts . set ( c . host , c ) ;
93
118
} ) ) . then ( _ => {
94
119
if ( this . host && ! this . _hosts . has ( this . host ) ) {
95
120
this . _hosts . set ( this . host , {
@@ -110,7 +135,10 @@ export class VSCodeConfiguration extends Configuration {
110
135
} ) ;
111
136
}
112
137
const config = vscode . workspace . getConfiguration ( SETTINGS_NAMESPACE ) ;
113
- // don't save the token to the user settings file
114
- config . update ( HOSTS_KEY , Array . from ( this . _hosts . values ( ) ) . map ( x => { return { host : x . host , username : x . username , token : 'system' } ; } ) , true ) ;
138
+ // don't save the token to the user settings file if it's in the keychain
139
+ config . update ( HOSTS_KEY , Array . from ( this . _hosts . values ( ) ) . map ( x => {
140
+ const token = this . _hostTokensInKeychain . has ( x . host ) ? 'system' : x . token ;
141
+ return { host : x . host , username : x . username , token } ;
142
+ } ) , true ) ;
115
143
}
116
144
}
0 commit comments