Skip to content

Commit 9c009a4

Browse files
committed
Enable 'structNullChecks' ts compiler option.
In the majority of cases, I simply turned stuff like this: ``` function fname(param: T) { if (!param) throw Error("invalid param; must not be nullish"); ... } ``` into this: ``` function fname(param: T|null|undefined) { if (!param) throw Error("invalid param; must not be nullish"); ... } ``` A more sensible approach would be eliminate the possibility of null/undef and eliminate the checks too, but that's a bit more involved and this patch is already enormous. But I think these sorts of improvements could be taken advantage of opportunistically as the code is worked on in the future.
1 parent 2605cf1 commit 9c009a4

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

55 files changed

+553
-436
lines changed

package-lock.json

Lines changed: 48 additions & 99 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@
6767
"devDependencies": {
6868
"@firebase/app": "^0.4.10",
6969
"@firebase/auth": "^0.11.3",
70+
"@firebase/auth-types": "^0.8.2",
7071
"@types/bcrypt": "^2.0.0",
7172
"@types/chai": "^3.4.34",
7273
"@types/chai-as-promised": "0.0.29",

src/auth/action-code-settings-builder.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ export class ActionCodeSettingsBuilder {
6363
* object used to initiliaze this server request builder.
6464
* @constructor
6565
*/
66-
constructor(actionCodeSettings: ActionCodeSettings) {
66+
constructor(actionCodeSettings?: ActionCodeSettings) {
6767
if (!validator.isNonNullObject(actionCodeSettings)) {
6868
throw new FirebaseAuthError(
6969
AuthClientErrorCode.INVALID_ARGUMENT,

src/auth/auth-api-request.ts

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ class AuthResourceUrlBuilder {
9797
* @param {string} version The endpoint API version.
9898
* @constructor
9999
*/
100-
constructor(protected projectId: string, protected version: string = 'v1') {
100+
constructor(protected projectId: string | null, protected version: string = 'v1') {
101101
this.urlFormat = FIREBASE_AUTH_BASE_URL_FORMAT;
102102
}
103103

@@ -132,7 +132,7 @@ class TenantAwareAuthResourceUrlBuilder extends AuthResourceUrlBuilder {
132132
* @param {string} tenantId The tenant ID.
133133
* @constructor
134134
*/
135-
constructor(protected projectId: string, protected version: string, protected tenantId: string) {
135+
constructor(protected projectId: string | null, protected version: string, protected tenantId: string) {
136136
super(projectId, version);
137137
this.urlFormat = FIREBASE_AUTH_TENANT_URL_FORMAT;
138138
}
@@ -683,7 +683,7 @@ const LIST_INBOUND_SAML_CONFIGS = new ApiSettings('/inboundSamlConfigs', 'GET')
683683
* Class that provides the mechanism to send requests to the Firebase Auth backend endpoints.
684684
*/
685685
export abstract class AbstractAuthRequestHandler {
686-
protected readonly projectId: string;
686+
protected readonly projectId: string | null;
687687
protected readonly httpClient: AuthorizedHttpClient;
688688
private authUrlBuilder: AuthResourceUrlBuilder;
689689
private projectConfigUrlBuilder: AuthResourceUrlBuilder;
@@ -693,7 +693,7 @@ export abstract class AbstractAuthRequestHandler {
693693
* @return {string|null} The error code if present; null otherwise.
694694
*/
695695
private static getErrorCode(response: any): string | null {
696-
return (validator.isNonNullObject(response) && response.error && (response.error as any).message) || null;
696+
return (validator.isNonNullObject(response) && (response as any).error && (response as any).error.message) || null;
697697
}
698698

699699
/**
@@ -844,7 +844,7 @@ export abstract class AbstractAuthRequestHandler {
844844
}
845845
// If no remaining user in request after client side processing, there is no need
846846
// to send the request to the server.
847-
if (request.users.length === 0) {
847+
if (!request.users || request.users.length === 0) {
848848
return Promise.resolve(userImportBuilder.buildResponse([]));
849849
}
850850
return this.invokeRequestHandler(this.getAuthUrlBuilder(), FIREBASE_AUTH_UPLOAD_ACCOUNT, request)
@@ -881,7 +881,7 @@ export abstract class AbstractAuthRequestHandler {
881881
* @return {Promise<string>} A promise that resolves when the operation completes
882882
* with the user id that was edited.
883883
*/
884-
public setCustomUserClaims(uid: string, customUserClaims: object): Promise<string> {
884+
public setCustomUserClaims(uid: string, customUserClaims: object | null): Promise<string> {
885885
// Validate user UID.
886886
if (!validator.isUid(uid)) {
887887
return Promise.reject(new FirebaseAuthError(AuthClientErrorCode.INVALID_UID));
@@ -1059,7 +1059,7 @@ export abstract class AbstractAuthRequestHandler {
10591059
* @param {string} email The email of the user the link is being sent to.
10601060
* @param {ActionCodeSettings=} actionCodeSettings The optional action code setings which defines whether
10611061
* the link is to be handled by a mobile app and the additional state information to be passed in the
1062-
* deep link, etc.
1062+
* deep link, etc. Required when requestType == 'EMAIL_SIGNIN'
10631063
* @return {Promise<string>} A promise that resolves with the email action link.
10641064
*/
10651065
public getEmailActionLink(
@@ -1156,7 +1156,7 @@ export abstract class AbstractAuthRequestHandler {
11561156
// Construct backend request.
11571157
let request;
11581158
try {
1159-
request = OIDCConfig.buildServerRequest(options);
1159+
request = OIDCConfig.buildServerRequest(options) || {};
11601160
} catch (e) {
11611161
return Promise.reject(e);
11621162
}
@@ -1278,7 +1278,7 @@ export abstract class AbstractAuthRequestHandler {
12781278
// Construct backend request.
12791279
let request;
12801280
try {
1281-
request = SAMLConfig.buildServerRequest(options);
1281+
request = SAMLConfig.buildServerRequest(options) || {};
12821282
} catch (e) {
12831283
return Promise.reject(e);
12841284
}
@@ -1311,7 +1311,7 @@ export abstract class AbstractAuthRequestHandler {
13111311
// Construct backend request.
13121312
let request: SAMLConfigServerRequest;
13131313
try {
1314-
request = SAMLConfig.buildServerRequest(options, true);
1314+
request = SAMLConfig.buildServerRequest(options, true) || {};
13151315
} catch (e) {
13161316
return Promise.reject(e);
13171317
}
@@ -1366,6 +1366,14 @@ export abstract class AbstractAuthRequestHandler {
13661366
if (err instanceof HttpError) {
13671367
const error = err.response.data;
13681368
const errorCode = AbstractAuthRequestHandler.getErrorCode(error);
1369+
if (!errorCode) {
1370+
throw new FirebaseAuthError(
1371+
AuthClientErrorCode.INTERNAL_ERROR,
1372+
'Error returned from server: ' + error + '. Additionally, an ' +
1373+
'internal error occurred while attempting to extract the ' +
1374+
'errorcode from the error.',
1375+
);
1376+
}
13691377
throw FirebaseAuthError.fromServerError(errorCode, /* message */ undefined, error);
13701378
}
13711379
throw err;

src/auth/auth-config.ts

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -193,7 +193,7 @@ export class EmailSignInConfig implements EmailSignInProviderConfig {
193193
*
194194
* @param {any} options The options object to validate.
195195
*/
196-
private static validate(options: {[key: string]: any}) {
196+
private static validate(options: EmailSignInProviderConfig) {
197197
// TODO: Validate the request.
198198
const validKeys = {
199199
enabled: true,
@@ -306,7 +306,7 @@ export class SAMLConfig implements SAMLAuthProviderConfig {
306306
};
307307
if (options.x509Certificates) {
308308
for (const cert of (options.x509Certificates || [])) {
309-
request.idpConfig.idpCertificates.push({x509Certificate: cert});
309+
request.idpConfig!.idpCertificates!.push({x509Certificate: cert});
310310
}
311311
}
312312
}
@@ -467,15 +467,26 @@ export class SAMLConfig implements SAMLAuthProviderConfig {
467467
constructor(response: SAMLConfigServerResponse) {
468468
if (!response ||
469469
!response.idpConfig ||
470+
!response.idpConfig.idpEntityId ||
471+
!response.idpConfig.ssoUrl ||
470472
!response.spConfig ||
473+
!response.spConfig.spEntityId ||
471474
!response.name ||
472475
!(validator.isString(response.name) &&
473476
SAMLConfig.getProviderIdFromResourceName(response.name))) {
474477
throw new FirebaseAuthError(
475478
AuthClientErrorCode.INTERNAL_ERROR,
476479
'INTERNAL ASSERT FAILED: Invalid SAML configuration response');
477480
}
478-
this.providerId = SAMLConfig.getProviderIdFromResourceName(response.name);
481+
482+
const providerId = SAMLConfig.getProviderIdFromResourceName(response.name);
483+
if (!providerId) {
484+
throw new FirebaseAuthError(
485+
AuthClientErrorCode.INTERNAL_ERROR,
486+
'INTERNAL ASSERT FAILED: Invalid SAML configuration response');
487+
}
488+
this.providerId = providerId;
489+
479490
// RP config.
480491
this.rpEntityId = response.spConfig.spEntityId;
481492
this.callbackURL = response.spConfig.callbackUri;
@@ -663,7 +674,15 @@ export class OIDCConfig implements OIDCAuthProviderConfig {
663674
AuthClientErrorCode.INTERNAL_ERROR,
664675
'INTERNAL ASSERT FAILED: Invalid OIDC configuration response');
665676
}
666-
this.providerId = OIDCConfig.getProviderIdFromResourceName(response.name);
677+
678+
const providerId = OIDCConfig.getProviderIdFromResourceName(response.name);
679+
if (!providerId) {
680+
throw new FirebaseAuthError(
681+
AuthClientErrorCode.INTERNAL_ERROR,
682+
'INTERNAL ASSERT FAILED: Invalid SAML configuration response');
683+
}
684+
this.providerId = providerId;
685+
667686
this.clientId = response.clientId;
668687
this.issuer = response.issuer;
669688
// When enabled is undefined, it takes its default value of false.

src/auth/auth.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ export class BaseAuth<T extends AbstractAuthRequestHandler> {
104104
* minting.
105105
* @constructor
106106
*/
107-
constructor(protected readonly projectId: string,
107+
constructor(protected readonly projectId: string | null,
108108
protected readonly authRequestHandler: T,
109109
cryptoSigner: CryptoSigner) {
110110
this.tokenGenerator = new FirebaseTokenGenerator(cryptoSigner);
@@ -731,7 +731,7 @@ export class Auth extends BaseAuth<AuthRequestHandler> implements FirebaseServic
731731
* @param {FirebaseApp} app The project ID for an app.
732732
* @return {string} The FirebaseApp's project ID.
733733
*/
734-
private static getProjectId(app: FirebaseApp): string {
734+
private static getProjectId(app: FirebaseApp): string | null {
735735
if (typeof app !== 'object' || app === null || !('options' in app)) {
736736
throw new FirebaseAuthError(
737737
AuthClientErrorCode.INVALID_ARGUMENT,

src/auth/credential.ts

Lines changed: 28 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ import fs = require('fs');
1919
import os = require('os');
2020
import path = require('path');
2121

22-
import {AppErrorCodes, FirebaseAppError} from '../utils/error';
22+
import {AppErrorCodes, FirebaseAppError, FirebaseAuthError, AuthClientErrorCode} from '../utils/error';
2323
import {HttpClient, HttpRequestConfig, HttpError, HttpResponse} from '../utils/api-request';
2424
import {Agent} from 'http';
2525

@@ -69,7 +69,7 @@ export class RefreshToken {
6969
* Tries to load a RefreshToken from a path. If the path is not present, returns null.
7070
* Throws if data at the path is invalid.
7171
*/
72-
public static fromPath(filePath: string): RefreshToken {
72+
public static fromPath(filePath: string): RefreshToken | null {
7373
let jsonString: string;
7474

7575
try {
@@ -224,7 +224,7 @@ function getDetailFromResponse(response: HttpResponse): string {
224224
}
225225
return detail;
226226
}
227-
return response.text;
227+
return response.text || 'Missing Error Payload';
228228
}
229229

230230
/**
@@ -234,7 +234,7 @@ export class CertCredential implements FirebaseCredential {
234234

235235
private readonly certificate: Certificate;
236236
private readonly httpClient: HttpClient;
237-
private readonly httpAgent: Agent;
237+
private readonly httpAgent?: Agent;
238238

239239
constructor(serviceAccountPathOrObject: string | object, httpAgent?: Agent) {
240240
this.certificate = (typeof serviceAccountPathOrObject === 'string') ?
@@ -306,8 +306,8 @@ export interface FirebaseCredential extends Credential {
306306
* @param {Credential} credential A Credential instance.
307307
* @return {Certificate} A Certificate instance or null.
308308
*/
309-
export function tryGetCertificate(credential: Credential): Certificate | null {
310-
if (isFirebaseCredential(credential)) {
309+
export function tryGetCertificate(credential?: Credential): Certificate | null {
310+
if (credential && isFirebaseCredential(credential)) {
311311
return credential.getCertificate();
312312
}
313313

@@ -325,11 +325,22 @@ export class RefreshTokenCredential implements Credential {
325325

326326
private readonly refreshToken: RefreshToken;
327327
private readonly httpClient: HttpClient;
328-
private readonly httpAgent: Agent;
328+
private readonly httpAgent?: Agent;
329329

330330
constructor(refreshTokenPathOrObject: string | object, httpAgent?: Agent) {
331-
this.refreshToken = (typeof refreshTokenPathOrObject === 'string') ?
332-
RefreshToken.fromPath(refreshTokenPathOrObject) : new RefreshToken(refreshTokenPathOrObject);
331+
if (typeof refreshTokenPathOrObject === 'string') {
332+
const refreshTokenOrNull = RefreshToken.fromPath(refreshTokenPathOrObject);
333+
if (!refreshTokenOrNull) {
334+
throw new FirebaseAuthError(
335+
AuthClientErrorCode.NOT_FOUND,
336+
'The file refered to by the refreshTokenPathOrObject parameter (' +
337+
refreshTokenPathOrObject + ') was not found.',
338+
);
339+
}
340+
this.refreshToken = refreshTokenOrNull;
341+
} else {
342+
this.refreshToken = new RefreshToken(refreshTokenPathOrObject);
343+
}
333344
this.httpClient = new HttpClient();
334345
this.httpAgent = httpAgent;
335346
}
@@ -362,7 +373,7 @@ export class RefreshTokenCredential implements Credential {
362373
export class MetadataServiceCredential implements Credential {
363374

364375
private readonly httpClient = new HttpClient();
365-
private readonly httpAgent: Agent;
376+
private readonly httpAgent?: Agent;
366377

367378
constructor(httpAgent?: Agent) {
368379
this.httpAgent = httpAgent;
@@ -396,10 +407,12 @@ export class ApplicationDefaultCredential implements FirebaseCredential {
396407
}
397408

398409
// It is OK to not have this file. If it is present, it must be valid.
399-
const refreshToken = RefreshToken.fromPath(GCLOUD_CREDENTIAL_PATH);
400-
if (refreshToken) {
401-
this.credential_ = new RefreshTokenCredential(refreshToken, httpAgent);
402-
return;
410+
if (GCLOUD_CREDENTIAL_PATH) {
411+
const refreshToken = RefreshToken.fromPath(GCLOUD_CREDENTIAL_PATH);
412+
if (refreshToken) {
413+
this.credential_ = new RefreshTokenCredential(refreshToken, httpAgent);
414+
return;
415+
}
403416
}
404417

405418
this.credential_ = new MetadataServiceCredential(httpAgent);
@@ -409,7 +422,7 @@ export class ApplicationDefaultCredential implements FirebaseCredential {
409422
return this.credential_.getAccessToken();
410423
}
411424

412-
public getCertificate(): Certificate {
425+
public getCertificate(): Certificate | null {
413426
return tryGetCertificate(this.credential_);
414427
}
415428

src/auth/tenant.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -117,17 +117,17 @@ export class Tenant {
117117
}
118118
}
119119
// Validate displayName type if provided.
120-
if (typeof request.displayName !== 'undefined' &&
121-
!validator.isNonEmptyString(request.displayName)) {
120+
if (typeof (request as any).displayName !== 'undefined' &&
121+
!validator.isNonEmptyString((request as any).displayName)) {
122122
throw new FirebaseAuthError(
123123
AuthClientErrorCode.INVALID_ARGUMENT,
124124
`"${label}.displayName" must be a valid non-empty string.`,
125125
);
126126
}
127127
// Validate emailSignInConfig type if provided.
128-
if (typeof request.emailSignInConfig !== 'undefined') {
128+
if (typeof (request as any).emailSignInConfig !== 'undefined') {
129129
// This will throw an error if invalid.
130-
EmailSignInConfig.buildServerRequest(request.emailSignInConfig);
130+
EmailSignInConfig.buildServerRequest((request as any).emailSignInConfig);
131131
}
132132
}
133133

0 commit comments

Comments
 (0)