Built motion from commit 6a09e18b.|2.6.11
[motion2.git] / legacy-libs / google-auth-library / build / src / auth / googleauth.js
1 "use strict";
2 /**
3  * Copyright 2019 Google LLC. All Rights Reserved.
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  *      http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */
17 var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
18     return new (P || (P = Promise))(function (resolve, reject) {
19         function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
20         function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
21         function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
22         step((generator = generator.apply(thisArg, _arguments || [])).next());
23     });
24 };
25 Object.defineProperty(exports, "__esModule", { value: true });
26 const child_process_1 = require("child_process");
27 const fs = require("fs");
28 const gcpMetadata = require("gcp-metadata");
29 const os = require("os");
30 const path = require("path");
31 const crypto_1 = require("../crypto/crypto");
32 const isbrowser_1 = require("../isbrowser");
33 const messages = require("../messages");
34 const transporters_1 = require("../transporters");
35 const computeclient_1 = require("./computeclient");
36 const envDetect_1 = require("./envDetect");
37 const jwtclient_1 = require("./jwtclient");
38 const refreshclient_1 = require("./refreshclient");
39 exports.CLOUD_SDK_CLIENT_ID = '764086051850-6qr4p6gpi6hn506pt8ejuq83di341hur.apps.googleusercontent.com';
40 class GoogleAuth {
41     constructor(opts) {
42         /**
43          * Caches a value indicating whether the auth layer is running on Google
44          * Compute Engine.
45          * @private
46          */
47         this.checkIsGCE = undefined;
48         // To save the contents of the JSON credential file
49         this.jsonContent = null;
50         this.cachedCredential = null;
51         opts = opts || {};
52         this._cachedProjectId = opts.projectId || null;
53         this.keyFilename = opts.keyFilename || opts.keyFile;
54         this.scopes = opts.scopes;
55         this.jsonContent = opts.credentials || null;
56         this.clientOptions = opts.clientOptions;
57     }
58     // Note:  this properly is only public to satisify unit tests.
59     // https://github.com/Microsoft/TypeScript/issues/5228
60     get isGCE() {
61         return this.checkIsGCE;
62     }
63     getDefaultProjectId(callback) {
64         messages.warn(messages.DEFAULT_PROJECT_ID_DEPRECATED);
65         if (callback) {
66             this.getProjectIdAsync().then(r => callback(null, r), callback);
67         }
68         else {
69             return this.getProjectIdAsync();
70         }
71     }
72     getProjectId(callback) {
73         if (callback) {
74             this.getProjectIdAsync().then(r => callback(null, r), callback);
75         }
76         else {
77             return this.getProjectIdAsync();
78         }
79     }
80     getProjectIdAsync() {
81         if (this._cachedProjectId) {
82             return Promise.resolve(this._cachedProjectId);
83         }
84         // In implicit case, supports three environments. In order of precedence,
85         // the implicit environments are:
86         // - GCLOUD_PROJECT or GOOGLE_CLOUD_PROJECT environment variable
87         // - GOOGLE_APPLICATION_CREDENTIALS JSON file
88         // - Cloud SDK: `gcloud config config-helper --format json`
89         // - GCE project ID from metadata server)
90         if (!this._getDefaultProjectIdPromise) {
91             this._getDefaultProjectIdPromise =
92                 new Promise((resolve, reject) => __awaiter(this, void 0, void 0, function* () {
93                     try {
94                         const projectId = this.getProductionProjectId() ||
95                             (yield this.getFileProjectId()) ||
96                             (yield this.getDefaultServiceProjectId()) ||
97                             (yield this.getGCEProjectId());
98                         this._cachedProjectId = projectId;
99                         resolve(projectId);
100                     }
101                     catch (e) {
102                         reject(e);
103                     }
104                 }));
105         }
106         return this._getDefaultProjectIdPromise;
107     }
108     getApplicationDefault(optionsOrCallback = {}, callback) {
109         let options;
110         if (typeof optionsOrCallback === 'function') {
111             callback = optionsOrCallback;
112         }
113         else {
114             options = optionsOrCallback;
115         }
116         if (callback) {
117             this.getApplicationDefaultAsync(options).then(r => callback(null, r.credential, r.projectId), callback);
118         }
119         else {
120             return this.getApplicationDefaultAsync(options);
121         }
122     }
123     getApplicationDefaultAsync(options) {
124         return __awaiter(this, void 0, void 0, function* () {
125             // If we've already got a cached credential, just return it.
126             if (this.cachedCredential) {
127                 return {
128                     credential: this.cachedCredential,
129                     projectId: yield this.getProjectIdAsync()
130                 };
131             }
132             let credential;
133             let projectId;
134             // Check for the existence of a local environment variable pointing to the
135             // location of the credential file. This is typically used in local
136             // developer scenarios.
137             credential =
138                 yield this._tryGetApplicationCredentialsFromEnvironmentVariable(options);
139             if (credential) {
140                 if (credential instanceof jwtclient_1.JWT) {
141                     credential.scopes = this.scopes;
142                 }
143                 this.cachedCredential = credential;
144                 projectId = yield this.getProjectId();
145                 return { credential, projectId };
146             }
147             // Look in the well-known credential file location.
148             credential =
149                 yield this._tryGetApplicationCredentialsFromWellKnownFile(options);
150             if (credential) {
151                 if (credential instanceof jwtclient_1.JWT) {
152                     credential.scopes = this.scopes;
153                 }
154                 this.cachedCredential = credential;
155                 projectId = yield this.getProjectId();
156                 return { credential, projectId };
157             }
158             // Determine if we're running on GCE.
159             let isGCE;
160             try {
161                 isGCE = yield this._checkIsGCE();
162             }
163             catch (e) {
164                 throw new Error('Unexpected error determining execution environment: ' + e.message);
165             }
166             if (!isGCE) {
167                 // We failed to find the default credentials. Bail out with an error.
168                 throw new Error('Could not load the default credentials. Browse to https://cloud.google.com/docs/authentication/getting-started for more information.');
169             }
170             // For GCE, just return a default ComputeClient. It will take care of
171             // the rest.
172             this.cachedCredential = new computeclient_1.Compute(options);
173             projectId = yield this.getProjectId();
174             return { projectId, credential: this.cachedCredential };
175         });
176     }
177     /**
178      * Determines whether the auth layer is running on Google Compute Engine.
179      * @returns A promise that resolves with the boolean.
180      * @api private
181      */
182     _checkIsGCE() {
183         return __awaiter(this, void 0, void 0, function* () {
184             if (this.checkIsGCE === undefined) {
185                 this.checkIsGCE = yield gcpMetadata.isAvailable();
186             }
187             return this.checkIsGCE;
188         });
189     }
190     /**
191      * Attempts to load default credentials from the environment variable path..
192      * @returns Promise that resolves with the OAuth2Client or null.
193      * @api private
194      */
195     _tryGetApplicationCredentialsFromEnvironmentVariable(options) {
196         return __awaiter(this, void 0, void 0, function* () {
197             const credentialsPath = process.env['GOOGLE_APPLICATION_CREDENTIALS'] ||
198                 process.env['google_application_credentials'];
199             if (!credentialsPath || credentialsPath.length === 0) {
200                 return null;
201             }
202             try {
203                 return this._getApplicationCredentialsFromFilePath(credentialsPath, options);
204             }
205             catch (e) {
206                 throw this.createError('Unable to read the credential file specified by the GOOGLE_APPLICATION_CREDENTIALS environment variable.', e);
207             }
208         });
209     }
210     /**
211      * Attempts to load default credentials from a well-known file location
212      * @return Promise that resolves with the OAuth2Client or null.
213      * @api private
214      */
215     _tryGetApplicationCredentialsFromWellKnownFile(options) {
216         return __awaiter(this, void 0, void 0, function* () {
217             // First, figure out the location of the file, depending upon the OS type.
218             let location = null;
219             if (this._isWindows()) {
220                 // Windows
221                 location = process.env['APPDATA'];
222             }
223             else {
224                 // Linux or Mac
225                 const home = process.env['HOME'];
226                 if (home) {
227                     location = this._pathJoin(home, '.config');
228                 }
229             }
230             // If we found the root path, expand it.
231             if (location) {
232                 location = this._pathJoin(location, 'gcloud');
233                 location =
234                     this._pathJoin(location, 'application_default_credentials.json');
235                 location = this._mockWellKnownFilePath(location);
236                 // Check whether the file exists.
237                 if (!this._fileExists(location)) {
238                     location = null;
239                 }
240             }
241             // The file does not exist.
242             if (!location) {
243                 return null;
244             }
245             // The file seems to exist. Try to use it.
246             const client = yield this._getApplicationCredentialsFromFilePath(location, options);
247             this.warnOnProblematicCredentials(client);
248             return client;
249         });
250     }
251     /**
252      * Attempts to load default credentials from a file at the given path..
253      * @param filePath The path to the file to read.
254      * @returns Promise that resolves with the OAuth2Client
255      * @api private
256      */
257     _getApplicationCredentialsFromFilePath(filePath, options = {}) {
258         return __awaiter(this, void 0, void 0, function* () {
259             // Make sure the path looks like a string.
260             if (!filePath || filePath.length === 0) {
261                 throw new Error('The file path is invalid.');
262             }
263             // Make sure there is a file at the path. lstatSync will throw if there is
264             // nothing there.
265             try {
266                 // Resolve path to actual file in case of symlink. Expect a thrown error
267                 // if not resolvable.
268                 filePath = fs.realpathSync(filePath);
269                 if (!fs.lstatSync(filePath).isFile()) {
270                     throw new Error();
271                 }
272             }
273             catch (err) {
274                 throw this.createError(`The file at ${filePath} does not exist, or it is not a file.`, err);
275             }
276             // Now open a read stream on the file, and parse it.
277             try {
278                 const readStream = this._createReadStream(filePath);
279                 return this.fromStream(readStream, options);
280             }
281             catch (err) {
282                 throw this.createError(`Unable to read the file at ${filePath}.`, err);
283             }
284         });
285     }
286     /**
287      * Credentials from the Cloud SDK that are associated with Cloud SDK's project
288      * are problematic because they may not have APIs enabled and have limited
289      * quota. If this is the case, warn about it.
290      */
291     warnOnProblematicCredentials(client) {
292         if (client.email === exports.CLOUD_SDK_CLIENT_ID) {
293             messages.warn(messages.PROBLEMATIC_CREDENTIALS_WARNING);
294         }
295     }
296     /**
297      * Create a credentials instance using the given input options.
298      * @param json The input object.
299      * @param options The JWT or UserRefresh options for the client
300      * @returns JWT or UserRefresh Client with data
301      */
302     fromJSON(json, options) {
303         let client;
304         if (!json) {
305             throw new Error('Must pass in a JSON object containing the Google auth settings.');
306         }
307         this.jsonContent = json;
308         options = options || {};
309         if (json.type === 'authorized_user') {
310             client = new refreshclient_1.UserRefreshClient(options);
311         }
312         else {
313             options.scopes = this.scopes;
314             client = new jwtclient_1.JWT(options);
315         }
316         client.fromJSON(json);
317         return client;
318     }
319     fromStream(inputStream, optionsOrCallback = {}, callback) {
320         let options = {};
321         if (typeof optionsOrCallback === 'function') {
322             callback = optionsOrCallback;
323         }
324         else {
325             options = optionsOrCallback;
326         }
327         if (callback) {
328             this.fromStreamAsync(inputStream, options)
329                 .then(r => callback(null, r), callback);
330         }
331         else {
332             return this.fromStreamAsync(inputStream, options);
333         }
334     }
335     fromStreamAsync(inputStream, options) {
336         return new Promise((resolve, reject) => {
337             if (!inputStream) {
338                 throw new Error('Must pass in a stream containing the Google auth settings.');
339             }
340             let s = '';
341             inputStream.setEncoding('utf8')
342                 .on('error', reject)
343                 .on('data', (chunk) => s += chunk)
344                 .on('end', () => {
345                 try {
346                     const data = JSON.parse(s);
347                     const r = this.fromJSON(data, options);
348                     return resolve(r);
349                 }
350                 catch (err) {
351                     return reject(err);
352                 }
353             });
354         });
355     }
356     /**
357      * Create a credentials instance using the given API key string.
358      * @param apiKey The API key string
359      * @param options An optional options object.
360      * @returns A JWT loaded from the key
361      */
362     fromAPIKey(apiKey, options) {
363         options = options || {};
364         const client = new jwtclient_1.JWT(options);
365         client.fromAPIKey(apiKey);
366         return client;
367     }
368     /**
369      * Determines whether the current operating system is Windows.
370      * @api private
371      */
372     _isWindows() {
373         const sys = this._osPlatform();
374         if (sys && sys.length >= 3) {
375             if (sys.substring(0, 3).toLowerCase() === 'win') {
376                 return true;
377             }
378         }
379         return false;
380     }
381     /**
382      * Creates a file stream. Allows mocking.
383      * @api private
384      */
385     _createReadStream(filePath) {
386         return fs.createReadStream(filePath);
387     }
388     /**
389      * Gets the current operating system platform. Allows mocking.
390      * @api private
391      */
392     _osPlatform() {
393         return os.platform();
394     }
395     /**
396      * Determines whether a file exists. Allows mocking.
397      * @api private
398      */
399     _fileExists(filePath) {
400         return fs.existsSync(filePath);
401     }
402     /**
403      * Joins two parts of a path. Allows mocking.
404      * @api private
405      */
406     _pathJoin(item1, item2) {
407         return path.join(item1, item2);
408     }
409     /**
410      * Allows mocking of the path to a well-known file.
411      * @api private
412      */
413     _mockWellKnownFilePath(filePath) {
414         return filePath;
415     }
416     // Creates an Error containing the given message, and includes the message
417     // from the optional err passed in.
418     createError(message, err) {
419         let s = message || '';
420         if (err) {
421             const errorMessage = String(err);
422             if (errorMessage && errorMessage.length > 0) {
423                 if (s.length > 0) {
424                     s += ' ';
425                 }
426                 s += errorMessage;
427             }
428         }
429         return Error(s);
430     }
431     /**
432      * Run the Google Cloud SDK command that prints the default project ID
433      */
434     getDefaultServiceProjectId() {
435         return __awaiter(this, void 0, void 0, function* () {
436             return new Promise(resolve => {
437                 child_process_1.exec('gcloud config config-helper --format json', (err, stdout, stderr) => {
438                     if (!err && stdout) {
439                         try {
440                             const projectId = JSON.parse(stdout).configuration.properties.core.project;
441                             resolve(projectId);
442                             return;
443                         }
444                         catch (e) {
445                             // ignore errors
446                         }
447                     }
448                     resolve(null);
449                 });
450             });
451         });
452     }
453     /**
454      * Loads the project id from environment variables.
455      * @api private
456      */
457     getProductionProjectId() {
458         return process.env['GCLOUD_PROJECT'] ||
459             process.env['GOOGLE_CLOUD_PROJECT'] || process.env['gcloud_project'] ||
460             process.env['google_cloud_project'];
461     }
462     /**
463      * Loads the project id from the GOOGLE_APPLICATION_CREDENTIALS json file.
464      * @api private
465      */
466     getFileProjectId() {
467         return __awaiter(this, void 0, void 0, function* () {
468             if (this.cachedCredential) {
469                 // Try to read the project ID from the cached credentials file
470                 return this.cachedCredential.projectId;
471             }
472             // Ensure the projectId is loaded from the keyFile if available.
473             if (this.keyFilename) {
474                 const creds = yield this.getClient();
475                 if (creds && creds.projectId) {
476                     return creds.projectId;
477                 }
478             }
479             // Try to load a credentials file and read its project ID
480             const r = yield this._tryGetApplicationCredentialsFromEnvironmentVariable();
481             if (r) {
482                 return r.projectId;
483             }
484             else {
485                 return null;
486             }
487         });
488     }
489     /**
490      * Gets the Compute Engine project ID if it can be inferred.
491      */
492     getGCEProjectId() {
493         return __awaiter(this, void 0, void 0, function* () {
494             try {
495                 const r = yield gcpMetadata.project('project-id');
496                 return r;
497             }
498             catch (e) {
499                 // Ignore any errors
500                 return null;
501             }
502         });
503     }
504     getCredentials(callback) {
505         if (callback) {
506             this.getCredentialsAsync().then(r => callback(null, r), callback);
507         }
508         else {
509             return this.getCredentialsAsync();
510         }
511     }
512     getCredentialsAsync() {
513         return __awaiter(this, void 0, void 0, function* () {
514             yield this.getClient();
515             if (this.jsonContent) {
516                 const credential = {
517                     client_email: this.jsonContent.client_email,
518                     private_key: this.jsonContent.private_key
519                 };
520                 return credential;
521             }
522             const isGCE = yield this._checkIsGCE();
523             if (!isGCE) {
524                 throw new Error('Unknown error.');
525             }
526             // For GCE, return the service account details from the metadata server
527             // NOTE: The trailing '/' at the end of service-accounts/ is very important!
528             // The GCF metadata server doesn't respect querystring params if this / is
529             // not included.
530             const data = yield gcpMetadata.instance({ property: 'service-accounts/', params: { recursive: 'true' } });
531             if (!data || !data.default || !data.default.email) {
532                 throw new Error('Failure from metadata server.');
533             }
534             return { client_email: data.default.email };
535         });
536     }
537     /**
538      * Automatically obtain a client based on the provided configuration.  If no
539      * options were passed, use Application Default Credentials.
540      */
541     getClient(options) {
542         return __awaiter(this, void 0, void 0, function* () {
543             if (options) {
544                 this.keyFilename =
545                     options.keyFilename || options.keyFile || this.keyFilename;
546                 this.scopes = options.scopes || this.scopes;
547                 this.jsonContent = options.credentials || this.jsonContent;
548                 this.clientOptions = options.clientOptions;
549             }
550             if (!this.cachedCredential) {
551                 if (this.jsonContent) {
552                     this.cachedCredential =
553                         yield this.fromJSON(this.jsonContent, this.clientOptions);
554                 }
555                 else if (this.keyFilename) {
556                     const filePath = path.resolve(this.keyFilename);
557                     const stream = fs.createReadStream(filePath);
558                     this.cachedCredential =
559                         yield this.fromStreamAsync(stream, this.clientOptions);
560                 }
561                 else {
562                     yield this.getApplicationDefaultAsync(this.clientOptions);
563                 }
564             }
565             return this.cachedCredential;
566         });
567     }
568     /**
569      * Automatically obtain application default credentials, and return
570      * an access token for making requests.
571      */
572     getAccessToken() {
573         return __awaiter(this, void 0, void 0, function* () {
574             const client = yield this.getClient();
575             return (yield client.getAccessToken()).token;
576         });
577     }
578     /**
579      * Obtain the HTTP headers that will provide authorization for a given
580      * request.
581      */
582     getRequestHeaders(url) {
583         return __awaiter(this, void 0, void 0, function* () {
584             const client = yield this.getClient();
585             return client.getRequestHeaders(url);
586         });
587     }
588     /**
589      * Obtain credentials for a request, then attach the appropriate headers to
590      * the request options.
591      * @param opts Axios or Request options on which to attach the headers
592      */
593     authorizeRequest(opts) {
594         return __awaiter(this, void 0, void 0, function* () {
595             opts = opts || {};
596             const url = opts.url || opts.uri;
597             const client = yield this.getClient();
598             const headers = yield client.getRequestHeaders(url);
599             opts.headers = Object.assign(opts.headers || {}, headers);
600             return opts;
601         });
602     }
603     /**
604      * Automatically obtain application default credentials, and make an
605      * HTTP request using the given options.
606      * @param opts Axios request options for the HTTP request.
607      */
608     // tslint:disable-next-line no-any
609     request(opts) {
610         return __awaiter(this, void 0, void 0, function* () {
611             const client = yield this.getClient();
612             return client.request(opts);
613         });
614     }
615     /**
616      * Determine the compute environment in which the code is running.
617      */
618     getEnv() {
619         return envDetect_1.getEnv();
620     }
621     /**
622      * Sign the given data with the current private key, or go out
623      * to the IAM API to sign it.
624      * @param data The data to be signed.
625      */
626     sign(data) {
627         return __awaiter(this, void 0, void 0, function* () {
628             const client = yield this.getClient();
629             const crypto = crypto_1.createCrypto();
630             if (client instanceof jwtclient_1.JWT && client.key && !isbrowser_1.isBrowser()) {
631                 const sign = crypto.createSign('RSA-SHA256');
632                 sign.update(data);
633                 return sign.sign(client.key, 'base64');
634             }
635             const projectId = yield this.getProjectId();
636             if (!projectId) {
637                 throw new Error('Cannot sign data without a project ID.');
638             }
639             const creds = yield this.getCredentials();
640             if (!creds.client_email) {
641                 throw new Error('Cannot sign data without `client_email`.');
642             }
643             const id = `projects/${projectId}/serviceAccounts/${creds.client_email}`;
644             const res = yield this.request({
645                 method: 'POST',
646                 url: `https://iam.googleapis.com/v1/${id}:signBlob`,
647                 data: { bytesToSign: crypto.encodeBase64StringUtf8(data) }
648             });
649             return res.data.signature;
650         });
651     }
652 }
653 /**
654  * Export DefaultTransporter as a static property of the class.
655  */
656 GoogleAuth.DefaultTransporter = transporters_1.DefaultTransporter;
657 exports.GoogleAuth = GoogleAuth;
658 //# sourceMappingURL=googleauth.js.map