Finished action

Adding the monolith node_modules dir for deployment
This commit is contained in:
Drew Heavner
2019-12-04 09:58:34 -05:00
parent d665ce5758
commit a29f8cd536
8629 changed files with 2587149 additions and 190 deletions

View File

@@ -0,0 +1,35 @@
/**
* Copyright 2012 Google Inc. All Rights Reserved.
*
* 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.
*/
/// <reference types="node" />
import { EventEmitter } from 'events';
import { GaxiosOptions, GaxiosPromise } from 'gaxios';
import { DefaultTransporter } from '../transporters';
import { Credentials } from './credentials';
export declare interface AuthClient {
on(event: 'tokens', listener: (tokens: Credentials) => void): this;
}
export declare abstract class AuthClient extends EventEmitter {
transporter: DefaultTransporter;
credentials: Credentials;
/**
* Provides an alternative Gaxios request implementation with auth credentials
*/
abstract request<T>(opts: GaxiosOptions): GaxiosPromise<T>;
/**
* Sets the auth credentials.
*/
setCredentials(credentials: Credentials): void;
}

View File

@@ -0,0 +1,34 @@
"use strict";
/**
* Copyright 2012 Google Inc. All Rights Reserved.
*
* 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 });
const events_1 = require("events");
const transporters_1 = require("../transporters");
class AuthClient extends events_1.EventEmitter {
constructor() {
super(...arguments);
this.transporter = new transporters_1.DefaultTransporter();
this.credentials = {};
}
/**
* Sets the auth credentials.
*/
setCredentials(credentials) {
this.credentials = credentials;
}
}
exports.AuthClient = AuthClient;
//# sourceMappingURL=authclient.js.map

View File

@@ -0,0 +1,54 @@
/**
* Copyright 2013 Google Inc. All Rights Reserved.
*
* 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.
*/
import { GaxiosError } from 'gaxios';
import { GetTokenResponse, OAuth2Client, RefreshOptions } from './oauth2client';
export interface ComputeOptions extends RefreshOptions {
/**
* The service account email to use, or 'default'. A Compute Engine instance
* may have multiple service accounts.
*/
serviceAccountEmail?: string;
/**
* The scopes that will be requested when acquiring service account
* credentials. Only applicable to modern App Engine and Cloud Function
* runtimes as of March 2019.
*/
scopes?: string | string[];
}
export declare class Compute extends OAuth2Client {
private serviceAccountEmail;
scopes: string[];
/**
* Google Compute Engine service account credentials.
*
* Retrieve access token from the metadata server.
* See: https://developers.google.com/compute/docs/authentication
*/
constructor(options?: ComputeOptions);
/**
* Indicates whether the credential requires scopes to be created by calling
* createdScoped before use.
* @deprecated
* @return Boolean indicating if scope is required.
*/
createScopedRequired(): boolean;
/**
* Refreshes the access token.
* @param refreshToken Unused parameter
*/
protected refreshTokenNoCache(refreshToken?: string | null): Promise<GetTokenResponse>;
protected wrapError(e: GaxiosError): void;
}

View File

@@ -0,0 +1,103 @@
"use strict";
/**
* Copyright 2013 Google Inc. All Rights Reserved.
*
* 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 });
const arrify = require("arrify");
const gcpMetadata = require("gcp-metadata");
const messages = require("../messages");
const oauth2client_1 = require("./oauth2client");
class Compute extends oauth2client_1.OAuth2Client {
/**
* Google Compute Engine service account credentials.
*
* Retrieve access token from the metadata server.
* See: https://developers.google.com/compute/docs/authentication
*/
constructor(options = {}) {
super(options);
// Start with an expired refresh token, which will automatically be
// refreshed before the first API call is made.
this.credentials = { expiry_date: 1, refresh_token: 'compute-placeholder' };
this.serviceAccountEmail = options.serviceAccountEmail || 'default';
this.scopes = arrify(options.scopes);
}
/**
* Indicates whether the credential requires scopes to be created by calling
* createdScoped before use.
* @deprecated
* @return Boolean indicating if scope is required.
*/
createScopedRequired() {
// On compute engine, scopes are specified at the compute instance's
// creation time, and cannot be changed. For this reason, always return
// false.
messages.warn(messages.COMPUTE_CREATE_SCOPED_DEPRECATED);
return false;
}
/**
* Refreshes the access token.
* @param refreshToken Unused parameter
*/
async refreshTokenNoCache(refreshToken) {
const tokenPath = `service-accounts/${this.serviceAccountEmail}/token`;
let data;
try {
const instanceOptions = {
property: tokenPath,
};
if (this.scopes.length > 0) {
instanceOptions.params = {
scopes: this.scopes.join(','),
};
}
data = await gcpMetadata.instance(instanceOptions);
}
catch (e) {
e.message = `Could not refresh access token: ${e.message}`;
this.wrapError(e);
throw e;
}
const tokens = data;
if (data && data.expires_in) {
tokens.expiry_date = new Date().getTime() + data.expires_in * 1000;
delete tokens.expires_in;
}
this.emit('tokens', tokens);
return { tokens, res: null };
}
wrapError(e) {
const res = e.response;
if (res && res.status) {
e.code = res.status.toString();
if (res.status === 403) {
e.message =
'A Forbidden error was returned while attempting to retrieve an access ' +
'token for the Compute Engine built-in service account. This may be because the Compute ' +
'Engine instance does not have the correct permission scopes specified: ' +
e.message;
}
else if (res.status === 404) {
e.message =
'A Not Found error was returned while attempting to retrieve an access' +
'token for the Compute Engine built-in service account. This may be because the Compute ' +
'Engine instance does not have any permission scopes specified: ' +
e.message;
}
}
}
}
exports.Compute = Compute;
//# sourceMappingURL=computeclient.js.map

View File

@@ -0,0 +1,43 @@
/**
* Copyright 2014 Google Inc. All Rights Reserved.
*
* 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.
*/
export interface Credentials {
refresh_token?: string | null;
expiry_date?: number | null;
access_token?: string | null;
token_type?: string | null;
id_token?: string | null;
}
export interface CredentialRequest {
refresh_token?: string;
access_token?: string;
token_type?: string;
expires_in?: number;
id_token?: string;
}
export interface JWTInput {
type?: string;
client_email?: string;
private_key?: string;
private_key_id?: string;
project_id?: string;
client_id?: string;
client_secret?: string;
refresh_token?: string;
}
export interface CredentialBody {
client_email?: string;
private_key?: string;
}

View File

@@ -0,0 +1,18 @@
"use strict";
/**
* Copyright 2014 Google Inc. All Rights Reserved.
*
* 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 });
//# sourceMappingURL=credentials.js.map

View File

@@ -0,0 +1,24 @@
/**
* Copyright 2018 Google LLC. All Rights Reserved.
*
* 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.
*/
export declare enum GCPEnv {
APP_ENGINE = "APP_ENGINE",
KUBERNETES_ENGINE = "KUBERNETES_ENGINE",
CLOUD_FUNCTIONS = "CLOUD_FUNCTIONS",
COMPUTE_ENGINE = "COMPUTE_ENGINE",
NONE = "NONE"
}
export declare function clear(): void;
export declare function getEnv(): Promise<GCPEnv>;

View File

@@ -0,0 +1,73 @@
"use strict";
/**
* Copyright 2018 Google LLC. All Rights Reserved.
*
* 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 });
const gcpMetadata = require("gcp-metadata");
var GCPEnv;
(function (GCPEnv) {
GCPEnv["APP_ENGINE"] = "APP_ENGINE";
GCPEnv["KUBERNETES_ENGINE"] = "KUBERNETES_ENGINE";
GCPEnv["CLOUD_FUNCTIONS"] = "CLOUD_FUNCTIONS";
GCPEnv["COMPUTE_ENGINE"] = "COMPUTE_ENGINE";
GCPEnv["NONE"] = "NONE";
})(GCPEnv = exports.GCPEnv || (exports.GCPEnv = {}));
let env;
function clear() {
env = undefined;
}
exports.clear = clear;
async function getEnv() {
if (!env) {
if (isAppEngine()) {
env = GCPEnv.APP_ENGINE;
}
else if (isCloudFunction()) {
env = GCPEnv.CLOUD_FUNCTIONS;
}
else if (await isComputeEngine()) {
if (await isKubernetesEngine()) {
env = GCPEnv.KUBERNETES_ENGINE;
}
else {
env = GCPEnv.COMPUTE_ENGINE;
}
}
else {
env = GCPEnv.NONE;
}
}
return env;
}
exports.getEnv = getEnv;
function isAppEngine() {
return !!(process.env.GAE_SERVICE || process.env.GAE_MODULE_NAME);
}
function isCloudFunction() {
return !!(process.env.FUNCTION_NAME || process.env.FUNCTION_TARGET);
}
async function isKubernetesEngine() {
try {
await gcpMetadata.instance('attributes/cluster-name');
return true;
}
catch (e) {
return false;
}
}
async function isComputeEngine() {
return gcpMetadata.isAvailable();
}
//# sourceMappingURL=envDetect.js.map

View File

@@ -0,0 +1,262 @@
/**
* Copyright 2019 Google LLC. All Rights Reserved.
*
* 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.
*/
/// <reference types="node" />
import { GaxiosOptions, GaxiosResponse } from 'gaxios';
import * as stream from 'stream';
import { DefaultTransporter, Transporter } from '../transporters';
import { Compute } from './computeclient';
import { CredentialBody, JWTInput } from './credentials';
import { GCPEnv } from './envDetect';
import { JWT, JWTOptions } from './jwtclient';
import { Headers, OAuth2Client, OAuth2ClientOptions, RefreshOptions } from './oauth2client';
import { UserRefreshClient, UserRefreshClientOptions } from './refreshclient';
export interface ProjectIdCallback {
(err?: Error | null, projectId?: string | null): void;
}
export interface CredentialCallback {
(err: Error | null, result?: UserRefreshClient | JWT): void;
}
interface DeprecatedGetClientOptions {
}
export interface ADCCallback {
(err: Error | null, credential?: OAuth2Client, projectId?: string | null): void;
}
export interface ADCResponse {
credential: OAuth2Client;
projectId: string | null;
}
export interface GoogleAuthOptions {
/**
* Path to a .json, .pem, or .p12 key file
*/
keyFilename?: string;
/**
* Path to a .json, .pem, or .p12 key file
*/
keyFile?: string;
/**
* Object containing client_email and private_key properties
*/
credentials?: CredentialBody;
/**
* Options object passed to the constructor of the client
*/
clientOptions?: JWTOptions | OAuth2ClientOptions | UserRefreshClientOptions;
/**
* Required scopes for the desired API request
*/
scopes?: string | string[];
/**
* Your project ID.
*/
projectId?: string;
}
export declare const CLOUD_SDK_CLIENT_ID = "764086051850-6qr4p6gpi6hn506pt8ejuq83di341hur.apps.googleusercontent.com";
export declare class GoogleAuth {
transporter?: Transporter;
/**
* Caches a value indicating whether the auth layer is running on Google
* Compute Engine.
* @private
*/
private checkIsGCE?;
readonly isGCE: boolean | undefined;
private _getDefaultProjectIdPromise?;
private _cachedProjectId?;
jsonContent: JWTInput | null;
cachedCredential: JWT | UserRefreshClient | Compute | null;
private keyFilename?;
private scopes?;
private clientOptions?;
/**
* Export DefaultTransporter as a static property of the class.
*/
static DefaultTransporter: typeof DefaultTransporter;
constructor(opts?: GoogleAuthOptions);
/**
* THIS METHOD HAS BEEN DEPRECATED.
* It will be removed in 3.0. Please use getProjectId instead.
*/
getDefaultProjectId(): Promise<string>;
getDefaultProjectId(callback: ProjectIdCallback): void;
/**
* Obtains the default project ID for the application.
* @param callback Optional callback
* @returns Promise that resolves with project Id (if used without callback)
*/
getProjectId(): Promise<string>;
getProjectId(callback: ProjectIdCallback): void;
private getProjectIdAsync;
/**
* Obtains the default service-level credentials for the application.
* @param callback Optional callback.
* @returns Promise that resolves with the ADCResponse (if no callback was
* passed).
*/
getApplicationDefault(): Promise<ADCResponse>;
getApplicationDefault(callback: ADCCallback): void;
getApplicationDefault(options: RefreshOptions): Promise<ADCResponse>;
getApplicationDefault(options: RefreshOptions, callback: ADCCallback): void;
private getApplicationDefaultAsync;
/**
* Determines whether the auth layer is running on Google Compute Engine.
* @returns A promise that resolves with the boolean.
* @api private
*/
_checkIsGCE(): Promise<boolean>;
/**
* Attempts to load default credentials from the environment variable path..
* @returns Promise that resolves with the OAuth2Client or null.
* @api private
*/
_tryGetApplicationCredentialsFromEnvironmentVariable(options?: RefreshOptions): Promise<JWT | UserRefreshClient | null>;
/**
* Attempts to load default credentials from a well-known file location
* @return Promise that resolves with the OAuth2Client or null.
* @api private
*/
_tryGetApplicationCredentialsFromWellKnownFile(options?: RefreshOptions): Promise<JWT | UserRefreshClient | null>;
/**
* Attempts to load default credentials from a file at the given path..
* @param filePath The path to the file to read.
* @returns Promise that resolves with the OAuth2Client
* @api private
*/
_getApplicationCredentialsFromFilePath(filePath: string, options?: RefreshOptions): Promise<JWT | UserRefreshClient>;
/**
* Credentials from the Cloud SDK that are associated with Cloud SDK's project
* are problematic because they may not have APIs enabled and have limited
* quota. If this is the case, warn about it.
*/
protected warnOnProblematicCredentials(client: JWT): void;
/**
* Create a credentials instance using the given input options.
* @param json The input object.
* @param options The JWT or UserRefresh options for the client
* @returns JWT or UserRefresh Client with data
*/
fromJSON(json: JWTInput, options?: RefreshOptions): JWT | UserRefreshClient;
/**
* Return a JWT or UserRefreshClient from JavaScript object, caching both the
* object used to instantiate and the client.
* @param json The input object.
* @param options The JWT or UserRefresh options for the client
* @returns JWT or UserRefresh Client with data
*/
private _cacheClientFromJSON;
/**
* Create a credentials instance using the given input stream.
* @param inputStream The input stream.
* @param callback Optional callback.
*/
fromStream(inputStream: stream.Readable): Promise<JWT | UserRefreshClient>;
fromStream(inputStream: stream.Readable, callback: CredentialCallback): void;
fromStream(inputStream: stream.Readable, options: RefreshOptions): Promise<JWT | UserRefreshClient>;
fromStream(inputStream: stream.Readable, options: RefreshOptions, callback: CredentialCallback): void;
private fromStreamAsync;
/**
* Create a credentials instance using the given API key string.
* @param apiKey The API key string
* @param options An optional options object.
* @returns A JWT loaded from the key
*/
fromAPIKey(apiKey: string, options?: RefreshOptions): JWT;
/**
* Determines whether the current operating system is Windows.
* @api private
*/
private _isWindows;
/**
* Run the Google Cloud SDK command that prints the default project ID
*/
private getDefaultServiceProjectId;
/**
* Loads the project id from environment variables.
* @api private
*/
private getProductionProjectId;
/**
* Loads the project id from the GOOGLE_APPLICATION_CREDENTIALS json file.
* @api private
*/
private getFileProjectId;
/**
* Gets the Compute Engine project ID if it can be inferred.
*/
private getGCEProjectId;
/**
* The callback function handles a credential object that contains the
* client_email and private_key (if exists).
* getCredentials checks for these values from the user JSON at first.
* If it doesn't exist, and the environment is on GCE, it gets the
* client_email from the cloud metadata server.
* @param callback Callback that handles the credential object that contains
* a client_email and optional private key, or the error.
* returned
*/
getCredentials(): Promise<CredentialBody>;
getCredentials(callback: (err: Error | null, credentials?: CredentialBody) => void): void;
private getCredentialsAsync;
/**
* Automatically obtain a client based on the provided configuration. If no
* options were passed, use Application Default Credentials.
*/
getClient(options?: DeprecatedGetClientOptions): Promise<Compute | JWT | UserRefreshClient>;
/**
* Automatically obtain application default credentials, and return
* an access token for making requests.
*/
getAccessToken(): Promise<string | null | undefined>;
/**
* Obtain the HTTP headers that will provide authorization for a given
* request.
*/
getRequestHeaders(url?: string): Promise<Headers>;
/**
* Obtain credentials for a request, then attach the appropriate headers to
* the request options.
* @param opts Axios or Request options on which to attach the headers
*/
authorizeRequest(opts: {
url?: string;
uri?: string;
headers?: Headers;
}): Promise<{
url?: string | undefined;
uri?: string | undefined;
headers?: Headers | undefined;
}>;
/**
* Automatically obtain application default credentials, and make an
* HTTP request using the given options.
* @param opts Axios request options for the HTTP request.
*/
request<T = any>(opts: GaxiosOptions): Promise<GaxiosResponse<T>>;
/**
* Determine the compute environment in which the code is running.
*/
getEnv(): Promise<GCPEnv>;
/**
* Sign the given data with the current private key, or go out
* to the IAM API to sign it.
* @param data The data to be signed.
*/
sign(data: string): Promise<string>;
}
export interface SignBlobResponse {
signature: string;
}
export {};

