1
0
mirror of https://github.com/jhillyerd/inbucket.git synced 2025-12-18 18:17:03 +00:00

Hide envelope, use Part.Content for #85

This commit is contained in:
James Hillyerd
2018-03-20 17:55:43 -07:00
parent 6d250a47b4
commit e7a86bd8f8
5 changed files with 65 additions and 36 deletions

View File

@@ -121,7 +121,7 @@ func (s *StoreManager) GetMessage(mailbox, id string) (*Message, error) {
} }
_ = r.Close() _ = r.Close()
header := makeMetadata(sm) header := makeMetadata(sm)
return &Message{Metadata: *header, Envelope: env}, nil return &Message{Metadata: *header, env: env}, nil
} }
// PurgeMessages removes all messages from the specified mailbox. // PurgeMessages removes all messages from the specified mailbox.

View File

@@ -5,6 +5,7 @@ import (
"io" "io"
"io/ioutil" "io/ioutil"
"net/mail" "net/mail"
"net/textproto"
"time" "time"
"github.com/jhillyerd/enmime" "github.com/jhillyerd/enmime"
@@ -25,7 +26,40 @@ type Metadata struct {
// Message holds both the metadata and content of a message. // Message holds both the metadata and content of a message.
type Message struct { type Message struct {
Metadata Metadata
Envelope *enmime.Envelope env *enmime.Envelope
}
// New constructs a new Message
func New(m Metadata, e *enmime.Envelope) *Message {
return &Message{
Metadata: m,
env: e,
}
}
// Attachments returns the MIME attachments for the message.
func (m *Message) Attachments() []*enmime.Part {
return m.env.Attachments
}
// Header returns the header map for this message.
func (m *Message) Header() textproto.MIMEHeader {
return m.env.Root.Header
}
// HTML returns the HTML body of the message.
func (m *Message) HTML() string {
return m.env.HTML
}
// MIMEErrors returns MIME parsing errors and warnings.
func (m *Message) MIMEErrors() []*enmime.Error {
return m.env.Errors
}
// Text returns the plain text body of the message.
func (m *Message) Text() string {
return m.env.Text
} }
// Delivery is used to add a message to storage. // Delivery is used to add a message to storage.

View File

@@ -7,7 +7,6 @@ import (
"crypto/md5" "crypto/md5"
"encoding/hex" "encoding/hex"
"io/ioutil"
"strconv" "strconv"
"github.com/jhillyerd/inbucket/pkg/log" "github.com/jhillyerd/inbucket/pkg/log"
@@ -63,19 +62,20 @@ func MailboxShowV1(w http.ResponseWriter, req *http.Request, ctx *web.Context) (
// This doesn't indicate empty, likely an IO error // This doesn't indicate empty, likely an IO error
return fmt.Errorf("GetMessage(%q) failed: %v", id, err) return fmt.Errorf("GetMessage(%q) failed: %v", id, err)
} }
mime := msg.Envelope
attachments := make([]*model.JSONMessageAttachmentV1, len(mime.Attachments)) attachParts := msg.Attachments()
for i, att := range mime.Attachments { attachments := make([]*model.JSONMessageAttachmentV1, len(attachParts))
var content []byte for i, part := range attachParts {
content, err = ioutil.ReadAll(att) content := part.Content
var checksum = md5.Sum(content) var checksum = md5.Sum(content)
attachments[i] = &model.JSONMessageAttachmentV1{ attachments[i] = &model.JSONMessageAttachmentV1{
ContentType: att.ContentType, ContentType: part.ContentType,
FileName: att.FileName, FileName: part.FileName,
DownloadLink: "http://" + req.Host + "/mailbox/dattach/" + name + "/" + id + "/" + strconv.Itoa(i) + "/" + att.FileName, DownloadLink: "http://" + req.Host + "/mailbox/dattach/" + name + "/" + id + "/" +
ViewLink: "http://" + req.Host + "/mailbox/vattach/" + name + "/" + id + "/" + strconv.Itoa(i) + "/" + att.FileName, strconv.Itoa(i) + "/" + part.FileName,
MD5: hex.EncodeToString(checksum[:]), ViewLink: "http://" + req.Host + "/mailbox/vattach/" + name + "/" + id + "/" +
strconv.Itoa(i) + "/" + part.FileName,
MD5: hex.EncodeToString(checksum[:]),
} }
} }
@@ -88,10 +88,10 @@ func MailboxShowV1(w http.ResponseWriter, req *http.Request, ctx *web.Context) (
Subject: msg.Subject, Subject: msg.Subject,
Date: msg.Date, Date: msg.Date,
Size: msg.Size, Size: msg.Size,
Header: mime.Root.Header, Header: msg.Header(),
Body: &model.JSONMessageBodyV1{ Body: &model.JSONMessageBodyV1{
Text: mime.Text, Text: msg.Text(),
HTML: mime.HTML, HTML: msg.HTML(),
}, },
Attachments: attachments, Attachments: attachments,
}) })

View File

@@ -172,8 +172,8 @@ func TestRestMessage(t *testing.T) {
} }
// Test JSON message headers // Test JSON message headers
msg1 := &message.Message{ msg1 := message.New(
Metadata: message.Metadata{ message.Metadata{
Mailbox: "good", Mailbox: "good",
ID: "0001", ID: "0001",
From: &mail.Address{Name: "", Address: "from1@host"}, From: &mail.Address{Name: "", Address: "from1@host"},
@@ -181,7 +181,7 @@ func TestRestMessage(t *testing.T) {
Subject: "subject 1", Subject: "subject 1",
Date: time.Date(2012, 2, 1, 10, 11, 12, 253, time.FixedZone("PST", -800)), Date: time.Date(2012, 2, 1, 10, 11, 12, 253, time.FixedZone("PST", -800)),
}, },
Envelope: &enmime.Envelope{ &enmime.Envelope{
Text: "This is some text", Text: "This is some text",
HTML: "This is some HTML", HTML: "This is some HTML",
Root: &enmime.Part{ Root: &enmime.Part{
@@ -191,7 +191,7 @@ func TestRestMessage(t *testing.T) {
}, },
}, },
}, },
} )
mm.AddMessage("good", msg1) mm.AddMessage("good", msg1)
// Check return code // Check return code

