mirror of
				https://github.com/go-gitea/gitea.git
				synced 2025-10-31 21:28:11 +09:00 
			
		
		
		
	Fix error message sanitiziation (#3082)
This commit is contained in:
		| @@ -6,18 +6,18 @@ package models | |||||||
|  |  | ||||||
| import ( | import ( | ||||||
| 	"fmt" | 	"fmt" | ||||||
| 	"strings" |  | ||||||
| 	"time" | 	"time" | ||||||
|  |  | ||||||
| 	"github.com/Unknwon/com" |  | ||||||
| 	"github.com/go-xorm/xorm" |  | ||||||
| 	"gopkg.in/ini.v1" |  | ||||||
|  |  | ||||||
| 	"code.gitea.io/git" | 	"code.gitea.io/git" | ||||||
| 	"code.gitea.io/gitea/modules/log" | 	"code.gitea.io/gitea/modules/log" | ||||||
| 	"code.gitea.io/gitea/modules/process" | 	"code.gitea.io/gitea/modules/process" | ||||||
| 	"code.gitea.io/gitea/modules/setting" | 	"code.gitea.io/gitea/modules/setting" | ||||||
| 	"code.gitea.io/gitea/modules/sync" | 	"code.gitea.io/gitea/modules/sync" | ||||||
|  | 	"code.gitea.io/gitea/modules/util" | ||||||
|  |  | ||||||
|  | 	"github.com/Unknwon/com" | ||||||
|  | 	"github.com/go-xorm/xorm" | ||||||
|  | 	"gopkg.in/ini.v1" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| // MirrorQueue holds an UniqueQueue object of the mirror | // MirrorQueue holds an UniqueQueue object of the mirror | ||||||
| @@ -95,24 +95,6 @@ func (m *Mirror) readAddress() { | |||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
| // HandleCloneUserCredentials replaces user credentials from HTTP/HTTPS URL |  | ||||||
| // with placeholder <credentials>. |  | ||||||
| // It will fail for any other forms of clone addresses. |  | ||||||
| func HandleCloneUserCredentials(url string, mosaics bool) string { |  | ||||||
| 	i := strings.Index(url, "@") |  | ||||||
| 	if i == -1 { |  | ||||||
| 		return url |  | ||||||
| 	} |  | ||||||
| 	start := strings.Index(url, "://") |  | ||||||
| 	if start == -1 { |  | ||||||
| 		return url |  | ||||||
| 	} |  | ||||||
| 	if mosaics { |  | ||||||
| 		return url[:start+3] + "<credentials>" + url[i:] |  | ||||||
| 	} |  | ||||||
| 	return url[:start+3] + url[i+1:] |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // sanitizeOutput sanitizes output of a command, replacing occurrences of the | // sanitizeOutput sanitizes output of a command, replacing occurrences of the | ||||||
| // repository's remote address with a sanitized version. | // repository's remote address with a sanitized version. | ||||||
| func sanitizeOutput(output, repoPath string) (string, error) { | func sanitizeOutput(output, repoPath string) (string, error) { | ||||||
| @@ -122,14 +104,13 @@ func sanitizeOutput(output, repoPath string) (string, error) { | |||||||
| 		// sanitize. | 		// sanitize. | ||||||
| 		return "", err | 		return "", err | ||||||
| 	} | 	} | ||||||
| 	sanitized := HandleCloneUserCredentials(remoteAddr, true) | 	return util.SanitizeMessage(output, remoteAddr), nil | ||||||
| 	return strings.Replace(output, remoteAddr, sanitized, -1), nil |  | ||||||
| } | } | ||||||
|  |  | ||||||
| // Address returns mirror address from Git repository config without credentials. | // Address returns mirror address from Git repository config without credentials. | ||||||
| func (m *Mirror) Address() string { | func (m *Mirror) Address() string { | ||||||
| 	m.readAddress() | 	m.readAddress() | ||||||
| 	return HandleCloneUserCredentials(m.address, false) | 	return util.SanitizeURLCredentials(m.address, false) | ||||||
| } | } | ||||||
|  |  | ||||||
| // FullAddress returns mirror address from Git repository config. | // FullAddress returns mirror address from Git repository config. | ||||||
|   | |||||||
							
								
								
									
										48
									
								
								modules/util/sanitize.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										48
									
								
								modules/util/sanitize.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,48 @@ | |||||||
|  | // Copyright 2017 The Gitea Authors. All rights reserved. | ||||||
|  | // Use of this source code is governed by a MIT-style | ||||||
|  | // license that can be found in the LICENSE file. | ||||||
|  |  | ||||||
|  | package util | ||||||
|  |  | ||||||
|  | import ( | ||||||
|  | 	"net/url" | ||||||
|  | 	"strings" | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | // urlSafeError wraps an error whose message may contain a sensitive URL | ||||||
|  | type urlSafeError struct { | ||||||
|  | 	err            error | ||||||
|  | 	unsanitizedURL string | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (err urlSafeError) Error() string { | ||||||
|  | 	return SanitizeMessage(err.err.Error(), err.unsanitizedURL) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // URLSanitizedError returns the sanitized version an error whose message may | ||||||
|  | // contain a sensitive URL | ||||||
|  | func URLSanitizedError(err error, unsanitizedURL string) error { | ||||||
|  | 	return urlSafeError{err: err, unsanitizedURL: unsanitizedURL} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // SanitizeMessage sanitizes a message which may contains a sensitive URL | ||||||
|  | func SanitizeMessage(message, unsanitizedURL string) string { | ||||||
|  | 	sanitizedURL := SanitizeURLCredentials(unsanitizedURL, true) | ||||||
|  | 	return strings.Replace(message, unsanitizedURL, sanitizedURL, -1) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // SanitizeURLCredentials sanitizes a url, either removing user credentials | ||||||
|  | // or replacing them with a placeholder. | ||||||
|  | func SanitizeURLCredentials(unsanitizedURL string, usePlaceholder bool) string { | ||||||
|  | 	u, err := url.Parse(unsanitizedURL) | ||||||
|  | 	if err != nil { | ||||||
|  | 		// don't log the error, since it might contain unsanitized URL. | ||||||
|  | 		return "(unparsable url)" | ||||||
|  | 	} | ||||||
|  | 	if u.User != nil && usePlaceholder { | ||||||
|  | 		u.User = url.User("<credentials>") | ||||||
|  | 	} else { | ||||||
|  | 		u.User = nil | ||||||
|  | 	} | ||||||
|  | 	return u.String() | ||||||
|  | } | ||||||
| @@ -9,8 +9,6 @@ import ( | |||||||
| 	"net/http" | 	"net/http" | ||||||
| 	"strings" | 	"strings" | ||||||
|  |  | ||||||
| 	api "code.gitea.io/sdk/gitea" |  | ||||||
|  |  | ||||||
| 	"code.gitea.io/gitea/models" | 	"code.gitea.io/gitea/models" | ||||||
| 	"code.gitea.io/gitea/modules/auth" | 	"code.gitea.io/gitea/modules/auth" | ||||||
| 	"code.gitea.io/gitea/modules/context" | 	"code.gitea.io/gitea/modules/context" | ||||||
| @@ -18,6 +16,7 @@ import ( | |||||||
| 	"code.gitea.io/gitea/modules/setting" | 	"code.gitea.io/gitea/modules/setting" | ||||||
| 	"code.gitea.io/gitea/modules/util" | 	"code.gitea.io/gitea/modules/util" | ||||||
| 	"code.gitea.io/gitea/routers/api/v1/convert" | 	"code.gitea.io/gitea/routers/api/v1/convert" | ||||||
|  | 	api "code.gitea.io/sdk/gitea" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| // Search repositories via options | // Search repositories via options | ||||||
| @@ -327,12 +326,13 @@ func Migrate(ctx *context.APIContext, form auth.MigrateRepoForm) { | |||||||
| 		RemoteAddr:  remoteAddr, | 		RemoteAddr:  remoteAddr, | ||||||
| 	}) | 	}) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
|  | 		err = util.URLSanitizedError(err, remoteAddr) | ||||||
| 		if repo != nil { | 		if repo != nil { | ||||||
| 			if errDelete := models.DeleteRepository(ctx.User, ctxUser.ID, repo.ID); errDelete != nil { | 			if errDelete := models.DeleteRepository(ctx.User, ctxUser.ID, repo.ID); errDelete != nil { | ||||||
| 				log.Error(4, "DeleteRepository: %v", errDelete) | 				log.Error(4, "DeleteRepository: %v", errDelete) | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| 		ctx.Error(500, "MigrateRepository", models.HandleCloneUserCredentials(err.Error(), true)) | 		ctx.Error(500, "MigrateRepository", err) | ||||||
| 		return | 		return | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|   | |||||||
| @@ -20,6 +20,7 @@ import ( | |||||||
| 	"code.gitea.io/gitea/modules/context" | 	"code.gitea.io/gitea/modules/context" | ||||||
| 	"code.gitea.io/gitea/modules/log" | 	"code.gitea.io/gitea/modules/log" | ||||||
| 	"code.gitea.io/gitea/modules/setting" | 	"code.gitea.io/gitea/modules/setting" | ||||||
|  | 	"code.gitea.io/gitea/modules/util" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| const ( | const ( | ||||||
| @@ -232,6 +233,9 @@ func MigratePost(ctx *context.Context, form auth.MigrateRepoForm) { | |||||||
| 		return | 		return | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | 	// remoteAddr may contain credentials, so we sanitize it | ||||||
|  | 	err = util.URLSanitizedError(err, remoteAddr) | ||||||
|  |  | ||||||
| 	if repo != nil { | 	if repo != nil { | ||||||
| 		if errDelete := models.DeleteRepository(ctx.User, ctxUser.ID, repo.ID); errDelete != nil { | 		if errDelete := models.DeleteRepository(ctx.User, ctxUser.ID, repo.ID); errDelete != nil { | ||||||
| 			log.Error(4, "DeleteRepository: %v", errDelete) | 			log.Error(4, "DeleteRepository: %v", errDelete) | ||||||
| @@ -241,11 +245,11 @@ func MigratePost(ctx *context.Context, form auth.MigrateRepoForm) { | |||||||
| 	if strings.Contains(err.Error(), "Authentication failed") || | 	if strings.Contains(err.Error(), "Authentication failed") || | ||||||
| 		strings.Contains(err.Error(), "could not read Username") { | 		strings.Contains(err.Error(), "could not read Username") { | ||||||
| 		ctx.Data["Err_Auth"] = true | 		ctx.Data["Err_Auth"] = true | ||||||
| 		ctx.RenderWithErr(ctx.Tr("form.auth_failed", models.HandleCloneUserCredentials(err.Error(), true)), tplMigrate, &form) | 		ctx.RenderWithErr(ctx.Tr("form.auth_failed", err.Error()), tplMigrate, &form) | ||||||
| 		return | 		return | ||||||
| 	} else if strings.Contains(err.Error(), "fatal:") { | 	} else if strings.Contains(err.Error(), "fatal:") { | ||||||
| 		ctx.Data["Err_CloneAddr"] = true | 		ctx.Data["Err_CloneAddr"] = true | ||||||
| 		ctx.RenderWithErr(ctx.Tr("repo.migrate.failed", models.HandleCloneUserCredentials(err.Error(), true)), tplMigrate, &form) | 		ctx.RenderWithErr(ctx.Tr("repo.migrate.failed", err.Error()), tplMigrate, &form) | ||||||
| 		return | 		return | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user