Skip to content

Commit 32b97b3

Browse files
lunnywxiaoguang
andauthored
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 <[email protected]>
1 parent fd7c364 commit 32b97b3

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

45 files changed

+360
-417
lines changed

cmd/web.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -213,6 +213,10 @@ func serveInstalled(ctx *cli.Context) error {
213213
log.Fatal("Can not find APP_DATA_PATH %q", setting.AppDataPath)
214214
}
215215

216+
// the AppDataTempDir is fully managed by us with a safe sub-path
217+
// so it's safe to automatically remove the outdated files
218+
setting.AppDataTempDir("").RemoveOutdated(3 * 24 * time.Hour)
219+
216220
// Override the provided port number within the configuration
217221
if ctx.IsSet("port") {
218222
if err := setPort(ctx.String("port")); err != nil {

custom/conf/app.example.ini

Lines changed: 3 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -197,13 +197,6 @@ RUN_USER = ; git
197197
;; relative paths are made absolute relative to the APP_DATA_PATH
198198
;SSH_SERVER_HOST_KEYS=ssh/gitea.rsa, ssh/gogs.rsa
199199
;;
200-
;; Directory to create temporary files in when testing public keys using ssh-keygen,
201-
;; default is the system temporary directory.
202-
;SSH_KEY_TEST_PATH =
203-
;;
204-
;; Use `ssh-keygen` to parse public SSH keys. The value is passed to the shell. By default, Gitea does the parsing itself.
205-
;SSH_KEYGEN_PATH =
206-
;;
207200
;; Enable SSH Authorized Key Backup when rewriting all keys, default is false
208201
;SSH_AUTHORIZED_KEYS_BACKUP = false
209202
;;
@@ -294,6 +287,9 @@ RUN_USER = ; git
294287
;; Default path for App data
295288
;APP_DATA_PATH = data ; relative paths will be made absolute with _`AppWorkPath`_
296289
;;
290+
;; Base path for App's temp files, leave empty to use the managed tmp directory in APP_DATA_PATH
291+
;APP_TEMP_PATH =
292+
;;
297293
;; Enable gzip compression for runtime-generated content, static resources excluded
298294
;ENABLE_GZIP = false
299295
;;
@@ -1069,15 +1065,6 @@ LEVEL = Info
10691065
;; Separate extensions with a comma. To line wrap files without an extension, just put a comma
10701066
;LINE_WRAP_EXTENSIONS = .txt,.md,.markdown,.mdown,.mkd,.livemd,
10711067

1072-
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1073-
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1074-
;[repository.local]
1075-
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1076-
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1077-
;;
1078-
;; Path for local repository copy. Defaults to `tmp/local-repo` (content gets deleted on gitea restart)
1079-
;LOCAL_COPY_PATH = tmp/local-repo
1080-
10811068
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
10821069
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
10831070
;[repository.upload]
@@ -1087,9 +1074,6 @@ LEVEL = Info
10871074
;; Whether repository file uploads are enabled. Defaults to `true`
10881075
;ENABLED = true
10891076
;;
1090-
;; Path for uploads. Defaults to `data/tmp/uploads` (content gets deleted on gitea restart)
1091-
;TEMP_PATH = data/tmp/uploads
1092-
;;
10931077
;; Comma-separated list of allowed file extensions (`.zip`), mime types (`text/plain`) or wildcard type (`image/*`, `audio/*`, `video/*`). Empty value or `*/*` allows all types.
10941078
;ALLOWED_TYPES =
10951079
;;
@@ -2594,9 +2578,6 @@ LEVEL = Info
25942578
;; Currently, only `minio` and `azureblob` is supported.
25952579
;SERVE_DIRECT = false
25962580
;;
2597-
;; Path for chunked uploads. Defaults to APP_DATA_PATH + `tmp/package-upload`
2598-
;CHUNKED_UPLOAD_PATH = tmp/package-upload
2599-
;;
26002581
;; Maximum count of package versions a single owner can have (`-1` means no limits)
26012582
;LIMIT_TOTAL_OWNER_COUNT = -1
26022583
;; Maximum size of packages a single owner can use (`-1` means no limits, format `1000`, `1 MB`, `1 GiB`)

models/asymkey/ssh_key_fingerprint.go

Lines changed: 2 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -6,27 +6,13 @@ package asymkey
66
import (
77
"context"
88
"fmt"
9-
"strings"
109

1110
"code.gitea.io/gitea/models/db"
12-
"code.gitea.io/gitea/modules/log"
13-
"code.gitea.io/gitea/modules/process"
14-
"code.gitea.io/gitea/modules/setting"
15-
"code.gitea.io/gitea/modules/util"
1611

1712
"golang.org/x/crypto/ssh"
1813
"xorm.io/builder"
1914
)
2015

21-
// ___________.__ .__ __
22-
// \_ _____/|__| ____ ____ ________________________|__| _____/ |_
23-
// | __) | |/ \ / ___\_/ __ \_ __ \____ \_ __ \ |/ \ __\
24-
// | \ | | | \/ /_/ > ___/| | \/ |_> > | \/ | | \ |
25-
// \___ / |__|___| /\___ / \___ >__| | __/|__| |__|___| /__|
26-
// \/ \//_____/ \/ |__| \/
27-
//
28-
// This file contains functions for fingerprinting SSH keys
29-
//
3016
// The database is used in checkKeyFingerprint however most of these functions probably belong in a module
3117

3218
// checkKeyFingerprint only checks if key fingerprint has been used as public key,
@@ -41,29 +27,6 @@ func checkKeyFingerprint(ctx context.Context, fingerprint string) error {
4127
return nil
4228
}
4329

44-
func calcFingerprintSSHKeygen(publicKeyContent string) (string, error) {
45-
// Calculate fingerprint.
46-
tmpPath, err := writeTmpKeyFile(publicKeyContent)
47-
if err != nil {
48-
return "", err
49-
}
50-
defer func() {
51-
if err := util.Remove(tmpPath); err != nil {
52-
log.Warn("Unable to remove temporary key file: %s: Error: %v", tmpPath, err)
53-
}
54-
}()
55-
stdout, stderr, err := process.GetManager().Exec("AddPublicKey", "ssh-keygen", "-lf", tmpPath)
56-
if err != nil {
57-
if strings.Contains(stderr, "is not a public key file") {
58-
return "", ErrKeyUnableVerify{stderr}
59-
}
60-
return "", util.NewInvalidArgumentErrorf("'ssh-keygen -lf %s' failed with error '%s': %s", tmpPath, err, stderr)
61-
} else if len(stdout) < 2 {
62-
return "", util.NewInvalidArgumentErrorf("not enough output for calculating fingerprint: %s", stdout)
63-
}
64-
return strings.Split(stdout, " ")[1], nil
65-
}
66-
6730
func calcFingerprintNative(publicKeyContent string) (string, error) {
6831
// Calculate fingerprint.
6932
pk, _, _, _, err := ssh.ParseAuthorizedKey([]byte(publicKeyContent))
@@ -75,15 +38,12 @@ func calcFingerprintNative(publicKeyContent string) (string, error) {
7538

7639
// CalcFingerprint calculate public key's fingerprint
7740
func CalcFingerprint(publicKeyContent string) (string, error) {
78-
// Call the method based on configuration
79-
useNative := setting.SSH.KeygenPath == ""
80-
calcFn := util.Iif(useNative, calcFingerprintNative, calcFingerprintSSHKeygen)
81-
fp, err := calcFn(publicKeyContent)
41+
fp, err := calcFingerprintNative(publicKeyContent)
8242
if err != nil {
8343
if IsErrKeyUnableVerify(err) {
8444
return "", err
8545
}
86-
return "", fmt.Errorf("CalcFingerprint(%s): %w", util.Iif(useNative, "native", "ssh-keygen"), err)
46+
return "", fmt.Errorf("CalcFingerprint: %w", err)
8747
}
8848
return fp, nil
8949
}

models/asymkey/ssh_key_parse.go

Lines changed: 2 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,9 @@ import (
1313
"errors"
1414
"fmt"
1515
"math/big"
16-
"os"
17-
"strconv"
1816
"strings"
1917

2018
"code.gitea.io/gitea/modules/log"
21-
"code.gitea.io/gitea/modules/process"
2219
"code.gitea.io/gitea/modules/setting"
2320
"code.gitea.io/gitea/modules/util"
2421

@@ -175,20 +172,9 @@ func CheckPublicKeyString(content string) (_ string, err error) {
175172
return content, nil
176173
}
177174

178-
var (
179-
fnName string
180-
keyType string
181-
length int
182-
)
183-
if len(setting.SSH.KeygenPath) == 0 {
184-
fnName = "SSHNativeParsePublicKey"
185-
keyType, length, err = SSHNativeParsePublicKey(content)
186-
} else {
187-
fnName = "SSHKeyGenParsePublicKey"
188-
keyType, length, err = SSHKeyGenParsePublicKey(content)
189-
}
175+
keyType, length, err := SSHNativeParsePublicKey(content)
190176
if err != nil {
191-
return "", fmt.Errorf("%s: %w", fnName, err)
177+
return "", fmt.Errorf("SSHNativeParsePublicKey: %w", err)
192178
}
193179
log.Trace("Key info [native: %v]: %s-%d", setting.SSH.StartBuiltinServer, keyType, length)
194180

@@ -258,56 +244,3 @@ func SSHNativeParsePublicKey(keyLine string) (string, int, error) {
258244
}
259245
return "", 0, fmt.Errorf("unsupported key length detection for type: %s", pkey.Type())
260246
}
261-
262-
// writeTmpKeyFile writes key content to a temporary file
263-
// and returns the name of that file, along with any possible errors.
264-
func writeTmpKeyFile(content string) (string, error) {
265-
tmpFile, err := os.CreateTemp(setting.SSH.KeyTestPath, "gitea_keytest")
266-
if err != nil {
267-
return "", fmt.Errorf("TempFile: %w", err)
268-
}
269-
defer tmpFile.Close()
270-
271-
if _, err = tmpFile.WriteString(content); err != nil {
272-
return "", fmt.Errorf("WriteString: %w", err)
273-
}
274-
return tmpFile.Name(), nil
275-
}
276-
277-
// SSHKeyGenParsePublicKey extracts key type and length using ssh-keygen.
278-
func SSHKeyGenParsePublicKey(key string) (string, int, error) {
279-
tmpName, err := writeTmpKeyFile(key)
280-
if err != nil {
281-
return "", 0, fmt.Errorf("writeTmpKeyFile: %w", err)
282-
}
283-
defer func() {
284-
if err := util.Remove(tmpName); err != nil {
285-
log.Warn("Unable to remove temporary key file: %s: Error: %v", tmpName, err)
286-
}
287-
}()
288-
289-
keygenPath := setting.SSH.KeygenPath
290-
if len(keygenPath) == 0 {
291-
keygenPath = "ssh-keygen"
292-
}
293-
294-
stdout, stderr, err := process.GetManager().Exec("SSHKeyGenParsePublicKey", keygenPath, "-lf", tmpName)
295-
if err != nil {
296-
return "", 0, fmt.Errorf("fail to parse public key: %s - %s", err, stderr)
297-
}
298-
if strings.Contains(stdout, "is not a public key file") {
299-
return "", 0, ErrKeyUnableVerify{stdout}
300-
}
301-
302-
fields := strings.Split(stdout, " ")
303-
if len(fields) < 4 {
304-
return "", 0, fmt.Errorf("invalid public key line: %s", stdout)
305-
}
306-
307-
keyType := strings.Trim(fields[len(fields)-1], "()\r\n")
308-
length, err := strconv.ParseInt(fields[0], 10, 32)
309-
if err != nil {
310-
return "", 0, err
311-
}
312-
return strings.ToLower(keyType), int(length), nil
313-
}

models/asymkey/ssh_key_test.go

Lines changed: 0 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@ import (
1818

1919
"github.com/42wim/sshsig"
2020
"github.com/stretchr/testify/assert"
21-
"github.com/stretchr/testify/require"
2221
)
2322

2423
func Test_SSHParsePublicKey(t *testing.T) {
@@ -45,27 +44,6 @@ func Test_SSHParsePublicKey(t *testing.T) {
4544
assert.Equal(t, tc.keyType, keyTypeN)
4645
assert.Equal(t, tc.length, lengthN)
4746
})
48-
if tc.skipSSHKeygen {
49-
return
50-
}
51-
t.Run("SSHKeygen", func(t *testing.T) {
52-
keyTypeK, lengthK, err := SSHKeyGenParsePublicKey(tc.content)
53-
if err != nil {
54-
// Some servers do not support ecdsa format.
55-
if !strings.Contains(err.Error(), "line 1 too long:") {
56-
require.NoError(t, err)
57-
}
58-
}
59-
assert.Equal(t, tc.keyType, keyTypeK)
60-
assert.Equal(t, tc.length, lengthK)
61-
})
62-
t.Run("SSHParseKeyNative", func(t *testing.T) {
63-
keyTypeK, lengthK, err := SSHNativeParsePublicKey(tc.content)
64-
require.NoError(t, err)
65-
66-
assert.Equal(t, tc.keyType, keyTypeK)
67-
assert.Equal(t, tc.length, lengthK)
68-
})
6947
})
7048
}
7149
}
@@ -186,14 +164,6 @@ func Test_calcFingerprint(t *testing.T) {
186164
assert.NoError(t, err)
187165
assert.Equal(t, tc.fp, fpN)
188166
})
189-
if tc.skipSSHKeygen {
190-
return
191-
}
192-
t.Run("SSHKeygen", func(t *testing.T) {
193-
fpK, err := calcFingerprintSSHKeygen(tc.content)
194-
assert.NoError(t, err)
195-
assert.Equal(t, tc.fp, fpK)
196-
})
197167
})
198168
}
199169
}

