feat: Guest WiFi, network intelligence, firmware orchestration, platform automation, api-ssl (v0.16.3-beta)
Guest WiFi (Hotspot): one-click captive-portal wizard that creates the guest SSID (virtual AP per radio), VLAN/bridge segregation + L3 VLAN interface, pool, DHCP, portal, rate-limited guest profile, and masquerade; vouchers with limits + printable sheets; live guest sessions; walled garden. Network intelligence: per-client device fingerprinting (vendor/hostname → category) with a persisted per-client override on the detail page; rogue/neighbor AP detection from stored AP scans (evil-twin flagging); Mist-style anomaly insights (client-count/CPU vs same-hour 14-day baseline + error bursts) in the Operations engine. Firmware orchestration: staged wave-based RouterOS rollouts (canary first) with pre-upgrade backup, reboot-ride-out, version verification, halt-on-failure, and scheduling; live per-device progress + cancel. Platform & automation: scoped API tokens (mtm_, read/write, hashed at rest, Bearer auth in requireAuth); outbound webhooks (12 events, HMAC-signed) fired from the alert pipeline + firmware orchestrator; scheduled email reports. api-ssl: RouterOSClient negotiates TLS on port 8729 and accepts RouterOS's default self-signed certs (rejectUnauthorized:false), so SSL-secured API devices connect without manual cert trust. Fixes #57. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
efb430d934
commit
9dfb8a5333
@@ -1,4 +1,5 @@
|
||||
import * as net from 'net';
|
||||
import * as tls from 'tls';
|
||||
import * as crypto from 'crypto';
|
||||
import { EventEmitter } from 'events';
|
||||
|
||||
@@ -34,15 +35,21 @@ export class RouterOSClient extends EventEmitter {
|
||||
|
||||
private tagCounter = 0;
|
||||
|
||||
private readonly useTls: boolean;
|
||||
|
||||
constructor(
|
||||
private readonly host: string,
|
||||
private readonly port: number = 8728,
|
||||
private readonly username: string,
|
||||
private readonly password: string,
|
||||
private readonly connectTimeoutMs: number = 15000,
|
||||
private readonly readTimeoutMs: number = 30000
|
||||
private readonly readTimeoutMs: number = 30000,
|
||||
useTls?: boolean
|
||||
) {
|
||||
super();
|
||||
// api-ssl runs on 8729 by RouterOS convention (the same heuristic the
|
||||
// security-posture code uses); callers can override explicitly.
|
||||
this.useTls = useTls ?? port === 8729;
|
||||
}
|
||||
|
||||
async connect(): Promise<void> {
|
||||
@@ -54,9 +61,7 @@ export class RouterOSClient extends EventEmitter {
|
||||
this.socket?.destroy();
|
||||
}, this.connectTimeoutMs);
|
||||
|
||||
this.socket = net.createConnection({ host: this.host, port: this.port });
|
||||
|
||||
this.socket.on('connect', async () => {
|
||||
const onReady = async () => {
|
||||
clearTimeout(timer);
|
||||
try {
|
||||
await this.authenticate();
|
||||
@@ -67,7 +72,21 @@ export class RouterOSClient extends EventEmitter {
|
||||
this.socket?.destroy();
|
||||
reject(err);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
if (this.useTls) {
|
||||
// api-ssl: RouterOS devices ship self-signed certificates by default,
|
||||
// so certificate verification is intentionally disabled — the same
|
||||
// trust model as the plaintext API this replaces, but with the
|
||||
// credentials and session encrypted in transit.
|
||||
this.socket = tls.connect(
|
||||
{ host: this.host, port: this.port, rejectUnauthorized: false },
|
||||
() => { void onReady(); }
|
||||
);
|
||||
} else {
|
||||
this.socket = net.createConnection({ host: this.host, port: this.port });
|
||||
this.socket.on('connect', () => { void onReady(); });
|
||||
}
|
||||
|
||||
this.socket.on('data', (data: Buffer) => {
|
||||
this.buffer = Buffer.concat([this.buffer, data]);
|
||||
|
||||
Reference in New Issue
Block a user