mirror of https://github.com/1Panel-dev/1Panel
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
3196 lines
94 KiB
3196 lines
94 KiB
package service
|
|
|
|
import (
|
|
"bufio"
|
|
"bytes"
|
|
"context"
|
|
"crypto/x509"
|
|
"encoding/base64"
|
|
"encoding/json"
|
|
"encoding/pem"
|
|
"errors"
|
|
"fmt"
|
|
"github.com/1Panel-dev/1Panel/agent/app/task"
|
|
"os"
|
|
"path"
|
|
"reflect"
|
|
"regexp"
|
|
"strconv"
|
|
"strings"
|
|
"syscall"
|
|
"time"
|
|
|
|
"github.com/1Panel-dev/1Panel/agent/utils/common"
|
|
"github.com/jinzhu/copier"
|
|
|
|
"github.com/1Panel-dev/1Panel/agent/i18n"
|
|
"github.com/spf13/afero"
|
|
|
|
"github.com/1Panel-dev/1Panel/agent/utils/compose"
|
|
"github.com/1Panel-dev/1Panel/agent/utils/env"
|
|
|
|
"github.com/1Panel-dev/1Panel/agent/app/api/v2/helper"
|
|
"github.com/1Panel-dev/1Panel/agent/cmd/server/nginx_conf"
|
|
"github.com/1Panel-dev/1Panel/agent/utils/cmd"
|
|
"github.com/1Panel-dev/1Panel/agent/utils/nginx"
|
|
"github.com/1Panel-dev/1Panel/agent/utils/nginx/components"
|
|
"github.com/1Panel-dev/1Panel/agent/utils/nginx/parser"
|
|
"golang.org/x/crypto/bcrypt"
|
|
"gopkg.in/ini.v1"
|
|
"gorm.io/gorm"
|
|
|
|
"github.com/1Panel-dev/1Panel/agent/app/dto/request"
|
|
"github.com/1Panel-dev/1Panel/agent/app/dto/response"
|
|
"github.com/1Panel-dev/1Panel/agent/app/repo"
|
|
"github.com/1Panel-dev/1Panel/agent/buserr"
|
|
"github.com/1Panel-dev/1Panel/agent/global"
|
|
|
|
"github.com/1Panel-dev/1Panel/agent/app/dto"
|
|
"github.com/1Panel-dev/1Panel/agent/app/model"
|
|
"github.com/1Panel-dev/1Panel/agent/constant"
|
|
"github.com/1Panel-dev/1Panel/agent/utils/files"
|
|
)
|
|
|
|
type WebsiteService struct {
|
|
}
|
|
|
|
type IWebsiteService interface {
|
|
PageWebsite(req request.WebsiteSearch) (int64, []response.WebsiteRes, error)
|
|
GetWebsites() ([]response.WebsiteDTO, error)
|
|
CreateWebsite(create request.WebsiteCreate) error
|
|
OpWebsite(req request.WebsiteOp) error
|
|
GetWebsiteOptions(req request.WebsiteOptionReq) ([]response.WebsiteOption, error)
|
|
UpdateWebsite(req request.WebsiteUpdate) error
|
|
DeleteWebsite(req request.WebsiteDelete) error
|
|
GetWebsite(id uint) (response.WebsiteDTO, error)
|
|
|
|
CreateWebsiteDomain(create request.WebsiteDomainCreate) ([]model.WebsiteDomain, error)
|
|
GetWebsiteDomain(websiteId uint) ([]model.WebsiteDomain, error)
|
|
DeleteWebsiteDomain(domainId uint) error
|
|
UpdateWebsiteDomain(req request.WebsiteDomainUpdate) error
|
|
|
|
GetNginxConfigByScope(req request.NginxScopeReq) (*response.WebsiteNginxConfig, error)
|
|
UpdateNginxConfigByScope(req request.NginxConfigUpdate) error
|
|
GetWebsiteNginxConfig(websiteId uint, configType string) (response.FileInfo, error)
|
|
UpdateNginxConfigFile(req request.WebsiteNginxUpdate) error
|
|
GetWebsiteHTTPS(websiteId uint) (response.WebsiteHTTPS, error)
|
|
OpWebsiteHTTPS(ctx context.Context, req request.WebsiteHTTPSOp) (*response.WebsiteHTTPS, error)
|
|
OpWebsiteLog(req request.WebsiteLogReq) (*response.WebsiteLog, error)
|
|
ChangeDefaultServer(id uint) error
|
|
PreInstallCheck(req request.WebsiteInstallCheckReq) ([]response.WebsitePreInstallCheck, error)
|
|
|
|
GetPHPConfig(id uint) (*response.PHPConfig, error)
|
|
UpdatePHPConfig(req request.WebsitePHPConfigUpdate) error
|
|
UpdatePHPConfigFile(req request.WebsitePHPFileUpdate) error
|
|
ChangePHPVersion(req request.WebsitePHPVersionReq) error
|
|
|
|
GetRewriteConfig(req request.NginxRewriteReq) (*response.NginxRewriteRes, error)
|
|
UpdateRewriteConfig(req request.NginxRewriteUpdate) error
|
|
LoadWebsiteDirConfig(req request.WebsiteCommonReq) (*response.WebsiteDirConfig, error)
|
|
UpdateSiteDir(req request.WebsiteUpdateDir) error
|
|
UpdateSitePermission(req request.WebsiteUpdateDirPermission) error
|
|
|
|
OperateProxy(req request.WebsiteProxyConfig) (err error)
|
|
GetProxies(id uint) (res []request.WebsiteProxyConfig, err error)
|
|
UpdateProxyFile(req request.NginxProxyUpdate) (err error)
|
|
|
|
GetAntiLeech(id uint) (*response.NginxAntiLeechRes, error)
|
|
UpdateAntiLeech(req request.NginxAntiLeechUpdate) (err error)
|
|
|
|
OperateRedirect(req request.NginxRedirectReq) (err error)
|
|
GetRedirect(id uint) (res []response.NginxRedirectConfig, err error)
|
|
UpdateRedirectFile(req request.NginxRedirectUpdate) (err error)
|
|
|
|
GetAuthBasics(req request.NginxAuthReq) (res response.NginxAuthRes, err error)
|
|
UpdateAuthBasic(req request.NginxAuthUpdate) (err error)
|
|
GetPathAuthBasics(req request.NginxAuthReq) (res []response.NginxPathAuthRes, err error)
|
|
UpdatePathAuthBasic(req request.NginxPathAuthUpdate) error
|
|
|
|
UpdateDefaultHtml(req request.WebsiteHtmlUpdate) error
|
|
GetDefaultHtml(resourceType string) (*response.WebsiteHtmlRes, error)
|
|
|
|
GetLoadBalances(id uint) ([]dto.NginxUpstream, error)
|
|
CreateLoadBalance(req request.WebsiteLBCreate) error
|
|
DeleteLoadBalance(req request.WebsiteLBDelete) error
|
|
UpdateLoadBalance(req request.WebsiteLBUpdate) error
|
|
UpdateLoadBalanceFile(req request.WebsiteLBUpdateFile) error
|
|
}
|
|
|
|
func NewIWebsiteService() IWebsiteService {
|
|
return &WebsiteService{}
|
|
}
|
|
|
|
func (w WebsiteService) PageWebsite(req request.WebsiteSearch) (int64, []response.WebsiteRes, error) {
|
|
var (
|
|
websiteDTOs []response.WebsiteRes
|
|
opts []repo.DBOption
|
|
)
|
|
nginxInstall, err := getAppInstallByKey(constant.AppOpenresty)
|
|
if err != nil {
|
|
if errors.Is(err, gorm.ErrRecordNotFound) {
|
|
return 0, nil, nil
|
|
}
|
|
return 0, nil, err
|
|
}
|
|
opts = append(opts, commonRepo.WithOrderRuleBy(req.OrderBy, req.Order))
|
|
if req.Name != "" {
|
|
domains, _ := websiteDomainRepo.GetBy(websiteDomainRepo.WithDomainLike(req.Name))
|
|
if len(domains) > 0 {
|
|
var websiteIds []uint
|
|
for _, domain := range domains {
|
|
websiteIds = append(websiteIds, domain.WebsiteID)
|
|
}
|
|
opts = append(opts, websiteRepo.WithIDs(websiteIds))
|
|
} else {
|
|
opts = append(opts, websiteRepo.WithDomainLike(req.Name))
|
|
}
|
|
}
|
|
if req.WebsiteGroupID != 0 {
|
|
opts = append(opts, websiteRepo.WithGroupID(req.WebsiteGroupID))
|
|
}
|
|
total, websites, err := websiteRepo.Page(req.Page, req.PageSize, opts...)
|
|
if err != nil {
|
|
return 0, nil, err
|
|
}
|
|
for _, web := range websites {
|
|
var (
|
|
appName string
|
|
runtimeName string
|
|
appInstallID uint
|
|
)
|
|
switch web.Type {
|
|
case constant.Deployment:
|
|
appInstall, err := appInstallRepo.GetFirst(commonRepo.WithByID(web.AppInstallID))
|
|
if err != nil {
|
|
return 0, nil, err
|
|
}
|
|
appName = appInstall.Name
|
|
appInstallID = appInstall.ID
|
|
case constant.Runtime:
|
|
runtime, err := runtimeRepo.GetFirst(commonRepo.WithByID(web.RuntimeID))
|
|
if err != nil {
|
|
return 0, nil, err
|
|
}
|
|
runtimeName = runtime.Name
|
|
appInstallID = runtime.ID
|
|
}
|
|
sitePath := path.Join(constant.AppInstallDir, constant.AppOpenresty, nginxInstall.Name, "www", "sites", web.Alias)
|
|
|
|
siteDTO := response.WebsiteRes{
|
|
ID: web.ID,
|
|
CreatedAt: web.CreatedAt,
|
|
Protocol: web.Protocol,
|
|
PrimaryDomain: web.PrimaryDomain,
|
|
Type: web.Type,
|
|
Remark: web.Remark,
|
|
Status: web.Status,
|
|
Alias: web.Alias,
|
|
AppName: appName,
|
|
ExpireDate: web.ExpireDate,
|
|
SSLExpireDate: web.WebsiteSSL.ExpireDate,
|
|
SSLStatus: checkSSLStatus(web.WebsiteSSL.ExpireDate),
|
|
RuntimeName: runtimeName,
|
|
SitePath: sitePath,
|
|
AppInstallID: appInstallID,
|
|
}
|
|
|
|
sites, _ := websiteRepo.List(websiteRepo.WithParentID(web.ID))
|
|
if len(sites) > 0 {
|
|
for _, site := range sites {
|
|
siteDTO.ChildSites = append(siteDTO.ChildSites, site.PrimaryDomain)
|
|
}
|
|
}
|
|
websiteDTOs = append(websiteDTOs, siteDTO)
|
|
}
|
|
return total, websiteDTOs, nil
|
|
}
|
|
|
|
func (w WebsiteService) GetWebsites() ([]response.WebsiteDTO, error) {
|
|
var websiteDTOs []response.WebsiteDTO
|
|
websites, _ := websiteRepo.List(commonRepo.WithOrderRuleBy("primary_domain", "ascending"))
|
|
for _, web := range websites {
|
|
res := response.WebsiteDTO{
|
|
Website: web,
|
|
}
|
|
websiteDTOs = append(websiteDTOs, res)
|
|
}
|
|
return websiteDTOs, nil
|
|
}
|
|
|
|
func (w WebsiteService) CreateWebsite(create request.WebsiteCreate) (err error) {
|
|
alias := create.Alias
|
|
if alias == "default" {
|
|
return buserr.New("ErrDefaultAlias")
|
|
}
|
|
if common.ContainsChinese(alias) {
|
|
alias, err = common.PunycodeEncode(alias)
|
|
if err != nil {
|
|
return
|
|
}
|
|
}
|
|
if exist, _ := websiteRepo.GetBy(websiteRepo.WithAlias(alias)); len(exist) > 0 {
|
|
return buserr.New(constant.ErrAliasIsExist)
|
|
}
|
|
if len(create.FtpPassword) != 0 {
|
|
pass, err := base64.StdEncoding.DecodeString(create.FtpPassword)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
create.FtpPassword = string(pass)
|
|
}
|
|
|
|
nginxInstall, err := getAppInstallByKey(constant.AppOpenresty)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defaultHttpPort := nginxInstall.HttpPort
|
|
var (
|
|
domains []model.WebsiteDomain
|
|
)
|
|
domains, _, _, err = getWebsiteDomains(create.Domains, defaultHttpPort, 0)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
primaryDomain := domains[0].Domain
|
|
if domains[0].Port != defaultHttpPort {
|
|
primaryDomain = fmt.Sprintf("%s:%v", domains[0].Domain, domains[0].Port)
|
|
}
|
|
|
|
defaultDate, _ := time.Parse(constant.DateLayout, constant.DefaultDate)
|
|
website := &model.Website{
|
|
PrimaryDomain: primaryDomain,
|
|
Type: create.Type,
|
|
Alias: alias,
|
|
Remark: create.Remark,
|
|
Status: constant.WebRunning,
|
|
ExpireDate: defaultDate,
|
|
WebsiteGroupID: create.WebsiteGroupID,
|
|
Protocol: constant.ProtocolHTTP,
|
|
Proxy: create.Proxy,
|
|
SiteDir: "/",
|
|
AccessLog: true,
|
|
ErrorLog: true,
|
|
IPV6: create.IPV6,
|
|
}
|
|
|
|
var (
|
|
appInstall *model.AppInstall
|
|
runtime *model.Runtime
|
|
)
|
|
|
|
createTask, err := task.NewTaskWithOps(primaryDomain, task.TaskCreate, task.TaskScopeWebsite, create.TaskID, 0)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if create.CreateDb {
|
|
createDataBase := func(t *task.Task) error {
|
|
database, _ := databaseRepo.Get(commonRepo.WithByName(create.DbHost))
|
|
if database.ID == 0 {
|
|
return nil
|
|
}
|
|
dbConfig := create.DataBaseConfig
|
|
switch database.Type {
|
|
case constant.AppPostgresql, constant.AppPostgres:
|
|
iPostgresqlRepo := repo.NewIPostgresqlRepo()
|
|
oldPostgresqlDb, _ := iPostgresqlRepo.Get(commonRepo.WithByName(create.DbName), iPostgresqlRepo.WithByFrom(constant.ResourceLocal))
|
|
if oldPostgresqlDb.ID > 0 {
|
|
return buserr.New(constant.ErrDbUserNotValid)
|
|
}
|
|
var createPostgresql dto.PostgresqlDBCreate
|
|
createPostgresql.Name = dbConfig.DbName
|
|
createPostgresql.Username = dbConfig.DbUser
|
|
createPostgresql.Database = database.Name
|
|
createPostgresql.Format = dbConfig.DBFormat
|
|
createPostgresql.Password = dbConfig.DbPassword
|
|
createPostgresql.From = database.From
|
|
createPostgresql.SuperUser = true
|
|
pgDB, err := NewIPostgresqlService().Create(context.Background(), createPostgresql)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
website.DbID = pgDB.ID
|
|
website.DbType = database.Type
|
|
case constant.AppMysql, constant.AppMariaDB:
|
|
iMysqlRepo := repo.NewIMysqlRepo()
|
|
oldMysqlDb, _ := iMysqlRepo.Get(commonRepo.WithByName(dbConfig.DbName), iMysqlRepo.WithByFrom(constant.ResourceLocal))
|
|
if oldMysqlDb.ID > 0 {
|
|
return buserr.New(constant.ErrDbUserNotValid)
|
|
}
|
|
var createMysql dto.MysqlDBCreate
|
|
createMysql.Name = dbConfig.DbName
|
|
createMysql.Username = dbConfig.DbUser
|
|
createMysql.Database = database.Name
|
|
createMysql.Format = dbConfig.DBFormat
|
|
createMysql.Permission = "%"
|
|
createMysql.Password = dbConfig.DbPassword
|
|
createMysql.From = database.From
|
|
mysqlDB, err := NewIMysqlService().Create(context.Background(), createMysql)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
website.DbID = mysqlDB.ID
|
|
website.DbType = database.Type
|
|
}
|
|
return nil
|
|
}
|
|
createTask.AddSubTask(task.GetTaskName(create.DbName, task.TaskCreate, task.TaskScopeDatabase), createDataBase, nil)
|
|
}
|
|
|
|
var proxy string
|
|
switch create.Type {
|
|
case constant.Deployment:
|
|
if create.AppType == constant.NewApp {
|
|
var (
|
|
req request.AppInstallCreate
|
|
install *model.AppInstall
|
|
)
|
|
req.Name = create.AppInstall.Name
|
|
req.AppDetailId = create.AppInstall.AppDetailId
|
|
req.Params = create.AppInstall.Params
|
|
req.AppContainerConfig = create.AppInstall.AppContainerConfig
|
|
install, err = NewIAppService().Install(req)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
appInstall = install
|
|
website.AppInstallID = install.ID
|
|
website.Proxy = fmt.Sprintf("127.0.0.1:%d", appInstall.HttpPort)
|
|
} else {
|
|
var install model.AppInstall
|
|
install, err = appInstallRepo.GetFirst(commonRepo.WithByID(create.AppInstallID))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
configApp := func(t *task.Task) error {
|
|
appInstall = &install
|
|
website.AppInstallID = appInstall.ID
|
|
website.Proxy = fmt.Sprintf("127.0.0.1:%d", appInstall.HttpPort)
|
|
return nil
|
|
}
|
|
createTask.AddSubTask(i18n.GetMsgByKey("ConfigApp"), configApp, nil)
|
|
}
|
|
case constant.Runtime:
|
|
runtime, err = runtimeRepo.GetFirst(commonRepo.WithByID(create.RuntimeID))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
website.RuntimeID = runtime.ID
|
|
|
|
switch runtime.Type {
|
|
case constant.RuntimePHP:
|
|
if runtime.Resource == constant.ResourceAppstore {
|
|
var (
|
|
req request.AppInstallCreate
|
|
install *model.AppInstall
|
|
)
|
|
reg, _ := regexp.Compile(`[^a-z0-9_-]+`)
|
|
req.Name = reg.ReplaceAllString(strings.ToLower(alias), "")
|
|
req.AppDetailId = create.AppInstall.AppDetailId
|
|
req.Params = create.AppInstall.Params
|
|
req.Params["IMAGE_NAME"] = runtime.Image
|
|
req.AppContainerConfig = create.AppInstall.AppContainerConfig
|
|
req.Params["PANEL_WEBSITE_DIR"] = path.Join(nginxInstall.GetPath(), "/www")
|
|
install, err = NewIAppService().Install(req)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
website.AppInstallID = install.ID
|
|
appInstall = install
|
|
website.Proxy = fmt.Sprintf("127.0.0.1:%d", appInstall.HttpPort)
|
|
} else {
|
|
website.ProxyType = create.ProxyType
|
|
if website.ProxyType == constant.RuntimeProxyUnix {
|
|
proxy = fmt.Sprintf("unix:%s", path.Join("/www/sites", website.Alias, "php-pool", "php-fpm.sock"))
|
|
}
|
|
if website.ProxyType == constant.RuntimeProxyTcp {
|
|
proxy = fmt.Sprintf("127.0.0.1:%d", create.Port)
|
|
}
|
|
website.Proxy = proxy
|
|
}
|
|
case constant.RuntimeNode, constant.RuntimeJava, constant.RuntimeGo:
|
|
website.Proxy = fmt.Sprintf("127.0.0.1:%d", runtime.Port)
|
|
}
|
|
case constant.Subsite:
|
|
parentWebsite, err := websiteRepo.GetFirst(commonRepo.WithByID(create.ParentWebsiteID))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
website.ParentWebsiteID = parentWebsite.ID
|
|
}
|
|
|
|
if len(create.FtpUser) != 0 && len(create.FtpPassword) != 0 {
|
|
createFtpUser := func(t *task.Task) error {
|
|
indexDir := path.Join(nginxInstall.GetPath(), "www", "sites", website.Alias, "index")
|
|
itemID, err := NewIFtpService().Create(dto.FtpCreate{User: create.FtpUser, Password: create.FtpPassword, Path: indexDir})
|
|
if err != nil {
|
|
createTask.Log(fmt.Sprintf("create ftp for website failed, err: %v", err))
|
|
}
|
|
website.FtpID = itemID
|
|
return nil
|
|
}
|
|
deleteFtpUser := func(t *task.Task) {
|
|
if website.FtpID > 0 {
|
|
if err = NewIFtpService().Delete(dto.BatchDeleteReq{Ids: []uint{website.FtpID}}); err != nil {
|
|
createTask.Log(err.Error())
|
|
}
|
|
}
|
|
}
|
|
createTask.AddSubTask(i18n.GetWithName("ConfigFTP", create.FtpUser), createFtpUser, deleteFtpUser)
|
|
}
|
|
|
|
configNginx := func(t *task.Task) error {
|
|
if err = configDefaultNginx(website, domains, appInstall, runtime); err != nil {
|
|
return err
|
|
}
|
|
if err = createWafConfig(website, domains); err != nil {
|
|
return err
|
|
}
|
|
tx, ctx := helper.GetTxAndContext()
|
|
defer tx.Rollback()
|
|
if err = websiteRepo.Create(ctx, website); err != nil {
|
|
return err
|
|
}
|
|
t.Task.ResourceID = website.ID
|
|
for i := range domains {
|
|
domains[i].WebsiteID = website.ID
|
|
}
|
|
if err = websiteDomainRepo.BatchCreate(ctx, domains); err != nil {
|
|
return err
|
|
}
|
|
tx.Commit()
|
|
return nil
|
|
}
|
|
|
|
deleteWebsite := func(t *task.Task) {
|
|
_ = deleteWebsiteFolder(nginxInstall, website)
|
|
}
|
|
|
|
createTask.AddSubTask(i18n.GetMsgByKey("ConfigOpenresty"), configNginx, deleteWebsite)
|
|
|
|
if create.EnableSSL {
|
|
enableSSL := func(t *task.Task) error {
|
|
websiteModel, err := websiteSSLRepo.GetFirst(commonRepo.WithByID(create.WebsiteSSLID))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
website.Protocol = constant.ProtocolHTTPS
|
|
website.WebsiteSSLID = create.WebsiteSSLID
|
|
appSSLReq := request.WebsiteHTTPSOp{
|
|
WebsiteID: website.ID,
|
|
Enable: true,
|
|
WebsiteSSLID: websiteModel.ID,
|
|
Type: "existed",
|
|
HttpConfig: "HTTPToHTTPS",
|
|
SSLProtocol: []string{"TLSv1.3", "TLSv1.2", "TLSv1.1", "TLSv1"},
|
|
Algorithm: "ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256:!aNULL:!eNULL:!EXPORT:!DSS:!DES:!RC4:!3DES:!MD5:!PSK:!KRB5:!SRP:!CAMELLIA:!SEED",
|
|
Hsts: true,
|
|
}
|
|
if err = applySSL(website, *websiteModel, appSSLReq); err != nil {
|
|
return err
|
|
}
|
|
if err = websiteRepo.Save(context.Background(), website); err != nil {
|
|
return err
|
|
}
|
|
return nil
|
|
}
|
|
createTask.AddSubTaskWithIgnoreErr(i18n.GetMsgByKey("EnableSSL"), enableSSL)
|
|
}
|
|
|
|
return createTask.Execute()
|
|
}
|
|
|
|
func (w WebsiteService) OpWebsite(req request.WebsiteOp) error {
|
|
website, err := websiteRepo.GetFirst(commonRepo.WithByID(req.ID))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if err := opWebsite(&website, req.Operate); err != nil {
|
|
return err
|
|
}
|
|
return websiteRepo.Save(context.Background(), &website)
|
|
}
|
|
|
|
func (w WebsiteService) GetWebsiteOptions(req request.WebsiteOptionReq) ([]response.WebsiteOption, error) {
|
|
var options []repo.DBOption
|
|
if len(req.Types) > 0 {
|
|
options = append(options, websiteRepo.WithTypes(req.Types))
|
|
}
|
|
webs, _ := websiteRepo.List(options...)
|
|
var datas []response.WebsiteOption
|
|
for _, web := range webs {
|
|
var item response.WebsiteOption
|
|
if err := copier.Copy(&item, &web); err != nil {
|
|
return nil, err
|
|
}
|
|
datas = append(datas, item)
|
|
}
|
|
return datas, nil
|
|
}
|
|
|
|
func (w WebsiteService) UpdateWebsite(req request.WebsiteUpdate) error {
|
|
website, err := websiteRepo.GetFirst(commonRepo.WithByID(req.ID))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if website.IPV6 != req.IPV6 {
|
|
if err := changeIPV6(website, req.IPV6); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
website.PrimaryDomain = req.PrimaryDomain
|
|
website.WebsiteGroupID = req.WebsiteGroupID
|
|
website.Remark = req.Remark
|
|
website.IPV6 = req.IPV6
|
|
|
|
if req.ExpireDate != "" {
|
|
expireDate, err := time.Parse(constant.DateLayout, req.ExpireDate)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
website.ExpireDate = expireDate
|
|
}
|
|
|
|
return websiteRepo.Save(context.TODO(), &website)
|
|
}
|
|
|
|
func (w WebsiteService) GetWebsite(id uint) (response.WebsiteDTO, error) {
|
|
var res response.WebsiteDTO
|
|
website, err := websiteRepo.GetFirst(commonRepo.WithByID(id))
|
|
if err != nil {
|
|
return res, err
|
|
}
|
|
res.Website = website
|
|
|
|
nginxInstall, err := getAppInstallByKey(constant.AppOpenresty)
|
|
if err != nil {
|
|
return res, err
|
|
}
|
|
sitePath := path.Join(constant.AppInstallDir, constant.AppOpenresty, nginxInstall.Name, "www", "sites", website.Alias)
|
|
res.ErrorLogPath = path.Join(sitePath, "log", "error.log")
|
|
res.AccessLogPath = path.Join(sitePath, "log", "access.log")
|
|
res.SitePath = sitePath
|
|
res.SiteDir = website.SiteDir
|
|
return res, nil
|
|
}
|
|
|
|
func (w WebsiteService) DeleteWebsite(req request.WebsiteDelete) error {
|
|
website, err := websiteRepo.GetFirst(commonRepo.WithByID(req.ID))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if website.Type != constant.Subsite {
|
|
parentWebsites, _ := websiteRepo.List(websiteRepo.WithParentID(website.ID))
|
|
if len(parentWebsites) > 0 {
|
|
var names []string
|
|
for _, site := range parentWebsites {
|
|
names = append(names, site.PrimaryDomain)
|
|
}
|
|
return buserr.WithName("ErrParentWebsite", strings.Join(names, ","))
|
|
}
|
|
}
|
|
if err = delNginxConfig(website, req.ForceDelete); err != nil {
|
|
return err
|
|
}
|
|
|
|
if err = delWafConfig(website, req.ForceDelete); err != nil {
|
|
return err
|
|
}
|
|
|
|
if checkIsLinkApp(website) && req.DeleteApp {
|
|
appInstall, _ := appInstallRepo.GetFirst(commonRepo.WithByID(website.AppInstallID))
|
|
if appInstall.ID > 0 {
|
|
deleteReq := request.AppInstallDelete{
|
|
Install: appInstall,
|
|
ForceDelete: req.ForceDelete,
|
|
DeleteBackup: true,
|
|
DeleteDB: true,
|
|
}
|
|
if err = deleteAppInstall(deleteReq); err != nil && !req.ForceDelete {
|
|
return err
|
|
}
|
|
}
|
|
}
|
|
|
|
tx, ctx := helper.GetTxAndContext()
|
|
defer tx.Rollback()
|
|
|
|
go func() {
|
|
_ = NewIBackupService().DeleteRecordByName("website", website.PrimaryDomain, website.Alias, req.DeleteBackup)
|
|
}()
|
|
|
|
if err := websiteRepo.DeleteBy(ctx, commonRepo.WithByID(req.ID)); err != nil {
|
|
return err
|
|
}
|
|
if err := websiteDomainRepo.DeleteBy(ctx, websiteDomainRepo.WithWebsiteId(req.ID)); err != nil {
|
|
return err
|
|
}
|
|
tx.Commit()
|
|
|
|
uploadDir := path.Join(global.CONF.System.BaseDir, fmt.Sprintf("1panel/uploads/website/%s", website.Alias))
|
|
if _, err := os.Stat(uploadDir); err == nil {
|
|
_ = os.RemoveAll(uploadDir)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (w WebsiteService) UpdateWebsiteDomain(req request.WebsiteDomainUpdate) error {
|
|
domain, err := websiteDomainRepo.GetFirst(commonRepo.WithByID(req.ID))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
domain.SSL = req.SSL
|
|
website, err := websiteRepo.GetFirst(commonRepo.WithByID(domain.WebsiteID))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if website.Protocol == constant.ProtocolHTTPS {
|
|
nginxFull, err := getNginxFull(&website)
|
|
if err != nil {
|
|
return nil
|
|
}
|
|
nginxConfig := nginxFull.SiteConfig
|
|
config := nginxFull.SiteConfig.Config
|
|
server := config.FindServers()[0]
|
|
var params []string
|
|
if domain.SSL {
|
|
params = append(params, "ssl", "http2")
|
|
}
|
|
server.UpdateListen(strconv.Itoa(domain.Port), false, params...)
|
|
if website.IPV6 {
|
|
server.UpdateListen("[::]:"+strconv.Itoa(domain.Port), false, params...)
|
|
}
|
|
if err = nginx.WriteConfig(config, nginx.IndentedStyle); err != nil {
|
|
return err
|
|
}
|
|
if err = nginxCheckAndReload(nginxConfig.OldContent, nginxConfig.FilePath, nginxFull.Install.ContainerName); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
return websiteDomainRepo.Save(context.TODO(), &domain)
|
|
}
|
|
|
|
func (w WebsiteService) CreateWebsiteDomain(create request.WebsiteDomainCreate) ([]model.WebsiteDomain, error) {
|
|
var (
|
|
domainModels []model.WebsiteDomain
|
|
addPorts []int
|
|
)
|
|
httpPort, _, err := getAppInstallPort(constant.AppOpenresty)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
website, err := websiteRepo.GetFirst(commonRepo.WithByID(create.WebsiteID))
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
domainModels, addPorts, _, err = getWebsiteDomains(create.Domains, httpPort, create.WebsiteID)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
go func() {
|
|
_ = OperateFirewallPort(nil, addPorts)
|
|
}()
|
|
|
|
if err = addListenAndServerName(website, domainModels); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
nginxInstall, err := getAppInstallByKey(constant.AppOpenresty)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
wafDataPath := path.Join(nginxInstall.GetPath(), "1pwaf", "data")
|
|
fileOp := files.NewFileOp()
|
|
if fileOp.Stat(wafDataPath) {
|
|
websitesConfigPath := path.Join(wafDataPath, "conf", "sites.json")
|
|
content, err := fileOp.GetContent(websitesConfigPath)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
var websitesArray []request.WafWebsite
|
|
if content != nil {
|
|
if err := json.Unmarshal(content, &websitesArray); err != nil {
|
|
return nil, err
|
|
}
|
|
}
|
|
for index, wafWebsite := range websitesArray {
|
|
if wafWebsite.Key == website.Alias {
|
|
wafSite := request.WafWebsite{
|
|
Key: website.Alias,
|
|
Domains: wafWebsite.Domains,
|
|
Host: wafWebsite.Host,
|
|
}
|
|
for _, domain := range domainModels {
|
|
wafSite.Domains = append(wafSite.Domains, domain.Domain)
|
|
wafSite.Host = append(wafSite.Host, domain.Domain+":"+strconv.Itoa(domain.Port))
|
|
}
|
|
if len(wafSite.Host) == 0 {
|
|
wafSite.Host = []string{}
|
|
}
|
|
websitesArray[index] = wafSite
|
|
break
|
|
}
|
|
}
|
|
websitesContent, err := json.Marshal(websitesArray)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if err := fileOp.SaveFileWithByte(websitesConfigPath, websitesContent, 0644); err != nil {
|
|
return nil, err
|
|
}
|
|
}
|
|
|
|
return domainModels, websiteDomainRepo.BatchCreate(context.TODO(), domainModels)
|
|
}
|
|
|
|
func (w WebsiteService) GetWebsiteDomain(websiteId uint) ([]model.WebsiteDomain, error) {
|
|
return websiteDomainRepo.GetBy(websiteDomainRepo.WithWebsiteId(websiteId))
|
|
}
|
|
|
|
func (w WebsiteService) DeleteWebsiteDomain(domainId uint) error {
|
|
webSiteDomain, err := websiteDomainRepo.GetFirst(commonRepo.WithByID(domainId))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if websiteDomains, _ := websiteDomainRepo.GetBy(websiteDomainRepo.WithWebsiteId(webSiteDomain.WebsiteID)); len(websiteDomains) == 1 {
|
|
return fmt.Errorf("can not delete last domain")
|
|
}
|
|
website, err := websiteRepo.GetFirst(commonRepo.WithByID(webSiteDomain.WebsiteID))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
var ports []int
|
|
if oldDomains, _ := websiteDomainRepo.GetBy(websiteDomainRepo.WithWebsiteId(webSiteDomain.WebsiteID), websiteDomainRepo.WithPort(webSiteDomain.Port)); len(oldDomains) == 1 {
|
|
ports = append(ports, webSiteDomain.Port)
|
|
}
|
|
|
|
var domains []string
|
|
if oldDomains, _ := websiteDomainRepo.GetBy(websiteDomainRepo.WithWebsiteId(webSiteDomain.WebsiteID), websiteDomainRepo.WithDomain(webSiteDomain.Domain)); len(oldDomains) == 1 {
|
|
domains = append(domains, webSiteDomain.Domain)
|
|
}
|
|
|
|
if len(ports) > 0 || len(domains) > 0 {
|
|
stringBinds := make([]string, len(ports))
|
|
for i := 0; i < len(ports); i++ {
|
|
stringBinds[i] = strconv.Itoa(ports[i])
|
|
}
|
|
if err := deleteListenAndServerName(website, stringBinds, domains); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
nginxInstall, err := getAppInstallByKey(constant.AppOpenresty)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
wafDataPath := path.Join(nginxInstall.GetPath(), "1pwaf", "data")
|
|
fileOp := files.NewFileOp()
|
|
if fileOp.Stat(wafDataPath) {
|
|
websitesConfigPath := path.Join(wafDataPath, "conf", "sites.json")
|
|
content, err := fileOp.GetContent(websitesConfigPath)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
var websitesArray []request.WafWebsite
|
|
var newWebsitesArray []request.WafWebsite
|
|
if content != nil {
|
|
if err := json.Unmarshal(content, &websitesArray); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
for _, wafWebsite := range websitesArray {
|
|
if wafWebsite.Key == website.Alias {
|
|
wafSite := wafWebsite
|
|
oldDomains := wafSite.Domains
|
|
var newDomains []string
|
|
for _, domain := range oldDomains {
|
|
if domain == webSiteDomain.Domain {
|
|
continue
|
|
}
|
|
newDomains = append(newDomains, domain)
|
|
}
|
|
wafSite.Domains = newDomains
|
|
oldHostArray := wafSite.Host
|
|
var newHostArray []string
|
|
for _, host := range oldHostArray {
|
|
if host == webSiteDomain.Domain+":"+strconv.Itoa(webSiteDomain.Port) {
|
|
continue
|
|
}
|
|
newHostArray = append(newHostArray, host)
|
|
}
|
|
wafSite.Host = newHostArray
|
|
if len(wafSite.Host) == 0 {
|
|
wafSite.Host = []string{}
|
|
}
|
|
newWebsitesArray = append(newWebsitesArray, wafSite)
|
|
} else {
|
|
newWebsitesArray = append(newWebsitesArray, wafWebsite)
|
|
}
|
|
}
|
|
websitesContent, err := json.Marshal(newWebsitesArray)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if err = fileOp.SaveFileWithByte(websitesConfigPath, websitesContent, 0644); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
return websiteDomainRepo.DeleteBy(context.TODO(), commonRepo.WithByID(domainId))
|
|
}
|
|
|
|
func (w WebsiteService) GetNginxConfigByScope(req request.NginxScopeReq) (*response.WebsiteNginxConfig, error) {
|
|
keys, ok := dto.ScopeKeyMap[req.Scope]
|
|
if !ok || len(keys) == 0 {
|
|
return nil, nil
|
|
}
|
|
|
|
website, err := websiteRepo.GetFirst(commonRepo.WithByID(req.WebsiteID))
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
var config response.WebsiteNginxConfig
|
|
params, err := getNginxParamsByKeys(constant.NginxScopeServer, keys, &website)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
config.Params = params
|
|
config.Enable = len(params[0].Params) > 0
|
|
|
|
return &config, nil
|
|
}
|
|
|
|
func (w WebsiteService) UpdateNginxConfigByScope(req request.NginxConfigUpdate) error {
|
|
keys, ok := dto.ScopeKeyMap[req.Scope]
|
|
if !ok || len(keys) == 0 {
|
|
return nil
|
|
}
|
|
website, err := websiteRepo.GetFirst(commonRepo.WithByID(req.WebsiteID))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if req.Operate == constant.ConfigDel {
|
|
var nginxParams []dto.NginxParam
|
|
for _, key := range keys {
|
|
nginxParams = append(nginxParams, dto.NginxParam{
|
|
Name: key,
|
|
})
|
|
}
|
|
return deleteNginxConfig(constant.NginxScopeServer, nginxParams, &website)
|
|
}
|
|
params := getNginxParams(req.Params, keys)
|
|
if req.Operate == constant.ConfigNew {
|
|
if _, ok := dto.StaticFileKeyMap[req.Scope]; ok {
|
|
params = getNginxParamsFromStaticFile(req.Scope, params)
|
|
}
|
|
}
|
|
return updateNginxConfig(constant.NginxScopeServer, params, &website)
|
|
}
|
|
|
|
func (w WebsiteService) GetWebsiteNginxConfig(websiteId uint, configType string) (response.FileInfo, error) {
|
|
website, err := websiteRepo.GetFirst(commonRepo.WithByID(websiteId))
|
|
if err != nil {
|
|
return response.FileInfo{}, err
|
|
}
|
|
configPath := ""
|
|
switch configType {
|
|
case constant.AppOpenresty:
|
|
nginxApp, err := appRepo.GetFirst(appRepo.WithKey(constant.AppOpenresty))
|
|
if err != nil {
|
|
return response.FileInfo{}, err
|
|
}
|
|
nginxInstall, err := appInstallRepo.GetFirst(appInstallRepo.WithAppId(nginxApp.ID))
|
|
if err != nil {
|
|
return response.FileInfo{}, err
|
|
}
|
|
configPath = path.Join(nginxInstall.GetPath(), "conf", "conf.d", website.Alias+".conf")
|
|
case constant.ConfigFPM:
|
|
runtimeInstall, err := appInstallRepo.GetFirst(commonRepo.WithByID(website.AppInstallID))
|
|
if err != nil {
|
|
return response.FileInfo{}, err
|
|
}
|
|
configPath = path.Join(runtimeInstall.GetPath(), "conf", "php-fpm.conf")
|
|
case constant.ConfigPHP:
|
|
runtimeInstall, err := appInstallRepo.GetFirst(commonRepo.WithByID(website.AppInstallID))
|
|
if err != nil {
|
|
return response.FileInfo{}, err
|
|
}
|
|
configPath = path.Join(runtimeInstall.GetPath(), "conf", "php.ini")
|
|
}
|
|
info, err := files.NewFileInfo(files.FileOption{
|
|
Path: configPath,
|
|
Expand: true,
|
|
})
|
|
if err != nil {
|
|
return response.FileInfo{}, err
|
|
}
|
|
return response.FileInfo{FileInfo: *info}, nil
|
|
}
|
|
|
|
func (w WebsiteService) GetWebsiteHTTPS(websiteId uint) (response.WebsiteHTTPS, error) {
|
|
website, err := websiteRepo.GetFirst(commonRepo.WithByID(websiteId))
|
|
if err != nil {
|
|
return response.WebsiteHTTPS{}, err
|
|
}
|
|
var (
|
|
res response.WebsiteHTTPS
|
|
httpsPorts []string
|
|
)
|
|
websiteDomains, _ := websiteDomainRepo.GetBy(websiteDomainRepo.WithWebsiteId(websiteId))
|
|
for _, domain := range websiteDomains {
|
|
if domain.SSL {
|
|
httpsPorts = append(httpsPorts, strconv.Itoa(domain.Port))
|
|
}
|
|
}
|
|
if len(httpsPorts) == 0 {
|
|
nginxInstall, _ := getAppInstallByKey(constant.AppOpenresty)
|
|
res.HttpsPort = strconv.Itoa(nginxInstall.HttpsPort)
|
|
} else {
|
|
res.HttpsPort = strings.Join(httpsPorts, ",")
|
|
}
|
|
if website.WebsiteSSLID == 0 {
|
|
res.Enable = false
|
|
return res, nil
|
|
}
|
|
websiteSSL, err := websiteSSLRepo.GetFirst(commonRepo.WithByID(website.WebsiteSSLID))
|
|
if err != nil {
|
|
return response.WebsiteHTTPS{}, err
|
|
}
|
|
res.SSL = *websiteSSL
|
|
res.Enable = true
|
|
if website.HttpConfig != "" {
|
|
res.HttpConfig = website.HttpConfig
|
|
} else {
|
|
res.HttpConfig = constant.HTTPToHTTPS
|
|
}
|
|
params, err := getNginxParamsByKeys(constant.NginxScopeServer, []string{"ssl_protocols", "ssl_ciphers", "add_header"}, &website)
|
|
if err != nil {
|
|
return res, err
|
|
}
|
|
for _, p := range params {
|
|
if p.Name == "ssl_protocols" {
|
|
res.SSLProtocol = p.Params
|
|
}
|
|
if p.Name == "ssl_ciphers" {
|
|
res.Algorithm = p.Params[0]
|
|
}
|
|
if p.Name == "add_header" && len(p.Params) > 0 && p.Params[0] == "Strict-Transport-Security" {
|
|
res.Hsts = true
|
|
}
|
|
}
|
|
return res, nil
|
|
}
|
|
|
|
func (w WebsiteService) OpWebsiteHTTPS(ctx context.Context, req request.WebsiteHTTPSOp) (*response.WebsiteHTTPS, error) {
|
|
website, err := websiteRepo.GetFirst(commonRepo.WithByID(req.WebsiteID))
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
var (
|
|
res response.WebsiteHTTPS
|
|
websiteSSL model.WebsiteSSL
|
|
)
|
|
nginxInstall, err := getAppInstallByKey(constant.AppOpenresty)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if err = ChangeHSTSConfig(req.Hsts, nginxInstall, website); err != nil {
|
|
return nil, err
|
|
}
|
|
res.Enable = req.Enable
|
|
res.SSLProtocol = req.SSLProtocol
|
|
res.Algorithm = req.Algorithm
|
|
if !req.Enable {
|
|
website.Protocol = constant.ProtocolHTTP
|
|
website.WebsiteSSLID = 0
|
|
|
|
httpsPorts, err := getHttpsPort(&website)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if len(httpsPorts) == 1 && httpsPorts[0] == nginxInstall.HttpsPort {
|
|
httpsPortStr := strconv.Itoa(httpsPorts[0])
|
|
if err = deleteListenAndServerName(website, []string{httpsPortStr, "[::]:" + httpsPortStr}, []string{}); err != nil {
|
|
return nil, err
|
|
}
|
|
} else {
|
|
for _, port := range httpsPorts {
|
|
httpsPortStr := strconv.Itoa(port)
|
|
if err = removeSSLListen(website, []string{httpsPortStr}); err != nil {
|
|
return nil, err
|
|
}
|
|
}
|
|
}
|
|
|
|
nginxParams := getNginxParamsFromStaticFile(dto.SSL, nil)
|
|
nginxParams = append(nginxParams,
|
|
dto.NginxParam{
|
|
Name: "if",
|
|
Params: []string{"($scheme", "=", "http)"},
|
|
},
|
|
dto.NginxParam{
|
|
Name: "ssl_certificate",
|
|
},
|
|
dto.NginxParam{
|
|
Name: "ssl_certificate_key",
|
|
},
|
|
dto.NginxParam{
|
|
Name: "ssl_protocols",
|
|
},
|
|
dto.NginxParam{
|
|
Name: "ssl_ciphers",
|
|
},
|
|
)
|
|
if err = deleteNginxConfig(constant.NginxScopeServer, nginxParams, &website); err != nil {
|
|
return nil, err
|
|
}
|
|
if err = websiteRepo.Save(ctx, &website); err != nil {
|
|
return nil, err
|
|
}
|
|
return nil, nil
|
|
}
|
|
|
|
if req.Type == constant.SSLExisted {
|
|
websiteModel, err := websiteSSLRepo.GetFirst(commonRepo.WithByID(req.WebsiteSSLID))
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
website.WebsiteSSLID = websiteModel.ID
|
|
res.SSL = *websiteModel
|
|
websiteSSL = *websiteModel
|
|
}
|
|
if req.Type == constant.SSLManual {
|
|
var (
|
|
certificate string
|
|
privateKey string
|
|
)
|
|
switch req.ImportType {
|
|
case "paste":
|
|
certificate = req.Certificate
|
|
privateKey = req.PrivateKey
|
|
case "local":
|
|
fileOp := files.NewFileOp()
|
|
if !fileOp.Stat(req.PrivateKeyPath) {
|
|
return nil, buserr.New("ErrSSLKeyNotFound")
|
|
}
|
|
if !fileOp.Stat(req.CertificatePath) {
|
|
return nil, buserr.New("ErrSSLCertificateNotFound")
|
|
}
|
|
if content, err := fileOp.GetContent(req.PrivateKeyPath); err != nil {
|
|
return nil, err
|
|
} else {
|
|
privateKey = string(content)
|
|
}
|
|
if content, err := fileOp.GetContent(req.CertificatePath); err != nil {
|
|
return nil, err
|
|
} else {
|
|
certificate = string(content)
|
|
}
|
|
}
|
|
|
|
privateKeyCertBlock, _ := pem.Decode([]byte(privateKey))
|
|
if privateKeyCertBlock == nil {
|
|
return nil, buserr.New("ErrSSLKeyFormat")
|
|
}
|
|
|
|
certBlock, _ := pem.Decode([]byte(certificate))
|
|
if certBlock == nil {
|
|
return nil, buserr.New("ErrSSLCertificateFormat")
|
|
}
|
|
cert, err := x509.ParseCertificate(certBlock.Bytes)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
websiteSSL.ExpireDate = cert.NotAfter
|
|
websiteSSL.StartDate = cert.NotBefore
|
|
websiteSSL.Type = cert.Issuer.CommonName
|
|
if len(cert.Issuer.Organization) > 0 {
|
|
websiteSSL.Organization = cert.Issuer.Organization[0]
|
|
} else {
|
|
websiteSSL.Organization = cert.Issuer.CommonName
|
|
}
|
|
if len(cert.DNSNames) > 0 {
|
|
websiteSSL.PrimaryDomain = cert.DNSNames[0]
|
|
websiteSSL.Domains = strings.Join(cert.DNSNames, ",")
|
|
}
|
|
websiteSSL.Provider = constant.Manual
|
|
websiteSSL.PrivateKey = privateKey
|
|
websiteSSL.Pem = certificate
|
|
|
|
res.SSL = websiteSSL
|
|
}
|
|
|
|
website.Protocol = constant.ProtocolHTTPS
|
|
if err = applySSL(&website, websiteSSL, req); err != nil {
|
|
return nil, err
|
|
}
|
|
website.HttpConfig = req.HttpConfig
|
|
|
|
if websiteSSL.ID == 0 {
|
|
if err = websiteSSLRepo.Create(ctx, &websiteSSL); err != nil {
|
|
return nil, err
|
|
}
|
|
website.WebsiteSSLID = websiteSSL.ID
|
|
}
|
|
if err = websiteRepo.Save(ctx, &website); err != nil {
|
|
return nil, err
|
|
}
|
|
return &res, nil
|
|
}
|
|
|
|
func (w WebsiteService) PreInstallCheck(req request.WebsiteInstallCheckReq) ([]response.WebsitePreInstallCheck, error) {
|
|
var (
|
|
res []response.WebsitePreInstallCheck
|
|
checkIds []uint
|
|
showErr = false
|
|
)
|
|
|
|
app, err := appRepo.GetFirst(appRepo.WithKey(constant.AppOpenresty))
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
appInstall, _ := appInstallRepo.GetFirst(appInstallRepo.WithAppId(app.ID))
|
|
if reflect.DeepEqual(appInstall, model.AppInstall{}) {
|
|
res = append(res, response.WebsitePreInstallCheck{
|
|
Name: appInstall.Name,
|
|
AppName: app.Name,
|
|
Status: buserr.WithDetail(constant.ErrNotInstall, app.Name, nil).Error(),
|
|
Version: appInstall.Version,
|
|
})
|
|
showErr = true
|
|
} else {
|
|
checkIds = append(req.InstallIds, appInstall.ID)
|
|
}
|
|
if len(checkIds) > 0 {
|
|
installList, _ := appInstallRepo.ListBy(commonRepo.WithIdsIn(checkIds))
|
|
for _, install := range installList {
|
|
if err = syncAppInstallStatus(&install, false); err != nil {
|
|
return nil, err
|
|
}
|
|
res = append(res, response.WebsitePreInstallCheck{
|
|
Name: install.Name,
|
|
Status: install.Status,
|
|
Version: install.Version,
|
|
AppName: install.App.Name,
|
|
})
|
|
if install.Status != constant.Running {
|
|
showErr = true
|
|
}
|
|
}
|
|
}
|
|
if showErr {
|
|
return res, nil
|
|
}
|
|
return nil, nil
|
|
}
|
|
|
|
func (w WebsiteService) UpdateNginxConfigFile(req request.WebsiteNginxUpdate) error {
|
|
website, err := websiteRepo.GetFirst(commonRepo.WithByID(req.ID))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
nginxFull, err := getNginxFull(&website)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
filePath := nginxFull.SiteConfig.FilePath
|
|
if err := files.NewFileOp().WriteFile(filePath, strings.NewReader(req.Content), 0755); err != nil {
|
|
return err
|
|
}
|
|
return nginxCheckAndReload(nginxFull.SiteConfig.OldContent, filePath, nginxFull.Install.ContainerName)
|
|
}
|
|
|
|
func (w WebsiteService) OpWebsiteLog(req request.WebsiteLogReq) (*response.WebsiteLog, error) {
|
|
website, err := websiteRepo.GetFirst(commonRepo.WithByID(req.ID))
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
nginx, err := getNginxFull(&website)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
sitePath := path.Join(nginx.SiteDir, "sites", website.Alias)
|
|
res := &response.WebsiteLog{
|
|
Content: "",
|
|
}
|
|
switch req.Operate {
|
|
case constant.GetLog:
|
|
switch req.LogType {
|
|
case constant.AccessLog:
|
|
res.Enable = website.AccessLog
|
|
if !website.AccessLog {
|
|
return res, nil
|
|
}
|
|
case constant.ErrorLog:
|
|
res.Enable = website.ErrorLog
|
|
if !website.ErrorLog {
|
|
return res, nil
|
|
}
|
|
}
|
|
filePath := path.Join(sitePath, "log", req.LogType)
|
|
lines, end, _, err := files.ReadFileByLine(filePath, req.Page, req.PageSize, false)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
res.End = end
|
|
res.Path = filePath
|
|
res.Content = strings.Join(lines, "\n")
|
|
return res, nil
|
|
case constant.DisableLog:
|
|
key := "access_log"
|
|
switch req.LogType {
|
|
case constant.AccessLog:
|
|
website.AccessLog = false
|
|
case constant.ErrorLog:
|
|
key = "error_log"
|
|
website.ErrorLog = false
|
|
}
|
|
var nginxParams []dto.NginxParam
|
|
nginxParams = append(nginxParams, dto.NginxParam{
|
|
Name: key,
|
|
Params: []string{"off"},
|
|
})
|
|
|
|
if err := updateNginxConfig(constant.NginxScopeServer, nginxParams, &website); err != nil {
|
|
return nil, err
|
|
}
|
|
if err := websiteRepo.Save(context.Background(), &website); err != nil {
|
|
return nil, err
|
|
}
|
|
case constant.EnableLog:
|
|
key := "access_log"
|
|
logPath := path.Join("/www", "sites", website.Alias, "log", req.LogType)
|
|
params := []string{logPath}
|
|
switch req.LogType {
|
|
case constant.AccessLog:
|
|
params = append(params, "main")
|
|
website.AccessLog = true
|
|
case constant.ErrorLog:
|
|
key = "error_log"
|
|
website.ErrorLog = true
|
|
}
|
|
if err := updateNginxConfig(constant.NginxScopeServer, []dto.NginxParam{{Name: key, Params: params}}, &website); err != nil {
|
|
return nil, err
|
|
}
|
|
if err := websiteRepo.Save(context.Background(), &website); err != nil {
|
|
return nil, err
|
|
}
|
|
case constant.DeleteLog:
|
|
logPath := path.Join(nginx.Install.GetPath(), "www", "sites", website.Alias, "log", req.LogType)
|
|
if err := files.NewFileOp().WriteFile(logPath, strings.NewReader(""), 0755); err != nil {
|
|
return nil, err
|
|
}
|
|
}
|
|
return res, nil
|
|
}
|
|
|
|
func (w WebsiteService) ChangeDefaultServer(id uint) error {
|
|
defaultWebsite, _ := websiteRepo.GetFirst(websiteRepo.WithDefaultServer())
|
|
if defaultWebsite.ID > 0 {
|
|
params, err := getNginxParamsByKeys(constant.NginxScopeServer, []string{"listen"}, &defaultWebsite)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
var changeParams []dto.NginxParam
|
|
for _, param := range params {
|
|
paramLen := len(param.Params)
|
|
var newParam []string
|
|
if paramLen > 1 && param.Params[paramLen-1] == components.DefaultServer {
|
|
newParam = param.Params[:paramLen-1]
|
|
}
|
|
changeParams = append(changeParams, dto.NginxParam{
|
|
Name: param.Name,
|
|
Params: newParam,
|
|
})
|
|
}
|
|
if err := updateNginxConfig(constant.NginxScopeServer, changeParams, &defaultWebsite); err != nil {
|
|
return err
|
|
}
|
|
defaultWebsite.DefaultServer = false
|
|
if err := websiteRepo.Save(context.Background(), &defaultWebsite); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
if id > 0 {
|
|
website, err := websiteRepo.GetFirst(commonRepo.WithByID(id))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
params, err := getNginxParamsByKeys(constant.NginxScopeServer, []string{"listen"}, &website)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
httpPort, httpsPort, err := getAppInstallPort(constant.AppOpenresty)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
var changeParams []dto.NginxParam
|
|
for _, param := range params {
|
|
paramLen := len(param.Params)
|
|
bind := param.Params[0]
|
|
var newParam []string
|
|
if bind == strconv.Itoa(httpPort) || bind == strconv.Itoa(httpsPort) || bind == "[::]:"+strconv.Itoa(httpPort) || bind == "[::]:"+strconv.Itoa(httpsPort) {
|
|
if param.Params[paramLen-1] == components.DefaultServer {
|
|
newParam = param.Params
|
|
} else {
|
|
newParam = append(param.Params, components.DefaultServer)
|
|
}
|
|
}
|
|
changeParams = append(changeParams, dto.NginxParam{
|
|
Name: param.Name,
|
|
Params: newParam,
|
|
})
|
|
}
|
|
if err := updateNginxConfig(constant.NginxScopeServer, changeParams, &website); err != nil {
|
|
return err
|
|
}
|
|
website.DefaultServer = true
|
|
return websiteRepo.Save(context.Background(), &website)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (w WebsiteService) GetPHPConfig(id uint) (*response.PHPConfig, error) {
|
|
website, err := websiteRepo.GetFirst(commonRepo.WithByID(id))
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
appInstall, err := appInstallRepo.GetFirst(commonRepo.WithByID(website.AppInstallID))
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
phpConfigPath := path.Join(appInstall.GetPath(), "conf", "php.ini")
|
|
fileOp := files.NewFileOp()
|
|
if !fileOp.Stat(phpConfigPath) {
|
|
return nil, buserr.WithMap("ErrFileNotFound", map[string]interface{}{"name": "php.ini"}, nil)
|
|
}
|
|
params := make(map[string]string)
|
|
configFile, err := fileOp.OpenFile(phpConfigPath)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer configFile.Close()
|
|
scanner := bufio.NewScanner(configFile)
|
|
for scanner.Scan() {
|
|
line := strings.TrimSpace(scanner.Text())
|
|
if strings.HasPrefix(line, ";") {
|
|
continue
|
|
}
|
|
matches := regexp.MustCompile(`^\s*([a-z_]+)\s*=\s*(.*)$`).FindStringSubmatch(line)
|
|
if len(matches) == 3 {
|
|
params[matches[1]] = matches[2]
|
|
}
|
|
}
|
|
cfg, err := ini.Load(phpConfigPath)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
phpConfig, err := cfg.GetSection("PHP")
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
disableFunctionStr := phpConfig.Key("disable_functions").Value()
|
|
res := &response.PHPConfig{Params: params}
|
|
if disableFunctionStr != "" {
|
|
disableFunctions := strings.Split(disableFunctionStr, ",")
|
|
if len(disableFunctions) > 0 {
|
|
res.DisableFunctions = disableFunctions
|
|
}
|
|
}
|
|
uploadMaxSize := phpConfig.Key("upload_max_filesize").Value()
|
|
if uploadMaxSize != "" {
|
|
res.UploadMaxSize = uploadMaxSize
|
|
}
|
|
return res, nil
|
|
}
|
|
|
|
func (w WebsiteService) UpdatePHPConfig(req request.WebsitePHPConfigUpdate) (err error) {
|
|
website, err := websiteRepo.GetFirst(commonRepo.WithByID(req.ID))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
appInstall, err := appInstallRepo.GetFirst(commonRepo.WithByID(website.AppInstallID))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
phpConfigPath := path.Join(appInstall.GetPath(), "conf", "php.ini")
|
|
fileOp := files.NewFileOp()
|
|
if !fileOp.Stat(phpConfigPath) {
|
|
return buserr.WithMap("ErrFileNotFound", map[string]interface{}{"name": "php.ini"}, nil)
|
|
}
|
|
configFile, err := fileOp.OpenFile(phpConfigPath)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer configFile.Close()
|
|
|
|
contentBytes, err := fileOp.GetContent(phpConfigPath)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
content := string(contentBytes)
|
|
lines := strings.Split(content, "\n")
|
|
for i, line := range lines {
|
|
if strings.HasPrefix(line, ";") {
|
|
continue
|
|
}
|
|
switch req.Scope {
|
|
case "params":
|
|
for key, value := range req.Params {
|
|
pattern := "^" + regexp.QuoteMeta(key) + "\\s*=\\s*.*$"
|
|
if matched, _ := regexp.MatchString(pattern, line); matched {
|
|
lines[i] = key + " = " + value
|
|
}
|
|
}
|
|
case "disable_functions":
|
|
pattern := "^" + regexp.QuoteMeta("disable_functions") + "\\s*=\\s*.*$"
|
|
if matched, _ := regexp.MatchString(pattern, line); matched {
|
|
lines[i] = "disable_functions" + " = " + strings.Join(req.DisableFunctions, ",")
|
|
break
|
|
}
|
|
case "upload_max_filesize":
|
|
pattern := "^" + regexp.QuoteMeta("post_max_size") + "\\s*=\\s*.*$"
|
|
if matched, _ := regexp.MatchString(pattern, line); matched {
|
|
lines[i] = "post_max_size" + " = " + req.UploadMaxSize
|
|
}
|
|
patternUpload := "^" + regexp.QuoteMeta("upload_max_filesize") + "\\s*=\\s*.*$"
|
|
if matched, _ := regexp.MatchString(patternUpload, line); matched {
|
|
lines[i] = "upload_max_filesize" + " = " + req.UploadMaxSize
|
|
}
|
|
}
|
|
}
|
|
updatedContent := strings.Join(lines, "\n")
|
|
if err := fileOp.WriteFile(phpConfigPath, strings.NewReader(updatedContent), 0755); err != nil {
|
|
return err
|
|
}
|
|
|
|
appInstallReq := request.AppInstalledOperate{
|
|
InstallId: appInstall.ID,
|
|
Operate: constant.Restart,
|
|
}
|
|
if err = NewIAppInstalledService().Operate(appInstallReq); err != nil {
|
|
_ = fileOp.WriteFile(phpConfigPath, strings.NewReader(string(contentBytes)), 0755)
|
|
return err
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (w WebsiteService) UpdatePHPConfigFile(req request.WebsitePHPFileUpdate) error {
|
|
website, err := websiteRepo.GetFirst(commonRepo.WithByID(req.ID))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if website.Type != constant.Runtime {
|
|
return nil
|
|
}
|
|
runtime, err := runtimeRepo.GetFirst(commonRepo.WithByID(website.RuntimeID))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if runtime.Resource != constant.ResourceAppstore {
|
|
return nil
|
|
}
|
|
runtimeInstall, err := appInstallRepo.GetFirst(commonRepo.WithByID(website.AppInstallID))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
configPath := ""
|
|
if req.Type == constant.ConfigFPM {
|
|
configPath = path.Join(runtimeInstall.GetPath(), "conf", "php-fpm.conf")
|
|
} else {
|
|
configPath = path.Join(runtimeInstall.GetPath(), "conf", "php.ini")
|
|
}
|
|
if err := files.NewFileOp().WriteFile(configPath, strings.NewReader(req.Content), 0755); err != nil {
|
|
return err
|
|
}
|
|
if _, err := compose.Restart(runtimeInstall.GetComposePath()); err != nil {
|
|
return err
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (w WebsiteService) ChangePHPVersion(req request.WebsitePHPVersionReq) error {
|
|
website, err := websiteRepo.GetFirst(commonRepo.WithByID(req.WebsiteID))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
runtime, err := runtimeRepo.GetFirst(commonRepo.WithByID(req.RuntimeID))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
oldRuntime, err := runtimeRepo.GetFirst(commonRepo.WithByID(website.RuntimeID))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if runtime.Resource == constant.ResourceLocal || oldRuntime.Resource == constant.ResourceLocal {
|
|
return buserr.New("ErrPHPResource")
|
|
}
|
|
appInstall, err := appInstallRepo.GetFirst(commonRepo.WithByID(website.AppInstallID))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
appDetail, err := appDetailRepo.GetFirst(commonRepo.WithByID(runtime.AppDetailID))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
envs := make(map[string]interface{})
|
|
if err = json.Unmarshal([]byte(appInstall.Env), &envs); err != nil {
|
|
return err
|
|
}
|
|
if out, err := compose.Down(appInstall.GetComposePath()); err != nil {
|
|
if out != "" {
|
|
return errors.New(out)
|
|
}
|
|
return err
|
|
}
|
|
|
|
var (
|
|
busErr error
|
|
fileOp = files.NewFileOp()
|
|
envPath = appInstall.GetEnvPath()
|
|
composePath = appInstall.GetComposePath()
|
|
confDir = path.Join(appInstall.GetPath(), "conf")
|
|
backupConfDir = path.Join(appInstall.GetPath(), "conf_bak")
|
|
fpmConfDir = path.Join(confDir, "php-fpm.conf")
|
|
phpDir = path.Join(constant.RuntimeDir, runtime.Type, runtime.Name, "php")
|
|
oldFmContent, _ = fileOp.GetContent(fpmConfDir)
|
|
newComposeByte []byte
|
|
)
|
|
envParams := make(map[string]string, len(envs))
|
|
handleMap(envs, envParams)
|
|
envParams["IMAGE_NAME"] = runtime.Image
|
|
defer func() {
|
|
if busErr != nil {
|
|
envParams["IMAGE_NAME"] = oldRuntime.Image
|
|
_ = env.Write(envParams, envPath)
|
|
_ = fileOp.WriteFile(composePath, strings.NewReader(appInstall.DockerCompose), 0775)
|
|
if fileOp.Stat(backupConfDir) {
|
|
_ = fileOp.DeleteDir(confDir)
|
|
_ = fileOp.Rename(backupConfDir, confDir)
|
|
}
|
|
}
|
|
}()
|
|
|
|
if busErr = env.Write(envParams, envPath); busErr != nil {
|
|
return busErr
|
|
}
|
|
|
|
newComposeByte, busErr = changeServiceName(appDetail.DockerCompose, appInstall.ServiceName)
|
|
if busErr != nil {
|
|
return err
|
|
}
|
|
|
|
if busErr = fileOp.WriteFile(composePath, bytes.NewReader(newComposeByte), 0775); busErr != nil {
|
|
return busErr
|
|
}
|
|
if !req.RetainConfig {
|
|
if busErr = fileOp.Rename(confDir, backupConfDir); busErr != nil {
|
|
return busErr
|
|
}
|
|
_ = fileOp.CreateDir(confDir, 0755)
|
|
if busErr = fileOp.CopyFile(path.Join(phpDir, "php-fpm.conf"), confDir); busErr != nil {
|
|
return busErr
|
|
}
|
|
if busErr = fileOp.CopyFile(path.Join(phpDir, "php.ini"), confDir); busErr != nil {
|
|
_ = fileOp.WriteFile(fpmConfDir, bytes.NewReader(oldFmContent), 0775)
|
|
return busErr
|
|
}
|
|
}
|
|
|
|
if out, err := compose.Up(appInstall.GetComposePath()); err != nil {
|
|
if out != "" {
|
|
busErr = errors.New(out)
|
|
return busErr
|
|
}
|
|
busErr = err
|
|
return busErr
|
|
}
|
|
|
|
_ = fileOp.DeleteDir(backupConfDir)
|
|
|
|
appInstall.AppDetailId = runtime.AppDetailID
|
|
appInstall.AppId = appDetail.AppId
|
|
appInstall.Version = appDetail.Version
|
|
appInstall.DockerCompose = string(newComposeByte)
|
|
|
|
_ = appInstallRepo.Save(context.Background(), &appInstall)
|
|
website.RuntimeID = req.RuntimeID
|
|
return websiteRepo.Save(context.Background(), &website)
|
|
}
|
|
|
|
func (w WebsiteService) UpdateRewriteConfig(req request.NginxRewriteUpdate) error {
|
|
website, err := websiteRepo.GetFirst(commonRepo.WithByID(req.WebsiteID))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
nginxFull, err := getNginxFull(&website)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
includePath := fmt.Sprintf("/www/sites/%s/rewrite/%s.conf", website.Alias, website.PrimaryDomain)
|
|
absolutePath := path.Join(nginxFull.Install.GetPath(), includePath)
|
|
fileOp := files.NewFileOp()
|
|
var oldRewriteContent []byte
|
|
if !fileOp.Stat(path.Dir(absolutePath)) {
|
|
if err := fileOp.CreateDir(path.Dir(absolutePath), 0755); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
if !fileOp.Stat(absolutePath) {
|
|
if err := fileOp.CreateFile(absolutePath); err != nil {
|
|
return err
|
|
}
|
|
} else {
|
|
oldRewriteContent, err = fileOp.GetContent(absolutePath)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
if err := fileOp.WriteFile(absolutePath, strings.NewReader(req.Content), 0755); err != nil {
|
|
return err
|
|
}
|
|
|
|
if err := updateNginxConfig(constant.NginxScopeServer, []dto.NginxParam{{Name: "include", Params: []string{includePath}}}, &website); err != nil {
|
|
_ = fileOp.WriteFile(absolutePath, bytes.NewReader(oldRewriteContent), 0755)
|
|
return err
|
|
}
|
|
website.Rewrite = req.Name
|
|
return websiteRepo.Save(context.Background(), &website)
|
|
}
|
|
|
|
func (w WebsiteService) GetRewriteConfig(req request.NginxRewriteReq) (*response.NginxRewriteRes, error) {
|
|
website, err := websiteRepo.GetFirst(commonRepo.WithByID(req.WebsiteID))
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
var contentByte []byte
|
|
if req.Name == "current" {
|
|
nginxInstall, err := getAppInstallByKey(constant.AppOpenresty)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
rewriteConfPath := path.Join(nginxInstall.GetPath(), "www", "sites", website.Alias, "rewrite", fmt.Sprintf("%s.conf", website.PrimaryDomain))
|
|
fileOp := files.NewFileOp()
|
|
if fileOp.Stat(rewriteConfPath) {
|
|
contentByte, err = fileOp.GetContent(rewriteConfPath)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
}
|
|
} else {
|
|
rewriteFile := fmt.Sprintf("rewrite/%s.conf", strings.ToLower(req.Name))
|
|
contentByte, err = nginx_conf.Rewrites.ReadFile(rewriteFile)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
}
|
|
return &response.NginxRewriteRes{
|
|
Content: string(contentByte),
|
|
}, err
|
|
}
|
|
|
|
func (w WebsiteService) UpdateSiteDir(req request.WebsiteUpdateDir) error {
|
|
website, err := websiteRepo.GetFirst(commonRepo.WithByID(req.ID))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
runDir := req.SiteDir
|
|
siteDir := path.Join("/www/sites", website.Alias, "index")
|
|
if req.SiteDir != "/" {
|
|
siteDir = fmt.Sprintf("%s%s", siteDir, req.SiteDir)
|
|
}
|
|
if err := updateNginxConfig(constant.NginxScopeServer, []dto.NginxParam{{Name: "root", Params: []string{siteDir}}}, &website); err != nil {
|
|
return err
|
|
}
|
|
website.SiteDir = runDir
|
|
return websiteRepo.Save(context.Background(), &website)
|
|
}
|
|
|
|
func (w WebsiteService) UpdateSitePermission(req request.WebsiteUpdateDirPermission) error {
|
|
website, err := websiteRepo.GetFirst(commonRepo.WithByID(req.ID))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
nginxInstall, err := getAppInstallByKey(constant.AppOpenresty)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
absoluteIndexPath := path.Join(nginxInstall.GetPath(), "www", "sites", website.Alias, "index")
|
|
chownCmd := fmt.Sprintf("chown -R %s:%s %s", req.User, req.Group, absoluteIndexPath)
|
|
if cmd.HasNoPasswordSudo() {
|
|
chownCmd = fmt.Sprintf("sudo %s", chownCmd)
|
|
}
|
|
if out, err := cmd.ExecWithTimeOut(chownCmd, 10*time.Second); err != nil {
|
|
if out != "" {
|
|
return errors.New(out)
|
|
}
|
|
return err
|
|
}
|
|
website.User = req.User
|
|
website.Group = req.Group
|
|
return websiteRepo.Save(context.Background(), &website)
|
|
}
|
|
|
|
func (w WebsiteService) OperateProxy(req request.WebsiteProxyConfig) (err error) {
|
|
var (
|
|
website model.Website
|
|
params []response.NginxParam
|
|
nginxInstall model.AppInstall
|
|
par *parser.Parser
|
|
oldContent []byte
|
|
)
|
|
|
|
website, err = websiteRepo.GetFirst(commonRepo.WithByID(req.ID))
|
|
if err != nil {
|
|
return
|
|
}
|
|
params, err = getNginxParamsByKeys(constant.NginxScopeHttp, []string{"proxy_cache"}, &website)
|
|
if err != nil {
|
|
return
|
|
}
|
|
nginxInstall, err = getAppInstallByKey(constant.AppOpenresty)
|
|
if err != nil {
|
|
return
|
|
}
|
|
fileOp := files.NewFileOp()
|
|
if len(params) == 0 || len(params[0].Params) == 0 {
|
|
commonDir := path.Join(nginxInstall.GetPath(), "www", "common", "proxy")
|
|
proxyTempPath := path.Join(commonDir, "proxy_temp_dir")
|
|
if !fileOp.Stat(proxyTempPath) {
|
|
_ = fileOp.CreateDir(proxyTempPath, 0755)
|
|
}
|
|
proxyCacheDir := path.Join(commonDir, "proxy_temp_dir")
|
|
if !fileOp.Stat(proxyCacheDir) {
|
|
_ = fileOp.CreateDir(proxyCacheDir, 0755)
|
|
}
|
|
nginxParams := getNginxParamsFromStaticFile(dto.CACHE, nil)
|
|
if err = updateNginxConfig(constant.NginxScopeHttp, nginxParams, &website); err != nil {
|
|
return
|
|
}
|
|
}
|
|
includeDir := path.Join(nginxInstall.GetPath(), "www", "sites", website.Alias, "proxy")
|
|
if !fileOp.Stat(includeDir) {
|
|
_ = fileOp.CreateDir(includeDir, 0755)
|
|
}
|
|
fileName := fmt.Sprintf("%s.conf", req.Name)
|
|
includePath := path.Join(includeDir, fileName)
|
|
backName := fmt.Sprintf("%s.bak", req.Name)
|
|
backPath := path.Join(includeDir, backName)
|
|
|
|
if req.Operate == "create" && (fileOp.Stat(includePath) || fileOp.Stat(backPath)) {
|
|
err = buserr.New(constant.ErrNameIsExist)
|
|
return
|
|
}
|
|
|
|
defer func() {
|
|
if err != nil {
|
|
switch req.Operate {
|
|
case "create":
|
|
_ = fileOp.DeleteFile(includePath)
|
|
case "edit":
|
|
_ = fileOp.WriteFile(includePath, bytes.NewReader(oldContent), 0755)
|
|
}
|
|
}
|
|
}()
|
|
|
|
var config *components.Config
|
|
|
|
switch req.Operate {
|
|
case "create":
|
|
config, err = parser.NewStringParser(string(nginx_conf.Proxy)).Parse()
|
|
if err != nil {
|
|
return
|
|
}
|
|
case "edit":
|
|
par, err = parser.NewParser(includePath)
|
|
if err != nil {
|
|
return
|
|
}
|
|
config, err = par.Parse()
|
|
if err != nil {
|
|
return
|
|
}
|
|
oldContent, err = fileOp.GetContent(includePath)
|
|
if err != nil {
|
|
return
|
|
}
|
|
case "delete":
|
|
_ = fileOp.DeleteFile(includePath)
|
|
_ = fileOp.DeleteFile(backPath)
|
|
return updateNginxConfig(constant.NginxScopeServer, nil, &website)
|
|
case "disable":
|
|
_ = fileOp.Rename(includePath, backPath)
|
|
return updateNginxConfig(constant.NginxScopeServer, nil, &website)
|
|
case "enable":
|
|
_ = fileOp.Rename(backPath, includePath)
|
|
return updateNginxConfig(constant.NginxScopeServer, nil, &website)
|
|
}
|
|
|
|
config.FilePath = includePath
|
|
directives := config.Directives
|
|
location, ok := directives[0].(*components.Location)
|
|
if !ok {
|
|
err = errors.New("error")
|
|
return
|
|
}
|
|
location.UpdateDirective("proxy_pass", []string{req.ProxyPass})
|
|
location.UpdateDirective("proxy_set_header", []string{"Host", req.ProxyHost})
|
|
location.ChangePath(req.Modifier, req.Match)
|
|
if req.Cache {
|
|
location.AddCache(req.CacheTime, req.CacheUnit)
|
|
} else {
|
|
location.RemoveCache()
|
|
}
|
|
if len(req.Replaces) > 0 {
|
|
location.AddSubFilter(req.Replaces)
|
|
} else {
|
|
location.RemoveSubFilter()
|
|
}
|
|
if req.SNI {
|
|
location.UpdateDirective("proxy_ssl_server_name", []string{"on"})
|
|
} else {
|
|
location.UpdateDirective("proxy_ssl_server_name", []string{"off"})
|
|
}
|
|
if err = nginx.WriteConfig(config, nginx.IndentedStyle); err != nil {
|
|
return buserr.WithErr(constant.ErrUpdateBuWebsite, err)
|
|
}
|
|
nginxInclude := fmt.Sprintf("/www/sites/%s/proxy/*.conf", website.Alias)
|
|
if err = updateNginxConfig(constant.NginxScopeServer, []dto.NginxParam{{Name: "include", Params: []string{nginxInclude}}}, &website); err != nil {
|
|
return
|
|
}
|
|
return
|
|
}
|
|
|
|
func (w WebsiteService) GetProxies(id uint) (res []request.WebsiteProxyConfig, err error) {
|
|
var (
|
|
website model.Website
|
|
nginxInstall model.AppInstall
|
|
fileList response.FileInfo
|
|
)
|
|
website, err = websiteRepo.GetFirst(commonRepo.WithByID(id))
|
|
if err != nil {
|
|
return
|
|
}
|
|
nginxInstall, err = getAppInstallByKey(constant.AppOpenresty)
|
|
if err != nil {
|
|
return
|
|
}
|
|
includeDir := path.Join(nginxInstall.GetPath(), "www", "sites", website.Alias, "proxy")
|
|
fileOp := files.NewFileOp()
|
|
if !fileOp.Stat(includeDir) {
|
|
return
|
|
}
|
|
fileList, err = NewIFileService().GetFileList(request.FileOption{FileOption: files.FileOption{Path: includeDir, Expand: true, Page: 1, PageSize: 100}})
|
|
if len(fileList.Items) == 0 {
|
|
return
|
|
}
|
|
var (
|
|
content []byte
|
|
config *components.Config
|
|
)
|
|
for _, configFile := range fileList.Items {
|
|
proxyConfig := request.WebsiteProxyConfig{
|
|
ID: website.ID,
|
|
}
|
|
parts := strings.Split(configFile.Name, ".")
|
|
proxyConfig.Name = parts[0]
|
|
if parts[1] == "conf" {
|
|
proxyConfig.Enable = true
|
|
} else {
|
|
proxyConfig.Enable = false
|
|
}
|
|
proxyConfig.FilePath = configFile.Path
|
|
content, err = fileOp.GetContent(configFile.Path)
|
|
if err != nil {
|
|
return
|
|
}
|
|
proxyConfig.Content = string(content)
|
|
config, err = parser.NewStringParser(string(content)).Parse()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
directives := config.GetDirectives()
|
|
|
|
location, ok := directives[0].(*components.Location)
|
|
if !ok {
|
|
err = errors.New("error")
|
|
return
|
|
}
|
|
proxyConfig.ProxyPass = location.ProxyPass
|
|
proxyConfig.Cache = location.Cache
|
|
if location.CacheTime > 0 {
|
|
proxyConfig.CacheTime = location.CacheTime
|
|
proxyConfig.CacheUnit = location.CacheUint
|
|
}
|
|
proxyConfig.Match = location.Match
|
|
proxyConfig.Modifier = location.Modifier
|
|
proxyConfig.ProxyHost = location.Host
|
|
proxyConfig.Replaces = location.Replaces
|
|
for _, directive := range location.Directives {
|
|
if directive.GetName() == "proxy_ssl_server_name" {
|
|
proxyConfig.SNI = directive.GetParameters()[0] == "on"
|
|
}
|
|
}
|
|
res = append(res, proxyConfig)
|
|
}
|
|
return
|
|
}
|
|
|
|
func (w WebsiteService) UpdateProxyFile(req request.NginxProxyUpdate) (err error) {
|
|
var (
|
|
website model.Website
|
|
nginxFull dto.NginxFull
|
|
oldRewriteContent []byte
|
|
)
|
|
website, err = websiteRepo.GetFirst(commonRepo.WithByID(req.WebsiteID))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
nginxFull, err = getNginxFull(&website)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
includePath := fmt.Sprintf("/www/sites/%s/proxy/%s.conf", website.Alias, req.Name)
|
|
absolutePath := path.Join(nginxFull.Install.GetPath(), includePath)
|
|
fileOp := files.NewFileOp()
|
|
oldRewriteContent, err = fileOp.GetContent(absolutePath)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if err = fileOp.WriteFile(absolutePath, strings.NewReader(req.Content), 0755); err != nil {
|
|
return err
|
|
}
|
|
defer func() {
|
|
if err != nil {
|
|
_ = fileOp.WriteFile(absolutePath, bytes.NewReader(oldRewriteContent), 0755)
|
|
}
|
|
}()
|
|
return updateNginxConfig(constant.NginxScopeServer, nil, &website)
|
|
}
|
|
|
|
func (w WebsiteService) GetAuthBasics(req request.NginxAuthReq) (res response.NginxAuthRes, err error) {
|
|
var (
|
|
website model.Website
|
|
nginxInstall model.AppInstall
|
|
authContent []byte
|
|
nginxParams []response.NginxParam
|
|
)
|
|
website, err = websiteRepo.GetFirst(commonRepo.WithByID(req.WebsiteID))
|
|
if err != nil {
|
|
return
|
|
}
|
|
nginxInstall, err = getAppInstallByKey(constant.AppOpenresty)
|
|
if err != nil {
|
|
return
|
|
}
|
|
authPath := fmt.Sprintf("/www/sites/%s/auth_basic/auth.pass", website.Alias)
|
|
absoluteAuthPath := path.Join(nginxInstall.GetPath(), authPath)
|
|
fileOp := files.NewFileOp()
|
|
if !fileOp.Stat(absoluteAuthPath) {
|
|
return
|
|
}
|
|
nginxParams, err = getNginxParamsByKeys(constant.NginxScopeServer, []string{"auth_basic"}, &website)
|
|
if err != nil {
|
|
return
|
|
}
|
|
res.Enable = len(nginxParams[0].Params) > 0
|
|
authContent, err = fileOp.GetContent(absoluteAuthPath)
|
|
authArray := strings.Split(string(authContent), "\n")
|
|
for _, line := range authArray {
|
|
if line == "" {
|
|
continue
|
|
}
|
|
params := strings.Split(line, ":")
|
|
auth := dto.NginxAuth{
|
|
Username: params[0],
|
|
}
|
|
if len(params) == 3 {
|
|
auth.Remark = params[2]
|
|
}
|
|
res.Items = append(res.Items, auth)
|
|
}
|
|
return
|
|
}
|
|
|
|
func (w WebsiteService) UpdateAuthBasic(req request.NginxAuthUpdate) (err error) {
|
|
var (
|
|
website model.Website
|
|
nginxInstall model.AppInstall
|
|
params []dto.NginxParam
|
|
authContent []byte
|
|
authArray []string
|
|
)
|
|
website, err = websiteRepo.GetFirst(commonRepo.WithByID(req.WebsiteID))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
nginxInstall, err = getAppInstallByKey(constant.AppOpenresty)
|
|
if err != nil {
|
|
return
|
|
}
|
|
authPath := fmt.Sprintf("/www/sites/%s/auth_basic/auth.pass", website.Alias)
|
|
absoluteAuthPath := path.Join(nginxInstall.GetPath(), authPath)
|
|
fileOp := files.NewFileOp()
|
|
if !fileOp.Stat(path.Dir(absoluteAuthPath)) {
|
|
_ = fileOp.CreateDir(path.Dir(absoluteAuthPath), 0755)
|
|
}
|
|
if !fileOp.Stat(absoluteAuthPath) {
|
|
_ = fileOp.CreateFile(absoluteAuthPath)
|
|
}
|
|
|
|
params = append(params, dto.NginxParam{Name: "auth_basic", Params: []string{`"Authentication"`}})
|
|
params = append(params, dto.NginxParam{Name: "auth_basic_user_file", Params: []string{authPath}})
|
|
authContent, err = fileOp.GetContent(absoluteAuthPath)
|
|
if err != nil {
|
|
return
|
|
}
|
|
if len(authContent) > 0 {
|
|
authArray = strings.Split(string(authContent), "\n")
|
|
}
|
|
switch req.Operate {
|
|
case "disable":
|
|
return deleteNginxConfig(constant.NginxScopeServer, params, &website)
|
|
case "enable":
|
|
return updateNginxConfig(constant.NginxScopeServer, params, &website)
|
|
case "create":
|
|
for _, line := range authArray {
|
|
authParams := strings.Split(line, ":")
|
|
username := authParams[0]
|
|
if username == req.Username {
|
|
err = buserr.New(constant.ErrUsernameIsExist)
|
|
return
|
|
}
|
|
}
|
|
var passwdHash []byte
|
|
passwdHash, err = bcrypt.GenerateFromPassword([]byte(req.Password), bcrypt.DefaultCost)
|
|
if err != nil {
|
|
return
|
|
}
|
|
line := fmt.Sprintf("%s:%s\n", req.Username, passwdHash)
|
|
if req.Remark != "" {
|
|
line = fmt.Sprintf("%s:%s:%s\n", req.Username, passwdHash, req.Remark)
|
|
}
|
|
authArray = append(authArray, line)
|
|
case "edit":
|
|
userExist := false
|
|
for index, line := range authArray {
|
|
authParams := strings.Split(line, ":")
|
|
username := authParams[0]
|
|
if username == req.Username {
|
|
userExist = true
|
|
var passwdHash []byte
|
|
passwdHash, err = bcrypt.GenerateFromPassword([]byte(req.Password), bcrypt.DefaultCost)
|
|
if err != nil {
|
|
return
|
|
}
|
|
userPasswd := fmt.Sprintf("%s:%s\n", req.Username, passwdHash)
|
|
if req.Remark != "" {
|
|
userPasswd = fmt.Sprintf("%s:%s:%s\n", req.Username, passwdHash, req.Remark)
|
|
}
|
|
authArray[index] = userPasswd
|
|
}
|
|
}
|
|
if !userExist {
|
|
err = buserr.New(constant.ErrUsernameIsNotExist)
|
|
return
|
|
}
|
|
case "delete":
|
|
deleteIndex := -1
|
|
for index, line := range authArray {
|
|
authParams := strings.Split(line, ":")
|
|
username := authParams[0]
|
|
if username == req.Username {
|
|
deleteIndex = index
|
|
}
|
|
}
|
|
if deleteIndex < 0 {
|
|
return
|
|
}
|
|
authArray = append(authArray[:deleteIndex], authArray[deleteIndex+1:]...)
|
|
}
|
|
|
|
var passFile *os.File
|
|
passFile, err = os.Create(absoluteAuthPath)
|
|
if err != nil {
|
|
return
|
|
}
|
|
defer passFile.Close()
|
|
writer := bufio.NewWriter(passFile)
|
|
for _, line := range authArray {
|
|
if line == "" {
|
|
continue
|
|
}
|
|
_, err = writer.WriteString(line + "\n")
|
|
if err != nil {
|
|
return
|
|
}
|
|
}
|
|
err = writer.Flush()
|
|
if err != nil {
|
|
return
|
|
}
|
|
authContent, err = fileOp.GetContent(absoluteAuthPath)
|
|
if err != nil {
|
|
return
|
|
}
|
|
if len(authContent) == 0 {
|
|
if err = deleteNginxConfig(constant.NginxScopeServer, params, &website); err != nil {
|
|
return
|
|
}
|
|
}
|
|
return
|
|
}
|
|
|
|
func (w WebsiteService) GetPathAuthBasics(req request.NginxAuthReq) (res []response.NginxPathAuthRes, err error) {
|
|
var (
|
|
website model.Website
|
|
nginxInstall model.AppInstall
|
|
authContent []byte
|
|
)
|
|
website, err = websiteRepo.GetFirst(commonRepo.WithByID(req.WebsiteID))
|
|
if err != nil {
|
|
return
|
|
}
|
|
nginxInstall, err = getAppInstallByKey(constant.AppOpenresty)
|
|
if err != nil {
|
|
return
|
|
}
|
|
fileOp := files.NewFileOp()
|
|
authDir := fmt.Sprintf("/www/sites/%s/path_auth", website.Alias)
|
|
absoluteAuthDir := path.Join(nginxInstall.GetPath(), authDir)
|
|
passDir := path.Join(absoluteAuthDir, "pass")
|
|
if !fileOp.Stat(absoluteAuthDir) || !fileOp.Stat(passDir) {
|
|
return
|
|
}
|
|
|
|
entries, err := os.ReadDir(absoluteAuthDir)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
for _, entry := range entries {
|
|
if !entry.IsDir() {
|
|
name := strings.TrimSuffix(entry.Name(), ".conf")
|
|
pathAuth := dto.NginxPathAuth{
|
|
Name: name,
|
|
}
|
|
configPath := path.Join(absoluteAuthDir, entry.Name())
|
|
content, err := fileOp.GetContent(configPath)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
config, err := parser.NewStringParser(string(content)).Parse()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
directives := config.Directives
|
|
location, _ := directives[0].(*components.Location)
|
|
pathAuth.Path = location.Match
|
|
passPath := path.Join(passDir, fmt.Sprintf("%s.pass", name))
|
|
authContent, err = fileOp.GetContent(passPath)
|
|
authArray := strings.Split(string(authContent), "\n")
|
|
for _, line := range authArray {
|
|
if line == "" {
|
|
continue
|
|
}
|
|
params := strings.Split(line, ":")
|
|
pathAuth.Username = params[0]
|
|
if len(params) == 3 {
|
|
pathAuth.Remark = params[2]
|
|
}
|
|
}
|
|
res = append(res, response.NginxPathAuthRes{
|
|
NginxPathAuth: pathAuth,
|
|
})
|
|
}
|
|
}
|
|
return
|
|
}
|
|
|
|
func (w WebsiteService) UpdatePathAuthBasic(req request.NginxPathAuthUpdate) error {
|
|
website, err := websiteRepo.GetFirst(commonRepo.WithByID(req.WebsiteID))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
nginxInstall, err := getAppInstallByKey(constant.AppOpenresty)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
fileOp := files.NewFileOp()
|
|
authDir := path.Join(nginxInstall.GetPath(), "www", "sites", website.Alias, "path_auth")
|
|
if !fileOp.Stat(authDir) {
|
|
_ = fileOp.CreateDir(authDir, 0755)
|
|
}
|
|
passDir := path.Join(authDir, "pass")
|
|
if !fileOp.Stat(passDir) {
|
|
_ = fileOp.CreateDir(passDir, 0755)
|
|
}
|
|
confPath := path.Join(authDir, fmt.Sprintf("%s.conf", req.Name))
|
|
passPath := path.Join(passDir, fmt.Sprintf("%s.pass", req.Name))
|
|
var config *components.Config
|
|
switch req.Operate {
|
|
case "delete":
|
|
_ = fileOp.DeleteFile(confPath)
|
|
_ = fileOp.DeleteFile(passPath)
|
|
return updateNginxConfig(constant.NginxScopeServer, nil, &website)
|
|
case "create":
|
|
config, err = parser.NewStringParser(string(nginx_conf.PathAuth)).Parse()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if fileOp.Stat(confPath) || fileOp.Stat(passPath) {
|
|
return buserr.New(constant.ErrNameIsExist)
|
|
}
|
|
case "edit":
|
|
par, err := parser.NewParser(confPath)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
config, err = par.Parse()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
config.FilePath = confPath
|
|
directives := config.Directives
|
|
location, _ := directives[0].(*components.Location)
|
|
location.UpdateDirective("auth_basic_user_file", []string{fmt.Sprintf("/www/sites/%s/path_auth/pass/%s", website.Alias, fmt.Sprintf("%s.pass", req.Name))})
|
|
location.ChangePath("~*", req.Path)
|
|
var passwdHash []byte
|
|
passwdHash, err = bcrypt.GenerateFromPassword([]byte(req.Password), bcrypt.DefaultCost)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
line := fmt.Sprintf("%s:%s\n", req.Username, passwdHash)
|
|
if req.Remark != "" {
|
|
line = fmt.Sprintf("%s:%s:%s\n", req.Username, passwdHash, req.Remark)
|
|
}
|
|
_ = fileOp.SaveFile(passPath, line, 0644)
|
|
if err = nginx.WriteConfig(config, nginx.IndentedStyle); err != nil {
|
|
return buserr.WithErr(constant.ErrUpdateBuWebsite, err)
|
|
}
|
|
nginxInclude := fmt.Sprintf("/www/sites/%s/path_auth/*.conf", website.Alias)
|
|
if err = updateNginxConfig(constant.NginxScopeServer, []dto.NginxParam{{Name: "include", Params: []string{nginxInclude}}}, &website); err != nil {
|
|
return nil
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (w WebsiteService) UpdateAntiLeech(req request.NginxAntiLeechUpdate) (err error) {
|
|
website, err := websiteRepo.GetFirst(commonRepo.WithByID(req.WebsiteID))
|
|
if err != nil {
|
|
return
|
|
}
|
|
nginxFull, err := getNginxFull(&website)
|
|
if err != nil {
|
|
return
|
|
}
|
|
fileOp := files.NewFileOp()
|
|
backupContent, err := fileOp.GetContent(nginxFull.SiteConfig.Config.FilePath)
|
|
if err != nil {
|
|
return
|
|
}
|
|
block := nginxFull.SiteConfig.Config.FindServers()[0]
|
|
locations := block.FindDirectives("location")
|
|
for _, location := range locations {
|
|
loParams := location.GetParameters()
|
|
if len(loParams) > 1 || loParams[0] == "~" {
|
|
extendStr := loParams[1]
|
|
if strings.HasPrefix(extendStr, `.*\.(`) && strings.HasSuffix(extendStr, `)$`) {
|
|
block.RemoveDirective("location", loParams)
|
|
}
|
|
}
|
|
}
|
|
if req.Enable {
|
|
exts := strings.Split(req.Extends, ",")
|
|
newDirective := components.Directive{
|
|
Name: "location",
|
|
Parameters: []string{"~", fmt.Sprintf(`.*\.(%s)$`, strings.Join(exts, "|"))},
|
|
}
|
|
|
|
newBlock := &components.Block{}
|
|
newBlock.Directives = make([]components.IDirective, 0)
|
|
if req.Cache {
|
|
newBlock.Directives = append(newBlock.Directives, &components.Directive{
|
|
Name: "expires",
|
|
Parameters: []string{strconv.Itoa(req.CacheTime) + req.CacheUint},
|
|
})
|
|
}
|
|
newBlock.Directives = append(newBlock.Directives, &components.Directive{
|
|
Name: "log_not_found",
|
|
Parameters: []string{"off"},
|
|
})
|
|
validDir := &components.Directive{
|
|
Name: "valid_referers",
|
|
Parameters: []string{},
|
|
}
|
|
if req.NoneRef {
|
|
validDir.Parameters = append(validDir.Parameters, "none")
|
|
}
|
|
if len(req.ServerNames) > 0 {
|
|
validDir.Parameters = append(validDir.Parameters, strings.Join(req.ServerNames, " "))
|
|
}
|
|
newBlock.Directives = append(newBlock.Directives, validDir)
|
|
|
|
ifDir := &components.Directive{
|
|
Name: "if",
|
|
Parameters: []string{"($invalid_referer)"},
|
|
}
|
|
ifDir.Block = &components.Block{
|
|
Directives: []components.IDirective{
|
|
&components.Directive{
|
|
Name: "return",
|
|
Parameters: []string{req.Return},
|
|
},
|
|
&components.Directive{
|
|
Name: "access_log",
|
|
Parameters: []string{"off"},
|
|
},
|
|
},
|
|
}
|
|
newBlock.Directives = append(newBlock.Directives, ifDir)
|
|
newDirective.Block = newBlock
|
|
block.Directives = append(block.Directives, &newDirective)
|
|
}
|
|
|
|
if err = nginx.WriteConfig(nginxFull.SiteConfig.Config, nginx.IndentedStyle); err != nil {
|
|
return
|
|
}
|
|
if err = updateNginxConfig(constant.NginxScopeServer, nil, &website); err != nil {
|
|
_ = fileOp.WriteFile(nginxFull.SiteConfig.Config.FilePath, bytes.NewReader(backupContent), 0755)
|
|
return
|
|
}
|
|
return
|
|
}
|
|
|
|
func (w WebsiteService) GetAntiLeech(id uint) (*response.NginxAntiLeechRes, error) {
|
|
website, err := websiteRepo.GetFirst(commonRepo.WithByID(id))
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
nginxFull, err := getNginxFull(&website)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
res := &response.NginxAntiLeechRes{
|
|
LogEnable: true,
|
|
ServerNames: []string{},
|
|
}
|
|
block := nginxFull.SiteConfig.Config.FindServers()[0]
|
|
locations := block.FindDirectives("location")
|
|
for _, location := range locations {
|
|
loParams := location.GetParameters()
|
|
if len(loParams) > 1 || loParams[0] == "~" {
|
|
extendStr := loParams[1]
|
|
if strings.HasPrefix(extendStr, `.*\.(`) && strings.HasSuffix(extendStr, `)$`) {
|
|
str1 := strings.TrimPrefix(extendStr, `.*\.(`)
|
|
str2 := strings.TrimSuffix(str1, ")$")
|
|
res.Extends = strings.Join(strings.Split(str2, "|"), ",")
|
|
}
|
|
}
|
|
lDirectives := location.GetBlock().GetDirectives()
|
|
for _, lDir := range lDirectives {
|
|
if lDir.GetName() == "valid_referers" {
|
|
res.Enable = true
|
|
params := lDir.GetParameters()
|
|
for _, param := range params {
|
|
if param == "none" {
|
|
res.NoneRef = true
|
|
continue
|
|
}
|
|
if param == "blocked" {
|
|
res.Blocked = true
|
|
continue
|
|
}
|
|
if param == "server_names" {
|
|
continue
|
|
}
|
|
res.ServerNames = append(res.ServerNames, param)
|
|
}
|
|
}
|
|
if lDir.GetName() == "if" && lDir.GetParameters()[0] == "($invalid_referer)" {
|
|
directives := lDir.GetBlock().GetDirectives()
|
|
for _, dir := range directives {
|
|
if dir.GetName() == "return" {
|
|
res.Return = strings.Join(dir.GetParameters(), " ")
|
|
}
|
|
if dir.GetName() == "access_log" {
|
|
if strings.Join(dir.GetParameters(), "") == "off" {
|
|
res.LogEnable = false
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if lDir.GetName() == "expires" {
|
|
res.Cache = true
|
|
re := regexp.MustCompile(`^(\d+)(\w+)$`)
|
|
matches := re.FindStringSubmatch(lDir.GetParameters()[0])
|
|
if matches == nil {
|
|
continue
|
|
}
|
|
cacheTime, err := strconv.Atoi(matches[1])
|
|
if err != nil {
|
|
continue
|
|
}
|
|
unit := matches[2]
|
|
res.CacheUint = unit
|
|
res.CacheTime = cacheTime
|
|
}
|
|
}
|
|
}
|
|
return res, nil
|
|
}
|
|
|
|
func (w WebsiteService) OperateRedirect(req request.NginxRedirectReq) (err error) {
|
|
var (
|
|
website model.Website
|
|
nginxInstall model.AppInstall
|
|
oldContent []byte
|
|
)
|
|
|
|
website, err = websiteRepo.GetFirst(commonRepo.WithByID(req.WebsiteID))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
nginxInstall, err = getAppInstallByKey(constant.AppOpenresty)
|
|
if err != nil {
|
|
return
|
|
}
|
|
includeDir := path.Join(nginxInstall.GetPath(), "www", "sites", website.Alias, "redirect")
|
|
fileOp := files.NewFileOp()
|
|
if !fileOp.Stat(includeDir) {
|
|
_ = fileOp.CreateDir(includeDir, 0755)
|
|
}
|
|
fileName := fmt.Sprintf("%s.conf", req.Name)
|
|
includePath := path.Join(includeDir, fileName)
|
|
backName := fmt.Sprintf("%s.bak", req.Name)
|
|
backPath := path.Join(includeDir, backName)
|
|
|
|
if req.Operate == "create" && (fileOp.Stat(includePath) || fileOp.Stat(backPath)) {
|
|
err = buserr.New(constant.ErrNameIsExist)
|
|
return
|
|
}
|
|
|
|
defer func() {
|
|
if err != nil {
|
|
switch req.Operate {
|
|
case "create":
|
|
_ = fileOp.DeleteFile(includePath)
|
|
case "edit":
|
|
_ = fileOp.WriteFile(includePath, bytes.NewReader(oldContent), 0755)
|
|
}
|
|
}
|
|
}()
|
|
|
|
var (
|
|
config *components.Config
|
|
oldPar *parser.Parser
|
|
)
|
|
|
|
switch req.Operate {
|
|
case "create":
|
|
config = &components.Config{}
|
|
case "edit":
|
|
oldPar, err = parser.NewParser(includePath)
|
|
if err != nil {
|
|
return
|
|
}
|
|
config, err = oldPar.Parse()
|
|
if err != nil {
|
|
return
|
|
}
|
|
oldContent, err = fileOp.GetContent(includePath)
|
|
if err != nil {
|
|
return
|
|
}
|
|
case "delete":
|
|
_ = fileOp.DeleteFile(includePath)
|
|
_ = fileOp.DeleteFile(backPath)
|
|
return updateNginxConfig(constant.NginxScopeServer, nil, &website)
|
|
case "disable":
|
|
_ = fileOp.Rename(includePath, backPath)
|
|
return updateNginxConfig(constant.NginxScopeServer, nil, &website)
|
|
case "enable":
|
|
_ = fileOp.Rename(backPath, includePath)
|
|
return updateNginxConfig(constant.NginxScopeServer, nil, &website)
|
|
}
|
|
|
|
target := req.Target
|
|
block := &components.Block{}
|
|
|
|
switch req.Type {
|
|
case "path":
|
|
if req.KeepPath {
|
|
target = req.Target + "$1"
|
|
} else {
|
|
target = req.Target + "?"
|
|
}
|
|
redirectKey := "permanent"
|
|
if req.Redirect == "302" {
|
|
redirectKey = "redirect"
|
|
}
|
|
block = &components.Block{
|
|
Directives: []components.IDirective{
|
|
&components.Directive{
|
|
Name: "rewrite",
|
|
Parameters: []string{fmt.Sprintf("^%s(.*)", req.Path), target, redirectKey},
|
|
},
|
|
},
|
|
}
|
|
case "domain":
|
|
if req.KeepPath {
|
|
target = req.Target + "$request_uri"
|
|
}
|
|
returnBlock := &components.Block{
|
|
Directives: []components.IDirective{
|
|
&components.Directive{
|
|
Name: "return",
|
|
Parameters: []string{req.Redirect, target},
|
|
},
|
|
},
|
|
}
|
|
for _, domain := range req.Domains {
|
|
block.Directives = append(block.Directives, &components.Directive{
|
|
Name: "if",
|
|
Parameters: []string{"($host", "~", fmt.Sprintf("'^%s')", domain)},
|
|
Block: returnBlock,
|
|
})
|
|
}
|
|
case "404":
|
|
if req.RedirectRoot {
|
|
target = "/"
|
|
}
|
|
block = &components.Block{
|
|
Directives: []components.IDirective{
|
|
&components.Directive{
|
|
Name: "error_page",
|
|
Parameters: []string{"404", "=", "@notfound"},
|
|
},
|
|
&components.Directive{
|
|
Name: "location",
|
|
Parameters: []string{"@notfound"},
|
|
Block: &components.Block{
|
|
Directives: []components.IDirective{
|
|
&components.Directive{
|
|
Name: "return",
|
|
Parameters: []string{req.Redirect, target},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
}
|
|
config.FilePath = includePath
|
|
config.Block = block
|
|
|
|
if err = nginx.WriteConfig(config, nginx.IndentedStyle); err != nil {
|
|
return buserr.WithErr(constant.ErrUpdateBuWebsite, err)
|
|
}
|
|
|
|
nginxInclude := fmt.Sprintf("/www/sites/%s/redirect/*.conf", website.Alias)
|
|
if err = updateNginxConfig(constant.NginxScopeServer, []dto.NginxParam{{Name: "include", Params: []string{nginxInclude}}}, &website); err != nil {
|
|
return
|
|
}
|
|
return
|
|
}
|
|
|
|
func (w WebsiteService) GetRedirect(id uint) (res []response.NginxRedirectConfig, err error) {
|
|
var (
|
|
website model.Website
|
|
nginxInstall model.AppInstall
|
|
fileList response.FileInfo
|
|
)
|
|
website, err = websiteRepo.GetFirst(commonRepo.WithByID(id))
|
|
if err != nil {
|
|
return
|
|
}
|
|
nginxInstall, err = getAppInstallByKey(constant.AppOpenresty)
|
|
if err != nil {
|
|
return
|
|
}
|
|
includeDir := path.Join(nginxInstall.GetPath(), "www", "sites", website.Alias, "redirect")
|
|
fileOp := files.NewFileOp()
|
|
if !fileOp.Stat(includeDir) {
|
|
return
|
|
}
|
|
fileList, err = NewIFileService().GetFileList(request.FileOption{FileOption: files.FileOption{Path: includeDir, Expand: true, Page: 1, PageSize: 100}})
|
|
if len(fileList.Items) == 0 {
|
|
return
|
|
}
|
|
var (
|
|
content []byte
|
|
config *components.Config
|
|
)
|
|
for _, configFile := range fileList.Items {
|
|
redirectConfig := response.NginxRedirectConfig{
|
|
WebsiteID: website.ID,
|
|
}
|
|
parts := strings.Split(configFile.Name, ".")
|
|
redirectConfig.Name = parts[0]
|
|
if parts[1] == "conf" {
|
|
redirectConfig.Enable = true
|
|
} else {
|
|
redirectConfig.Enable = false
|
|
}
|
|
redirectConfig.FilePath = configFile.Path
|
|
content, err = fileOp.GetContent(configFile.Path)
|
|
if err != nil {
|
|
return
|
|
}
|
|
redirectConfig.Content = string(content)
|
|
config, err = parser.NewStringParser(string(content)).Parse()
|
|
if err != nil {
|
|
return
|
|
}
|
|
|
|
dirs := config.GetDirectives()
|
|
if len(dirs) > 0 {
|
|
firstName := dirs[0].GetName()
|
|
switch firstName {
|
|
case "if":
|
|
for _, ifDir := range dirs {
|
|
params := ifDir.GetParameters()
|
|
if len(params) > 2 && params[0] == "($host" {
|
|
domain := strings.Trim(strings.Trim(params[2], "'"), "^")
|
|
redirectConfig.Domains = append(redirectConfig.Domains, domain)
|
|
if len(redirectConfig.Domains) > 1 {
|
|
continue
|
|
}
|
|
redirectConfig.Type = "domain"
|
|
}
|
|
childDirs := ifDir.GetBlock().GetDirectives()
|
|
for _, dir := range childDirs {
|
|
if dir.GetName() == "return" {
|
|
dirParams := dir.GetParameters()
|
|
if len(dirParams) > 1 {
|
|
redirectConfig.Redirect = dirParams[0]
|
|
if strings.HasSuffix(dirParams[1], "$request_uri") {
|
|
redirectConfig.KeepPath = true
|
|
redirectConfig.Target = strings.TrimSuffix(dirParams[1], "$request_uri")
|
|
} else {
|
|
redirectConfig.KeepPath = false
|
|
redirectConfig.Target = dirParams[1]
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
case "rewrite":
|
|
redirectConfig.Type = "path"
|
|
for _, pathDir := range dirs {
|
|
if pathDir.GetName() == "rewrite" {
|
|
params := pathDir.GetParameters()
|
|
if len(params) > 2 {
|
|
redirectConfig.Path = strings.Trim(strings.Trim(params[0], "^"), "(.*)")
|
|
if strings.HasSuffix(params[1], "$1") {
|
|
redirectConfig.KeepPath = true
|
|
redirectConfig.Target = strings.TrimSuffix(params[1], "$1")
|
|
} else {
|
|
redirectConfig.KeepPath = false
|
|
redirectConfig.Target = strings.TrimSuffix(params[1], "?")
|
|
}
|
|
if params[2] == "permanent" {
|
|
redirectConfig.Redirect = "301"
|
|
} else {
|
|
redirectConfig.Redirect = "302"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
case "error_page":
|
|
redirectConfig.Type = "404"
|
|
for _, errDir := range dirs {
|
|
if errDir.GetName() == "location" {
|
|
childDirs := errDir.GetBlock().GetDirectives()
|
|
for _, dir := range childDirs {
|
|
if dir.GetName() == "return" {
|
|
dirParams := dir.GetParameters()
|
|
if len(dirParams) > 1 {
|
|
redirectConfig.Redirect = dirParams[0]
|
|
if strings.HasSuffix(dirParams[1], "$request_uri") {
|
|
redirectConfig.KeepPath = true
|
|
redirectConfig.Target = strings.TrimSuffix(dirParams[1], "$request_uri")
|
|
redirectConfig.RedirectRoot = false
|
|
} else {
|
|
redirectConfig.KeepPath = false
|
|
redirectConfig.Target = dirParams[1]
|
|
redirectConfig.RedirectRoot = redirectConfig.Target == "/"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
res = append(res, redirectConfig)
|
|
}
|
|
return
|
|
}
|
|
|
|
func (w WebsiteService) UpdateRedirectFile(req request.NginxRedirectUpdate) (err error) {
|
|
var (
|
|
website model.Website
|
|
nginxFull dto.NginxFull
|
|
oldRewriteContent []byte
|
|
)
|
|
website, err = websiteRepo.GetFirst(commonRepo.WithByID(req.WebsiteID))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
nginxFull, err = getNginxFull(&website)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
includePath := fmt.Sprintf("/www/sites/%s/redirect/%s.conf", website.Alias, req.Name)
|
|
absolutePath := path.Join(nginxFull.Install.GetPath(), includePath)
|
|
fileOp := files.NewFileOp()
|
|
oldRewriteContent, err = fileOp.GetContent(absolutePath)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if err = fileOp.WriteFile(absolutePath, strings.NewReader(req.Content), 0755); err != nil {
|
|
return err
|
|
}
|
|
defer func() {
|
|
if err != nil {
|
|
_ = fileOp.WriteFile(absolutePath, bytes.NewReader(oldRewriteContent), 0755)
|
|
}
|
|
}()
|
|
return updateNginxConfig(constant.NginxScopeServer, nil, &website)
|
|
}
|
|
|
|
func (w WebsiteService) LoadWebsiteDirConfig(req request.WebsiteCommonReq) (*response.WebsiteDirConfig, error) {
|
|
website, err := websiteRepo.GetFirst(commonRepo.WithByID(req.ID))
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
res := &response.WebsiteDirConfig{}
|
|
nginxInstall, err := getAppInstallByKey(constant.AppOpenresty)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
absoluteIndexPath := path.Join(nginxInstall.GetPath(), "www", "sites", website.Alias, "index")
|
|
var appFs = afero.NewOsFs()
|
|
info, err := appFs.Stat(absoluteIndexPath)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
res.User = strconv.FormatUint(uint64(info.Sys().(*syscall.Stat_t).Uid), 10)
|
|
res.UserGroup = strconv.FormatUint(uint64(info.Sys().(*syscall.Stat_t).Gid), 10)
|
|
|
|
indexFiles, err := os.ReadDir(absoluteIndexPath)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
res.Dirs = []string{"/"}
|
|
for _, file := range indexFiles {
|
|
if !file.IsDir() || file.Name() == "node_modules" || file.Name() == "vendor" {
|
|
continue
|
|
}
|
|
res.Dirs = append(res.Dirs, fmt.Sprintf("/%s", file.Name()))
|
|
fileInfo, _ := file.Info()
|
|
if fileInfo.Sys().(*syscall.Stat_t).Uid != 1000 || fileInfo.Sys().(*syscall.Stat_t).Gid != 1000 {
|
|
res.Msg = i18n.GetMsgByKey("ErrPathPermission")
|
|
}
|
|
childFiles, _ := os.ReadDir(absoluteIndexPath + "/" + file.Name())
|
|
for _, childFile := range childFiles {
|
|
if !childFile.IsDir() {
|
|
continue
|
|
}
|
|
childInfo, _ := childFile.Info()
|
|
if childInfo.Sys().(*syscall.Stat_t).Uid != 1000 || childInfo.Sys().(*syscall.Stat_t).Gid != 1000 {
|
|
res.Msg = i18n.GetMsgByKey("ErrPathPermission")
|
|
}
|
|
res.Dirs = append(res.Dirs, fmt.Sprintf("/%s/%s", file.Name(), childFile.Name()))
|
|
}
|
|
}
|
|
|
|
return res, nil
|
|
}
|
|
|
|
func (w WebsiteService) GetDefaultHtml(resourceType string) (*response.WebsiteHtmlRes, error) {
|
|
nginxInstall, err := getAppInstallByKey(constant.AppOpenresty)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
rootPath := path.Join(nginxInstall.GetPath(), "root")
|
|
fileOp := files.NewFileOp()
|
|
defaultPath := path.Join(rootPath, "default")
|
|
if !fileOp.Stat(defaultPath) {
|
|
_ = fileOp.CreateDir(defaultPath, 0755)
|
|
}
|
|
|
|
res := &response.WebsiteHtmlRes{}
|
|
|
|
switch resourceType {
|
|
case "404":
|
|
resourcePath := path.Join(defaultPath, "404.html")
|
|
if content, _ := getResourceContent(fileOp, resourcePath); content != "" {
|
|
res.Content = content
|
|
return res, nil
|
|
}
|
|
res.Content = string(nginx_conf.NotFoundHTML)
|
|
return res, nil
|
|
case "php":
|
|
resourcePath := path.Join(defaultPath, "index.php")
|
|
if content, _ := getResourceContent(fileOp, resourcePath); content != "" {
|
|
res.Content = content
|
|
return res, nil
|
|
}
|
|
res.Content = string(nginx_conf.IndexPHP)
|
|
return res, nil
|
|
case "index":
|
|
resourcePath := path.Join(defaultPath, "index.html")
|
|
if content, _ := getResourceContent(fileOp, resourcePath); content != "" {
|
|
res.Content = content
|
|
return res, nil
|
|
}
|
|
res.Content = string(nginx_conf.Index)
|
|
return res, nil
|
|
case "domain404":
|
|
resourcePath := path.Join(rootPath, "404.html")
|
|
if content, _ := getResourceContent(fileOp, resourcePath); content != "" {
|
|
res.Content = content
|
|
return res, nil
|
|
}
|
|
res.Content = string(nginx_conf.DomainNotFoundHTML)
|
|
return res, nil
|
|
case "stop":
|
|
resourcePath := path.Join(rootPath, "stop", "index.html")
|
|
if content, _ := getResourceContent(fileOp, resourcePath); content != "" {
|
|
res.Content = content
|
|
return res, nil
|
|
}
|
|
res.Content = string(nginx_conf.StopHTML)
|
|
return res, nil
|
|
}
|
|
return res, nil
|
|
}
|
|
|
|
func (w WebsiteService) UpdateDefaultHtml(req request.WebsiteHtmlUpdate) error {
|
|
nginxInstall, err := getAppInstallByKey(constant.AppOpenresty)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
rootPath := path.Join(nginxInstall.GetPath(), "root")
|
|
fileOp := files.NewFileOp()
|
|
defaultPath := path.Join(rootPath, "default")
|
|
if !fileOp.Stat(defaultPath) {
|
|
_ = fileOp.CreateDir(defaultPath, 0755)
|
|
}
|
|
var resourcePath string
|
|
switch req.Type {
|
|
case "404":
|
|
resourcePath = path.Join(defaultPath, "404.html")
|
|
case "php":
|
|
resourcePath = path.Join(defaultPath, "index.php")
|
|
case "index":
|
|
resourcePath = path.Join(defaultPath, "index.html")
|
|
case "domain404":
|
|
resourcePath = path.Join(rootPath, "404.html")
|
|
case "stop":
|
|
resourcePath = path.Join(rootPath, "stop", "index.html")
|
|
default:
|
|
return nil
|
|
}
|
|
return fileOp.SaveFile(resourcePath, req.Content, 0644)
|
|
}
|
|
|
|
func (w WebsiteService) GetLoadBalances(id uint) ([]dto.NginxUpstream, error) {
|
|
website, err := websiteRepo.GetFirst(commonRepo.WithByID(id))
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
nginxInstall, err := getAppInstallByKey(constant.AppOpenresty)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
includeDir := path.Join(nginxInstall.GetPath(), "www", "sites", website.Alias, "upstream")
|
|
fileOp := files.NewFileOp()
|
|
if !fileOp.Stat(includeDir) {
|
|
return nil, nil
|
|
}
|
|
entries, err := os.ReadDir(includeDir)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
var res []dto.NginxUpstream
|
|
for _, entry := range entries {
|
|
if entry.IsDir() {
|
|
continue
|
|
}
|
|
name := entry.Name()
|
|
if !strings.HasSuffix(name, ".conf") {
|
|
continue
|
|
}
|
|
upstreamName := strings.TrimSuffix(name, ".conf")
|
|
upstream := dto.NginxUpstream{
|
|
Name: upstreamName,
|
|
}
|
|
upstreamPath := path.Join(includeDir, name)
|
|
content, err := fileOp.GetContent(upstreamPath)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
upstream.Content = string(content)
|
|
nginxParser, err := parser.NewParser(upstreamPath)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
config, err := nginxParser.Parse()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
upstreams := config.FindUpstreams()
|
|
for _, up := range upstreams {
|
|
if up.UpstreamName == upstreamName {
|
|
directives := up.GetDirectives()
|
|
for _, d := range directives {
|
|
dName := d.GetName()
|
|
if _, ok := dto.LBAlgorithms[dName]; ok {
|
|
upstream.Algorithm = dName
|
|
}
|
|
}
|
|
var servers []dto.NginxUpstreamServer
|
|
for _, ups := range up.UpstreamServers {
|
|
server := dto.NginxUpstreamServer{
|
|
Server: ups.Address,
|
|
}
|
|
parameters := ups.Parameters
|
|
if weight, ok := parameters["weight"]; ok {
|
|
num, err := strconv.Atoi(weight)
|
|
if err == nil {
|
|
server.Weight = num
|
|
}
|
|
}
|
|
if maxFails, ok := parameters["max_fails"]; ok {
|
|
num, err := strconv.Atoi(maxFails)
|
|
if err == nil {
|
|
server.MaxFails = num
|
|
}
|
|
}
|
|
if failTimeout, ok := parameters["fail_timeout"]; ok {
|
|
server.FailTimeout = failTimeout
|
|
}
|
|
if maxConns, ok := parameters["max_conns"]; ok {
|
|
num, err := strconv.Atoi(maxConns)
|
|
if err == nil {
|
|
server.MaxConns = num
|
|
}
|
|
}
|
|
for _, flag := range ups.Flags {
|
|
server.Flag = flag
|
|
}
|
|
servers = append(servers, server)
|
|
}
|
|
upstream.Servers = servers
|
|
}
|
|
}
|
|
res = append(res, upstream)
|
|
}
|
|
return res, nil
|
|
}
|
|
|
|
func (w WebsiteService) CreateLoadBalance(req request.WebsiteLBCreate) error {
|
|
website, err := websiteRepo.GetFirst(commonRepo.WithByID(req.WebsiteID))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
nginxInstall, err := getAppInstallByKey(constant.AppOpenresty)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
includeDir := path.Join(nginxInstall.GetPath(), "www", "sites", website.Alias, "upstream")
|
|
fileOp := files.NewFileOp()
|
|
if !fileOp.Stat(includeDir) {
|
|
_ = fileOp.CreateDir(includeDir, 0644)
|
|
}
|
|
filePath := path.Join(includeDir, fmt.Sprintf("%s.conf", req.Name))
|
|
if fileOp.Stat(filePath) {
|
|
return buserr.New(constant.ErrNameIsExist)
|
|
}
|
|
config, err := parser.NewStringParser(string(nginx_conf.Upstream)).Parse()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
config.Block = &components.Block{}
|
|
config.FilePath = filePath
|
|
upstream := components.Upstream{
|
|
UpstreamName: req.Name,
|
|
}
|
|
if req.Algorithm != "default" {
|
|
upstream.UpdateDirective(req.Algorithm, []string{})
|
|
}
|
|
|
|
servers := make([]*components.UpstreamServer, 0)
|
|
|
|
for _, server := range req.Servers {
|
|
upstreamServer := &components.UpstreamServer{
|
|
Address: server.Server,
|
|
}
|
|
parameters := make(map[string]string)
|
|
if server.Weight > 0 {
|
|
parameters["weight"] = strconv.Itoa(server.Weight)
|
|
}
|
|
if server.MaxFails > 0 {
|
|
parameters["max_fails"] = strconv.Itoa(server.MaxFails)
|
|
}
|
|
if server.FailTimeout != "" {
|
|
parameters["fail_timeout"] = server.FailTimeout
|
|
}
|
|
if server.MaxConns > 0 {
|
|
parameters["max_conns"] = strconv.Itoa(server.MaxConns)
|
|
}
|
|
if server.Flag != "" {
|
|
upstreamServer.Flags = []string{server.Flag}
|
|
}
|
|
upstreamServer.Parameters = parameters
|
|
servers = append(servers, upstreamServer)
|
|
}
|
|
upstream.UpstreamServers = servers
|
|
config.Block.Directives = append(config.Block.Directives, &upstream)
|
|
|
|
defer func() {
|
|
if err != nil {
|
|
_ = fileOp.DeleteFile(filePath)
|
|
}
|
|
}()
|
|
|
|
if err = nginx.WriteConfig(config, nginx.IndentedStyle); err != nil {
|
|
return buserr.WithErr(constant.ErrUpdateBuWebsite, err)
|
|
}
|
|
nginxInclude := fmt.Sprintf("/www/sites/%s/upstream/*.conf", website.Alias)
|
|
if err = updateNginxConfig("", []dto.NginxParam{{Name: "include", Params: []string{nginxInclude}}}, &website); err != nil {
|
|
return err
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (w WebsiteService) UpdateLoadBalance(req request.WebsiteLBUpdate) error {
|
|
website, err := websiteRepo.GetFirst(commonRepo.WithByID(req.WebsiteID))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
nginxInstall, err := getAppInstallByKey(constant.AppOpenresty)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
includeDir := path.Join(nginxInstall.GetPath(), "www", "sites", website.Alias, "upstream")
|
|
fileOp := files.NewFileOp()
|
|
filePath := path.Join(includeDir, fmt.Sprintf("%s.conf", req.Name))
|
|
if !fileOp.Stat(filePath) {
|
|
return nil
|
|
}
|
|
parser, err := parser.NewParser(filePath)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
config, err := parser.Parse()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
upstreams := config.FindUpstreams()
|
|
for _, up := range upstreams {
|
|
if up.UpstreamName == req.Name {
|
|
directives := up.GetDirectives()
|
|
for _, d := range directives {
|
|
dName := d.GetName()
|
|
if _, ok := dto.LBAlgorithms[dName]; ok {
|
|
up.RemoveDirective(dName, nil)
|
|
}
|
|
}
|
|
if req.Algorithm != "default" {
|
|
up.UpdateDirective(req.Algorithm, []string{})
|
|
}
|
|
var servers []*components.UpstreamServer
|
|
for _, server := range req.Servers {
|
|
upstreamServer := &components.UpstreamServer{
|
|
Address: server.Server,
|
|
}
|
|
parameters := make(map[string]string)
|
|
if server.Weight > 0 {
|
|
parameters["weight"] = strconv.Itoa(server.Weight)
|
|
}
|
|
if server.MaxFails > 0 {
|
|
parameters["max_fails"] = strconv.Itoa(server.MaxFails)
|
|
}
|
|
if server.FailTimeout != "" {
|
|
parameters["fail_timeout"] = server.FailTimeout
|
|
}
|
|
if server.MaxConns > 0 {
|
|
parameters["max_conns"] = strconv.Itoa(server.MaxConns)
|
|
}
|
|
if server.Flag != "" {
|
|
upstreamServer.Flags = []string{server.Flag}
|
|
}
|
|
upstreamServer.Parameters = parameters
|
|
servers = append(servers, upstreamServer)
|
|
}
|
|
up.UpstreamServers = servers
|
|
}
|
|
}
|
|
if err = nginx.WriteConfig(config, nginx.IndentedStyle); err != nil {
|
|
return buserr.WithErr(constant.ErrUpdateBuWebsite, err)
|
|
}
|
|
if err = opNginx(nginxInstall.ContainerName, constant.NginxReload); err != nil {
|
|
return err
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (w WebsiteService) DeleteLoadBalance(req request.WebsiteLBDelete) error {
|
|
website, err := websiteRepo.GetFirst(commonRepo.WithByID(req.WebsiteID))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
nginxInstall, err := getAppInstallByKey(constant.AppOpenresty)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
includeDir := path.Join(nginxInstall.GetPath(), "www", "sites", website.Alias, "upstream")
|
|
fileOp := files.NewFileOp()
|
|
filePath := path.Join(includeDir, fmt.Sprintf("%s.conf", req.Name))
|
|
if !fileOp.Stat(filePath) {
|
|
return nil
|
|
}
|
|
if err = fileOp.DeleteFile(filePath); err != nil {
|
|
return err
|
|
}
|
|
return opNginx(nginxInstall.ContainerName, constant.NginxReload)
|
|
}
|
|
|
|
func (w WebsiteService) UpdateLoadBalanceFile(req request.WebsiteLBUpdateFile) error {
|
|
website, err := websiteRepo.GetFirst(commonRepo.WithByID(req.WebsiteID))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
nginxInstall, err := getAppInstallByKey(constant.AppOpenresty)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
includeDir := path.Join(nginxInstall.GetPath(), "www", "sites", website.Alias, "upstream")
|
|
filePath := path.Join(includeDir, fmt.Sprintf("%s.conf", req.Name))
|
|
fileOp := files.NewFileOp()
|
|
oldContent, err := fileOp.GetContent(filePath)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if err = fileOp.WriteFile(filePath, strings.NewReader(req.Content), 0755); err != nil {
|
|
return err
|
|
}
|
|
defer func() {
|
|
if err != nil {
|
|
_ = fileOp.WriteFile(filePath, bytes.NewReader(oldContent), 0755)
|
|
}
|
|
}()
|
|
return opNginx(nginxInstall.ContainerName, constant.NginxReload)
|
|
}
|