View File

@@ -102,12 +102,11 @@ func MailboxShow(w http.ResponseWriter, req *http.Request, ctx *web.Context) (er
// This doesn't indicate empty, likely an IO error // This doesn't indicate empty, likely an IO error
return fmt.Errorf("GetMessage(%q) failed: %v", id, err) return fmt.Errorf("GetMessage(%q) failed: %v", id, err)
} }
mime := msg.Envelope body := template.HTML(web.TextToHTML(msg.Text()))
body := template.HTML(web.TextToHTML(mime.Text)) htmlAvailable := msg.HTML() != ""
htmlAvailable := mime.HTML != ""
var htmlBody template.HTML var htmlBody template.HTML
if htmlAvailable { if htmlAvailable {
if str, err := sanitize.HTML(mime.HTML); err == nil { if str, err := sanitize.HTML(msg.HTML()); err == nil {
htmlBody = template.HTML(str) htmlBody = template.HTML(str)
} else { } else {
log.Warnf("HTML sanitizer failed: %s", err) log.Warnf("HTML sanitizer failed: %s", err)
@@ -121,8 +120,8 @@ func MailboxShow(w http.ResponseWriter, req *http.Request, ctx *web.Context) (er
"body": body, "body": body,
"htmlAvailable": htmlAvailable, "htmlAvailable": htmlAvailable,
"htmlBody": htmlBody, "htmlBody": htmlBody,
"mimeErrors": mime.Errors, "mimeErrors": msg.MIMEErrors(),
"attachments": mime.Attachments, "attachments": msg.Attachments(),
}) })
} }
@@ -143,14 +142,13 @@ func MailboxHTML(w http.ResponseWriter, req *http.Request, ctx *web.Context) (er
// This doesn't indicate empty, likely an IO error // This doesn't indicate empty, likely an IO error
return fmt.Errorf("GetMessage(%q) failed: %v", id, err) return fmt.Errorf("GetMessage(%q) failed: %v", id, err)
} }
mime := msg.Envelope
// Render partial template // Render partial template
w.Header().Set("Content-Type", "text/html; charset=UTF-8") w.Header().Set("Content-Type", "text/html; charset=UTF-8")
return web.RenderPartial("mailbox/_html.html", w, map[string]interface{}{ return web.RenderPartial("mailbox/_html.html", w, map[string]interface{}{
"ctx": ctx, "ctx": ctx,
"name": name, "name": name,
"message": msg, "message": msg,
"body": template.HTML(mime.HTML), "body": template.HTML(msg.HTML()),
}) })
} }
@@ -206,18 +204,16 @@ func MailboxDownloadAttach(w http.ResponseWriter, req *http.Request, ctx *web.Co
// This doesn't indicate empty, likely an IO error // This doesn't indicate empty, likely an IO error
return fmt.Errorf("GetMessage(%q) failed: %v", id, err) return fmt.Errorf("GetMessage(%q) failed: %v", id, err)
} }
body := msg.Envelope if int(num) >= len(msg.Attachments()) {
if int(num) >= len(body.Attachments) {
ctx.Session.AddFlash("Attachment number too high", "errors") ctx.Session.AddFlash("Attachment number too high", "errors")
_ = ctx.Session.Save(req, w) _ = ctx.Session.Save(req, w)
http.Redirect(w, req, web.Reverse("RootIndex"), http.StatusSeeOther) http.Redirect(w, req, web.Reverse("RootIndex"), http.StatusSeeOther)
return nil return nil
} }
part := body.Attachments[num]
// Output attachment // Output attachment
w.Header().Set("Content-Type", "application/octet-stream") w.Header().Set("Content-Type", "application/octet-stream")
w.Header().Set("Content-Disposition", "attachment") w.Header().Set("Content-Disposition", "attachment")
_, err = io.Copy(w, part) _, err = w.Write(msg.Attachments()[num].Content)
return err return err
} }
@@ -249,16 +245,15 @@ func MailboxViewAttach(w http.ResponseWriter, req *http.Request, ctx *web.Contex
// This doesn't indicate empty, likely an IO error // This doesn't indicate empty, likely an IO error
return fmt.Errorf("GetMessage(%q) failed: %v", id, err) return fmt.Errorf("GetMessage(%q) failed: %v", id, err)
} }
body := msg.Envelope if int(num) >= len(msg.Attachments()) {
if int(num) >= len(body.Attachments) {
ctx.Session.AddFlash("Attachment number too high", "errors") ctx.Session.AddFlash("Attachment number too high", "errors")
_ = ctx.Session.Save(req, w) _ = ctx.Session.Save(req, w)
http.Redirect(w, req, web.Reverse("RootIndex"), http.StatusSeeOther) http.Redirect(w, req, web.Reverse("RootIndex"), http.StatusSeeOther)
return nil return nil
} }
part := body.Attachments[num]
// Output attachment // Output attachment
part := msg.Attachments()[num]
w.Header().Set("Content-Type", part.ContentType) w.Header().Set("Content-Type", part.ContentType)
_, err = io.Copy(w, part) _, err = w.Write(part.Content)
return err return err
} }