models/issues/issue_update.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -845,6 +845,7 @@ func DeleteOrphanedIssues(ctx context.Context) error {
845845

846846
// Remove issue attachment files.
847847
for i := range attachmentPaths {
848+
// FIXME: it's not right, because the attachment might not be on local filesystem
848849
system_model.RemoveAllWithNotice(ctx, "Delete issue attachment", attachmentPaths[i])
849850
}
850851
return nil

models/migrations/base/tests.go

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import (
1515
"code.gitea.io/gitea/models/unittest"
1616
"code.gitea.io/gitea/modules/git"
1717
"code.gitea.io/gitea/modules/setting"
18+
"code.gitea.io/gitea/modules/tempdir"
1819
"code.gitea.io/gitea/modules/test"
1920
"code.gitea.io/gitea/modules/testlogger"
2021

@@ -114,15 +115,16 @@ func MainTest(m *testing.M) {
114115
setting.CustomConf = giteaConf
115116
}
116117

117-
tmpDataPath, err := os.MkdirTemp("", "data")
118+
tmpDataPath, cleanup, err := tempdir.OsTempDir("gitea-test").MkdirTempRandom("data")
118119
if err != nil {
119120
testlogger.Fatalf("Unable to create temporary data path %v\n", err)
120121
}
122+
defer cleanup()
121123

122124
setting.CustomPath = filepath.Join(setting.AppWorkPath, "custom")
123125
setting.AppDataPath = tmpDataPath
124126

125-
unittest.InitSettings()
127+
unittest.InitSettingsForTesting()
126128
if err = git.InitFull(context.Background()); err != nil {
127129
testlogger.Fatalf("Unable to InitFull: %v\n", err)
128130
}
@@ -134,8 +136,5 @@ func MainTest(m *testing.M) {
134136
if err := removeAllWithRetry(setting.RepoRootPath); err != nil {
135137
fmt.Fprintf(os.Stderr, "os.RemoveAll: %v\n", err)
136138
}
137-
if err := removeAllWithRetry(tmpDataPath); err != nil {
138-
fmt.Fprintf(os.Stderr, "os.RemoveAll: %v\n", err)
139-
}
140139
os.Exit(exitStatus)
141140
}

models/repo/upload.go

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -51,14 +51,10 @@ func init() {
5151
db.RegisterModel(new(Upload))
5252
}
5353

54-
// UploadLocalPath returns where uploads is stored in local file system based on given UUID.
55-
func UploadLocalPath(uuid string) string {
56-
return filepath.Join(setting.Repository.Upload.TempPath, uuid[0:1], uuid[1:2], uuid)
57-
}
58-
59-
// LocalPath returns where uploads are temporarily stored in local file system.
54+
// LocalPath returns where uploads are temporarily stored in local file system based on given UUID.
6055
func (upload *Upload) LocalPath() string {
61-
return UploadLocalPath(upload.UUID)
56+
uuid := upload.UUID
57+
return setting.AppDataTempDir("repo-uploads").JoinPath(uuid[0:1], uuid[1:2], uuid)
6258
}
6359

6460
// NewUpload creates a new upload object.

0 commit comments

Comments
 (0)