Skip to content

Commit 760e34b

Browse files
committed
Validate credential files
1 parent b6f4cfb commit 760e34b

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
@@ -237,8 +237,8 @@ export class RefreshTokenCredential implements Credential {
237237
readonly implicit: boolean = false) {
238238

239239
(typeof refreshTokenPathOrObject === 'string') ?
240-
RefreshToken.fromPath(refreshTokenPathOrObject)
241-
: new RefreshToken(refreshTokenPathOrObject);
240+
RefreshToken.validateFromPath(refreshTokenPathOrObject)
241+
: RefreshToken.validateFromJSON(refreshTokenPathOrObject);
242242
}
243243

244244
private getGoogleAuth(): GoogleAuth {
@@ -260,18 +260,18 @@ export class RefreshTokenCredential implements Credential {
260260

261261
class RefreshToken {
262262

263-
public readonly clientId: string;
264-
public readonly clientSecret: string;
265-
public readonly refreshToken: string;
266-
public readonly type: string;
263+
// public readonly clientId: string;
264+
// public readonly clientSecret: string;
265+
// public readonly refreshToken: string;
266+
// public readonly type: string;
267267

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

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

290290
let errorMessage;
291-
if (!util.isNonEmptyString(this.clientId)) {
291+
if (!util.isNonEmptyString(clientId)) {
292292
errorMessage = 'Refresh token must contain a "client_id" property.';
293-
} else if (!util.isNonEmptyString(this.clientSecret)) {
293+
} else if (!util.isNonEmptyString(clientSecret)) {
294294
errorMessage = 'Refresh token must contain a "client_secret" property.';
295-
} else if (!util.isNonEmptyString(this.refreshToken)) {
295+
} else if (!util.isNonEmptyString(refreshToken)) {
296296
errorMessage = 'Refresh token must contain a "refresh_token" property.';
297-
} else if (!util.isNonEmptyString(this.type)) {
297+
} else if (!util.isNonEmptyString(type)) {
298298
errorMessage = 'Refresh token must contain a "type" property.';
299299
}
300300

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

330330
(typeof impersonatedServiceAccountPathOrObject === 'string') ?
331-
ImpersonatedServiceAccount.fromPath(impersonatedServiceAccountPathOrObject)
332-
: new ImpersonatedServiceAccount(impersonatedServiceAccountPathOrObject);
331+
ImpersonatedServiceAccount.validateFromPath(impersonatedServiceAccountPathOrObject)
332+
: ImpersonatedServiceAccount.validateFromJSON(impersonatedServiceAccountPathOrObject);
333333
}
334334

335335
private getGoogleAuth(): GoogleAuth {
@@ -350,22 +350,17 @@ export class ImpersonatedServiceAccountCredential implements Credential {
350350
}
351351

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

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

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

387378
let errorMessage;
388-
if (!util.isNonEmptyString(this.clientId)) {
379+
if (!util.isNonEmptyString(clientId)) {
389380
errorMessage = 'Impersonated Service Account must contain a "source_credentials.client_id" property.';
390-
} else if (!util.isNonEmptyString(this.clientSecret)) {
381+
} else if (!util.isNonEmptyString(clientSecret)) {
391382
errorMessage = 'Impersonated Service Account must contain a "source_credentials.client_secret" property.';
392-
} else if (!util.isNonEmptyString(this.refreshToken)) {
383+
} else if (!util.isNonEmptyString(refreshToken)) {
393384
errorMessage = 'Impersonated Service Account must contain a "source_credentials.refresh_token" property.';
394-
} else if (!util.isNonEmptyString(this.type)) {
385+
} else if (!util.isNonEmptyString(type)) {
395386
errorMessage = 'Impersonated Service Account must contain a "source_credentials.type" property.';
396387
}
397388

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

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

0 commit comments

Comments
 (0)