mirror of
https://github.com/Termix-SSH/Termix.git
synced 2026-10-30 07:05: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
@@ -316,7 +316,7 @@
|
||||
"connecting": "Connecting...",
|
||||
"connectedSuccessfully": "Connected successfully",
|
||||
"totpVerificationFailed": "TOTP verification failed",
|
||||
"warpgateVerificationFailed": "Warpgate authentication failed",
|
||||
"browserSignInFailed": "Sign-in failed. Please try again.",
|
||||
"authenticationFailed": "Authentication failed",
|
||||
"incorrectPassphrase": "Incorrect passphrase. Please try again.",
|
||||
"verificationCodePrompt": "Verification code:",
|
||||
|
||||
@@ -290,7 +290,6 @@
|
||||
"connecting": "Verbind...",
|
||||
"connectedSuccessfully": "Suksesvol gekoppel",
|
||||
"totpVerificationFailed": "TOTP-verifikasie het misluk",
|
||||
"warpgateVerificationFailed": "Warpgate-verifikasie het misluk",
|
||||
"authenticationFailed": "Verifikasie het misluk",
|
||||
"incorrectPassphrase": "Verkeerde wagwoordfrase. Probeer asseblief weer.",
|
||||
"verificationCodePrompt": "Verifikasiekode:",
|
||||
|
||||
@@ -290,7 +290,6 @@
|
||||
"connecting": "جارٍ الاتصال...",
|
||||
"connectedSuccessfully": "تم الاتصال بنجاح",
|
||||
"totpVerificationFailed": "فشل التحقق من TOTP",
|
||||
"warpgateVerificationFailed": "فشلت مصادقة Warpgate",
|
||||
"authenticationFailed": "فشلت المصادقة",
|
||||
"incorrectPassphrase": "عبارة المرور غير صحيحة. يرجى المحاولة مرة أخرى.",
|
||||
"verificationCodePrompt": "رمز التحقق:",
|
||||
|
||||
@@ -290,7 +290,6 @@
|
||||
"connecting": "Свързване...",
|
||||
"connectedSuccessfully": "Свързаването е осъществено успешно",
|
||||
"totpVerificationFailed": "Проверката на TOTP не бе успешна",
|
||||
"warpgateVerificationFailed": "Удостоверяването на Warpgate не беше успешно",
|
||||
"authenticationFailed": "Удостоверяването не бе успешно",
|
||||
"incorrectPassphrase": "Неправилна парола. Моля, опитайте отново.",
|
||||
"verificationCodePrompt": "Код за потвърждение:",
|
||||
|
||||
@@ -290,7 +290,6 @@
|
||||
"connecting": "সংযোগ স্থাপন...",
|
||||
"connectedSuccessfully": "সফলভাবে সংযুক্ত হয়েছে",
|
||||
"totpVerificationFailed": "TOTP যাচাইকরণ ব্যর্থ হয়েছে",
|
||||
"warpgateVerificationFailed": "ওয়ার্পগেট প্রমাণীকরণ ব্যর্থ হয়েছে",
|
||||
"authenticationFailed": "প্রমাণীকরণ ব্যর্থ হয়েছে",
|
||||
"incorrectPassphrase": "ভুল পাসফ্রেজ। অনুগ্রহ করে আবার চেষ্টা করুন।",
|
||||
"verificationCodePrompt": "যাচাইকরণ কোড:",
|
||||
|
||||
@@ -290,7 +290,6 @@
|
||||
"connecting": "Connectant...",
|
||||
"connectedSuccessfully": "Connexió correcta",
|
||||
"totpVerificationFailed": "La verificació TOTP ha fallat",
|
||||
"warpgateVerificationFailed": "L'autenticació de Warpgate ha fallat",
|
||||
"authenticationFailed": "L'autenticació ha fallat",
|
||||
"incorrectPassphrase": "Contrasenya incorrecta. Si us plau, torneu-ho a intentar.",
|
||||
"verificationCodePrompt": "Codi de verificació:",
|
||||
|
||||
@@ -290,7 +290,6 @@
|
||||
"connecting": "Spojovací...",
|
||||
"connectedSuccessfully": "Úspěšné připojení",
|
||||
"totpVerificationFailed": "Ověření TOTP se nezdařilo",
|
||||
"warpgateVerificationFailed": "Ověření Warpgate selhalo",
|
||||
"authenticationFailed": "Ověření se nezdařilo",
|
||||
"incorrectPassphrase": "Nesprávné heslo. Zkuste to prosím znovu.",
|
||||
"verificationCodePrompt": "Ověřovací kód:",
|
||||
|
||||
@@ -290,7 +290,6 @@
|
||||
"connecting": "Forbinder...",
|
||||
"connectedSuccessfully": "Forbindelsen er oprettet",
|
||||
"totpVerificationFailed": "TOTP-bekræftelse mislykkedes",
|
||||
"warpgateVerificationFailed": "Warpgate-godkendelse mislykkedes",
|
||||
"authenticationFailed": "Godkendelse mislykkedes",
|
||||
"incorrectPassphrase": "Forkert adgangskode. Prøv igen.",
|
||||
"verificationCodePrompt": "Bekræftelseskode:",
|
||||
|
||||
@@ -290,7 +290,6 @@
|
||||
"connecting": "Verbindung wird hergestellt...",
|
||||
"connectedSuccessfully": "Erfolgreich verbunden",
|
||||
"totpVerificationFailed": "TOTP-Überprüfung fehlgeschlagen",
|
||||
"warpgateVerificationFailed": "Warpgate-Authentifizierung fehlgeschlagen",
|
||||
"authenticationFailed": "Authentifizierung fehlgeschlagen",
|
||||
"incorrectPassphrase": "Falsche Passphrase. Bitte versuchen Sie es erneut.",
|
||||
"verificationCodePrompt": "Verifizierungscode:",
|
||||
|
||||
@@ -290,7 +290,6 @@
|
||||
"connecting": "Συνδετικός...",
|
||||
"connectedSuccessfully": "Η σύνδεση ολοκληρώθηκε με επιτυχία",
|
||||
"totpVerificationFailed": "Η επαλήθευση TOTP απέτυχε.",
|
||||
"warpgateVerificationFailed": "Η πιστοποίηση Warpgate απέτυχε.",
|
||||
"authenticationFailed": "Η επαλήθευση ταυτότητας απέτυχε",
|
||||
"incorrectPassphrase": "Λανθασμένη φράση πρόσβασης. Δοκιμάστε ξανά.",
|
||||
"verificationCodePrompt": "Κωδικός επαλήθευσης:",
|
||||
|
||||
@@ -290,7 +290,6 @@
|
||||
"connecting": "Conectando...",
|
||||
"connectedSuccessfully": "Conectado correctamente",
|
||||
"totpVerificationFailed": "Error en la verificación TOTP",
|
||||
"warpgateVerificationFailed": "Error de autenticación de Warpgate",
|
||||
"authenticationFailed": "Error de autenticación",
|
||||
"incorrectPassphrase": "Frase de contraseña incorrecta. Inténtelo de nuevo.",
|
||||
"verificationCodePrompt": "Código de verificación:",
|
||||
|
||||
@@ -290,7 +290,6 @@
|
||||
"connecting": "Yhdistetään...",
|
||||
"connectedSuccessfully": "Yhteys onnistui",
|
||||
"totpVerificationFailed": "TOTP-vahvistus epäonnistui",
|
||||
"warpgateVerificationFailed": "Warpgate-todennus epäonnistui",
|
||||
"authenticationFailed": "Todennus epäonnistui",
|
||||
"incorrectPassphrase": "Virheellinen salasana. Yritä uudelleen.",
|
||||
"verificationCodePrompt": "Vahvistuskoodi:",
|
||||
|
||||
@@ -290,7 +290,6 @@
|
||||
"connecting": "Connexion en cours...",
|
||||
"connectedSuccessfully": "Connecté avec succès",
|
||||
"totpVerificationFailed": "Échec de la vérification TOTP",
|
||||
"warpgateVerificationFailed": "Échec de l'authentification Warpgate",
|
||||
"authenticationFailed": "Échec de l'authentification",
|
||||
"incorrectPassphrase": "Phrase secrète incorrecte. Veuillez réessayer.",
|
||||
"verificationCodePrompt": "Code de vérification :",
|
||||
|
||||
@@ -290,7 +290,6 @@
|
||||
"connecting": "מְקַשֵׁר...",
|
||||
"connectedSuccessfully": "התחבר בהצלחה",
|
||||
"totpVerificationFailed": "אימות TOTP נכשל",
|
||||
"warpgateVerificationFailed": "אימות Warpgate נכשל",
|
||||
"authenticationFailed": "האימות נכשל",
|
||||
"incorrectPassphrase": "סיסמה שגויה. אנא נסה שוב.",
|
||||
"verificationCodePrompt": "קוד אימות:",
|
||||
|
||||
@@ -290,7 +290,6 @@
|
||||
"connecting": "कनेक्ट हो रहा है...",
|
||||
"connectedSuccessfully": "सफलतापूर्वक कनेक्ट हुआ",
|
||||
"totpVerificationFailed": "TOTP सत्यापन विफल",
|
||||
"warpgateVerificationFailed": "Warpgate सत्यापन विफल",
|
||||
"authenticationFailed": "प्रमाणीकरण विफल",
|
||||
"incorrectPassphrase": "गलत पासफ़्रेज़। कृपया पुनः प्रयास करें।",
|
||||
"verificationCodePrompt": "सत्यापन कोड:",
|
||||
|
||||
@@ -290,7 +290,6 @@
|
||||
"connecting": "Kapcsolódás...",
|
||||
"connectedSuccessfully": "Sikeres csatlakozás",
|
||||
"totpVerificationFailed": "TOTP-ellenőrzés sikertelen",
|
||||
"warpgateVerificationFailed": "Warpgate hitelesítés sikertelen",
|
||||
"authenticationFailed": "Hitelesítés sikertelen",
|
||||
"incorrectPassphrase": "Hibás jelszó. Kérjük, próbálja újra.",
|
||||
"verificationCodePrompt": "Ellenőrző kód:",
|
||||
|
||||
@@ -290,7 +290,6 @@
|
||||
"connecting": "Menghubungkan...",
|
||||
"connectedSuccessfully": "Terhubung berhasil",
|
||||
"totpVerificationFailed": "Verifikasi TOTP gagal",
|
||||
"warpgateVerificationFailed": "Autentikasi Warpgate gagal",
|
||||
"authenticationFailed": "Autentikasi gagal",
|
||||
"incorrectPassphrase": "Kata sandi salah. Silakan coba lagi.",
|
||||
"verificationCodePrompt": "Kode verifikasi:",
|
||||
|
||||
@@ -290,7 +290,6 @@
|
||||
"connecting": "Connessione in corso...",
|
||||
"connectedSuccessfully": "Connesso con successo",
|
||||
"totpVerificationFailed": "Verifica TOTP non riuscita",
|
||||
"warpgateVerificationFailed": "Autenticazione Warpgate non riuscita",
|
||||
"authenticationFailed": "Autenticazione non riuscita",
|
||||
"incorrectPassphrase": "Frase di accesso non corretta. Riprova.",
|
||||
"verificationCodePrompt": "Codice di verifica:",
|
||||
|
||||
@@ -290,7 +290,6 @@
|
||||
"connecting": "接続中...",
|
||||
"connectedSuccessfully": "接続しました",
|
||||
"totpVerificationFailed": "TOTP検証に失敗しました",
|
||||
"warpgateVerificationFailed": "Warpgate認証に失敗しました",
|
||||
"authenticationFailed": "認証に失敗しました",
|
||||
"incorrectPassphrase": "パスフレーズが間違っています。もう一度お試しください。",
|
||||
"verificationCodePrompt": "認証コード:",
|
||||
|
||||
@@ -290,7 +290,6 @@
|
||||
"connecting": "연결 중...",
|
||||
"connectedSuccessfully": "연결 성공",
|
||||
"totpVerificationFailed": "TOTP 인증 실패",
|
||||
"warpgateVerificationFailed": "Warpgate 인증 실패",
|
||||
"authenticationFailed": "인증 실패",
|
||||
"incorrectPassphrase": "잘못된 암호입니다. 다시 시도하세요.",
|
||||
"verificationCodePrompt": "인증 코드:",
|
||||
|
||||
@@ -290,7 +290,6 @@
|
||||
"connecting": "Verbinden...",
|
||||
"connectedSuccessfully": "Verbinding succesvol tot stand gebracht.",
|
||||
"totpVerificationFailed": "TOTP-verificatie mislukt",
|
||||
"warpgateVerificationFailed": "Warpgate-authenticatie mislukt",
|
||||
"authenticationFailed": "Authenticatie mislukt",
|
||||
"incorrectPassphrase": "Onjuiste wachtzin. Probeer het opnieuw.",
|
||||
"verificationCodePrompt": "Verificatiecode:",
|
||||
|
||||
@@ -290,7 +290,6 @@
|
||||
"connecting": "Kobler til...",
|
||||
"connectedSuccessfully": "Tilkoblet",
|
||||
"totpVerificationFailed": "TOTP-verifisering mislyktes",
|
||||
"warpgateVerificationFailed": "Warpgate-autentisering mislyktes",
|
||||
"authenticationFailed": "Autentisering mislyktes",
|
||||
"incorrectPassphrase": "Feil passordfrase. Prøv på nytt.",
|
||||
"verificationCodePrompt": "Verifiseringskode:",
|
||||
|
||||
@@ -290,7 +290,6 @@
|
||||
"connecting": "Łączenie...",
|
||||
"connectedSuccessfully": "Połączono pomyślnie",
|
||||
"totpVerificationFailed": "Weryfikacja TOTP nie powiodła się",
|
||||
"warpgateVerificationFailed": "Uwierzytelnianie Warpgate nie powiodło się",
|
||||
"authenticationFailed": "Uwierzytelnianie nie powiodło się",
|
||||
"incorrectPassphrase": "Nieprawidłowe hasło klucza. Spróbuj ponownie.",
|
||||
"verificationCodePrompt": "Kod weryfikacyjny:",
|
||||
|
||||
@@ -290,7 +290,6 @@
|
||||
"connecting": "Conectando...",
|
||||
"connectedSuccessfully": "Conexão estabelecida com sucesso.",
|
||||
"totpVerificationFailed": "A verificação TOTP falhou.",
|
||||
"warpgateVerificationFailed": "A autenticação do portal de guerra falhou.",
|
||||
"authenticationFailed": "A autenticação falhou.",
|
||||
"incorrectPassphrase": "Senha incorreta. Tente novamente.",
|
||||
"verificationCodePrompt": "Código de verificação:",
|
||||
|
||||
@@ -290,7 +290,6 @@
|
||||
"connecting": "A ligar...",
|
||||
"connectedSuccessfully": "Ligado com sucesso",
|
||||
"totpVerificationFailed": "Falha na verificação TOTP",
|
||||
"warpgateVerificationFailed": "Falha na autenticação Warpgate",
|
||||
"authenticationFailed": "Falha na autenticação",
|
||||
"incorrectPassphrase": "Frase-passe incorreta. Tente novamente.",
|
||||
"verificationCodePrompt": "Código de verificação:",
|
||||
|
||||
@@ -290,7 +290,6 @@
|
||||
"connecting": "Se conectează...",
|
||||
"connectedSuccessfully": "Conectare reușită",
|
||||
"totpVerificationFailed": "Verificarea TOTP a eșuat",
|
||||
"warpgateVerificationFailed": "Autentificarea Warpgate a eșuat",
|
||||
"authenticationFailed": "Autentificarea a eșuat",
|
||||
"incorrectPassphrase": "Parolă incorectă. Vă rugăm să încercați din nou.",
|
||||
"verificationCodePrompt": "Cod de verificare:",
|
||||
|
||||
@@ -290,7 +290,6 @@
|
||||
"connecting": "Подключение...",
|
||||
"connectedSuccessfully": "Подключено успешно",
|
||||
"totpVerificationFailed": "Ошибка проверки TOTP",
|
||||
"warpgateVerificationFailed": "Ошибка аутентификации Warpgate",
|
||||
"authenticationFailed": "Ошибка аутентификации",
|
||||
"incorrectPassphrase": "Неверная парольная фраза. Попробуйте еще раз.",
|
||||
"verificationCodePrompt": "Код подтверждения:",
|
||||
|
||||
@@ -290,7 +290,6 @@
|
||||
"connecting": "Повезивање...",
|
||||
"connectedSuccessfully": "Успешно повезано",
|
||||
"totpVerificationFailed": "Верификација TOTP-а није успела",
|
||||
"warpgateVerificationFailed": "Аутентификација Варпгејта није успела",
|
||||
"authenticationFailed": "Аутентификација није успела",
|
||||
"incorrectPassphrase": "Нетачна лозинка. Молимо покушајте поново.",
|
||||
"verificationCodePrompt": "Верификациони код:",
|
||||
|
||||
@@ -290,7 +290,6 @@
|
||||
"connecting": "Ansluter...",
|
||||
"connectedSuccessfully": "Ansluten",
|
||||
"totpVerificationFailed": "TOTP-verifiering misslyckades",
|
||||
"warpgateVerificationFailed": "Warpgate-autentisering misslyckades",
|
||||
"authenticationFailed": "Autentiseringen misslyckades",
|
||||
"incorrectPassphrase": "Felaktigt lösenord. Försök igen.",
|
||||
"verificationCodePrompt": "Verifieringskod:",
|
||||
|
||||
@@ -290,7 +290,6 @@
|
||||
"connecting": "กำลังเชื่อมต่อ...",
|
||||
"connectedSuccessfully": "เชื่อมต่อสำเร็จแล้ว",
|
||||
"totpVerificationFailed": "การตรวจสอบ TOTP ล้มเหลว",
|
||||
"warpgateVerificationFailed": "การตรวจสอบสิทธิ์วาร์ปไม่สำเร็จ",
|
||||
"authenticationFailed": "การตรวจสอบสิทธิ์ล้มเหลว",
|
||||
"incorrectPassphrase": "รหัสผ่านไม่ถูกต้อง โปรดลองอีกครั้ง",
|
||||
"verificationCodePrompt": "รหัสยืนยัน:",
|
||||
|
||||
@@ -290,7 +290,6 @@
|
||||
"connecting": "Bağlanıyor...",
|
||||
"connectedSuccessfully": "Bağlantı başarıyla kuruldu",
|
||||
"totpVerificationFailed": "TOTP doğrulaması başarısız oldu",
|
||||
"warpgateVerificationFailed": "Warpgate kimlik doğrulaması başarısız oldu",
|
||||
"authenticationFailed": "Kimlik doğrulama başarısız oldu",
|
||||
"incorrectPassphrase": "Yanlış parola. Lütfen tekrar deneyin.",
|
||||
"verificationCodePrompt": "Doğrulama kodu:",
|
||||
|
||||
@@ -290,7 +290,6 @@
|
||||
"connecting": "Підключення...",
|
||||
"connectedSuccessfully": "Підключено успішно",
|
||||
"totpVerificationFailed": "Не вдалося перевірити TOTP",
|
||||
"warpgateVerificationFailed": "Автентифікація Warpgate не вдалася",
|
||||
"authenticationFailed": "Помилка автентифікації",
|
||||
"incorrectPassphrase": "Неправильна парольна фраза. Спробуйте ще раз.",
|
||||
"verificationCodePrompt": "Код підтвердження:",
|
||||
|
||||
@@ -290,7 +290,6 @@
|
||||
"connecting": "Đang kết nối...",
|
||||
"connectedSuccessfully": "Đã kết nối thành công",
|
||||
"totpVerificationFailed": "Xác minh TOTP thất bại",
|
||||
"warpgateVerificationFailed": "Xác thực Warpgate thất bại",
|
||||
"authenticationFailed": "Xác thực thất bại",
|
||||
"incorrectPassphrase": "Cụm mật khẩu không đúng. Vui lòng thử lại.",
|
||||
"verificationCodePrompt": "Mã xác minh:",
|
||||
|
||||
@@ -290,7 +290,6 @@
|
||||
"connecting": "连接中...",
|
||||
"connectedSuccessfully": "连接成功",
|
||||
"totpVerificationFailed": "TOTP 验证失败",
|
||||
"warpgateVerificationFailed": "Warpgate 认证失败",
|
||||
"authenticationFailed": "认证失败",
|
||||
"incorrectPassphrase": "密码错误。请重试。",
|
||||
"verificationCodePrompt": "验证码:",
|
||||
|
||||
@@ -290,7 +290,6 @@
|
||||
"connecting": "連線中...",
|
||||
"connectedSuccessfully": "已成功連線",
|
||||
"totpVerificationFailed": "TOTP 驗證失敗",
|
||||
"warpgateVerificationFailed": "Warpgate 驗證失敗",
|
||||
"authenticationFailed": "驗證失敗",
|
||||
"incorrectPassphrase": "密碼片語錯誤。請再試一次。",
|
||||
"verificationCodePrompt": "驗證碼:",
|
||||
|
||||
@@ -200,7 +200,7 @@ export async function activate(ctx: PluginContext) {
|
||||
);
|
||||
}
|
||||
|
||||
// Pending TOTP/Warpgate parking sessions expire on their own; sweep stale
|
||||
// Pending TOTP and browser sign-in parking sessions expire on their own; sweep stale
|
||||
// ones so a session left mid-handshake doesn't leak an open ssh2 Client.
|
||||
const pendingSweep = setInterval(() => {
|
||||
const now = Date.now();
|
||||
@@ -386,7 +386,7 @@ export async function activate(ctx: PluginContext) {
|
||||
if (
|
||||
req.path === "/connect" ||
|
||||
req.path === "/connect-totp" ||
|
||||
req.path === "/connect-warpgate"
|
||||
req.path === "/connect-browser-sign-in"
|
||||
) {
|
||||
return next();
|
||||
}
|
||||
@@ -463,7 +463,7 @@ export async function activate(ctx: PluginContext) {
|
||||
* type: array
|
||||
* responses:
|
||||
* 200:
|
||||
* description: SSH connection established, or requires TOTP/Warpgate authentication.
|
||||
* description: SSH connection established, or requires TOTP or a browser sign-in.
|
||||
* 400:
|
||||
* description: Missing required parameters or invalid SSH key format.
|
||||
* 401:
|
||||
@@ -983,7 +983,7 @@ export async function activate(ctx: PluginContext) {
|
||||
finish: (responses: string[]) => void,
|
||||
prompts: Array<{ prompt: string; echo: boolean }>,
|
||||
promptIndex: number,
|
||||
isWarpgate = false,
|
||||
isBrowserSignIn = false,
|
||||
) => {
|
||||
pendingTOTPSessions[sessionId] = {
|
||||
client,
|
||||
@@ -1000,7 +1000,7 @@ export async function activate(ctx: PluginContext) {
|
||||
totpPromptIndex: promptIndex,
|
||||
resolvedPassword: resolvedCredentials.password,
|
||||
totpAttempts: 0,
|
||||
...(isWarpgate ? { isWarpgate: true } : {}),
|
||||
...(isBrowserSignIn ? { isBrowserSignIn: true } : {}),
|
||||
};
|
||||
};
|
||||
|
||||
@@ -1025,23 +1025,24 @@ export async function activate(ctx: PluginContext) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (decision.kind === "warpgate") {
|
||||
if (decision.kind === "browser") {
|
||||
if (responseSent) return;
|
||||
responseSent = true;
|
||||
connectionLogs.push(
|
||||
createConnectionLog(
|
||||
"info",
|
||||
"sftp_auth",
|
||||
"Warpgate authentication required",
|
||||
`${decision.label} sign-in required`,
|
||||
{ url: decision.url },
|
||||
),
|
||||
);
|
||||
parkForAnswer(finish, prompts, -1, true);
|
||||
res.json({
|
||||
requires_warpgate: true,
|
||||
requires_browser_sign_in: true,
|
||||
sessionId,
|
||||
label: decision.label,
|
||||
url: decision.url,
|
||||
securityKey: decision.securityKey,
|
||||
code: decision.code,
|
||||
connectionLogs,
|
||||
});
|
||||
return;
|
||||
@@ -1347,10 +1348,10 @@ export async function activate(ctx: PluginContext) {
|
||||
|
||||
/**
|
||||
* @openapi
|
||||
* /plugin-api/file-manager/connect-warpgate:
|
||||
* /plugin-api/file-manager/connect-browser-sign-in:
|
||||
* post:
|
||||
* summary: Complete Warpgate authentication
|
||||
* description: Submits empty response to complete Warpgate authentication after user completes browser auth.
|
||||
* summary: Continue after a browser sign-in
|
||||
* description: Answers the parked keyboard-interactive round once the user finished signing in in the browser (an SSH gateway's approval, for example).
|
||||
* tags:
|
||||
* - File Manager
|
||||
* requestBody:
|
||||
@@ -1366,15 +1367,15 @@ export async function activate(ctx: PluginContext) {
|
||||
* type: string
|
||||
* responses:
|
||||
* 200:
|
||||
* description: Warpgate authentication completed successfully.
|
||||
* description: Signed in, SSH connection established.
|
||||
* 401:
|
||||
* description: Authentication failed or unauthorized.
|
||||
* 404:
|
||||
* description: Warpgate session expired.
|
||||
* description: Sign-in session expired.
|
||||
* 408:
|
||||
* description: Warpgate session timeout.
|
||||
* description: Sign-in session timeout.
|
||||
*/
|
||||
app.post("/connect-warpgate", async (req, res) => {
|
||||
app.post("/connect-browser-sign-in", async (req, res) => {
|
||||
const { sessionId } = req.body;
|
||||
const userId = ctx.currentActor();
|
||||
|
||||
@@ -1389,12 +1390,12 @@ export async function activate(ctx: PluginContext) {
|
||||
if (!session) {
|
||||
return res
|
||||
.status(404)
|
||||
.json({ error: "Warpgate session expired. Please reconnect." });
|
||||
.json({ error: "Sign-in session expired. Please reconnect." });
|
||||
}
|
||||
if (!session.isWarpgate) {
|
||||
if (!session.isBrowserSignIn) {
|
||||
return res
|
||||
.status(400)
|
||||
.json({ error: "Session is not a Warpgate session" });
|
||||
.json({ error: "Session is not waiting for a browser sign-in" });
|
||||
}
|
||||
if (Date.now() - session.createdAt > 300000) {
|
||||
delete pendingTOTPSessions[sessionId];
|
||||
@@ -1405,7 +1406,7 @@ export async function activate(ctx: PluginContext) {
|
||||
}
|
||||
return res
|
||||
.status(408)
|
||||
.json({ error: "Warpgate session timeout. Please reconnect." });
|
||||
.json({ error: "Sign-in session timeout. Please reconnect." });
|
||||
}
|
||||
|
||||
let responseSent = false;
|
||||
@@ -1413,7 +1414,7 @@ export async function activate(ctx: PluginContext) {
|
||||
if (!responseSent) {
|
||||
responseSent = true;
|
||||
delete pendingTOTPSessions[sessionId];
|
||||
res.status(408).json({ error: "Warpgate verification timeout" });
|
||||
res.status(408).json({ error: "Sign-in verification timeout" });
|
||||
}
|
||||
}, 60000);
|
||||
|
||||
@@ -1440,7 +1441,7 @@ export async function activate(ctx: PluginContext) {
|
||||
|
||||
res.json({
|
||||
status: "success",
|
||||
message: "Warpgate verified, SSH connection established",
|
||||
message: "Signed in, SSH connection established",
|
||||
});
|
||||
|
||||
if (session.hostId && session.userId) {
|
||||
@@ -1460,9 +1461,7 @@ export async function activate(ctx: PluginContext) {
|
||||
responseSent = true;
|
||||
clearTimeout(responseTimeout);
|
||||
delete pendingTOTPSessions[sessionId];
|
||||
res
|
||||
.status(401)
|
||||
.json({ status: "error", message: "Warpgate authentication failed" });
|
||||
res.status(401).json({ status: "error", message: "Sign-in failed" });
|
||||
});
|
||||
|
||||
session.finish([""]);
|
||||
@@ -1567,12 +1566,10 @@ export async function activate(ctx: PluginContext) {
|
||||
}
|
||||
const session = sshSessions[sessionId];
|
||||
if (!session || !session.isConnected) {
|
||||
return res
|
||||
.status(400)
|
||||
.json({
|
||||
error: "SSH session not found or not connected",
|
||||
connected: false,
|
||||
});
|
||||
return res.status(400).json({
|
||||
error: "SSH session not found or not connected",
|
||||
connected: false,
|
||||
});
|
||||
}
|
||||
if (!userId || !verifySessionOwnership(session, userId)) {
|
||||
return res.status(403).json({ error: "Session access denied" });
|
||||
|
||||
@@ -57,7 +57,7 @@ export interface PendingTOTPSession {
|
||||
totpPromptIndex?: number;
|
||||
resolvedPassword?: string;
|
||||
totpAttempts: number;
|
||||
isWarpgate?: boolean;
|
||||
isBrowserSignIn?: boolean;
|
||||
}
|
||||
|
||||
export function execWithSudo(
|
||||
|
||||
@@ -38,7 +38,7 @@ export function connectSsh(
|
||||
|
||||
/**
|
||||
* Lower-level primitives for the interactive /connect route, which drives its
|
||||
* own ssh2 Client through the TOTP/Warpgate parking flow rather than letting
|
||||
* own ssh2 Client through the TOTP and browser sign-in parking flow rather than letting
|
||||
* ctx.ssh.connect finish the handshake itself.
|
||||
*/
|
||||
export function prepareSsh(
|
||||
|
||||
@@ -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