Установка: приветственный экран консоли (bj-welcome: адрес веб-входа и состояние, всегда), ядро с образа без ключа продукта (--bundle), ключ продукта на первой веб-странице, повтор вопроса при каждой загрузке
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Q4YVo4UMopqT5DzicqpPjL
This commit is contained in:
@@ -7,10 +7,12 @@ package lkgateway
|
||||
// (открытый режим до создания первого пользователя).
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"html/template"
|
||||
"log"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
@@ -36,6 +38,8 @@ func firstRunPending() bool {
|
||||
|
||||
type firstRunData struct {
|
||||
Error, Login, Name string
|
||||
NeedKey bool // лицензия ещё не активирована — предложить ввести ключ продукта здесь
|
||||
ProductKey string
|
||||
}
|
||||
|
||||
var firstRunTpl = template.Must(template.New("first-run").Parse(firstRunHTML))
|
||||
@@ -47,11 +51,13 @@ func registerFirstRun(mux *http.ServeMux) {
|
||||
return
|
||||
}
|
||||
var d firstRunData
|
||||
d.NeedKey = globalRC != nil && !licenseStatus(globalRC).Valid
|
||||
w.Header().Set("Cache-Control", "no-store")
|
||||
if r.Method == http.MethodPost {
|
||||
ip := clientIP(r)
|
||||
key := "first-run|" + ip
|
||||
d.Login, d.Name = strings.TrimSpace(r.FormValue("login")), strings.TrimSpace(r.FormValue("name"))
|
||||
d.ProductKey = strings.ToUpper(strings.NewReplacer(" ", "").Replace(strings.TrimSpace(r.FormValue("product_key"))))
|
||||
pw, pw2 := r.FormValue("password"), r.FormValue("password2")
|
||||
code := strings.NewReplacer("-", "", " ", "").Replace(strings.TrimSpace(r.FormValue("code")))
|
||||
var st firstRunState
|
||||
@@ -88,6 +94,23 @@ func registerFirstRun(mux *http.ServeMux) {
|
||||
s := globalSessions.New(u.Login, ip, r.UserAgent())
|
||||
http.SetCookie(w, &http.Cookie{Name: sessionCookie, Value: s.Token, Path: "/", HttpOnly: true, SameSite: http.SameSiteLaxMode, Secure: r.TLS != nil, MaxAge: int(sessionMaxLife.Seconds())})
|
||||
log.Printf("auth: первичная настройка: создан администратор %s с %s", u.Login, ip)
|
||||
// ключ продукта, если его не вводили на сервере: активируем сразу, чтобы модули и обновления заработали
|
||||
if d.NeedKey && d.ProductKey != "" && globalRC != nil {
|
||||
actx, acancel := context.WithTimeout(r.Context(), 30*time.Second)
|
||||
err := LicenseActivate(actx, globalRC, d.ProductKey)
|
||||
acancel()
|
||||
if err != nil {
|
||||
log.Printf("auth: первичная настройка: ключ продукта не принят: %v", err)
|
||||
http.Redirect(w, r, "/admin/setup?flash="+url.QueryEscape("Лицензия: ключ продукта не принят — "+err.Error()+". Введите его в разделе «Лицензия».")+"#sec-license", http.StatusSeeOther)
|
||||
return
|
||||
}
|
||||
http.Redirect(w, r, "/admin/setup?flash="+url.QueryEscape("Лицензия активирована. Дальше — подключение к базе DEPO, затем реквизиты НРД (кнопка «Определить из DEPO»)."), http.StatusSeeOther)
|
||||
return
|
||||
}
|
||||
if d.NeedKey {
|
||||
http.Redirect(w, r, "/admin/setup?flash="+url.QueryEscape("Администратор создан. Лицензия ещё не активирована — введите ключ продукта в разделе «Лицензия», иначе модули и обновления недоступны.")+"#sec-license", http.StatusSeeOther)
|
||||
return
|
||||
}
|
||||
http.Redirect(w, r, "/admin/setup", http.StatusSeeOther)
|
||||
return
|
||||
}
|
||||
@@ -123,6 +146,7 @@ code{font-size:12px}
|
||||
<label>Имя</label><input type="text" name="name" value="{{.Name}}" autocomplete="name">
|
||||
<label>Пароль, не короче 10 символов</label><input type="password" name="password" minlength="10" autocomplete="new-password" required>
|
||||
<label>Повтор пароля</label><input type="password" name="password2" minlength="10" autocomplete="new-password" required>
|
||||
{{if .NeedKey}}<label>Ключ продукта (BJ-XXXX-XXXX-XXXX) — если не вводили на сервере; можно позже в «Настройка → Лицензия»</label><input type="text" name="product_key" value="{{.ProductKey}}" placeholder="BJ-XXXX-XXXX-XXXX" autocomplete="off" style="text-transform:uppercase">{{end}}
|
||||
<button type="submit">Создать администратора</button>
|
||||
{{if .Error}}<div class="err">{{.Error}}</div>{{end}}
|
||||
<div class="hint">Код потерян или истёк: на сервере выполните <code>sudo bj-installer first-run-code</code>.</div>
|
||||
|
||||
Reference in New Issue
Block a user