Files
phishingclub/backend/service/page.go
T
Ronni Skansing f9365ab299 cleanup from old proxy page test
Signed-off-by: Ronni Skansing <rskansing@gmail.com>
2025-09-30 21:56:44 +02:00

337 lines
8.4 KiB
Go

package service
import (
"context"
"github.com/go-errors/errors"
"github.com/google/uuid"
"github.com/phishingclub/phishingclub/data"
"github.com/phishingclub/phishingclub/errs"
"github.com/phishingclub/phishingclub/model"
"github.com/phishingclub/phishingclub/repository"
"github.com/phishingclub/phishingclub/validate"
"gorm.io/gorm"
)
// Page is a Page service
type Page struct {
Common
PageRepository *repository.Page
CampaignRepository *repository.Campaign
CampaignTemplateService *CampaignTemplate
TemplateService *Template
DomainRepository *repository.Domain
}
// Create creates a new page
func (p *Page) Create(
ctx context.Context,
session *model.Session,
page *model.Page,
) (*uuid.UUID, error) {
ae := NewAuditEvent("Page.Create", session)
// check permissions
isAuthorized, err := IsAuthorized(session, data.PERMISSION_ALLOW_GLOBAL)
if err != nil && !errors.Is(err, errs.ErrAuthorizationFailed) {
p.LogAuthError(err)
return nil, errs.Wrap(err)
}
if !isAuthorized {
p.AuditLogNotAuthorized(ae)
return nil, errs.ErrAuthorizationFailed
}
var companyID *uuid.UUID
if cid, err := page.CompanyID.Get(); err == nil {
companyID = &cid
}
// validate data
if err := page.Validate(); err != nil {
p.Logger.Errorw("failed to validate page", "error", err)
return nil, errs.Wrap(err)
}
// validate template content
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(
ctx,
p.PageRepository.DB,
"pages",
name.String(),
companyID,
nil,
)
if err != nil {
p.Logger.Errorw("failed to check page uniqueness", "error", err)
return nil, errs.Wrap(err)
}
if !isOK {
p.Logger.Debugw("page name is already taken", "name", name.String())
return nil, validate.WrapErrorWithField(errors.New("is not unique"), "name")
}
// create page
id, err := p.PageRepository.Insert(
ctx,
page,
)
if err != nil {
p.Logger.Errorw("failed to create page", "error", err)
return nil, errs.Wrap(err)
}
ae.Details["id"] = id.String()
p.AuditLogAuthorized(ae)
return id, nil
}
// GetAll gets pages
func (p *Page) GetAll(
ctx context.Context,
session *model.Session,
companyID *uuid.UUID,
options *repository.PageOption,
) (*model.Result[model.Page], error) {
result := model.NewEmptyResult[model.Page]()
ae := NewAuditEvent("Page.GetAll", session)
// check permissions
isAuthorized, err := IsAuthorized(session, data.PERMISSION_ALLOW_GLOBAL)
if err != nil && !errors.Is(err, errs.ErrAuthorizationFailed) {
p.LogAuthError(err)
return result, errs.Wrap(err)
}
if !isAuthorized {
p.AuditLogNotAuthorized(ae)
return result, errs.ErrAuthorizationFailed
}
result, err = p.PageRepository.GetAll(
ctx,
companyID,
options,
)
if err != nil {
p.Logger.Errorw("failed to get pages", "error", err)
return result, errs.Wrap(err)
}
// no audit log on read
return result, nil
}
// GetByID gets a page by ID
func (p *Page) GetByID(
ctx context.Context,
session *model.Session,
id *uuid.UUID,
options *repository.PageOption,
) (*model.Page, error) {
ae := NewAuditEvent("Page.GetByID", session)
ae.Details["id"] = id.String()
// check permissions
isAuthorized, err := IsAuthorized(session, data.PERMISSION_ALLOW_GLOBAL)
if err != nil && !errors.Is(err, errs.ErrAuthorizationFailed) {
p.LogAuthError(err)
return nil, errs.Wrap(err)
}
if !isAuthorized {
p.AuditLogNotAuthorized(ae)
return nil, errs.ErrAuthorizationFailed
}
// get page
page, err := p.PageRepository.GetByID(
ctx,
id,
options,
)
if errors.Is(err, gorm.ErrRecordNotFound) {
// return early this is not a an error
return nil, errs.Wrap(err)
}
if err != nil {
p.Logger.Errorw("failed to get page by ID", "error", err)
return nil, errs.Wrap(err)
}
// no audit log on read
return page, nil
}
// GetByCompanyID gets a page by company ID
func (p *Page) GetByCompanyID(
ctx context.Context,
session *model.Session,
companyID *uuid.UUID,
options *repository.PageOption,
) (*model.Result[model.Page], error) {
result := model.NewEmptyResult[model.Page]()
ae := NewAuditEvent("Page.GetByCompanyID", session)
if companyID != nil {
ae.Details["companyId"] = companyID.String()
}
// check permissions
isAuthorized, err := IsAuthorized(session, data.PERMISSION_ALLOW_GLOBAL)
if err != nil && !errors.Is(err, errs.ErrAuthorizationFailed) {
p.LogAuthError(err)
return result, errs.Wrap(err)
}
if !isAuthorized {
p.AuditLogNotAuthorized(ae)
return result, errs.ErrAuthorizationFailed
}
// get pages
result, err = p.PageRepository.GetAllByCompanyID(
ctx,
companyID,
&repository.PageOption{},
)
if errors.Is(err, gorm.ErrRecordNotFound) {
// return early this is not a an error
return result, errs.Wrap(err)
}
if err != nil {
p.Logger.Errorw("failed to get page by company ID", "error", err)
return result, errs.Wrap(err)
}
// no audit log on read
return result, nil
}
// UpdateByID updates a page by ID
func (p *Page) UpdateByID(
ctx context.Context,
session *model.Session,
id *uuid.UUID,
page *model.Page,
) error {
ae := NewAuditEvent("Page.UpdateByID", session)
ae.Details["id"] = id.String()
// check permissions
isAuthorized, err := IsAuthorized(session, data.PERMISSION_ALLOW_GLOBAL)
if err != nil && !errors.Is(err, errs.ErrAuthorizationFailed) {
p.LogAuthError(err)
return err
}
if !isAuthorized {
p.AuditLogNotAuthorized(ae)
return errs.ErrAuthorizationFailed
}
// get current
current, err := p.PageRepository.GetByID(
ctx,
id,
&repository.PageOption{},
)
if errors.Is(err, gorm.ErrRecordNotFound) {
p.Logger.Debugw("failed to update page by ID", "error", err)
return err
}
if err != nil {
p.Logger.Errorw("failed to update page by ID", "error", err)
return err
}
// update page - if a field is present and not null, update it
if v, err := page.Name.Get(); err == nil {
// check uniqueness
var companyID *uuid.UUID
if cid, err := current.CompanyID.Get(); err == nil {
companyID = &cid
}
name := page.Name.MustGet()
isOK, err := repository.CheckNameIsUnique(
ctx,
p.PageRepository.DB,
"pages",
name.String(),
companyID,
id,
)
if err != nil {
p.Logger.Errorw("failed to check page uniqueness", "error", err)
return err
}
if !isOK {
p.Logger.Debugw("page name is already taken", "name", name.String())
return validate.WrapErrorWithField(errors.New("is not unique"), "name")
}
current.Name.Set(v)
}
if v, err := page.Content.Get(); err == nil {
current.Content.Set(v)
}
// validate template content
if content, err := current.Content.Get(); err == nil {
if err := p.TemplateService.ValidatePageTemplate(content.String()); err != nil {
p.Logger.Errorw("failed to validate page template", "error", err)
return validate.WrapErrorWithField(errors.New("invalid template: "+err.Error()), "content")
}
}
// update page
err = p.PageRepository.UpdateByID(
ctx,
id,
current,
)
if err != nil {
p.Logger.Errorw("failed to update page by ID", "error", err)
return err
}
ae.Details["id"] = id.String()
p.AuditLogNotAuthorized(ae)
return nil
}
// DeleteByID deletes a page by ID
func (p *Page) DeleteByID(
ctx context.Context,
session *model.Session,
id *uuid.UUID,
) error {
ae := NewAuditEvent("Page.DeleteByID", session)
ae.Details["id"] = id.String()
// check permissions
isAuthorized, err := IsAuthorized(session, data.PERMISSION_ALLOW_GLOBAL)
if err != nil && !errors.Is(err, errs.ErrAuthorizationFailed) {
p.LogAuthError(err)
return err
}
if !isAuthorized {
p.AuditLogNotAuthorized(ae)
return errs.ErrAuthorizationFailed
}
// remove the relation to campaign allow deny PageRepository
err = p.CampaignRepository.RemoveDenyPageByDenyPageIDs(
ctx,
[]*uuid.UUID{id},
)
// delete the relation from campaign templates
err = p.CampaignTemplateService.RemovePagesByPageID(
ctx,
session,
id,
)
if err != nil {
p.Logger.Errorw("failed to remove page ID relations from campaign templates", "error", err)
return err
}
// delete page
err = p.PageRepository.DeleteByID(
ctx,
id,
)
if err != nil {
p.Logger.Errorw("failed to delete page by ID", "error", err)
return err
}
p.AuditLogAuthorized(ae)
return nil
}