UNPKG

usezap-cli

Version:

Zap CLI - Command-line interface for Zap API client

217 lines (189 loc) 8.5 kB
const { interpolate } = require('@usezap/common'); const { each, forOwn, cloneDeep, find } = require('lodash'); const FormData = require('form-data'); const getContentType = (headers = {}) => { let contentType = ''; forOwn(headers, (value, key) => { if (key && key.toLowerCase() === 'content-type') { contentType = value; } }); return contentType; }; const interpolateVars = (request, envVariables = {}, runtimeVariables = {}, processEnvVars = {}) => { const collectionVariables = request?.collectionVariables || {}; const folderVariables = request?.folderVariables || {}; const requestVariables = request?.requestVariables || {}; // we clone envVars because we don't want to modify the original object envVariables = cloneDeep(envVariables); // envVars can inturn have values as {{process.env.VAR_NAME}} // so we need to interpolate envVars first with processEnvVars forOwn(envVariables, (value, key) => { // Safety check: only interpolate if value is a string if (value && typeof value === 'string') { envVariables[key] = interpolate(value, { process: { env: { ...processEnvVars } } }); } }); const _interpolate = (str, { escapeJSONStrings } = {}) => { if (!str || !str.length || typeof str !== 'string') { return str; } // runtimeVariables take precedence over envVars const combinedVars = { ...collectionVariables, ...envVariables, ...folderVariables, ...requestVariables, ...runtimeVariables, process: { env: { ...processEnvVars } } }; return interpolate(str, combinedVars, { escapeJSONStrings }); }; request.url = _interpolate(request.url); forOwn(request.headers, (value, key) => { delete request.headers[key]; request.headers[_interpolate(key)] = _interpolate(value); }); const contentType = getContentType(request.headers); if (contentType.includes('json')) { if (typeof request.data === 'object') { try { let parsed = JSON.stringify(request.data); parsed = _interpolate(parsed, { escapeJSONStrings: true }); request.data = JSON.parse(parsed); } catch (err) { console.error(`Error parsing interpolated JSON data: ${err.message}`); console.error(`Data that failed to parse: ${JSON.stringify(request.data).substring(0, 200)}...`); // Keep original data if parsing fails } } if (typeof request.data === 'string') { if (request?.data?.length) { request.data = _interpolate(request.data, { escapeJSONStrings: true }); } } } else if (contentType === 'application/x-www-form-urlencoded') { if (typeof request.data === 'object') { try { forOwn(request?.data, (value, key) => { request.data[key] = _interpolate(value); }); } catch (err) {} } } else if (contentType === 'multipart/form-data') { if (Array.isArray(request?.data) && !(request.data instanceof FormData)) { try { request.data = request?.data?.map(d => ({ ...d, value: _interpolate(d?.value) })); } catch (err) {} } } else { request.data = _interpolate(request.data); } each(request?.pathParams, (param) => { param.value = _interpolate(param.value); }); if (request?.pathParams?.length) { let url = request.url; if (!url.startsWith('http://') && !url.startsWith('https://')) { url = `http://${url}`; } try { url = new URL(url); } catch (e) { throw { message: 'Invalid URL format', originalError: e.message }; } const interpolatedUrlPath = url.pathname .split('/') .filter((path) => path !== '') .map((path) => { if (path[0] !== ':') { return '/' + path; } else { const name = path.slice(1); const existingPathParam = request?.pathParams?.find((param) => param.type === 'path' && param.name === name); return existingPathParam ? '/' + existingPathParam.value : ''; } }) .join(''); const trailingSlash = url.pathname.endsWith('/') ? '/' : ''; request.url = url.origin + interpolatedUrlPath + trailingSlash + url.search; } if (request.proxy) { request.proxy.protocol = _interpolate(request.proxy.protocol); request.proxy.hostname = _interpolate(request.proxy.hostname); request.proxy.port = _interpolate(request.proxy.port); if (request.proxy.auth) { request.proxy.auth.username = _interpolate(request.proxy.auth.username); request.proxy.auth.password = _interpolate(request.proxy.auth.password); } } // todo: we have things happening in two places w.r.t basic auth // need to refactor this in the future // the request.auth (basic auth) object gets set inside the prepare-request.js file if (request.basicAuth) { const username = _interpolate(request.basicAuth.username) || ''; const password = _interpolate(request.basicAuth.password) || ''; // use auth header based approach and delete the request.auth object request.headers['Authorization'] = `Basic ${Buffer.from(`${username}:${password}`).toString('base64')}`; delete request.basicAuth; } if (request?.oauth2?.grantType) { switch (request.oauth2.grantType) { case 'password': request.oauth2.accessTokenUrl = _interpolate(request.oauth2.accessTokenUrl) || ''; request.oauth2.refreshTokenUrl = _interpolate(request.oauth2.refreshTokenUrl) || ''; request.oauth2.username = _interpolate(request.oauth2.username) || ''; request.oauth2.password = _interpolate(request.oauth2.password) || ''; request.oauth2.clientId = _interpolate(request.oauth2.clientId) || ''; request.oauth2.clientSecret = _interpolate(request.oauth2.clientSecret) || ''; request.oauth2.scope = _interpolate(request.oauth2.scope) || ''; request.oauth2.credentialsPlacement = _interpolate(request.oauth2.credentialsPlacement) || ''; request.oauth2.tokenPlacement = _interpolate(request.oauth2.tokenPlacement) || ''; request.oauth2.tokenHeaderPrefix = _interpolate(request.oauth2.tokenHeaderPrefix) || ''; request.oauth2.tokenQueryKey = _interpolate(request.oauth2.tokenQueryKey) || ''; break; case 'client_credentials': request.oauth2.accessTokenUrl = _interpolate(request.oauth2.accessTokenUrl) || ''; request.oauth2.refreshTokenUrl = _interpolate(request.oauth2.refreshTokenUrl) || ''; request.oauth2.clientId = _interpolate(request.oauth2.clientId) || ''; request.oauth2.clientSecret = _interpolate(request.oauth2.clientSecret) || ''; request.oauth2.scope = _interpolate(request.oauth2.scope) || ''; request.oauth2.credentialsPlacement = _interpolate(request.oauth2.credentialsPlacement) || ''; request.oauth2.tokenPlacement = _interpolate(request.oauth2.tokenPlacement) || ''; request.oauth2.tokenHeaderPrefix = _interpolate(request.oauth2.tokenHeaderPrefix) || ''; request.oauth2.tokenQueryKey = _interpolate(request.oauth2.tokenQueryKey) || ''; break; default: break; } } if (request.awsv4config) { request.awsv4config.accessKeyId = _interpolate(request.awsv4config.accessKeyId) || ''; request.awsv4config.secretAccessKey = _interpolate(request.awsv4config.secretAccessKey) || ''; request.awsv4config.sessionToken = _interpolate(request.awsv4config.sessionToken) || ''; request.awsv4config.service = _interpolate(request.awsv4config.service) || ''; request.awsv4config.region = _interpolate(request.awsv4config.region) || ''; request.awsv4config.profileName = _interpolate(request.awsv4config.profileName) || ''; } // interpolate vars for ntlmConfig auth if (request.ntlmConfig) { request.ntlmConfig.username = _interpolate(request.ntlmConfig.username) || ''; request.ntlmConfig.password = _interpolate(request.ntlmConfig.password) || ''; request.ntlmConfig.domain = _interpolate(request.ntlmConfig.domain) || ''; } if(request?.auth) delete request.auth; if (request) return request; }; module.exports = interpolateVars;