Compare commits
No commits in common. "8d063e13301ecfdef6e14f81480989c1caac975c" and "55d241b873b2e478fc4322e74aef51fe45c4cb67" have entirely different histories.
8d063e1330
...
55d241b873
174
src/acme-client.go
Normal file
174
src/acme-client.go
Normal file
|
@ -0,0 +1,174 @@
|
||||||
|
package src
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto"
|
||||||
|
"crypto/ecdsa"
|
||||||
|
"crypto/elliptic"
|
||||||
|
"crypto/rand"
|
||||||
|
"crypto/x509"
|
||||||
|
"encoding/json"
|
||||||
|
"encoding/pem"
|
||||||
|
"github.com/go-acme/lego/v4/certificate"
|
||||||
|
"github.com/go-acme/lego/v4/challenge"
|
||||||
|
"github.com/go-acme/lego/v4/lego"
|
||||||
|
"github.com/go-acme/lego/v4/log"
|
||||||
|
"github.com/go-acme/lego/v4/providers/dns/alidns"
|
||||||
|
"github.com/go-acme/lego/v4/registration"
|
||||||
|
"os"
|
||||||
|
"path"
|
||||||
|
"path/filepath"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Apply 申请证书
|
||||||
|
// domain: 申请的域名
|
||||||
|
func Apply(domain Domain) {
|
||||||
|
email, hosts, name := domain.Email, domain.Host, domain.Name
|
||||||
|
privateKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
acmeUser := &AcmeUser{
|
||||||
|
Email: email,
|
||||||
|
key: privateKey,
|
||||||
|
}
|
||||||
|
|
||||||
|
config := lego.NewConfig(acmeUser)
|
||||||
|
|
||||||
|
client, err := lego.NewClient(config)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
ali := appConfig.Provider.Ali
|
||||||
|
conf := alidns.NewDefaultConfig()
|
||||||
|
conf.RegionID = ali.RegionID
|
||||||
|
conf.APIKey = ali.APIKey
|
||||||
|
conf.SecretKey = ali.SecretKey
|
||||||
|
provider, err := alidns.NewDNSProviderConfig(conf)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
challenge := client.Challenge
|
||||||
|
err = challenge.SetDNS01Provider(provider)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
registrar := client.Registration
|
||||||
|
reg, err := registrar.Register(registration.RegisterOptions{TermsOfServiceAgreed: true})
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
acmeUser.Registration = reg
|
||||||
|
|
||||||
|
request := certificate.ObtainRequest{
|
||||||
|
Domains: hosts,
|
||||||
|
Bundle: true,
|
||||||
|
}
|
||||||
|
|
||||||
|
cert, err := client.Certificate.Obtain(request)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
saveCertFile(cert, name)
|
||||||
|
}
|
||||||
|
|
||||||
|
func getProvider() challenge.Provider {
|
||||||
|
config := GetAppConfig()
|
||||||
|
|
||||||
|
switch config.Use {
|
||||||
|
case "alidns":
|
||||||
|
return getAliProvider()
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
func getAliProvider() challenge.Provider {
|
||||||
|
ali := GetAppConfig().Provider.Ali
|
||||||
|
conf := alidns.NewDefaultConfig()
|
||||||
|
conf.RegionID = ali.RegionID
|
||||||
|
conf.APIKey = ali.APIKey
|
||||||
|
conf.SecretKey = ali.SecretKey
|
||||||
|
provider, err := alidns.NewDNSProviderConfig(conf)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
return provider
|
||||||
|
}
|
||||||
|
func getTencentProvider() challenge.Provider {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// saveCertFile 保存证书文件
|
||||||
|
func saveCertFile(cert *certificate.Resource, name string) {
|
||||||
|
dir := GetAppConfig().CertDir
|
||||||
|
dir = filepath.Join(dir, name)
|
||||||
|
_, err := os.Stat(dir)
|
||||||
|
if os.IsNotExist(err) {
|
||||||
|
err := os.MkdirAll(dir, 0755)
|
||||||
|
if err != nil {
|
||||||
|
log.Infof("创建目录 %s 失败", dir)
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
log.Infof("创建目录 %s", dir)
|
||||||
|
}
|
||||||
|
|
||||||
|
certBytes := cert.Certificate
|
||||||
|
err = os.WriteFile(path.Join(dir, CertFileName), certBytes, 0755)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("Failed to save certificate: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = os.WriteFile(path.Join(dir, KeyFileName), cert.PrivateKey, 0755)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("Failed to save private key: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
block, _ := pem.Decode(certBytes)
|
||||||
|
if block == nil {
|
||||||
|
log.Fatalf("Failed to decode PEM block")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
certParse, err := x509.ParseCertificate(block.Bytes)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("Failed to parse certificate: %v", err)
|
||||||
|
}
|
||||||
|
certInfo := CertInfo{
|
||||||
|
Cert: *cert,
|
||||||
|
Info: *certParse,
|
||||||
|
}
|
||||||
|
// 将 cert 转换为json格式并保存到文件中
|
||||||
|
certJson, err := json.Marshal(certInfo)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("Failed to marshal certificate: %v", err)
|
||||||
|
}
|
||||||
|
err = os.WriteFile(path.Join(dir, CertInfoFileName), certJson, 0644)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("Failed to save certificate info: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
type AcmeUser struct {
|
||||||
|
Email string
|
||||||
|
Registration *registration.Resource
|
||||||
|
key crypto.PrivateKey
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u AcmeUser) GetEmail() string {
|
||||||
|
return u.Email
|
||||||
|
}
|
||||||
|
func (u AcmeUser) GetRegistration() *registration.Resource {
|
||||||
|
return u.Registration
|
||||||
|
}
|
||||||
|
func (u AcmeUser) GetPrivateKey() crypto.PrivateKey {
|
||||||
|
return u.key
|
||||||
|
}
|
||||||
|
|
||||||
|
type CertInfo struct {
|
||||||
|
Cert certificate.Resource
|
||||||
|
Info x509.Certificate
|
||||||
|
}
|
|
@ -1,238 +0,0 @@
|
||||||
package acme
|
|
||||||
|
|
||||||
import (
|
|
||||||
"acme-mana/src/common"
|
|
||||||
"acme-mana/src/conf"
|
|
||||||
"crypto"
|
|
||||||
"crypto/ecdsa"
|
|
||||||
"crypto/elliptic"
|
|
||||||
"crypto/rand"
|
|
||||||
"crypto/x509"
|
|
||||||
"encoding/json"
|
|
||||||
"encoding/pem"
|
|
||||||
"github.com/go-acme/lego/v4/certificate"
|
|
||||||
"github.com/go-acme/lego/v4/challenge"
|
|
||||||
"github.com/go-acme/lego/v4/lego"
|
|
||||||
"github.com/go-acme/lego/v4/log"
|
|
||||||
"github.com/go-acme/lego/v4/providers/dns/alidns"
|
|
||||||
"github.com/go-acme/lego/v4/registration"
|
|
||||||
"os"
|
|
||||||
"path"
|
|
||||||
"path/filepath"
|
|
||||||
)
|
|
||||||
|
|
||||||
func Apply(cert *conf.CertConf) {
|
|
||||||
email := cert.Email
|
|
||||||
host := cert.Host
|
|
||||||
name := cert.Name
|
|
||||||
|
|
||||||
privateKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
acmeUser := &AcmeUser{
|
|
||||||
Email: email,
|
|
||||||
key: privateKey,
|
|
||||||
}
|
|
||||||
config := lego.NewConfig(acmeUser)
|
|
||||||
client, err := lego.NewClient(config)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
providerName := cert.Provider
|
|
||||||
p, _ := conf.FindProvider(providerName)
|
|
||||||
|
|
||||||
provider := getProvider(p)
|
|
||||||
|
|
||||||
//var provider challenge.Provider
|
|
||||||
//
|
|
||||||
//switch p.Type {
|
|
||||||
//case "ali":
|
|
||||||
// conf := alidns.NewDefaultConfig()
|
|
||||||
// conf.RegionID = p.Conf["RegionID"]
|
|
||||||
// conf.APIKey = p.Conf["APIKey"]
|
|
||||||
// conf.SecretKey = p.Conf["SecretKey"]
|
|
||||||
// provider, err = alidns.NewDNSProviderConfig(conf)
|
|
||||||
// if err != nil {
|
|
||||||
// log.Fatal(err)
|
|
||||||
// }
|
|
||||||
//}
|
|
||||||
|
|
||||||
chall := client.Challenge
|
|
||||||
err = chall.SetDNS01Provider(provider)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
registrar := client.Registration
|
|
||||||
reg, err := registrar.Register(registration.RegisterOptions{TermsOfServiceAgreed: true})
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
acmeUser.Registration = reg
|
|
||||||
|
|
||||||
request := certificate.ObtainRequest{
|
|
||||||
Domains: host,
|
|
||||||
Bundle: true,
|
|
||||||
}
|
|
||||||
|
|
||||||
res, err := client.Certificate.Obtain(request)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
saveCertFile(res, cert, name)
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
//func Apply1(domain Domain) {
|
|
||||||
// email, hosts, name := domain.Email, domain.Host, domain.Name
|
|
||||||
// privateKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
|
|
||||||
// if err != nil {
|
|
||||||
// log.Fatal(err)
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// acmeUser := &AcmeUser{
|
|
||||||
// Email: email,
|
|
||||||
// key: privateKey,
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// config := lego.NewConfig(acmeUser)
|
|
||||||
//
|
|
||||||
// client, err := lego.NewClient(config)
|
|
||||||
// if err != nil {
|
|
||||||
// log.Fatal(err)
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// ali := appConfig.Provider.Ali
|
|
||||||
// conf := alidns.NewDefaultConfig()
|
|
||||||
// conf.RegionID = ali.RegionID
|
|
||||||
// conf.APIKey = ali.APIKey
|
|
||||||
// conf.SecretKey = ali.SecretKey
|
|
||||||
// provider, err := alidns.NewDNSProviderConfig(conf)
|
|
||||||
// if err != nil {
|
|
||||||
// log.Fatal(err)
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// challenge := client.Challenge
|
|
||||||
// err = challenge.SetDNS01Provider(provider)
|
|
||||||
// if err != nil {
|
|
||||||
// return
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// registrar := client.Registration
|
|
||||||
// reg, err := registrar.Register(registration.RegisterOptions{TermsOfServiceAgreed: true})
|
|
||||||
// if err != nil {
|
|
||||||
// log.Fatal(err)
|
|
||||||
// }
|
|
||||||
// acmeUser.Registration = reg
|
|
||||||
//
|
|
||||||
// request := certificate.ObtainRequest{
|
|
||||||
// Domains: hosts,
|
|
||||||
// Bundle: true,
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// cert, err := client.Certificate.Obtain(request)
|
|
||||||
// if err != nil {
|
|
||||||
// log.Fatal(err)
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// saveCertFile(cert, name)
|
|
||||||
//}
|
|
||||||
|
|
||||||
func getProvider(p *conf.ProviderConf) challenge.Provider {
|
|
||||||
|
|
||||||
switch p.Type {
|
|
||||||
case "ali":
|
|
||||||
return aliProvider(p)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
func aliProvider(p *conf.ProviderConf) challenge.Provider {
|
|
||||||
aliConf := alidns.NewDefaultConfig()
|
|
||||||
aliConf.RegionID = p.Conf["RegionID"]
|
|
||||||
aliConf.APIKey = p.Conf["APIKey"]
|
|
||||||
aliConf.SecretKey = p.Conf["SecretKey"]
|
|
||||||
provider, err := alidns.NewDNSProviderConfig(aliConf)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
return provider
|
|
||||||
}
|
|
||||||
func tencentProvider() challenge.Provider {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// saveCertFile 保存证书文件
|
|
||||||
func saveCertFile(cert *certificate.Resource, cerfConf *conf.CertConf, name string) {
|
|
||||||
dir := cerfConf.Dir
|
|
||||||
dir = filepath.Join(dir, name)
|
|
||||||
_, err := os.Stat(dir)
|
|
||||||
if os.IsNotExist(err) {
|
|
||||||
err := os.MkdirAll(dir, 0755)
|
|
||||||
if err != nil {
|
|
||||||
log.Infof("创建目录 %s 失败", dir)
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
log.Infof("创建目录 %s", dir)
|
|
||||||
}
|
|
||||||
|
|
||||||
certBytes := cert.Certificate
|
|
||||||
err = os.WriteFile(path.Join(dir, common.CertFileName), certBytes, 0755)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatalf("Failed to save certificate: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
err = os.WriteFile(path.Join(dir, common.KeyFileName), cert.PrivateKey, 0755)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatalf("Failed to save private key: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
block, _ := pem.Decode(certBytes)
|
|
||||||
if block == nil {
|
|
||||||
log.Fatalf("Failed to decode PEM block")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
certParse, err := x509.ParseCertificate(block.Bytes)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatalf("Failed to parse certificate: %v", err)
|
|
||||||
}
|
|
||||||
certInfo := CertInfo{
|
|
||||||
Cert: *cert,
|
|
||||||
Info: *certParse,
|
|
||||||
}
|
|
||||||
// 将 cert 转换为json格式并保存到文件中
|
|
||||||
certJson, err := json.Marshal(certInfo)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatalf("Failed to marshal certificate: %v", err)
|
|
||||||
}
|
|
||||||
err = os.WriteFile(path.Join(dir, common.CertInfoFileName), certJson, 0644)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatalf("Failed to save certificate info: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
type AcmeUser struct {
|
|
||||||
Email string
|
|
||||||
Registration *registration.Resource
|
|
||||||
key crypto.PrivateKey
|
|
||||||
}
|
|
||||||
|
|
||||||
func (u AcmeUser) GetEmail() string {
|
|
||||||
return u.Email
|
|
||||||
}
|
|
||||||
func (u AcmeUser) GetRegistration() *registration.Resource {
|
|
||||||
return u.Registration
|
|
||||||
}
|
|
||||||
func (u AcmeUser) GetPrivateKey() crypto.PrivateKey {
|
|
||||||
return u.key
|
|
||||||
}
|
|
||||||
|
|
||||||
type CertInfo struct {
|
|
||||||
Cert certificate.Resource
|
|
||||||
Info x509.Certificate
|
|
||||||
}
|
|
|
@ -1,7 +1,6 @@
|
||||||
package cmd
|
package cmd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"acme-mana/src/cmd/cmd_handle"
|
|
||||||
"acme-mana/src/common"
|
"acme-mana/src/common"
|
||||||
"acme-mana/src/conf"
|
"acme-mana/src/conf"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
|
@ -32,8 +31,7 @@ func InitCmd() (*cobra.Command, error) {
|
||||||
//rootCmd.GenPowerShellCompletion(os.Stdout)
|
//rootCmd.GenPowerShellCompletion(os.Stdout)
|
||||||
//rootCmd.GenZshCompletion(os.Stdout)
|
//rootCmd.GenZshCompletion(os.Stdout)
|
||||||
|
|
||||||
conf.LoadAppConfig()
|
conf.InitAppConfig()
|
||||||
|
|
||||||
err := rootCmd.Execute()
|
err := rootCmd.Execute()
|
||||||
|
|
||||||
return rootCmd, err
|
return rootCmd, err
|
||||||
|
@ -53,7 +51,7 @@ func initConfCmd() *cobra.Command {
|
||||||
Short: "查看配置列表",
|
Short: "查看配置列表",
|
||||||
Long: "查看系统配置列表",
|
Long: "查看系统配置列表",
|
||||||
Run: func(cmd *cobra.Command, args []string) {
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
cmd_handle.ConfShow(cmd, args)
|
confShow(cmd, args)
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
confCmd.AddCommand(confShow)
|
confCmd.AddCommand(confShow)
|
||||||
|
@ -63,13 +61,10 @@ func initConfCmd() *cobra.Command {
|
||||||
func initServerCmd() *cobra.Command {
|
func initServerCmd() *cobra.Command {
|
||||||
serverCmd := &cobra.Command{
|
serverCmd := &cobra.Command{
|
||||||
Use: "server",
|
Use: "server",
|
||||||
Short: "服务端命令",
|
Short: "服务相关命令",
|
||||||
Long: "acme-mana服务端相关命令, 配置服务相关参数, 如监听端口,监听地址等",
|
Long: "配置服务相关参数, 如监听端口,监听地址等",
|
||||||
Run: func(cmd *cobra.Command, args []string) {
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
err := cmd.Help()
|
cmd.Help()
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
editCmd := &cobra.Command{
|
editCmd := &cobra.Command{
|
||||||
|
@ -77,7 +72,7 @@ func initServerCmd() *cobra.Command {
|
||||||
Short: "编辑服务配置",
|
Short: "编辑服务配置",
|
||||||
Long: "编辑服务配置",
|
Long: "编辑服务配置",
|
||||||
Run: func(cmd *cobra.Command, args []string) {
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
cmd_handle.ServerEdit(cmd, args)
|
editServer(cmd, args)
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
stateCmd := &cobra.Command{
|
stateCmd := &cobra.Command{
|
||||||
|
@ -85,7 +80,7 @@ func initServerCmd() *cobra.Command {
|
||||||
Short: "查看服务状态",
|
Short: "查看服务状态",
|
||||||
Long: "查看服务状态",
|
Long: "查看服务状态",
|
||||||
Run: func(cmd *cobra.Command, args []string) {
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
cmd_handle.ServerState(cmd, args)
|
serverState(cmd, args)
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
startCmd := &cobra.Command{
|
startCmd := &cobra.Command{
|
||||||
|
@ -93,7 +88,7 @@ func initServerCmd() *cobra.Command {
|
||||||
Short: "启动服务",
|
Short: "启动服务",
|
||||||
Long: "启动服务",
|
Long: "启动服务",
|
||||||
Run: func(cmd *cobra.Command, args []string) {
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
cmd_handle.ServerStart(cmd, args)
|
startServer(cmd, args)
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
stopCmd := &cobra.Command{
|
stopCmd := &cobra.Command{
|
||||||
|
@ -101,7 +96,7 @@ func initServerCmd() *cobra.Command {
|
||||||
Short: "停止服务",
|
Short: "停止服务",
|
||||||
Long: "停止服务",
|
Long: "停止服务",
|
||||||
Run: func(cmd *cobra.Command, args []string) {
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
cmd_handle.ServerStop(cmd, args)
|
stopServer(cmd, args)
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -126,7 +121,7 @@ func initTaskCmd() *cobra.Command {
|
||||||
Short: "编辑定时任务配置",
|
Short: "编辑定时任务配置",
|
||||||
Long: "编辑定时任务配置",
|
Long: "编辑定时任务配置",
|
||||||
Run: func(cmd *cobra.Command, args []string) {
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
cmd_handle.TaskEdit(cmd, args)
|
editTask(cmd, args)
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
startTask := &cobra.Command{
|
startTask := &cobra.Command{
|
||||||
|
@ -134,7 +129,7 @@ func initTaskCmd() *cobra.Command {
|
||||||
Short: "启动定时任务",
|
Short: "启动定时任务",
|
||||||
Long: "启动定时任务",
|
Long: "启动定时任务",
|
||||||
Run: func(cmd *cobra.Command, args []string) {
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
cmd_handle.TaskStart(cmd, args)
|
startTask(cmd, args)
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
stopTask := &cobra.Command{
|
stopTask := &cobra.Command{
|
||||||
|
@ -142,7 +137,7 @@ func initTaskCmd() *cobra.Command {
|
||||||
Short: "停止定时任务",
|
Short: "停止定时任务",
|
||||||
Long: "停止定时任务",
|
Long: "停止定时任务",
|
||||||
Run: func(cmd *cobra.Command, args []string) {
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
cmd_handle.TaskStop(cmd, args)
|
stopTask(cmd, args)
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
statusTask := &cobra.Command{
|
statusTask := &cobra.Command{
|
||||||
|
@ -150,7 +145,7 @@ func initTaskCmd() *cobra.Command {
|
||||||
Short: "查看定时任务状态",
|
Short: "查看定时任务状态",
|
||||||
Long: "查看定时任务状态",
|
Long: "查看定时任务状态",
|
||||||
Run: func(cmd *cobra.Command, args []string) {
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
cmd_handle.TaskStatus(cmd, args)
|
statusTask(cmd, args)
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
runTask := &cobra.Command{
|
runTask := &cobra.Command{
|
||||||
|
@ -158,7 +153,7 @@ func initTaskCmd() *cobra.Command {
|
||||||
Short: "手动执行一次任务",
|
Short: "手动执行一次任务",
|
||||||
Long: "手动执行一次任务",
|
Long: "手动执行一次任务",
|
||||||
Run: func(cmd *cobra.Command, args []string) {
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
cmd_handle.TaskRun(cmd, args)
|
runTask(cmd, args)
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
taskCmd.AddCommand(editTask)
|
taskCmd.AddCommand(editTask)
|
||||||
|
@ -183,7 +178,7 @@ func initProviderCmd() *cobra.Command {
|
||||||
Short: "列出支持的DNS服务商",
|
Short: "列出支持的DNS服务商",
|
||||||
Long: "列出支持的DNS服务商",
|
Long: "列出支持的DNS服务商",
|
||||||
Run: func(cmd *cobra.Command, args []string) {
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
cmd_handle.ProviderSupport(cmd, args)
|
providerSupport(cmd, args)
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
providerList := &cobra.Command{
|
providerList := &cobra.Command{
|
||||||
|
@ -191,7 +186,7 @@ func initProviderCmd() *cobra.Command {
|
||||||
Short: "列出已配置的DNS服务商",
|
Short: "列出已配置的DNS服务商",
|
||||||
Long: "列出已配置的DNS服务商",
|
Long: "列出已配置的DNS服务商",
|
||||||
Run: func(cmd *cobra.Command, args []string) {
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
cmd_handle.ProviderList(cmd, args)
|
providerList(cmd, args)
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
providerAdd := &cobra.Command{
|
providerAdd := &cobra.Command{
|
||||||
|
@ -199,7 +194,7 @@ func initProviderCmd() *cobra.Command {
|
||||||
Short: "添加DNS服务商",
|
Short: "添加DNS服务商",
|
||||||
Long: "添加DNS服务商",
|
Long: "添加DNS服务商",
|
||||||
Run: func(cmd *cobra.Command, args []string) {
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
cmd_handle.ProviderAdd(cmd, args)
|
providerAdd(cmd, args)
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
providerEdit := &cobra.Command{
|
providerEdit := &cobra.Command{
|
||||||
|
@ -207,7 +202,7 @@ func initProviderCmd() *cobra.Command {
|
||||||
Short: "编辑DNS服务商",
|
Short: "编辑DNS服务商",
|
||||||
Long: "编辑DNS服务商",
|
Long: "编辑DNS服务商",
|
||||||
Run: func(cmd *cobra.Command, args []string) {
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
cmd_handle.ProviderEdit(cmd, args)
|
providerEdit(cmd, args)
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
providerDelete := &cobra.Command{
|
providerDelete := &cobra.Command{
|
||||||
|
@ -215,7 +210,7 @@ func initProviderCmd() *cobra.Command {
|
||||||
Short: "删除DNS服务商",
|
Short: "删除DNS服务商",
|
||||||
Long: "删除DNS服务商",
|
Long: "删除DNS服务商",
|
||||||
Run: func(cmd *cobra.Command, args []string) {
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
cmd_handle.ProviderDelete(cmd, args)
|
providerDelete(cmd, args)
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -241,7 +236,7 @@ func certCmd() *cobra.Command {
|
||||||
Short: "列出已配置的证书",
|
Short: "列出已配置的证书",
|
||||||
Long: "列出已配置的证书",
|
Long: "列出已配置的证书",
|
||||||
Run: func(cmd *cobra.Command, args []string) {
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
cmd_handle.CertList(cmd, args)
|
certList(cmd, args)
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
certAdd := &cobra.Command{
|
certAdd := &cobra.Command{
|
||||||
|
@ -249,7 +244,7 @@ func certCmd() *cobra.Command {
|
||||||
Short: "添加证书",
|
Short: "添加证书",
|
||||||
Long: "添加证书",
|
Long: "添加证书",
|
||||||
Run: func(cmd *cobra.Command, args []string) {
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
cmd_handle.CertAdd(cmd, args)
|
certAdd(cmd, args)
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
certDelete := &cobra.Command{
|
certDelete := &cobra.Command{
|
||||||
|
@ -257,7 +252,7 @@ func certCmd() *cobra.Command {
|
||||||
Short: "删除证书",
|
Short: "删除证书",
|
||||||
Long: "删除证书",
|
Long: "删除证书",
|
||||||
Run: func(cmd *cobra.Command, args []string) {
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
cmd_handle.CertDelete(cmd, args)
|
certDelete(cmd, args)
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
editCert := &cobra.Command{
|
editCert := &cobra.Command{
|
||||||
|
@ -265,7 +260,7 @@ func certCmd() *cobra.Command {
|
||||||
Short: "编辑证书",
|
Short: "编辑证书",
|
||||||
Long: "编辑证书",
|
Long: "编辑证书",
|
||||||
Run: func(cmd *cobra.Command, args []string) {
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
cmd_handle.CertEdit(cmd, args)
|
editCert(cmd, args)
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
certCmd.AddCommand(certList)
|
certCmd.AddCommand(certList)
|
||||||
|
@ -279,7 +274,7 @@ func acmeCmd() *cobra.Command {
|
||||||
acmeCmd := &cobra.Command{
|
acmeCmd := &cobra.Command{
|
||||||
Use: "acme",
|
Use: "acme",
|
||||||
Short: "ACME相关命令",
|
Short: "ACME相关命令",
|
||||||
Long: "acme.sh原生命令",
|
Long: "ACME相关命令",
|
||||||
Run: func(cmd *cobra.Command, args []string) {
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
cmd.Help()
|
cmd.Help()
|
||||||
},
|
},
|
||||||
|
|
|
@ -1,22 +0,0 @@
|
||||||
package cmd_handle
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"github.com/spf13/cobra"
|
|
||||||
)
|
|
||||||
|
|
||||||
func CertEdit(cmd *cobra.Command, args []string) {
|
|
||||||
fmt.Println("edit cert")
|
|
||||||
}
|
|
||||||
|
|
||||||
func CertDelete(cmd *cobra.Command, args []string) {
|
|
||||||
fmt.Println("delete cert")
|
|
||||||
}
|
|
||||||
|
|
||||||
func CertAdd(cmd *cobra.Command, args []string) {
|
|
||||||
fmt.Println("add cert")
|
|
||||||
}
|
|
||||||
|
|
||||||
func CertList(cmd *cobra.Command, args []string) {
|
|
||||||
fmt.Println("list cert")
|
|
||||||
}
|
|
|
@ -1,19 +0,0 @@
|
||||||
package cmd_handle
|
|
||||||
|
|
||||||
import (
|
|
||||||
"acme-mana/src/conf"
|
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
|
||||||
tea "github.com/charmbracelet/bubbletea"
|
|
||||||
"github.com/spf13/cobra"
|
|
||||||
)
|
|
||||||
|
|
||||||
// ConfShow 打印 配置信息
|
|
||||||
func ConfShow(cmd *cobra.Command, args []string) {
|
|
||||||
tea.Println()
|
|
||||||
confJson, err := json.MarshalIndent(conf.Config(), "", " ")
|
|
||||||
if err != nil {
|
|
||||||
fmt.Println("序列化配置信息失败:", err)
|
|
||||||
}
|
|
||||||
fmt.Println(string(confJson))
|
|
||||||
}
|
|
|
@ -1,26 +0,0 @@
|
||||||
package cmd_handle
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"github.com/spf13/cobra"
|
|
||||||
)
|
|
||||||
|
|
||||||
func ProviderDelete(cmd *cobra.Command, args []string) {
|
|
||||||
fmt.Println("delete provider")
|
|
||||||
}
|
|
||||||
|
|
||||||
func ProviderEdit(cmd *cobra.Command, args []string) {
|
|
||||||
fmt.Println("edit provider")
|
|
||||||
}
|
|
||||||
|
|
||||||
func ProviderAdd(cmd *cobra.Command, args []string) {
|
|
||||||
fmt.Println("add provider")
|
|
||||||
}
|
|
||||||
|
|
||||||
func ProviderList(cmd *cobra.Command, args []string) {
|
|
||||||
fmt.Println("list provider")
|
|
||||||
}
|
|
||||||
|
|
||||||
func ProviderSupport(cmd *cobra.Command, args []string) {
|
|
||||||
fmt.Println("support provider")
|
|
||||||
}
|
|
|
@ -1,148 +0,0 @@
|
||||||
package cmd_handle
|
|
||||||
|
|
||||||
import (
|
|
||||||
"acme-mana/src/common"
|
|
||||||
"acme-mana/src/conf"
|
|
||||||
"acme-mana/src/server"
|
|
||||||
"acme-mana/src/util"
|
|
||||||
"fmt"
|
|
||||||
"github.com/spf13/cobra"
|
|
||||||
"log"
|
|
||||||
"os"
|
|
||||||
"os/exec"
|
|
||||||
"path"
|
|
||||||
"path/filepath"
|
|
||||||
"strconv"
|
|
||||||
"syscall"
|
|
||||||
)
|
|
||||||
|
|
||||||
var stdout *os.File
|
|
||||||
var stderr *os.File
|
|
||||||
|
|
||||||
func ServerStart(command *cobra.Command, args []string) {
|
|
||||||
initLog()
|
|
||||||
|
|
||||||
isDaemon := os.Getenv("GO_DAEMON")
|
|
||||||
log.Println("守护进程启动: " + isDaemon)
|
|
||||||
|
|
||||||
if isRunning() {
|
|
||||||
log.Println("守护进程已启动, 跳过执行")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if isDaemon == "1" {
|
|
||||||
daemonStart()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
workPath, err := os.Executable()
|
|
||||||
if err != nil {
|
|
||||||
log.Fatalf("无法获取当前工作路径: %v", err)
|
|
||||||
}
|
|
||||||
cmd := exec.Cmd{
|
|
||||||
Path: workPath,
|
|
||||||
Args: os.Args,
|
|
||||||
Dir: filepath.Dir(workPath),
|
|
||||||
Env: append(os.Environ(), "GO_DAEMON=1"),
|
|
||||||
//Stdin: os.Stdin,
|
|
||||||
Stdout: stdout,
|
|
||||||
Stderr: stderr,
|
|
||||||
SysProcAttr: &syscall.SysProcAttr{},
|
|
||||||
}
|
|
||||||
log.Println("启动守护进程中...")
|
|
||||||
err = cmd.Start()
|
|
||||||
if err != nil {
|
|
||||||
log.Fatalf("无法启动守护进程: %v", err)
|
|
||||||
}
|
|
||||||
err = os.WriteFile(common.PidFile, []byte(strconv.Itoa(cmd.Process.Pid)), 0644)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatalf("无法写出PID文件: %v", err)
|
|
||||||
}
|
|
||||||
log.Printf("启动进程启动成功, PID: %d", cmd.Process.Pid)
|
|
||||||
os.Exit(0)
|
|
||||||
}
|
|
||||||
|
|
||||||
func ServerEdit(cmd *cobra.Command, args []string) {
|
|
||||||
s := conf.Config().Server
|
|
||||||
host := util.ReadLine("请输入服务监听地址;", s.Host)
|
|
||||||
port := util.ReadInt("请输入服务监听端口;", strconv.Itoa(s.Port))
|
|
||||||
key := util.ReadLine("请输入服务通信认证秘钥;", s.Key)
|
|
||||||
conf.EditServer(host, port, key)
|
|
||||||
fmt.Println("服务监听配置已完成")
|
|
||||||
}
|
|
||||||
|
|
||||||
func ServerState(cmd *cobra.Command, args []string) {
|
|
||||||
server.HttpInstance.Status()
|
|
||||||
}
|
|
||||||
func ServerStop(cmd *cobra.Command, args []string) {
|
|
||||||
server.HttpInstance.Stop()
|
|
||||||
}
|
|
||||||
|
|
||||||
func daemonStart() {
|
|
||||||
// 启动 HttpServer
|
|
||||||
server.HttpInstance.Init()
|
|
||||||
server.HttpInstance.Start()
|
|
||||||
|
|
||||||
// 启动 SocketServer
|
|
||||||
server.SocketInstance.Start()
|
|
||||||
|
|
||||||
// TODO 启动 AutoRefreshCert
|
|
||||||
}
|
|
||||||
|
|
||||||
func isRunning() bool {
|
|
||||||
log.Println("Checking if daemon is running...")
|
|
||||||
pid, err := readPID()
|
|
||||||
if err != nil {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
process, err := os.FindProcess(pid)
|
|
||||||
log.Println("Found process:", process)
|
|
||||||
if err != nil {
|
|
||||||
log.Println("Failed to find process:", err)
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
// 读取PID文件
|
|
||||||
func readPID() (int, error) {
|
|
||||||
log.Println("Reading PID file...")
|
|
||||||
data, err := os.ReadFile(common.PidFile)
|
|
||||||
if err != nil {
|
|
||||||
log.Println("Failed to read PID file:", err)
|
|
||||||
return 0, err
|
|
||||||
}
|
|
||||||
log.Println("PID file content:", string(data))
|
|
||||||
|
|
||||||
pid, err := strconv.Atoi(string(data))
|
|
||||||
if err != nil {
|
|
||||||
log.Println("Failed to parse PID:", err)
|
|
||||||
return 0, err
|
|
||||||
}
|
|
||||||
log.Println("PID:", pid)
|
|
||||||
|
|
||||||
return pid, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func initLog() {
|
|
||||||
pwd, err := os.Getwd()
|
|
||||||
if err != nil {
|
|
||||||
log.Fatalf("无法获取当前工作路径: %v", err)
|
|
||||||
}
|
|
||||||
dir := path.Join(pwd, "log")
|
|
||||||
_, err = os.Stat(dir)
|
|
||||||
if os.IsNotExist(err) {
|
|
||||||
err := os.Mkdir(dir, 0777)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatalf("无法创建日志目录: %v", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
outFile, err := os.OpenFile(path.Join(dir, "out.log"), os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0644)
|
|
||||||
defer outFile.Close()
|
|
||||||
stdout = outFile
|
|
||||||
|
|
||||||
errFile, err := os.OpenFile(path.Join(dir, "err.log"), os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0644)
|
|
||||||
defer stderr.Close()
|
|
||||||
stderr = errFile
|
|
||||||
}
|
|
|
@ -1,26 +0,0 @@
|
||||||
package cmd_handle
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"github.com/spf13/cobra"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TaskEdit(cmd *cobra.Command, args []string) {
|
|
||||||
fmt.Println("edit task")
|
|
||||||
}
|
|
||||||
|
|
||||||
func TaskStatus(cmd *cobra.Command, args []string) {
|
|
||||||
fmt.Println("status task")
|
|
||||||
}
|
|
||||||
|
|
||||||
func TaskStop(cmd *cobra.Command, args []string) {
|
|
||||||
fmt.Println("stop task")
|
|
||||||
}
|
|
||||||
|
|
||||||
func TaskStart(cmd *cobra.Command, args []string) {
|
|
||||||
fmt.Println("start task")
|
|
||||||
}
|
|
||||||
|
|
||||||
func TaskRun(cmd *cobra.Command, args []string) {
|
|
||||||
fmt.Println("run task")
|
|
||||||
}
|
|
95
src/cmd/handler.go
Normal file
95
src/cmd/handler.go
Normal file
|
@ -0,0 +1,95 @@
|
||||||
|
package cmd
|
||||||
|
|
||||||
|
import (
|
||||||
|
"acme-mana/src/common"
|
||||||
|
"acme-mana/src/conf"
|
||||||
|
"acme-mana/src/http"
|
||||||
|
"acme-mana/src/util"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
tea "github.com/charmbracelet/bubbletea"
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
"strconv"
|
||||||
|
)
|
||||||
|
|
||||||
|
// 打印 配置信息
|
||||||
|
func confShow(cmd *cobra.Command, args []string) {
|
||||||
|
tea.Println()
|
||||||
|
confJson, err := json.MarshalIndent(common.AppConf, "", " ")
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println("序列化配置信息失败:", err)
|
||||||
|
}
|
||||||
|
fmt.Println(string(confJson))
|
||||||
|
}
|
||||||
|
|
||||||
|
func editServer(cmd *cobra.Command, args []string) {
|
||||||
|
server := common.AppConf.Server
|
||||||
|
server.Host = util.ReadLine("请输入服务监听地址;", server.Host)
|
||||||
|
server.Port = util.ReadInt("请输入服务监听端口;", strconv.Itoa(server.Port))
|
||||||
|
conf.WriteConfig()
|
||||||
|
fmt.Println("服务监听配置已完成")
|
||||||
|
}
|
||||||
|
|
||||||
|
func serverState(cmd *cobra.Command, args []string) {
|
||||||
|
http.Start()
|
||||||
|
}
|
||||||
|
func startServer(cmd *cobra.Command, args []string) {
|
||||||
|
http.Start()
|
||||||
|
}
|
||||||
|
func stopServer(cmd *cobra.Command, args []string) {
|
||||||
|
fmt.Println("stop server")
|
||||||
|
}
|
||||||
|
|
||||||
|
func editTask(cmd *cobra.Command, args []string) {
|
||||||
|
fmt.Println("edit task")
|
||||||
|
}
|
||||||
|
func runTask(cmd *cobra.Command, args []string) {
|
||||||
|
fmt.Println("run task")
|
||||||
|
}
|
||||||
|
|
||||||
|
func statusTask(cmd *cobra.Command, args []string) {
|
||||||
|
fmt.Println("status task")
|
||||||
|
}
|
||||||
|
|
||||||
|
func stopTask(cmd *cobra.Command, args []string) {
|
||||||
|
fmt.Println("stop task")
|
||||||
|
}
|
||||||
|
|
||||||
|
func startTask(cmd *cobra.Command, args []string) {
|
||||||
|
fmt.Println("start task")
|
||||||
|
}
|
||||||
|
func providerDelete(cmd *cobra.Command, args []string) {
|
||||||
|
fmt.Println("delete provider")
|
||||||
|
}
|
||||||
|
|
||||||
|
func providerEdit(cmd *cobra.Command, args []string) {
|
||||||
|
fmt.Println("edit provider")
|
||||||
|
}
|
||||||
|
|
||||||
|
func providerAdd(cmd *cobra.Command, args []string) {
|
||||||
|
fmt.Println("add provider")
|
||||||
|
}
|
||||||
|
|
||||||
|
func providerList(cmd *cobra.Command, args []string) {
|
||||||
|
fmt.Println("list provider")
|
||||||
|
}
|
||||||
|
|
||||||
|
func providerSupport(cmd *cobra.Command, args []string) {
|
||||||
|
fmt.Println("support provider")
|
||||||
|
}
|
||||||
|
|
||||||
|
func editCert(cmd *cobra.Command, args []string) {
|
||||||
|
fmt.Println("edit cert")
|
||||||
|
}
|
||||||
|
|
||||||
|
func certDelete(cmd *cobra.Command, args []string) {
|
||||||
|
fmt.Println("delete cert")
|
||||||
|
}
|
||||||
|
|
||||||
|
func certAdd(cmd *cobra.Command, args []string) {
|
||||||
|
fmt.Println("add cert")
|
||||||
|
}
|
||||||
|
|
||||||
|
func certList(cmd *cobra.Command, args []string) {
|
||||||
|
fmt.Println("list cert")
|
||||||
|
}
|
161
src/command.go
161
src/command.go
|
@ -1,82 +1,83 @@
|
||||||
package src
|
package src
|
||||||
|
|
||||||
//import (
|
import (
|
||||||
// "log"
|
"log"
|
||||||
// "net"
|
"net"
|
||||||
// "os"
|
"os"
|
||||||
//)
|
)
|
||||||
//
|
|
||||||
//// InitSocket 初始化 socket 文件
|
// InitSocket 初始化 socket 文件
|
||||||
//func InitSocket() {
|
func InitSocket() {
|
||||||
// log.Println("Start listen command")
|
log.Println("Start listen command")
|
||||||
// // 删除旧的 socket 文件
|
// 删除旧的 socket 文件
|
||||||
// if _, err := os.Stat(SocketFile); err == nil {
|
if _, err := os.Stat(SocketFile); err == nil {
|
||||||
// os.Remove(SocketFile)
|
os.Remove(SocketFile)
|
||||||
// }
|
}
|
||||||
//
|
|
||||||
// listener, err := net.Listen("unix", SocketFile)
|
listener, err := net.Listen("unix", SocketFile)
|
||||||
// if err != nil {
|
if err != nil {
|
||||||
// log.Fatalf("Failed to listen on socket: %v", err)
|
log.Fatalf("Failed to listen on socket: %v", err)
|
||||||
// }
|
}
|
||||||
// defer listener.Close()
|
defer listener.Close()
|
||||||
//
|
|
||||||
// for {
|
for {
|
||||||
// log.Println("Waiting for connections...")
|
log.Println("Waiting for connections...")
|
||||||
// conn, err := listener.Accept()
|
conn, err := listener.Accept()
|
||||||
// if err != nil {
|
if err != nil {
|
||||||
// log.Printf("Failed to accept connection: %v", err)
|
log.Printf("Failed to accept connection: %v", err)
|
||||||
// continue
|
continue
|
||||||
// }
|
}
|
||||||
//
|
|
||||||
// go handleConnection(conn)
|
go handleConnection(conn)
|
||||||
// }
|
}
|
||||||
//}
|
}
|
||||||
//
|
|
||||||
///*
|
/*
|
||||||
//*
|
*
|
||||||
//处理连接
|
处理连接
|
||||||
//*/
|
*/
|
||||||
//func handleConnection(conn net.Conn) {
|
func handleConnection(conn net.Conn) {
|
||||||
// defer conn.Close()
|
defer conn.Close()
|
||||||
//
|
|
||||||
// buf := make([]byte, 1024)
|
buf := make([]byte, 1024)
|
||||||
// n, err := conn.Read(buf)
|
n, err := conn.Read(buf)
|
||||||
// if err != nil {
|
if err != nil {
|
||||||
// log.Printf("Failed to read command: %v", err)
|
log.Printf("Failed to read command: %v", err)
|
||||||
// return
|
return
|
||||||
// }
|
}
|
||||||
//
|
|
||||||
// command := string(buf[:n])
|
command := string(buf[:n])
|
||||||
// log.Printf("Received command: %s", command)
|
log.Printf("Received command: %s", command)
|
||||||
//
|
|
||||||
// // 在这里处理接收到的命令
|
// 在这里处理接收到的命令
|
||||||
// switch command {
|
switch command {
|
||||||
// case "stop":
|
case "stop":
|
||||||
// onStop()
|
onStop()
|
||||||
// default:
|
default:
|
||||||
// onCommand(command)
|
onCommand(command)
|
||||||
// }
|
}
|
||||||
//}
|
}
|
||||||
//
|
|
||||||
///*
|
/*
|
||||||
//*
|
*
|
||||||
//收到停止命令
|
收到停止命令
|
||||||
//*/
|
*/
|
||||||
//func onStop() {
|
func onStop() {
|
||||||
// log.Println("Stopping daemon...")// os.Remove(PidFile)
|
log.Println("Stopping daemon...")
|
||||||
// log.Println("Remove PID File...")
|
os.Remove(PidFile)
|
||||||
// os.Remove(SocketFile)
|
log.Println("Remove PID File...")
|
||||||
// log.Println("Remove Socket File...")
|
os.Remove(SocketFile)
|
||||||
// os.Exit(0)
|
log.Println("Remove Socket File...")
|
||||||
//}
|
os.Exit(0)
|
||||||
//
|
}
|
||||||
///*
|
|
||||||
//收到命令
|
/*
|
||||||
//*/
|
收到命令
|
||||||
//func onCommand(command string) {
|
*/
|
||||||
//
|
func onCommand(command string) {
|
||||||
//}
|
|
||||||
//
|
}
|
||||||
//func onConfig() {
|
|
||||||
//
|
func onConfig() {
|
||||||
//}
|
|
||||||
|
}
|
||||||
|
|
|
@ -1,14 +1,10 @@
|
||||||
package common
|
package common
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"acme-mana/src/model"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
)
|
)
|
||||||
|
|
||||||
const PidFile = "acme-mana.pid"
|
|
||||||
const SocketFile = "acme-mana.sock"
|
|
||||||
|
|
||||||
const CertFileName = "fullchain.pem"
|
|
||||||
const KeyFileName = "privkey.pem"
|
|
||||||
const CertInfoFileName = "info.json"
|
|
||||||
|
|
||||||
var RootCmd *cobra.Command
|
var RootCmd *cobra.Command
|
||||||
|
|
||||||
|
var AppConf *model.AppConfig
|
||||||
|
|
|
@ -1,63 +0,0 @@
|
||||||
package conf
|
|
||||||
|
|
||||||
// AppConfig
|
|
||||||
// 配置文件
|
|
||||||
type AppConfig struct {
|
|
||||||
// 服务器配置
|
|
||||||
Server *ServerConf `json:"server" yaml:"server"`
|
|
||||||
// 网页配置
|
|
||||||
Web *WebConf `json:"web" yaml:"web"`
|
|
||||||
// 任务配置
|
|
||||||
Task *TaskConf `json:"task" yaml:"task"`
|
|
||||||
// 认证配置
|
|
||||||
Providers *[]ProviderConf `json:"provider" yaml:"provider"`
|
|
||||||
// 证书配置
|
|
||||||
Certs *[]CertConf `json:"cert" yaml:"cert"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// ServerConf 服务端配置
|
|
||||||
type ServerConf struct {
|
|
||||||
// 监听地址
|
|
||||||
Host string `json:"host" yaml:"host"`
|
|
||||||
// 监听端口
|
|
||||||
Port int `json:"port" yaml:"port"`
|
|
||||||
// 通信密钥, DES 加密
|
|
||||||
Key string `json:"key" yaml:"key"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// WebConf 网页服务配置
|
|
||||||
type WebConf struct {
|
|
||||||
// 是否启用
|
|
||||||
Enable bool `json:"enable" yaml:"enable"`
|
|
||||||
// 监听地址
|
|
||||||
Host string `json:"host" yaml:"host"`
|
|
||||||
// 监听端口
|
|
||||||
Port int `json:"port" yaml:"port"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// TaskConf 定时任务配置
|
|
||||||
type TaskConf struct {
|
|
||||||
// 启动延迟时间, 单位: 毫秒, 默认: 0
|
|
||||||
Delay int `json:"delay" yaml:"delay"`
|
|
||||||
// 间隔时间
|
|
||||||
Interval int `json:"interval" yaml:"interval"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// ProviderConf 三方认证配置
|
|
||||||
type ProviderConf struct {
|
|
||||||
// 认证名称
|
|
||||||
Name string `json:"name" yaml:"name"`
|
|
||||||
// 认证类型
|
|
||||||
Type string `json:"type" yaml:"type"`
|
|
||||||
// 认证配置
|
|
||||||
Conf map[string]string `json:"conf" yaml:"conf"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// CertConf 证书配置
|
|
||||||
type CertConf struct {
|
|
||||||
Name string `json:"name" yaml:"name"`
|
|
||||||
Provider string `json:"use" yaml:"provider"`
|
|
||||||
Dir string `json:"dir" yaml:"dir"`
|
|
||||||
Email string `json:"email" yaml:"email"`
|
|
||||||
Host []string `json:"host" yaml:"host"`
|
|
||||||
}
|
|
129
src/conf/func.go
129
src/conf/func.go
|
@ -1,129 +0,0 @@
|
||||||
package conf
|
|
||||||
|
|
||||||
import "log"
|
|
||||||
|
|
||||||
func Config() *AppConfig {
|
|
||||||
return appConf
|
|
||||||
}
|
|
||||||
|
|
||||||
func EditServer(host string, port int, key string) *AppConfig {
|
|
||||||
appConf.Server.Host = host
|
|
||||||
appConf.Server.Port = port
|
|
||||||
appConf.Server.Key = key
|
|
||||||
WriteConfig()
|
|
||||||
return appConf
|
|
||||||
}
|
|
||||||
|
|
||||||
func EditWeb(host string, port int) *AppConfig {
|
|
||||||
appConf.Web.Host = host
|
|
||||||
appConf.Web.Port = port
|
|
||||||
WriteConfig()
|
|
||||||
return appConf
|
|
||||||
}
|
|
||||||
|
|
||||||
func ExecWeb(run bool) *AppConfig {
|
|
||||||
appConf.Web.Enable = run
|
|
||||||
WriteConfig()
|
|
||||||
return appConf
|
|
||||||
}
|
|
||||||
|
|
||||||
func EditTask(delay int, interval int) *AppConfig {
|
|
||||||
appConf.Task.Delay = delay
|
|
||||||
appConf.Task.Interval = interval
|
|
||||||
WriteConfig()
|
|
||||||
return appConf
|
|
||||||
}
|
|
||||||
|
|
||||||
func FindProvider(name string) (*ProviderConf, int) {
|
|
||||||
for index, provider := range *appConf.Providers {
|
|
||||||
if provider.Name == name {
|
|
||||||
return &provider, index
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil, -1
|
|
||||||
}
|
|
||||||
|
|
||||||
func AddProvider(name string, typeName string, conf map[string]string) *AppConfig {
|
|
||||||
provider, _ := FindProvider(name)
|
|
||||||
if provider != nil {
|
|
||||||
log.Fatal("已存在相同名称的配置")
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
provider = &ProviderConf{
|
|
||||||
Name: name,
|
|
||||||
Type: typeName,
|
|
||||||
Conf: conf,
|
|
||||||
}
|
|
||||||
providers := *appConf.Providers
|
|
||||||
newProviders := append(providers, *provider)
|
|
||||||
appConf.Providers = &newProviders
|
|
||||||
return appConf
|
|
||||||
}
|
|
||||||
|
|
||||||
func EditProvider(name string, typeName string, conf map[string]string) *AppConfig {
|
|
||||||
provider, _ := FindProvider(name)
|
|
||||||
if provider == nil {
|
|
||||||
log.Fatal("不存在该配置")
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
provider.Type = typeName
|
|
||||||
provider.Conf = conf
|
|
||||||
WriteConfig()
|
|
||||||
return appConf
|
|
||||||
}
|
|
||||||
|
|
||||||
func RmProvider(name string) *AppConfig {
|
|
||||||
_, index := FindProvider(name)
|
|
||||||
if index == -1 {
|
|
||||||
log.Fatal("不存在该配置")
|
|
||||||
}
|
|
||||||
providers := *appConf.Providers
|
|
||||||
newProviders := append(providers[:index], providers[index+1:]...)
|
|
||||||
appConf.Providers = &newProviders
|
|
||||||
return appConf
|
|
||||||
}
|
|
||||||
|
|
||||||
func FindCert(name string) (*CertConf, int) {
|
|
||||||
for index, cert := range *appConf.Certs {
|
|
||||||
if cert.Name == name {
|
|
||||||
return &cert, index
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil, -1
|
|
||||||
}
|
|
||||||
func FindCertByProvider(provider string) *[]CertConf {
|
|
||||||
var result []CertConf
|
|
||||||
for _, cert := range *appConf.Certs {
|
|
||||||
if cert.Provider == provider {
|
|
||||||
result = append(result, cert)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return &result
|
|
||||||
}
|
|
||||||
|
|
||||||
func AddCert(cert *CertConf) *AppConfig {
|
|
||||||
certs := *appConf.Certs
|
|
||||||
newCerts := append(certs, *cert)
|
|
||||||
appConf.Certs = &newCerts
|
|
||||||
return appConf
|
|
||||||
}
|
|
||||||
func EditCert(name string, cert *CertConf) *AppConfig {
|
|
||||||
_, index := FindCert(name)
|
|
||||||
if index == -1 {
|
|
||||||
log.Fatal("不存在该配置")
|
|
||||||
}
|
|
||||||
certs := *appConf.Certs
|
|
||||||
certs[index] = *cert
|
|
||||||
appConf.Certs = &certs
|
|
||||||
return appConf
|
|
||||||
}
|
|
||||||
func RmCert(name string) *AppConfig {
|
|
||||||
_, index := FindCert(name)
|
|
||||||
if index == -1 {
|
|
||||||
log.Fatal("不存在该配置")
|
|
||||||
}
|
|
||||||
certs := *appConf.Certs
|
|
||||||
newCerts := append(certs[:index], certs[index+1:]...)
|
|
||||||
appConf.Certs = &newCerts
|
|
||||||
return appConf
|
|
||||||
}
|
|
|
@ -2,90 +2,25 @@ package conf
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"acme-mana/src/common"
|
"acme-mana/src/common"
|
||||||
|
"acme-mana/src/model"
|
||||||
"acme-mana/src/util"
|
"acme-mana/src/util"
|
||||||
"gopkg.in/yaml.v3"
|
"gopkg.in/yaml.v3"
|
||||||
"log"
|
"log"
|
||||||
"os"
|
"os"
|
||||||
)
|
)
|
||||||
|
|
||||||
func LoadAppConfig() {
|
func readAppConfig(c *model.AppConfig) *model.AppConfig {
|
||||||
// 读取配置文件位置
|
confFile, err := common.RootCmd.PersistentFlags().GetString("conf")
|
||||||
confFile := getConfFile()
|
if err != nil {
|
||||||
// 判断配资文件是否存在
|
log.Fatalln("读取配置文件参数失败")
|
||||||
if _, err := os.Stat(confFile); os.IsNotExist(err) {
|
}
|
||||||
|
|
||||||
|
_, err = os.Stat(confFile)
|
||||||
|
if os.IsNotExist(err) {
|
||||||
log.Println("配置文件不存在, 自动创建")
|
log.Println("配置文件不存在, 自动创建")
|
||||||
config := defaultAppConfig()
|
writeConf(c, confFile)
|
||||||
log.Println("默认配置文件创建成功")
|
|
||||||
log.Println("服务器通信密钥: " + config.Server.Key)
|
|
||||||
appConf = config
|
|
||||||
writeConf(appConf, confFile)
|
|
||||||
} else {
|
|
||||||
appConf = readAppConfig(appConf)
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// RefreshConfig 刷新配置
|
|
||||||
func RefreshConfig() {
|
|
||||||
readAppConfig(appConf)
|
|
||||||
}
|
|
||||||
|
|
||||||
// WriteConfig 写入配置文件
|
|
||||||
func WriteConfig() {
|
|
||||||
confFile, err := common.RootCmd.PersistentFlags().GetString("conf")
|
|
||||||
if err != nil {
|
|
||||||
log.Fatalln("读取配置文件参数失败")
|
|
||||||
}
|
|
||||||
writeConf(appConf, confFile)
|
|
||||||
}
|
|
||||||
|
|
||||||
func writeConf(c *AppConfig, file string) {
|
|
||||||
out, err := yaml.Marshal(c)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatalln("序列化配置文件失败")
|
|
||||||
}
|
|
||||||
util.MkFileDir(file)
|
|
||||||
err = os.WriteFile(file, out, 0644)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatalln("写入配置文件失败")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// DefaultAppConfig 默认配置
|
|
||||||
func defaultAppConfig() *AppConfig {
|
|
||||||
serverKey := util.RandomStr(32)
|
|
||||||
|
|
||||||
return &AppConfig{
|
|
||||||
Server: &ServerConf{
|
|
||||||
Host: "0.0.0.0",
|
|
||||||
Port: 36851,
|
|
||||||
Key: serverKey,
|
|
||||||
},
|
|
||||||
Web: &WebConf{
|
|
||||||
Enable: false,
|
|
||||||
Host: "0.0.0.0",
|
|
||||||
Port: 36852,
|
|
||||||
},
|
|
||||||
Task: &TaskConf{
|
|
||||||
Delay: 0,
|
|
||||||
Interval: 0,
|
|
||||||
},
|
|
||||||
Certs: nil,
|
|
||||||
Providers: nil,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// getConfFile 获取配置文件位置
|
|
||||||
func getConfFile() string {
|
|
||||||
confFile, err := common.RootCmd.PersistentFlags().GetString("conf")
|
|
||||||
if err != nil {
|
|
||||||
log.Fatalln("读取配置文件参数失败")
|
|
||||||
}
|
|
||||||
return confFile
|
|
||||||
}
|
|
||||||
|
|
||||||
// readAppConfig 读取配置文件
|
|
||||||
func readAppConfig(c *AppConfig) *AppConfig {
|
|
||||||
confFile := getConfFile()
|
|
||||||
file, err := os.ReadFile(confFile)
|
file, err := os.ReadFile(confFile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalln("读取配置文件失败")
|
log.Fatalln("读取配置文件失败")
|
||||||
|
@ -97,3 +32,46 @@ func readAppConfig(c *AppConfig) *AppConfig {
|
||||||
}
|
}
|
||||||
return c
|
return c
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func InitAppConfig() {
|
||||||
|
common.AppConf = DefaultAppConfig()
|
||||||
|
}
|
||||||
|
|
||||||
|
func RefreshConfig() {
|
||||||
|
readAppConfig(common.AppConf)
|
||||||
|
}
|
||||||
|
|
||||||
|
func WriteConfig() {
|
||||||
|
confFile, err := common.RootCmd.PersistentFlags().GetString("conf")
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalln("读取配置文件参数失败")
|
||||||
|
}
|
||||||
|
writeConf(common.AppConf, confFile)
|
||||||
|
}
|
||||||
|
|
||||||
|
func writeConf(c *model.AppConfig, file string) {
|
||||||
|
out, err := yaml.Marshal(c)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalln("序列化配置文件失败")
|
||||||
|
}
|
||||||
|
util.MkFileDir(file)
|
||||||
|
err = os.WriteFile(file, out, 0644)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalln("写入配置文件失败")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func DefaultAppConfig() *model.AppConfig {
|
||||||
|
return &model.AppConfig{
|
||||||
|
Server: &model.ServerConf{
|
||||||
|
Host: "0.0.0.0",
|
||||||
|
Port: 36851,
|
||||||
|
},
|
||||||
|
Task: &model.TaskConf{
|
||||||
|
Delay: 0,
|
||||||
|
Interval: 0,
|
||||||
|
},
|
||||||
|
Certs: nil,
|
||||||
|
Providers: nil,
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,3 +0,0 @@
|
||||||
package conf
|
|
||||||
|
|
||||||
var appConf *AppConfig
|
|
530
src/config.go
530
src/config.go
|
@ -1,267 +1,267 @@
|
||||||
package src
|
package src
|
||||||
|
|
||||||
//import (
|
import (
|
||||||
// "acme-mana/src/crypto"
|
"acme-mana/src/crypto"
|
||||||
// "bufio"
|
"bufio"
|
||||||
// "fmt"
|
"fmt"
|
||||||
// "github.com/go-acme/lego/v4/log"
|
"github.com/go-acme/lego/v4/log"
|
||||||
// "github.com/go-acme/lego/v4/platform/config/env"
|
"github.com/go-acme/lego/v4/platform/config/env"
|
||||||
// "gopkg.in/yaml.v3"
|
"gopkg.in/yaml.v3"
|
||||||
// "os"
|
"os"
|
||||||
// "strings"
|
"strings"
|
||||||
//)
|
)
|
||||||
//
|
|
||||||
//func ReadConfig() *AppConfig {
|
func ReadConfig() *AppConfig {
|
||||||
// if DnsProviderSupports != nil {
|
if DnsProviderSupports != nil {
|
||||||
// return nil
|
return nil
|
||||||
// }
|
}
|
||||||
// InitConfig()
|
InitConfig()
|
||||||
// file, err := os.ReadFile(GetEnvConf().ConfFile)
|
file, err := os.ReadFile(GetEnvConf().ConfFile)
|
||||||
// if err != nil {
|
if err != nil {
|
||||||
// log.Fatal(err)
|
log.Fatal(err)
|
||||||
// }
|
}
|
||||||
// var conf *AppConfig
|
var conf *AppConfig
|
||||||
// err = yaml.Unmarshal(file, &conf)
|
err = yaml.Unmarshal(file, &conf)
|
||||||
// if err != nil {
|
if err != nil {
|
||||||
// log.Fatal(err)
|
log.Fatal(err)
|
||||||
// }
|
}
|
||||||
// return conf
|
return conf
|
||||||
//}
|
}
|
||||||
//
|
|
||||||
//func InitConfig() {
|
func InitConfig() {
|
||||||
// // 判断当前目录下是否存在配置文件 config.yml
|
// 判断当前目录下是否存在配置文件 config.yml
|
||||||
// _, err := os.Stat(GetEnvConf().ConfFile)
|
_, err := os.Stat(GetEnvConf().ConfFile)
|
||||||
//
|
|
||||||
// if os.IsNotExist(err) {
|
if os.IsNotExist(err) {
|
||||||
// // 配置文件不存在,则创建一个
|
// 配置文件不存在,则创建一个
|
||||||
// log.Infof("配置文件不存在,自动创建默认配置文件")
|
log.Infof("配置文件不存在,自动创建默认配置文件")
|
||||||
// // 生成默认配置
|
// 生成默认配置
|
||||||
// conf := readNewConf()
|
conf := readNewConf()
|
||||||
// // 创建一个默认的配置文件
|
// 创建一个默认的配置文件
|
||||||
// file, err := os.Create(GetEnvConf().ConfFile)
|
file, err := os.Create(GetEnvConf().ConfFile)
|
||||||
// if err != nil {
|
if err != nil {
|
||||||
// log.Fatal(err)
|
log.Fatal(err)
|
||||||
// }
|
}
|
||||||
// data, err := yaml.Marshal(conf)
|
data, err := yaml.Marshal(conf)
|
||||||
// if err != nil {
|
if err != nil {
|
||||||
// log.Fatal(err)
|
log.Fatal(err)
|
||||||
// }
|
}
|
||||||
// // 写入配置文件
|
// 写入配置文件
|
||||||
// _, err = file.Write(data)
|
_, err = file.Write(data)
|
||||||
// if err != nil {
|
if err != nil {
|
||||||
// log.Fatal(err)
|
log.Fatal(err)
|
||||||
// }
|
}
|
||||||
// }
|
}
|
||||||
//
|
|
||||||
//}
|
}
|
||||||
//
|
|
||||||
//func readNewConf() *AppConfig {
|
func readNewConf() *AppConfig {
|
||||||
// conf := defaultConf()
|
conf := defaultConf()
|
||||||
// log.Println("无配置文件, 生成配置文件")
|
log.Println("无配置文件, 生成配置文件")
|
||||||
//
|
|
||||||
// conf.CertDir = scanConfDefault("请输入证书保存目录; 默认为 cert", "cert")
|
conf.CertDir = scanConfDefault("请输入证书保存目录; 默认为 cert", "cert")
|
||||||
// isGenMsg := "是否需要自动生成用于数据传输加密的RSA密钥对? \n请输入yes(Y)/no(N) 默认为 yes"
|
isGenMsg := "是否需要自动生成用于数据传输加密的RSA密钥对? \n请输入yes(Y)/no(N) 默认为 yes"
|
||||||
// isGenErrMsg := "请输入yes(Y)/no(N)"
|
isGenErrMsg := "请输入yes(Y)/no(N)"
|
||||||
// isGenValues := []string{"yes", "no", "Y", "N"}
|
isGenValues := []string{"yes", "no", "Y", "N"}
|
||||||
// isGenEncrypt := scanConfDefaultCheck(isGenMsg, "yes", isGenValues, isGenErrMsg)
|
isGenEncrypt := scanConfDefaultCheck(isGenMsg, "yes", isGenValues, isGenErrMsg)
|
||||||
// if isGenEncrypt == "no" || isGenEncrypt == "N" {
|
if isGenEncrypt == "no" || isGenEncrypt == "N" {
|
||||||
// conf.Encrypt.PriKey = scanConf("请输入RSA私钥", "请输入RSA私钥")
|
conf.Encrypt.PriKey = scanConf("请输入RSA私钥", "请输入RSA私钥")
|
||||||
// conf.Encrypt.PubKey = scanConf("请输入RSA公钥", "请输入RSA公钥")
|
conf.Encrypt.PubKey = scanConf("请输入RSA公钥", "请输入RSA公钥")
|
||||||
// }
|
}
|
||||||
//
|
|
||||||
// msg := fmt.Sprintf("请输入DNS提供商; 当前支持的: %s", strings.Join(DnsProviderSupports, ","))
|
msg := fmt.Sprintf("请输入DNS提供商; 当前支持的: %s", strings.Join(DnsProviderSupports, ","))
|
||||||
// errMsg := fmt.Sprintf("不支持的DNS提供商; 当前支持的: %s", strings.Join(DnsProviderSupports, ","))
|
errMsg := fmt.Sprintf("不支持的DNS提供商; 当前支持的: %s", strings.Join(DnsProviderSupports, ","))
|
||||||
// conf.Use = scanConfDefaultCheck(msg, "", DnsProviderSupports, errMsg)
|
conf.Use = scanConfDefaultCheck(msg, "", DnsProviderSupports, errMsg)
|
||||||
// switch conf.Use {
|
switch conf.Use {
|
||||||
// case "alidns":
|
case "alidns":
|
||||||
// fmt.Printf("阿里云DNS配置帮助页: \n%s\n", "https://go-acme.github.io/lego/dns/alidns/index.html")
|
fmt.Printf("阿里云DNS配置帮助页: \n%s\n", "https://go-acme.github.io/lego/dns/alidns/index.html")
|
||||||
// fmt.Printf("阿里云令牌获取方式:\n%s\n", "https://usercenter.console.aliyun.com/#/manage/ak")
|
fmt.Printf("阿里云令牌获取方式:\n%s\n", "https://usercenter.console.aliyun.com/#/manage/ak")
|
||||||
// fmt.Printf("阿里云SDK客户端项目地址:\n%s\n", "https://github.com/aliyun/alibaba-cloud-sdk-go?tab=readme-ov-file")
|
fmt.Printf("阿里云SDK客户端项目地址:\n%s\n", "https://github.com/aliyun/alibaba-cloud-sdk-go?tab=readme-ov-file")
|
||||||
// conf.Provider.Ali.RegionID = scanConf("请输入阿里云Region ID", "请输入阿里云Region ID")
|
conf.Provider.Ali.RegionID = scanConf("请输入阿里云Region ID", "请输入阿里云Region ID")
|
||||||
// conf.Provider.Ali.APIKey = scanConf("请输入阿里云API Key", "请输入阿里云API Key")
|
conf.Provider.Ali.APIKey = scanConf("请输入阿里云API Key", "请输入阿里云API Key")
|
||||||
// conf.Provider.Ali.SecretKey = scanConf("请输入阿里云Secret Key", "请输入阿里云Secret Key")
|
conf.Provider.Ali.SecretKey = scanConf("请输入阿里云Secret Key", "请输入阿里云Secret Key")
|
||||||
// case "tencentcloud":
|
case "tencentcloud":
|
||||||
// fmt.Printf("腾讯云DNS配置帮助页: \n%s\n", "https://go-acme.github.io/lego/dns/tencentcloud/index.html")
|
fmt.Printf("腾讯云DNS配置帮助页: \n%s\n", "https://go-acme.github.io/lego/dns/tencentcloud/index.html")
|
||||||
// fmt.Printf("腾讯云令牌获取方式: \n%s\n", "https://console.cloud.tencent.com/cam/capi")
|
fmt.Printf("腾讯云令牌获取方式: \n%s\n", "https://console.cloud.tencent.com/cam/capi")
|
||||||
// fmt.Printf("腾讯云SDK客户端项目地址: \n%s\n", "https://github.com/tencentcloud/tencentcloud-sdk-go?tab=readme-ov-file")
|
fmt.Printf("腾讯云SDK客户端项目地址: \n%s\n", "https://github.com/tencentcloud/tencentcloud-sdk-go?tab=readme-ov-file")
|
||||||
// conf.Provider.Tencent.SecretId = scanConf("请输入腾讯云Secret Id", "请输入腾讯云Secret Id")
|
conf.Provider.Tencent.SecretId = scanConf("请输入腾讯云Secret Id", "请输入腾讯云Secret Id")
|
||||||
// conf.Provider.Tencent.SecretKey = scanConf("请输入腾讯云Secret Key", "请输入腾讯云Secret Key")
|
conf.Provider.Tencent.SecretKey = scanConf("请输入腾讯云Secret Key", "请输入腾讯云Secret Key")
|
||||||
// case "cloudflare":
|
case "cloudflare":
|
||||||
// fmt.Printf("Cloudflare DNS配置帮助页: \n%s\n", "https://go-acme.github.io/lego/dns/tencentcloud/index.html")
|
fmt.Printf("Cloudflare DNS配置帮助页: \n%s\n", "https://go-acme.github.io/lego/dns/tencentcloud/index.html")
|
||||||
// fmt.Printf("Cloudflare 令牌获取方式: \n%s\n", "https://blog.cloudflare.com/zh-cn/api-tokens-general-availability/")
|
fmt.Printf("Cloudflare 令牌获取方式: \n%s\n", "https://blog.cloudflare.com/zh-cn/api-tokens-general-availability/")
|
||||||
// fmt.Printf("Cloudflare SDK客户端项目地址: \n%s\n", "https://github.com/cloudflare/cloudflare-go")
|
fmt.Printf("Cloudflare SDK客户端项目地址: \n%s\n", "https://github.com/cloudflare/cloudflare-go")
|
||||||
// conf.Provider.CloudFlare.Token = scanConf("请输入CloudFlare DNS API Token", "请输入CloudFlare Token")
|
conf.Provider.CloudFlare.Token = scanConf("请输入CloudFlare DNS API Token", "请输入CloudFlare Token")
|
||||||
// }
|
}
|
||||||
// isAddDomainMsg := "是否需要添加证书获取配置?\n您可以在此处通过控制台交互添加;也可以在配置文件创建后,直接修改配置文件.\n请输入yes(Y)/no(N) 默认为 yes"
|
isAddDomainMsg := "是否需要添加证书获取配置?\n您可以在此处通过控制台交互添加;也可以在配置文件创建后,直接修改配置文件.\n请输入yes(Y)/no(N) 默认为 yes"
|
||||||
// isAddDomain := scanConfDefaultCheck(isAddDomainMsg, "yes", isGenValues, isGenErrMsg)
|
isAddDomain := scanConfDefaultCheck(isAddDomainMsg, "yes", isGenValues, isGenErrMsg)
|
||||||
// if isAddDomain == "no" || isAddDomain == "N" {
|
if isAddDomain == "no" || isAddDomain == "N" {
|
||||||
// fmt.Printf("您可以通过手动修改%s文件, 调整证书获取配置.", GetEnvConf().ConfFile)
|
fmt.Printf("您可以通过手动修改%s文件, 调整证书获取配置.", GetEnvConf().ConfFile)
|
||||||
// conf.Domains = []Domain{}
|
conf.Domains = []Domain{}
|
||||||
// return conf
|
return conf
|
||||||
// }
|
}
|
||||||
// conf.Domains = []Domain{}
|
conf.Domains = []Domain{}
|
||||||
// for {
|
for {
|
||||||
// name := scanConf("请输入配置名称", "配置名称不能为空")
|
name := scanConf("请输入配置名称", "配置名称不能为空")
|
||||||
// email := scanConf("请输入邮箱", "邮箱不能为空")
|
email := scanConf("请输入邮箱", "邮箱不能为空")
|
||||||
// host := scanConf("请输入主机名;支持泛解析;\n支持多个域名,多个域名用,(英文逗号)分割;\n如: example.com,*.example.com\n", "主机名不能为空")
|
host := scanConf("请输入主机名;支持泛解析;\n支持多个域名,多个域名用,(英文逗号)分割;\n如: example.com,*.example.com\n", "主机名不能为空")
|
||||||
// // 将host通过,分割为数组
|
// 将host通过,分割为数组
|
||||||
// hosts := strings.Split(host, ",")
|
hosts := strings.Split(host, ",")
|
||||||
// conf.Domains = append(conf.Domains, Domain{
|
conf.Domains = append(conf.Domains, Domain{
|
||||||
// Name: name,
|
Name: name,
|
||||||
// Email: email,
|
Email: email,
|
||||||
// Host: hosts,
|
Host: hosts,
|
||||||
// })
|
})
|
||||||
// isAddNextDomainMsg := "是否需要继续添加证书获取配置?\n请输入yes(Y)/no(N) 默认为 yes"
|
isAddNextDomainMsg := "是否需要继续添加证书获取配置?\n请输入yes(Y)/no(N) 默认为 yes"
|
||||||
// isAddNextDomain := scanConfDefaultCheck(isAddNextDomainMsg, "yes", isGenValues, isGenErrMsg)
|
isAddNextDomain := scanConfDefaultCheck(isAddNextDomainMsg, "yes", isGenValues, isGenErrMsg)
|
||||||
// if isAddNextDomain == "no" || isAddNextDomain == "N" {
|
if isAddNextDomain == "no" || isAddNextDomain == "N" {
|
||||||
// fmt.Printf("您后续可以通过手动修改%s文件, 调整证书获取配置.", GetEnvConf().ConfFile)
|
fmt.Printf("您后续可以通过手动修改%s文件, 调整证书获取配置.", GetEnvConf().ConfFile)
|
||||||
// return conf
|
return conf
|
||||||
// }
|
}
|
||||||
// }
|
}
|
||||||
//}
|
}
|
||||||
//
|
|
||||||
//// 读取用户输入
|
// 读取用户输入
|
||||||
//func scanConf(msg string, errMsg string) string {
|
func scanConf(msg string, errMsg string) string {
|
||||||
// for {
|
for {
|
||||||
// log.Println(msg)
|
log.Println(msg)
|
||||||
// reader := bufio.NewReader(os.Stdin)
|
reader := bufio.NewReader(os.Stdin)
|
||||||
// name, err := reader.ReadString('\n')
|
name, err := reader.ReadString('\n')
|
||||||
// if err != nil {
|
if err != nil {
|
||||||
// fmt.Println("读取失败;", err)
|
fmt.Println("读取失败;", err)
|
||||||
// continue
|
continue
|
||||||
// }
|
}
|
||||||
// name = strings.Trim(name, "\r\n")
|
name = strings.Trim(name, "\r\n")
|
||||||
// if name == "" {
|
if name == "" {
|
||||||
// fmt.Println(errMsg)
|
fmt.Println(errMsg)
|
||||||
// continue
|
continue
|
||||||
// }
|
}
|
||||||
// return name
|
return name
|
||||||
// }
|
}
|
||||||
//}
|
}
|
||||||
//
|
|
||||||
//func scanConfDefault(msg string, defaultContent string) string {
|
func scanConfDefault(msg string, defaultContent string) string {
|
||||||
// for {
|
for {
|
||||||
// log.Println(msg)
|
log.Println(msg)
|
||||||
// reader := bufio.NewReader(os.Stdin)
|
reader := bufio.NewReader(os.Stdin)
|
||||||
// name, err := reader.ReadString('\n')
|
name, err := reader.ReadString('\n')
|
||||||
// if err != nil {
|
if err != nil {
|
||||||
// fmt.Println("读取失败;", err)
|
fmt.Println("读取失败;", err)
|
||||||
// continue
|
continue
|
||||||
// }
|
}
|
||||||
// name = strings.Trim(name, "\r\n")
|
name = strings.Trim(name, "\r\n")
|
||||||
// if name == "" {
|
if name == "" {
|
||||||
// return defaultContent
|
return defaultContent
|
||||||
// }
|
}
|
||||||
// return name
|
return name
|
||||||
// }
|
}
|
||||||
//}
|
}
|
||||||
//
|
|
||||||
//func scanConfDefaultCheck(msg string, defaultContent string, values []string, errMsg string) string {
|
func scanConfDefaultCheck(msg string, defaultContent string, values []string, errMsg string) string {
|
||||||
// for {
|
for {
|
||||||
// content := scanConfDefault(msg, defaultContent)
|
content := scanConfDefault(msg, defaultContent)
|
||||||
// // 判断内容是否在values中
|
// 判断内容是否在values中
|
||||||
// for _, value := range values {
|
for _, value := range values {
|
||||||
// if value == content {
|
if value == content {
|
||||||
// return content
|
return content
|
||||||
// }
|
}
|
||||||
// }
|
}
|
||||||
// log.Println(errMsg)
|
log.Println(errMsg)
|
||||||
// }
|
}
|
||||||
//}
|
}
|
||||||
//
|
|
||||||
//func defaultConf() *AppConfig {
|
func defaultConf() *AppConfig {
|
||||||
// //priKey, pubKey, err := GenRsa()
|
//priKey, pubKey, err := GenRsa()
|
||||||
// priKey, pubKey, err := crypto.GenRSA()
|
priKey, pubKey, err := crypto.GenRSA()
|
||||||
// if err != nil {
|
if err != nil {
|
||||||
// log.Fatal(err)
|
log.Fatal(err)
|
||||||
// }
|
}
|
||||||
// return &AppConfig{
|
return &AppConfig{
|
||||||
// Use: "Ali",
|
Use: "Ali",
|
||||||
// CertDir: "cert",
|
CertDir: "cert",
|
||||||
// Provider: AppProvider{
|
Provider: AppProvider{
|
||||||
// Ali: AliProvider{
|
Ali: AliProvider{
|
||||||
// RegionID: "cn-hangzhou",
|
RegionID: "cn-hangzhou",
|
||||||
// APIKey: "api_key",
|
APIKey: "api_key",
|
||||||
// SecretKey: "secret_key",
|
SecretKey: "secret_key",
|
||||||
// },
|
},
|
||||||
// Tencent: TencentProvider{
|
Tencent: TencentProvider{
|
||||||
// SecretId: "secret_id",
|
SecretId: "secret_id",
|
||||||
// SecretKey: "secret_key",
|
SecretKey: "secret_key",
|
||||||
// },
|
},
|
||||||
// CloudFlare: CloudFlareProvider{
|
CloudFlare: CloudFlareProvider{
|
||||||
// Token: "token",
|
Token: "token",
|
||||||
// },
|
},
|
||||||
// },
|
},
|
||||||
// Domains: []Domain{
|
Domains: []Domain{
|
||||||
// {
|
{
|
||||||
// Name: "example.com",
|
Name: "example.com",
|
||||||
// Email: "email@example.com",
|
Email: "email@example.com",
|
||||||
// Host: []string{"www.example.com"},
|
Host: []string{"www.example.com"},
|
||||||
// },
|
},
|
||||||
// },
|
},
|
||||||
// Encrypt: Encrypt{
|
Encrypt: Encrypt{
|
||||||
// PriKey: priKey,
|
PriKey: priKey,
|
||||||
// PubKey: pubKey,
|
PubKey: pubKey,
|
||||||
// },
|
},
|
||||||
// }
|
}
|
||||||
//}
|
}
|
||||||
//
|
|
||||||
//type AppConfig struct {
|
type AppConfig struct {
|
||||||
// Use string
|
Use string
|
||||||
//
|
|
||||||
// CertDir string
|
CertDir string
|
||||||
//
|
|
||||||
// Provider AppProvider
|
Provider AppProvider
|
||||||
//
|
|
||||||
// Domains []Domain
|
Domains []Domain
|
||||||
//
|
|
||||||
// Encrypt Encrypt
|
Encrypt Encrypt
|
||||||
//}
|
}
|
||||||
//
|
|
||||||
//type AppProvider struct {
|
type AppProvider struct {
|
||||||
// Ali AliProvider
|
Ali AliProvider
|
||||||
// Tencent TencentProvider
|
Tencent TencentProvider
|
||||||
// CloudFlare CloudFlareProvider
|
CloudFlare CloudFlareProvider
|
||||||
//}
|
}
|
||||||
//type AliProvider struct {
|
type AliProvider struct {
|
||||||
// RegionID string
|
RegionID string
|
||||||
// APIKey string
|
APIKey string
|
||||||
// SecretKey string
|
SecretKey string
|
||||||
//}
|
}
|
||||||
//type TencentProvider struct {
|
type TencentProvider struct {
|
||||||
// SecretId string
|
SecretId string
|
||||||
// SecretKey string
|
SecretKey string
|
||||||
//}
|
}
|
||||||
//type CloudFlareProvider struct {
|
type CloudFlareProvider struct {
|
||||||
// Token string
|
Token string
|
||||||
//}
|
}
|
||||||
//type Domain struct {
|
type Domain struct {
|
||||||
// Name string
|
Name string
|
||||||
// Email string
|
Email string
|
||||||
// Host []string
|
Host []string
|
||||||
//}
|
}
|
||||||
//type Encrypt struct {
|
type Encrypt struct {
|
||||||
// PriKey string
|
PriKey string
|
||||||
// PubKey string
|
PubKey string
|
||||||
//}
|
}
|
||||||
//
|
|
||||||
//func (conf AppConfig) FindDomain(name string) *Domain {
|
func (conf AppConfig) FindDomain(name string) *Domain {
|
||||||
// for _, domain := range conf.Domains {
|
for _, domain := range conf.Domains {
|
||||||
// if domain.Name == name {
|
if domain.Name == name {
|
||||||
// return &domain
|
return &domain
|
||||||
// }
|
}
|
||||||
// }
|
}
|
||||||
// return nil
|
return nil
|
||||||
//}
|
}
|
||||||
//
|
|
||||||
//const ENV_CONF_FILE = "ACME_MANA_CONF_FILE"
|
const ENV_CONF_FILE = "ACME_MANA_CONF_FILE"
|
||||||
//
|
|
||||||
//func InitRuntimeConf() *EnvConf {
|
func InitRuntimeConf() *EnvConf {
|
||||||
// return &EnvConf{
|
return &EnvConf{
|
||||||
// ConfFile: env.GetOrDefaultString(ENV_CONF_FILE, "config.yml"),
|
ConfFile: env.GetOrDefaultString(ENV_CONF_FILE, "config.yml"),
|
||||||
// }
|
}
|
||||||
//}
|
}
|
||||||
//
|
|
||||||
//type EnvConf struct {
|
type EnvConf struct {
|
||||||
// ConfFile string
|
ConfFile string
|
||||||
//}
|
}
|
||||||
|
|
534
src/daemon.go
534
src/daemon.go
|
@ -1,269 +1,269 @@
|
||||||
package src
|
package src
|
||||||
|
|
||||||
//import (
|
import (
|
||||||
// "encoding/json"
|
"encoding/json"
|
||||||
// "log"
|
"log"
|
||||||
// "net"
|
"net"
|
||||||
// "os"
|
"os"
|
||||||
// "os/exec"
|
"os/exec"
|
||||||
// "path"
|
"path"
|
||||||
// "path/filepath"
|
"path/filepath"
|
||||||
// "strconv"
|
"strconv"
|
||||||
// "syscall"
|
"syscall"
|
||||||
//)
|
)
|
||||||
//
|
|
||||||
//var stdout *os.File
|
var stdout *os.File
|
||||||
//var stderr *os.File
|
var stderr *os.File
|
||||||
//
|
|
||||||
//// Start 启动/*
|
// Start 启动/*
|
||||||
//func Start() {
|
func Start() {
|
||||||
// initLog()
|
initLog()
|
||||||
// args := os.Args
|
args := os.Args
|
||||||
// if len(args) <= 1 {
|
if len(args) <= 1 {
|
||||||
// //daemonStart()
|
//daemonStart()
|
||||||
// doTask()
|
doTask()
|
||||||
// return
|
return
|
||||||
// }
|
}
|
||||||
// command := args[1]
|
command := args[1]
|
||||||
// switch command {
|
switch command {
|
||||||
// case "help":
|
case "help":
|
||||||
// showHelp()
|
showHelp()
|
||||||
// case "block":
|
case "block":
|
||||||
// doTask()
|
doTask()
|
||||||
// case "start":
|
case "start":
|
||||||
// daemonStart()
|
daemonStart()
|
||||||
// case "stop":
|
case "stop":
|
||||||
// daemonStop()
|
daemonStop()
|
||||||
// case "status":
|
case "status":
|
||||||
// daemonStatus()
|
daemonStatus()
|
||||||
// case "dump":
|
case "dump":
|
||||||
// dumpConfig()
|
dumpConfig()
|
||||||
// case "domains":
|
case "domains":
|
||||||
// showDomains()
|
showDomains()
|
||||||
// case "pubkey":
|
case "pubkey":
|
||||||
// showPubkey()
|
showPubkey()
|
||||||
// case "apply":
|
case "apply":
|
||||||
// applyOnce()
|
applyOnce()
|
||||||
// case "-s":
|
case "-s":
|
||||||
// daemonCommand()
|
daemonCommand()
|
||||||
// default:
|
default:
|
||||||
// log.Fatalf("Unknown command: %s", command)
|
log.Fatalf("Unknown command: %s", command)
|
||||||
// }
|
}
|
||||||
//}
|
}
|
||||||
//
|
|
||||||
//// 初始化日志文件
|
// 初始化日志文件
|
||||||
//func initLog() {
|
func initLog() {
|
||||||
// pwd, err := os.Getwd()
|
pwd, err := os.Getwd()
|
||||||
// if err != nil {
|
if err != nil {
|
||||||
// log.Fatalf("Failed to get current working directory: %v", err)
|
log.Fatalf("Failed to get current working directory: %v", err)
|
||||||
// }
|
}
|
||||||
// dir := path.Join(pwd, "log")
|
dir := path.Join(pwd, "log")
|
||||||
// _, err = os.Stat(dir)
|
_, err = os.Stat(dir)
|
||||||
// if os.IsNotExist(err) {
|
if os.IsNotExist(err) {
|
||||||
// err := os.Mkdir(dir, 0777)
|
err := os.Mkdir(dir, 0777)
|
||||||
// if err != nil {
|
if err != nil {
|
||||||
// log.Fatalf("Failed to create directory: %v", err)
|
log.Fatalf("Failed to create directory: %v", err)
|
||||||
// }
|
}
|
||||||
// }
|
}
|
||||||
// outFile, err := os.OpenFile(path.Join(dir, "out.log"), os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0644)
|
outFile, err := os.OpenFile(path.Join(dir, "out.log"), os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0644)
|
||||||
// defer outFile.Close()
|
defer outFile.Close()
|
||||||
// stdout = outFile
|
stdout = outFile
|
||||||
//
|
|
||||||
// errFile, err := os.OpenFile(path.Join(dir, "err.log"), os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0644)
|
errFile, err := os.OpenFile(path.Join(dir, "err.log"), os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0644)
|
||||||
// defer stderr.Close()
|
defer stderr.Close()
|
||||||
// stderr = errFile
|
stderr = errFile
|
||||||
//}
|
}
|
||||||
//
|
|
||||||
//func showHelp() {
|
func showHelp() {
|
||||||
//}
|
}
|
||||||
//
|
|
||||||
//// 守护进程启动
|
// 守护进程启动
|
||||||
//func daemonStart() {
|
func daemonStart() {
|
||||||
// GetAppConfig()
|
GetAppConfig()
|
||||||
// isDaemon := os.Getenv("GO_DAEMON")
|
isDaemon := os.Getenv("GO_DAEMON")
|
||||||
// log.Println("Run Daemon, DAEMON Is " + isDaemon)
|
log.Println("Run Daemon, DAEMON Is " + isDaemon)
|
||||||
// if isDaemon != "1" {
|
if isDaemon != "1" {
|
||||||
// // 直接启动
|
// 直接启动
|
||||||
// if isRunning() {
|
if isRunning() {
|
||||||
// log.Println("Daemon is already running.")
|
log.Println("Daemon is already running.")
|
||||||
// return
|
return
|
||||||
// }
|
}
|
||||||
//
|
|
||||||
// workPath, err := os.Executable()
|
workPath, err := os.Executable()
|
||||||
// if err != nil {
|
if err != nil {
|
||||||
// log.Fatalf("Failed to get executable path: %v", err)
|
log.Fatalf("Failed to get executable path: %v", err)
|
||||||
// }
|
}
|
||||||
// cmd := exec.Cmd{
|
cmd := exec.Cmd{
|
||||||
// Path: workPath,
|
Path: workPath,
|
||||||
// Args: os.Args,
|
Args: os.Args,
|
||||||
// Dir: filepath.Dir(workPath),
|
Dir: filepath.Dir(workPath),
|
||||||
// Env: append(os.Environ(), "GO_DAEMON=1"),
|
Env: append(os.Environ(), "GO_DAEMON=1"),
|
||||||
// //Stdin: os.Stdin,
|
//Stdin: os.Stdin,
|
||||||
// Stdout: stdout,
|
Stdout: stdout,
|
||||||
// Stderr: stderr,
|
Stderr: stderr,
|
||||||
// //Stdin: os.Stdin,
|
//Stdin: os.Stdin,
|
||||||
// //Stdout: os.Stdout,
|
//Stdout: os.Stdout,
|
||||||
// //Stderr: os.Stderr,
|
//Stderr: os.Stderr,
|
||||||
// SysProcAttr: &syscall.SysProcAttr{},
|
SysProcAttr: &syscall.SysProcAttr{},
|
||||||
// }
|
}
|
||||||
//
|
|
||||||
// log.Println("Starting daemon...")
|
log.Println("Starting daemon...")
|
||||||
// err = cmd.Start()
|
err = cmd.Start()
|
||||||
// if err != nil {
|
if err != nil {
|
||||||
// log.Fatalf("Failed to start daemon: %v", err)
|
log.Fatalf("Failed to start daemon: %v", err)
|
||||||
// }
|
}
|
||||||
// err = os.WriteFile(PidFile, []byte(strconv.Itoa(cmd.Process.Pid)), 0644)
|
err = os.WriteFile(PidFile, []byte(strconv.Itoa(cmd.Process.Pid)), 0644)
|
||||||
// if err != nil {
|
if err != nil {
|
||||||
// log.Fatalf("Failed to write PID file: %v", err)
|
log.Fatalf("Failed to write PID file: %v", err)
|
||||||
// }
|
}
|
||||||
// log.Printf("Daemon started with PID: %d", cmd.Process.Pid)
|
log.Printf("Daemon started with PID: %d", cmd.Process.Pid)
|
||||||
// os.Exit(0)
|
os.Exit(0)
|
||||||
//
|
|
||||||
// } else {
|
} else {
|
||||||
// // 子进程
|
// 子进程
|
||||||
// doTask()
|
doTask()
|
||||||
// }
|
}
|
||||||
//
|
|
||||||
//}
|
}
|
||||||
//
|
|
||||||
//// 守护进程停止
|
// 守护进程停止
|
||||||
//func daemonStop() {
|
func daemonStop() {
|
||||||
// sendCommand("stop")
|
sendCommand("stop")
|
||||||
//}
|
}
|
||||||
//
|
|
||||||
//// 守护进程状态
|
// 守护进程状态
|
||||||
//func daemonStatus() {
|
func daemonStatus() {
|
||||||
// if isRunning() {
|
if isRunning() {
|
||||||
// log.Println("Daemon is running.")
|
log.Println("Daemon is running.")
|
||||||
// } else {
|
} else {
|
||||||
// log.Println("Daemon is not running.")
|
log.Println("Daemon is not running.")
|
||||||
// }
|
}
|
||||||
//}
|
}
|
||||||
//
|
|
||||||
//// 输出配置文件
|
// 输出配置文件
|
||||||
//func dumpConfig() {
|
func dumpConfig() {
|
||||||
// //config, err := json.Marshal(GetAppConfig())
|
//config, err := json.Marshal(GetAppConfig())
|
||||||
// config, err := json.MarshalIndent(GetAppConfig(), "", " ")
|
config, err := json.MarshalIndent(GetAppConfig(), "", " ")
|
||||||
// if err != nil {
|
if err != nil {
|
||||||
// log.Fatalf("Failed to marshal config: %v", err)
|
log.Fatalf("Failed to marshal config: %v", err)
|
||||||
// }
|
}
|
||||||
// log.Println(string(config))
|
log.Println(string(config))
|
||||||
//}
|
}
|
||||||
//
|
|
||||||
//// 手动执行一次证书申请
|
// 手动执行一次证书申请
|
||||||
//func applyOnce() {
|
func applyOnce() {
|
||||||
// if len(os.Args) < 3 {
|
if len(os.Args) < 3 {
|
||||||
// log.Fatalf("Please enter domain name!")
|
log.Fatalf("Please enter domain name!")
|
||||||
// }
|
}
|
||||||
// name := os.Args[2]
|
name := os.Args[2]
|
||||||
// if name == "" {
|
if name == "" {
|
||||||
// log.Fatalf("No domain specified!")
|
log.Fatalf("No domain specified!")
|
||||||
// }
|
}
|
||||||
// domain := GetAppConfig().FindDomain(name)
|
domain := GetAppConfig().FindDomain(name)
|
||||||
// if domain == nil {
|
if domain == nil {
|
||||||
// log.Fatalf("Domain not found: %s", name)
|
log.Fatalf("Domain not found: %s", name)
|
||||||
// }
|
}
|
||||||
// Apply(*domain)
|
Apply(*domain)
|
||||||
//}
|
}
|
||||||
//
|
|
||||||
//// 输出域名列表
|
// 输出域名列表
|
||||||
//func showDomains() {
|
func showDomains() {
|
||||||
// domains := GetAppConfig().Domains
|
domains := GetAppConfig().Domains
|
||||||
// // 格式化为json并打印
|
// 格式化为json并打印
|
||||||
// config, err := json.MarshalIndent(domains, "", " ")
|
config, err := json.MarshalIndent(domains, "", " ")
|
||||||
// if err != nil {
|
if err != nil {
|
||||||
// log.Fatalf("Failed to marshal config: %v", err)
|
log.Fatalf("Failed to marshal config: %v", err)
|
||||||
// }
|
}
|
||||||
// log.Println(string(config))
|
log.Println(string(config))
|
||||||
//}
|
}
|
||||||
//
|
|
||||||
//// 输出公钥
|
// 输出公钥
|
||||||
//func showPubkey() {
|
func showPubkey() {
|
||||||
// key := GetAppConfig().Encrypt.PubKey
|
key := GetAppConfig().Encrypt.PubKey
|
||||||
// log.Println(key)
|
log.Println(key)
|
||||||
//}
|
}
|
||||||
//
|
|
||||||
//// 守护进程接收命令
|
// 守护进程接收命令
|
||||||
//func daemonCommand() {
|
func daemonCommand() {
|
||||||
// log.Println("Sending command...")
|
log.Println("Sending command...")
|
||||||
// command := os.Args[2]
|
command := os.Args[2]
|
||||||
// sendCommand(command)
|
sendCommand(command)
|
||||||
//
|
|
||||||
//}
|
}
|
||||||
//
|
|
||||||
//// 发送命令
|
// 发送命令
|
||||||
//func sendCommand(command string) {
|
func sendCommand(command string) {
|
||||||
// conn, err := net.Dial("unix", SocketFile)
|
conn, err := net.Dial("unix", SocketFile)
|
||||||
// if err != nil {
|
if err != nil {
|
||||||
// log.Fatalf("Failed to connect to daemon: %v", err)
|
log.Fatalf("Failed to connect to daemon: %v", err)
|
||||||
// }
|
}
|
||||||
// defer func(conn net.Conn) {
|
defer func(conn net.Conn) {
|
||||||
// err := conn.Close()
|
err := conn.Close()
|
||||||
// if err != nil {
|
if err != nil {
|
||||||
// log.Fatalf("Failed to close connection: %v", err)
|
log.Fatalf("Failed to close connection: %v", err)
|
||||||
// }
|
}
|
||||||
// }(conn)
|
}(conn)
|
||||||
//
|
|
||||||
// _, err = conn.Write([]byte(command))
|
_, err = conn.Write([]byte(command))
|
||||||
// if err != nil {
|
if err != nil {
|
||||||
// log.Fatalf("Failed to send command: %v", err)
|
log.Fatalf("Failed to send command: %v", err)
|
||||||
// }
|
}
|
||||||
//
|
|
||||||
// log.Printf("Sending command '%s' to daemon with PID: %d", command, 0)
|
log.Printf("Sending command '%s' to daemon with PID: %d", command, 0)
|
||||||
//}
|
}
|
||||||
//
|
|
||||||
//// 业务进程执行任务
|
// 业务进程执行任务
|
||||||
//func doTask() {
|
func doTask() {
|
||||||
//
|
|
||||||
// // 监听主进程下发的指令
|
// 监听主进程下发的指令
|
||||||
// go InitSocket()
|
go InitSocket()
|
||||||
//
|
|
||||||
// // 监听HTTP请求
|
// 监听HTTP请求
|
||||||
// go InitHttpServer("0.0.0.0", 10000)
|
go InitHttpServer("0.0.0.0", 10000)
|
||||||
//
|
|
||||||
// // 自动执行域名证书更新
|
// 自动执行域名证书更新
|
||||||
// go AutoRefreshCert()
|
go AutoRefreshCert()
|
||||||
//
|
|
||||||
// // 阻止退出
|
// 阻止退出
|
||||||
// select {}
|
select {}
|
||||||
//}
|
}
|
||||||
//
|
|
||||||
//// 是否已启动
|
// 是否已启动
|
||||||
//func isRunning() bool {
|
func isRunning() bool {
|
||||||
// log.Println("Checking if daemon is running...")
|
log.Println("Checking if daemon is running...")
|
||||||
// pid, err := readPID()
|
pid, err := readPID()
|
||||||
// if err != nil {
|
if err != nil {
|
||||||
// return false
|
return false
|
||||||
// }
|
}
|
||||||
//
|
|
||||||
// process, err := os.FindProcess(pid)
|
process, err := os.FindProcess(pid)
|
||||||
// log.Println("Found process:", process)
|
log.Println("Found process:", process)
|
||||||
// if err != nil {
|
if err != nil {
|
||||||
// log.Println("Failed to find process:", err)
|
log.Println("Failed to find process:", err)
|
||||||
// return false
|
return false
|
||||||
// }
|
}
|
||||||
// return true
|
return true
|
||||||
// //err = process.Signal(syscall.Signal(0))
|
//err = process.Signal(syscall.Signal(0))
|
||||||
// //log.Println("Signal result:", err)
|
//log.Println("Signal result:", err)
|
||||||
// //return err == nil
|
//return err == nil
|
||||||
//}
|
}
|
||||||
//
|
|
||||||
//// 读取PID文件
|
// 读取PID文件
|
||||||
//func readPID() (int, error) {
|
func readPID() (int, error) {
|
||||||
// log.Println("Reading PID file...")
|
log.Println("Reading PID file...")
|
||||||
// data, err := os.ReadFile(PidFile)
|
data, err := os.ReadFile(PidFile)
|
||||||
// if err != nil {
|
if err != nil {
|
||||||
// log.Println("Failed to read PID file:", err)
|
log.Println("Failed to read PID file:", err)
|
||||||
// return 0, err
|
return 0, err
|
||||||
// }
|
}
|
||||||
// log.Println("PID file content:", string(data))
|
log.Println("PID file content:", string(data))
|
||||||
//
|
|
||||||
// pid, err := strconv.Atoi(string(data))
|
pid, err := strconv.Atoi(string(data))
|
||||||
// if err != nil {
|
if err != nil {
|
||||||
// log.Println("Failed to parse PID:", err)
|
log.Println("Failed to parse PID:", err)
|
||||||
// return 0, err
|
return 0, err
|
||||||
// }
|
}
|
||||||
// log.Println("PID:", pid)
|
log.Println("PID:", pid)
|
||||||
//
|
|
||||||
// return pid, nil
|
return pid, nil
|
||||||
//}
|
}
|
||||||
|
|
286
src/http.go
286
src/http.go
|
@ -1,145 +1,145 @@
|
||||||
package src
|
package src
|
||||||
|
|
||||||
//import (
|
import (
|
||||||
// "acme-mana/src/crypto"
|
"acme-mana/src/crypto"
|
||||||
// "encoding/base64"
|
"encoding/base64"
|
||||||
// "encoding/hex"
|
"encoding/hex"
|
||||||
// "encoding/json"
|
"encoding/json"
|
||||||
// "github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
// "log"
|
"log"
|
||||||
// "os"
|
"os"
|
||||||
// "path"
|
"path"
|
||||||
// "path/filepath"
|
"path/filepath"
|
||||||
// "strconv"
|
"strconv"
|
||||||
//)
|
)
|
||||||
//
|
|
||||||
//func InitHttpServer(host string, port int) {
|
func InitHttpServer(host string, port int) {
|
||||||
//
|
|
||||||
// log.Println("Start http server, Listen " + strconv.Itoa(port))
|
log.Println("Start http server, Listen " + strconv.Itoa(port))
|
||||||
// h := gin.Default()
|
h := gin.Default()
|
||||||
// h.GET("/api/v1/refresh", refreshCert)
|
h.GET("/api/v1/refresh", refreshCert)
|
||||||
// h.GET("/api/v1/cert", getCert)
|
h.GET("/api/v1/cert", getCert)
|
||||||
// h.GET("/api/v1/domain/list", domainList)
|
h.GET("/api/v1/domain/list", domainList)
|
||||||
// err := h.Run(host + ":" + strconv.Itoa(port))
|
err := h.Run(host + ":" + strconv.Itoa(port))
|
||||||
// if err != nil {
|
if err != nil {
|
||||||
// return
|
return
|
||||||
// }
|
}
|
||||||
//}
|
}
|
||||||
//
|
|
||||||
//func domainList(c *gin.Context) {
|
func domainList(c *gin.Context) {
|
||||||
// token := getToken(c)
|
token := getToken(c)
|
||||||
// domains := GetAppConfig().Domains
|
domains := GetAppConfig().Domains
|
||||||
// data, err := json.Marshal(domains)
|
data, err := json.Marshal(domains)
|
||||||
// if err != nil {
|
if err != nil {
|
||||||
// log.Fatal(err)
|
log.Fatal(err)
|
||||||
// }
|
}
|
||||||
//
|
|
||||||
// encryptData := encryptResult(string(data), token)
|
encryptData := encryptResult(string(data), token)
|
||||||
// c.JSON(200, gin.H{
|
c.JSON(200, gin.H{
|
||||||
// "code": 200,
|
"code": 200,
|
||||||
// "msg": "success",
|
"msg": "success",
|
||||||
// "data": encryptData,
|
"data": encryptData,
|
||||||
// })
|
})
|
||||||
//}
|
}
|
||||||
//
|
|
||||||
//func getCert(c *gin.Context) {
|
func getCert(c *gin.Context) {
|
||||||
// name := c.Query("name")
|
name := c.Query("name")
|
||||||
// token := getToken(c)
|
token := getToken(c)
|
||||||
//
|
|
||||||
// dir := GetAppConfig().CertDir
|
dir := GetAppConfig().CertDir
|
||||||
// dir = filepath.Join(dir, name)
|
dir = filepath.Join(dir, name)
|
||||||
// _, err := os.Stat(dir)
|
_, err := os.Stat(dir)
|
||||||
// if os.IsNotExist(err) {
|
if os.IsNotExist(err) {
|
||||||
// c.JSON(200, gin.H{
|
c.JSON(200, gin.H{
|
||||||
// "code": 500,
|
"code": 500,
|
||||||
// "msg": "Name does not exist.",
|
"msg": "Name does not exist.",
|
||||||
// })
|
})
|
||||||
// return
|
return
|
||||||
// }
|
}
|
||||||
// crtFilePath := path.Join(dir, CertFileName)
|
crtFilePath := path.Join(dir, CertFileName)
|
||||||
// crtContent, err := os.ReadFile(crtFilePath)
|
crtContent, err := os.ReadFile(crtFilePath)
|
||||||
// if err != nil {
|
if err != nil {
|
||||||
// c.JSON(200, gin.H{
|
c.JSON(200, gin.H{
|
||||||
// "code": 500,
|
"code": 500,
|
||||||
// "msg": "Failed to read crt file.",
|
"msg": "Failed to read crt file.",
|
||||||
// })
|
})
|
||||||
// return
|
return
|
||||||
// }
|
}
|
||||||
// crt := string(crtContent)
|
crt := string(crtContent)
|
||||||
//
|
|
||||||
// keyFilePath := path.Join(dir, KeyFileName)
|
keyFilePath := path.Join(dir, KeyFileName)
|
||||||
// keyContent, err := os.ReadFile(keyFilePath)
|
keyContent, err := os.ReadFile(keyFilePath)
|
||||||
// if err != nil {
|
if err != nil {
|
||||||
// c.JSON(200, gin.H{
|
c.JSON(200, gin.H{
|
||||||
// "code": 500,
|
"code": 500,
|
||||||
// "msg": "Failed to read key file.",
|
"msg": "Failed to read key file.",
|
||||||
// })
|
})
|
||||||
// return
|
return
|
||||||
// }
|
}
|
||||||
// key := string(keyContent)
|
key := string(keyContent)
|
||||||
//
|
|
||||||
// certInfoFilePath := path.Join(dir, CertInfoFileName)
|
certInfoFilePath := path.Join(dir, CertInfoFileName)
|
||||||
// certInfoContent, err := os.ReadFile(certInfoFilePath)
|
certInfoContent, err := os.ReadFile(certInfoFilePath)
|
||||||
// if err != nil {
|
if err != nil {
|
||||||
// c.JSON(200, gin.H{
|
c.JSON(200, gin.H{
|
||||||
// "code": 500,
|
"code": 500,
|
||||||
// "msg": "Failed to read cert info file.",
|
"msg": "Failed to read cert info file.",
|
||||||
// })
|
})
|
||||||
// return
|
return
|
||||||
// }
|
}
|
||||||
// certInfo := string(certInfoContent)
|
certInfo := string(certInfoContent)
|
||||||
//
|
|
||||||
// data, err := json.Marshal(&DomainData{
|
data, err := json.Marshal(&DomainData{
|
||||||
// Fullchain: crt,
|
Fullchain: crt,
|
||||||
// Key: key,
|
Key: key,
|
||||||
// Info: certInfo,
|
Info: certInfo,
|
||||||
// })
|
})
|
||||||
// if err != nil {
|
if err != nil {
|
||||||
// log.Fatal(err)
|
log.Fatal(err)
|
||||||
// }
|
}
|
||||||
//
|
|
||||||
// encryptData := encryptResult(string(data), token)
|
encryptData := encryptResult(string(data), token)
|
||||||
// c.JSON(200, gin.H{
|
c.JSON(200, gin.H{
|
||||||
// "code": 200,
|
"code": 200,
|
||||||
// "msg": "Success",
|
"msg": "Success",
|
||||||
// "data": encryptData,
|
"data": encryptData,
|
||||||
// })
|
})
|
||||||
//}
|
}
|
||||||
//
|
|
||||||
//func refreshCert(c *gin.Context) {
|
func refreshCert(c *gin.Context) {
|
||||||
// name := c.Param("name")
|
name := c.Param("name")
|
||||||
// domain := GetAppConfig().FindDomain(name)
|
domain := GetAppConfig().FindDomain(name)
|
||||||
// if domain == nil {
|
if domain == nil {
|
||||||
// c.JSON(200, gin.H{
|
c.JSON(200, gin.H{
|
||||||
// "code": 500,
|
"code": 500,
|
||||||
// "msg": "Name does not exist.",
|
"msg": "Name does not exist.",
|
||||||
// })
|
})
|
||||||
// return
|
return
|
||||||
// }
|
}
|
||||||
// Apply(*domain)
|
Apply(*domain)
|
||||||
// c.JSON(200, gin.H{
|
c.JSON(200, gin.H{
|
||||||
// "code": 200,
|
"code": 200,
|
||||||
// "msg": "Success",
|
"msg": "Success",
|
||||||
// })
|
})
|
||||||
//}
|
}
|
||||||
//
|
|
||||||
//func getToken(c *gin.Context) (token string) {
|
func getToken(c *gin.Context) (token string) {
|
||||||
// token = c.Query("token")
|
token = c.Query("token")
|
||||||
// token = decryptParam(token)
|
token = decryptParam(token)
|
||||||
// return
|
return
|
||||||
//}
|
}
|
||||||
//
|
|
||||||
//func decryptParam(param string) string {
|
func decryptParam(param string) string {
|
||||||
// priKey := GetAppConfig().Encrypt.PriKey
|
priKey := GetAppConfig().Encrypt.PriKey
|
||||||
// tokenBytes, err := hex.DecodeString(param)
|
tokenBytes, err := hex.DecodeString(param)
|
||||||
// tokenPlain, err := crypto.DecryptRSABase64(priKey, tokenBytes)
|
tokenPlain, err := crypto.DecryptRSABase64(priKey, tokenBytes)
|
||||||
// if err != nil {
|
if err != nil {
|
||||||
// log.Fatal(err)
|
log.Fatal(err)
|
||||||
// }
|
}
|
||||||
// return string(tokenPlain)
|
return string(tokenPlain)
|
||||||
//}
|
}
|
||||||
//
|
|
||||||
//func encryptResult(content string, token string) string {
|
func encryptResult(content string, token string) string {
|
||||||
// result := crypto.EncryptAES([]byte(token), []byte(content))
|
result := crypto.EncryptAES([]byte(token), []byte(content))
|
||||||
// return base64.StdEncoding.EncodeToString(result)
|
return base64.StdEncoding.EncodeToString(result)
|
||||||
//}
|
}
|
||||||
|
|
18
src/http/handler.go
Normal file
18
src/http/handler.go
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
package http
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
)
|
||||||
|
|
||||||
|
func domainList(context *gin.Context) {
|
||||||
|
fmt.Println("domainList")
|
||||||
|
}
|
||||||
|
|
||||||
|
func getCert(context *gin.Context) {
|
||||||
|
fmt.Println("getCert")
|
||||||
|
}
|
||||||
|
|
||||||
|
func refreshCert(context *gin.Context) {
|
||||||
|
fmt.Println("refreshCert")
|
||||||
|
}
|
42
src/http/server.go
Normal file
42
src/http/server.go
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
package http
|
||||||
|
|
||||||
|
import (
|
||||||
|
"acme-mana/src/common"
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
"github.com/go-acme/lego/v4/log"
|
||||||
|
"strconv"
|
||||||
|
)
|
||||||
|
|
||||||
|
var service *gin.Engine
|
||||||
|
var isRunning bool
|
||||||
|
|
||||||
|
func Start() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func Stop() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func Status() bool {
|
||||||
|
return isRunning
|
||||||
|
}
|
||||||
|
|
||||||
|
func start() {
|
||||||
|
conf := common.AppConf
|
||||||
|
server := conf.Server
|
||||||
|
service := gin.Default()
|
||||||
|
register(service)
|
||||||
|
isRunning = true
|
||||||
|
err := service.Run(server.Host + ":" + strconv.Itoa(server.Port))
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal("http server start error \n", err)
|
||||||
|
}
|
||||||
|
isRunning = false
|
||||||
|
}
|
||||||
|
|
||||||
|
func register(service *gin.Engine) {
|
||||||
|
service.GET("/api/v1/refresh", refreshCert)
|
||||||
|
service.GET("/api/v1/cert", getCert)
|
||||||
|
service.GET("/api/v1/domain/list", domainList)
|
||||||
|
}
|
34
src/model/conf.go
Normal file
34
src/model/conf.go
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
package model
|
||||||
|
|
||||||
|
type AppConfig struct {
|
||||||
|
Server *ServerConf `json:"server" yaml:"server"`
|
||||||
|
Task *TaskConf `json:"task" yaml:"task"`
|
||||||
|
Certs *[]CertConf `json:"cert" yaml:"cert"`
|
||||||
|
Providers *[]ProviderConf `json:"provider" yaml:"provider"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ServerConf struct {
|
||||||
|
Host string `json:"host" yaml:"host"`
|
||||||
|
Port int `json:"port" yaml:"port"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type TaskConf struct {
|
||||||
|
// 启动延迟时间, 单位: 毫秒, 默认: 0
|
||||||
|
Delay int `json:"delay" yaml:"delay"`
|
||||||
|
// 间隔时间
|
||||||
|
Interval int `json:"interval" yaml:"interval"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ProviderConf struct {
|
||||||
|
Name string `json:"name" yaml:"name"`
|
||||||
|
Type string `json:"type" yaml:"type"`
|
||||||
|
Conf map[string]string `json:"conf" yaml:"conf"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type CertConf struct {
|
||||||
|
Name string `json:"name" yaml:"name"`
|
||||||
|
Provider string `json:"use" yaml:"provider"`
|
||||||
|
Dir string `json:"dir" yaml:"dir"`
|
||||||
|
Email string `json:"email" yaml:"email"`
|
||||||
|
Host []string `json:"host" yaml:"host"`
|
||||||
|
}
|
|
@ -1,8 +1,6 @@
|
||||||
package src
|
package src
|
||||||
|
|
||||||
import (
|
import "acme-mana/src/cmd"
|
||||||
"acme-mana/src/cmd"
|
|
||||||
)
|
|
||||||
|
|
||||||
func StartProgram() {
|
func StartProgram() {
|
||||||
_, err := cmd.InitCmd()
|
_, err := cmd.InitCmd()
|
||||||
|
@ -10,5 +8,4 @@ func StartProgram() {
|
||||||
panic(err)
|
panic(err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,79 +0,0 @@
|
||||||
package server
|
|
||||||
|
|
||||||
import (
|
|
||||||
"acme-mana/src/conf"
|
|
||||||
"acme-mana/src/server/http_handler"
|
|
||||||
"context"
|
|
||||||
"errors"
|
|
||||||
"github.com/gin-gonic/gin"
|
|
||||||
"log"
|
|
||||||
"net/http"
|
|
||||||
"strconv"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
type HttpServer struct {
|
|
||||||
server *http.Server
|
|
||||||
status bool
|
|
||||||
engine *gin.Engine
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *HttpServer) Init() {
|
|
||||||
config := conf.Config()
|
|
||||||
var serverConf = config.Server
|
|
||||||
s.initServer(serverConf.Host, serverConf.Port)
|
|
||||||
}
|
|
||||||
|
|
||||||
// initServer 初始化
|
|
||||||
func (s *HttpServer) initServer(host string, port int) {
|
|
||||||
s.engine = gin.Default()
|
|
||||||
s.register()
|
|
||||||
s.status = false
|
|
||||||
|
|
||||||
s.server = &http.Server{
|
|
||||||
Addr: host + ":" + strconv.Itoa(port),
|
|
||||||
Handler: s.engine,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *HttpServer) Start() {
|
|
||||||
if s.status {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
go func() {
|
|
||||||
if err := s.server.ListenAndServe(); !errors.Is(err, http.ErrServerClosed) {
|
|
||||||
log.Printf("listen: %s\n\n", err)
|
|
||||||
s.status = true
|
|
||||||
} else {
|
|
||||||
s.status = false
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *HttpServer) Stop() {
|
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
|
||||||
defer cancel()
|
|
||||||
err := HttpInstance.server.Shutdown(ctx)
|
|
||||||
s.status = false
|
|
||||||
if err != nil {
|
|
||||||
log.Fatalln("HttpInstance Shutdown:", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *HttpServer) Status() bool {
|
|
||||||
return s.status
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *HttpServer) register() {
|
|
||||||
service := s.engine
|
|
||||||
service.Use(gin.Logger())
|
|
||||||
service.Use(http_handler.GlobalErrorHandler())
|
|
||||||
|
|
||||||
certHandler := http_handler.CertHandlerInstance
|
|
||||||
certGroup := service.Group("/api/v1/cert", http_handler.AuthMiddleware())
|
|
||||||
certGroup.GET("/", certHandler.Get)
|
|
||||||
|
|
||||||
confHandler := http_handler.ConfHandlerInstance
|
|
||||||
confGroup := service.Group("/api/v1", http_handler.AuthMiddleware())
|
|
||||||
confGroup.GET("/conf", confHandler.Get)
|
|
||||||
}
|
|
|
@ -1,149 +0,0 @@
|
||||||
package server
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"github.com/gin-gonic/gin"
|
|
||||||
"net/http"
|
|
||||||
"os"
|
|
||||||
"os/signal"
|
|
||||||
"syscall"
|
|
||||||
"testing"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestHttpServer_InitServer(t *testing.T) {
|
|
||||||
type fields struct {
|
|
||||||
server *http.Server
|
|
||||||
status bool
|
|
||||||
engine *gin.Engine
|
|
||||||
}
|
|
||||||
tests := []struct {
|
|
||||||
name string
|
|
||||||
fields fields
|
|
||||||
}{
|
|
||||||
// TODO: Add test cases.
|
|
||||||
}
|
|
||||||
for _, tt := range tests {
|
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
|
||||||
s := &HttpServer{
|
|
||||||
server: tt.fields.server,
|
|
||||||
status: tt.fields.status,
|
|
||||||
engine: tt.fields.engine,
|
|
||||||
}
|
|
||||||
s.Init()
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestHttpServer_Start(t *testing.T) {
|
|
||||||
type fields struct {
|
|
||||||
server *http.Server
|
|
||||||
status bool
|
|
||||||
engine *gin.Engine
|
|
||||||
}
|
|
||||||
tests := []struct {
|
|
||||||
name string
|
|
||||||
fields fields
|
|
||||||
}{
|
|
||||||
// TODO: Add test cases.
|
|
||||||
{
|
|
||||||
name: "0.0.0.0",
|
|
||||||
fields: fields{
|
|
||||||
server: nil,
|
|
||||||
status: false,
|
|
||||||
engine: nil,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
for _, tt := range tests {
|
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
|
||||||
s := &HttpServer{
|
|
||||||
server: tt.fields.server,
|
|
||||||
status: tt.fields.status,
|
|
||||||
engine: tt.fields.engine,
|
|
||||||
}
|
|
||||||
s.initServer("0.0.0.0", 35541)
|
|
||||||
s.Start()
|
|
||||||
quit := make(chan os.Signal, 1)
|
|
||||||
signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)
|
|
||||||
<-quit
|
|
||||||
fmt.Println("Shutting down server...")
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestHttpServer_Stop(t *testing.T) {
|
|
||||||
type fields struct {
|
|
||||||
server *http.Server
|
|
||||||
status bool
|
|
||||||
engine *gin.Engine
|
|
||||||
}
|
|
||||||
tests := []struct {
|
|
||||||
name string
|
|
||||||
fields fields
|
|
||||||
}{
|
|
||||||
// TODO: Add test cases.
|
|
||||||
}
|
|
||||||
for _, tt := range tests {
|
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
|
||||||
s := &HttpServer{
|
|
||||||
server: tt.fields.server,
|
|
||||||
status: tt.fields.status,
|
|
||||||
engine: tt.fields.engine,
|
|
||||||
}
|
|
||||||
s.Stop()
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestHttpServer_register(t *testing.T) {
|
|
||||||
type fields struct {
|
|
||||||
server *http.Server
|
|
||||||
status bool
|
|
||||||
engine *gin.Engine
|
|
||||||
}
|
|
||||||
tests := []struct {
|
|
||||||
name string
|
|
||||||
fields fields
|
|
||||||
}{
|
|
||||||
// TODO: Add test cases.
|
|
||||||
}
|
|
||||||
for _, tt := range tests {
|
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
|
||||||
s := &HttpServer{
|
|
||||||
server: tt.fields.server,
|
|
||||||
status: tt.fields.status,
|
|
||||||
engine: tt.fields.engine,
|
|
||||||
}
|
|
||||||
s.register()
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestHttpServer_initServer(t *testing.T) {
|
|
||||||
type fields struct {
|
|
||||||
server *http.Server
|
|
||||||
status bool
|
|
||||||
engine *gin.Engine
|
|
||||||
}
|
|
||||||
type args struct {
|
|
||||||
host string
|
|
||||||
port int
|
|
||||||
}
|
|
||||||
tests := []struct {
|
|
||||||
name string
|
|
||||||
fields fields
|
|
||||||
args args
|
|
||||||
}{
|
|
||||||
// TODO: Add test cases.
|
|
||||||
}
|
|
||||||
for _, tt := range tests {
|
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
|
||||||
s := &HttpServer{
|
|
||||||
server: tt.fields.server,
|
|
||||||
status: tt.fields.status,
|
|
||||||
engine: tt.fields.engine,
|
|
||||||
}
|
|
||||||
s.initServer(tt.args.host, tt.args.port)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,13 +0,0 @@
|
||||||
package http_handler
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/gin-gonic/gin"
|
|
||||||
)
|
|
||||||
|
|
||||||
func AuthMiddleware() gin.HandlerFunc {
|
|
||||||
return func(c *gin.Context) {
|
|
||||||
|
|
||||||
// 进行身份认证
|
|
||||||
c.Next()
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,43 +0,0 @@
|
||||||
package http_handler
|
|
||||||
|
|
||||||
import (
|
|
||||||
"acme-mana/src/acme"
|
|
||||||
"acme-mana/src/conf"
|
|
||||||
"acme-mana/src/server/model"
|
|
||||||
"github.com/gin-gonic/gin"
|
|
||||||
"log"
|
|
||||||
)
|
|
||||||
|
|
||||||
var CertHandlerInstance = &CertHandler{}
|
|
||||||
|
|
||||||
type CertHandler struct {
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h *CertHandler) List(c *gin.Context) {
|
|
||||||
log.Println("list cert")
|
|
||||||
certs := conf.Config().Certs
|
|
||||||
c.JSON(200, model.SuccessD(certs))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h *CertHandler) Get(c *gin.Context) {
|
|
||||||
log.Println("get cert")
|
|
||||||
name := c.Query("name")
|
|
||||||
if name == "" {
|
|
||||||
c.Error(model.NewAppError(500, "请输入名称"))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
cert, _ := conf.FindCert(name)
|
|
||||||
c.JSON(200, model.SuccessD(cert))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h *CertHandler) Refresh(c *gin.Context) {
|
|
||||||
log.Println("refresh cert")
|
|
||||||
name := c.Query("name")
|
|
||||||
if name == "" {
|
|
||||||
c.Error(model.NewAppError(500, "请输入名称"))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
cert, _ := conf.FindCert(name)
|
|
||||||
acme.Apply(cert)
|
|
||||||
c.JSON(200, model.Success())
|
|
||||||
}
|
|
|
@ -1,17 +0,0 @@
|
||||||
package http_handler
|
|
||||||
|
|
||||||
import (
|
|
||||||
"acme-mana/src/conf"
|
|
||||||
"acme-mana/src/server/model"
|
|
||||||
"github.com/gin-gonic/gin"
|
|
||||||
)
|
|
||||||
|
|
||||||
var ConfHandlerInstance = &ConfHandler{}
|
|
||||||
|
|
||||||
type ConfHandler struct {
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h *ConfHandler) Get(c *gin.Context) {
|
|
||||||
config := conf.Config()
|
|
||||||
c.JSON(200, model.SuccessD(config))
|
|
||||||
}
|
|
|
@ -1,34 +0,0 @@
|
||||||
package http_handler
|
|
||||||
|
|
||||||
import (
|
|
||||||
"acme-mana/src/server/model"
|
|
||||||
"github.com/gin-gonic/gin"
|
|
||||||
"net/http"
|
|
||||||
)
|
|
||||||
|
|
||||||
// GlobalErrorHandler 是一个全局错误处理器中间件
|
|
||||||
func GlobalErrorHandler() gin.HandlerFunc {
|
|
||||||
return func(c *gin.Context) {
|
|
||||||
// 继续执行后续中间件和处理函数
|
|
||||||
c.Next()
|
|
||||||
|
|
||||||
// 获取上下文中的错误
|
|
||||||
if err, ok := c.Get("error"); ok {
|
|
||||||
switch typedErr := err.(type) {
|
|
||||||
case *model.AppError:
|
|
||||||
c.JSON(200, &model.Result{
|
|
||||||
Code: typedErr.Code,
|
|
||||||
Message: typedErr.Message,
|
|
||||||
Data: nil,
|
|
||||||
})
|
|
||||||
default:
|
|
||||||
c.JSON(http.StatusInternalServerError, gin.H{
|
|
||||||
"error": "Internal Server Error",
|
|
||||||
"success": false,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
c.Abort()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,19 +0,0 @@
|
||||||
package model
|
|
||||||
|
|
||||||
type AppError struct {
|
|
||||||
Code int `json:"code"`
|
|
||||||
Message string `json:"message"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// Error 实现 error 接口
|
|
||||||
func (e *AppError) Error() string {
|
|
||||||
return e.Message
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewAppError 创建一个新的 AppError
|
|
||||||
func NewAppError(code int, message string) *AppError {
|
|
||||||
return &AppError{
|
|
||||||
Code: code,
|
|
||||||
Message: message,
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,27 +0,0 @@
|
||||||
package model
|
|
||||||
|
|
||||||
type Result struct {
|
|
||||||
Code int `json:"code"`
|
|
||||||
Message string `json:"message"`
|
|
||||||
Data any `json:"data"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r Result) SetData(data any) Result {
|
|
||||||
r.Data = data
|
|
||||||
return r
|
|
||||||
}
|
|
||||||
|
|
||||||
func Success() *Result {
|
|
||||||
return &Result{
|
|
||||||
Code: 200,
|
|
||||||
Message: "success",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func SuccessD(data any) *Result {
|
|
||||||
return &Result{
|
|
||||||
Code: 200,
|
|
||||||
Message: "success",
|
|
||||||
Data: data,
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,53 +0,0 @@
|
||||||
package server
|
|
||||||
|
|
||||||
import (
|
|
||||||
"acme-mana/src/common"
|
|
||||||
socker_handler "acme-mana/src/server/socket_handler"
|
|
||||||
"log"
|
|
||||||
"net"
|
|
||||||
"os"
|
|
||||||
)
|
|
||||||
|
|
||||||
type SocketServer struct {
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *SocketServer) InitSocketServer() {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *SocketServer) Start() {
|
|
||||||
go start()
|
|
||||||
}
|
|
||||||
|
|
||||||
func start() {
|
|
||||||
log.Println("启动指令监听服务...")
|
|
||||||
// 删除旧的 socket 文件
|
|
||||||
if _, err := os.Stat(common.SocketFile); err == nil {
|
|
||||||
err := os.Remove(common.SocketFile)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatalf("无法删除Socket文件: %v\n", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
listener, err := net.Listen("unix", common.SocketFile)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatalf("Failed to listen on socket: %v", err)
|
|
||||||
}
|
|
||||||
defer func(listener net.Listener) {
|
|
||||||
err := listener.Close()
|
|
||||||
if err != nil {
|
|
||||||
log.Fatalf("无法关闭Socket文件监听: %v", err)
|
|
||||||
}
|
|
||||||
}(listener)
|
|
||||||
|
|
||||||
for {
|
|
||||||
log.Println("等待连接...")
|
|
||||||
conn, err := listener.Accept()
|
|
||||||
if err != nil {
|
|
||||||
log.Printf("无法建立连接: %v", err)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
go socker_handler.HandleConnection(conn)
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1 +0,0 @@
|
||||||
package socket_handler
|
|
|
@ -1,47 +0,0 @@
|
||||||
package socket_handler
|
|
||||||
|
|
||||||
import (
|
|
||||||
"acme-mana/src/common"
|
|
||||||
"log"
|
|
||||||
"net"
|
|
||||||
"os"
|
|
||||||
)
|
|
||||||
|
|
||||||
func HandleConnection(conn net.Conn) {
|
|
||||||
defer conn.Close()
|
|
||||||
|
|
||||||
buf := make([]byte, 1024)
|
|
||||||
n, err := conn.Read(buf)
|
|
||||||
if err != nil {
|
|
||||||
log.Printf("Failed to read command: %v", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
command := string(buf[:n])
|
|
||||||
log.Printf("Received command: %s", command)
|
|
||||||
|
|
||||||
// 在这里处理接收到的命令
|
|
||||||
switch command {
|
|
||||||
case "stop":
|
|
||||||
onStop()
|
|
||||||
default:
|
|
||||||
onCommand(command)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
收到命令
|
|
||||||
*/
|
|
||||||
func onCommand(command string) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// 收到停止命令
|
|
||||||
func onStop() {
|
|
||||||
log.Println("停止守护进程...")
|
|
||||||
os.Remove(common.PidFile)
|
|
||||||
log.Println("删除PID文件...")
|
|
||||||
os.Remove(common.SocketFile)
|
|
||||||
log.Println("删除Socket文件...")
|
|
||||||
os.Exit(0)
|
|
||||||
}
|
|
|
@ -1,4 +0,0 @@
|
||||||
package server
|
|
||||||
|
|
||||||
var HttpInstance *HttpServer
|
|
||||||
var SocketInstance *SocketServer
|
|
168
src/task.go
168
src/task.go
|
@ -1,86 +1,86 @@
|
||||||
package src
|
package src
|
||||||
|
|
||||||
//import (
|
import (
|
||||||
// "encoding/json"
|
"encoding/json"
|
||||||
// "log"
|
"log"
|
||||||
// "os"
|
"os"
|
||||||
// "path"
|
"path"
|
||||||
// "time"
|
"time"
|
||||||
//)
|
)
|
||||||
//
|
|
||||||
//var AutoRefreshCertTicker = time.NewTicker(time.Hour)
|
var AutoRefreshCertTicker = time.NewTicker(time.Hour)
|
||||||
//
|
|
||||||
//func AutoRefreshCert() {
|
func AutoRefreshCert() {
|
||||||
// log.Println("Start auto refresh cert")
|
log.Println("Start auto refresh cert")
|
||||||
// defer AutoRefreshCertTicker.Stop()
|
defer AutoRefreshCertTicker.Stop()
|
||||||
// for {
|
for {
|
||||||
// select {
|
select {
|
||||||
// case <-AutoRefreshCertTicker.C:
|
case <-AutoRefreshCertTicker.C:
|
||||||
// doRefreshCert()
|
doRefreshCert()
|
||||||
// }
|
}
|
||||||
// }
|
}
|
||||||
//}
|
}
|
||||||
//
|
|
||||||
//func doRefreshCert() {
|
func doRefreshCert() {
|
||||||
// domains := GetAppConfig().Domains
|
domains := GetAppConfig().Domains
|
||||||
// for _, domain := range domains {
|
for _, domain := range domains {
|
||||||
// doRefreshCertOnce(domain)
|
doRefreshCertOnce(domain)
|
||||||
// }
|
}
|
||||||
//}
|
}
|
||||||
//
|
|
||||||
//func doRefreshCertOnce(domain Domain) {
|
func doRefreshCertOnce(domain Domain) {
|
||||||
// name := domain.Name
|
name := domain.Name
|
||||||
// dir := GetAppConfig().CertDir
|
dir := GetAppConfig().CertDir
|
||||||
// certDir := path.Join(dir, name)
|
certDir := path.Join(dir, name)
|
||||||
// if !ValidExist(certDir, domain) {
|
if !ValidExist(certDir, domain) {
|
||||||
// Apply(domain)
|
Apply(domain)
|
||||||
// }
|
}
|
||||||
// infoFile := path.Join(certDir, CertInfoFileName)
|
infoFile := path.Join(certDir, CertInfoFileName)
|
||||||
// certInfo := ParseCertInfo(infoFile, domain)
|
certInfo := ParseCertInfo(infoFile, domain)
|
||||||
// log.Println("Checking if the certificate is expired, Domain: {}", name)
|
log.Println("Checking if the certificate is expired, Domain: {}", name)
|
||||||
// if certInfo.Info.NotAfter.Sub(time.Now()) < 14*24*time.Hour {
|
if certInfo.Info.NotAfter.Sub(time.Now()) < 14*24*time.Hour {
|
||||||
// log.Println("Apply for a certificate that is about to expire, domain name:", name)
|
log.Println("Apply for a certificate that is about to expire, domain name:", name)
|
||||||
// Apply(domain)
|
Apply(domain)
|
||||||
// }
|
}
|
||||||
//}
|
}
|
||||||
//
|
|
||||||
//func ValidExist(certDir string, domain Domain) bool {
|
func ValidExist(certDir string, domain Domain) bool {
|
||||||
// _, err := os.Stat(certDir)
|
_, err := os.Stat(certDir)
|
||||||
// if os.IsNotExist(err) {
|
if os.IsNotExist(err) {
|
||||||
// log.Printf("Applying for a certificate, Domain: %s certificate directory does not exist!", domain.Name)
|
log.Printf("Applying for a certificate, Domain: %s certificate directory does not exist!", domain.Name)
|
||||||
// return false
|
return false
|
||||||
// }
|
}
|
||||||
// if !ExistFile(certDir, CertFileName) {
|
if !ExistFile(certDir, CertFileName) {
|
||||||
// log.Printf("Applying for a certificate, Domain: %s %s does not exist!", domain.Name, CertFileName)
|
log.Printf("Applying for a certificate, Domain: %s %s does not exist!", domain.Name, CertFileName)
|
||||||
// return false
|
return false
|
||||||
// }
|
}
|
||||||
// if !ExistFile(certDir, KeyFileName) {
|
if !ExistFile(certDir, KeyFileName) {
|
||||||
// log.Printf("Applying for a certificate, Domain: %s %s does not exist!", domain.Name, KeyFileName)
|
log.Printf("Applying for a certificate, Domain: %s %s does not exist!", domain.Name, KeyFileName)
|
||||||
// return false
|
return false
|
||||||
// }
|
}
|
||||||
// if !ExistFile(certDir, CertInfoFileName) {
|
if !ExistFile(certDir, CertInfoFileName) {
|
||||||
// log.Printf("Applying for a certificate, Domain: %s %s does not exist!", domain.Name, CertInfoFileName)
|
log.Printf("Applying for a certificate, Domain: %s %s does not exist!", domain.Name, CertInfoFileName)
|
||||||
// return false
|
return false
|
||||||
// }
|
}
|
||||||
// return true
|
return true
|
||||||
//}
|
}
|
||||||
//
|
|
||||||
//func ParseCertInfo(infoFile string, domain Domain) CertInfo {
|
func ParseCertInfo(infoFile string, domain Domain) CertInfo {
|
||||||
// infoBytes, err := os.ReadFile(infoFile)
|
infoBytes, err := os.ReadFile(infoFile)
|
||||||
// if err != nil {
|
if err != nil {
|
||||||
// log.Println("Failed to read cert info file, Domain: {}", domain.Name)
|
log.Println("Failed to read cert info file, Domain: {}", domain.Name)
|
||||||
// }
|
}
|
||||||
// var certInfo CertInfo
|
var certInfo CertInfo
|
||||||
// err = json.Unmarshal(infoBytes, &certInfo)
|
err = json.Unmarshal(infoBytes, &certInfo)
|
||||||
// //if err != nil {
|
//if err != nil {
|
||||||
// // log.Println("Failed to parse cert info file, Domain: {}", domain.Name)
|
// log.Println("Failed to parse cert info file, Domain: {}", domain.Name)
|
||||||
// //}
|
//}
|
||||||
// return certInfo
|
return certInfo
|
||||||
//}
|
}
|
||||||
//
|
|
||||||
//func ExistFile(dir string, fileName string) bool {
|
func ExistFile(dir string, fileName string) bool {
|
||||||
// f := path.Join(dir, fileName)
|
f := path.Join(dir, fileName)
|
||||||
// _, err := os.Stat(f)
|
_, err := os.Stat(f)
|
||||||
// return !os.IsNotExist(err)
|
return !os.IsNotExist(err)
|
||||||
//
|
|
||||||
//}
|
}
|
||||||
|
|
114
src/task/task.go
114
src/task/task.go
|
@ -1,114 +0,0 @@
|
||||||
package task
|
|
||||||
|
|
||||||
import (
|
|
||||||
"acme-mana/src/acme"
|
|
||||||
"acme-mana/src/common"
|
|
||||||
"acme-mana/src/conf"
|
|
||||||
"encoding/json"
|
|
||||||
"log"
|
|
||||||
"os"
|
|
||||||
"path"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
var AutoRefreshCertTicker = time.NewTicker(time.Hour)
|
|
||||||
|
|
||||||
func AutoRefreshCert() {
|
|
||||||
log.Println("Start auto refresh cert")
|
|
||||||
defer AutoRefreshCertTicker.Stop()
|
|
||||||
for {
|
|
||||||
select {
|
|
||||||
case <-AutoRefreshCertTicker.C:
|
|
||||||
doRefreshCert()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func doRefreshCert() {
|
|
||||||
config := conf.Config()
|
|
||||||
certs := config.Certs
|
|
||||||
|
|
||||||
for _, cert := range *certs {
|
|
||||||
doRefreshCertOne(&cert)
|
|
||||||
}
|
|
||||||
|
|
||||||
//domains := GetAppConfig().Domains
|
|
||||||
//for _, domain := range domains {
|
|
||||||
// doRefreshCertOnce(domain)
|
|
||||||
//}
|
|
||||||
}
|
|
||||||
|
|
||||||
func doRefreshCertOne(cert *conf.CertConf) {
|
|
||||||
name := cert.Name
|
|
||||||
dir := cert.Dir
|
|
||||||
certDir := path.Join(dir, name)
|
|
||||||
if !ValidExist(certDir, cert) {
|
|
||||||
acme.Apply(cert)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
infoFile := path.Join(certDir, common.CertInfoFileName)
|
|
||||||
certInfo := ParseCertInfo(infoFile, cert)
|
|
||||||
log.Println("校验当前证书有效时间, 证书: {}", name)
|
|
||||||
if certInfo.Info.NotAfter.Sub(time.Now()) < 14*24*time.Hour {
|
|
||||||
log.Println("申请即将过期的证书: {}", name)
|
|
||||||
acme.Apply(cert)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
//func doRefreshCertOnce(domain Domain) {
|
|
||||||
// name := domain.Name
|
|
||||||
// dir := GetAppConfig().CertDir
|
|
||||||
// certDir := path.Join(dir, name)
|
|
||||||
// if !ValidExist(certDir, domain) {
|
|
||||||
// Apply(domain)
|
|
||||||
// }
|
|
||||||
// infoFile := path.Join(certDir, CertInfoFileName)
|
|
||||||
// certInfo := ParseCertInfo(infoFile, domain)
|
|
||||||
// log.Println("Checking if the certificate is expired, Domain: {}", name)
|
|
||||||
// if certInfo.Info.NotAfter.Sub(time.Now()) < 14*24*time.Hour {
|
|
||||||
// log.Println("Apply for a certificate that is about to expire, domain name:", name)
|
|
||||||
// Apply(domain)
|
|
||||||
// }
|
|
||||||
//}
|
|
||||||
|
|
||||||
func ValidExist(certDir string, cert *conf.CertConf) bool {
|
|
||||||
_, err := os.Stat(certDir)
|
|
||||||
if os.IsNotExist(err) {
|
|
||||||
log.Printf("Applying for a certificate, Domain: %s certificate directory does not exist!", cert.Name)
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
if !ExistFile(certDir, common.CertFileName) {
|
|
||||||
log.Printf("Applying for a certificate, Domain: %s %s does not exist!", cert.Name, common.CertFileName)
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
if !ExistFile(certDir, common.KeyFileName) {
|
|
||||||
log.Printf("Applying for a certificate, Domain: %s %s does not exist!", cert.Name, common.KeyFileName)
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
if !ExistFile(certDir, common.CertInfoFileName) {
|
|
||||||
log.Printf("Applying for a certificate, Domain: %s %s does not exist!", cert.Name, common.CertInfoFileName)
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
func ParseCertInfo(infoFile string, cert *conf.CertConf) *acme.CertInfo {
|
|
||||||
infoBytes, err := os.ReadFile(infoFile)
|
|
||||||
if err != nil {
|
|
||||||
log.Println("Failed to read cert info file, Domain: {}", cert.Name)
|
|
||||||
}
|
|
||||||
var certInfo acme.CertInfo
|
|
||||||
err = json.Unmarshal(infoBytes, &certInfo)
|
|
||||||
//if err != nil {
|
|
||||||
// log.Println("Failed to parse cert info file, Domain: {}", domain.Name)
|
|
||||||
//}
|
|
||||||
return &certInfo
|
|
||||||
}
|
|
||||||
|
|
||||||
func ExistFile(dir string, fileName string) bool {
|
|
||||||
f := path.Join(dir, fileName)
|
|
||||||
_, err := os.Stat(f)
|
|
||||||
return !os.IsNotExist(err)
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,17 +0,0 @@
|
||||||
package util
|
|
||||||
|
|
||||||
import (
|
|
||||||
"math/rand"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
const letterBytes = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890"
|
|
||||||
|
|
||||||
func RandomStr(size int) string {
|
|
||||||
rand.NewSource(time.Now().UnixNano())
|
|
||||||
b := make([]byte, size)
|
|
||||||
for i := range b {
|
|
||||||
b[i] = letterBytes[rand.Intn(len(letterBytes))]
|
|
||||||
}
|
|
||||||
return string(b)
|
|
||||||
}
|
|
28
src/variable.go
Normal file
28
src/variable.go
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
package src
|
||||||
|
|
||||||
|
const PidFile = "acme-mana.pid"
|
||||||
|
const SocketFile = "acme-mana.sock"
|
||||||
|
|
||||||
|
const CertFileName = "fullchain.pem"
|
||||||
|
const KeyFileName = "privkey.pem"
|
||||||
|
const CertInfoFileName = "info.json"
|
||||||
|
|
||||||
|
var DnsProviderSupports = []string{"alidns", "tencentcloud", "cloudflare"}
|
||||||
|
|
||||||
|
var appConfig *AppConfig = ReadConfig()
|
||||||
|
|
||||||
|
func GetAppConfig() *AppConfig {
|
||||||
|
return appConfig
|
||||||
|
}
|
||||||
|
|
||||||
|
var envConf *EnvConf = InitRuntimeConf()
|
||||||
|
|
||||||
|
func GetEnvConf() *EnvConf {
|
||||||
|
return envConf
|
||||||
|
}
|
||||||
|
|
||||||
|
type DomainData struct {
|
||||||
|
Fullchain string `json:"fullchain"`
|
||||||
|
Key string `json:"key"`
|
||||||
|
Info string `json:"info"`
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user