feat: RDP flap auto-disconnect and hide break button after reconnect (0.4.10)
Add optional auto logoff of stuck sessions on RDG flap and direct RDP failure. Hide the RDS break button on old flap 302 when the user later reconnects or the workstation session is closed. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -472,6 +472,23 @@ export function updateWinAdminSettings(payload: {
|
||||
});
|
||||
}
|
||||
|
||||
export interface RdpFlapSettings {
|
||||
auto_disconnect: boolean;
|
||||
win_admin_configured: boolean;
|
||||
source: string;
|
||||
}
|
||||
|
||||
export function fetchRdpFlapSettings(): Promise<RdpFlapSettings> {
|
||||
return apiFetch<RdpFlapSettings>("/api/v1/settings/rdp-flap");
|
||||
}
|
||||
|
||||
export function updateRdpFlapSettings(payload: { auto_disconnect: boolean }): Promise<RdpFlapSettings> {
|
||||
return apiFetch<RdpFlapSettings>("/api/v1/settings/rdp-flap", {
|
||||
method: "PUT",
|
||||
body: JSON.stringify(payload),
|
||||
});
|
||||
}
|
||||
|
||||
export interface HostWinRmTestResult {
|
||||
ok: boolean;
|
||||
message: string;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/** Fallback до загрузки /health; при релизе держите в sync с backend/app/version.py */
|
||||
export const APP_NAME = "Security Alert Center";
|
||||
export const APP_VERSION = "0.4.8";
|
||||
export const APP_VERSION = "0.4.10";
|
||||
export const APP_VERSION_LABEL = `${APP_NAME} v.${APP_VERSION}`;
|
||||
|
||||
@@ -159,6 +159,28 @@
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<form class="settings-form" @submit.prevent="saveRdpFlapSettings">
|
||||
<h3>RDP flapping</h3>
|
||||
<p class="settings-hint">
|
||||
При включении SAC автоматически завершает зависшую сессию пользователя на целевом ПК
|
||||
(WinRM qwinsta/logoff): при RDG flap 302→303 и при прямом RDP, если вход не удался из‑за
|
||||
открытой сессии. Нужен настроенный доменный admin выше.
|
||||
</p>
|
||||
<label class="settings-field settings-inline">
|
||||
<input v-model="rdpFlapForm.auto_disconnect" type="checkbox" />
|
||||
Автоматически определять RDP flapping и отключать сессии
|
||||
</label>
|
||||
<p v-if="rdpFlapLoaded" class="settings-meta">
|
||||
Windows admin: {{ rdpFlapLoaded.win_admin_configured ? "настроен" : "не настроен" }}
|
||||
· источник: <code>{{ rdpFlapLoaded.source }}</code>
|
||||
</p>
|
||||
<div class="settings-actions">
|
||||
<button type="submit" :disabled="savingRdpFlap">
|
||||
{{ savingRdpFlap ? "Сохранение…" : "Сохранить RDP flapping" }}
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</section>
|
||||
|
||||
<section class="card settings-card settings-policy">
|
||||
@@ -681,6 +703,8 @@ import {
|
||||
fetchMobileSettings,
|
||||
fetchUsers,
|
||||
fetchWinAdminSettings,
|
||||
fetchRdpFlapSettings,
|
||||
updateRdpFlapSettings,
|
||||
fetchLinuxAdminSettings,
|
||||
fetchAgentUpdateSettings,
|
||||
saveAgentUpdateSettings,
|
||||
@@ -702,6 +726,7 @@ import {
|
||||
type MobileEnrollmentCode,
|
||||
type MobileSettings,
|
||||
type AgentUpdateSettings,
|
||||
type RdpFlapSettings,
|
||||
type UserSummary,
|
||||
} from "../api";
|
||||
|
||||
@@ -811,6 +836,8 @@ const emailLoaded = ref<EmailSettings | null>(null);
|
||||
const policyLoaded = ref<NotificationPolicy | null>(null);
|
||||
const uiLoaded = ref<UiSettings | null>(null);
|
||||
const winAdminLoaded = ref<WinAdminSettings | null>(null);
|
||||
const rdpFlapLoaded = ref<RdpFlapSettings | null>(null);
|
||||
const savingRdpFlap = ref(false);
|
||||
const linuxAdminLoaded = ref<LinuxAdminSettings | null>(null);
|
||||
const agentUpdateLoaded = ref<AgentUpdateSettings | null>(null);
|
||||
const loginSecurityLoaded = ref<LoginSecuritySettings | null>(null);
|
||||
@@ -887,6 +914,10 @@ const winAdminForm = reactive({
|
||||
password: "",
|
||||
});
|
||||
|
||||
const rdpFlapForm = reactive({
|
||||
auto_disconnect: false,
|
||||
});
|
||||
|
||||
const linuxAdminForm = reactive({
|
||||
user: "",
|
||||
password: "",
|
||||
@@ -1114,6 +1145,28 @@ async function loadWinAdminSettings() {
|
||||
winAdminForm.password = "";
|
||||
}
|
||||
|
||||
async function loadRdpFlapSettings() {
|
||||
const data = await fetchRdpFlapSettings();
|
||||
rdpFlapLoaded.value = data;
|
||||
rdpFlapForm.auto_disconnect = data.auto_disconnect;
|
||||
}
|
||||
|
||||
async function saveRdpFlapSettings() {
|
||||
savingRdpFlap.value = true;
|
||||
error.value = "";
|
||||
success.value = "";
|
||||
try {
|
||||
rdpFlapLoaded.value = await updateRdpFlapSettings({
|
||||
auto_disconnect: rdpFlapForm.auto_disconnect,
|
||||
});
|
||||
success.value = "Настройки RDP flapping сохранены.";
|
||||
} catch (e) {
|
||||
error.value = e instanceof Error ? e.message : "Ошибка сохранения RDP flapping";
|
||||
} finally {
|
||||
savingRdpFlap.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
async function saveWinAdminSettings() {
|
||||
savingWinAdmin.value = true;
|
||||
error.value = "";
|
||||
@@ -1428,6 +1481,7 @@ async function load() {
|
||||
await loadUiSettings();
|
||||
await loadLoginSecuritySettings();
|
||||
await loadWinAdminSettings();
|
||||
await loadRdpFlapSettings();
|
||||
await loadLinuxAdminSettings();
|
||||
await loadAgentUpdateSettings();
|
||||
await loadSeverityOverrides();
|
||||
@@ -1617,6 +1671,10 @@ onMounted(() => {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
.settings-card h3 {
|
||||
margin-top: 1.25rem;
|
||||
}
|
||||
|
||||
.settings-form {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
Reference in New Issue
Block a user