Skip to content

Commit 7b30191

Browse files
committed
feat: not contain null&NTFS
mv check to /validator add validator test,
1 parent df0e7ca commit 7b30191

File tree

8 files changed

+215
-112
lines changed

8 files changed

+215
-112
lines changed

controller/branch_ctl.go

Lines changed: 3 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,10 @@ package controller
33
import (
44
"context"
55
"errors"
6-
"fmt"
7-
"net/http"
8-
"regexp"
9-
"strings"
10-
116
"github.com/jiaozifs/jiaozifs/block/params"
12-
7+
"github.com/jiaozifs/jiaozifs/controller/validator"
138
"github.com/jiaozifs/jiaozifs/versionmgr"
9+
"net/http"
1410

1511
"github.com/jiaozifs/jiaozifs/api"
1612
"github.com/jiaozifs/jiaozifs/auth"
@@ -19,36 +15,6 @@ import (
1915
"go.uber.org/fx"
2016
)
2117

22-
var MaxBranchNameLength = 40
23-
var branchNameRegex = regexp.MustCompile(`^[\w]+\/?[\w]+$`)
24-
25-
func CheckBranchName(name string) error {
26-
for _, blackName := range RepoNameBlackList {
27-
if name == blackName {
28-
return errors.New("repository name is black list")
29-
}
30-
}
31-
32-
if len(name) > MaxBranchNameLength {
33-
return fmt.Errorf("branch name is too long")
34-
}
35-
36-
seg := strings.Split(name, "/")
37-
if len(seg) > 2 {
38-
return fmt.Errorf("branch format must be <name> or <name>/<name>")
39-
}
40-
41-
if !branchNameRegex.Match([]byte(seg[0])) {
42-
return fmt.Errorf("invalid branch name: %s, must start with a number or letter and can only contain numbers, letters, hyphens or underscores", seg[0])
43-
}
44-
if len(seg) > 2 {
45-
if !branchNameRegex.Match([]byte(seg[1])) {
46-
return fmt.Errorf("invalid branch name: %s, must start with a number or letter and can only contain numbers, letters, hyphens or underscores", seg[1])
47-
}
48-
}
49-
return nil
50-
}
51-
5218
type BranchController struct {
5319
fx.In
5420

@@ -127,7 +93,7 @@ func (bct BranchController) ListBranches(ctx context.Context, w *api.JiaozifsRes
12793
}
12894

12995
func (bct BranchController) CreateBranch(ctx context.Context, w *api.JiaozifsResponse, _ *http.Request, body api.CreateBranchJSONRequestBody, ownerName string, repositoryName string) {
130-
if err := CheckBranchName(body.Name); err != nil {
96+
if err := validator.ValidateBranchName(body.Name); err != nil {
13197
w.BadRequest(err.Error())
13298
return
13399
}

controller/object_ctl.go

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,11 @@ import (
44
"context"
55
"errors"
66
"fmt"
7+
"github.com/jiaozifs/jiaozifs/controller/validator"
78
"io"
89
"mime"
910
"mime/multipart"
1011
"net/http"
11-
"regexp"
1212
"time"
1313

1414
"github.com/go-openapi/swag"
@@ -26,14 +26,6 @@ import (
2626
)
2727

2828
var objLog = logging.Logger("object_ctl")
29-
var pathRegex = regexp.MustCompile(`^([a-zA-Z0-9]+\/)*[a-zA-Z0-9]+(?:\.[a-zA-Z0-9]+)?$`) //nolint
30-
31-
func CheckObjectPath(path string) error {
32-
if !pathRegex.MatchString(path) {
33-
return fmt.Errorf("invalid object path: it must start with a letter or digit, can contain letters, digits, and must be separated by slashes")
34-
}
35-
return nil
36-
}
3729

3830
type ObjectController struct {
3931
fx.In
@@ -321,7 +313,7 @@ func (oct ObjectController) UploadObject(ctx context.Context, w *api.JiaozifsRes
321313
}
322314
defer reader.Close() //nolint
323315

324-
err = CheckObjectPath(params.Path)
316+
err = validator.ValidateObjectPath(params.Path)
325317
if err != nil {
326318
w.BadRequest(err.Error())
327319
return

controller/repository_ctl.go

Lines changed: 2 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,10 @@ package controller
33
import (
44
"context"
55
"encoding/json"
6-
"errors"
76
"fmt"
7+
"github.com/jiaozifs/jiaozifs/controller/validator"
88
"io"
99
"net/http"
10-
"regexp"
1110
"time"
1211

1312
"github.com/google/uuid"
@@ -27,23 +26,6 @@ import (
2726
const DefaultBranchName = "main"
2827

2928
var repoLog = logging.Logger("repo control")
30-
var alphanumeric = regexp.MustCompile(`^[a-zA-Z0-9][a-zA-Z0-9_\-]{1,61}[a-zA-Z0-9]$`)
31-
32-
// RepoNameBlackList forbid repo name, reserve for routes
33-
var RepoNameBlackList = []string{"repository", "repositories", "wip", "wips", "object", "objects", "commit", "commits", "ref", "refs", "repo", "repos", "user", "users"}
34-
35-
func CheckRepositoryName(name string) error {
36-
for _, blackName := range RepoNameBlackList {
37-
if name == blackName {
38-
return errors.New("repository name is black list")
39-
}
40-
}
41-
42-
if !alphanumeric.MatchString(name) {
43-
return errors.New("repository name must start with a number or letter, can only contain numbers, letters, or hyphens, and must be between 3 and 63 characters in length")
44-
}
45-
return nil
46-
}
4729

4830
type RepositoryController struct {
4931
fx.In
@@ -150,7 +132,7 @@ func (repositoryCtl RepositoryController) ListRepository(ctx context.Context, w
150132
}
151133

152134
func (repositoryCtl RepositoryController) CreateRepository(ctx context.Context, w *api.JiaozifsResponse, _ *http.Request, body api.CreateRepositoryJSONRequestBody) {
153-
err := CheckRepositoryName(body.Name)
135+
err := validator.ValidateRepoName(body.Name)
154136
if err != nil {
155137
w.BadRequest(err.Error())
156138
return

controller/user_ctl.go

Lines changed: 2 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,8 @@ package controller
33
import (
44
"context"
55
"encoding/hex"
6-
"errors"
6+
"github.com/jiaozifs/jiaozifs/controller/validator"
77
"net/http"
8-
"regexp"
98
"time"
109

1110
"github.com/jiaozifs/jiaozifs/utils"
@@ -23,19 +22,11 @@ import (
2322
)
2423

2524
var userCtlLog = logging.Logger("user_ctl")
26-
var usernameRegex = regexp.MustCompile(`^[a-zA-Z0-9][a-zA-Z0-9_-]{1,28}[a-zA-Z0-9]$`)
2725

2826
const (
2927
AuthHeader = "Authorization"
3028
)
3129

32-
func CheckUserName(name string) error {
33-
if !usernameRegex.MatchString(name) {
34-
return errors.New("invalid username: it must start and end with a letter or digit, can contain letters, digits, hyphens, and cannot start or end with a hyphen; the length must be between 3 and 30 characters")
35-
}
36-
return nil
37-
}
38-
3930
type UserController struct {
4031
fx.In
4132

@@ -90,7 +81,7 @@ func (userCtl UserController) Login(ctx context.Context, w *api.JiaozifsResponse
9081
}
9182

9283
func (userCtl UserController) Register(ctx context.Context, w *api.JiaozifsResponse, _ *http.Request, body api.RegisterJSONRequestBody) {
93-
err := CheckUserName(body.Name)
84+
err := validator.ValidateUsername(body.Name)
9485
if err != nil {
9586
w.BadRequest(err.Error())
9687
return

controller/validator/validate.go

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
package validator
2+
3+
import (
4+
"errors"
5+
"regexp"
6+
"strings"
7+
)
8+
9+
var (
10+
MaxBranchNameLength = 40
11+
12+
ReValidRef = regexp.MustCompile(`^\w+/?\w+$`)
13+
ReValidRepo = regexp.MustCompile(`^[a-zA-Z0-9][a-zA-Z0-9_\-]{1,61}[a-zA-Z0-9]$`)
14+
ReValidUser = regexp.MustCompile(`^[a-zA-Z0-9][a-zA-Z0-9_-]{1,28}[a-zA-Z0-9]$`)
15+
ReValidPath = regexp.MustCompile(`^(?:[^\x00-\x1F\\/:*?"<>|]+/)*[^\x00-\x1F\\/:*?"<>|]+$`)
16+
17+
// RepoNameBlackList forbid repo name, reserve for routes
18+
RepoNameBlackList = []string{"repository", "repositories", "wip", "wips", "object", "objects", "commit", "commits", "ref", "refs", "repo", "repos", "user", "users"}
19+
)
20+
21+
var (
22+
ErrNameBlackList = errors.New("repository name is black list")
23+
ErrNameTooLong = errors.New("name too long")
24+
ErrBranchFormat = errors.New("branch format must be <name> or <name>/<name>")
25+
ErrInvalidBranchName = errors.New("invalid branch name: must start with a number or letter and can only contain numbers, letters, hyphens or underscores")
26+
ErrInvalidRepoName = errors.New("repository name must start with a number or letter, can only contain numbers, letters, or hyphens, and must be between 3 and 63 characters in length")
27+
ErrInvalidUsername = errors.New("invalid username: it must start and end with a letter or digit, can contain letters, digits, hyphens, and cannot start or end with a hyphen; the length must be between 3 and 30 characters")
28+
ErrInvalidObjectPath = errors.New("invalid object path: it must not contain null characters or NTFS forbidden characters")
29+
)
30+
31+
func ValidateBranchName(name string) error {
32+
for _, blackName := range RepoNameBlackList {
33+
if name == blackName {
34+
return ErrNameBlackList
35+
}
36+
}
37+
38+
if len(name) > MaxBranchNameLength {
39+
return ErrNameTooLong
40+
}
41+
42+
seg := strings.Split(name, "/")
43+
if len(seg) > 2 {
44+
return ErrBranchFormat
45+
}
46+
47+
if !ReValidRef.Match([]byte(seg[0])) {
48+
return ErrInvalidBranchName
49+
}
50+
if len(seg) > 1 {
51+
if !ReValidRef.Match([]byte(seg[1])) {
52+
return ErrInvalidBranchName
53+
}
54+
}
55+
return nil
56+
}
57+
58+
func ValidateRepoName(name string) error {
59+
for _, blackName := range RepoNameBlackList {
60+
if name == blackName {
61+
return ErrNameBlackList
62+
}
63+
}
64+
65+
if !ReValidRepo.MatchString(name) {
66+
return ErrInvalidRepoName
67+
}
68+
return nil
69+
}
70+
71+
func ValidateUsername(name string) error {
72+
if !ReValidUser.MatchString(name) {
73+
return ErrInvalidUsername
74+
}
75+
return nil
76+
}
77+
78+
func ValidateObjectPath(path string) error {
79+
if !ReValidPath.MatchString(path) {
80+
return ErrInvalidObjectPath
81+
}
82+
return nil
83+
}
Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
package validator
2+
3+
import (
4+
"testing"
5+
)
6+
7+
func TestValidateBranchName(t *testing.T) {
8+
//Validate branch names
9+
validBranchNames := []string{"main", "feat/branch", "fix/bugfix"}
10+
for _, name := range validBranchNames {
11+
err := ValidateBranchName(name)
12+
if err != nil {
13+
t.Errorf("Expected no error for branch name '%s', but got: %s", name, err)
14+
}
15+
}
16+
17+
//Invalidate branch names
18+
invalidBranchNames := []struct {
19+
name string
20+
error string
21+
}{
22+
{"repository", "repository name is black list"},
23+
{"wip", "repository name is black list"},
24+
{"too_long_branch_name_that_exceeds_max_length_limit", "name too long"},
25+
{"invalid/name\x00", "invalid branch name: must start with a number or letter and can only contain numbers, letters, hyphens or underscores"},
26+
{"invalid/branch/name", "branch format must be <name> or <name>/<name>"},
27+
}
28+
29+
for _, testCase := range invalidBranchNames {
30+
err := ValidateBranchName(testCase.name)
31+
if err == nil || err.Error() != testCase.error {
32+
t.Errorf("Expected error '%s' for invalid branch name '%s', but got: %v", testCase.error, testCase.name, err)
33+
}
34+
}
35+
}
36+
37+
func TestValidateRepoName(t *testing.T) {
38+
//Validate Repo names
39+
validRepoNames := []string{"myrepo", "user123", "project-name", "repo123_name"}
40+
for _, name := range validRepoNames {
41+
err := ValidateRepoName(name)
42+
if err != nil {
43+
t.Errorf("Expected no error for repo name '%s', but got: %s", name, err)
44+
}
45+
}
46+
47+
//Invalidate Repo names
48+
invalidRepoNames := []struct {
49+
name string
50+
error string
51+
}{
52+
{"repository", "repository name is black list"},
53+
{"wip", "repository name is black list"},
54+
{"invalid/name", "repository name must start with a number or letter, can only contain numbers, letters, or hyphens, and must be between 3 and 63 characters in length"},
55+
}
56+
57+
for _, testCase := range invalidRepoNames {
58+
err := ValidateRepoName(testCase.name)
59+
if err == nil || err.Error() != testCase.error {
60+
t.Errorf("Expected error '%s' for invalid repo name '%s', but got: %v", testCase.error, testCase.name, err)
61+
}
62+
}
63+
}
64+
65+
func TestValidateUsername(t *testing.T) {
66+
//Validate Username
67+
validUsernames := []string{"user123", "username", "user_name", "user-123"}
68+
for _, name := range validUsernames {
69+
err := ValidateUsername(name)
70+
if err != nil {
71+
t.Errorf("Expected no error for username '%s', but got: %s", name, err)
72+
}
73+
}
74+
75+
//Invalidate Username
76+
invalidUsernames := []struct {
77+
name string
78+
error string
79+
}{
80+
{"user name", "invalid username: it must start and end with a letter or digit, can contain letters, digits, hyphens, and cannot start or end with a hyphen; the length must be between 3 and 30 characters"},
81+
{"user-with-hyphen-", "invalid username: it must start and end with a letter or digit, can contain letters, digits, hyphens, and cannot start or end with a hyphen; the length must be between 3 and 30 characters"},
82+
{"invalid/username", "invalid username: it must start and end with a letter or digit, can contain letters, digits, hyphens, and cannot start or end with a hyphen; the length must be between 3 and 30 characters"},
83+
}
84+
85+
for _, testCase := range invalidUsernames {
86+
err := ValidateUsername(testCase.name)
87+
if err == nil || err.Error() != testCase.error {
88+
t.Errorf("Expected error '%s' for invalid username '%s', but got: %v", testCase.error, testCase.name, err)
89+
}
90+
}
91+
}
92+
93+
func TestValidateObjectPath(t *testing.T) {
94+
//Validate Obj Path
95+
validObjectPaths := []string{"path/to/object", "file.txt", "folder/file.txt"}
96+
for _, path := range validObjectPaths {
97+
err := ValidateObjectPath(path)
98+
if err != nil {
99+
t.Errorf("Expected no error for object path '%s', but got: %s", path, err)
100+
}
101+
}
102+
103+
//Invalidate Obj Path
104+
invalidObjectPaths := []struct {
105+
path string
106+
error string
107+
}{
108+
{"path/with/null\x00character", "invalid object path: it must not contain null characters or NTFS forbidden characters"},
109+
{"path/with/invalid/characters/:", "invalid object path: it must not contain null characters or NTFS forbidden characters"},
110+
{"path/with/invalid/characters/*", "invalid object path: it must not contain null characters or NTFS forbidden characters"},
111+
{"path/with/invalid/characters/\"", "invalid object path: it must not contain null characters or NTFS forbidden characters"},
112+
{"path/with/invalid/characters/<?", "invalid object path: it must not contain null characters or NTFS forbidden characters"},
113+
}
114+
115+
for _, testCase := range invalidObjectPaths {
116+
err := ValidateObjectPath(testCase.path)
117+
if err == nil || err.Error() != testCase.error {
118+
t.Errorf("Expected error '%s' for invalid object path '%s', but got: %v", testCase.error, testCase.path, err)
119+
}
120+
}
121+
}

0 commit comments

Comments
 (0)