mirror of
https://hubproxy.babadafafafafa.cn/https://github.com/1Panel-dev/1Panel.git
synced 2026-09-20 16:13:59 +08:00
* fix: Fix the issue of menu loss caused by switching service regions * fix: Fix the issue of menu loss caused by switching service regions
845 lines
23 KiB
Go
845 lines
23 KiB
Go
package service
|
|
|
|
import (
|
|
"bytes"
|
|
"context"
|
|
"crypto/rand"
|
|
"crypto/rsa"
|
|
"crypto/tls"
|
|
"crypto/x509"
|
|
"encoding/json"
|
|
"encoding/pem"
|
|
"fmt"
|
|
"io"
|
|
"net"
|
|
"net/http"
|
|
"net/url"
|
|
"os"
|
|
"path"
|
|
"sort"
|
|
"strconv"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/1Panel-dev/1Panel/core/app/dto"
|
|
"github.com/1Panel-dev/1Panel/core/app/model"
|
|
"github.com/1Panel-dev/1Panel/core/app/repo"
|
|
"github.com/1Panel-dev/1Panel/core/buserr"
|
|
"github.com/1Panel-dev/1Panel/core/constant"
|
|
"github.com/1Panel-dev/1Panel/core/global"
|
|
"github.com/1Panel-dev/1Panel/core/i18n"
|
|
"github.com/1Panel-dev/1Panel/core/utils/common"
|
|
"github.com/1Panel-dev/1Panel/core/utils/controller"
|
|
"github.com/1Panel-dev/1Panel/core/utils/encrypt"
|
|
"github.com/1Panel-dev/1Panel/core/utils/firewall"
|
|
"github.com/1Panel-dev/1Panel/core/utils/menutree"
|
|
"github.com/1Panel-dev/1Panel/core/utils/passkey"
|
|
"github.com/1Panel-dev/1Panel/core/utils/req_helper/proxy_local"
|
|
"github.com/1Panel-dev/1Panel/core/utils/xpack"
|
|
"github.com/gin-gonic/gin"
|
|
"golang.org/x/net/proxy"
|
|
)
|
|
|
|
type SettingService struct{}
|
|
|
|
type ISettingService interface {
|
|
GetSettingInfo() (*dto.SettingInfo, error)
|
|
GetSettingBaseInfo() (*dto.SettingBaseInfo, error)
|
|
LoadInterfaceAddr() ([]string, error)
|
|
Update(c *gin.Context, key, value string) error
|
|
UpdatePort(port uint) error
|
|
UpdateBindInfo(req dto.BindInfo) error
|
|
UpdateSSL(c *gin.Context, req dto.SSLUpdate) error
|
|
LoadFromCert() (*dto.SSLInfo, error)
|
|
|
|
UpdateProxy(req dto.ProxyUpdate) error
|
|
|
|
GetTerminalInfo() (*dto.TerminalInfo, error)
|
|
UpdateTerminal(req dto.TerminalInfo) error
|
|
|
|
UpdateSystemSSL() error
|
|
GenerateRSAKey() error
|
|
|
|
UpdateAppstoreConfig(req dto.AppstoreUpdate) error
|
|
GetAppstoreConfig() (*dto.AppstoreConfig, error)
|
|
DefaultMenu() error
|
|
|
|
GetMemo() (string, error)
|
|
UpdateMemo(content string) error
|
|
}
|
|
|
|
func NewISettingService() ISettingService {
|
|
return &SettingService{}
|
|
}
|
|
|
|
func (u *SettingService) GetSettingInfo() (*dto.SettingInfo, error) {
|
|
setting, err := settingRepo.List()
|
|
if err != nil {
|
|
return nil, buserr.New("ErrRecordNotFound")
|
|
}
|
|
settingMap := make(map[string]string)
|
|
for _, set := range setting {
|
|
settingMap[set.Key] = set.Value
|
|
}
|
|
repairAndSortHideMenu(settingMap)
|
|
var info dto.SettingInfo
|
|
arr, err := json.Marshal(settingMap)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if err := json.Unmarshal(arr, &info); err != nil {
|
|
return nil, err
|
|
}
|
|
if info.Edition == "" {
|
|
info.Edition = "cn"
|
|
_ = settingRepo.UpdateOrCreate("Edition", info.Edition)
|
|
}
|
|
if info.MenuAccordion == "" {
|
|
info.MenuAccordion = constant.StatusDisable
|
|
_ = settingRepo.UpdateOrCreate("MenuAccordion", info.MenuAccordion)
|
|
}
|
|
if info.ProxyPasswdKeep != constant.StatusEnable {
|
|
info.ProxyPasswd = ""
|
|
} else {
|
|
info.ProxyPasswd, _ = encrypt.StringDecrypt(info.ProxyPasswd)
|
|
}
|
|
|
|
return &info, err
|
|
}
|
|
|
|
func (u *SettingService) GetSettingBaseInfo() (*dto.SettingBaseInfo, error) {
|
|
setting, err := settingRepo.List()
|
|
if err != nil {
|
|
return nil, buserr.New("ErrRecordNotFound")
|
|
}
|
|
settingMap := make(map[string]string)
|
|
for _, set := range setting {
|
|
settingMap[set.Key] = set.Value
|
|
}
|
|
repairAndSortHideMenu(settingMap)
|
|
var info dto.SettingBaseInfo
|
|
arr, err := json.Marshal(settingMap)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if err := json.Unmarshal(arr, &info); err != nil {
|
|
return nil, err
|
|
}
|
|
if info.Edition == "" {
|
|
info.Edition = "cn"
|
|
_ = settingRepo.UpdateOrCreate("Edition", info.Edition)
|
|
}
|
|
if info.MenuAccordion == "" {
|
|
info.MenuAccordion = constant.StatusDisable
|
|
_ = settingRepo.UpdateOrCreate("MenuAccordion", info.MenuAccordion)
|
|
}
|
|
|
|
return &info, err
|
|
}
|
|
|
|
func repairAndSortHideMenu(settingMap map[string]string) {
|
|
hideMenu, ok := settingMap["HideMenu"]
|
|
if !ok || strings.TrimSpace(hideMenu) == "" {
|
|
return
|
|
}
|
|
var menus []dto.ShowMenu
|
|
if err := json.Unmarshal([]byte(hideMenu), &menus); err != nil || len(menus) == 0 {
|
|
return
|
|
}
|
|
|
|
menus, changed := menutree.EnsureXpackAppMenus(menus, nil)
|
|
if changed {
|
|
repairedBytes, err := json.Marshal(menus)
|
|
if err != nil {
|
|
global.LOG.Warnf("marshal repaired HideMenu failed, err: %v", err)
|
|
} else {
|
|
updated, err := settingRepo.UpdateIfMatch("HideMenu", hideMenu, string(repairedBytes))
|
|
if err != nil {
|
|
global.LOG.Warnf("persist repaired HideMenu failed, err: %v", err)
|
|
} else if !updated {
|
|
global.LOG.Debug("skip persisting repaired HideMenu because the setting changed concurrently")
|
|
}
|
|
}
|
|
}
|
|
sortShowMenus(menus)
|
|
if sortedBytes, err := json.Marshal(menus); err == nil {
|
|
settingMap["HideMenu"] = string(sortedBytes)
|
|
}
|
|
}
|
|
|
|
func sortShowMenus(menus []dto.ShowMenu) {
|
|
for i := range menus {
|
|
if len(menus[i].Children) > 0 {
|
|
sortShowMenus(menus[i].Children)
|
|
}
|
|
}
|
|
sort.SliceStable(menus, func(i, j int) bool {
|
|
if menus[i].Sort == menus[j].Sort {
|
|
return menus[i].ID < menus[j].ID
|
|
}
|
|
return menus[i].Sort < menus[j].Sort
|
|
})
|
|
}
|
|
|
|
func (u *SettingService) Update(c *gin.Context, key, value string) error {
|
|
oldVal, err := settingRepo.Get(repo.WithByKey(key))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if oldVal.Value == value && key != "HideMenu" {
|
|
return nil
|
|
}
|
|
sessionLifeTime := 0
|
|
switch key {
|
|
case "SessionTimeout":
|
|
sessionLifeTime, err = strconv.Atoi(value)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
case "AppStoreLastModified":
|
|
exist, _ := settingRepo.Get(repo.WithByKey("AppStoreLastModified"))
|
|
if exist.ID == 0 {
|
|
_ = settingRepo.Create("AppStoreLastModified", value)
|
|
return nil
|
|
}
|
|
case "HideMenu":
|
|
var menus []dto.ShowMenu
|
|
if err := json.Unmarshal([]byte(value), &menus); err != nil {
|
|
return err
|
|
}
|
|
var previousMenus []dto.ShowMenu
|
|
_ = json.Unmarshal([]byte(oldVal.Value), &previousMenus)
|
|
menus, _ = menutree.PreserveMissingMenus(menus, previousMenus)
|
|
if len(menus) == 0 {
|
|
return fmt.Errorf("hide menu cannot be empty")
|
|
}
|
|
menus, _ = menutree.EnsureXpackAppMenus(menus, previousMenus)
|
|
for i := 0; i < len(menus); i++ {
|
|
if menus[i].Label == "Home-Menu" || menus[i].Label == "App-Menu" || menus[i].Label == "Setting-Menu" {
|
|
menus[i].IsShow = true
|
|
}
|
|
}
|
|
menuItem, err := json.Marshal(&menus)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
value = string(menuItem)
|
|
}
|
|
if oldVal.Value == value {
|
|
return nil
|
|
}
|
|
|
|
if err := settingRepo.Update(key, value); err != nil {
|
|
return err
|
|
}
|
|
if key == "ExpirationDays" {
|
|
if err := xpack.AuthProvider.SyncPasswordExpirationTime(value); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
if key == "SessionTimeout" {
|
|
global.SESSION.ApplyTimeout(sessionLifeTime)
|
|
}
|
|
|
|
switch key {
|
|
case "BindDomain":
|
|
if len(value) != 0 {
|
|
_ = global.SESSION.Clean()
|
|
}
|
|
if err := u.clearPasskeySettings(); err != nil {
|
|
return err
|
|
}
|
|
case "Language":
|
|
i18n.SetCachedDBLanguage(value)
|
|
if err := xpack.MultiNodeProvider.Sync(constant.SyncLanguage); err != nil {
|
|
global.LOG.Errorf("sync language to node failed, err: %v", err)
|
|
}
|
|
case "UpgradeBackupCopies":
|
|
dropBackupCopies()
|
|
case "ScriptSync":
|
|
if value == constant.StatusEnable {
|
|
StartSync()
|
|
} else {
|
|
global.Cron.Remove(global.ScriptSyncJobID)
|
|
}
|
|
case "Edition":
|
|
global.CONF.Base.Edition = value
|
|
if err := xpack.MultiNodeProvider.Sync(constant.SyncEdition); err != nil {
|
|
global.LOG.Errorf("sync edition to node failed, err: %v", err)
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (u *SettingService) LoadInterfaceAddr() ([]string, error) {
|
|
addrMap := make(map[string]struct{})
|
|
addrs, err := net.InterfaceAddrs()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
for _, addr := range addrs {
|
|
ipNet, ok := addr.(*net.IPNet)
|
|
if ok && ipNet.IP.To16() != nil {
|
|
addrMap[ipNet.IP.String()] = struct{}{}
|
|
}
|
|
}
|
|
var data []string
|
|
for key := range addrMap {
|
|
data = append(data, key)
|
|
}
|
|
return data, nil
|
|
}
|
|
|
|
func (u *SettingService) UpdateBindInfo(req dto.BindInfo) error {
|
|
if err := settingRepo.Update("Ipv6", req.Ipv6); err != nil {
|
|
return err
|
|
}
|
|
if err := settingRepo.Update("BindAddress", req.BindAddress); err != nil {
|
|
return err
|
|
}
|
|
go func() {
|
|
time.Sleep(1 * time.Second)
|
|
controller.RestartPanel(true, false, false)
|
|
}()
|
|
return nil
|
|
}
|
|
|
|
func (u *SettingService) UpdateProxy(req dto.ProxyUpdate) error {
|
|
if req.ProxyType == "https" || req.ProxyType == "http" {
|
|
req.ProxyUrl = req.ProxyType + "://" + req.ProxyUrl
|
|
}
|
|
if err := checkProxy(req); err != nil {
|
|
return err
|
|
}
|
|
if err := settingRepo.Update("ProxyUrl", req.ProxyUrl); err != nil {
|
|
return err
|
|
}
|
|
if err := settingRepo.Update("ProxyType", req.ProxyType); err != nil {
|
|
return err
|
|
}
|
|
if err := settingRepo.Update("ProxyPort", req.ProxyPort); err != nil {
|
|
return err
|
|
}
|
|
if err := settingRepo.Update("ProxyUser", req.ProxyUser); err != nil {
|
|
return err
|
|
}
|
|
pass, _ := encrypt.StringEncrypt(req.ProxyPasswd)
|
|
if err := settingRepo.Update("ProxyPasswd", pass); err != nil {
|
|
return err
|
|
}
|
|
if err := settingRepo.Update("ProxyPasswdKeep", req.ProxyPasswdKeep); err != nil {
|
|
return err
|
|
}
|
|
if err := xpack.MultiNodeProvider.ProxyDocker(loadDockerProxy(req)); err != nil {
|
|
return err
|
|
}
|
|
syncScope := constant.SyncSystemProxy
|
|
if req.WithDockerRestart {
|
|
syncScope = constant.SyncSystemProxyWithRestartDocker
|
|
}
|
|
if err := xpack.MultiNodeProvider.Sync(syncScope); err != nil {
|
|
global.LOG.Errorf("sync proxy to node failed, err: %v", err)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (u *SettingService) UpdatePort(port uint) error {
|
|
if common.ScanPort(int(port)) {
|
|
return buserr.WithDetail("ErrPortInUsed", port, nil)
|
|
}
|
|
oldPort, err := settingRepo.Get(repo.WithByKey("ServerPort"))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if oldPort.Value == fmt.Sprintf("%v", port) {
|
|
return nil
|
|
}
|
|
if err := firewall.UpdatePort(oldPort.Value, fmt.Sprintf("%v", port)); err != nil {
|
|
return err
|
|
}
|
|
|
|
if err := settingRepo.Update("ServerPort", strconv.Itoa(int(port))); err != nil {
|
|
return err
|
|
}
|
|
if err := u.clearPasskeySettings(); err != nil {
|
|
return err
|
|
}
|
|
go func() {
|
|
time.Sleep(1 * time.Second)
|
|
controller.RestartPanel(true, false, false)
|
|
}()
|
|
return nil
|
|
}
|
|
|
|
func (u *SettingService) UpdateSSL(c *gin.Context, req dto.SSLUpdate) error {
|
|
secretDir := path.Join(global.CONF.Base.InstallDir, "1panel/secret")
|
|
if req.SSL == constant.StatusDisable {
|
|
c.SetCookie(constant.SessionName, "", -1, "/", "", false, true)
|
|
c.SetCookie(constant.CSRFTokenName, "", -1, "/", "", false, false)
|
|
if err := settingRepo.Update("SSL", constant.StatusDisable); err != nil {
|
|
return err
|
|
}
|
|
if err := settingRepo.Update("SSLType", "self"); err != nil {
|
|
return err
|
|
}
|
|
_ = os.Remove(path.Join(secretDir, "server.crt"))
|
|
_ = os.Remove(path.Join(secretDir, "server.key"))
|
|
go func() {
|
|
time.Sleep(1 * time.Second)
|
|
controller.RestartPanel(true, false, false)
|
|
}()
|
|
return nil
|
|
}
|
|
if _, err := os.Stat(secretDir); err != nil && os.IsNotExist(err) {
|
|
if err = os.MkdirAll(secretDir, os.ModePerm); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
if err := settingRepo.Update("SSLType", req.SSLType); err != nil {
|
|
return err
|
|
}
|
|
var (
|
|
secret string
|
|
key string
|
|
)
|
|
|
|
switch req.SSLType {
|
|
case "import-paste":
|
|
secret = req.Cert
|
|
key = req.Key
|
|
case "import-local":
|
|
keyFile, err := os.ReadFile(req.Key)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
key = string(keyFile)
|
|
certFile, err := os.ReadFile(req.Cert)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
secret = string(certFile)
|
|
case "select":
|
|
ssl, err := agentRepo.GetWebsiteSSL(repo.WithByID(req.SSLID))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
secret = ssl.Pem
|
|
key = ssl.PrivateKey
|
|
if err := settingRepo.Update("SSLID", strconv.Itoa(int(req.SSLID))); err != nil {
|
|
return err
|
|
}
|
|
case "self":
|
|
ca, err := agentRepo.GetCA(repo.WithByName("1Panel"))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
params := make(map[string]interface{})
|
|
params["domains"] = req.Domain
|
|
params["time"] = 10
|
|
params["unit"] = "year"
|
|
params["keyType"] = "EC256"
|
|
params["id"] = ca.ID
|
|
jsonData, err := json.Marshal(params)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
res, err := proxy_local.NewLocalClient("/api/v2/websites/ca/obtain", http.MethodPost, bytes.NewReader(jsonData), nil)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
jsonBytes, err := json.Marshal(res)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
var ssl model.WebsiteSSL
|
|
if err := json.Unmarshal(jsonBytes, &ssl); err != nil {
|
|
return err
|
|
}
|
|
secret = ssl.Pem
|
|
key = ssl.PrivateKey
|
|
if err := settingRepo.Update("SSLID", strconv.Itoa(int(ssl.ID))); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
if err := os.WriteFile(path.Join(secretDir, "server.crt.tmp"), []byte(secret), 0600); err != nil {
|
|
return err
|
|
}
|
|
if err := os.WriteFile(path.Join(secretDir, "server.key.tmp"), []byte(key), 0600); err != nil {
|
|
return err
|
|
}
|
|
if err := checkCertValid(); err != nil {
|
|
return err
|
|
}
|
|
if err := os.Rename(path.Join(secretDir, "server.crt.tmp"), path.Join(secretDir, "server.crt")); err != nil {
|
|
return err
|
|
}
|
|
if err := os.Rename(path.Join(secretDir, "server.key.tmp"), path.Join(secretDir, "server.key")); err != nil {
|
|
return err
|
|
}
|
|
status := global.CONF.Conn.SSL
|
|
if req.SSL != status {
|
|
go func() {
|
|
time.Sleep(1 * time.Second)
|
|
controller.RestartPanel(true, false, false)
|
|
}()
|
|
}
|
|
if err := settingRepo.Update("SSL", req.SSL); err != nil {
|
|
return err
|
|
}
|
|
global.CONF.Conn.SSL = req.SSL
|
|
return u.UpdateSystemSSL()
|
|
}
|
|
|
|
func (u *SettingService) LoadFromCert() (*dto.SSLInfo, error) {
|
|
ssl, err := settingRepo.Get(repo.WithByKey("SSL"))
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if ssl.Value == constant.StatusDisable {
|
|
return &dto.SSLInfo{}, nil
|
|
}
|
|
sslType, err := settingRepo.Get(repo.WithByKey("SSLType"))
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
var data dto.SSLInfo
|
|
switch sslType.Value {
|
|
case "self":
|
|
data, err = loadInfoFromCert()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
case "import-paste", "import-local":
|
|
data, err = loadInfoFromCert()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if _, err := os.Stat(path.Join(global.CONF.Base.InstallDir, "1panel/secret/server.crt")); err != nil {
|
|
return nil, fmt.Errorf("load server.crt file failed, err: %v", err)
|
|
}
|
|
certFile, _ := os.ReadFile(path.Join(global.CONF.Base.InstallDir, "1panel/secret/server.crt"))
|
|
data.Cert = string(certFile)
|
|
|
|
if _, err := os.Stat(path.Join(global.CONF.Base.InstallDir, "1panel/secret/server.key")); err != nil {
|
|
return nil, fmt.Errorf("load server.key file failed, err: %v", err)
|
|
}
|
|
keyFile, _ := os.ReadFile(path.Join(global.CONF.Base.InstallDir, "1panel/secret/server.key"))
|
|
data.Key = string(keyFile)
|
|
case "select":
|
|
sslID, err := settingRepo.Get(repo.WithByKey("SSLID"))
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
id, _ := strconv.Atoi(sslID.Value)
|
|
ssl, err := agentRepo.GetWebsiteSSL(repo.WithByID(uint(id)))
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
data.Domain = ssl.PrimaryDomain
|
|
data.SSLID = uint(id)
|
|
data.Timeout = ssl.ExpireDate.Format(constant.DateTimeLayout)
|
|
}
|
|
return &data, nil
|
|
}
|
|
|
|
func (u *SettingService) GetTerminalInfo() (*dto.TerminalInfo, error) {
|
|
setting, err := settingRepo.List()
|
|
if err != nil {
|
|
return nil, buserr.New("ErrRecordNotFound")
|
|
}
|
|
settingMap := make(map[string]string)
|
|
for _, set := range setting {
|
|
settingMap[set.Key] = set.Value
|
|
}
|
|
var info dto.TerminalInfo
|
|
arr, err := json.Marshal(settingMap)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if err := json.Unmarshal(arr, &info); err != nil {
|
|
return nil, err
|
|
}
|
|
return &info, err
|
|
}
|
|
func (u *SettingService) UpdateTerminal(req dto.TerminalInfo) error {
|
|
if err := settingRepo.UpdateOrCreate("LineHeight", req.LineHeight); err != nil {
|
|
return err
|
|
}
|
|
if err := settingRepo.UpdateOrCreate("LetterSpacing", req.LetterSpacing); err != nil {
|
|
return err
|
|
}
|
|
if err := settingRepo.UpdateOrCreate("FontSize", req.FontSize); err != nil {
|
|
return err
|
|
}
|
|
if err := settingRepo.UpdateOrCreate("FontFamily", req.FontFamily); err != nil {
|
|
return err
|
|
}
|
|
if err := settingRepo.UpdateOrCreate("CursorBlink", req.CursorBlink); err != nil {
|
|
return err
|
|
}
|
|
if err := settingRepo.UpdateOrCreate("BackgroundColor", req.BackgroundColor); err != nil {
|
|
return err
|
|
}
|
|
if err := settingRepo.UpdateOrCreate("ForegroundColor", req.ForegroundColor); err != nil {
|
|
return err
|
|
}
|
|
if err := settingRepo.UpdateOrCreate("CursorBlink", req.CursorBlink); err != nil {
|
|
return err
|
|
}
|
|
if err := settingRepo.UpdateOrCreate("CursorStyle", req.CursorStyle); err != nil {
|
|
return err
|
|
}
|
|
if err := settingRepo.UpdateOrCreate("Scrollback", req.Scrollback); err != nil {
|
|
return err
|
|
}
|
|
if err := settingRepo.UpdateOrCreate("ScrollSensitivity", req.ScrollSensitivity); err != nil {
|
|
return err
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (u *SettingService) deleteCurrentSession(c *gin.Context) {
|
|
if c == nil {
|
|
return
|
|
}
|
|
sessionUser, err := global.SESSION.Get(c)
|
|
if err != nil || sessionUser.ID == "" {
|
|
return
|
|
}
|
|
_ = global.SESSION.DeleteByID(sessionUser.ID)
|
|
}
|
|
|
|
func (u *SettingService) clearPasskeySettings() error {
|
|
if err := settingRepo.Update(passkey.PasskeyUserIDSettingKey, ""); err != nil {
|
|
return err
|
|
}
|
|
if err := settingRepo.Update(passkey.PasskeyCredentialSettingKey, ""); err != nil {
|
|
return err
|
|
}
|
|
return xpack.AuthProvider.ClearPasskeys()
|
|
}
|
|
|
|
func (u *SettingService) UpdateSystemSSL() error {
|
|
certPath := path.Join(global.CONF.Base.InstallDir, "1panel/secret/server.crt")
|
|
keyPath := path.Join(global.CONF.Base.InstallDir, "1panel/secret/server.key")
|
|
certificate, err := os.ReadFile(certPath)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
key, err := os.ReadFile(keyPath)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
cert, err := tls.X509KeyPair(certificate, key)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
constant.CertStore.Store(&cert)
|
|
return nil
|
|
}
|
|
|
|
func loadInfoFromCert() (dto.SSLInfo, error) {
|
|
var info dto.SSLInfo
|
|
certFile := path.Join(global.CONF.Base.InstallDir, "1panel/secret/server.crt")
|
|
if _, err := os.Stat(certFile); err != nil {
|
|
return info, err
|
|
}
|
|
certData, err := os.ReadFile(certFile)
|
|
if err != nil {
|
|
return info, err
|
|
}
|
|
certBlock, _ := pem.Decode(certData)
|
|
if certBlock == nil {
|
|
return info, err
|
|
}
|
|
certObj, err := x509.ParseCertificate(certBlock.Bytes)
|
|
if err != nil {
|
|
return info, err
|
|
}
|
|
var domains []string
|
|
if len(certObj.IPAddresses) != 0 {
|
|
for _, ip := range certObj.IPAddresses {
|
|
domains = append(domains, ip.String())
|
|
}
|
|
}
|
|
if len(certObj.DNSNames) != 0 {
|
|
domains = append(domains, certObj.DNSNames...)
|
|
}
|
|
return dto.SSLInfo{
|
|
Domain: strings.Join(domains, ","),
|
|
Timeout: certObj.NotAfter.Format(constant.DateTimeLayout),
|
|
RootPath: path.Join(global.CONF.Base.InstallDir, "1panel/secret/server.crt"),
|
|
}, nil
|
|
}
|
|
|
|
func checkCertValid() error {
|
|
certificate, err := os.ReadFile(path.Join(global.CONF.Base.InstallDir, "1panel/secret/server.crt.tmp"))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
key, err := os.ReadFile(path.Join(global.CONF.Base.InstallDir, "1panel/secret/server.key.tmp"))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if _, err = tls.X509KeyPair(certificate, key); err != nil {
|
|
return err
|
|
}
|
|
certBlock, _ := pem.Decode(certificate)
|
|
if certBlock == nil {
|
|
return err
|
|
}
|
|
if _, err := x509.ParseCertificate(certBlock.Bytes); err != nil {
|
|
return err
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (u *SettingService) GenerateRSAKey() error {
|
|
priKey, _ := settingRepo.Get(repo.WithByKey("PASSWORD_PRIVATE_KEY"))
|
|
pubKey, _ := settingRepo.Get(repo.WithByKey("PASSWORD_PUBLIC_KEY"))
|
|
if priKey.Value != "" && pubKey.Value != "" {
|
|
return nil
|
|
}
|
|
privateKey, err := rsa.GenerateKey(rand.Reader, 2048)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
privateKeyPEM := encrypt.ExportPrivateKeyToPEM(privateKey)
|
|
publicKeyPEM, err := encrypt.ExportPublicKeyToPEM(&privateKey.PublicKey)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
err = settingRepo.UpdateOrCreate("PASSWORD_PRIVATE_KEY", privateKeyPEM)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
err = settingRepo.UpdateOrCreate("PASSWORD_PUBLIC_KEY", publicKeyPEM)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (u *SettingService) UpdateAppstoreConfig(req dto.AppstoreUpdate) error {
|
|
return settingRepo.UpdateOrCreate(req.Scope, req.Status)
|
|
}
|
|
|
|
func (u *SettingService) GetAppstoreConfig() (*dto.AppstoreConfig, error) {
|
|
res := &dto.AppstoreConfig{}
|
|
res.UninstallDeleteImage, _ = settingRepo.GetValueByKey("UninstallDeleteImage")
|
|
if res.UninstallDeleteImage == "" {
|
|
res.UninstallDeleteImage = constant.StatusDisable
|
|
}
|
|
res.UpgradeBackup, _ = settingRepo.GetValueByKey("UpgradeBackup")
|
|
if res.UpgradeBackup == "" {
|
|
res.UpgradeBackup = constant.StatusDisable
|
|
}
|
|
res.UpgradeDeleteImage, _ = settingRepo.GetValueByKey("UpgradeDeleteImage")
|
|
if res.UpgradeDeleteImage == "" {
|
|
res.UpgradeDeleteImage = constant.StatusDisable
|
|
}
|
|
res.UninstallDeleteBackup, _ = settingRepo.GetValueByKey("UninstallDeleteBackup")
|
|
if res.UninstallDeleteBackup == "" {
|
|
res.UninstallDeleteBackup = constant.StatusDisable
|
|
}
|
|
res.InstallAllowPort, _ = settingRepo.GetValueByKey("InstallAllowPort")
|
|
if res.InstallAllowPort == "" {
|
|
res.InstallAllowPort = constant.StatusDisable
|
|
}
|
|
return res, nil
|
|
}
|
|
|
|
func loadDockerProxy(req dto.ProxyUpdate) string {
|
|
if req.ProxyType == "" || req.ProxyType == "close" || !req.ProxyDocker {
|
|
return ""
|
|
}
|
|
var account string
|
|
if req.ProxyUser != "" {
|
|
account = req.ProxyUser
|
|
if req.ProxyPasswd != "" {
|
|
account += ":" + req.ProxyPasswd
|
|
}
|
|
account += "@"
|
|
}
|
|
|
|
return fmt.Sprintf("%s://%s%s:%s", req.ProxyType, account, strings.ReplaceAll(req.ProxyUrl, req.ProxyType+"://", ""), req.ProxyPort)
|
|
}
|
|
|
|
func checkProxy(req dto.ProxyUpdate) error {
|
|
var transport http.Transport
|
|
proxyItem := fmt.Sprintf("%s:%s", req.ProxyUrl, req.ProxyPort)
|
|
switch req.ProxyType {
|
|
case "http", "https":
|
|
proxyURL, err := url.Parse(proxyItem)
|
|
if err != nil {
|
|
return buserr.WithErr("ErrProxySetting", fmt.Errorf("parse url %s failed, err: %v", proxyItem, err))
|
|
}
|
|
if len(req.ProxyUser) != 0 {
|
|
proxyURL.User = url.UserPassword(req.ProxyUser, req.ProxyPasswd)
|
|
}
|
|
transport = http.Transport{Proxy: http.ProxyURL(proxyURL), TLSClientConfig: &tls.Config{InsecureSkipVerify: true}}
|
|
case "socks5":
|
|
var auth *proxy.Auth
|
|
if len(req.ProxyUser) == 0 {
|
|
auth = nil
|
|
} else {
|
|
auth = &proxy.Auth{User: req.ProxyUser, Password: req.ProxyPasswd}
|
|
}
|
|
dialer, err := proxy.SOCKS5("tcp", proxyItem, auth, proxy.Direct)
|
|
if err != nil {
|
|
return buserr.WithErr("ErrProxySetting", fmt.Errorf("new socks5 proxy failed, err: %v", err))
|
|
}
|
|
dialContext := func(ctx context.Context, network, addr string) (net.Conn, error) {
|
|
return dialer.Dial(network, addr)
|
|
}
|
|
transport = http.Transport{DialContext: dialContext}
|
|
case "", "close":
|
|
return nil
|
|
default:
|
|
return buserr.WithName("ErrNotSupportType", req.ProxyType)
|
|
}
|
|
defer func() {
|
|
if r := recover(); r != nil {
|
|
global.LOG.Errorf("handle request failed, error message: %v", r)
|
|
return
|
|
}
|
|
}()
|
|
|
|
client := http.Client{Timeout: 3 * time.Second, Transport: &transport}
|
|
ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
|
|
defer cancel()
|
|
request, err := http.NewRequestWithContext(ctx, http.MethodGet, "https://1panel.cn/", nil)
|
|
if err != nil {
|
|
return buserr.WithErr("ErrProxySetting", err)
|
|
}
|
|
request.Header.Set("Content-Type", "application/json")
|
|
resp, err := client.Do(request)
|
|
if err != nil {
|
|
return buserr.WithErr("ErrProxySetting", err)
|
|
}
|
|
defer resp.Body.Close()
|
|
if _, err := io.ReadAll(resp.Body); err != nil {
|
|
return buserr.WithErr("ErrProxySetting", err)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (u *SettingService) DefaultMenu() error {
|
|
return settingRepo.DefaultMenu()
|
|
}
|
|
|
|
func (u *SettingService) GetMemo() (string, error) {
|
|
memo, err := settingRepo.GetValueByKey("DashboardMemo")
|
|
if err != nil {
|
|
return "", nil
|
|
}
|
|
return memo, nil
|
|
}
|
|
|
|
func (u *SettingService) UpdateMemo(content string) error {
|
|
return settingRepo.UpdateOrCreate("DashboardMemo", content)
|
|
}
|