voluptasmollitia
Version:
Monorepo for the Firebase JavaScript SDK
1,512 lines (1,363 loc) • 109 kB
JavaScript
/**
* @license
* Copyright 2017 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* @fileoverview Utility for handling RPC requests to server.
*/
goog.provide('fireauth.RpcHandler');
goog.provide('fireauth.RpcHandler.ApiMethodHandler');
goog.provide('fireauth.RpcHandler.VerifyAssertionData');
goog.provide('fireauth.XmlHttpFactory');
goog.require('fireauth.AuthError');
goog.require('fireauth.AuthErrorWithCredential');
goog.require('fireauth.authenum.Error');
goog.require('fireauth.constants');
goog.require('fireauth.idp');
goog.require('fireauth.idp.ProviderId');
goog.require('fireauth.object');
goog.require('fireauth.util');
goog.require('goog.Promise');
goog.require('goog.Uri');
goog.require('goog.html.TrustedResourceUrl');
goog.require('goog.json');
goog.require('goog.net.CorsXmlHttpFactory');
goog.require('goog.net.EventType');
goog.require('goog.net.FetchXmlHttpFactory');
goog.require('goog.net.XhrIo');
goog.require('goog.net.XmlHttpFactory');
goog.require('goog.net.jsloader');
goog.require('goog.object');
goog.require('goog.string.Const');
/**
* Firebase Auth XmlHttpRequest factory. This is useful for environments like
* Node.js where XMLHttpRequest does not exist. XmlHttpFactory would be
* initialized using the polyfill XMLHttpRequest module.
* @param {function(new:XMLHttpRequest)} xmlHttpRequest The xmlHttpRequest
* constructor.
* @constructor
* @extends {goog.net.XmlHttpFactory}
* @final
*/
fireauth.XmlHttpFactory = function(xmlHttpRequest) {
/**
* @private {function(new:XMLHttpRequest)} The underlying XHR reference.
*/
this.xmlHttpRequest_ = xmlHttpRequest;
fireauth.XmlHttpFactory.base(this, 'constructor');
};
goog.inherits(fireauth.XmlHttpFactory, goog.net.XmlHttpFactory);
/**
* @return {!goog.net.XhrLike|!XMLHttpRequest} A new XhrLike instance.
* @override
*/
fireauth.XmlHttpFactory.prototype.createInstance = function() {
return new this.xmlHttpRequest_();
};
/**
* @return {!Object} Options describing how XHR objects obtained from this
* factory should be used.
* @override
*/
fireauth.XmlHttpFactory.prototype.internalGetOptions = function() {
return {};
};
/**
* Creates an RPC request handler for the project specified by the API key.
*
* @param {string} apiKey The API key.
* @param {?Object=} opt_config The RPC request processor configuration.
* @param {?string=} opt_firebaseClientVersion The optional Firebase client
* version to log with requests to Firebase Auth server.
* @constructor
*/
fireauth.RpcHandler = function(apiKey, opt_config, opt_firebaseClientVersion) {
/** @private {string} The project API key. */
this.apiKey_ = apiKey;
var config = opt_config || {};
this.secureTokenEndpoint_ = config['secureTokenEndpoint'] ||
fireauth.RpcHandler.SECURE_TOKEN_ENDPOINT_;
/**
* @private @const {!fireauth.util.Delay} The delay for secure token endpoint
* network timeout.
*/
this.secureTokenTimeout_ = config['secureTokenTimeout'] ||
fireauth.RpcHandler.DEFAULT_SECURE_TOKEN_TIMEOUT_;
/** @private @const {!Object} The secure token server headers. */
this.secureTokenHeaders_ = goog.object.clone(
config['secureTokenHeaders'] ||
fireauth.RpcHandler.DEFAULT_SECURE_TOKEN_HEADERS_);
/** @private {string} The Firebase Auth endpoint. */
this.firebaseEndpoint_ = config['firebaseEndpoint'] ||
fireauth.RpcHandler.FIREBASE_ENDPOINT_;
/** @private {string} The identity platform endpoint. */
this.identityPlatformEndpoint_ = config['identityPlatformEndpoint'] ||
fireauth.RpcHandler.IDENTITY_PLATFORM_ENDPOINT_;
/**
* @private @const {!fireauth.util.Delay} The delay for Firebase Auth endpoint
* network timeout.
*/
this.firebaseTimeout_ = config['firebaseTimeout'] ||
fireauth.RpcHandler.DEFAULT_FIREBASE_TIMEOUT_;
this.firebaseHeaders_ = goog.object.clone(
config['firebaseHeaders'] ||
fireauth.RpcHandler.DEFAULT_FIREBASE_HEADERS_);
// If Firebase client version needs to be logged too.
if (opt_firebaseClientVersion) {
// Log client version for Firebase Auth server.
this.firebaseHeaders_['X-Client-Version'] = opt_firebaseClientVersion;
// Log client version for securetoken server.
this.secureTokenHeaders_['X-Client-Version'] = opt_firebaseClientVersion;
}
// Get XMLHttpRequest reference.
var XMLHttpRequest = fireauth.RpcHandler.getXMLHttpRequest();
if (!XMLHttpRequest && !fireauth.util.isWorker()) {
// In a Node.js environment, xmlhttprequest module needs to be required.
throw new fireauth.AuthError(fireauth.authenum.Error.INTERNAL_ERROR,
'The XMLHttpRequest compatibility library was not found.');
}
/** @private {!goog.net.XmlHttpFactory|undefined} The XHR factory. */
this.rpcHandlerXhrFactory_ = undefined;
// Initialize XHR factory. CORS does not apply in native environments or
// workers so don't use CorsXmlHttpFactory in those cases.
if (fireauth.util.isWorker()) {
// For worker environment use FetchXmlHttpFactory.
this.rpcHandlerXhrFactory_ = new goog.net.FetchXmlHttpFactory(
/** @type {!WorkerGlobalScope} */ (self));
} else if (fireauth.util.isNativeEnvironment()) {
// For Node.js, this is the polyfill library. For other environments,
// this is the native global XMLHttpRequest.
this.rpcHandlerXhrFactory_ = new fireauth.XmlHttpFactory(
/** @type {function(new:XMLHttpRequest)} */ (XMLHttpRequest));
} else {
// CORS Browser environment.
this.rpcHandlerXhrFactory_ = new goog.net.CorsXmlHttpFactory();
}
/** @private {?string} The tenant ID. */
this.tenantId_ = null;
};
/**
* @return {?function(new:XMLHttpRequest)|undefined} The current environment
* XMLHttpRequest. This is undefined for worker environment.
*/
fireauth.RpcHandler.getXMLHttpRequest = function() {
// In Node.js XMLHttpRequest is polyfilled.
var isNode = fireauth.util.getEnvironment() == fireauth.util.Env.NODE;
var XMLHttpRequest = goog.global['XMLHttpRequest'] ||
(isNode &&
firebase.INTERNAL['node'] &&
firebase.INTERNAL['node']['XMLHttpRequest']);
return XMLHttpRequest;
};
/**
* Enums for HTTP request methods.
* @enum {string}
*/
fireauth.RpcHandler.HttpMethod = {
POST: 'POST',
GET: 'GET'
};
/**
* Firebase Auth server error codes.
* @enum {string}
*/
fireauth.RpcHandler.ServerError = {
ADMIN_ONLY_OPERATION: 'ADMIN_ONLY_OPERATION',
CAPTCHA_CHECK_FAILED: 'CAPTCHA_CHECK_FAILED',
CORS_UNSUPPORTED: 'CORS_UNSUPPORTED',
CREDENTIAL_MISMATCH: 'CREDENTIAL_MISMATCH',
CREDENTIAL_TOO_OLD_LOGIN_AGAIN: 'CREDENTIAL_TOO_OLD_LOGIN_AGAIN',
DYNAMIC_LINK_NOT_ACTIVATED: 'DYNAMIC_LINK_NOT_ACTIVATED',
EMAIL_CHANGE_NEEDS_VERIFICATION: 'EMAIL_CHANGE_NEEDS_VERIFICATION',
EMAIL_EXISTS: 'EMAIL_EXISTS',
EMAIL_NOT_FOUND: 'EMAIL_NOT_FOUND',
EXPIRED_OOB_CODE: 'EXPIRED_OOB_CODE',
FEDERATED_USER_ID_ALREADY_LINKED: 'FEDERATED_USER_ID_ALREADY_LINKED',
INVALID_APP_CREDENTIAL: 'INVALID_APP_CREDENTIAL',
INVALID_APP_ID: 'INVALID_APP_ID',
INVALID_CERT_HASH: 'INVALID_CERT_HASH',
INVALID_CODE: 'INVALID_CODE',
INVALID_CONTINUE_URI: 'INVALID_CONTINUE_URI',
INVALID_CUSTOM_TOKEN: 'INVALID_CUSTOM_TOKEN',
INVALID_DYNAMIC_LINK_DOMAIN: 'INVALID_DYNAMIC_LINK_DOMAIN',
INVALID_EMAIL: 'INVALID_EMAIL',
INVALID_ID_TOKEN: 'INVALID_ID_TOKEN',
INVALID_IDP_RESPONSE: 'INVALID_IDP_RESPONSE',
INVALID_IDENTIFIER: 'INVALID_IDENTIFIER',
INVALID_MESSAGE_PAYLOAD: 'INVALID_MESSAGE_PAYLOAD',
INVALID_MFA_PENDING_CREDENTIAL: 'INVALID_MFA_PENDING_CREDENTIAL',
INVALID_OAUTH_CLIENT_ID: 'INVALID_OAUTH_CLIENT_ID',
INVALID_OOB_CODE: 'INVALID_OOB_CODE',
INVALID_PASSWORD: 'INVALID_PASSWORD',
INVALID_PENDING_TOKEN: 'INVALID_PENDING_TOKEN',
INVALID_PHONE_NUMBER: 'INVALID_PHONE_NUMBER',
INVALID_PROVIDER_ID: 'INVALID_PROVIDER_ID',
INVALID_RECIPIENT_EMAIL: 'INVALID_RECIPIENT_EMAIL',
INVALID_SENDER: 'INVALID_SENDER',
INVALID_SESSION_INFO: 'INVALID_SESSION_INFO',
INVALID_TEMPORARY_PROOF: 'INVALID_TEMPORARY_PROOF',
INVALID_TENANT_ID: 'INVALID_TENANT_ID',
MFA_ENROLLMENT_NOT_FOUND: 'MFA_ENROLLMENT_NOT_FOUND',
MISSING_ANDROID_PACKAGE_NAME: 'MISSING_ANDROID_PACKAGE_NAME',
MISSING_APP_CREDENTIAL: 'MISSING_APP_CREDENTIAL',
MISSING_CODE: 'MISSING_CODE',
MISSING_CONTINUE_URI: 'MISSING_CONTINUE_URI',
MISSING_CUSTOM_TOKEN: 'MISSING_CUSTOM_TOKEN',
MISSING_IOS_BUNDLE_ID: 'MISSING_IOS_BUNDLE_ID',
MISSING_MFA_ENROLLMENT_ID: 'MISSING_MFA_ENROLLMENT_ID',
MISSING_MFA_PENDING_CREDENTIAL: 'MISSING_MFA_PENDING_CREDENTIAL',
MISSING_OOB_CODE: 'MISSING_OOB_CODE',
MISSING_OR_INVALID_NONCE: 'MISSING_OR_INVALID_NONCE',
MISSING_PASSWORD: 'MISSING_PASSWORD',
MISSING_PHONE_NUMBER: 'MISSING_PHONE_NUMBER',
MISSING_SESSION_INFO: 'MISSING_SESSION_INFO',
OPERATION_NOT_ALLOWED: 'OPERATION_NOT_ALLOWED',
PASSWORD_LOGIN_DISABLED: 'PASSWORD_LOGIN_DISABLED',
QUOTA_EXCEEDED: 'QUOTA_EXCEEDED',
RESET_PASSWORD_EXCEED_LIMIT: 'RESET_PASSWORD_EXCEED_LIMIT',
REJECTED_CREDENTIAL: 'REJECTED_CREDENTIAL',
SECOND_FACTOR_EXISTS: 'SECOND_FACTOR_EXISTS',
SECOND_FACTOR_LIMIT_EXCEEDED: 'SECOND_FACTOR_LIMIT_EXCEEDED',
SESSION_EXPIRED: 'SESSION_EXPIRED',
TENANT_ID_MISMATCH: 'TENANT_ID_MISMATCH',
TOKEN_EXPIRED: 'TOKEN_EXPIRED',
TOO_MANY_ATTEMPTS_TRY_LATER: 'TOO_MANY_ATTEMPTS_TRY_LATER',
UNSUPPORTED_FIRST_FACTOR: 'UNSUPPORTED_FIRST_FACTOR',
UNSUPPORTED_TENANT_OPERATION: 'UNSUPPORTED_TENANT_OPERATION',
UNVERIFIED_EMAIL: 'UNVERIFIED_EMAIL',
UNAUTHORIZED_DOMAIN: 'UNAUTHORIZED_DOMAIN',
USER_CANCELLED: 'USER_CANCELLED',
USER_DISABLED: 'USER_DISABLED',
USER_NOT_FOUND: 'USER_NOT_FOUND',
WEAK_PASSWORD: 'WEAK_PASSWORD'
};
/**
* A map of server error codes to client errors.
* @typedef {!Object<
* !fireauth.RpcHandler.ServerError, !fireauth.authenum.Error>}
*/
fireauth.RpcHandler.ServerErrorMap;
/**
* Firebase Auth response field names.
* @enum {string}
*/
fireauth.RpcHandler.AuthServerField = {
ALL_PROVIDERS: 'allProviders',
AUTH_URI: 'authUri',
AUTHORIZED_DOMAINS: 'authorizedDomains',
DYNAMIC_LINKS_DOMAIN: 'dynamicLinksDomain',
EMAIL: 'email',
ERROR_MESSAGE: 'errorMessage',
EXPIRES_IN: 'expiresIn',
ID_TOKEN: 'idToken',
MFA_PENDING_CREDENTIAL: 'mfaPendingCredential',
NEED_CONFIRMATION: 'needConfirmation',
OAUTH_ID_TOKEN: 'oauthIdToken',
PENDING_TOKEN: 'pendingToken',
PHONE_RESPONSE_INFO: 'phoneResponseInfo',
PHONE_SESSION_INFO: 'phoneSessionInfo',
POST_BODY: 'postBody',
PROVIDER_ID: 'providerId',
RECAPTCHA_SITE_KEY: 'recaptchaSiteKey',
REQUEST_URI: 'requestUri',
REFRESH_TOKEN: 'refreshToken',
SESSION_ID: 'sessionId',
SESSION_INFO: 'sessionInfo',
SIGNIN_METHODS: 'signinMethods',
TEMPORARY_PROOF: 'temporaryProof'
};
/**
* Firebase Auth response injected fields.
* @enum {string}
*/
fireauth.RpcHandler.InjectedResponseField = {
NONCE: 'nonce'
};
/**
* Firebase Auth getOobConfirmationCode requestType possible values.
* @enum {string}
*/
fireauth.RpcHandler.GetOobCodeRequestType = {
EMAIL_SIGNIN: 'EMAIL_SIGNIN',
NEW_EMAIL_ACCEPT: 'NEW_EMAIL_ACCEPT',
PASSWORD_RESET: 'PASSWORD_RESET',
VERIFY_AND_CHANGE_EMAIL: 'VERIFY_AND_CHANGE_EMAIL',
VERIFY_EMAIL: 'VERIFY_EMAIL'
};
/**
* Firebase Auth response field names.
* @enum {string}
*/
fireauth.RpcHandler.StsServerField = {
ACCESS_TOKEN: 'access_token',
EXPIRES_IN: 'expires_in',
REFRESH_TOKEN: 'refresh_token'
};
/**
* @return {string} The API key.
*/
fireauth.RpcHandler.prototype.getApiKey = function() {
return this.apiKey_;
};
/**
* The Firebase custom locale header.
* @const {string}
* @private
*/
fireauth.RpcHandler.FIREBASE_LOCALE_KEY_ = 'X-Firebase-Locale';
/**
* The secure token endpoint.
* @const {string}
* @private
*/
fireauth.RpcHandler.SECURE_TOKEN_ENDPOINT_ =
'https://securetoken.googleapis.com/v1/token';
/**
* The default timeout delay (units in milliseconds) for requests sending to
* STS token endpoint.
* @const {!fireauth.util.Delay}
* @private
*/
fireauth.RpcHandler.DEFAULT_SECURE_TOKEN_TIMEOUT_ =
new fireauth.util.Delay(30000, 60000);
/**
* The STS token RPC content headers.
* @const {!Object}
* @private
*/
fireauth.RpcHandler.DEFAULT_SECURE_TOKEN_HEADERS_ = {
'Content-Type': 'application/x-www-form-urlencoded'
};
/**
* The Firebase endpoint.
* @const {string}
* @private
*/
fireauth.RpcHandler.FIREBASE_ENDPOINT_ =
'https://www.googleapis.com/identitytoolkit/v3/relyingparty/';
/**
* The Identity Platform endpoint.
* @const {string}
* @private
*/
fireauth.RpcHandler.IDENTITY_PLATFORM_ENDPOINT_ =
'https://identitytoolkit.googleapis.com/v2/';
/**
* The default timeout delay (units in milliseconds) for requests sending to
* Firebase endpoint.
* @const {!fireauth.util.Delay}
* @private
*/
fireauth.RpcHandler.DEFAULT_FIREBASE_TIMEOUT_ =
new fireauth.util.Delay(30000, 60000);
/**
* The Firebase RPC content headers.
* @const {!Object}
* @private
*/
fireauth.RpcHandler.DEFAULT_FIREBASE_HEADERS_ = {
'Content-Type': 'application/json'
};
/**
* Updates the custom locale header.
* @param {?string} languageCode The new languageCode.
*/
fireauth.RpcHandler.prototype.updateCustomLocaleHeader =
function(languageCode) {
if (languageCode) {
// If a language code is provided, add it to the header.
this.firebaseHeaders_[fireauth.RpcHandler.FIREBASE_LOCALE_KEY_] =
languageCode;
} else {
// Otherwise remove the custom locale header.
delete this.firebaseHeaders_[fireauth.RpcHandler.FIREBASE_LOCALE_KEY_];
}
};
/**
* Updates the emulator configuration.
* @param {?fireauth.constants.EmulatorSettings} emulatorConfig The new
* emulator config.
*/
fireauth.RpcHandler.prototype.updateEmulatorConfig = function(emulatorConfig) {
if (!emulatorConfig) {
return;
}
// If an emulator config is provided, update the endpoints.
this.secureTokenEndpoint_ =
fireauth.RpcHandler.generateEmululatorEndpointUrl_(
fireauth.RpcHandler.SECURE_TOKEN_ENDPOINT_, emulatorConfig);
this.firebaseEndpoint_ =
fireauth.RpcHandler.generateEmululatorEndpointUrl_(
fireauth.RpcHandler.FIREBASE_ENDPOINT_, emulatorConfig);
this.identityPlatformEndpoint_ =
fireauth.RpcHandler.generateEmululatorEndpointUrl_(
fireauth.RpcHandler.IDENTITY_PLATFORM_ENDPOINT_, emulatorConfig);
}
/**
* Creates an endpoint URL intended for use by the emulator.
* @param {string} endpoint the production endpoint URL.
* @param {?fireauth.constants.EmulatorSettings} emulatorConfig The emulator
* config.
* @return {string} The emulator endpoint URL.
* @private
*/
fireauth.RpcHandler.generateEmululatorEndpointUrl_ = function(endpoint, emulatorConfig) {
const uri = goog.Uri.parse(endpoint);
const emulatorUri = goog.Uri.parse(emulatorConfig.url);
uri.setPath(uri.getDomain() + uri.getPath());
uri.setScheme(emulatorUri.getScheme());
uri.setDomain(emulatorUri.getDomain());
uri.setPort(emulatorUri.getPort());
return uri.toString();
}
/**
* Updates the X-Client-Version in the header.
* @param {?string} clientVersion The new client version.
*/
fireauth.RpcHandler.prototype.updateClientVersion = function(clientVersion) {
if (clientVersion) {
// Update client version for Firebase Auth server.
this.firebaseHeaders_['X-Client-Version'] = clientVersion;
// Update client version for securetoken server.
this.secureTokenHeaders_['X-Client-Version'] = clientVersion;
} else {
// Remove client version from header.
delete this.firebaseHeaders_['X-Client-Version'];
delete this.secureTokenHeaders_['X-Client-Version'];
}
};
/**
* Updates the tenant ID in the request.
* @param {?string} tenantId The new tenant ID.
*/
fireauth.RpcHandler.prototype.updateTenantId = function(tenantId) {
this.tenantId_ = tenantId;
};
/**
* Returns the tenant ID.
* @return {?string} The tenant ID.
*/
fireauth.RpcHandler.prototype.getTenantId = function() {
return this.tenantId_;
};
/**
* Sends XhrIo request using goog.net.XhrIo.
* @param {string} url The URL to make a request to.
* @param {function(?Object)=} opt_callback The callback to run on completion.
* @param {fireauth.RpcHandler.HttpMethod=} opt_httpMethod The HTTP send method.
* @param {?ArrayBuffer|?ArrayBufferView|?Blob|?Document|?FormData|string=}
* opt_data The request content.
* @param {?Object=} opt_headers The request content headers.
* @param {number=} opt_timeout The request timeout.
* @private
*/
fireauth.RpcHandler.prototype.sendXhr_ = function(
url,
opt_callback,
opt_httpMethod,
opt_data,
opt_headers,
opt_timeout) {
var sendXhr;
if (fireauth.util.supportsCors() || fireauth.util.isWorker()) {
// If supports CORS use goog.net.XhrIo.
sendXhr = goog.bind(this.sendXhrUsingXhrIo_, this);
} else {
// Load gapi.client.request and gapi.auth dependency dynamically.
if (!fireauth.RpcHandler.loadGApi_) {
fireauth.RpcHandler.loadGApi_ =
new goog.Promise(function(resolve, reject) {
// On load, resolve.
fireauth.RpcHandler.loadGApiJs_(resolve, reject);
});
}
// If does not support CORS, use gapi.client.request.
sendXhr = goog.bind(this.sendXhrUsingGApiClient_, this);
}
sendXhr(
url, opt_callback, opt_httpMethod, opt_data, opt_headers, opt_timeout);
};
/**
* Sends XhrIo request using goog.net.XhrIo.
* @param {string} url The URL to make a request to.
* @param {function(?Object)=} opt_callback The callback to run on completion.
* @param {fireauth.RpcHandler.HttpMethod=} opt_httpMethod The HTTP send method.
* @param {?ArrayBuffer|?ArrayBufferView|?Blob|?Document|?FormData|string=}
* opt_data The request content.
* @param {?Object=} opt_headers The request content headers.
* @param {number=} opt_timeout The request timeout.
* @private
*/
fireauth.RpcHandler.prototype.sendXhrUsingXhrIo_ = function(
url,
opt_callback,
opt_httpMethod,
opt_data,
opt_headers,
opt_timeout) {
if (fireauth.util.isWorker() && !fireauth.util.isFetchSupported()) {
throw new fireauth.AuthError(
fireauth.authenum.Error.OPERATION_NOT_SUPPORTED,
'fetch, Headers and Request native APIs or equivalent Polyfills ' +
'must be available to support HTTP requests from a Worker ' +
'environment.');
}
var xhrIo = new goog.net.XhrIo(this.rpcHandlerXhrFactory_);
// xhrIo.setTimeoutInterval not working in IE10 and IE11, handle manually.
var requestTimeout;
if (opt_timeout) {
xhrIo.setTimeoutInterval(opt_timeout);
requestTimeout = setTimeout(function() {
xhrIo.dispatchEvent(goog.net.EventType.TIMEOUT);
}, opt_timeout);
}
// Run callback function on completion.
xhrIo.listen(
goog.net.EventType.COMPLETE,
/** @this {goog.net.XhrIo} */
function() {
// Clear timeout timer.
if (requestTimeout) {
clearTimeout(requestTimeout);
}
// Response assumed to be in json format. If not, catch, log error and
// pass null to callback.
var response = null;
try {
// Do not use this.responseJson() as it uses goog.json.parse
// underneath. Internal goog.json.parse parsing uses eval and since
// recommended Content Security Policy does not allow unsafe-eval,
// this is failing and throwing an error in chrome extensions and
// warnings else where. Use native parsing instead via JSON.parse.
response = JSON.parse(this.getResponseText()) || null;
} catch (e) {
response = null;
}
if (opt_callback) {
opt_callback(/** @type {?Object} */ (response));
}
});
// Dispose xhrIo on ready.
xhrIo.listenOnce(
goog.net.EventType.READY,
/** @this {goog.net.XhrIo} */
function() {
// Clear timeout timer.
if (requestTimeout) {
clearTimeout(requestTimeout);
}
// Dispose xhrIo.
this.dispose();
});
// Listen to timeout error.
// This should work when request is aborted too.
xhrIo.listenOnce(
goog.net.EventType.TIMEOUT,
/** @this {goog.net.XhrIo} */
function() {
// Clear timeout timer.
if (requestTimeout) {
clearTimeout(requestTimeout);
}
// Dispose xhrIo.
this.dispose();
// The request timed out.
if (opt_callback) {
opt_callback(null);
}
});
xhrIo.send(url, opt_httpMethod, opt_data, opt_headers);
};
/**
* @const {!goog.string.Const} The GApi client library URL.
* @private
*/
fireauth.RpcHandler.GAPI_SRC_ = goog.string.Const.from(
'https://apis.google.com/js/client.js?onload=%{onload}');
/**
* @const {string}
* @private
*/
fireauth.RpcHandler.GAPI_CALLBACK_NAME_ =
'__fcb' + Math.floor(Math.random() * 1000000).toString();
/**
* Loads the GApi client library if it is not loaded.
* @param {function()} callback The callback to invoke once it's loaded.
* @param {function(?Object)} errback The error callback.
* @private
*/
fireauth.RpcHandler.loadGApiJs_ = function(callback, errback) {
// If gapi.client.request not available, load it dynamically.
if (!((window['gapi'] || {})['client'] || {})['request']) {
goog.global[fireauth.RpcHandler.GAPI_CALLBACK_NAME_] = function() {
// Callback will be called by GApi, test properly loaded here instead of
// after jsloader resolves.
if (!((window['gapi'] || {})['client'] || {})['request']) {
errback(new Error(fireauth.RpcHandler.ServerError.CORS_UNSUPPORTED));
} else {
callback();
}
};
var url = goog.html.TrustedResourceUrl.format(
fireauth.RpcHandler.GAPI_SRC_,
{'onload': fireauth.RpcHandler.GAPI_CALLBACK_NAME_});
// TODO: replace goog.net.jsloader with our own script includer.
var result = goog.net.jsloader.safeLoad(url);
result.addErrback(function() {
// In case file fails to load.
errback(new Error(fireauth.RpcHandler.ServerError.CORS_UNSUPPORTED));
});
} else {
callback();
}
};
/**
* Sends XhrIo request using gapi.client.
* @param {string} url The URL to make a request to.
* @param {function(?Object)=} opt_callback The callback to run on completion.
* @param {fireauth.RpcHandler.HttpMethod=} opt_httpMethod The HTTP send method.
* @param {?ArrayBuffer|?ArrayBufferView|?Blob|?Document|?FormData|string=}
* opt_data The request content.
* @param {?Object=} opt_headers The request content headers.
* @param {number=} opt_timeout The request timeout.
* @private
*/
fireauth.RpcHandler.prototype.sendXhrUsingGApiClient_ = function(
url,
opt_callback,
opt_httpMethod,
opt_data,
opt_headers,
opt_timeout) {
var self = this;
// Wait for GApi dependency to load.
fireauth.RpcHandler.loadGApi_.then(function() {
window['gapi']['client']['setApiKey'](self.getApiKey());
// GApi maintains the Auth result and automatically append the Auth token to
// all outgoing requests. Firebase Auth requests will be rejected if there
// are others scopes (e.g. google plus) for the Auth token. Need to empty
// the token before call gitkit api. Restored in callback.
var oauth2Token = window['gapi']['auth']['getToken']();
window['gapi']['auth']['setToken'](null);
window['gapi']['client']['request']({
'path': url,
'method': opt_httpMethod,
'body': opt_data,
'headers': opt_headers,
// This needs to be set to none, otherwise the access token will be passed
// in the header field causing apiary to complain.
'authType': 'none',
'callback': function(response) {
window['gapi']['auth']['setToken'](oauth2Token);
if (opt_callback) {
opt_callback(response);
}
}
});
}).thenCatch(function(error) {
// Catches failure to support CORS and propagates it.
if (opt_callback) {
// Simulate backend server error to be caught by upper layer.
opt_callback({
'error': {
'message': (error && error['message']) ||
fireauth.RpcHandler.ServerError.CORS_UNSUPPORTED
}
});
}
});
};
/**
* Validates the request for the STS access token.
*
* @param {?Object} data The STS token request body.
* @return {boolean} Whether the request is valid.
* @private
*/
fireauth.RpcHandler.prototype.validateStsTokenRequest_ = function(data) {
if (data['grant_type'] == 'refresh_token' && data['refresh_token']) {
// Exchange refresh token.
return true;
} else if (data['grant_type'] == 'authorization_code' && data['code']) {
// Exchange ID token.
return true;
} else {
// Invalid.
return false;
}
};
/**
* Handles the request for the STS access token.
*
* @param {!Object} data The STS token request body.
* @return {!goog.Promise<!Object>}
*/
fireauth.RpcHandler.prototype.requestStsToken = function(data) {
var self = this;
return new goog.Promise(function(resolve, reject) {
if (self.validateStsTokenRequest_(data)) {
self.sendXhr_(
self.secureTokenEndpoint_ + '?key=' +
encodeURIComponent(self.getApiKey()),
function(response) {
if (!response) {
// An unparseable response from the XHR most likely indicates some
// problem with the network.
reject(new fireauth.AuthError(
fireauth.authenum.Error.NETWORK_REQUEST_FAILED));
} else if (fireauth.RpcHandler.hasError_(response)) {
reject(fireauth.RpcHandler.getDeveloperError_(response));
} else if (
!response[fireauth.RpcHandler.StsServerField.ACCESS_TOKEN] ||
!response[fireauth.RpcHandler.StsServerField.REFRESH_TOKEN]) {
reject(new fireauth.AuthError(
fireauth.authenum.Error.INTERNAL_ERROR));
} else {
resolve(response);
}
},
fireauth.RpcHandler.HttpMethod.POST,
goog.Uri.QueryData.createFromMap(data).toString(),
self.secureTokenHeaders_,
self.secureTokenTimeout_.get());
} else {
reject(new fireauth.AuthError(fireauth.authenum.Error.INTERNAL_ERROR));
}
});
};
/**
* @param {!Object} data The object to serialize.
* @return {string} The serialized object with null, undefined and empty string
* values removed.
* @private
*/
fireauth.RpcHandler.serialize_ = function(data) {
// goog.json.serialize converts undefined values to null.
// This helper removes all empty strings, nulls and undefined from serialized
// object.
// Serialize trimmed data.
return goog.json.serialize(fireauth.util.copyWithoutNullsOrUndefined(data));
};
/**
* Creates and executes a request for the given API method using the legacy
* Firebase Auth endpoint.
* @param {string} method The API method.
* @param {!fireauth.RpcHandler.HttpMethod} httpMethod The http request method.
* @param {!Object} data The data for the API request. In the case of a GET
* request, the contents of this object will be form encoded and appended
* to the query string of the URL. No post body is sent in that case. If an
* object value is specified, it will be converted to a string:
* encodeURIComponent(String(value)).
* @param {?fireauth.RpcHandler.ServerErrorMap=} opt_customErrorMap A map
* of server error codes to client errors to override default error
* handling.
* @param {boolean=} opt_cachebuster Whether to append a unique string to
* request to force backend to return an uncached response to request.
* @return {!goog.Promise<!Object>}
*/
fireauth.RpcHandler.prototype.requestFirebaseEndpoint = function(
method, httpMethod, data, opt_customErrorMap, opt_cachebuster) {
return this.requestAuthEndpoint_(
this.firebaseEndpoint_, method, httpMethod, data, opt_customErrorMap,
opt_cachebuster);
};
/**
* Creates and executes a request for the given API method using the identity
* platform endpoint.
* @param {string} method The API method.
* @param {!fireauth.RpcHandler.HttpMethod} httpMethod The http request method.
* @param {!Object} data The data for the API request. In the case of a GET
* request, the contents of this object will be form encoded and appended
* to the query string of the URL. No post body is sent in that case. If an
* object value is specified, it will be converted to a string:
* encodeURIComponent(String(value)).
* @param {?fireauth.RpcHandler.ServerErrorMap=} opt_customErrorMap A map
* of server error codes to client errors to override default error
* handling.
* @param {boolean=} opt_cachebuster Whether to append a unique string to
* request to force backend to return an uncached response to request.
* @return {!goog.Promise<!Object>}
*/
fireauth.RpcHandler.prototype.requestIdentityPlatformEndpoint = function(
method, httpMethod, data, opt_customErrorMap, opt_cachebuster) {
return this.requestAuthEndpoint_(
this.identityPlatformEndpoint_, method, httpMethod, data,
opt_customErrorMap, opt_cachebuster);
};
/**
* Creates and executes a request for the given API method and Auth endpoint.
* @param {string} endpoint The Auth endpoint to use.
* @param {string} method The API method.
* @param {!fireauth.RpcHandler.HttpMethod} httpMethod The http request method.
* @param {!Object} data The data for the API request. In the case of a GET
* request, the contents of this object will be form encoded and appended
* to the query string of the URL. No post body is sent in that case. If an
* object value is specified, it will be converted to a string:
* encodeURIComponent(String(value)).
* @param {?fireauth.RpcHandler.ServerErrorMap=} opt_customErrorMap A map
* of server error codes to client errors to override default error
* handling.
* @param {boolean=} opt_cachebuster Whether to append a unique string to
* request to force backend to return an uncached response to request.
* @return {!goog.Promise<!Object>}
* @private
*/
fireauth.RpcHandler.prototype.requestAuthEndpoint_ = function(
endpoint, method, httpMethod, data, opt_customErrorMap, opt_cachebuster) {
var self = this;
// Construct endpoint URL.
var uri = goog.Uri.parse(endpoint + method);
uri.setParameterValue('key', this.getApiKey());
// Check whether to append cachebuster to request.
if (opt_cachebuster) {
uri.setParameterValue('cb', Date.now().toString());
}
// Firebase allows GET endpoints.
var isGet = httpMethod == fireauth.RpcHandler.HttpMethod.GET;
if (isGet) {
// For GET HTTP method, append data to query string.
for (var key in data) {
if (data.hasOwnProperty(key)) {
uri.setParameterValue(key, data[key]);
}
}
}
return new goog.Promise(function(resolve, reject) {
self.sendXhr_(
uri.toString(),
function(response) {
if (!response) {
// An unparseable response from the XHR most likely indicates some
// problem with the network.
reject(new fireauth.AuthError(
fireauth.authenum.Error.NETWORK_REQUEST_FAILED));
} else if (fireauth.RpcHandler.hasError_(response)) {
reject(fireauth.RpcHandler.getDeveloperError_(response,
opt_customErrorMap || {}));
} else {
resolve(response);
}
},
httpMethod,
// No post body data in GET requests.
isGet ? undefined : fireauth.RpcHandler.serialize_(data),
self.firebaseHeaders_,
self.firebaseTimeout_.get());
});
};
/**
* Verifies that the request has a valid email set.
* @param {!Object} request
* @private
*/
fireauth.RpcHandler.validateRequestHasEmail_ = function(request) {
if (!fireauth.util.isValidEmailAddress(request['email'])) {
throw new fireauth.AuthError(fireauth.authenum.Error.INVALID_EMAIL);
}
};
/**
* Verifies that the response has a valid email set.
* @param {!Object} response
* @private
*/
fireauth.RpcHandler.validateResponseHasEmail_ = function(response) {
if (!fireauth.util.isValidEmailAddress(response['email'])) {
throw new fireauth.AuthError(fireauth.authenum.Error.INTERNAL_ERROR);
}
};
/**
* Verifies that the an email is valid, if it is there.
* @param {!Object} request
* @private
*/
fireauth.RpcHandler.validateEmailIfPresent_ = function(request) {
if ('email' in request) {
fireauth.RpcHandler.validateRequestHasEmail_(request);
}
};
/**
* @param {string} providerId The provider ID.
* @param {?Array<string>=} opt_additionalScopes The list of scope strings.
* @return {?string} The IDP and its comma separated scope strings serialized.
* @private
*/
fireauth.RpcHandler.getAdditionalScopes_ =
function(providerId, opt_additionalScopes) {
var scopes = {};
if (opt_additionalScopes && opt_additionalScopes.length) {
scopes[providerId] = opt_additionalScopes.join(',');
// Return stringified scopes.
return goog.json.serialize(scopes);
}
return null;
};
/**
* Validates a response from getAuthUri.
* @param {?Object} response The getAuthUri response data.
* @private
*/
fireauth.RpcHandler.validateGetAuthResponse_ = function(response) {
if (!response[fireauth.RpcHandler.AuthServerField.AUTH_URI]) {
throw new fireauth.AuthError(fireauth.authenum.Error.INTERNAL_ERROR,
'Unable to determine the authorization endpoint for the specified '+
'provider. This may be an issue in the provider configuration.');
} else if ( !response[fireauth.RpcHandler.AuthServerField.SESSION_ID]) {
throw new fireauth.AuthError(fireauth.authenum.Error.INTERNAL_ERROR);
}
};
/**
* Requests createAuthUri endpoint to retrieve the authUri and session ID for
* the start of an OAuth handshake.
* @param {string} providerId The provider ID.
* @param {string} continueUri The IdP callback URL.
* @param {?Object=} opt_customParameters The optional OAuth custom parameters
* plain object.
* @param {?Array<string>=} opt_additionalScopes The list of scope strings.
* @param {?string=} opt_email The optional email.
* @param {?string=} opt_sessionId The optional session ID.
* @return {!goog.Promise<!Object>}
*/
fireauth.RpcHandler.prototype.getAuthUri = function(
providerId,
continueUri,
opt_customParameters,
opt_additionalScopes,
opt_email,
opt_sessionId) {
// SAML provider request is constructed differently than OAuth requests.
var isSaml = fireauth.idp.isSaml(providerId);
var request = {
'identifier': opt_email,
'providerId': providerId,
'continueUri': continueUri,
'customParameter': opt_customParameters || {},
'oauthScope': fireauth.RpcHandler.getAdditionalScopes_(
providerId, opt_additionalScopes),
'sessionId': opt_sessionId
};
// Custom parameters and OAuth scopes should be ignored.
if (isSaml) {
delete request['customParameter'];
delete request['oauthScope'];
}
// When sessionId is provided, mobile flow (Cordova) is being used, force
// code flow and not implicit flow. All other providers use code flow by
// default.
if (opt_sessionId && providerId == fireauth.idp.ProviderId.GOOGLE) {
request['authFlowType'] = 'CODE_FLOW';
}
return this.invokeRpc(fireauth.RpcHandler.ApiMethod.GET_AUTH_URI,
request);
};
/**
* Gets the list of IDPs that can be used to log in for the given identifier.
* @param {string} identifier The identifier, such as an email address.
* @return {!goog.Promise<!Array<string>>}
*/
fireauth.RpcHandler.prototype.fetchProvidersForIdentifier =
function(identifier) {
// createAuthUri returns an error if continue URI is not http or https.
// For environments like Cordova, Chrome extensions, native frameworks, file
// systems, etc, use http://localhost as continue URL.
var continueUri = fireauth.util.isHttpOrHttps() ?
fireauth.util.getCurrentUrl() : 'http://localhost';
var request = {
'identifier': identifier,
'continueUri': continueUri
};
return this.invokeRpc(fireauth.RpcHandler.ApiMethod.CREATE_AUTH_URI, request)
.then(function(response) {
return response[fireauth.RpcHandler.AuthServerField.ALL_PROVIDERS] ||
[];
});
};
/**
* Returns the list of sign in methods for the given identifier.
* @param {string} identifier The identifier, such as an email address.
* @return {!goog.Promise<!Array<string>>}
*/
fireauth.RpcHandler.prototype.fetchSignInMethodsForIdentifier = function(
identifier) {
// createAuthUri returns an error if continue URI is not http or https.
// For environments like Cordova, Chrome extensions, native frameworks, file
// systems, etc, use http://localhost as continue URL.
var continueUri = fireauth.util.isHttpOrHttps() ?
fireauth.util.getCurrentUrl() :
'http://localhost';
var request = {
'identifier': identifier,
'continueUri': continueUri
};
return this.invokeRpc(fireauth.RpcHandler.ApiMethod.CREATE_AUTH_URI, request)
.then(function(response) {
return response[fireauth.RpcHandler.AuthServerField.SIGNIN_METHODS] ||
[];
});
};
/**
* Gets the list of authorized domains for the specified project.
* @return {!goog.Promise<!Array<string>>}
*/
fireauth.RpcHandler.prototype.getAuthorizedDomains = function() {
return this.invokeRpc(fireauth.RpcHandler.ApiMethod.GET_PROJECT_CONFIG, {})
.then(function(response) {
return response[
fireauth.RpcHandler.AuthServerField.AUTHORIZED_DOMAINS] || [];
});
};
/**
* Gets the reCAPTCHA parameters needed to render the project's provisioned
* reCAPTCHA.
* @return {!goog.Promise<!Object>}
*/
fireauth.RpcHandler.prototype.getRecaptchaParam = function() {
return this.invokeRpc(fireauth.RpcHandler.ApiMethod.GET_RECAPTCHA_PARAM, {});
};
/**
* Gets the list of authorized domains for the specified project.
* @return {!goog.Promise<string>}
*/
fireauth.RpcHandler.prototype.getDynamicLinkDomain = function() {
var request = {
'returnDynamicLink': true
};
return this.invokeRpc(
fireauth.RpcHandler.ApiMethod.RETURN_DYNAMIC_LINK, request);
};
/**
* Checks if the provided iOS bundle ID belongs to the project as specified by
* the API key.
* @param {string} iosBundleId The iOS bundle ID to check.
* @return {!goog.Promise<void>}
*/
fireauth.RpcHandler.prototype.isIosBundleIdValid = function(iosBundleId) {
var request = {
'iosBundleId': iosBundleId
};
// This will either resolve if the identifier is valid or throw INVALID_APP_ID
// if not.
return this.invokeRpc(
fireauth.RpcHandler.ApiMethod.GET_PROJECT_CONFIG, request)
.then(function(result) {
// Do not return anything.
});
};
/**
* Checks if the provided Android package name belongs to the project as
* specified by the API key.
* @param {string} androidPackageName The iOS bundle ID to check.
* @param {?string=} opt_sha1Cert The optional SHA-1 Android cert to check.
* @return {!goog.Promise<void>}
*/
fireauth.RpcHandler.prototype.isAndroidPackageNameValid =
function(androidPackageName, opt_sha1Cert) {
var request = {
'androidPackageName': androidPackageName
};
// This is relevant for the native Android SDK flow.
// This will redirect to an FDL domain owned by GMScore instead of
// the developer's FDL domain as is done for Cordova apps.
if (!!opt_sha1Cert) {
request['sha1Cert'] = opt_sha1Cert;
}
// When no sha1Cert is passed, this will either resolve if the identifier is
// valid or throw INVALID_APP_ID if not.
// When sha1Cert is also passed, this will either resolve or fail with an
// INVALID_CERT_HASH error.
return this.invokeRpc(
fireauth.RpcHandler.ApiMethod.GET_PROJECT_CONFIG, request)
.then(function(result) {
// Do not return anything.
});
};
/**
* Checks if the provided OAuth client ID belongs to the project as specified by
* the API key.
* @param {string} clientId The OAuth client ID to check.
* @return {!goog.Promise<void>}
*/
fireauth.RpcHandler.prototype.isOAuthClientIdValid = function(clientId) {
var request = {
'clientId': clientId
};
// This will either resolve if the client ID is valid or throw
// INVALID_OAUTH_CLIENT_ID if not.
return this.invokeRpc(
fireauth.RpcHandler.ApiMethod.GET_PROJECT_CONFIG, request)
.then(function(result) {
// Do not return anything.
});
};
/**
* Requests getAccountInfo endpoint using an ID token.
* @param {string} idToken The ID token.
* @return {!goog.Promise<!Object>}
*/
fireauth.RpcHandler.prototype.getAccountInfoByIdToken = function(idToken) {
var request = {'idToken': idToken};
return this.invokeRpc(fireauth.RpcHandler.ApiMethod.GET_ACCOUNT_INFO,
request);
};
/**
* Validates a request to sign in with email and password.
* @param {!Object} request
* @private
*/
fireauth.RpcHandler.validateVerifyCustomTokenRequest_ = function(request) {
if (!request['token']) {
throw new fireauth.AuthError(fireauth.authenum.Error.INVALID_CUSTOM_TOKEN);
}
};
/**
* Verifies a custom token and returns a Promise that resolves with the ID
* token.
* @param {string} token The custom token.
* @return {!goog.Promise<!Object>}
*/
fireauth.RpcHandler.prototype.verifyCustomToken = function(token) {
var request = {'token': token};
return this.invokeRpc(fireauth.RpcHandler.ApiMethod.VERIFY_CUSTOM_TOKEN,
request);
};
/**
* Validates a request to sign in with email and password.
* @param {!Object} request
* @private
*/
fireauth.RpcHandler.validateVerifyPasswordRequest_ = function(request) {
fireauth.RpcHandler.validateRequestHasEmail_(request);
if (!request['password']) {
throw new fireauth.AuthError(fireauth.authenum.Error.INVALID_PASSWORD);
}
};
/**
* Verifies a password and returns a Promise that resolves with the ID
* token.
* @param {string} email The email address.
* @param {string} password The entered password.
* @return {!goog.Promise<!Object>}
*/
fireauth.RpcHandler.prototype.verifyPassword = function(email, password) {
var request = {
'email': email,
'password': password
};
return this.invokeRpc(fireauth.RpcHandler.ApiMethod.VERIFY_PASSWORD,
request);
};
/**
* Verifies an email link OTP for sign-in and returns a Promise that resolves
* with the ID token.
* @param {string} email The email address.
* @param {string} oobCode The email action OTP.
* @return {!goog.Promise<!Object>}
*/
fireauth.RpcHandler.prototype.emailLinkSignIn = function(email, oobCode) {
var request = {
'email': email,
'oobCode': oobCode
};
return this.invokeRpc(
fireauth.RpcHandler.ApiMethod.EMAIL_LINK_SIGNIN, request);
};
/**
* Verifies an email link OTP for linking and returns a Promise that resolves
* with the ID token.
* @param {string} idToken The ID token.
* @param {string} email The email address.
* @param {string} oobCode The email action OTP.
* @return {!goog.Promise<!Object>}
*/
fireauth.RpcHandler.prototype.emailLinkSignInForLinking =
function(idToken, email, oobCode) {
var request = {
'idToken': idToken,
'email': email,
'oobCode': oobCode
};
return this.invokeRpc(
fireauth.RpcHandler.ApiMethod.EMAIL_LINK_SIGNIN_FOR_LINKING,
request);
};
/**
* Validates a response that should contain an ID token.
* If no ID token is available, it checks if a multi-factor pending credential
* is available instead. In that case, it throws the MFA_REQUIRED error code.
* @param {?Object} response The server response data.
* @private
*/
fireauth.RpcHandler.validateIdTokenResponse_ = function(response) {
if (!response[fireauth.RpcHandler.AuthServerField.ID_TOKEN]) {
// User could be a second factor user.
// When second factor is required, a pending credential is returned.
if (response[fireauth.RpcHandler.AuthServerField.MFA_PENDING_CREDENTIAL]) {
throw new fireauth.AuthError(
fireauth.authenum.Error.MFA_REQUIRED,
null,
goog.object.clone(response));
}
throw new fireauth.AuthError(fireauth.authenum.Error.INTERNAL_ERROR);
}
};
/**
* Validates a getRecaptchaParam response.
* @param {?Object} response The server response data.
* @private
*/
fireauth.RpcHandler.validateGetRecaptchaParamResponse_ = function(response) {
// Both are required. This could change though.
if (!response[fireauth.RpcHandler.AuthServerField.RECAPTCHA_SITE_KEY]) {
throw new fireauth.AuthError(fireauth.authenum.Error.INTERNAL_ERROR);
}
};
/**
* Validates a request that sends the verification ID and code for a sign in/up
* phone Auth flow.
* @param {!Object} request The server request object.
* @private
*/
fireauth.RpcHandler.validateVerifyPhoneNumberRequest_ = function(request) {
// There are 2 cases here:
// case 1: sessionInfo and code
// case 2: phoneNumber and temporaryProof
if (request['phoneNumber'] || request['temporaryProof']) {
// Case 2. Both phoneNumber and temporaryProof should be set.
if (!request['phoneNumber'] || !request['temporaryProof']) {
throw new fireauth.AuthError(fireauth.authenum.Error.INTERNAL_ERROR);
}
} else {
// Otherwise it's case 1, so we expect sessionInfo and code.
if (!request['sessionInfo']) {
throw new fireauth.AuthError(
fireauth.authenum.Error.MISSING_SESSION_INFO);
}
if (!request['code']) {
throw new fireauth.AuthError(fireauth.authenum.Error.MISSING_CODE);
}
}
};
/**
* Validates a request that sends the verification ID and code for a link/update
* phone Auth flow.
* @param {!Object} request The server request object.
* @private
*/
fireauth.RpcHandler.validateVerifyPhoneNumberLinkRequest_ = function(request) {
// idToken should be required here.
if (!request['idToken']) {
throw new fireauth.AuthError(fireauth.authenum.Error.INTERNAL_ERROR);
}
// The other request parameters match the sign in flow.
fireauth.RpcHandler.validateVerifyPhoneNumberRequest_(request);
};
/**
* Validates a request to create an email and password account.
* @param {!Object} request
* @private
*/
fireauth.RpcHandler.validateCreateAccountRequest_ = function(request) {
fireauth.RpcHandler.validateRequestHasEmail_(request);
if (!request['password']) {
throw new fireauth.AuthError(fireauth.authenum.Error.WEAK_PASSWORD);
}
};
/**
* Validates a request to createAuthUri.
* @param {!Object} request
* @private
*/
fireauth.RpcHandler.validateGetAuthUriRequest_ = function(request) {
if (!request['continueUri']) {
throw new fireauth.AuthError(fireauth.authenum.Error.MISSING_CONTINUE_URI);
}
// Either a SAML or non SAML providerId must be provided.
if (!request['providerId']) {
throw new fireauth.AuthError(
fireauth.authenum.Error.INTERNAL_ERROR,
'A provider ID must be provided in the request.');
}
};
/**
* Creates an email/password account. Returns a Promise that resolves with the
* ID token.
* @param {string} email The email address of the account.
* @param {string} password The password.
* @return {!goog.Promise<!Object>}
*/
fireauth.RpcHandler.prototype.createAccount = function(email, password) {
var request = {
'email': email,
'password': password
};
return this.invokeRpc(fireauth.RpcHandler.ApiMethod.CREATE_ACCOUNT,
request);
};
/**
* Signs in a user as anonymous. Returns a Promise that resolves with the
* ID token.
* @return {!goog.Promise<!Object>}
*/
fireauth.RpcHandler.prototype.signInAnonymously = function() {
return this.invokeRpc(fireauth.RpcHandler.ApiMethod.SIGN_IN_ANONYMOUSLY, {});
};
/**
* Deletes the user's account corresponding to the idToken given.
* @param {string} idToken The idToken of the user.
* @return {!goog.Promise<undefined>}
*/
fireauth.RpcHandler.prototype.deleteAccount = function(idToken) {
var request = {
'idToken': idToken
};
return this.invokeRpc(fireauth.RpcHandler.ApiMethod.DELETE_ACCOUNT,
request);
};
/**
* Requests setAccountInfo endpoint for updateEmail operation.
* @param {string} idToken The ID token.
* @param {string} newEmail The new email.
* @return {!goog.Promise<!Object>}
*/
fireauth.RpcHandler.prototype.updateEmail = function(idToken, newEmail) {
var request = {
'idToken': idToken,
'email': newEmail
};
return this.invokeRpc(fireauth.RpcHandler.ApiMethod.SET_ACCOUNT_INFO,
request);
};
/**
* Validates a setAccountInfo request that updates the password.
* @param {!Object} request
* @private
*/
fireauth.RpcHandler.validateSetAccountInfoSensitive_ = function(request) {
fireauth.RpcHandler.validateEmailIfPresent_(request);
if (!request['password']) {
throw new fireauth.AuthError(fireauth.authenum.Error.WEAK_PASSWORD);
}
};
/**
* Requests setAccountInfo endpoint for updatePassword operation.
* @param {string} idToken The ID token.
* @param {string} newPassword The new password.
* @return {!goog.Promise<!Object>}
*/
fireauth.RpcHandler.prototype.updatePassword = function(idToken, newPassword) {
var request = {
'idToken': idToken,
'password': newPassword
};
return this