gitea源码

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107
  1. // Copyright 2021 The Gitea Authors. All rights reserved.
  2. // SPDX-License-Identifier: MIT
  3. package smtp
  4. import (
  5. "crypto/tls"
  6. "errors"
  7. "fmt"
  8. "net"
  9. "net/smtp"
  10. "os"
  11. "strconv"
  12. )
  13. // _________ __________________________
  14. // / _____/ / \__ ___/\______ \
  15. // \_____ \ / \ / \| | | ___/
  16. // / \/ Y \ | | |
  17. // /_______ /\____|__ /____| |____|
  18. // \/ \/
  19. type loginAuthenticator struct {
  20. username, password string
  21. }
  22. func (auth *loginAuthenticator) Start(server *smtp.ServerInfo) (string, []byte, error) {
  23. return "LOGIN", []byte(auth.username), nil
  24. }
  25. func (auth *loginAuthenticator) Next(fromServer []byte, more bool) ([]byte, error) {
  26. if more {
  27. switch string(fromServer) {
  28. case "Username:":
  29. return []byte(auth.username), nil
  30. case "Password:":
  31. return []byte(auth.password), nil
  32. }
  33. }
  34. return nil, nil
  35. }
  36. // SMTP authentication type names.
  37. const (
  38. PlainAuthentication = "PLAIN"
  39. LoginAuthentication = "LOGIN"
  40. CRAMMD5Authentication = "CRAM-MD5"
  41. )
  42. // Authenticators contains available SMTP authentication type names.
  43. var Authenticators = []string{PlainAuthentication, LoginAuthentication, CRAMMD5Authentication}
  44. // ErrUnsupportedLoginType login source is unknown error
  45. var ErrUnsupportedLoginType = errors.New("Login source is unknown")
  46. // Authenticate performs an SMTP authentication.
  47. func Authenticate(a smtp.Auth, source *Source) error {
  48. tlsConfig := &tls.Config{
  49. InsecureSkipVerify: source.SkipVerify,
  50. ServerName: source.Host,
  51. }
  52. conn, err := net.Dial("tcp", net.JoinHostPort(source.Host, strconv.Itoa(source.Port)))
  53. if err != nil {
  54. return err
  55. }
  56. defer conn.Close()
  57. if source.UseTLS() {
  58. conn = tls.Client(conn, tlsConfig)
  59. }
  60. client, err := smtp.NewClient(conn, source.Host)
  61. if err != nil {
  62. return fmt.Errorf("failed to create NewClient: %w", err)
  63. }
  64. defer client.Close()
  65. if !source.DisableHelo {
  66. hostname := source.HeloHostname
  67. if len(hostname) == 0 {
  68. hostname, err = os.Hostname()
  69. if err != nil {
  70. return fmt.Errorf("failed to find Hostname: %w", err)
  71. }
  72. }
  73. if err = client.Hello(hostname); err != nil {
  74. return fmt.Errorf("failed to send Helo: %w", err)
  75. }
  76. }
  77. // If not using SMTPS, always use STARTTLS if available
  78. hasStartTLS, _ := client.Extension("STARTTLS")
  79. if !source.UseTLS() && hasStartTLS {
  80. if err = client.StartTLS(tlsConfig); err != nil {
  81. return fmt.Errorf("failed to start StartTLS: %w", err)
  82. }
  83. }
  84. if ok, _ := client.Extension("AUTH"); ok {
  85. return client.Auth(a)
  86. }
  87. return ErrUnsupportedLoginType
  88. }