gitea源码

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788
  1. // Copyright 2021 The Gitea Authors. All rights reserved.
  2. // SPDX-License-Identifier: MIT
  3. package smtp
  4. import (
  5. "context"
  6. "errors"
  7. "net/smtp"
  8. "net/textproto"
  9. "strings"
  10. auth_model "code.gitea.io/gitea/models/auth"
  11. user_model "code.gitea.io/gitea/models/user"
  12. "code.gitea.io/gitea/modules/optional"
  13. "code.gitea.io/gitea/modules/util"
  14. )
  15. // Authenticate queries if the provided login/password is authenticates against the SMTP server
  16. // Users will be autoregistered as required
  17. func (source *Source) Authenticate(ctx context.Context, user *user_model.User, userName, password string) (*user_model.User, error) {
  18. // Verify allowed domains.
  19. if len(source.AllowedDomains) > 0 {
  20. idx := strings.Index(userName, "@")
  21. if idx == -1 {
  22. return nil, user_model.ErrUserNotExist{Name: userName}
  23. } else if !util.SliceContainsString(strings.Split(source.AllowedDomains, ","), userName[idx+1:], true) {
  24. return nil, user_model.ErrUserNotExist{Name: userName}
  25. }
  26. }
  27. var auth smtp.Auth
  28. switch source.Auth {
  29. case PlainAuthentication:
  30. auth = smtp.PlainAuth("", userName, password, source.Host)
  31. case LoginAuthentication:
  32. auth = &loginAuthenticator{userName, password}
  33. case CRAMMD5Authentication:
  34. auth = smtp.CRAMMD5Auth(userName, password)
  35. default:
  36. return nil, errors.New("unsupported SMTP auth type")
  37. }
  38. if err := Authenticate(auth, source); err != nil {
  39. // Check standard error format first,
  40. // then fallback to worse case.
  41. tperr, ok := err.(*textproto.Error)
  42. if (ok && tperr.Code == 535) ||
  43. strings.Contains(err.Error(), "Username and Password not accepted") {
  44. return nil, user_model.ErrUserNotExist{Name: userName}
  45. }
  46. if (ok && tperr.Code == 534) ||
  47. strings.Contains(err.Error(), "Application-specific password required") {
  48. return nil, user_model.ErrUserNotExist{Name: userName}
  49. }
  50. return nil, err
  51. }
  52. if user != nil {
  53. return user, nil
  54. }
  55. username := userName
  56. idx := strings.Index(userName, "@")
  57. if idx > -1 {
  58. username = userName[:idx]
  59. }
  60. user = &user_model.User{
  61. LowerName: strings.ToLower(username),
  62. Name: strings.ToLower(username),
  63. Email: userName,
  64. Passwd: password,
  65. LoginType: auth_model.SMTP,
  66. LoginSource: source.AuthSource.ID,
  67. LoginName: userName,
  68. }
  69. overwriteDefault := &user_model.CreateUserOverwriteOptions{
  70. IsActive: optional.Some(true),
  71. }
  72. if err := user_model.CreateUser(ctx, user, &user_model.Meta{}, overwriteDefault); err != nil {
  73. return user, err
  74. }
  75. return user, nil
  76. }