diff --git a/main.go b/main.go index 2f1332dd..1effefd9 100644 --- a/main.go +++ b/main.go @@ -3,10 +3,10 @@ package main import ( "context" "flag" - "github.com/0xJacky/Nginx-UI/model" - "github.com/0xJacky/Nginx-UI/router" - "github.com/0xJacky/Nginx-UI/settings" - "github.com/0xJacky/Nginx-UI/tool" + "github.com/0xJacky/Nginx-UI/server/model" + "github.com/0xJacky/Nginx-UI/server/router" + "github.com/0xJacky/Nginx-UI/server/settings" + tool2 "github.com/0xJacky/Nginx-UI/server/tool" "log" "net/http" "os/signal" @@ -31,9 +31,9 @@ func main() { Handler: router.InitRouter(), } - log.Printf("nginx config dir path: %s", tool.GetNginxConfPath("")) + log.Printf("nginx config dir path: %s", tool2.GetNginxConfPath("")) - go tool.AutoCert() + go tool2.AutoCert() // Initializing the server in a goroutine so that // it won't block the graceful shutdown handling below diff --git a/nginx-ui.service b/nginx-ui.service index 0ffcde15..9cd7c4a3 100644 --- a/nginx-ui.service +++ b/nginx-ui.service @@ -6,5 +6,6 @@ After=network.target [Service] Type=simple ExecStart=/usr/local/bin/nginx-ui -d /usr/local/etc/nginx-ui +Restart=on-failure TimeoutStopSec=5 -KillMode=mixed \ No newline at end of file +KillMode=mixed diff --git a/api/analytic.go b/server/api/analytic.go similarity index 100% rename from api/analytic.go rename to server/api/analytic.go diff --git a/api/api.go b/server/api/api.go similarity index 100% rename from api/api.go rename to server/api/api.go diff --git a/api/auth.go b/server/api/auth.go similarity index 96% rename from api/auth.go rename to server/api/auth.go index 6cf7a93a..b01ce0f1 100644 --- a/api/auth.go +++ b/server/api/auth.go @@ -1,7 +1,7 @@ package api import ( - "github.com/0xJacky/Nginx-UI/model" + "github.com/0xJacky/Nginx-UI/server/model" "github.com/gin-gonic/gin" "golang.org/x/crypto/bcrypt" "net/http" diff --git a/api/backup.go b/server/api/backup.go similarity index 90% rename from api/backup.go rename to server/api/backup.go index 0081649e..f27c1bde 100644 --- a/api/backup.go +++ b/server/api/backup.go @@ -1,7 +1,7 @@ package api import ( - "github.com/0xJacky/Nginx-UI/model" + "github.com/0xJacky/Nginx-UI/server/model" "github.com/gin-gonic/gin" "github.com/unknwon/com" "net/http" diff --git a/api/cert.go b/server/api/cert.go similarity index 89% rename from api/cert.go rename to server/api/cert.go index a43ab60f..02597195 100644 --- a/api/cert.go +++ b/server/api/cert.go @@ -2,7 +2,7 @@ package api import ( "encoding/json" - "github.com/0xJacky/Nginx-UI/tool" + tool2 "github.com/0xJacky/Nginx-UI/server/tool" "github.com/gin-gonic/gin" "github.com/gorilla/websocket" "log" @@ -13,7 +13,7 @@ import ( func CertInfo(c *gin.Context) { domain := c.Param("domain") - key := tool.GetCertInfo(domain) + key := tool2.GetCertInfo(domain) c.JSON(http.StatusOK, gin.H{ "subject_name": key.Subject.CommonName, @@ -55,7 +55,7 @@ func IssueCert(c *gin.Context) { if string(message) == "go" { var m []byte - err = tool.IssueCert(domain) + err = tool2.IssueCert(domain) if err != nil { m, err = json.Marshal(gin.H{ "status": "error", @@ -78,7 +78,7 @@ func IssueCert(c *gin.Context) { return } - sslCertificatePath := tool.GetNginxConfPath("ssl/" + domain + "/fullchain.cer") + sslCertificatePath := tool2.GetNginxConfPath("ssl/" + domain + "/fullchain.cer") _, err = os.Stat(sslCertificatePath) if err != nil { @@ -104,7 +104,7 @@ func IssueCert(c *gin.Context) { return } - sslCertificateKeyPath := tool.GetNginxConfPath("ssl/" + domain + "/" + domain + ".key") + sslCertificateKeyPath := tool2.GetNginxConfPath("ssl/" + domain + "/" + domain + ".key") _, err = os.Stat(sslCertificateKeyPath) if err != nil { diff --git a/api/config.go b/server/api/config.go similarity index 85% rename from api/config.go rename to server/api/config.go index 80c6e4e1..e1cf0720 100644 --- a/api/config.go +++ b/server/api/config.go @@ -1,7 +1,7 @@ package api import ( - "github.com/0xJacky/Nginx-UI/tool" + tool2 "github.com/0xJacky/Nginx-UI/server/tool" "github.com/gin-gonic/gin" "io/ioutil" "log" @@ -19,7 +19,7 @@ func GetConfigs(c *gin.Context) { "modify": "time", } - configFiles, err := ioutil.ReadDir(tool.GetNginxConfPath("/")) + configFiles, err := ioutil.ReadDir(tool2.GetNginxConfPath("/")) if err != nil { ErrHandler(c, err) @@ -40,7 +40,7 @@ func GetConfigs(c *gin.Context) { } } - configs = tool.Sort(orderBy, sort, mySort[orderBy], configs) + configs = tool2.Sort(orderBy, sort, mySort[orderBy], configs) c.JSON(http.StatusOK, gin.H{ "configs": configs, @@ -49,7 +49,7 @@ func GetConfigs(c *gin.Context) { func GetConfig(c *gin.Context) { name := c.Param("name") - path := filepath.Join(tool.GetNginxConfPath("/"), name) + path := filepath.Join(tool2.GetNginxConfPath("/"), name) content, err := ioutil.ReadFile(path) @@ -80,7 +80,7 @@ func AddConfig(c *gin.Context) { name := request.Name content := request.Content - path := filepath.Join(tool.GetNginxConfPath("/"), name) + path := filepath.Join(tool2.GetNginxConfPath("/"), name) log.Println(path) if _, err = os.Stat(path); err == nil { @@ -98,7 +98,7 @@ func AddConfig(c *gin.Context) { } } - output := tool.ReloadNginx() + output := tool2.ReloadNginx() if output != "" { c.JSON(http.StatusInternalServerError, gin.H{ @@ -126,7 +126,7 @@ func EditConfig(c *gin.Context) { ErrHandler(c, err) return } - path := filepath.Join(tool.GetNginxConfPath("/"), name) + path := filepath.Join(tool2.GetNginxConfPath("/"), name) content := request.Content origContent, err := ioutil.ReadFile(path) @@ -144,7 +144,7 @@ func EditConfig(c *gin.Context) { } } - output := tool.ReloadNginx() + output := tool2.ReloadNginx() if output != "" { c.JSON(http.StatusInternalServerError, gin.H{ diff --git a/api/domain.go b/server/api/domain.go similarity index 74% rename from api/domain.go rename to server/api/domain.go index 717ad347..e5352718 100644 --- a/api/domain.go +++ b/server/api/domain.go @@ -1,8 +1,8 @@ package api import ( - "github.com/0xJacky/Nginx-UI/model" - "github.com/0xJacky/Nginx-UI/tool" + "github.com/0xJacky/Nginx-UI/server/model" + tool2 "github.com/0xJacky/Nginx-UI/server/tool" "github.com/gin-gonic/gin" "io/ioutil" "net/http" @@ -20,14 +20,14 @@ func GetDomains(c *gin.Context) { "modify": "time", } - configFiles, err := ioutil.ReadDir(tool.GetNginxConfPath("sites-available")) + configFiles, err := ioutil.ReadDir(tool2.GetNginxConfPath("sites-available")) if err != nil { ErrHandler(c, err) return } - enabledConfig, err := ioutil.ReadDir(filepath.Join(tool.GetNginxConfPath("sites-enabled"))) + enabledConfig, err := ioutil.ReadDir(filepath.Join(tool2.GetNginxConfPath("sites-enabled"))) enabledConfigMap := make(map[string]bool) for i := range enabledConfig { @@ -53,7 +53,7 @@ func GetDomains(c *gin.Context) { } } - configs = tool.Sort(orderBy, sort, mySort[orderBy], configs) + configs = tool2.Sort(orderBy, sort, mySort[orderBy], configs) c.JSON(http.StatusOK, gin.H{ "configs": configs, @@ -62,10 +62,10 @@ func GetDomains(c *gin.Context) { func GetDomain(c *gin.Context) { name := c.Param("name") - path := filepath.Join(tool.GetNginxConfPath("sites-available"), name) + path := filepath.Join(tool2.GetNginxConfPath("sites-available"), name) enabled := true - if _, err := os.Stat(filepath.Join(tool.GetNginxConfPath("sites-enabled"), name)); os.IsNotExist(err) { + if _, err := os.Stat(filepath.Join(tool2.GetNginxConfPath("sites-enabled"), name)); os.IsNotExist(err) { enabled = false } @@ -98,7 +98,7 @@ func EditDomain(c *gin.Context) { name := c.Param("name") request := make(gin.H) err = c.BindJSON(&request) - path := filepath.Join(tool.GetNginxConfPath("sites-available"), name) + path := filepath.Join(tool2.GetNginxConfPath("sites-available"), name) err = ioutil.WriteFile(path, []byte(request["content"].(string)), 0644) if err != nil { @@ -106,10 +106,10 @@ func EditDomain(c *gin.Context) { return } - enabledConfigFilePath := filepath.Join(tool.GetNginxConfPath("sites-enabled"), name) + enabledConfigFilePath := filepath.Join(tool2.GetNginxConfPath("sites-enabled"), name) if _, err = os.Stat(enabledConfigFilePath); err == nil { // 测试配置文件 - err = tool.TestNginxConf(enabledConfigFilePath) + err = tool2.TestNginxConf(enabledConfigFilePath) if err != nil { c.JSON(http.StatusInternalServerError, gin.H{ "message": err.Error(), @@ -117,7 +117,7 @@ func EditDomain(c *gin.Context) { return } - output := tool.ReloadNginx() + output := tool2.ReloadNginx() if output != "" { c.JSON(http.StatusInternalServerError, gin.H{ @@ -131,8 +131,8 @@ func EditDomain(c *gin.Context) { } func EnableDomain(c *gin.Context) { - configFilePath := filepath.Join(tool.GetNginxConfPath("sites-available"), c.Param("name")) - enabledConfigFilePath := filepath.Join(tool.GetNginxConfPath("sites-enabled"), c.Param("name")) + configFilePath := filepath.Join(tool2.GetNginxConfPath("sites-available"), c.Param("name")) + enabledConfigFilePath := filepath.Join(tool2.GetNginxConfPath("sites-enabled"), c.Param("name")) _, err := os.Stat(configFilePath) @@ -149,7 +149,7 @@ func EnableDomain(c *gin.Context) { } // 测试配置文件,不通过则撤回启用 - err = tool.TestNginxConf(enabledConfigFilePath) + err = tool2.TestNginxConf(enabledConfigFilePath) if err != nil { _ = os.Remove(enabledConfigFilePath) c.JSON(http.StatusInternalServerError, gin.H{ @@ -158,7 +158,7 @@ func EnableDomain(c *gin.Context) { return } - output := tool.ReloadNginx() + output := tool2.ReloadNginx() if output != "" { c.JSON(http.StatusInternalServerError, gin.H{ @@ -173,7 +173,7 @@ func EnableDomain(c *gin.Context) { } func DisableDomain(c *gin.Context) { - enabledConfigFilePath := filepath.Join(tool.GetNginxConfPath("sites-enabled"), c.Param("name")) + enabledConfigFilePath := filepath.Join(tool2.GetNginxConfPath("sites-enabled"), c.Param("name")) _, err := os.Stat(enabledConfigFilePath) @@ -189,7 +189,7 @@ func DisableDomain(c *gin.Context) { return } - output := tool.ReloadNginx() + output := tool2.ReloadNginx() if output != "" { c.JSON(http.StatusInternalServerError, gin.H{ @@ -206,8 +206,8 @@ func DisableDomain(c *gin.Context) { func DeleteDomain(c *gin.Context) { var err error name := c.Param("name") - availablePath := filepath.Join(tool.GetNginxConfPath("sites-available"), name) - enabledPath := filepath.Join(tool.GetNginxConfPath("sites-enabled"), name) + availablePath := filepath.Join(tool2.GetNginxConfPath("sites-available"), name) + enabledPath := filepath.Join(tool2.GetNginxConfPath("sites-enabled"), name) if _, err = os.Stat(availablePath); os.IsNotExist(err) { c.JSON(http.StatusNotFound, gin.H{ diff --git a/api/install.go b/server/api/install.go similarity index 88% rename from api/install.go rename to server/api/install.go index 9452f8aa..9418507f 100644 --- a/api/install.go +++ b/server/api/install.go @@ -1,8 +1,8 @@ package api import ( - "github.com/0xJacky/Nginx-UI/model" - "github.com/0xJacky/Nginx-UI/settings" + model2 "github.com/0xJacky/Nginx-UI/server/model" + "github.com/0xJacky/Nginx-UI/server/settings" "github.com/gin-gonic/gin" "github.com/google/uuid" "golang.org/x/crypto/bcrypt" @@ -54,9 +54,9 @@ func InstallNginxUI(c *gin.Context) { return } - curd := model.NewCurd(&model.Auth{}) + curd := model2.NewCurd(&model2.Auth{}) pwd, _ := bcrypt.GenerateFromPassword([]byte(json.Password), bcrypt.DefaultCost) - err = curd.Add(&model.Auth{ + err = curd.Add(&model2.Auth{ Name: json.Username, Password: string(pwd), }) diff --git a/api/template.go b/server/api/template.go similarity index 93% rename from api/template.go rename to server/api/template.go index 8eaf9de5..2f3c1ec0 100644 --- a/api/template.go +++ b/server/api/template.go @@ -1,7 +1,7 @@ package api import ( - "github.com/0xJacky/Nginx-UI/settings" + "github.com/0xJacky/Nginx-UI/server/settings" "github.com/gin-gonic/gin" "io/ioutil" "net/http" diff --git a/api/user.go b/server/api/user.go similarity index 82% rename from api/user.go rename to server/api/user.go index e8885ad4..2fa451cf 100644 --- a/api/user.go +++ b/server/api/user.go @@ -2,7 +2,7 @@ package api import ( "errors" - "github.com/0xJacky/Nginx-UI/model" + model2 "github.com/0xJacky/Nginx-UI/server/model" "github.com/gin-gonic/gin" "github.com/spf13/cast" "golang.org/x/crypto/bcrypt" @@ -10,9 +10,9 @@ import ( ) func GetUsers(c *gin.Context) { - curd := model.NewCurd(&model.Auth{}) + curd := model2.NewCurd(&model2.Auth{}) - var list []model.Auth + var list []model2.Auth err := curd.GetList(&list) if err != nil { @@ -25,10 +25,10 @@ func GetUsers(c *gin.Context) { } func GetUser(c *gin.Context) { - curd := model.NewCurd(&model.Auth{}) + curd := model2.NewCurd(&model2.Auth{}) id := c.Param("id") - var user model.Auth + var user model2.Auth err := curd.First(&user, id) if err != nil { @@ -49,7 +49,7 @@ func AddUser(c *gin.Context) { if !ok { return } - curd := model.NewCurd(&model.Auth{}) + curd := model2.NewCurd(&model2.Auth{}) pwd, err := bcrypt.GenerateFromPassword([]byte(json.Password), bcrypt.DefaultCost) if err != nil { @@ -58,7 +58,7 @@ func AddUser(c *gin.Context) { } json.Password = string(pwd) - user := model.Auth{ + user := model2.Auth{ Name: json.Name, Password: json.Password, } @@ -80,9 +80,9 @@ func EditUser(c *gin.Context) { if !ok { return } - curd := model.NewCurd(&model.Auth{}) + curd := model2.NewCurd(&model2.Auth{}) - var user, edit model.Auth + var user, edit model2.Auth err := curd.First(&user, c.Param("id")) @@ -120,8 +120,8 @@ func DeleteUser(c *gin.Context) { ErrHandler(c, errors.New("不允许删除默认账户")) return } - curd := model.NewCurd(&model.Auth{}) - err := curd.Delete(&model.Auth{}, "id", id) + curd := model2.NewCurd(&model2.Auth{}) + err := curd.Delete(&model2.Auth{}, "id", id) if err != nil { ErrHandler(c, err) return diff --git a/model/auth.go b/server/model/auth.go similarity index 96% rename from model/auth.go rename to server/model/auth.go index a69d6618..e9f99b83 100644 --- a/model/auth.go +++ b/server/model/auth.go @@ -1,7 +1,7 @@ package model import ( - "github.com/0xJacky/Nginx-UI/settings" + "github.com/0xJacky/Nginx-UI/server/settings" "github.com/dgrijalva/jwt-go" "time" ) diff --git a/model/cert.go b/server/model/cert.go similarity index 100% rename from model/cert.go rename to server/model/cert.go diff --git a/model/config-backup.go b/server/model/config-backup.go similarity index 100% rename from model/config-backup.go rename to server/model/config-backup.go diff --git a/model/curd.go b/server/model/curd.go similarity index 100% rename from model/curd.go rename to server/model/curd.go diff --git a/model/log.go b/server/model/log.go similarity index 100% rename from model/log.go rename to server/model/log.go diff --git a/model/models.go b/server/model/models.go similarity index 94% rename from model/models.go rename to server/model/models.go index 8d3b8f53..27849185 100644 --- a/model/models.go +++ b/server/model/models.go @@ -1,7 +1,7 @@ package model import ( - "github.com/0xJacky/Nginx-UI/settings" + "github.com/0xJacky/Nginx-UI/server/settings" "gorm.io/driver/sqlite" "gorm.io/gorm" "gorm.io/gorm/logger" diff --git a/router/routers.go b/server/router/routers.go similarity index 59% rename from router/routers.go rename to server/router/routers.go index d26edaa6..9d4bb5d9 100644 --- a/router/routers.go +++ b/server/router/routers.go @@ -3,9 +3,9 @@ package router import ( "bufio" "encoding/base64" - "github.com/0xJacky/Nginx-UI/api" "github.com/0xJacky/Nginx-UI/frontend" - "github.com/0xJacky/Nginx-UI/model" + api2 "github.com/0xJacky/Nginx-UI/server/api" + "github.com/0xJacky/Nginx-UI/server/model" "github.com/gin-contrib/static" "github.com/gin-gonic/gin" "io/fs" @@ -87,46 +87,46 @@ func InitRouter() *gin.Engine { g := r.Group("/api") { - g.GET("install", api.InstallLockCheck) - g.POST("install", api.InstallNginxUI) + g.GET("install", api2.InstallLockCheck) + g.POST("install", api2.InstallNginxUI) - g.POST("/login", api.Login) - g.DELETE("/logout", api.Logout) + g.POST("/login", api2.Login) + g.DELETE("/logout", api2.Logout) g := g.Group("/", authRequired()) { - g.GET("/analytic", api.Analytic) + g.GET("/analytic", api2.Analytic) - g.GET("/users", api.GetUsers) - g.GET("/user/:id", api.GetUser) - g.POST("/user", api.AddUser) - g.POST("/user/:id", api.EditUser) - g.DELETE("/user/:id", api.DeleteUser) + g.GET("/users", api2.GetUsers) + g.GET("/user/:id", api2.GetUser) + g.POST("/user", api2.AddUser) + g.POST("/user/:id", api2.EditUser) + g.DELETE("/user/:id", api2.DeleteUser) - g.GET("domains", api.GetDomains) - g.GET("domain/:name", api.GetDomain) - g.POST("domain/:name", api.EditDomain) - g.POST("domain/:name/enable", api.EnableDomain) - g.POST("domain/:name/disable", api.DisableDomain) - g.DELETE("domain/:name", api.DeleteDomain) + g.GET("domains", api2.GetDomains) + g.GET("domain/:name", api2.GetDomain) + g.POST("domain/:name", api2.EditDomain) + g.POST("domain/:name/enable", api2.EnableDomain) + g.POST("domain/:name/disable", api2.DisableDomain) + g.DELETE("domain/:name", api2.DeleteDomain) - g.GET("configs", api.GetConfigs) - g.GET("config/:name", api.GetConfig) - g.POST("config", api.AddConfig) - g.POST("config/:name", api.EditConfig) + g.GET("configs", api2.GetConfigs) + g.GET("config/:name", api2.GetConfig) + g.POST("config", api2.AddConfig) + g.POST("config/:name", api2.EditConfig) - g.GET("backups", api.GetFileBackupList) - g.GET("backup/:id", api.GetFileBackup) + g.GET("backups", api2.GetFileBackupList) + g.GET("backup/:id", api2.GetFileBackup) - g.GET("template/:name", api.GetTemplate) + g.GET("template/:name", api2.GetTemplate) - g.GET("cert/issue/:domain", api.IssueCert) - g.GET("cert/:domain/info", api.CertInfo) + g.GET("cert/issue/:domain", api2.IssueCert) + g.GET("cert/:domain/info", api2.CertInfo) // 添加域名到自动续期列表 - g.POST("cert/:domain", api.AddDomainToAutoCert) + g.POST("cert/:domain", api2.AddDomainToAutoCert) // 从自动续期列表中删除域名 - g.DELETE("cert/:domain", api.RemoveDomainFromAutoCert) + g.DELETE("cert/:domain", api2.RemoveDomainFromAutoCert) } } diff --git a/settings/settings.go b/server/settings/settings.go similarity index 100% rename from settings/settings.go rename to server/settings/settings.go diff --git a/template/http-conf b/server/template/http-conf similarity index 100% rename from template/http-conf rename to server/template/http-conf diff --git a/template/https-conf b/server/template/https-conf similarity index 100% rename from template/https-conf rename to server/template/https-conf diff --git a/test/acme_test.go b/server/test/acme_test.go similarity index 96% rename from test/acme_test.go rename to server/test/acme_test.go index b73ed30d..d94d0780 100644 --- a/test/acme_test.go +++ b/server/test/acme_test.go @@ -2,7 +2,7 @@ package test import ( "fmt" - "github.com/0xJacky/Nginx-UI/tool" + "github.com/0xJacky/Nginx-UI/server/tool" "io/ioutil" "log" "os" diff --git a/test/analytic_test.go b/server/test/analytic_test.go similarity index 100% rename from test/analytic_test.go rename to server/test/analytic_test.go diff --git a/test/cert_test.go b/server/test/cert_test.go similarity index 93% rename from test/cert_test.go rename to server/test/cert_test.go index dc13e00b..b06a0efc 100644 --- a/test/cert_test.go +++ b/server/test/cert_test.go @@ -2,7 +2,7 @@ package test import ( "fmt" - "github.com/0xJacky/Nginx-UI/tool" + "github.com/0xJacky/Nginx-UI/server/tool" "log" "os" "os/exec" diff --git a/test/lego_test.go b/server/test/lego_test.go similarity index 100% rename from test/lego_test.go rename to server/test/lego_test.go diff --git a/test/nginx_test.go b/server/test/nginx_test.go similarity index 100% rename from test/nginx_test.go rename to server/test/nginx_test.go diff --git a/server/tool/cert.go b/server/tool/cert.go new file mode 100644 index 00000000..9d9049db --- /dev/null +++ b/server/tool/cert.go @@ -0,0 +1,169 @@ +package tool + +import ( + "crypto" + "crypto/ecdsa" + "crypto/elliptic" + "crypto/rand" + "crypto/tls" + "crypto/x509" + "github.com/0xJacky/Nginx-UI/server/model" + "github.com/0xJacky/Nginx-UI/server/settings" + "github.com/go-acme/lego/v4/certcrypto" + "github.com/go-acme/lego/v4/certificate" + "github.com/go-acme/lego/v4/challenge/http01" + "github.com/go-acme/lego/v4/lego" + "github.com/go-acme/lego/v4/registration" + "io" + "io/ioutil" + "log" + "net/http" + "os" + "path/filepath" + "time" +) + +// MyUser You'll need a user or account type that implements acme.User +type MyUser struct { + Email string + Registration *registration.Resource + key crypto.PrivateKey +} + +func (u *MyUser) GetEmail() string { + return u.Email +} +func (u MyUser) GetRegistration() *registration.Resource { + return u.Registration +} +func (u *MyUser) GetPrivateKey() crypto.PrivateKey { + return u.key +} + +func AutoCert() { + for { + log.Println("[AutoCert] Start") + autoCertList := model.GetAutoCertList() + for i := range autoCertList { + domain := autoCertList[i].Domain + key := GetCertInfo(domain) + // 未到一个月 + if time.Now().Before(key.NotBefore.AddDate(0, 1, 0)) { + continue + } + // 过一个月了 + err := IssueCert(domain) + if err != nil { + log.Println(err) + } + } + time.Sleep(1 * time.Hour) + } +} + +func GetCertInfo(domain string) (key *x509.Certificate) { + ts := &http.Transport{ + TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, + } + + client := &http.Client{Transport: ts} + + response, err := client.Get("https://" + domain) + + if err != nil { + return + } + + defer func(Body io.ReadCloser) { + err = Body.Close() + if err != nil { + log.Println(err) + return + } + }(response.Body) + + key = response.TLS.PeerCertificates[0] + + return +} + +func IssueCert(domain string) error { + // Create a user. New accounts need an email and private key to start. + privateKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) + if err != nil { + log.Println(err) + return err + } + + myUser := MyUser{ + Email: settings.ServerSettings.Email, + key: privateKey, + } + + config := lego.NewConfig(&myUser) + + //config.CADirURL = "https://acme-staging-v02.api.letsencrypt.org/directory" + config.Certificate.KeyType = certcrypto.RSA2048 + + // A client facilitates communication with the CA server. + client, err := lego.NewClient(config) + if err != nil { + log.Println(err) + return err + } + + err = client.Challenge.SetHTTP01Provider( + http01.NewProviderServer("", + settings.ServerSettings.HTTPChallengePort, + ), + ) + if err != nil { + log.Println(err) + return err + } + + // New users will need to register + reg, err := client.Registration.Register(registration.RegisterOptions{TermsOfServiceAgreed: true}) + if err != nil { + log.Println(err) + return err + } + myUser.Registration = reg + + request := certificate.ObtainRequest{ + Domains: []string{domain}, + Bundle: true, + } + certificates, err := client.Certificate.Obtain(request) + if err != nil { + log.Println(err) + return err + } + saveDir := GetNginxConfPath("ssl/" + domain) + if _, err := os.Stat(saveDir); os.IsNotExist(err) { + err = os.Mkdir(saveDir, 0755) + if err != nil { + log.Println("fail to create", saveDir) + return err + } + } + + // Each certificate comes back with the cert bytes, the bytes of the client's + // private key, and a certificate URL. SAVE THESE TO DISK. + err = ioutil.WriteFile(filepath.Join(saveDir, "fullchain.cer"), + certificates.Certificate, 0644) + if err != nil { + log.Println(err) + return err + } + err = ioutil.WriteFile(filepath.Join(saveDir, domain+".key"), + certificates.PrivateKey, 0644) + if err != nil { + log.Println(err) + return err + } + + ReloadNginx() + + return nil +} diff --git a/tool/config_list.go b/server/tool/config_list.go similarity index 100% rename from tool/config_list.go rename to server/tool/config_list.go diff --git a/tool/nginx.go b/server/tool/nginx.go similarity index 100% rename from tool/nginx.go rename to server/tool/nginx.go diff --git a/tool/cert.go b/tool/cert.go deleted file mode 100644 index 981f1e38..00000000 --- a/tool/cert.go +++ /dev/null @@ -1,169 +0,0 @@ -package tool - -import ( - "crypto" - "crypto/ecdsa" - "crypto/elliptic" - "crypto/rand" - "crypto/tls" - "crypto/x509" - "github.com/0xJacky/Nginx-UI/model" - "github.com/0xJacky/Nginx-UI/settings" - "github.com/go-acme/lego/v4/certcrypto" - "github.com/go-acme/lego/v4/certificate" - "github.com/go-acme/lego/v4/challenge/http01" - "github.com/go-acme/lego/v4/lego" - "github.com/go-acme/lego/v4/registration" - "io" - "io/ioutil" - "log" - "net/http" - "os" - "path/filepath" - "time" -) - -// MyUser You'll need a user or account type that implements acme.User -type MyUser struct { - Email string - Registration *registration.Resource - key crypto.PrivateKey -} - -func (u *MyUser) GetEmail() string { - return u.Email -} -func (u MyUser) GetRegistration() *registration.Resource { - return u.Registration -} -func (u *MyUser) GetPrivateKey() crypto.PrivateKey { - return u.key -} - -func AutoCert() { - for { - log.Println("[AutoCert] Start") - autoCertList := model.GetAutoCertList() - for i := range autoCertList { - domain := autoCertList[i].Domain - key := GetCertInfo(domain) - // 未到一个月 - if time.Now().Before(key.NotBefore.AddDate(0, 1, 0)) { - continue - } - // 过一个月了 - err := IssueCert(domain) - if err != nil { - log.Println(err) - } - } - time.Sleep(1 * time.Hour) - } -} - -func GetCertInfo(domain string) (key *x509.Certificate) { - ts := &http.Transport{ - TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, - } - - client := &http.Client{Transport: ts} - - response, err := client.Get("https://" + domain) - - if err != nil { - return - } - - defer func(Body io.ReadCloser) { - err = Body.Close() - if err != nil { - log.Println(err) - return - } - }(response.Body) - - key = response.TLS.PeerCertificates[0] - - return -} - -func IssueCert(domain string) error { - // Create a user. New accounts need an email and private key to start. - privateKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) - if err != nil { - log.Println(err) - return err - } - - myUser := MyUser{ - Email: settings.ServerSettings.Email, - key: privateKey, - } - - config := lego.NewConfig(&myUser) - - //config.CADirURL = "https://acme-staging-v02.api.letsencrypt.org/directory" - config.Certificate.KeyType = certcrypto.RSA2048 - - // A client facilitates communication with the CA server. - client, err := lego.NewClient(config) - if err != nil { - log.Println(err) - return err - } - - err = client.Challenge.SetHTTP01Provider( - http01.NewProviderServer("", - settings.ServerSettings.HTTPChallengePort, - ), - ) - if err != nil { - log.Println(err) - return err - } - - // New users will need to register - reg, err := client.Registration.Register(registration.RegisterOptions{TermsOfServiceAgreed: true}) - if err != nil { - log.Println(err) - return err - } - myUser.Registration = reg - - request := certificate.ObtainRequest{ - Domains: []string{domain}, - Bundle: true, - } - certificates, err := client.Certificate.Obtain(request) - if err != nil { - log.Println(err) - return err - } - saveDir := GetNginxConfPath("ssl/" + domain) - if _, err := os.Stat(saveDir); os.IsNotExist(err) { - err = os.Mkdir(saveDir, 0755) - if err != nil { - log.Println("fail to create", saveDir) - return err - } - } - - // Each certificate comes back with the cert bytes, the bytes of the client's - // private key, and a certificate URL. SAVE THESE TO DISK. - err = ioutil.WriteFile(filepath.Join(saveDir, "fullchain.cer"), - certificates.Certificate, 0644) - if err != nil { - log.Println(err) - return err - } - err = ioutil.WriteFile(filepath.Join(saveDir, domain+".key"), - certificates.PrivateKey, 0644) - if err != nil { - log.Println(err) - return err - } - - ReloadNginx() - - return nil -}