2020-12-02 12:56:04 +08:00
// Copyright 2020 The Gitea Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package doctor
import (
"bufio"
"bytes"
2022-01-20 07:26:57 +08:00
"context"
2020-12-02 12:56:04 +08:00
"fmt"
"os"
"path/filepath"
"strings"
2021-12-10 16:14:24 +08:00
asymkey_model "code.gitea.io/gitea/models/asymkey"
2022-10-12 13:18:26 +08:00
"code.gitea.io/gitea/modules/container"
2020-12-02 12:56:04 +08:00
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/setting"
)
const tplCommentPrefix = ` # gitea public key `
2022-01-20 07:26:57 +08:00
func checkAuthorizedKeys ( ctx context . Context , logger log . Logger , autofix bool ) error {
2020-12-02 12:56:04 +08:00
if setting . SSH . StartBuiltinServer || ! setting . SSH . CreateAuthorizedKeysFile {
return nil
}
fPath := filepath . Join ( setting . SSH . RootPath , "authorized_keys" )
f , err := os . Open ( fPath )
if err != nil {
if ! autofix {
logger . Critical ( "Unable to open authorized_keys file. ERROR: %v" , err )
2022-10-25 03:29:17 +08:00
return fmt . Errorf ( "Unable to open authorized_keys file. ERROR: %w" , err )
2020-12-02 12:56:04 +08:00
}
logger . Warn ( "Unable to open authorized_keys. (ERROR: %v). Attempting to rewrite..." , err )
2021-12-10 16:14:24 +08:00
if err = asymkey_model . RewriteAllPublicKeys ( ) ; err != nil {
2020-12-02 12:56:04 +08:00
logger . Critical ( "Unable to rewrite authorized_keys file. ERROR: %v" , err )
2022-10-25 03:29:17 +08:00
return fmt . Errorf ( "Unable to rewrite authorized_keys file. ERROR: %w" , err )
2020-12-02 12:56:04 +08:00
}
}
defer f . Close ( )
2022-10-12 13:18:26 +08:00
linesInAuthorizedKeys := make ( container . Set [ string ] )
2020-12-02 12:56:04 +08:00
scanner := bufio . NewScanner ( f )
for scanner . Scan ( ) {
line := scanner . Text ( )
if strings . HasPrefix ( line , tplCommentPrefix ) {
continue
}
2022-10-12 13:18:26 +08:00
linesInAuthorizedKeys . Add ( line )
2020-12-02 12:56:04 +08:00
}
f . Close ( )
// now we regenerate and check if there are any lines missing
regenerated := & bytes . Buffer { }
2022-05-20 22:08:52 +08:00
if err := asymkey_model . RegeneratePublicKeys ( ctx , regenerated ) ; err != nil {
2020-12-02 12:56:04 +08:00
logger . Critical ( "Unable to regenerate authorized_keys file. ERROR: %v" , err )
2022-10-25 03:29:17 +08:00
return fmt . Errorf ( "Unable to regenerate authorized_keys file. ERROR: %w" , err )
2020-12-02 12:56:04 +08:00
}
scanner = bufio . NewScanner ( regenerated )
for scanner . Scan ( ) {
line := scanner . Text ( )
if strings . HasPrefix ( line , tplCommentPrefix ) {
continue
}
2022-10-12 13:18:26 +08:00
if linesInAuthorizedKeys . Contains ( line ) {
2020-12-02 12:56:04 +08:00
continue
}
if ! autofix {
logger . Critical (
"authorized_keys file %q is out of date.\nRegenerate it with:\n\t\"%s\"\nor\n\t\"%s\"" ,
fPath ,
"gitea admin regenerate keys" ,
2022-04-25 02:06:33 +08:00
"gitea doctor --run authorized-keys --fix" )
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" ` )
2020-12-02 12:56:04 +08:00
}
logger . Warn ( "authorized_keys is out of date. Attempting rewrite..." )
2021-12-10 16:14:24 +08:00
err = asymkey_model . RewriteAllPublicKeys ( )
2020-12-02 12:56:04 +08:00
if err != nil {
logger . Critical ( "Unable to rewrite authorized_keys file. ERROR: %v" , err )
2022-10-25 03:29:17 +08:00
return fmt . Errorf ( "Unable to rewrite authorized_keys file. ERROR: %w" , err )
2020-12-02 12:56:04 +08:00
}
}
return nil
}
func init ( ) {
Register ( & Check {
Title : "Check if OpenSSH authorized_keys file is up-to-date" ,
Name : "authorized-keys" ,
IsDefault : true ,
Run : checkAuthorizedKeys ,
Priority : 4 ,
} )
}