View File

@@ -0,0 +1,587 @@
"use strict";
/**
* Copyright 2019 Google LLC. All Rights Reserved.
*
* 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 });
const child_process_1 = require("child_process");
const fs = require("fs");
const gcpMetadata = require("gcp-metadata");
const os = require("os");
const path = require("path");
const crypto_1 = require("../crypto/crypto");
const messages = require("../messages");
const transporters_1 = require("../transporters");
const computeclient_1 = require("./computeclient");
const envDetect_1 = require("./envDetect");
const jwtclient_1 = require("./jwtclient");
const refreshclient_1 = require("./refreshclient");
exports.CLOUD_SDK_CLIENT_ID = '764086051850-6qr4p6gpi6hn506pt8ejuq83di341hur.apps.googleusercontent.com';
class GoogleAuth {
constructor(opts) {
/**
* Caches a value indicating whether the auth layer is running on Google
* Compute Engine.
* @private
*/
this.checkIsGCE = undefined;
// To save the contents of the JSON credential file
this.jsonContent = null;
this.cachedCredential = null;
opts = opts || {};
this._cachedProjectId = opts.projectId || null;
this.keyFilename = opts.keyFilename || opts.keyFile;
this.scopes = opts.scopes;
this.jsonContent = opts.credentials || null;
this.clientOptions = opts.clientOptions;
}
// Note: this properly is only public to satisify unit tests.
// https://github.com/Microsoft/TypeScript/issues/5228
get isGCE() {
return this.checkIsGCE;
}
getDefaultProjectId(callback) {
messages.warn(messages.DEFAULT_PROJECT_ID_DEPRECATED);
if (callback) {
this.getProjectIdAsync().then(r => callback(null, r), callback);
}
else {
return this.getProjectIdAsync();
}
}
getProjectId(callback) {
if (callback) {
this.getProjectIdAsync().then(r => callback(null, r), callback);
}
else {
return this.getProjectIdAsync();
}
}
getProjectIdAsync() {
if (this._cachedProjectId) {
return Promise.resolve(this._cachedProjectId);
}
// In implicit case, supports three environments. In order of precedence,
// the implicit environments are:
// - GCLOUD_PROJECT or GOOGLE_CLOUD_PROJECT environment variable
// - GOOGLE_APPLICATION_CREDENTIALS JSON file
// - Cloud SDK: `gcloud config config-helper --format json`
// - GCE project ID from metadata server)
if (!this._getDefaultProjectIdPromise) {
this._getDefaultProjectIdPromise = new Promise(async (resolve, reject) => {
try {
const projectId = this.getProductionProjectId() ||
(await this.getFileProjectId()) ||
(await this.getDefaultServiceProjectId()) ||
(await this.getGCEProjectId());
this._cachedProjectId = projectId;
if (!projectId) {
throw new Error('Unable to detect a Project Id in the current environment. \n' +
'To learn more about authentication and Google APIs, visit: \n' +
'https://cloud.google.com/docs/authentication/getting-started');
}
resolve(projectId);
}
catch (e) {
reject(e);
}
});
}
return this._getDefaultProjectIdPromise;
}
getApplicationDefault(optionsOrCallback = {}, callback) {
let options;
if (typeof optionsOrCallback === 'function') {
callback = optionsOrCallback;
}
else {
options = optionsOrCallback;
}
if (callback) {
this.getApplicationDefaultAsync(options).then(r => callback(null, r.credential, r.projectId), callback);
}
else {
return this.getApplicationDefaultAsync(options);
}
}
async getApplicationDefaultAsync(options = {}) {
// If we've already got a cached credential, just return it.
if (this.cachedCredential) {
return {
credential: this.cachedCredential,
projectId: await this.getProjectIdAsync(),
};
}
let credential;
let projectId;
// Check for the existence of a local environment variable pointing to the
// location of the credential file. This is typically used in local
// developer scenarios.
credential = await this._tryGetApplicationCredentialsFromEnvironmentVariable(options);
if (credential) {
if (credential instanceof jwtclient_1.JWT) {
credential.scopes = this.scopes;
}
this.cachedCredential = credential;
projectId = await this.getProjectId();
return { credential, projectId };
}
// Look in the well-known credential file location.
credential = await this._tryGetApplicationCredentialsFromWellKnownFile(options);
if (credential) {
if (credential instanceof jwtclient_1.JWT) {
credential.scopes = this.scopes;
}
this.cachedCredential = credential;
projectId = await this.getProjectId();
return { credential, projectId };
}
// Determine if we're running on GCE.
let isGCE;
try {
isGCE = await this._checkIsGCE();
}
catch (e) {
e.message = `Unexpected error determining execution environment: ${e.message}`;
throw e;
}
if (!isGCE) {
// We failed to find the default credentials. Bail out with an error.
throw new Error('Could not load the default credentials. Browse to https://cloud.google.com/docs/authentication/getting-started for more information.');
}
// For GCE, just return a default ComputeClient. It will take care of
// the rest.
options.scopes = this.scopes;
this.cachedCredential = new computeclient_1.Compute(options);
projectId = await this.getProjectId();
return { projectId, credential: this.cachedCredential };
}
/**
* Determines whether the auth layer is running on Google Compute Engine.
* @returns A promise that resolves with the boolean.
* @api private
*/
async _checkIsGCE() {
if (this.checkIsGCE === undefined) {
this.checkIsGCE = await gcpMetadata.isAvailable();
}
return this.checkIsGCE;
}
/**
* Attempts to load default credentials from the environment variable path..
* @returns Promise that resolves with the OAuth2Client or null.
* @api private
*/
async _tryGetApplicationCredentialsFromEnvironmentVariable(options) {
const credentialsPath = process.env['GOOGLE_APPLICATION_CREDENTIALS'] ||
process.env['google_application_credentials'];
if (!credentialsPath || credentialsPath.length === 0) {
return null;
}
try {
return this._getApplicationCredentialsFromFilePath(credentialsPath, options);
}
catch (e) {
e.message = `Unable to read the credential file specified by the GOOGLE_APPLICATION_CREDENTIALS environment variable: ${e.message}`;
throw e;
}
}
/**
* Attempts to load default credentials from a well-known file location
* @return Promise that resolves with the OAuth2Client or null.
* @api private
*/
async _tryGetApplicationCredentialsFromWellKnownFile(options) {
// First, figure out the location of the file, depending upon the OS type.
let location = null;
if (this._isWindows()) {
// Windows
location = process.env['APPDATA'];
}
else {
// Linux or Mac
const home = process.env['HOME'];
if (home) {
location = path.join(home, '.config');
}
}
// If we found the root path, expand it.
if (location) {
location = path.join(location, 'gcloud', 'application_default_credentials.json');
if (!fs.existsSync(location)) {
location = null;
}
}
// The file does not exist.
if (!location) {
return null;
}
// The file seems to exist. Try to use it.
const client = await this._getApplicationCredentialsFromFilePath(location, options);
this.warnOnProblematicCredentials(client);
return client;
}
/**
* Attempts to load default credentials from a file at the given path..
* @param filePath The path to the file to read.
* @returns Promise that resolves with the OAuth2Client
* @api private
*/
async _getApplicationCredentialsFromFilePath(filePath, options = {}) {
// Make sure the path looks like a string.
if (!filePath || filePath.length === 0) {
throw new Error('The file path is invalid.');
}
// 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 = fs.realpathSync(filePath);
if (!fs.lstatSync(filePath).isFile()) {
throw new Error();
}
}
catch (err) {
err.message = `The file at ${filePath} does not exist, or it is not a file. ${err.message}`;
throw err;
}
// Now open a read stream on the file, and parse it.
const readStream = fs.createReadStream(filePath);
return this.fromStream(readStream, options);
}
/**
* Credentials from the Cloud SDK that are associated with Cloud SDK's project
* are problematic because they may not have APIs enabled and have limited
* quota. If this is the case, warn about it.
*/
warnOnProblematicCredentials(client) {
if (client.email === exports.CLOUD_SDK_CLIENT_ID) {
messages.warn(messages.PROBLEMATIC_CREDENTIALS_WARNING);
}
}
/**
* Create a credentials instance using the given input options.
* @param json The input object.
* @param options The JWT or UserRefresh options for the client
* @returns JWT or UserRefresh Client with data
*/
fromJSON(json, options) {
let client;
if (!json) {
throw new Error('Must pass in a JSON object containing the Google auth settings.');
}
options = options || {};
if (json.type === 'authorized_user') {
client = new refreshclient_1.UserRefreshClient(options);
}
else {
options.scopes = this.scopes;
client = new jwtclient_1.JWT(options);
}
client.fromJSON(json);
return client;
}
/**
* Return a JWT or UserRefreshClient from JavaScript object, caching both the
* object used to instantiate and the client.
* @param json The input object.
* @param options The JWT or UserRefresh options for the client
* @returns JWT or UserRefresh Client with data
*/
_cacheClientFromJSON(json, options) {
let client;
// create either a UserRefreshClient or JWT client.
options = options || {};
if (json.type === 'authorized_user') {
client = new refreshclient_1.UserRefreshClient(options);
}
else {
options.scopes = this.scopes;
client = new jwtclient_1.JWT(options);
}
client.fromJSON(json);
// cache both raw data used to instantiate client and client itself.
this.jsonContent = json;
this.cachedCredential = client;
return this.cachedCredential;
}
fromStream(inputStream, optionsOrCallback = {}, callback) {
let options = {};
if (typeof optionsOrCallback === 'function') {
callback = optionsOrCallback;
}
else {
options = optionsOrCallback;
}
if (callback) {
this.fromStreamAsync(inputStream, options).then(r => callback(null, r), callback);
}
else {
return this.fromStreamAsync(inputStream, options);
}
}
fromStreamAsync(inputStream, options) {
return new Promise((resolve, reject) => {
if (!inputStream) {
throw new Error('Must pass in a stream containing the Google auth settings.');
}
let s = '';
inputStream
.setEncoding('utf8')
.on('error', reject)
.on('data', chunk => (s += chunk))
.on('end', () => {
try {
const data = JSON.parse(s);
const r = this._cacheClientFromJSON(data, options);
return resolve(r);
}
catch (err) {
return reject(err);
}
});
});
}
/**
* Create a credentials instance using the given API key string.
* @param apiKey The API key string
* @param options An optional options object.
* @returns A JWT loaded from the key
*/
fromAPIKey(apiKey, options) {
options = options || {};
const client = new jwtclient_1.JWT(options);
client.fromAPIKey(apiKey);
return client;
}
/**
* Determines whether the current operating system is Windows.
* @api private
*/
_isWindows() {
const sys = os.platform();
if (sys && sys.length >= 3) {
if (sys.substring(0, 3).toLowerCase() === 'win') {
return true;
}
}
return false;
}
/**
* Run the Google Cloud SDK command that prints the default project ID
*/
async getDefaultServiceProjectId() {
return new Promise(resolve => {
child_process_1.exec('gcloud config config-helper --format json', (err, stdout, stderr) => {
if (!err && stdout) {
try {
const projectId = JSON.parse(stdout).configuration.properties.core
.project;
resolve(projectId);
return;
}
catch (e) {
// ignore errors
}
}
resolve(null);
});
});
}
/**
* Loads the project id from environment variables.
* @api private
*/
getProductionProjectId() {
return (process.env['GCLOUD_PROJECT'] ||
process.env['GOOGLE_CLOUD_PROJECT'] ||
process.env['gcloud_project'] ||
process.env['google_cloud_project']);
}
/**
* Loads the project id from the GOOGLE_APPLICATION_CREDENTIALS json file.
* @api private
*/
async getFileProjectId() {
if (this.cachedCredential) {
// Try to read the project ID from the cached credentials file
return this.cachedCredential.projectId;
}
// Ensure the projectId is loaded from the keyFile if available.
if (this.keyFilename) {
const creds = await this.getClient();
if (creds && creds.projectId) {
return creds.projectId;
}
}
// Try to load a credentials file and read its project ID
const r = await this._tryGetApplicationCredentialsFromEnvironmentVariable();
if (r) {
return r.projectId;
}
else {
return null;
}
}
/**
* Gets the Compute Engine project ID if it can be inferred.
*/
async getGCEProjectId() {
try {
const r = await gcpMetadata.project('project-id');
return r;
}
catch (e) {
// Ignore any errors
return null;
}
}
getCredentials(callback) {
if (callback) {
this.getCredentialsAsync().then(r => callback(null, r), callback);
}
else {
return this.getCredentialsAsync();
}
}
async getCredentialsAsync() {
await this.getClient();
if (this.jsonContent) {
const credential = {
client_email: this.jsonContent.client_email,
private_key: this.jsonContent.private_key,
};
return credential;
}
const isGCE = await this._checkIsGCE();
if (!isGCE) {
throw new Error('Unknown error.');
}
// For GCE, return the service account details from the metadata server
// NOTE: The trailing '/' at the end of service-accounts/ is very important!
// The GCF metadata server doesn't respect querystring params if this / is
// not included.
const data = await gcpMetadata.instance({
property: 'service-accounts/',
params: { recursive: 'true' },
});
if (!data || !data.default || !data.default.email) {
throw new Error('Failure from metadata server.');
}
return { client_email: data.default.email };
}
/**
* Automatically obtain a client based on the provided configuration. If no
* options were passed, use Application Default Credentials.
*/
async getClient(options) {
if (options) {
throw new Error('Passing options to getClient is forbidden in v5.0.0. Use new GoogleAuth(opts) instead.');
}
if (!this.cachedCredential) {
if (this.jsonContent) {
this._cacheClientFromJSON(this.jsonContent, this.clientOptions);
}
else if (this.keyFilename) {
const filePath = path.resolve(this.keyFilename);
const stream = fs.createReadStream(filePath);
await this.fromStreamAsync(stream, this.clientOptions);
}
else {
await this.getApplicationDefaultAsync(this.clientOptions);
}
}
return this.cachedCredential;
}
/**
* Automatically obtain application default credentials, and return
* an access token for making requests.
*/
async getAccessToken() {
const client = await this.getClient();
return (await client.getAccessToken()).token;
}
/**
* Obtain the HTTP headers that will provide authorization for a given
* request.
*/
async getRequestHeaders(url) {
const client = await this.getClient();
return client.getRequestHeaders(url);
}
/**
* Obtain credentials for a request, then attach the appropriate headers to
* the request options.
* @param opts Axios or Request options on which to attach the headers
*/
async authorizeRequest(opts) {
opts = opts || {};
const url = opts.url || opts.uri;
const client = await this.getClient();
const headers = await client.getRequestHeaders(url);
opts.headers = Object.assign(opts.headers || {}, headers);
return opts;
}
/**
* Automatically obtain application default credentials, and make an
* HTTP request using the given options.
* @param opts Axios request options for the HTTP request.
*/
// tslint:disable-next-line no-any
async request(opts) {
const client = await this.getClient();
return client.request(opts);
}
/**
* Determine the compute environment in which the code is running.
*/
getEnv() {
return envDetect_1.getEnv();
}
/**
* Sign the given data with the current private key, or go out
* to the IAM API to sign it.
* @param data The data to be signed.
*/
async sign(data) {
const client = await this.getClient();
const crypto = crypto_1.createCrypto();
if (client instanceof jwtclient_1.JWT && client.key) {
const sign = await crypto.sign(client.key, data);
return sign;
}
const projectId = await this.getProjectId();
if (!projectId) {
throw new Error('Cannot sign data without a project ID.');
}
const creds = await this.getCredentials();
if (!creds.client_email) {
throw new Error('Cannot sign data without `client_email`.');
}
const id = `projects/${projectId}/serviceAccounts/${creds.client_email}`;
const res = await this.request({
method: 'POST',
url: `https://iam.googleapis.com/v1/${id}:signBlob`,
data: { bytesToSign: crypto.encodeBase64StringUtf8(data) },
});
return res.data.signature;
}
}
exports.GoogleAuth = GoogleAuth;
/**
* Export DefaultTransporter as a static property of the class.
*/
GoogleAuth.DefaultTransporter = transporters_1.DefaultTransporter;
//# sourceMappingURL=googleauth.js.map

