HTTPS: одна кнопка «Сохранить» на раздел (перенаправление, доменное имя, адрес без порта)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Q7eREaYwUt1i4fNLZcGnjn
This commit is contained in:
fontvielle
2026-10-22 15:39:30 +03:00
parent 005c5e8368
commit 7fd4bd0af9
3 changed files with 137 additions and 123 deletions
+63 -40
View File
@@ -294,17 +294,38 @@ func registerHTTPS(mux *http.ServeMux, rc *RuntimeConfig) {
http.Error(w, "method", http.StatusMethodNotAllowed)
return
}
// одна форма раздела: перенаправление, доменное имя, адрес без порта. Применяется только изменённое;
// порты — последними: bj после них перезапускается.
h := rc.Snapshot().HTTPS
h.RedirectOff = r.FormValue("redirect") == ""
if err := rc.UpdateHTTPS(h); err != nil {
setupFlash(w, r, "HTTPS: "+err.Error())
return
var msgs []string
if off := r.FormValue("redirect") == ""; off != h.RedirectOff {
h.RedirectOff = off
if err := rc.UpdateHTTPS(h); err != nil {
setupFlash(w, r, "HTTPS: "+err.Error())
return
}
if h.RedirectOn() {
msgs = append(msgs, "Браузеры перенаправляются с http:// на https://.")
} else {
msgs = append(msgs, "Перенаправление с http:// выключено.")
}
}
msg := "HTTPS: перенаправление с HTTP выключено"
if h.RedirectOn() {
msg = "HTTPS: браузеры теперь перенаправляются на https://" + httpsHostPort("…", h.publicPort())
if _, sent := r.Form["hostnames"]; sent && strings.Join(strings.Fields(strings.ToLower(r.FormValue("hostnames"))), " ") != strings.Join(h.Hostnames, " ") {
msg, ok := saveHostnames(r.Context(), rc, r.FormValue("hostnames"))
msgs = append(msgs, msg)
if !ok {
setupFlash(w, r, strings.Join(msgs, " "))
return
}
}
setupFlash(w, r, msg)
// включено, но порт 443 не поднялся — «Сохранить» повторяет выдачу права
if on := r.FormValue("std_ports") != ""; on != rc.Snapshot().HTTPS.StdPorts || (on && stdPortsState() != "ok") {
msgs = append(msgs, applyStdPorts(r.Context(), rc, on))
}
if len(msgs) == 0 {
msgs = append(msgs, "HTTPS: изменений нет.")
}
setupFlash(w, r, strings.Join(msgs, " "))
})
// адрес без номера порта: 443 и 80 (право на порты — через root-помощника, bj перезапускается)
mux.HandleFunc("/admin/setup/https/stdports", func(w http.ResponseWriter, r *http.Request) {
@@ -312,38 +333,7 @@ func registerHTTPS(mux *http.ServeMux, rc *RuntimeConfig) {
http.Error(w, "method", http.StatusMethodNotAllowed)
return
}
on := r.FormValue("std_ports") != ""
h := rc.Snapshot().HTTPS
h.StdPorts = on
if err := rc.UpdateHTTPS(h); err != nil {
setupFlash(w, r, "HTTPS: "+err.Error())
return
}
mode := "off"
if on {
mode = "on"
}
ctx, cancel := context.WithTimeout(r.Context(), 40*time.Second)
res, err := runKeymediaOp(ctx, "system-ports", map[string]string{"extra": mode})
cancel()
if err == nil {
if ok, _ := res["ok"].(bool); !ok {
err = fmt.Errorf("%v", res["error"])
}
}
if err != nil {
setupFlash(w, r, "Адрес без номера порта: настройка сохранена, но право на порты не выдано — "+err.Error())
return
}
name := "имя-сервера"
if len(h.Hostnames) > 0 {
name = h.Hostnames[0]
}
if on {
setupFlash(w, r, "Готово: bj перезапускается (несколько секунд) и будет открываться по https://"+name+"/ — без :"+strconv.Itoa(h.port())+"; http://"+name+"/ перейдёт на https:// сам. Обновите страницу через 10 секунд.")
} else {
setupFlash(w, r, "Адрес без номера порта выключен: bj перезапускается и открывается по https://"+name+":"+strconv.Itoa(h.port())+"/.")
}
setupFlash(w, r, applyStdPorts(r.Context(), rc, r.FormValue("std_ports") != ""))
})
// свой сертификат организации (PEM: сертификат с цепочкой и закрытый ключ)
mux.HandleFunc("/admin/setup/https/cert", func(w http.ResponseWriter, r *http.Request) {
@@ -541,3 +531,36 @@ func stdPortsState() string {
}
return "ожидает перезапуска bj"
}
// applyStdPorts — адрес без номера порта: сохранить настройку и выдать/снять службе право на 443/80
// (через root-помощника; bj после этого перезапускается). Возвращает текст для пользователя.
func applyStdPorts(ctx0 context.Context, rc *RuntimeConfig, on bool) string {
h := rc.Snapshot().HTTPS
h.StdPorts = on
if err := rc.UpdateHTTPS(h); err != nil {
return "HTTPS: " + err.Error()
}
mode := "off"
if on {
mode = "on"
}
ctx, cancel := context.WithTimeout(ctx0, 40*time.Second)
res, err := runKeymediaOp(ctx, "system-ports", map[string]string{"extra": mode})
cancel()
if err == nil {
if ok, _ := res["ok"].(bool); !ok {
err = fmt.Errorf("%v", res["error"])
}
}
if err != nil {
return "Адрес без номера порта: настройка сохранена, но право на порты не выдано — " + err.Error()
}
name := "имя-сервера"
if len(h.Hostnames) > 0 {
name = h.Hostnames[0]
}
if on {
return "Готово: bj перезапускается (несколько секунд) и будет открываться по https://" + name + "/ — без :" + strconv.Itoa(h.port()) + "; http://" + name + "/ перейдёт на https:// сам. Обновите страницу через 10 секунд."
}
return "Адрес без номера порта выключен: bj перезапускается и открывается по https://" + name + ":" + strconv.Itoa(h.port()) + "/."
}