Skip to content

Commit 1a7f722

Browse files
authored
Removing getCertificate() from the Credential interface (#576)
* Removing getCertificate() from the Credential interface * Updated other usages of getCertificate
1 parent b715ad5 commit 1a7f722

File tree

6 files changed

+60
-24
lines changed

6 files changed

+60
-24
lines changed

src/auth/credential.ts

Lines changed: 29 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -230,7 +230,7 @@ function getDetailFromResponse(response: HttpResponse): string {
230230
/**
231231
* Implementation of Credential that uses a service account certificate.
232232
*/
233-
export class CertCredential implements Credential {
233+
export class CertCredential implements FirebaseCredential {
234234

235235
private readonly certificate: Certificate;
236236
private readonly httpClient: HttpClient;
@@ -290,7 +290,32 @@ export class CertCredential implements Credential {
290290
*/
291291
export interface Credential {
292292
getAccessToken(): Promise<GoogleOAuthAccessToken>;
293-
getCertificate(): Certificate;
293+
}
294+
295+
/**
296+
* Internal interface for credentials that can both generate access tokens and may have a Certificate
297+
* associated with them.
298+
*/
299+
export interface FirebaseCredential extends Credential {
300+
getCertificate(): Certificate | null;
301+
}
302+
303+
/**
304+
* Attempts to extract a Certificate from the given credential.
305+
*
306+
* @param {Credential} credential A Credential instance.
307+
* @return {Certificate} A Certificate instance or null.
308+
*/
309+
export function tryGetCertificate(credential: Credential): Certificate | null {
310+
if (isFirebaseCredential(credential)) {
311+
return credential.getCertificate();
312+
}
313+
314+
return null;
315+
}
316+
317+
function isFirebaseCredential(credential: Credential): credential is FirebaseCredential {
318+
return 'getCertificate' in credential;
294319
}
295320

296321
/**
@@ -326,10 +351,6 @@ export class RefreshTokenCredential implements Credential {
326351
};
327352
return requestAccessToken(this.httpClient, request);
328353
}
329-
330-
public getCertificate(): Certificate {
331-
return null;
332-
}
333354
}
334355

335356

@@ -358,18 +379,14 @@ export class MetadataServiceCredential implements Credential {
358379
};
359380
return requestAccessToken(this.httpClient, request);
360381
}
361-
362-
public getCertificate(): Certificate {
363-
return null;
364-
}
365382
}
366383

367384

368385
/**
369386
* ApplicationDefaultCredential implements the process for loading credentials as
370387
* described in https://developers.google.com/identity/protocols/application-default-credentials
371388
*/
372-
export class ApplicationDefaultCredential implements Credential {
389+
export class ApplicationDefaultCredential implements FirebaseCredential {
373390
private credential_: Credential;
374391

375392
constructor(httpAgent?: Agent) {
@@ -393,7 +410,7 @@ export class ApplicationDefaultCredential implements Credential {
393410
}
394411

395412
public getCertificate(): Certificate {
396-
return this.credential_.getCertificate();
413+
return tryGetCertificate(this.credential_);
397414
}
398415

399416
// Used in testing to verify we are delegating to the correct implementation.

src/auth/token-generator.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,8 @@
1515
*/
1616

1717
import { FirebaseApp } from '../firebase-app';
18-
import {Certificate} from './credential';
19-
import {AuthClientErrorCode, FirebaseAuthError, FirebaseError} from '../utils/error';
18+
import {Certificate, tryGetCertificate} from './credential';
19+
import {AuthClientErrorCode, FirebaseAuthError } from '../utils/error';
2020
import { AuthorizedHttpClient, HttpError, HttpRequestConfig, HttpClient } from '../utils/api-request';
2121

2222
import * as validator from '../utils/validator';
@@ -220,7 +220,7 @@ export class IAMSigner implements CryptoSigner {
220220
* @return {CryptoSigner} A CryptoSigner instance.
221221
*/
222222
export function cryptoSignerFromApp(app: FirebaseApp): CryptoSigner {
223-
const cert = app.options.credential.getCertificate();
223+
const cert = tryGetCertificate(app.options.credential);
224224
if (cert != null && validator.isNonEmptyString(cert.privateKey) && validator.isNonEmptyString(cert.clientEmail)) {
225225
return new ServiceAccountSigner(cert);
226226
}

src/firestore/firestore.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
import {FirebaseApp} from '../firebase-app';
1818
import {FirebaseFirestoreError} from '../utils/error';
1919
import {FirebaseServiceInterface, FirebaseServiceInternalsInterface} from '../firebase-service';
20-
import {ApplicationDefaultCredential, Certificate} from '../auth/credential';
20+
import {ApplicationDefaultCredential, Certificate, tryGetCertificate} from '../auth/credential';
2121
import {Firestore, Settings} from '@google-cloud/firestore';
2222

2323
import * as validator from '../utils/validator';
@@ -72,7 +72,7 @@ export function getFirestoreOptions(app: FirebaseApp): Settings {
7272
}
7373

7474
const projectId: string = utils.getProjectId(app);
75-
const cert: Certificate = app.options.credential.getCertificate();
75+
const cert: Certificate = tryGetCertificate(app.options.credential);
7676
const { version: firebaseVersion } = require('../../package.json');
7777
if (cert != null) {
7878
// cert is available when the SDK has been initialized with a service account JSON file,

src/storage/storage.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
import {FirebaseApp} from '../firebase-app';
1818
import {FirebaseError} from '../utils/error';
1919
import {FirebaseServiceInterface, FirebaseServiceInternalsInterface} from '../firebase-service';
20-
import {ApplicationDefaultCredential, Certificate} from '../auth/credential';
20+
import {ApplicationDefaultCredential, Certificate, tryGetCertificate} from '../auth/credential';
2121
import {Bucket, Storage as StorageClient} from '@google-cloud/storage';
2222

2323
import * as validator from '../utils/validator';
@@ -70,7 +70,7 @@ export class Storage implements FirebaseServiceInterface {
7070
});
7171
}
7272

73-
const cert: Certificate = app.options.credential.getCertificate();
73+
const cert: Certificate = tryGetCertificate(app.options.credential);
7474
if (cert != null) {
7575
// cert is available when the SDK has been initialized with a service account JSON file,
7676
// or by setting the GOOGLE_APPLICATION_CREDENTIALS envrionment variable.

src/utils/index.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
*/
1616

1717
import {FirebaseApp, FirebaseAppOptions} from '../firebase-app';
18-
import {Certificate} from '../auth/credential';
18+
import {Certificate, tryGetCertificate} from '../auth/credential';
1919

2020
import * as validator from './validator';
2121

@@ -69,7 +69,7 @@ export function getProjectId(app: FirebaseApp): string {
6969
return options.projectId;
7070
}
7171

72-
const cert: Certificate = options.credential.getCertificate();
72+
const cert: Certificate = tryGetCertificate(options.credential);
7373
if (cert != null && validator.isNonEmptyString(cert.projectId)) {
7474
return cert.projectId;
7575
}

test/unit/auth/credential.spec.ts

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ import * as mocks from '../../resources/mocks';
3232

3333
import {
3434
ApplicationDefaultCredential, CertCredential, Certificate, GoogleOAuthAccessToken,
35-
MetadataServiceCredential, RefreshTokenCredential,
35+
MetadataServiceCredential, RefreshTokenCredential, tryGetCertificate,
3636
} from '../../../src/auth/credential';
3737
import { HttpClient } from '../../../src/utils/api-request';
3838
import {Agent} from 'https';
@@ -255,6 +255,15 @@ describe('Credential', () => {
255255
});
256256
});
257257

258+
it('should return a certificate', () => {
259+
const c = new CertCredential(mockCertificateObject);
260+
expect(tryGetCertificate(c)).to.deep.equal({
261+
projectId: mockCertificateObject.project_id,
262+
clientEmail: mockCertificateObject.client_email,
263+
privateKey: mockCertificateObject.private_key,
264+
});
265+
});
266+
258267
it('should create access tokens', () => {
259268
const c = new CertCredential(mockCertificateObject);
260269
return c.getAccessToken().then((token) => {
@@ -292,7 +301,7 @@ describe('Credential', () => {
292301
describe('RefreshTokenCredential', () => {
293302
it('should not return a certificate', () => {
294303
const c = new RefreshTokenCredential(MOCK_REFRESH_TOKEN_CONFIG);
295-
expect(c.getCertificate()).to.be.null;
304+
expect(tryGetCertificate(c)).to.be.null;
296305
});
297306

298307
it('should create access tokens', () => {
@@ -322,7 +331,7 @@ describe('Credential', () => {
322331

323332
it('should not return a certificate', () => {
324333
const c = new MetadataServiceCredential();
325-
expect(c.getCertificate()).to.be.null;
334+
expect(tryGetCertificate(c)).to.be.null;
326335
});
327336

328337
it('should create access tokens', () => {
@@ -428,6 +437,16 @@ describe('Credential', () => {
428437
});
429438
});
430439

440+
it('should return a Certificate', () => {
441+
process.env.GOOGLE_APPLICATION_CREDENTIALS = path.resolve(__dirname, '../../resources/mock.key.json');
442+
const c = new ApplicationDefaultCredential();
443+
expect(tryGetCertificate(c)).to.deep.equal({
444+
projectId: mockCertificateObject.project_id,
445+
clientEmail: mockCertificateObject.client_email,
446+
privateKey: mockCertificateObject.private_key,
447+
});
448+
});
449+
431450
it('should parse valid RefreshTokenCredential if GOOGLE_APPLICATION_CREDENTIALS environment variable ' +
432451
'points to default refresh token location', () => {
433452
process.env.GOOGLE_APPLICATION_CREDENTIALS = GCLOUD_CREDENTIAL_PATH;

0 commit comments

Comments
 (0)