1
0
mirror of https://github.com/axllent/mailpit.git synced 2025-08-13 20:04:49 +02:00

Chore: Refactor error handling and resource management across multiple files (golangci-lint)

- Updated error handling to use the error return value for resource closures in tests and functions, ensuring proper error reporting.
- Replaced direct calls to `Close()` with deferred functions that handle errors gracefully.
- Improved readability by using `strings.ReplaceAll` instead of `strings.Replace` for string manipulation.
- Enhanced network connection handling by adding default cases for unsupported network types.
- Updated HTTP response handling to use the appropriate status codes and error messages.
- Removed unused variables and commented-out code to clean up the codebase.
This commit is contained in:
Ralph Slooten
2025-06-22 10:32:03 +12:00
parent 429d2e2b3a
commit f99d9ecf69
35 changed files with 250 additions and 232 deletions

View File

@@ -55,7 +55,7 @@ The --recent flag will only consider files with a modification date within the l
logger.Log().Errorf("%s: %s", path, err.Error())
return nil
}
defer f.Close() // #nosec
defer func() { _ = f.Close() }()
body, err := io.ReadAll(f)
if err != nil {

View File

@@ -13,7 +13,7 @@ import (
// IsFile returns whether a file exists and is readable
func isFile(path string) bool {
f, err := os.Open(filepath.Clean(path))
defer f.Close()
defer func() { _ = f.Close() }()
return err == nil
}

View File

@@ -39,14 +39,14 @@ func Sync(d string) error {
if URL != "" {
if !linkRe.MatchString(URL) {
return errors.New("Invalid URL")
return errors.New("invalid URL")
}
base = strings.TrimRight(URL, "/") + "/"
}
if base == "" && config.Database == "" {
return errors.New("No database or API URL specified")
return errors.New("no database or API URL specified")
}
if !tools.IsDir(outDir) {
@@ -109,7 +109,7 @@ func loadIDs() error {
}
if len(summary) == 0 {
return errors.New("No messages found")
return errors.New("no messages found")
}
return nil

View File

@@ -193,10 +193,10 @@ func downloadToBytes(url string) ([]byte, error) {
if err != nil {
return nil, err
}
defer resp.Body.Close()
defer func() { _ = resp.Body.Close() }()
if resp.StatusCode != 200 {
err := fmt.Errorf("Error downloading %s", url)
err := fmt.Errorf("error downloading %s", url)
return nil, err
}

View File

@@ -152,13 +152,14 @@ func (c CanIEmail) getTest(k string) (Warning, error) {
s.Platform = platform
s.Version = version
if support == "y" {
switch support {
case "y":
y++
s.Support = "yes"
} else if support == "n" {
case "n":
n++
s.Support = "no"
} else {
default:
p++
s.Support = "partial"

View File

@@ -18,7 +18,7 @@ func authUser(username, password string) bool {
// Send a response with debug logging
func sendResponse(c net.Conn, m string) {
fmt.Fprintf(c, "%s\r\n", m)
_, _ = fmt.Fprintf(c, "%s\r\n", m)
logger.Log().Debugf("[pop3] response: %s", m)
if strings.HasPrefix(m, "-ERR ") {
@@ -29,7 +29,7 @@ func sendResponse(c net.Conn, m string) {
// Send a response without debug logging (for data)
func sendData(c net.Conn, m string) {
fmt.Fprintf(c, "%s\r\n", m)
_, _ = fmt.Fprintf(c, "%s\r\n", m)
}
// Get the latest 100 messages

View File

@@ -29,22 +29,21 @@ func TestPOP3(t *testing.T) {
// connect with bad password
t.Log("Testing invalid login")
c, err := connectBadAuth()
if err == nil {
if _, err := connectBadAuth(); err == nil {
t.Error("invalid login gained access")
return
}
t.Log("Testing valid login")
c, err = connectAuth()
c, err := connectAuth()
if err != nil {
t.Errorf(err.Error())
t.Error(err.Error())
return
}
count, size, err := c.Stat()
if err != nil {
t.Errorf(err.Error())
t.Error(err.Error())
return
}
@@ -53,7 +52,7 @@ func TestPOP3(t *testing.T) {
// quit else we get old data
if err := c.Quit(); err != nil {
t.Errorf(err.Error())
t.Error(err.Error())
return
}
@@ -63,13 +62,13 @@ func TestPOP3(t *testing.T) {
c, err = connectAuth()
if err != nil {
t.Errorf(err.Error())
t.Error(err.Error())
return
}
count, _, err = c.Stat()
if err != nil {
t.Errorf(err.Error())
t.Error(err.Error())
return
}
@@ -80,7 +79,7 @@ func TestPOP3(t *testing.T) {
for i := 1; i <= 20; i++ {
_, err := c.Retr(i)
if err != nil {
t.Errorf(err.Error())
t.Error(err.Error())
return
}
}
@@ -89,14 +88,14 @@ func TestPOP3(t *testing.T) {
for i := 1; i <= 25; i++ {
if err := c.Dele(i); err != nil {
t.Errorf(err.Error())
t.Error(err.Error())
return
}
}
// messages get deleted after a QUIT
if err := c.Quit(); err != nil {
t.Errorf(err.Error())
t.Error(err.Error())
return
}
@@ -105,7 +104,7 @@ func TestPOP3(t *testing.T) {
c, err = connectAuth()
if err != nil {
t.Errorf(err.Error())
t.Error(err.Error())
return
}
@@ -113,7 +112,7 @@ func TestPOP3(t *testing.T) {
count, _, err = c.Stat()
if err != nil {
t.Errorf(err.Error())
t.Error(err.Error())
return
}
@@ -121,13 +120,13 @@ func TestPOP3(t *testing.T) {
// messages get deleted after a QUIT
if err := c.Quit(); err != nil {
t.Errorf(err.Error())
t.Error(err.Error())
return
}
c, err = connectAuth()
if err != nil {
t.Errorf(err.Error())
t.Error(err.Error())
return
}
@@ -135,7 +134,7 @@ func TestPOP3(t *testing.T) {
for i := 1; i <= 25; i++ {
if err := c.Dele(i); err != nil {
t.Errorf(err.Error())
t.Error(err.Error())
return
}
}
@@ -143,31 +142,31 @@ func TestPOP3(t *testing.T) {
t.Log("Undeleting messages")
if err := c.Rset(); err != nil {
t.Errorf(err.Error())
t.Error(err.Error())
return
}
if err := c.Quit(); err != nil {
t.Errorf(err.Error())
t.Error(err.Error())
return
}
c, err = connectAuth()
if err != nil {
t.Errorf(err.Error())
t.Error(err.Error())
return
}
count, _, err = c.Stat()
if err != nil {
t.Errorf(err.Error())
t.Error(err.Error())
return
}
assertEqual(t, count, 25, "incorrect message count")
if err := c.Quit(); err != nil {
t.Errorf(err.Error())
t.Error(err.Error())
return
}
}
@@ -190,7 +189,7 @@ func TestAuthentication(t *testing.T) {
// non-authenticated connection
c, err := connect()
if err != nil {
t.Errorf(err.Error())
t.Error(err.Error())
return
}
@@ -207,7 +206,7 @@ func TestAuthentication(t *testing.T) {
}
if err := c.Quit(); err != nil {
t.Errorf(err.Error())
t.Error(err.Error())
return
}
@@ -216,7 +215,7 @@ func TestAuthentication(t *testing.T) {
// authenticated connection
c, err = connectAuth()
if err != nil {
t.Errorf(err.Error())
t.Error(err.Error())
return
}
@@ -233,13 +232,15 @@ func TestAuthentication(t *testing.T) {
}
if err := c.Quit(); err != nil {
t.Errorf(err.Error())
t.Error(err.Error())
return
}
}
func setup() {
auth.SetPOP3Auth("username:password")
if err := auth.SetPOP3Auth("username:password"); err != nil {
panic(err)
}
logger.NoLogging = true
config.MaxMessages = 0
config.Database = os.Getenv("MP_DATABASE")

View File

@@ -271,7 +271,7 @@ func handleTransactionCommand(conn net.Conn, cmd string, args []string, messages
// begins with the termination octet, the line is "byte-stuffed" by
// pre-pending the termination octet to that line of the response.
// @see: https://www.ietf.org/rfc/rfc1939.txt
sendData(conn, strings.Replace(string(raw), "\n.", "\n..", -1))
sendData(conn, strings.ReplaceAll(string(raw), "\n.", "\n.."))
sendResponse(conn, ".")
case "TOP":
arg, err := getSafeArg(args, 0)

View File

@@ -422,7 +422,7 @@ func (c *Conn) Noop() error {
// Message deletions (DELE command) are only executed by the server on a graceful
// quit and close.
func (c *Conn) Quit() error {
defer c.conn.Close()
defer func() { _ = c.conn.Close() }()
if _, err := c.Cmd("QUIT", false); err != nil {
return err

View File

@@ -179,10 +179,10 @@ func StartSeparateServer() {
func GetMode() string {
mode := strings.ToLower(strings.TrimSpace(config.PrometheusListen))
switch {
case mode == "false", mode == "":
switch mode {
case "false", "":
return "disabled"
case mode == "true":
case "true":
return "integrated"
default:
return "separate"

View File

@@ -37,7 +37,7 @@ func createForwardingSMTPClient(config config.SMTPForwardConfigStruct, addr stri
client, err := smtp.NewClient(conn, tlsConf.ServerName)
if err != nil {
conn.Close()
_ = conn.Close()
return nil, fmt.Errorf("SMTP client error: %v", err)
}
@@ -55,7 +55,7 @@ func createForwardingSMTPClient(config config.SMTPForwardConfigStruct, addr stri
tlsConf.InsecureSkipVerify = config.AllowInsecure
if err = client.StartTLS(tlsConf); err != nil {
client.Close()
_ = client.Close()
return nil, fmt.Errorf("error creating StartTLS config: %v", err)
}
}
@@ -72,7 +72,7 @@ func forward(from string, msg []byte) error {
if err != nil {
return err
}
defer c.Close()
defer func() { _ = c.Close() }()
auth := forwardAuthFromConfig()

View File

@@ -71,7 +71,7 @@ func createRelaySMTPClient(config config.SMTPRelayConfigStruct, addr string) (*s
client, err := smtp.NewClient(conn, tlsConf.ServerName)
if err != nil {
conn.Close()
_ = conn.Close()
return nil, fmt.Errorf("SMTP client error: %v", err)
}
@@ -89,7 +89,7 @@ func createRelaySMTPClient(config config.SMTPRelayConfigStruct, addr string) (*s
tlsConf.InsecureSkipVerify = config.AllowInsecure
if err = client.StartTLS(tlsConf); err != nil {
client.Close()
_ = client.Close()
return nil, fmt.Errorf("error creating StartTLS config: %v", err)
}
}
@@ -106,7 +106,7 @@ func Relay(from string, to []string, msg []byte) error {
if err != nil {
return err
}
defer c.Close()
defer func() { _ = c.Close() }()
auth := relayAuthFromConfig()
@@ -193,7 +193,7 @@ func (a *loginAuth) Next(fromServer []byte, more bool) ([]byte, error) {
case "Password:":
return []byte(a.password), nil
default:
return nil, errors.New("Unknown fromServer")
return nil, errors.New("unknown fromServer")
}
}

View File

@@ -217,7 +217,7 @@ func (srv *Server) Serve(ln net.Listener) error {
return ErrServerClosed
}
defer ln.Close()
defer func() { _ = ln.Close() }()
for {
// if we are shutting down, don't accept new connections
@@ -229,7 +229,7 @@ func (srv *Server) Serve(ln net.Listener) error {
conn, err := ln.Accept()
if err != nil {
if netErr, ok := err.(net.Error); ok && netErr.Temporary() {
if netErr, ok := err.(net.Error); ok && netErr.Timeout() {
continue
}
return err
@@ -356,7 +356,9 @@ func (srv *Server) Shutdown(ctx context.Context) error {
// Function called to handle connection requests.
func (s *session) serve() {
defer atomic.AddInt32(&s.srv.openSessions, -1)
defer s.conn.Close()
// pass the connection into the defer function to ensure it is closed,
// otherwise results in a 5s timeout for each connection
defer func(c net.Conn) { _ = c.Close() }(s.conn)
var from string
var gotFrom bool
@@ -517,9 +519,9 @@ loop:
// On other errors, allow the client to try again.
data, err := s.readData()
if err != nil {
switch err.(type) {
switch err := err.(type) {
case net.Error:
if err.(net.Error).Timeout() {
if err.Timeout() {
s.writef("421 4.4.2 %s %s ESMTP Service closing transmission channel after timeout exceeded", s.srv.Hostname, s.srv.AppName)
}
break loop
@@ -749,7 +751,7 @@ func (s *session) writef(format string, args ...interface{}) {
}
line := fmt.Sprintf(format, args...)
fmt.Fprintf(s.bw, "%s\r\n", line)
_, _ = fmt.Fprintf(s.bw, "%s\r\n", line)
_ = s.bw.Flush()
if Debug {

View File

@@ -12,7 +12,6 @@ import (
"fmt"
"io"
"net"
"os"
"reflect"
"regexp"
"strings"
@@ -40,7 +39,7 @@ func newConn(t *testing.T, server *Server) net.Conn {
// Send a command and verify the 3 digit code from the response.
func cmdCode(t *testing.T, conn net.Conn, cmd string, code string) string {
fmt.Fprintf(conn, "%s\r\n", cmd)
_, _ = fmt.Fprintf(conn, "%s\r\n", cmd)
resp, err := bufio.NewReader(conn).ReadString('\n')
if err != nil {
t.Fatalf("Failed to read response from test server: %v", err)
@@ -72,7 +71,9 @@ func TestSimpleCommands(t *testing.T) {
conn := newConn(t, &Server{})
cmdCode(t, conn, tt.cmd, tt.code)
cmdCode(t, conn, "QUIT", "221")
conn.Close()
if err := conn.Close(); err != nil {
t.Errorf("Failed to close connection after command %s: %v", tt.cmd, err)
}
}
}
@@ -90,7 +91,7 @@ func TestCmdHELO(t *testing.T) {
cmdCode(t, conn, "DATA", "503")
cmdCode(t, conn, "QUIT", "221")
conn.Close()
_ = conn.Close()
}
func TestCmdEHLO(t *testing.T) {
@@ -107,7 +108,7 @@ func TestCmdEHLO(t *testing.T) {
cmdCode(t, conn, "DATA", "503")
cmdCode(t, conn, "QUIT", "221")
conn.Close()
_ = conn.Close()
}
func TestCmdRSET(t *testing.T) {
@@ -121,7 +122,7 @@ func TestCmdRSET(t *testing.T) {
cmdCode(t, conn, "DATA", "503")
cmdCode(t, conn, "QUIT", "221")
conn.Close()
_ = conn.Close()
}
func TestCmdMAIL(t *testing.T) {
@@ -162,7 +163,7 @@ func TestCmdMAIL(t *testing.T) {
// TODO: MAIL with invalid AUTH parameter must return 501 syntax error
cmdCode(t, conn, "QUIT", "221")
conn.Close()
_ = conn.Close()
}
func TestCmdMAILMaxSize(t *testing.T) {
@@ -192,7 +193,7 @@ func TestCmdMAILMaxSize(t *testing.T) {
// Clients should send either RSET or QUIT after receiving 552 (RFC 1870 section 6.2).
cmdCode(t, conn, "QUIT", "221")
conn.Close()
_ = conn.Close()
}
func TestCmdRCPT(t *testing.T) {
@@ -239,7 +240,7 @@ func TestCmdRCPT(t *testing.T) {
cmdCode(t, conn, "RCPT TO: <recipient@example.com>", "501")
cmdCode(t, conn, "QUIT", "221")
conn.Close()
_ = conn.Close()
}
func TestCmdMaxRecipients(t *testing.T) {
@@ -256,7 +257,7 @@ func TestCmdMaxRecipients(t *testing.T) {
cmdCode(t, conn, "RCPT TO: <recipient5@example.com>", "452")
cmdCode(t, conn, "QUIT", "221")
conn.Close()
_ = conn.Close()
}
func TestCmdDATA(t *testing.T) {
@@ -286,7 +287,7 @@ func TestCmdDATA(t *testing.T) {
cmdCode(t, conn, "Test message.\r\n.", "250")
cmdCode(t, conn, "QUIT", "221")
conn.Close()
_ = conn.Close()
}
func TestCmdDATAWithMaxSize(t *testing.T) {
@@ -323,7 +324,7 @@ func TestCmdDATAWithMaxSize(t *testing.T) {
// Clients should send either RSET or QUIT after receiving 552 (RFC 1870 section 6.2).
cmdCode(t, conn, "QUIT", "221")
conn.Close()
_ = conn.Close()
}
type mockHandler struct {
@@ -347,7 +348,7 @@ func TestCmdDATAWithHandler(t *testing.T) {
cmdCode(t, conn, "DATA", "354")
cmdCode(t, conn, "Test message.\r\n.", "250")
cmdCode(t, conn, "QUIT", "221")
conn.Close()
_ = conn.Close()
if m.handlerCalled != 1 {
t.Errorf("MailHandler called %d times, want one call", m.handlerCalled)
@@ -364,7 +365,7 @@ func TestCmdDATAWithHandlerError(t *testing.T) {
cmdCode(t, conn, "DATA", "354")
cmdCode(t, conn, "Test message.\r\n.", "451")
cmdCode(t, conn, "QUIT", "221")
conn.Close()
_ = conn.Close()
if m.handlerCalled != 1 {
t.Errorf("MailHandler called %d times, want one call", m.handlerCalled)
@@ -382,7 +383,7 @@ func TestCmdSTARTTLS(t *testing.T) {
cmdCode(t, conn, "STARTTLS FOO", "501")
cmdCode(t, conn, "QUIT", "221")
conn.Close()
_ = conn.Close()
}
func TestCmdSTARTTLSFailure(t *testing.T) {
@@ -411,7 +412,7 @@ func TestCmdSTARTTLSFailure(t *testing.T) {
}
cmdCode(t, conn, "QUIT", "221")
tlsConn.Close()
_ = tlsConn.Close()
}
// Utility function to make a valid TLS certificate for use by the server.
@@ -497,7 +498,7 @@ func TestCmdSTARTTLSSuccess(t *testing.T) {
cmdCode(t, tlsConn, "STARTTLS", "503")
cmdCode(t, tlsConn, "QUIT", "221")
tlsConn.Close()
_ = tlsConn.Close()
}
func TestCmdSTARTTLSRequired(t *testing.T) {
@@ -548,7 +549,7 @@ func TestCmdSTARTTLSRequired(t *testing.T) {
}
cmdCode(t, tlsConn, "QUIT", "221")
tlsConn.Close()
_ = tlsConn.Close()
}
func TestMakeHeaders(t *testing.T) {
@@ -798,8 +799,8 @@ func TestMakeEHLOResponse(t *testing.T) {
t.Errorf("AUTH does not appear in the extension list when an AuthHandler is specified")
}
reLogin := regexp.MustCompile("\\bLOGIN\\b")
rePlain := regexp.MustCompile("\\bPLAIN\\b")
reLogin := regexp.MustCompile(`\bLOGIN\b`)
rePlain := regexp.MustCompile(`\bPLAIN\b`)
// RFC 4954 specifies that, without TLS in use, plaintext authentication mechanisms must not be advertised.
s.tls = false
@@ -822,86 +823,86 @@ func TestMakeEHLOResponse(t *testing.T) {
}
}
func createTmpFile(content string) (file *os.File, err error) {
file, err = os.CreateTemp("", "")
if err != nil {
return
}
_, err = file.Write([]byte(content))
if err != nil {
return
}
err = file.Close()
return
}
// func createTmpFile(content string) (file *os.File, err error) {
// file, err = os.CreateTemp("", "")
// if err != nil {
// return
// }
// _, err = file.Write([]byte(content))
// if err != nil {
// return
// }
// err = file.Close()
// return
// }
func createTLSFiles() (
certFile *os.File,
keyFile *os.File,
passphrase string,
err error,
) {
const certPEM = `-----BEGIN CERTIFICATE-----
MIIDRzCCAi+gAwIBAgIJAKtg4oViVwv4MA0GCSqGSIb3DQEBCwUAMBQxEjAQBgNV
BAMMCWxvY2FsaG9zdDAgFw0xODA0MjAxMzMxNTBaGA8yMDg2MDUwODEzMzE1MFow
FDESMBAGA1UEAwwJbG9jYWxob3N0MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB
CgKCAQEA8h7vl0gUquis5jRtcnETyD+8WITZO0s53aIzp0Y+9HXiHW6FGJjbOZjM
IvozNVni+83QWKumRTgeSzIIW2j4V8iFMSNrvWmhmCKloesXS1aY6H979e01Ve8J
WAJFRe6vZJd6gC6Z/P+ELU3ie4Vtr1GYfkV7nZ6VFp5/V/5nxGFag5TUlpP5hcoS
9r2kvXofosVwe3x3udT8SEbv5eBD4bKeVyJs/RLbxSuiU1358Y1cDdVuHjcvfm3c
ajhheQ4vX9WXsk7LGGhnf1SrrPN/y+IDTXfvoHn+nJh4vMAB4yzQdE1V1N1AB8RA
0yBVJ6dwxRrSg4BFrNWhj3gfsvrA7wIDAQABo4GZMIGWMB0GA1UdDgQWBBQ4/ncp
befFuKH1hoYkPqLwuRrPRjAfBgNVHSMEGDAWgBQ4/ncpbefFuKH1hoYkPqLwuRrP
RjAJBgNVHRMEAjAAMBEGCWCGSAGG+EIBAQQEAwIGQDALBgNVHQ8EBAMCBaAwEwYD
VR0lBAwwCgYIKwYBBQUHAwEwFAYDVR0RBA0wC4IJbG9jYWxob3N0MA0GCSqGSIb3
DQEBCwUAA4IBAQBJBetEXiEIzKAEpXGX87j6aUON51Fdf6BiLMCghuGKyhnaOG32
4KJhtvVoS3ZUKPylh9c2VdItYlhWp76zd7YKk+3xUOixWeTMQHIvCvRGTyFibOPT
mApwp2pEnJCe4vjUrBaRhiyI+xnB70cWVF2qeernlLUeJA1mfYyQLz+v06ebDWOL
c/hPVQFB94lEdiyjGO7RZfIe8KwcK48g7iv0LQU4+c9MoWM2ZsVM1AL2tHzokSeA
u64gDTW4K0Tzx1ab7KmOFXYUjbz/xWuReMt33EwDXAErKCjbVt2T55Qx8UoKzSh1
tY0KDHdnYOzgsm2HIj2xcJqbeylYQvckNnoC
-----END CERTIFICATE-----`
// func createTLSFiles() (
// certFile *os.File,
// keyFile *os.File,
// passphrase string,
// err error,
// ) {
// const certPEM = `-----BEGIN CERTIFICATE-----
// MIIDRzCCAi+gAwIBAgIJAKtg4oViVwv4MA0GCSqGSIb3DQEBCwUAMBQxEjAQBgNV
// BAMMCWxvY2FsaG9zdDAgFw0xODA0MjAxMzMxNTBaGA8yMDg2MDUwODEzMzE1MFow
// FDESMBAGA1UEAwwJbG9jYWxob3N0MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB
// CgKCAQEA8h7vl0gUquis5jRtcnETyD+8WITZO0s53aIzp0Y+9HXiHW6FGJjbOZjM
// IvozNVni+83QWKumRTgeSzIIW2j4V8iFMSNrvWmhmCKloesXS1aY6H979e01Ve8J
// WAJFRe6vZJd6gC6Z/P+ELU3ie4Vtr1GYfkV7nZ6VFp5/V/5nxGFag5TUlpP5hcoS
// 9r2kvXofosVwe3x3udT8SEbv5eBD4bKeVyJs/RLbxSuiU1358Y1cDdVuHjcvfm3c
// ajhheQ4vX9WXsk7LGGhnf1SrrPN/y+IDTXfvoHn+nJh4vMAB4yzQdE1V1N1AB8RA
// 0yBVJ6dwxRrSg4BFrNWhj3gfsvrA7wIDAQABo4GZMIGWMB0GA1UdDgQWBBQ4/ncp
// befFuKH1hoYkPqLwuRrPRjAfBgNVHSMEGDAWgBQ4/ncpbefFuKH1hoYkPqLwuRrP
// RjAJBgNVHRMEAjAAMBEGCWCGSAGG+EIBAQQEAwIGQDALBgNVHQ8EBAMCBaAwEwYD
// VR0lBAwwCgYIKwYBBQUHAwEwFAYDVR0RBA0wC4IJbG9jYWxob3N0MA0GCSqGSIb3
// DQEBCwUAA4IBAQBJBetEXiEIzKAEpXGX87j6aUON51Fdf6BiLMCghuGKyhnaOG32
// 4KJhtvVoS3ZUKPylh9c2VdItYlhWp76zd7YKk+3xUOixWeTMQHIvCvRGTyFibOPT
// mApwp2pEnJCe4vjUrBaRhiyI+xnB70cWVF2qeernlLUeJA1mfYyQLz+v06ebDWOL
// c/hPVQFB94lEdiyjGO7RZfIe8KwcK48g7iv0LQU4+c9MoWM2ZsVM1AL2tHzokSeA
// u64gDTW4K0Tzx1ab7KmOFXYUjbz/xWuReMt33EwDXAErKCjbVt2T55Qx8UoKzSh1
// tY0KDHdnYOzgsm2HIj2xcJqbeylYQvckNnoC
// -----END CERTIFICATE-----`
const keyPEM = `-----BEGIN RSA PRIVATE KEY-----
Proc-Type: 4,ENCRYPTED
DEK-Info: AES-256-CBC,C16BF8745B2CDB53AC2B1D7609893AA0
// const keyPEM = `-----BEGIN RSA PRIVATE KEY-----
// Proc-Type: 4,ENCRYPTED
// DEK-Info: AES-256-CBC,C16BF8745B2CDB53AC2B1D7609893AA0
O13z7Yq7butaJmMfg9wRis9YnIDPsp4coYI6Ud+JGcP7iXoy95QMhovKWx25o1ol
tvUTsrsG27fHGf9qG02KizApIVtO9c1e0swCWzFrKRQX0JDiZDmilb9xosBNNst1
BOzOTRZEwFGSOCKZRBfSXyqC93TvLJ3DO9IUnKIeGt7upipvg29b/Dur/fyCy2WV
bLHXwUTDBm7j49yfoEyGkDjoB2QO9wgcgbacbnQJQ25fTFUwZpZJEJv6o1tRhoYM
ZMOhC9x1URmdHKN1+z2y5BrB6oNpParfeAMEvs/9FE6jJwYUR28Ql6Mhphfvr9W2
5Gxd3J65Ao9Vi2I5j5X6aBuNjyhXN3ScLjPG4lVZm9RU/uTPEt81pig/d5nSAjvF
Nfc08NuG3cnMyJSE/xScJ4D+GtX8U969wO4oKPCR4E/NFyXPR730ppupDFG6hzPD
PDmiszDtU438JAZ8AuFa1LkbyFnEW6KVD4h7VRr8YDjirCqnkgjNSI6dFY0NQ8H7
SyexB0lrceX6HZc+oNdAtkX3tYdzY3ExzUM5lSF1dkldnRbApLbqc4uuNIVXhXFM
dJnoPdKAzM6i+2EeVUxWNdafKDxnjVSHIHzHfIFJLQ4GS5rnz9keRFdyDjQL07tT
Lu9pPOmsadDXp7oSa81RgoCUfNZeR4jKpCk2BOft0L6ZSqwYFLcQHLIfJaGfn902
TUOTxHt0KzEUYeYSrXC2a6cyvXAd1YI7lOgy60qG89VHyCc2v5Bs4c4FNUDC/+Dj
4ZwogaAbSNkLaE0q3sYQRPdxSqLftyX0KitAgE7oGtdzBfe1cdBoozw3U67NEMMT
6qvk5j7RepPRSrapHtK5pMMdg5XpKFWcOXZ26VHVrDCj4JKdjVb4iyiQi94VveV0
w9+KcOtyrM7/jbQlCWnXpsIkP8VA/RIgh7CBn/h4oF1sO8ywP25OGQ7VWAVq1R9D
8bl8GzIdR9PZpFyOxuIac4rPa8tkDeoXKs4cxoao7H/OZO9o9aTB7CJMTL9yv0Kb
ntWuYxQchE6syoGsOgdGyZhaw4JeFkasDUP5beyNY+278NkzgGTOIMMTXIX46woP
ehzHKGHXVGf7ZiSFF+zAHMXZRSwNVMkOYwlIoRg1IbvIRbAXqAR6xXQTCVzNG0SU
cskojycBca1Cz3hDVIKYZd9beDhprVdr2a4K2nft2g2xRNjKPopsaqXx+VPibFUx
X7542eQ3eAlhkWUuXvt0q5a9WJdjJp9ODA0/d0akF6JQlEHIAyLfoUKB1HYwgUGG
6uRm651FDAab9U4cVC5PY1hfv/QwzpkNDkzgJAZ5SMOfZhq7IdBcqGd3lzPmq2FP
Vy1LVZIl3eM+9uJx5TLsBHH6NhMwtNhFCNa/5ksodQYlTvR8IrrgWlYg4EL69vjS
yt6HhhEN3lFCWvrQXQMp93UklbTlpVt6qcDXiC7HYbs3+EINargRd5Z+xL5i5vkN
f9k7s0xqhloWNPZcyOXMrox8L81WOY+sP4mVlGcfDRLdEJ8X2ofJpOAcwYCnjsKd
uEGsi+l2fTj/F+eZLE6sYoMprgJrbfeqtRWFguUgTn7s5hfU0tZ46al5d0vz8fWK
-----END RSA PRIVATE KEY-----`
// O13z7Yq7butaJmMfg9wRis9YnIDPsp4coYI6Ud+JGcP7iXoy95QMhovKWx25o1ol
// tvUTsrsG27fHGf9qG02KizApIVtO9c1e0swCWzFrKRQX0JDiZDmilb9xosBNNst1
// BOzOTRZEwFGSOCKZRBfSXyqC93TvLJ3DO9IUnKIeGt7upipvg29b/Dur/fyCy2WV
// bLHXwUTDBm7j49yfoEyGkDjoB2QO9wgcgbacbnQJQ25fTFUwZpZJEJv6o1tRhoYM
// ZMOhC9x1URmdHKN1+z2y5BrB6oNpParfeAMEvs/9FE6jJwYUR28Ql6Mhphfvr9W2
// 5Gxd3J65Ao9Vi2I5j5X6aBuNjyhXN3ScLjPG4lVZm9RU/uTPEt81pig/d5nSAjvF
// Nfc08NuG3cnMyJSE/xScJ4D+GtX8U969wO4oKPCR4E/NFyXPR730ppupDFG6hzPD
// PDmiszDtU438JAZ8AuFa1LkbyFnEW6KVD4h7VRr8YDjirCqnkgjNSI6dFY0NQ8H7
// SyexB0lrceX6HZc+oNdAtkX3tYdzY3ExzUM5lSF1dkldnRbApLbqc4uuNIVXhXFM
// dJnoPdKAzM6i+2EeVUxWNdafKDxnjVSHIHzHfIFJLQ4GS5rnz9keRFdyDjQL07tT
// Lu9pPOmsadDXp7oSa81RgoCUfNZeR4jKpCk2BOft0L6ZSqwYFLcQHLIfJaGfn902
// TUOTxHt0KzEUYeYSrXC2a6cyvXAd1YI7lOgy60qG89VHyCc2v5Bs4c4FNUDC/+Dj
// 4ZwogaAbSNkLaE0q3sYQRPdxSqLftyX0KitAgE7oGtdzBfe1cdBoozw3U67NEMMT
// 6qvk5j7RepPRSrapHtK5pMMdg5XpKFWcOXZ26VHVrDCj4JKdjVb4iyiQi94VveV0
// w9+KcOtyrM7/jbQlCWnXpsIkP8VA/RIgh7CBn/h4oF1sO8ywP25OGQ7VWAVq1R9D
// 8bl8GzIdR9PZpFyOxuIac4rPa8tkDeoXKs4cxoao7H/OZO9o9aTB7CJMTL9yv0Kb
// ntWuYxQchE6syoGsOgdGyZhaw4JeFkasDUP5beyNY+278NkzgGTOIMMTXIX46woP
// ehzHKGHXVGf7ZiSFF+zAHMXZRSwNVMkOYwlIoRg1IbvIRbAXqAR6xXQTCVzNG0SU
// cskojycBca1Cz3hDVIKYZd9beDhprVdr2a4K2nft2g2xRNjKPopsaqXx+VPibFUx
// X7542eQ3eAlhkWUuXvt0q5a9WJdjJp9ODA0/d0akF6JQlEHIAyLfoUKB1HYwgUGG
// 6uRm651FDAab9U4cVC5PY1hfv/QwzpkNDkzgJAZ5SMOfZhq7IdBcqGd3lzPmq2FP
// Vy1LVZIl3eM+9uJx5TLsBHH6NhMwtNhFCNa/5ksodQYlTvR8IrrgWlYg4EL69vjS
// yt6HhhEN3lFCWvrQXQMp93UklbTlpVt6qcDXiC7HYbs3+EINargRd5Z+xL5i5vkN
// f9k7s0xqhloWNPZcyOXMrox8L81WOY+sP4mVlGcfDRLdEJ8X2ofJpOAcwYCnjsKd
// uEGsi+l2fTj/F+eZLE6sYoMprgJrbfeqtRWFguUgTn7s5hfU0tZ46al5d0vz8fWK
// -----END RSA PRIVATE KEY-----`
passphrase = "test"
// passphrase = "test"
certFile, err = createTmpFile(certPEM)
if err != nil {
return
}
keyFile, err = createTmpFile(keyPEM)
return
}
// certFile, err = createTmpFile(certPEM)
// if err != nil {
// return
// }
// keyFile, err = createTmpFile(keyPEM)
// return
// }
func TestAuthMechs(t *testing.T) {
s := session{}
@@ -966,7 +967,7 @@ func TestCmdAUTH(t *testing.T) {
cmdCode(t, conn, "AUTH", "502")
cmdCode(t, conn, "QUIT", "221")
conn.Close()
_ = conn.Close()
}
func TestCmdAUTHOptional(t *testing.T) {
@@ -1007,7 +1008,7 @@ func TestCmdAUTHOptional(t *testing.T) {
cmdCode(t, conn, "*", "501")
cmdCode(t, conn, "QUIT", "221")
conn.Close()
_ = conn.Close()
}
func TestCmdAUTHRequired(t *testing.T) {
@@ -1056,7 +1057,7 @@ func TestCmdAUTHRequired(t *testing.T) {
cmdCode(t, conn, "AUTH PLAIN", "504")
cmdCode(t, conn, "QUIT", "221")
conn.Close()
_ = conn.Close()
}
func TestCmdAUTHLOGIN(t *testing.T) {
@@ -1113,7 +1114,7 @@ func TestCmdAUTHLOGIN(t *testing.T) {
cmdCode(t, tlsConn, "AUTH CRAM-MD5", "503")
cmdCode(t, tlsConn, "QUIT", "221")
tlsConn.Close()
_ = tlsConn.Close()
}
func TestCmdAUTHLOGINFast(t *testing.T) {
@@ -1165,7 +1166,7 @@ func TestCmdAUTHLOGINFast(t *testing.T) {
cmdCode(t, tlsConn, "AUTH CRAM-MD5", "503")
cmdCode(t, tlsConn, "QUIT", "221")
tlsConn.Close()
_ = tlsConn.Close()
}
func TestCmdAUTHPLAIN(t *testing.T) {
@@ -1224,7 +1225,7 @@ func TestCmdAUTHPLAIN(t *testing.T) {
cmdCode(t, tlsConn, "AUTH CRAM-MD5", "503")
cmdCode(t, tlsConn, "QUIT", "221")
tlsConn.Close()
_ = tlsConn.Close()
}
func TestCmdAUTHPLAINEmpty(t *testing.T) {
@@ -1283,7 +1284,7 @@ func TestCmdAUTHPLAINEmpty(t *testing.T) {
cmdCode(t, tlsConn, "AUTH CRAM-MD5", "503")
cmdCode(t, tlsConn, "QUIT", "221")
tlsConn.Close()
_ = tlsConn.Close()
}
func TestCmdAUTHPLAINFast(t *testing.T) {
@@ -1335,7 +1336,7 @@ func TestCmdAUTHPLAINFast(t *testing.T) {
cmdCode(t, tlsConn, "AUTH CRAM-MD5", "503")
cmdCode(t, tlsConn, "QUIT", "221")
tlsConn.Close()
_ = tlsConn.Close()
}
func TestCmdAUTHPLAINFastAndEmpty(t *testing.T) {
@@ -1387,7 +1388,7 @@ func TestCmdAUTHPLAINFastAndEmpty(t *testing.T) {
cmdCode(t, tlsConn, "AUTH CRAM-MD5", "503")
cmdCode(t, tlsConn, "QUIT", "221")
tlsConn.Close()
_ = tlsConn.Close()
}
// makeCRAMMD5Response is a helper function to create the CRAM-MD5 hash.
@@ -1457,7 +1458,7 @@ func TestCmdAUTHCRAMMD5(t *testing.T) {
cmdCode(t, conn, "AUTH CRAM-MD5", "503")
cmdCode(t, conn, "QUIT", "221")
conn.Close()
_ = conn.Close()
}
func TestCmdAUTHCRAMMD5WithTLS(t *testing.T) {
@@ -1523,7 +1524,7 @@ func TestCmdAUTHCRAMMD5WithTLS(t *testing.T) {
cmdCode(t, tlsConn, "AUTH CRAM-MD5", "503")
cmdCode(t, tlsConn, "QUIT", "221")
tlsConn.Close()
_ = tlsConn.Close()
}
// Benchmark the mail handling without the network stack introducing latency.
@@ -1540,17 +1541,17 @@ func BenchmarkReceive(b *testing.B) {
// Benchmark a full mail transaction.
for i := 0; i < b.N; i++ {
fmt.Fprintf(clientConn, "%s\r\n", "HELO host.example.com")
_, _ = fmt.Fprintf(clientConn, "%s\r\n", "HELO host.example.com")
_, _ = reader.ReadString('\n')
fmt.Fprintf(clientConn, "%s\r\n", "MAIL FROM:<sender@example.com>")
_, _ = fmt.Fprintf(clientConn, "%s\r\n", "MAIL FROM:<sender@example.com>")
_, _ = reader.ReadString('\n')
fmt.Fprintf(clientConn, "%s\r\n", "RCPT TO:<recipient@example.com>")
_, _ = fmt.Fprintf(clientConn, "%s\r\n", "RCPT TO:<recipient@example.com>")
_, _ = reader.ReadString('\n')
fmt.Fprintf(clientConn, "%s\r\n", "DATA")
_, _ = fmt.Fprintf(clientConn, "%s\r\n", "DATA")
_, _ = reader.ReadString('\n')
fmt.Fprintf(clientConn, "%s\r\n", "Test message.\r\n.")
_, _ = fmt.Fprintf(clientConn, "%s\r\n", "Test message.\r\n.")
_, _ = reader.ReadString('\n')
fmt.Fprintf(clientConn, "%s\r\n", "QUIT")
_, _ = fmt.Fprintf(clientConn, "%s\r\n", "QUIT")
_, _ = reader.ReadString('\n')
}
}
@@ -1589,11 +1590,11 @@ func TestCmdShutdown(t *testing.T) {
cmdCode(t, conn, "QUIT", "221")
// connection should now be closed
fmt.Fprintf(conn, "%s\r\n", "HELO host.example.com")
_, _ = fmt.Fprintf(conn, "%s\r\n", "HELO host.example.com")
_, err := bufio.NewReader(conn).ReadString('\n')
if err != io.EOF {
t.Errorf("Expected connection to be closed\n")
}
conn.Close()
_ = conn.Close()
}

View File

@@ -59,7 +59,7 @@ func Check(email []byte, timeout int) (Response, error) {
return r, err
}
defer resp.Body.Close()
defer func() { _ = resp.Body.Close() }()
err = json.NewDecoder(resp.Body).Decode(&r)

View File

@@ -70,21 +70,22 @@ type Result struct {
// dial connects to spamd through TCP or a Unix socket.
func (c *Client) dial() (connection, error) {
if c.net == "tcp" {
switch c.net {
case "tcp":
tcpAddr, err := net.ResolveTCPAddr("tcp", c.addr)
if err != nil {
return nil, err
}
return net.DialTCP("tcp", nil, tcpAddr)
} else if c.net == "unix" {
case "unix":
unixAddr, err := net.ResolveUnixAddr("unix", c.addr)
if err != nil {
return nil, err
}
return net.DialUnix("unix", nil, unixAddr)
default:
return nil, fmt.Errorf("unsupported network type: %s", c.net)
}
panic("Client.net must be either \"tcp\" or \"unix\"")
}
// Report checks if message is spam or not, and returns score plus report
@@ -103,7 +104,7 @@ func (c *Client) report(email []byte) ([]string, error) {
return nil, err
}
defer conn.Close()
defer func() { _ = conn.Close() }()
if err := conn.SetDeadline(time.Now().Add(time.Duration(c.timeout) * time.Second)); err != nil {
return nil, err
@@ -221,7 +222,7 @@ func (c *Client) Ping() error {
if err != nil {
return err
}
defer conn.Close()
defer func() { _ = conn.Close() }()
if err := conn.SetDeadline(time.Now().Add(time.Duration(c.timeout) * time.Second)); err != nil {
return err

View File

@@ -27,7 +27,6 @@ import (
var (
db *sql.DB
dbFile string
sqlDriver string
dbLastAction time.Time
@@ -139,7 +138,6 @@ func InitDB() error {
LoadTagFilters()
dbFile = p
dbLastAction = time.Now()
sigs := make(chan os.Signal, 1)

View File

@@ -86,7 +86,7 @@ func Store(body *[]byte, username *string) (string, error) {
}
// roll back if it fails
defer tx.Rollback()
defer func() { _ = tx.Rollback() }()
subject := env.GetHeader("Subject")
size := uint64(len(*body))
@@ -118,8 +118,6 @@ func Store(body *[]byte, username *string) (string, error) {
} else {
_, err = tx.Exec(fmt.Sprintf(`INSERT INTO %s (ID, Email, Compressed) VALUES(?, ?, 1)`, tenant("mailbox_data")), id, compressed) // #nosec
}
compressed = nil
} else {
// insert uncompressed raw message
_, err = tx.Exec(fmt.Sprintf(`INSERT INTO %s (ID, Email, Compressed) VALUES(?, ?, 0)`, tenant("mailbox_data")), id, string(*body)) // #nosec
@@ -639,7 +637,7 @@ func DeleteMessages(ids []string) error {
if err != nil {
return err
}
defer rows.Close()
defer func() { _ = rows.Close() }()
toDelete := []string{}
var totalSize uint64
@@ -738,7 +736,7 @@ func DeleteAllMessages() error {
}
// roll back if it fails
defer tx.Rollback()
defer func() { _ = tx.Rollback() }()
tables := []string{"mailbox", "mailbox_data", "tags", "message_tags"}

View File

@@ -114,7 +114,7 @@ func ReindexAll() {
}
// roll back if it fails
defer tx.Rollback()
defer func() { _ = tx.Rollback() }()
// insert mail summary data
for _, u := range updates {

View File

@@ -193,7 +193,7 @@ func DeleteSearch(search, timezone string) error {
}
// roll back if it fails
defer tx.Rollback()
defer func() { _ = tx.Rollback() }()
for _, ids := range chunks {
delIDs := make([]interface{}, len(ids))

View File

@@ -8,7 +8,7 @@ import (
// IsFile returns whether a file exists and is readable
func IsFile(path string) bool {
f, err := os.Open(filepath.Clean(path))
defer f.Close()
defer func() { _ = f.Close() }()
return err == nil
}

View File

@@ -27,7 +27,7 @@ func ListUnsubscribeParser(v string) ([]string, error) {
comments := reComments.FindAllStringSubmatch(v, -1)
for _, c := range comments {
// strip comments
v = strings.Replace(v, c[0], "", -1)
v = strings.ReplaceAll(v, c[0], "")
v = strings.TrimSpace(v)
}

View File

@@ -115,7 +115,7 @@ func extract(filePath string, directory string) error {
if err != nil {
return err
}
defer gzipReader.Close()
defer func() { _ = gzipReader.Close() }()
tarReader := tar.NewReader(gzipReader)

View File

@@ -19,7 +19,7 @@ func Unzip(src string, dest string) ([]string, error) {
if err != nil {
return filenames, err
}
defer r.Close()
defer func() { _ = r.Close() }()
for _, f := range r.File {

View File

@@ -5,6 +5,7 @@ import (
"crypto/rand"
"encoding/hex"
"encoding/json"
"errors"
"fmt"
"io"
"net/http"
@@ -70,7 +71,7 @@ func GithubLatest(repo, name string) (string, string, string, error) {
return "", "", "", err
}
defer resp.Body.Close()
defer func() { _ = resp.Body.Close() }()
body, err := io.ReadAll(resp.Body)
@@ -119,7 +120,7 @@ func GithubLatest(repo, name string) (string, string, string, error) {
if len(allReleases) == 0 {
// no releases with suitable assets found
return "", "", "", fmt.Errorf("No binary releases found")
return "", "", "", errors.New("no binary releases found")
}
var latestRelease = Release{}
@@ -149,11 +150,11 @@ func GithubUpdate(repo, appName, currentVersion string) (string, error) {
}
if ver == currentVersion {
return "", fmt.Errorf("No new release found")
return "", errors.New("no new release found")
}
if semver.Compare(ver, currentVersion) < 1 {
return "", fmt.Errorf("No newer releases found (latest %s)", ver)
return "", fmt.Errorf("no newer releases found (latest %s)", ver)
}
tmpDir := getTempDir()
@@ -212,7 +213,7 @@ func downloadToFile(url, fileName string) error {
if err != nil {
return err
}
defer resp.Body.Close()
defer func() { _ = resp.Body.Close() }()
// Create the file
out, err := os.Create(filepath.Clean(fileName))

View File

@@ -121,14 +121,14 @@ func Run() {
// handles `sendmail -bs`
// telnet directly to SMTP
if UseB && UseS {
var caller telnet.Caller = telnet.StandardCaller
if isSocket {
var caller = telnet.StandardCaller
switch isSocket {
case true:
if err := telnet.DialToAndCallUnix(socketAddr, caller); err != nil {
fmt.Println(err)
os.Exit(1)
}
} else {
default:
if err := telnet.DialToAndCall(SMTPAddr, caller); err != nil {
fmt.Println(err)
os.Exit(1)

View File

@@ -18,7 +18,7 @@ func fourOFour(w http.ResponseWriter) {
w.Header().Set("Content-Security-Policy", config.ContentSecurityPolicy)
w.WriteHeader(http.StatusNotFound)
w.Header().Set("Content-Type", "text/plain")
fmt.Fprint(w, "404 page not found")
_, _ = fmt.Fprint(w, "404 page not found")
}
// HTTPError returns a basic error message (400 response)
@@ -27,7 +27,7 @@ func httpError(w http.ResponseWriter, msg string) {
w.Header().Set("Content-Security-Policy", config.ContentSecurityPolicy)
w.WriteHeader(http.StatusBadRequest)
w.Header().Set("Content-Type", "text/plain")
fmt.Fprint(w, msg)
_, _ = fmt.Fprint(w, msg)
}
// httpJSONError returns a basic error message (400 response) in JSON format

View File

@@ -49,7 +49,7 @@ func GetMessage(w http.ResponseWriter, r *http.Request) {
id, err = storage.LatestID(r)
if err != nil {
w.WriteHeader(404)
fmt.Fprint(w, err.Error())
_, _ = fmt.Fprint(w, err.Error())
return
}
}
@@ -108,7 +108,7 @@ func GetHeaders(w http.ResponseWriter, r *http.Request) {
id, err = storage.LatestID(r)
if err != nil {
w.WriteHeader(404)
fmt.Fprint(w, err.Error())
_, _ = fmt.Fprint(w, err.Error())
return
}
}
@@ -179,7 +179,7 @@ func DownloadAttachment(w http.ResponseWriter, r *http.Request) {
id, err = storage.LatestID(r)
if err != nil {
w.WriteHeader(404)
fmt.Fprint(w, err.Error())
_, _ = fmt.Fprint(w, err.Error())
return
}
}
@@ -238,7 +238,7 @@ func DownloadRaw(w http.ResponseWriter, r *http.Request) {
id, err = storage.LatestID(r)
if err != nil {
w.WriteHeader(404)
fmt.Fprint(w, err.Error())
_, _ = fmt.Fprint(w, err.Error())
return
}
}

View File

@@ -210,7 +210,7 @@ func SpamAssassinCheck(w http.ResponseWriter, r *http.Request) {
id, err = storage.LatestID(r)
if err != nil {
w.WriteHeader(404)
fmt.Fprint(w, err.Error())
_, _ = fmt.Fprint(w, err.Error())
return
}
}

View File

@@ -67,7 +67,7 @@ func GetMessageHTML(w http.ResponseWriter, r *http.Request) {
id, err = storage.LatestID(r)
if err != nil {
w.WriteHeader(404)
fmt.Fprint(w, err.Error())
_, _ = fmt.Fprint(w, err.Error())
return
}
}
@@ -75,12 +75,12 @@ func GetMessageHTML(w http.ResponseWriter, r *http.Request) {
msg, err := storage.GetMessage(id)
if err != nil {
w.WriteHeader(404)
fmt.Fprint(w, "Message not found")
_, _ = fmt.Fprint(w, "Message not found")
return
}
if msg.HTML == "" {
w.WriteHeader(404)
fmt.Fprint(w, "This message does not contain a HTML part")
_, _ = fmt.Fprint(w, "This message does not contain a HTML part")
return
}
@@ -161,7 +161,7 @@ func GetMessageText(w http.ResponseWriter, r *http.Request) {
id, err = storage.LatestID(r)
if err != nil {
w.WriteHeader(404)
fmt.Fprint(w, err.Error())
_, _ = fmt.Fprint(w, err.Error())
return
}
}
@@ -169,7 +169,7 @@ func GetMessageText(w http.ResponseWriter, r *http.Request) {
msg, err := storage.GetMessage(id)
if err != nil {
w.WriteHeader(404)
fmt.Fprint(w, "Message not found")
_, _ = fmt.Fprint(w, "Message not found")
return
}

View File

@@ -39,5 +39,5 @@ func RedirectToLatestMessage(w http.ResponseWriter, r *http.Request) {
}
}
http.Redirect(w, r, uri, 302)
http.Redirect(w, r, uri, http.StatusFound)
}

View File

@@ -60,7 +60,8 @@ func ProxyHandler(w http.ResponseWriter, r *http.Request) {
return
}
defer resp.Body.Close()
defer func() { _ = resp.Body.Close() }()
body, err := io.ReadAll(resp.Body)
if err != nil {
logger.Log().Warnf("[proxy] %s", err.Error())
@@ -141,7 +142,7 @@ func absoluteURL(link, baseURL string) (string, error) {
// ensure link is HTTP(S)
if result.Scheme != "http" && result.Scheme != "https" {
return link, fmt.Errorf("Invalid URL: %s", result.String())
return link, fmt.Errorf("invalid URL: %s", result.String())
}
return result.String(), nil
@@ -153,5 +154,5 @@ func httpError(w http.ResponseWriter, msg string) {
w.Header().Set("Content-Security-Policy", config.ContentSecurityPolicy)
w.WriteHeader(http.StatusBadRequest)
w.Header().Set("Content-Type", "text/plain")
fmt.Fprint(w, msg)
_, _ = fmt.Fprint(w, msg)
}

View File

@@ -290,8 +290,9 @@ func middleWareFunc(fn http.HandlerFunc) http.HandlerFunc {
}
// Check basic authentication headers if configured.
// OPTIONS requests are skipped if CORS is enabled, since browsers omit credentials for preflight.
if !(AccessControlAllowOrigin != "" && r.Method == http.MethodOptions) && auth.UICredentials != nil {
// OPTIONS requests are skipped if CORS is enabled, since browsers omit credentials for preflight checks.
isCORSOptionsRequest := AccessControlAllowOrigin != "" && r.Method == http.MethodOptions
if !isCORSOptionsRequest && auth.UICredentials != nil {
user, pass, ok := r.BasicAuth()
if !ok {
@@ -312,7 +313,7 @@ func middleWareFunc(fn http.HandlerFunc) http.HandlerFunc {
w.Header().Set("Content-Encoding", "gzip")
gz := gzip.NewWriter(w)
defer gz.Close()
defer func() { _ = gz.Close() }()
gzr := gzipResponseWriter{Writer: gz, ResponseWriter: w}
fn(gzr, r)
}

View File

@@ -345,7 +345,9 @@ func TestSendAPIAuthMiddleware(t *testing.T) {
// Set up UI auth that would normally block requests
testHash, _ := bcrypt.GenerateFromPassword([]byte("testpass"), bcrypt.DefaultCost)
auth.SetUIAuth("testuser:" + string(testHash))
if err := auth.SetUIAuth("testuser:" + string(testHash)); err != nil {
t.Fatalf("Failed to set UI auth: %s", err.Error())
}
r := apiRoutes()
ts := httptest.NewServer(r)
@@ -374,11 +376,15 @@ func TestSendAPIAuthMiddleware(t *testing.T) {
// Set up UI auth
uiHash, _ := bcrypt.GenerateFromPassword([]byte("uipass"), bcrypt.DefaultCost)
auth.SetUIAuth("uiuser:" + string(uiHash))
if err := auth.SetUIAuth("uiuser:" + string(uiHash)); err != nil {
t.Fatalf("Failed to set UI auth: %s", err.Error())
}
// Set up dedicated Send API auth
sendHash, _ := bcrypt.GenerateFromPassword([]byte("sendpass"), bcrypt.DefaultCost)
auth.SetSendAPIAuth("senduser:" + string(sendHash))
if err := auth.SetSendAPIAuth("senduser:" + string(sendHash)); err != nil {
t.Fatalf("Failed to set Send API auth: %s", err.Error())
}
r := apiRoutes()
ts := httptest.NewServer(r)
@@ -421,7 +427,9 @@ func TestSendAPIAuthMiddleware(t *testing.T) {
// Set up only UI auth
uiHash, _ := bcrypt.GenerateFromPassword([]byte("uipass"), bcrypt.DefaultCost)
auth.SetUIAuth("uiuser:" + string(uiHash))
if err := auth.SetUIAuth("uiuser:" + string(uiHash)); err != nil {
t.Fatalf("Failed to set UI auth: %s", err.Error())
}
r := apiRoutes()
ts := httptest.NewServer(r)
@@ -455,9 +463,14 @@ func TestSendAPIAuthMiddleware(t *testing.T) {
// Set up UI auth and Send API auth
uiHash, _ := bcrypt.GenerateFromPassword([]byte("uipass"), bcrypt.DefaultCost)
auth.SetUIAuth("uiuser:" + string(uiHash))
if err := auth.SetUIAuth("uiuser:" + string(uiHash)); err != nil {
t.Fatalf("Failed to set UI auth: %s", err.Error())
}
sendHash, _ := bcrypt.GenerateFromPassword([]byte("sendpass"), bcrypt.DefaultCost)
auth.SetSendAPIAuth("senduser:" + string(sendHash))
if err := auth.SetSendAPIAuth("senduser:" + string(sendHash)); err != nil {
t.Fatalf("Failed to set Send API auth: %s", err.Error())
}
r := apiRoutes()
ts := httptest.NewServer(r)
@@ -604,7 +617,7 @@ func clientGet(url string) ([]byte, error) {
return nil, fmt.Errorf("%s returned status %d", url, resp.StatusCode)
}
defer resp.Body.Close()
defer func() { _ = resp.Body.Close() }()
data, err := io.ReadAll(resp.Body)
@@ -625,7 +638,7 @@ func clientDelete(url, body string) ([]byte, error) {
return nil, err
}
defer resp.Body.Close()
defer func() { _ = resp.Body.Close() }()
if resp.StatusCode != http.StatusOK {
return nil, fmt.Errorf("%s returned status %d", url, resp.StatusCode)
@@ -650,7 +663,7 @@ func clientPut(url, body string) ([]byte, error) {
return nil, err
}
defer resp.Body.Close()
defer func() { _ = resp.Body.Close() }()
if resp.StatusCode != http.StatusOK {
return nil, fmt.Errorf("%s returned status %d", url, resp.StatusCode)
@@ -675,7 +688,7 @@ func clientPost(url, body string) ([]byte, error) {
return nil, err
}
defer resp.Body.Close()
defer func() { _ = resp.Body.Close() }()
if resp.StatusCode != http.StatusOK {
return nil, fmt.Errorf("%s returned status %d", url, resp.StatusCode)
@@ -702,7 +715,7 @@ func clientPostWithAuth(url, body, username, password string) ([]byte, error) {
return nil, err
}
defer resp.Body.Close()
defer func() { _ = resp.Body.Close() }()
if resp.StatusCode != http.StatusOK {
return nil, fmt.Errorf("%s returned status %d", url, resp.StatusCode)
@@ -728,7 +741,7 @@ func clientGetWithAuth(url, username, password string) ([]byte, error) {
return nil, err
}
defer resp.Body.Close()
defer func() { _ = resp.Body.Close() }()
if resp.StatusCode != http.StatusOK {
return nil, fmt.Errorf("%s returned status %d", url, resp.StatusCode)

View File

@@ -22,7 +22,7 @@ var (
)
// Send will post the MessageSummary to a webhook (if configured)
func Send(msg interface{}) {
func Send(msg any) {
if config.WebhookURL == "" {
return
}
@@ -70,7 +70,7 @@ func Send(msg interface{}) {
return
}
defer resp.Body.Close()
_ = resp.Body.Close()
})
}()
}