mirror of
https://github.com/Termix-SSH/Termix.git
synced 2026-10-28 14:15:24 +00:00
77 lines
2.6 KiB
TypeScript
77 lines
2.6 KiB
TypeScript
import type {
|
|
PluginContext,
|
|
PluginSshAuthProvider,
|
|
} from "@termix/plugin-sdk/backend";
|
|
import {
|
|
isTailscaleCheckCompleteBanner,
|
|
parseTailscaleCheckBanner,
|
|
TAILSCALE_CHECK_TIMEOUT_MS,
|
|
} from "./tailscale-check.js";
|
|
|
|
const AUTH_FAILED_PATTERN = /All configured authentication methods failed/i;
|
|
|
|
export const tailscaleSshAuthProvider: PluginSshAuthProvider = {
|
|
type: "tailscale",
|
|
labelKey: "hosts.filterAuthTailscale",
|
|
// Nothing host-specific to look up, so it works for an unsaved host.
|
|
quickConnect: true,
|
|
connectOptions: (_host, purpose) =>
|
|
purpose === "terminal"
|
|
? {
|
|
tryKeyboard: false,
|
|
readyTimeout: TAILSCALE_CHECK_TIMEOUT_MS,
|
|
// The socket sits idle while a check-mode login is pending.
|
|
timeout: TAILSCALE_CHECK_TIMEOUT_MS,
|
|
}
|
|
: { tryKeyboard: false },
|
|
prepare: async (_config, _host, env) => {
|
|
env.log("info", "Using Tailscale SSH");
|
|
return { status: "ready" };
|
|
},
|
|
onBanner: (banner) => {
|
|
const check = parseTailscaleCheckBanner(banner);
|
|
if (check) {
|
|
return {
|
|
action: "hold",
|
|
timeoutMs: TAILSCALE_CHECK_TIMEOUT_MS,
|
|
message: `Tailscale SSH requires an additional check. Waiting for browser authentication at ${check.url}`,
|
|
details: { url: check.url, message: check.message },
|
|
};
|
|
}
|
|
if (isTailscaleCheckCompleteBanner(banner)) {
|
|
return { action: "release" };
|
|
}
|
|
return undefined;
|
|
},
|
|
onAuthFailed: (host, _env, context) => {
|
|
const failed =
|
|
context.methodNotAvailable ||
|
|
AUTH_FAILED_PATTERN.test(context.error.message);
|
|
if (!failed) return;
|
|
|
|
// Tailscale documents the "+password" suffix for clients that mishandle a
|
|
// successful "none" reply. The password value is ignored.
|
|
if (context.retries === 0 && context.canRetry) {
|
|
return {
|
|
status: "retry",
|
|
message: "Retrying Tailscale SSH in forced password mode",
|
|
patch: {
|
|
username: `${host.username}+password`,
|
|
password: "termix",
|
|
tryKeyboard: false,
|
|
},
|
|
};
|
|
}
|
|
|
|
return {
|
|
status: "error",
|
|
code: "failed",
|
|
message: `Tailscale SSH authentication failed for user "${host.username}". Ensure Tailscale is running on the server, SSH is advertised (tailscale set --ssh), and your ACL policy grants the "${host.username}" user to your identity. If your Tailscale identity maps to a different Unix user, update the username on this host.`,
|
|
};
|
|
},
|
|
};
|
|
|
|
export function registerTailscaleSshAuth(ctx: PluginContext): void {
|
|
ctx.auth.registerSshAuthProvider(tailscaleSshAuthProvider);
|
|
}
|