added email verification

This commit is contained in:
andrei-mihnea-cerbu
2025-02-04 19:08:34 +02:00
parent 9baec7a7cb
commit dcf505c89b
67 changed files with 3922 additions and 3638 deletions
+145 -145
View File
@@ -1,161 +1,161 @@
import dgram from 'dgram';
import ping from 'ping';
import { OperationHandler } from '../operations_base/operation_handler';
import { MessageHandler } from '../message_handler';
import { GeneralOperations } from "../operations_custom/general_operations";
import { operationCodes } from "../operation_codes";
import os from 'os';
import dgram from 'dgram'
import ping from 'ping'
import { OperationHandler } from '../operations_base/operation_handler'
import { MessageHandler } from '../message_handler'
import { GeneralOperations } from '../operations_custom/general_operations'
import { operationCodes } from '../operation_codes'
import os from 'os'
export class UdpClient {
private udpSocket: dgram.Socket;
private readonly port: number;
private operationHandler: OperationHandler;
private udpSocket: dgram.Socket
private readonly port: number
private operationHandler: OperationHandler
constructor(port: number) {
this.port = port;
this.udpSocket = dgram.createSocket('udp4');
this.operationHandler = OperationHandler.getInstance();
this.operationHandler.loadPlugin(new GeneralOperations());
constructor(port: number) {
this.port = port
this.udpSocket = dgram.createSocket('udp4')
this.operationHandler = OperationHandler.getInstance()
this.operationHandler.loadPlugin(new GeneralOperations())
}
// Unified logging function
private log(message: string, level: 'log' | 'error' = 'log'): void {
const prefix = '[UdpClient]'
if (level === 'error') {
console.error(`${prefix} ${message}`)
} else {
console.log(`${prefix} ${message}`)
}
}
// Send heartbeat and get clients that respond with ALIVE, excluding the host machine's IP addresses
async getTargetClients(heartbeatCode: string): Promise<string[]> {
const subnet = this.getSubnet()
const ipRange = this.getIPRange(subnet)
// Get local machine's IP addresses to exclude
const localIPs = this.getLocalIPs()
this.log(`Local IPs to exclude from scan: ${localIPs.join(', ')}`)
// First, filter active IPs that respond to ping
const activeIps = await this.filterActiveIps(ipRange)
this.log(`Active IPs in subnet ${subnet}: ${activeIps.join(', ')}`)
// Send heartbeat to each active IP and keep only those that respond with ALIVE
const aliveClients: string[] = []
for (const ip of activeIps) {
if (!localIPs.includes(ip)) {
const result = await this.sendHeartbeat(ip, heartbeatCode)
if (result.found) {
aliveClients.push(ip)
}
}
}
// Unified logging function
private log(message: string, level: 'log' | 'error' = 'log'): void {
const prefix = '[UdpClient]';
if (level === 'error') {
console.error(`${prefix} ${message}`);
this.log(`Alive clients (excluding local machine): ${aliveClients.join(', ')}`)
return aliveClients
}
// Get local IP addresses of the host machine (excluding loopback)
private getLocalIPs(): string[] {
const interfaces = os.networkInterfaces()
const localIPs: string[] = []
Object.values(interfaces).forEach((iface) => {
iface?.forEach((address) => {
if (address.family === 'IPv4' && !address.internal) {
localIPs.push(address.address)
}
})
})
return localIPs
}
// Send heartbeat to an IP
private async sendHeartbeat(ip: string, heartbeatCode: string): Promise<{ found: boolean }> {
return new Promise((resolve) => {
const heartbeatMessage = MessageHandler.formatMessage(heartbeatCode)
this.log(`Sending heartbeat to ${ip}`)
this.udpSocket.send(heartbeatMessage, this.port, ip, (err) => {
if (err) {
this.log(`Failed to send heartbeat to ${ip}: ${err.message}`, 'error')
resolve({ found: false })
} else {
console.log(`${prefix} ${message}`);
}
}
const timeout = setTimeout(() => {
this.dropConnection(ip)
resolve({ found: false })
}, 1500)
// Send heartbeat and get clients that respond with ALIVE, excluding the host machine's IP addresses
async getTargetClients(heartbeatCode: string): Promise<string[]> {
const subnet = this.getSubnet();
const ipRange = this.getIPRange(subnet);
// Get local machine's IP addresses to exclude
const localIPs = this.getLocalIPs();
this.log(`Local IPs to exclude from scan: ${localIPs.join(', ')}`);
// First, filter active IPs that respond to ping
const activeIps = await this.filterActiveIps(ipRange);
this.log(`Active IPs in subnet ${subnet}: ${activeIps.join(', ')}`);
// Send heartbeat to each active IP and keep only those that respond with ALIVE
const aliveClients: string[] = [];
for (const ip of activeIps) {
if (!localIPs.includes(ip)) {
const result = await this.sendHeartbeat(ip, heartbeatCode);
if (result.found) {
aliveClients.push(ip);
}
this.udpSocket.once('message', (msg, rinfo) => {
if (rinfo.address === ip) {
clearTimeout(timeout)
const parsedMessage = MessageHandler.parseMessage(msg.toString())
if (parsedMessage?.operationCode === operationCodes.ALIVE) {
this.log(`Received ALIVE response from ${ip}`)
resolve({ found: true })
} else {
this.log(`Unexpected response from ${ip}`)
resolve({ found: false })
}
}
})
}
})
})
}
this.log(`Alive clients (excluding local machine): ${aliveClients.join(', ')}`);
return aliveClients;
// Drop connection for a specific IP
private dropConnection(ip: string): void {
try {
this.udpSocket.removeAllListeners('message')
this.log(`Dropped connection listeners for ${ip}`)
} catch (err: any) {
this.log(`Error dropping connection to ${ip}: ${err.message}`, 'error')
}
}
// Get local IP addresses of the host machine (excluding loopback)
private getLocalIPs(): string[] {
const interfaces = os.networkInterfaces();
const localIPs: string[] = [];
Object.values(interfaces).forEach((iface) => {
iface?.forEach((address) => {
if (address.family === 'IPv4' && !address.internal) {
localIPs.push(address.address);
}
});
});
return localIPs;
}
// Send heartbeat to an IP
private async sendHeartbeat(ip: string, heartbeatCode: string): Promise<{ found: boolean }> {
return new Promise((resolve) => {
const heartbeatMessage = MessageHandler.formatMessage(heartbeatCode);
this.log(`Sending heartbeat to ${ip}`);
this.udpSocket.send(heartbeatMessage, this.port, ip, (err) => {
if (err) {
this.log(`Failed to send heartbeat to ${ip}: ${err.message}`, 'error');
resolve({ found: false });
} else {
const timeout = setTimeout(() => {
this.dropConnection(ip);
resolve({ found: false });
}, 1500);
this.udpSocket.once('message', (msg, rinfo) => {
if (rinfo.address === ip) {
clearTimeout(timeout);
const parsedMessage = MessageHandler.parseMessage(msg.toString());
if (parsedMessage?.operationCode === operationCodes.ALIVE) {
this.log(`Received ALIVE response from ${ip}`);
resolve({ found: true });
} else {
this.log(`Unexpected response from ${ip}`);
resolve({ found: false });
}
}
});
}
});
});
}
// Drop connection for a specific IP
private dropConnection(ip: string): void {
try {
this.udpSocket.removeAllListeners('message');
this.log(`Dropped connection listeners for ${ip}`);
} catch (err: any) {
this.log(`Error dropping connection to ${ip}: ${err.message}`, 'error');
// Get the subnet (e.g., 192.168.1)
private getSubnet(): string {
const interfaces = os.networkInterfaces()
for (const iface of Object.values(interfaces)) {
for (const address of iface || []) {
if (address.family === 'IPv4' && !address.internal) {
const subnet = address.address.split('.').slice(0, 3).join('.')
this.log(`Detected subnet: ${subnet}`)
return subnet
}
}
}
return ''
}
// Get IP range (assuming /24 subnet)
private getIPRange(subnet: string): string[] {
const ipRange = []
for (let i = 1; i < 255; i++) {
ipRange.push(`${subnet}.${i}`)
}
this.log(`Generated IP range for subnet ${subnet}`)
return ipRange
}
// Filter only active IPs by pinging each IP in the range
private async filterActiveIps(ipRange: string[]): Promise<string[]> {
const activeIps: string[] = []
const pingPromises = ipRange.map((ip) => ping.promise.probe(ip, { timeout: 1 }))
const pingResults = await Promise.all(pingPromises)
for (const result of pingResults) {
if (result.alive) {
activeIps.push(result.host)
}
}
// Get the subnet (e.g., 192.168.1)
private getSubnet(): string {
const interfaces = os.networkInterfaces();
for (const iface of Object.values(interfaces)) {
for (const address of iface || []) {
if (address.family === 'IPv4' && !address.internal) {
const subnet = address.address.split('.').slice(0, 3).join('.');
this.log(`Detected subnet: ${subnet}`);
return subnet;
}
}
}
return '';
}
// Get IP range (assuming /24 subnet)
private getIPRange(subnet: string): string[] {
const ipRange = [];
for (let i = 1; i < 255; i++) {
ipRange.push(`${subnet}.${i}`);
}
this.log(`Generated IP range for subnet ${subnet}`);
return ipRange;
}
// Filter only active IPs by pinging each IP in the range
private async filterActiveIps(ipRange: string[]): Promise<string[]> {
const activeIps: string[] = [];
const pingPromises = ipRange.map(ip => ping.promise.probe(ip, { timeout: 1 }));
const pingResults = await Promise.all(pingPromises);
for (const result of pingResults) {
if (result.alive) {
activeIps.push(result.host);
}
}
this.log(`Active IPs after pinging: ${activeIps.join(', ')}`);
return activeIps;
}
this.log(`Active IPs after pinging: ${activeIps.join(', ')}`)
return activeIps
}
}
+70 -67
View File
@@ -1,77 +1,80 @@
import dgram, { RemoteInfo } from 'dgram';
import { UdpSocketCommunicator } from "../socket_communicator/udp_socket_communicator";
import { OperationHandler } from "../operations_base/operation_handler";
import { GeneralOperations } from "../operations_custom/general_operations";
import dgram, { RemoteInfo } from 'dgram'
import { UdpSocketCommunicator } from '../socket_communicator/udp_socket_communicator'
import { OperationHandler } from '../operations_base/operation_handler'
import { GeneralOperations } from '../operations_custom/general_operations'
export class UdpServer {
private readonly udpServer: dgram.Socket;
private readonly operationHandler: OperationHandler;
private readonly port: number;
private readonly host: string;
private readonly udpServer: dgram.Socket
private readonly operationHandler: OperationHandler
private readonly port: number
private readonly host: string
constructor(host: string, port: number) {
this.udpServer = dgram.createSocket('udp4');
this.operationHandler = OperationHandler.getInstance();
this.host = host;
this.port = port;
constructor(host: string, port: number) {
this.udpServer = dgram.createSocket('udp4')
this.operationHandler = OperationHandler.getInstance()
this.host = host
this.port = port
// Load only the GeneralOperations into the operation handler
this.operationHandler.loadPlugin(new GeneralOperations());
// Load only the GeneralOperations into the operation handler
this.operationHandler.loadPlugin(new GeneralOperations())
}
// Unified logging function
private log(message: string, level: 'log' | 'error' = 'log'): void {
const prefix = '[UdpServer]'
if (level === 'error') {
console.error(`${prefix} ${message}`)
} else {
console.log(`${prefix} ${message}`)
}
}
// Unified logging function
private log(message: string, level: 'log' | 'error' = 'log'): void {
const prefix = '[UdpServer]';
if (level === 'error') {
console.error(`${prefix} ${message}`);
} else {
console.log(`${prefix} ${message}`);
}
// Start the UDP server
public start(): void {
this.udpServer.on('message', this.handleUdpMessages.bind(this))
this.udpServer.on('error', this.handleError.bind(this))
this.udpServer.on('listening', this.handleListening.bind(this))
// Bind the server to the UDP port and host
this.udpServer.bind(this.port, this.host)
}
// Handle incoming UDP messages
private async handleUdpMessages(msg: Buffer, rinfo: RemoteInfo): Promise<void> {
const ip = rinfo.address
const port = rinfo.port
this.log(`Received message from ${ip}:${port}`)
// Create a temporary communicator for the incoming message
const communicator = new UdpSocketCommunicator(this.udpServer, ip, port, this.operationHandler)
// Process the incoming message using the communicator
await communicator.handleIncomingMessage(msg.toString())
const communicatorResult = communicator.getHandlerResult()
if (communicatorResult) {
// Send response back to the client using the temporary communicator
try {
await communicator.sendMessage(
communicatorResult.operationCode,
communicatorResult.metaInfo,
)
this.log(`Sent response to ${ip}:${port}`)
} catch (error: any) {
this.log(`Error sending response to ${ip}:${port}: ${error.message}`, 'error')
}
}
}
// Start the UDP server
public start(): void {
this.udpServer.on('message', this.handleUdpMessages.bind(this));
this.udpServer.on('error', this.handleError.bind(this));
this.udpServer.on('listening', this.handleListening.bind(this));
// Handle UDP server errors
private handleError(err: Error): void {
this.log(`UDP server error:\n${err.stack}`, 'error')
}
// Bind the server to the UDP port and host
this.udpServer.bind(this.port, this.host);
}
// Handle incoming UDP messages
private async handleUdpMessages(msg: Buffer, rinfo: RemoteInfo): Promise<void> {
const ip = rinfo.address;
const port = rinfo.port;
this.log(`Received message from ${ip}:${port}`);
// Create a temporary communicator for the incoming message
const communicator = new UdpSocketCommunicator(this.udpServer, ip, port, this.operationHandler);
// Process the incoming message using the communicator
await communicator.handleIncomingMessage(msg.toString());
const communicatorResult = communicator.getHandlerResult();
if (communicatorResult) {
// Send response back to the client using the temporary communicator
try {
await communicator.sendMessage(communicatorResult.operationCode, communicatorResult.metaInfo);
this.log(`Sent response to ${ip}:${port}`);
} catch (error: any) {
this.log(`Error sending response to ${ip}:${port}: ${error.message}`, 'error');
}
}
}
// Handle UDP server errors
private handleError(err: Error): void {
this.log(`UDP server error:\n${err.stack}`, 'error');
}
// Handle when the UDP server starts listening
private handleListening(): void {
const address = this.udpServer.address();
this.log(`UDP server listening on ${address.address}:${address.port}`);
}
// Handle when the UDP server starts listening
private handleListening(): void {
const address = this.udpServer.address()
this.log(`UDP server listening on ${address.address}:${address.port}`)
}
}