UNPKG

9.61 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.CryptoSignerErrorCode = exports.CryptoSignerError = exports.cryptoSignerFromApp = exports.IAMSigner = exports.ServiceAccountSigner = void 0;
34var credential_internal_1 = require("../app/credential-internal");
35var api_request_1 = require("./api-request");
36var validator = require("../utils/validator");
37var ALGORITHM_RS256 = 'RS256';
38/**
39 * A CryptoSigner implementation that uses an explicitly specified service account private key to
40 * sign data. Performs all operations locally, and does not make any RPC calls.
41 */
42var ServiceAccountSigner = /** @class */ (function () {
43 /**
44 * Creates a new CryptoSigner instance from the given service account credential.
45 *
46 * @param credential - A service account credential.
47 */
48 function ServiceAccountSigner(credential) {
49 this.credential = credential;
50 this.algorithm = ALGORITHM_RS256;
51 if (!credential) {
52 throw new CryptoSignerError({
53 code: CryptoSignerErrorCode.INVALID_CREDENTIAL,
54 message: 'INTERNAL ASSERT: Must provide a service account credential to initialize ServiceAccountSigner.',
55 });
56 }
57 }
58 /**
59 * @inheritDoc
60 */
61 ServiceAccountSigner.prototype.sign = function (buffer) {
62 var crypto = require('crypto'); // eslint-disable-line @typescript-eslint/no-var-requires
63 var sign = crypto.createSign('RSA-SHA256');
64 sign.update(buffer);
65 return Promise.resolve(sign.sign(this.credential.privateKey));
66 };
67 /**
68 * @inheritDoc
69 */
70 ServiceAccountSigner.prototype.getAccountId = function () {
71 return Promise.resolve(this.credential.clientEmail);
72 };
73 return ServiceAccountSigner;
74}());
75exports.ServiceAccountSigner = ServiceAccountSigner;
76/**
77 * A CryptoSigner implementation that uses the remote IAM service to sign data. If initialized without
78 * a service account ID, attempts to discover a service account ID by consulting the local Metadata
79 * service. This will succeed in managed environments like Google Cloud Functions and App Engine.
80 *
81 * @see https://cloud.google.com/iam/reference/rest/v1/projects.serviceAccounts/signBlob
82 * @see https://cloud.google.com/compute/docs/storing-retrieving-metadata
83 */
84var IAMSigner = /** @class */ (function () {
85 function IAMSigner(httpClient, serviceAccountId) {
86 this.algorithm = ALGORITHM_RS256;
87 if (!httpClient) {
88 throw new CryptoSignerError({
89 code: CryptoSignerErrorCode.INVALID_ARGUMENT,
90 message: 'INTERNAL ASSERT: Must provide a HTTP client to initialize IAMSigner.',
91 });
92 }
93 if (typeof serviceAccountId !== 'undefined' && !validator.isNonEmptyString(serviceAccountId)) {
94 throw new CryptoSignerError({
95 code: CryptoSignerErrorCode.INVALID_ARGUMENT,
96 message: 'INTERNAL ASSERT: Service account ID must be undefined or a non-empty string.',
97 });
98 }
99 this.httpClient = httpClient;
100 this.serviceAccountId = serviceAccountId;
101 }
102 /**
103 * @inheritDoc
104 */
105 IAMSigner.prototype.sign = function (buffer) {
106 var _this = this;
107 return this.getAccountId().then(function (serviceAccount) {
108 var request = {
109 method: 'POST',
110 url: "https://iamcredentials.googleapis.com/v1/projects/-/serviceAccounts/" + serviceAccount + ":signBlob",
111 data: { payload: buffer.toString('base64') },
112 };
113 return _this.httpClient.send(request);
114 }).then(function (response) {
115 // Response from IAM is base64 encoded. Decode it into a buffer and return.
116 return Buffer.from(response.data.signedBlob, 'base64');
117 }).catch(function (err) {
118 if (err instanceof api_request_1.HttpError) {
119 throw new CryptoSignerError({
120 code: CryptoSignerErrorCode.SERVER_ERROR,
121 message: err.message,
122 cause: err
123 });
124 }
125 throw err;
126 });
127 };
128 /**
129 * @inheritDoc
130 */
131 IAMSigner.prototype.getAccountId = function () {
132 var _this = this;
133 if (validator.isNonEmptyString(this.serviceAccountId)) {
134 return Promise.resolve(this.serviceAccountId);
135 }
136 var request = {
137 method: 'GET',
138 url: 'http://metadata/computeMetadata/v1/instance/service-accounts/default/email',
139 headers: {
140 'Metadata-Flavor': 'Google',
141 },
142 };
143 var client = new api_request_1.HttpClient();
144 return client.send(request).then(function (response) {
145 if (!response.text) {
146 throw new CryptoSignerError({
147 code: CryptoSignerErrorCode.INTERNAL_ERROR,
148 message: 'HTTP Response missing payload',
149 });
150 }
151 _this.serviceAccountId = response.text;
152 return response.text;
153 }).catch(function (err) {
154 throw new CryptoSignerError({
155 code: CryptoSignerErrorCode.INVALID_CREDENTIAL,
156 message: 'Failed to determine service account. Make sure to initialize ' +
157 'the SDK with a service account credential. Alternatively specify a service ' +
158 ("account with iam.serviceAccounts.signBlob permission. Original error: " + err),
159 });
160 });
161 };
162 return IAMSigner;
163}());
164exports.IAMSigner = IAMSigner;
165/**
166 * Creates a new CryptoSigner instance for the given app. If the app has been initialized with a
167 * service account credential, creates a ServiceAccountSigner.
168 *
169 * @param app - A FirebaseApp instance.
170 * @returns A CryptoSigner instance.
171 */
172function cryptoSignerFromApp(app) {
173 var credential = app.options.credential;
174 if (credential instanceof credential_internal_1.ServiceAccountCredential) {
175 return new ServiceAccountSigner(credential);
176 }
177 return new IAMSigner(new api_request_1.AuthorizedHttpClient(app), app.options.serviceAccountId);
178}
179exports.cryptoSignerFromApp = cryptoSignerFromApp;
180/**
181 * CryptoSigner error code structure.
182 *
183 * @param errorInfo - The error information (code and message).
184 * @constructor
185 */
186var CryptoSignerError = /** @class */ (function (_super) {
187 __extends(CryptoSignerError, _super);
188 function CryptoSignerError(errorInfo) {
189 var _this = _super.call(this, errorInfo.message) || this;
190 _this.errorInfo = errorInfo;
191 /* tslint:disable:max-line-length */
192 // Set the prototype explicitly. See the following link for more details:
193 // https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work
194 /* tslint:enable:max-line-length */
195 _this.__proto__ = CryptoSignerError.prototype;
196 return _this;
197 }
198 Object.defineProperty(CryptoSignerError.prototype, "code", {
199 /** @returns The error code. */
200 get: function () {
201 return this.errorInfo.code;
202 },
203 enumerable: false,
204 configurable: true
205 });
206 Object.defineProperty(CryptoSignerError.prototype, "message", {
207 /** @returns The error message. */
208 get: function () {
209 return this.errorInfo.message;
210 },
211 enumerable: false,
212 configurable: true
213 });
214 Object.defineProperty(CryptoSignerError.prototype, "cause", {
215 /** @returns The error data. */
216 get: function () {
217 return this.errorInfo.cause;
218 },
219 enumerable: false,
220 configurable: true
221 });
222 return CryptoSignerError;
223}(Error));
224exports.CryptoSignerError = CryptoSignerError;
225/**
226 * Crypto Signer error codes and their default messages.
227 */
228var CryptoSignerErrorCode = /** @class */ (function () {
229 function CryptoSignerErrorCode() {
230 }
231 CryptoSignerErrorCode.INVALID_ARGUMENT = 'invalid-argument';
232 CryptoSignerErrorCode.INTERNAL_ERROR = 'internal-error';
233 CryptoSignerErrorCode.INVALID_CREDENTIAL = 'invalid-credential';
234 CryptoSignerErrorCode.SERVER_ERROR = 'server-error';
235 return CryptoSignerErrorCode;
236}());
237exports.CryptoSignerErrorCode = CryptoSignerErrorCode;