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

chore: Update BeforeMailAccepted (#547)

* chore: rename BeforeMailAccepted to BeforeMailFromAccepted

Signed-off-by: James Hillyerd <james@hillyerd.com>

* chore: update BeforeMailAccepted to use SMTPSession

Signed-off-by: James Hillyerd <james@hillyerd.com>

---------

Signed-off-by: James Hillyerd <james@hillyerd.com>
This commit is contained in:
James Hillyerd
2024-10-19 14:06:51 -07:00
committed by GitHub
parent 9f90a59bef
commit 78d4c4f4e7
7 changed files with 70 additions and 62 deletions

View File

@@ -20,11 +20,11 @@ type Host struct {
// processed asynchronously with respect to the rest of Inbuckets operation. However, an event // processed asynchronously with respect to the rest of Inbuckets operation. However, an event
// listener will not be called until the one before it completes. // listener will not be called until the one before it completes.
type Events struct { type Events struct {
AfterMessageDeleted AsyncEventBroker[event.MessageMetadata] AfterMessageDeleted AsyncEventBroker[event.MessageMetadata]
AfterMessageStored AsyncEventBroker[event.MessageMetadata] AfterMessageStored AsyncEventBroker[event.MessageMetadata]
BeforeMailAccepted EventBroker[event.AddressParts, event.SMTPResponse] BeforeMailFromAccepted EventBroker[event.SMTPSession, event.SMTPResponse]
BeforeMessageStored EventBroker[event.InboundMessage, event.InboundMessage] BeforeMessageStored EventBroker[event.InboundMessage, event.InboundMessage]
BeforeRcptToAccepted EventBroker[event.SMTPSession, event.SMTPResponse] BeforeRcptToAccepted EventBroker[event.SMTPSession, event.SMTPResponse]
} }
// Void indicates the event emitter will ignore any value returned by listeners. // Void indicates the event emitter will ignore any value returned by listeners.

View File

@@ -29,9 +29,9 @@ type InbucketAfterFuncs struct {
// InbucketBeforeFuncs holds references to Lua extension functions to be called // InbucketBeforeFuncs holds references to Lua extension functions to be called
// before Inbucket handles an event. // before Inbucket handles an event.
type InbucketBeforeFuncs struct { type InbucketBeforeFuncs struct {
MailAccepted *lua.LFunction MailFromAccepted *lua.LFunction
MessageStored *lua.LFunction MessageStored *lua.LFunction
RcptToAccepted *lua.LFunction RcptToAccepted *lua.LFunction
} }
func registerInbucketTypes(ls *lua.LState) { func registerInbucketTypes(ls *lua.LState) {
@@ -186,8 +186,8 @@ func inbucketBeforeIndex(ls *lua.LState) int {
// Push the requested field's value onto the stack. // Push the requested field's value onto the stack.
switch field { switch field {
case "mail_accepted": case "mail_from_accepted":
ls.Push(funcOrNil(before.MailAccepted)) ls.Push(funcOrNil(before.MailFromAccepted))
case "message_stored": case "message_stored":
ls.Push(funcOrNil(before.MessageStored)) ls.Push(funcOrNil(before.MessageStored))
case "rcpt_to_accepted": case "rcpt_to_accepted":
@@ -206,8 +206,8 @@ func inbucketBeforeNewIndex(ls *lua.LState) int {
index := ls.CheckString(2) index := ls.CheckString(2)
switch index { switch index {
case "mail_accepted": case "mail_from_accepted":
m.MailAccepted = ls.CheckFunction(3) m.MailFromAccepted = ls.CheckFunction(3)
case "message_stored": case "message_stored":
m.MessageStored = ls.CheckFunction(3) m.MessageStored = ls.CheckFunction(3)
case "rcpt_to_accepted": case "rcpt_to_accepted":

View File

@@ -62,7 +62,7 @@ func TestInbucketBeforeFuncs(t *testing.T) {
assert(inbucket, "inbucket should not be nil") assert(inbucket, "inbucket should not be nil")
assert(inbucket.before, "inbucket.before should not be nil") assert(inbucket.before, "inbucket.before should not be nil")
local fns = { "mail_accepted", "message_stored" } local fns = { "mail_from_accepted", "message_stored", "rcpt_to_accepted" }
-- Verify functions start off nil. -- Verify functions start off nil.
for i, name in ipairs(fns) do for i, name in ipairs(fns) do

View File

@@ -106,8 +106,8 @@ func (h *Host) wireFunctions(logger zerolog.Logger, ls *lua.LState) {
if ib.After.MessageStored != nil { if ib.After.MessageStored != nil {
events.AfterMessageStored.AddListener(listenerName, h.handleAfterMessageStored) events.AfterMessageStored.AddListener(listenerName, h.handleAfterMessageStored)
} }
if ib.Before.MailAccepted != nil { if ib.Before.MailFromAccepted != nil {
events.BeforeMailAccepted.AddListener(listenerName, h.handleBeforeMailAccepted) events.BeforeMailFromAccepted.AddListener(listenerName, h.handleBeforeMailFromAccepted)
} }
if ib.Before.MessageStored != nil { if ib.Before.MessageStored != nil {
events.BeforeMessageStored.AddListener(listenerName, h.handleBeforeMessageStored) events.BeforeMessageStored.AddListener(listenerName, h.handleBeforeMessageStored)
@@ -151,18 +151,17 @@ func (h *Host) handleAfterMessageStored(msg event.MessageMetadata) {
} }
} }
func (h *Host) handleBeforeMailAccepted(addr event.AddressParts) *event.SMTPResponse { func (h *Host) handleBeforeMailFromAccepted(session event.SMTPSession) *event.SMTPResponse {
logger, ls, ib, ok := h.prepareInbucketFuncCall("before.mail_accepted") logger, ls, ib, ok := h.prepareInbucketFuncCall("before.mail_from_accepted")
if !ok { if !ok {
return nil return nil
} }
defer h.pool.putState(ls) defer h.pool.putState(ls)
logger.Debug().Msgf("Calling Lua function with %+v", addr) logger.Debug().Msgf("Calling Lua function with %+v", session)
if err := ls.CallByParam( if err := ls.CallByParam(
lua.P{Fn: ib.Before.MailAccepted, NRet: 1, Protect: true}, lua.P{Fn: ib.Before.MailFromAccepted, NRet: 1, Protect: true},
lua.LString(addr.Local), wrapSMTPSession(ls, &session),
lua.LString(addr.Domain),
); err != nil { ); err != nil {
logger.Error().Err(err).Msg("Failed to call Lua function") logger.Error().Err(err).Msg("Failed to call Lua function")
return nil return nil

View File

@@ -105,11 +105,11 @@ func TestAfterMessageStored(t *testing.T) {
test.AssertNotified(t, notify) test.AssertNotified(t, notify)
} }
func TestBeforeMailAccepted(t *testing.T) { func TestBeforeMailFromAccepted(t *testing.T) {
// Register lua event listener. // Register lua event listener.
script := ` script := `
function inbucket.before.mail_accepted(localpart, domain) function inbucket.before.mail_from_accepted(session)
if localpart == "from" and domain == "test" then if session.from.address == "from@example.com" then
logger.info("allowing message", {}) logger.info("allowing message", {})
return smtp.allow() return smtp.allow()
else else
@@ -123,22 +123,30 @@ func TestBeforeMailAccepted(t *testing.T) {
consoleLogger, extHost, strings.NewReader(test.LuaInit+script), "test.lua") consoleLogger, extHost, strings.NewReader(test.LuaInit+script), "test.lua")
require.NoError(t, err) require.NoError(t, err)
// Send event to be accepted. {
addr := &event.AddressParts{Local: "from", Domain: "test"} // Send event to be accepted.
got := extHost.Events.BeforeMailAccepted.Emit(addr) session := event.SMTPSession{
want := event.ActionAllow From: &mail.Address{Name: "", Address: "from@example.com"},
require.NotNil(t, got, "Expected result from Emit()") }
if got.Action != want { got := extHost.Events.BeforeMailFromAccepted.Emit(&session)
t.Errorf("Got %v, wanted %v for addr %v", got.Action, want, addr) want := event.ActionAllow
require.NotNil(t, got, "Expected result from Emit()")
if got.Action != want {
t.Errorf("Got %v, wanted %v for addr %v", got.Action, want, session.From)
}
} }
// Send event to be denied. {
addr = &event.AddressParts{Local: "reject", Domain: "me"} // Send event to be denied.
got = extHost.Events.BeforeMailAccepted.Emit(addr) session := event.SMTPSession{
want = event.ActionDeny From: &mail.Address{Name: "", Address: "from@reject.com"},
require.NotNil(t, got, "Expected result from Emit()") }
if got.Action != want { got := extHost.Events.BeforeMailFromAccepted.Emit(&session)
t.Errorf("Got %v, wanted %v for addr %v", got.Action, want, addr) want := event.ActionDeny
require.NotNil(t, got, "Expected result from Emit()")
if got.Action != want {
t.Errorf("Got %v, wanted %v for addr %v", got.Action, want, session.From)
}
} }
} }

View File

@@ -408,7 +408,7 @@ func (s *Session) parseMailFromCmd(arg string) {
s.logger.Debug().Msgf("Mail sender is %v", from) s.logger.Debug().Msgf("Mail sender is %v", from)
// Parse from address. // Parse from address.
localpart, domain, err := policy.ParseEmailAddress(from) _, domain, err := policy.ParseEmailAddress(from)
s.logger.Debug().Msgf("Origin domain is %v", domain) s.logger.Debug().Msgf("Origin domain is %v", domain)
if from != "" && err != nil { if from != "" && err != nil {
s.send("501 Bad sender address syntax") s.send("501 Bad sender address syntax")
@@ -446,10 +446,17 @@ func (s *Session) parseMailFromCmd(arg string) {
} }
} }
// Parse origin (from) address.
origin, err := s.addrPolicy.ParseOrigin(from)
if err != nil {
s.send("501 Bad origin address syntax")
s.logger.Warn().Str("from", from).Err(err).Msg("Bad address as MAIL arg")
return
}
// Process through extensions. // Process through extensions.
extAction := event.ActionDefer extAction := event.ActionDefer
extResult := s.extHost.Events.BeforeMailAccepted.Emit( extResult := s.extHost.Events.BeforeMailFromAccepted.Emit(&event.SMTPSession{From: &origin.Address})
&event.AddressParts{Local: localpart, Domain: domain})
if extResult != nil { if extResult != nil {
extAction = extResult.Action extAction = extResult.Action
} }
@@ -460,12 +467,6 @@ func (s *Session) parseMailFromCmd(arg string) {
} }
// Sender was permitted by an extension, or no extension rejected it. // Sender was permitted by an extension, or no extension rejected it.
origin, err := s.addrPolicy.ParseOrigin(from)
if err != nil {
s.send("501 Bad origin address syntax")
s.logger.Warn().Str("from", from).Err(err).Msg("Bad address as MAIL arg")
return
}
s.from = origin s.from = origin
// Ignore ShouldAccept if extensions explicitly allowed this From. // Ignore ShouldAccept if extensions explicitly allowed this From.
if extAction == event.ActionDefer && !s.from.ShouldAccept() { if extAction == event.ActionDefer && !s.from.ShouldAccept() {

View File

@@ -385,17 +385,17 @@ Hi!
_, _, _ = c.ReadCodeLine(221) _, _, _ = c.ReadCodeLine(221)
} }
// Tests "MAIL FROM" emits BeforeMailAccepted event. // Tests "MAIL FROM" emits BeforeMailFromAccepted event.
func TestBeforeMailAcceptedEventEmitted(t *testing.T) { func TestBeforeMailFromAcceptedEventEmitted(t *testing.T) {
ds := test.NewStore() ds := test.NewStore()
extHost := extension.NewHost() extHost := extension.NewHost()
server := setupSMTPServer(ds, extHost) server := setupSMTPServer(ds, extHost)
var got *event.AddressParts var got *event.SMTPSession
extHost.Events.BeforeMailAccepted.AddListener( extHost.Events.BeforeMailFromAccepted.AddListener(
"test", "test",
func(addr event.AddressParts) *event.SMTPResponse { func(session event.SMTPSession) *event.SMTPResponse {
got = &addr got = &session
return &event.SMTPResponse{Action: event.ActionDefer} return &event.SMTPResponse{Action: event.ActionDefer}
}) })
@@ -407,22 +407,22 @@ func TestBeforeMailAcceptedEventEmitted(t *testing.T) {
playSession(t, server, script) playSession(t, server, script)
assert.NotNil(t, got, "BeforeMailListener did not receive Address") assert.NotNil(t, got, "BeforeMailListener did not receive Address")
assert.Equal(t, "john", got.Local, "Address local part had wrong value") assert.Equal(t, "john@gmail.com", got.From.Address, "Address had wrong value")
assert.Equal(t, "gmail.com", got.Domain, "Address domain part had wrong value")
} }
// Test "MAIL FROM" acts on BeforeMailAccepted event result. // Test "MAIL FROM" acts on BeforeMailFromAccepted event result.
func TestBeforeMailAcceptedEventResponse(t *testing.T) { func TestBeforeMailFromAcceptedEventResponse(t *testing.T) {
ds := test.NewStore() ds := test.NewStore()
extHost := extension.NewHost() extHost := extension.NewHost()
server := setupSMTPServer(ds, extHost) server := setupSMTPServer(ds, extHost)
var shouldReturn *event.SMTPResponse var shouldReturn *event.SMTPResponse
var gotEvent *event.AddressParts var gotEvent *event.SMTPSession
extHost.Events.BeforeMailAccepted.AddListener(
extHost.Events.BeforeMailFromAccepted.AddListener(
"test", "test",
func(addr event.AddressParts) *event.SMTPResponse { func(session event.SMTPSession) *event.SMTPResponse {
gotEvent = &addr gotEvent = &session
return shouldReturn return shouldReturn
}) })
@@ -462,7 +462,7 @@ func TestBeforeMailAcceptedEventResponse(t *testing.T) {
{"QUIT", 221}} {"QUIT", 221}}
playSession(t, server, script) playSession(t, server, script)
assert.NotNil(t, gotEvent, "BeforeMailListener did not receive Address") assert.NotNil(t, gotEvent, "BeforeMailFromAccepted did not receive event")
}) })
} }
} }