Sindbad~EG File Manager
"use strict";
// Copyright 2021 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.
var _a, _b, _c;
Object.defineProperty(exports, "__esModule", { value: true });
exports.IdentityPoolClient = void 0;
const fs = require("fs");
const util_1 = require("util");
const baseexternalclient_1 = require("./baseexternalclient");
const util_2 = require("../util");
// fs.readfile is undefined in browser karma tests causing
// `npm run browser-test` to fail as test.oauth2.ts imports this file via
// src/index.ts.
// Fallback to void function to avoid promisify throwing a TypeError.
const readFile = (0, util_1.promisify)((_a = fs.readFile) !== null && _a !== void 0 ? _a : (() => { }));
const realpath = (0, util_1.promisify)((_b = fs.realpath) !== null && _b !== void 0 ? _b : (() => { }));
const lstat = (0, util_1.promisify)((_c = fs.lstat) !== null && _c !== void 0 ? _c : (() => { }));
/**
* Defines the Url-sourced and file-sourced external account clients mainly
* used for K8s and Azure workloads.
*/
class IdentityPoolClient extends baseexternalclient_1.BaseExternalAccountClient {
/**
* Instantiate an IdentityPoolClient instance using the provided JSON
* object loaded from an external account credentials file.
* An error is thrown if the credential is not a valid file-sourced or
* url-sourced credential or a workforce pool user project is provided
* with a non workforce audience.
* @param options The external account options object typically loaded
* from the external account JSON credential file. The camelCased options
* are aliases for the snake_cased options.
* @param additionalOptions **DEPRECATED, all options are available in the
* `options` parameter.** Optional additional behavior customization options.
* These currently customize expiration threshold time and whether to retry
* on 401/403 API request errors.
*/
constructor(options, additionalOptions) {
super(options, additionalOptions);
const opts = (0, util_2.originalOrCamelOptions)(options);
const credentialSource = opts.get('credential_source');
const credentialSourceOpts = (0, util_2.originalOrCamelOptions)(credentialSource);
this.file = credentialSourceOpts.get('file');
this.url = credentialSourceOpts.get('url');
this.headers = credentialSourceOpts.get('headers');
if (this.file && this.url) {
throw new Error('No valid Identity Pool "credential_source" provided, must be either file or url.');
}
else if (this.file && !this.url) {
this.credentialSourceType = 'file';
}
else if (!this.file && this.url) {
this.credentialSourceType = 'url';
}
else {
throw new Error('No valid Identity Pool "credential_source" provided, must be either file or url.');
}
const formatOpts = (0, util_2.originalOrCamelOptions)(credentialSourceOpts.get('format'));
// Text is the default format type.
this.formatType = formatOpts.get('type') || 'text';
this.formatSubjectTokenFieldName = formatOpts.get('subject_token_field_name');
if (this.formatType !== 'json' && this.formatType !== 'text') {
throw new Error(`Invalid credential_source format "${this.formatType}"`);
}
if (this.formatType === 'json' && !this.formatSubjectTokenFieldName) {
throw new Error('Missing subject_token_field_name for JSON credential_source format');
}
}
/**
* Triggered when a external subject token is needed to be exchanged for a GCP
* access token via GCP STS endpoint.
* This uses the `options.credential_source` object to figure out how
* to retrieve the token using the current environment. In this case,
* this either retrieves the local credential from a file location (k8s
* workload) or by sending a GET request to a local metadata server (Azure
* workloads).
* @return A promise that resolves with the external subject token.
*/
async retrieveSubjectToken() {
if (this.file) {
return await this.getTokenFromFile(this.file, this.formatType, this.formatSubjectTokenFieldName);
}
return await this.getTokenFromUrl(this.url, this.formatType, this.formatSubjectTokenFieldName, this.headers);
}
/**
* Looks up the external subject token in the file path provided and
* resolves with that token.
* @param file The file path where the external credential is located.
* @param formatType The token file or URL response type (JSON or text).
* @param formatSubjectTokenFieldName For JSON response types, this is the
* subject_token field name. For Azure, this is access_token. For text
* response types, this is ignored.
* @return A promise that resolves with the external subject token.
*/
async getTokenFromFile(filePath, formatType, formatSubjectTokenFieldName) {
// Make sure there is a file at the path. lstatSync will throw if there is
// nothing there.
try {
// Resolve path to actual file in case of symlink. Expect a thrown error
// if not resolvable.
filePath = await realpath(filePath);
if (!(await lstat(filePath)).isFile()) {
throw new Error();
}
}
catch (err) {
if (err instanceof Error) {
err.message = `The file at ${filePath} does not exist, or it is not a file. ${err.message}`;
}
throw err;
}
let subjectToken;
const rawText = await readFile(filePath, { encoding: 'utf8' });
if (formatType === 'text') {
subjectToken = rawText;
}
else if (formatType === 'json' && formatSubjectTokenFieldName) {
const json = JSON.parse(rawText);
subjectToken = json[formatSubjectTokenFieldName];
}
if (!subjectToken) {
throw new Error('Unable to parse the subject_token from the credential_source file');
}
return subjectToken;
}
/**
* Sends a GET request to the URL provided and resolves with the returned
* external subject token.
* @param url The URL to call to retrieve the subject token. This is typically
* a local metadata server.
* @param formatType The token file or URL response type (JSON or text).
* @param formatSubjectTokenFieldName For JSON response types, this is the
* subject_token field name. For Azure, this is access_token. For text
* response types, this is ignored.
* @param headers The optional additional headers to send with the request to
* the metadata server url.
* @return A promise that resolves with the external subject token.
*/
async getTokenFromUrl(url, formatType, formatSubjectTokenFieldName, headers) {
const opts = {
...IdentityPoolClient.RETRY_CONFIG,
url,
method: 'GET',
headers,
responseType: formatType,
};
let subjectToken;
if (formatType === 'text') {
const response = await this.transporter.request(opts);
subjectToken = response.data;
}
else if (formatType === 'json' && formatSubjectTokenFieldName) {
const response = await this.transporter.request(opts);
subjectToken = response.data[formatSubjectTokenFieldName];
}
if (!subjectToken) {
throw new Error('Unable to parse the subject_token from the credential_source URL');
}
return subjectToken;
}
}
exports.IdentityPoolClient = IdentityPoolClient;
Sindbad File Manager Version 1.0, Coded By Sindbad EG ~ The Terrorists