mirror of
https://github.com/go-gitea/gitea
synced 2025-07-22 18:28:37 +00:00
Uniform all temporary directories and allow customizing temp path (#32352)
This PR uniform all temporary directory usage so that it will be easier to manage. Relate to #31792 - [x] Added a new setting to allow users to configure the global temporary directory. - [x] Move all temporary files and directories to be placed under os.Temp()/gitea. - [x] `setting.Repository.Local.LocalCopyPath` now will be `setting.TempPath/local-repo` and the customized path is removed. ```diff -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;[repository.local] -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; -;; Path for local repository copy. Defaults to TEMP_PATH + `local-repo`, this is deprecated and cannot be changed -;LOCAL_COPY_PATH = local-repo ``` - [x] `setting.Repository.Upload.TempPath` now will be `settting.TempPath/uploads` and the customized path is removed. ```diff ;[repository.upload] -;; -;; Path for uploads. Defaults to TEMP_PATH + `uploads` -;TEMP_PATH = uploads ``` - [x] `setting.Packages.ChunkedUploadPath` now will be `settting.TempPath/package-upload` and the customized path is removed. ```diff ;[packages] -;; -;; Path for chunked uploads. Defaults it's `package-upload` under `TEMP_PATH` unless it's an absolute path. -;CHUNKED_UPLOAD_PATH = package-upload ``` - [x] `setting.SSH.KeyTestPath` now will be `settting.TempPath/ssh_key_test` and the customized path is removed. ```diff [server] -;; -;; Directory to create temporary files in when testing public keys using ssh-keygen, -;; default is the system temporary directory. -;SSH_KEY_TEST_PATH = ``` TODO: - [ ] setting.PprofDataPath haven't been changed because it may need to be kept until somebody read it but temp path may be clean up any time. --------- Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
This commit is contained in:
@@ -6,27 +6,13 @@ package asymkey
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"code.gitea.io/gitea/models/db"
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
"code.gitea.io/gitea/modules/process"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
"code.gitea.io/gitea/modules/util"
|
||||
|
||||
"golang.org/x/crypto/ssh"
|
||||
"xorm.io/builder"
|
||||
)
|
||||
|
||||
// ___________.__ .__ __
|
||||
// \_ _____/|__| ____ ____ ________________________|__| _____/ |_
|
||||
// | __) | |/ \ / ___\_/ __ \_ __ \____ \_ __ \ |/ \ __\
|
||||
// | \ | | | \/ /_/ > ___/| | \/ |_> > | \/ | | \ |
|
||||
// \___ / |__|___| /\___ / \___ >__| | __/|__| |__|___| /__|
|
||||
// \/ \//_____/ \/ |__| \/
|
||||
//
|
||||
// This file contains functions for fingerprinting SSH keys
|
||||
//
|
||||
// The database is used in checkKeyFingerprint however most of these functions probably belong in a module
|
||||
|
||||
// checkKeyFingerprint only checks if key fingerprint has been used as public key,
|
||||
@@ -41,29 +27,6 @@ func checkKeyFingerprint(ctx context.Context, fingerprint string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func calcFingerprintSSHKeygen(publicKeyContent string) (string, error) {
|
||||
// Calculate fingerprint.
|
||||
tmpPath, err := writeTmpKeyFile(publicKeyContent)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
defer func() {
|
||||
if err := util.Remove(tmpPath); err != nil {
|
||||
log.Warn("Unable to remove temporary key file: %s: Error: %v", tmpPath, err)
|
||||
}
|
||||
}()
|
||||
stdout, stderr, err := process.GetManager().Exec("AddPublicKey", "ssh-keygen", "-lf", tmpPath)
|
||||
if err != nil {
|
||||
if strings.Contains(stderr, "is not a public key file") {
|
||||
return "", ErrKeyUnableVerify{stderr}
|
||||
}
|
||||
return "", util.NewInvalidArgumentErrorf("'ssh-keygen -lf %s' failed with error '%s': %s", tmpPath, err, stderr)
|
||||
} else if len(stdout) < 2 {
|
||||
return "", util.NewInvalidArgumentErrorf("not enough output for calculating fingerprint: %s", stdout)
|
||||
}
|
||||
return strings.Split(stdout, " ")[1], nil
|
||||
}
|
||||
|
||||
func calcFingerprintNative(publicKeyContent string) (string, error) {
|
||||
// Calculate fingerprint.
|
||||
pk, _, _, _, err := ssh.ParseAuthorizedKey([]byte(publicKeyContent))
|
||||
@@ -75,15 +38,12 @@ func calcFingerprintNative(publicKeyContent string) (string, error) {
|
||||
|
||||
// CalcFingerprint calculate public key's fingerprint
|
||||
func CalcFingerprint(publicKeyContent string) (string, error) {
|
||||
// Call the method based on configuration
|
||||
useNative := setting.SSH.KeygenPath == ""
|
||||
calcFn := util.Iif(useNative, calcFingerprintNative, calcFingerprintSSHKeygen)
|
||||
fp, err := calcFn(publicKeyContent)
|
||||
fp, err := calcFingerprintNative(publicKeyContent)
|
||||
if err != nil {
|
||||
if IsErrKeyUnableVerify(err) {
|
||||
return "", err
|
||||
}
|
||||
return "", fmt.Errorf("CalcFingerprint(%s): %w", util.Iif(useNative, "native", "ssh-keygen"), err)
|
||||
return "", fmt.Errorf("CalcFingerprint: %w", err)
|
||||
}
|
||||
return fp, nil
|
||||
}
|
||||
|
@@ -13,12 +13,9 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"math/big"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
"code.gitea.io/gitea/modules/process"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
"code.gitea.io/gitea/modules/util"
|
||||
|
||||
@@ -175,20 +172,9 @@ func CheckPublicKeyString(content string) (_ string, err error) {
|
||||
return content, nil
|
||||
}
|
||||
|
||||
var (
|
||||
fnName string
|
||||
keyType string
|
||||
length int
|
||||
)
|
||||
if len(setting.SSH.KeygenPath) == 0 {
|
||||
fnName = "SSHNativeParsePublicKey"
|
||||
keyType, length, err = SSHNativeParsePublicKey(content)
|
||||
} else {
|
||||
fnName = "SSHKeyGenParsePublicKey"
|
||||
keyType, length, err = SSHKeyGenParsePublicKey(content)
|
||||
}
|
||||
keyType, length, err := SSHNativeParsePublicKey(content)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("%s: %w", fnName, err)
|
||||
return "", fmt.Errorf("SSHNativeParsePublicKey: %w", err)
|
||||
}
|
||||
log.Trace("Key info [native: %v]: %s-%d", setting.SSH.StartBuiltinServer, keyType, length)
|
||||
|
||||
@@ -258,56 +244,3 @@ func SSHNativeParsePublicKey(keyLine string) (string, int, error) {
|
||||
}
|
||||
return "", 0, fmt.Errorf("unsupported key length detection for type: %s", pkey.Type())
|
||||
}
|
||||
|
||||
// writeTmpKeyFile writes key content to a temporary file
|
||||
// and returns the name of that file, along with any possible errors.
|
||||
func writeTmpKeyFile(content string) (string, error) {
|
||||
tmpFile, err := os.CreateTemp(setting.SSH.KeyTestPath, "gitea_keytest")
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("TempFile: %w", err)
|
||||
}
|
||||
defer tmpFile.Close()
|
||||
|
||||
if _, err = tmpFile.WriteString(content); err != nil {
|
||||
return "", fmt.Errorf("WriteString: %w", err)
|
||||
}
|
||||
return tmpFile.Name(), nil
|
||||
}
|
||||
|
||||
// SSHKeyGenParsePublicKey extracts key type and length using ssh-keygen.
|
||||
func SSHKeyGenParsePublicKey(key string) (string, int, error) {
|
||||
tmpName, err := writeTmpKeyFile(key)
|
||||
if err != nil {
|
||||
return "", 0, fmt.Errorf("writeTmpKeyFile: %w", err)
|
||||
}
|
||||
defer func() {
|
||||
if err := util.Remove(tmpName); err != nil {
|
||||
log.Warn("Unable to remove temporary key file: %s: Error: %v", tmpName, err)
|
||||
}
|
||||
}()
|
||||
|
||||
keygenPath := setting.SSH.KeygenPath
|
||||
if len(keygenPath) == 0 {
|
||||
keygenPath = "ssh-keygen"
|
||||
}
|
||||
|
||||
stdout, stderr, err := process.GetManager().Exec("SSHKeyGenParsePublicKey", keygenPath, "-lf", tmpName)
|
||||
if err != nil {
|
||||
return "", 0, fmt.Errorf("fail to parse public key: %s - %s", err, stderr)
|
||||
}
|
||||
if strings.Contains(stdout, "is not a public key file") {
|
||||
return "", 0, ErrKeyUnableVerify{stdout}
|
||||
}
|
||||
|
||||
fields := strings.Split(stdout, " ")
|
||||
if len(fields) < 4 {
|
||||
return "", 0, fmt.Errorf("invalid public key line: %s", stdout)
|
||||
}
|
||||
|
||||
keyType := strings.Trim(fields[len(fields)-1], "()\r\n")
|
||||
length, err := strconv.ParseInt(fields[0], 10, 32)
|
||||
if err != nil {
|
||||
return "", 0, err
|
||||
}
|
||||
return strings.ToLower(keyType), int(length), nil
|
||||
}
|
||||
|
@@ -18,7 +18,6 @@ import (
|
||||
|
||||
"github.com/42wim/sshsig"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func Test_SSHParsePublicKey(t *testing.T) {
|
||||
@@ -45,27 +44,6 @@ func Test_SSHParsePublicKey(t *testing.T) {
|
||||
assert.Equal(t, tc.keyType, keyTypeN)
|
||||
assert.Equal(t, tc.length, lengthN)
|
||||
})
|
||||
if tc.skipSSHKeygen {
|
||||
return
|
||||
}
|
||||
t.Run("SSHKeygen", func(t *testing.T) {
|
||||
keyTypeK, lengthK, err := SSHKeyGenParsePublicKey(tc.content)
|
||||
if err != nil {
|
||||
// Some servers do not support ecdsa format.
|
||||
if !strings.Contains(err.Error(), "line 1 too long:") {
|
||||
require.NoError(t, err)
|
||||
}
|
||||
}
|
||||
assert.Equal(t, tc.keyType, keyTypeK)
|
||||
assert.Equal(t, tc.length, lengthK)
|
||||
})
|
||||
t.Run("SSHParseKeyNative", func(t *testing.T) {
|
||||
keyTypeK, lengthK, err := SSHNativeParsePublicKey(tc.content)
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.Equal(t, tc.keyType, keyTypeK)
|
||||
assert.Equal(t, tc.length, lengthK)
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -186,14 +164,6 @@ func Test_calcFingerprint(t *testing.T) {
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, tc.fp, fpN)
|
||||
})
|
||||
if tc.skipSSHKeygen {
|
||||
return
|
||||
}
|
||||
t.Run("SSHKeygen", func(t *testing.T) {
|
||||
fpK, err := calcFingerprintSSHKeygen(tc.content)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, tc.fp, fpK)
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user