Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions cmd/archive.go
Original file line number Diff line number Diff line change
Expand Up @@ -244,6 +244,10 @@ func (a *App) compileArchiveCampaigns(camps []models.Campaign) ([]manager.Campai
)
for _, c := range camps {
camp := c

// Resolve data-embed images to media URLs as cid: cannot resolve on a web page.
a.manager.ApplyArchiveImages(&camp)

if err := camp.CompileTemplate(a.manager.TemplateFuncs(&camp)); err != nil {
a.log.Printf("error compiling template: %v", err)
return nil, echo.NewHTTPError(http.StatusInternalServerError, a.i18n.T("public.errorFetchingCampaign"))
Expand Down
10 changes: 10 additions & 0 deletions cmd/manager_store.go
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,16 @@ func (s *store) GetInlineAttachmentByFilename(filename string) (models.Attachmen
}, cid, nil
}

// GetMediaURLByFilename returns the public URL of a media item by filename.
func (s *store) GetMediaURLByFilename(filename string) (string, error) {
m, err := s.core.GetMedia(0, "", filename, s.media)
if err != nil {
return "", err
}

return m.URL, nil
}

// CreateLink registers a URL with a UUID for tracking clicks and returns the UUID.
func (s *store) CreateLink(url string) (string, error) {
// Create a new UUID for the URL. If the URL already exists in the DB
Expand Down
3 changes: 3 additions & 0 deletions cmd/public.go
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,9 @@ func (a *App) ViewCampaignMessage(c echo.Context) error {
makeMsgTpl(a.i18n.T("public.errorTitle"), "", a.i18n.Ts("public.errorFetchingCampaign")))
}

// Resolve data-embed images to media URLs as cid: cannot resolve on a web page.
a.manager.ApplyArchiveImages(&camp)

// Compile the template.
if err := camp.CompileTemplate(a.manager.TemplateFuncs(&camp)); err != nil {
a.log.Printf("error compiling template: %v", err)
Expand Down
46 changes: 46 additions & 0 deletions internal/manager/manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ type Store interface {
GetCampaign(campID int) (*models.Campaign, error)
GetAttachment(mediaID int) (models.Attachment, error)
GetInlineAttachmentByFilename(filename string) (models.Attachment, string, error)
GetMediaURLByFilename(filename string) (string, error)
UpdateCampaignStatus(campID int, status string) error
UpdateCampaignCounts(campID int, toSend int, sent int, lastSubID int) error
CreateLink(url string) (string, error)
Expand Down Expand Up @@ -766,6 +767,51 @@ func (m *Manager) applyInlineImages(body string, cache map[string]string) (strin
return out, atts
}

// ApplyArchiveImages resolves any <img ... data-embed ...> tags in the campaign
// body and template body to public media URLs. The archive is rendered as a
// standalone HTML page and not a MIME message, so cid: cannot resolve there.
func (m *Manager) ApplyArchiveImages(c *models.Campaign) {
if c.ContentType == models.CampaignContentTypePlain {
return
}

cache := make(map[string]string)
c.Body = m.applyArchiveImages(c.Body, cache)
c.TemplateBody = m.applyArchiveImages(c.TemplateBody, cache)
}

func (m *Manager) applyArchiveImages(body string, cache map[string]string) string {
if !strings.Contains(body, attribInlineEmbed) {
return body
}

return reInlineImage.ReplaceAllStringFunc(body, func(tag string) string {
src := extractSrc(tag)
if src == "" || strings.HasPrefix(strings.ToLower(src), "cid:") {
return tag
}

fname := filenameFromSrc(src)
if fname == "" {
return tag
}

u, ok := cache[src]
if !ok {
s, err := m.store.GetMediaURLByFilename(fname)
if err != nil {
m.log.Printf("archive image %q not resolved: %v", src, err)
}
u = s
cache[src] = u
}
if u == "" {
return tag
}
return reImgSrc.ReplaceAllString(tag, `${1}src="`+u+`"`)
})
}

// MakeContentID returns a standard `Content-ID` value (without the angle brackets).
func MakeContentID(key string) string {
sum := sha1.Sum([]byte(key))
Expand Down