From 9114df9c2a7130d543e9fd601f648d28d9c259a0 Mon Sep 17 00:00:00 2001 From: zhengkunwang <31820853+zhengkunwang223@users.noreply.github.com> Date: Fri, 9 Aug 2024 18:00:39 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E7=BD=91=E7=AB=99=E5=AF=86=E7=A0=81?= =?UTF-8?q?=E8=AE=A4=E8=AF=81=E6=94=AF=E6=8C=81=E5=AD=90=E7=9B=AE=E5=BD=95?= =?UTF-8?q?=20(#6078)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Refs https://github.com/1Panel-dev/1Panel/issues/5863 --- agent/app/api/v2/website.go | 41 ++++ agent/app/dto/nginx.go | 7 + agent/app/dto/request/nginx.go | 10 + agent/app/dto/response/nginx.go | 4 + agent/app/service/website.go | 187 +++++++++++++++--- agent/cmd/server/nginx_conf/nginx_conf.go | 3 + agent/cmd/server/nginx_conf/path_auth.conf | 4 + agent/router/ro_website.go | 2 + frontend/src/api/interface/website.ts | 13 ++ frontend/src/api/modules/website.ts | 8 + frontend/src/lang/modules/en.ts | 2 +- frontend/src/lang/modules/tw.ts | 2 +- frontend/src/lang/modules/zh.ts | 2 +- .../config/basic/auth-basic/create/index.vue | 56 ++++-- .../website/config/basic/auth-basic/index.vue | 131 +++++++++--- .../config/basic/proxy/create/index.vue | 3 +- 16 files changed, 407 insertions(+), 68 deletions(-) create mode 100644 agent/cmd/server/nginx_conf/path_auth.conf diff --git a/agent/app/api/v2/website.go b/agent/app/api/v2/website.go index 7241a6811..df4af1da4 100644 --- a/agent/app/api/v2/website.go +++ b/agent/app/api/v2/website.go @@ -643,6 +643,47 @@ func (b *BaseApi) UpdateAuthConfig(c *gin.Context) { helper.SuccessWithOutData(c) } +// @Tags Website +// @Summary Get AuthBasic conf +// @Description 获取路由密码访问配置 +// @Accept json +// @Param request body request.NginxAuthReq true "request" +// @Success 200 +// @Security ApiKeyAuth +// @Router /websites/auths/path [post] +func (b *BaseApi) GetPathAuthConfig(c *gin.Context) { + var req request.NginxAuthReq + if err := helper.CheckBindAndValidate(&req, c); err != nil { + return + } + res, err := websiteService.GetPathAuthBasics(req) + if err != nil { + helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err) + return + } + helper.SuccessWithData(c, res) +} + +// @Tags Website +// @Summary Get AuthBasic conf +// @Description 更新路由密码访问配置 +// @Accept json +// @Param request body request.NginxPathAuthUpdate true "request" +// @Success 200 +// @Security ApiKeyAuth +// @Router /websites/auths/path/update [post] +func (b *BaseApi) UpdatePathAuthConfig(c *gin.Context) { + var req request.NginxPathAuthUpdate + if err := helper.CheckBindAndValidate(&req, c); err != nil { + return + } + if err := websiteService.UpdatePathAuthBasic(req); err != nil { + helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err) + return + } + helper.SuccessWithOutData(c) +} + // @Tags Website // @Summary Get AntiLeech conf // @Description 获取防盗链配置 diff --git a/agent/app/dto/nginx.go b/agent/app/dto/nginx.go index 422c2d9f9..129f6ecfe 100644 --- a/agent/app/dto/nginx.go +++ b/agent/app/dto/nginx.go @@ -33,6 +33,13 @@ type NginxAuth struct { Remark string `json:"remark"` } +type NginxPathAuth struct { + Username string `json:"username"` + Remark string `json:"remark"` + Path string `json:"path"` + Name string `json:"name"` +} + type NginxKey string const ( diff --git a/agent/app/dto/request/nginx.go b/agent/app/dto/request/nginx.go index 3cdc15ec4..e6c77bf8a 100644 --- a/agent/app/dto/request/nginx.go +++ b/agent/app/dto/request/nginx.go @@ -44,6 +44,16 @@ type NginxAuthUpdate struct { Remark string `json:"remark"` } +type NginxPathAuthUpdate struct { + WebsiteID uint `json:"websiteID" validate:"required"` + Operate string `json:"operate" validate:"required"` + Name string `json:"name"` + Username string `json:"username"` + Password string `json:"password"` + Path string `json:"path"` + Remark string `json:"remark"` +} + type NginxAuthReq struct { WebsiteID uint `json:"websiteID" validate:"required"` } diff --git a/agent/app/dto/response/nginx.go b/agent/app/dto/response/nginx.go index e7d787787..e05b6ed9d 100644 --- a/agent/app/dto/response/nginx.go +++ b/agent/app/dto/response/nginx.go @@ -22,6 +22,10 @@ type NginxAuthRes struct { Items []dto.NginxAuth `json:"items"` } +type NginxPathAuthRes struct { + dto.NginxPathAuth +} + type NginxAntiLeechRes struct { Enable bool `json:"enable"` Extends string `json:"extends"` diff --git a/agent/app/service/website.go b/agent/app/service/website.go index 3dd058b42..c2ddef28b 100644 --- a/agent/app/service/website.go +++ b/agent/app/service/website.go @@ -89,17 +89,23 @@ type IWebsiteService interface { 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) - GetAuthBasics(req request.NginxAuthReq) (res response.NginxAuthRes, err error) - UpdateAuthBasic(req request.NginxAuthUpdate) (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) } @@ -1935,6 +1941,50 @@ func (w WebsiteService) UpdateProxyFile(req request.NginxProxyUpdate) (err error 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 @@ -2064,12 +2114,11 @@ func (w WebsiteService) UpdateAuthBasic(req request.NginxAuthUpdate) (err error) return } -func (w WebsiteService) GetAuthBasics(req request.NginxAuthReq) (res response.NginxAuthRes, err error) { +func (w WebsiteService) GetPathAuthBasics(req request.NginxAuthReq) (res []response.NginxPathAuthRes, 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 { @@ -2079,35 +2128,127 @@ func (w WebsiteService) GetAuthBasics(req request.NginxAuthReq) (res response.Ng 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) { + 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 } - nginxParams, err = getNginxParamsByKeys(constant.NginxScopeServer, []string{"auth_basic"}, &website) + + entries, err := os.ReadDir(absoluteAuthDir) if err != nil { - return + return nil, err } - 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 + + 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, + }) } - 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) 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 { diff --git a/agent/cmd/server/nginx_conf/nginx_conf.go b/agent/cmd/server/nginx_conf/nginx_conf.go index 7b376a9b0..abee3b724 100644 --- a/agent/cmd/server/nginx_conf/nginx_conf.go +++ b/agent/cmd/server/nginx_conf/nginx_conf.go @@ -37,3 +37,6 @@ var DomainNotFoundHTML []byte //go:embed stop.html var StopHTML []byte + +//go:embed path_auth.conf +var PathAuth []byte diff --git a/agent/cmd/server/nginx_conf/path_auth.conf b/agent/cmd/server/nginx_conf/path_auth.conf new file mode 100644 index 000000000..38e75566f --- /dev/null +++ b/agent/cmd/server/nginx_conf/path_auth.conf @@ -0,0 +1,4 @@ +location ~* ^/test* { + auth_basic "Authorization"; + auth_basic_user_file /www/site/pass/ceshi.pass ; +} \ No newline at end of file diff --git a/agent/router/ro_website.go b/agent/router/ro_website.go index 4554d770a..0e49bfbfb 100644 --- a/agent/router/ro_website.go +++ b/agent/router/ro_website.go @@ -56,6 +56,8 @@ func (a *WebsiteRouter) InitRouter(Router *gin.RouterGroup) { websiteRouter.POST("/auths", baseApi.GetAuthConfig) websiteRouter.POST("/auths/update", baseApi.UpdateAuthConfig) + websiteRouter.POST("/auths/path", baseApi.GetPathAuthConfig) + websiteRouter.POST("/auths/path/update", baseApi.UpdatePathAuthConfig) websiteRouter.POST("/leech", baseApi.GetAntiLeech) websiteRouter.POST("/leech/update", baseApi.UpdateAntiLeech) diff --git a/frontend/src/api/interface/website.ts b/frontend/src/api/interface/website.ts index 8e2e1e371..ed09aa84f 100644 --- a/frontend/src/api/interface/website.ts +++ b/frontend/src/api/interface/website.ts @@ -393,6 +393,7 @@ export namespace Website { content?: string; proxyAddress?: string; proxyProtocol?: string; + sni?: boolean; } export interface ProxReplace { @@ -425,6 +426,18 @@ export namespace Website { username: string; password: string; remark: string; + scope: string; + path?: ''; + name?: ''; + } + + export interface NginxPathAuthConfig { + websiteID: number; + operate: string; + path: string; + username: string; + password: string; + name: string; } export interface LeechConfig { diff --git a/frontend/src/api/modules/website.ts b/frontend/src/api/modules/website.ts index 750df38b1..416f457fc 100644 --- a/frontend/src/api/modules/website.ts +++ b/frontend/src/api/modules/website.ts @@ -210,6 +210,14 @@ export const OperateAuthConfig = (req: Website.NginxAuthConfig) => { return http.post(`/websites/auths/update`, req); }; +export const GetPathAuthConfig = (req: Website.AuthReq) => { + return http.post(`/websites/auths/path`, req); +}; + +export const OperatePathAuthConfig = (req: Website.NginxPathAuthConfig) => { + return http.post(`/websites/auths/path/update`, req); +}; + export const GetAntiLeech = (req: Website.LeechReq) => { return http.post(`/websites/leech`, req); }; diff --git a/frontend/src/lang/modules/en.ts b/frontend/src/lang/modules/en.ts index 2641b7040..8736d4e5e 100644 --- a/frontend/src/lang/modules/en.ts +++ b/frontend/src/lang/modules/en.ts @@ -2056,7 +2056,6 @@ const message = { proxyHelper1: 'When accessing this directory, the content of the target URL will be returned and displayed', proxyPassHelper: 'The proxied site must be a valid and accessible URL', proxyHostHelper: 'Pass the domain name in the request header to the proxy server', - replacementHelper: 'Up to 5 replacements can be added, please leave blank if no replacement is required', modifier: 'Matching Rules', modifierHelper: 'Example: = exact match, ~ regular match, ^~ match the beginning of the path, etc', replace: 'Text Replacement', @@ -2134,6 +2133,7 @@ const message = { generateDomain: 'Generate', domainSSLHelper: 'Enabling SSL on a non-443 port will cause the 443 port to stop listening. If you need the 443 port to continue listening, please add the domain:443', + global: 'Global', }, php: { short_open_tag: 'Short tag support', diff --git a/frontend/src/lang/modules/tw.ts b/frontend/src/lang/modules/tw.ts index d18ffa652..50cb9a769 100644 --- a/frontend/src/lang/modules/tw.ts +++ b/frontend/src/lang/modules/tw.ts @@ -1912,7 +1912,6 @@ const message = { proxyHelper1: '訪問這個目錄時將會把目標URL的內容返回並顯示', proxyPassHelper: '代理的站點,必須為可正常訪問的URL', proxyHostHelper: '將域名添加到請求頭傳遞到代理服務器', - replacementHelper: '最多可以添加5條替換內容,如果不需要替換請留空', modifier: '匹配規則', modifierHelper: '例:= 精確匹配,~ 正則匹配,^~ 匹配路徑開頭 等', replace: '文本替換', @@ -1983,6 +1982,7 @@ const message = { batchAdd: '批量添加域名', generateDomain: '生成', domainSSLHelper: '非 443 端口開啟 SSL 會導致 443 端口移除監聽,如需 443 端口繼續監聽,請添加域名:443', + global: '全局', }, php: { short_open_tag: '短標簽支持', diff --git a/frontend/src/lang/modules/zh.ts b/frontend/src/lang/modules/zh.ts index 3051cd449..316b35d8e 100644 --- a/frontend/src/lang/modules/zh.ts +++ b/frontend/src/lang/modules/zh.ts @@ -1914,7 +1914,6 @@ const message = { proxyHelper1: '访问这个目录时将会把目标URL的内容返回并显示', proxyPassHelper: '代理的站点,必须为可正常访问的URL', proxyHostHelper: '将域名添加到请求头传递到代理服务器', - replacementHelper: '最多可以添加5条替换内容,如果不需要替换请留空', modifier: '匹配规则', modifierHelper: '例:= 精确匹配,~ 正则匹配,^~ 匹配路径开头 等', replace: '文本替换', @@ -1985,6 +1984,7 @@ const message = { batchAdd: '批量添加域名', generateDomain: '生成', domainSSLHelper: '非 443 端口开启 SSL 会导致 443 端口去掉监听,如需 443 端口继续监听,请添加域名:443', + global: '全局', }, php: { short_open_tag: '短标签支持', diff --git a/frontend/src/views/website/website/config/basic/auth-basic/create/index.vue b/frontend/src/views/website/website/config/basic/auth-basic/create/index.vue index 056e92b66..ba2fe3774 100644 --- a/frontend/src/views/website/website/config/basic/auth-basic/create/index.vue +++ b/frontend/src/views/website/website/config/basic/auth-basic/create/index.vue @@ -20,8 +20,17 @@ /> + + + + + + - + @@ -51,7 +60,7 @@ diff --git a/frontend/src/views/website/website/config/basic/proxy/create/index.vue b/frontend/src/views/website/website/config/basic/proxy/create/index.vue index 407afcdb9..0100be0b6 100644 --- a/frontend/src/views/website/website/config/basic/proxy/create/index.vue +++ b/frontend/src/views/website/website/config/basic/proxy/create/index.vue @@ -99,7 +99,7 @@ - + {{ $t('website.addReplace') }}
@@ -159,6 +159,7 @@ const initData = (): Website.ProxyConfig => ({ replaces: {}, proxyAddress: '', proxyProtocol: 'http://', + sni: false, }); let proxy = ref(initData()); const replaces = ref([]);