View File

@@ -0,0 +1,53 @@
/**
* Copyright 2014 Google Inc. All Rights Reserved.
*
* 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.
*/
export interface RequestMetadata {
'x-goog-iam-authority-selector': string;
'x-goog-iam-authorization-token': string;
}
export declare class IAMAuth {
selector: string;
token: string;
/**
* IAM credentials.
*
* @param selector the iam authority selector
* @param token the token
* @constructor
*/
constructor(selector: string, token: string);
/**
* Indicates whether the credential requires scopes to be created by calling
* createdScoped before use.
* @deprecated
* @return always false
*/
createScopedRequired(): boolean;
/**
* Pass the selector and token to the metadataFn callback.
* @deprecated
* @param unused_uri is required of the credentials interface
* @param metadataFn a callback invoked with object containing request
* metadata.
*/
getRequestMetadata(unusedUri: string | null, metadataFn: (err: Error | null, metadata?: RequestMetadata) => void): void;
/**
* Acquire the HTTP headers required to make an authenticated request.
*/
getRequestHeaders(): {
'x-goog-iam-authority-selector': string;
'x-goog-iam-authorization-token': string;
};
}

66
node_modules/google-auth-library/build/src/auth/iam.js generated vendored Normal file
View File

@@ -0,0 +1,66 @@
"use strict";
/**
* Copyright 2014 Google Inc. All Rights Reserved.
*
* 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 });
const messages = require("../messages");
class IAMAuth {
/**
* IAM credentials.
*
* @param selector the iam authority selector
* @param token the token
* @constructor
*/
constructor(selector, token) {
this.selector = selector;
this.token = token;
this.selector = selector;
this.token = token;
}
/**
* Indicates whether the credential requires scopes to be created by calling
* createdScoped before use.
* @deprecated
* @return always false
*/
createScopedRequired() {
// IAM authorization does not use scopes.
messages.warn(messages.IAM_CREATE_SCOPED_DEPRECATED);
return false;
}
/**
* Pass the selector and token to the metadataFn callback.
* @deprecated
* @param unused_uri is required of the credentials interface
* @param metadataFn a callback invoked with object containing request
* metadata.
*/
getRequestMetadata(unusedUri, metadataFn) {
messages.warn(messages.IAM_GET_REQUEST_METADATA_DEPRECATED);
metadataFn(null, this.getRequestHeaders());
}
/**
* Acquire the HTTP headers required to make an authenticated request.
*/
getRequestHeaders() {
return {
'x-goog-iam-authority-selector': this.selector,
'x-goog-iam-authorization-token': this.token,
};
}
}
exports.IAMAuth = IAMAuth;
//# sourceMappingURL=iam.js.map

View File

@@ -0,0 +1,79 @@
/**
* Copyright 2015 Google Inc. All Rights Reserved.
*
* 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.
*/
/// <reference types="node" />
import * as stream from 'stream';
import { JWTInput } from './credentials';
import { Headers, RequestMetadataResponse } from './oauth2client';
export interface Claims {
[index: string]: string;
}
export declare class JWTAccess {
email?: string | null;
key?: string | null;
keyId?: string | null;
projectId?: string;
private cache;
/**
* JWTAccess service account credentials.
*
* Create a new access token by using the credential to create a new JWT token
* that's recognized as the access token.
*
* @param email the service account email address.
* @param key the private key that will be used to sign the token.
* @param keyId the ID of the private key used to sign the token.
*/
constructor(email?: string | null, key?: string | null, keyId?: string | null);
/**
* Indicates whether the credential requires scopes to be created by calling
* createdScoped before use.
* @deprecated
* @return always false
*/
createScopedRequired(): boolean;
/**
* Get a non-expired access token, after refreshing if necessary.
*
* @param authURI The URI being authorized.
* @param additionalClaims An object with a set of additional claims to
* include in the payload.
* @deprecated Please use `getRequestHeaders` instead.
* @returns An object that includes the authorization header.
*/
getRequestMetadata(url: string, additionalClaims?: Claims): RequestMetadataResponse;
/**
* Get a non-expired access token, after refreshing if necessary.
*
* @param url The URI being authorized.
* @param additionalClaims An object with a set of additional claims to
* include in the payload.
* @returns An object that includes the authorization header.
*/
getRequestHeaders(url: string, additionalClaims?: Claims): Headers;
/**
* Create a JWTAccess credentials instance using the given input options.
* @param json The input object.
*/
fromJSON(json: JWTInput): void;
/**
* Create a JWTAccess credentials instance using the given input stream.
* @param inputStream The input stream.
* @param callback Optional callback.
*/
fromStream(inputStream: stream.Readable): Promise<void>;
fromStream(inputStream: stream.Readable, callback: (err?: Error) => void): void;
private fromStreamAsync;
}

