mirror of
https://github.com/phishingclub/phishingclub.git
synced 2026-07-07 04:47:55 +02:00
perform validation on save
Signed-off-by: Ronni Skansing <rskansing@gmail.com>
This commit is contained in:
@@ -138,6 +138,7 @@ func NewServices(
|
||||
CampaignRepository: repositories.Campaign,
|
||||
PageRepository: repositories.Page,
|
||||
CampaignTemplateService: campaignTemplate,
|
||||
TemplateService: templateService,
|
||||
}
|
||||
domain := &service.Domain{
|
||||
Common: common,
|
||||
@@ -149,6 +150,7 @@ func NewServices(
|
||||
CampaignTemplateService: campaignTemplate,
|
||||
AssetService: asset,
|
||||
FileService: file,
|
||||
TemplateService: templateService,
|
||||
}
|
||||
email := &service.Email{
|
||||
Common: common,
|
||||
|
||||
@@ -36,6 +36,7 @@ type Domain struct {
|
||||
CampaignTemplateService *CampaignTemplate
|
||||
AssetService *Asset
|
||||
FileService *File
|
||||
TemplateService *Template
|
||||
}
|
||||
|
||||
// Create creates a new domain
|
||||
@@ -60,6 +61,19 @@ func (d *Domain) Create(
|
||||
// d.Logger.Debugf("failed to validate domain", "error", err)
|
||||
return nil, errs.Wrap(err)
|
||||
}
|
||||
// validate template content if present
|
||||
if pageContent, err := domain.PageContent.Get(); err == nil {
|
||||
if err := d.TemplateService.ValidateDomainTemplate(pageContent.String()); err != nil {
|
||||
d.Logger.Errorw("failed to validate domain page template", "error", err)
|
||||
return nil, validate.WrapErrorWithField(errors.New("invalid page template: "+err.Error()), "pageContent")
|
||||
}
|
||||
}
|
||||
if notFoundContent, err := domain.PageNotFoundContent.Get(); err == nil {
|
||||
if err := d.TemplateService.ValidateDomainTemplate(notFoundContent.String()); err != nil {
|
||||
d.Logger.Errorw("failed to validate domain not found template", "error", err)
|
||||
return nil, validate.WrapErrorWithField(errors.New("invalid not found template: "+err.Error()), "pageNotFoundContent")
|
||||
}
|
||||
}
|
||||
// check for uniqueness
|
||||
name := domain.Name.MustGet() // safe as we have validated
|
||||
_, err = d.DomainRepository.GetByName(
|
||||
@@ -403,9 +417,19 @@ func (d *Domain) UpdateByID(
|
||||
current.HostWebsite.Set(v)
|
||||
}
|
||||
if v, err := incoming.PageContent.Get(); err == nil {
|
||||
// validate template content before updating
|
||||
if err := d.TemplateService.ValidateDomainTemplate(v.String()); err != nil {
|
||||
d.Logger.Errorw("failed to validate domain page template", "error", err)
|
||||
return validate.WrapErrorWithField(errors.New("invalid page template: "+err.Error()), "pageContent")
|
||||
}
|
||||
current.PageContent.Set(v)
|
||||
}
|
||||
if v, err := incoming.PageNotFoundContent.Get(); err == nil {
|
||||
// validate template content before updating
|
||||
if err := d.TemplateService.ValidateDomainTemplate(v.String()); err != nil {
|
||||
d.Logger.Errorw("failed to validate domain not found template", "error", err)
|
||||
return validate.WrapErrorWithField(errors.New("invalid not found template: "+err.Error()), "pageNotFoundContent")
|
||||
}
|
||||
current.PageNotFoundContent.Set(v)
|
||||
}
|
||||
if v, err := incoming.RedirectURL.Get(); err == nil {
|
||||
|
||||
@@ -171,6 +171,13 @@ func (m *Email) Create(
|
||||
if err := email.Validate(); err != nil {
|
||||
return nil, errs.Wrap(err)
|
||||
}
|
||||
// validate template content if present
|
||||
if content, err := email.Content.Get(); err == nil {
|
||||
if err := m.TemplateService.ValidateEmailTemplate(content.String()); err != nil {
|
||||
m.Logger.Errorw("failed to validate email template", "error", err)
|
||||
return nil, validate.WrapErrorWithField(errors.New("invalid template: "+err.Error()), "content")
|
||||
}
|
||||
}
|
||||
// check uniqueness
|
||||
var companyID *uuid.UUID
|
||||
if cid, err := email.CompanyID.Get(); err == nil {
|
||||
@@ -780,6 +787,11 @@ func (m *Email) UpdateByID(
|
||||
current.MailHeaderSubject.Set(v)
|
||||
}
|
||||
if v, err := email.Content.Get(); err == nil {
|
||||
// validate template content before updating
|
||||
if err := m.TemplateService.ValidateEmailTemplate(v.String()); err != nil {
|
||||
m.Logger.Errorw("failed to validate email template", "error", err)
|
||||
return validate.WrapErrorWithField(errors.New("invalid template: "+err.Error()), "content")
|
||||
}
|
||||
if _, err := email.AddTrackingPixel.Get(); err == nil {
|
||||
// handle tracking pixel
|
||||
email, err = m.toggleTrackingPixel(email)
|
||||
|
||||
@@ -20,6 +20,7 @@ type Page struct {
|
||||
PageRepository *repository.Page
|
||||
CampaignRepository *repository.Campaign
|
||||
CampaignTemplateService *CampaignTemplate
|
||||
TemplateService *Template
|
||||
}
|
||||
|
||||
// Create creates a new page
|
||||
@@ -49,6 +50,13 @@ func (p *Page) Create(
|
||||
p.Logger.Errorw("failed to validate page", "error", err)
|
||||
return nil, errs.Wrap(err)
|
||||
}
|
||||
// validate template content if present
|
||||
if content, err := page.Content.Get(); err == nil {
|
||||
if err := p.TemplateService.ValidatePageTemplate(content.String()); err != nil {
|
||||
p.Logger.Errorw("failed to validate page template", "error", err)
|
||||
return nil, validate.WrapErrorWithField(errors.New("invalid template: "+err.Error()), "content")
|
||||
}
|
||||
}
|
||||
// check uniqueness
|
||||
name := page.Name.MustGet()
|
||||
isOK, err := repository.CheckNameIsUnique(
|
||||
@@ -253,6 +261,11 @@ func (p *Page) UpdateByID(
|
||||
current.Name.Set(v)
|
||||
}
|
||||
if v, err := page.Content.Get(); err == nil {
|
||||
// validate template content before updating
|
||||
if err := p.TemplateService.ValidatePageTemplate(v.String()); err != nil {
|
||||
p.Logger.Errorw("failed to validate page template", "error", err)
|
||||
return validate.WrapErrorWithField(errors.New("invalid template: "+err.Error()), "content")
|
||||
}
|
||||
current.Content.Set(v)
|
||||
}
|
||||
// update page
|
||||
|
||||
@@ -18,6 +18,7 @@ import (
|
||||
"github.com/phishingclub/phishingclub/errs"
|
||||
"github.com/phishingclub/phishingclub/model"
|
||||
"github.com/phishingclub/phishingclub/utils"
|
||||
"github.com/phishingclub/phishingclub/vo"
|
||||
"github.com/yeqown/go-qrcode/v2"
|
||||
)
|
||||
|
||||
@@ -71,6 +72,104 @@ func (t *Template) CreateMail(
|
||||
)
|
||||
}
|
||||
|
||||
// ValidatePageTemplate validates that a page template can be parsed and executed without errors
|
||||
func (t *Template) ValidatePageTemplate(content string) error {
|
||||
// use the same parsing approach as CreatePhishingPage but without executing
|
||||
_, err := template.New("validation").
|
||||
Funcs(TemplateFuncs()).
|
||||
Parse(content)
|
||||
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to parse page template: %s", err)
|
||||
}
|
||||
|
||||
// also try to execute with mock data to catch runtime errors
|
||||
_, err = t.ApplyPageMock(content)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to execute page template: %s", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// ValidateEmailTemplate validates that an email template can be parsed and executed without errors
|
||||
func (t *Template) ValidateEmailTemplate(content string) error {
|
||||
// use the same parsing approach as email creation but without executing
|
||||
_, err := template.New("validation").
|
||||
Funcs(TemplateFuncs()).
|
||||
Parse(content)
|
||||
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to parse email template: %s", err)
|
||||
}
|
||||
|
||||
// also try to execute with mock data to catch runtime errors
|
||||
domain := &model.Domain{
|
||||
Name: nullable.NewNullableWithValue(
|
||||
*vo.NewString255Must("example.test"),
|
||||
),
|
||||
}
|
||||
recipient := model.NewRecipientExample()
|
||||
campaignRecipient := model.CampaignRecipient{
|
||||
ID: nullable.NewNullableWithValue(
|
||||
uuid.New(),
|
||||
),
|
||||
Recipient: recipient,
|
||||
}
|
||||
email := model.NewEmailExample()
|
||||
email.Content = nullable.NewNullableWithValue(
|
||||
*vo.NewUnsafeOptionalString1MB(content),
|
||||
)
|
||||
apiSender := model.NewAPISenderExample()
|
||||
|
||||
_, err = t.CreateMailBody(
|
||||
"id",
|
||||
"/test",
|
||||
domain,
|
||||
&campaignRecipient,
|
||||
email,
|
||||
apiSender,
|
||||
)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to execute email template: %s", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// ValidateDomainTemplate validates that a domain template can be parsed and executed without errors
|
||||
func (t *Template) ValidateDomainTemplate(content string) error {
|
||||
// use the same parsing approach as domain content but without executing
|
||||
_, err := template.New("validation").
|
||||
Funcs(TemplateFuncs()).
|
||||
Parse(content)
|
||||
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to parse domain template: %s", err)
|
||||
}
|
||||
|
||||
// also try to execute with mock data to catch runtime errors
|
||||
// domains only have access to BaseURL variable
|
||||
data := map[string]any{
|
||||
"BaseURL": "https://example.test",
|
||||
}
|
||||
|
||||
tmpl, err := template.New("domain").
|
||||
Funcs(TemplateFuncs()).
|
||||
Parse(content)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to parse domain template: %s", err)
|
||||
}
|
||||
|
||||
var buf bytes.Buffer
|
||||
err = tmpl.Execute(&buf, data)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to execute domain template: %s", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// ApplyPageMock
|
||||
func (t *Template) ApplyPageMock(content string) (*bytes.Buffer, error) {
|
||||
// build response
|
||||
|
||||
Reference in New Issue
Block a user