@@ -355,63 +355,19 @@ export class ApplicationDefaultCredential implements Credential {
355355 private credential_ : Credential ;
356356
357357 constructor ( httpAgent ?: Agent ) {
358-
359- if ( typeof process . env . GOOGLE_APPLICATION_CREDENTIALS === 'string' &&
360- ! fs . existsSync ( process . env . GOOGLE_APPLICATION_CREDENTIALS ) ) {
361- throw new Error (
362- "env variable 'GOOGLE_APPLICATION_CREDENTIAL' set to invalid path: " +
363- process . env . GOOGLE_APPLICATION_CREDENTIALS ) ;
358+ if ( process . env . GOOGLE_APPLICATION_CREDENTIALS ) {
359+ this . credential_ = credentialFromFile ( process . env . GOOGLE_APPLICATION_CREDENTIALS , httpAgent ) ;
360+ return ;
364361 }
365362
366- let lastError : Error ;
367- const paths : string [ ] = process . env . GOOGLE_APPLICATION_CREDENTIALS ?
368- [ process . env . GOOGLE_APPLICATION_CREDENTIALS ] : [ ] ;
369- if ( GCLOUD_CREDENTIAL_PATH !== process . env . GOOGLE_APPLICATION_CREDENTIALS ) {
370- paths . push ( GCLOUD_CREDENTIAL_PATH ) ;
371- }
372- paths . forEach ( ( filePath ) => {
373- if ( ! this . credential_ && filePath && typeof filePath === 'string' ) {
374- let fileText : string ;
375- try {
376- fileText = fs . readFileSync ( filePath , 'utf8' ) ;
377- } catch ( error ) {
378- // ignore and return to allow default
379- return ;
380- }
381- try {
382- const fileContents = JSON . parse ( fileText ) ;
383- if ( ! fileContents . type ) {
384- lastError = new FirebaseAppError (
385- AppErrorCodes . INVALID_CREDENTIAL , "Certificate file did not have 'type' parameter" ) ;
386- } else {
387- switch ( fileContents . type ) {
388- case 'authorized_user' :
389- this . credential_ = new RefreshTokenCredential ( new RefreshToken ( fileContents ) , httpAgent ) ;
390- break ;
391- case 'service_account' :
392- this . credential_ = new CertCredential ( new Certificate ( fileContents ) , httpAgent ) ;
393- break ;
394- default :
395- lastError = new FirebaseAppError ( AppErrorCodes . INVALID_CREDENTIAL ,
396- `invalid certificate type: '${ fileContents . type } '` ) ;
397- break ;
398- }
399- }
400- } catch ( error ) {
401- // Throw a nicely formed error message if the file contents cannot be parsed
402- lastError = new FirebaseAppError (
403- AppErrorCodes . INVALID_CREDENTIAL ,
404- `Failed to parse certificate key file (${ filePath } ): ${ error } ` ,
405- ) ;
406- }
407- }
408- } ) ;
409- if ( lastError ) {
410- throw lastError ;
411- }
412- if ( ! this . credential_ ) {
413- this . credential_ = new MetadataServiceCredential ( httpAgent ) ;
363+ // It is OK to not have this file. If it is present, it must be valid.
364+ const refreshToken = RefreshToken . fromPath ( GCLOUD_CREDENTIAL_PATH ) ;
365+ if ( refreshToken ) {
366+ this . credential_ = new RefreshTokenCredential ( refreshToken , httpAgent ) ;
367+ return ;
414368 }
369+
370+ this . credential_ = new MetadataServiceCredential ( httpAgent ) ;
415371 }
416372
417373 public getAccessToken ( ) : Promise < GoogleOAuthAccessToken > {
@@ -427,3 +383,49 @@ export class ApplicationDefaultCredential implements Credential {
427383 return this . credential_ ;
428384 }
429385}
386+
387+ function credentialFromFile ( filePath : string , httpAgent ?: Agent ) : Credential {
388+ const credentialsFile = readCredentialFile ( filePath ) ;
389+ if ( typeof credentialsFile !== 'object' ) {
390+ throw new FirebaseAppError (
391+ AppErrorCodes . INVALID_CREDENTIAL ,
392+ 'Failed to parse contents of the credentials file as an object' ,
393+ ) ;
394+ }
395+ if ( credentialsFile . type === 'service_account' ) {
396+ return new CertCredential ( credentialsFile , httpAgent ) ;
397+ }
398+ if ( credentialsFile . type === 'authorized_user' ) {
399+ return new RefreshTokenCredential ( credentialsFile , httpAgent ) ;
400+ }
401+ throw new FirebaseAppError (
402+ AppErrorCodes . INVALID_CREDENTIAL ,
403+ 'Invalid contents in the credentials file' ,
404+ ) ;
405+ }
406+
407+ function readCredentialFile ( filePath : string ) : { [ key : string ] : any } {
408+ if ( typeof filePath !== 'string' ) {
409+ throw new FirebaseAppError (
410+ AppErrorCodes . INVALID_CREDENTIAL ,
411+ 'Failed to parse credentials file: TypeError: path must be a string' ,
412+ ) ;
413+ }
414+ let fileText : string ;
415+ try {
416+ fileText = fs . readFileSync ( filePath , 'utf8' ) ;
417+ } catch ( error ) {
418+ throw new FirebaseAppError (
419+ AppErrorCodes . INVALID_CREDENTIAL ,
420+ `Failed to read credentials from file ${ filePath } : ` + error ,
421+ ) ;
422+ }
423+ try {
424+ return JSON . parse ( fileText ) ;
425+ } catch ( error ) {
426+ throw new FirebaseAppError (
427+ AppErrorCodes . INVALID_CREDENTIAL ,
428+ 'Failed to parse contents of the credentials file as an object: ' + error ,
429+ ) ;
430+ }
431+ }
0 commit comments