View File

@@ -0,0 +1,161 @@
"use strict";
/**
* Copyright 2015 Google Inc. All Rights Reserved.
*
* 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 });
const jws = require("jws");
const LRU = require("lru-cache");
const messages = require("../messages");
const DEFAULT_HEADER = {
alg: 'RS256',
typ: 'JWT',
};
class JWTAccess {
/**
* JWTAccess service account credentials.
*
* Create a new access token by using the credential to create a new JWT token
* that's recognized as the access token.
*
* @param email the service account email address.
* @param key the private key that will be used to sign the token.
* @param keyId the ID of the private key used to sign the token.
*/
constructor(email, key, keyId) {
this.cache = new LRU({ max: 500, maxAge: 60 * 60 * 1000 });
this.email = email;
this.key = key;
this.keyId = keyId;
}
/**
* Indicates whether the credential requires scopes to be created by calling
* createdScoped before use.
* @deprecated
* @return always false
*/
createScopedRequired() {
// JWT Header authentication does not use scopes.
messages.warn(messages.JWT_ACCESS_CREATE_SCOPED_DEPRECATED);
return false;
}
/**
* Get a non-expired access token, after refreshing if necessary.
*
* @param authURI The URI being authorized.
* @param additionalClaims An object with a set of additional claims to
* include in the payload.
* @deprecated Please use `getRequestHeaders` instead.
* @returns An object that includes the authorization header.
*/
getRequestMetadata(url, additionalClaims) {
messages.warn(messages.JWT_ACCESS_GET_REQUEST_METADATA_DEPRECATED);
return { headers: this.getRequestHeaders(url, additionalClaims) };
}
/**
* Get a non-expired access token, after refreshing if necessary.
*
* @param url The URI being authorized.
* @param additionalClaims An object with a set of additional claims to
* include in the payload.
* @returns An object that includes the authorization header.
*/
getRequestHeaders(url, additionalClaims) {
const cachedToken = this.cache.get(url);
if (cachedToken) {
return cachedToken;
}
const iat = Math.floor(new Date().getTime() / 1000);
const exp = iat + 3600; // 3600 seconds = 1 hour
// The payload used for signed JWT headers has:
// iss == sub == <client email>
// aud == <the authorization uri>
const defaultClaims = {
iss: this.email,
sub: this.email,
aud: url,
exp,
iat,
};
// if additionalClaims are provided, ensure they do not collide with
// other required claims.
if (additionalClaims) {
for (const claim in defaultClaims) {
if (additionalClaims[claim]) {
throw new Error(`The '${claim}' property is not allowed when passing additionalClaims. This claim is included in the JWT by default.`);
}
}
}
const header = this.keyId
? Object.assign(Object.assign({}, DEFAULT_HEADER), { kid: this.keyId }) : DEFAULT_HEADER;
const payload = Object.assign(defaultClaims, additionalClaims);
// Sign the jwt and add it to the cache
const signedJWT = jws.sign({ header, payload, secret: this.key });
const headers = { Authorization: `Bearer ${signedJWT}` };
this.cache.set(url, headers);
return headers;
}
/**
* Create a JWTAccess credentials instance using the given input options.
* @param json The input object.
*/
fromJSON(json) {
if (!json) {
throw new Error('Must pass in a JSON object containing the service account auth settings.');
}
if (!json.client_email) {
throw new Error('The incoming JSON object does not contain a client_email field');
}
if (!json.private_key) {
throw new Error('The incoming JSON object does not contain a private_key field');
}
// Extract the relevant information from the json key file.
this.email = json.client_email;
this.key = json.private_key;
this.keyId = json.private_key_id;
this.projectId = json.project_id;
}
fromStream(inputStream, callback) {
if (callback) {
this.fromStreamAsync(inputStream).then(r => callback(), callback);
}
else {
return this.fromStreamAsync(inputStream);
}
}
fromStreamAsync(inputStream) {
return new Promise((resolve, reject) => {
if (!inputStream) {
reject(new Error('Must pass in a stream containing the service account auth settings.'));
}
let s = '';
inputStream
.setEncoding('utf8')
.on('data', chunk => (s += chunk))
.on('error', reject)
.on('end', () => {
try {
const data = JSON.parse(s);
this.fromJSON(data);
resolve();
}
catch (err) {
reject(err);
}
});
});
}
}
exports.JWTAccess = JWTAccess;
//# sourceMappingURL=jwtaccess.js.map

View File

@@ -0,0 +1,119 @@
/**
* Copyright 2013 Google Inc. All Rights Reserved.
*
* 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.
*/
/// <reference types="node" />
import { GoogleToken } from 'gtoken';
import * as stream from 'stream';
import { CredentialBody, Credentials, JWTInput } from './credentials';
import { GetTokenResponse, OAuth2Client, RefreshOptions, RequestMetadataResponse } from './oauth2client';
export interface JWTOptions extends RefreshOptions {
email?: string;
keyFile?: string;
key?: string;
keyId?: string;
scopes?: string | string[];
subject?: string;
additionalClaims?: {};
}
export declare class JWT extends OAuth2Client {
email?: string;
keyFile?: string;
key?: string;
keyId?: string;
scopes?: string | string[];
scope?: string;
subject?: string;
gtoken?: GoogleToken;
additionalClaims?: {};
private access?;
/**
* JWT service account credentials.
*
* Retrieve access token using gtoken.
*
* @param email service account email address.
* @param keyFile path to private key file.
* @param key value of key
* @param scopes list of requested scopes or a single scope.
* @param subject impersonated account's email address.
* @param key_id the ID of the key
*/
constructor(options: JWTOptions);
constructor(email?: string, keyFile?: string, key?: string, scopes?: string | string[], subject?: string, keyId?: string);
/**
* Creates a copy of the credential with the specified scopes.
* @param scopes List of requested scopes or a single scope.
* @return The cloned instance.
*/
createScoped(scopes?: string | string[]): JWT;
/**
* Obtains the metadata to be sent with the request.
*
* @param url the URI being authorized.
*/
protected getRequestMetadataAsync(url?: string | null): Promise<RequestMetadataResponse>;
/**
* Indicates whether the credential requires scopes to be created by calling
* createScoped before use.
* @deprecated
* @return false if createScoped does not need to be called.
*/
createScopedRequired(): boolean;
/**
* Determine if there are currently scopes available.
*/
private hasScopes;
/**
* Get the initial access token using gToken.
* @param callback Optional callback.
* @returns Promise that resolves with credentials
*/
authorize(): Promise<Credentials>;
authorize(callback: (err: Error | null, result?: Credentials) => void): void;
private authorizeAsync;
/**
* Refreshes the access token.
* @param refreshToken ignored
* @private
*/
protected refreshTokenNoCache(refreshToken?: string | null): Promise<GetTokenResponse>;
/**
* Create a gToken if it doesn't already exist.
*/
private createGToken;
/**
* Create a JWT credentials instance using the given input options.
* @param json The input object.
*/
fromJSON(json: JWTInput): void;
/**
* Create a JWT credentials instance using the given input stream.
* @param inputStream The input stream.
* @param callback Optional callback.
*/
fromStream(inputStream: stream.Readable): Promise<void>;
fromStream(inputStream: stream.Readable, callback: (err?: Error | null) => void): void;
private fromStreamAsync;
/**
* Creates a JWT credentials instance using an API Key for authentication.
* @param apiKey The API Key in string form.
*/
fromAPIKey(apiKey: string): void;
/**
* Using the key or keyFile on the JWT client, obtain an object that contains
* the key and the client email.
*/
getCredentials(): Promise<CredentialBody>;
}

View File

@@ -0,0 +1,237 @@
"use strict";
/**
* Copyright 2013 Google Inc. All Rights Reserved.
*
* 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 });
const gtoken_1 = require("gtoken");
const messages = require("../messages");
const jwtaccess_1 = require("./jwtaccess");
const oauth2client_1 = require("./oauth2client");
class JWT extends oauth2client_1.OAuth2Client {
constructor(optionsOrEmail, keyFile, key, scopes, subject, keyId) {
const opts = optionsOrEmail && typeof optionsOrEmail === 'object'
? optionsOrEmail
: { email: optionsOrEmail, keyFile, key, keyId, scopes, subject };
super({
eagerRefreshThresholdMillis: opts.eagerRefreshThresholdMillis,
forceRefreshOnFailure: opts.forceRefreshOnFailure,
});
this.email = opts.email;
this.keyFile = opts.keyFile;
this.key = opts.key;
this.keyId = opts.keyId;
this.scopes = opts.scopes;
this.subject = opts.subject;
this.additionalClaims = opts.additionalClaims;
this.credentials = { refresh_token: 'jwt-placeholder', expiry_date: 1 };
}
/**
* Creates a copy of the credential with the specified scopes.
* @param scopes List of requested scopes or a single scope.
* @return The cloned instance.
*/
createScoped(scopes) {
return new JWT({
email: this.email,
keyFile: this.keyFile,
key: this.key,
keyId: this.keyId,
scopes,
subject: this.subject,
additionalClaims: this.additionalClaims,
});
}
/**
* Obtains the metadata to be sent with the request.
*
* @param url the URI being authorized.
*/
async getRequestMetadataAsync(url) {
if (!this.apiKey && !this.hasScopes() && url) {
if (this.additionalClaims &&
this.additionalClaims.target_audience) {
const { tokens } = await this.refreshToken();
return { headers: { Authorization: `Bearer ${tokens.id_token}` } };
}
else {
// no scopes have been set, but a uri has been provided. Use JWTAccess
// credentials.
if (!this.access) {
this.access = new jwtaccess_1.JWTAccess(this.email, this.key, this.keyId);
}
const headers = await this.access.getRequestHeaders(url, this.additionalClaims);
return { headers };
}
}
else {
return super.getRequestMetadataAsync(url);
}
}
/**
* Indicates whether the credential requires scopes to be created by calling
* createScoped before use.
* @deprecated
* @return false if createScoped does not need to be called.
*/
createScopedRequired() {
messages.warn(messages.JWT_CREATE_SCOPED_DEPRECATED);
return !this.hasScopes();
}
/**
* Determine if there are currently scopes available.
*/
hasScopes() {
if (!this.scopes) {
return false;
}
// For arrays, check the array length.
if (this.scopes instanceof Array) {
return this.scopes.length > 0;
}
// For others, convert to a string and check the length.
return String(this.scopes).length > 0;
}
authorize(callback) {
if (callback) {
this.authorizeAsync().then(r => callback(null, r), callback);
}
else {
return this.authorizeAsync();
}
}
async authorizeAsync() {
const result = await this.refreshToken();
if (!result) {
throw new Error('No result returned');
}
this.credentials = result.tokens;
this.credentials.refresh_token = 'jwt-placeholder';
this.key = this.gtoken.key;
this.email = this.gtoken.iss;
return result.tokens;
}
/**
* Refreshes the access token.
* @param refreshToken ignored
* @private
*/
async refreshTokenNoCache(refreshToken) {
const gtoken = this.createGToken();
const token = await gtoken.getToken({
forceRefresh: this.isTokenExpiring(),
});
const tokens = {
access_token: token.access_token,
token_type: 'Bearer',
expiry_date: gtoken.expiresAt,
id_token: gtoken.idToken,
};
this.emit('tokens', tokens);
return { res: null, tokens };
}
/**
* Create a gToken if it doesn't already exist.
*/
createGToken() {
if (!this.gtoken) {
this.gtoken = new gtoken_1.GoogleToken({
iss: this.email,
sub: this.subject,
scope: this.scopes,
keyFile: this.keyFile,
key: this.key,
additionalClaims: this.additionalClaims,
});
}
return this.gtoken;
}
/**
* Create a JWT credentials instance using the given input options.
* @param json The input object.
*/
fromJSON(json) {
if (!json) {
throw new Error('Must pass in a JSON object containing the service account auth settings.');
}
if (!json.client_email) {
throw new Error('The incoming JSON object does not contain a client_email field');
}
if (!json.private_key) {
throw new Error('The incoming JSON object does not contain a private_key field');
}
// Extract the relevant information from the json key file.
this.email = json.client_email;
this.key = json.private_key;
this.keyId = json.private_key_id;
this.projectId = json.project_id;
}
fromStream(inputStream, callback) {
if (callback) {
this.fromStreamAsync(inputStream).then(r => callback(), callback);
}
else {
return this.fromStreamAsync(inputStream);
}
}
fromStreamAsync(inputStream) {
return new Promise((resolve, reject) => {
if (!inputStream) {
throw new Error('Must pass in a stream containing the service account auth settings.');
}
let s = '';
inputStream
.setEncoding('utf8')
.on('error', reject)
.on('data', chunk => (s += chunk))
.on('end', () => {
try {
const data = JSON.parse(s);
this.fromJSON(data);
resolve();
}
catch (e) {
reject(e);
}
});
});
}
/**
* Creates a JWT credentials instance using an API Key for authentication.
* @param apiKey The API Key in string form.
*/
fromAPIKey(apiKey) {
if (typeof apiKey !== 'string') {
throw new Error('Must provide an API Key string.');
}
this.apiKey = apiKey;
}
/**
* Using the key or keyFile on the JWT client, obtain an object that contains
* the key and the client email.
*/
async getCredentials() {
if (this.key) {
return { private_key: this.key, client_email: this.email };
}
else if (this.keyFile) {
const gtoken = this.createGToken();
const creds = await gtoken.getCredentials(this.keyFile);
return { private_key: creds.privateKey, client_email: creds.clientEmail };
}
throw new Error('A key or a keyFile must be provided to getCredentials.');
}
}
exports.JWT = JWT;
//# sourceMappingURL=jwtclient.js.map

