Files

90 lines
3.8 KiB
Go

package lkgateway
import (
"crypto/sha256"
"crypto/subtle"
"encoding/hex"
"net/http"
"os"
)
// advanced_gate.go — пароль на «перспективные модули» (QUIK МНП, Обмен Fancy).
// Эти модули относятся к будущим профилям («автомат/полуавтомат» со своим ЛК) и
// пока не в проде. Чтобы оператор их случайно не трогал, они скрыты и
// открываются паролем. Простая cookie-схема: значение cookie = токен пароля,
// подделать без пароля нельзя. Пароль берётся из BJ_ADVANCED_PASSWORD, иначе —
// значение по умолчанию.
const defaultAdvancedPassword = "bj-modules-2026"
const advancedCookie = "bj_adv"
func effectiveAdvancedPassword() string {
if p := os.Getenv("BJ_ADVANCED_PASSWORD"); p != "" {
return p
}
return defaultAdvancedPassword
}
// advancedToken — неподделываемый токен для cookie: hex(sha256(пароль)).
func advancedToken() string {
sum := sha256.Sum256([]byte("bj-adv:" + effectiveAdvancedPassword()))
return hex.EncodeToString(sum[:])
}
// advancedUnlocked — открыт ли доступ к перспективным модулям в этом запросе.
func advancedUnlocked(r *http.Request) bool {
// Модуль QUIK МНП (обмен Fancy) есть в лицензии — разделы открыты без пароля: пароль нужен
// только там, где модули не куплены. Иначе кнопки разделов видны, а настройки пустые.
if globalRC != nil && moduleAllowed(globalRC, "quik-mnp") {
return true
}
if !devMode(globalRC) { // пароль на модули — инструмент разработчиков
return false
}
c, err := r.Cookie(advancedCookie)
if err != nil {
return false
}
want := advancedToken()
return subtle.ConstantTimeCompare([]byte(c.Value), []byte(want)) == 1
}
// requireAdvanced — защита ручек сохранения перспективных модулей: если доступ
// не открыт, отвечает 403. true — можно продолжать.
func requireAdvanced(w http.ResponseWriter, r *http.Request) bool {
if advancedUnlocked(r) {
return true
}
http.Error(w, "Раздел «Перспективные модули» закрыт. Откройте его паролем в Настройке.", http.StatusForbidden)
return false
}
// unlockAdvanced — POST /admin/setup/advanced-unlock: проверяет пароль и ставит
// cookie доступа.
func (h *setupHandlers) unlockAdvanced(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodPost {
http.Error(w, "method", http.StatusMethodNotAllowed)
return
}
if r.FormValue("password") != effectiveAdvancedPassword() {
setupFlash(w, r, "Перспективные модули: неверный пароль")
return
}
http.SetCookie(w, &http.Cookie{
Name: advancedCookie, Value: advancedToken(), Path: "/admin",
HttpOnly: true, SameSite: http.SameSiteLaxMode, MaxAge: 30 * 24 * 3600,
})
setupFlash(w, r, "Перспективные модули открыты (QUIK, Обмен Fancy). Разделы появились в меню слева.")
}
// lockAdvanced — POST /admin/setup/advanced-lock: снова прячет модули.
func (h *setupHandlers) lockAdvanced(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodPost {
http.Error(w, "method", http.StatusMethodNotAllowed)
return
}
http.SetCookie(w, &http.Cookie{
Name: advancedCookie, Value: "", Path: "/admin", HttpOnly: true, MaxAge: -1,
})
setupFlash(w, r, "Перспективные модули снова скрыты")
}