mirror of
				https://github.com/go-gitea/gitea.git
				synced 2025-10-31 21:28:11 +09:00 
			
		
		
		
	Validate External Tracker URL Format (#7089)
* Validate External Tracker URL Format Add some validation checks for external tracker URL format. Fixes #7068 * Don't make {index} a hard requirement * Fix Description * make fmt * move regex to package level * fix copyright date
This commit is contained in:
		| @@ -7,6 +7,7 @@ package validation | |||||||
| import ( | import ( | ||||||
| 	"net" | 	"net" | ||||||
| 	"net/url" | 	"net/url" | ||||||
|  | 	"regexp" | ||||||
| 	"strings" | 	"strings" | ||||||
|  |  | ||||||
| 	"code.gitea.io/gitea/modules/setting" | 	"code.gitea.io/gitea/modules/setting" | ||||||
| @@ -14,6 +15,8 @@ import ( | |||||||
|  |  | ||||||
| var loopbackIPBlocks []*net.IPNet | var loopbackIPBlocks []*net.IPNet | ||||||
|  |  | ||||||
|  | var externalTrackerRegex = regexp.MustCompile(`({?)(?:user|repo|index)+?(}?)`) | ||||||
|  |  | ||||||
| func init() { | func init() { | ||||||
| 	for _, cidr := range []string{ | 	for _, cidr := range []string{ | ||||||
| 		"127.0.0.0/8", // IPv4 loopback | 		"127.0.0.0/8", // IPv4 loopback | ||||||
| @@ -75,3 +78,19 @@ func IsValidExternalURL(uri string) bool { | |||||||
|  |  | ||||||
| 	return true | 	return true | ||||||
| } | } | ||||||
|  |  | ||||||
|  | // IsValidExternalTrackerURLFormat checks if URL matches required syntax for external trackers | ||||||
|  | func IsValidExternalTrackerURLFormat(uri string) bool { | ||||||
|  | 	if !IsValidExternalURL(uri) { | ||||||
|  | 		return false | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	// check for typoed variables like /{index/ or /[repo} | ||||||
|  | 	for _, match := range externalTrackerRegex.FindAllStringSubmatch(uri, -1) { | ||||||
|  | 		if (match[1] == "{" || match[2] == "}") && (match[1] != "{" || match[2] != "}") { | ||||||
|  | 			return false | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return true | ||||||
|  | } | ||||||
|   | |||||||
| @@ -88,3 +88,70 @@ func Test_IsValidExternalURL(t *testing.T) { | |||||||
| 		}) | 		}) | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
|  | func Test_IsValidExternalTrackerURLFormat(t *testing.T) { | ||||||
|  | 	setting.AppURL = "https://try.gitea.io/" | ||||||
|  |  | ||||||
|  | 	cases := []struct { | ||||||
|  | 		description string | ||||||
|  | 		url         string | ||||||
|  | 		valid       bool | ||||||
|  | 	}{ | ||||||
|  | 		{ | ||||||
|  | 			description: "Correct external tracker URL with all placeholders", | ||||||
|  | 			url:         "https://github.com/{user}/{repo}/issues/{index}", | ||||||
|  | 			valid:       true, | ||||||
|  | 		}, | ||||||
|  | 		{ | ||||||
|  | 			description: "Local external tracker URL with all placeholders", | ||||||
|  | 			url:         "https://127.0.0.1/{user}/{repo}/issues/{index}", | ||||||
|  | 			valid:       false, | ||||||
|  | 		}, | ||||||
|  | 		{ | ||||||
|  | 			description: "External tracker URL with typo placeholder", | ||||||
|  | 			url:         "https://github.com/{user}/{repo/issues/{index}", | ||||||
|  | 			valid:       false, | ||||||
|  | 		}, | ||||||
|  | 		{ | ||||||
|  | 			description: "External tracker URL with typo placeholder", | ||||||
|  | 			url:         "https://github.com/[user}/{repo/issues/{index}", | ||||||
|  | 			valid:       false, | ||||||
|  | 		}, | ||||||
|  | 		{ | ||||||
|  | 			description: "External tracker URL with typo placeholder", | ||||||
|  | 			url:         "https://github.com/{user}/repo}/issues/{index}", | ||||||
|  | 			valid:       false, | ||||||
|  | 		}, | ||||||
|  | 		{ | ||||||
|  | 			description: "External tracker URL missing optional placeholder", | ||||||
|  | 			url:         "https://github.com/{user}/issues/{index}", | ||||||
|  | 			valid:       true, | ||||||
|  | 		}, | ||||||
|  | 		{ | ||||||
|  | 			description: "External tracker URL missing optional placeholder", | ||||||
|  | 			url:         "https://github.com/{repo}/issues/{index}", | ||||||
|  | 			valid:       true, | ||||||
|  | 		}, | ||||||
|  | 		{ | ||||||
|  | 			description: "External tracker URL missing optional placeholder", | ||||||
|  | 			url:         "https://github.com/issues/{index}", | ||||||
|  | 			valid:       true, | ||||||
|  | 		}, | ||||||
|  | 		{ | ||||||
|  | 			description: "External tracker URL missing optional placeholder", | ||||||
|  | 			url:         "https://github.com/issues/{user}", | ||||||
|  | 			valid:       true, | ||||||
|  | 		}, | ||||||
|  | 		{ | ||||||
|  | 			description: "External tracker URL with similar placeholder names test", | ||||||
|  | 			url:         "https://github.com/user/repo/issues/{index}", | ||||||
|  | 			valid:       true, | ||||||
|  | 		}, | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	for _, testCase := range cases { | ||||||
|  | 		t.Run(testCase.description, func(t *testing.T) { | ||||||
|  | 			assert.Equal(t, testCase.valid, IsValidExternalTrackerURLFormat(testCase.url)) | ||||||
|  | 		}) | ||||||
|  | 	} | ||||||
|  | } | ||||||
|   | |||||||
| @@ -249,7 +249,7 @@ func SettingsPost(ctx *context.Context, form auth.RepoSettingForm) { | |||||||
| 					ctx.Redirect(repo.Link() + "/settings") | 					ctx.Redirect(repo.Link() + "/settings") | ||||||
| 					return | 					return | ||||||
| 				} | 				} | ||||||
| 				if len(form.TrackerURLFormat) != 0 && !validation.IsValidExternalURL(form.TrackerURLFormat) { | 				if len(form.TrackerURLFormat) != 0 && !validation.IsValidExternalTrackerURLFormat(form.TrackerURLFormat) { | ||||||
| 					ctx.Flash.Error(ctx.Tr("repo.settings.tracker_url_format_error")) | 					ctx.Flash.Error(ctx.Tr("repo.settings.tracker_url_format_error")) | ||||||
| 					ctx.Redirect(repo.Link() + "/settings") | 					ctx.Redirect(repo.Link() + "/settings") | ||||||
| 					return | 					return | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user