UNPKG

31.5 kBJavaScriptView Raw
1/*! firebase-admin v10.0.0 */
2"use strict";
3/*!
4 * Copyright 2018 Google Inc.
5 *
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
17 */
18Object.defineProperty(exports, "__esModule", { value: true });
19exports.OIDCConfig = exports.SAMLConfig = exports.EmailSignInConfig = exports.validateTestPhoneNumbers = exports.MultiFactorAuthConfig = exports.MAXIMUM_TEST_PHONE_NUMBERS = void 0;
20var validator = require("../utils/validator");
21var deep_copy_1 = require("../utils/deep-copy");
22var error_1 = require("../utils/error");
23/** A maximum of 10 test phone number / code pairs can be configured. */
24exports.MAXIMUM_TEST_PHONE_NUMBERS = 10;
25/** Client Auth factor type to server auth factor type mapping. */
26var AUTH_FACTOR_CLIENT_TO_SERVER_TYPE = {
27 phone: 'PHONE_SMS',
28};
29/** Server Auth factor type to client auth factor type mapping. */
30var AUTH_FACTOR_SERVER_TO_CLIENT_TYPE = Object.keys(AUTH_FACTOR_CLIENT_TO_SERVER_TYPE)
31 .reduce(function (res, key) {
32 res[AUTH_FACTOR_CLIENT_TO_SERVER_TYPE[key]] = key;
33 return res;
34}, {});
35/**
36 * Defines the multi-factor config class used to convert client side MultiFactorConfig
37 * to a format that is understood by the Auth server.
38 */
39var MultiFactorAuthConfig = /** @class */ (function () {
40 /**
41 * The MultiFactorAuthConfig constructor.
42 *
43 * @param response - The server side response used to initialize the
44 * MultiFactorAuthConfig object.
45 * @constructor
46 * @internal
47 */
48 function MultiFactorAuthConfig(response) {
49 var _this = this;
50 if (typeof response.state === 'undefined') {
51 throw new error_1.FirebaseAuthError(error_1.AuthClientErrorCode.INTERNAL_ERROR, 'INTERNAL ASSERT FAILED: Invalid multi-factor configuration response');
52 }
53 this.state = response.state;
54 this.factorIds = [];
55 (response.enabledProviders || []).forEach(function (enabledProvider) {
56 // Ignore unsupported types. It is possible the current admin SDK version is
57 // not up to date and newer backend types are supported.
58 if (typeof AUTH_FACTOR_SERVER_TO_CLIENT_TYPE[enabledProvider] !== 'undefined') {
59 _this.factorIds.push(AUTH_FACTOR_SERVER_TO_CLIENT_TYPE[enabledProvider]);
60 }
61 });
62 }
63 /**
64 * Static method to convert a client side request to a MultiFactorAuthServerConfig.
65 * Throws an error if validation fails.
66 *
67 * @param options - The options object to convert to a server request.
68 * @returns The resulting server request.
69 * @internal
70 */
71 MultiFactorAuthConfig.buildServerRequest = function (options) {
72 var request = {};
73 MultiFactorAuthConfig.validate(options);
74 if (Object.prototype.hasOwnProperty.call(options, 'state')) {
75 request.state = options.state;
76 }
77 if (Object.prototype.hasOwnProperty.call(options, 'factorIds')) {
78 (options.factorIds || []).forEach(function (factorId) {
79 if (typeof request.enabledProviders === 'undefined') {
80 request.enabledProviders = [];
81 }
82 request.enabledProviders.push(AUTH_FACTOR_CLIENT_TO_SERVER_TYPE[factorId]);
83 });
84 // In case an empty array is passed. Ensure it gets populated so the array is cleared.
85 if (options.factorIds && options.factorIds.length === 0) {
86 request.enabledProviders = [];
87 }
88 }
89 return request;
90 };
91 /**
92 * Validates the MultiFactorConfig options object. Throws an error on failure.
93 *
94 * @param options - The options object to validate.
95 */
96 MultiFactorAuthConfig.validate = function (options) {
97 var validKeys = {
98 state: true,
99 factorIds: true,
100 };
101 if (!validator.isNonNullObject(options)) {
102 throw new error_1.FirebaseAuthError(error_1.AuthClientErrorCode.INVALID_CONFIG, '"MultiFactorConfig" must be a non-null object.');
103 }
104 // Check for unsupported top level attributes.
105 for (var key in options) {
106 if (!(key in validKeys)) {
107 throw new error_1.FirebaseAuthError(error_1.AuthClientErrorCode.INVALID_CONFIG, "\"" + key + "\" is not a valid MultiFactorConfig parameter.");
108 }
109 }
110 // Validate content.
111 if (typeof options.state !== 'undefined' &&
112 options.state !== 'ENABLED' &&
113 options.state !== 'DISABLED') {
114 throw new error_1.FirebaseAuthError(error_1.AuthClientErrorCode.INVALID_CONFIG, '"MultiFactorConfig.state" must be either "ENABLED" or "DISABLED".');
115 }
116 if (typeof options.factorIds !== 'undefined') {
117 if (!validator.isArray(options.factorIds)) {
118 throw new error_1.FirebaseAuthError(error_1.AuthClientErrorCode.INVALID_CONFIG, '"MultiFactorConfig.factorIds" must be an array of valid "AuthFactorTypes".');
119 }
120 // Validate content of array.
121 options.factorIds.forEach(function (factorId) {
122 if (typeof AUTH_FACTOR_CLIENT_TO_SERVER_TYPE[factorId] === 'undefined') {
123 throw new error_1.FirebaseAuthError(error_1.AuthClientErrorCode.INVALID_CONFIG, "\"" + factorId + "\" is not a valid \"AuthFactorType\".");
124 }
125 });
126 }
127 };
128 /** @returns The plain object representation of the multi-factor config instance. */
129 MultiFactorAuthConfig.prototype.toJSON = function () {
130 return {
131 state: this.state,
132 factorIds: this.factorIds,
133 };
134 };
135 return MultiFactorAuthConfig;
136}());
137exports.MultiFactorAuthConfig = MultiFactorAuthConfig;
138/**
139 * Validates the provided map of test phone number / code pairs.
140 * @param testPhoneNumbers - The phone number / code pairs to validate.
141 */
142function validateTestPhoneNumbers(testPhoneNumbers) {
143 if (!validator.isObject(testPhoneNumbers)) {
144 throw new error_1.FirebaseAuthError(error_1.AuthClientErrorCode.INVALID_ARGUMENT, '"testPhoneNumbers" must be a map of phone number / code pairs.');
145 }
146 if (Object.keys(testPhoneNumbers).length > exports.MAXIMUM_TEST_PHONE_NUMBERS) {
147 throw new error_1.FirebaseAuthError(error_1.AuthClientErrorCode.MAXIMUM_TEST_PHONE_NUMBER_EXCEEDED);
148 }
149 for (var phoneNumber in testPhoneNumbers) {
150 // Validate phone number.
151 if (!validator.isPhoneNumber(phoneNumber)) {
152 throw new error_1.FirebaseAuthError(error_1.AuthClientErrorCode.INVALID_TESTING_PHONE_NUMBER, "\"" + phoneNumber + "\" is not a valid E.164 standard compliant phone number.");
153 }
154 // Validate code.
155 if (!validator.isString(testPhoneNumbers[phoneNumber]) ||
156 !/^[\d]{6}$/.test(testPhoneNumbers[phoneNumber])) {
157 throw new error_1.FirebaseAuthError(error_1.AuthClientErrorCode.INVALID_TESTING_PHONE_NUMBER, "\"" + testPhoneNumbers[phoneNumber] + "\" is not a valid 6 digit code string.");
158 }
159 }
160}
161exports.validateTestPhoneNumbers = validateTestPhoneNumbers;
162/**
163 * Defines the email sign-in config class used to convert client side EmailSignInConfig
164 * to a format that is understood by the Auth server.
165 *
166 * @internal
167 */
168var EmailSignInConfig = /** @class */ (function () {
169 /**
170 * The EmailSignInConfig constructor.
171 *
172 * @param response - The server side response used to initialize the
173 * EmailSignInConfig object.
174 * @constructor
175 */
176 function EmailSignInConfig(response) {
177 if (typeof response.allowPasswordSignup === 'undefined') {
178 throw new error_1.FirebaseAuthError(error_1.AuthClientErrorCode.INTERNAL_ERROR, 'INTERNAL ASSERT FAILED: Invalid email sign-in configuration response');
179 }
180 this.enabled = response.allowPasswordSignup;
181 this.passwordRequired = !response.enableEmailLinkSignin;
182 }
183 /**
184 * Static method to convert a client side request to a EmailSignInConfigServerRequest.
185 * Throws an error if validation fails.
186 *
187 * @param options - The options object to convert to a server request.
188 * @returns The resulting server request.
189 * @internal
190 */
191 EmailSignInConfig.buildServerRequest = function (options) {
192 var request = {};
193 EmailSignInConfig.validate(options);
194 if (Object.prototype.hasOwnProperty.call(options, 'enabled')) {
195 request.allowPasswordSignup = options.enabled;
196 }
197 if (Object.prototype.hasOwnProperty.call(options, 'passwordRequired')) {
198 request.enableEmailLinkSignin = !options.passwordRequired;
199 }
200 return request;
201 };
202 /**
203 * Validates the EmailSignInConfig options object. Throws an error on failure.
204 *
205 * @param options - The options object to validate.
206 */
207 EmailSignInConfig.validate = function (options) {
208 // TODO: Validate the request.
209 var validKeys = {
210 enabled: true,
211 passwordRequired: true,
212 };
213 if (!validator.isNonNullObject(options)) {
214 throw new error_1.FirebaseAuthError(error_1.AuthClientErrorCode.INVALID_ARGUMENT, '"EmailSignInConfig" must be a non-null object.');
215 }
216 // Check for unsupported top level attributes.
217 for (var key in options) {
218 if (!(key in validKeys)) {
219 throw new error_1.FirebaseAuthError(error_1.AuthClientErrorCode.INVALID_ARGUMENT, "\"" + key + "\" is not a valid EmailSignInConfig parameter.");
220 }
221 }
222 // Validate content.
223 if (typeof options.enabled !== 'undefined' &&
224 !validator.isBoolean(options.enabled)) {
225 throw new error_1.FirebaseAuthError(error_1.AuthClientErrorCode.INVALID_ARGUMENT, '"EmailSignInConfig.enabled" must be a boolean.');
226 }
227 if (typeof options.passwordRequired !== 'undefined' &&
228 !validator.isBoolean(options.passwordRequired)) {
229 throw new error_1.FirebaseAuthError(error_1.AuthClientErrorCode.INVALID_ARGUMENT, '"EmailSignInConfig.passwordRequired" must be a boolean.');
230 }
231 };
232 /** @returns The plain object representation of the email sign-in config. */
233 EmailSignInConfig.prototype.toJSON = function () {
234 return {
235 enabled: this.enabled,
236 passwordRequired: this.passwordRequired,
237 };
238 };
239 return EmailSignInConfig;
240}());
241exports.EmailSignInConfig = EmailSignInConfig;
242/**
243 * Defines the SAMLConfig class used to convert a client side configuration to its
244 * server side representation.
245 *
246 * @internal
247 */
248var SAMLConfig = /** @class */ (function () {
249 /**
250 * The SAMLConfig constructor.
251 *
252 * @param response - The server side response used to initialize the SAMLConfig object.
253 * @constructor
254 */
255 function SAMLConfig(response) {
256 if (!response ||
257 !response.idpConfig ||
258 !response.idpConfig.idpEntityId ||
259 !response.idpConfig.ssoUrl ||
260 !response.spConfig ||
261 !response.spConfig.spEntityId ||
262 !response.name ||
263 !(validator.isString(response.name) &&
264 SAMLConfig.getProviderIdFromResourceName(response.name))) {
265 throw new error_1.FirebaseAuthError(error_1.AuthClientErrorCode.INTERNAL_ERROR, 'INTERNAL ASSERT FAILED: Invalid SAML configuration response');
266 }
267 var providerId = SAMLConfig.getProviderIdFromResourceName(response.name);
268 if (!providerId) {
269 throw new error_1.FirebaseAuthError(error_1.AuthClientErrorCode.INTERNAL_ERROR, 'INTERNAL ASSERT FAILED: Invalid SAML configuration response');
270 }
271 this.providerId = providerId;
272 // RP config.
273 this.rpEntityId = response.spConfig.spEntityId;
274 this.callbackURL = response.spConfig.callbackUri;
275 // IdP config.
276 this.idpEntityId = response.idpConfig.idpEntityId;
277 this.ssoURL = response.idpConfig.ssoUrl;
278 this.enableRequestSigning = !!response.idpConfig.signRequest;
279 var x509Certificates = [];
280 for (var _i = 0, _a = (response.idpConfig.idpCertificates || []); _i < _a.length; _i++) {
281 var cert = _a[_i];
282 if (cert.x509Certificate) {
283 x509Certificates.push(cert.x509Certificate);
284 }
285 }
286 this.x509Certificates = x509Certificates;
287 // When enabled is undefined, it takes its default value of false.
288 this.enabled = !!response.enabled;
289 this.displayName = response.displayName;
290 }
291 /**
292 * Converts a client side request to a SAMLConfigServerRequest which is the format
293 * accepted by the backend server.
294 * Throws an error if validation fails. If the request is not a SAMLConfig request,
295 * returns null.
296 *
297 * @param options - The options object to convert to a server request.
298 * @param ignoreMissingFields - Whether to ignore missing fields.
299 * @returns The resulting server request or null if not valid.
300 */
301 SAMLConfig.buildServerRequest = function (options, ignoreMissingFields) {
302 if (ignoreMissingFields === void 0) { ignoreMissingFields = false; }
303 var makeRequest = validator.isNonNullObject(options) &&
304 (options.providerId || ignoreMissingFields);
305 if (!makeRequest) {
306 return null;
307 }
308 var request = {};
309 // Validate options.
310 SAMLConfig.validate(options, ignoreMissingFields);
311 request.enabled = options.enabled;
312 request.displayName = options.displayName;
313 // IdP config.
314 if (options.idpEntityId || options.ssoURL || options.x509Certificates) {
315 request.idpConfig = {
316 idpEntityId: options.idpEntityId,
317 ssoUrl: options.ssoURL,
318 signRequest: options.enableRequestSigning,
319 idpCertificates: typeof options.x509Certificates === 'undefined' ? undefined : [],
320 };
321 if (options.x509Certificates) {
322 for (var _i = 0, _a = (options.x509Certificates || []); _i < _a.length; _i++) {
323 var cert = _a[_i];
324 request.idpConfig.idpCertificates.push({ x509Certificate: cert });
325 }
326 }
327 }
328 // RP config.
329 if (options.callbackURL || options.rpEntityId) {
330 request.spConfig = {
331 spEntityId: options.rpEntityId,
332 callbackUri: options.callbackURL,
333 };
334 }
335 return request;
336 };
337 /**
338 * Returns the provider ID corresponding to the resource name if available.
339 *
340 * @param resourceName - The server side resource name.
341 * @returns The provider ID corresponding to the resource, null otherwise.
342 */
343 SAMLConfig.getProviderIdFromResourceName = function (resourceName) {
344 // name is of form projects/project1/inboundSamlConfigs/providerId1
345 var matchProviderRes = resourceName.match(/\/inboundSamlConfigs\/(saml\..*)$/);
346 if (!matchProviderRes || matchProviderRes.length < 2) {
347 return null;
348 }
349 return matchProviderRes[1];
350 };
351 /**
352 * @param providerId - The provider ID to check.
353 * @returns Whether the provider ID corresponds to a SAML provider.
354 */
355 SAMLConfig.isProviderId = function (providerId) {
356 return validator.isNonEmptyString(providerId) && providerId.indexOf('saml.') === 0;
357 };
358 /**
359 * Validates the SAMLConfig options object. Throws an error on failure.
360 *
361 * @param options - The options object to validate.
362 * @param ignoreMissingFields - Whether to ignore missing fields.
363 */
364 SAMLConfig.validate = function (options, ignoreMissingFields) {
365 if (ignoreMissingFields === void 0) { ignoreMissingFields = false; }
366 var validKeys = {
367 enabled: true,
368 displayName: true,
369 providerId: true,
370 idpEntityId: true,
371 ssoURL: true,
372 x509Certificates: true,
373 rpEntityId: true,
374 callbackURL: true,
375 enableRequestSigning: true,
376 };
377 if (!validator.isNonNullObject(options)) {
378 throw new error_1.FirebaseAuthError(error_1.AuthClientErrorCode.INVALID_CONFIG, '"SAMLAuthProviderConfig" must be a valid non-null object.');
379 }
380 // Check for unsupported top level attributes.
381 for (var key in options) {
382 if (!(key in validKeys)) {
383 throw new error_1.FirebaseAuthError(error_1.AuthClientErrorCode.INVALID_CONFIG, "\"" + key + "\" is not a valid SAML config parameter.");
384 }
385 }
386 // Required fields.
387 if (validator.isNonEmptyString(options.providerId)) {
388 if (options.providerId.indexOf('saml.') !== 0) {
389 throw new error_1.FirebaseAuthError(error_1.AuthClientErrorCode.INVALID_PROVIDER_ID, '"SAMLAuthProviderConfig.providerId" must be a valid non-empty string prefixed with "saml.".');
390 }
391 }
392 else if (!ignoreMissingFields) {
393 // providerId is required and not provided correctly.
394 throw new error_1.FirebaseAuthError(!options.providerId ? error_1.AuthClientErrorCode.MISSING_PROVIDER_ID : error_1.AuthClientErrorCode.INVALID_PROVIDER_ID, '"SAMLAuthProviderConfig.providerId" must be a valid non-empty string prefixed with "saml.".');
395 }
396 if (!(ignoreMissingFields && typeof options.idpEntityId === 'undefined') &&
397 !validator.isNonEmptyString(options.idpEntityId)) {
398 throw new error_1.FirebaseAuthError(error_1.AuthClientErrorCode.INVALID_CONFIG, '"SAMLAuthProviderConfig.idpEntityId" must be a valid non-empty string.');
399 }
400 if (!(ignoreMissingFields && typeof options.ssoURL === 'undefined') &&
401 !validator.isURL(options.ssoURL)) {
402 throw new error_1.FirebaseAuthError(error_1.AuthClientErrorCode.INVALID_CONFIG, '"SAMLAuthProviderConfig.ssoURL" must be a valid URL string.');
403 }
404 if (!(ignoreMissingFields && typeof options.rpEntityId === 'undefined') &&
405 !validator.isNonEmptyString(options.rpEntityId)) {
406 throw new error_1.FirebaseAuthError(!options.rpEntityId ? error_1.AuthClientErrorCode.MISSING_SAML_RELYING_PARTY_CONFIG :
407 error_1.AuthClientErrorCode.INVALID_CONFIG, '"SAMLAuthProviderConfig.rpEntityId" must be a valid non-empty string.');
408 }
409 if (!(ignoreMissingFields && typeof options.callbackURL === 'undefined') &&
410 !validator.isURL(options.callbackURL)) {
411 throw new error_1.FirebaseAuthError(error_1.AuthClientErrorCode.INVALID_CONFIG, '"SAMLAuthProviderConfig.callbackURL" must be a valid URL string.');
412 }
413 if (!(ignoreMissingFields && typeof options.x509Certificates === 'undefined') &&
414 !validator.isArray(options.x509Certificates)) {
415 throw new error_1.FirebaseAuthError(error_1.AuthClientErrorCode.INVALID_CONFIG, '"SAMLAuthProviderConfig.x509Certificates" must be a valid array of X509 certificate strings.');
416 }
417 (options.x509Certificates || []).forEach(function (cert) {
418 if (!validator.isNonEmptyString(cert)) {
419 throw new error_1.FirebaseAuthError(error_1.AuthClientErrorCode.INVALID_CONFIG, '"SAMLAuthProviderConfig.x509Certificates" must be a valid array of X509 certificate strings.');
420 }
421 });
422 if (typeof options.enableRequestSigning !== 'undefined' &&
423 !validator.isBoolean(options.enableRequestSigning)) {
424 throw new error_1.FirebaseAuthError(error_1.AuthClientErrorCode.INVALID_CONFIG, '"SAMLAuthProviderConfig.enableRequestSigning" must be a boolean.');
425 }
426 if (typeof options.enabled !== 'undefined' &&
427 !validator.isBoolean(options.enabled)) {
428 throw new error_1.FirebaseAuthError(error_1.AuthClientErrorCode.INVALID_CONFIG, '"SAMLAuthProviderConfig.enabled" must be a boolean.');
429 }
430 if (typeof options.displayName !== 'undefined' &&
431 !validator.isString(options.displayName)) {
432 throw new error_1.FirebaseAuthError(error_1.AuthClientErrorCode.INVALID_CONFIG, '"SAMLAuthProviderConfig.displayName" must be a valid string.');
433 }
434 };
435 /** @returns The plain object representation of the SAMLConfig. */
436 SAMLConfig.prototype.toJSON = function () {
437 return {
438 enabled: this.enabled,
439 displayName: this.displayName,
440 providerId: this.providerId,
441 idpEntityId: this.idpEntityId,
442 ssoURL: this.ssoURL,
443 x509Certificates: deep_copy_1.deepCopy(this.x509Certificates),
444 rpEntityId: this.rpEntityId,
445 callbackURL: this.callbackURL,
446 enableRequestSigning: this.enableRequestSigning,
447 };
448 };
449 return SAMLConfig;
450}());
451exports.SAMLConfig = SAMLConfig;
452/**
453 * Defines the OIDCConfig class used to convert a client side configuration to its
454 * server side representation.
455 *
456 * @internal
457 */
458var OIDCConfig = /** @class */ (function () {
459 /**
460 * The OIDCConfig constructor.
461 *
462 * @param response - The server side response used to initialize the OIDCConfig object.
463 * @constructor
464 */
465 function OIDCConfig(response) {
466 if (!response ||
467 !response.issuer ||
468 !response.clientId ||
469 !response.name ||
470 !(validator.isString(response.name) &&
471 OIDCConfig.getProviderIdFromResourceName(response.name))) {
472 throw new error_1.FirebaseAuthError(error_1.AuthClientErrorCode.INTERNAL_ERROR, 'INTERNAL ASSERT FAILED: Invalid OIDC configuration response');
473 }
474 var providerId = OIDCConfig.getProviderIdFromResourceName(response.name);
475 if (!providerId) {
476 throw new error_1.FirebaseAuthError(error_1.AuthClientErrorCode.INTERNAL_ERROR, 'INTERNAL ASSERT FAILED: Invalid SAML configuration response');
477 }
478 this.providerId = providerId;
479 this.clientId = response.clientId;
480 this.issuer = response.issuer;
481 // When enabled is undefined, it takes its default value of false.
482 this.enabled = !!response.enabled;
483 this.displayName = response.displayName;
484 if (typeof response.clientSecret !== 'undefined') {
485 this.clientSecret = response.clientSecret;
486 }
487 if (typeof response.responseType !== 'undefined') {
488 this.responseType = response.responseType;
489 }
490 }
491 /**
492 * Converts a client side request to a OIDCConfigServerRequest which is the format
493 * accepted by the backend server.
494 * Throws an error if validation fails. If the request is not a OIDCConfig request,
495 * returns null.
496 *
497 * @param options - The options object to convert to a server request.
498 * @param ignoreMissingFields - Whether to ignore missing fields.
499 * @returns The resulting server request or null if not valid.
500 */
501 OIDCConfig.buildServerRequest = function (options, ignoreMissingFields) {
502 if (ignoreMissingFields === void 0) { ignoreMissingFields = false; }
503 var makeRequest = validator.isNonNullObject(options) &&
504 (options.providerId || ignoreMissingFields);
505 if (!makeRequest) {
506 return null;
507 }
508 var request = {};
509 // Validate options.
510 OIDCConfig.validate(options, ignoreMissingFields);
511 request.enabled = options.enabled;
512 request.displayName = options.displayName;
513 request.issuer = options.issuer;
514 request.clientId = options.clientId;
515 if (typeof options.clientSecret !== 'undefined') {
516 request.clientSecret = options.clientSecret;
517 }
518 if (typeof options.responseType !== 'undefined') {
519 request.responseType = options.responseType;
520 }
521 return request;
522 };
523 /**
524 * Returns the provider ID corresponding to the resource name if available.
525 *
526 * @param resourceName - The server side resource name
527 * @returns The provider ID corresponding to the resource, null otherwise.
528 */
529 OIDCConfig.getProviderIdFromResourceName = function (resourceName) {
530 // name is of form projects/project1/oauthIdpConfigs/providerId1
531 var matchProviderRes = resourceName.match(/\/oauthIdpConfigs\/(oidc\..*)$/);
532 if (!matchProviderRes || matchProviderRes.length < 2) {
533 return null;
534 }
535 return matchProviderRes[1];
536 };
537 /**
538 * @param providerId - The provider ID to check.
539 * @returns Whether the provider ID corresponds to an OIDC provider.
540 */
541 OIDCConfig.isProviderId = function (providerId) {
542 return validator.isNonEmptyString(providerId) && providerId.indexOf('oidc.') === 0;
543 };
544 /**
545 * Validates the OIDCConfig options object. Throws an error on failure.
546 *
547 * @param options - The options object to validate.
548 * @param ignoreMissingFields - Whether to ignore missing fields.
549 */
550 OIDCConfig.validate = function (options, ignoreMissingFields) {
551 if (ignoreMissingFields === void 0) { ignoreMissingFields = false; }
552 var validKeys = {
553 enabled: true,
554 displayName: true,
555 providerId: true,
556 clientId: true,
557 issuer: true,
558 clientSecret: true,
559 responseType: true,
560 };
561 var validResponseTypes = {
562 idToken: true,
563 code: true,
564 };
565 if (!validator.isNonNullObject(options)) {
566 throw new error_1.FirebaseAuthError(error_1.AuthClientErrorCode.INVALID_CONFIG, '"OIDCAuthProviderConfig" must be a valid non-null object.');
567 }
568 // Check for unsupported top level attributes.
569 for (var key in options) {
570 if (!(key in validKeys)) {
571 throw new error_1.FirebaseAuthError(error_1.AuthClientErrorCode.INVALID_CONFIG, "\"" + key + "\" is not a valid OIDC config parameter.");
572 }
573 }
574 // Required fields.
575 if (validator.isNonEmptyString(options.providerId)) {
576 if (options.providerId.indexOf('oidc.') !== 0) {
577 throw new error_1.FirebaseAuthError(!options.providerId ? error_1.AuthClientErrorCode.MISSING_PROVIDER_ID : error_1.AuthClientErrorCode.INVALID_PROVIDER_ID, '"OIDCAuthProviderConfig.providerId" must be a valid non-empty string prefixed with "oidc.".');
578 }
579 }
580 else if (!ignoreMissingFields) {
581 throw new error_1.FirebaseAuthError(!options.providerId ? error_1.AuthClientErrorCode.MISSING_PROVIDER_ID : error_1.AuthClientErrorCode.INVALID_PROVIDER_ID, '"OIDCAuthProviderConfig.providerId" must be a valid non-empty string prefixed with "oidc.".');
582 }
583 if (!(ignoreMissingFields && typeof options.clientId === 'undefined') &&
584 !validator.isNonEmptyString(options.clientId)) {
585 throw new error_1.FirebaseAuthError(!options.clientId ? error_1.AuthClientErrorCode.MISSING_OAUTH_CLIENT_ID : error_1.AuthClientErrorCode.INVALID_OAUTH_CLIENT_ID, '"OIDCAuthProviderConfig.clientId" must be a valid non-empty string.');
586 }
587 if (!(ignoreMissingFields && typeof options.issuer === 'undefined') &&
588 !validator.isURL(options.issuer)) {
589 throw new error_1.FirebaseAuthError(!options.issuer ? error_1.AuthClientErrorCode.MISSING_ISSUER : error_1.AuthClientErrorCode.INVALID_CONFIG, '"OIDCAuthProviderConfig.issuer" must be a valid URL string.');
590 }
591 if (typeof options.enabled !== 'undefined' &&
592 !validator.isBoolean(options.enabled)) {
593 throw new error_1.FirebaseAuthError(error_1.AuthClientErrorCode.INVALID_CONFIG, '"OIDCAuthProviderConfig.enabled" must be a boolean.');
594 }
595 if (typeof options.displayName !== 'undefined' &&
596 !validator.isString(options.displayName)) {
597 throw new error_1.FirebaseAuthError(error_1.AuthClientErrorCode.INVALID_CONFIG, '"OIDCAuthProviderConfig.displayName" must be a valid string.');
598 }
599 if (typeof options.clientSecret !== 'undefined' &&
600 !validator.isNonEmptyString(options.clientSecret)) {
601 throw new error_1.FirebaseAuthError(error_1.AuthClientErrorCode.INVALID_CONFIG, '"OIDCAuthProviderConfig.clientSecret" must be a valid string.');
602 }
603 if (validator.isNonNullObject(options.responseType) && typeof options.responseType !== 'undefined') {
604 Object.keys(options.responseType).forEach(function (key) {
605 if (!(key in validResponseTypes)) {
606 throw new error_1.FirebaseAuthError(error_1.AuthClientErrorCode.INVALID_CONFIG, "\"" + key + "\" is not a valid OAuthResponseType parameter.");
607 }
608 });
609 var idToken = options.responseType.idToken;
610 if (typeof idToken !== 'undefined' && !validator.isBoolean(idToken)) {
611 throw new error_1.FirebaseAuthError(error_1.AuthClientErrorCode.INVALID_ARGUMENT, '"OIDCAuthProviderConfig.responseType.idToken" must be a boolean.');
612 }
613 var code = options.responseType.code;
614 if (typeof code !== 'undefined') {
615 if (!validator.isBoolean(code)) {
616 throw new error_1.FirebaseAuthError(error_1.AuthClientErrorCode.INVALID_ARGUMENT, '"OIDCAuthProviderConfig.responseType.code" must be a boolean.');
617 }
618 // If code flow is enabled, client secret must be provided.
619 if (code && typeof options.clientSecret === 'undefined') {
620 throw new error_1.FirebaseAuthError(error_1.AuthClientErrorCode.MISSING_OAUTH_CLIENT_SECRET, 'The OAuth configuration client secret is required to enable OIDC code flow.');
621 }
622 }
623 var allKeys = Object.keys(options.responseType).length;
624 var enabledCount = Object.values(options.responseType).filter(Boolean).length;
625 // Only one of OAuth response types can be set to true.
626 if (allKeys > 1 && enabledCount != 1) {
627 throw new error_1.FirebaseAuthError(error_1.AuthClientErrorCode.INVALID_OAUTH_RESPONSETYPE, 'Only exactly one OAuth responseType should be set to true.');
628 }
629 }
630 };
631 /** @returns The plain object representation of the OIDCConfig. */
632 OIDCConfig.prototype.toJSON = function () {
633 return {
634 enabled: this.enabled,
635 displayName: this.displayName,
636 providerId: this.providerId,
637 issuer: this.issuer,
638 clientId: this.clientId,
639 clientSecret: deep_copy_1.deepCopy(this.clientSecret),
640 responseType: deep_copy_1.deepCopy(this.responseType),
641 };
642 };
643 return OIDCConfig;
644}());
645exports.OIDCConfig = OIDCConfig;