@microsoft/windows-admin-center-sdk
Version:
Microsoft - Windows Admin Center Shell
234 lines (232 loc) • 10.1 kB
JavaScript
import { of } from 'rxjs';
import { map, mergeMap } from 'rxjs/operators';
import { SmeWebTelemetry } from '../diagnostics/sme-web-telemetry';
import { EnvironmentModule } from '../manifest/environment-modules';
import { GatewayUrlTranslator } from './gateway-url-translator';
import { headerConstants } from './http-constants';
import { Net } from './net';
/**
* Node Cim output type.
*/
export var NodeCimOutput;
(function (NodeCimOutput) {
/**
* Single instance.
*/
NodeCimOutput[NodeCimOutput["Single"] = 0] = "Single";
/**
* Multiple instances.
*/
NodeCimOutput[NodeCimOutput["Multiple"] = 1] = "Multiple";
/**
* Invoke result.
*/
NodeCimOutput[NodeCimOutput["Result"] = 2] = "Result";
/**
* WQL query result.
*/
NodeCimOutput[NodeCimOutput["Query"] = 3] = "Query";
})(NodeCimOutput || (NodeCimOutput = {}));
/**
* The Node Connection class for creating requests and calling the Gateway's Node API
*/
export class NodeConnection {
gateway;
authorizationManager;
/**
* Initializes a new instance of the GatewayService class.
*
* @param gateway the gateway Connection
* @param authorizationManager the authorization manager.
*/
constructor(gateway, authorizationManager) {
this.gateway = gateway;
this.authorizationManager = authorizationManager;
}
post(nodeOrService, remained, body, request) {
const { nodeName, relativeUrl } = this.getNodeUrl(nodeOrService, remained);
request = this.createNodeRequest(request || {}, nodeName);
return this.gateway.post(relativeUrl, body, request);
}
get(nodeOrService, remained, request) {
const { nodeName, relativeUrl } = this.getNodeUrl(nodeOrService, remained);
request = this.createNodeRequest(request || {}, nodeName);
return this.gateway.get(relativeUrl, request);
}
put(nodeOrService, remained, body, request) {
const { nodeName, relativeUrl } = this.getNodeUrl(nodeOrService, remained);
request = this.createNodeRequest(request || {}, nodeName);
return this.gateway.put(relativeUrl, body, request);
}
patch(nodeOrService, remained, body, request) {
const { nodeName, relativeUrl } = this.getNodeUrl(nodeOrService, remained);
request = this.createNodeRequest(request || {}, nodeName);
return this.gateway.patch(relativeUrl, body, request);
}
delete(nodeOrService, remained, body, request) {
const { nodeName, relativeUrl } = this.getNodeUrl(nodeOrService, remained);
request = this.createNodeRequest(request || {}, nodeName);
return this.gateway.delete(relativeUrl, body, request);
}
deleteQuick(nodeOrService, remained, request) {
const { nodeName, relativeUrl } = this.getNodeUrl(nodeOrService, remained);
request.headers = request.headers || {};
if (!request.authToken) {
// if we don't have an authToken, then make sure we are not waiting on one.
this.authorizationManager.addAuthorizationRequestHeader(request, nodeName);
}
else {
this.authorizationManager.addAuthorizationRequestHeader(request, nodeName, request.authToken);
}
const endpoint = this.authorizationManager.getJeaEndpoint(nodeName);
if (request.powerShellEndpoint) {
// Override JEA fallback if endpoint is explicitly set for debugging purposes
request.headers[headerConstants.POWERSHELL_ENDPOINT] = request.powerShellEndpoint;
}
else if (endpoint) {
request.headers[headerConstants.POWERSHELL_ENDPOINT] = endpoint;
}
if (request.authenticationMechanism === 'Credssp') {
request.headers[headerConstants.AUTHENTICATION_MECHANISM] = request.authenticationMechanism;
}
return this.gateway.deleteQuick(relativeUrl, request.headers);
}
/**
* Persists the JEA powershell endpoint context
* @param nodeName The node name
* @param endpoint The powershell endpoint
*/
saveJeaContext(nodeName, endpoint) {
this.authorizationManager.saveJeaContext(nodeName, endpoint);
}
/**
* Gets the JEA powershell endpoint, if it exists
* @param nodeName The node name
*/
getJeaEndpoint(nodeName) {
return this.authorizationManager.getJeaEndpoint(nodeName);
}
/**
* Creates service node API for Gateway V2.
*
* @param serviceName the name of service.
* @param apiName the name of api.
* @param nodeName the name of node.
* @param remained the remained URL after it including option parameters.
* @returns URL string.
*/
getServiceUrl(serviceName, apiName, nodeName, remained) {
// 1) if null or empty, it's empty.
// 2) if start with "?", remains as is.
// 3) if not started with "/", add "/".
remained = remained ?? '';
if (remained.length > 0 && !remained.startsWith('/')) {
if (!remained.startsWith('?')) {
remained = `/${remained}`;
}
}
// for example, "/api/services/WinREST/PowerShell/nodes/computer-abc/invoke"
return `/Services/${serviceName}/${apiName}/nodes/${nodeName}${remained}`;
}
/**
* Adds default parameters to a NodeRequest
*
* @param method the http method to use
* @param relativeUrl the relative Url after "/api/"
* @param body the body string JSON.stringfy'ed
* @param request the node request object to extend.
*/
createNodeRequest(request, nodeName) {
// if we did not specify no auth, and we are not using a custom token...
request = MsftSme.deepAssign({}, request);
if (!request.noAuth && !request.authToken) {
// ...then add node specific authorization handlers
request.retryHandlers = (request.retryHandlers || []).concat([{
canHandle: (code, error) => this.authorizationManager.canHandleAjaxFailure(code, error),
handle: (code, originalRequest, error) => this.authorizationManager.handleAjaxFailure(code, originalRequest, error, nodeName)
}]);
}
const oldBeforeCall = request.beforeCall;
// Add before call handler to wait for any pending node authorization
request.beforeCall = pendingRequest => {
let observable = null;
if (!request.authToken) {
// if we dont have an authToken, then make sure we are not waiting on one.
observable = this.authorizationManager.authAwaiter
.pipe(map(() => this.authorizationManager.addAuthorizationRequestHeader(pendingRequest, nodeName)));
}
else {
observable = of(this.authorizationManager.addAuthorizationRequestHeader(pendingRequest, nodeName, request.authToken));
}
if (oldBeforeCall) {
return oldBeforeCall(request).pipe(mergeMap(() => observable));
}
return observable;
};
request.headers = request.headers || {};
if (request.logAudit === true || request.logAudit === false) {
request.headers[headerConstants.LOG_AUDIT] = request.logAudit ? 'true' : 'false';
}
if (request.logTelemetry === true || request.logTelemetry === false) {
request.headers[headerConstants.LOG_TELEMETRY] = request.logTelemetry ? 'true' : 'false';
}
const endpoint = this.authorizationManager.getJeaEndpoint(nodeName);
if (request.powerShellEndpoint) {
// Override JEA fallback if endpoint is explicitly set for debugging purposes
request.headers[headerConstants.POWERSHELL_ENDPOINT] = request.powerShellEndpoint;
}
else if (endpoint) {
request.headers[headerConstants.POWERSHELL_ENDPOINT] = endpoint;
}
if (request.authenticationMechanism === 'Credssp') {
request.headers[headerConstants.AUTHENTICATION_MECHANISM] = request.authenticationMechanism;
}
return request;
}
/**
* Get node name and node url.
* @param nodeOrService The node name or service request object.
* @param remained The remained url.
* @returns node name and node url.
*/
getNodeUrl(nodeOrService, remained) {
if (typeof nodeOrService === 'string') {
const nodeName = nodeOrService;
return { nodeName, relativeUrl: this.getNodeMappedUrl(nodeName, remained) };
}
const service = nodeOrService;
return {
nodeName: service.nodeName,
relativeUrl: this.getServiceUrl(service.serviceName, service.controllerName, service.nodeName, remained)
};
}
/**
* Creates a Node url
*
* @param nodeName the name of the node to make a call against
* @param relativeUrl the relative Url after "/nodes/<nodeName>/"
*/
getNodeMappedUrl(nodeName, relativeUrl) {
if (EnvironmentModule.isGatewayV200) {
const translation = GatewayUrlTranslator.translate(relativeUrl);
if (translation) {
return `${translation.startUrl}/nodes/${nodeName}/${translation.newUrl}`;
}
SmeWebTelemetry.traceAction(null, {
content: {
message: 'Could not get translation for URL: {0}'.format(relativeUrl),
action: 'TranslateUrlToGateWayV2'
}
}, { type: 'error' });
throw new Error(MsftSme.getStrings().MsftSmeShell.Core.TranslateGatewayUrls.Url.Not.expected.ErrorMessage
.format(relativeUrl));
}
// create node url from current url
if (!relativeUrl.startsWith('/')) {
relativeUrl = `/${relativeUrl}`;
}
relativeUrl = Net.updateApiVersion20190201(relativeUrl);
return `/nodes/${nodeName}${relativeUrl}`;
}
}
//# sourceMappingURL=node-connection.js.map