Here is a complete solution that allows one to use Postman environment variables, put this in a Package library within Postman:
// acornsoft-unit-testing.js
// Custom Postman library for Acornsoft unit testing utilities
// Includes SAS token generation for Azure Service Bus
const CryptoJS = require('crypto-js');
/**
* Parses an Azure Service Bus connection string into its components.
* @param {string} connStr - The connection string
* @returns {object} - { endpoint, keyName, keyValue }
*/
function parseConnectionString(connStr) {
const parts = (connStr || '').split(';').filter(Boolean);
const map = {};
for (const p of parts) {
const idx = p.indexOf('=');
if (idx > -1) {
const key = p.substring(0, idx);
const val = p.substring(idx + 1); // Preserve '=' padding
map[key] = val;
}
}
return {
endpoint: (map.Endpoint || '').trim(),
keyName: (map.SharedAccessKeyName || '').trim(),
keyValue: (map.SharedAccessKey || '').trim()
};
}
/**
* Derives the resource URI for SAS signing.
* @param {string} requestUrl - The request URL
* @param {string} namespace - Namespace
* @param {string} entityPath - Entity path
* @returns {string} - Resource URI
*/
function deriveResource(requestUrl, namespace, entityPath) {
if (requestUrl) {
const base = requestUrl.split('?')[0].replace(/\/$/, '').replace(/\/messages$/, '');
if (base) return base;
}
return `https://${namespace}/${entityPath}`;
}
/**
* Generates a Service Bus SAS token.
* @param {string} resource - Resource URI
* @param {string} keyName - Key name
* @param {string} keyValue - Key value
* @param {number} ttl - TTL
* @returns {string} - SAS token
*/
function generateSasToken(resource, keyName, keyValue, ttl = Math.round(Date.now() / 1000) + 60 * 60 * 24 * 7) {
const encodedResource = encodeURIComponent(resource);
const stringToSign = `${encodedResource}\n${ttl}`;
const sig = CryptoJS.HmacSHA256(stringToSign, keyValue).toString(CryptoJS.enc.Base64);
return `SharedAccessSignature sr=${encodedResource}&sig=${encodeURIComponent(sig)}&se=${ttl}&skn=${keyName}`;
}
/**
* Generates SAS from connection string.
* @param {string} connStr - Connection string
* @param {string} requestUrl - Request URL
* @param {string} entityPath - Entity path
* @param {number} ttl - TTL
* @returns {string|null} - SAS token
*/
function generateFromConnectionString(connStr, requestUrl, entityPath, ttl) {
const { endpoint, keyName, keyValue } = parseConnectionString(connStr);
if (!endpoint || !keyName || !keyValue) return null;
const namespace = endpoint.replace('sb://', '').replace(/\/$/, '');
const resource = deriveResource(requestUrl, namespace, entityPath);
if (!resource) return null;
return generateSasToken(resource, keyName, keyValue, ttl);
}
/**
* Sets up Postman variables and generates SAS token for Service Bus requests.
* This function parses the connection string, sets serviceBusNamespace and entityPath variables,
* and generates the SAS token using the request URL.
* @param {string} connStr - Connection string
* @param {string} entityPath - Entity path (optional, will be set as variable)
* @param {number} ttl - TTL (optional)
* @returns {string|null} - SAS token
*/
function setupAndGenerateSas(connStr, entityPath, ttl) {
if (!connStr) return null;
// Parse connection string
const { endpoint, keyName, keyValue } = parseConnectionString(connStr);
if (!endpoint || !keyName || !keyValue) return null;
// Extract namespace
const namespace = endpoint.replace('sb://', '').replace('.servicebus.windows.net/', '').replace(/\/$/, '');
// Set variables for URL resolution
pm.variables.set('serviceBusNamespace', namespace);
if (entityPath) {
pm.variables.set('entityPath', entityPath);
}
// Generate SAS using resolved request URL
const requestUrl = resolvePostmanVariables(pm.request.url.toString());
return generateFromConnectionString(connStr, requestUrl, entityPath || pm.variables.get('entityPath'), ttl);
}
/**
* Resolves Postman variables in a URL string.
* @param {string} url - URL with {{variables}}
* @returns {string} - URL with variables resolved
*/
function resolvePostmanVariables(url) {
return url.replace(/\{\{([^}]+)\}\}/g, (match, varName) => {
const value = pm.variables.get(varName) || pm.environment.get(varName) || pm.globals.get(varName);
return value || match; // Keep as-is if not found
});
}
// Export functions
module.exports = {
parseConnectionString,
deriveResource,
generateSasToken,
generateFromConnectionString,
setupAndGenerateSas,
resolvePostmanVariables
};
To use in a request here is an example how to leverage this library, which requires you to define (2) variables in Postman:
serviceBusConnectionString = "
entityPath = "someTopic" (or) "someQueue"
Put this in the POST Request.
// Load the library
const someLib = pm.require('@acornsoft365/acornsoft-unit-testing');
// Get inputs from Postman variables
const connStr = pm.variables.get('serviceBusConnectionString');
const entityPath = pm.variables.get('entityPath');
const requestUrl = pm.request.url.toString();
// Generate SAS token
const sasToken = someLib.generateFromConnectionString(connStr, requestUrl, entityPath);
if (sasToken) {
pm.environment.set('sasToken', sasToken);
console.log('SAS token generated successfully');
} else {
console.error('Failed to generate SAS token');
}