package nginx import ( "fmt" "slices" "strings" "github.com/tufanbarisyildirim/gonginx/config" ) func (p *Parser) SetListen(listen [][]string) error { var directives []*config.Directive for _, l := range listen { directives = append(directives, &config.Directive{ Name: "listen", Parameters: l, }) } if err := p.Clear("server.listen"); err != nil { return err } return p.Set("server", directives) } func (p *Parser) SetServerName(serverName []string) error { if err := p.Clear("server.server_name"); err != nil { return err } return p.Set("server", []*config.Directive{ { Name: "server_name", Parameters: serverName, }, }) } func (p *Parser) SetIndex(index []string) error { if err := p.Clear("server.index"); err != nil { return err } return p.Set("server", []*config.Directive{ { Name: "index", Parameters: index, }, }) } func (p *Parser) SetIndexWithComment(index []string, comment []string) error { if err := p.Clear("server.index"); err != nil { return err } return p.Set("server", []*config.Directive{ { Name: "index", Parameters: index, Comment: comment, }, }) } func (p *Parser) SetRoot(root string) error { if err := p.Clear("server.root"); err != nil { return err } return p.Set("server", []*config.Directive{ { Name: "root", Parameters: []string{root}, }, }) } func (p *Parser) SetRootWithComment(root string, comment []string) error { if err := p.Clear("server.root"); err != nil { return err } return p.Set("server", []*config.Directive{ { Name: "root", Parameters: []string{root}, Comment: comment, }, }) } func (p *Parser) SetIncludes(includes []string, comments [][]string) error { if err := p.Clear("server.include"); err != nil { return err } var directives []*config.Directive for i, item := range includes { var comment []string if i < len(comments) { comment = comments[i] } directives = append(directives, &config.Directive{ Name: "include", Parameters: []string{item}, Comment: comment, }) } return p.Set("server", directives) } func (p *Parser) SetPHP(php int) error { old, err := p.Find("server.include") if err != nil { return err } if err = p.Clear("server.include"); err != nil { return err } var directives []*config.Directive var foundFlag bool for _, item := range old { // 查找enable-php的配置 if slices.ContainsFunc(item.GetParameters(), func(s string) bool { return strings.HasPrefix(s, "enable-php-") && strings.HasSuffix(s, ".conf") }) { foundFlag = true directives = append(directives, &config.Directive{ Name: item.GetName(), Parameters: []string{fmt.Sprintf("enable-php-%d.conf", php)}, Comment: item.GetComment(), }) } else { // 其余的原样保留 directives = append(directives, &config.Directive{ Name: item.GetName(), Parameters: item.GetParameters(), Comment: item.GetComment(), }) } } // 如果没有找到enable-php的配置,直接添加一个 if !foundFlag { directives = append(directives, &config.Directive{ Name: "include", Parameters: []string{fmt.Sprintf("enable-php-%d.conf", php)}, }) } return p.Set("server", directives) } func (p *Parser) ClearSetHTTPS() error { if err := p.Clear("server.ssl_certificate"); err != nil { return err } if err := p.Clear("server.ssl_certificate_key"); err != nil { return err } if err := p.Clear("server.ssl_session_timeout"); err != nil { return err } if err := p.Clear("server.ssl_session_cache"); err != nil { return err } if err := p.Clear("server.ssl_protocols"); err != nil { return err } if err := p.Clear("server.ssl_ciphers"); err != nil { return err } if err := p.Clear("server.ssl_prefer_server_ciphers"); err != nil { return err } if err := p.Clear("server.ssl_early_data"); err != nil { return err } return nil } func (p *Parser) SetHTTPS(cert, key string) error { if err := p.ClearSetHTTPS(); err != nil { return err } return p.Set("server", []*config.Directive{ { Name: "ssl_certificate", Parameters: []string{cert}, }, { Name: "ssl_certificate_key", Parameters: []string{key}, }, { Name: "ssl_session_timeout", Parameters: []string{"1d"}, }, { Name: "ssl_session_cache", Parameters: []string{"shared:SSL:10m"}, }, { Name: "ssl_protocols", Parameters: []string{"TLSv1.2", "TLSv1.3"}, }, { Name: "ssl_ciphers", Parameters: []string{"ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-CHACHA20-POLY1305"}, }, { Name: "ssl_prefer_server_ciphers", Parameters: []string{"off"}, }, { Name: "ssl_early_data", Parameters: []string{"on"}, }, }) } func (p *Parser) SetHTTPSProtocols(protocols []string) error { if err := p.Clear("server.ssl_protocols"); err != nil { return err } return p.Set("server", []*config.Directive{ { Name: "ssl_protocols", Parameters: protocols, }, }) } func (p *Parser) SetHTTPSCiphers(ciphers string) error { if err := p.Clear("server.ssl_ciphers"); err != nil { return err } return p.Set("server", []*config.Directive{ { Name: "ssl_ciphers", Parameters: []string{ciphers}, }, }) } func (p *Parser) SetOCSP(ocsp bool) error { if err := p.Clear("server.ssl_stapling"); err != nil { return err } if err := p.Clear("server.ssl_stapling_verify"); err != nil { return err } if ocsp { return p.Set("server", []*config.Directive{ { Name: "ssl_stapling", Parameters: []string{"on"}, }, { Name: "ssl_stapling_verify", Parameters: []string{"on"}, }, }) } return nil } func (p *Parser) SetHSTS(hsts bool) error { old, err := p.Find("server.add_header") if err != nil { return err } if err = p.Clear("server.add_header"); err != nil { return err } var directives []*config.Directive var foundFlag bool for _, dir := range old { if slices.Contains(dir.GetParameters(), "Strict-Transport-Security") { foundFlag = true if hsts { directives = append(directives, &config.Directive{ Name: dir.GetName(), Parameters: []string{"Strict-Transport-Security", "max-age=31536000"}, Comment: dir.GetComment(), }) } } else { directives = append(directives, &config.Directive{ Name: dir.GetName(), Parameters: dir.GetParameters(), Comment: dir.GetComment(), }) } } if !foundFlag && hsts { directives = append(directives, &config.Directive{ Name: "add_header", Parameters: []string{"Strict-Transport-Security", "max-age=31536000"}, }) } return p.Set("server", directives) } func (p *Parser) SetHTTPRedirect(httpRedirect bool) error { // if 重定向 ifs, err := p.Find("server.if") if err != nil { return err } if err = p.Clear("server.if"); err != nil { return err } var directives []*config.Directive var foundFlag bool for _, dir := range ifs { // 所有 if var ifDirectives []config.IDirective for _, dir2 := range dir.GetBlock().GetDirectives() { // 每个 if 中所有指令 if !httpRedirect { // 不启用http重定向,则判断并移除特定的return指令 if dir2.GetName() != "return" && !slices.Contains(dir2.GetParameters(), "https://$host$request_uri") { ifDirectives = append(ifDirectives, dir2) } } else { // 启用http重定向,需要检查防止重复添加 if dir2.GetName() == "return" && slices.Contains(dir2.GetParameters(), "https://$host$request_uri") { foundFlag = true } ifDirectives = append(ifDirectives, dir2) } } // 写回 if 指令 if block, ok := dir.GetBlock().(*config.Block); ok { block.Directives = ifDirectives } directives = append(directives, &config.Directive{ Block: dir.GetBlock(), Name: dir.GetName(), Parameters: dir.GetParameters(), Comment: dir.GetComment(), }) } if !foundFlag && httpRedirect { ifDir := &config.Directive{ Name: "if", Block: &config.Block{}, Parameters: []string{"($scheme", "=", "http)"}, } redirectDir := &config.Directive{ Name: "return", Parameters: []string{"308", "https://$host$request_uri"}, } redirectDir.SetParent(ifDir.GetBlock()) ifBlock := ifDir.GetBlock().(*config.Block) ifBlock.Directives = append(ifBlock.Directives, redirectDir) directives = append(directives, ifDir) } if err = p.Set("server", directives); err != nil { return err } // error_page 497 重定向 directives = nil errorPages, err := p.Find("server.error_page") if err != nil { return err } if err = p.Clear("server.error_page"); err != nil { return err } var found497 bool for _, dir := range errorPages { if !httpRedirect { // 不启用https重定向,则判断并移除特定的return指令 if !slices.Contains(dir.GetParameters(), "497") && !slices.Contains(dir.GetParameters(), "https://$host:$server_port$request_uri") { directives = append(directives, &config.Directive{ Block: dir.GetBlock(), Name: dir.GetName(), Parameters: dir.GetParameters(), Comment: dir.GetComment(), }) } } else { // 启用https重定向,需要检查防止重复添加 if slices.Contains(dir.GetParameters(), "497") && slices.Contains(dir.GetParameters(), "https://$host:$server_port$request_uri") { found497 = true } directives = append(directives, &config.Directive{ Block: dir.GetBlock(), Name: dir.GetName(), Parameters: dir.GetParameters(), Comment: dir.GetComment(), }) } } if !found497 && httpRedirect { directives = append(directives, &config.Directive{ Name: "error_page", Parameters: []string{"497", "=307", "https://$host:$server_port$request_uri"}, }) } return p.Set("server", directives) } func (p *Parser) SetAccessLog(accessLog string) error { if err := p.Clear("server.access_log"); err != nil { return err } return p.Set("server", []*config.Directive{ { Name: "access_log", Parameters: []string{accessLog}, }, }) } func (p *Parser) SetErrorLog(errorLog string) error { if err := p.Clear("server.error_log"); err != nil { return err } return p.Set("server", []*config.Directive{ { Name: "error_log", Parameters: []string{errorLog}, }, }) }