View File

@@ -0,0 +1,150 @@
/**
* Copyright 2014 Google Inc. All Rights Reserved.
*
* 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.
*/
export declare class LoginTicket {
private envelope?;
private payload?;
/**
* Create a simple class to extract user ID from an ID Token
*
* @param {string} env Envelope of the jwt
* @param {TokenPayload} pay Payload of the jwt
* @constructor
*/
constructor(env?: string, pay?: TokenPayload);
getEnvelope(): string | undefined;
getPayload(): TokenPayload | undefined;
/**
* Create a simple class to extract user ID from an ID Token
*
* @return The user ID
*/
getUserId(): string | null;
/**
* Returns attributes from the login ticket. This can contain
* various information about the user session.
*
* @return The envelope and payload
*/
getAttributes(): {
envelope: string | undefined;
payload: TokenPayload | undefined;
};
}
export interface TokenPayload {
/**
* The Issuer Identifier for the Issuer of the response. Always
* https://accounts.google.com or accounts.google.com for Google ID tokens.
*/
iss: string;
/**
* Access token hash. Provides validation that the access token is tied to the
* identity token. If the ID token is issued with an access token in the
* server flow, this is always included. This can be used as an alternate
* mechanism to protect against cross-site request forgery attacks, but if you
* follow Step 1 and Step 3 it is not necessary to verify the access token.
*/
at_hash?: string;
/**
* True if the user's e-mail address has been verified; otherwise false.
*/
email_verified?: boolean;
/**
* An identifier for the user, unique among all Google accounts and never
* reused. A Google account can have multiple emails at different points in
* time, but the sub value is never changed. Use sub within your application
* as the unique-identifier key for the user.
*/
sub: string;
/**
* The client_id of the authorized presenter. This claim is only needed when
* the party requesting the ID token is not the same as the audience of the ID
* token. This may be the case at Google for hybrid apps where a web
* application and Android app have a different client_id but share the same
* project.
*/
azp?: string;
/**
* The user's email address. This may not be unique and is not suitable for
* use as a primary key. Provided only if your scope included the string
* "email".
*/
email?: string;
/**
* The URL of the user's profile page. Might be provided when:
* - The request scope included the string "profile"
* - The ID token is returned from a token refresh
* - When profile claims are present, you can use them to update your app's
* user records. Note that this claim is never guaranteed to be present.
*/
profile?: string;
/**
* The URL of the user's profile picture. Might be provided when:
* - The request scope included the string "profile"
* - The ID token is returned from a token refresh
* - When picture claims are present, you can use them to update your app's
* user records. Note that this claim is never guaranteed to be present.
*/
picture?: string;
/**
* The user's full name, in a displayable form. Might be provided when:
* - The request scope included the string "profile"
* - The ID token is returned from a token refresh
* - When name claims are present, you can use them to update your app's user
* records. Note that this claim is never guaranteed to be present.
*/
name?: string;
/**
* The user's given name, in a displayable form. Might be provided when:
* - The request scope included the string "profile"
* - The ID token is returned from a token refresh
* - When name claims are present, you can use them to update your app's user
* records. Note that this claim is never guaranteed to be present.
*/
given_name?: string;
/**
* The user's family name, in a displayable form. Might be provided when:
* - The request scope included the string "profile"
* - The ID token is returned from a token refresh
* - When name claims are present, you can use them to update your app's user
* records. Note that this claim is never guaranteed to be present.
*/
family_name?: string;
/**
* Identifies the audience that this ID token is intended for. It must be one
* of the OAuth 2.0 client IDs of your application.
*/
aud: string;
/**
* The time the ID token was issued, represented in Unix time (integer
* seconds).
*/
iat: number;
/**
* The time the ID token expires, represented in Unix time (integer seconds).
*/
exp: number;
/**
* The value of the nonce supplied by your app in the authentication request.
* You should enforce protection against replay attacks by ensuring it is
* presented only once.
*/
nonce?: string;
/**
* The hosted G Suite domain of the user. Provided only if the user belongs to
* a hosted domain.
*/
hd?: string;
}

View File

@@ -0,0 +1,59 @@
"use strict";
/**
* Copyright 2014 Google Inc. All Rights Reserved.
*
* 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 });
class LoginTicket {
/**
* Create a simple class to extract user ID from an ID Token
*
* @param {string} env Envelope of the jwt
* @param {TokenPayload} pay Payload of the jwt
* @constructor
*/
constructor(env, pay) {
this.envelope = env;
this.payload = pay;
}
getEnvelope() {
return this.envelope;
}
getPayload() {
return this.payload;
}
/**
* Create a simple class to extract user ID from an ID Token
*
* @return The user ID
*/
getUserId() {
const payload = this.getPayload();
if (payload && payload.sub) {
return payload.sub;
}
return null;
}
/**
* Returns attributes from the login ticket. This can contain
* various information about the user session.
*
* @return The envelope and payload
*/
getAttributes() {
return { envelope: this.getEnvelope(), payload: this.getPayload() };
}
}
exports.LoginTicket = LoginTicket;
//# sourceMappingURL=loginticket.js.map

View File

