@sap/ams-dev
Version:
NodesJS AMS development environment
82 lines (69 loc) • 3.1 kB
JavaScript
const https = require('node:https');
const { URL } = require('node:url');
const { addDefaultHeaders, createHTTPSAgent, createTgzFromDirectory } = require('./util');
const { sanitizeForLog } = require('../util');
const APPNAME_HEADER = "X-Appname";
async function uploadBaseDcl(credentials, dclRoot, uploadParams) {
const bundle = await createTgzFromDirectory(dclRoot);
// Todo: Calculate SHA256 of local policies and upload only when it differs from current policies
// For comparison, use the new HEAD request to get current SHA256 from server
const request = createDclUploadRequest(credentials, bundle, uploadParams);
await postDcl(request);
}
/**
* Creates an abstract DCL upload request object for use with an arbitrary http client
* @param {object} credentials - the Identity Service credentials
* @param {Buffer} bundle - the .tgz archive buffer containing the DCL files
* @param {object} [uploadParams] - optional parameters for the upload request
* @param {string} [uploadParams.deployerAppName] - a descriptive name of this deployer application to trace back the currently deployed DCL bundle on the AMS server to its source when DCL is deployed from more than one source.
* @returns {object} - the request object
*/
function createDclUploadRequest(credentials, bundle, uploadParams) {
const appName = uploadParams.deployerAppName || "@sap/ams-dev:AmsClient";
const request = {
url: `${credentials.url}/sap/ams/v1/ams-instances/${credentials.authorization_instance_id}/dcl-upload`,
method: "POST",
headers: {
"Content-Type": "application/gzip",
[APPNAME_HEADER]: appName
},
body: bundle,
agent: createHTTPSAgent(credentials)
};
addDefaultHeaders(request.headers, credentials);
return request;
}
async function postDcl(request) {
return new Promise((resolve, reject) => {
const url = new URL(request.url);
const options = {
hostname: url.hostname,
port: url.port || 443,
path: url.pathname + url.search,
method: request.method,
headers: {
...request.headers,
'Content-Length': request.body.length
},
agent: request.agent
};
const req = https.request(options, (res) => {
let data = '';
res.on('data', chunk => data += chunk);
res.on('end', () => {
if (res.statusCode >= 200 && res.statusCode < 300) {
resolve(data);
} else {
// statusCode/statusMessage are server-controlled; sanitize to prevent log injection
reject(new Error(`DCL upload rejected by server: ${res.statusCode} ${sanitizeForLog(res.statusMessage)}`));
}
});
});
req.on('error', (e) => {
reject(new Error(`DCL upload could not be sent: ${e.message}`));
});
req.write(request.body);
req.end();
});
}
module.exports = uploadBaseDcl;