summaryrefslogtreecommitdiffstats
path: root/modules/repository
diff options
context:
space:
mode:
authorKyle D <kdumontnu@gmail.com>2023-06-20 17:14:47 -0400
committerGitHub <noreply@github.com>2023-06-20 21:14:47 +0000
commit8220e50b56cf7bf9cdfff29a287c5721c3949464 (patch)
tree67c9a607550159f0cada700343c8044d93e3fc21 /modules/repository
parente50c3e8431972a41fc9792939956c3281b1b4810 (diff)
downloadgitea-8220e50b56cf7bf9cdfff29a287c5721c3949464.tar.gz
gitea-8220e50b56cf7bf9cdfff29a287c5721c3949464.zip
Substitute variables in path names of template repos too (#25294)
### Summary Extend the template variable substitution to replace file paths. This can be helpful for setting up log files & directories that should match the repository name. ### PR Changes - Move files matching glob pattern when setting up repos from template - For security, added ~escaping~ sanitization for cross-platform support and to prevent directory traversal (thanks @silverwind for the reference) - Added unit testing for escaping function - Fixed the integration tests for repo template generation by passing the repo_template_id - Updated the integration testfiles to add some variable substitution & assert the outputs I had to fix the existing repo template integration test and extend it to add a check for variable substitutions. Example: ![image](https://github.com/go-gitea/gitea/assets/12700993/621feb09-0ef3-460e-afa8-da74cd84fa4e)
Diffstat (limited to 'modules/repository')
-rw-r--r--modules/repository/generate.go32
-rw-r--r--modules/repository/generate_test.go11
2 files changed, 41 insertions, 2 deletions
diff --git a/modules/repository/generate.go b/modules/repository/generate.go
index 31d5ebbb11..102c5af1c9 100644
--- a/modules/repository/generate.go
+++ b/modules/repository/generate.go
@@ -11,6 +11,7 @@ import (
"os"
"path"
"path/filepath"
+ "regexp"
"strings"
"time"
@@ -48,7 +49,7 @@ var defaultTransformers = []transformer{
{Name: "TITLE", Transform: util.ToTitleCase},
}
-func generateExpansion(src string, templateRepo, generateRepo *repo_model.Repository) string {
+func generateExpansion(src string, templateRepo, generateRepo *repo_model.Repository, sanitizeFileName bool) string {
expansions := []expansion{
{Name: "REPO_NAME", Value: generateRepo.Name, Transformers: defaultTransformers},
{Name: "TEMPLATE_NAME", Value: templateRepo.Name, Transformers: defaultTransformers},
@@ -74,6 +75,9 @@ func generateExpansion(src string, templateRepo, generateRepo *repo_model.Reposi
return os.Expand(src, func(key string) string {
if expansion, ok := expansionMap[key]; ok {
+ if sanitizeFileName {
+ return fileNameSanitize(expansion)
+ }
return expansion
}
return key
@@ -191,10 +195,24 @@ func generateRepoCommit(ctx context.Context, repo, templateRepo, generateRepo *r
}
if err := os.WriteFile(path,
- []byte(generateExpansion(string(content), templateRepo, generateRepo)),
+ []byte(generateExpansion(string(content), templateRepo, generateRepo, false)),
0o644); err != nil {
return err
}
+
+ substPath := filepath.FromSlash(filepath.Join(tmpDirSlash,
+ generateExpansion(base, templateRepo, generateRepo, true)))
+
+ // Create parent subdirectories if needed or continue silently if it exists
+ if err := os.MkdirAll(filepath.Dir(substPath), 0o755); err != nil {
+ return err
+ }
+
+ // Substitute filename variables
+ if err := os.Rename(path, substPath); err != nil {
+ return err
+ }
+
break
}
}
@@ -353,3 +371,13 @@ func GenerateRepository(ctx context.Context, doer, owner *user_model.User, templ
return generateRepo, nil
}
+
+// Sanitize user input to valid OS filenames
+//
+// Based on https://github.com/sindresorhus/filename-reserved-regex
+// Adds ".." to prevent directory traversal
+func fileNameSanitize(s string) string {
+ re := regexp.MustCompile(`(?i)\.\.|[<>:\"/\\|?*\x{0000}-\x{001F}]|^(con|prn|aux|nul|com\d|lpt\d)$`)
+
+ return strings.TrimSpace(re.ReplaceAllString(s, "_"))
+}
diff --git a/modules/repository/generate_test.go b/modules/repository/generate_test.go
index 1cb9a50f67..b0f97d0ffb 100644
--- a/modules/repository/generate_test.go
+++ b/modules/repository/generate_test.go
@@ -54,3 +54,14 @@ func TestGiteaTemplate(t *testing.T) {
})
}
}
+
+func TestFileNameSanitize(t *testing.T) {
+ assert.Equal(t, "test_CON", fileNameSanitize("test_CON"))
+ assert.Equal(t, "test CON", fileNameSanitize("test CON "))
+ assert.Equal(t, "__traverse__", fileNameSanitize("../traverse/.."))
+ assert.Equal(t, "http___localhost_3003_user_test.git", fileNameSanitize("http://localhost:3003/user/test.git"))
+ assert.Equal(t, "_", fileNameSanitize("CON"))
+ assert.Equal(t, "_", fileNameSanitize("con"))
+ assert.Equal(t, "_", fileNameSanitize("\u0000"))
+ assert.Equal(t, "目标", fileNameSanitize("目标"))
+}