Skip to content

Commit 20be530

Browse files
committed
Validate credential files
1 parent a6240d2 commit 20be530

File tree

2 files changed

+31
-40
lines changed

2 files changed

+31
-40
lines changed

src/app/credential-internal.ts

Lines changed: 30 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -238,8 +238,8 @@ export class RefreshTokenCredential implements Credential {
238238
readonly implicit: boolean = false) {
239239

240240
(typeof refreshTokenPathOrObject === 'string') ?
241-
RefreshToken.fromPath(refreshTokenPathOrObject)
242-
: new RefreshToken(refreshTokenPathOrObject);
241+
RefreshToken.validateFromPath(refreshTokenPathOrObject)
242+
: RefreshToken.validateFromJSON(refreshTokenPathOrObject);
243243
}
244244

245245
private getGoogleAuth(): GoogleAuth {
@@ -261,18 +261,18 @@ export class RefreshTokenCredential implements Credential {
261261

262262
class RefreshToken {
263263

264-
public readonly clientId: string;
265-
public readonly clientSecret: string;
266-
public readonly refreshToken: string;
267-
public readonly type: string;
264+
// public readonly clientId: string;
265+
// public readonly clientSecret: string;
266+
// public readonly refreshToken: string;
267+
// public readonly type: string;
268268

269269
/*
270270
* Tries to load a RefreshToken from a path. Throws if the path doesn't exist or the
271271
* data at the path is invalid.
272272
*/
273-
public static fromPath(filePath: string): RefreshToken {
273+
public static validateFromPath(filePath: string): void {
274274
try {
275-
return new RefreshToken(JSON.parse(fs.readFileSync(filePath, 'utf8')));
275+
RefreshToken.validateFromJSON(JSON.parse(fs.readFileSync(filePath, 'utf8')));
276276
} catch (error) {
277277
// Throw a nicely formed error message if the file contents cannot be parsed
278278
throw new FirebaseAppError(
@@ -282,20 +282,20 @@ class RefreshToken {
282282
}
283283
}
284284

285-
constructor(json: object) {
286-
copyAttr(this, json, 'clientId', 'client_id');
287-
copyAttr(this, json, 'clientSecret', 'client_secret');
288-
copyAttr(this, json, 'refreshToken', 'refresh_token');
289-
copyAttr(this, json, 'type', 'type');
285+
public static validateFromJSON(json: object): void {
286+
287+
const {
288+
client_id: clientId, client_secret: clientSecret, refresh_token: refreshToken, type
289+
} = (json as { [key: string]: any });
290290

291291
let errorMessage;
292-
if (!util.isNonEmptyString(this.clientId)) {
292+
if (!util.isNonEmptyString(clientId)) {
293293
errorMessage = 'Refresh token must contain a "client_id" property.';
294-
} else if (!util.isNonEmptyString(this.clientSecret)) {
294+
} else if (!util.isNonEmptyString(clientSecret)) {
295295
errorMessage = 'Refresh token must contain a "client_secret" property.';
296-
} else if (!util.isNonEmptyString(this.refreshToken)) {
296+
} else if (!util.isNonEmptyString(refreshToken)) {
297297
errorMessage = 'Refresh token must contain a "refresh_token" property.';
298-
} else if (!util.isNonEmptyString(this.type)) {
298+
} else if (!util.isNonEmptyString(type)) {
299299
errorMessage = 'Refresh token must contain a "type" property.';
300300
}
301301

@@ -329,8 +329,8 @@ export class ImpersonatedServiceAccountCredential implements Credential {
329329
readonly implicit: boolean = false) {
330330

331331
(typeof impersonatedServiceAccountPathOrObject === 'string') ?
332-
ImpersonatedServiceAccount.fromPath(impersonatedServiceAccountPathOrObject)
333-
: new ImpersonatedServiceAccount(impersonatedServiceAccountPathOrObject);
332+
ImpersonatedServiceAccount.validateFromPath(impersonatedServiceAccountPathOrObject)
333+
: ImpersonatedServiceAccount.validateFromJSON(impersonatedServiceAccountPathOrObject);
334334
}
335335

336336
private getGoogleAuth(): GoogleAuth {
@@ -351,22 +351,17 @@ export class ImpersonatedServiceAccountCredential implements Credential {
351351
}
352352

353353
/**
354-
* A struct containing the properties necessary to use impersonated service account JSON credentials.
354+
* A helper class to validate the properties necessary to use impersonated service account credentials.
355355
*/
356356
class ImpersonatedServiceAccount {
357357

358-
public readonly clientId: string;
359-
public readonly clientSecret: string;
360-
public readonly refreshToken: string;
361-
public readonly type: string;
362-
363358
/*
364359
* Tries to load a ImpersonatedServiceAccount from a path. Throws if the path doesn't exist or the
365360
* data at the path is invalid.
366361
*/
367-
public static fromPath(filePath: string): ImpersonatedServiceAccount {
362+
public static validateFromPath(filePath: string): void {
368363
try {
369-
return new ImpersonatedServiceAccount(JSON.parse(fs.readFileSync(filePath, 'utf8')));
364+
ImpersonatedServiceAccount.validateFromJSON(JSON.parse(fs.readFileSync(filePath, 'utf8')));
370365
} catch (error) {
371366
// Throw a nicely formed error message if the file contents cannot be parsed
372367
throw new FirebaseAppError(
@@ -376,23 +371,19 @@ class ImpersonatedServiceAccount {
376371
}
377372
}
378373

379-
constructor(json: object) {
380-
const sourceCredentials = (json as { [key: string]: any })['source_credentials']
381-
if (sourceCredentials) {
382-
copyAttr(this, sourceCredentials, 'clientId', 'client_id');
383-
copyAttr(this, sourceCredentials, 'clientSecret', 'client_secret');
384-
copyAttr(this, sourceCredentials, 'refreshToken', 'refresh_token');
385-
copyAttr(this, sourceCredentials, 'type', 'type');
386-
}
374+
public static validateFromJSON(json: object): void {
375+
const {
376+
client_id: clientId, client_secret: clientSecret, refresh_token: refreshToken, type
377+
} = (json as { [key: string]: any })['source_credentials'];
387378

388379
let errorMessage;
389-
if (!util.isNonEmptyString(this.clientId)) {
380+
if (!util.isNonEmptyString(clientId)) {
390381
errorMessage = 'Impersonated Service Account must contain a "source_credentials.client_id" property.';
391-
} else if (!util.isNonEmptyString(this.clientSecret)) {
382+
} else if (!util.isNonEmptyString(clientSecret)) {
392383
errorMessage = 'Impersonated Service Account must contain a "source_credentials.client_secret" property.';
393-
} else if (!util.isNonEmptyString(this.refreshToken)) {
384+
} else if (!util.isNonEmptyString(refreshToken)) {
394385
errorMessage = 'Impersonated Service Account must contain a "source_credentials.refresh_token" property.';
395-
} else if (!util.isNonEmptyString(this.type)) {
386+
} else if (!util.isNonEmptyString(type)) {
396387
errorMessage = 'Impersonated Service Account must contain a "source_credentials.type" property.';
397388
}
398389

src/functions/functions-api-client-internal.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -320,7 +320,7 @@ export class FunctionsApiClient {
320320
task.httpRequest.url = functionUrl;
321321
// When run from a deployed extension, we should be using ComputeEngineCredentials
322322
if (validator.isNonEmptyString(extensionId) && this.app.options.credential
323-
instanceof ApplicationDefaultCredential) {
323+
instanceof ApplicationDefaultCredential && await this.app.options.credential.isComputeEngineCredential()) {
324324
const idToken = await this.app.options.credential.getIDToken(functionUrl);
325325
task.httpRequest.headers = { ...task.httpRequest.headers, 'Authorization': `Bearer ${idToken}` };
326326
// Don't send httpRequest.oidcToken if we set Authorization header, or Cloud Tasks will overwrite it.

0 commit comments

Comments
 (0)