Skip to content

Commit 6cfef94

Browse files
authored
Merge pull request #25 from FreeOps-Tools/dev
Dev
2 parents 554b938 + e96a73e commit 6cfef94

2 files changed

Lines changed: 152 additions & 20 deletions

File tree

modules/analyze.js

Lines changed: 92 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -5,28 +5,73 @@ const now = require('performance-now');
55
const { isURL } = require('validator');
66
const makeHttpRequest = require('./httpRequest');
77
const performDnsLookup = require('./dnsLookup');
8+
const checkSSLCertificate = require('./sslCheck');
89

910
function analyzeURL(req, res) {
1011
try {
1112
if (!req.body.url) {
1213
throw new Error('URL is missing');
1314
}
1415

15-
const urlToAnalyze = req.body.url;
16+
let urlToAnalyze = req.body.url.trim();
17+
const originalUrl = urlToAnalyze;
18+
const parsedUrl = url.parse(urlToAnalyze);
19+
const hadProtocol = !!parsedUrl.protocol;
20+
21+
// If no protocol, try HTTPS first
22+
if (!hadProtocol) {
23+
urlToAnalyze = `https://${urlToAnalyze}`;
24+
}
1625

26+
// Validate the URL
1727
if (!isURL(urlToAnalyze)) {
1828
throw new Error('Invalid URL');
1929
}
2030

2131
const hostname = url.parse(urlToAnalyze).hostname;
32+
const isHttps = urlToAnalyze.startsWith('https://');
33+
34+
// Try the request
2235
makeHttpRequest(urlToAnalyze, {}, (responseDetails, latencyMs, httpRequestError) => {
36+
// If HTTPS failed and we added the protocol (no protocol originally), try HTTP as fallback
37+
if (httpRequestError && isHttps && !hadProtocol) {
38+
const httpUrl = urlToAnalyze.replace('https://', 'http://');
39+
return makeHttpRequest(httpUrl, {}, (httpResponseDetails, httpLatencyMs, httpError) => {
40+
if (httpError || !httpResponseDetails) {
41+
return res.json({
42+
isUp: false,
43+
ipAddress: null,
44+
uptime: 0,
45+
latencyMs: 0,
46+
dnsLookupMs: 0,
47+
statusCode: null,
48+
protocol: 'http',
49+
sslInfo: null
50+
});
51+
}
52+
processResponse(httpResponseDetails, httpLatencyMs, hostname, 'http', res);
53+
});
54+
}
55+
2356
if (httpRequestError || !responseDetails) {
2457
console.error(`Failed to request ${urlToAnalyze}: ${httpRequestError || 'Unknown error'}`);
25-
return res.json({ isUp: false, ipAddress: null, uptime: 0, latencyMs: 0, dnsLookupMs: 0 });
58+
return res.json({
59+
isUp: false,
60+
ipAddress: null,
61+
uptime: 0,
62+
latencyMs: 0,
63+
dnsLookupMs: 0,
64+
statusCode: null,
65+
protocol: isHttps ? 'https' : 'http',
66+
sslInfo: null
67+
});
2668
}
69+
70+
processResponse(responseDetails, latencyMs, hostname, isHttps ? 'https' : 'http', res);
71+
});
2772

28-
const isUp =
29-
responseDetails.statusCode >= 200 && responseDetails.statusCode < 400;
73+
function processResponse(responseDetails, latencyMs, hostname, protocol, res) {
74+
const isUp = responseDetails.statusCode >= 200 && responseDetails.statusCode < 400;
3075
if (!isUp) {
3176
return res.json({
3277
isUp: false,
@@ -35,31 +80,58 @@ function analyzeURL(req, res) {
3580
latencyMs,
3681
dnsLookupMs: 0,
3782
statusCode: responseDetails.statusCode,
83+
protocol: protocol,
84+
sslInfo: null
3885
});
3986
}
4087

4188
performDnsLookup(hostname, ({ ipAddress, lookupMs, error: dnsLookupError }) => {
4289
if (dnsLookupError) {
43-
console.error(`Failed to lookup IP address for ${urlToAnalyze}: ${dnsLookupError}`);
90+
console.error(`Failed to lookup IP address: ${dnsLookupError}`);
4491
return res.status(500).json({ error: 'Internal server error' });
4592
}
4693

47-
// Calculate uptime baseline on successful check
48-
const uptime = 100;
49-
50-
console.log(
51-
`isUp: ${isUp}, ipAddress: ${ipAddress}, uptime: ${uptime}%, latencyMs: ${latencyMs}, dnsLookupMs: ${lookupMs}`
52-
);
53-
return res.json({
54-
isUp: true,
55-
ipAddress,
56-
uptime,
57-
latencyMs,
58-
dnsLookupMs: lookupMs,
59-
statusCode: responseDetails.statusCode,
60-
});
94+
// Check SSL certificate if HTTPS
95+
if (protocol === 'https') {
96+
checkSSLCertificate(hostname, 443, (sslError, sslInfo) => {
97+
const uptime = 100;
98+
const response = {
99+
isUp: true,
100+
ipAddress,
101+
uptime,
102+
latencyMs,
103+
dnsLookupMs: lookupMs,
104+
statusCode: responseDetails.statusCode,
105+
protocol: protocol,
106+
sslInfo: sslInfo
107+
};
108+
109+
console.log(
110+
`isUp: ${isUp}, ipAddress: ${ipAddress}, uptime: ${uptime}%, latencyMs: ${latencyMs}, dnsLookupMs: ${lookupMs}, protocol: ${protocol}, sslInfo: ${sslInfo ? JSON.stringify(sslInfo) : 'null'}`
111+
);
112+
return res.json(response);
113+
});
114+
} else {
115+
// HTTP - no SSL info
116+
const uptime = 100;
117+
const response = {
118+
isUp: true,
119+
ipAddress,
120+
uptime,
121+
latencyMs,
122+
dnsLookupMs: lookupMs,
123+
statusCode: responseDetails.statusCode,
124+
protocol: protocol,
125+
sslInfo: null
126+
};
127+
128+
console.log(
129+
`isUp: ${isUp}, ipAddress: ${ipAddress}, uptime: ${uptime}%, latencyMs: ${latencyMs}, dnsLookupMs: ${lookupMs}, protocol: ${protocol}`
130+
);
131+
return res.json(response);
132+
}
61133
});
62-
});
134+
}
63135
} catch (error) {
64136
console.error(`Error analyzing URL: ${error.message}`);
65137
return res.status(400).json({ error: error.message });

modules/sslCheck.js

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
const https = require('https');
2+
const tls = require('tls');
3+
4+
function checkSSLCertificate(hostname, port = 443, callback) {
5+
let certRetrieved = false;
6+
7+
// Use tls.connect for more reliable certificate retrieval
8+
const socket = tls.connect({
9+
host: hostname,
10+
port: port,
11+
rejectUnauthorized: false, // We want to check even if cert is invalid
12+
servername: hostname, // Important for SNI
13+
}, () => {
14+
try {
15+
const cert = socket.getPeerCertificate(true);
16+
17+
if (cert && cert.valid_to) {
18+
certRetrieved = true;
19+
const expirationDate = new Date(cert.valid_to);
20+
const now = new Date();
21+
const daysUntilExpiry = Math.ceil((expirationDate - now) / (1000 * 60 * 60 * 24));
22+
23+
callback(null, {
24+
expirationDate: expirationDate.toISOString(),
25+
daysUntilExpiry: daysUntilExpiry,
26+
isValid: expirationDate > now,
27+
issuer: cert.issuer ? (cert.issuer.CN || JSON.stringify(cert.issuer)) : null,
28+
subject: cert.subject ? (cert.subject.CN || hostname) : hostname,
29+
});
30+
} else {
31+
callback(null, null);
32+
}
33+
} catch (err) {
34+
callback(null, null);
35+
} finally {
36+
if (!socket.destroyed) {
37+
socket.end();
38+
}
39+
}
40+
});
41+
42+
socket.on('error', (error) => {
43+
if (!certRetrieved) {
44+
// If we can't get the certificate, return null (might be HTTP or connection issue)
45+
callback(null, null);
46+
}
47+
});
48+
49+
socket.on('timeout', () => {
50+
if (!certRetrieved) {
51+
socket.destroy();
52+
callback(null, null);
53+
}
54+
});
55+
56+
socket.setTimeout(5000);
57+
}
58+
59+
module.exports = checkSSLCertificate;
60+

0 commit comments

Comments
 (0)