diff options
Diffstat (limited to 'src/pkg/net/smtp/smtp_test.go')
-rw-r--r-- | src/pkg/net/smtp/smtp_test.go | 694 |
1 files changed, 0 insertions, 694 deletions
diff --git a/src/pkg/net/smtp/smtp_test.go b/src/pkg/net/smtp/smtp_test.go deleted file mode 100644 index 3fba1ea5a..000000000 --- a/src/pkg/net/smtp/smtp_test.go +++ /dev/null @@ -1,694 +0,0 @@ -// Copyright 2010 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package smtp - -import ( - "bufio" - "bytes" - "crypto/tls" - "crypto/x509" - "io" - "net" - "net/textproto" - "strings" - "testing" - "time" -) - -type authTest struct { - auth Auth - challenges []string - name string - responses []string -} - -var authTests = []authTest{ - {PlainAuth("", "user", "pass", "testserver"), []string{}, "PLAIN", []string{"\x00user\x00pass"}}, - {PlainAuth("foo", "bar", "baz", "testserver"), []string{}, "PLAIN", []string{"foo\x00bar\x00baz"}}, - {CRAMMD5Auth("user", "pass"), []string{"<123456.1322876914@testserver>"}, "CRAM-MD5", []string{"", "user 287eb355114cf5c471c26a875f1ca4ae"}}, -} - -func TestAuth(t *testing.T) { -testLoop: - for i, test := range authTests { - name, resp, err := test.auth.Start(&ServerInfo{"testserver", true, nil}) - if name != test.name { - t.Errorf("#%d got name %s, expected %s", i, name, test.name) - } - if !bytes.Equal(resp, []byte(test.responses[0])) { - t.Errorf("#%d got response %s, expected %s", i, resp, test.responses[0]) - } - if err != nil { - t.Errorf("#%d error: %s", i, err) - } - for j := range test.challenges { - challenge := []byte(test.challenges[j]) - expected := []byte(test.responses[j+1]) - resp, err := test.auth.Next(challenge, true) - if err != nil { - t.Errorf("#%d error: %s", i, err) - continue testLoop - } - if !bytes.Equal(resp, expected) { - t.Errorf("#%d got %s, expected %s", i, resp, expected) - continue testLoop - } - } - } -} - -func TestAuthPlain(t *testing.T) { - auth := PlainAuth("foo", "bar", "baz", "servername") - - tests := []struct { - server *ServerInfo - err string - }{ - { - server: &ServerInfo{Name: "servername", TLS: true}, - }, - { - // Okay; explicitly advertised by server. - server: &ServerInfo{Name: "servername", Auth: []string{"PLAIN"}}, - }, - { - server: &ServerInfo{Name: "servername", Auth: []string{"CRAM-MD5"}}, - err: "unencrypted connection", - }, - { - server: &ServerInfo{Name: "attacker", TLS: true}, - err: "wrong host name", - }, - } - for i, tt := range tests { - _, _, err := auth.Start(tt.server) - got := "" - if err != nil { - got = err.Error() - } - if got != tt.err { - t.Errorf("%d. got error = %q; want %q", i, got, tt.err) - } - } -} - -type faker struct { - io.ReadWriter -} - -func (f faker) Close() error { return nil } -func (f faker) LocalAddr() net.Addr { return nil } -func (f faker) RemoteAddr() net.Addr { return nil } -func (f faker) SetDeadline(time.Time) error { return nil } -func (f faker) SetReadDeadline(time.Time) error { return nil } -func (f faker) SetWriteDeadline(time.Time) error { return nil } - -func TestBasic(t *testing.T) { - server := strings.Join(strings.Split(basicServer, "\n"), "\r\n") - client := strings.Join(strings.Split(basicClient, "\n"), "\r\n") - - var cmdbuf bytes.Buffer - bcmdbuf := bufio.NewWriter(&cmdbuf) - var fake faker - fake.ReadWriter = bufio.NewReadWriter(bufio.NewReader(strings.NewReader(server)), bcmdbuf) - c := &Client{Text: textproto.NewConn(fake), localName: "localhost"} - - if err := c.helo(); err != nil { - t.Fatalf("HELO failed: %s", err) - } - if err := c.ehlo(); err == nil { - t.Fatalf("Expected first EHLO to fail") - } - if err := c.ehlo(); err != nil { - t.Fatalf("Second EHLO failed: %s", err) - } - - c.didHello = true - if ok, args := c.Extension("aUtH"); !ok || args != "LOGIN PLAIN" { - t.Fatalf("Expected AUTH supported") - } - if ok, _ := c.Extension("DSN"); ok { - t.Fatalf("Shouldn't support DSN") - } - - if err := c.Mail("user@gmail.com"); err == nil { - t.Fatalf("MAIL should require authentication") - } - - if err := c.Verify("user1@gmail.com"); err == nil { - t.Fatalf("First VRFY: expected no verification") - } - if err := c.Verify("user2@gmail.com"); err != nil { - t.Fatalf("Second VRFY: expected verification, got %s", err) - } - - // fake TLS so authentication won't complain - c.tls = true - c.serverName = "smtp.google.com" - if err := c.Auth(PlainAuth("", "user", "pass", "smtp.google.com")); err != nil { - t.Fatalf("AUTH failed: %s", err) - } - - if err := c.Mail("user@gmail.com"); err != nil { - t.Fatalf("MAIL failed: %s", err) - } - if err := c.Rcpt("golang-nuts@googlegroups.com"); err != nil { - t.Fatalf("RCPT failed: %s", err) - } - msg := `From: user@gmail.com -To: golang-nuts@googlegroups.com -Subject: Hooray for Go - -Line 1 -.Leading dot line . -Goodbye.` - w, err := c.Data() - if err != nil { - t.Fatalf("DATA failed: %s", err) - } - if _, err := w.Write([]byte(msg)); err != nil { - t.Fatalf("Data write failed: %s", err) - } - if err := w.Close(); err != nil { - t.Fatalf("Bad data response: %s", err) - } - - if err := c.Quit(); err != nil { - t.Fatalf("QUIT failed: %s", err) - } - - bcmdbuf.Flush() - actualcmds := cmdbuf.String() - if client != actualcmds { - t.Fatalf("Got:\n%s\nExpected:\n%s", actualcmds, client) - } -} - -var basicServer = `250 mx.google.com at your service -502 Unrecognized command. -250-mx.google.com at your service -250-SIZE 35651584 -250-AUTH LOGIN PLAIN -250 8BITMIME -530 Authentication required -252 Send some mail, I'll try my best -250 User is valid -235 Accepted -250 Sender OK -250 Receiver OK -354 Go ahead -250 Data OK -221 OK -` - -var basicClient = `HELO localhost -EHLO localhost -EHLO localhost -MAIL FROM:<user@gmail.com> BODY=8BITMIME -VRFY user1@gmail.com -VRFY user2@gmail.com -AUTH PLAIN AHVzZXIAcGFzcw== -MAIL FROM:<user@gmail.com> BODY=8BITMIME -RCPT TO:<golang-nuts@googlegroups.com> -DATA -From: user@gmail.com -To: golang-nuts@googlegroups.com -Subject: Hooray for Go - -Line 1 -..Leading dot line . -Goodbye. -. -QUIT -` - -func TestNewClient(t *testing.T) { - server := strings.Join(strings.Split(newClientServer, "\n"), "\r\n") - client := strings.Join(strings.Split(newClientClient, "\n"), "\r\n") - - var cmdbuf bytes.Buffer - bcmdbuf := bufio.NewWriter(&cmdbuf) - out := func() string { - bcmdbuf.Flush() - return cmdbuf.String() - } - var fake faker - fake.ReadWriter = bufio.NewReadWriter(bufio.NewReader(strings.NewReader(server)), bcmdbuf) - c, err := NewClient(fake, "fake.host") - if err != nil { - t.Fatalf("NewClient: %v\n(after %v)", err, out()) - } - defer c.Close() - if ok, args := c.Extension("aUtH"); !ok || args != "LOGIN PLAIN" { - t.Fatalf("Expected AUTH supported") - } - if ok, _ := c.Extension("DSN"); ok { - t.Fatalf("Shouldn't support DSN") - } - if err := c.Quit(); err != nil { - t.Fatalf("QUIT failed: %s", err) - } - - actualcmds := out() - if client != actualcmds { - t.Fatalf("Got:\n%s\nExpected:\n%s", actualcmds, client) - } -} - -var newClientServer = `220 hello world -250-mx.google.com at your service -250-SIZE 35651584 -250-AUTH LOGIN PLAIN -250 8BITMIME -221 OK -` - -var newClientClient = `EHLO localhost -QUIT -` - -func TestNewClient2(t *testing.T) { - server := strings.Join(strings.Split(newClient2Server, "\n"), "\r\n") - client := strings.Join(strings.Split(newClient2Client, "\n"), "\r\n") - - var cmdbuf bytes.Buffer - bcmdbuf := bufio.NewWriter(&cmdbuf) - var fake faker - fake.ReadWriter = bufio.NewReadWriter(bufio.NewReader(strings.NewReader(server)), bcmdbuf) - c, err := NewClient(fake, "fake.host") - if err != nil { - t.Fatalf("NewClient: %v", err) - } - defer c.Close() - if ok, _ := c.Extension("DSN"); ok { - t.Fatalf("Shouldn't support DSN") - } - if err := c.Quit(); err != nil { - t.Fatalf("QUIT failed: %s", err) - } - - bcmdbuf.Flush() - actualcmds := cmdbuf.String() - if client != actualcmds { - t.Fatalf("Got:\n%s\nExpected:\n%s", actualcmds, client) - } -} - -var newClient2Server = `220 hello world -502 EH? -250-mx.google.com at your service -250-SIZE 35651584 -250-AUTH LOGIN PLAIN -250 8BITMIME -221 OK -` - -var newClient2Client = `EHLO localhost -HELO localhost -QUIT -` - -func TestHello(t *testing.T) { - - if len(helloServer) != len(helloClient) { - t.Fatalf("Hello server and client size mismatch") - } - - for i := 0; i < len(helloServer); i++ { - server := strings.Join(strings.Split(baseHelloServer+helloServer[i], "\n"), "\r\n") - client := strings.Join(strings.Split(baseHelloClient+helloClient[i], "\n"), "\r\n") - var cmdbuf bytes.Buffer - bcmdbuf := bufio.NewWriter(&cmdbuf) - var fake faker - fake.ReadWriter = bufio.NewReadWriter(bufio.NewReader(strings.NewReader(server)), bcmdbuf) - c, err := NewClient(fake, "fake.host") - if err != nil { - t.Fatalf("NewClient: %v", err) - } - defer c.Close() - c.localName = "customhost" - err = nil - - switch i { - case 0: - err = c.Hello("customhost") - case 1: - err = c.StartTLS(nil) - if err.Error() == "502 Not implemented" { - err = nil - } - case 2: - err = c.Verify("test@example.com") - case 3: - c.tls = true - c.serverName = "smtp.google.com" - err = c.Auth(PlainAuth("", "user", "pass", "smtp.google.com")) - case 4: - err = c.Mail("test@example.com") - case 5: - ok, _ := c.Extension("feature") - if ok { - t.Errorf("Expected FEATURE not to be supported") - } - case 6: - err = c.Reset() - case 7: - err = c.Quit() - case 8: - err = c.Verify("test@example.com") - if err != nil { - err = c.Hello("customhost") - if err != nil { - t.Errorf("Want error, got none") - } - } - default: - t.Fatalf("Unhandled command") - } - - if err != nil { - t.Errorf("Command %d failed: %v", i, err) - } - - bcmdbuf.Flush() - actualcmds := cmdbuf.String() - if client != actualcmds { - t.Errorf("Got:\n%s\nExpected:\n%s", actualcmds, client) - } - } -} - -var baseHelloServer = `220 hello world -502 EH? -250-mx.google.com at your service -250 FEATURE -` - -var helloServer = []string{ - "", - "502 Not implemented\n", - "250 User is valid\n", - "235 Accepted\n", - "250 Sender ok\n", - "", - "250 Reset ok\n", - "221 Goodbye\n", - "250 Sender ok\n", -} - -var baseHelloClient = `EHLO customhost -HELO customhost -` - -var helloClient = []string{ - "", - "STARTTLS\n", - "VRFY test@example.com\n", - "AUTH PLAIN AHVzZXIAcGFzcw==\n", - "MAIL FROM:<test@example.com>\n", - "", - "RSET\n", - "QUIT\n", - "VRFY test@example.com\n", -} - -func TestSendMail(t *testing.T) { - server := strings.Join(strings.Split(sendMailServer, "\n"), "\r\n") - client := strings.Join(strings.Split(sendMailClient, "\n"), "\r\n") - var cmdbuf bytes.Buffer - bcmdbuf := bufio.NewWriter(&cmdbuf) - l, err := net.Listen("tcp", "127.0.0.1:0") - if err != nil { - t.Fatalf("Unable to to create listener: %v", err) - } - defer l.Close() - - // prevent data race on bcmdbuf - var done = make(chan struct{}) - go func(data []string) { - - defer close(done) - - conn, err := l.Accept() - if err != nil { - t.Errorf("Accept error: %v", err) - return - } - defer conn.Close() - - tc := textproto.NewConn(conn) - for i := 0; i < len(data) && data[i] != ""; i++ { - tc.PrintfLine(data[i]) - for len(data[i]) >= 4 && data[i][3] == '-' { - i++ - tc.PrintfLine(data[i]) - } - if data[i] == "221 Goodbye" { - return - } - read := false - for !read || data[i] == "354 Go ahead" { - msg, err := tc.ReadLine() - bcmdbuf.Write([]byte(msg + "\r\n")) - read = true - if err != nil { - t.Errorf("Read error: %v", err) - return - } - if data[i] == "354 Go ahead" && msg == "." { - break - } - } - } - }(strings.Split(server, "\r\n")) - - err = SendMail(l.Addr().String(), nil, "test@example.com", []string{"other@example.com"}, []byte(strings.Replace(`From: test@example.com -To: other@example.com -Subject: SendMail test - -SendMail is working for me. -`, "\n", "\r\n", -1))) - - if err != nil { - t.Errorf("%v", err) - } - - <-done - bcmdbuf.Flush() - actualcmds := cmdbuf.String() - if client != actualcmds { - t.Errorf("Got:\n%s\nExpected:\n%s", actualcmds, client) - } -} - -var sendMailServer = `220 hello world -502 EH? -250 mx.google.com at your service -250 Sender ok -250 Receiver ok -354 Go ahead -250 Data ok -221 Goodbye -` - -var sendMailClient = `EHLO localhost -HELO localhost -MAIL FROM:<test@example.com> -RCPT TO:<other@example.com> -DATA -From: test@example.com -To: other@example.com -Subject: SendMail test - -SendMail is working for me. -. -QUIT -` - -func TestAuthFailed(t *testing.T) { - server := strings.Join(strings.Split(authFailedServer, "\n"), "\r\n") - client := strings.Join(strings.Split(authFailedClient, "\n"), "\r\n") - var cmdbuf bytes.Buffer - bcmdbuf := bufio.NewWriter(&cmdbuf) - var fake faker - fake.ReadWriter = bufio.NewReadWriter(bufio.NewReader(strings.NewReader(server)), bcmdbuf) - c, err := NewClient(fake, "fake.host") - if err != nil { - t.Fatalf("NewClient: %v", err) - } - defer c.Close() - - c.tls = true - c.serverName = "smtp.google.com" - err = c.Auth(PlainAuth("", "user", "pass", "smtp.google.com")) - - if err == nil { - t.Error("Auth: expected error; got none") - } else if err.Error() != "535 Invalid credentials\nplease see www.example.com" { - t.Errorf("Auth: got error: %v, want: %s", err, "535 Invalid credentials\nplease see www.example.com") - } - - bcmdbuf.Flush() - actualcmds := cmdbuf.String() - if client != actualcmds { - t.Errorf("Got:\n%s\nExpected:\n%s", actualcmds, client) - } -} - -var authFailedServer = `220 hello world -250-mx.google.com at your service -250 AUTH LOGIN PLAIN -535-Invalid credentials -535 please see www.example.com -221 Goodbye -` - -var authFailedClient = `EHLO localhost -AUTH PLAIN AHVzZXIAcGFzcw== -* -QUIT -` - -func TestTLSClient(t *testing.T) { - ln := newLocalListener(t) - defer ln.Close() - errc := make(chan error) - go func() { - errc <- sendMail(ln.Addr().String()) - }() - conn, err := ln.Accept() - if err != nil { - t.Fatalf("failed to accept connection: %v", err) - } - defer conn.Close() - if err := serverHandle(conn, t); err != nil { - t.Fatalf("failed to handle connection: %v", err) - } - if err := <-errc; err != nil { - t.Fatalf("client error: %v", err) - } -} - -func newLocalListener(t *testing.T) net.Listener { - ln, err := net.Listen("tcp", "127.0.0.1:0") - if err != nil { - ln, err = net.Listen("tcp6", "[::1]:0") - } - if err != nil { - t.Fatal(err) - } - return ln -} - -type smtpSender struct { - w io.Writer -} - -func (s smtpSender) send(f string) { - s.w.Write([]byte(f + "\r\n")) -} - -// smtp server, finely tailored to deal with our own client only! -func serverHandle(c net.Conn, t *testing.T) error { - send := smtpSender{c}.send - send("220 127.0.0.1 ESMTP service ready") - s := bufio.NewScanner(c) - for s.Scan() { - switch s.Text() { - case "EHLO localhost": - send("250-127.0.0.1 ESMTP offers a warm hug of welcome") - send("250-STARTTLS") - send("250 Ok") - case "STARTTLS": - send("220 Go ahead") - keypair, err := tls.X509KeyPair(localhostCert, localhostKey) - if err != nil { - return err - } - config := &tls.Config{Certificates: []tls.Certificate{keypair}} - c = tls.Server(c, config) - defer c.Close() - return serverHandleTLS(c, t) - default: - t.Fatalf("unrecognized command: %q", s.Text()) - } - } - return s.Err() -} - -func serverHandleTLS(c net.Conn, t *testing.T) error { - send := smtpSender{c}.send - s := bufio.NewScanner(c) - for s.Scan() { - switch s.Text() { - case "EHLO localhost": - send("250 Ok") - case "MAIL FROM:<joe1@example.com>": - send("250 Ok") - case "RCPT TO:<joe2@example.com>": - send("250 Ok") - case "DATA": - send("354 send the mail data, end with .") - send("250 Ok") - case "Subject: test": - case "": - case "howdy!": - case ".": - case "QUIT": - send("221 127.0.0.1 Service closing transmission channel") - return nil - default: - t.Fatalf("unrecognized command during TLS: %q", s.Text()) - } - } - return s.Err() -} - -func init() { - testRootCAs := x509.NewCertPool() - testRootCAs.AppendCertsFromPEM(localhostCert) - testHookStartTLS = func(config *tls.Config) { - config.RootCAs = testRootCAs - } -} - -func sendMail(hostPort string) error { - host, _, err := net.SplitHostPort(hostPort) - if err != nil { - return err - } - auth := PlainAuth("", "", "", host) - from := "joe1@example.com" - to := []string{"joe2@example.com"} - return SendMail(hostPort, auth, from, to, []byte("Subject: test\n\nhowdy!")) -} - -// (copied from net/http/httptest) -// localhostCert is a PEM-encoded TLS cert with SAN IPs -// "127.0.0.1" and "[::1]", expiring at the last second of 2049 (the end -// of ASN.1 time). -// generated from src/pkg/crypto/tls: -// go run generate_cert.go --rsa-bits 512 --host 127.0.0.1,::1,example.com --ca --start-date "Jan 1 00:00:00 1970" --duration=1000000h -var localhostCert = []byte(`-----BEGIN CERTIFICATE----- -MIIBdzCCASOgAwIBAgIBADALBgkqhkiG9w0BAQUwEjEQMA4GA1UEChMHQWNtZSBD -bzAeFw03MDAxMDEwMDAwMDBaFw00OTEyMzEyMzU5NTlaMBIxEDAOBgNVBAoTB0Fj -bWUgQ28wWjALBgkqhkiG9w0BAQEDSwAwSAJBAN55NcYKZeInyTuhcCwFMhDHCmwa -IUSdtXdcbItRB/yfXGBhiex00IaLXQnSU+QZPRZWYqeTEbFSgihqi1PUDy8CAwEA -AaNoMGYwDgYDVR0PAQH/BAQDAgCkMBMGA1UdJQQMMAoGCCsGAQUFBwMBMA8GA1Ud -EwEB/wQFMAMBAf8wLgYDVR0RBCcwJYILZXhhbXBsZS5jb22HBH8AAAGHEAAAAAAA -AAAAAAAAAAAAAAEwCwYJKoZIhvcNAQEFA0EAAoQn/ytgqpiLcZu9XKbCJsJcvkgk -Se6AbGXgSlq+ZCEVo0qIwSgeBqmsJxUu7NCSOwVJLYNEBO2DtIxoYVk+MA== ------END CERTIFICATE-----`) - -// localhostKey is the private key for localhostCert. -var localhostKey = []byte(`-----BEGIN RSA PRIVATE KEY----- -MIIBPAIBAAJBAN55NcYKZeInyTuhcCwFMhDHCmwaIUSdtXdcbItRB/yfXGBhiex0 -0IaLXQnSU+QZPRZWYqeTEbFSgihqi1PUDy8CAwEAAQJBAQdUx66rfh8sYsgfdcvV -NoafYpnEcB5s4m/vSVe6SU7dCK6eYec9f9wpT353ljhDUHq3EbmE4foNzJngh35d -AekCIQDhRQG5Li0Wj8TM4obOnnXUXf1jRv0UkzE9AHWLG5q3AwIhAPzSjpYUDjVW -MCUXgckTpKCuGwbJk7424Nb8bLzf3kllAiA5mUBgjfr/WtFSJdWcPQ4Zt9KTMNKD -EUO0ukpTwEIl6wIhAMbGqZK3zAAFdq8DD2jPx+UJXnh0rnOkZBzDtJ6/iN69AiEA -1Aq8MJgTaYsDQWyU/hDq5YkDJc9e9DSCvUIzqxQWMQE= ------END RSA PRIVATE KEY-----`) |