mirror of
https://github.com/jhillyerd/inbucket.git
synced 2025-12-17 17:47:03 +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:
@@ -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.
|
||||||
|
|||||||
@@ -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":
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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() {
|
||||||
|
|||||||
@@ -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")
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user