diff --git a/docs/superpowers/plans/2026-03-12-wraith-build.md b/docs/superpowers/plans/2026-03-12-wraith-build.md index de75f6b..61a591d 100644 --- a/docs/superpowers/plans/2026-03-12-wraith-build.md +++ b/docs/superpowers/plans/2026-03-12-wraith-build.md @@ -2448,6 +2448,7 @@ This is the core of Wraith. The SSH connection service manages ssh2 connections, ```typescript import { Injectable, Logger } from '@nestjs/common'; import { Client, ClientChannel } from 'ssh2'; +import { createHash } from 'crypto'; import { CredentialsService } from '../vault/credentials.service'; import { HostsService } from '../connections/hosts.service'; import { PrismaService } from '../prisma/prisma.service'; @@ -2522,16 +2523,27 @@ export class SshConnectionService { host: host.hostname, port: host.port, username: cred?.username || 'root', - hostVerifier: (key: Buffer) => { - const fingerprint = require('crypto') - .createHash('sha256') - .update(key) - .digest('base64'); + hostVerifier: (key: Buffer, verify: (accept: boolean) => void) => { + const fingerprint = createHash('sha256').update(key).digest('base64'); const fp = `SHA256:${fingerprint}`; - if (host.hostFingerprint === fp) return true; // known host - // Async verification — return false for now, handle via callback - return true; // TODO: wire up onHostKeyVerify properly with async flow + if (host.hostFingerprint === fp) { + verify(true); // known host — accept silently + return; + } + + // Unknown or changed fingerprint — ask the user via WebSocket + const isNew = !host.hostFingerprint; + onHostKeyVerify(fp, isNew).then((accepted) => { + if (accepted) { + // Persist fingerprint so future connections auto-accept + this.prisma.host.update({ + where: { id: hostId }, + data: { hostFingerprint: fp }, + }).catch(() => {}); + } + verify(accepted); + }); }, };