UNPKG

8.38 kBJavaScriptView Raw
1/*! firebase-admin v10.0.0 */
2"use strict";
3/*!
4 * @license
5 * Copyright 2021 Google Inc.
6 *
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 */
19var __extends = (this && this.__extends) || (function () {
20 var extendStatics = function (d, b) {
21 extendStatics = Object.setPrototypeOf ||
22 ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
23 function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
24 return extendStatics(d, b);
25 };
26 return function (d, b) {
27 extendStatics(d, b);
28 function __() { this.constructor = d; }
29 d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
30 };
31})();
32Object.defineProperty(exports, "__esModule", { value: true });
33exports.FirebaseAppCheckError = exports.APP_CHECK_ERROR_CODE_MAPPING = exports.AppCheckApiClient = void 0;
34var api_request_1 = require("../utils/api-request");
35var error_1 = require("../utils/error");
36var utils = require("../utils/index");
37var validator = require("../utils/validator");
38// App Check backend constants
39var FIREBASE_APP_CHECK_V1_API_URL_FORMAT = 'https://firebaseappcheck.googleapis.com/v1beta/projects/{projectId}/apps/{appId}:exchangeCustomToken';
40var FIREBASE_APP_CHECK_CONFIG_HEADERS = {
41 'X-Firebase-Client': "fire-admin-node/" + utils.getSdkVersion()
42};
43/**
44 * Class that facilitates sending requests to the Firebase App Check backend API.
45 *
46 * @internal
47 */
48var AppCheckApiClient = /** @class */ (function () {
49 function AppCheckApiClient(app) {
50 this.app = app;
51 if (!validator.isNonNullObject(app) || !('options' in app)) {
52 throw new FirebaseAppCheckError('invalid-argument', 'First argument passed to admin.appCheck() must be a valid Firebase app instance.');
53 }
54 this.httpClient = new api_request_1.AuthorizedHttpClient(app);
55 }
56 /**
57 * Exchange a signed custom token to App Check token
58 *
59 * @param customToken - The custom token to be exchanged.
60 * @param appId - The mobile App ID.
61 * @returns A promise that fulfills with a `AppCheckToken`.
62 */
63 AppCheckApiClient.prototype.exchangeToken = function (customToken, appId) {
64 var _this = this;
65 if (!validator.isNonEmptyString(appId)) {
66 throw new FirebaseAppCheckError('invalid-argument', '`appId` must be a non-empty string.');
67 }
68 if (!validator.isNonEmptyString(customToken)) {
69 throw new FirebaseAppCheckError('invalid-argument', '`customToken` must be a non-empty string.');
70 }
71 return this.getUrl(appId)
72 .then(function (url) {
73 var request = {
74 method: 'POST',
75 url: url,
76 headers: FIREBASE_APP_CHECK_CONFIG_HEADERS,
77 data: { customToken: customToken }
78 };
79 return _this.httpClient.send(request);
80 })
81 .then(function (resp) {
82 return _this.toAppCheckToken(resp);
83 })
84 .catch(function (err) {
85 throw _this.toFirebaseError(err);
86 });
87 };
88 AppCheckApiClient.prototype.getUrl = function (appId) {
89 return this.getProjectId()
90 .then(function (projectId) {
91 var urlParams = {
92 projectId: projectId,
93 appId: appId,
94 };
95 var baseUrl = utils.formatString(FIREBASE_APP_CHECK_V1_API_URL_FORMAT, urlParams);
96 return utils.formatString(baseUrl);
97 });
98 };
99 AppCheckApiClient.prototype.getProjectId = function () {
100 var _this = this;
101 if (this.projectId) {
102 return Promise.resolve(this.projectId);
103 }
104 return utils.findProjectId(this.app)
105 .then(function (projectId) {
106 if (!validator.isNonEmptyString(projectId)) {
107 throw new FirebaseAppCheckError('unknown-error', 'Failed to determine project ID. Initialize the '
108 + 'SDK with service account credentials or set project ID as an app option. '
109 + 'Alternatively, set the GOOGLE_CLOUD_PROJECT environment variable.');
110 }
111 _this.projectId = projectId;
112 return projectId;
113 });
114 };
115 AppCheckApiClient.prototype.toFirebaseError = function (err) {
116 if (err instanceof error_1.PrefixedFirebaseError) {
117 return err;
118 }
119 var response = err.response;
120 if (!response.isJson()) {
121 return new FirebaseAppCheckError('unknown-error', "Unexpected response with status: " + response.status + " and body: " + response.text);
122 }
123 var error = response.data.error || {};
124 var code = 'unknown-error';
125 if (error.status && error.status in exports.APP_CHECK_ERROR_CODE_MAPPING) {
126 code = exports.APP_CHECK_ERROR_CODE_MAPPING[error.status];
127 }
128 var message = error.message || "Unknown server error: " + response.text;
129 return new FirebaseAppCheckError(code, message);
130 };
131 /**
132 * Creates an AppCheckToken from the API response.
133 *
134 * @param resp - API response object.
135 * @returns An AppCheckToken instance.
136 */
137 AppCheckApiClient.prototype.toAppCheckToken = function (resp) {
138 var token = resp.data.attestationToken;
139 // `ttl` is a string with the suffix "s" preceded by the number of seconds,
140 // with nanoseconds expressed as fractional seconds.
141 var ttlMillis = this.stringToMilliseconds(resp.data.ttl);
142 return {
143 token: token,
144 ttlMillis: ttlMillis
145 };
146 };
147 /**
148 * Converts a duration string with the suffix `s` to milliseconds.
149 *
150 * @param duration - The duration as a string with the suffix "s" preceded by the
151 * number of seconds, with fractional seconds. For example, 3 seconds with 0 nanoseconds
152 * is expressed as "3s", while 3 seconds and 1 nanosecond is expressed as "3.000000001s",
153 * and 3 seconds and 1 microsecond is expressed as "3.000001s".
154 *
155 * @returns The duration in milliseconds.
156 */
157 AppCheckApiClient.prototype.stringToMilliseconds = function (duration) {
158 if (!validator.isNonEmptyString(duration) || !duration.endsWith('s')) {
159 throw new FirebaseAppCheckError('invalid-argument', '`ttl` must be a valid duration string with the suffix `s`.');
160 }
161 var seconds = duration.slice(0, -1);
162 return Math.floor(Number(seconds) * 1000);
163 };
164 return AppCheckApiClient;
165}());
166exports.AppCheckApiClient = AppCheckApiClient;
167exports.APP_CHECK_ERROR_CODE_MAPPING = {
168 ABORTED: 'aborted',
169 INVALID_ARGUMENT: 'invalid-argument',
170 INVALID_CREDENTIAL: 'invalid-credential',
171 INTERNAL: 'internal-error',
172 PERMISSION_DENIED: 'permission-denied',
173 UNAUTHENTICATED: 'unauthenticated',
174 NOT_FOUND: 'not-found',
175 UNKNOWN: 'unknown-error',
176};
177/**
178 * Firebase App Check error code structure. This extends PrefixedFirebaseError.
179 *
180 * @param code - The error code.
181 * @param message - The error message.
182 * @constructor
183 */
184var FirebaseAppCheckError = /** @class */ (function (_super) {
185 __extends(FirebaseAppCheckError, _super);
186 function FirebaseAppCheckError(code, message) {
187 var _this = _super.call(this, 'app-check', code, message) || this;
188 /* tslint:disable:max-line-length */
189 // Set the prototype explicitly. See the following link for more details:
190 // https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work
191 /* tslint:enable:max-line-length */
192 _this.__proto__ = FirebaseAppCheckError.prototype;
193 return _this;
194 }
195 return FirebaseAppCheckError;
196}(error_1.PrefixedFirebaseError));
197exports.FirebaseAppCheckError = FirebaseAppCheckError;