@@ -0,0 +1,476 @@
/**
* Copyright 2019 Google LLC. All Rights Reserved.
*
* 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.
*/
import { GaxiosError, GaxiosOptions, GaxiosPromise, GaxiosResponse } from 'gaxios';
import { JwkCertificate } from '../crypto/crypto';
import { BodyResponseCallback } from '../transporters';
import { AuthClient } from './authclient';
import { Credentials } from './credentials';
import { LoginTicket } from './loginticket';
export interface Certificates {
[index: string]: string | JwkCertificate;
}
export interface Headers {
[index: string]: string;
}
export declare enum CodeChallengeMethod {
Plain = "plain",
S256 = "S256"
}
export declare enum CertificateFormat {
PEM = "PEM",
JWK = "JWK"
}
export interface GetTokenOptions {
code: string;
codeVerifier?: string;
/**
* The client ID for your application. The value passed into the constructor
* will be used if not provided. Must match any client_id option passed to
* a corresponding call to generateAuthUrl.
*/
client_id?: string;
/**
* Determines where the API server redirects the user after the user
* completes the authorization flow. The value passed into the constructor
* will be used if not provided. Must match any redirect_uri option passed to
* a corresponding call to generateAuthUrl.
*/
redirect_uri?: string;
}
export interface TokenInfo {
/**
* The application that is the intended user of the access token.
*/
aud: string;
/**
* This value lets you correlate profile information from multiple Google
* APIs. It is only present in the response if you included the profile scope
* in your request in step 1. The field value is an immutable identifier for
* the logged-in user that can be used to create and manage user sessions in
* your application. The identifier is the same regardless of which client ID
* is used to retrieve it. This enables multiple applications in the same
* organization to correlate profile information.
*/
user_id?: string;
/**
* An array of scopes that the user granted access to.
*/
scopes: string[];
/**
* The datetime when the token becomes invalid.
*/
expiry_date: number;
/**
* An identifier for the user, unique among all Google accounts and never
* reused. A Google account can have multiple emails at different points in
* time, but the sub value is never changed. Use sub within your application
* as the unique-identifier key for the user.
*/
sub?: string;
/**
* The client_id of the authorized presenter. This claim is only needed when
* the party requesting the ID token is not the same as the audience of the ID
* token. This may be the case at Google for hybrid apps where a web
* application and Android app have a different client_id but share the same
* project.
*/
azp?: string;
/**
* Indicates whether your application can refresh access tokens
* when the user is not present at the browser. Valid parameter values are
* 'online', which is the default value, and 'offline'. Set the value to
* 'offline' if your application needs to refresh access tokens when the user
* is not present at the browser. This value instructs the Google
* authorization server to return a refresh token and an access token the
* first time that your application exchanges an authorization code for
* tokens.
*/
access_type?: string;
}
export interface GenerateAuthUrlOpts {
/**
* Recommended. Indicates whether your application can refresh access tokens
* when the user is not present at the browser. Valid parameter values are
* 'online', which is the default value, and 'offline'. Set the value to
* 'offline' if your application needs to refresh access tokens when the user
* is not present at the browser. This value instructs the Google
* authorization server to return a refresh token and an access token the
* first time that your application exchanges an authorization code for
* tokens.
*/
access_type?: string;
/**
* The hd (hosted domain) parameter streamlines the login process for G Suite
* hosted accounts. By including the domain of the G Suite user (for example,
* mycollege.edu), you can indicate that the account selection UI should be
* optimized for accounts at that domain. To optimize for G Suite accounts
* generally instead of just one domain, use an asterisk: hd=*.
* Don't rely on this UI optimization to control who can access your app,
* as client-side requests can be modified. Be sure to validate that the
* returned ID token has an hd claim value that matches what you expect
* (e.g. mycolledge.edu). Unlike the request parameter, the ID token claim is
* contained within a security token from Google, so the value can be trusted.
*/
hd?: string;
/**
* The 'response_type' will always be set to 'CODE'.
*/
response_type?: string;
/**
* The client ID for your application. The value passed into the constructor
* will be used if not provided. You can find this value in the API Console.
*/
client_id?: string;
/**
* Determines where the API server redirects the user after the user
* completes the authorization flow. The value must exactly match one of the
* 'redirect_uri' values listed for your project in the API Console. Note that
* the http or https scheme, case, and trailing slash ('/') must all match.
* The value passed into the constructor will be used if not provided.
*/
redirect_uri?: string;
/**
* Required. A space-delimited list of scopes that identify the resources that
* your application could access on the user's behalf. These values inform the
* consent screen that Google displays to the user. Scopes enable your
* application to only request access to the resources that it needs while
* also enabling users to control the amount of access that they grant to your
* application. Thus, there is an inverse relationship between the number of
* scopes requested and the likelihood of obtaining user consent. The
* OAuth 2.0 API Scopes document provides a full list of scopes that you might
* use to access Google APIs. We recommend that your application request
* access to authorization scopes in context whenever possible. By requesting
* access to user data in context, via incremental authorization, you help
* users to more easily understand why your application needs the access it is
* requesting.
*/
scope?: string[] | string;
/**
* Recommended. Specifies any string value that your application uses to
* maintain state between your authorization request and the authorization
* server's response. The server returns the exact value that you send as a
* name=value pair in the hash (#) fragment of the 'redirect_uri' after the
* user consents to or denies your application's access request. You can use
* this parameter for several purposes, such as directing the user to the
* correct resource in your application, sending nonces, and mitigating
* cross-site request forgery. Since your redirect_uri can be guessed, using a
* state value can increase your assurance that an incoming connection is the
* result of an authentication request. If you generate a random string or
* encode the hash of a cookie or another value that captures the client's
* state, you can validate the response to additionally ensure that the
* request and response originated in the same browser, providing protection
* against attacks such as cross-site request forgery. See the OpenID Connect
* documentation for an example of how to create and confirm a state token.
*/
state?: string;
/**
* Optional. Enables applications to use incremental authorization to request
* access to additional scopes in context. If you set this parameter's value
* to true and the authorization request is granted, then the new access token
* will also cover any scopes to which the user previously granted the
* application access. See the incremental authorization section for examples.
*/
include_granted_scopes?: boolean;
/**
* Optional. If your application knows which user is trying to authenticate,
* it can use this parameter to provide a hint to the Google Authentication
* Server. The server uses the hint to simplify the login flow either by
* prefilling the email field in the sign-in form or by selecting the
* appropriate multi-login session. Set the parameter value to an email
* address or sub identifier, which is equivalent to the user's Google ID.
*/
login_hint?: string;
/**
* Optional. A space-delimited, case-sensitive list of prompts to present the
* user. If you don't specify this parameter, the user will be prompted only
* the first time your app requests access. Possible values are:
*
* 'none' - Donot display any authentication or consent screens. Must not be
* specified with other values.
* 'consent' - Prompt the user for consent.
* 'select_account' - Prompt the user to select an account.
*/
prompt?: string;
/**
* Recommended. Specifies what method was used to encode a 'code_verifier'
* that will be used during authorization code exchange. This parameter must
* be used with the 'code_challenge' parameter. The value of the
* 'code_challenge_method' defaults to "plain" if not present in the request
* that includes a 'code_challenge'. The only supported values for this
* parameter are "S256" or "plain".
*/
code_challenge_method?: CodeChallengeMethod;
/**
* Recommended. Specifies an encoded 'code_verifier' that will be used as a
* server-side challenge during authorization code exchange. This parameter
* must be used with the 'code_challenge' parameter described above.
*/
code_challenge?: string;
}
export interface GetTokenCallback {
(err: GaxiosError | null, token?: Credentials | null, res?: GaxiosResponse | null): void;
}
export interface GetTokenResponse {
tokens: Credentials;
res: GaxiosResponse | null;
}
export interface GetAccessTokenCallback {
(err: GaxiosError | null, token?: string | null, res?: GaxiosResponse | null): void;
}
export interface GetAccessTokenResponse {
token?: string | null;
res?: GaxiosResponse | null;
}
export interface RefreshAccessTokenCallback {
(err: GaxiosError | null, credentials?: Credentials | null, res?: GaxiosResponse | null): void;
}
export interface RefreshAccessTokenResponse {
credentials: Credentials;
res: GaxiosResponse | null;
}
export interface RequestMetadataResponse {
headers: Headers;
res?: GaxiosResponse<void> | null;
}
export interface RequestMetadataCallback {
(err: GaxiosError | null, headers?: Headers, res?: GaxiosResponse<void> | null): void;
}
export interface GetFederatedSignonCertsCallback {
(err: GaxiosError | null, certs?: Certificates, response?: GaxiosResponse<void> | null): void;
}
export interface FederatedSignonCertsResponse {
certs: Certificates;
format: CertificateFormat;
res?: GaxiosResponse<void> | null;
}
export interface RevokeCredentialsResult {
success: boolean;
}
export interface VerifyIdTokenOptions {
idToken: string;
audience: string | string[];
maxExpiry?: number;
}
export interface OAuth2ClientOptions extends RefreshOptions {
clientId?: string;
clientSecret?: string;
redirectUri?: string;
}
export interface RefreshOptions {
eagerRefreshThresholdMillis?: number;
forceRefreshOnFailure?: boolean;
}
export declare class OAuth2Client extends AuthClient {
private redirectUri?;
private certificateCache;
private certificateExpiry;
private certificateCacheFormat;
protected refreshTokenPromises: Map<string, Promise<GetTokenResponse>>;
_clientId?: string;
_clientSecret?: string;
apiKey?: string;
projectId?: string;
eagerRefreshThresholdMillis: number;
forceRefreshOnFailure: boolean;
/**
* Handles OAuth2 flow for Google APIs.
*
* @param clientId The authentication client ID.
* @param clientSecret The authentication client secret.
* @param redirectUri The URI to redirect to after completing the auth
* request.
* @param opts optional options for overriding the given parameters.
* @constructor
*/
constructor(options?: OAuth2ClientOptions);
constructor(clientId?: string, clientSecret?: string, redirectUri?: string);
protected static readonly GOOGLE_TOKEN_INFO_URL = "https://oauth2.googleapis.com/tokeninfo";
/**
* The base URL for auth endpoints.
*/
private static readonly GOOGLE_OAUTH2_AUTH_BASE_URL_;
/**
* The base endpoint for token retrieval.
*/
private static readonly GOOGLE_OAUTH2_TOKEN_URL_;
/**
* The base endpoint to revoke tokens.
*/
private static readonly GOOGLE_OAUTH2_REVOKE_URL_;
/**
* Google Sign on certificates in PEM format.
*/
private static readonly GOOGLE_OAUTH2_FEDERATED_SIGNON_PEM_CERTS_URL_;
/**
* Google Sign on certificates in JWK format.
*/
private static readonly GOOGLE_OAUTH2_FEDERATED_SIGNON_JWK_CERTS_URL_;
/**
* Clock skew - five minutes in seconds
*/
private static readonly CLOCK_SKEW_SECS_;
/**
* Max Token Lifetime is one day in seconds
*/
private static readonly MAX_TOKEN_LIFETIME_SECS_;
/**
* The allowed oauth token issuers.
*/
private static readonly ISSUERS_;
/**
* Generates URL for consent page landing.
* @param opts Options.
* @return URL to consent page.
*/
generateAuthUrl(opts?: GenerateAuthUrlOpts): string;
generateCodeVerifier(): void;
/**
* Convenience method to automatically generate a code_verifier, and it's
* resulting SHA256. If used, this must be paired with a S256
* code_challenge_method.
*/
generateCodeVerifierAsync(): Promise<{
codeVerifier: string;
codeChallenge: string;
}>;
/**
* Gets the access token for the given code.
* @param code The authorization code.
* @param callback Optional callback fn.
*/
getToken(code: string): Promise<GetTokenResponse>;
getToken(options: GetTokenOptions): Promise<GetTokenResponse>;
getToken(code: string, callback: GetTokenCallback): void;
getToken(options: GetTokenOptions, callback: GetTokenCallback): void;
private getTokenAsync;
/**
* Refreshes the access token.
* @param refresh_token Existing refresh token.
* @private
*/
protected refreshToken(refreshToken?: string | null): Promise<GetTokenResponse>;
protected refreshTokenNoCache(refreshToken?: string | null): Promise<GetTokenResponse>;
/**
* Retrieves the access token using refresh token
*
* @deprecated use getRequestHeaders instead.
* @param callback callback
*/
refreshAccessToken(): Promise<RefreshAccessTokenResponse>;
refreshAccessToken(callback: RefreshAccessTokenCallback): void;
private refreshAccessTokenAsync;
/**
* Get a non-expired access token, after refreshing if necessary
*
* @param callback Callback to call with the access token
*/
getAccessToken(): Promise<GetAccessTokenResponse>;
getAccessToken(callback: GetAccessTokenCallback): void;
private getAccessTokenAsync;
/**
* Obtain the set of headers required to authenticate a request.
*
* @deprecated Use getRequestHeaders instead.
* @param url the Uri being authorized
* @param callback the func described above
*/
getRequestMetadata(url?: string | null): Promise<RequestMetadataResponse>;
getRequestMetadata(url: string | null, callback: RequestMetadataCallback): void;
/**
* The main authentication interface. It takes an optional url which when
* present is the endpoint being accessed, and returns a Promise which
* resolves with authorization header fields.
*
* In OAuth2Client, the result has the form:
* { Authorization: 'Bearer <access_token_value>' }
* @param url The optional url being authorized
*/
getRequestHeaders(url?: string): Promise<Headers>;
protected getRequestMetadataAsync(url?: string | null): Promise<RequestMetadataResponse>;
/**
* Generates an URL to revoke the given token.
* @param token The existing token to be revoked.
*/
static getRevokeTokenUrl(token: string): string;
/**
* Revokes the access given to token.
* @param token The existing token to be revoked.
* @param callback Optional callback fn.
*/
revokeToken(token: string): GaxiosPromise<RevokeCredentialsResult>;
revokeToken(token: string, callback: BodyResponseCallback<RevokeCredentialsResult>): void;
/**
* Revokes access token and clears the credentials object
* @param callback callback
*/
revokeCredentials(): GaxiosPromise<RevokeCredentialsResult>;
revokeCredentials(callback: BodyResponseCallback<RevokeCredentialsResult>): void;
private revokeCredentialsAsync;
/**
* Provides a request implementation with OAuth 2.0 flow. If credentials have
* a refresh_token, in cases of HTTP 401 and 403 responses, it automatically
* asks for a new access token and replays the unsuccessful request.
* @param opts Request options.
* @param callback callback.
* @return Request object
*/
request<T>(opts: GaxiosOptions): GaxiosPromise<T>;
request<T>(opts: GaxiosOptions, callback: BodyResponseCallback<T>): void;
protected requestAsync<T>(opts: GaxiosOptions, retry?: boolean): Promise<GaxiosResponse<T>>;
/**
* Verify id token is token by checking the certs and audience
* @param options that contains all options.
* @param callback Callback supplying GoogleLogin if successful
*/
verifyIdToken(options: VerifyIdTokenOptions): Promise<LoginTicket>;
verifyIdToken(options: VerifyIdTokenOptions, callback: (err: Error | null, login?: LoginTicket) => void): void;
private verifyIdTokenAsync;
/**
* Obtains information about the provisioned access token. Especially useful
* if you want to check the scopes that were provisioned to a given token.
*
* @param accessToken Required. The Access Token for which you want to get
* user info.
*/
getTokenInfo(accessToken: string): Promise<TokenInfo>;
/**
* Gets federated sign-on certificates to use for verifying identity tokens.
* Returns certs as array structure, where keys are key ids, and values
* are certificates in either PEM or JWK format.
* @param callback Callback supplying the certificates
*/
getFederatedSignonCerts(): Promise<FederatedSignonCertsResponse>;
getFederatedSignonCerts(callback: GetFederatedSignonCertsCallback): void;
getFederatedSignonCertsAsync(): Promise<FederatedSignonCertsResponse>;
verifySignedJwtWithCerts(): void;
/**
* Verify the id token is signed with the correct certificate
* and is from the correct audience.
* @param jwt The jwt to verify (The ID Token in this case).
* @param certs The array of certs to test the jwt against.
* @param requiredAudience The audience to test the jwt against.
* @param issuers The allowed issuers of the jwt (Optional).
* @param maxExpiry The max expiry the certificate can be (Optional).
* @return Returns a promise resolving to LoginTicket on verification.
*/
verifySignedJwtWithCertsAsync(jwt: string, certs: Certificates, requiredAudience: string | string[], issuers?: string[], maxExpiry?: number): Promise<LoginTicket>;
/**
* Returns true if a token is expired or will expire within
* eagerRefreshThresholdMillismilliseconds.
* If there is no expiry time, assumes the token is not expired or expiring.
*/
protected isTokenExpiring(): boolean;
}

View File

