mirror of
https://github.com/phishingclub/phishingclub.git
synced 2026-06-08 23:43:59 +02:00
f9365ab299
Signed-off-by: Ronni Skansing <rskansing@gmail.com>
337 lines
8.4 KiB
Go
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
|
|
}
|