github.com/roboticscm/goman@v0.0.0-20210203095141-87c07b4a0a55/src/net/smtp/smtp_test.go (about) 1 // Copyright 2010 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package smtp 6 7 import ( 8 "bufio" 9 "bytes" 10 "crypto/tls" 11 "crypto/x509" 12 "io" 13 "net" 14 "net/textproto" 15 "strings" 16 "testing" 17 "time" 18 ) 19 20 type authTest struct { 21 auth Auth 22 challenges []string 23 name string 24 responses []string 25 } 26 27 var authTests = []authTest{ 28 {PlainAuth("", "user", "pass", "testserver"), []string{}, "PLAIN", []string{"\x00user\x00pass"}}, 29 {PlainAuth("foo", "bar", "baz", "testserver"), []string{}, "PLAIN", []string{"foo\x00bar\x00baz"}}, 30 {CRAMMD5Auth("user", "pass"), []string{"<123456.1322876914@testserver>"}, "CRAM-MD5", []string{"", "user 287eb355114cf5c471c26a875f1ca4ae"}}, 31 } 32 33 func TestAuth(t *testing.T) { 34 testLoop: 35 for i, test := range authTests { 36 name, resp, err := test.auth.Start(&ServerInfo{"testserver", true, nil}) 37 if name != test.name { 38 t.Errorf("#%d got name %s, expected %s", i, name, test.name) 39 } 40 if !bytes.Equal(resp, []byte(test.responses[0])) { 41 t.Errorf("#%d got response %s, expected %s", i, resp, test.responses[0]) 42 } 43 if err != nil { 44 t.Errorf("#%d error: %s", i, err) 45 } 46 for j := range test.challenges { 47 challenge := []byte(test.challenges[j]) 48 expected := []byte(test.responses[j+1]) 49 resp, err := test.auth.Next(challenge, true) 50 if err != nil { 51 t.Errorf("#%d error: %s", i, err) 52 continue testLoop 53 } 54 if !bytes.Equal(resp, expected) { 55 t.Errorf("#%d got %s, expected %s", i, resp, expected) 56 continue testLoop 57 } 58 } 59 } 60 } 61 62 func TestAuthPlain(t *testing.T) { 63 auth := PlainAuth("foo", "bar", "baz", "servername") 64 65 tests := []struct { 66 server *ServerInfo 67 err string 68 }{ 69 { 70 server: &ServerInfo{Name: "servername", TLS: true}, 71 }, 72 { 73 // Okay; explicitly advertised by server. 74 server: &ServerInfo{Name: "servername", Auth: []string{"PLAIN"}}, 75 }, 76 { 77 server: &ServerInfo{Name: "servername", Auth: []string{"CRAM-MD5"}}, 78 err: "unencrypted connection", 79 }, 80 { 81 server: &ServerInfo{Name: "attacker", TLS: true}, 82 err: "wrong host name", 83 }, 84 } 85 for i, tt := range tests { 86 _, _, err := auth.Start(tt.server) 87 got := "" 88 if err != nil { 89 got = err.Error() 90 } 91 if got != tt.err { 92 t.Errorf("%d. got error = %q; want %q", i, got, tt.err) 93 } 94 } 95 } 96 97 type faker struct { 98 io.ReadWriter 99 } 100 101 func (f faker) Close() error { return nil } 102 func (f faker) LocalAddr() net.Addr { return nil } 103 func (f faker) RemoteAddr() net.Addr { return nil } 104 func (f faker) SetDeadline(time.Time) error { return nil } 105 func (f faker) SetReadDeadline(time.Time) error { return nil } 106 func (f faker) SetWriteDeadline(time.Time) error { return nil } 107 108 func TestBasic(t *testing.T) { 109 server := strings.Join(strings.Split(basicServer, "\n"), "\r\n") 110 client := strings.Join(strings.Split(basicClient, "\n"), "\r\n") 111 112 var cmdbuf bytes.Buffer 113 bcmdbuf := bufio.NewWriter(&cmdbuf) 114 var fake faker 115 fake.ReadWriter = bufio.NewReadWriter(bufio.NewReader(strings.NewReader(server)), bcmdbuf) 116 c := &Client{Text: textproto.NewConn(fake), localName: "localhost"} 117 118 if err := c.helo(); err != nil { 119 t.Fatalf("HELO failed: %s", err) 120 } 121 if err := c.ehlo(); err == nil { 122 t.Fatalf("Expected first EHLO to fail") 123 } 124 if err := c.ehlo(); err != nil { 125 t.Fatalf("Second EHLO failed: %s", err) 126 } 127 128 c.didHello = true 129 if ok, args := c.Extension("aUtH"); !ok || args != "LOGIN PLAIN" { 130 t.Fatalf("Expected AUTH supported") 131 } 132 if ok, _ := c.Extension("DSN"); ok { 133 t.Fatalf("Shouldn't support DSN") 134 } 135 136 if err := c.Mail("user@gmail.com"); err == nil { 137 t.Fatalf("MAIL should require authentication") 138 } 139 140 if err := c.Verify("user1@gmail.com"); err == nil { 141 t.Fatalf("First VRFY: expected no verification") 142 } 143 if err := c.Verify("user2@gmail.com"); err != nil { 144 t.Fatalf("Second VRFY: expected verification, got %s", err) 145 } 146 147 // fake TLS so authentication won't complain 148 c.tls = true 149 c.serverName = "smtp.google.com" 150 if err := c.Auth(PlainAuth("", "user", "pass", "smtp.google.com")); err != nil { 151 t.Fatalf("AUTH failed: %s", err) 152 } 153 154 if err := c.Mail("user@gmail.com"); err != nil { 155 t.Fatalf("MAIL failed: %s", err) 156 } 157 if err := c.Rcpt("golang-nuts@googlegroups.com"); err != nil { 158 t.Fatalf("RCPT failed: %s", err) 159 } 160 msg := `From: user@gmail.com 161 To: golang-nuts@googlegroups.com 162 Subject: Hooray for Go 163 164 Line 1 165 .Leading dot line . 166 Goodbye.` 167 w, err := c.Data() 168 if err != nil { 169 t.Fatalf("DATA failed: %s", err) 170 } 171 if _, err := w.Write([]byte(msg)); err != nil { 172 t.Fatalf("Data write failed: %s", err) 173 } 174 if err := w.Close(); err != nil { 175 t.Fatalf("Bad data response: %s", err) 176 } 177 178 if err := c.Quit(); err != nil { 179 t.Fatalf("QUIT failed: %s", err) 180 } 181 182 bcmdbuf.Flush() 183 actualcmds := cmdbuf.String() 184 if client != actualcmds { 185 t.Fatalf("Got:\n%s\nExpected:\n%s", actualcmds, client) 186 } 187 } 188 189 var basicServer = `250 mx.google.com at your service 190 502 Unrecognized command. 191 250-mx.google.com at your service 192 250-SIZE 35651584 193 250-AUTH LOGIN PLAIN 194 250 8BITMIME 195 530 Authentication required 196 252 Send some mail, I'll try my best 197 250 User is valid 198 235 Accepted 199 250 Sender OK 200 250 Receiver OK 201 354 Go ahead 202 250 Data OK 203 221 OK 204 ` 205 206 var basicClient = `HELO localhost 207 EHLO localhost 208 EHLO localhost 209 MAIL FROM:<user@gmail.com> BODY=8BITMIME 210 VRFY user1@gmail.com 211 VRFY user2@gmail.com 212 AUTH PLAIN AHVzZXIAcGFzcw== 213 MAIL FROM:<user@gmail.com> BODY=8BITMIME 214 RCPT TO:<golang-nuts@googlegroups.com> 215 DATA 216 From: user@gmail.com 217 To: golang-nuts@googlegroups.com 218 Subject: Hooray for Go 219 220 Line 1 221 ..Leading dot line . 222 Goodbye. 223 . 224 QUIT 225 ` 226 227 func TestNewClient(t *testing.T) { 228 server := strings.Join(strings.Split(newClientServer, "\n"), "\r\n") 229 client := strings.Join(strings.Split(newClientClient, "\n"), "\r\n") 230 231 var cmdbuf bytes.Buffer 232 bcmdbuf := bufio.NewWriter(&cmdbuf) 233 out := func() string { 234 bcmdbuf.Flush() 235 return cmdbuf.String() 236 } 237 var fake faker 238 fake.ReadWriter = bufio.NewReadWriter(bufio.NewReader(strings.NewReader(server)), bcmdbuf) 239 c, err := NewClient(fake, "fake.host") 240 if err != nil { 241 t.Fatalf("NewClient: %v\n(after %v)", err, out()) 242 } 243 defer c.Close() 244 if ok, args := c.Extension("aUtH"); !ok || args != "LOGIN PLAIN" { 245 t.Fatalf("Expected AUTH supported") 246 } 247 if ok, _ := c.Extension("DSN"); ok { 248 t.Fatalf("Shouldn't support DSN") 249 } 250 if err := c.Quit(); err != nil { 251 t.Fatalf("QUIT failed: %s", err) 252 } 253 254 actualcmds := out() 255 if client != actualcmds { 256 t.Fatalf("Got:\n%s\nExpected:\n%s", actualcmds, client) 257 } 258 } 259 260 var newClientServer = `220 hello world 261 250-mx.google.com at your service 262 250-SIZE 35651584 263 250-AUTH LOGIN PLAIN 264 250 8BITMIME 265 221 OK 266 ` 267 268 var newClientClient = `EHLO localhost 269 QUIT 270 ` 271 272 func TestNewClient2(t *testing.T) { 273 server := strings.Join(strings.Split(newClient2Server, "\n"), "\r\n") 274 client := strings.Join(strings.Split(newClient2Client, "\n"), "\r\n") 275 276 var cmdbuf bytes.Buffer 277 bcmdbuf := bufio.NewWriter(&cmdbuf) 278 var fake faker 279 fake.ReadWriter = bufio.NewReadWriter(bufio.NewReader(strings.NewReader(server)), bcmdbuf) 280 c, err := NewClient(fake, "fake.host") 281 if err != nil { 282 t.Fatalf("NewClient: %v", err) 283 } 284 defer c.Close() 285 if ok, _ := c.Extension("DSN"); ok { 286 t.Fatalf("Shouldn't support DSN") 287 } 288 if err := c.Quit(); err != nil { 289 t.Fatalf("QUIT failed: %s", err) 290 } 291 292 bcmdbuf.Flush() 293 actualcmds := cmdbuf.String() 294 if client != actualcmds { 295 t.Fatalf("Got:\n%s\nExpected:\n%s", actualcmds, client) 296 } 297 } 298 299 var newClient2Server = `220 hello world 300 502 EH? 301 250-mx.google.com at your service 302 250-SIZE 35651584 303 250-AUTH LOGIN PLAIN 304 250 8BITMIME 305 221 OK 306 ` 307 308 var newClient2Client = `EHLO localhost 309 HELO localhost 310 QUIT 311 ` 312 313 func TestHello(t *testing.T) { 314 315 if len(helloServer) != len(helloClient) { 316 t.Fatalf("Hello server and client size mismatch") 317 } 318 319 for i := 0; i < len(helloServer); i++ { 320 server := strings.Join(strings.Split(baseHelloServer+helloServer[i], "\n"), "\r\n") 321 client := strings.Join(strings.Split(baseHelloClient+helloClient[i], "\n"), "\r\n") 322 var cmdbuf bytes.Buffer 323 bcmdbuf := bufio.NewWriter(&cmdbuf) 324 var fake faker 325 fake.ReadWriter = bufio.NewReadWriter(bufio.NewReader(strings.NewReader(server)), bcmdbuf) 326 c, err := NewClient(fake, "fake.host") 327 if err != nil { 328 t.Fatalf("NewClient: %v", err) 329 } 330 defer c.Close() 331 c.localName = "customhost" 332 err = nil 333 334 switch i { 335 case 0: 336 err = c.Hello("customhost") 337 case 1: 338 err = c.StartTLS(nil) 339 if err.Error() == "502 Not implemented" { 340 err = nil 341 } 342 case 2: 343 err = c.Verify("test@example.com") 344 case 3: 345 c.tls = true 346 c.serverName = "smtp.google.com" 347 err = c.Auth(PlainAuth("", "user", "pass", "smtp.google.com")) 348 case 4: 349 err = c.Mail("test@example.com") 350 case 5: 351 ok, _ := c.Extension("feature") 352 if ok { 353 t.Errorf("Expected FEATURE not to be supported") 354 } 355 case 6: 356 err = c.Reset() 357 case 7: 358 err = c.Quit() 359 case 8: 360 err = c.Verify("test@example.com") 361 if err != nil { 362 err = c.Hello("customhost") 363 if err != nil { 364 t.Errorf("Want error, got none") 365 } 366 } 367 default: 368 t.Fatalf("Unhandled command") 369 } 370 371 if err != nil { 372 t.Errorf("Command %d failed: %v", i, err) 373 } 374 375 bcmdbuf.Flush() 376 actualcmds := cmdbuf.String() 377 if client != actualcmds { 378 t.Errorf("Got:\n%s\nExpected:\n%s", actualcmds, client) 379 } 380 } 381 } 382 383 var baseHelloServer = `220 hello world 384 502 EH? 385 250-mx.google.com at your service 386 250 FEATURE 387 ` 388 389 var helloServer = []string{ 390 "", 391 "502 Not implemented\n", 392 "250 User is valid\n", 393 "235 Accepted\n", 394 "250 Sender ok\n", 395 "", 396 "250 Reset ok\n", 397 "221 Goodbye\n", 398 "250 Sender ok\n", 399 } 400 401 var baseHelloClient = `EHLO customhost 402 HELO customhost 403 ` 404 405 var helloClient = []string{ 406 "", 407 "STARTTLS\n", 408 "VRFY test@example.com\n", 409 "AUTH PLAIN AHVzZXIAcGFzcw==\n", 410 "MAIL FROM:<test@example.com>\n", 411 "", 412 "RSET\n", 413 "QUIT\n", 414 "VRFY test@example.com\n", 415 } 416 417 func TestSendMail(t *testing.T) { 418 server := strings.Join(strings.Split(sendMailServer, "\n"), "\r\n") 419 client := strings.Join(strings.Split(sendMailClient, "\n"), "\r\n") 420 var cmdbuf bytes.Buffer 421 bcmdbuf := bufio.NewWriter(&cmdbuf) 422 l, err := net.Listen("tcp", "127.0.0.1:0") 423 if err != nil { 424 t.Fatalf("Unable to to create listener: %v", err) 425 } 426 defer l.Close() 427 428 // prevent data race on bcmdbuf 429 var done = make(chan struct{}) 430 go func(data []string) { 431 432 defer close(done) 433 434 conn, err := l.Accept() 435 if err != nil { 436 t.Errorf("Accept error: %v", err) 437 return 438 } 439 defer conn.Close() 440 441 tc := textproto.NewConn(conn) 442 for i := 0; i < len(data) && data[i] != ""; i++ { 443 tc.PrintfLine(data[i]) 444 for len(data[i]) >= 4 && data[i][3] == '-' { 445 i++ 446 tc.PrintfLine(data[i]) 447 } 448 if data[i] == "221 Goodbye" { 449 return 450 } 451 read := false 452 for !read || data[i] == "354 Go ahead" { 453 msg, err := tc.ReadLine() 454 bcmdbuf.Write([]byte(msg + "\r\n")) 455 read = true 456 if err != nil { 457 t.Errorf("Read error: %v", err) 458 return 459 } 460 if data[i] == "354 Go ahead" && msg == "." { 461 break 462 } 463 } 464 } 465 }(strings.Split(server, "\r\n")) 466 467 err = SendMail(l.Addr().String(), nil, "test@example.com", []string{"other@example.com"}, []byte(strings.Replace(`From: test@example.com 468 To: other@example.com 469 Subject: SendMail test 470 471 SendMail is working for me. 472 `, "\n", "\r\n", -1))) 473 474 if err != nil { 475 t.Errorf("%v", err) 476 } 477 478 <-done 479 bcmdbuf.Flush() 480 actualcmds := cmdbuf.String() 481 if client != actualcmds { 482 t.Errorf("Got:\n%s\nExpected:\n%s", actualcmds, client) 483 } 484 } 485 486 var sendMailServer = `220 hello world 487 502 EH? 488 250 mx.google.com at your service 489 250 Sender ok 490 250 Receiver ok 491 354 Go ahead 492 250 Data ok 493 221 Goodbye 494 ` 495 496 var sendMailClient = `EHLO localhost 497 HELO localhost 498 MAIL FROM:<test@example.com> 499 RCPT TO:<other@example.com> 500 DATA 501 From: test@example.com 502 To: other@example.com 503 Subject: SendMail test 504 505 SendMail is working for me. 506 . 507 QUIT 508 ` 509 510 func TestAuthFailed(t *testing.T) { 511 server := strings.Join(strings.Split(authFailedServer, "\n"), "\r\n") 512 client := strings.Join(strings.Split(authFailedClient, "\n"), "\r\n") 513 var cmdbuf bytes.Buffer 514 bcmdbuf := bufio.NewWriter(&cmdbuf) 515 var fake faker 516 fake.ReadWriter = bufio.NewReadWriter(bufio.NewReader(strings.NewReader(server)), bcmdbuf) 517 c, err := NewClient(fake, "fake.host") 518 if err != nil { 519 t.Fatalf("NewClient: %v", err) 520 } 521 defer c.Close() 522 523 c.tls = true 524 c.serverName = "smtp.google.com" 525 err = c.Auth(PlainAuth("", "user", "pass", "smtp.google.com")) 526 527 if err == nil { 528 t.Error("Auth: expected error; got none") 529 } else if err.Error() != "535 Invalid credentials\nplease see www.example.com" { 530 t.Errorf("Auth: got error: %v, want: %s", err, "535 Invalid credentials\nplease see www.example.com") 531 } 532 533 bcmdbuf.Flush() 534 actualcmds := cmdbuf.String() 535 if client != actualcmds { 536 t.Errorf("Got:\n%s\nExpected:\n%s", actualcmds, client) 537 } 538 } 539 540 var authFailedServer = `220 hello world 541 250-mx.google.com at your service 542 250 AUTH LOGIN PLAIN 543 535-Invalid credentials 544 535 please see www.example.com 545 221 Goodbye 546 ` 547 548 var authFailedClient = `EHLO localhost 549 AUTH PLAIN AHVzZXIAcGFzcw== 550 * 551 QUIT 552 ` 553 554 func TestTLSClient(t *testing.T) { 555 ln := newLocalListener(t) 556 defer ln.Close() 557 errc := make(chan error) 558 go func() { 559 errc <- sendMail(ln.Addr().String()) 560 }() 561 conn, err := ln.Accept() 562 if err != nil { 563 t.Fatalf("failed to accept connection: %v", err) 564 } 565 defer conn.Close() 566 if err := serverHandle(conn, t); err != nil { 567 t.Fatalf("failed to handle connection: %v", err) 568 } 569 if err := <-errc; err != nil { 570 t.Fatalf("client error: %v", err) 571 } 572 } 573 574 func newLocalListener(t *testing.T) net.Listener { 575 ln, err := net.Listen("tcp", "127.0.0.1:0") 576 if err != nil { 577 ln, err = net.Listen("tcp6", "[::1]:0") 578 } 579 if err != nil { 580 t.Fatal(err) 581 } 582 return ln 583 } 584 585 type smtpSender struct { 586 w io.Writer 587 } 588 589 func (s smtpSender) send(f string) { 590 s.w.Write([]byte(f + "\r\n")) 591 } 592 593 // smtp server, finely tailored to deal with our own client only! 594 func serverHandle(c net.Conn, t *testing.T) error { 595 send := smtpSender{c}.send 596 send("220 127.0.0.1 ESMTP service ready") 597 s := bufio.NewScanner(c) 598 for s.Scan() { 599 switch s.Text() { 600 case "EHLO localhost": 601 send("250-127.0.0.1 ESMTP offers a warm hug of welcome") 602 send("250-STARTTLS") 603 send("250 Ok") 604 case "STARTTLS": 605 send("220 Go ahead") 606 keypair, err := tls.X509KeyPair(localhostCert, localhostKey) 607 if err != nil { 608 return err 609 } 610 config := &tls.Config{Certificates: []tls.Certificate{keypair}} 611 c = tls.Server(c, config) 612 defer c.Close() 613 return serverHandleTLS(c, t) 614 default: 615 t.Fatalf("unrecognized command: %q", s.Text()) 616 } 617 } 618 return s.Err() 619 } 620 621 func serverHandleTLS(c net.Conn, t *testing.T) error { 622 send := smtpSender{c}.send 623 s := bufio.NewScanner(c) 624 for s.Scan() { 625 switch s.Text() { 626 case "EHLO localhost": 627 send("250 Ok") 628 case "MAIL FROM:<joe1@example.com>": 629 send("250 Ok") 630 case "RCPT TO:<joe2@example.com>": 631 send("250 Ok") 632 case "DATA": 633 send("354 send the mail data, end with .") 634 send("250 Ok") 635 case "Subject: test": 636 case "": 637 case "howdy!": 638 case ".": 639 case "QUIT": 640 send("221 127.0.0.1 Service closing transmission channel") 641 return nil 642 default: 643 t.Fatalf("unrecognized command during TLS: %q", s.Text()) 644 } 645 } 646 return s.Err() 647 } 648 649 func init() { 650 testRootCAs := x509.NewCertPool() 651 testRootCAs.AppendCertsFromPEM(localhostCert) 652 testHookStartTLS = func(config *tls.Config) { 653 config.RootCAs = testRootCAs 654 } 655 } 656 657 func sendMail(hostPort string) error { 658 host, _, err := net.SplitHostPort(hostPort) 659 if err != nil { 660 return err 661 } 662 auth := PlainAuth("", "", "", host) 663 from := "joe1@example.com" 664 to := []string{"joe2@example.com"} 665 return SendMail(hostPort, auth, from, to, []byte("Subject: test\n\nhowdy!")) 666 } 667 668 // (copied from net/http/httptest) 669 // localhostCert is a PEM-encoded TLS cert with SAN IPs 670 // "127.0.0.1" and "[::1]", expiring at the last second of 2049 (the end 671 // of ASN.1 time). 672 // generated from src/crypto/tls: 673 // 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 674 var localhostCert = []byte(`-----BEGIN CERTIFICATE----- 675 MIIBdzCCASOgAwIBAgIBADALBgkqhkiG9w0BAQUwEjEQMA4GA1UEChMHQWNtZSBD 676 bzAeFw03MDAxMDEwMDAwMDBaFw00OTEyMzEyMzU5NTlaMBIxEDAOBgNVBAoTB0Fj 677 bWUgQ28wWjALBgkqhkiG9w0BAQEDSwAwSAJBAN55NcYKZeInyTuhcCwFMhDHCmwa 678 IUSdtXdcbItRB/yfXGBhiex00IaLXQnSU+QZPRZWYqeTEbFSgihqi1PUDy8CAwEA 679 AaNoMGYwDgYDVR0PAQH/BAQDAgCkMBMGA1UdJQQMMAoGCCsGAQUFBwMBMA8GA1Ud 680 EwEB/wQFMAMBAf8wLgYDVR0RBCcwJYILZXhhbXBsZS5jb22HBH8AAAGHEAAAAAAA 681 AAAAAAAAAAAAAAEwCwYJKoZIhvcNAQEFA0EAAoQn/ytgqpiLcZu9XKbCJsJcvkgk 682 Se6AbGXgSlq+ZCEVo0qIwSgeBqmsJxUu7NCSOwVJLYNEBO2DtIxoYVk+MA== 683 -----END CERTIFICATE-----`) 684 685 // localhostKey is the private key for localhostCert. 686 var localhostKey = []byte(`-----BEGIN RSA PRIVATE KEY----- 687 MIIBPAIBAAJBAN55NcYKZeInyTuhcCwFMhDHCmwaIUSdtXdcbItRB/yfXGBhiex0 688 0IaLXQnSU+QZPRZWYqeTEbFSgihqi1PUDy8CAwEAAQJBAQdUx66rfh8sYsgfdcvV 689 NoafYpnEcB5s4m/vSVe6SU7dCK6eYec9f9wpT353ljhDUHq3EbmE4foNzJngh35d 690 AekCIQDhRQG5Li0Wj8TM4obOnnXUXf1jRv0UkzE9AHWLG5q3AwIhAPzSjpYUDjVW 691 MCUXgckTpKCuGwbJk7424Nb8bLzf3kllAiA5mUBgjfr/WtFSJdWcPQ4Zt9KTMNKD 692 EUO0ukpTwEIl6wIhAMbGqZK3zAAFdq8DD2jPx+UJXnh0rnOkZBzDtJ6/iN69AiEA 693 1Aq8MJgTaYsDQWyU/hDq5YkDJc9e9DSCvUIzqxQWMQE= 694 -----END RSA PRIVATE KEY-----`)