Initial commit

This commit is contained in:
talksik
2021-12-29 01:57:42 -08:00
commit ce39a60b42
4634 changed files with 997667 additions and 0 deletions
+230
View File
@@ -0,0 +1,230 @@
/*! firebase-admin v10.0.1 */
/*!
* @license
* 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.
*/
/// <reference types="node" />
import { FirebaseApp } from '../app/firebase-app';
import http = require('http');
import { EventEmitter } from 'events';
/** Http method type definition. */
export declare type HttpMethod = 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH' | 'HEAD';
/** API callback function type definition. */
export declare type ApiCallbackFunction = (data: object) => void;
/**
* Configuration for constructing a new HTTP request.
*/
export interface HttpRequestConfig {
method: HttpMethod;
/** Target URL of the request. Should be a well-formed URL including protocol, hostname, port and path. */
url: string;
headers?: {
[key: string]: string;
};
data?: string | object | Buffer | null;
/** Connect and read timeout (in milliseconds) for the outgoing request. */
timeout?: number;
httpAgent?: http.Agent;
}
/**
* Represents an HTTP response received from a remote server.
*/
export interface HttpResponse {
readonly status: number;
readonly headers: any;
/** Response data as a raw string. */
readonly text?: string;
/** Response data as a parsed JSON object. */
readonly data?: any;
/** For multipart responses, the payloads of individual parts. */
readonly multipart?: Buffer[];
/**
* Indicates if the response content is JSON-formatted or not. If true, data field can be used
* to retrieve the content as a parsed JSON object.
*/
isJson(): boolean;
}
export declare class HttpError extends Error {
readonly response: HttpResponse;
constructor(response: HttpResponse);
}
/**
* Specifies how failing HTTP requests should be retried.
*/
export interface RetryConfig {
/** Maximum number of times to retry a given request. */
maxRetries: number;
/** HTTP status codes that should be retried. */
statusCodes?: number[];
/** Low-level I/O error codes that should be retried. */
ioErrorCodes?: string[];
/**
* The multiplier for exponential back off. The retry delay is calculated in seconds using the formula
* `(2^n) * backOffFactor`, where n is the number of retries performed so far. When the backOffFactor is set
* to 0, retries are not delayed. When the backOffFactor is 1, retry duration is doubled each iteration.
*/
backOffFactor?: number;
/** Maximum duration to wait before initiating a retry. */
maxDelayInMillis: number;
}
/**
* Default retry configuration for HTTP requests. Retries up to 4 times on connection reset and timeout errors
* as well as HTTP 503 errors. Exposed as a function to ensure that every HttpClient gets its own RetryConfig
* instance.
*/
export declare function defaultRetryConfig(): RetryConfig;
export declare class HttpClient {
private readonly retry;
constructor(retry?: RetryConfig | null);
/**
* 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 config - HTTP request to be sent.
* @returns A promise that resolves with the response details.
*/
send(config: HttpRequestConfig): Promise<HttpResponse>;
/**
* Sends an HTTP request. In the event of an error, retries the HTTP request according to the
* RetryConfig set on the HttpClient.
*
* @param config - HTTP request to be sent.
* @param retryAttempts - Number of retries performed up to now.
* @returns A promise that resolves with the response details.
*/
private sendWithRetry;
private createHttpResponse;
private waitForRetry;
/**
* Checks if a failed request is eligible for a retry, and if so returns the duration to wait before initiating
* the retry.
*
* @param retryAttempts - Number of retries completed up to now.
* @param err - The last encountered error.
* @returns A 2-tuple where the 1st element is the duration to wait before another retry, and the
* 2nd element is a boolean indicating whether the request is eligible for a retry or not.
*/
private getRetryDelayMillis;
private isRetryEligible;
/**
* Parses the Retry-After HTTP header as a milliseconds value. Return value is negative if the Retry-After header
* contains an expired timestamp or otherwise malformed.
*/
private parseRetryAfterIntoMillis;
private backOffDelayMillis;
}
/**
* Parses a full HTTP response message containing both a header and a body.
*
* @param response - The HTTP response to be parsed.
* @param config - The request configuration that resulted in the HTTP response.
* @returns An object containing the parsed HTTP status, headers and the body.
*/
export declare function parseHttpResponse(response: string | Buffer, config: HttpRequestConfig): HttpResponse;
export declare class AuthorizedHttpClient extends HttpClient {
private readonly app;
constructor(app: FirebaseApp);
send(request: HttpRequestConfig): Promise<HttpResponse>;
protected getToken(): Promise<string>;
}
/**
* Class that defines all the settings for the backend API endpoint.
*
* @param endpoint - The Firebase Auth backend endpoint.
* @param httpMethod - The http method for that endpoint.
* @constructor
*/
export declare class ApiSettings {
private endpoint;
private httpMethod;
private requestValidator;
private responseValidator;
constructor(endpoint: string, httpMethod?: HttpMethod);
/** @returns The backend API endpoint. */
getEndpoint(): string;
/** @returns The request HTTP method. */
getHttpMethod(): HttpMethod;
/**
* @param requestValidator - The request validator.
* @returns The current API settings instance.
*/
setRequestValidator(requestValidator: ApiCallbackFunction | null): ApiSettings;
/** @returns The request validator. */
getRequestValidator(): ApiCallbackFunction;
/**
* @param responseValidator - The response validator.
* @returns The current API settings instance.
*/
setResponseValidator(responseValidator: ApiCallbackFunction | null): ApiSettings;
/** @returns The response validator. */
getResponseValidator(): ApiCallbackFunction;
}
/**
* Class used for polling an endpoint with exponential backoff.
*
* Example usage:
* ```
* const poller = new ExponentialBackoffPoller();
* poller
* .poll(() => {
* return myRequestToPoll()
* .then((responseData: any) => {
* if (!isValid(responseData)) {
* // Continue polling.
* return null;
* }
*
* // Polling complete. Resolve promise with final response data.
* return responseData;
* });
* })
* .then((responseData: any) => {
* console.log(`Final response: ${responseData}`);
* });
* ```
*/
export declare class ExponentialBackoffPoller<T> extends EventEmitter {
private readonly initialPollingDelayMillis;
private readonly maxPollingDelayMillis;
private readonly masterTimeoutMillis;
private numTries;
private completed;
private masterTimer;
private repollTimer;
private pollCallback?;
private resolve;
private reject;
constructor(initialPollingDelayMillis?: number, maxPollingDelayMillis?: number, masterTimeoutMillis?: number);
/**
* Poll the provided callback with exponential backoff.
*
* @param callback - The callback to be called for each poll. If the
* callback resolves to a falsey value, polling will continue. Otherwise, the truthy
* resolution will be used to resolve the promise returned by this method.
* @returns A Promise which resolves to the truthy value returned by the provided
* callback when polling is complete.
*/
poll(callback: () => Promise<T>): Promise<T>;
private repoll;
private getPollingDelayMillis;
private markCompleted;
}
+845
View File
@@ -0,0 +1,845 @@
/*! firebase-admin v10.0.1 */
"use strict";
/*!
* @license
* 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 = function (d, b) {
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 extendStatics(d, b);
};
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 });
exports.ExponentialBackoffPoller = exports.ApiSettings = exports.AuthorizedHttpClient = exports.parseHttpResponse = exports.HttpClient = exports.defaultRetryConfig = exports.HttpError = void 0;
var error_1 = require("./error");
var validator = require("./validator");
var http = require("http");
var https = require("https");
var url = require("url");
var events_1 = require("events");
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 {
if (!resp.data) {
throw new error_1.FirebaseAppError(error_1.AppErrorCodes.INTERNAL_ERROR, 'HTTP response missing data.');
}
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: false,
configurable: true
});
DefaultHttpResponse.prototype.isJson = function () {
return typeof this.parsedData !== 'undefined';
};
return DefaultHttpResponse;
}());
/**
* Represents a multipart HTTP response. Parts that constitute the response body can be accessed
* via the multipart getter. Getters for text and data throw errors.
*/
var MultipartHttpResponse = /** @class */ (function () {
function MultipartHttpResponse(resp) {
this.status = resp.status;
this.headers = resp.headers;
this.multipart = resp.multipart;
}
Object.defineProperty(MultipartHttpResponse.prototype, "text", {
get: function () {
throw new error_1.FirebaseAppError(error_1.AppErrorCodes.UNABLE_TO_PARSE_RESPONSE, 'Unable to parse multipart payload as text');
},
enumerable: false,
configurable: true
});
Object.defineProperty(MultipartHttpResponse.prototype, "data", {
get: function () {
throw new error_1.FirebaseAppError(error_1.AppErrorCodes.UNABLE_TO_PARSE_RESPONSE, 'Unable to parse multipart payload as JSON');
},
enumerable: false,
configurable: true
});
MultipartHttpResponse.prototype.isJson = function () {
return false;
};
return MultipartHttpResponse;
}());
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;
/**
* Default retry configuration for HTTP requests. Retries up to 4 times on connection reset and timeout errors
* as well as HTTP 503 errors. Exposed as a function to ensure that every HttpClient gets its own RetryConfig
* instance.
*/
function defaultRetryConfig() {
return {
maxRetries: 4,
statusCodes: [503],
ioErrorCodes: ['ECONNRESET', 'ETIMEDOUT'],
backOffFactor: 0.5,
maxDelayInMillis: 60 * 1000,
};
}
exports.defaultRetryConfig = defaultRetryConfig;
/**
* Ensures that the given RetryConfig object is valid.
*
* @param retry - The configuration to be validated.
*/
function validateRetryConfig(retry) {
if (!validator.isNumber(retry.maxRetries) || retry.maxRetries < 0) {
throw new error_1.FirebaseAppError(error_1.AppErrorCodes.INVALID_ARGUMENT, 'maxRetries must be a non-negative integer');
}
if (typeof retry.backOffFactor !== 'undefined') {
if (!validator.isNumber(retry.backOffFactor) || retry.backOffFactor < 0) {
throw new error_1.FirebaseAppError(error_1.AppErrorCodes.INVALID_ARGUMENT, 'backOffFactor must be a non-negative number');
}
}
if (!validator.isNumber(retry.maxDelayInMillis) || retry.maxDelayInMillis < 0) {
throw new error_1.FirebaseAppError(error_1.AppErrorCodes.INVALID_ARGUMENT, 'maxDelayInMillis must be a non-negative integer');
}
if (typeof retry.statusCodes !== 'undefined' && !validator.isArray(retry.statusCodes)) {
throw new error_1.FirebaseAppError(error_1.AppErrorCodes.INVALID_ARGUMENT, 'statusCodes must be an array');
}
if (typeof retry.ioErrorCodes !== 'undefined' && !validator.isArray(retry.ioErrorCodes)) {
throw new error_1.FirebaseAppError(error_1.AppErrorCodes.INVALID_ARGUMENT, 'ioErrorCodes must be an array');
}
}
var HttpClient = /** @class */ (function () {
function HttpClient(retry) {
if (retry === void 0) { retry = defaultRetryConfig(); }
this.retry = retry;
if (this.retry) {
validateRetryConfig(this.retry);
}
}
/**
* 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 config - HTTP request to be sent.
* @returns A promise that resolves with the response details.
*/
HttpClient.prototype.send = function (config) {
return this.sendWithRetry(config);
};
/**
* Sends an HTTP request. In the event of an error, retries the HTTP request according to the
* RetryConfig set on the HttpClient.
*
* @param config - HTTP request to be sent.
* @param retryAttempts - Number of retries performed up to now.
* @returns A promise that resolves with the response details.
*/
HttpClient.prototype.sendWithRetry = function (config, retryAttempts) {
var _this = this;
if (retryAttempts === void 0) { retryAttempts = 0; }
return AsyncHttpCall.invoke(config)
.then(function (resp) {
return _this.createHttpResponse(resp);
})
.catch(function (err) {
var _a = _this.getRetryDelayMillis(retryAttempts, err), delayMillis = _a[0], canRetry = _a[1];
if (canRetry && _this.retry && delayMillis <= _this.retry.maxDelayInMillis) {
return _this.waitForRetry(delayMillis).then(function () {
return _this.sendWithRetry(config, retryAttempts + 1);
});
}
if (err.response) {
throw new HttpError(_this.createHttpResponse(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);
});
};
HttpClient.prototype.createHttpResponse = function (resp) {
if (resp.multipart) {
return new MultipartHttpResponse(resp);
}
return new DefaultHttpResponse(resp);
};
HttpClient.prototype.waitForRetry = function (delayMillis) {
if (delayMillis > 0) {
return new Promise(function (resolve) {
setTimeout(resolve, delayMillis);
});
}
return Promise.resolve();
};
/**
* Checks if a failed request is eligible for a retry, and if so returns the duration to wait before initiating
* the retry.
*
* @param retryAttempts - Number of retries completed up to now.
* @param err - The last encountered error.
* @returns A 2-tuple where the 1st element is the duration to wait before another retry, and the
* 2nd element is a boolean indicating whether the request is eligible for a retry or not.
*/
HttpClient.prototype.getRetryDelayMillis = function (retryAttempts, err) {
if (!this.isRetryEligible(retryAttempts, err)) {
return [0, false];
}
var response = err.response;
if (response && response.headers['retry-after']) {
var delayMillis = this.parseRetryAfterIntoMillis(response.headers['retry-after']);
if (delayMillis > 0) {
return [delayMillis, true];
}
}
return [this.backOffDelayMillis(retryAttempts), true];
};
HttpClient.prototype.isRetryEligible = function (retryAttempts, err) {
if (!this.retry) {
return false;
}
if (retryAttempts >= this.retry.maxRetries) {
return false;
}
if (err.response) {
var statusCodes = this.retry.statusCodes || [];
return statusCodes.indexOf(err.response.status) !== -1;
}
if (err.code) {
var retryCodes = this.retry.ioErrorCodes || [];
return retryCodes.indexOf(err.code) !== -1;
}
return false;
};
/**
* Parses the Retry-After HTTP header as a milliseconds value. Return value is negative if the Retry-After header
* contains an expired timestamp or otherwise malformed.
*/
HttpClient.prototype.parseRetryAfterIntoMillis = function (retryAfter) {
var delaySeconds = parseInt(retryAfter, 10);
if (!isNaN(delaySeconds)) {
return delaySeconds * 1000;
}
var date = new Date(retryAfter);
if (!isNaN(date.getTime())) {
return date.getTime() - Date.now();
}
return -1;
};
HttpClient.prototype.backOffDelayMillis = function (retryAttempts) {
if (retryAttempts === 0) {
return 0;
}
if (!this.retry) {
throw new error_1.FirebaseAppError(error_1.AppErrorCodes.INTERNAL_ERROR, 'Expected this.retry to exist.');
}
var backOffFactor = this.retry.backOffFactor || 0;
var delayInSeconds = (Math.pow(2, retryAttempts)) * backOffFactor;
return Math.min(delayInSeconds * 1000, this.retry.maxDelayInMillis);
};
return HttpClient;
}());
exports.HttpClient = HttpClient;
/**
* Parses a full HTTP response message containing both a header and a body.
*
* @param response - The HTTP response to be parsed.
* @param config - The request configuration that resulted in the HTTP response.
* @returns An object containing the parsed HTTP status, headers and the body.
*/
function parseHttpResponse(response, config) {
var responseText = validator.isBuffer(response) ?
response.toString('utf-8') : response;
var endOfHeaderPos = responseText.indexOf('\r\n\r\n');
var headerLines = responseText.substring(0, endOfHeaderPos).split('\r\n');
var statusLine = headerLines[0];
var status = statusLine.trim().split(/\s/)[1];
var headers = {};
headerLines.slice(1).forEach(function (line) {
var colonPos = line.indexOf(':');
var name = line.substring(0, colonPos).trim().toLowerCase();
var value = line.substring(colonPos + 1).trim();
headers[name] = value;
});
var data = responseText.substring(endOfHeaderPos + 4);
if (data.endsWith('\n')) {
data = data.slice(0, -1);
}
if (data.endsWith('\r')) {
data = data.slice(0, -1);
}
var lowLevelResponse = {
status: parseInt(status, 10),
headers: headers,
data: data,
config: config,
request: null,
};
if (!validator.isNumber(lowLevelResponse.status)) {
throw new error_1.FirebaseAppError(error_1.AppErrorCodes.INTERNAL_ERROR, 'Malformed HTTP status line.');
}
return new DefaultHttpResponse(lowLevelResponse);
}
exports.parseHttpResponse = parseHttpResponse;
/**
* A helper class for sending HTTP requests over the wire. This is a wrapper around the standard
* http and https packages of Node.js, providing content processing, timeouts and error handling.
* It also wraps the callback API of the Node.js standard library in a more flexible Promise API.
*/
var AsyncHttpCall = /** @class */ (function () {
function AsyncHttpCall(config) {
var _this = this;
try {
this.config = new HttpRequestConfigImpl(config);
this.options = this.config.buildRequestOptions();
this.entity = this.config.buildEntity(this.options.headers);
this.promise = new Promise(function (resolve, reject) {
_this.resolve = resolve;
_this.reject = reject;
_this.execute();
});
}
catch (err) {
this.promise = Promise.reject(this.enhanceError(err, null));
}
}
/**
* Sends an HTTP request based on the provided configuration.
*/
AsyncHttpCall.invoke = function (config) {
return new AsyncHttpCall(config).promise;
};
AsyncHttpCall.prototype.execute = function () {
var _this = this;
var transport = this.options.protocol === 'https:' ? https : http;
var req = transport.request(this.options, function (res) {
_this.handleResponse(res, req);
});
// Handle errors
req.on('error', function (err) {
if (req.aborted) {
return;
}
_this.enhanceAndReject(err, null, req);
});
var timeout = this.config.timeout;
var timeoutCallback = function () {
req.abort();
_this.rejectWithError("timeout of " + timeout + "ms exceeded", 'ETIMEDOUT', req);
};
if (timeout) {
// Listen to timeouts and throw an error.
req.setTimeout(timeout, timeoutCallback);
req.on('socket', function (socket) {
socket.setTimeout(timeout, timeoutCallback);
});
}
// Send the request
req.end(this.entity);
};
AsyncHttpCall.prototype.handleResponse = function (res, req) {
if (req.aborted) {
return;
}
if (!res.statusCode) {
throw new error_1.FirebaseAppError(error_1.AppErrorCodes.INTERNAL_ERROR, 'Expected a statusCode on the response from a ClientRequest');
}
var response = {
status: res.statusCode,
headers: res.headers,
request: req,
data: undefined,
config: this.config,
};
var boundary = this.getMultipartBoundary(res.headers);
var respStream = this.uncompressResponse(res);
if (boundary) {
this.handleMultipartResponse(response, respStream, boundary);
}
else {
this.handleRegularResponse(response, respStream);
}
};
/**
* Extracts multipart boundary from the HTTP header. The content-type header of a multipart
* response has the form 'multipart/subtype; boundary=string'.
*
* If the content-type header does not exist, or does not start with
* 'multipart/', then null will be returned.
*/
AsyncHttpCall.prototype.getMultipartBoundary = function (headers) {
var contentType = headers['content-type'];
if (!contentType || !contentType.startsWith('multipart/')) {
return null;
}
var segments = contentType.split(';');
var emptyObject = {};
var headerParams = segments.slice(1)
.map(function (segment) { return segment.trim().split('='); })
.reduce(function (curr, params) {
// Parse key=value pairs in the content-type header into properties of an object.
if (params.length === 2) {
var keyValuePair = {};
keyValuePair[params[0]] = params[1];
return Object.assign(curr, keyValuePair);
}
return curr;
}, emptyObject);
return headerParams.boundary;
};
AsyncHttpCall.prototype.uncompressResponse = function (res) {
// Uncompress the response body transparently if required.
var respStream = res;
var encodings = ['gzip', 'compress', 'deflate'];
if (res.headers['content-encoding'] && encodings.indexOf(res.headers['content-encoding']) !== -1) {
// Add the unzipper to the body stream processing pipeline.
var zlib = require('zlib'); // eslint-disable-line @typescript-eslint/no-var-requires
respStream = respStream.pipe(zlib.createUnzip());
// Remove the content-encoding in order to not confuse downstream operations.
delete res.headers['content-encoding'];
}
return respStream;
};
AsyncHttpCall.prototype.handleMultipartResponse = function (response, respStream, boundary) {
var _this = this;
var dicer = require('dicer'); // eslint-disable-line @typescript-eslint/no-var-requires
var multipartParser = new dicer({ boundary: boundary });
var responseBuffer = [];
multipartParser.on('part', function (part) {
var tempBuffers = [];
part.on('data', function (partData) {
tempBuffers.push(partData);
});
part.on('end', function () {
responseBuffer.push(Buffer.concat(tempBuffers));
});
});
multipartParser.on('finish', function () {
response.data = undefined;
response.multipart = responseBuffer;
_this.finalizeResponse(response);
});
respStream.pipe(multipartParser);
};
AsyncHttpCall.prototype.handleRegularResponse = function (response, respStream) {
var _this = this;
var responseBuffer = [];
respStream.on('data', function (chunk) {
responseBuffer.push(chunk);
});
respStream.on('error', function (err) {
var req = response.request;
if (req && req.aborted) {
return;
}
_this.enhanceAndReject(err, null, req);
});
respStream.on('end', function () {
response.data = Buffer.concat(responseBuffer).toString();
_this.finalizeResponse(response);
});
};
/**
* Finalizes the current HTTP call in-flight by either resolving or rejecting the associated
* promise. In the event of an error, adds additional useful information to the returned error.
*/
AsyncHttpCall.prototype.finalizeResponse = function (response) {
if (response.status >= 200 && response.status < 300) {
this.resolve(response);
}
else {
this.rejectWithError('Request failed with status code ' + response.status, null, response.request, response);
}
};
/**
* Creates a new error from the given message, and enhances it with other information available.
* Then the promise associated with this HTTP call is rejected with the resulting error.
*/
AsyncHttpCall.prototype.rejectWithError = function (message, code, request, response) {
var error = new Error(message);
this.enhanceAndReject(error, code, request, response);
};
AsyncHttpCall.prototype.enhanceAndReject = function (error, code, request, response) {
this.reject(this.enhanceError(error, 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.
*/
AsyncHttpCall.prototype.enhanceError = function (error, code, request, response) {
error.config = this.config;
if (code) {
error.code = code;
}
error.request = request;
error.response = response;
return error;
};
return AsyncHttpCall;
}());
/**
* An adapter class for extracting options and entity data from an HttpRequestConfig.
*/
var HttpRequestConfigImpl = /** @class */ (function () {
function HttpRequestConfigImpl(config) {
this.config = config;
}
Object.defineProperty(HttpRequestConfigImpl.prototype, "method", {
get: function () {
return this.config.method;
},
enumerable: false,
configurable: true
});
Object.defineProperty(HttpRequestConfigImpl.prototype, "url", {
get: function () {
return this.config.url;
},
enumerable: false,
configurable: true
});
Object.defineProperty(HttpRequestConfigImpl.prototype, "headers", {
get: function () {
return this.config.headers;
},
enumerable: false,
configurable: true
});
Object.defineProperty(HttpRequestConfigImpl.prototype, "data", {
get: function () {
return this.config.data;
},
enumerable: false,
configurable: true
});
Object.defineProperty(HttpRequestConfigImpl.prototype, "timeout", {
get: function () {
return this.config.timeout;
},
enumerable: false,
configurable: true
});
Object.defineProperty(HttpRequestConfigImpl.prototype, "httpAgent", {
get: function () {
return this.config.httpAgent;
},
enumerable: false,
configurable: true
});
HttpRequestConfigImpl.prototype.buildRequestOptions = function () {
var parsed = this.buildUrl();
var protocol = parsed.protocol;
var port = parsed.port;
if (!port) {
var isHttps = protocol === 'https:';
port = isHttps ? '443' : '80';
}
return {
protocol: protocol,
hostname: parsed.hostname,
port: port,
path: parsed.path,
method: this.method,
agent: this.httpAgent,
headers: Object.assign({}, this.headers),
};
};
HttpRequestConfigImpl.prototype.buildEntity = function (headers) {
var data;
if (!this.hasEntity() || !this.isEntityEnclosingRequest()) {
return data;
}
if (validator.isBuffer(this.data)) {
data = this.data;
}
else if (validator.isObject(this.data)) {
data = Buffer.from(JSON.stringify(this.data), 'utf-8');
if (typeof headers['content-type'] === 'undefined') {
headers['content-type'] = 'application/json;charset=utf-8';
}
}
else if (validator.isString(this.data)) {
data = Buffer.from(this.data, 'utf-8');
}
else {
throw new Error('Request data must be a string, a Buffer or a json serializable object');
}
// Add Content-Length header if data exists.
headers['Content-Length'] = data.length.toString();
return data;
};
HttpRequestConfigImpl.prototype.buildUrl = function () {
var fullUrl = this.urlWithProtocol();
if (!this.hasEntity() || this.isEntityEnclosingRequest()) {
return url.parse(fullUrl);
}
if (!validator.isObject(this.data)) {
throw new Error(this.method + " requests cannot have a body");
}
// Parse URL and append data to query string.
var parsedUrl = new url.URL(fullUrl);
var dataObj = this.data;
for (var key in dataObj) {
if (Object.prototype.hasOwnProperty.call(dataObj, key)) {
parsedUrl.searchParams.append(key, dataObj[key]);
}
}
return url.parse(parsedUrl.toString());
};
HttpRequestConfigImpl.prototype.urlWithProtocol = function () {
var fullUrl = this.url;
if (fullUrl.startsWith('http://') || fullUrl.startsWith('https://')) {
return fullUrl;
}
return "https://" + fullUrl;
};
HttpRequestConfigImpl.prototype.hasEntity = function () {
return !!this.data;
};
HttpRequestConfigImpl.prototype.isEntityEnclosingRequest = function () {
// GET and HEAD requests do not support entity (body) in request.
return this.method !== 'GET' && this.method !== 'HEAD';
};
return HttpRequestConfigImpl;
}());
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.getToken().then(function (token) {
var requestCopy = Object.assign({}, request);
requestCopy.headers = Object.assign({}, request.headers);
var authHeader = 'Authorization';
requestCopy.headers[authHeader] = "Bearer " + token;
if (!requestCopy.httpAgent && _this.app.options.httpAgent) {
requestCopy.httpAgent = _this.app.options.httpAgent;
}
return _super.prototype.send.call(_this, requestCopy);
});
};
AuthorizedHttpClient.prototype.getToken = function () {
return this.app.INTERNAL.getToken()
.then(function (accessTokenObj) {
return accessTokenObj.accessToken;
});
};
return AuthorizedHttpClient;
}(HttpClient));
exports.AuthorizedHttpClient = AuthorizedHttpClient;
/**
* Class that defines all the settings for the backend API endpoint.
*
* @param endpoint - The Firebase Auth backend endpoint.
* @param 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);
}
/** @returns The backend API endpoint. */
ApiSettings.prototype.getEndpoint = function () {
return this.endpoint;
};
/** @returns The request HTTP method. */
ApiSettings.prototype.getHttpMethod = function () {
return this.httpMethod;
};
/**
* @param requestValidator - The request validator.
* @returns The current API settings instance.
*/
ApiSettings.prototype.setRequestValidator = function (requestValidator) {
var nullFunction = function () { return undefined; };
this.requestValidator = requestValidator || nullFunction;
return this;
};
/** @returns The request validator. */
ApiSettings.prototype.getRequestValidator = function () {
return this.requestValidator;
};
/**
* @param responseValidator - The response validator.
* @returns The current API settings instance.
*/
ApiSettings.prototype.setResponseValidator = function (responseValidator) {
var nullFunction = function () { return undefined; };
this.responseValidator = responseValidator || nullFunction;
return this;
};
/** @returns The response validator. */
ApiSettings.prototype.getResponseValidator = function () {
return this.responseValidator;
};
return ApiSettings;
}());
exports.ApiSettings = ApiSettings;
/**
* Class used for polling an endpoint with exponential backoff.
*
* Example usage:
* ```
* const poller = new ExponentialBackoffPoller();
* poller
* .poll(() => {
* return myRequestToPoll()
* .then((responseData: any) => {
* if (!isValid(responseData)) {
* // Continue polling.
* return null;
* }
*
* // Polling complete. Resolve promise with final response data.
* return responseData;
* });
* })
* .then((responseData: any) => {
* console.log(`Final response: ${responseData}`);
* });
* ```
*/
var ExponentialBackoffPoller = /** @class */ (function (_super) {
__extends(ExponentialBackoffPoller, _super);
function ExponentialBackoffPoller(initialPollingDelayMillis, maxPollingDelayMillis, masterTimeoutMillis) {
if (initialPollingDelayMillis === void 0) { initialPollingDelayMillis = 1000; }
if (maxPollingDelayMillis === void 0) { maxPollingDelayMillis = 10000; }
if (masterTimeoutMillis === void 0) { masterTimeoutMillis = 60000; }
var _this = _super.call(this) || this;
_this.initialPollingDelayMillis = initialPollingDelayMillis;
_this.maxPollingDelayMillis = maxPollingDelayMillis;
_this.masterTimeoutMillis = masterTimeoutMillis;
_this.numTries = 0;
_this.completed = false;
return _this;
}
/**
* Poll the provided callback with exponential backoff.
*
* @param callback - The callback to be called for each poll. If the
* callback resolves to a falsey value, polling will continue. Otherwise, the truthy
* resolution will be used to resolve the promise returned by this method.
* @returns A Promise which resolves to the truthy value returned by the provided
* callback when polling is complete.
*/
ExponentialBackoffPoller.prototype.poll = function (callback) {
var _this = this;
if (this.pollCallback) {
throw new Error('poll() can only be called once per instance of ExponentialBackoffPoller');
}
this.pollCallback = callback;
this.on('poll', this.repoll);
this.masterTimer = setTimeout(function () {
if (_this.completed) {
return;
}
_this.markCompleted();
_this.reject(new Error('ExponentialBackoffPoller deadline exceeded - Master timeout reached'));
}, this.masterTimeoutMillis);
return new Promise(function (resolve, reject) {
_this.resolve = resolve;
_this.reject = reject;
_this.repoll();
});
};
ExponentialBackoffPoller.prototype.repoll = function () {
var _this = this;
this.pollCallback()
.then(function (result) {
if (_this.completed) {
return;
}
if (!result) {
_this.repollTimer =
setTimeout(function () { return _this.emit('poll'); }, _this.getPollingDelayMillis());
_this.numTries++;
return;
}
_this.markCompleted();
_this.resolve(result);
})
.catch(function (err) {
if (_this.completed) {
return;
}
_this.markCompleted();
_this.reject(err);
});
};
ExponentialBackoffPoller.prototype.getPollingDelayMillis = function () {
var increasedPollingDelay = Math.pow(2, this.numTries) * this.initialPollingDelayMillis;
return Math.min(increasedPollingDelay, this.maxPollingDelayMillis);
};
ExponentialBackoffPoller.prototype.markCompleted = function () {
this.completed = true;
if (this.masterTimer) {
clearTimeout(this.masterTimer);
}
if (this.repollTimer) {
clearTimeout(this.repollTimer);
}
};
return ExponentialBackoffPoller;
}(events_1.EventEmitter));
exports.ExponentialBackoffPoller = ExponentialBackoffPoller;
+128
View File
@@ -0,0 +1,128 @@
/*! firebase-admin v10.0.1 */
/*!
* @license
* Copyright 2021 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.
*/
/// <reference types="node" />
import { App } from '../app';
import { ServiceAccountCredential } from '../app/credential-internal';
import { AuthorizedHttpClient } from './api-request';
import { Algorithm } from 'jsonwebtoken';
import { ErrorInfo } from '../utils/error';
/**
* CryptoSigner interface represents an object that can be used to sign JWTs.
*/
export interface CryptoSigner {
/**
* The name of the signing algorithm.
*/
readonly algorithm: Algorithm;
/**
* Cryptographically signs a buffer of data.
*
* @param buffer - The data to be signed.
* @returns A promise that resolves with the raw bytes of a signature.
*/
sign(buffer: Buffer): Promise<Buffer>;
/**
* Returns the ID of the service account used to sign tokens.
*
* @returns A promise that resolves with a service account ID.
*/
getAccountId(): Promise<string>;
}
/**
* A CryptoSigner implementation that uses an explicitly specified service account private key to
* sign data. Performs all operations locally, and does not make any RPC calls.
*/
export declare class ServiceAccountSigner implements CryptoSigner {
private readonly credential;
algorithm: Algorithm;
/**
* Creates a new CryptoSigner instance from the given service account credential.
*
* @param credential - A service account credential.
*/
constructor(credential: ServiceAccountCredential);
/**
* @inheritDoc
*/
sign(buffer: Buffer): Promise<Buffer>;
/**
* @inheritDoc
*/
getAccountId(): Promise<string>;
}
/**
* A CryptoSigner implementation that uses the remote IAM service to sign data. If initialized without
* a service account ID, attempts to discover a service account ID by consulting the local Metadata
* service. This will succeed in managed environments like Google Cloud Functions and App Engine.
*
* @see https://cloud.google.com/iam/reference/rest/v1/projects.serviceAccounts/signBlob
* @see https://cloud.google.com/compute/docs/storing-retrieving-metadata
*/
export declare class IAMSigner implements CryptoSigner {
algorithm: Algorithm;
private readonly httpClient;
private serviceAccountId?;
constructor(httpClient: AuthorizedHttpClient, serviceAccountId?: string);
/**
* @inheritDoc
*/
sign(buffer: Buffer): Promise<Buffer>;
/**
* @inheritDoc
*/
getAccountId(): Promise<string>;
}
/**
* Creates a new CryptoSigner instance for the given app. If the app has been initialized with a
* service account credential, creates a ServiceAccountSigner.
*
* @param app - A FirebaseApp instance.
* @returns A CryptoSigner instance.
*/
export declare function cryptoSignerFromApp(app: App): CryptoSigner;
/**
* Defines extended error info type. This includes a code, message string, and error data.
*/
export interface ExtendedErrorInfo extends ErrorInfo {
cause?: Error;
}
/**
* CryptoSigner error code structure.
*
* @param errorInfo - The error information (code and message).
* @constructor
*/
export declare class CryptoSignerError extends Error {
private errorInfo;
constructor(errorInfo: ExtendedErrorInfo);
/** @returns The error code. */
get code(): string;
/** @returns The error message. */
get message(): string;
/** @returns The error data. */
get cause(): Error | undefined;
}
/**
* Crypto Signer error codes and their default messages.
*/
export declare class CryptoSignerErrorCode {
static INVALID_ARGUMENT: string;
static INTERNAL_ERROR: string;
static INVALID_CREDENTIAL: string;
static SERVER_ERROR: string;
}
+237
View File
@@ -0,0 +1,237 @@
/*! firebase-admin v10.0.1 */
"use strict";
/*!
* @license
* Copyright 2021 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 = function (d, b) {
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 extendStatics(d, b);
};
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 });
exports.CryptoSignerErrorCode = exports.CryptoSignerError = exports.cryptoSignerFromApp = exports.IAMSigner = exports.ServiceAccountSigner = void 0;
var credential_internal_1 = require("../app/credential-internal");
var api_request_1 = require("./api-request");
var validator = require("../utils/validator");
var ALGORITHM_RS256 = 'RS256';
/**
* A CryptoSigner implementation that uses an explicitly specified service account private key to
* sign data. Performs all operations locally, and does not make any RPC calls.
*/
var ServiceAccountSigner = /** @class */ (function () {
/**
* Creates a new CryptoSigner instance from the given service account credential.
*
* @param credential - A service account credential.
*/
function ServiceAccountSigner(credential) {
this.credential = credential;
this.algorithm = ALGORITHM_RS256;
if (!credential) {
throw new CryptoSignerError({
code: CryptoSignerErrorCode.INVALID_CREDENTIAL,
message: 'INTERNAL ASSERT: Must provide a service account credential to initialize ServiceAccountSigner.',
});
}
}
/**
* @inheritDoc
*/
ServiceAccountSigner.prototype.sign = function (buffer) {
var crypto = require('crypto'); // eslint-disable-line @typescript-eslint/no-var-requires
var sign = crypto.createSign('RSA-SHA256');
sign.update(buffer);
return Promise.resolve(sign.sign(this.credential.privateKey));
};
/**
* @inheritDoc
*/
ServiceAccountSigner.prototype.getAccountId = function () {
return Promise.resolve(this.credential.clientEmail);
};
return ServiceAccountSigner;
}());
exports.ServiceAccountSigner = ServiceAccountSigner;
/**
* A CryptoSigner implementation that uses the remote IAM service to sign data. If initialized without
* a service account ID, attempts to discover a service account ID by consulting the local Metadata
* service. This will succeed in managed environments like Google Cloud Functions and App Engine.
*
* @see https://cloud.google.com/iam/reference/rest/v1/projects.serviceAccounts/signBlob
* @see https://cloud.google.com/compute/docs/storing-retrieving-metadata
*/
var IAMSigner = /** @class */ (function () {
function IAMSigner(httpClient, serviceAccountId) {
this.algorithm = ALGORITHM_RS256;
if (!httpClient) {
throw new CryptoSignerError({
code: CryptoSignerErrorCode.INVALID_ARGUMENT,
message: 'INTERNAL ASSERT: Must provide a HTTP client to initialize IAMSigner.',
});
}
if (typeof serviceAccountId !== 'undefined' && !validator.isNonEmptyString(serviceAccountId)) {
throw new CryptoSignerError({
code: CryptoSignerErrorCode.INVALID_ARGUMENT,
message: 'INTERNAL ASSERT: Service account ID must be undefined or a non-empty string.',
});
}
this.httpClient = httpClient;
this.serviceAccountId = serviceAccountId;
}
/**
* @inheritDoc
*/
IAMSigner.prototype.sign = function (buffer) {
var _this = this;
return this.getAccountId().then(function (serviceAccount) {
var request = {
method: 'POST',
url: "https://iamcredentials.googleapis.com/v1/projects/-/serviceAccounts/" + serviceAccount + ":signBlob",
data: { payload: buffer.toString('base64') },
};
return _this.httpClient.send(request);
}).then(function (response) {
// Response from IAM is base64 encoded. Decode it into a buffer and return.
return Buffer.from(response.data.signedBlob, 'base64');
}).catch(function (err) {
if (err instanceof api_request_1.HttpError) {
throw new CryptoSignerError({
code: CryptoSignerErrorCode.SERVER_ERROR,
message: err.message,
cause: err
});
}
throw err;
});
};
/**
* @inheritDoc
*/
IAMSigner.prototype.getAccountId = function () {
var _this = this;
if (validator.isNonEmptyString(this.serviceAccountId)) {
return Promise.resolve(this.serviceAccountId);
}
var request = {
method: 'GET',
url: 'http://metadata/computeMetadata/v1/instance/service-accounts/default/email',
headers: {
'Metadata-Flavor': 'Google',
},
};
var client = new api_request_1.HttpClient();
return client.send(request).then(function (response) {
if (!response.text) {
throw new CryptoSignerError({
code: CryptoSignerErrorCode.INTERNAL_ERROR,
message: 'HTTP Response missing payload',
});
}
_this.serviceAccountId = response.text;
return response.text;
}).catch(function (err) {
throw new CryptoSignerError({
code: CryptoSignerErrorCode.INVALID_CREDENTIAL,
message: 'Failed to determine service account. Make sure to initialize ' +
'the SDK with a service account credential. Alternatively specify a service ' +
("account with iam.serviceAccounts.signBlob permission. Original error: " + err),
});
});
};
return IAMSigner;
}());
exports.IAMSigner = IAMSigner;
/**
* Creates a new CryptoSigner instance for the given app. If the app has been initialized with a
* service account credential, creates a ServiceAccountSigner.
*
* @param app - A FirebaseApp instance.
* @returns A CryptoSigner instance.
*/
function cryptoSignerFromApp(app) {
var credential = app.options.credential;
if (credential instanceof credential_internal_1.ServiceAccountCredential) {
return new ServiceAccountSigner(credential);
}
return new IAMSigner(new api_request_1.AuthorizedHttpClient(app), app.options.serviceAccountId);
}
exports.cryptoSignerFromApp = cryptoSignerFromApp;
/**
* CryptoSigner error code structure.
*
* @param errorInfo - The error information (code and message).
* @constructor
*/
var CryptoSignerError = /** @class */ (function (_super) {
__extends(CryptoSignerError, _super);
function CryptoSignerError(errorInfo) {
var _this = _super.call(this, errorInfo.message) || this;
_this.errorInfo = errorInfo;
/* tslint:disable:max-line-length */
// Set the prototype explicitly. See the following link for more details:
// https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work
/* tslint:enable:max-line-length */
_this.__proto__ = CryptoSignerError.prototype;
return _this;
}
Object.defineProperty(CryptoSignerError.prototype, "code", {
/** @returns The error code. */
get: function () {
return this.errorInfo.code;
},
enumerable: false,
configurable: true
});
Object.defineProperty(CryptoSignerError.prototype, "message", {
/** @returns The error message. */
get: function () {
return this.errorInfo.message;
},
enumerable: false,
configurable: true
});
Object.defineProperty(CryptoSignerError.prototype, "cause", {
/** @returns The error data. */
get: function () {
return this.errorInfo.cause;
},
enumerable: false,
configurable: true
});
return CryptoSignerError;
}(Error));
exports.CryptoSignerError = CryptoSignerError;
/**
* Crypto Signer error codes and their default messages.
*/
var CryptoSignerErrorCode = /** @class */ (function () {
function CryptoSignerErrorCode() {
}
CryptoSignerErrorCode.INVALID_ARGUMENT = 'invalid-argument';
CryptoSignerErrorCode.INTERNAL_ERROR = 'internal-error';
CryptoSignerErrorCode.INVALID_CREDENTIAL = 'invalid-credential';
CryptoSignerErrorCode.SERVER_ERROR = 'server-error';
return CryptoSignerErrorCode;
}());
exports.CryptoSignerErrorCode = CryptoSignerErrorCode;
+40
View File
@@ -0,0 +1,40 @@
/*! firebase-admin v10.0.1 */
/*!
* @license
* 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.
*/
/**
* Returns a deep copy of an object or array.
*
* @param value - The object or array to deep copy.
* @returns A deep copy of the provided object or array.
*/
export declare function deepCopy<T>(value: T): T;
/**
* Copies properties from source to target (recursively allows extension of objects and arrays).
* Scalar values in the target are over-written. If target is undefined, an object of the
* appropriate type will be created (and returned).
*
* We recursively copy all child properties of plain objects in the source - so that namespace-like
* objects are merged.
*
* Note that the target can be a function, in which case the properties in the source object are
* copied onto it as static properties of the function.
*
* @param target - The value which is being extended.
* @param source - The value whose properties are extending the target.
* @returns The target value.
*/
export declare function deepExtend(target: any, source: any): any;
+78
View File
@@ -0,0 +1,78 @@
/*! firebase-admin v10.0.1 */
"use strict";
/*!
* @license
* 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.
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.deepExtend = exports.deepCopy = void 0;
/**
* Returns a deep copy of an object or array.
*
* @param value - The object or array to deep copy.
* @returns A deep copy of the provided object or array.
*/
function deepCopy(value) {
return deepExtend(undefined, value);
}
exports.deepCopy = deepCopy;
/**
* Copies properties from source to target (recursively allows extension of objects and arrays).
* Scalar values in the target are over-written. If target is undefined, an object of the
* appropriate type will be created (and returned).
*
* We recursively copy all child properties of plain objects in the source - so that namespace-like
* objects are merged.
*
* Note that the target can be a function, in which case the properties in the source object are
* copied onto it as static properties of the function.
*
* @param target - The value which is being extended.
* @param source - The value whose properties are extending the target.
* @returns The target value.
*/
function deepExtend(target, source) {
if (!(source instanceof Object)) {
return source;
}
switch (source.constructor) {
case Date: {
// Treat Dates like scalars; if the target date object had any child
// properties - they will be lost!
var dateValue = source;
return new Date(dateValue.getTime());
}
case Object:
if (target === undefined) {
target = {};
}
break;
case Array:
// Always copy the array source and overwrite the target.
target = [];
break;
default:
// Not a plain Object - treat it as a scalar.
return source;
}
for (var prop in source) {
if (!Object.prototype.hasOwnProperty.call(source, prop)) {
continue;
}
target[prop] = deepExtend(target[prop], source[prop]);
}
return target;
}
exports.deepExtend = deepExtend;
+650
View File
@@ -0,0 +1,650 @@
/*! firebase-admin v10.0.1 */
/*!
* @license
* 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.
*/
import { FirebaseError as FirebaseErrorInterface } from '../app';
/**
* Defines error info type. This includes a code and message string.
*/
export interface ErrorInfo {
code: string;
message: string;
}
/**
* Firebase error code structure. This extends Error.
*
* @param errorInfo - The error information (code and message).
* @constructor
*/
export declare class FirebaseError extends Error implements FirebaseErrorInterface {
private errorInfo;
constructor(errorInfo: ErrorInfo);
/** @returns The error code. */
get code(): string;
/** @returns The error message. */
get message(): string;
/** @returns The object representation of the error. */
toJSON(): object;
}
/**
* A FirebaseError with a prefix in front of the error code.
*
* @param codePrefix - The prefix to apply to the error code.
* @param code - The error code.
* @param message - The error message.
* @constructor
*/
export declare class PrefixedFirebaseError extends FirebaseError {
private codePrefix;
constructor(codePrefix: string, code: string, message: string);
/**
* Allows the error type to be checked without needing to know implementation details
* of the code prefixing.
*
* @param code - The non-prefixed error code to test against.
* @returns True if the code matches, false otherwise.
*/
hasCode(code: string): boolean;
}
/**
* Firebase App error code structure. This extends PrefixedFirebaseError.
*
* @param code - The error code.
* @param message - The error message.
* @constructor
*/
export declare class FirebaseAppError extends PrefixedFirebaseError {
constructor(code: string, message: string);
}
/**
* Firebase Auth error code structure. This extends PrefixedFirebaseError.
*
* @param info - The error code info.
* @param [message] The error message. This will override the default
* message if provided.
* @constructor
*/
export declare class FirebaseAuthError extends PrefixedFirebaseError {
/**
* Creates the developer-facing error corresponding to the backend error code.
*
* @param serverErrorCode - The server error code.
* @param [message] The error message. The default message is used
* if not provided.
* @param [rawServerResponse] The error's raw server response.
* @returns The corresponding developer-facing error.
*/
static fromServerError(serverErrorCode: string, message?: string, rawServerResponse?: object): FirebaseAuthError;
constructor(info: ErrorInfo, message?: string);
}
/**
* Firebase Database error code structure. This extends FirebaseError.
*
* @param info - The error code info.
* @param [message] The error message. This will override the default
* message if provided.
* @constructor
*/
export declare class FirebaseDatabaseError extends FirebaseError {
constructor(info: ErrorInfo, message?: string);
}
/**
* Firebase Firestore error code structure. This extends FirebaseError.
*
* @param info - The error code info.
* @param [message] The error message. This will override the default
* message if provided.
* @constructor
*/
export declare class FirebaseFirestoreError extends FirebaseError {
constructor(info: ErrorInfo, message?: string);
}
/**
* Firebase instance ID error code structure. This extends FirebaseError.
*
* @param info - The error code info.
* @param [message] The error message. This will override the default
* message if provided.
* @constructor
*/
export declare class FirebaseInstanceIdError extends FirebaseError {
constructor(info: ErrorInfo, message?: string);
}
/**
* Firebase Installations service error code structure. This extends `FirebaseError`.
*
* @param info - The error code info.
* @param message - The error message. This will override the default
* message if provided.
* @constructor
*/
export declare class FirebaseInstallationsError extends FirebaseError {
constructor(info: ErrorInfo, message?: string);
}
/**
* Firebase Messaging error code structure. This extends PrefixedFirebaseError.
*
* @param info - The error code info.
* @param [message] The error message. This will override the default message if provided.
* @constructor
*/
export declare class FirebaseMessagingError extends PrefixedFirebaseError {
/**
* Creates the developer-facing error corresponding to the backend error code.
*
* @param serverErrorCode - The server error code.
* @param [message] The error message. The default message is used
* if not provided.
* @param [rawServerResponse] The error's raw server response.
* @returns The corresponding developer-facing error.
*/
static fromServerError(serverErrorCode: string | null, message?: string | null, rawServerResponse?: object): FirebaseMessagingError;
static fromTopicManagementServerError(serverErrorCode: string, message?: string, rawServerResponse?: object): FirebaseMessagingError;
constructor(info: ErrorInfo, message?: string);
}
/**
* Firebase project management error code structure. This extends PrefixedFirebaseError.
*
* @param code - The error code.
* @param message - The error message.
* @constructor
*/
export declare class FirebaseProjectManagementError extends PrefixedFirebaseError {
constructor(code: ProjectManagementErrorCode, message: string);
}
/**
* App client error codes and their default messages.
*/
export declare class AppErrorCodes {
static APP_DELETED: string;
static DUPLICATE_APP: string;
static INVALID_ARGUMENT: string;
static INTERNAL_ERROR: string;
static INVALID_APP_NAME: string;
static INVALID_APP_OPTIONS: string;
static INVALID_CREDENTIAL: string;
static NETWORK_ERROR: string;
static NETWORK_TIMEOUT: string;
static NO_APP: string;
static UNABLE_TO_PARSE_RESPONSE: string;
}
/**
* Auth client error codes and their default messages.
*/
export declare class AuthClientErrorCode {
static BILLING_NOT_ENABLED: {
code: string;
message: string;
};
static CLAIMS_TOO_LARGE: {
code: string;
message: string;
};
static CONFIGURATION_EXISTS: {
code: string;
message: string;
};
static CONFIGURATION_NOT_FOUND: {
code: string;
message: string;
};
static ID_TOKEN_EXPIRED: {
code: string;
message: string;
};
static INVALID_ARGUMENT: {
code: string;
message: string;
};
static INVALID_CONFIG: {
code: string;
message: string;
};
static EMAIL_ALREADY_EXISTS: {
code: string;
message: string;
};
static EMAIL_NOT_FOUND: {
code: string;
message: string;
};
static FORBIDDEN_CLAIM: {
code: string;
message: string;
};
static INVALID_ID_TOKEN: {
code: string;
message: string;
};
static ID_TOKEN_REVOKED: {
code: string;
message: string;
};
static INTERNAL_ERROR: {
code: string;
message: string;
};
static INVALID_CLAIMS: {
code: string;
message: string;
};
static INVALID_CONTINUE_URI: {
code: string;
message: string;
};
static INVALID_CREATION_TIME: {
code: string;
message: string;
};
static INVALID_CREDENTIAL: {
code: string;
message: string;
};
static INVALID_DISABLED_FIELD: {
code: string;
message: string;
};
static INVALID_DISPLAY_NAME: {
code: string;
message: string;
};
static INVALID_DYNAMIC_LINK_DOMAIN: {
code: string;
message: string;
};
static INVALID_EMAIL_VERIFIED: {
code: string;
message: string;
};
static INVALID_EMAIL: {
code: string;
message: string;
};
static INVALID_ENROLLED_FACTORS: {
code: string;
message: string;
};
static INVALID_ENROLLMENT_TIME: {
code: string;
message: string;
};
static INVALID_HASH_ALGORITHM: {
code: string;
message: string;
};
static INVALID_HASH_BLOCK_SIZE: {
code: string;
message: string;
};
static INVALID_HASH_DERIVED_KEY_LENGTH: {
code: string;
message: string;
};
static INVALID_HASH_KEY: {
code: string;
message: string;
};
static INVALID_HASH_MEMORY_COST: {
code: string;
message: string;
};
static INVALID_HASH_PARALLELIZATION: {
code: string;
message: string;
};
static INVALID_HASH_ROUNDS: {
code: string;
message: string;
};
static INVALID_HASH_SALT_SEPARATOR: {
code: string;
message: string;
};
static INVALID_LAST_SIGN_IN_TIME: {
code: string;
message: string;
};
static INVALID_NAME: {
code: string;
message: string;
};
static INVALID_OAUTH_CLIENT_ID: {
code: string;
message: string;
};
static INVALID_PAGE_TOKEN: {
code: string;
message: string;
};
static INVALID_PASSWORD: {
code: string;
message: string;
};
static INVALID_PASSWORD_HASH: {
code: string;
message: string;
};
static INVALID_PASSWORD_SALT: {
code: string;
message: string;
};
static INVALID_PHONE_NUMBER: {
code: string;
message: string;
};
static INVALID_PHOTO_URL: {
code: string;
message: string;
};
static INVALID_PROJECT_ID: {
code: string;
message: string;
};
static INVALID_PROVIDER_DATA: {
code: string;
message: string;
};
static INVALID_PROVIDER_ID: {
code: string;
message: string;
};
static INVALID_PROVIDER_UID: {
code: string;
message: string;
};
static INVALID_OAUTH_RESPONSETYPE: {
code: string;
message: string;
};
static INVALID_SESSION_COOKIE_DURATION: {
code: string;
message: string;
};
static INVALID_TENANT_ID: {
code: string;
message: string;
};
static INVALID_TENANT_TYPE: {
code: string;
message: string;
};
static INVALID_TESTING_PHONE_NUMBER: {
code: string;
message: string;
};
static INVALID_UID: {
code: string;
message: string;
};
static INVALID_USER_IMPORT: {
code: string;
message: string;
};
static INVALID_TOKENS_VALID_AFTER_TIME: {
code: string;
message: string;
};
static MISMATCHING_TENANT_ID: {
code: string;
message: string;
};
static MISSING_ANDROID_PACKAGE_NAME: {
code: string;
message: string;
};
static MISSING_CONFIG: {
code: string;
message: string;
};
static MISSING_CONTINUE_URI: {
code: string;
message: string;
};
static MISSING_DISPLAY_NAME: {
code: string;
message: string;
};
static MISSING_EMAIL: {
code: string;
message: string;
};
static MISSING_IOS_BUNDLE_ID: {
code: string;
message: string;
};
static MISSING_ISSUER: {
code: string;
message: string;
};
static MISSING_HASH_ALGORITHM: {
code: string;
message: string;
};
static MISSING_OAUTH_CLIENT_ID: {
code: string;
message: string;
};
static MISSING_OAUTH_CLIENT_SECRET: {
code: string;
message: string;
};
static MISSING_PROVIDER_ID: {
code: string;
message: string;
};
static MISSING_SAML_RELYING_PARTY_CONFIG: {
code: string;
message: string;
};
static MAXIMUM_TEST_PHONE_NUMBER_EXCEEDED: {
code: string;
message: string;
};
static MAXIMUM_USER_COUNT_EXCEEDED: {
code: string;
message: string;
};
static MISSING_UID: {
code: string;
message: string;
};
static OPERATION_NOT_ALLOWED: {
code: string;
message: string;
};
static PHONE_NUMBER_ALREADY_EXISTS: {
code: string;
message: string;
};
static PROJECT_NOT_FOUND: {
code: string;
message: string;
};
static INSUFFICIENT_PERMISSION: {
code: string;
message: string;
};
static QUOTA_EXCEEDED: {
code: string;
message: string;
};
static SECOND_FACTOR_LIMIT_EXCEEDED: {
code: string;
message: string;
};
static SECOND_FACTOR_UID_ALREADY_EXISTS: {
code: string;
message: string;
};
static SESSION_COOKIE_EXPIRED: {
code: string;
message: string;
};
static SESSION_COOKIE_REVOKED: {
code: string;
message: string;
};
static TENANT_NOT_FOUND: {
code: string;
message: string;
};
static UID_ALREADY_EXISTS: {
code: string;
message: string;
};
static UNAUTHORIZED_DOMAIN: {
code: string;
message: string;
};
static UNSUPPORTED_FIRST_FACTOR: {
code: string;
message: string;
};
static UNSUPPORTED_SECOND_FACTOR: {
code: string;
message: string;
};
static UNSUPPORTED_TENANT_OPERATION: {
code: string;
message: string;
};
static UNVERIFIED_EMAIL: {
code: string;
message: string;
};
static USER_NOT_FOUND: {
code: string;
message: string;
};
static NOT_FOUND: {
code: string;
message: string;
};
static USER_DISABLED: {
code: string;
message: string;
};
static USER_NOT_DISABLED: {
code: string;
message: string;
};
}
/**
* Messaging client error codes and their default messages.
*/
export declare class MessagingClientErrorCode {
static INVALID_ARGUMENT: {
code: string;
message: string;
};
static INVALID_RECIPIENT: {
code: string;
message: string;
};
static INVALID_PAYLOAD: {
code: string;
message: string;
};
static INVALID_DATA_PAYLOAD_KEY: {
code: string;
message: string;
};
static PAYLOAD_SIZE_LIMIT_EXCEEDED: {
code: string;
message: string;
};
static INVALID_OPTIONS: {
code: string;
message: string;
};
static INVALID_REGISTRATION_TOKEN: {
code: string;
message: string;
};
static REGISTRATION_TOKEN_NOT_REGISTERED: {
code: string;
message: string;
};
static MISMATCHED_CREDENTIAL: {
code: string;
message: string;
};
static INVALID_PACKAGE_NAME: {
code: string;
message: string;
};
static DEVICE_MESSAGE_RATE_EXCEEDED: {
code: string;
message: string;
};
static TOPICS_MESSAGE_RATE_EXCEEDED: {
code: string;
message: string;
};
static MESSAGE_RATE_EXCEEDED: {
code: string;
message: string;
};
static THIRD_PARTY_AUTH_ERROR: {
code: string;
message: string;
};
static TOO_MANY_TOPICS: {
code: string;
message: string;
};
static AUTHENTICATION_ERROR: {
code: string;
message: string;
};
static SERVER_UNAVAILABLE: {
code: string;
message: string;
};
static INTERNAL_ERROR: {
code: string;
message: string;
};
static UNKNOWN_ERROR: {
code: string;
message: string;
};
}
export declare class InstallationsClientErrorCode {
static INVALID_ARGUMENT: {
code: string;
message: string;
};
static INVALID_PROJECT_ID: {
code: string;
message: string;
};
static INVALID_INSTALLATION_ID: {
code: string;
message: string;
};
static API_ERROR: {
code: string;
message: string;
};
}
export declare class InstanceIdClientErrorCode extends InstallationsClientErrorCode {
static INVALID_INSTANCE_ID: {
code: string;
message: string;
};
}
export declare type ProjectManagementErrorCode = 'already-exists' | 'authentication-error' | 'internal-error' | 'invalid-argument' | 'invalid-project-id' | 'invalid-server-response' | 'not-found' | 'service-unavailable' | 'unknown-error';
+1065
View File
File diff suppressed because it is too large Load Diff
+105
View File
@@ -0,0 +1,105 @@
/*! firebase-admin v10.0.1 */
/*!
* @license
* 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.
*/
/// <reference types="node" />
import { App } from '../app/index';
export declare function getSdkVersion(): string;
/**
* Renames properties on an object given a mapping from old to new property names.
*
* For example, this can be used to map underscore_cased properties to camelCase.
*
* @param obj - The object whose properties to rename.
* @param keyMap - The mapping from old to new property names.
*/
export declare function renameProperties(obj: {
[key: string]: any;
}, keyMap: {
[key: string]: string;
}): void;
/**
* Defines a new read-only property directly on an object and returns the object.
*
* @param obj - The object on which to define the property.
* @param prop - The name of the property to be defined or modified.
* @param value - The value associated with the property.
*/
export declare function addReadonlyGetter(obj: object, prop: string, value: any): void;
/**
* Returns the Google Cloud project ID associated with a Firebase app, if it's explicitly
* specified in either the Firebase app options, credentials or the local environment.
* Otherwise returns null.
*
* @param app - A Firebase app to get the project ID from.
*
* @returns A project ID string or null.
*/
export declare function getExplicitProjectId(app: App): string | null;
/**
* Determines the Google Cloud project ID associated with a Firebase app. This method
* first checks if a project ID is explicitly specified in either the Firebase app options,
* credentials or the local environment in that order. If no explicit project ID is
* configured, but the SDK has been initialized with ComputeEngineCredentials, this
* method attempts to discover the project ID from the local metadata service.
*
* @param app - A Firebase app to get the project ID from.
*
* @returns A project ID string or null.
*/
export declare function findProjectId(app: App): Promise<string | null>;
/**
* Encodes data using web-safe-base64.
*
* @param data - The raw data byte input.
* @returns The base64-encoded result.
*/
export declare function toWebSafeBase64(data: Buffer): string;
/**
* Formats a string of form 'project/{projectId}/{api}' and replaces
* with corresponding arguments {projectId: '1234', api: 'resource'}
* and returns output: 'project/1234/resource'.
*
* @param str - The original string where the param need to be
* replaced.
* @param params - The optional parameters to replace in the
* string.
* @returns The resulting formatted string.
*/
export declare function formatString(str: string, params?: object): string;
/**
* Generates the update mask for the provided object.
* Note this will ignore the last key with value undefined.
*
* @param obj - The object to generate the update mask for.
* @param terminalPaths - The optional map of keys for maximum paths to traverse.
* Nested objects beyond that path will be ignored. This is useful for
* keys with variable object values.
* @param root - The path so far.
* @returns The computed update mask list.
*/
export declare function generateUpdateMask(obj: any, terminalPaths?: string[], root?: string): string[];
/**
* Transforms milliseconds to a protobuf Duration type string.
* Returns the duration in seconds with up to nine fractional
* digits, terminated by 's'. Example: "3 seconds 0 nano seconds as 3s,
* 3 seconds 1 nano seconds as 3.000000001s".
*
* @param milliseconds - The duration in milliseconds.
* @returns The resulting formatted string in seconds with up to nine fractional
* digits, terminated by 's'.
*/
export declare function transformMillisecondsToSecondsString(milliseconds: number): string;
+218
View File
@@ -0,0 +1,218 @@
/*! firebase-admin v10.0.1 */
"use strict";
/*!
* @license
* 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.
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.transformMillisecondsToSecondsString = exports.generateUpdateMask = exports.formatString = exports.toWebSafeBase64 = exports.findProjectId = exports.getExplicitProjectId = exports.addReadonlyGetter = exports.renameProperties = exports.getSdkVersion = void 0;
var credential_internal_1 = require("../app/credential-internal");
var validator = require("./validator");
var sdkVersion;
// TODO: Move to firebase-admin/app as an internal member.
function getSdkVersion() {
if (!sdkVersion) {
var version = require('../../package.json').version; // eslint-disable-line @typescript-eslint/no-var-requires
sdkVersion = version;
}
return sdkVersion;
}
exports.getSdkVersion = getSdkVersion;
/**
* Renames properties on an object given a mapping from old to new property names.
*
* For example, this can be used to map underscore_cased properties to camelCase.
*
* @param obj - The object whose properties to rename.
* @param keyMap - The mapping from old to new property names.
*/
function renameProperties(obj, keyMap) {
Object.keys(keyMap).forEach(function (oldKey) {
if (oldKey in obj) {
var newKey = keyMap[oldKey];
// The old key's value takes precedence over the new key's value.
obj[newKey] = obj[oldKey];
delete obj[oldKey];
}
});
}
exports.renameProperties = renameProperties;
/**
* Defines a new read-only property directly on an object and returns the object.
*
* @param obj - The object on which to define the property.
* @param prop - The name of the property to be defined or modified.
* @param value - The value associated with the property.
*/
function addReadonlyGetter(obj, prop, value) {
Object.defineProperty(obj, prop, {
value: value,
// Make this property read-only.
writable: false,
// Include this property during enumeration of obj's properties.
enumerable: true,
});
}
exports.addReadonlyGetter = addReadonlyGetter;
/**
* Returns the Google Cloud project ID associated with a Firebase app, if it's explicitly
* specified in either the Firebase app options, credentials or the local environment.
* Otherwise returns null.
*
* @param app - A Firebase app to get the project ID from.
*
* @returns A project ID string or null.
*/
function getExplicitProjectId(app) {
var options = app.options;
if (validator.isNonEmptyString(options.projectId)) {
return options.projectId;
}
var credential = app.options.credential;
if (credential instanceof credential_internal_1.ServiceAccountCredential) {
return credential.projectId;
}
var projectId = process.env.GOOGLE_CLOUD_PROJECT || process.env.GCLOUD_PROJECT;
if (validator.isNonEmptyString(projectId)) {
return projectId;
}
return null;
}
exports.getExplicitProjectId = getExplicitProjectId;
/**
* Determines the Google Cloud project ID associated with a Firebase app. This method
* first checks if a project ID is explicitly specified in either the Firebase app options,
* credentials or the local environment in that order. If no explicit project ID is
* configured, but the SDK has been initialized with ComputeEngineCredentials, this
* method attempts to discover the project ID from the local metadata service.
*
* @param app - A Firebase app to get the project ID from.
*
* @returns A project ID string or null.
*/
function findProjectId(app) {
var projectId = getExplicitProjectId(app);
if (projectId) {
return Promise.resolve(projectId);
}
var credential = app.options.credential;
if (credential instanceof credential_internal_1.ComputeEngineCredential) {
return credential.getProjectId();
}
return Promise.resolve(null);
}
exports.findProjectId = findProjectId;
/**
* Encodes data using web-safe-base64.
*
* @param data - The raw data byte input.
* @returns The base64-encoded result.
*/
function toWebSafeBase64(data) {
return data.toString('base64').replace(/\//g, '_').replace(/\+/g, '-');
}
exports.toWebSafeBase64 = toWebSafeBase64;
/**
* Formats a string of form 'project/{projectId}/{api}' and replaces
* with corresponding arguments {projectId: '1234', api: 'resource'}
* and returns output: 'project/1234/resource'.
*
* @param str - The original string where the param need to be
* replaced.
* @param params - The optional parameters to replace in the
* string.
* @returns The resulting formatted string.
*/
function formatString(str, params) {
var formatted = str;
Object.keys(params || {}).forEach(function (key) {
formatted = formatted.replace(new RegExp('{' + key + '}', 'g'), params[key]);
});
return formatted;
}
exports.formatString = formatString;
/**
* Generates the update mask for the provided object.
* Note this will ignore the last key with value undefined.
*
* @param obj - The object to generate the update mask for.
* @param terminalPaths - The optional map of keys for maximum paths to traverse.
* Nested objects beyond that path will be ignored. This is useful for
* keys with variable object values.
* @param root - The path so far.
* @returns The computed update mask list.
*/
function generateUpdateMask(obj, terminalPaths, root) {
if (terminalPaths === void 0) { terminalPaths = []; }
if (root === void 0) { root = ''; }
var updateMask = [];
if (!validator.isNonNullObject(obj)) {
return updateMask;
}
var _loop_1 = function (key) {
if (typeof obj[key] !== 'undefined') {
var nextPath = root ? root + "." + key : key;
// We hit maximum path.
// Consider switching to Set<string> if the list grows too large.
if (terminalPaths.indexOf(nextPath) !== -1) {
// Add key and stop traversing this branch.
updateMask.push(key);
}
else {
var maskList = generateUpdateMask(obj[key], terminalPaths, nextPath);
if (maskList.length > 0) {
maskList.forEach(function (mask) {
updateMask.push(key + "." + mask);
});
}
else {
updateMask.push(key);
}
}
}
};
for (var key in obj) {
_loop_1(key);
}
return updateMask;
}
exports.generateUpdateMask = generateUpdateMask;
/**
* Transforms milliseconds to a protobuf Duration type string.
* Returns the duration in seconds with up to nine fractional
* digits, terminated by 's'. Example: "3 seconds 0 nano seconds as 3s,
* 3 seconds 1 nano seconds as 3.000000001s".
*
* @param milliseconds - The duration in milliseconds.
* @returns The resulting formatted string in seconds with up to nine fractional
* digits, terminated by 's'.
*/
function transformMillisecondsToSecondsString(milliseconds) {
var duration;
var seconds = Math.floor(milliseconds / 1000);
var nanos = Math.floor((milliseconds - seconds * 1000) * 1000000);
if (nanos > 0) {
var nanoString = nanos.toString();
while (nanoString.length < 9) {
nanoString = '0' + nanoString;
}
duration = seconds + "." + nanoString + "s";
}
else {
duration = seconds + "s";
}
return duration;
}
exports.transformMillisecondsToSecondsString = transformMillisecondsToSecondsString;
+131
View File
@@ -0,0 +1,131 @@
/*! firebase-admin v10.0.1 */
/*!
* Copyright 2021 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.
*/
/// <reference types="node" />
import * as jwt from 'jsonwebtoken';
import { Agent } from 'http';
export declare const ALGORITHM_RS256: jwt.Algorithm;
export declare type Dictionary = {
[key: string]: any;
};
export declare type DecodedToken = {
header: Dictionary;
payload: Dictionary;
};
export interface SignatureVerifier {
verify(token: string): Promise<void>;
}
interface KeyFetcher {
fetchPublicKeys(): Promise<{
[key: string]: string;
}>;
}
export declare class JwksFetcher implements KeyFetcher {
private publicKeys;
private publicKeysExpireAt;
private client;
constructor(jwksUrl: string);
fetchPublicKeys(): Promise<{
[key: string]: string;
}>;
private shouldRefresh;
private refresh;
}
/**
* Class to fetch public keys from a client certificates URL.
*/
export declare class UrlKeyFetcher implements KeyFetcher {
private clientCertUrl;
private readonly httpAgent?;
private publicKeys;
private publicKeysExpireAt;
constructor(clientCertUrl: string, httpAgent?: Agent | undefined);
/**
* Fetches the public keys for the Google certs.
*
* @returns A promise fulfilled with public keys for the Google certs.
*/
fetchPublicKeys(): Promise<{
[key: string]: string;
}>;
/**
* Checks if the cached public keys need to be refreshed.
*
* @returns Whether the keys should be fetched from the client certs url or not.
*/
private shouldRefresh;
private refresh;
}
/**
* Class for verifying JWT signature with a public key.
*/
export declare class PublicKeySignatureVerifier implements SignatureVerifier {
private keyFetcher;
constructor(keyFetcher: KeyFetcher);
static withCertificateUrl(clientCertUrl: string, httpAgent?: Agent): PublicKeySignatureVerifier;
static withJwksUrl(jwksUrl: string): PublicKeySignatureVerifier;
verify(token: string): Promise<void>;
private verifyWithoutKid;
private verifyWithAllKeys;
}
/**
* Class for verifying unsigned (emulator) JWTs.
*/
export declare class EmulatorSignatureVerifier implements SignatureVerifier {
verify(token: string): Promise<void>;
}
/**
* Verifies the signature of a JWT using the provided secret or a function to fetch
* the secret or public key.
*
* @param token - The JWT to be verified.
* @param secretOrPublicKey - The secret or a function to fetch the secret or public key.
* @param options - JWT verification options.
* @returns A Promise resolving for a token with a valid signature.
*/
export declare function verifyJwtSignature(token: string, secretOrPublicKey: jwt.Secret | jwt.GetPublicKeyOrSecret, options?: jwt.VerifyOptions): Promise<void>;
/**
* Decodes general purpose Firebase JWTs.
*
* @param jwtToken - JWT token to be decoded.
* @returns Decoded token containing the header and payload.
*/
export declare function decodeJwt(jwtToken: string): Promise<DecodedToken>;
/**
* Jwt error code structure.
*
* @param code - The error code.
* @param message - The error message.
* @constructor
*/
export declare class JwtError extends Error {
readonly code: JwtErrorCode;
readonly message: string;
constructor(code: JwtErrorCode, message: string);
}
/**
* JWT error codes.
*/
export declare enum JwtErrorCode {
INVALID_ARGUMENT = "invalid-argument",
INVALID_CREDENTIAL = "invalid-credential",
TOKEN_EXPIRED = "token-expired",
INVALID_SIGNATURE = "invalid-token",
NO_MATCHING_KID = "no-matching-kid-error",
NO_KID_IN_HEADER = "no-kid-error",
KEY_FETCH_ERROR = "key-fetch-error"
}
export {};
+355
View File
@@ -0,0 +1,355 @@
/*! firebase-admin v10.0.1 */
"use strict";
/*!
* Copyright 2021 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 = function (d, b) {
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 extendStatics(d, b);
};
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 });
exports.JwtErrorCode = exports.JwtError = exports.decodeJwt = exports.verifyJwtSignature = exports.EmulatorSignatureVerifier = exports.PublicKeySignatureVerifier = exports.UrlKeyFetcher = exports.JwksFetcher = exports.ALGORITHM_RS256 = void 0;
var validator = require("./validator");
var jwt = require("jsonwebtoken");
var jwks = require("jwks-rsa");
var api_request_1 = require("../utils/api-request");
exports.ALGORITHM_RS256 = 'RS256';
// `jsonwebtoken` converts errors from the `getKey` callback to its own `JsonWebTokenError` type
// and prefixes the error message with the following. Use the prefix to identify errors thrown
// from the key provider callback.
// https://github.com/auth0/node-jsonwebtoken/blob/d71e383862fc735991fd2e759181480f066bf138/verify.js#L96
var JWT_CALLBACK_ERROR_PREFIX = 'error in secret or public key callback: ';
var NO_MATCHING_KID_ERROR_MESSAGE = 'no-matching-kid-error';
var NO_KID_IN_HEADER_ERROR_MESSAGE = 'no-kid-in-header-error';
var HOUR_IN_SECONDS = 3600;
var JwksFetcher = /** @class */ (function () {
function JwksFetcher(jwksUrl) {
this.publicKeysExpireAt = 0;
if (!validator.isURL(jwksUrl)) {
throw new Error('The provided JWKS URL is not a valid URL.');
}
this.client = jwks({
jwksUri: jwksUrl,
cache: false,
});
}
JwksFetcher.prototype.fetchPublicKeys = function () {
if (this.shouldRefresh()) {
return this.refresh();
}
return Promise.resolve(this.publicKeys);
};
JwksFetcher.prototype.shouldRefresh = function () {
return !this.publicKeys || this.publicKeysExpireAt <= Date.now();
};
JwksFetcher.prototype.refresh = function () {
var _this = this;
return this.client.getSigningKeys()
.then(function (signingKeys) {
// reset expire at from previous set of keys.
_this.publicKeysExpireAt = 0;
var newKeys = signingKeys.reduce(function (map, signingKey) {
map[signingKey.kid] = signingKey.getPublicKey();
return map;
}, {});
_this.publicKeysExpireAt = Date.now() + (HOUR_IN_SECONDS * 6 * 1000);
_this.publicKeys = newKeys;
return newKeys;
}).catch(function (err) {
throw new Error("Error fetching Json Web Keys: " + err.message);
});
};
return JwksFetcher;
}());
exports.JwksFetcher = JwksFetcher;
/**
* Class to fetch public keys from a client certificates URL.
*/
var UrlKeyFetcher = /** @class */ (function () {
function UrlKeyFetcher(clientCertUrl, httpAgent) {
this.clientCertUrl = clientCertUrl;
this.httpAgent = httpAgent;
this.publicKeysExpireAt = 0;
if (!validator.isURL(clientCertUrl)) {
throw new Error('The provided public client certificate URL is not a valid URL.');
}
}
/**
* Fetches the public keys for the Google certs.
*
* @returns A promise fulfilled with public keys for the Google certs.
*/
UrlKeyFetcher.prototype.fetchPublicKeys = function () {
if (this.shouldRefresh()) {
return this.refresh();
}
return Promise.resolve(this.publicKeys);
};
/**
* Checks if the cached public keys need to be refreshed.
*
* @returns Whether the keys should be fetched from the client certs url or not.
*/
UrlKeyFetcher.prototype.shouldRefresh = function () {
return !this.publicKeys || this.publicKeysExpireAt <= Date.now();
};
UrlKeyFetcher.prototype.refresh = function () {
var _this = this;
var client = new api_request_1.HttpClient();
var request = {
method: 'GET',
url: this.clientCertUrl,
httpAgent: this.httpAgent,
};
return client.send(request).then(function (resp) {
if (!resp.isJson() || resp.data.error) {
// Treat all non-json messages and messages with an 'error' field as
// error responses.
throw new api_request_1.HttpError(resp);
}
// reset expire at from previous set of keys.
_this.publicKeysExpireAt = 0;
if (Object.prototype.hasOwnProperty.call(resp.headers, 'cache-control')) {
var cacheControlHeader = resp.headers['cache-control'];
var parts = cacheControlHeader.split(',');
parts.forEach(function (part) {
var subParts = part.trim().split('=');
if (subParts[0] === 'max-age') {
var maxAge = +subParts[1];
_this.publicKeysExpireAt = Date.now() + (maxAge * 1000);
}
});
}
_this.publicKeys = resp.data;
return resp.data;
}).catch(function (err) {
if (err instanceof api_request_1.HttpError) {
var errorMessage = 'Error fetching public keys for Google certs: ';
var resp = err.response;
if (resp.isJson() && resp.data.error) {
errorMessage += "" + resp.data.error;
if (resp.data.error_description) {
errorMessage += ' (' + resp.data.error_description + ')';
}
}
else {
errorMessage += "" + resp.text;
}
throw new Error(errorMessage);
}
throw err;
});
};
return UrlKeyFetcher;
}());
exports.UrlKeyFetcher = UrlKeyFetcher;
/**
* Class for verifying JWT signature with a public key.
*/
var PublicKeySignatureVerifier = /** @class */ (function () {
function PublicKeySignatureVerifier(keyFetcher) {
this.keyFetcher = keyFetcher;
if (!validator.isNonNullObject(keyFetcher)) {
throw new Error('The provided key fetcher is not an object or null.');
}
}
PublicKeySignatureVerifier.withCertificateUrl = function (clientCertUrl, httpAgent) {
return new PublicKeySignatureVerifier(new UrlKeyFetcher(clientCertUrl, httpAgent));
};
PublicKeySignatureVerifier.withJwksUrl = function (jwksUrl) {
return new PublicKeySignatureVerifier(new JwksFetcher(jwksUrl));
};
PublicKeySignatureVerifier.prototype.verify = function (token) {
var _this = this;
if (!validator.isString(token)) {
return Promise.reject(new JwtError(JwtErrorCode.INVALID_ARGUMENT, 'The provided token must be a string.'));
}
return verifyJwtSignature(token, getKeyCallback(this.keyFetcher), { algorithms: [exports.ALGORITHM_RS256] })
.catch(function (error) {
if (error.code === JwtErrorCode.NO_KID_IN_HEADER) {
// No kid in JWT header. Try with all the public keys.
return _this.verifyWithoutKid(token);
}
throw error;
});
};
PublicKeySignatureVerifier.prototype.verifyWithoutKid = function (token) {
var _this = this;
return this.keyFetcher.fetchPublicKeys()
.then(function (publicKeys) { return _this.verifyWithAllKeys(token, publicKeys); });
};
PublicKeySignatureVerifier.prototype.verifyWithAllKeys = function (token, keys) {
var promises = [];
Object.values(keys).forEach(function (key) {
var result = verifyJwtSignature(token, key)
.then(function () { return true; })
.catch(function (error) {
if (error.code === JwtErrorCode.TOKEN_EXPIRED) {
throw error;
}
return false;
});
promises.push(result);
});
return Promise.all(promises)
.then(function (result) {
if (result.every(function (r) { return r === false; })) {
throw new JwtError(JwtErrorCode.INVALID_SIGNATURE, 'Invalid token signature.');
}
});
};
return PublicKeySignatureVerifier;
}());
exports.PublicKeySignatureVerifier = PublicKeySignatureVerifier;
/**
* Class for verifying unsigned (emulator) JWTs.
*/
var EmulatorSignatureVerifier = /** @class */ (function () {
function EmulatorSignatureVerifier() {
}
EmulatorSignatureVerifier.prototype.verify = function (token) {
// Signature checks skipped for emulator; no need to fetch public keys.
return verifyJwtSignature(token, '');
};
return EmulatorSignatureVerifier;
}());
exports.EmulatorSignatureVerifier = EmulatorSignatureVerifier;
/**
* Provides a callback to fetch public keys.
*
* @param fetcher - KeyFetcher to fetch the keys from.
* @returns A callback function that can be used to get keys in `jsonwebtoken`.
*/
function getKeyCallback(fetcher) {
return function (header, callback) {
if (!header.kid) {
callback(new Error(NO_KID_IN_HEADER_ERROR_MESSAGE));
}
var kid = header.kid || '';
fetcher.fetchPublicKeys().then(function (publicKeys) {
if (!Object.prototype.hasOwnProperty.call(publicKeys, kid)) {
callback(new Error(NO_MATCHING_KID_ERROR_MESSAGE));
}
else {
callback(null, publicKeys[kid]);
}
})
.catch(function (error) {
callback(error);
});
};
}
/**
* Verifies the signature of a JWT using the provided secret or a function to fetch
* the secret or public key.
*
* @param token - The JWT to be verified.
* @param secretOrPublicKey - The secret or a function to fetch the secret or public key.
* @param options - JWT verification options.
* @returns A Promise resolving for a token with a valid signature.
*/
function verifyJwtSignature(token, secretOrPublicKey, options) {
if (!validator.isString(token)) {
return Promise.reject(new JwtError(JwtErrorCode.INVALID_ARGUMENT, 'The provided token must be a string.'));
}
return new Promise(function (resolve, reject) {
jwt.verify(token, secretOrPublicKey, options, function (error) {
if (!error) {
return resolve();
}
if (error.name === 'TokenExpiredError') {
return reject(new JwtError(JwtErrorCode.TOKEN_EXPIRED, 'The provided token has expired. Get a fresh token from your ' +
'client app and try again.'));
}
else if (error.name === 'JsonWebTokenError') {
if (error.message && error.message.includes(JWT_CALLBACK_ERROR_PREFIX)) {
var message = error.message.split(JWT_CALLBACK_ERROR_PREFIX).pop() || 'Error fetching public keys.';
var code = JwtErrorCode.KEY_FETCH_ERROR;
if (message === NO_MATCHING_KID_ERROR_MESSAGE) {
code = JwtErrorCode.NO_MATCHING_KID;
}
else if (message === NO_KID_IN_HEADER_ERROR_MESSAGE) {
code = JwtErrorCode.NO_KID_IN_HEADER;
}
return reject(new JwtError(code, message));
}
}
return reject(new JwtError(JwtErrorCode.INVALID_SIGNATURE, error.message));
});
});
}
exports.verifyJwtSignature = verifyJwtSignature;
/**
* Decodes general purpose Firebase JWTs.
*
* @param jwtToken - JWT token to be decoded.
* @returns Decoded token containing the header and payload.
*/
function decodeJwt(jwtToken) {
if (!validator.isString(jwtToken)) {
return Promise.reject(new JwtError(JwtErrorCode.INVALID_ARGUMENT, 'The provided token must be a string.'));
}
var fullDecodedToken = jwt.decode(jwtToken, {
complete: true,
});
if (!fullDecodedToken) {
return Promise.reject(new JwtError(JwtErrorCode.INVALID_ARGUMENT, 'Decoding token failed.'));
}
var header = fullDecodedToken === null || fullDecodedToken === void 0 ? void 0 : fullDecodedToken.header;
var payload = fullDecodedToken === null || fullDecodedToken === void 0 ? void 0 : fullDecodedToken.payload;
return Promise.resolve({ header: header, payload: payload });
}
exports.decodeJwt = decodeJwt;
/**
* Jwt error code structure.
*
* @param code - The error code.
* @param message - The error message.
* @constructor
*/
var JwtError = /** @class */ (function (_super) {
__extends(JwtError, _super);
function JwtError(code, message) {
var _this = _super.call(this, message) || this;
_this.code = code;
_this.message = message;
_this.__proto__ = JwtError.prototype;
return _this;
}
return JwtError;
}(Error));
exports.JwtError = JwtError;
/**
* JWT error codes.
*/
var JwtErrorCode;
(function (JwtErrorCode) {
JwtErrorCode["INVALID_ARGUMENT"] = "invalid-argument";
JwtErrorCode["INVALID_CREDENTIAL"] = "invalid-credential";
JwtErrorCode["TOKEN_EXPIRED"] = "token-expired";
JwtErrorCode["INVALID_SIGNATURE"] = "invalid-token";
JwtErrorCode["NO_MATCHING_KID"] = "no-matching-kid-error";
JwtErrorCode["NO_KID_IN_HEADER"] = "no-kid-error";
JwtErrorCode["KEY_FETCH_ERROR"] = "key-fetch-error";
})(JwtErrorCode = exports.JwtErrorCode || (exports.JwtErrorCode = {}));
+144
View File
@@ -0,0 +1,144 @@
/*! firebase-admin v10.0.1 */
/*!
* @license
* 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.
*/
/// <reference types="node" />
/**
* Validates that a value is a byte buffer.
*
* @param value - The value to validate.
* @returns Whether the value is byte buffer or not.
*/
export declare function isBuffer(value: any): value is Buffer;
/**
* Validates that a value is an array.
*
* @param value - The value to validate.
* @returns Whether the value is an array or not.
*/
export declare function isArray<T>(value: any): value is T[];
/**
* Validates that a value is a non-empty array.
*
* @param value - The value to validate.
* @returns Whether the value is a non-empty array or not.
*/
export declare function isNonEmptyArray<T>(value: any): value is T[];
/**
* Validates that a value is a boolean.
*
* @param value - The value to validate.
* @returns Whether the value is a boolean or not.
*/
export declare function isBoolean(value: any): boolean;
/**
* Validates that a value is a number.
*
* @param value - The value to validate.
* @returns Whether the value is a number or not.
*/
export declare function isNumber(value: any): boolean;
/**
* Validates that a value is a string.
*
* @param value - The value to validate.
* @returns Whether the value is a string or not.
*/
export declare function isString(value: any): value is string;
/**
* Validates that a value is a base64 string.
*
* @param value - The value to validate.
* @returns Whether the value is a base64 string or not.
*/
export declare function isBase64String(value: any): boolean;
/**
* Validates that a value is a non-empty string.
*
* @param value - The value to validate.
* @returns Whether the value is a non-empty string or not.
*/
export declare function isNonEmptyString(value: any): value is string;
/**
* Validates that a value is a nullable object.
*
* @param value - The value to validate.
* @returns Whether the value is an object or not.
*/
export declare function isObject(value: any): boolean;
/**
* Validates that a value is a non-null object.
*
* @param value - The value to validate.
* @returns Whether the value is a non-null object or not.
*/
export declare function isNonNullObject<T>(value: T | null | undefined): value is T;
/**
* Validates that a string is a valid Firebase Auth uid.
*
* @param uid - The string to validate.
* @returns Whether the string is a valid Firebase Auth uid.
*/
export declare function isUid(uid: any): boolean;
/**
* Validates that a string is a valid Firebase Auth password.
*
* @param password - The password string to validate.
* @returns Whether the string is a valid Firebase Auth password.
*/
export declare function isPassword(password: any): boolean;
/**
* Validates that a string is a valid email.
*
* @param email - The string to validate.
* @returns Whether the string is valid email or not.
*/
export declare function isEmail(email: any): boolean;
/**
* Validates that a string is a valid phone number.
*
* @param phoneNumber - The string to validate.
* @returns Whether the string is a valid phone number or not.
*/
export declare function isPhoneNumber(phoneNumber: any): boolean;
/**
* Validates that a string is a valid ISO date string.
*
* @param dateString - The string to validate.
* @returns Whether the string is a valid ISO date string.
*/
export declare function isISODateString(dateString: any): boolean;
/**
* Validates that a string is a valid UTC date string.
*
* @param dateString - The string to validate.
* @returns Whether the string is a valid UTC date string.
*/
export declare function isUTCDateString(dateString: any): boolean;
/**
* Validates that a string is a valid web URL.
*
* @param urlStr - The string to validate.
* @returns Whether the string is valid web URL or not.
*/
export declare function isURL(urlStr: any): boolean;
/**
* Validates that the provided topic is a valid FCM topic name.
*
* @param topic - The topic to validate.
* @returns Whether the provided topic is a valid FCM topic name.
*/
export declare function isTopic(topic: any): boolean;
+271
View File
@@ -0,0 +1,271 @@
/*! firebase-admin v10.0.1 */
"use strict";
/*!
* @license
* 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.
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.isTopic = exports.isURL = exports.isUTCDateString = exports.isISODateString = exports.isPhoneNumber = exports.isEmail = exports.isPassword = exports.isUid = exports.isNonNullObject = exports.isObject = exports.isNonEmptyString = exports.isBase64String = exports.isString = exports.isNumber = exports.isBoolean = exports.isNonEmptyArray = exports.isArray = exports.isBuffer = void 0;
var url = require("url");
/**
* Validates that a value is a byte buffer.
*
* @param value - The value to validate.
* @returns Whether the value is byte buffer or not.
*/
function isBuffer(value) {
return value instanceof Buffer;
}
exports.isBuffer = isBuffer;
/**
* Validates that a value is an array.
*
* @param value - The value to validate.
* @returns Whether the value is an array or not.
*/
function isArray(value) {
return Array.isArray(value);
}
exports.isArray = isArray;
/**
* Validates that a value is a non-empty array.
*
* @param value - The value to validate.
* @returns Whether the value is a non-empty array or not.
*/
function isNonEmptyArray(value) {
return isArray(value) && value.length !== 0;
}
exports.isNonEmptyArray = isNonEmptyArray;
/**
* Validates that a value is a boolean.
*
* @param value - The value to validate.
* @returns Whether the value is a boolean or not.
*/
function isBoolean(value) {
return typeof value === 'boolean';
}
exports.isBoolean = isBoolean;
/**
* Validates that a value is a number.
*
* @param value - The value to validate.
* @returns Whether the value is a number or not.
*/
function isNumber(value) {
return typeof value === 'number' && !isNaN(value);
}
exports.isNumber = isNumber;
/**
* Validates that a value is a string.
*
* @param value - The value to validate.
* @returns Whether the value is a string or not.
*/
function isString(value) {
return typeof value === 'string';
}
exports.isString = isString;
/**
* Validates that a value is a base64 string.
*
* @param value - The value to validate.
* @returns Whether the value is a base64 string or not.
*/
function isBase64String(value) {
if (!isString(value)) {
return false;
}
return /^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$/.test(value);
}
exports.isBase64String = isBase64String;
/**
* Validates that a value is a non-empty string.
*
* @param value - The value to validate.
* @returns Whether the value is a non-empty string or not.
*/
function isNonEmptyString(value) {
return isString(value) && value !== '';
}
exports.isNonEmptyString = isNonEmptyString;
/**
* Validates that a value is a nullable object.
*
* @param value - The value to validate.
* @returns Whether the value is an object or not.
*/
function isObject(value) {
return typeof value === 'object' && !isArray(value);
}
exports.isObject = isObject;
/**
* Validates that a value is a non-null object.
*
* @param value - The value to validate.
* @returns Whether the value is a non-null object or not.
*/
function isNonNullObject(value) {
return isObject(value) && value !== null;
}
exports.isNonNullObject = isNonNullObject;
/**
* Validates that a string is a valid Firebase Auth uid.
*
* @param uid - The string to validate.
* @returns Whether the string is a valid Firebase Auth uid.
*/
function isUid(uid) {
return typeof uid === 'string' && uid.length > 0 && uid.length <= 128;
}
exports.isUid = isUid;
/**
* Validates that a string is a valid Firebase Auth password.
*
* @param password - The password string to validate.
* @returns Whether the string is a valid Firebase Auth password.
*/
function isPassword(password) {
// A password must be a string of at least 6 characters.
return typeof password === 'string' && password.length >= 6;
}
exports.isPassword = isPassword;
/**
* Validates that a string is a valid email.
*
* @param email - The string to validate.
* @returns Whether the string is valid email or not.
*/
function isEmail(email) {
if (typeof email !== 'string') {
return false;
}
// There must at least one character before the @ symbol and another after.
var re = /^[^@]+@[^@]+$/;
return re.test(email);
}
exports.isEmail = isEmail;
/**
* Validates that a string is a valid phone number.
*
* @param phoneNumber - The string to validate.
* @returns Whether the string is a valid phone number or not.
*/
function isPhoneNumber(phoneNumber) {
if (typeof phoneNumber !== 'string') {
return false;
}
// Phone number validation is very lax here. Backend will enforce E.164
// spec compliance and will normalize accordingly.
// The phone number string must be non-empty and starts with a plus sign.
var re1 = /^\+/;
// The phone number string must contain at least one alphanumeric character.
var re2 = /[\da-zA-Z]+/;
return re1.test(phoneNumber) && re2.test(phoneNumber);
}
exports.isPhoneNumber = isPhoneNumber;
/**
* Validates that a string is a valid ISO date string.
*
* @param dateString - The string to validate.
* @returns Whether the string is a valid ISO date string.
*/
function isISODateString(dateString) {
try {
return isNonEmptyString(dateString) &&
(new Date(dateString).toISOString() === dateString);
}
catch (e) {
return false;
}
}
exports.isISODateString = isISODateString;
/**
* Validates that a string is a valid UTC date string.
*
* @param dateString - The string to validate.
* @returns Whether the string is a valid UTC date string.
*/
function isUTCDateString(dateString) {
try {
return isNonEmptyString(dateString) &&
(new Date(dateString).toUTCString() === dateString);
}
catch (e) {
return false;
}
}
exports.isUTCDateString = isUTCDateString;
/**
* Validates that a string is a valid web URL.
*
* @param urlStr - The string to validate.
* @returns Whether the string is valid web URL or not.
*/
function isURL(urlStr) {
if (typeof urlStr !== 'string') {
return false;
}
// Lookup illegal characters.
var re = /[^a-z0-9:/?#[\]@!$&'()*+,;=.\-_~%]/i;
if (re.test(urlStr)) {
return false;
}
try {
var uri = url.parse(urlStr);
var scheme = uri.protocol;
var slashes = uri.slashes;
var hostname = uri.hostname;
var pathname = uri.pathname;
if ((scheme !== 'http:' && scheme !== 'https:') || !slashes) {
return false;
}
// Validate hostname: Can contain letters, numbers, underscore and dashes separated by a dot.
// Each zone must not start with a hyphen or underscore.
if (!hostname || !/^[a-zA-Z0-9]+[\w-]*([.]?[a-zA-Z0-9]+[\w-]*)*$/.test(hostname)) {
return false;
}
// Allow for pathnames: (/chars+)*/?
// Where chars can be a combination of: a-z A-Z 0-9 - _ . ~ ! $ & ' ( ) * + , ; = : @ %
var pathnameRe = /^(\/[\w\-.~!$'()*+,;=:@%]+)*\/?$/;
// Validate pathname.
if (pathname &&
pathname !== '/' &&
!pathnameRe.test(pathname)) {
return false;
}
// Allow any query string and hash as long as no invalid character is used.
}
catch (e) {
return false;
}
return true;
}
exports.isURL = isURL;
/**
* Validates that the provided topic is a valid FCM topic name.
*
* @param topic - The topic to validate.
* @returns Whether the provided topic is a valid FCM topic name.
*/
function isTopic(topic) {
if (typeof topic !== 'string') {
return false;
}
var VALID_TOPIC_REGEX = /^(\/topics\/)?(private\/)?[a-zA-Z0-9-_.~%]+$/;
return VALID_TOPIC_REGEX.test(topic);
}
exports.isTopic = isTopic;