Backport #30885 Fix #30883 Fix #29591 Co-authored-by: KN4CK3R <admin@oldschoolhack.me>
This commit is contained in:
parent
d410e2acce
commit
d4c2db39bf
|
@ -9,10 +9,10 @@ import (
|
||||||
"image/png"
|
"image/png"
|
||||||
"io"
|
"io"
|
||||||
"net/url"
|
"net/url"
|
||||||
"strings"
|
|
||||||
|
|
||||||
"code.gitea.io/gitea/models/db"
|
"code.gitea.io/gitea/models/db"
|
||||||
"code.gitea.io/gitea/modules/avatar"
|
"code.gitea.io/gitea/modules/avatar"
|
||||||
|
"code.gitea.io/gitea/modules/httplib"
|
||||||
"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/storage"
|
"code.gitea.io/gitea/modules/storage"
|
||||||
|
@ -84,13 +84,7 @@ func (repo *Repository) relAvatarLink(ctx context.Context) string {
|
||||||
return setting.AppSubURL + "/repo-avatars/" + url.PathEscape(repo.Avatar)
|
return setting.AppSubURL + "/repo-avatars/" + url.PathEscape(repo.Avatar)
|
||||||
}
|
}
|
||||||
|
|
||||||
// AvatarLink returns a link to the repository's avatar.
|
// AvatarLink returns the full avatar url with http host. TODO: refactor it to a relative URL, but it is still used in API response at the moment
|
||||||
func (repo *Repository) AvatarLink(ctx context.Context) string {
|
func (repo *Repository) AvatarLink(ctx context.Context) string {
|
||||||
link := repo.relAvatarLink(ctx)
|
return httplib.MakeAbsoluteURL(ctx, repo.relAvatarLink(ctx))
|
||||||
// we only prepend our AppURL to our known (relative, internal) avatar link to get an absolute URL
|
|
||||||
if strings.HasPrefix(link, "/") && !strings.HasPrefix(link, "//") {
|
|
||||||
return setting.AppURL + strings.TrimPrefix(link, setting.AppSubURL)[1:]
|
|
||||||
}
|
|
||||||
// otherwise, return the link as it is
|
|
||||||
return link
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,11 +9,11 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"image/png"
|
"image/png"
|
||||||
"io"
|
"io"
|
||||||
"strings"
|
|
||||||
|
|
||||||
"code.gitea.io/gitea/models/avatars"
|
"code.gitea.io/gitea/models/avatars"
|
||||||
"code.gitea.io/gitea/models/db"
|
"code.gitea.io/gitea/models/db"
|
||||||
"code.gitea.io/gitea/modules/avatar"
|
"code.gitea.io/gitea/modules/avatar"
|
||||||
|
"code.gitea.io/gitea/modules/httplib"
|
||||||
"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/storage"
|
"code.gitea.io/gitea/modules/storage"
|
||||||
|
@ -89,13 +89,9 @@ func (u *User) AvatarLinkWithSize(ctx context.Context, size int) string {
|
||||||
return avatars.GenerateEmailAvatarFastLink(ctx, u.AvatarEmail, size)
|
return avatars.GenerateEmailAvatarFastLink(ctx, u.AvatarEmail, size)
|
||||||
}
|
}
|
||||||
|
|
||||||
// AvatarLink returns the full avatar link with http host
|
// AvatarLink returns the full avatar url with http host. TODO: refactor it to a relative URL, but it is still used in API response at the moment
|
||||||
func (u *User) AvatarLink(ctx context.Context) string {
|
func (u *User) AvatarLink(ctx context.Context) string {
|
||||||
link := u.AvatarLinkWithSize(ctx, 0)
|
return httplib.MakeAbsoluteURL(ctx, u.AvatarLinkWithSize(ctx, 0))
|
||||||
if !strings.HasPrefix(link, "//") && !strings.Contains(link, "://") {
|
|
||||||
return setting.AppURL + strings.TrimPrefix(link, setting.AppSubURL+"/")
|
|
||||||
}
|
|
||||||
return link
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsUploadAvatarChanged returns true if the current user's avatar would be changed with the provided data
|
// IsUploadAvatarChanged returns true if the current user's avatar would be changed with the provided data
|
||||||
|
|
|
@ -4,6 +4,8 @@
|
||||||
package httplib
|
package httplib
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
@ -11,6 +13,10 @@ import (
|
||||||
"code.gitea.io/gitea/modules/util"
|
"code.gitea.io/gitea/modules/util"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type RequestContextKeyStruct struct{}
|
||||||
|
|
||||||
|
var RequestContextKey = RequestContextKeyStruct{}
|
||||||
|
|
||||||
func urlIsRelative(s string, u *url.URL) bool {
|
func urlIsRelative(s string, u *url.URL) bool {
|
||||||
// Unfortunately browsers consider a redirect Location with preceding "//", "\\", "/\" and "\/" as meaning redirect to "http(s)://REST_OF_PATH"
|
// Unfortunately browsers consider a redirect Location with preceding "//", "\\", "/\" and "\/" as meaning redirect to "http(s)://REST_OF_PATH"
|
||||||
// Therefore we should ignore these redirect locations to prevent open redirects
|
// Therefore we should ignore these redirect locations to prevent open redirects
|
||||||
|
@ -26,7 +32,56 @@ func IsRelativeURL(s string) bool {
|
||||||
return err == nil && urlIsRelative(s, u)
|
return err == nil && urlIsRelative(s, u)
|
||||||
}
|
}
|
||||||
|
|
||||||
func IsCurrentGiteaSiteURL(s string) bool {
|
func guessRequestScheme(req *http.Request, def string) string {
|
||||||
|
// https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Forwarded-Proto
|
||||||
|
if s := req.Header.Get("X-Forwarded-Proto"); s != "" {
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
if s := req.Header.Get("X-Forwarded-Protocol"); s != "" {
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
if s := req.Header.Get("X-Url-Scheme"); s != "" {
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
if s := req.Header.Get("Front-End-Https"); s != "" {
|
||||||
|
return util.Iif(s == "on", "https", "http")
|
||||||
|
}
|
||||||
|
if s := req.Header.Get("X-Forwarded-Ssl"); s != "" {
|
||||||
|
return util.Iif(s == "on", "https", "http")
|
||||||
|
}
|
||||||
|
return def
|
||||||
|
}
|
||||||
|
|
||||||
|
func guessForwardedHost(req *http.Request) string {
|
||||||
|
// https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Forwarded-Host
|
||||||
|
return req.Header.Get("X-Forwarded-Host")
|
||||||
|
}
|
||||||
|
|
||||||
|
// GuessCurrentAppURL tries to guess the current full URL by http headers. It always has a '/' suffix, exactly the same as setting.AppURL
|
||||||
|
func GuessCurrentAppURL(ctx context.Context) string {
|
||||||
|
req, ok := ctx.Value(RequestContextKey).(*http.Request)
|
||||||
|
if !ok {
|
||||||
|
return setting.AppURL
|
||||||
|
}
|
||||||
|
if host := guessForwardedHost(req); host != "" {
|
||||||
|
// if it is behind a reverse proxy, use "https" as default scheme in case the site admin forgets to set the correct forwarded-protocol headers
|
||||||
|
return guessRequestScheme(req, "https") + "://" + host + setting.AppSubURL + "/"
|
||||||
|
} else if req.Host != "" {
|
||||||
|
// if it is not behind a reverse proxy, use the scheme from config options, meanwhile use "https" as much as possible
|
||||||
|
defaultScheme := util.Iif(setting.Protocol == "http", "http", "https")
|
||||||
|
return guessRequestScheme(req, defaultScheme) + "://" + req.Host + setting.AppSubURL + "/"
|
||||||
|
}
|
||||||
|
return setting.AppURL
|
||||||
|
}
|
||||||
|
|
||||||
|
func MakeAbsoluteURL(ctx context.Context, s string) string {
|
||||||
|
if IsRelativeURL(s) {
|
||||||
|
return GuessCurrentAppURL(ctx) + strings.TrimPrefix(s, "/")
|
||||||
|
}
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
func IsCurrentGiteaSiteURL(ctx context.Context, s string) bool {
|
||||||
u, err := url.Parse(s)
|
u, err := url.Parse(s)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false
|
return false
|
||||||
|
@ -45,5 +100,6 @@ func IsCurrentGiteaSiteURL(s string) bool {
|
||||||
if u.Path == "" {
|
if u.Path == "" {
|
||||||
u.Path = "/"
|
u.Path = "/"
|
||||||
}
|
}
|
||||||
return strings.HasPrefix(strings.ToLower(u.String()), strings.ToLower(setting.AppURL))
|
urlLower := strings.ToLower(u.String())
|
||||||
|
return strings.HasPrefix(urlLower, strings.ToLower(setting.AppURL)) || strings.HasPrefix(urlLower, strings.ToLower(GuessCurrentAppURL(ctx)))
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,8 @@
|
||||||
package httplib
|
package httplib
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
|
"net/http"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"code.gitea.io/gitea/modules/setting"
|
"code.gitea.io/gitea/modules/setting"
|
||||||
|
@ -37,9 +39,44 @@ func TestIsRelativeURL(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestMakeAbsoluteURL(t *testing.T) {
|
||||||
|
defer test.MockVariableValue(&setting.Protocol, "http")()
|
||||||
|
defer test.MockVariableValue(&setting.AppURL, "http://the-host/sub/")()
|
||||||
|
defer test.MockVariableValue(&setting.AppSubURL, "/sub")()
|
||||||
|
|
||||||
|
ctx := context.Background()
|
||||||
|
assert.Equal(t, "http://the-host/sub/", MakeAbsoluteURL(ctx, ""))
|
||||||
|
assert.Equal(t, "http://the-host/sub/foo", MakeAbsoluteURL(ctx, "foo"))
|
||||||
|
assert.Equal(t, "http://the-host/sub/foo", MakeAbsoluteURL(ctx, "/foo"))
|
||||||
|
assert.Equal(t, "http://other/foo", MakeAbsoluteURL(ctx, "http://other/foo"))
|
||||||
|
|
||||||
|
ctx = context.WithValue(ctx, RequestContextKey, &http.Request{
|
||||||
|
Host: "user-host",
|
||||||
|
})
|
||||||
|
assert.Equal(t, "http://user-host/sub/foo", MakeAbsoluteURL(ctx, "/foo"))
|
||||||
|
|
||||||
|
ctx = context.WithValue(ctx, RequestContextKey, &http.Request{
|
||||||
|
Host: "user-host",
|
||||||
|
Header: map[string][]string{
|
||||||
|
"X-Forwarded-Host": {"forwarded-host"},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
assert.Equal(t, "https://forwarded-host/sub/foo", MakeAbsoluteURL(ctx, "/foo"))
|
||||||
|
|
||||||
|
ctx = context.WithValue(ctx, RequestContextKey, &http.Request{
|
||||||
|
Host: "user-host",
|
||||||
|
Header: map[string][]string{
|
||||||
|
"X-Forwarded-Host": {"forwarded-host"},
|
||||||
|
"X-Forwarded-Proto": {"https"},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
assert.Equal(t, "https://forwarded-host/sub/foo", MakeAbsoluteURL(ctx, "/foo"))
|
||||||
|
}
|
||||||
|
|
||||||
func TestIsCurrentGiteaSiteURL(t *testing.T) {
|
func TestIsCurrentGiteaSiteURL(t *testing.T) {
|
||||||
defer test.MockVariableValue(&setting.AppURL, "http://localhost:3000/sub/")()
|
defer test.MockVariableValue(&setting.AppURL, "http://localhost:3000/sub/")()
|
||||||
defer test.MockVariableValue(&setting.AppSubURL, "/sub")()
|
defer test.MockVariableValue(&setting.AppSubURL, "/sub")()
|
||||||
|
ctx := context.Background()
|
||||||
good := []string{
|
good := []string{
|
||||||
"?key=val",
|
"?key=val",
|
||||||
"/sub",
|
"/sub",
|
||||||
|
@ -50,7 +87,7 @@ func TestIsCurrentGiteaSiteURL(t *testing.T) {
|
||||||
"http://localhost:3000/sub/",
|
"http://localhost:3000/sub/",
|
||||||
}
|
}
|
||||||
for _, s := range good {
|
for _, s := range good {
|
||||||
assert.True(t, IsCurrentGiteaSiteURL(s), "good = %q", s)
|
assert.True(t, IsCurrentGiteaSiteURL(ctx, s), "good = %q", s)
|
||||||
}
|
}
|
||||||
bad := []string{
|
bad := []string{
|
||||||
".",
|
".",
|
||||||
|
@ -64,13 +101,23 @@ func TestIsCurrentGiteaSiteURL(t *testing.T) {
|
||||||
"http://other/",
|
"http://other/",
|
||||||
}
|
}
|
||||||
for _, s := range bad {
|
for _, s := range bad {
|
||||||
assert.False(t, IsCurrentGiteaSiteURL(s), "bad = %q", s)
|
assert.False(t, IsCurrentGiteaSiteURL(ctx, s), "bad = %q", s)
|
||||||
}
|
}
|
||||||
|
|
||||||
setting.AppURL = "http://localhost:3000/"
|
setting.AppURL = "http://localhost:3000/"
|
||||||
setting.AppSubURL = ""
|
setting.AppSubURL = ""
|
||||||
assert.False(t, IsCurrentGiteaSiteURL("//"))
|
assert.False(t, IsCurrentGiteaSiteURL(ctx, "//"))
|
||||||
assert.False(t, IsCurrentGiteaSiteURL("\\\\"))
|
assert.False(t, IsCurrentGiteaSiteURL(ctx, "\\\\"))
|
||||||
assert.False(t, IsCurrentGiteaSiteURL("http://localhost"))
|
assert.False(t, IsCurrentGiteaSiteURL(ctx, "http://localhost"))
|
||||||
assert.True(t, IsCurrentGiteaSiteURL("http://localhost:3000?key=val"))
|
assert.True(t, IsCurrentGiteaSiteURL(ctx, "http://localhost:3000?key=val"))
|
||||||
|
|
||||||
|
ctx = context.WithValue(ctx, RequestContextKey, &http.Request{
|
||||||
|
Host: "user-host",
|
||||||
|
Header: map[string][]string{
|
||||||
|
"X-Forwarded-Host": {"forwarded-host"},
|
||||||
|
"X-Forwarded-Proto": {"https"},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
assert.True(t, IsCurrentGiteaSiteURL(ctx, "http://localhost:3000"))
|
||||||
|
assert.True(t, IsCurrentGiteaSiteURL(ctx, "https://forwarded-host"))
|
||||||
}
|
}
|
||||||
|
|
|
@ -42,7 +42,7 @@ func renderCodeBlock(ctx *RenderContext, node *html.Node) (urlPosStart, urlPosSt
|
||||||
CommitID: node.Data[m[6]:m[7]],
|
CommitID: node.Data[m[6]:m[7]],
|
||||||
FilePath: node.Data[m[8]:m[9]],
|
FilePath: node.Data[m[8]:m[9]],
|
||||||
}
|
}
|
||||||
if !httplib.IsCurrentGiteaSiteURL(opts.FullURL) {
|
if !httplib.IsCurrentGiteaSiteURL(ctx.Ctx, opts.FullURL) {
|
||||||
return 0, 0, "", nil
|
return 0, 0, "", nil
|
||||||
}
|
}
|
||||||
u, err := url.Parse(opts.FilePath)
|
u, err := url.Parse(opts.FilePath)
|
||||||
|
|
|
@ -71,6 +71,7 @@ import (
|
||||||
|
|
||||||
"code.gitea.io/gitea/models/actions"
|
"code.gitea.io/gitea/models/actions"
|
||||||
"code.gitea.io/gitea/models/db"
|
"code.gitea.io/gitea/models/db"
|
||||||
|
"code.gitea.io/gitea/modules/httplib"
|
||||||
"code.gitea.io/gitea/modules/json"
|
"code.gitea.io/gitea/modules/json"
|
||||||
"code.gitea.io/gitea/modules/log"
|
"code.gitea.io/gitea/modules/log"
|
||||||
"code.gitea.io/gitea/modules/setting"
|
"code.gitea.io/gitea/modules/setting"
|
||||||
|
@ -184,8 +185,8 @@ type artifactRoutes struct {
|
||||||
fs storage.ObjectStorage
|
fs storage.ObjectStorage
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ar artifactRoutes) buildArtifactURL(runID int64, artifactHash, suffix string) string {
|
func (ar artifactRoutes) buildArtifactURL(ctx *ArtifactContext, runID int64, artifactHash, suffix string) string {
|
||||||
uploadURL := strings.TrimSuffix(setting.AppURL, "/") + strings.TrimSuffix(ar.prefix, "/") +
|
uploadURL := strings.TrimSuffix(httplib.GuessCurrentAppURL(ctx), "/") + strings.TrimSuffix(ar.prefix, "/") +
|
||||||
strings.ReplaceAll(artifactRouteBase, "{run_id}", strconv.FormatInt(runID, 10)) +
|
strings.ReplaceAll(artifactRouteBase, "{run_id}", strconv.FormatInt(runID, 10)) +
|
||||||
"/" + artifactHash + "/" + suffix
|
"/" + artifactHash + "/" + suffix
|
||||||
return uploadURL
|
return uploadURL
|
||||||
|
@ -224,7 +225,7 @@ func (ar artifactRoutes) getUploadArtifactURL(ctx *ArtifactContext) {
|
||||||
// use md5(artifact_name) to create upload url
|
// use md5(artifact_name) to create upload url
|
||||||
artifactHash := fmt.Sprintf("%x", md5.Sum([]byte(req.Name)))
|
artifactHash := fmt.Sprintf("%x", md5.Sum([]byte(req.Name)))
|
||||||
resp := getUploadArtifactResponse{
|
resp := getUploadArtifactResponse{
|
||||||
FileContainerResourceURL: ar.buildArtifactURL(runID, artifactHash, "upload"+retentionQuery),
|
FileContainerResourceURL: ar.buildArtifactURL(ctx, runID, artifactHash, "upload"+retentionQuery),
|
||||||
}
|
}
|
||||||
log.Debug("[artifact] get upload url: %s", resp.FileContainerResourceURL)
|
log.Debug("[artifact] get upload url: %s", resp.FileContainerResourceURL)
|
||||||
ctx.JSON(http.StatusOK, resp)
|
ctx.JSON(http.StatusOK, resp)
|
||||||
|
@ -365,7 +366,7 @@ func (ar artifactRoutes) listArtifacts(ctx *ArtifactContext) {
|
||||||
artifactHash := fmt.Sprintf("%x", md5.Sum([]byte(art.ArtifactName)))
|
artifactHash := fmt.Sprintf("%x", md5.Sum([]byte(art.ArtifactName)))
|
||||||
item := listArtifactsResponseItem{
|
item := listArtifactsResponseItem{
|
||||||
Name: art.ArtifactName,
|
Name: art.ArtifactName,
|
||||||
FileContainerResourceURL: ar.buildArtifactURL(runID, artifactHash, "download_url"),
|
FileContainerResourceURL: ar.buildArtifactURL(ctx, runID, artifactHash, "download_url"),
|
||||||
}
|
}
|
||||||
items = append(items, item)
|
items = append(items, item)
|
||||||
values[art.ArtifactName] = true
|
values[art.ArtifactName] = true
|
||||||
|
@ -437,7 +438,7 @@ func (ar artifactRoutes) getDownloadArtifactURL(ctx *ArtifactContext) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if downloadURL == "" {
|
if downloadURL == "" {
|
||||||
downloadURL = ar.buildArtifactURL(runID, strconv.FormatInt(artifact.ID, 10), "download")
|
downloadURL = ar.buildArtifactURL(ctx, runID, strconv.FormatInt(artifact.ID, 10), "download")
|
||||||
}
|
}
|
||||||
item := downloadArtifactResponseItem{
|
item := downloadArtifactResponseItem{
|
||||||
Path: util.PathJoinRel(itemPath, artifact.ArtifactPath),
|
Path: util.PathJoinRel(itemPath, artifact.ArtifactPath),
|
||||||
|
|
|
@ -92,6 +92,7 @@ import (
|
||||||
|
|
||||||
"code.gitea.io/gitea/models/actions"
|
"code.gitea.io/gitea/models/actions"
|
||||||
"code.gitea.io/gitea/models/db"
|
"code.gitea.io/gitea/models/db"
|
||||||
|
"code.gitea.io/gitea/modules/httplib"
|
||||||
"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/storage"
|
"code.gitea.io/gitea/modules/storage"
|
||||||
|
@ -160,9 +161,9 @@ func (r artifactV4Routes) buildSignature(endp, expires, artifactName string, tas
|
||||||
return mac.Sum(nil)
|
return mac.Sum(nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r artifactV4Routes) buildArtifactURL(endp, artifactName string, taskID int64) string {
|
func (r artifactV4Routes) buildArtifactURL(ctx *ArtifactContext, endp, artifactName string, taskID int64) string {
|
||||||
expires := time.Now().Add(60 * time.Minute).Format("2006-01-02 15:04:05.999999999 -0700 MST")
|
expires := time.Now().Add(60 * time.Minute).Format("2006-01-02 15:04:05.999999999 -0700 MST")
|
||||||
uploadURL := strings.TrimSuffix(setting.AppURL, "/") + strings.TrimSuffix(r.prefix, "/") +
|
uploadURL := strings.TrimSuffix(httplib.GuessCurrentAppURL(ctx), "/") + strings.TrimSuffix(r.prefix, "/") +
|
||||||
"/" + endp + "?sig=" + base64.URLEncoding.EncodeToString(r.buildSignature(endp, expires, artifactName, taskID)) + "&expires=" + url.QueryEscape(expires) + "&artifactName=" + url.QueryEscape(artifactName) + "&taskID=" + fmt.Sprint(taskID)
|
"/" + endp + "?sig=" + base64.URLEncoding.EncodeToString(r.buildSignature(endp, expires, artifactName, taskID)) + "&expires=" + url.QueryEscape(expires) + "&artifactName=" + url.QueryEscape(artifactName) + "&taskID=" + fmt.Sprint(taskID)
|
||||||
return uploadURL
|
return uploadURL
|
||||||
}
|
}
|
||||||
|
@ -278,7 +279,7 @@ func (r *artifactV4Routes) createArtifact(ctx *ArtifactContext) {
|
||||||
|
|
||||||
respData := CreateArtifactResponse{
|
respData := CreateArtifactResponse{
|
||||||
Ok: true,
|
Ok: true,
|
||||||
SignedUploadUrl: r.buildArtifactURL("UploadArtifact", artifactName, ctx.ActionTask.ID),
|
SignedUploadUrl: r.buildArtifactURL(ctx, "UploadArtifact", artifactName, ctx.ActionTask.ID),
|
||||||
}
|
}
|
||||||
r.sendProtbufBody(ctx, &respData)
|
r.sendProtbufBody(ctx, &respData)
|
||||||
}
|
}
|
||||||
|
@ -454,7 +455,7 @@ func (r *artifactV4Routes) getSignedArtifactURL(ctx *ArtifactContext) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if respData.SignedUrl == "" {
|
if respData.SignedUrl == "" {
|
||||||
respData.SignedUrl = r.buildArtifactURL("DownloadArtifact", artifactName, ctx.ActionTask.ID)
|
respData.SignedUrl = r.buildArtifactURL(ctx, "DownloadArtifact", artifactName, ctx.ActionTask.ID)
|
||||||
}
|
}
|
||||||
r.sendProtbufBody(ctx, &respData)
|
r.sendProtbufBody(ctx, &respData)
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,6 +17,7 @@ import (
|
||||||
packages_model "code.gitea.io/gitea/models/packages"
|
packages_model "code.gitea.io/gitea/models/packages"
|
||||||
container_model "code.gitea.io/gitea/models/packages/container"
|
container_model "code.gitea.io/gitea/models/packages/container"
|
||||||
user_model "code.gitea.io/gitea/models/user"
|
user_model "code.gitea.io/gitea/models/user"
|
||||||
|
"code.gitea.io/gitea/modules/httplib"
|
||||||
"code.gitea.io/gitea/modules/json"
|
"code.gitea.io/gitea/modules/json"
|
||||||
"code.gitea.io/gitea/modules/log"
|
"code.gitea.io/gitea/modules/log"
|
||||||
packages_module "code.gitea.io/gitea/modules/packages"
|
packages_module "code.gitea.io/gitea/modules/packages"
|
||||||
|
@ -115,7 +116,7 @@ func apiErrorDefined(ctx *context.Context, err *namedError) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func apiUnauthorizedError(ctx *context.Context) {
|
func apiUnauthorizedError(ctx *context.Context) {
|
||||||
ctx.Resp.Header().Add("WWW-Authenticate", `Bearer realm="`+setting.AppURL+`v2/token",service="container_registry",scope="*"`)
|
ctx.Resp.Header().Add("WWW-Authenticate", `Bearer realm="`+httplib.GuessCurrentAppURL(ctx)+`v2/token",service="container_registry",scope="*"`)
|
||||||
apiErrorDefined(ctx, errUnauthorized)
|
apiErrorDefined(ctx, errUnauthorized)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,11 +4,13 @@
|
||||||
package common
|
package common
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
go_context "context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"code.gitea.io/gitea/modules/cache"
|
"code.gitea.io/gitea/modules/cache"
|
||||||
|
"code.gitea.io/gitea/modules/httplib"
|
||||||
"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/web/middleware"
|
"code.gitea.io/gitea/modules/web/middleware"
|
||||||
|
@ -34,6 +36,7 @@ func ProtocolMiddlewares() (handlers []any) {
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
req = req.WithContext(middleware.WithContextData(req.Context()))
|
req = req.WithContext(middleware.WithContextData(req.Context()))
|
||||||
|
req = req.WithContext(go_context.WithValue(req.Context(), httplib.RequestContextKey, req))
|
||||||
next.ServeHTTP(resp, req)
|
next.ServeHTTP(resp, req)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
|
@ -17,7 +17,7 @@ func FetchRedirectDelegate(resp http.ResponseWriter, req *http.Request) {
|
||||||
// The typical page is "issue comment" page. The backend responds "/owner/repo/issues/1#comment-2",
|
// The typical page is "issue comment" page. The backend responds "/owner/repo/issues/1#comment-2",
|
||||||
// then frontend needs this delegate to redirect to the new location with hash correctly.
|
// then frontend needs this delegate to redirect to the new location with hash correctly.
|
||||||
redirect := req.PostFormValue("redirect")
|
redirect := req.PostFormValue("redirect")
|
||||||
if !httplib.IsCurrentGiteaSiteURL(redirect) {
|
if !httplib.IsCurrentGiteaSiteURL(req.Context(), redirect) {
|
||||||
resp.WriteHeader(http.StatusBadRequest)
|
resp.WriteHeader(http.StatusBadRequest)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
|
@ -368,7 +368,7 @@ func handleSignInFull(ctx *context.Context, u *user_model.User, remember, obeyRe
|
||||||
return setting.AppSubURL + "/"
|
return setting.AppSubURL + "/"
|
||||||
}
|
}
|
||||||
|
|
||||||
if redirectTo := ctx.GetSiteCookie("redirect_to"); redirectTo != "" && httplib.IsCurrentGiteaSiteURL(redirectTo) {
|
if redirectTo := ctx.GetSiteCookie("redirect_to"); redirectTo != "" && httplib.IsCurrentGiteaSiteURL(ctx, redirectTo) {
|
||||||
middleware.DeleteRedirectToCookie(ctx.Resp)
|
middleware.DeleteRedirectToCookie(ctx.Resp)
|
||||||
if obeyRedirect {
|
if obeyRedirect {
|
||||||
ctx.RedirectToCurrentSite(redirectTo)
|
ctx.RedirectToCurrentSite(redirectTo)
|
||||||
|
|
|
@ -254,7 +254,7 @@ func (b *Base) Redirect(location string, status ...int) {
|
||||||
code = status[0]
|
code = status[0]
|
||||||
}
|
}
|
||||||
|
|
||||||
if strings.HasPrefix(location, "http://") || strings.HasPrefix(location, "https://") || strings.HasPrefix(location, "//") {
|
if !httplib.IsRelativeURL(location) {
|
||||||
// Some browsers (Safari) have buggy behavior for Cookie + Cache + External Redirection, eg: /my-path => https://other/path
|
// Some browsers (Safari) have buggy behavior for Cookie + Cache + External Redirection, eg: /my-path => https://other/path
|
||||||
// 1. the first request to "/my-path" contains cookie
|
// 1. the first request to "/my-path" contains cookie
|
||||||
// 2. some time later, the request to "/my-path" doesn't contain cookie (caused by Prevent web tracking)
|
// 2. some time later, the request to "/my-path" doesn't contain cookie (caused by Prevent web tracking)
|
||||||
|
|
|
@ -52,7 +52,7 @@ func (ctx *Context) RedirectToCurrentSite(location ...string) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if !httplib.IsCurrentGiteaSiteURL(loc) {
|
if !httplib.IsCurrentGiteaSiteURL(ctx, loc) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user