From 2507b8214ac1669d733cce5cff6f480fd42271dd Mon Sep 17 00:00:00 2001 From: pupilcc Date: Tue, 9 Jan 2024 23:04:25 +0800 Subject: [PATCH] feat: acme.sh support --- Dockerfile | 5 ++- internal/domain/ssl.go | 5 +++ internal/service/ssl_service.go | 4 +- main.go | 3 ++ middleware/acme.go | 76 +++++++++++++++++++++++++++++++++ web/ssl.go | 17 ++++++++ 6 files changed, 107 insertions(+), 3 deletions(-) create mode 100644 middleware/acme.go diff --git a/Dockerfile b/Dockerfile index aa41113..319e2cd 100644 --- a/Dockerfile +++ b/Dockerfile @@ -7,7 +7,10 @@ COPY . . RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o /go/bin/autossl . FROM alpine:latest -RUN apk --no-cache add ca-certificates + +RUN apk --no-cache add ca-certificates curl openssl +RUN curl https://get.acme.sh | sh + WORKDIR /root/ COPY --from=builder /go/bin/autossl . EXPOSE 1323 diff --git a/internal/domain/ssl.go b/internal/domain/ssl.go index 0829733..787837c 100644 --- a/internal/domain/ssl.go +++ b/internal/domain/ssl.go @@ -5,6 +5,11 @@ type Cert struct { Id string `json:"id"` } +type CertCommand struct { + Domain string `json:"domain"` + Algorithm string `json:"algorithm"` +} + type CertDTO struct { Name string `json:"name"` Id string `json:"id"` diff --git a/internal/service/ssl_service.go b/internal/service/ssl_service.go index 7ff7078..bb56f67 100644 --- a/internal/service/ssl_service.go +++ b/internal/service/ssl_service.go @@ -28,7 +28,7 @@ func AddCert(name string, certFile *multipart.FileHeader, keyFile *multipart.Fil id := util.GenerateID() - saveUuid(id, name) + SaveUuid(name, id) err := uploadFile(id, certFile, keyFile) if err != nil { @@ -78,7 +78,7 @@ func uploadFile(id string, certFile *multipart.FileHeader, keyFile *multipart.Fi return nil } -func saveUuid(id string, name string) { +func SaveUuid(name string, id string) { certs := GetCerts() if certs == nil { certs = []domain.Cert{{Name: name, Id: id}} diff --git a/main.go b/main.go index db28b48..5c9133b 100644 --- a/main.go +++ b/main.go @@ -40,6 +40,9 @@ func main() { // Logger e.Use(middleware.RequestLogger()) + // Init acme.sh + middleware.InitAcme() + // Start the service e.Logger.Fatal(e.Start(":1323")) } diff --git a/middleware/acme.go b/middleware/acme.go new file mode 100644 index 0000000..8299046 --- /dev/null +++ b/middleware/acme.go @@ -0,0 +1,76 @@ +package middleware + +import ( + "autossl/internal/service" + "go.uber.org/zap" + "os" + "os/exec" +) + +func InitAcme() { + ca() + email() + export() +} + +func ca() { + logger := GetLogger() + ca := os.Getenv("ACME_CA") + cmd := exec.Command("~/.acme.sh/acme.sh --set-default-ca --server", ca) + cmd.Stdout = os.Stdout + cmd.Stderr = os.Stdout + err := cmd.Start() + if err != nil { + logger.Error("cmd.Start() failed with %s\n", zap.String("error", err.Error())) + } +} + +func email() { + logger := GetLogger() + email := os.Getenv("ACME_EMAIL") + cmd := exec.Command("~/.acme.sh/acme.sh --update-account --email", email) + cmd.Stdout = os.Stdout + cmd.Stderr = os.Stdout + err := cmd.Start() + if err != nil { + logger.Error("cmd.Start() failed with %s\n", zap.String("error", err.Error())) + } +} + +func Issue(name string) { + logger := GetLogger() + produce := os.Getenv("ACME_PRODUCE") + alias := os.Getenv("ACME_ALIAS") + + cmd := exec.Command("~/.acme.sh/acme.sh --issue", "--dns", produce, "-d", name, "--challenge-alias", alias) + cmd.Stdout = os.Stdout + cmd.Stderr = os.Stdout + err := cmd.Start() + if err != nil { + logger.Error("cmd.Start() failed with %s\n", zap.String("error", err.Error())) + } +} + +func Install(name string, id string) { + logger := GetLogger() + cmd := exec.Command("~/.acme.sh/acme.sh --install-cert", "-d", name, "--key-file", service.CertPath+id+".key", "--fullchain-file", service.CertPath+id+".crt") + cmd.Stdout = os.Stdout + cmd.Stderr = os.Stdout + err := cmd.Start() + if err != nil { + logger.Error("cmd.Start() failed with %s\n", zap.String("error", err.Error())) + } +} + +func export() { + logger := GetLogger() + account := os.Getenv("ACME_ACCOUNT") + token := os.Getenv("ACME_TOKEN") + cmd := exec.Command("export CF_EMAIL=%s && export CF_KEY=%s", account, token) + cmd.Stdout = os.Stdout + cmd.Stderr = os.Stdout + err := cmd.Start() + if err != nil { + logger.Error("cmd.Start() failed with %s\n", zap.String("error", err.Error())) + } +} diff --git a/web/ssl.go b/web/ssl.go index 91e174e..1c7322c 100644 --- a/web/ssl.go +++ b/web/ssl.go @@ -2,8 +2,10 @@ package web import ( "autossl/common/response" + "autossl/common/util" "autossl/internal/domain" "autossl/internal/service" + "autossl/middleware" "fmt" "github.com/labstack/echo/v4" "net/http" @@ -16,6 +18,7 @@ func SSLRoutes(e *echo.Echo) { e.GET("/dl/:uuid", download) e.HEAD("/dl/:uuid", downloadHead) e.GET("/list", list) + e.POST("/generate", generate) } func upload(c echo.Context) error { @@ -80,3 +83,17 @@ func list(c echo.Context) error { _ = c.JSON(http.StatusOK, list) return nil } + +func generate(c echo.Context) error { + var certCommand *domain.CertCommand + if err := c.Bind(&certCommand); err != nil { + return err + } + + id := util.GenerateID() + middleware.Issue(certCommand.Domain) + middleware.Install(certCommand.Domain, id) + service.SaveUuid(certCommand.Domain, id) + + return nil +}