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 }