diff --git a/Kexa/emails/teams.ts b/Kexa/emails/teams.ts
new file mode 100644
index 00000000..eb68faaa
--- /dev/null
+++ b/Kexa/emails/teams.ts
@@ -0,0 +1,55 @@
+const levelAlert = ["info", "warning", "error", "fatal"];
+export const Teams = {
+ //https://learn.microsoft.com/en-us/microsoftteams/platform/webhooks-and-connectors/how-to/connectors-using?tabs=cURL
+ OneTeams: (color:string, subject:string, url:string, description:string) => {
+ return JSON.stringify({
+ "@type": "MessageCard",
+ "@context": "http://schema.org/extensions",
+ "themeColor": color,
+ "summary": subject,
+ "sections": [
+ {
+ "activityTitle": subject,
+ "activitySubtitle": description,
+ "activityImage": "https://kexa.io/kexa-no-background-color.png",
+ "markdown": true
+ }
+ ],
+ "potentialAction": [
+ {
+ "@type": "OpenUri",
+ "name": "Go to ressource",
+ "targets": [
+ {
+ "os": "default",
+ "uri": url
+ }
+ ]
+ }
+ ]
+ });
+ },
+ GlobalTeams: (color:string, subject:string, text:string, errors:{ [x: string]: number; }) => {
+ return JSON.stringify({
+ "@type": "MessageCard",
+ "@context": "http://schema.org/extensions",
+ "themeColor": color,
+ "summary": subject,
+ "sections": [
+ {
+ "activityTitle": subject,
+ "activitySubtitle": "Kexa by 4urcloud",
+ "activityImage": "https://kexa.io/kexa-no-background-color.png",
+ "text": text,
+ "facts": Object.entries(errors).map(([name, value]) => {
+ return {
+ "name": name,
+ "value": value.toString()
+ };
+ }),
+ "markdown": true
+ }
+ ]
+ });
+ },
+};
\ No newline at end of file
diff --git a/Kexa/helpers/extractURL.ts b/Kexa/helpers/extractURL.ts
new file mode 100644
index 00000000..4fe3f753
--- /dev/null
+++ b/Kexa/helpers/extractURL.ts
@@ -0,0 +1,34 @@
+const jsdom = require("jsdom")
+const { JSDOM } = jsdom
+global.DOMParser = new JSDOM().window.DOMParser
+
+export const extractURL = (text: string): string | null => {
+ return extractFirstURLFromHTML(text)??extractFirstURL(text);
+}
+
+function extractFirstURLFromHTML(html: string): string | null {
+ const parser = new DOMParser();
+ const doc = parser.parseFromString(html, 'text/html');
+
+ const urlElements = Array.from(doc.querySelectorAll('a[href], img[src]'));
+
+ for (const element of urlElements) {
+ const url = (element as HTMLAnchorElement).href || (element as HTMLImageElement).src;
+ if (url) {
+ return url;
+ }
+ }
+
+ return null;
+}
+
+function extractFirstURL(input:string): string | null {
+ const urlRegex = /(https?:\/\/[^\s]+)/g;
+ const matches = input.match(urlRegex);
+
+ if (matches && matches.length > 0) {
+ return matches[0];
+ }
+
+ return null;
+}
\ No newline at end of file
diff --git a/Kexa/helpers/spliter.ts b/Kexa/helpers/spliter.ts
new file mode 100644
index 00000000..c21e219a
--- /dev/null
+++ b/Kexa/helpers/spliter.ts
@@ -0,0 +1,21 @@
+export const splitProperty = (prop: string, delimiter:string, ignore:string="/"):string[] => {
+ const result = [];
+ let current = "";
+ let escape = false;
+
+ for (const char of prop) {
+ if (char === delimiter && !escape) {
+ result.push(current);
+ current = "";
+ } else if (char === ignore && !escape) {
+ escape = true;
+ } else {
+ if(escape && char !== delimiter) current += ignore;
+ current += char;
+ escape = false;
+ }
+ }
+
+ result.push(current);
+ return result;
+}
\ No newline at end of file
diff --git a/Kexa/services/alerte.service.ts b/Kexa/services/alerte.service.ts
index a9f5ae1a..5ab9cb98 100644
--- a/Kexa/services/alerte.service.ts
+++ b/Kexa/services/alerte.service.ts
@@ -11,12 +11,15 @@ import { Readable } from "stream";
import { propertyToSend, renderTableAllScan, renderTableAllScanLoud } from "./display.service";
import { groupBy } from "../helpers/groupBy";
import { getConfigOrEnvVar } from "./manageVarEnvironnement.service";
+import axios from 'axios';
+import { extractURL } from "../helpers/extractURL";
+import { Teams } from "../emails/teams";
const jsome = require('jsome');
jsome.level.show = true;
const request = require('request');
const nodemailer = require("nodemailer");
-const levelAlert = ["info", "warning", "error", "critical"];
+const levelAlert = ["info", "warning", "error", "fatal"];
const colors = ["#4f5660", "#ffcc00", "#cc3300", "#cc3300"];
const config = require('node-config-ts');
@@ -164,20 +167,24 @@ export function alertWebhookGlobal(alert: GlobalConfigAlert, compteError: number
export function alertTeamsGlobal(alert: GlobalConfigAlert, compteError: number[], allScan: ResultScan[][]) {
logger.debug("alert Teams Global");
- let content = compteRender(allScan);
- let nbrError: { [x: string]: number; }[] = [];
+ let nbrError: { [x: string]: number; } = {};
compteError.forEach((value, index) => {
- nbrError.push({
- [levelAlert[index]] : value
- });
+ nbrError[levelAlert[index]] = value;
});
- content["nbrError"] = nbrError;
- content["title"] = "Kexa - Global Alert - "+(alert.name??"Uname");
+ let content = ""
+ let render_table = renderTableAllScan(allScan.map(scan => scan.filter(value => value.error.length>0)));
+ let render_table_loud = renderTableAllScanLoud(allScan.map(scan => scan.filter(value => value.loud)));
+ content += render_table;
+ if(render_table_loud.length > 30){
+ content += "\n\n\n
Loud Section:
\n"
+ content += render_table_loud;
+ }
for (const teams_to of alert.to) {
const regex = /^https:\/\/(?:[a-zA-Z0-9_-]+\.)?webhook\.office\.com\/[^\s"]+$/;
- if(regex.test(teams_to)) return;
+ if(!regex.test(teams_to)) return;
logger.debug("send teams to:"+teams_to);
- sendCardMessageToTeamsChannel(teams_to, "Kexa - Global Alert - "+ (alert.name??"Uname"), content);
+ const payload = Teams.GlobalTeams(colors[0], "Global Alert - "+(alert.name??"Uname"), content, nbrError);
+ sendCardMessageToTeamsChannel(teams_to, payload);
}
}
@@ -307,11 +314,13 @@ export function alertTeams(detailAlert: ConfigAlert|GlobalConfigAlert ,rule: Rul
logger.debug("alert Teams");
for (const teams_to of detailAlert.to) {
const regex = /^https:\/\/(?:[a-zA-Z0-9_-]+\.)?webhook\.office\.com\/[^\s"]+$/;
- if(regex.test(teams_to)) return;
+ if(!regex.test(teams_to)) return;
let content = propertyToSend(rule, objectResource);
- sendCardMessageToTeamsChannel(teams_to, "Kexa - "+levelAlert[rule.level]+" - "+rule.name, content);
+ const payload = Teams.OneTeams(colors[rule.level], "Kexa - "+levelAlert[rule.level]+" - "+rule.name, extractURL(content)??"", rule.description??"");
+ sendCardMessageToTeamsChannel(teams_to, payload);
}
}
+
export function alertEmail(detailAlert: ConfigAlert|GlobalConfigAlert ,rule: Rules, conditions:SubResultScan[], objectResource:any){
logger.debug("alert email");
detailAlert.to.forEach((email_to) => {
@@ -414,7 +423,7 @@ async function sendWebhook(alert: ConfigAlert, subject: string, content: any) {
for (const webhook_to of alert.to) {
if(!webhook_to.includes("http")) continue;
const payload = {
- title: "Kexa scan : ",
+ title: "Kexa scan : " + subject,
text: content.content,
};
try {
@@ -426,25 +435,28 @@ async function sendWebhook(alert: ConfigAlert, subject: string, content: any) {
logger.error('Failed to send Webhook.');
}
} catch (error) {
- logger.error('Teams webhook : An error occurred:', error);
+ logger.error('Webhook : An error occurred:', error);
}
}
}
-import axios from 'axios';
-
-export async function sendCardMessageToTeamsChannel(channelWebhook: string, subject: string, content: any): Promise {
+export async function sendCardMessageToTeamsChannel(channelWebhook: string, payload:string): Promise {
const context = getContext();
if (!channelWebhook) {
logger.error("Cannot retrieve TEAMS_CHANNEL_WEBHOOK_URL from env");
throw("Error on TEAMS_CHANNEL_WEBHOOK_URL retrieve");
}
- const payload = {
- title: subject,
- text: content,
+ let config = {
+ method: 'post',
+ maxBodyLength: Infinity,
+ url: channelWebhook,
+ headers: {
+ 'Content-Type': 'application/json'
+ },
+ data : payload
};
try {
- const response = await axios.post(channelWebhook, payload);
+ const response = await axios.request(config);
if (response.status === 200) {
context?.log('Card sent successfully!');
logger.info('Card sent successfully!');
diff --git a/Kexa/services/analyse.service.ts b/Kexa/services/analyse.service.ts
index c102a34b..7f7a00a1 100644
--- a/Kexa/services/analyse.service.ts
+++ b/Kexa/services/analyse.service.ts
@@ -22,6 +22,7 @@ import { extractHeaders } from './addOn.service';
////////////////////////////////////////////////////////////////////////////////////////////////////////
import {getContext, getNewLogger} from "./logger.service";
+import { splitProperty } from '../helpers/spliter';
const logger = getNewLogger("AnalyseLogger");
const jsome = require('jsome');
@@ -430,7 +431,7 @@ export function parentResultScan(subResultScans: SubResultScan[], result: boolea
value: null,
condition: subResultScans.map((value) => value.condition).flat(),
result,
- message : subResultScans.map((value) => value.message).join(" || ")
+ message : subResultScans.map((value) => value.message).filter(item => item != "").join(" || ")
};
}
@@ -530,7 +531,7 @@ export function resultScan(condition: RulesConditions, value: any, fs: Function[
export function getSubProperty(object:any, property:string): any {
if (property === ".") return object;
- let properties = property.split(".");
+ let properties = splitProperty(property, ".", "/");
let result = object;
properties.forEach(prop => {
result = result[prop];
diff --git a/documentation/Documentation-Kexa.md b/documentation/Documentation-Kexa.md
index 80820116..ae5e40b5 100644
--- a/documentation/Documentation-Kexa.md
+++ b/documentation/Documentation-Kexa.md
@@ -472,6 +472,7 @@ Here is the structure and required fields for a new rule :
conditions: # the list of criteria to match
- property : string
# the object field name to check (you can see the objects fields by launching Kexa with npm run start:o option)
+ # for any property with a dot in his name, add "/" before the dot
condition : enum
# the condition for this comparison (defined in ./enum/condition.enum.ts)
value : string
diff --git a/package-lock.json b/package-lock.json
index 70f5b48c..96105e37 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,12 +1,12 @@
{
"name": "Kexa",
- "version": "1.10.0-SNAPSHOT.29.a6375e2",
+ "version": "1.10.0-SNAPSHOT.31.b2209bd",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "Kexa",
- "version": "1.10.0-SNAPSHOT.29.a6375e2",
+ "version": "1.10.0-SNAPSHOT.31.b2209bd",
"hasInstallScript": true,
"license": "MIT",
"dependencies": {
@@ -75,6 +75,7 @@
"googleapis": "^105.0.0",
"helm-ts": "^0.1.5",
"js-yaml": "^4.1.0",
+ "jsdom": "^23.0.1",
"jsome": "^2.3.26",
"moment": "^2.29.4",
"node-config-ts": "^3.3.1",
@@ -4634,6 +4635,17 @@
"node": ">= 8"
}
},
+ "node_modules/cssstyle": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-3.0.0.tgz",
+ "integrity": "sha512-N4u2ABATi3Qplzf0hWbVCdjenim8F3ojEXpBDF5hBpjzW182MjNGLqfmQ0SkSPeQ+V86ZXgeH8aXj6kayd4jgg==",
+ "dependencies": {
+ "rrweb-cssom": "^0.6.0"
+ },
+ "engines": {
+ "node": ">=14"
+ }
+ },
"node_modules/dashdash": {
"version": "1.14.1",
"resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz",
@@ -4645,6 +4657,49 @@
"node": ">=0.10"
}
},
+ "node_modules/data-urls": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-5.0.0.tgz",
+ "integrity": "sha512-ZYP5VBHshaDAiVZxjbRVcFJpc+4xGgT0bK3vzy1HLN8jTO975HEbuYzZJcHoQEY5K1a0z8YayJkyVETa08eNTg==",
+ "dependencies": {
+ "whatwg-mimetype": "^4.0.0",
+ "whatwg-url": "^14.0.0"
+ },
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/data-urls/node_modules/tr46": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/tr46/-/tr46-5.0.0.tgz",
+ "integrity": "sha512-tk2G5R2KRwBd+ZN0zaEXpmzdKyOYksXwywulIX95MBODjSzMIuQnQ3m8JxgbhnL1LeVo7lqQKsYa1O3Htl7K5g==",
+ "dependencies": {
+ "punycode": "^2.3.1"
+ },
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/data-urls/node_modules/webidl-conversions": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz",
+ "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==",
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/data-urls/node_modules/whatwg-url": {
+ "version": "14.0.0",
+ "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-14.0.0.tgz",
+ "integrity": "sha512-1lfMEm2IEr7RIV+f4lUNPOqfFL+pO+Xw3fJSqmjX9AbXcXcYOkCe1P6+9VBZB6n94af16NfZf+sSk0JCBZC9aw==",
+ "dependencies": {
+ "tr46": "^5.0.0",
+ "webidl-conversions": "^7.0.0"
+ },
+ "engines": {
+ "node": ">=18"
+ }
+ },
"node_modules/dayjs": {
"version": "1.11.10",
"resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.10.tgz",
@@ -4678,6 +4733,11 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
+ "node_modules/decimal.js": {
+ "version": "10.4.3",
+ "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.4.3.tgz",
+ "integrity": "sha512-VBBaLc1MgL5XpzgIP7ny5Z6Nx3UrRkIViUkPUdtl9aya5amy3De1gsUUSB1g3+3sExYNjCAsAznmukyxCb1GRA=="
+ },
"node_modules/deep-eql": {
"version": "4.1.3",
"resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-4.1.3.tgz",
@@ -6304,6 +6364,17 @@
"@typescript-eslint/eslint-plugin": "^4.1.1"
}
},
+ "node_modules/html-encoding-sniffer": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-4.0.0.tgz",
+ "integrity": "sha512-Y22oTqIU4uuPgEemfz7NDJz6OeKf12Lsu+QC+s3BVpda64lTiMYCyGwg5ki4vFxkMwQdeZDl2adZoqUgdFuTgQ==",
+ "dependencies": {
+ "whatwg-encoding": "^3.1.1"
+ },
+ "engines": {
+ "node": ">=18"
+ }
+ },
"node_modules/http-proxy-agent": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-5.0.0.tgz",
@@ -6676,6 +6747,11 @@
"node": ">=0.10.0"
}
},
+ "node_modules/is-potential-custom-element-name": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz",
+ "integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ=="
+ },
"node_modules/is-regex": {
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz",
@@ -6922,6 +6998,125 @@
"node": ">=8"
}
},
+ "node_modules/jsdom": {
+ "version": "23.0.1",
+ "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-23.0.1.tgz",
+ "integrity": "sha512-2i27vgvlUsGEBO9+/kJQRbtqtm+191b5zAZrU/UezVmnC2dlDAFLgDYJvAEi94T4kjsRKkezEtLQTgsNEsW2lQ==",
+ "dependencies": {
+ "cssstyle": "^3.0.0",
+ "data-urls": "^5.0.0",
+ "decimal.js": "^10.4.3",
+ "form-data": "^4.0.0",
+ "html-encoding-sniffer": "^4.0.0",
+ "http-proxy-agent": "^7.0.0",
+ "https-proxy-agent": "^7.0.2",
+ "is-potential-custom-element-name": "^1.0.1",
+ "nwsapi": "^2.2.7",
+ "parse5": "^7.1.2",
+ "rrweb-cssom": "^0.6.0",
+ "saxes": "^6.0.0",
+ "symbol-tree": "^3.2.4",
+ "tough-cookie": "^4.1.3",
+ "w3c-xmlserializer": "^5.0.0",
+ "webidl-conversions": "^7.0.0",
+ "whatwg-encoding": "^3.1.1",
+ "whatwg-mimetype": "^4.0.0",
+ "whatwg-url": "^14.0.0",
+ "ws": "^8.14.2",
+ "xml-name-validator": "^5.0.0"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "peerDependencies": {
+ "canvas": "^2.11.2"
+ },
+ "peerDependenciesMeta": {
+ "canvas": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/jsdom/node_modules/agent-base": {
+ "version": "7.1.0",
+ "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.0.tgz",
+ "integrity": "sha512-o/zjMZRhJxny7OyEF+Op8X+efiELC7k7yOjMzgfzVqOzXqkBkWI79YoTdOtsuWd5BWhAGAuOY/Xa6xpiaWXiNg==",
+ "dependencies": {
+ "debug": "^4.3.4"
+ },
+ "engines": {
+ "node": ">= 14"
+ }
+ },
+ "node_modules/jsdom/node_modules/http-proxy-agent": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.0.tgz",
+ "integrity": "sha512-+ZT+iBxVUQ1asugqnD6oWoRiS25AkjNfG085dKJGtGxkdwLQrMKU5wJr2bOOFAXzKcTuqq+7fZlTMgG3SRfIYQ==",
+ "dependencies": {
+ "agent-base": "^7.1.0",
+ "debug": "^4.3.4"
+ },
+ "engines": {
+ "node": ">= 14"
+ }
+ },
+ "node_modules/jsdom/node_modules/https-proxy-agent": {
+ "version": "7.0.2",
+ "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.2.tgz",
+ "integrity": "sha512-NmLNjm6ucYwtcUmL7JQC1ZQ57LmHP4lT15FQ8D61nak1rO6DH+fz5qNK2Ap5UN4ZapYICE3/0KodcLYSPsPbaA==",
+ "dependencies": {
+ "agent-base": "^7.0.2",
+ "debug": "4"
+ },
+ "engines": {
+ "node": ">= 14"
+ }
+ },
+ "node_modules/jsdom/node_modules/tough-cookie": {
+ "version": "4.1.3",
+ "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.3.tgz",
+ "integrity": "sha512-aX/y5pVRkfRnfmuX+OdbSdXvPe6ieKX/G2s7e98f4poJHnqH3281gDPm/metm6E/WRamfx7WC4HUqkWHfQHprw==",
+ "dependencies": {
+ "psl": "^1.1.33",
+ "punycode": "^2.1.1",
+ "universalify": "^0.2.0",
+ "url-parse": "^1.5.3"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/jsdom/node_modules/tr46": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/tr46/-/tr46-5.0.0.tgz",
+ "integrity": "sha512-tk2G5R2KRwBd+ZN0zaEXpmzdKyOYksXwywulIX95MBODjSzMIuQnQ3m8JxgbhnL1LeVo7lqQKsYa1O3Htl7K5g==",
+ "dependencies": {
+ "punycode": "^2.3.1"
+ },
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/jsdom/node_modules/webidl-conversions": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz",
+ "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==",
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/jsdom/node_modules/whatwg-url": {
+ "version": "14.0.0",
+ "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-14.0.0.tgz",
+ "integrity": "sha512-1lfMEm2IEr7RIV+f4lUNPOqfFL+pO+Xw3fJSqmjX9AbXcXcYOkCe1P6+9VBZB6n94af16NfZf+sSk0JCBZC9aw==",
+ "dependencies": {
+ "tr46": "^5.0.0",
+ "webidl-conversions": "^7.0.0"
+ },
+ "engines": {
+ "node": ">=18"
+ }
+ },
"node_modules/jsome": {
"version": "2.5.0",
"resolved": "https://registry.npmjs.org/jsome/-/jsome-2.5.0.tgz",
@@ -8016,6 +8211,11 @@
"node": ">=0.10.0"
}
},
+ "node_modules/nwsapi": {
+ "version": "2.2.7",
+ "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.7.tgz",
+ "integrity": "sha512-ub5E4+FBPKwAZx0UwIQOjYWGHTEq5sPqHQNRN8Z9e4A7u3Tj1weLJsL59yH9vmvqEtBHaOmT6cYQKIZOxp35FQ=="
+ },
"node_modules/oauth-sign": {
"version": "0.9.0",
"resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz",
@@ -8304,6 +8504,28 @@
"node": ">=6"
}
},
+ "node_modules/parse5": {
+ "version": "7.1.2",
+ "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.1.2.tgz",
+ "integrity": "sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw==",
+ "dependencies": {
+ "entities": "^4.4.0"
+ },
+ "funding": {
+ "url": "https://github.com/inikulin/parse5?sponsor=1"
+ }
+ },
+ "node_modules/parse5/node_modules/entities": {
+ "version": "4.5.0",
+ "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz",
+ "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==",
+ "engines": {
+ "node": ">=0.12"
+ },
+ "funding": {
+ "url": "https://github.com/fb55/entities?sponsor=1"
+ }
+ },
"node_modules/path-exists": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
@@ -8923,6 +9145,11 @@
"url": "https://github.com/sponsors/isaacs"
}
},
+ "node_modules/rrweb-cssom": {
+ "version": "0.6.0",
+ "resolved": "https://registry.npmjs.org/rrweb-cssom/-/rrweb-cssom-0.6.0.tgz",
+ "integrity": "sha512-APM0Gt1KoXBz0iIkkdB/kfvGOwC4UuJFeG/c+yV7wSc7q96cG/kJ0HiYCnzivD9SB53cLV1MlHFNfOuPaadYSw=="
+ },
"node_modules/run-parallel": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz",
@@ -9009,6 +9236,17 @@
"resolved": "https://registry.npmjs.org/sax/-/sax-1.2.1.tgz",
"integrity": "sha512-8I2a3LovHTOpm7NV5yOyO8IHqgVsfK4+UuySrXU8YXkSRX7k6hCV9b3HrkKCr3nMpgj+0bmocaJJWpvp1oc7ZA=="
},
+ "node_modules/saxes": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/saxes/-/saxes-6.0.0.tgz",
+ "integrity": "sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==",
+ "dependencies": {
+ "xmlchars": "^2.2.0"
+ },
+ "engines": {
+ "node": ">=v12.22.7"
+ }
+ },
"node_modules/scmp": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/scmp/-/scmp-2.1.0.tgz",
@@ -9457,6 +9695,11 @@
"url": "https://github.com/chalk/supports-color?sponsor=1"
}
},
+ "node_modules/symbol-tree": {
+ "version": "3.2.4",
+ "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz",
+ "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw=="
+ },
"node_modules/table": {
"version": "6.8.1",
"resolved": "https://registry.npmjs.org/table/-/table-6.8.1.tgz",
@@ -9912,6 +10155,14 @@
"resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-6.0.1.tgz",
"integrity": "sha512-yCzhz6FN2wU1NiiQRogkTQszlQSlpWaw8SvVegAc+bDxbzHgh1vX8uIe8OYyMH6DwH+sdTJsgMl36+mSMdRJIQ=="
},
+ "node_modules/universalify": {
+ "version": "0.2.0",
+ "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.2.0.tgz",
+ "integrity": "sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==",
+ "engines": {
+ "node": ">= 4.0.0"
+ }
+ },
"node_modules/uri-js": {
"version": "4.4.1",
"resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz",
@@ -10002,11 +10253,41 @@
"extsprintf": "^1.2.0"
}
},
+ "node_modules/w3c-xmlserializer": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-5.0.0.tgz",
+ "integrity": "sha512-o8qghlI8NZHU1lLPrpi2+Uq7abh4GGPpYANlalzWxyWteJOCsr/P+oPBA49TOLu5FTZO4d3F9MnWJfiMo4BkmA==",
+ "dependencies": {
+ "xml-name-validator": "^5.0.0"
+ },
+ "engines": {
+ "node": ">=18"
+ }
+ },
"node_modules/webidl-conversions": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
"integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ=="
},
+ "node_modules/whatwg-encoding": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-3.1.1.tgz",
+ "integrity": "sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ==",
+ "dependencies": {
+ "iconv-lite": "0.6.3"
+ },
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/whatwg-mimetype": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-4.0.0.tgz",
+ "integrity": "sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg==",
+ "engines": {
+ "node": ">=18"
+ }
+ },
"node_modules/whatwg-url": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz",
@@ -10166,6 +10447,14 @@
}
}
},
+ "node_modules/xml-name-validator": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-5.0.0.tgz",
+ "integrity": "sha512-EvGK8EJ3DhaHfbRlETOWAS5pO9MZITeauHKJyb8wyajUfQUenkIg2MvLDTZ4T/TgIcm3HU0TFBgWWboAZ30UHg==",
+ "engines": {
+ "node": ">=18"
+ }
+ },
"node_modules/xml2js": {
"version": "0.5.0",
"resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.5.0.tgz",
@@ -10194,6 +10483,11 @@
"node": ">=6.0"
}
},
+ "node_modules/xmlchars": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz",
+ "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw=="
+ },
"node_modules/xmlcreate": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/xmlcreate/-/xmlcreate-2.0.4.tgz",
diff --git a/package.json b/package.json
index f4fae57c..d82edd26 100644
--- a/package.json
+++ b/package.json
@@ -65,6 +65,7 @@
"googleapis": "^105.0.0",
"helm-ts": "^0.1.5",
"js-yaml": "^4.1.0",
+ "jsdom": "^23.0.1",
"jsome": "^2.3.26",
"moment": "^2.29.4",
"node-config-ts": "^3.3.1",
@@ -114,4 +115,4 @@
"author": "4urcloud | Esteban MATHIA | Adrien EPPLING",
"license": "MIT",
"description": "Kexa helps you save money and automate the standardization, security and verification of your cloud deployments."
-}
\ No newline at end of file
+}