mirror of
https://github.com/Termix-SSH/Termix.git
synced 2026-08-29 10:21:34 +00:00
* feat: Step CA SSH certificates as a host authentication type Issue short-lived SSH user certificates from a smallstep CA through its OIDC provisioner, over the CA's HTTP API rather than the step binary. Everything after issuance reuses the OPKSSH plumbing: the same encrypted per-user/host token store, WebSocket dialog and ssh2 certificate injection, with the connect paths branching on a shared usesIssuedCertificate() predicate. Instance-wide CA settings live in the admin panel, with a private-host allowlist for the SSRF guard. * fix: harden Step CA callback flow * style: format Step CA changes
63 lines
1.6 KiB
TypeScript
63 lines
1.6 KiB
TypeScript
import type { Client } from "ssh2";
|
|
import { usesIssuedCertificate } from "../issued-certificate-auth.js";
|
|
|
|
export type StatsCapableHost = {
|
|
connectionType?: string;
|
|
authType?: string;
|
|
};
|
|
|
|
export type TcpPingStatsConfig = {
|
|
statusCheckEnabled: boolean;
|
|
disableTcpPing?: boolean;
|
|
};
|
|
|
|
export function supportsMetrics(host: StatsCapableHost): boolean {
|
|
const connectionType = host.connectionType || "ssh";
|
|
if (connectionType !== "ssh") return false;
|
|
if (host.authType === "none" || usesIssuedCertificate(host.authType))
|
|
return false;
|
|
return true;
|
|
}
|
|
|
|
export function isTcpPingEnabled(statsConfig: TcpPingStatsConfig): boolean {
|
|
return statsConfig.statusCheckEnabled && !statsConfig.disableTcpPing;
|
|
}
|
|
|
|
export function parseStatusHostIds(value: unknown): Set<number> | null {
|
|
if (value === undefined) return null;
|
|
if (typeof value !== "string") return new Set();
|
|
|
|
return new Set(
|
|
value
|
|
.split(",")
|
|
.map(Number)
|
|
.filter((id) => Number.isSafeInteger(id) && id > 0),
|
|
);
|
|
}
|
|
|
|
export function tcpPingThroughJumpHost(
|
|
jumpClient: Pick<Client, "forwardOut" | "end">,
|
|
host: string,
|
|
port: number,
|
|
timeoutMs = 5000,
|
|
): Promise<boolean> {
|
|
return new Promise((resolve) => {
|
|
let settled = false;
|
|
|
|
const finish = (result: boolean) => {
|
|
if (settled) return;
|
|
settled = true;
|
|
clearTimeout(timeout);
|
|
jumpClient.end();
|
|
resolve(result);
|
|
};
|
|
|
|
const timeout = setTimeout(() => finish(false), timeoutMs);
|
|
|
|
jumpClient.forwardOut("127.0.0.1", 0, host, port, (error, stream) => {
|
|
stream?.destroy();
|
|
finish(!error && !!stream);
|
|
});
|
|
});
|
|
}
|