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 +}