chore(coderd/notifications): expand golden file testing for notifications (#15032)

This PR aims to close https://github.com/coder/coder/issues/14913.

It expands the golden files for the notifier to include the entire
payload serialised as JSON.
This commit is contained in:
Sas Swart
2024-10-14 14:34:32 +02:00
committed by GitHub
parent 9c8ecb82a3
commit 208ed1efd7
79 changed files with 2265 additions and 204 deletions

View File

@@ -0,0 +1,18 @@
[ req ]
distinguished_name = req_distinguished_name
x509_extensions = v3_ca
prompt = no
[ req_distinguished_name ]
C = ZA
ST = WC
L = Cape Town
O = Coder
OU = Team Coconut
CN = Coder CA
[ v3_ca ]
basicConstraints = critical,CA:TRUE
keyUsage = critical,keyCertSign,cRLSign
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid:always,issuer:always

View File

@@ -0,0 +1,25 @@
-----BEGIN CERTIFICATE-----
MIIESjCCAzKgAwIBAgIUceUne8C8ezg1leBzhm5M5QLjBc4wDQYJKoZIhvcNAQEL
BQAwaDELMAkGA1UEBhMCWkExCzAJBgNVBAgMAldDMRIwEAYDVQQHDAlDYXBlIFRv
d24xDjAMBgNVBAoMBUNvZGVyMRUwEwYDVQQLDAxUZWFtIENvY29udXQxETAPBgNV
BAMMCENvZGVyIENBMB4XDTI0MDcxNTEzMzYwOFoXDTM0MDcxMzEzMzYwOFowaDEL
MAkGA1UEBhMCWkExCzAJBgNVBAgMAldDMRIwEAYDVQQHDAlDYXBlIFRvd24xDjAM
BgNVBAoMBUNvZGVyMRUwEwYDVQQLDAxUZWFtIENvY29udXQxETAPBgNVBAMMCENv
ZGVyIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAijVhQfmImkQF
kDiBqCdSAaG7dO7slAjJH0jYizYCwVzCKP72Z7DJ2b/ohcGBw1YWZ8dOm88uCpsS
oWM5FvxIeaNeGpcFar+wEoR/o5p91DgwvpmkbNyu3uQaNRvIKoqGdTAu5GUNd+Ej
MxvwfofgRetziA56sa6ovQV11hPbKxp0YbSJXMRN64sGCqx+VNqpk2A57JCdCjcB
T1fc7LIqKc9uoqCaC0Hr2OaBCc8IxLwpwwOz5qCaOGmylXY3YE4lKNJkA1s/HXO/
GAZ6aO0GqkO00fxIQwW13BexuaiDJfcAhUmJ8CjFt9qgKfnkP26jU8gfMxOkRkn2
qG8sWy3z8wIDAQABo4HrMIHoMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQD
AgEGMB0GA1UdDgQWBBSk2BGdRQZDMvzOfLQkUmkwzjrOFzCBpQYDVR0jBIGdMIGa
gBSk2BGdRQZDMvzOfLQkUmkwzjrOF6FspGowaDELMAkGA1UEBhMCWkExCzAJBgNV
BAgMAldDMRIwEAYDVQQHDAlDYXBlIFRvd24xDjAMBgNVBAoMBUNvZGVyMRUwEwYD
VQQLDAxUZWFtIENvY29udXQxETAPBgNVBAMMCENvZGVyIENBghRx5Sd7wLx7ODWV
4HOGbkzlAuMFzjANBgkqhkiG9w0BAQsFAAOCAQEAFJtks88lruyIIbFpzQ8M932a
hNmkm3ZFM8qrjFWCEINmzeeQHV+rviu4Spd4Cltx+lf6+51V68jE730IGEzAu14o
U2dmhRxn+w17H6/Qmnxlbz4Da2HvVgL9C4IoEbCTTGEa+hDg3cH6Mah1rfC0zAXH
zxe/M2ahM+SOMDxmoUUf6M4tDVqu98FpELfsFe4MqTUbzQ32PyoP4ZOBpma1dl8Y
fMm0rJE9/g/9Tkj8WfA4AwedCWUA4e7MLZikmntcein310uSy1sEpA+HVji+Gt68
2+TJgIGOX1EHj44SqK5hVExQNzqqi1IIhR05imFaJ426DX82LtOA1bIg7HNCWA==
-----END CERTIFICATE-----

View File

@@ -0,0 +1,28 @@
-----BEGIN PRIVATE KEY-----
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCKNWFB+YiaRAWQ
OIGoJ1IBobt07uyUCMkfSNiLNgLBXMIo/vZnsMnZv+iFwYHDVhZnx06bzy4KmxKh
YzkW/Eh5o14alwVqv7AShH+jmn3UODC+maRs3K7e5Bo1G8gqioZ1MC7kZQ134SMz
G/B+h+BF63OIDnqxrqi9BXXWE9srGnRhtIlcxE3riwYKrH5U2qmTYDnskJ0KNwFP
V9zssiopz26ioJoLQevY5oEJzwjEvCnDA7PmoJo4abKVdjdgTiUo0mQDWz8dc78Y
Bnpo7QaqQ7TR/EhDBbXcF7G5qIMl9wCFSYnwKMW32qAp+eQ/bqNTyB8zE6RGSfao
byxbLfPzAgMBAAECggEAMPlfYFiDDl8iNYvAbgyY45ki6vmq/X3rftl6WkImUcyD
xLEsMWwU6sM1Kwh56fT8dYPLmCyfHQT8YhHd7gYxzGCWfQec1MneI4GuFRQumF/c
7f1VpXnBwZvEqaMRl/mEUcxkIWypjBxMM9UnsD6Hu18GjmTLF2FTy78+lUBt/mSZ
CptLNIQJ0vncdAlxg9PYxfXhrtWj8I2T7PCAmBM+wbcGzfWTKyo/JMKylnEe4NNg
j4elBHhISSUACpZd2pU+iA2nTaaD1Rzlqang/FypIzwLye/Sz2a6spM9yL8H9UN5
zdz+QIwNoSC4fhEAlDo7FMBr8ZdR97qadP78XH+3SQKBgQDC5mwvIEoLQSD7H9PT
t+J59uq90Dcg7qRxM+jbrtmPmvSuAql2Mx7KO5kf45CO7mLA1oE7YG2ceXQb4hFO
HCrIGYtK6iEyizvIOCmbwoPbYXBf2o6iSl1t7f4wQ4N35KjQptviW5CO3ThFI2H4
Oco2zR1Bjtig/lPKPv4TlAA4ZwKBgQC1iTZzynr2UP6f2MIByNEzN86BAiHJBya0
BCWrl93A66GRSjV/tNikSZ/Me/SU3h44WuiFVRMuDrYrCcrUgmXpVMSnAy6AiwXx
ItMsQNJW3JryN7uki/swI0zLWj8B+FMf8nXa2FS545etjOj1w6scoKT4txmVT0C+
61l4KNXglQKBgQCQRD3qOE12vTPrjyiePCwxOZuS+1ADWYJxpQoFqwyx5vKc562G
p9pvuePjnfAATObedSldyUf5nlFa3mEO33yvd3EK9/mwzy1mTGRIPpiZyCuFWGNi
MAeueo9ALIlhMune4NQ8XqjHh2rCiqlXM3fCTtwMDe++Y+Oj/jLWTSRImwKBgDTb
UNmCGS9jAeB08ngmipMJKr1xa3jm9iPwGS/PNigX86EkJFOcyn97WGXnqZ0210G9
Znp7/OuqKOx7G22o0heQMPoX+RBAamh9pVL7RMM51Hu2MpKEl4y6mn+TNUlTjpB8
vkgMOQ8u71j+8E2uvUHGnII2feJ1gvqT+Cb+bNfJAoGAJNK6ufPA0lHJwuDlGlNu
eKU0bP3tkz7nM20PS8R2djoNGN+D+pFFR71TB2gTN6YmqBcwP7TjPwNLKSg9xJvY
ST1F2QnOyds/OgdFlabcNdmbNivT0rHX6qZs7vYXNVjt7rmIRY2TW3ifRLeCK0Ls
5Anq4SkaoH/ctBnP3TYRnQI=
-----END PRIVATE KEY-----

View File

@@ -0,0 +1 @@
0330C6D190E3FE649DAFCDA2F4D765E2D29328DE

View File

@@ -0,0 +1,90 @@
#!/bin/bash
# Set filenames
CA_KEY="ca.key"
CA_CERT="ca.crt"
SERVER_KEY="server.key"
SERVER_CSR="server.csr"
SERVER_CERT="server.crt"
CA_CONF="ca.conf"
SERVER_CONF="server.conf"
V3_EXT_CONF="v3_ext.conf"
# Generate the CA key
openssl genpkey -algorithm RSA -out $CA_KEY -pkeyopt rsa_keygen_bits:2048
# Create the CA configuration file
cat >$CA_CONF <<EOL
[ req ]
distinguished_name = req_distinguished_name
x509_extensions = v3_ca
prompt = no
[ req_distinguished_name ]
C = ZA
ST = WC
L = Cape Town
O = Coder
OU = Team Coconut
CN = Coder CA
[ v3_ca ]
basicConstraints = critical,CA:TRUE
keyUsage = critical,keyCertSign,cRLSign
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid:always,issuer:always
EOL
# Generate the CA certificate
openssl req -new -x509 -key $CA_KEY -out $CA_CERT -days 3650 -config $CA_CONF -extensions v3_ca
# Generate the server key
openssl genpkey -algorithm RSA -out $SERVER_KEY -pkeyopt rsa_keygen_bits:2048
# Create the server configuration file
cat >$SERVER_CONF <<EOL
[ req ]
distinguished_name = req_distinguished_name
req_extensions = v3_req
prompt = no
[ req_distinguished_name ]
C = ZA
ST = WC
L = Cape Town
O = Coder
OU = Team Coconut
CN = myserver.local
[ v3_req ]
subjectAltName = @alt_names
[ alt_names ]
DNS.1 = myserver.local
DNS.2 = www.myserver.local
IP.1 = 127.0.0.1
EOL
# Generate the server CSR
openssl req -new -key $SERVER_KEY -out $SERVER_CSR -config $SERVER_CONF
# Create the server extensions configuration file
cat >$V3_EXT_CONF <<EOL
authorityKeyIdentifier=keyid,issuer
basicConstraints=CA:FALSE
keyUsage = digitalSignature, nonRepudiation, keyEncipherment, dataEncipherment
subjectAltName = @alt_names
[ alt_names ]
DNS.1 = myserver.local
DNS.2 = www.myserver.local
IP.1 = 127.0.0.1
EOL
# Generate the server certificate signed by the CA with a validity of 825 days
openssl x509 -req -in $SERVER_CSR -CA $CA_CERT -CAkey $CA_KEY -CAcreateserial -out $SERVER_CERT -days 825 -extfile $V3_EXT_CONF
# Verify the server certificate
openssl x509 -in $SERVER_CERT -text -noout | grep -A 1 "Subject Alternative Name"
echo "CA and server certificates generated successfully."

View File

@@ -0,0 +1 @@
🤫

View File

@@ -0,0 +1,20 @@
[ req ]
distinguished_name = req_distinguished_name
req_extensions = v3_req
prompt = no
[ req_distinguished_name ]
C = ZA
ST = WC
L = Cape Town
O = Coder
OU = Team Coconut
CN = myserver.local
[ v3_req ]
subjectAltName = @alt_names
[ alt_names ]
DNS.1 = myserver.local
DNS.2 = www.myserver.local
IP.1 = 127.0.0.1

View File

@@ -0,0 +1,24 @@
-----BEGIN CERTIFICATE-----
MIID9TCCAt2gAwIBAgIUAzDG0ZDj/mSdr82i9Ndl4tKTKN4wDQYJKoZIhvcNAQEL
BQAwaDELMAkGA1UEBhMCWkExCzAJBgNVBAgMAldDMRIwEAYDVQQHDAlDYXBlIFRv
d24xDjAMBgNVBAoMBUNvZGVyMRUwEwYDVQQLDAxUZWFtIENvY29udXQxETAPBgNV
BAMMCENvZGVyIENBMB4XDTI0MDcxNTEzMzYwOFoXDTI2MTAxODEzMzYwOFowbjEL
MAkGA1UEBhMCWkExCzAJBgNVBAgMAldDMRIwEAYDVQQHDAlDYXBlIFRvd24xDjAM
BgNVBAoMBUNvZGVyMRUwEwYDVQQLDAxUZWFtIENvY29udXQxFzAVBgNVBAMMDm15
c2VydmVyLmxvY2FsMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArvkV
9OEO/g3KmKrOzuvF1HQJiF/oR4wvbkLWrpuc4o0+++uJqEwHx/PkkHJLZiYvOuLG
1ostI6G8it8pK8FjSLrdBZCMxi3yOAhXJaErTyOm4ACvf27o3HyWEcngUbpGyptZ
ey7mcGFmqRsz4a9rzSjtuZQPuugCZfHpdo/w6WAE+W+/8KpUjvv/bsmKbsli1AsY
edCcx5ZkYK3j7Dn/M95v/+hHvGdtcTXodWVqnEzblcUBw2zgZFo7B6jJNt6kgzJz
ofv4r7st/F0LVOGc+VWkwnhL1yjcdXEsnGvhP4n5qzupVMEDGKThuOkBuYZ7Ug99
8tcnuN1usJgvCDk1awIDAQABo4GQMIGNMB8GA1UdIwQYMBaAFKTYEZ1FBkMy/M58
tCRSaTDOOs4XMAkGA1UdEwQCMAAwCwYDVR0PBAQDAgTwMDMGA1UdEQQsMCqCDm15
c2VydmVyLmxvY2FsghJ3d3cubXlzZXJ2ZXIubG9jYWyHBH8AAAEwHQYDVR0OBBYE
FFGiAovKgGehDTXyxtI66xpHuyrSMA0GCSqGSIb3DQEBCwUAA4IBAQAVifeEzc3g
wTaogC3GVYn4ty/oA5kMHEXNN39QSElZ0qKordPmjZx/5k5SkneCgN3LYzcJm1l6
/t5khedYmtbuUmT91BC8R4+d4aGFGvvR8/4XHKAOyei9w50JIrSf0HkY91cEXzhU
N1p/491TvLt/uNgHeSNBRQXXkBZj5ZCPgs6D1vLZUxI4XnVwE01I+Ivhiuo5UMC8
AjFzomUVnqH23nTgRlaFQZJOYfWV80VV8oXfHzXKiqfGwizFzKaF01XBVdmzjz2x
iL6OoOM/EiBgsmDeb3HP4HYuFDvgWqCNbmP6z7M+rs2XjJLM8Uaywvxdkm/ib3+y
rSJnQig8Prw9
-----END CERTIFICATE-----

View File

@@ -0,0 +1,18 @@
-----BEGIN CERTIFICATE REQUEST-----
MIIC+TCCAeECAQAwbjELMAkGA1UEBhMCWkExCzAJBgNVBAgMAldDMRIwEAYDVQQH
DAlDYXBlIFRvd24xDjAMBgNVBAoMBUNvZGVyMRUwEwYDVQQLDAxUZWFtIENvY29u
dXQxFzAVBgNVBAMMDm15c2VydmVyLmxvY2FsMIIBIjANBgkqhkiG9w0BAQEFAAOC
AQ8AMIIBCgKCAQEArvkV9OEO/g3KmKrOzuvF1HQJiF/oR4wvbkLWrpuc4o0+++uJ
qEwHx/PkkHJLZiYvOuLG1ostI6G8it8pK8FjSLrdBZCMxi3yOAhXJaErTyOm4ACv
f27o3HyWEcngUbpGyptZey7mcGFmqRsz4a9rzSjtuZQPuugCZfHpdo/w6WAE+W+/
8KpUjvv/bsmKbsli1AsYedCcx5ZkYK3j7Dn/M95v/+hHvGdtcTXodWVqnEzblcUB
w2zgZFo7B6jJNt6kgzJzofv4r7st/F0LVOGc+VWkwnhL1yjcdXEsnGvhP4n5qzup
VMEDGKThuOkBuYZ7Ug998tcnuN1usJgvCDk1awIDAQABoEYwRAYJKoZIhvcNAQkO
MTcwNTAzBgNVHREELDAqgg5teXNlcnZlci5sb2NhbIISd3d3Lm15c2VydmVyLmxv
Y2FshwR/AAABMA0GCSqGSIb3DQEBCwUAA4IBAQCPWO5rV82kb4zI7OR4pjyU/AaD
Wo2zIeyFIj+BpOe9jCYSdnPp4lagbV8Nal+rQPc7/pPTkjC+u1OZB2N3wYbICATn
vw4lVLtrtIzts7lG+EI5tjqCU2nub5k3nDNGyrK/EuX3c9VJFTw9qmfB48gZWpAV
mAkl4BO7HsSaGFXlykmoACERCHT8sVfJOO/rDxMJks+u++EyNQ1cQ9tR3hWaL4I2
e1ZAmJ5Citlntwvq5BUDS96yYHZdM8rA0PQPeHi6CTJfgyEdX+yjtv/SZiXGYx1f
KjGhgp6ln/DcDIhgp4oSmZID+3P3Kx8Yhv1U+2LbZoC8+4mkDhJw9Yns640O
-----END CERTIFICATE REQUEST-----

View File

@@ -0,0 +1,28 @@
-----BEGIN PRIVATE KEY-----
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCu+RX04Q7+DcqY
qs7O68XUdAmIX+hHjC9uQtaum5zijT7764moTAfH8+SQcktmJi864sbWiy0jobyK
3ykrwWNIut0FkIzGLfI4CFcloStPI6bgAK9/bujcfJYRyeBRukbKm1l7LuZwYWap
GzPhr2vNKO25lA+66AJl8el2j/DpYAT5b7/wqlSO+/9uyYpuyWLUCxh50JzHlmRg
rePsOf8z3m//6Ee8Z21xNeh1ZWqcTNuVxQHDbOBkWjsHqMk23qSDMnOh+/ivuy38
XQtU4Zz5VaTCeEvXKNx1cSyca+E/ifmrO6lUwQMYpOG46QG5hntSD33y1ye43W6w
mC8IOTVrAgMBAAECggEACUw2JPmSnOBpvBwTej5gGE6ENSl3g9nIqXDGzKd7OjSs
PKHDAlzr6u2kXyKbrBVqXBQx4bOqleKhzLVYEDmqB3LajNGmEV/ep6iVzOuYDBAG
bY/Lw5dGq3S5Wr+h+mXOHjUMF7Yhy6X5WRIXey4hqdi7bSmXfmSWwAkPUVwLvrLj
gj1Tp8Ll5SxeD1G9eOX1GYVChh2SUsVbLeGrovwcfCZaobEvc2U30SNOW4Sep7P1
e+CZlIO02Ts1EroW7G41YvAon3EziaZEb3Esusx1LH+cpbCyDtiA/aCfLVKKJ2Ev
YAbZAyBOAcXtIa+RT0Ipph/6fsC1l1uyyUOETGVwpQKBgQDV9mpX+UBmU6vXz1b+
cZ116dI1irK8qrF2G62rTtwGEhhaDC1AIISsqm0Huav763KQ2OsM1eJiPUC3/Q/9
ouNXPA5pTT524XnZhr3KEkDRgXmw1xbzYcLMVYYsDrvKvVUNlQcYGwxTzxcielMB
Jx2F3P90uegMKwUGM5XAChhVpwKBgQDRWaDja7QN6NCrq6o1pAueJnAEGK4IqloS
v/6tFJ6XTqCAUXhFkoAyXFUi1QN7PMV5igNF0VQkU90G9e2wTeE4GJr5yKRxBP9+
v9KgRkDKz1DJcep2Abm618vGTPIs72sUph9R5eraI161F4AiGv6PLuM4/LbF+6YK
/GF6Wz+inQKBgAYaEexSWmjQqAzuh8+X0+LB+VG3k+NXhtoUbf59sD6oE3O19zBl
/QKjlZprzCDSFSFWXlWuX9dnYcodeHBGTe918f9EyaxAP+ZZNl5l6N1QsPS/HZNx
TUnggoQNI4PjpGJPxrUESHS3ajR8gpN81xWzOMHOb3SxYWJM5E9mukzvAoGBAIZ2
2R35maateQoqsqLNgSDNc3lOGMo8EKqmYv/slIh+2hxRN70IAgtWvuAmjZvkRrpv
6PY5I6BJtVe5Mjfhbd1IAJKbSvPE0A4rSy/ir88UJcGdx4iQRyk5Xgs6dPpjtRWI
Nem2kYgW28fZFlXRnNt+tDdwKj00C0xXGo0qes8JAoGAD9mj697kYV8LIsIk5Eo+
NdbcjungM8dk8WKMgDxYnkviY/3liBHuvq99YPna2iVAQ3pHpuInFjbOTYdf26JB
5wbuIBFHVGNsKKwIDAZdK1VzPh/E/88sDp63F/nLu8Q4EAVHxTr8VTt/GWV+VJSK
RQi4ETleSTjzYeKWjJxlf+4=
-----END PRIVATE KEY-----

View File

@@ -0,0 +1,9 @@
authorityKeyIdentifier=keyid,issuer
basicConstraints=CA:FALSE
keyUsage = digitalSignature, nonRepudiation, keyEncipherment, dataEncipherment
subjectAltName = @alt_names
[ alt_names ]
DNS.1 = myserver.local
DNS.2 = www.myserver.local
IP.1 = 127.0.0.1

View File

@@ -0,0 +1,221 @@
package smtptest
import (
"crypto/tls"
_ "embed"
"io"
"net"
"sync"
"time"
"github.com/emersion/go-sasl"
"github.com/emersion/go-smtp"
"golang.org/x/xerrors"
)
// TLS cert files.
var (
//go:embed fixtures/server.crt
certFile []byte
//go:embed fixtures/server.key
keyFile []byte
)
type Config struct {
AuthMechanisms []string
AcceptedIdentity, AcceptedUsername, AcceptedPassword string
FailOnDataFn func() error
}
type Message struct {
AuthMech string
Identity, Username, Password string // Auth
From string
To []string // Address
Subject, Contents string // Content
}
type Backend struct {
cfg Config
mu sync.Mutex
lastMsg *Message
}
func NewBackend(cfg Config) *Backend {
return &Backend{
cfg: cfg,
}
}
// NewSession is called after client greeting (EHLO, HELO).
func (b *Backend) NewSession(c *smtp.Conn) (smtp.Session, error) {
return &Session{conn: c, backend: b}, nil
}
func (b *Backend) LastMessage() *Message {
return b.lastMsg
}
func (b *Backend) Reset() {
b.lastMsg = nil
}
type Session struct {
conn *smtp.Conn
backend *Backend
}
// AuthMechanisms returns a slice of available auth mechanisms; only PLAIN is
// supported in this example.
func (s *Session) AuthMechanisms() []string {
return s.backend.cfg.AuthMechanisms
}
// Auth is the handler for supported authenticators.
func (s *Session) Auth(mech string) (sasl.Server, error) {
s.backend.mu.Lock()
defer s.backend.mu.Unlock()
if s.backend.lastMsg == nil {
s.backend.lastMsg = &Message{AuthMech: mech}
}
switch mech {
case sasl.Plain:
return sasl.NewPlainServer(func(identity, username, password string) error {
s.backend.lastMsg.Identity = identity
s.backend.lastMsg.Username = username
s.backend.lastMsg.Password = password
if s.backend.cfg.AcceptedIdentity != "" && identity != s.backend.cfg.AcceptedIdentity {
return xerrors.Errorf("unknown identity: %q", identity)
}
if username != s.backend.cfg.AcceptedUsername {
return xerrors.Errorf("unknown user: %q", username)
}
if password != s.backend.cfg.AcceptedPassword {
return xerrors.Errorf("incorrect password for username: %q", username)
}
return nil
}), nil
case sasl.Login:
return sasl.NewLoginServer(func(username, password string) error {
s.backend.lastMsg.Username = username
s.backend.lastMsg.Password = password
if username != s.backend.cfg.AcceptedUsername {
return xerrors.Errorf("unknown user: %q", username)
}
if password != s.backend.cfg.AcceptedPassword {
return xerrors.Errorf("incorrect password for username: %q", username)
}
return nil
}), nil
default:
return nil, xerrors.Errorf("unexpected auth mechanism: %q", mech)
}
}
func (s *Session) Mail(from string, _ *smtp.MailOptions) error {
s.backend.mu.Lock()
defer s.backend.mu.Unlock()
if s.backend.lastMsg == nil {
s.backend.lastMsg = &Message{}
}
s.backend.lastMsg.From = from
return nil
}
func (s *Session) Rcpt(to string, _ *smtp.RcptOptions) error {
s.backend.mu.Lock()
defer s.backend.mu.Unlock()
s.backend.lastMsg.To = append(s.backend.lastMsg.To, to)
return nil
}
func (s *Session) Data(r io.Reader) error {
s.backend.mu.Lock()
defer s.backend.mu.Unlock()
b, err := io.ReadAll(r)
if err != nil {
return err
}
if s.backend.cfg.FailOnDataFn != nil {
return s.backend.cfg.FailOnDataFn()
}
s.backend.lastMsg.Contents = string(b)
return nil
}
func (*Session) Reset() {}
func (*Session) Logout() error { return nil }
// nolint:revive // Yes, useTLS is a control flag.
func CreateMockSMTPServer(be *Backend, useTLS bool) (*smtp.Server, net.Listener, error) {
// nolint:gosec
tlsCfg := &tls.Config{
GetCertificate: readCert,
}
l, err := net.Listen("tcp", "localhost:0")
if err != nil {
return nil, nil, xerrors.Errorf("connect: tls? %v: %w", useTLS, err)
}
if useTLS {
l = tls.NewListener(l, tlsCfg)
}
addr, ok := l.Addr().(*net.TCPAddr)
if !ok {
return nil, nil, xerrors.Errorf("unexpected address type: %T", l.Addr())
}
s := smtp.NewServer(be)
s.Addr = addr.String()
s.WriteTimeout = 10 * time.Second
s.ReadTimeout = 10 * time.Second
s.MaxMessageBytes = 1024 * 1024
s.MaxRecipients = 50
s.AllowInsecureAuth = !useTLS
s.TLSConfig = tlsCfg
return s, l, nil
}
func readCert(_ *tls.ClientHelloInfo) (*tls.Certificate, error) {
crt, err := tls.X509KeyPair(certFile, keyFile)
if err != nil {
return nil, xerrors.Errorf("load x509 cert: %w", err)
}
return &crt, nil
}
func PingClient(listen net.Listener, useTLS bool, startTLS bool) (*smtp.Client, error) {
tlsCfg := &tls.Config{
// nolint:gosec // It's a test.
InsecureSkipVerify: true,
}
switch {
case useTLS:
return smtp.DialTLS(listen.Addr().String(), tlsCfg)
case startTLS:
return smtp.DialStartTLS(listen.Addr().String(), tlsCfg)
default:
return smtp.Dial(listen.Addr().String())
}
}