import { TokenCredentialsBase } from "@azure/ms-rest-nodeauth" ; import * as path from 'path' ; import * as request from 'request-promise-native' ; import { Source } from 'vscode-debugadapter' ; import { getBearerToken } from '../utils/requestUtil' ; import { StackFrameScopeContract } from './debuggerConnection' ; import { PolicyLocation , PolicyMap , PolicyMapper } from './policyMapper' ; export class PolicySource { private static NextSourceReference : number = 1 ; private managementAddress : string ; private credential : TokenCredentialsBase | undefined ; private auth : string | undefined ; private policies : { [ key ] : Policy ; } = { } ; constructor ( managementAddress , credential ? , auth ? ) { this . managementAddress = managementAddress ; this . credential = credential ; this . auth = auth ; if ( ! credential && ! auth ) { throw new Error ( "Missing credentials!" ) ; } } public getPolicyLocation ( scopeId , path ) { const policy = this . policies [ this . normalizeScopeId ( scopeId ) ] ; if ( ! policy ) { return null ; } if ( Object . keys ( policy . map ) . includes ( path ) ) { return policy . map [ path ] ; } const paths = path . split ( "/" ) ; const mapKeys = Object . keys ( policy . map ) . map ( s => s . split ( "/" ) ) . filter ( s => s . length === paths . length ) ; for ( const curKey of mapKeys ) { let isEqual = true ; for ( let idx = 0 ; idx < paths . length ; idx ++ ) { if ( paths [ idx ] === curKey [ idx ] ) { continue ; } else { isEqual = false ; } } if ( isEqual === true ) { return policy . map [ curKey . join ( "/" ) ] ; } } return null ; } public async fetchPolicies ( scopes ) { const policiesToRequest = scopes . map ( s => this . normalizeScopeId ( s ) ) . filter ( s => ! this . policies [ s ] ) ; if ( policiesToRequest . length ) { await Promise . all ( policiesToRequest . map ( s => this . fetchPolicy ( s ) . catch ( _e => null ) ) ) ; } } public getPolicyBySourceReference ( id ) { for ( const scope in this . policies ) { const policy = this . policies [ scope ] ; if ( policy && policy . source && policy . source . sourceReference === id ) { return policy ; } } return null ; } public getPolicy ( scopeId ) { return this . policies [ this . normalizeScopeId ( scopeId ) ] ; } public async fetchPolicy ( scopeId ) { scopeId = this . normalizeScopeId ( scopeId ) ; const policyUrl = this . getPolicyUrl ( scopeId ) ; if ( ! policyUrl ) { return null ; } let authToken ; if ( this . auth ) { authToken = this . auth ; } else { authToken = await getBearerToken ( policyUrl , "GET" , this . credential ! ) ; } const policyContract = await request . get ( policyUrl , { headers : { Authorization : authToken } , strictSSL : false , json : true } ) . on ( 'error' , _e => { } ) . on ( 'response' , _e => { } ) ; const policy = this . policies [ scopeId ] || ( this . policies [ scopeId ] = { scopeId : scopeId , xml : null , source : new Source ( scopeId , path . normalize ( scopeId ) , PolicySource . NextSourceReference ++ ) , map : { } } ) ; policy . xml = policyContract . properties . value ; this . mapPolicy ( policy ) ; return policy ; } private normalizeScopeId ( scopeId ) { return scopeId . replace ( /\\/g , '/' ) ; } private mapPolicy ( policy ) { if ( ! policy || ! policy . xml ) { return ; } policy . map = new PolicyMapper ( ) . mapPolicy ( policy . xml ) ; } private getPolicyUrl ( scopeId ) { if ( scopeId === StackFrameScopeContract . tenant ) { return `${ this . managementAddress }/policies/policy?api-version=2019-01-01&format=xml-raw` ; } else { return `${ this . managementAddress }/${ scopeId }/policies/policy?api-version=2019-01-01&format=xml-raw` ; } } } interface PolicyContract { properties : { format : string ; value : string ; } ; } interface Policy { scopeId : string ; xml : string | null ; source : Source ; map : PolicyMap ; }