import Hostname from 'Common/Types/API/Hostname'; import URL from 'Common/Types/API/URL'; import { LIMIT_PER_PROJECT } from 'Common/Types/Database/LimitMax'; import Dictionary from 'Common/Types/Dictionary'; import { PromiseVoidFunction } from 'Common/Types/FunctionTypes'; import IP from 'Common/Types/IP/IP'; import { JSONObject } from 'Common/Types/JSON'; import JSONFunctions from 'Common/Types/JSONFunctions'; import MonitorType from 'Common/Types/Monitor/MonitorType'; import MonitorSecretService from 'CommonServer/Services/MonitorSecretService'; import QueryHelper from 'CommonServer/Types/Database/QueryHelper'; import VMUtil from 'CommonServer/Utils/VM/VMAPI'; import Monitor from 'Model/Models/Monitor'; import MonitorSecret from 'Model/Models/MonitorSecret'; export default class MonitorUtil { public static async populateSecrets(monitor: Monitor): Promise { const isSecretsLoaded: boolean = false; let monitorSecrets: MonitorSecret[] = []; const loadSecrets: PromiseVoidFunction = async (): Promise => { if (isSecretsLoaded) { return; } if (!monitor.id) { return; } const secrets: Array = await MonitorSecretService.findBy({ query: { monitors: QueryHelper.in([monitor.id]), }, select: { secretValue: true, name: true, }, limit: LIMIT_PER_PROJECT, skip: 0, props: { isRoot: true, }, }); monitorSecrets = secrets; }; if (!monitor.monitorSteps) { return monitor; } if (monitor.monitorType === MonitorType.API) { for (const monitorStep of monitor.monitorSteps?.data ?.monitorStepsInstanceArray || []) { if ( monitorStep.data?.requestHeaders && this.hasSecrets( JSONFunctions.toString(monitorStep.data.requestHeaders) ) ) { await loadSecrets(); monitorStep.data.requestHeaders = (await MonitorUtil.fillSecretsInStringOrJSON({ secrets: monitorSecrets, populateSecretsIn: monitorStep.data.requestHeaders, })) as Dictionary; } else if ( monitorStep.data?.requestBody && this.hasSecrets( JSONFunctions.toString(monitorStep.data.requestBody) ) ) { await loadSecrets(); monitorStep.data.requestBody = (await MonitorUtil.fillSecretsInStringOrJSON({ secrets: monitorSecrets, populateSecretsIn: monitorStep.data.requestBody, })) as string; } } } if ( monitor.monitorType === MonitorType.API || monitor.monitorType === MonitorType.IP || monitor.monitorType === MonitorType.Ping || monitor.monitorType === MonitorType.Port || monitor.monitorType === MonitorType.Website || monitor.monitorType === MonitorType.SSLCertificate ) { for (const monitorStep of monitor.monitorSteps?.data ?.monitorStepsInstanceArray || []) { if ( monitorStep.data?.monitorDestination && this.hasSecrets( JSONFunctions.toString( monitorStep.data.monitorDestination ) ) ) { // replace secret in monitorDestination. await loadSecrets(); monitorStep.data.monitorDestination = (await MonitorUtil.fillSecretsInStringOrJSON({ secrets: monitorSecrets, populateSecretsIn: monitorStep.data.monitorDestination, })) as URL | Hostname | IP; } } } if ( monitor.monitorType === MonitorType.SyntheticMonitor || monitor.monitorType === MonitorType.CustomJavaScriptCode ) { for (const monitorStep of monitor.monitorSteps?.data ?.monitorStepsInstanceArray || []) { if ( monitorStep.data?.customCode && this.hasSecrets( JSONFunctions.toString(monitorStep.data.customCode) ) ) { // replace secret in script await loadSecrets(); monitorStep.data.customCode = (await MonitorUtil.fillSecretsInStringOrJSON({ secrets: monitorSecrets, populateSecretsIn: monitorStep.data.customCode, })) as string; } } } return monitor; } private static hasSecrets(prepopulatedString: string): boolean { return prepopulatedString.includes('monitorSecrets.'); } private static async fillSecretsInStringOrJSON(data: { secrets: MonitorSecret[]; populateSecretsIn: string | JSONObject | URL | Hostname | IP; }): Promise { // get all secrets for this monitor. const secrets: MonitorSecret[] = data.secrets; if (secrets.length === 0) { return data.populateSecretsIn; } // replace all secrets in the populateSecretsIn const storageMap: JSONObject = { monitorSecrets: {}, }; for (const monitorSecret of secrets) { if (!monitorSecret.name) { continue; } if (!monitorSecret.secretValue) { continue; } (storageMap['monitorSecrets'] as JSONObject)[ monitorSecret.name as string ] = monitorSecret.secretValue; } const isValueJSON: boolean = typeof data.populateSecretsIn === 'object'; return VMUtil.replaceValueInPlace( storageMap, data.populateSecretsIn as string, isValueJSON ); } }