feat: per-site SSL email and error display

This commit is contained in:
orohi
2026-06-17 06:05:34 +03:00
parent 02201fb4e3
commit f2c05d15ec
9 changed files with 151 additions and 59 deletions
+19 -6
View File
@@ -7,6 +7,7 @@ import (
"regexp"
"strings"
"github.com/panelhosting/panel/internal/auth"
"github.com/panelhosting/panel/internal/models"
"github.com/panelhosting/panel/internal/repository"
)
@@ -15,6 +16,8 @@ var (
ErrInvalidSiteName = errors.New("site name must be 3-64 chars: lowercase letters, digits, hyphen")
ErrInvalidDomain = errors.New("invalid domain")
ErrInvalidPHPVersion = errors.New("unsupported php version")
ErrInvalidSSLEmail = errors.New("invalid ssl email")
ErrSSLEmailRequired = errors.New("ssl email is required when issuing certificate")
)
var (
@@ -23,8 +26,8 @@ var (
)
type SSLIssuer interface {
IssueAsync(sslID, domainID int64, domain, webroot string)
IssueForSite(ctx context.Context, siteID int64) error
IssueAsync(sslID, domainID int64, domain, webroot, email string)
IssueForSite(ctx context.Context, siteID int64, email string) error
}
type Service struct {
@@ -42,6 +45,7 @@ type CreateInput struct {
Name string
Domain string
PHPVersion string
SSLEmail string
ServerID int64
OwnerID int64
IsAdmin bool
@@ -60,6 +64,7 @@ func (s *Service) Create(ctx context.Context, in CreateInput) (*repository.SiteW
name := strings.ToLower(strings.TrimSpace(in.Name))
domain := strings.ToLower(strings.TrimSpace(in.Domain))
phpVersion := strings.TrimSpace(in.PHPVersion)
sslEmail := strings.TrimSpace(in.SSLEmail)
if !siteNameRegex.MatchString(name) {
return nil, ErrInvalidSiteName
@@ -70,6 +75,14 @@ func (s *Service) Create(ctx context.Context, in CreateInput) (*repository.SiteW
if phpVersion == "" {
return nil, ErrInvalidPHPVersion
}
if in.IssueSSL {
if sslEmail == "" {
return nil, ErrSSLEmailRequired
}
if err := auth.ValidateEmail(sslEmail); err != nil {
return nil, ErrInvalidSSLEmail
}
}
active, err := s.phpVers.IsActive(ctx, phpVersion)
if err != nil {
@@ -93,23 +106,23 @@ func (s *Service) Create(ctx context.Context, in CreateInput) (*repository.SiteW
}
documentRoot := fmt.Sprintf("/var/www/%s/public", name)
site, err := s.sites.Create(ctx, serverID, in.OwnerID, name, documentRoot, phpVersion, domain, in.IssueSSL)
site, err := s.sites.Create(ctx, serverID, in.OwnerID, name, documentRoot, phpVersion, domain, sslEmail, in.IssueSSL)
if err != nil {
return nil, err
}
if in.IssueSSL && s.ssl != nil && site.SSLID > 0 {
s.ssl.IssueAsync(site.SSLID, site.DomainID, domain, documentRoot)
s.ssl.IssueAsync(site.SSLID, site.DomainID, domain, documentRoot, sslEmail)
}
return site, nil
}
func (s *Service) ReissueSSLAsync(siteID int64) {
func (s *Service) ReissueSSLAsync(siteID int64, email string) {
if s.ssl == nil {
return
}
go func() {
_ = s.ssl.IssueForSite(context.Background(), siteID)
_ = s.ssl.IssueForSite(context.Background(), siteID, email)
}()
}