mirror of
https://github.com/go-gitea/gitea.git
synced 2025-10-04 07:19:21 +02:00
Address some CodeQL security concerns (#35572)
Although there is no real security problem
This commit is contained in:
parent
c4532101a4
commit
71360a94cb
@ -151,6 +151,7 @@ func runCreateUser(ctx context.Context, c *cli.Command) error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
// codeql[disable-next-line=go/clear-text-logging]
|
||||||
fmt.Printf("generated random password is '%s'\n", password)
|
fmt.Printf("generated random password is '%s'\n", password)
|
||||||
} else if userType == user_model.UserTypeIndividual {
|
} else if userType == user_model.UserTypeIndividual {
|
||||||
return errors.New("must set either password or random-password flag")
|
return errors.New("must set either password or random-password flag")
|
||||||
|
@ -58,6 +58,7 @@ func runMustChangePassword(ctx context.Context, c *cli.Command) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// codeql[disable-next-line=go/clear-text-logging]
|
||||||
fmt.Printf("Updated %d users setting MustChangePassword to %t\n", n, mustChangePassword)
|
fmt.Printf("Updated %d users setting MustChangePassword to %t\n", n, mustChangePassword)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -91,6 +91,7 @@ func runGenerateSecretKey(_ context.Context, c *cli.Command) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// codeql[disable-next-line=go/clear-text-logging]
|
||||||
fmt.Printf("%s", secretKey)
|
fmt.Printf("%s", secretKey)
|
||||||
|
|
||||||
if isatty.IsTerminal(os.Stdout.Fd()) {
|
if isatty.IsTerminal(os.Stdout.Fd()) {
|
||||||
|
@ -186,7 +186,7 @@ Gitea or set your environment appropriately.`, "")
|
|||||||
userID, _ := strconv.ParseInt(os.Getenv(repo_module.EnvPusherID), 10, 64)
|
userID, _ := strconv.ParseInt(os.Getenv(repo_module.EnvPusherID), 10, 64)
|
||||||
prID, _ := strconv.ParseInt(os.Getenv(repo_module.EnvPRID), 10, 64)
|
prID, _ := strconv.ParseInt(os.Getenv(repo_module.EnvPRID), 10, 64)
|
||||||
deployKeyID, _ := strconv.ParseInt(os.Getenv(repo_module.EnvDeployKeyID), 10, 64)
|
deployKeyID, _ := strconv.ParseInt(os.Getenv(repo_module.EnvDeployKeyID), 10, 64)
|
||||||
actionPerm, _ := strconv.ParseInt(os.Getenv(repo_module.EnvActionPerm), 10, 64)
|
actionPerm, _ := strconv.Atoi(os.Getenv(repo_module.EnvActionPerm))
|
||||||
|
|
||||||
hookOptions := private.HookOptions{
|
hookOptions := private.HookOptions{
|
||||||
UserID: userID,
|
UserID: userID,
|
||||||
@ -196,7 +196,7 @@ Gitea or set your environment appropriately.`, "")
|
|||||||
GitPushOptions: pushOptions(),
|
GitPushOptions: pushOptions(),
|
||||||
PullRequestID: prID,
|
PullRequestID: prID,
|
||||||
DeployKeyID: deployKeyID,
|
DeployKeyID: deployKeyID,
|
||||||
ActionPerm: int(actionPerm),
|
ActionPerm: actionPerm,
|
||||||
}
|
}
|
||||||
|
|
||||||
scanner := bufio.NewScanner(os.Stdin)
|
scanner := bufio.NewScanner(os.Stdin)
|
||||||
|
@ -605,7 +605,7 @@ func (repo *Repository) IsGenerated() bool {
|
|||||||
|
|
||||||
// RepoPath returns repository path by given user and repository name.
|
// RepoPath returns repository path by given user and repository name.
|
||||||
func RepoPath(userName, repoName string) string { //revive:disable-line:exported
|
func RepoPath(userName, repoName string) string { //revive:disable-line:exported
|
||||||
return filepath.Join(user_model.UserPath(userName), strings.ToLower(repoName)+".git")
|
return filepath.Join(setting.RepoRootPath, filepath.Clean(strings.ToLower(userName)), filepath.Clean(strings.ToLower(repoName)+".git"))
|
||||||
}
|
}
|
||||||
|
|
||||||
// RepoPath returns the repository path
|
// RepoPath returns the repository path
|
||||||
|
@ -980,7 +980,7 @@ func GetInactiveUsers(ctx context.Context, olderThan time.Duration) ([]*User, er
|
|||||||
|
|
||||||
// UserPath returns the path absolute path of user repositories.
|
// UserPath returns the path absolute path of user repositories.
|
||||||
func UserPath(userName string) string { //revive:disable-line:exported
|
func UserPath(userName string) string { //revive:disable-line:exported
|
||||||
return filepath.Join(setting.RepoRootPath, strings.ToLower(userName))
|
return filepath.Join(setting.RepoRootPath, filepath.Clean(strings.ToLower(userName)))
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetUserByID returns the user object by given ID if exists.
|
// GetUserByID returns the user object by given ID if exists.
|
||||||
|
@ -61,17 +61,11 @@ func NewArgon2Hasher(config string) *Argon2Hasher {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
parsed, err := parseUIntParam(vals[0], "time", "argon2", config, nil)
|
var err error
|
||||||
hasher.time = uint32(parsed)
|
hasher.time, err = parseUintParam[uint32](vals[0], "time", "argon2", config, nil)
|
||||||
|
hasher.memory, err = parseUintParam[uint32](vals[1], "memory", "argon2", config, err)
|
||||||
parsed, err = parseUIntParam(vals[1], "memory", "argon2", config, err)
|
hasher.threads, err = parseUintParam[uint8](vals[2], "threads", "argon2", config, err)
|
||||||
hasher.memory = uint32(parsed)
|
hasher.keyLen, err = parseUintParam[uint32](vals[3], "keyLen", "argon2", config, err)
|
||||||
|
|
||||||
parsed, err = parseUIntParam(vals[2], "threads", "argon2", config, err)
|
|
||||||
hasher.threads = uint8(parsed)
|
|
||||||
|
|
||||||
parsed, err = parseUIntParam(vals[3], "keyLen", "argon2", config, err)
|
|
||||||
hasher.keyLen = uint32(parsed)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -7,6 +7,7 @@ import (
|
|||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
"code.gitea.io/gitea/modules/log"
|
"code.gitea.io/gitea/modules/log"
|
||||||
|
"code.gitea.io/gitea/modules/util"
|
||||||
)
|
)
|
||||||
|
|
||||||
func parseIntParam(value, param, algorithmName, config string, previousErr error) (int, error) {
|
func parseIntParam(value, param, algorithmName, config string, previousErr error) (int, error) {
|
||||||
@ -18,11 +19,12 @@ func parseIntParam(value, param, algorithmName, config string, previousErr error
|
|||||||
return parsed, previousErr // <- Keep the previous error as this function should still return an error once everything has been checked if any call failed
|
return parsed, previousErr // <- Keep the previous error as this function should still return an error once everything has been checked if any call failed
|
||||||
}
|
}
|
||||||
|
|
||||||
func parseUIntParam(value, param, algorithmName, config string, previousErr error) (uint64, error) { //nolint:unparam // algorithmName is always argon2
|
func parseUintParam[T uint32 | uint8](value, param, algorithmName, config string, previousErr error) (ret T, _ error) {
|
||||||
parsed, err := strconv.ParseUint(value, 10, 64)
|
_, isUint32 := any(ret).(uint32)
|
||||||
|
parsed, err := strconv.ParseUint(value, 10, util.Iif(isUint32, 32, 8))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("invalid integer for %s representation in %s hash spec %s", param, algorithmName, config)
|
log.Error("invalid integer for %s representation in %s hash spec %s", param, algorithmName, config)
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
return parsed, previousErr // <- Keep the previous error as this function should still return an error once everything has been checked if any call failed
|
return T(parsed), previousErr // <- Keep the previous error as this function should still return an error once everything has been checked if any call failed
|
||||||
}
|
}
|
||||||
|
@ -72,7 +72,7 @@ func newRequest(ctx context.Context, method, url string, body io.ReadCloser) (*h
|
|||||||
// Adding padding will make requests more secure, however is also slower
|
// Adding padding will make requests more secure, however is also slower
|
||||||
// because artificial responses will be added to the response
|
// because artificial responses will be added to the response
|
||||||
// For more information, see https://www.troyhunt.com/enhancing-pwned-passwords-privacy-with-padding/
|
// For more information, see https://www.troyhunt.com/enhancing-pwned-passwords-privacy-with-padding/
|
||||||
func (c *Client) CheckPassword(pw string, padding bool) (int, error) {
|
func (c *Client) CheckPassword(pw string, padding bool) (int64, error) {
|
||||||
if pw == "" {
|
if pw == "" {
|
||||||
return -1, ErrEmptyPassword
|
return -1, ErrEmptyPassword
|
||||||
}
|
}
|
||||||
@ -111,7 +111,7 @@ func (c *Client) CheckPassword(pw string, padding bool) (int, error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return -1, err
|
return -1, err
|
||||||
}
|
}
|
||||||
return int(count), nil
|
return count, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return 0, nil
|
return 0, nil
|
||||||
|
@ -37,25 +37,25 @@ func TestPassword(t *testing.T) {
|
|||||||
|
|
||||||
count, err := client.CheckPassword("", false)
|
count, err := client.CheckPassword("", false)
|
||||||
assert.ErrorIs(t, err, ErrEmptyPassword, "blank input should return ErrEmptyPassword")
|
assert.ErrorIs(t, err, ErrEmptyPassword, "blank input should return ErrEmptyPassword")
|
||||||
assert.Equal(t, -1, count)
|
assert.EqualValues(t, -1, count)
|
||||||
|
|
||||||
count, err = client.CheckPassword("pwned", false)
|
count, err = client.CheckPassword("pwned", false)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Equal(t, 1, count)
|
assert.EqualValues(t, 1, count)
|
||||||
|
|
||||||
count, err = client.CheckPassword("notpwned", false)
|
count, err = client.CheckPassword("notpwned", false)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Equal(t, 0, count)
|
assert.EqualValues(t, 0, count)
|
||||||
|
|
||||||
count, err = client.CheckPassword("paddedpwned", true)
|
count, err = client.CheckPassword("paddedpwned", true)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Equal(t, 1, count)
|
assert.EqualValues(t, 1, count)
|
||||||
|
|
||||||
count, err = client.CheckPassword("paddednotpwned", true)
|
count, err = client.CheckPassword("paddednotpwned", true)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Equal(t, 0, count)
|
assert.EqualValues(t, 0, count)
|
||||||
|
|
||||||
count, err = client.CheckPassword("paddednotpwnedzero", true)
|
count, err = client.CheckPassword("paddednotpwnedzero", true)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Equal(t, 0, count)
|
assert.EqualValues(t, 0, count)
|
||||||
}
|
}
|
||||||
|
@ -45,7 +45,7 @@ func GetHook(repoPath, name string) (*Hook, error) {
|
|||||||
}
|
}
|
||||||
h := &Hook{
|
h := &Hook{
|
||||||
name: name,
|
name: name,
|
||||||
path: filepath.Join(repoPath, "hooks", name+".d", name),
|
path: filepath.Join(repoPath, filepath.Join("hooks", name+".d", name)),
|
||||||
}
|
}
|
||||||
isFile, err := util.IsFile(h.path)
|
isFile, err := util.IsFile(h.path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -18,6 +18,7 @@ func GetLevel() Level {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func Log(skip int, level Level, format string, v ...any) {
|
func Log(skip int, level Level, format string, v ...any) {
|
||||||
|
// codeql[disable-next-line=go/clear-text-logging]
|
||||||
GetLogger(DEFAULT).Log(skip+1, &Event{Level: level}, format, v...)
|
GetLogger(DEFAULT).Log(skip+1, &Event{Level: level}, format, v...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -20,6 +20,7 @@ func BaseLoggerToGeneralLogger(b BaseLogger) Logger {
|
|||||||
var _ Logger = (*baseToLogger)(nil)
|
var _ Logger = (*baseToLogger)(nil)
|
||||||
|
|
||||||
func (s *baseToLogger) Log(skip int, event *Event, format string, v ...any) {
|
func (s *baseToLogger) Log(skip int, event *Event, format string, v ...any) {
|
||||||
|
// codeql[disable-next-line=go/clear-text-logging]
|
||||||
s.base.Log(skip+1, event, format, v...)
|
s.base.Log(skip+1, event, format, v...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -65,7 +65,7 @@ func decodeEnvSectionKey(encoded string) (ok bool, section, key string) {
|
|||||||
decodedBytes := make([]byte, len(toDecode)/2)
|
decodedBytes := make([]byte, len(toDecode)/2)
|
||||||
for i := 0; i < len(toDecode)/2; i++ {
|
for i := 0; i < len(toDecode)/2; i++ {
|
||||||
// Can ignore error here as we know these should be hexadecimal from the regexp
|
// Can ignore error here as we know these should be hexadecimal from the regexp
|
||||||
byteInt, _ := strconv.ParseInt(toDecode[2*i:2*i+2], 16, 0)
|
byteInt, _ := strconv.ParseInt(toDecode[2*i:2*i+2], 16, 8)
|
||||||
decodedBytes[i] = byte(byteInt)
|
decodedBytes[i] = byte(byteInt)
|
||||||
}
|
}
|
||||||
if inKey {
|
if inKey {
|
||||||
|
@ -19,7 +19,7 @@ type TempDir struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (td *TempDir) JoinPath(elems ...string) string {
|
func (td *TempDir) JoinPath(elems ...string) string {
|
||||||
return filepath.Join(append([]string{td.base, td.sub}, elems...)...)
|
return filepath.Join(append([]string{td.base, td.sub}, filepath.Join(elems...))...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// MkdirAllSub works like os.MkdirAll, but the base directory must exist
|
// MkdirAllSub works like os.MkdirAll, but the base directory must exist
|
||||||
|
@ -62,6 +62,9 @@ sub = Changed Sub String
|
|||||||
found := lang1.HasKey("no-such")
|
found := lang1.HasKey("no-such")
|
||||||
assert.False(t, found)
|
assert.False(t, found)
|
||||||
assert.NoError(t, ls.Close())
|
assert.NoError(t, ls.Close())
|
||||||
|
|
||||||
|
res := lang1.TrHTML("<no-such>")
|
||||||
|
assert.Equal(t, "<no-such>", string(res))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestLocaleStoreMoreSource(t *testing.T) {
|
func TestLocaleStoreMoreSource(t *testing.T) {
|
||||||
|
@ -6,6 +6,7 @@ package i18n
|
|||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"html"
|
||||||
"html/template"
|
"html/template"
|
||||||
"slices"
|
"slices"
|
||||||
|
|
||||||
@ -109,8 +110,7 @@ func (store *localeStore) Close() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (l *locale) TrString(trKey string, trArgs ...any) string {
|
func (l *locale) TrString(trKey string, trArgs ...any) string {
|
||||||
format := trKey
|
var format string
|
||||||
|
|
||||||
idx, ok := l.store.trKeyToIdxMap[trKey]
|
idx, ok := l.store.trKeyToIdxMap[trKey]
|
||||||
if ok {
|
if ok {
|
||||||
if msg, ok := l.idxToMsgMap[idx]; ok {
|
if msg, ok := l.idxToMsgMap[idx]; ok {
|
||||||
@ -122,7 +122,9 @@ func (l *locale) TrString(trKey string, trArgs ...any) string {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if format == "" {
|
||||||
|
format = html.EscapeString(trKey)
|
||||||
|
}
|
||||||
msg, err := Format(format, trArgs...)
|
msg, err := Format(format, trArgs...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("Error whilst formatting %q in %s: %v", trKey, l.langName, err)
|
log.Error("Error whilst formatting %q in %s: %v", trKey, l.langName, err)
|
||||||
|
@ -26,13 +26,14 @@ func HexToRBGColor(colorString string) (float64, float64, float64) {
|
|||||||
if len(hexString) == 8 {
|
if len(hexString) == 8 {
|
||||||
hexString = hexString[0:6]
|
hexString = hexString[0:6]
|
||||||
}
|
}
|
||||||
color, err := strconv.ParseUint(hexString, 16, 64)
|
color, err := strconv.ParseUint(hexString, 16, 32)
|
||||||
|
color32 := uint32(color)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, 0, 0
|
return 0, 0, 0
|
||||||
}
|
}
|
||||||
r := float64(uint8(0xFF & (uint32(color) >> 16)))
|
r := float64(uint8(0xFF & (color32 >> 16)))
|
||||||
g := float64(uint8(0xFF & (uint32(color) >> 8)))
|
g := float64(uint8(0xFF & (color32 >> 8)))
|
||||||
b := float64(uint8(0xFF & uint32(color)))
|
b := float64(uint8(0xFF & color32))
|
||||||
return r, g, b
|
return r, g, b
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -169,7 +169,7 @@ func MoveIssuePin(ctx *context.APIContext) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
err = issues_model.MovePin(ctx, issue, int(ctx.PathParamInt64("position")))
|
err = issues_model.MovePin(ctx, issue, ctx.PathParamInt("position"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.APIErrorInternal(err)
|
ctx.APIErrorInternal(err)
|
||||||
return
|
return
|
||||||
|
@ -35,7 +35,7 @@ type RepoSearchOptions struct {
|
|||||||
// This function is also used to render the Admin Repository Management page.
|
// This function is also used to render the Admin Repository Management page.
|
||||||
func RenderRepoSearch(ctx *context.Context, opts *RepoSearchOptions) {
|
func RenderRepoSearch(ctx *context.Context, opts *RepoSearchOptions) {
|
||||||
// Sitemap index for sitemap paths
|
// Sitemap index for sitemap paths
|
||||||
page := int(ctx.PathParamInt64("idx"))
|
page := ctx.PathParamInt("idx")
|
||||||
isSitemap := ctx.PathParam("idx") != ""
|
isSitemap := ctx.PathParam("idx") != ""
|
||||||
if page <= 1 {
|
if page <= 1 {
|
||||||
page = ctx.FormInt("page")
|
page = ctx.FormInt("page")
|
||||||
|
@ -34,7 +34,7 @@ func isKeywordValid(keyword string) bool {
|
|||||||
// RenderUserSearch render user search page
|
// RenderUserSearch render user search page
|
||||||
func RenderUserSearch(ctx *context.Context, opts user_model.SearchUserOptions, tplName templates.TplName) {
|
func RenderUserSearch(ctx *context.Context, opts user_model.SearchUserOptions, tplName templates.TplName) {
|
||||||
// Sitemap index for sitemap paths
|
// Sitemap index for sitemap paths
|
||||||
opts.Page = int(ctx.PathParamInt64("idx"))
|
opts.Page = ctx.PathParamInt("idx")
|
||||||
isSitemap := ctx.PathParam("idx") != ""
|
isSitemap := ctx.PathParam("idx") != ""
|
||||||
if opts.Page <= 1 {
|
if opts.Page <= 1 {
|
||||||
opts.Page = ctx.FormInt("page")
|
opts.Page = ctx.FormInt("page")
|
||||||
|
@ -25,33 +25,28 @@ func Activity(ctx *context.Context) {
|
|||||||
|
|
||||||
ctx.Data["PageIsPulse"] = true
|
ctx.Data["PageIsPulse"] = true
|
||||||
|
|
||||||
ctx.Data["Period"] = ctx.PathParam("period")
|
|
||||||
|
|
||||||
timeUntil := time.Now()
|
timeUntil := time.Now()
|
||||||
var timeFrom time.Time
|
period, timeFrom := "weekly", timeUntil.Add(-time.Hour*168)
|
||||||
|
switch ctx.PathParam("period") {
|
||||||
switch ctx.Data["Period"] {
|
|
||||||
case "daily":
|
case "daily":
|
||||||
timeFrom = timeUntil.Add(-time.Hour * 24)
|
period, timeFrom = "daily", timeUntil.Add(-time.Hour*24)
|
||||||
case "halfweekly":
|
case "halfweekly":
|
||||||
timeFrom = timeUntil.Add(-time.Hour * 72)
|
period, timeFrom = "halfweekly", timeUntil.Add(-time.Hour*72)
|
||||||
case "weekly":
|
case "weekly":
|
||||||
timeFrom = timeUntil.Add(-time.Hour * 168)
|
period, timeFrom = "weekly", timeUntil.Add(-time.Hour*168)
|
||||||
case "monthly":
|
case "monthly":
|
||||||
timeFrom = timeUntil.AddDate(0, -1, 0)
|
period, timeFrom = "monthly", timeUntil.AddDate(0, -1, 0)
|
||||||
case "quarterly":
|
case "quarterly":
|
||||||
timeFrom = timeUntil.AddDate(0, -3, 0)
|
period, timeFrom = "quarterly", timeUntil.AddDate(0, -3, 0)
|
||||||
case "semiyearly":
|
case "semiyearly":
|
||||||
timeFrom = timeUntil.AddDate(0, -6, 0)
|
period, timeFrom = "semiyearly", timeUntil.AddDate(0, -6, 0)
|
||||||
case "yearly":
|
case "yearly":
|
||||||
timeFrom = timeUntil.AddDate(-1, 0, 0)
|
period, timeFrom = "yearly", timeUntil.AddDate(-1, 0, 0)
|
||||||
default:
|
|
||||||
ctx.Data["Period"] = "weekly"
|
|
||||||
timeFrom = timeUntil.Add(-time.Hour * 168)
|
|
||||||
}
|
}
|
||||||
ctx.Data["DateFrom"] = timeFrom
|
ctx.Data["DateFrom"] = timeFrom
|
||||||
ctx.Data["DateUntil"] = timeUntil
|
ctx.Data["DateUntil"] = timeUntil
|
||||||
ctx.Data["PeriodText"] = ctx.Tr("repo.activity.period." + ctx.Data["Period"].(string))
|
ctx.Data["Period"] = period
|
||||||
|
ctx.Data["PeriodText"] = ctx.Tr("repo.activity.period." + period)
|
||||||
|
|
||||||
canReadCode := ctx.Repo.CanRead(unit.TypeCode)
|
canReadCode := ctx.Repo.CanRead(unit.TypeCode)
|
||||||
if canReadCode {
|
if canReadCode {
|
||||||
|
@ -376,7 +376,7 @@ func (h *serviceHandler) sendFile(ctx *context.Context, contentType, file string
|
|||||||
ctx.Resp.WriteHeader(http.StatusBadRequest)
|
ctx.Resp.WriteHeader(http.StatusBadRequest)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
reqFile := filepath.Join(h.getRepoDir(), file)
|
reqFile := filepath.Join(h.getRepoDir(), filepath.Clean(file))
|
||||||
|
|
||||||
fi, err := os.Stat(reqFile)
|
fi, err := os.Stat(reqFile)
|
||||||
if os.IsNotExist(err) {
|
if os.IsNotExist(err) {
|
||||||
@ -395,13 +395,12 @@ func (h *serviceHandler) sendFile(ctx *context.Context, contentType, file string
|
|||||||
var safeGitProtocolHeader = regexp.MustCompile(`^[0-9a-zA-Z]+=[0-9a-zA-Z]+(:[0-9a-zA-Z]+=[0-9a-zA-Z]+)*$`)
|
var safeGitProtocolHeader = regexp.MustCompile(`^[0-9a-zA-Z]+=[0-9a-zA-Z]+(:[0-9a-zA-Z]+=[0-9a-zA-Z]+)*$`)
|
||||||
|
|
||||||
func prepareGitCmdWithAllowedService(service string) (*gitcmd.Command, error) {
|
func prepareGitCmdWithAllowedService(service string) (*gitcmd.Command, error) {
|
||||||
if service == "receive-pack" {
|
if service == ServiceTypeReceivePack {
|
||||||
return gitcmd.NewCommand("receive-pack"), nil
|
return gitcmd.NewCommand(ServiceTypeReceivePack), nil
|
||||||
}
|
}
|
||||||
if service == "upload-pack" {
|
if service == ServiceTypeUploadPack {
|
||||||
return gitcmd.NewCommand("upload-pack"), nil
|
return gitcmd.NewCommand(ServiceTypeUploadPack), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil, fmt.Errorf("service %q is not allowed", service)
|
return nil, fmt.Errorf("service %q is not allowed", service)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -464,11 +463,16 @@ func serviceRPC(ctx *context.Context, h *serviceHandler, service string) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
ServiceTypeUploadPack = "upload-pack"
|
||||||
|
ServiceTypeReceivePack = "receive-pack"
|
||||||
|
)
|
||||||
|
|
||||||
// ServiceUploadPack implements Git Smart HTTP protocol
|
// ServiceUploadPack implements Git Smart HTTP protocol
|
||||||
func ServiceUploadPack(ctx *context.Context) {
|
func ServiceUploadPack(ctx *context.Context) {
|
||||||
h := httpBase(ctx)
|
h := httpBase(ctx)
|
||||||
if h != nil {
|
if h != nil {
|
||||||
serviceRPC(ctx, h, "upload-pack")
|
serviceRPC(ctx, h, ServiceTypeUploadPack)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -476,16 +480,18 @@ func ServiceUploadPack(ctx *context.Context) {
|
|||||||
func ServiceReceivePack(ctx *context.Context) {
|
func ServiceReceivePack(ctx *context.Context) {
|
||||||
h := httpBase(ctx)
|
h := httpBase(ctx)
|
||||||
if h != nil {
|
if h != nil {
|
||||||
serviceRPC(ctx, h, "receive-pack")
|
serviceRPC(ctx, h, ServiceTypeReceivePack)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func getServiceType(ctx *context.Context) string {
|
func getServiceType(ctx *context.Context) string {
|
||||||
serviceType := ctx.Req.FormValue("service")
|
switch ctx.Req.FormValue("service") {
|
||||||
if !strings.HasPrefix(serviceType, "git-") {
|
case "git-" + ServiceTypeUploadPack:
|
||||||
return ""
|
return ServiceTypeUploadPack
|
||||||
|
case "git-" + ServiceTypeReceivePack:
|
||||||
|
return ServiceTypeReceivePack
|
||||||
}
|
}
|
||||||
return strings.TrimPrefix(serviceType, "git-")
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
func updateServerInfo(ctx gocontext.Context, dir string) []byte {
|
func updateServerInfo(ctx gocontext.Context, dir string) []byte {
|
||||||
|
@ -279,7 +279,7 @@ func handleRepoViewSubmodule(ctx *context.Context, commitSubmoduleFile *git.Comm
|
|||||||
ctx.Data["NotFoundPrompt"] = redirectLink
|
ctx.Data["NotFoundPrompt"] = redirectLink
|
||||||
ctx.NotFound(nil)
|
ctx.NotFound(nil)
|
||||||
} else {
|
} else {
|
||||||
ctx.Redirect(submoduleWebLink.CommitWebLink)
|
ctx.RedirectToCurrentSite(redirectLink)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -31,7 +31,7 @@ func AvatarByUsernameSize(ctx *context.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
cacheableRedirect(ctx, user.AvatarLinkWithSize(ctx, int(ctx.PathParamInt64("size"))))
|
cacheableRedirect(ctx, user.AvatarLinkWithSize(ctx, ctx.PathParamInt("size")))
|
||||||
}
|
}
|
||||||
|
|
||||||
// AvatarByEmailHash redirects the browser to the email avatar link
|
// AvatarByEmailHash redirects the browser to the email avatar link
|
||||||
|
@ -10,6 +10,7 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"text/template"
|
"text/template"
|
||||||
"time"
|
"time"
|
||||||
|
"unicode"
|
||||||
|
|
||||||
user_model "code.gitea.io/gitea/models/user"
|
user_model "code.gitea.io/gitea/models/user"
|
||||||
"code.gitea.io/gitea/modules/log"
|
"code.gitea.io/gitea/modules/log"
|
||||||
@ -37,6 +38,16 @@ const keyOfRequestIDInTemplate = ".RequestID"
|
|||||||
// So, we accept a Request ID with a maximum character length of 40
|
// So, we accept a Request ID with a maximum character length of 40
|
||||||
const maxRequestIDByteLength = 40
|
const maxRequestIDByteLength = 40
|
||||||
|
|
||||||
|
func isSafeRequestID(id string) bool {
|
||||||
|
for _, r := range id {
|
||||||
|
safe := unicode.IsPrint(r)
|
||||||
|
if !safe {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
func parseRequestIDFromRequestHeader(req *http.Request) string {
|
func parseRequestIDFromRequestHeader(req *http.Request) string {
|
||||||
requestID := "-"
|
requestID := "-"
|
||||||
for _, key := range setting.Log.RequestIDHeaders {
|
for _, key := range setting.Log.RequestIDHeaders {
|
||||||
@ -45,6 +56,9 @@ func parseRequestIDFromRequestHeader(req *http.Request) string {
|
|||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if !isSafeRequestID(requestID) {
|
||||||
|
return "-"
|
||||||
|
}
|
||||||
if len(requestID) > maxRequestIDByteLength {
|
if len(requestID) > maxRequestIDByteLength {
|
||||||
requestID = requestID[:maxRequestIDByteLength] + "..."
|
requestID = requestID[:maxRequestIDByteLength] + "..."
|
||||||
}
|
}
|
||||||
|
@ -69,3 +69,8 @@ func TestAccessLogger(t *testing.T) {
|
|||||||
recorder.record(time.Date(2000, 1, 2, 3, 4, 5, 0, time.UTC), &testAccessLoggerResponseWriterMock{}, req)
|
recorder.record(time.Date(2000, 1, 2, 3, 4, 5, 0, time.UTC), &testAccessLoggerResponseWriterMock{}, req)
|
||||||
assert.Equal(t, []string{`remote-addr - - [02/Jan/2000:03:04:05 +0000] "GET /path https" 200 123123 "referer" "user-agent"`}, mockLogger.logs)
|
assert.Equal(t, []string{`remote-addr - - [02/Jan/2000:03:04:05 +0000] "GET /path https" 200 123123 "referer" "user-agent"`}, mockLogger.logs)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestAccessLoggerRequestID(t *testing.T) {
|
||||||
|
assert.False(t, isSafeRequestID("\x00"))
|
||||||
|
assert.True(t, isSafeRequestID("a b-c"))
|
||||||
|
}
|
||||||
|
@ -37,6 +37,11 @@ func (b *Base) PathParamInt64(p string) int64 {
|
|||||||
return v
|
return v
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (b *Base) PathParamInt(p string) int {
|
||||||
|
v, _ := strconv.Atoi(b.PathParam(p))
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
|
||||||
// SetPathParam set request path params into routes
|
// SetPathParam set request path params into routes
|
||||||
func (b *Base) SetPathParam(name, value string) {
|
func (b *Base) SetPathParam(name, value string) {
|
||||||
if strings.HasPrefix(name, ":") {
|
if strings.HasPrefix(name, ":") {
|
||||||
|
@ -1144,8 +1144,8 @@ $.api.settings = {
|
|||||||
},
|
},
|
||||||
|
|
||||||
regExp : {
|
regExp : {
|
||||||
required : /\{\$*[A-z0-9]+\}/g,
|
required : /\{\$*[_A-Za-z0-9]+\}/g, // GITEA-PATCH: use "_A-Za-z" instead of "A-z" for variable name matching
|
||||||
optional : /\{\/\$*[A-z0-9]+\}/g,
|
optional : /\{\/\$*[_A-Za-z0-9]+\}/g, // GITEA-PATCH: use "_A-Za-z" instead of "A-z" for variable name matching
|
||||||
},
|
},
|
||||||
|
|
||||||
className: {
|
className: {
|
||||||
|
@ -66,7 +66,7 @@ $.fn.dropdown = function(parameters) {
|
|||||||
moduleNamespace = 'module-' + namespace,
|
moduleNamespace = 'module-' + namespace,
|
||||||
|
|
||||||
$module = $(this),
|
$module = $(this),
|
||||||
$context = $(settings.context),
|
$context = (typeof settings.context === 'string') ? $(document).find(settings.context) : $(settings.context), // GITEA-PATCH: use "jQuery.find(selector)" instead of "jQuery(selector)"
|
||||||
$text = $module.find(selector.text),
|
$text = $module.find(selector.text),
|
||||||
$search = $module.find(selector.search),
|
$search = $module.find(selector.search),
|
||||||
$sizer = $module.find(selector.sizer),
|
$sizer = $module.find(selector.sizer),
|
||||||
|
@ -64,7 +64,7 @@ $.fn.modal = function(parameters) {
|
|||||||
moduleNamespace = 'module-' + namespace,
|
moduleNamespace = 'module-' + namespace,
|
||||||
|
|
||||||
$module = $(this),
|
$module = $(this),
|
||||||
$context = $(settings.context),
|
$context = (typeof settings.context === 'string') ? $(document).find(settings.context) : $(settings.context), // GITEA-PATCH: use "jQuery.find(selector)" instead of "jQuery(selector)"
|
||||||
$close = $module.find(selector.close),
|
$close = $module.find(selector.close),
|
||||||
|
|
||||||
$allModals,
|
$allModals,
|
||||||
|
@ -26,13 +26,13 @@ test('textareaSplitLines', () => {
|
|||||||
test('markdownHandleIndention', () => {
|
test('markdownHandleIndention', () => {
|
||||||
const testInput = (input: string, expected?: string) => {
|
const testInput = (input: string, expected?: string) => {
|
||||||
const inputPos = input.indexOf('|');
|
const inputPos = input.indexOf('|');
|
||||||
input = input.replace('|', '');
|
input = input.replaceAll('|', '');
|
||||||
const ret = markdownHandleIndention({value: input, selStart: inputPos, selEnd: inputPos});
|
const ret = markdownHandleIndention({value: input, selStart: inputPos, selEnd: inputPos});
|
||||||
if (expected === null) {
|
if (expected === null) {
|
||||||
expect(ret).toEqual({handled: false});
|
expect(ret).toEqual({handled: false});
|
||||||
} else {
|
} else {
|
||||||
const expectedPos = expected.indexOf('|');
|
const expectedPos = expected.indexOf('|');
|
||||||
expected = expected.replace('|', '');
|
expected = expected.replaceAll('|', '');
|
||||||
expect(ret).toEqual({
|
expect(ret).toEqual({
|
||||||
handled: true,
|
handled: true,
|
||||||
valueSelection: {value: expected, selStart: expectedPos, selEnd: expectedPos},
|
valueSelection: {value: expected, selStart: expectedPos, selEnd: expectedPos},
|
||||||
|
@ -333,7 +333,7 @@ export function initRepoPullRequestReview() {
|
|||||||
let ntr = tr.nextElementSibling;
|
let ntr = tr.nextElementSibling;
|
||||||
if (!ntr?.classList.contains('add-comment')) {
|
if (!ntr?.classList.contains('add-comment')) {
|
||||||
ntr = createElementFromHTML(`
|
ntr = createElementFromHTML(`
|
||||||
<tr class="add-comment" data-line-type="${lineType}">
|
<tr class="add-comment" data-line-type="${htmlEscape(lineType)}">
|
||||||
${isSplit ? `
|
${isSplit ? `
|
||||||
<td class="add-comment-left" colspan="4"></td>
|
<td class="add-comment-left" colspan="4"></td>
|
||||||
<td class="add-comment-right" colspan="4"></td>
|
<td class="add-comment-right" colspan="4"></td>
|
||||||
|
@ -14,4 +14,7 @@ export function linkLabelAndInput(label: Element, input: Element) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const fomanticQuery = $;
|
export function fomanticQuery(s: string | Element | NodeListOf<Element>): ReturnType<typeof $> {
|
||||||
|
// intentionally make it only work for query selector, it isn't used for creating HTML elements (for safety)
|
||||||
|
return typeof s === 'string' ? $(document).find(s) : $(s);
|
||||||
|
}
|
||||||
|
@ -35,7 +35,12 @@ export function isDarkTheme(): boolean {
|
|||||||
|
|
||||||
/** strip <tags> from a string */
|
/** strip <tags> from a string */
|
||||||
export function stripTags(text: string): string {
|
export function stripTags(text: string): string {
|
||||||
return text.replace(/<[^>]*>?/g, '');
|
let prev = '';
|
||||||
|
while (prev !== text) {
|
||||||
|
prev = text;
|
||||||
|
text = text.replace(/<[^>]*>?/g, '');
|
||||||
|
}
|
||||||
|
return text;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function parseIssueHref(href: string): IssuePathInfo {
|
export function parseIssueHref(href: string): IssuePathInfo {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user