@@ -0,0 +1,652 @@
"use strict";
/**
* Copyright 2019 Google LLC. All Rights Reserved.
*
* 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 });
const querystring = require("querystring");
const stream = require("stream");
const crypto_1 = require("../crypto/crypto");
const messages = require("../messages");
const authclient_1 = require("./authclient");
const loginticket_1 = require("./loginticket");
var CodeChallengeMethod;
(function (CodeChallengeMethod) {
CodeChallengeMethod["Plain"] = "plain";
CodeChallengeMethod["S256"] = "S256";
})(CodeChallengeMethod = exports.CodeChallengeMethod || (exports.CodeChallengeMethod = {}));
var CertificateFormat;
(function (CertificateFormat) {
CertificateFormat["PEM"] = "PEM";
CertificateFormat["JWK"] = "JWK";
})(CertificateFormat = exports.CertificateFormat || (exports.CertificateFormat = {}));
class OAuth2Client extends authclient_1.AuthClient {
constructor(optionsOrClientId, clientSecret, redirectUri) {
super();
this.certificateCache = {};
this.certificateExpiry = null;
this.certificateCacheFormat = CertificateFormat.PEM;
this.refreshTokenPromises = new Map();
const opts = optionsOrClientId && typeof optionsOrClientId === 'object'
? optionsOrClientId
: { clientId: optionsOrClientId, clientSecret, redirectUri };
this._clientId = opts.clientId;
this._clientSecret = opts.clientSecret;
this.redirectUri = opts.redirectUri;
this.eagerRefreshThresholdMillis =
opts.eagerRefreshThresholdMillis || 5 * 60 * 1000;
this.forceRefreshOnFailure = !!opts.forceRefreshOnFailure;
}
/**
* Generates URL for consent page landing.
* @param opts Options.
* @return URL to consent page.
*/
generateAuthUrl(opts = {}) {
if (opts.code_challenge_method && !opts.code_challenge) {
throw new Error('If a code_challenge_method is provided, code_challenge must be included.');
}
opts.response_type = opts.response_type || 'code';
opts.client_id = opts.client_id || this._clientId;
opts.redirect_uri = opts.redirect_uri || this.redirectUri;
// Allow scopes to be passed either as array or a string
if (opts.scope instanceof Array) {
opts.scope = opts.scope.join(' ');
}
const rootUrl = OAuth2Client.GOOGLE_OAUTH2_AUTH_BASE_URL_;
return rootUrl + '?' + querystring.stringify(opts);
}
generateCodeVerifier() {
// To make the code compatible with browser SubtleCrypto we need to make
// this method async.
throw new Error('generateCodeVerifier is removed, please use generateCodeVerifierAsync instead.');
}
/**
* Convenience method to automatically generate a code_verifier, and it's
* resulting SHA256. If used, this must be paired with a S256
* code_challenge_method.
*/
async generateCodeVerifierAsync() {
// base64 encoding uses 6 bits per character, and we want to generate128
// characters. 6*128/8 = 96.
const crypto = crypto_1.createCrypto();
const randomString = crypto.randomBytesBase64(96);
// The valid characters in the code_verifier are [A-Z]/[a-z]/[0-9]/
// "-"/"."/"_"/"~". Base64 encoded strings are pretty close, so we're just
// swapping out a few chars.
const codeVerifier = randomString
.replace(/\+/g, '~')
.replace(/=/g, '_')
.replace(/\//g, '-');
// Generate the base64 encoded SHA256
const unencodedCodeChallenge = await crypto.sha256DigestBase64(codeVerifier);
// We need to use base64UrlEncoding instead of standard base64
const codeChallenge = unencodedCodeChallenge
.split('=')[0]
.replace(/\+/g, '-')
.replace(/\//g, '_');
return { codeVerifier, codeChallenge };
}
getToken(codeOrOptions, callback) {
const options = typeof codeOrOptions === 'string' ? { code: codeOrOptions } : codeOrOptions;
if (callback) {
this.getTokenAsync(options).then(r => callback(null, r.tokens, r.res), e => callback(e, null, e.response));
}
else {
return this.getTokenAsync(options);
}
}
async getTokenAsync(options) {
const url = OAuth2Client.GOOGLE_OAUTH2_TOKEN_URL_;
const values = {
code: options.code,
client_id: options.client_id || this._clientId,
client_secret: this._clientSecret,
redirect_uri: options.redirect_uri || this.redirectUri,
grant_type: 'authorization_code',
code_verifier: options.codeVerifier,
};
const res = await this.transporter.request({
method: 'POST',
url,
data: querystring.stringify(values),
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
});
const tokens = res.data;
if (res.data && res.data.expires_in) {
tokens.expiry_date = new Date().getTime() + res.data.expires_in * 1000;
delete tokens.expires_in;
}
this.emit('tokens', tokens);
return { tokens, res };
}
/**
* Refreshes the access token.
* @param refresh_token Existing refresh token.
* @private
*/
async refreshToken(refreshToken) {
if (!refreshToken) {
return this.refreshTokenNoCache(refreshToken);
}
// If a request to refresh using the same token has started,
// return the same promise.
if (this.refreshTokenPromises.has(refreshToken)) {
return this.refreshTokenPromises.get(refreshToken);
}
const p = this.refreshTokenNoCache(refreshToken).then(r => {
this.refreshTokenPromises.delete(refreshToken);
return r;
}, e => {
this.refreshTokenPromises.delete(refreshToken);
throw e;
});
this.refreshTokenPromises.set(refreshToken, p);
return p;
}
async refreshTokenNoCache(refreshToken) {
if (!refreshToken) {
throw new Error('No refresh token is set.');
}
const url = OAuth2Client.GOOGLE_OAUTH2_TOKEN_URL_;
const data = {
refresh_token: refreshToken,
client_id: this._clientId,
client_secret: this._clientSecret,
grant_type: 'refresh_token',
};
// request for new token
const res = await this.transporter.request({
method: 'POST',
url,
data: querystring.stringify(data),
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
});
const tokens = res.data;
// TODO: de-duplicate this code from a few spots
if (res.data && res.data.expires_in) {
tokens.expiry_date = new Date().getTime() + res.data.expires_in * 1000;
delete tokens.expires_in;
}
this.emit('tokens', tokens);
return { tokens, res };
}
refreshAccessToken(callback) {
if (callback) {
this.refreshAccessTokenAsync().then(r => callback(null, r.credentials, r.res), callback);
}
else {
return this.refreshAccessTokenAsync();
}
}
async refreshAccessTokenAsync() {
const r = await this.refreshToken(this.credentials.refresh_token);
const tokens = r.tokens;
tokens.refresh_token = this.credentials.refresh_token;
this.credentials = tokens;
return { credentials: this.credentials, res: r.res };
}
getAccessToken(callback) {
if (callback) {
this.getAccessTokenAsync().then(r => callback(null, r.token, r.res), callback);
}
else {
return this.getAccessTokenAsync();
}
}
async getAccessTokenAsync() {
const shouldRefresh = !this.credentials.access_token || this.isTokenExpiring();
if (shouldRefresh) {
if (!this.credentials.refresh_token) {
throw new Error('No refresh token is set.');
}
const r = await this.refreshAccessTokenAsync();
if (!r.credentials || (r.credentials && !r.credentials.access_token)) {
throw new Error('Could not refresh access token.');
}
return { token: r.credentials.access_token, res: r.res };
}
else {
return { token: this.credentials.access_token };
}
}
getRequestMetadata(url, callback) {
messages.warn(messages.OAUTH_GET_REQUEST_METADATA_DEPRECATED);
if (callback) {
this.getRequestMetadataAsync(url).then(r => callback(null, r.headers, r.res), callback);
}
else {
return this.getRequestMetadataAsync();
}
}
/**
* The main authentication interface. It takes an optional url which when
* present is the endpoint being accessed, and returns a Promise which
* resolves with authorization header fields.
*
* In OAuth2Client, the result has the form:
* { Authorization: 'Bearer <access_token_value>' }
* @param url The optional url being authorized
*/
async getRequestHeaders(url) {
const res = await this.getRequestMetadataAsync(url);
return res.headers;
}
async getRequestMetadataAsync(url) {
const thisCreds = this.credentials;
if (!thisCreds.access_token && !thisCreds.refresh_token && !this.apiKey) {
throw new Error('No access, refresh token or API key is set.');
}
if (thisCreds.access_token && !this.isTokenExpiring()) {
thisCreds.token_type = thisCreds.token_type || 'Bearer';
const headers = {
Authorization: thisCreds.token_type + ' ' + thisCreds.access_token,
};
return { headers };
}
if (this.apiKey) {
return { headers: { 'X-Goog-Api-Key': this.apiKey } };
}
let r = null;
let tokens = null;
try {
r = await this.refreshToken(thisCreds.refresh_token);
tokens = r.tokens;
}
catch (err) {
const e = err;
if (e.response &&
(e.response.status === 403 || e.response.status === 404)) {
e.message = `Could not refresh access token: ${e.message}`;
}
throw e;
}
const credentials = this.credentials;
credentials.token_type = credentials.token_type || 'Bearer';
tokens.refresh_token = credentials.refresh_token;
this.credentials = tokens;
const headers = {
Authorization: credentials.token_type + ' ' + tokens.access_token,
};
return { headers, res: r.res };
}
/**
* Generates an URL to revoke the given token.
* @param token The existing token to be revoked.
*/
static getRevokeTokenUrl(token) {
const parameters = querystring.stringify({ token });
return `${OAuth2Client.GOOGLE_OAUTH2_REVOKE_URL_}?${parameters}`;
}
revokeToken(token, callback) {
const opts = {
url: OAuth2Client.getRevokeTokenUrl(token),
method: 'POST',
};
if (callback) {
this.transporter
.request(opts)
.then(r => callback(null, r), callback);
}
else {
return this.transporter.request(opts);
}
}
revokeCredentials(callback) {
if (callback) {
this.revokeCredentialsAsync().then(res => callback(null, res), callback);
}
else {
return this.revokeCredentialsAsync();
}
}
async revokeCredentialsAsync() {
const token = this.credentials.access_token;
this.credentials = {};
if (token) {
return this.revokeToken(token);
}
else {
throw new Error('No access token to revoke.');
}
}
request(opts, callback) {
if (callback) {
this.requestAsync(opts).then(r => callback(null, r), e => {
return callback(e, e.response);
});
}
else {
return this.requestAsync(opts);
}
}
async requestAsync(opts, retry = false) {
let r2;
try {
const r = await this.getRequestMetadataAsync(opts.url);
if (r.headers && r.headers.Authorization) {
opts.headers = opts.headers || {};
opts.headers.Authorization = r.headers.Authorization;
}
if (this.apiKey) {
opts.headers = opts.headers || {};
opts.headers['X-Goog-Api-Key'] = this.apiKey;
}
r2 = await this.transporter.request(opts);
}
catch (e) {
const res = e.response;
if (res) {
const statusCode = res.status;
// Retry the request for metadata if the following criteria are true:
// - We haven't already retried. It only makes sense to retry once.
// - The response was a 401 or a 403
// - The request didn't send a readableStream
// - An access_token and refresh_token were available, but either no
// expiry_date was available or the forceRefreshOnFailure flag is set.
// The absent expiry_date case can happen when developers stash the
// access_token and refresh_token for later use, but the access_token
// fails on the first try because it's expired. Some developers may
// choose to enable forceRefreshOnFailure to mitigate time-related
// errors.
const mayRequireRefresh = this.credentials &&
this.credentials.access_token &&
this.credentials.refresh_token &&
(!this.credentials.expiry_date || this.forceRefreshOnFailure);
const isReadableStream = res.config.data instanceof stream.Readable;
const isAuthErr = statusCode === 401 || statusCode === 403;
if (!retry && isAuthErr && !isReadableStream && mayRequireRefresh) {
await this.refreshAccessTokenAsync();
return this.requestAsync(opts, true);
}
}
throw e;
}
return r2;
}
verifyIdToken(options, callback) {
// This function used to accept two arguments instead of an options object.
// Check the types to help users upgrade with less pain.
// This check can be removed after a 2.0 release.
if (callback && typeof callback !== 'function') {
throw new Error('This method accepts an options object as the first parameter, which includes the idToken, audience, and maxExpiry.');
}
if (callback) {
this.verifyIdTokenAsync(options).then(r => callback(null, r), callback);
}
else {
return this.verifyIdTokenAsync(options);
}
}
async verifyIdTokenAsync(options) {
if (!options.idToken) {
throw new Error('The verifyIdToken method requires an ID Token');
}
const response = await this.getFederatedSignonCertsAsync();
const login = await this.verifySignedJwtWithCertsAsync(options.idToken, response.certs, options.audience, OAuth2Client.ISSUERS_, options.maxExpiry);
return login;
}
/**
* Obtains information about the provisioned access token. Especially useful
* if you want to check the scopes that were provisioned to a given token.
*
* @param accessToken Required. The Access Token for which you want to get
* user info.
*/
async getTokenInfo(accessToken) {
const { data } = await this.transporter.request({
method: 'GET',
url: OAuth2Client.GOOGLE_TOKEN_INFO_URL,
params: { access_token: accessToken },
});
const info = Object.assign({
expiry_date: new Date().getTime() + data.expires_in * 1000,
scopes: data.scope.split(' '),
}, data);
delete info.expires_in;
delete info.scope;
return info;
}
getFederatedSignonCerts(callback) {
if (callback) {
this.getFederatedSignonCertsAsync().then(r => callback(null, r.certs, r.res), callback);
}
else {
return this.getFederatedSignonCertsAsync();
}
}
async getFederatedSignonCertsAsync() {
const nowTime = new Date().getTime();
const format = crypto_1.hasBrowserCrypto()
? CertificateFormat.JWK
: CertificateFormat.PEM;
if (this.certificateExpiry &&
nowTime < this.certificateExpiry.getTime() &&
this.certificateCacheFormat === format) {
return { certs: this.certificateCache, format };
}
let res;
let url;
switch (format) {
case CertificateFormat.PEM:
url = OAuth2Client.GOOGLE_OAUTH2_FEDERATED_SIGNON_PEM_CERTS_URL_;
break;
case CertificateFormat.JWK:
url = OAuth2Client.GOOGLE_OAUTH2_FEDERATED_SIGNON_JWK_CERTS_URL_;
break;
default:
throw new Error(`Unsupported certificate format ${format}`);
}
try {
res = await this.transporter.request({ url });
}
catch (e) {
e.message = `Failed to retrieve verification certificates: ${e.message}`;
throw e;
}
const cacheControl = res ? res.headers['cache-control'] : undefined;
let cacheAge = -1;
if (cacheControl) {
const pattern = new RegExp('max-age=([0-9]*)');
const regexResult = pattern.exec(cacheControl);
if (regexResult && regexResult.length === 2) {
// Cache results with max-age (in seconds)
cacheAge = Number(regexResult[1]) * 1000; // milliseconds
}
}
let certificates = {};
switch (format) {
case CertificateFormat.PEM:
certificates = res.data;
break;
case CertificateFormat.JWK:
for (const key of res.data.keys) {
certificates[key.kid] = key;
}
break;
default:
throw new Error(`Unsupported certificate format ${format}`);
}
const now = new Date();
this.certificateExpiry =
cacheAge === -1 ? null : new Date(now.getTime() + cacheAge);
this.certificateCache = certificates;
this.certificateCacheFormat = format;
return { certs: certificates, format, res };
}
verifySignedJwtWithCerts() {
// To make the code compatible with browser SubtleCrypto we need to make
// this method async.
throw new Error('verifySignedJwtWithCerts is removed, please use verifySignedJwtWithCertsAsync instead.');
}
/**
* Verify the id token is signed with the correct certificate
* and is from the correct audience.
* @param jwt The jwt to verify (The ID Token in this case).
* @param certs The array of certs to test the jwt against.
* @param requiredAudience The audience to test the jwt against.
* @param issuers The allowed issuers of the jwt (Optional).
* @param maxExpiry The max expiry the certificate can be (Optional).
* @return Returns a promise resolving to LoginTicket on verification.
*/
async verifySignedJwtWithCertsAsync(jwt, certs, requiredAudience, issuers, maxExpiry) {
const crypto = crypto_1.createCrypto();
if (!maxExpiry) {
maxExpiry = OAuth2Client.MAX_TOKEN_LIFETIME_SECS_;
}
const segments = jwt.split('.');
if (segments.length !== 3) {
throw new Error('Wrong number of segments in token: ' + jwt);
}
const signed = segments[0] + '.' + segments[1];
const signature = segments[2];
let envelope;
let payload;
try {
envelope = JSON.parse(crypto.decodeBase64StringUtf8(segments[0]));
}
catch (err) {
err.message = `Can't parse token envelope: ${segments[0]}': ${err.message}`;
throw err;
}
if (!envelope) {
throw new Error("Can't parse token envelope: " + segments[0]);
}
try {
payload = JSON.parse(crypto.decodeBase64StringUtf8(segments[1]));
}
catch (err) {
err.message = `Can't parse token payload '${segments[0]}`;
throw err;
}
if (!payload) {
throw new Error("Can't parse token payload: " + segments[1]);
}
if (!certs.hasOwnProperty(envelope.kid)) {
// If this is not present, then there's no reason to attempt verification
throw new Error('No pem found for envelope: ' + JSON.stringify(envelope));
}
const cert = certs[envelope.kid];
const verified = await crypto.verify(cert, signed, signature);
if (!verified) {
throw new Error('Invalid token signature: ' + jwt);
}
if (!payload.iat) {
throw new Error('No issue time in token: ' + JSON.stringify(payload));
}
if (!payload.exp) {
throw new Error('No expiration time in token: ' + JSON.stringify(payload));
}
const iat = Number(payload.iat);
if (isNaN(iat))
throw new Error('iat field using invalid format');
const exp = Number(payload.exp);
if (isNaN(exp))
throw new Error('exp field using invalid format');
const now = new Date().getTime() / 1000;
if (exp >= now + maxExpiry) {
throw new Error('Expiration time too far in future: ' + JSON.stringify(payload));
}
const earliest = iat - OAuth2Client.CLOCK_SKEW_SECS_;
const latest = exp + OAuth2Client.CLOCK_SKEW_SECS_;
if (now < earliest) {
throw new Error('Token used too early, ' +
now +
' < ' +
earliest +
': ' +
JSON.stringify(payload));
}
if (now > latest) {
throw new Error('Token used too late, ' +
now +
' > ' +
latest +
': ' +
JSON.stringify(payload));
}
if (issuers && issuers.indexOf(payload.iss) < 0) {
throw new Error('Invalid issuer, expected one of [' +
issuers +
'], but got ' +
payload.iss);
}
// Check the audience matches if we have one
if (typeof requiredAudience !== 'undefined' && requiredAudience !== null) {
const aud = payload.aud;
let audVerified = false;
// If the requiredAudience is an array, check if it contains token
// audience
if (requiredAudience.constructor === Array) {
audVerified = requiredAudience.indexOf(aud) > -1;
}
else {
audVerified = aud === requiredAudience;
}
if (!audVerified) {
throw new Error('Wrong recipient, payload audience != requiredAudience');
}
}
return new loginticket_1.LoginTicket(envelope, payload);
}
/**
* Returns true if a token is expired or will expire within
* eagerRefreshThresholdMillismilliseconds.
* If there is no expiry time, assumes the token is not expired or expiring.
*/
isTokenExpiring() {
const expiryDate = this.credentials.expiry_date;
return expiryDate
? expiryDate <= new Date().getTime() + this.eagerRefreshThresholdMillis
: false;
}
}
exports.OAuth2Client = OAuth2Client;
OAuth2Client.GOOGLE_TOKEN_INFO_URL = 'https://oauth2.googleapis.com/tokeninfo';
/**
* The base URL for auth endpoints.
*/
OAuth2Client.GOOGLE_OAUTH2_AUTH_BASE_URL_ = 'https://accounts.google.com/o/oauth2/v2/auth';
/**
* The base endpoint for token retrieval.
*/
OAuth2Client.GOOGLE_OAUTH2_TOKEN_URL_ = 'https://oauth2.googleapis.com/token';
/**
* The base endpoint to revoke tokens.
*/
OAuth2Client.GOOGLE_OAUTH2_REVOKE_URL_ = 'https://oauth2.googleapis.com/revoke';
/**
* Google Sign on certificates in PEM format.
*/
OAuth2Client.GOOGLE_OAUTH2_FEDERATED_SIGNON_PEM_CERTS_URL_ = 'https://www.googleapis.com/oauth2/v1/certs';
/**
* Google Sign on certificates in JWK format.
*/
OAuth2Client.GOOGLE_OAUTH2_FEDERATED_SIGNON_JWK_CERTS_URL_ = 'https://www.googleapis.com/oauth2/v3/certs';
/**
* Clock skew - five minutes in seconds
*/
OAuth2Client.CLOCK_SKEW_SECS_ = 300;
/**
* Max Token Lifetime is one day in seconds
*/
OAuth2Client.MAX_TOKEN_LIFETIME_SECS_ = 86400;
/**
* The allowed oauth token issuers.
*/
OAuth2Client.ISSUERS_ = [
'accounts.google.com',
'https://accounts.google.com',
];
//# sourceMappingURL=oauth2client.js.map

View File

@@ -0,0 +1,58 @@
/**
* Copyright 2015 Google Inc. All Rights Reserved.
*
* 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.
*/
/// <reference types="node" />
import * as stream from 'stream';
import { JWTInput } from './credentials';
import { GetTokenResponse, OAuth2Client, RefreshOptions } from './oauth2client';
export interface UserRefreshClientOptions extends RefreshOptions {
clientId?: string;
clientSecret?: string;
refreshToken?: string;
}
export declare class UserRefreshClient extends OAuth2Client {
_refreshToken?: string | null;
/**
* User Refresh Token credentials.
*
* @param clientId The authentication client ID.
* @param clientSecret The authentication client secret.
* @param refreshToken The authentication refresh token.
*/
constructor(clientId?: string, clientSecret?: string, refreshToken?: string);
constructor(options: UserRefreshClientOptions);
constructor(clientId?: string, clientSecret?: string, refreshToken?: string);
/**
* Refreshes the access token.
* @param refreshToken An ignored refreshToken..
* @param callback Optional callback.
*/
protected refreshTokenNoCache(refreshToken?: string | null): Promise<GetTokenResponse>;
/**
* Create a UserRefreshClient credentials instance using the given input
* options.
* @param json The input object.
*/
fromJSON(json: JWTInput): void;
/**
* Create a UserRefreshClient credentials instance using the given input
* stream.
* @param inputStream The input stream.
* @param callback Optional callback.
*/
fromStream(inputStream: stream.Readable): Promise<void>;
fromStream(inputStream: stream.Readable, callback: (err?: Error) => void): void;
private fromStreamAsync;
}

View File

@@ -0,0 +1,104 @@
"use strict";
/**
* Copyright 2015 Google Inc. All Rights Reserved.
*
* 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 });
const oauth2client_1 = require("./oauth2client");
class UserRefreshClient extends oauth2client_1.OAuth2Client {
constructor(optionsOrClientId, clientSecret, refreshToken, eagerRefreshThresholdMillis, forceRefreshOnFailure) {
const opts = optionsOrClientId && typeof optionsOrClientId === 'object'
? optionsOrClientId
: {
clientId: optionsOrClientId,
clientSecret,
refreshToken,
eagerRefreshThresholdMillis,
forceRefreshOnFailure,
};
super({
clientId: opts.clientId,
clientSecret: opts.clientSecret,
eagerRefreshThresholdMillis: opts.eagerRefreshThresholdMillis,
forceRefreshOnFailure: opts.forceRefreshOnFailure,
});
this._refreshToken = opts.refreshToken;
}
/**
* Refreshes the access token.
* @param refreshToken An ignored refreshToken..
* @param callback Optional callback.
*/
async refreshTokenNoCache(refreshToken) {
return super.refreshTokenNoCache(this._refreshToken);
}
/**
* Create a UserRefreshClient credentials instance using the given input
* options.
* @param json The input object.
*/
fromJSON(json) {
if (!json) {
throw new Error('Must pass in a JSON object containing the user refresh token');
}
if (json.type !== 'authorized_user') {
throw new Error('The incoming JSON object does not have the "authorized_user" type');
}
if (!json.client_id) {
throw new Error('The incoming JSON object does not contain a client_id field');
}
if (!json.client_secret) {
throw new Error('The incoming JSON object does not contain a client_secret field');
}
if (!json.refresh_token) {
throw new Error('The incoming JSON object does not contain a refresh_token field');
}
this._clientId = json.client_id;
this._clientSecret = json.client_secret;
this._refreshToken = json.refresh_token;
this.credentials.refresh_token = json.refresh_token;
}
fromStream(inputStream, callback) {
if (callback) {
this.fromStreamAsync(inputStream).then(r => callback(), callback);
}
else {
return this.fromStreamAsync(inputStream);
}
}
async fromStreamAsync(inputStream) {
return new Promise((resolve, reject) => {
if (!inputStream) {
return reject(new Error('Must pass in a stream containing the user refresh token.'));
}
let s = '';
inputStream
.setEncoding('utf8')
.on('error', reject)
.on('data', chunk => (s += chunk))
.on('end', () => {
try {
const data = JSON.parse(s);
this.fromJSON(data);
return resolve();
}
catch (err) {
return reject(err);
}
});
});
}
}
exports.UserRefreshClient = UserRefreshClient;
//# sourceMappingURL=refreshclient.js.map