feat: move opkssh and warpgate into plugins (C3)

This commit is contained in:
LukeGus committed 2026-09-24 19:28:19 -05:00
1 parent 925da4a661
commit 98d367d7e2
336 files changed
+22380 -4746

No files matched your search

+37
View File
@@ -0,0 +1,37 @@
import type {
PluginKeyboardInteractiveDetection,
PluginKeyboardInteractivePrompt,
} from "@termix/plugin-sdk/backend";
const WARPGATE_PATTERN = /warpgate\s+authentication/i;
const URL_PATTERN = /https?:\/\/[^\s\n]+/i;
const SECURITY_KEY_PATTERN =
/security key[:\s]+([a-z0-9](?:\s+[a-z0-9]){3}|[a-z0-9]{4})/i;
/**
* Warpgate asks for its browser approval as a keyboard-interactive round
* that names itself and carries the sign-in URL and a security key.
*/
export function detectWarpgateRound(round: {
name: string;
instructions: string;
prompts: PluginKeyboardInteractivePrompt[];
}): PluginKeyboardInteractiveDetection | null {
const texts = round.prompts.map((prompt) => prompt.prompt);
const isWarpgate =
WARPGATE_PATTERN.test(round.name) ||
WARPGATE_PATTERN.test(round.instructions) ||
texts.some((text) => WARPGATE_PATTERN.test(text));
if (!isWarpgate) return null;
const fullText = `${round.name}\n${round.instructions}\n${texts.join("\n")}`;
const url = fullText.match(URL_PATTERN);
if (!url) return null;
const key = fullText.match(SECURITY_KEY_PATTERN);
return {
kind: "browser",
url: url[0],
code: key ? key[1] : "N/A",
instructions: round.instructions,
};
}
@@ -0,0 +1,14 @@
/**
* Registered as "warpgate.hostImportNormalizer" so core's host import keeps
* the flag. Reads a Termix export's pluginSettings.warpgate first, then the
* useWarpgate host field exports had before 2.9.0.
*/
export function hostImportNormalizer(
raw: Record<string, unknown>,
): Record<string, unknown> | null {
const pluginSettings = raw.pluginSettings as
Record<string, Record<string, unknown> | undefined> | undefined;
const value = pluginSettings?.warpgate?.useWarpgate ?? raw.useWarpgate;
if (value === undefined || value === null) return null;
return { useWarpgate: value === true || value === 1 || value === "true" };
}
+22
View File
@@ -0,0 +1,22 @@
import type { PluginContext } from "@termix/plugin-sdk/backend";
import { detectWarpgateRound } from "./detect.js";
import { hostImportNormalizer } from "./host-import.js";
export const HANDLER_ID = "warpgate";
export async function activate(ctx: PluginContext) {
ctx.auth.registerKeyboardInteractiveHandler({
id: HANDLER_ID,
label: "Warpgate",
detect: (round) => detectWarpgateRound(round),
// Warpgate asks for the password before its browser round; answer it
// silently so the only thing the user sees is the sign-in dialog.
autoAnswerPasswords: (_host, settings) => settings.useWarpgate === true,
});
ctx.registry.provide("warpgate.hostImportNormalizer", hostImportNormalizer);
}
export async function deactivate() {
// Registered through ctx, so core removes it.
}