oneuptime/probe/workers/apiMonitors.js
2021-05-10 21:09:13 +01:00

181 lines
6.1 KiB
JavaScript
Executable File

/* eslint-disable no-console */
const ApiService = require('../utils/apiService');
const ErrorService = require('../utils/errorService');
const fetch = require('node-fetch');
const sslCert = require('get-ssl-certificate');
const https = require('https');
const http = require('http');
const httpsAgent = new https.Agent({
rejectUnauthorized: false,
});
const httpAgent = new http.Agent();
// it collects all monitors then ping them one by one to store their response
// checks if the website of the url in the monitors is up or down
// creates incident if a website is down and resolves it when they come back up
module.exports = {
ping: async monitor => {
try {
if (monitor && monitor.type) {
if (monitor.data.url) {
const headers = await ApiService.headers(
monitor.headers,
monitor.bodyType
);
const body = await ApiService.body(
monitor && monitor.text && monitor.text.length
? monitor.text
: monitor.formData,
monitor && monitor.text && monitor.text.length
? 'text'
: 'formData'
);
let retry = true;
let retryCount = 0;
while (retry) {
const { res, resp, rawResp } = await pingfetch(
monitor.data.url,
monitor.method,
body,
headers
);
const response = await ApiService.ping(monitor._id, {
monitor,
res,
resp,
rawResp,
type: monitor.type,
retryCount,
});
if (response && !response.retry) {
retry = false;
} else {
retryCount++;
}
}
}
}
} catch (error) {
ErrorService.log('apiMonitors.ping', error);
throw error;
}
},
};
const pingfetch = async (url, method, body, headers) => {
const now = new Date().getTime();
let resp, res, response;
try {
let sslCertificate, data;
const urlObject = new URL(url);
const payload = {
method: method,
timeout: 120000,
};
if (headers && Object.keys(headers).length) {
payload.headers = headers;
}
if (body && Object.keys(body).length) {
payload.body = body;
}
try {
/* Try with a normal http / https agent.
If this fails we'll try with an agent which has
{
rejectUnauthorized: false,
}
to check for self-signed SSL certs.
*/
response = await fetch(url, { ...payload });
res = new Date().getTime() - now;
try {
/* Try getting response json body
If this fails, body is either empty or not valid json
and data should return null
*/
data = await response.json();
} catch (e) {
//
}
if (urlObject.protocol === 'https:') {
const certificate = await sslCert.get(urlObject.hostname);
if (certificate) {
sslCertificate = {
issuer: certificate.issuer,
expires: certificate.valid_to,
fingerprint: certificate.fingerprint,
selfSigned: false,
};
}
}
} catch (e) {
/* Retry with an agent which has
{
rejectUnauthorized: false,
}
to check for self-signed SSL certs.
*/
response = await fetch(url, {
...payload,
...(url.startsWith('https')
? { agent: httpsAgent }
: { agent: httpAgent }),
});
res = new Date().getTime() - now;
try {
/* Try getting response json body
If this fails, body is either empty or not valid json
and data should return null
*/
data = await response.json();
} catch (e) {
//
}
if (urlObject.protocol === 'https:') {
const certificate = await sslCert.get(urlObject.hostname);
if (certificate) {
sslCertificate = {
issuer: certificate.issuer,
expires: certificate.valid_to,
fingerprint: certificate.fingerprint,
selfSigned: e.code === 'DEPTH_ZERO_SELF_SIGNED_CERT',
};
}
}
}
resp = { status: response.status, body: data, sslCertificate };
} catch (error) {
res = new Date().getTime() - now;
resp = { status: 408, body: error };
}
return {
res,
resp,
rawResp: {
ok: response && response.ok ? response.ok : null,
status:
response && response.status
? response.status
: resp && resp.status
? resp.status
: null,
statusText:
response && response.statusText ? response.statusText : null,
headers:
response && response.headers && response.headers.raw()
? response.headers.raw()
: null,
body: resp && resp.body ? resp.body : null,
},
};
};