add edit and all in one menu for hosts and services

This commit is contained in:
redlineo committed 2026-07-22 15:54:44 +03:00
1 parent 8c1b93c14e
commit e39ad275b5
15 files changed
+1136 -675

No files matched your search

+6 -21
View File
@@ -28,29 +28,14 @@ func RenderInstructions(username, keyFileName string, forwards []AllocatedForwar
b.WriteString(" - config — настройка подключения\n")
b.WriteString(" - INSTRUCTIONS.txt — этот файл\n\n")
b.WriteString("ШАГ 1. Проверьте, что на компьютере есть SSH\n")
b.WriteString("--------------------------------------------\n")
b.WriteString("Откройте программу PowerShell (найдите её через Пуск) и введите:\n\n")
b.WriteString(" ssh -V\n\n")
b.WriteString("Если появилась ошибка — зайдите в Параметры Windows -> Приложения ->\n")
b.WriteString("Дополнительные компоненты -> Добавить компонент -> найдите «OpenSSH Client»\n")
b.WriteString("-> Установить.\n\n")
b.WriteString("ШАГ 2. Разложите файлы по нужной папке\n")
b.WriteString("ШАГ 1. Разложите файлы по нужной папке\n")
b.WriteString("---------------------------------------\n")
b.WriteString("Создайте (если её ещё нет) папку:\n\n")
b.WriteString(" C:\\Users\\ВАШЕ_ИМЯ\\.ssh\\\n\n")
fmt.Fprintf(&b, "И скопируйте туда все 3 файла из архива (%s, %s.pub, config).\n", keyFileName, keyFileName)
b.WriteString("Важно: у файла config не должно быть никакого расширения (не config.txt).\n\n")
b.WriteString("ШАГ 3. Настройте доступ к ключу\n")
b.WriteString("---------------------------------\n")
b.WriteString("В PowerShell по очереди выполните две команды (замените ничего не нужно,\n")
b.WriteString("копируйте как есть):\n\n")
fmt.Fprintf(&b, " icacls $env:USERPROFILE\\.ssh\\%s /inheritance:r\n", keyFileName)
fmt.Fprintf(&b, " icacls $env:USERPROFILE\\.ssh\\%s /grant:r \"$env:USERNAME:(R)\"\n\n", keyFileName)
b.WriteString("ШАГ 4. Подключитесь\n")
b.WriteString("ШАГ 2. Подключитесь\n")
b.WriteString("---------------------\n")
b.WriteString("В PowerShell введите команду:\n\n")
b.WriteString(" ssh -N jump\n\n")
@@ -59,12 +44,12 @@ func RenderInstructions(username, keyFileName string, forwards []AllocatedForwar
b.WriteString("таблицы ниже. Закрыли окно (или выключили компьютер) — доступ пропал, просто\n")
b.WriteString("откройте заново командой выше, когда снова понадобится.\n\n")
b.WriteString("ШАГ 5. Пользуйтесь\n")
b.WriteString("ШАГ 3. Пользуйтесь\n")
b.WriteString("--------------------\n")
b.WriteString("Эта настройка открывает у вас на компьютере (локально) следующие адреса.\n")
b.WriteString("В программе, которая должна подключиться к сервису (браузер, клиент базы\n")
b.WriteString("данных и т.п.), укажите вместо настоящего адреса тот, что указан ниже как\n")
b.WriteString("«localhost:порт» — и она подключится к нужному сервису через это соединение.\n\n")
b.WriteString("«127.0.0.1:порт» — и она подключится к нужному сервису через это соединение.\n\n")
// A numbered list rather than an aligned table: this file is opened in
// Notepad with whatever font the user has, so column alignment based on
@@ -75,7 +60,7 @@ func RenderInstructions(username, keyFileName string, forwards []AllocatedForwar
if f.Description != "" {
what = fmt.Sprintf("%s (%s)", f.ServiceName, f.Description)
}
fmt.Fprintf(&b, " %d. localhost:%d\n", i+1, f.LocalPort)
fmt.Fprintf(&b, " %d. 127.0.0.1:%d\n", i+1, f.LocalPort)
fmt.Fprintf(&b, " Это: %s\n", what)
fmt.Fprintf(&b, " Реально находится на: %s:%d\n\n", f.HostName, f.Port)
}
@@ -118,7 +103,7 @@ func RenderConfigUpdateInstructions(username string, forwards []AllocatedForward
if f.Description != "" {
what = fmt.Sprintf("%s (%s)", f.ServiceName, f.Description)
}
fmt.Fprintf(&b, " %d. localhost:%d\n", i+1, f.LocalPort)
fmt.Fprintf(&b, " %d. 127.0.0.1:%d\n", i+1, f.LocalPort)
fmt.Fprintf(&b, " Это: %s\n", what)
fmt.Fprintf(&b, " Реально находится на: %s:%d\n\n", f.HostName, f.Port)
}
+15 -25
View File
@@ -9,39 +9,29 @@ type AllocatedForward struct {
LocalPort int
}
// localPortBase is where fallback local ports are handed out from once a
// forward's natural remote port is already taken locally by another
// forward. Chosen high enough to avoid colliding with well-known ports the
// user's own machine might already be using.
// localPortBase is where every local port is handed out from. Forwards are
// never given a local port equal to their remote port: many remote ports
// worth forwarding are privileged (< 1024 — ssh's own 22 above all), and
// binding a listener on a privileged local port requires admin/root rights
// the end user does not have and should not need. Even for unprivileged
// remote ports, always starting from a fixed high range keeps assignment
// simple and collision-free without a "does this port happen to be free
// locally" special case.
const localPortBase = 20000
// AllocateLocalPorts assigns every forward a local port, all of which the
// user opens at once over a single ssh connection (one LocalForward line
// per forward — see RenderClientConfig). This is the actual answer to
// "avoid collisions when forwarding everything simultaneously": many hosts
// commonly expose the same remote port (e.g. 22, or an app port like 7888
// repeated across ten hosts), but only one of them can bind to that same
// port number locally. Each forward keeps its remote port as the local
// port when that's still free (so the common case reads naturally, e.g.
// remote 7888 -> local 7888), and falls back to the next free port from
// localPortBase upward on collision. Assignment is a pure function of the
// input order and set, so re-exporting an unchanged host list reproduces
// the same local ports.
// per forward — see RenderClientConfig). Ports are handed out sequentially
// from localPortBase, so many forwards sharing the same remote port (e.g.
// port 22 repeated across ten hosts) each still get a distinct, unprivileged
// local port. Assignment is a pure function of the input order, so
// re-exporting an unchanged host list reproduces the same local ports.
func AllocateLocalPorts(forwards []model.Forward) []AllocatedForward {
used := make(map[int]bool, len(forwards))
next := localPortBase
out := make([]AllocatedForward, 0, len(forwards))
for _, f := range forwards {
lp := f.Port
if lp <= 0 || lp > 65535 || used[lp] {
for used[next] {
next++
}
lp = next
next++
}
used[lp] = true
out = append(out, AllocatedForward{Forward: f, LocalPort: lp})
out = append(out, AllocatedForward{Forward: f, LocalPort: next})
next++
}
return out
}