import arrify = require ( 'arrify' ) ; import { GaxiosError } from 'gaxios' ; import * as gcpMetadata from 'gcp-metadata' ; import { CredentialRequest , Credentials } from './credentials' ; 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 class Compute extends OAuth2Client { private serviceAccountEmail : string ; 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 = { } ) { super ( options ) ; this . credentials = { expiry_date : 1 , refresh_token : 'compute-placeholder' } ; this . serviceAccountEmail = options . serviceAccountEmail || 'default' ; this . scopes = arrify ( options . scopes ) ; } param refreshToken protected 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 as Credentials ; if ( data && data . expires_in ) { tokens . expiry_date = new Date ( ) . getTime ( ) + data . expires_in * 1000 ; delete ( tokens as CredentialRequest ) . expires_in ; } this . emit ( 'tokens' , tokens ) ; return { tokens , res : null } ; } param targetAudience async fetchIdToken ( targetAudience ) { const idTokenPath = `service-accounts/${ this . serviceAccountEmail }/identity` + `?format=full&audience=${ targetAudience }` ; let idToken ; try { const instanceOptions = { property : idTokenPath , } ; idToken = await gcpMetadata . instance ( instanceOptions ) ; } catch ( e ) { e . message = `Could not fetch ID token: ${ e . message }` ; throw e ; } return idToken ; } protected 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 ; } } } }