@mindconnect/mindconnect-nodejs
Version:
NodeJS Library for Siemens Insights Hub Connectivity - TypeScript SDK for Insights Hub and Industrial IoT - Command Line Interface - Insights Hub Development Proxy (Siemens Insights Hub was formerly known as MindSphere)
369 lines • 14.3 kB
JavaScript
;
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.removeTrailingSlash = exports.printTree = exports.isGuid = exports.convertToDataPoints = exports.checkList = exports.addAndStoreConfiguration = exports.pruneCert = exports.checksumFile = exports.removeUndefined = exports.toQueryString = exports.throwError = exports.checkAssetId = exports.retry = exports.checkCertificate = exports.getConfigProfile = exports.getFullConfig = exports.loadAuth = exports.storeAuth = exports.getHomeDotMcDir = exports.getAgentDir = exports.decrypt = exports.encrypt = exports.getPiamUrl = exports.isUrl = exports.upgradeOldConfiguration = exports.convertToTdpArray = void 0;
// Copyright (C), Siemens AG 2017
const crypto = require("crypto");
const fs = require("fs");
const os = require("os");
const url_1 = require("url");
const groupby = require("json-groupby");
const convertToTdpArray = (data) => {
const tdpArray = [];
const groupedData = groupby(data, ["timestamp"]);
for (const element in groupedData) {
groupedData[element].forEach((x) => {
delete x["timestamp"];
});
const tdp = {
timestamp: element,
values: groupedData[element],
};
tdpArray.push(tdp);
}
return tdpArray;
};
exports.convertToTdpArray = convertToTdpArray;
function upgradeOldConfiguration(obj) {
if (obj.auth && obj.iv && obj.gateway && obj.tenant) {
return {
credentials: [
Object.assign(Object.assign({}, obj), { selected: true, type: "SERVICE", createdAt: new Date().toISOString(), appName: "", appVersion: "", usertenant: "" }),
],
};
}
return obj;
}
exports.upgradeOldConfiguration = upgradeOldConfiguration;
const isUrl = (url) => {
try {
new url_1.URL(url);
return true;
}
catch (e) {
return false;
}
};
exports.isUrl = isUrl;
const getPiamUrl = (gateway, tenant) => {
const piamUrl = gateway.replace("gateway", `${tenant}.piam`);
return piamUrl.endsWith("/") ? piamUrl : piamUrl + "/";
};
exports.getPiamUrl = getPiamUrl;
const normalizePasskey = (passkey) => {
return passkey.length < 32 ? passkey + new Array(33 - passkey.length).join("$") : passkey.substr(0, 32);
};
const encrypt = ({ user, password, passkey, gateway, tenant, type, usertenant, appName, appVersion, createdAt, selected, }) => {
const base64encoded = Buffer.from(`${user}:${password}`).toString("base64");
const iv = crypto.randomBytes(16);
const cipher = crypto.createCipheriv("aes-256-ctr", Buffer.from(normalizePasskey(passkey)), iv);
let crypted = cipher.update(`Basic ${base64encoded}`, "utf8", "hex");
crypted += cipher.final("hex");
const encryptedAuth = {
auth: crypted.toString(),
iv: iv.toString("base64"),
gateway: gateway,
tenant: tenant,
type: type,
usertenant: usertenant,
appName: appName,
appVersion: appVersion,
createdAt: createdAt,
selected: selected,
};
// console.log(encryptedAuth);
return encryptedAuth;
};
exports.encrypt = encrypt;
const decrypt = (encryptedAuth, passkey) => {
const decipher = crypto.createDecipheriv("aes-256-ctr", normalizePasskey(passkey), Buffer.from(encryptedAuth.iv, "base64"));
let dec = decipher.update(encryptedAuth.auth, "hex", "utf8");
dec += decipher.final("utf8");
return dec;
};
exports.decrypt = decrypt;
const getAgentDir = (path) => {
let result;
if (fs.existsSync(`${path}/.mc/`)) {
result = `${path}/.mc/`;
}
else if (fs.existsSync(`${process.cwd()}/.mc/`)) {
result = `${process.cwd()}/.mc/`;
}
else {
result = (0, exports.getHomeDotMcDir)();
}
return result;
};
exports.getAgentDir = getAgentDir;
const getHomeDotMcDir = () => {
return `${os.homedir()}/.mc/`;
};
exports.getHomeDotMcDir = getHomeDotMcDir;
const storeAuth = (auth) => {
const homeDir = (0, exports.getHomeDotMcDir)();
if (!fs.existsSync(homeDir)) {
fs.mkdirSync(homeDir);
}
const pathName = `${(0, exports.getHomeDotMcDir)()}auth.json`;
fs.writeFileSync(pathName, JSON.stringify(auth));
};
exports.storeAuth = storeAuth;
const loadAuth = () => {
const fullConfig = getFullConfig();
let result = undefined;
for (let index = 0; index < fullConfig.credentials.length; index++) {
const element = fullConfig.credentials[index];
if (element.selected) {
result = element;
break;
}
}
!result &&
(0, exports.throwError)("please configure the authentication: https://developer.siemens.com/industrial-iot-open-source/mindconnect-nodejs/cli/setting-up-the-cli.html ");
return result;
};
exports.loadAuth = loadAuth;
function getFullConfig() {
const homeDir = (0, exports.getHomeDotMcDir)();
if (!fs.existsSync(homeDir)) {
fs.mkdirSync(homeDir);
console.log(`creating ${homeDir} folder`);
}
// create empty auth.json
const pathName = `${(0, exports.getHomeDotMcDir)()}auth.json`;
if (!fs.existsSync(pathName)) {
fs.writeFileSync(pathName, JSON.stringify({ credentials: [] }));
console.log(`initializing ${pathName} with empty configuration`);
}
const buffer = fs.readFileSync(pathName);
let obj = JSON.parse(buffer.toString());
// console.log(obj);
if (obj.auth && obj.iv && obj.gateway && obj.tenant) {
const upgraded = upgradeOldConfiguration(obj);
fs.writeFileSync(pathName, JSON.stringify(upgraded));
obj = upgraded;
console.log("upgraded configuration to the new format");
}
return obj;
}
exports.getFullConfig = getFullConfig;
const getConfigProfile = (config) => {
try {
const result = `${config.content.clientCredentialProfile}`;
if (["SHARED_SECRET", "RSA_3072"].indexOf(result) < 0) {
throw new Error("Configuration profile not supported. The library only supports the shared_secret and RSA_3072 config profiles");
}
return result;
}
catch (err) {
throw new Error("Configuration profile not supported. The library only supports the shared_secret and RSA_3072 config profiles");
}
};
exports.getConfigProfile = getConfigProfile;
const checkCertificate = (config, options) => {
const profile = (0, exports.getConfigProfile)(config);
if (profile === "RSA_3072") {
if (!options.cert) {
throw new Error("You have to specify --cert parameter for RSA_3072 agents");
}
if (!fs.existsSync(options.cert)) {
throw new Error(`Can't find file ${options.cert}`);
}
}
return profile === "RSA_3072";
};
exports.checkCertificate = checkCertificate;
const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
/**
* retry the function n times (while progressively waiting for the success) until success
* the waiting schema is iteration * timeoutInMiliseconds (default is 300ms)
*
* @param {number} n
* @param {Function} func
* @param {number} [timoutinMilliseconds=300]
* @param {Function} [logFunction]
* @returns
*/
const retry = (n_1, func_1, ...args_1) => __awaiter(void 0, [n_1, func_1, ...args_1], void 0, function* (n, func, timoutinMilliseconds = 300, logFunction) {
let error;
for (let i = 0; i < n; i++) {
try {
if (logFunction) {
logFunction();
}
if (i > 0) {
yield sleep(i * timoutinMilliseconds);
}
return yield func();
}
catch (err) {
error = err;
}
}
throw error;
});
exports.retry = retry;
const checkAssetId = (agentId) => {
if (!/[a-f0-9]{32}/gi.test(agentId)) {
throw new Error("You have to pass valid 32 char long asset id");
}
};
exports.checkAssetId = checkAssetId;
const throwError = (error) => {
throw new Error(error);
};
exports.throwError = throwError;
const toQueryString = (qs) => {
return Object.keys(qs || {})
.filter((key) => {
return qs[key] !== undefined;
})
.map((key) => {
const value = qs[key] instanceof Date ? qs[key].toISOString() : qs[key];
return encodeURIComponent(key) + "=" + encodeURIComponent(value);
})
.join("&");
};
exports.toQueryString = toQueryString;
const removeUndefined = (obj) => {
Object.keys(obj).forEach((key) => obj[key] === undefined && delete obj[key]);
return obj;
};
exports.removeUndefined = removeUndefined;
function checksumFile(hashName, path) {
return __awaiter(this, void 0, void 0, function* () {
return new Promise((resolve, reject) => {
const hash = crypto.createHash(hashName);
const stream = fs.createReadStream(path);
stream.on("error", (err) => reject(err));
stream.on("data", (chunk) => hash.update(chunk));
stream.on("end", () => resolve(hash.digest("hex")));
});
});
}
exports.checksumFile = checksumFile;
function pruneCert(s) {
return s
.split(/\r\n|\r|\n/)
.filter((x) => {
return x.indexOf("CERTIFICATE") < 0;
})
.join("");
}
exports.pruneCert = pruneCert;
function addAndStoreConfiguration(configuration) {
const newConfiguration = {
credentials: [],
};
(!configuration || !configuration.credentials) && (0, exports.throwError)("invalid configuration!");
configuration.credentials.forEach((element) => {
element.gateway = (0, exports.isUrl)(element.gateway) ? element.gateway : `https://gateway.${element.gateway}.mindsphere.io`;
newConfiguration.credentials.push(element.passkey ? (0, exports.encrypt)(element) : element);
});
checkList(newConfiguration.credentials);
(0, exports.storeAuth)(newConfiguration);
}
exports.addAndStoreConfiguration = addAndStoreConfiguration;
function checkList(list) {
let count = 0;
for (let i = 0; i < list.length; i++) {
const element = list[i];
element.selected && count++;
}
if (count !== 1) {
for (let i = 0; i < list.length; i++) {
const element = list[i];
element.selected = i === 0;
}
}
}
exports.checkList = checkList;
/**
* Iterates over all properties of an object and returns it serialized as data points
*
* @export
* @param {{ [x: string]: any }} obj Object to iterate over
* @param {string} aspect aspect name in mindsphere
* @param {((propertyName: string, aspect: string) => string | undefined)} dataPointFunction find id in the object
* @param {((propertyName: string, aspect: string) => string | undefined)} qualityCodeFunction find quality code in the object
* @param {(propertyName: string, aspect: string) => void} invalidDataFunction what to do if the data is not available
* @returns
*/
function convertToDataPoints(obj, aspect, dataPointFunction, qualityCodeFunction, invalidDataFunction) {
const res = [];
function recurse(obj) {
for (const propertyName in obj) {
const value = obj[propertyName];
if (value) {
if (Array.isArray(value)) {
const dataPointId = dataPointFunction(propertyName, aspect);
const qualityCode = qualityCodeFunction(propertyName, aspect);
if (!dataPointId || !qualityCode) {
invalidDataFunction(propertyName, aspect);
}
res.push({
dataPointId: `${dataPointId}`,
qualityCode: `${qualityCode}`,
value: `${JSON.stringify(value)}`,
});
}
else if (value && typeof value === "object") {
recurse(value);
}
else {
const dataPointId = dataPointFunction(propertyName, aspect);
const qualityCode = qualityCodeFunction(propertyName, aspect);
if (!dataPointId || !qualityCode) {
invalidDataFunction(propertyName, aspect);
}
res.push({
dataPointId: `${dataPointId}`,
qualityCode: `${qualityCode}`,
value: `${value}`,
});
}
}
}
}
recurse(obj);
return res;
}
exports.convertToDataPoints = convertToDataPoints;
function isGuid(x) {
const guidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
return guidRegex.test(x);
}
exports.isGuid = isGuid;
function printTree(treeItem, level, color) {
const prefix = level == 0 ? "" : "│ ".repeat(level) + "├─";
console.log(`${prefix}[${color(treeItem.data.assetId)}] ${treeItem.data.name} [${treeItem.data.typeId}]`);
treeItem.children.forEach((child) => {
printTree(child, level + 1, color);
});
}
exports.printTree = printTree;
function removeTrailingSlash(url) {
if (url.endsWith("/api/assetmanagement/v3/") || url.endsWith("/api/eventmanagement/v3/")) {
return url;
}
// console.log(url);
if (url.includes("?")) {
const parts = url.split("?");
parts[0] = parts[0].replace(/\/+$/, "");
return parts.join("?");
}
else {
return url.replace(/\/+$/, "");
}
}
exports.removeTrailingSlash = removeTrailingSlash;
//# sourceMappingURL=utils.js.map