mirror of
https://github.com/Termix-SSH/Termix.git
synced 2026-10-29 22:55:24 +00:00
feat: move opkssh and warpgate into plugins (C3)
This commit is contained in:
1 parent
925da4a661
commit
98d367d7e2
336 files changed
+22380
-4746
No files matched your search
@@ -59,7 +59,7 @@ import {
|
||||
moveSSHItem,
|
||||
connectSSH,
|
||||
verifySSHTOTP,
|
||||
verifySSHWarpgate,
|
||||
verifySSHBrowserSignIn,
|
||||
getSSHStatus,
|
||||
keepSSHAlive,
|
||||
identifySSHSymlink,
|
||||
@@ -199,12 +199,13 @@ function FileManagerContent({
|
||||
const [totpRequired, setTotpRequired] = useState(false);
|
||||
const [totpSessionId, setTotpSessionId] = useState<string | null>(null);
|
||||
const [totpPrompt, setTotpPrompt] = useState<string>("");
|
||||
const [warpgateRequired, setWarpgateRequired] = useState(false);
|
||||
const [warpgateSessionId, setWarpgateSessionId] = useState<string | null>(
|
||||
null,
|
||||
);
|
||||
const [warpgateUrl, setWarpgateUrl] = useState<string>("");
|
||||
const [warpgateSecurityKey, setWarpgateSecurityKey] = useState<string>("");
|
||||
const [browserSignInRequired, setBrowserSignInRequired] = useState(false);
|
||||
const [browserSignInSessionId, setBrowserSignInSessionId] = useState<
|
||||
string | null
|
||||
>(null);
|
||||
const [browserSignInUrl, setBrowserSignInUrl] = useState<string>("");
|
||||
const [browserSignInCode, setBrowserSignInCode] = useState<string>("");
|
||||
const [browserSignInLabel, setBrowserSignInLabel] = useState<string>("");
|
||||
const [showAuthDialog, setShowAuthDialog] = useState(false);
|
||||
const [authDialogReason, setAuthDialogReason] = useState<
|
||||
"no_keyboard" | "auth_failed" | "timeout"
|
||||
@@ -421,7 +422,7 @@ function FileManagerContent({
|
||||
!!currentHost &&
|
||||
!sshSessionId &&
|
||||
!totpRequired &&
|
||||
!warpgateRequired &&
|
||||
!browserSignInRequired &&
|
||||
!showAuthDialog &&
|
||||
!showPassphraseDialog,
|
||||
autoStart: false,
|
||||
@@ -627,11 +628,12 @@ function FileManagerContent({
|
||||
socks5ProxyChain: currentHost.socks5ProxyChain,
|
||||
});
|
||||
|
||||
if (result?.requires_warpgate) {
|
||||
setWarpgateRequired(true);
|
||||
setWarpgateSessionId(sessionId);
|
||||
setWarpgateUrl(result.url || "");
|
||||
setWarpgateSecurityKey(result.securityKey || "N/A");
|
||||
if (result?.requires_browser_sign_in) {
|
||||
setBrowserSignInRequired(true);
|
||||
setBrowserSignInSessionId(sessionId);
|
||||
setBrowserSignInUrl(result.url || "");
|
||||
setBrowserSignInCode(result.code || "N/A");
|
||||
setBrowserSignInLabel(result.label || "");
|
||||
setIsLoading(false);
|
||||
return;
|
||||
}
|
||||
@@ -698,11 +700,14 @@ function FileManagerContent({
|
||||
setIsLoading(false);
|
||||
return;
|
||||
}
|
||||
if (sshError.requires_warpgate) {
|
||||
setWarpgateRequired(true);
|
||||
setWarpgateSessionId(sshError.sessionId || currentHost.id.toString());
|
||||
setWarpgateUrl(sshError.url || "");
|
||||
setWarpgateSecurityKey(sshError.securityKey || "N/A");
|
||||
if (sshError.requires_browser_sign_in) {
|
||||
setBrowserSignInRequired(true);
|
||||
setBrowserSignInSessionId(
|
||||
sshError.sessionId || currentHost.id.toString(),
|
||||
);
|
||||
setBrowserSignInUrl(sshError.url || "");
|
||||
setBrowserSignInCode(sshError.code || "N/A");
|
||||
setBrowserSignInLabel(sshError.label || "");
|
||||
setIsLoading(false);
|
||||
return;
|
||||
}
|
||||
@@ -2660,23 +2665,26 @@ function FileManagerContent({
|
||||
if (onClose) onClose();
|
||||
}
|
||||
|
||||
async function handleWarpgateContinue() {
|
||||
if (!warpgateSessionId) return;
|
||||
async function handleBrowserSignInContinue() {
|
||||
if (!browserSignInSessionId) return;
|
||||
|
||||
try {
|
||||
setIsLoading(true);
|
||||
const result = await verifySSHWarpgate(warpgateSessionId);
|
||||
const result = await verifySSHBrowserSignIn(browserSignInSessionId);
|
||||
|
||||
if (result?.status === "success") {
|
||||
setWarpgateRequired(false);
|
||||
setWarpgateUrl("");
|
||||
setWarpgateSecurityKey("");
|
||||
setSshSessionId(warpgateSessionId);
|
||||
setWarpgateSessionId(null);
|
||||
setBrowserSignInRequired(false);
|
||||
setBrowserSignInUrl("");
|
||||
setBrowserSignInCode("");
|
||||
setSshSessionId(browserSignInSessionId);
|
||||
setBrowserSignInSessionId(null);
|
||||
connectRetryRef.current.markConnected();
|
||||
|
||||
try {
|
||||
const response = await listSSHFiles(warpgateSessionId, currentPath);
|
||||
const response = await listSSHFiles(
|
||||
browserSignInSessionId,
|
||||
currentPath,
|
||||
);
|
||||
const files = Array.isArray(response)
|
||||
? response
|
||||
: response?.files || [];
|
||||
@@ -2691,24 +2699,24 @@ function FileManagerContent({
|
||||
}
|
||||
}
|
||||
} catch (error: unknown) {
|
||||
console.error("Warpgate verification failed:", error);
|
||||
toast.error(t("fileManager.warpgateVerificationFailed"));
|
||||
console.error("Browser sign-in failed:", error);
|
||||
toast.error(t("fileManager.browserSignInFailed"));
|
||||
} finally {
|
||||
setIsLoading(false);
|
||||
}
|
||||
}
|
||||
|
||||
function handleWarpgateCancel() {
|
||||
setWarpgateRequired(false);
|
||||
setWarpgateUrl("");
|
||||
setWarpgateSecurityKey("");
|
||||
setWarpgateSessionId(null);
|
||||
function handleBrowserSignInCancel() {
|
||||
setBrowserSignInRequired(false);
|
||||
setBrowserSignInUrl("");
|
||||
setBrowserSignInCode("");
|
||||
setBrowserSignInSessionId(null);
|
||||
if (onClose) onClose();
|
||||
}
|
||||
|
||||
function handleWarpgateOpenUrl() {
|
||||
if (warpgateUrl) {
|
||||
window.open(warpgateUrl, "_blank", "noopener,noreferrer");
|
||||
function handleBrowserSignInOpenUrl() {
|
||||
if (browserSignInUrl) {
|
||||
window.open(browserSignInUrl, "_blank", "noopener,noreferrer");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2745,11 +2753,12 @@ function FileManagerContent({
|
||||
socks5ProxyChain: currentHost.socks5ProxyChain,
|
||||
});
|
||||
|
||||
if (result?.requires_warpgate) {
|
||||
setWarpgateRequired(true);
|
||||
setWarpgateSessionId(sessionId);
|
||||
setWarpgateUrl(result.url || "");
|
||||
setWarpgateSecurityKey(result.securityKey || "N/A");
|
||||
if (result?.requires_browser_sign_in) {
|
||||
setBrowserSignInRequired(true);
|
||||
setBrowserSignInSessionId(sessionId);
|
||||
setBrowserSignInUrl(result.url || "");
|
||||
setBrowserSignInCode(result.code || "N/A");
|
||||
setBrowserSignInLabel(result.label || "");
|
||||
setIsLoading(false);
|
||||
return;
|
||||
}
|
||||
@@ -3626,12 +3635,13 @@ function FileManagerContent({
|
||||
totpPrompt={totpPrompt}
|
||||
handleTotpSubmit={handleTotpSubmit}
|
||||
handleTotpCancel={handleTotpCancel}
|
||||
warpgateRequired={warpgateRequired}
|
||||
warpgateUrl={warpgateUrl}
|
||||
warpgateSecurityKey={warpgateSecurityKey}
|
||||
handleWarpgateContinue={handleWarpgateContinue}
|
||||
handleWarpgateCancel={handleWarpgateCancel}
|
||||
handleWarpgateOpenUrl={handleWarpgateOpenUrl}
|
||||
browserSignInRequired={browserSignInRequired}
|
||||
browserSignInUrl={browserSignInUrl}
|
||||
browserSignInCode={browserSignInCode}
|
||||
browserSignInLabel={browserSignInLabel}
|
||||
handleBrowserSignInContinue={handleBrowserSignInContinue}
|
||||
handleBrowserSignInCancel={handleBrowserSignInCancel}
|
||||
handleBrowserSignInOpenUrl={handleBrowserSignInOpenUrl}
|
||||
currentHost={currentHost}
|
||||
showAuthDialog={showAuthDialog}
|
||||
authDialogReason={authDialogReason}
|
||||
|
||||
@@ -2,7 +2,7 @@ import type { FileItem, SSHHost } from "@/types/index";
|
||||
import {
|
||||
TOTPDialog,
|
||||
SSHAuthDialog,
|
||||
WarpgateDialog,
|
||||
BrowserSignInDialog,
|
||||
} from "@termix/plugin-sdk/ui";
|
||||
import { PermissionsDialog } from "./components/PermissionsDialog.tsx";
|
||||
import { CompressDialog } from "./components/CompressDialog.tsx";
|
||||
@@ -17,12 +17,13 @@ type FileManagerDialogsProps = {
|
||||
totpPrompt: string;
|
||||
handleTotpSubmit: (code: string) => void | Promise<void>;
|
||||
handleTotpCancel: () => void;
|
||||
warpgateRequired: boolean;
|
||||
warpgateUrl: string;
|
||||
warpgateSecurityKey: string;
|
||||
handleWarpgateContinue: () => void | Promise<void>;
|
||||
handleWarpgateCancel: () => void;
|
||||
handleWarpgateOpenUrl: () => void;
|
||||
browserSignInRequired: boolean;
|
||||
browserSignInUrl: string;
|
||||
browserSignInCode: string;
|
||||
browserSignInLabel: string;
|
||||
handleBrowserSignInContinue: () => void | Promise<void>;
|
||||
handleBrowserSignInCancel: () => void;
|
||||
handleBrowserSignInOpenUrl: () => void;
|
||||
currentHost: SSHHost | null;
|
||||
showAuthDialog: boolean;
|
||||
authDialogReason: "no_keyboard" | "auth_failed" | "timeout";
|
||||
@@ -49,12 +50,13 @@ export function FileManagerDialogs({
|
||||
totpPrompt,
|
||||
handleTotpSubmit,
|
||||
handleTotpCancel,
|
||||
warpgateRequired,
|
||||
warpgateUrl,
|
||||
warpgateSecurityKey,
|
||||
handleWarpgateContinue,
|
||||
handleWarpgateCancel,
|
||||
handleWarpgateOpenUrl,
|
||||
browserSignInRequired,
|
||||
browserSignInUrl,
|
||||
browserSignInCode,
|
||||
browserSignInLabel,
|
||||
handleBrowserSignInContinue,
|
||||
handleBrowserSignInCancel,
|
||||
handleBrowserSignInOpenUrl,
|
||||
currentHost,
|
||||
showAuthDialog,
|
||||
authDialogReason,
|
||||
@@ -85,13 +87,14 @@ export function FileManagerDialogs({
|
||||
backgroundColor="var(--bg-canvas)"
|
||||
/>
|
||||
|
||||
<WarpgateDialog
|
||||
isOpen={warpgateRequired}
|
||||
url={warpgateUrl}
|
||||
securityKey={warpgateSecurityKey}
|
||||
onContinue={handleWarpgateContinue}
|
||||
onCancel={handleWarpgateCancel}
|
||||
onOpenUrl={handleWarpgateOpenUrl}
|
||||
<BrowserSignInDialog
|
||||
isOpen={browserSignInRequired}
|
||||
label={browserSignInLabel}
|
||||
url={browserSignInUrl}
|
||||
code={browserSignInCode}
|
||||
onContinue={handleBrowserSignInContinue}
|
||||
onCancel={handleBrowserSignInCancel}
|
||||
onOpenUrl={handleBrowserSignInOpenUrl}
|
||||
backgroundColor="var(--bg-canvas)"
|
||||
/>
|
||||
|
||||
|
||||
@@ -30,11 +30,12 @@ type ConnectErrorResponse = {
|
||||
message?: string;
|
||||
connectionLogs?: ApiConnectionLog[];
|
||||
requires_totp?: boolean;
|
||||
requires_warpgate?: boolean;
|
||||
requires_browser_sign_in?: boolean;
|
||||
sessionId?: string;
|
||||
prompt?: string;
|
||||
url?: string;
|
||||
securityKey?: string;
|
||||
code?: string;
|
||||
label?: string;
|
||||
status?: string;
|
||||
reason?: string;
|
||||
};
|
||||
@@ -48,11 +49,12 @@ export interface SSHConnectResult {
|
||||
status?: string;
|
||||
reason?: "timeout" | "no_keyboard" | "auth_failed";
|
||||
requires_totp?: boolean;
|
||||
requires_warpgate?: boolean;
|
||||
requires_browser_sign_in?: boolean;
|
||||
sessionId?: string;
|
||||
prompt?: string;
|
||||
url?: string;
|
||||
securityKey?: string;
|
||||
code?: string;
|
||||
label?: string;
|
||||
}
|
||||
|
||||
function triggerBlobDownload(blob: Blob, fileName: string): void {
|
||||
@@ -125,12 +127,13 @@ export async function connectSSH(
|
||||
prompt: data.prompt,
|
||||
});
|
||||
}
|
||||
if (data.requires_warpgate) {
|
||||
if (data.requires_browser_sign_in) {
|
||||
Object.assign(errorWithLogs, {
|
||||
requires_warpgate: true,
|
||||
requires_browser_sign_in: true,
|
||||
sessionId: data.sessionId,
|
||||
url: data.url,
|
||||
securityKey: data.securityKey,
|
||||
code: data.code,
|
||||
label: data.label,
|
||||
});
|
||||
}
|
||||
if (data.status === "auth_required") {
|
||||
@@ -176,17 +179,17 @@ export async function verifySSHTOTP(
|
||||
}
|
||||
}
|
||||
|
||||
export async function verifySSHWarpgate(
|
||||
export async function verifySSHBrowserSignIn(
|
||||
sessionId: string,
|
||||
): Promise<Record<string, unknown>> {
|
||||
try {
|
||||
const response = await getFileManagerApiForSession(sessionId).post(
|
||||
"/ssh/connect-warpgate",
|
||||
"/ssh/connect-browser-sign-in",
|
||||
{ sessionId },
|
||||
);
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
handleApiError(error, "verify SSH Warpgate");
|
||||
handleApiError(error, "verify SSH browser sign-in");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1020,7 +1023,7 @@ export async function ensureSSHSessionForHost(
|
||||
|
||||
if (
|
||||
result?.requires_totp ||
|
||||
result?.requires_warpgate ||
|
||||
result?.requires_browser_sign_in ||
|
||||
result?.status === "auth_required"
|
||||
) {
|
||||
return { state: "auth_required", sessionId };
|
||||
|
||||
@@ -16,11 +16,12 @@ export type ConnectionLogPayload = Omit<LogEntry, "id" | "timestamp">;
|
||||
export type SSHConnectionError = Error & {
|
||||
connectionLogs?: ConnectionLogPayload[];
|
||||
requires_totp?: boolean;
|
||||
requires_warpgate?: boolean;
|
||||
requires_browser_sign_in?: boolean;
|
||||
sessionId?: string;
|
||||
prompt?: string;
|
||||
url?: string;
|
||||
securityKey?: string;
|
||||
code?: string;
|
||||
label?: string;
|
||||
status?: string;
|
||||
reason?: "no_keyboard" | "auth_failed" | "timeout";
|
||||
};
|
||||
|
||||
Reference in new issue
Block a user