mirror of
https://github.com/titanscouting/tra-analysis.git
synced 2024-11-10 15:04:45 +00:00
507 lines
21 KiB
JavaScript
507 lines
21 KiB
JavaScript
/*! firebase-admin v6.0.0 */
|
|
"use strict";
|
|
/*!
|
|
* Copyright 2017 Google Inc.
|
|
*
|
|
* 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.
|
|
*/
|
|
var __extends = (this && this.__extends) || (function () {
|
|
var extendStatics = Object.setPrototypeOf ||
|
|
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
|
|
function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
|
|
return function (d, b) {
|
|
extendStatics(d, b);
|
|
function __() { this.constructor = d; }
|
|
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
|
|
};
|
|
})();
|
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
var deep_copy_1 = require("./deep-copy");
|
|
var error_1 = require("./error");
|
|
var validator = require("./validator");
|
|
var http = require("http");
|
|
var https = require("https");
|
|
var url = require("url");
|
|
var DefaultHttpResponse = /** @class */ (function () {
|
|
/**
|
|
* Constructs a new HttpResponse from the given LowLevelResponse.
|
|
*/
|
|
function DefaultHttpResponse(resp) {
|
|
this.status = resp.status;
|
|
this.headers = resp.headers;
|
|
this.text = resp.data;
|
|
try {
|
|
this.parsedData = JSON.parse(resp.data);
|
|
}
|
|
catch (err) {
|
|
this.parsedData = undefined;
|
|
this.parseError = err;
|
|
}
|
|
this.request = resp.config.method + " " + resp.config.url;
|
|
}
|
|
Object.defineProperty(DefaultHttpResponse.prototype, "data", {
|
|
get: function () {
|
|
if (this.isJson()) {
|
|
return this.parsedData;
|
|
}
|
|
throw new error_1.FirebaseAppError(error_1.AppErrorCodes.UNABLE_TO_PARSE_RESPONSE, "Error while parsing response data: \"" + this.parseError.toString() + "\". Raw server " +
|
|
("response: \"" + this.text + "\". Status code: \"" + this.status + "\". Outgoing ") +
|
|
("request: \"" + this.request + ".\""));
|
|
},
|
|
enumerable: true,
|
|
configurable: true
|
|
});
|
|
DefaultHttpResponse.prototype.isJson = function () {
|
|
return typeof this.parsedData !== 'undefined';
|
|
};
|
|
return DefaultHttpResponse;
|
|
}());
|
|
var HttpError = /** @class */ (function (_super) {
|
|
__extends(HttpError, _super);
|
|
function HttpError(response) {
|
|
var _this = _super.call(this, "Server responded with status " + response.status + ".") || this;
|
|
_this.response = response;
|
|
// Set the prototype so that instanceof checks will work correctly.
|
|
// See: https://github.com/Microsoft/TypeScript/issues/13965
|
|
Object.setPrototypeOf(_this, HttpError.prototype);
|
|
return _this;
|
|
}
|
|
return HttpError;
|
|
}(Error));
|
|
exports.HttpError = HttpError;
|
|
var HttpClient = /** @class */ (function () {
|
|
function HttpClient() {
|
|
}
|
|
/**
|
|
* Sends an HTTP request to a remote server. If the server responds with a successful response (2xx), the returned
|
|
* promise resolves with an HttpResponse. If the server responds with an error (3xx, 4xx, 5xx), the promise rejects
|
|
* with an HttpError. In case of all other errors, the promise rejects with a FirebaseAppError. If a request fails
|
|
* due to a low-level network error, transparently retries the request once before rejecting the promise.
|
|
*
|
|
* If the request data is specified as an object, it will be serialized into a JSON string. The application/json
|
|
* content-type header will also be automatically set in this case. For all other payload types, the content-type
|
|
* header should be explicitly set by the caller. To send a JSON leaf value (e.g. "foo", 5), parse it into JSON,
|
|
* and pass as a string or a Buffer along with the appropriate content-type header.
|
|
*
|
|
* @param {HttpRequest} request HTTP request to be sent.
|
|
* @return {Promise<HttpResponse>} A promise that resolves with the response details.
|
|
*/
|
|
HttpClient.prototype.send = function (config) {
|
|
return this.sendWithRetry(config);
|
|
};
|
|
/**
|
|
* Sends an HTTP request, and retries it once in case of low-level network errors.
|
|
*/
|
|
HttpClient.prototype.sendWithRetry = function (config, attempts) {
|
|
var _this = this;
|
|
if (attempts === void 0) { attempts = 0; }
|
|
return sendRequest(config)
|
|
.then(function (resp) {
|
|
return new DefaultHttpResponse(resp);
|
|
}).catch(function (err) {
|
|
var retryCodes = ['ECONNRESET', 'ETIMEDOUT'];
|
|
if (retryCodes.indexOf(err.code) !== -1 && attempts === 0) {
|
|
return _this.sendWithRetry(config, attempts + 1);
|
|
}
|
|
if (err.response) {
|
|
throw new HttpError(new DefaultHttpResponse(err.response));
|
|
}
|
|
if (err.code === 'ETIMEDOUT') {
|
|
throw new error_1.FirebaseAppError(error_1.AppErrorCodes.NETWORK_TIMEOUT, "Error while making request: " + err.message + ".");
|
|
}
|
|
throw new error_1.FirebaseAppError(error_1.AppErrorCodes.NETWORK_ERROR, "Error while making request: " + err.message + ". Error code: " + err.code);
|
|
});
|
|
};
|
|
return HttpClient;
|
|
}());
|
|
exports.HttpClient = HttpClient;
|
|
/**
|
|
* Sends an HTTP request based on the provided configuration. This is a wrapper around the http and https
|
|
* packages of Node.js, providing content processing, timeouts and error handling.
|
|
*/
|
|
function sendRequest(config) {
|
|
return new Promise(function (resolve, reject) {
|
|
var data;
|
|
var headers = config.headers || {};
|
|
if (config.data) {
|
|
if (validator.isObject(config.data)) {
|
|
data = new Buffer(JSON.stringify(config.data), 'utf-8');
|
|
if (typeof headers['Content-Type'] === 'undefined') {
|
|
headers['Content-Type'] = 'application/json;charset=utf-8';
|
|
}
|
|
}
|
|
else if (validator.isString(config.data)) {
|
|
data = new Buffer(config.data, 'utf-8');
|
|
}
|
|
else if (validator.isBuffer(config.data)) {
|
|
data = config.data;
|
|
}
|
|
else {
|
|
return reject(createError('Request data must be a string, a Buffer or a json serializable object', config));
|
|
}
|
|
// Add Content-Length header if data exists
|
|
headers['Content-Length'] = data.length.toString();
|
|
}
|
|
var parsed = url.parse(config.url);
|
|
var protocol = parsed.protocol || 'https:';
|
|
var isHttps = protocol === 'https:';
|
|
var options = {
|
|
hostname: parsed.hostname,
|
|
port: parsed.port,
|
|
path: parsed.path,
|
|
method: config.method,
|
|
headers: headers,
|
|
};
|
|
var transport = isHttps ? https : http;
|
|
var req = transport.request(options, function (res) {
|
|
if (req.aborted) {
|
|
return;
|
|
}
|
|
// Uncompress the response body transparently if required.
|
|
var respStream = res;
|
|
var encodings = ['gzip', 'compress', 'deflate'];
|
|
if (encodings.indexOf(res.headers['content-encoding']) !== -1) {
|
|
// Add the unzipper to the body stream processing pipeline.
|
|
var zlib = require('zlib');
|
|
respStream = respStream.pipe(zlib.createUnzip());
|
|
// Remove the content-encoding in order to not confuse downstream operations.
|
|
delete res.headers['content-encoding'];
|
|
}
|
|
var response = {
|
|
status: res.statusCode,
|
|
headers: res.headers,
|
|
request: req,
|
|
data: undefined,
|
|
config: config,
|
|
};
|
|
var responseBuffer = [];
|
|
respStream.on('data', function (chunk) {
|
|
responseBuffer.push(chunk);
|
|
});
|
|
respStream.on('error', function (err) {
|
|
if (req.aborted) {
|
|
return;
|
|
}
|
|
reject(enhanceError(err, config, null, req));
|
|
});
|
|
respStream.on('end', function () {
|
|
var responseData = Buffer.concat(responseBuffer).toString();
|
|
response.data = responseData;
|
|
finalizeRequest(resolve, reject, response);
|
|
});
|
|
});
|
|
// Handle errors
|
|
req.on('error', function (err) {
|
|
if (req.aborted) {
|
|
return;
|
|
}
|
|
reject(enhanceError(err, config, null, req));
|
|
});
|
|
if (config.timeout) {
|
|
// Listen to timeouts and throw an error.
|
|
req.setTimeout(config.timeout, function () {
|
|
req.abort();
|
|
reject(createError("timeout of " + config.timeout + "ms exceeded", config, 'ETIMEDOUT', req));
|
|
});
|
|
}
|
|
// Send the request
|
|
req.end(data);
|
|
});
|
|
}
|
|
/**
|
|
* Creates a new error from the given message, and enhances it with other information available.
|
|
*/
|
|
function createError(message, config, code, request, response) {
|
|
var error = new Error(message);
|
|
return enhanceError(error, config, code, request, response);
|
|
}
|
|
/**
|
|
* Enhances the given error by adding more information to it. Specifically, the HttpRequestConfig,
|
|
* the underlying request and response will be attached to the error.
|
|
*/
|
|
function enhanceError(error, config, code, request, response) {
|
|
error.config = config;
|
|
if (code) {
|
|
error.code = code;
|
|
}
|
|
error.request = request;
|
|
error.response = response;
|
|
return error;
|
|
}
|
|
/**
|
|
* Finalizes the current request in-flight by either resolving or rejecting the associated promise. In the event
|
|
* of an error, adds additional useful information to the returned error.
|
|
*/
|
|
function finalizeRequest(resolve, reject, response) {
|
|
if (response.status >= 200 && response.status < 300) {
|
|
resolve(response);
|
|
}
|
|
else {
|
|
reject(createError('Request failed with status code ' + response.status, response.config, null, response.request, response));
|
|
}
|
|
}
|
|
var AuthorizedHttpClient = /** @class */ (function (_super) {
|
|
__extends(AuthorizedHttpClient, _super);
|
|
function AuthorizedHttpClient(app) {
|
|
var _this = _super.call(this) || this;
|
|
_this.app = app;
|
|
return _this;
|
|
}
|
|
AuthorizedHttpClient.prototype.send = function (request) {
|
|
var _this = this;
|
|
return this.app.INTERNAL.getToken().then(function (accessTokenObj) {
|
|
var requestCopy = deep_copy_1.deepCopy(request);
|
|
requestCopy.headers = requestCopy.headers || {};
|
|
var authHeader = 'Authorization';
|
|
requestCopy.headers[authHeader] = "Bearer " + accessTokenObj.accessToken;
|
|
return _super.prototype.send.call(_this, requestCopy);
|
|
});
|
|
};
|
|
return AuthorizedHttpClient;
|
|
}(HttpClient));
|
|
exports.AuthorizedHttpClient = AuthorizedHttpClient;
|
|
/**
|
|
* Base class for handling HTTP requests.
|
|
*/
|
|
var HttpRequestHandler = /** @class */ (function () {
|
|
function HttpRequestHandler() {
|
|
}
|
|
/**
|
|
* Sends HTTP requests and returns a promise that resolves with the result.
|
|
* Will retry once if the first attempt encounters an AppErrorCodes.NETWORK_ERROR.
|
|
*
|
|
* @param {string} host The HTTP host.
|
|
* @param {number} port The port number.
|
|
* @param {string} path The endpoint path.
|
|
* @param {HttpMethod} httpMethod The http method.
|
|
* @param {object} [data] The request JSON.
|
|
* @param {object} [headers] The request headers.
|
|
* @param {number} [timeout] The request timeout in milliseconds.
|
|
* @return {Promise<object>} A promise that resolves with the response.
|
|
*/
|
|
HttpRequestHandler.prototype.sendRequest = function (host, port, path, httpMethod, data, headers, timeout) {
|
|
var _this = this;
|
|
// Convenience for calling the real _sendRequest() method with the original params.
|
|
var sendOneRequest = function () {
|
|
return _this._sendRequest(host, port, path, httpMethod, data, headers, timeout);
|
|
};
|
|
return sendOneRequest()
|
|
.catch(function (response) {
|
|
// Retry if the request failed due to a network error.
|
|
if (response.error instanceof error_1.FirebaseAppError) {
|
|
if (response.error.hasCode(error_1.AppErrorCodes.NETWORK_ERROR)) {
|
|
return sendOneRequest();
|
|
}
|
|
}
|
|
return Promise.reject(response);
|
|
});
|
|
};
|
|
/**
|
|
* Sends HTTP requests and returns a promise that resolves with the result.
|
|
*
|
|
* @param {string} host The HTTP host.
|
|
* @param {number} port The port number.
|
|
* @param {string} path The endpoint path.
|
|
* @param {HttpMethod} httpMethod The http method.
|
|
* @param {object} [data] The request JSON.
|
|
* @param {object} [headers] The request headers.
|
|
* @param {number} [timeout] The request timeout in milliseconds.
|
|
* @return {Promise<object>} A promise that resolves with the response.
|
|
*/
|
|
HttpRequestHandler.prototype._sendRequest = function (host, port, path, httpMethod, data, headers, timeout) {
|
|
var requestData;
|
|
if (data) {
|
|
try {
|
|
requestData = JSON.stringify(data);
|
|
}
|
|
catch (e) {
|
|
return Promise.reject(e);
|
|
}
|
|
}
|
|
var options = {
|
|
method: httpMethod,
|
|
host: host,
|
|
port: port,
|
|
path: path,
|
|
headers: headers,
|
|
};
|
|
// Only https endpoints.
|
|
return new Promise(function (resolve, reject) {
|
|
var req = https.request(options, function (res) {
|
|
var buffers = [];
|
|
res.on('data', function (buffer) { return buffers.push(buffer); });
|
|
res.on('end', function () {
|
|
var response = Buffer.concat(buffers).toString();
|
|
var statusCode = res.statusCode || 200;
|
|
var responseHeaders = res.headers || {};
|
|
var contentType = responseHeaders['content-type'] || 'application/json';
|
|
if (contentType.indexOf('text/html') !== -1 || contentType.indexOf('text/plain') !== -1) {
|
|
// Text response
|
|
if (statusCode >= 200 && statusCode < 300) {
|
|
resolve(response);
|
|
}
|
|
else {
|
|
reject({
|
|
statusCode: statusCode,
|
|
error: response,
|
|
});
|
|
}
|
|
}
|
|
else {
|
|
// JSON response
|
|
try {
|
|
var json = JSON.parse(response);
|
|
if (statusCode >= 200 && statusCode < 300) {
|
|
resolve(json);
|
|
}
|
|
else {
|
|
reject({
|
|
statusCode: statusCode,
|
|
error: json,
|
|
});
|
|
}
|
|
}
|
|
catch (error) {
|
|
var parsingError = new error_1.FirebaseAppError(error_1.AppErrorCodes.UNABLE_TO_PARSE_RESPONSE, "Failed to parse response data: \"" + error.toString() + "\". Raw server" +
|
|
("response: \"" + response + "\". Status code: \"" + res.statusCode + "\". Outgoing ") +
|
|
("request: \"" + options.method + " " + options.host + options.path + "\""));
|
|
reject({
|
|
statusCode: statusCode,
|
|
error: parsingError,
|
|
});
|
|
}
|
|
}
|
|
});
|
|
});
|
|
if (timeout) {
|
|
// Listen to timeouts and throw a network error.
|
|
req.on('socket', function (socket) {
|
|
socket.setTimeout(timeout);
|
|
socket.on('timeout', function () {
|
|
req.abort();
|
|
var networkTimeoutError = new error_1.FirebaseAppError(error_1.AppErrorCodes.NETWORK_TIMEOUT, host + " network timeout. Please try again.");
|
|
reject({
|
|
statusCode: 408,
|
|
error: networkTimeoutError,
|
|
});
|
|
});
|
|
});
|
|
}
|
|
req.on('error', function (error) {
|
|
var networkRequestError = new error_1.FirebaseAppError(error_1.AppErrorCodes.NETWORK_ERROR, "A network request error has occurred: " + (error && error.message));
|
|
reject({
|
|
statusCode: 502,
|
|
error: networkRequestError,
|
|
});
|
|
});
|
|
if (requestData) {
|
|
req.write(requestData);
|
|
}
|
|
req.end();
|
|
});
|
|
};
|
|
return HttpRequestHandler;
|
|
}());
|
|
exports.HttpRequestHandler = HttpRequestHandler;
|
|
/**
|
|
* Class that extends HttpRequestHandler and signs HTTP requests with a service
|
|
* credential access token.
|
|
*
|
|
* @param {Credential} credential The service account credential used to
|
|
* sign HTTP requests.
|
|
* @constructor
|
|
*/
|
|
var SignedApiRequestHandler = /** @class */ (function (_super) {
|
|
__extends(SignedApiRequestHandler, _super);
|
|
function SignedApiRequestHandler(app_) {
|
|
var _this = _super.call(this) || this;
|
|
_this.app_ = app_;
|
|
return _this;
|
|
}
|
|
/**
|
|
* Sends HTTP requests and returns a promise that resolves with the result.
|
|
*
|
|
* @param {string} host The HTTP host.
|
|
* @param {number} port The port number.
|
|
* @param {string} path The endpoint path.
|
|
* @param {HttpMethod} httpMethod The http method.
|
|
* @param {object} data The request JSON.
|
|
* @param {object} headers The request headers.
|
|
* @param {number} timeout The request timeout in milliseconds.
|
|
* @return {Promise} A promise that resolves with the response.
|
|
*/
|
|
SignedApiRequestHandler.prototype.sendRequest = function (host, port, path, httpMethod, data, headers, timeout) {
|
|
var _this = this;
|
|
return this.app_.INTERNAL.getToken().then(function (accessTokenObj) {
|
|
var headersCopy = (headers && deep_copy_1.deepCopy(headers)) || {};
|
|
var authorizationHeaderKey = 'Authorization';
|
|
headersCopy[authorizationHeaderKey] = 'Bearer ' + accessTokenObj.accessToken;
|
|
return _super.prototype.sendRequest.call(_this, host, port, path, httpMethod, data, headersCopy, timeout);
|
|
});
|
|
};
|
|
return SignedApiRequestHandler;
|
|
}(HttpRequestHandler));
|
|
exports.SignedApiRequestHandler = SignedApiRequestHandler;
|
|
/**
|
|
* Class that defines all the settings for the backend API endpoint.
|
|
*
|
|
* @param {string} endpoint The Firebase Auth backend endpoint.
|
|
* @param {HttpMethod} httpMethod The http method for that endpoint.
|
|
* @constructor
|
|
*/
|
|
var ApiSettings = /** @class */ (function () {
|
|
function ApiSettings(endpoint, httpMethod) {
|
|
if (httpMethod === void 0) { httpMethod = 'POST'; }
|
|
this.endpoint = endpoint;
|
|
this.httpMethod = httpMethod;
|
|
this.setRequestValidator(null)
|
|
.setResponseValidator(null);
|
|
}
|
|
/** @return {string} The backend API endpoint. */
|
|
ApiSettings.prototype.getEndpoint = function () {
|
|
return this.endpoint;
|
|
};
|
|
/** @return {HttpMethod} The request HTTP method. */
|
|
ApiSettings.prototype.getHttpMethod = function () {
|
|
return this.httpMethod;
|
|
};
|
|
/**
|
|
* @param {ApiCallbackFunction} requestValidator The request validator.
|
|
* @return {ApiSettings} The current API settings instance.
|
|
*/
|
|
ApiSettings.prototype.setRequestValidator = function (requestValidator) {
|
|
var nullFunction = function (request) { return undefined; };
|
|
this.requestValidator = requestValidator || nullFunction;
|
|
return this;
|
|
};
|
|
/** @return {ApiCallbackFunction} The request validator. */
|
|
ApiSettings.prototype.getRequestValidator = function () {
|
|
return this.requestValidator;
|
|
};
|
|
/**
|
|
* @param {ApiCallbackFunction} responseValidator The response validator.
|
|
* @return {ApiSettings} The current API settings instance.
|
|
*/
|
|
ApiSettings.prototype.setResponseValidator = function (responseValidator) {
|
|
var nullFunction = function (request) { return undefined; };
|
|
this.responseValidator = responseValidator || nullFunction;
|
|
return this;
|
|
};
|
|
/** @return {ApiCallbackFunction} The response validator. */
|
|
ApiSettings.prototype.getResponseValidator = function () {
|
|
return this.responseValidator;
|
|
};
|
|
return ApiSettings;
|
|
}());
|
|
exports.ApiSettings = ApiSettings;
|