Handle special case of application default credentials location by yinzara · Pull Request #444 · firebase/firebase-admin-node

This doesn't need to be this complex. You only have to modify the first if block in the existing constructor. Rest of the constructor can remain unchanged. Something like:

constructor(httpAgent?: Agent) {
    if (process.env.GOOGLE_APPLICATION_CREDENTIALS) {
      this.credential_ = credentialFromFile(process.env.GOOGLE_APPLICATION_CREDENTIALS, httpAgent);
      return;
    }

    // Rest is unchanged
}

function credentialFromFile(filePath: string, httpAgent?: Agent): Credential {
  const credentialsFile = readCredentialFile(filePath);
  if (typeof credentialsFile !== 'object') {
    throw new FirebaseAppError(
      AppErrorCodes.INVALID_CREDENTIAL,
      'Failed to parse contents of the credentials file as an object',
    );
  }
  if (credentialsFile.type === 'service_account') {
    return new CertCredential(credentialsFile, httpAgent);
  }
  if (credentialsFile.type === 'authorized_user') {
    return new RefreshTokenCredential(credentialsFile, httpAgent);
  }
  throw new FirebaseAppError(
    AppErrorCodes.INVALID_CREDENTIAL,
    'Invalid contents in the credentials file',
  );
}

function readCredentialFile(filePath: string): {[key: string]: any} {
  if (typeof filePath !== 'string') {
      throw new FirebaseAppError(
        AppErrorCodes.INVALID_CREDENTIAL,
        'Failed to parse credentials file: TypeError: path must be a string',
      );
  }
  let fileText: string;
  try {
    fileText = fs.readFileSync(filePath, 'utf8');
  } catch (error) {
    throw new FirebaseAppError(
      AppErrorCodes.INVALID_CREDENTIAL,
      `Failed to read credentials from file ${filePath}: ` + error,
    );
  }
  try {
    return JSON.parse(fileText);
  } catch (error) {
    throw new FirebaseAppError(
      AppErrorCodes.INVALID_CREDENTIAL,
      'Failed to parse contents of the credentials file as an object: ' + error,
    );
  }
}