132 lines
3.1 KiB
Go
132 lines
3.1 KiB
Go
package sslsvc
|
|
|
|
import (
|
|
"context"
|
|
"log"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/panelhosting/panel/internal/config"
|
|
"github.com/panelhosting/panel/internal/nginx"
|
|
"github.com/panelhosting/panel/internal/repository"
|
|
"github.com/panelhosting/panel/internal/ssl"
|
|
)
|
|
|
|
type Service struct {
|
|
repo *repository.SSLRepository
|
|
sites *repository.SiteRepository
|
|
issuer *ssl.Issuer
|
|
nginx *nginx.Manager
|
|
cfg *config.Config
|
|
}
|
|
|
|
func NewService(repo *repository.SSLRepository, sites *repository.SiteRepository, issuer *ssl.Issuer, ngx *nginx.Manager, cfg *config.Config) *Service {
|
|
return &Service{repo: repo, sites: sites, issuer: issuer, nginx: ngx, cfg: cfg}
|
|
}
|
|
|
|
func (s *Service) IssueAsync(sslID, domainID int64, domain, webroot, email string) {
|
|
go func() {
|
|
ctx := context.Background()
|
|
if err := s.Issue(ctx, sslID, domainID, domain, webroot, email); err != nil {
|
|
log.Printf("ssl issue %s: %v", domain, err)
|
|
}
|
|
}()
|
|
}
|
|
|
|
func (s *Service) resolveEmail(email string) string {
|
|
email = strings.TrimSpace(strings.ToLower(email))
|
|
if email != "" {
|
|
return email
|
|
}
|
|
return strings.TrimSpace(strings.ToLower(s.cfg.ACMEEmail))
|
|
}
|
|
|
|
func (s *Service) Issue(ctx context.Context, sslID, domainID int64, domain, webroot, email string) error {
|
|
email = s.resolveEmail(email)
|
|
if email == "" {
|
|
return s.repo.MarkError(ctx, sslID, "укажите email для Let's Encrypt")
|
|
}
|
|
|
|
if s.nginx.Enabled() {
|
|
if err := s.nginx.PrepareHTTPChallenge(domain, webroot); err != nil {
|
|
msg := "nginx: " + err.Error()
|
|
_ = s.repo.MarkError(ctx, sslID, msg)
|
|
return err
|
|
}
|
|
time.Sleep(2 * time.Second)
|
|
}
|
|
|
|
res, err := s.issuer.Obtain(ctx, email, domain, webroot)
|
|
if err != nil {
|
|
_ = s.repo.MarkError(ctx, sslID, err.Error())
|
|
return err
|
|
}
|
|
|
|
expiresAt, err := ssl.ParseCertExpiry(res.Certificate)
|
|
if err != nil {
|
|
expiresAt = time.Now().Add(90 * 24 * time.Hour)
|
|
}
|
|
|
|
issuerName := "Let's Encrypt"
|
|
if s.cfg.ACMEStaging {
|
|
issuerName = "Let's Encrypt (staging)"
|
|
}
|
|
|
|
if err := s.repo.MarkActive(ctx, sslID, issuerName, string(res.Certificate), string(res.PrivateKey), string(res.IssuerCertificate), time.Now(), expiresAt); err != nil {
|
|
return err
|
|
}
|
|
|
|
if s.nginx.Enabled() {
|
|
if err := s.nginx.ApplyHTTPS(domain, webroot); err != nil {
|
|
log.Printf("nginx apply https %s: %v", domain, err)
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (s *Service) IssueForSite(ctx context.Context, siteID int64, email string) error {
|
|
if email != "" {
|
|
if err := s.sites.UpdateSSLEmail(ctx, siteID, email); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
domainID, err := s.repo.GetDomainIDBySite(ctx, siteID)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
domain, webroot, err := s.repo.GetDomainInfo(ctx, domainID)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
siteEmail, err := s.sites.GetSSLEmail(ctx, siteID)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
cert, err := s.repo.GetByDomainID(ctx, domainID)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
var sslID int64
|
|
if cert == nil {
|
|
sslID, err = s.repo.CreatePending(ctx, domainID)
|
|
} else {
|
|
sslID = cert.ID
|
|
}
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
go func() {
|
|
if err := s.Issue(context.Background(), sslID, domainID, domain, webroot, siteEmail); err != nil {
|
|
log.Printf("ssl reissue %s: %v", domain, err)
|
|
}
|
|
}()
|
|
return nil
|
|
}
|