fix(documentation): Improve documentation formatting and code consistency across project files

This commit is contained in:
2025-05-26 12:57:15 +00:00
parent 393f479b4e
commit 5593c3932a
7 changed files with 228 additions and 73 deletions

View File

@@ -3,6 +3,6 @@
*/
export const commitinfo = {
name: '@uptime.link/detector',
version: '2.1.1',
version: '2.1.2',
description: 'a detector for answering network questions locally. It does not rely on any online services.'
}

View File

@@ -24,11 +24,11 @@ export class Detector {
parseInt(parsedUrl.port, 10),
);
const portAvailable = !portUnused;
const result: IDetectorResult = {
isActive: portAvailable
isActive: portAvailable,
};
if (options?.detectServiceType) {
if (portAvailable) {
const serviceType = await this.detectType(urlArg);
@@ -37,7 +37,7 @@ export class Detector {
result.serviceType = ServiceType.UNKNOWN;
}
}
return result;
} else {
console.log(`detector target is remote domain ${parsedUrl.host} on port ${parsedUrl.port}`);
@@ -45,11 +45,11 @@ export class Detector {
parsedUrl.host,
parseInt(parsedUrl.port, 10),
);
const result: IDetectorResult = {
isActive: portAvailable
isActive: portAvailable,
};
if (options?.detectServiceType) {
if (portAvailable) {
const serviceType = await this.detectType(urlArg);
@@ -58,36 +58,36 @@ export class Detector {
result.serviceType = ServiceType.UNKNOWN;
}
}
return result;
}
}
public async detectType(urlArg: string): Promise<ServiceType> {
const parsedUrl = plugins.smarturl.Smarturl.createFromUrl(urlArg);
// Handle different URL schemes and default ports
let port = parseInt(parsedUrl.port, 10);
if (isNaN(port)) {
// Set default ports based on scheme
const defaultPorts: { [key: string]: number } = {
'http': 80,
'https': 443,
'ssh': 22,
'ftp': 21,
'smtp': 25,
'mysql': 3306,
'postgresql': 5432,
'mongodb': 27017,
'redis': 6379
http: 80,
https: 443,
ssh: 22,
ftp: 21,
smtp: 25,
mysql: 3306,
postgresql: 5432,
mongodb: 27017,
redis: 6379,
};
const scheme = parsedUrl.protocol.replace(':', '').toLowerCase();
port = defaultPorts[scheme] || 80;
}
const hostname = parsedUrl.hostname;
// Check common ports first
const commonPorts: { [key: number]: ServiceType } = {
80: ServiceType.HTTP,
@@ -100,9 +100,9 @@ export class Detector {
3306: ServiceType.MYSQL,
5432: ServiceType.POSTGRESQL,
27017: ServiceType.MONGODB,
6379: ServiceType.REDIS
6379: ServiceType.REDIS,
};
if (commonPorts[port]) {
// Verify the service is actually what we expect
const verified = await this.verifyServiceType(hostname, port, commonPorts[port]);
@@ -110,12 +110,16 @@ export class Detector {
return commonPorts[port];
}
}
// Try to detect service by banner/protocol
return await this.detectServiceByProtocol(hostname, port);
}
private async verifyServiceType(hostname: string, port: number, expectedType: ServiceType): Promise<boolean> {
private async verifyServiceType(
hostname: string,
port: number,
expectedType: ServiceType,
): Promise<boolean> {
try {
switch (expectedType) {
case ServiceType.HTTP:
@@ -130,33 +134,37 @@ export class Detector {
return false;
}
}
private async detectServiceByProtocol(hostname: string, port: number): Promise<ServiceType> {
// Try HTTPS first
if (await this.checkHttpService(hostname, port, true)) {
return ServiceType.HTTPS;
}
// Try HTTP
if (await this.checkHttpService(hostname, port, false)) {
return ServiceType.HTTP;
}
// Try SSH
if (await this.checkSshService(hostname, port)) {
return ServiceType.SSH;
}
// Try to get banner for other services
const banner = await this.getBanner(hostname, port);
if (banner) {
return this.identifyServiceByBanner(banner);
}
return ServiceType.UNKNOWN;
}
private async checkHttpService(hostname: string, port: number, isHttps: boolean): Promise<boolean> {
private async checkHttpService(
hostname: string,
port: number,
isHttps: boolean,
): Promise<boolean> {
return new Promise((resolve) => {
const protocol = isHttps ? plugins.https : plugins.http;
const options = {
@@ -164,81 +172,81 @@ export class Detector {
port,
method: 'HEAD',
timeout: 5000,
rejectUnauthorized: false // Accept self-signed certificates
rejectUnauthorized: false, // Accept self-signed certificates
};
const req = protocol.request(options, () => {
resolve(true);
});
req.on('error', () => {
resolve(false);
});
req.on('timeout', () => {
req.destroy();
resolve(false);
});
req.end();
});
}
private async checkSshService(hostname: string, port: number): Promise<boolean> {
return new Promise((resolve) => {
const socket = new plugins.net.Socket();
socket.setTimeout(5000);
socket.on('data', (data) => {
const banner = data.toString();
socket.destroy();
// SSH banners typically start with "SSH-"
resolve(banner.startsWith('SSH-'));
});
socket.on('error', () => {
resolve(false);
});
socket.on('timeout', () => {
socket.destroy();
resolve(false);
});
socket.connect(port, hostname);
});
}
private async getBanner(hostname: string, port: number): Promise<string | null> {
return new Promise((resolve) => {
const socket = new plugins.net.Socket();
let banner = '';
socket.setTimeout(5000);
socket.on('data', (data) => {
banner += data.toString();
socket.destroy();
resolve(banner);
});
socket.on('error', () => {
resolve(null);
});
socket.on('timeout', () => {
socket.destroy();
resolve(banner || null);
});
socket.connect(port, hostname);
});
}
private identifyServiceByBanner(banner: string): ServiceType {
const bannerLower = banner.toLowerCase();
if (bannerLower.includes('ssh')) return ServiceType.SSH;
if (bannerLower.includes('ftp')) return ServiceType.FTP;
if (bannerLower.includes('smtp')) return ServiceType.SMTP;
@@ -248,7 +256,7 @@ export class Detector {
if (bannerLower.includes('postgresql')) return ServiceType.POSTGRESQL;
if (bannerLower.includes('mongodb')) return ServiceType.MONGODB;
if (bannerLower.includes('redis')) return ServiceType.REDIS;
return ServiceType.UNKNOWN;
}
}

View File

@@ -10,7 +10,7 @@ export enum ServiceType {
POSTGRESQL = 'postgresql',
MONGODB = 'mongodb',
REDIS = 'redis',
UNKNOWN = 'unknown'
UNKNOWN = 'unknown',
}
export interface IDetectorResult {
@@ -41,4 +41,4 @@ export interface IDetectorOptions {
timeout?: number;
includeNetworkDiagnostics?: boolean;
detectServiceType?: boolean;
}
}