initial commit
This commit is contained in:
156
server/node_modules/google-auth-library/build/src/auth/pluggable-auth-handler.js
generated
vendored
Normal file
156
server/node_modules/google-auth-library/build/src/auth/pluggable-auth-handler.js
generated
vendored
Normal file
@@ -0,0 +1,156 @@
|
||||
"use strict";
|
||||
// Copyright 2022 Google LLC
|
||||
//
|
||||
// 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.PluggableAuthHandler = void 0;
|
||||
const pluggable_auth_client_1 = require("./pluggable-auth-client");
|
||||
const executable_response_1 = require("./executable-response");
|
||||
const childProcess = require("child_process");
|
||||
const fs = require("fs");
|
||||
/**
|
||||
* A handler used to retrieve 3rd party token responses from user defined
|
||||
* executables and cached file output for the PluggableAuthClient class.
|
||||
*/
|
||||
class PluggableAuthHandler {
|
||||
/**
|
||||
* Instantiates a PluggableAuthHandler instance using the provided
|
||||
* PluggableAuthHandlerOptions object.
|
||||
*/
|
||||
constructor(options) {
|
||||
if (!options.command) {
|
||||
throw new Error('No command provided.');
|
||||
}
|
||||
this.commandComponents = PluggableAuthHandler.parseCommand(options.command);
|
||||
this.timeoutMillis = options.timeoutMillis;
|
||||
if (!this.timeoutMillis) {
|
||||
throw new Error('No timeoutMillis provided.');
|
||||
}
|
||||
this.outputFile = options.outputFile;
|
||||
}
|
||||
/**
|
||||
* Calls user provided executable to get a 3rd party subject token and
|
||||
* returns the response.
|
||||
* @param envMap a Map of additional Environment Variables required for
|
||||
* the executable.
|
||||
* @return A promise that resolves with the executable response.
|
||||
*/
|
||||
retrieveResponseFromExecutable(envMap) {
|
||||
return new Promise((resolve, reject) => {
|
||||
// Spawn process to run executable using added environment variables.
|
||||
const child = childProcess.spawn(this.commandComponents[0], this.commandComponents.slice(1), {
|
||||
env: { ...process.env, ...Object.fromEntries(envMap) },
|
||||
});
|
||||
let output = '';
|
||||
// Append stdout to output as executable runs.
|
||||
child.stdout.on('data', (data) => {
|
||||
output += data;
|
||||
});
|
||||
// Append stderr as executable runs.
|
||||
child.stderr.on('data', (err) => {
|
||||
output += err;
|
||||
});
|
||||
// Set up a timeout to end the child process and throw an error.
|
||||
const timeout = setTimeout(() => {
|
||||
// Kill child process and remove listeners so 'close' event doesn't get
|
||||
// read after child process is killed.
|
||||
child.removeAllListeners();
|
||||
child.kill();
|
||||
return reject(new Error('The executable failed to finish within the timeout specified.'));
|
||||
}, this.timeoutMillis);
|
||||
child.on('close', (code) => {
|
||||
// Cancel timeout if executable closes before timeout is reached.
|
||||
clearTimeout(timeout);
|
||||
if (code === 0) {
|
||||
// If the executable completed successfully, try to return the parsed response.
|
||||
try {
|
||||
const responseJson = JSON.parse(output);
|
||||
const response = new executable_response_1.ExecutableResponse(responseJson);
|
||||
return resolve(response);
|
||||
}
|
||||
catch (error) {
|
||||
if (error instanceof executable_response_1.ExecutableResponseError) {
|
||||
return reject(error);
|
||||
}
|
||||
return reject(new executable_response_1.ExecutableResponseError(`The executable returned an invalid response: ${output}`));
|
||||
}
|
||||
}
|
||||
else {
|
||||
return reject(new pluggable_auth_client_1.ExecutableError(output, code.toString()));
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
/**
|
||||
* Checks user provided output file for response from previous run of
|
||||
* executable and return the response if it exists, is formatted correctly, and is not expired.
|
||||
*/
|
||||
async retrieveCachedResponse() {
|
||||
if (!this.outputFile || this.outputFile.length === 0) {
|
||||
return undefined;
|
||||
}
|
||||
let filePath;
|
||||
try {
|
||||
filePath = await fs.promises.realpath(this.outputFile);
|
||||
}
|
||||
catch (_a) {
|
||||
// If file path cannot be resolved, return undefined.
|
||||
return undefined;
|
||||
}
|
||||
if (!(await fs.promises.lstat(filePath)).isFile()) {
|
||||
// If path does not lead to file, return undefined.
|
||||
return undefined;
|
||||
}
|
||||
const responseString = await fs.promises.readFile(filePath, {
|
||||
encoding: 'utf8',
|
||||
});
|
||||
if (responseString === '') {
|
||||
return undefined;
|
||||
}
|
||||
try {
|
||||
const responseJson = JSON.parse(responseString);
|
||||
const response = new executable_response_1.ExecutableResponse(responseJson);
|
||||
// Check if response is successful and unexpired.
|
||||
if (response.isValid()) {
|
||||
return new executable_response_1.ExecutableResponse(responseJson);
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
catch (error) {
|
||||
if (error instanceof executable_response_1.ExecutableResponseError) {
|
||||
throw error;
|
||||
}
|
||||
throw new executable_response_1.ExecutableResponseError(`The output file contained an invalid response: ${responseString}`);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Parses given command string into component array, splitting on spaces unless
|
||||
* spaces are between quotation marks.
|
||||
*/
|
||||
static parseCommand(command) {
|
||||
// Split the command into components by splitting on spaces,
|
||||
// unless spaces are contained in quotation marks.
|
||||
const components = command.match(/(?:[^\s"]+|"[^"]*")+/g);
|
||||
if (!components) {
|
||||
throw new Error(`Provided command: "${command}" could not be parsed.`);
|
||||
}
|
||||
// Remove quotation marks from the beginning and end of each component if they are present.
|
||||
for (let i = 0; i < components.length; i++) {
|
||||
if (components[i][0] === '"' && components[i].slice(-1) === '"') {
|
||||
components[i] = components[i].slice(1, -1);
|
||||
}
|
||||
}
|
||||
return components;
|
||||
}
|
||||
}
|
||||
exports.PluggableAuthHandler = PluggableAuthHandler;
|
||||
Reference in New Issue
Block a user