gitea源码

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103
  1. // Copyright 2020 The Gitea Authors. All rights reserved.
  2. // SPDX-License-Identifier: MIT
  3. package doctor
  4. import (
  5. "bufio"
  6. "bytes"
  7. "context"
  8. "errors"
  9. "fmt"
  10. "os"
  11. "path/filepath"
  12. "strings"
  13. asymkey_model "code.gitea.io/gitea/models/asymkey"
  14. "code.gitea.io/gitea/modules/container"
  15. "code.gitea.io/gitea/modules/log"
  16. "code.gitea.io/gitea/modules/setting"
  17. asymkey_service "code.gitea.io/gitea/services/asymkey"
  18. )
  19. const tplCommentPrefix = `# gitea public key`
  20. func checkAuthorizedKeys(ctx context.Context, logger log.Logger, autofix bool) error {
  21. if setting.SSH.StartBuiltinServer || !setting.SSH.CreateAuthorizedKeysFile {
  22. return nil
  23. }
  24. fPath := filepath.Join(setting.SSH.RootPath, "authorized_keys")
  25. f, err := os.Open(fPath)
  26. if err != nil {
  27. if !autofix {
  28. logger.Critical("Unable to open authorized_keys file. ERROR: %v", err)
  29. return fmt.Errorf("Unable to open authorized_keys file. ERROR: %w", err)
  30. }
  31. logger.Warn("Unable to open authorized_keys. (ERROR: %v). Attempting to rewrite...", err)
  32. if err = asymkey_service.RewriteAllPublicKeys(ctx); err != nil {
  33. logger.Critical("Unable to rewrite authorized_keys file. ERROR: %v", err)
  34. return fmt.Errorf("Unable to rewrite authorized_keys file. ERROR: %w", err)
  35. }
  36. }
  37. defer f.Close()
  38. linesInAuthorizedKeys := make(container.Set[string])
  39. scanner := bufio.NewScanner(f)
  40. for scanner.Scan() {
  41. line := scanner.Text()
  42. if strings.HasPrefix(line, tplCommentPrefix) {
  43. continue
  44. }
  45. linesInAuthorizedKeys.Add(line)
  46. }
  47. if err = scanner.Err(); err != nil {
  48. return fmt.Errorf("scan: %w", err)
  49. }
  50. // although there is a "defer close" above, here close explicitly before the generating, because it needs to open the file for writing again
  51. _ = f.Close()
  52. // now we regenerate and check if there are any lines missing
  53. regenerated := &bytes.Buffer{}
  54. if err := asymkey_model.RegeneratePublicKeys(ctx, regenerated); err != nil {
  55. logger.Critical("Unable to regenerate authorized_keys file. ERROR: %v", err)
  56. return fmt.Errorf("Unable to regenerate authorized_keys file. ERROR: %w", err)
  57. }
  58. scanner = bufio.NewScanner(regenerated)
  59. for scanner.Scan() {
  60. line := scanner.Text()
  61. if strings.HasPrefix(line, tplCommentPrefix) {
  62. continue
  63. }
  64. if linesInAuthorizedKeys.Contains(line) {
  65. continue
  66. }
  67. if !autofix {
  68. logger.Critical(
  69. "authorized_keys file %q is out of date.\nRegenerate it with:\n\t\"%s\"\nor\n\t\"%s\"",
  70. fPath,
  71. "gitea admin regenerate keys",
  72. "gitea doctor --run authorized-keys --fix")
  73. return errors.New(`authorized_keys is out of date and should be regenerated with "gitea admin regenerate keys" or "gitea doctor --run authorized-keys --fix"`)
  74. }
  75. logger.Warn("authorized_keys is out of date. Attempting rewrite...")
  76. err = asymkey_service.RewriteAllPublicKeys(ctx)
  77. if err != nil {
  78. logger.Critical("Unable to rewrite authorized_keys file. ERROR: %v", err)
  79. return fmt.Errorf("Unable to rewrite authorized_keys file. ERROR: %w", err)
  80. }
  81. }
  82. return nil
  83. }
  84. func init() {
  85. Register(&Check{
  86. Title: "Check if OpenSSH authorized_keys file is up-to-date",
  87. Name: "authorized-keys",
  88. IsDefault: true,
  89. Run: checkAuthorizedKeys,
  90. Priority: 4,
  91. })
  92. }