diff --git a/.vscode/launch.json b/.vscode/launch.json index e1a11413ce..e53425836b 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -139,34 +139,6 @@ "restart": true, "autoAttachChildProcesses": true }, - { - "address": "127.0.0.1", - "localRoot": "${workspaceFolder}/Ingestor", - "name": "Probe API: Debug with Docker", - "port": 9251, - "remoteRoot": "/usr/src/app", - "request": "attach", - "skipFiles": [ - "/**" - ], - "type": "node", - "restart": true, - "autoAttachChildProcesses": true - }, - { - "address": "127.0.0.1", - "localRoot": "${workspaceFolder}/Identity", - "name": "File: Debug with Docker", - "port": 9012, - "remoteRoot": "/usr/src/app", - "request": "attach", - "skipFiles": [ - "/**" - ], - "type": "node", - "restart": true, - "autoAttachChildProcesses": true - }, { "address": "127.0.0.1", "localRoot": "${workspaceFolder}/HttpTestServer", diff --git a/Common/Types/Monitor/MonitorCriteriaInstance.ts b/Common/Types/Monitor/MonitorCriteriaInstance.ts index 93810fb0e8..d731673daf 100644 --- a/Common/Types/Monitor/MonitorCriteriaInstance.ts +++ b/Common/Types/Monitor/MonitorCriteriaInstance.ts @@ -79,7 +79,7 @@ export default class MonitorCriteriaInstance extends DatabaseProperty { return monitorCriteriaInstance; } - if (arg.monitorType === MonitorType.SSL) { + if (arg.monitorType === MonitorType.SSLCertificate) { const monitorCriteriaInstance: MonitorCriteriaInstance = new MonitorCriteriaInstance(); @@ -282,7 +282,7 @@ export default class MonitorCriteriaInstance extends DatabaseProperty { }; } - if (arg.monitorType === MonitorType.SSL) { + if (arg.monitorType === MonitorType.SSLCertificate) { monitorCriteriaInstance.data = { id: ObjectID.generate().toString(), monitorStatusId: arg.monitorStatusId, diff --git a/Common/Types/Monitor/MonitorStep.ts b/Common/Types/Monitor/MonitorStep.ts index 206af1d854..c2b659a863 100644 --- a/Common/Types/Monitor/MonitorStep.ts +++ b/Common/Types/Monitor/MonitorStep.ts @@ -136,7 +136,7 @@ export default class MonitorStep extends DatabaseProperty { monitorType === MonitorType.Ping || monitorType === MonitorType.Website || monitorType === MonitorType.IP || - monitorType === MonitorType.SSL) + monitorType === MonitorType.SSLCertificate) ) { return 'Monitor Destination is required'; } diff --git a/Common/Types/Monitor/MonitorType.ts b/Common/Types/Monitor/MonitorType.ts index 0f0607ab5d..ff64eae830 100644 --- a/Common/Types/Monitor/MonitorType.ts +++ b/Common/Types/Monitor/MonitorType.ts @@ -10,7 +10,7 @@ enum MonitorType { IncomingRequest = 'Incoming Request', Port = 'Port', Server = 'Server', - SSL = 'SSL', + SSLCertificate = 'SSL Certificate', } export default MonitorType; @@ -79,8 +79,8 @@ export class MonitorTypeHelper { 'This monitor types lets you monitor any server, VM, or any machine.', }, { - monitorType: MonitorType.SSL, - title: 'SSL', + monitorType: MonitorType.SSLCertificate, + title: 'SSL Certificate', description: 'This monitor types lets you monitor SSL certificates of any domain.', }, diff --git a/CommonServer/Services/MonitorService.ts b/CommonServer/Services/MonitorService.ts index bd634cfe0a..8446224b56 100644 --- a/CommonServer/Services/MonitorService.ts +++ b/CommonServer/Services/MonitorService.ts @@ -161,7 +161,7 @@ export class Service extends DatabaseService { createdItem.monitorType === MonitorType.Ping || createdItem.monitorType === MonitorType.IP || createdItem.monitorType === MonitorType.Port || - createdItem.monitorType === MonitorType.SSL) + createdItem.monitorType === MonitorType.SSLCertificate) ) { await this.addDefaultProbesToMonitor( createdItem.projectId, diff --git a/CommonServer/Utils/Probe/Criteria/SSLMonitorCriteria.ts b/CommonServer/Utils/Probe/Criteria/SSLMonitorCriteria.ts index dc094f6cd6..5671f45fcd 100644 --- a/CommonServer/Utils/Probe/Criteria/SSLMonitorCriteria.ts +++ b/CommonServer/Utils/Probe/Criteria/SSLMonitorCriteria.ts @@ -14,10 +14,6 @@ export default class ServerMonitorCriteria { dataToProcess: DataToProcess; criteriaFilter: CriteriaFilter; }): Promise { - // Server Monitoring Checks - - debugger; - let threshold: number | string | undefined | null = input.criteriaFilter.value; diff --git a/CommonServer/Utils/Probe/ProbeMonitorResponse.ts b/CommonServer/Utils/Probe/ProbeMonitorResponse.ts index ce42356c94..c7d26f9e4d 100644 --- a/CommonServer/Utils/Probe/ProbeMonitorResponse.ts +++ b/CommonServer/Utils/Probe/ProbeMonitorResponse.ts @@ -124,7 +124,7 @@ export default class ProbeMonitorResponseService { monitor.monitorType === MonitorType.IP || monitor.monitorType === MonitorType.Ping || monitor.monitorType === MonitorType.Website || - monitor.monitorType === MonitorType.SSL + monitor.monitorType === MonitorType.SSLCertificate ) { dataToProcess = dataToProcess as ProbeMonitorResponse; if ((dataToProcess as ProbeMonitorResponse).probeId) { @@ -1077,7 +1077,7 @@ export default class ProbeMonitorResponseService { } } - if (input.monitor.monitorType === MonitorType.SSL) { + if (input.monitor.monitorType === MonitorType.SSLCertificate) { // check server monitor const sslMonitorResult: string | null = await SSLMonitorCriteria.isMonitorInstanceCriteriaFilterMet({ diff --git a/Dashboard/src/Components/Form/Monitor/MonitorStep.tsx b/Dashboard/src/Components/Form/Monitor/MonitorStep.tsx index 8aeb435cf0..ab6e1d2746 100644 --- a/Dashboard/src/Components/Form/Monitor/MonitorStep.tsx +++ b/Dashboard/src/Components/Form/Monitor/MonitorStep.tsx @@ -188,7 +188,7 @@ const MonitorStepElement: FunctionComponent = ( destination = URL.fromString(value); } else if ( props.monitorType === - MonitorType.SSL + MonitorType.SSLCertificate ) { destination = URL.fromString(value); } diff --git a/Dashboard/src/Utils/Form/Monitor/CriteriaFilter.ts b/Dashboard/src/Utils/Form/Monitor/CriteriaFilter.ts index f025677a1f..a45ed35825 100644 --- a/Dashboard/src/Utils/Form/Monitor/CriteriaFilter.ts +++ b/Dashboard/src/Utils/Form/Monitor/CriteriaFilter.ts @@ -183,7 +183,7 @@ export default class CriteriaFilterUtil { }); } - if (monitorType === MonitorType.SSL) { + if (monitorType === MonitorType.SSLCertificate) { options = options.filter((i: DropdownOption) => { return ( i.value === CheckOn.IsValidCertificate || diff --git a/Probe/Utils/Monitors/Monitor.ts b/Probe/Utils/Monitors/Monitor.ts index aaa52448de..a325d68c68 100644 --- a/Probe/Utils/Monitors/Monitor.ts +++ b/Probe/Utils/Monitors/Monitor.ts @@ -198,7 +198,7 @@ export default class MonitorUtil { result.failureCause = response.failureCause; } - if (monitor.monitorType === MonitorType.SSL) { + if (monitor.monitorType === MonitorType.SSLCertificate) { if (!monitorStep.data?.monitorDestination) { result.isOnline = false; result.responseTimeInMs = 0; diff --git a/Probe/Utils/Monitors/MonitorTypes/SslMonitor.ts b/Probe/Utils/Monitors/MonitorTypes/SslMonitor.ts index 5dbf3434ca..969ba69d69 100644 --- a/Probe/Utils/Monitors/MonitorTypes/SslMonitor.ts +++ b/Probe/Utils/Monitors/MonitorTypes/SslMonitor.ts @@ -10,7 +10,7 @@ import https, { RequestOptions } from 'https'; import ObjectUtil from 'Common/Utils/ObjectUtil'; import BadDataException from 'Common/Types/Exception/BadDataException'; import OneUptimeDate from 'Common/Types/Date'; -import { IncomingMessage } from 'http'; +import { ClientRequest, IncomingMessage } from 'http'; export interface SslResponse extends SSLMonitorReponse { isOnline: boolean; @@ -114,18 +114,86 @@ export default class SSLMonitor { host: string, port = 443 ): Promise { - debugger; + let isSelfSigned = false; + let certificate: tls.PeerCertificate | null = null; - const sslPromise = new Promise( + try { + certificate = await this.getCertificate({ + host, + port, + rejectUnauthorized: true, + }); + } catch (err) { + try { + certificate = await this.getCertificate({ + host, + port, + rejectUnauthorized: false, + }); + + isSelfSigned = true; + } catch (err) { + return { + isOnline: false, + failureCause: (err as any).toString(), + }; + } + } + + if (!certificate) { + return { + isOnline: false, + failureCause: 'No certificate found', + }; + } + + const res: SslResponse = { + isOnline: true, + isSelfSigned: isSelfSigned, + createdAt: OneUptimeDate.fromString(certificate.valid_from), + expiresAt: OneUptimeDate.fromString(certificate.valid_to), + commonName: certificate.subject.CN, + organizationalUnit: certificate.subject.OU, + organization: certificate.subject.O, + locality: certificate.subject.L, + state: certificate.subject.ST, + country: certificate.subject.C, + serialNumber: certificate.serialNumber, + fingerprint: certificate.fingerprint, + fingerprint256: certificate.fingerprint256, + failureCause: '', + }; + + return res; + } + + public static async getCertificate(data: { + host: string; + port: number; + rejectUnauthorized: boolean; + }): Promise { + const { host, rejectUnauthorized } = data; + + let { port } = data; + + if (!port) { + port = 443; + } + + const sslPromise: Promise = new Promise( ( resolve: (value: tls.PeerCertificate) => void, reject: (err: Error) => void ) => { - const requestOptions = this.getOptions(host, port); + const requestOptions: https.RequestOptions = this.getOptions( + host, + port, + rejectUnauthorized + ); - let isResolvedOrRejected = false; + let isResolvedOrRejected: boolean = false; - const req = https.get( + const req: ClientRequest = https.get( requestOptions, (res: IncomingMessage) => { const certificate: tls.PeerCertificate = ( @@ -158,31 +226,18 @@ export default class SSLMonitor { const certificate: tls.PeerCertificate = await sslPromise; - const res: SslResponse = { - isOnline: true, - isSelfSigned: certificate.issuer.CN === certificate.subject.CN, - createdAt: OneUptimeDate.fromString(certificate.valid_from), - expiresAt: OneUptimeDate.fromString(certificate.valid_to), - commonName: certificate.subject.CN, - organizationalUnit: certificate.subject.OU, - organization: certificate.subject.O, - locality: certificate.subject.L, - state: certificate.subject.ST, - country: certificate.subject.C, - serialNumber: certificate.serialNumber, - fingerprint: certificate.fingerprint, - fingerprint256: certificate.fingerprint256, - failureCause: '', - }; - - return res; + return certificate; } - private static getOptions(url: string, port: number): RequestOptions { + private static getOptions( + url: string, + port: number, + rejectUnauthorized: boolean + ): RequestOptions { return { hostname: url, agent: false, - rejectUnauthorized: false, + rejectUnauthorized: rejectUnauthorized, ciphers: 'ALL', port, protocol: 'https:',