From 27821632c693808dcc11bfb440d6a43423aae22a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89mile=20R=C3=A9?= Date: Wed, 4 Feb 2026 14:32:33 +0400 Subject: [PATCH] Serve email static assets from object store MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Émile Ré --- .../emails/assets}/probo-gray-small.png | Bin packages/emails/assets/probo.png | Bin 0 -> 76205 bytes packages/emails/emails.go | 132 ++++++++++++++++-- packages/emails/src/components/ProboLogo.tsx | 2 +- pkg/iam/account_service.go | 2 +- pkg/iam/auth_service.go | 6 +- pkg/iam/compliance_page_service.go | 2 +- pkg/iam/organization_service.go | 2 +- pkg/iam/service.go | 4 + pkg/probo/document_service.go | 4 +- pkg/probo/framework_service.go | 24 ++-- pkg/probo/service.go | 74 +++++----- pkg/probo/trust_center_service.go | 2 +- pkg/probod/probod.go | 13 ++ pkg/trust/service.go | 74 +++++----- pkg/trust/trust_center_service.go | 2 +- 16 files changed, 240 insertions(+), 103 deletions(-) rename {apps/console/public/logos => packages/emails/assets}/probo-gray-small.png (100%) create mode 100644 packages/emails/assets/probo.png diff --git a/apps/console/public/logos/probo-gray-small.png b/packages/emails/assets/probo-gray-small.png similarity index 100% rename from apps/console/public/logos/probo-gray-small.png rename to packages/emails/assets/probo-gray-small.png diff --git a/packages/emails/assets/probo.png b/packages/emails/assets/probo.png new file mode 100644 index 0000000000000000000000000000000000000000..6ef651e42a1157c0e336b88ef3c1c7a609cd29c1 GIT binary patch literal 76205 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%0DN`QKhB>jAN`|g|b`netHO`k4Bvbl7Q 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∈ZmK$aJU1{a3`6B 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 Kxvw&2@Ba^PcI4y$ literal 0 HcmV?d00001 diff --git a/packages/emails/emails.go b/packages/emails/emails.go index 135e8280f..b9a7d7463 100644 --- a/packages/emails/emails.go +++ b/packages/emails/emails.go @@ -16,22 +16,46 @@ package emails import ( "bytes" + "context" "embed" + "errors" "fmt" htmltemplate "html/template" + "io/fs" + "mime" "net/url" + "path/filepath" texttemplate "text/template" "time" + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/service/s3" "go.probo.inc/probo/pkg/baseurl" + "go.probo.inc/probo/pkg/filevalidation" ) //go:embed dist var Templates embed.FS +var ( + //go:embed assets + staticAssets embed.FS + + staticAssetsValidator = filevalidation.NewValidator( + filevalidation.WithMaxFileSize(5*1024*1024), + filevalidation.WithCategories( + filevalidation.CategoryImage, + filevalidation.CategoryVideo, + ), + ) +) + +type StaticAssetURLs map[string]string + type ( PresenterConfig struct { BaseURL string + PoweredByLogoURL string SenderCompanyName string SenderCompanyWebsiteURL string SenderCompanyLogoURL string @@ -40,8 +64,8 @@ type ( PresenterVariables struct { // Static variables - BaseOrigin string BaseURL string + PoweredByLogoURL string SenderCompanyName string SenderCompanyWebsiteURL string SenderCompanyLogoURL string @@ -58,27 +82,22 @@ type ( } ) -func DefaultPresenterConfig(baseURL string) PresenterConfig { +func DefaultPresenterConfig(baseURL string, staticAssetURLs StaticAssetURLs) PresenterConfig { return PresenterConfig{ BaseURL: baseURL, + PoweredByLogoURL: staticAssetURLs["probo-gray-small.png"], SenderCompanyName: "Probo", SenderCompanyWebsiteURL: "https://www.getprobo.com", - SenderCompanyLogoURL: baseurl.MustParse(baseURL).AppendPath("/logos/probo.png").MustString(), + SenderCompanyLogoURL: staticAssetURLs["probo.png"], SenderCompanyHeadquarterAddress: "Probo Inc, 490 Post St, STE 640, San Francisco, CA, 94102, US", } } func NewPresenterFromConfig(cfg PresenterConfig, fullName string) *Presenter { - baseURL := baseurl.MustParse(cfg.BaseURL) - baseOrigin := url.URL{ - Scheme: baseURL.Scheme(), - Host: baseURL.Host(), - } - return &Presenter{ variables: PresenterVariables{ - BaseOrigin: baseOrigin.String(), BaseURL: cfg.BaseURL, + PoweredByLogoURL: cfg.PoweredByLogoURL, SenderCompanyName: cfg.SenderCompanyName, SenderCompanyWebsiteURL: cfg.SenderCompanyWebsiteURL, SenderCompanyLogoURL: cfg.SenderCompanyLogoURL, @@ -89,13 +108,102 @@ func NewPresenterFromConfig(cfg PresenterConfig, fullName string) *Presenter { } } -func NewPresenter(baseURL string, fullName string) *Presenter { +func NewPresenter(baseURL string, staticAssetURLs StaticAssetURLs, fullName string) *Presenter { return NewPresenterFromConfig( - DefaultPresenterConfig(baseURL), + DefaultPresenterConfig(baseURL, staticAssetURLs), fullName, ) } +func GenerateStaticAssetURLs(ctx context.Context, s3Client *s3.Client, bucket string) (StaticAssetURLs, error) { + assetURLs := make(map[string]string) + + subFS, err := fs.Sub(staticAssets, "assets") + if err != nil { + return nil, fmt.Errorf("cannot create subtree file system: %w", err) + } + + err = fs.WalkDir(subFS, ".", func(path string, d fs.DirEntry, err error) error { + if err != nil { + return err + } + + if d.IsDir() { + return nil + } + + info, err := d.Info() + if err != nil { + if errors.Is(err, fs.ErrNotExist) { + return nil + } + + return fmt.Errorf("cannot get dir entry info: %w", err) + } + + ext := filepath.Ext(info.Name()) + mimeType := mime.TypeByExtension(ext) + + if err := staticAssetsValidator.Validate(info.Name(), mimeType, info.Size()); err != nil { + return fmt.Errorf("cannot validate file: %w", err) + } + + file, err := subFS.Open(path) + if err != nil { + return err + } + defer func() { _ = file.Close() }() + + _, err = s3Client.PutObject( + ctx, + &s3.PutObjectInput{ + Bucket: aws.String(bucket), + Key: aws.String(path), + Body: file, + Metadata: map[string]string{ + "type": "static-email-asset", + }, + ContentType: aws.String(mimeType), + }, + ) + if err != nil { + return fmt.Errorf("cannot upload file to S3: %w", err) + } + + presignClient := s3.NewPresignClient(s3Client) + + encodedFilename := url.QueryEscape(info.Name()) + contentDisposition := fmt.Sprintf("attachment; filename=%q; filename*=UTF-8''%s", + encodedFilename, encodedFilename) + + presignedReq, err := presignClient.PresignGetObject( + ctx, + &s3.GetObjectInput{ + Bucket: aws.String(bucket), + Key: aws.String(path), + ResponseCacheControl: aws.String("max-age=3600, public"), + ResponseContentDisposition: &contentDisposition, + }, + func(opts *s3.PresignOptions) { + opts.Expires = 7 * 24 * time.Hour + }, + ) + if err != nil { + return fmt.Errorf("cannot presign GetObject request: %w", err) + } + + assetURLs[path] = presignedReq.URL + + return nil + }) + + if err != nil { + return nil, fmt.Errorf("cannot generate asset URLs: %w", err) + } + + return assetURLs, nil +} + const ( subjectConfirmEmail = "Confirm your email address" subjectPasswordReset = "Reset your password" diff --git a/packages/emails/src/components/ProboLogo.tsx b/packages/emails/src/components/ProboLogo.tsx index ac66ff9f1..804b62af7 100644 --- a/packages/emails/src/components/ProboLogo.tsx +++ b/packages/emails/src/components/ProboLogo.tsx @@ -5,7 +5,7 @@ export function ProboLogo() { return ( Probo diff --git a/pkg/iam/account_service.go b/pkg/iam/account_service.go index 6d6d923e4..26de2f85f 100644 --- a/pkg/iam/account_service.go +++ b/pkg/iam/account_service.go @@ -116,7 +116,7 @@ func (s AccountService) ChangeEmail(ctx context.Context, identityID gid.GID, req return fmt.Errorf("cannot update identity: %w", err) } - emailPresenter := emails.NewPresenter(s.baseURL, identity.FullName) + emailPresenter := emails.NewPresenter(s.baseURL, s.emailStaticAssetURLs, identity.FullName) subject, textBody, htmlBody, err := emailPresenter.RenderConfirmEmail("/auth/verify-email", confirmationToken) if err != nil { diff --git a/pkg/iam/auth_service.go b/pkg/iam/auth_service.go index 102e6e7be..bddf0ea6f 100644 --- a/pkg/iam/auth_service.go +++ b/pkg/iam/auth_service.go @@ -290,7 +290,7 @@ func (s AuthService) SendPasswordResetInstructionByEmail( return fmt.Errorf("cannot load identity: %w", err) } - emailPresenter := emails.NewPresenter(s.baseURL, identity.FullName) + emailPresenter := emails.NewPresenter(s.baseURL, s.emailStaticAssetURLs, identity.FullName) subject, textBody, htmlBody, err := emailPresenter.RenderPasswordReset( "/auth/reset-password", @@ -406,7 +406,7 @@ func (s AuthService) CreateIdentityWithPassword( return nil, nil, fmt.Errorf("cannot generate confirmation token: %w", err) } - emailPresenter := emails.NewPresenter(s.baseURL, req.FullName) + emailPresenter := emails.NewPresenter(s.baseURL, s.emailStaticAssetURLs, req.FullName) subject, textBody, htmlBody, err := emailPresenter.RenderConfirmEmail("/auth/verify-email", confirmationToken) if err != nil { @@ -569,7 +569,7 @@ func (s AuthService) SendMagicLink(ctx context.Context, req *SendMagicLinkReques return fmt.Errorf("cannot load organization: %w", err) } - emailPresenterCfg := emails.DefaultPresenterConfig(s.baseURL) + emailPresenterCfg := emails.DefaultPresenterConfig(s.baseURL, s.emailStaticAssetURLs) if req.CompliancePageID != nil { var err error emailPresenterCfg, err = s.CompliancePageService.EmailPresenterConfig(ctx, *req.CompliancePageID) diff --git a/pkg/iam/compliance_page_service.go b/pkg/iam/compliance_page_service.go index 8c533aaf2..f56e7fb3f 100644 --- a/pkg/iam/compliance_page_service.go +++ b/pkg/iam/compliance_page_service.go @@ -91,7 +91,7 @@ func (s *CompliancePageService) EmailPresenterConfig(ctx context.Context, compli organization = &coredata.Organization{} customDomain *coredata.CustomDomain logoFile = &coredata.File{} - emailPresenterCfg = emails.DefaultPresenterConfig(s.baseURL) + emailPresenterCfg = emails.DefaultPresenterConfig(s.baseURL, s.emailStaticAssetURLs) ) scope := coredata.NewScopeFromObjectID(compliancePageID) diff --git a/pkg/iam/organization_service.go b/pkg/iam/organization_service.go index 5f7789bdf..e3c43603a 100644 --- a/pkg/iam/organization_service.go +++ b/pkg/iam/organization_service.go @@ -464,7 +464,7 @@ func (s *OrganizationService) InviteMember( return fmt.Errorf("cannot generate invitation token: %w", err) } - emailPresenter := emails.NewPresenter(s.baseURL, identity.FullName) + emailPresenter := emails.NewPresenter(s.baseURL, s.emailStaticAssetURLs, identity.FullName) subject, textBody, htmlBody, err := emailPresenter.RenderInvitation( "/auth/signup-from-invitation", diff --git a/pkg/iam/service.go b/pkg/iam/service.go index 3ae13e40d..e237e38ff 100644 --- a/pkg/iam/service.go +++ b/pkg/iam/service.go @@ -11,6 +11,7 @@ import ( "go.gearno.de/kit/log" "go.gearno.de/kit/pg" "go.opentelemetry.io/otel/trace" + "go.probo.inc/probo/packages/emails" "go.probo.inc/probo/pkg/baseurl" "go.probo.inc/probo/pkg/connector" "go.probo.inc/probo/pkg/coredata" @@ -28,6 +29,7 @@ type ( pg *pg.Client fm *filemanager.Service hp *passwdhash.Profile + emailStaticAssetURLs emails.StaticAssetURLs encryptionKey cipher.EncryptionKey baseURL string tokenSecret string @@ -82,6 +84,7 @@ func NewService( pgClient *pg.Client, fm *filemanager.Service, hp *passwdhash.Profile, + emailStaticAssetURLs emails.StaticAssetURLs, cfg Config, ) (*Service, error) { if cfg.Bucket == "" { @@ -104,6 +107,7 @@ func NewService( pg: pgClient, fm: fm, hp: hp, + emailStaticAssetURLs: emailStaticAssetURLs, baseURL: cfg.BaseURL.String(), tokenSecret: cfg.TokenSecret, disableSignup: cfg.DisableSignup, diff --git a/pkg/probo/document_service.go b/pkg/probo/document_service.go index 533c89e0f..683296db9 100644 --- a/pkg/probo/document_service.go +++ b/pkg/probo/document_service.go @@ -543,7 +543,7 @@ func (s *DocumentService) SendSigningNotifications( return fmt.Errorf("cannot create signing request token: %w", err) } - emailPresenter := emails.NewPresenter(s.svc.baseURL, people.FullName) + emailPresenter := emails.NewPresenter(s.svc.baseURL, s.svc.emailStaticAssetURLs, people.FullName) subject, textBody, htmlBody, err := emailPresenter.RenderDocumentSigning( "/documents/signing-requests", @@ -1823,7 +1823,7 @@ func (s *DocumentService) SendExportEmail( return fmt.Errorf("cannot generate download URL: %w", err) } - emailPresenter := emails.NewPresenter(s.svc.baseURL, recipientName) + emailPresenter := emails.NewPresenter(s.svc.baseURL, s.svc.emailStaticAssetURLs, recipientName) subject, textBody, htmlBody, err := emailPresenter.RenderDocumentExport( downloadURL, diff --git a/pkg/probo/framework_service.go b/pkg/probo/framework_service.go index 03691fbe5..e53402a21 100644 --- a/pkg/probo/framework_service.go +++ b/pkg/probo/framework_service.go @@ -254,17 +254,17 @@ func (s FrameworkService) Export( return fmt.Errorf("cannot load evidence file: %w", err) } - object, err := s.svc.s3.GetObject( - ctx, - &s3.GetObjectInput{ - Bucket: aws.String(s.svc.bucket), - Key: aws.String(evidence_file.FileKey), - }, - ) - if err != nil { - return fmt.Errorf("cannot download evidence: %w", err) - } - defer func() { _ = object.Body.Close() }() + object, err := s.svc.s3.GetObject( + ctx, + &s3.GetObjectInput{ + Bucket: aws.String(s.svc.bucket), + Key: aws.String(evidence_file.FileKey), + }, + ) + if err != nil { + return fmt.Errorf("cannot download evidence: %w", err) + } + defer func() { _ = object.Body.Close() }() w, err := archive.Create(fmt.Sprintf("%s/%s/%s/%s", framework.Name, control.SectionTitle, measure.Name, evidence_file.FileName)) if err != nil { @@ -800,7 +800,7 @@ func (s FrameworkService) SendExportEmail( return fmt.Errorf("cannot generate download URL: %w", err) } - emailPresenter := emails.NewPresenter(s.svc.baseURL, recipientName) + emailPresenter := emails.NewPresenter(s.svc.baseURL, s.svc.emailStaticAssetURLs, recipientName) subject, textBody, htmlBody, err := emailPresenter.RenderFrameworkExport( downloadURL, diff --git a/pkg/probo/service.go b/pkg/probo/service.go index dae5acb12..77c6df0d0 100644 --- a/pkg/probo/service.go +++ b/pkg/probo/service.go @@ -23,6 +23,7 @@ import ( "go.gearno.de/kit/log" "go.gearno.de/kit/pg" "go.gearno.de/x/ref" + "go.probo.inc/probo/packages/emails" "go.probo.inc/probo/pkg/agents" "go.probo.inc/probo/pkg/certmanager" "go.probo.inc/probo/pkg/coredata" @@ -49,18 +50,19 @@ type ExportService interface { type ( Service struct { - pg *pg.Client - s3 *s3.Client - bucket string - encryptionKey cipher.EncryptionKey - baseURL string - tokenSecret string - agentConfig agents.Config - html2pdfConverter *html2pdf.Converter - acmeService *certmanager.ACMEService - fileManager *filemanager.Service - logger *log.Logger - slack *slack.Service + pg *pg.Client + s3 *s3.Client + bucket string + encryptionKey cipher.EncryptionKey + baseURL string + tokenSecret string + agentConfig agents.Config + html2pdfConverter *html2pdf.Converter + acmeService *certmanager.ACMEService + fileManager *filemanager.Service + logger *log.Logger + slack *slack.Service + emailStaticAssetURLs emails.StaticAssetURLs } TenantService struct { @@ -73,6 +75,7 @@ type ( tokenSecret string agent *agents.Agent fileManager *filemanager.Service + emailStaticAssetURLs emails.StaticAssetURLs Frameworks *FrameworkService Measures *MeasureService Tasks *TaskService @@ -106,7 +109,7 @@ type ( ProcessingActivities *ProcessingActivityService DataProtectionImpactAssessments *DataProtectionImpactAssessmentService TransferImpactAssessments *TransferImpactAssessmentService - StatesOfApplicability *StateOfApplicabilityService + StatesOfApplicability *StateOfApplicabilityService Files *FileService CustomDomains *CustomDomainService SlackMessages *slack.SlackMessageService @@ -128,6 +131,7 @@ func NewService( logger *log.Logger, slackService *slack.Service, iamService *iam.Service, + emailStaticAssetURLs emails.StaticAssetURLs, ) (*Service, error) { if bucket == "" { return nil, fmt.Errorf("bucket is required") @@ -136,18 +140,19 @@ func NewService( iamService.Authorizer.RegisterPolicySet(ProboPolicySet()) svc := &Service{ - pg: pgClient, - s3: s3Client, - bucket: bucket, - encryptionKey: encryptionKey, - baseURL: baseURL, - tokenSecret: tokenSecret, - agentConfig: agentConfig, - html2pdfConverter: html2pdfConverter, - acmeService: acmeService, - fileManager: fileManagerService, - logger: logger, - slack: slackService, + pg: pgClient, + s3: s3Client, + bucket: bucket, + encryptionKey: encryptionKey, + baseURL: baseURL, + tokenSecret: tokenSecret, + agentConfig: agentConfig, + html2pdfConverter: html2pdfConverter, + acmeService: acmeService, + fileManager: fileManagerService, + logger: logger, + slack: slackService, + emailStaticAssetURLs: emailStaticAssetURLs, } return svc, nil @@ -155,15 +160,16 @@ func NewService( func (s *Service) WithTenant(tenantID gid.TenantID) *TenantService { tenantService := &TenantService{ - pg: s.pg, - s3: s.s3, - bucket: s.bucket, - encryptionKey: s.encryptionKey, - baseURL: s.baseURL, - scope: coredata.NewScope(tenantID), - tokenSecret: s.tokenSecret, - agent: agents.NewAgent(nil, s.agentConfig), - fileManager: s.fileManager, + pg: s.pg, + s3: s.s3, + bucket: s.bucket, + encryptionKey: s.encryptionKey, + baseURL: s.baseURL, + scope: coredata.NewScope(tenantID), + tokenSecret: s.tokenSecret, + agent: agents.NewAgent(nil, s.agentConfig), + fileManager: s.fileManager, + emailStaticAssetURLs: s.emailStaticAssetURLs, } tenantService.Frameworks = &FrameworkService{ diff --git a/pkg/probo/trust_center_service.go b/pkg/probo/trust_center_service.go index 8fbbbaec2..bf8e17f8b 100644 --- a/pkg/probo/trust_center_service.go +++ b/pkg/probo/trust_center_service.go @@ -609,7 +609,7 @@ func (s *TrustCenterService) EmailPresenterConfig(ctx context.Context, complianc organization = &coredata.Organization{} customDomain *coredata.CustomDomain logoFile = &coredata.File{} - emailPresenterCfg = emails.DefaultPresenterConfig(s.svc.baseURL) + emailPresenterCfg = emails.DefaultPresenterConfig(s.svc.baseURL, s.svc.emailStaticAssetURLs) ) scope := coredata.NewScopeFromObjectID(compliancePageID) diff --git a/pkg/probod/probod.go b/pkg/probod/probod.go index 46b97b3cd..563557f38 100644 --- a/pkg/probod/probod.go +++ b/pkg/probod/probod.go @@ -29,6 +29,7 @@ import ( "sync" "time" + "go.probo.inc/probo/packages/emails" pemutil "go.probo.inc/probo/pkg/crypto/pem" "github.com/aws/aws-sdk-go-v2/service/s3" @@ -292,11 +293,21 @@ func (impl *Implm) Run( } } + emailStaticAssetURLs, err := emails.GenerateStaticAssetURLs( + ctx, + s3Client, + impl.cfg.AWS.Bucket, + ) + if err != nil { + return fmt.Errorf("cannot generate email static asset URLs: %w", err) + } + iamService, err := iam.NewService( ctx, pgClient, fileManagerService, hp, + emailStaticAssetURLs, iam.Config{ DisableSignup: impl.cfg.Auth.DisableSignup, InvitationTokenValidity: time.Duration(impl.cfg.Auth.InvitationConfirmationTokenValidity) * time.Second, @@ -376,6 +387,7 @@ func (impl *Implm) Run( l.Named("probo"), slackService, iamService, + emailStaticAssetURLs, ) if err != nil { return fmt.Errorf("cannot create probo service: %w", err) @@ -393,6 +405,7 @@ func (impl *Implm) Run( fileManagerService, l, slackService, + emailStaticAssetURLs, ) serverHandler, err := server.NewServer( diff --git a/pkg/trust/service.go b/pkg/trust/service.go index ab357b097..1b11ddfa7 100644 --- a/pkg/trust/service.go +++ b/pkg/trust/service.go @@ -22,6 +22,7 @@ import ( "github.com/aws/aws-sdk-go-v2/service/s3" "go.gearno.de/kit/log" "go.gearno.de/kit/pg" + "go.probo.inc/probo/packages/emails" "go.probo.inc/probo/pkg/coredata" "go.probo.inc/probo/pkg/crypto/cipher" "go.probo.inc/probo/pkg/filemanager" @@ -35,18 +36,19 @@ import ( type ( Service struct { - pg *pg.Client - s3 *s3.Client - bucket string - proboSvc *probo.Service - encryptionKey cipher.EncryptionKey - slackSigningSecret string - baseURL string - iam *iam.Service - html2pdfConverter *html2pdf.Converter - fileManager *filemanager.Service - logger *log.Logger - slack *slack.Service + pg *pg.Client + s3 *s3.Client + bucket string + proboSvc *probo.Service + encryptionKey cipher.EncryptionKey + slackSigningSecret string + baseURL string + iam *iam.Service + html2pdfConverter *html2pdf.Converter + fileManager *filemanager.Service + logger *log.Logger + slack *slack.Service + emailStaticAssetURLs emails.StaticAssetURLs } TenantService struct { @@ -61,6 +63,7 @@ type ( html2pdfConverter *html2pdf.Converter fileManager *filemanager.Service logger *log.Logger + emailStaticAssetURLs emails.StaticAssetURLs TrustCenters *TrustCenterService Documents *DocumentService Audits *AuditService @@ -87,35 +90,38 @@ func NewService( fileManagerService *filemanager.Service, logger *log.Logger, slack *slack.Service, + emailStaticAssetURLs emails.StaticAssetURLs, ) *Service { return &Service{ - pg: pgClient, - s3: s3Client, - bucket: bucket, - encryptionKey: encryptionKey, - slackSigningSecret: slackSigningSecret, - baseURL: baseURL, - iam: iam, - html2pdfConverter: html2pdfConverter, - fileManager: fileManagerService, - logger: logger, - slack: slack, + pg: pgClient, + s3: s3Client, + bucket: bucket, + encryptionKey: encryptionKey, + slackSigningSecret: slackSigningSecret, + baseURL: baseURL, + iam: iam, + html2pdfConverter: html2pdfConverter, + fileManager: fileManagerService, + logger: logger, + slack: slack, + emailStaticAssetURLs: emailStaticAssetURLs, } } func (s *Service) WithTenant(tenantID gid.TenantID) *TenantService { tenantService := &TenantService{ - pg: s.pg, - s3: s.s3, - bucket: s.bucket, - scope: coredata.NewScope(tenantID), - proboSvc: s.proboSvc, - encryptionKey: s.encryptionKey, - baseURL: s.baseURL, - iam: s.iam, - html2pdfConverter: s.html2pdfConverter, - fileManager: s.fileManager, - logger: s.logger, + pg: s.pg, + s3: s.s3, + bucket: s.bucket, + scope: coredata.NewScope(tenantID), + proboSvc: s.proboSvc, + encryptionKey: s.encryptionKey, + baseURL: s.baseURL, + iam: s.iam, + html2pdfConverter: s.html2pdfConverter, + fileManager: s.fileManager, + logger: s.logger, + emailStaticAssetURLs: s.emailStaticAssetURLs, } tenantService.TrustCenters = &TrustCenterService{svc: tenantService} diff --git a/pkg/trust/trust_center_service.go b/pkg/trust/trust_center_service.go index 16efbd65b..5560f135d 100644 --- a/pkg/trust/trust_center_service.go +++ b/pkg/trust/trust_center_service.go @@ -226,7 +226,7 @@ func (s *TrustCenterService) EmailPresenterConfig(ctx context.Context, complianc organization = &coredata.Organization{} customDomain *coredata.CustomDomain logoFile = &coredata.File{} - emailPresenterCfg = emails.DefaultPresenterConfig(s.svc.baseURL) + emailPresenterCfg = emails.DefaultPresenterConfig(s.svc.baseURL, s.svc.emailStaticAssetURLs) ) scope := coredata.NewScopeFromObjectID(compliancePageID)