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