2022-11-11 17:41:39 +08:00
|
|
|
package service
|
|
|
|
|
|
|
|
import (
|
2022-11-16 10:31:35 +08:00
|
|
|
"context"
|
|
|
|
"crypto/x509"
|
2022-11-17 17:39:33 +08:00
|
|
|
"encoding/pem"
|
2022-12-14 15:26:51 +08:00
|
|
|
"github.com/1Panel-dev/1Panel/backend/app/dto/request"
|
|
|
|
"github.com/1Panel-dev/1Panel/backend/app/dto/response"
|
2022-11-16 10:31:35 +08:00
|
|
|
"github.com/1Panel-dev/1Panel/backend/app/model"
|
2022-12-05 15:50:53 +08:00
|
|
|
"github.com/1Panel-dev/1Panel/backend/buserr"
|
2022-11-24 14:58:29 +08:00
|
|
|
"github.com/1Panel-dev/1Panel/backend/constant"
|
2023-01-04 11:44:43 +08:00
|
|
|
"github.com/1Panel-dev/1Panel/backend/global"
|
2022-11-16 10:31:35 +08:00
|
|
|
"github.com/1Panel-dev/1Panel/backend/utils/ssl"
|
2022-11-24 14:58:29 +08:00
|
|
|
"path"
|
2022-11-16 10:31:35 +08:00
|
|
|
"strings"
|
2022-11-11 17:41:39 +08:00
|
|
|
)
|
|
|
|
|
2022-12-13 17:20:13 +08:00
|
|
|
type WebsiteSSLService struct {
|
2022-11-11 17:41:39 +08:00
|
|
|
}
|
|
|
|
|
2023-01-04 11:44:43 +08:00
|
|
|
type IWebsiteSSLService interface {
|
|
|
|
Page(search request.WebsiteSSLSearch) (int64, []response.WebsiteSSLDTO, error)
|
|
|
|
GetSSL(id uint) (*response.WebsiteSSLDTO, error)
|
|
|
|
Search() ([]response.WebsiteSSLDTO, error)
|
|
|
|
Create(create request.WebsiteSSLCreate) (request.WebsiteSSLCreate, error)
|
|
|
|
Renew(sslId uint) error
|
|
|
|
GetDNSResolve(req request.WebsiteDNSReq) ([]response.WebsiteDNSRes, error)
|
|
|
|
GetWebsiteSSL(websiteId uint) (response.WebsiteSSLDTO, error)
|
|
|
|
Delete(id uint) error
|
|
|
|
}
|
|
|
|
|
|
|
|
func NewIWebsiteSSLService() IWebsiteSSLService {
|
|
|
|
return &WebsiteSSLService{}
|
|
|
|
}
|
|
|
|
|
2022-12-14 15:26:51 +08:00
|
|
|
func (w WebsiteSSLService) Page(search request.WebsiteSSLSearch) (int64, []response.WebsiteSSLDTO, error) {
|
2022-11-11 17:41:39 +08:00
|
|
|
total, sslList, err := websiteSSLRepo.Page(search.Page, search.PageSize, commonRepo.WithOrderBy("created_at desc"))
|
2022-11-20 18:32:56 +08:00
|
|
|
if err != nil {
|
|
|
|
return 0, nil, err
|
|
|
|
}
|
2022-12-14 15:26:51 +08:00
|
|
|
var sslDTOs []response.WebsiteSSLDTO
|
2022-11-11 17:41:39 +08:00
|
|
|
for _, ssl := range sslList {
|
2022-12-14 15:26:51 +08:00
|
|
|
sslDTOs = append(sslDTOs, response.WebsiteSSLDTO{
|
2022-12-13 17:20:13 +08:00
|
|
|
WebsiteSSL: ssl,
|
2022-11-11 17:41:39 +08:00
|
|
|
})
|
|
|
|
}
|
|
|
|
return total, sslDTOs, err
|
|
|
|
}
|
|
|
|
|
2022-12-29 14:55:20 +08:00
|
|
|
func (w WebsiteSSLService) GetSSL(id uint) (*response.WebsiteSSLDTO, error) {
|
|
|
|
var res response.WebsiteSSLDTO
|
|
|
|
websiteSSL, err := websiteSSLRepo.GetFirst(commonRepo.WithByID(id))
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
res.WebsiteSSL = websiteSSL
|
|
|
|
return &res, nil
|
|
|
|
}
|
|
|
|
|
2022-12-14 15:26:51 +08:00
|
|
|
func (w WebsiteSSLService) Search() ([]response.WebsiteSSLDTO, error) {
|
2022-11-20 18:32:56 +08:00
|
|
|
sslList, err := websiteSSLRepo.List()
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2022-12-14 15:26:51 +08:00
|
|
|
var sslDTOs []response.WebsiteSSLDTO
|
2022-11-20 18:32:56 +08:00
|
|
|
for _, ssl := range sslList {
|
2022-12-14 15:26:51 +08:00
|
|
|
sslDTOs = append(sslDTOs, response.WebsiteSSLDTO{
|
2022-12-13 17:20:13 +08:00
|
|
|
WebsiteSSL: ssl,
|
2022-11-20 18:32:56 +08:00
|
|
|
})
|
|
|
|
}
|
|
|
|
return sslDTOs, err
|
|
|
|
}
|
|
|
|
|
2022-12-14 15:26:51 +08:00
|
|
|
func (w WebsiteSSLService) Create(create request.WebsiteSSLCreate) (request.WebsiteSSLCreate, error) {
|
|
|
|
var res request.WebsiteSSLCreate
|
2022-11-16 10:31:35 +08:00
|
|
|
acmeAccount, err := websiteAcmeRepo.GetFirst(commonRepo.WithByID(create.AcmeAccountID))
|
|
|
|
if err != nil {
|
|
|
|
return res, err
|
|
|
|
}
|
|
|
|
client, err := ssl.NewPrivateKeyClient(acmeAccount.Email, acmeAccount.PrivateKey)
|
|
|
|
if err != nil {
|
|
|
|
return res, err
|
|
|
|
}
|
|
|
|
|
2022-11-17 17:39:33 +08:00
|
|
|
switch create.Provider {
|
2022-12-14 15:26:51 +08:00
|
|
|
case constant.DNSAccount:
|
2022-11-17 17:39:33 +08:00
|
|
|
dnsAccount, err := websiteDnsRepo.GetFirst(commonRepo.WithByID(create.DnsAccountID))
|
|
|
|
if err != nil {
|
|
|
|
return res, err
|
|
|
|
}
|
2022-11-16 10:31:35 +08:00
|
|
|
if err := client.UseDns(ssl.DnsType(dnsAccount.Type), dnsAccount.Authorization); err != nil {
|
|
|
|
return res, err
|
|
|
|
}
|
2022-12-14 15:26:51 +08:00
|
|
|
case constant.Http:
|
2023-02-22 17:13:08 +08:00
|
|
|
appInstall, err := getAppInstallByKey(constant.AppOpenresty)
|
2022-11-24 14:58:29 +08:00
|
|
|
if err != nil {
|
2022-12-14 15:26:51 +08:00
|
|
|
return request.WebsiteSSLCreate{}, err
|
2022-11-24 14:58:29 +08:00
|
|
|
}
|
2023-02-22 17:13:08 +08:00
|
|
|
if err := client.UseHTTP(path.Join(constant.AppInstallDir, constant.AppOpenresty, appInstall.Name, "root")); err != nil {
|
2022-11-24 14:58:29 +08:00
|
|
|
return res, err
|
|
|
|
}
|
2022-11-16 10:31:35 +08:00
|
|
|
}
|
|
|
|
|
2022-11-17 17:39:33 +08:00
|
|
|
domains := []string{create.PrimaryDomain}
|
|
|
|
otherDomainArray := strings.Split(create.OtherDomains, "\n")
|
|
|
|
if create.OtherDomains != "" {
|
|
|
|
domains = append(otherDomainArray, domains...)
|
|
|
|
}
|
|
|
|
resource, err := client.ObtainSSL(domains)
|
2022-11-16 10:31:35 +08:00
|
|
|
if err != nil {
|
|
|
|
return res, err
|
|
|
|
}
|
2022-12-13 17:20:13 +08:00
|
|
|
var websiteSSL model.WebsiteSSL
|
2022-11-17 17:39:33 +08:00
|
|
|
websiteSSL.DnsAccountID = create.DnsAccountID
|
|
|
|
websiteSSL.AcmeAccountID = acmeAccount.ID
|
2022-12-14 15:26:51 +08:00
|
|
|
websiteSSL.Provider = create.Provider
|
2022-11-17 17:39:33 +08:00
|
|
|
websiteSSL.Domains = strings.Join(otherDomainArray, ",")
|
|
|
|
websiteSSL.PrimaryDomain = create.PrimaryDomain
|
2022-11-16 10:31:35 +08:00
|
|
|
websiteSSL.PrivateKey = string(resource.PrivateKey)
|
|
|
|
websiteSSL.Pem = string(resource.Certificate)
|
|
|
|
websiteSSL.CertURL = resource.CertURL
|
2022-11-17 17:39:33 +08:00
|
|
|
certBlock, _ := pem.Decode(resource.Certificate)
|
|
|
|
cert, err := x509.ParseCertificate(certBlock.Bytes)
|
2022-11-16 10:31:35 +08:00
|
|
|
if err != nil {
|
2022-12-14 15:26:51 +08:00
|
|
|
return request.WebsiteSSLCreate{}, err
|
2022-11-16 10:31:35 +08:00
|
|
|
}
|
|
|
|
websiteSSL.ExpireDate = cert.NotAfter
|
|
|
|
websiteSSL.StartDate = cert.NotBefore
|
|
|
|
websiteSSL.Type = cert.Issuer.CommonName
|
2022-11-17 17:39:33 +08:00
|
|
|
websiteSSL.Organization = cert.Issuer.Organization[0]
|
2022-11-16 10:31:35 +08:00
|
|
|
|
|
|
|
if err := websiteSSLRepo.Create(context.TODO(), &websiteSSL); err != nil {
|
|
|
|
return res, err
|
|
|
|
}
|
|
|
|
|
|
|
|
return create, nil
|
|
|
|
}
|
|
|
|
|
2022-12-13 17:20:13 +08:00
|
|
|
func (w WebsiteSSLService) Renew(sslId uint) error {
|
2022-11-17 17:39:33 +08:00
|
|
|
websiteSSL, err := websiteSSLRepo.GetFirst(commonRepo.WithByID(sslId))
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
acmeAccount, err := websiteAcmeRepo.GetFirst(commonRepo.WithByID(websiteSSL.AcmeAccountID))
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
client, err := ssl.NewPrivateKeyClient(acmeAccount.Email, acmeAccount.PrivateKey)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
switch websiteSSL.Provider {
|
2022-12-14 15:26:51 +08:00
|
|
|
case constant.DNSAccount:
|
2022-11-17 17:39:33 +08:00
|
|
|
dnsAccount, err := websiteDnsRepo.GetFirst(commonRepo.WithByID(websiteSSL.DnsAccountID))
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
if err := client.UseDns(ssl.DnsType(dnsAccount.Type), dnsAccount.Authorization); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2022-12-14 15:26:51 +08:00
|
|
|
case constant.Http:
|
2023-02-22 17:13:08 +08:00
|
|
|
appInstall, err := getAppInstallByKey(constant.AppOpenresty)
|
2022-11-24 17:50:47 +08:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2023-02-22 17:13:08 +08:00
|
|
|
if err := client.UseHTTP(path.Join(constant.AppInstallDir, constant.AppOpenresty, appInstall.Name, "root")); err != nil {
|
2022-11-24 17:50:47 +08:00
|
|
|
return err
|
|
|
|
}
|
2022-11-17 17:39:33 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
resource, err := client.RenewSSL(websiteSSL.CertURL)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
websiteSSL.PrivateKey = string(resource.PrivateKey)
|
|
|
|
websiteSSL.Pem = string(resource.Certificate)
|
|
|
|
websiteSSL.CertURL = resource.CertURL
|
|
|
|
certBlock, _ := pem.Decode(resource.Certificate)
|
|
|
|
cert, err := x509.ParseCertificate(certBlock.Bytes)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
websiteSSL.ExpireDate = cert.NotAfter
|
|
|
|
websiteSSL.StartDate = cert.NotBefore
|
|
|
|
websiteSSL.Type = cert.Issuer.CommonName
|
|
|
|
websiteSSL.Organization = cert.Issuer.Organization[0]
|
|
|
|
|
2023-01-04 11:44:43 +08:00
|
|
|
if err := websiteSSLRepo.Save(websiteSSL); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
websites, _ := websiteRepo.GetBy(websiteRepo.WithWebsiteSSLID(sslId))
|
|
|
|
for _, website := range websites {
|
|
|
|
if err := createPemFile(website, websiteSSL); err != nil {
|
|
|
|
global.LOG.Errorf("create website [%s] ssl file failed! err:%s", website.PrimaryDomain, err.Error())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if len(websites) > 0 {
|
2023-02-22 17:13:08 +08:00
|
|
|
nginxInstall, err := getAppInstallByKey(constant.AppOpenresty)
|
2023-01-04 11:44:43 +08:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
if err := opNginx(nginxInstall.ContainerName, constant.NginxReload); err != nil {
|
|
|
|
return buserr.New(constant.ErrSSLApply)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return nil
|
2022-11-17 17:39:33 +08:00
|
|
|
}
|
|
|
|
|
2022-12-14 15:26:51 +08:00
|
|
|
func (w WebsiteSSLService) GetDNSResolve(req request.WebsiteDNSReq) ([]response.WebsiteDNSRes, error) {
|
2022-11-16 10:31:35 +08:00
|
|
|
acmeAccount, err := websiteAcmeRepo.GetFirst(commonRepo.WithByID(req.AcmeAccountID))
|
|
|
|
if err != nil {
|
2022-11-25 00:08:44 +08:00
|
|
|
return nil, err
|
2022-11-16 10:31:35 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
client, err := ssl.NewPrivateKeyClient(acmeAccount.Email, acmeAccount.PrivateKey)
|
|
|
|
if err != nil {
|
2022-11-25 00:08:44 +08:00
|
|
|
return nil, err
|
2022-11-16 10:31:35 +08:00
|
|
|
}
|
2022-11-25 00:08:44 +08:00
|
|
|
resolves, err := client.GetDNSResolve(req.Domains)
|
2022-11-16 10:31:35 +08:00
|
|
|
if err != nil {
|
2022-11-25 00:08:44 +08:00
|
|
|
return nil, err
|
|
|
|
}
|
2022-12-14 15:26:51 +08:00
|
|
|
var res []response.WebsiteDNSRes
|
2022-11-25 00:08:44 +08:00
|
|
|
for k, v := range resolves {
|
2022-12-14 15:26:51 +08:00
|
|
|
res = append(res, response.WebsiteDNSRes{
|
2022-11-25 00:08:44 +08:00
|
|
|
Domain: k,
|
|
|
|
Key: v.Key,
|
|
|
|
Value: v.Value,
|
|
|
|
Err: v.Err,
|
|
|
|
})
|
2022-11-16 10:31:35 +08:00
|
|
|
}
|
|
|
|
return res, nil
|
|
|
|
}
|
2022-11-11 17:41:39 +08:00
|
|
|
|
2022-12-14 15:26:51 +08:00
|
|
|
func (w WebsiteSSLService) GetWebsiteSSL(websiteId uint) (response.WebsiteSSLDTO, error) {
|
|
|
|
var res response.WebsiteSSLDTO
|
2022-11-17 17:39:33 +08:00
|
|
|
website, err := websiteRepo.GetFirst(commonRepo.WithByID(websiteId))
|
|
|
|
if err != nil {
|
|
|
|
return res, err
|
|
|
|
}
|
2022-12-13 17:20:13 +08:00
|
|
|
websiteSSL, err := websiteSSLRepo.GetFirst(commonRepo.WithByID(website.WebsiteSSLID))
|
2022-11-17 17:39:33 +08:00
|
|
|
if err != nil {
|
|
|
|
return res, err
|
|
|
|
}
|
2022-12-13 17:20:13 +08:00
|
|
|
res.WebsiteSSL = websiteSSL
|
2022-11-17 17:39:33 +08:00
|
|
|
return res, nil
|
|
|
|
}
|
|
|
|
|
2022-12-13 17:20:13 +08:00
|
|
|
func (w WebsiteSSLService) Delete(id uint) error {
|
2022-12-05 15:50:53 +08:00
|
|
|
if websites, _ := websiteRepo.GetBy(websiteRepo.WithWebsiteSSLID(id)); len(websites) > 0 {
|
|
|
|
return buserr.New(constant.ErrSSLCannotDelete)
|
|
|
|
}
|
2022-11-11 17:41:39 +08:00
|
|
|
return websiteSSLRepo.DeleteBy(commonRepo.WithByID(id))
|
|
|
|
}
|