mirror of
https://github.com/wiggin77/mailrelay.git
synced 2025-07-13 04:35:57 +02:00
371 lines
9.3 KiB
Go
371 lines
9.3 KiB
Go
package main
|
|
|
|
import (
|
|
"bytes"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/jpillora/ipfilter"
|
|
"github.com/phires/go-guerrilla/log"
|
|
"github.com/phires/go-guerrilla/mail"
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
// setupTestLogger initializes the logger for testing
|
|
func setupTestLogger(t *testing.T) {
|
|
var err error
|
|
Logger, err = log.GetLogger("stdout", "info")
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
func TestSendMail_Success(t *testing.T) {
|
|
setupTestLogger(t)
|
|
|
|
// Start mock SMTP server
|
|
server := NewMockSMTPServer(t)
|
|
require.NoError(t, server.Start())
|
|
defer server.Stop()
|
|
|
|
// Configure for testing
|
|
config := &relayConfig{
|
|
Server: server.Address(),
|
|
Port: server.Port(),
|
|
STARTTLS: true,
|
|
LoginAuthType: false,
|
|
Username: "",
|
|
Password: "",
|
|
SkipVerify: true,
|
|
HeloHost: "",
|
|
}
|
|
|
|
// Create test envelope
|
|
envelope := &mail.Envelope{
|
|
MailFrom: mail.Address{User: "sender", Host: "test.com"},
|
|
RcptTo: []mail.Address{
|
|
{User: "recipient1", Host: "example.com"},
|
|
{User: "recipient2", Host: "example.com"},
|
|
},
|
|
Data: *bytes.NewBufferString("Subject: Test\r\n\r\nThis is a test email."),
|
|
RemoteIP: "127.0.0.1",
|
|
}
|
|
|
|
// Set up IP filter to allow this IP
|
|
AllowedSendersFilter = ipfilter.New(ipfilter.Options{
|
|
AllowedIPs: []string{"127.0.0.1"},
|
|
BlockByDefault: false,
|
|
})
|
|
|
|
// Send email
|
|
err := sendMail(envelope, config)
|
|
assert.NoError(t, err)
|
|
|
|
// Verify the mock server received the email
|
|
conn := server.GetLastConnection()
|
|
require.NotNil(t, conn)
|
|
assert.Equal(t, "sender@test.com", conn.From)
|
|
assert.Equal(t, []string{"recipient1@example.com", "recipient2@example.com"}, conn.To)
|
|
assert.Contains(t, conn.Data, "Subject: Test")
|
|
assert.Contains(t, conn.Data, "This is a test email.")
|
|
}
|
|
|
|
func TestSendMail_WithAuthentication(t *testing.T) {
|
|
setupTestLogger(t)
|
|
// Start mock SMTP server with auth requirement
|
|
server := NewMockSMTPServer(t)
|
|
server.RequireAuth = true
|
|
require.NoError(t, server.Start())
|
|
defer server.Stop()
|
|
|
|
// Configure with authentication
|
|
config := &relayConfig{
|
|
Server: server.Address(),
|
|
Port: server.Port(),
|
|
STARTTLS: true,
|
|
LoginAuthType: false,
|
|
Username: "testuser",
|
|
Password: "testpass",
|
|
SkipVerify: true,
|
|
HeloHost: "relay.test.com",
|
|
}
|
|
|
|
// Create test envelope
|
|
envelope := &mail.Envelope{
|
|
MailFrom: mail.Address{User: "sender", Host: "test.com"},
|
|
RcptTo: []mail.Address{
|
|
{User: "recipient", Host: "example.com"},
|
|
},
|
|
Data: *bytes.NewBufferString("Subject: Auth Test\r\n\r\nAuthenticated email."),
|
|
RemoteIP: "127.0.0.1",
|
|
}
|
|
|
|
// Allow IP
|
|
AllowedSendersFilter = ipfilter.New(ipfilter.Options{
|
|
BlockByDefault: false,
|
|
})
|
|
|
|
// Send email
|
|
err := sendMail(envelope, config)
|
|
assert.NoError(t, err)
|
|
|
|
// Verify authentication was used
|
|
conn := server.GetLastConnection()
|
|
require.NotNil(t, conn)
|
|
assert.NotEmpty(t, conn.AuthUser)
|
|
assert.NotEmpty(t, conn.AuthPass)
|
|
}
|
|
|
|
func TestSendMail_WithLoginAuth(t *testing.T) {
|
|
setupTestLogger(t)
|
|
// Start mock SMTP server with LOGIN auth support
|
|
server := NewMockSMTPServer(t)
|
|
server.RequireAuth = true
|
|
server.SupportLoginAuth = true
|
|
require.NoError(t, server.Start())
|
|
defer server.Stop()
|
|
|
|
// Configure with LOGIN authentication
|
|
config := &relayConfig{
|
|
Server: server.Address(),
|
|
Port: server.Port(),
|
|
STARTTLS: true,
|
|
LoginAuthType: true,
|
|
Username: "testuser",
|
|
Password: "testpass",
|
|
SkipVerify: true,
|
|
HeloHost: "",
|
|
}
|
|
|
|
// Create test envelope
|
|
envelope := &mail.Envelope{
|
|
MailFrom: mail.Address{User: "sender", Host: "test.com"},
|
|
RcptTo: []mail.Address{
|
|
{User: "recipient", Host: "example.com"},
|
|
},
|
|
Data: *bytes.NewBufferString("Subject: LOGIN Auth Test\r\n\r\nLOGIN authenticated email."),
|
|
RemoteIP: "127.0.0.1",
|
|
}
|
|
|
|
// Allow IP
|
|
AllowedSendersFilter = ipfilter.New(ipfilter.Options{
|
|
BlockByDefault: false,
|
|
})
|
|
|
|
// Send email
|
|
err := sendMail(envelope, config)
|
|
assert.NoError(t, err)
|
|
|
|
// Verify LOGIN authentication was used
|
|
conn := server.GetLastConnection()
|
|
require.NotNil(t, conn)
|
|
assert.NotEmpty(t, conn.AuthUser)
|
|
assert.NotEmpty(t, conn.AuthPass)
|
|
}
|
|
|
|
func TestSendMail_IPFiltering_Blocked(t *testing.T) {
|
|
setupTestLogger(t)
|
|
// Start mock SMTP server
|
|
server := NewMockSMTPServer(t)
|
|
require.NoError(t, server.Start())
|
|
defer server.Stop()
|
|
|
|
// Configure server
|
|
config := &relayConfig{
|
|
Server: server.Address(),
|
|
Port: server.Port(),
|
|
STARTTLS: true,
|
|
LoginAuthType: false,
|
|
Username: "",
|
|
Password: "",
|
|
SkipVerify: true,
|
|
HeloHost: "",
|
|
}
|
|
|
|
// Create test envelope with blocked IP
|
|
envelope := &mail.Envelope{
|
|
MailFrom: mail.Address{User: "sender", Host: "test.com"},
|
|
RcptTo: []mail.Address{
|
|
{User: "recipient", Host: "example.com"},
|
|
},
|
|
Data: *bytes.NewBufferString("Subject: Test\r\n\r\nThis should be blocked."),
|
|
RemoteIP: "192.168.1.100", // This IP will be blocked
|
|
}
|
|
|
|
// Set up IP filter to block this IP
|
|
AllowedSendersFilter = ipfilter.New(ipfilter.Options{
|
|
AllowedIPs: []string{"127.0.0.1"},
|
|
BlockByDefault: true,
|
|
})
|
|
|
|
// Send email - should fail due to IP filtering
|
|
err := sendMail(envelope, config)
|
|
assert.Error(t, err)
|
|
assert.Contains(t, err.Error(), "192.168.1.100")
|
|
assert.Contains(t, err.Error(), "not allowed to send email")
|
|
|
|
// Verify no email was sent to the server
|
|
conn := server.GetLastConnection()
|
|
// The connection might be nil or have no data since the IP was blocked before SMTP
|
|
if conn != nil {
|
|
assert.Empty(t, conn.From)
|
|
}
|
|
}
|
|
|
|
func TestSendMail_IPFiltering_Allowed(t *testing.T) {
|
|
setupTestLogger(t)
|
|
// Start mock SMTP server
|
|
server := NewMockSMTPServer(t)
|
|
require.NoError(t, server.Start())
|
|
defer server.Stop()
|
|
|
|
// Configure server
|
|
config := &relayConfig{
|
|
Server: server.Address(),
|
|
Port: server.Port(),
|
|
STARTTLS: true,
|
|
LoginAuthType: false,
|
|
Username: "",
|
|
Password: "",
|
|
SkipVerify: true,
|
|
HeloHost: "",
|
|
}
|
|
|
|
// Create test envelope with allowed IP
|
|
envelope := &mail.Envelope{
|
|
MailFrom: mail.Address{User: "sender", Host: "test.com"},
|
|
RcptTo: []mail.Address{
|
|
{User: "recipient", Host: "example.com"},
|
|
},
|
|
Data: *bytes.NewBufferString("Subject: Test\r\n\r\nThis should be allowed."),
|
|
RemoteIP: "192.168.1.100",
|
|
}
|
|
|
|
// Set up IP filter to allow this specific IP
|
|
AllowedSendersFilter = ipfilter.New(ipfilter.Options{
|
|
AllowedIPs: []string{"192.168.1.0/24"},
|
|
BlockByDefault: true,
|
|
})
|
|
|
|
// Send email - should succeed
|
|
err := sendMail(envelope, config)
|
|
assert.NoError(t, err)
|
|
|
|
// Verify email was sent to the server
|
|
conn := server.GetLastConnection()
|
|
require.NotNil(t, conn)
|
|
assert.Equal(t, "sender@test.com", conn.From)
|
|
assert.Equal(t, []string{"recipient@example.com"}, conn.To)
|
|
}
|
|
|
|
func TestSendMail_ServerErrors(t *testing.T) {
|
|
setupTestLogger(t)
|
|
tests := []struct {
|
|
name string
|
|
failCommand string
|
|
expectError string
|
|
}{
|
|
{
|
|
name: "MAIL command fails",
|
|
failCommand: "MAIL",
|
|
expectError: "mail error",
|
|
},
|
|
{
|
|
name: "RCPT command fails",
|
|
failCommand: "RCPT",
|
|
expectError: "rcpt error",
|
|
},
|
|
{
|
|
name: "DATA command fails",
|
|
failCommand: "DATA",
|
|
expectError: "data error",
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
// Start mock SMTP server
|
|
server := NewMockSMTPServer(t)
|
|
server.FailCommands[tt.failCommand] = true
|
|
require.NoError(t, server.Start())
|
|
defer server.Stop()
|
|
|
|
// Configure server
|
|
config := &relayConfig{
|
|
Server: server.Address(),
|
|
Port: server.Port(),
|
|
STARTTLS: true,
|
|
LoginAuthType: false,
|
|
Username: "",
|
|
Password: "",
|
|
SkipVerify: true,
|
|
HeloHost: "",
|
|
}
|
|
|
|
// Create test envelope
|
|
envelope := &mail.Envelope{
|
|
MailFrom: mail.Address{User: "sender", Host: "test.com"},
|
|
RcptTo: []mail.Address{
|
|
{User: "recipient", Host: "example.com"},
|
|
},
|
|
Data: *bytes.NewBufferString("Subject: Test\r\n\r\nThis should fail."),
|
|
RemoteIP: "127.0.0.1",
|
|
}
|
|
|
|
// Allow IP
|
|
AllowedSendersFilter = ipfilter.New(ipfilter.Options{
|
|
BlockByDefault: false,
|
|
})
|
|
|
|
// Send email - should fail
|
|
err := sendMail(envelope, config)
|
|
assert.Error(t, err)
|
|
assert.Contains(t, err.Error(), tt.expectError)
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestSendMail_ConnectionTimeout(t *testing.T) {
|
|
setupTestLogger(t)
|
|
// Start mock SMTP server with delay
|
|
server := NewMockSMTPServer(t)
|
|
server.ResponseDelay = 100 * time.Millisecond
|
|
require.NoError(t, server.Start())
|
|
defer server.Stop()
|
|
|
|
// Configure server
|
|
config := &relayConfig{
|
|
Server: server.Address(),
|
|
Port: server.Port(),
|
|
STARTTLS: true,
|
|
LoginAuthType: false,
|
|
Username: "",
|
|
Password: "",
|
|
SkipVerify: true,
|
|
HeloHost: "",
|
|
}
|
|
|
|
// Create test envelope
|
|
envelope := &mail.Envelope{
|
|
MailFrom: mail.Address{User: "sender", Host: "test.com"},
|
|
RcptTo: []mail.Address{
|
|
{User: "recipient", Host: "example.com"},
|
|
},
|
|
Data: *bytes.NewBufferString("Subject: Timeout Test\r\n\r\nThis tests server delays."),
|
|
RemoteIP: "127.0.0.1",
|
|
}
|
|
|
|
// Allow IP
|
|
AllowedSendersFilter = ipfilter.New(ipfilter.Options{
|
|
BlockByDefault: false,
|
|
})
|
|
|
|
// Send email - should still succeed despite delay
|
|
err := sendMail(envelope, config)
|
|
assert.NoError(t, err)
|
|
|
|
// Verify email was eventually sent
|
|
conn := server.GetLastConnection()
|
|
require.NotNil(t, conn)
|
|
assert.Equal(t, "sender@test.com", conn.From)
|
|
}
|