Merge pull request '[gitea] week 2024-38 cherry pick (gitea/main -> forgejo)' (#5325) from algernon/wcp/2024-38 into forgejo

Reviewed-on: https://codeberg.org/forgejo/forgejo/pulls/5325
Reviewed-by: Gusted <gusted@noreply.codeberg.org>
Reviewed-by: Earl Warren <earl-warren@noreply.codeberg.org>
This commit is contained in:
Earl Warren 2024-09-20 05:06:42 +00:00
commit 64d3fcd403
19 changed files with 181 additions and 35 deletions

View file

@ -163,6 +163,9 @@ code.gitea.io/gitea/modules/graceful
code.gitea.io/gitea/modules/hcaptcha code.gitea.io/gitea/modules/hcaptcha
WithHTTP WithHTTP
code.gitea.io/gitea/modules/hostmatcher
HostMatchList.AppendPattern
code.gitea.io/gitea/modules/json code.gitea.io/gitea/modules/json
StdJSON.Marshal StdJSON.Marshal
StdJSON.Unmarshal StdJSON.Unmarshal

View file

@ -63,9 +63,9 @@ func (cc *cacheContext) isDiscard() bool {
} }
// cacheContextLifetime is the max lifetime of cacheContext. // cacheContextLifetime is the max lifetime of cacheContext.
// Since cacheContext is used to cache data in a request level context, 10s is enough. // Since cacheContext is used to cache data in a request level context, 5 minutes is enough.
// If a cacheContext is used more than 10s, it's probably misuse. // If a cacheContext is used more than 5 minutes, it's probably misuse.
const cacheContextLifetime = 10 * time.Second const cacheContextLifetime = 5 * time.Minute
var timeNow = time.Now var timeNow = time.Now
@ -133,7 +133,7 @@ func GetContextData(ctx context.Context, tp, key any) any {
if c.Expired() { if c.Expired() {
// The warning means that the cache context is misused for long-life task, // The warning means that the cache context is misused for long-life task,
// it can be resolved with WithNoCacheContext(ctx). // it can be resolved with WithNoCacheContext(ctx).
log.Warn("cache context is expired, may be misused for long-life tasks: %v", c) log.Warn("cache context is expired, is highly likely to be misused for long-life tasks: %v", c)
return nil return nil
} }
return c.Get(tp, key) return c.Get(tp, key)
@ -146,7 +146,7 @@ func SetContextData(ctx context.Context, tp, key, value any) {
if c.Expired() { if c.Expired() {
// The warning means that the cache context is misused for long-life task, // The warning means that the cache context is misused for long-life task,
// it can be resolved with WithNoCacheContext(ctx). // it can be resolved with WithNoCacheContext(ctx).
log.Warn("cache context is expired, may be misused for long-life tasks: %v", c) log.Warn("cache context is expired, is highly likely to be misused for long-life tasks: %v", c)
return return
} }
c.Put(tp, key, value) c.Put(tp, key, value)
@ -159,7 +159,7 @@ func RemoveContextData(ctx context.Context, tp, key any) {
if c.Expired() { if c.Expired() {
// The warning means that the cache context is misused for long-life task, // The warning means that the cache context is misused for long-life task,
// it can be resolved with WithNoCacheContext(ctx). // it can be resolved with WithNoCacheContext(ctx).
log.Warn("cache context is expired, may be misused for long-life tasks: %v", c) log.Warn("cache context is expired, is highly likely to be misused for long-life tasks: %v", c)
return return
} }
c.Delete(tp, key) c.Delete(tp, key)

View file

@ -46,7 +46,7 @@ func TestWithCacheContext(t *testing.T) {
timeNow = now timeNow = now
}() }()
timeNow = func() time.Time { timeNow = func() time.Time {
return now().Add(10 * time.Second) return now().Add(5 * time.Minute)
} }
v = GetContextData(ctx, field, "my_config1") v = GetContextData(ctx, field, "my_config1")
assert.Nil(t, v) assert.Nil(t, v)

View file

@ -13,11 +13,7 @@ import (
) )
// NewDialContext returns a DialContext for Transport, the DialContext will do allow/block list check // NewDialContext returns a DialContext for Transport, the DialContext will do allow/block list check
func NewDialContext(usage string, allowList, blockList *HostMatchList) func(ctx context.Context, network, addr string) (net.Conn, error) { func NewDialContext(usage string, allowList, blockList *HostMatchList, proxy *url.URL) func(ctx context.Context, network, addr string) (net.Conn, error) {
return NewDialContextWithProxy(usage, allowList, blockList, nil)
}
func NewDialContextWithProxy(usage string, allowList, blockList *HostMatchList, proxy *url.URL) func(ctx context.Context, network, addr string) (net.Conn, error) {
// How Go HTTP Client works with redirection: // How Go HTTP Client works with redirection:
// transport.RoundTrip URL=http://domain.com, Host=domain.com // transport.RoundTrip URL=http://domain.com, Host=domain.com
// transport.DialContext addrOrHost=domain.com:80 // transport.DialContext addrOrHost=domain.com:80

14
options/gitignore/Hexo Normal file
View file

@ -0,0 +1,14 @@
# gitignore template for Hexo sites
# website: https://hexo.io/
# Recommended: Node.gitignore
# Ignore generated directory
public/
# Ignore temp files
tmp/
.tmp*
# additional files
db.json
.deploy*/

View file

@ -0,0 +1,3 @@
/node_modules/
/lib/
.bsb.lock

View file

@ -0,0 +1,3 @@
# Ignore the default terragrunt cache directory
# https://terragrunt.gruntwork.io/docs/features/caching/
.terragrunt-cache

View file

@ -0,0 +1,13 @@
Copyright 2005 Norman Walsh, Sun Microsystems,
Inc., and the Organization for the Advancement
of Structured Information Standards (OASIS).
Release: $Id: db4-upgrade.xsl 8905 2010-09-12 11:47:07Z bobstayton $
Permission to use, copy, modify and distribute this stylesheet
and its accompanying documentation for any purpose and
without fee is hereby granted in perpetuity, provided that
the above copyright notice and this paragraph appear in
all copies. The copyright holders make no representation
about the suitability of the schema for any purpose. It
is provided "as is" without expressed or implied warranty.

View file

@ -0,0 +1,10 @@
Additional permission under GPLv3 section 7:
If you modify this Program, or any covered work, by
linking or combining it with OpenSSL, or a modified
version of OpenSSL licensed under the OpenSSL license
(https://www.openssl.org/source/license.html), the licensors of this
Program grant you additional permission to convey the resulting work.
Corresponding Source for a non-source form of such a combination
shall include the source code for the parts that are licensed
under the OpenSSL license as well as that of the covered work.

30
options/license/MIT-Click Normal file
View file

@ -0,0 +1,30 @@
Portions of this software are subject to the license below. The relevant
source files are clearly marked; they refer to this file using the phrase
"the Click LICENSE file". This license is an MIT license, plus a clause
(taken from the W3C license) requiring prior written permission to use our
names in publicity.
===========================================================================
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
The name and trademarks of copyright holders may NOT be used in advertising
or publicity pertaining to the Software without specific, written prior
permission. Title to copyright in this Software and any associated
documentation will at all times remain with copyright holders.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.

View file

@ -0,0 +1,58 @@
Copyright (C) 2001-2015 American Radio Relay League, Inc. All rights
reserved.
Portions (C) 2003-2023 The TrustedQSL Developers. Please see the AUTHORS.txt
file for contributors.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Any redistribution of source code must retain the above copyright
notice, this list of conditions and the disclaimer shown in
Paragraph 5 (below).
2. Redistribution in binary form must reproduce the above copyright
notice, this list of conditions and the disclaimer shown in
Paragraph 5 (below) in the documentation and/or other materials
provided with the distribution.
3. Products derived from or including this software may not use
"Logbook of the World" or "LoTW" or any other American Radio Relay
League, Incorporated trademarks or servicemarks in their names
without prior written permission of the ARRL. See Paragraph 6
(below) for contact information.
4. Use of this software does not imply endorsement by ARRL of
products derived from or including this software and vendors may not
claim such endorsement.
5. Disclaimer: This software is provided "as-is" without
representation, guarantee or warranty of any kind, either express or
implied, including but not limited to the implied warranties of
merchantability or of fitness for a particular purpose. The entire
risk as to the quality and performance of the software is solely
with you. Should the software prove defective, you (and not the
American Radio Relay League, its officers, directors, employees or
agents) assume the entire cost of all necessary servicing, repair or
correction. In no event will ARRL be liable to you or to any third
party for any damages, whether direct or indirect, including lost
profits, lost savings, or other incidental or consequential damages
arising out of the use or inability to use such software, regardless
of whether ARRL has been advised of the possibility of such damages.
6. Contact information:
American Radio Relay League, Inc.
Attn: Logbook of the World Manager
225 Main St
Newington, CT 06111
voice: 860-594-0200
fax: 860-594-0259
email: logbook@arrl.org
Worldwide Web: www.arrl.org
This software consists of voluntary contributions made by many
individuals on behalf of the ARRL. More information on the "Logbook
of The World" project and the ARRL is available from the ARRL Web
site at www.arrl.org.

View file

@ -12,6 +12,7 @@ import (
"code.gitea.io/gitea/models/perm" "code.gitea.io/gitea/models/perm"
repo_model "code.gitea.io/gitea/models/repo" repo_model "code.gitea.io/gitea/models/repo"
"code.gitea.io/gitea/models/unit" "code.gitea.io/gitea/models/unit"
"code.gitea.io/gitea/modules/git"
api "code.gitea.io/gitea/modules/structs" api "code.gitea.io/gitea/modules/structs"
"code.gitea.io/gitea/modules/web" "code.gitea.io/gitea/modules/web"
"code.gitea.io/gitea/routers/api/v1/utils" "code.gitea.io/gitea/routers/api/v1/utils"
@ -252,6 +253,8 @@ func CreateRelease(ctx *context.APIContext) {
ctx.Error(http.StatusConflict, "ReleaseAlreadyExist", err) ctx.Error(http.StatusConflict, "ReleaseAlreadyExist", err)
} else if models.IsErrProtectedTagName(err) { } else if models.IsErrProtectedTagName(err) {
ctx.Error(http.StatusUnprocessableEntity, "ProtectedTagName", err) ctx.Error(http.StatusUnprocessableEntity, "ProtectedTagName", err)
} else if git.IsErrNotExist(err) {
ctx.Error(http.StatusNotFound, "ErrNotExist", fmt.Errorf("target \"%v\" not found: %w", rel.Target, err))
} else { } else {
ctx.Error(http.StatusInternalServerError, "CreateRelease", err) ctx.Error(http.StatusInternalServerError, "CreateRelease", err)
} }

View file

@ -236,12 +236,12 @@ func SignInPost(ctx *context.Context) {
if err != nil { if err != nil {
if errors.Is(err, util.ErrNotExist) || errors.Is(err, util.ErrInvalidArgument) { if errors.Is(err, util.ErrNotExist) || errors.Is(err, util.ErrInvalidArgument) {
ctx.RenderWithErr(ctx.Tr("form.username_password_incorrect"), tplSignIn, &form) ctx.RenderWithErr(ctx.Tr("form.username_password_incorrect"), tplSignIn, &form)
log.Info("Failed authentication attempt for %s from %s: %v", form.UserName, ctx.RemoteAddr(), err) log.Warn("Failed authentication attempt for %s from %s: %v", form.UserName, ctx.RemoteAddr(), err)
} else if user_model.IsErrEmailAlreadyUsed(err) { } else if user_model.IsErrEmailAlreadyUsed(err) {
ctx.RenderWithErr(ctx.Tr("form.email_been_used"), tplSignIn, &form) ctx.RenderWithErr(ctx.Tr("form.email_been_used"), tplSignIn, &form)
log.Info("Failed authentication attempt for %s from %s: %v", form.UserName, ctx.RemoteAddr(), err) log.Warn("Failed authentication attempt for %s from %s: %v", form.UserName, ctx.RemoteAddr(), err)
} else if user_model.IsErrUserProhibitLogin(err) { } else if user_model.IsErrUserProhibitLogin(err) {
log.Info("Failed authentication attempt for %s from %s: %v", form.UserName, ctx.RemoteAddr(), err) log.Warn("Failed authentication attempt for %s from %s: %v", form.UserName, ctx.RemoteAddr(), err)
ctx.Data["Title"] = ctx.Tr("auth.prohibit_login") ctx.Data["Title"] = ctx.Tr("auth.prohibit_login")
ctx.HTML(http.StatusOK, "user/auth/prohibit_login") ctx.HTML(http.StatusOK, "user/auth/prohibit_login")
} else if user_model.IsErrUserInactive(err) { } else if user_model.IsErrUserInactive(err) {
@ -249,7 +249,7 @@ func SignInPost(ctx *context.Context) {
ctx.Data["Title"] = ctx.Tr("auth.active_your_account") ctx.Data["Title"] = ctx.Tr("auth.active_your_account")
ctx.HTML(http.StatusOK, TplActivate) ctx.HTML(http.StatusOK, TplActivate)
} else { } else {
log.Info("Failed authentication attempt for %s from %s: %v", form.UserName, ctx.RemoteAddr(), err) log.Warn("Failed authentication attempt for %s from %s: %v", form.UserName, ctx.RemoteAddr(), err)
ctx.Data["Title"] = ctx.Tr("auth.prohibit_login") ctx.Data["Title"] = ctx.Tr("auth.prohibit_login")
ctx.HTML(http.StatusOK, "user/auth/prohibit_login") ctx.HTML(http.StatusOK, "user/auth/prohibit_login")
} }

View file

@ -480,6 +480,7 @@ func ToLFSLock(ctx context.Context, l *git_model.LFSLock) *api.LFSLock {
// ToChangedFile convert a gitdiff.DiffFile to api.ChangedFile // ToChangedFile convert a gitdiff.DiffFile to api.ChangedFile
func ToChangedFile(f *gitdiff.DiffFile, repo *repo_model.Repository, commit string) *api.ChangedFile { func ToChangedFile(f *gitdiff.DiffFile, repo *repo_model.Repository, commit string) *api.ChangedFile {
status := "changed" status := "changed"
previousFilename := ""
if f.IsDeleted { if f.IsDeleted {
status = "deleted" status = "deleted"
} else if f.IsCreated { } else if f.IsCreated {
@ -488,23 +489,21 @@ func ToChangedFile(f *gitdiff.DiffFile, repo *repo_model.Repository, commit stri
status = "copied" status = "copied"
} else if f.IsRenamed && f.Type == gitdiff.DiffFileRename { } else if f.IsRenamed && f.Type == gitdiff.DiffFileRename {
status = "renamed" status = "renamed"
previousFilename = f.OldName
} else if f.Addition == 0 && f.Deletion == 0 { } else if f.Addition == 0 && f.Deletion == 0 {
status = "unchanged" status = "unchanged"
} }
file := &api.ChangedFile{ file := &api.ChangedFile{
Filename: f.GetDiffFileName(), Filename: f.GetDiffFileName(),
Status: status, Status: status,
Additions: f.Addition, Additions: f.Addition,
Deletions: f.Deletion, Deletions: f.Deletion,
Changes: f.Addition + f.Deletion, Changes: f.Addition + f.Deletion,
HTMLURL: fmt.Sprint(repo.HTMLURL(), "/src/commit/", commit, "/", util.PathEscapeSegments(f.GetDiffFileName())), PreviousFilename: previousFilename,
ContentsURL: fmt.Sprint(repo.APIURL(), "/contents/", util.PathEscapeSegments(f.GetDiffFileName()), "?ref=", commit), HTMLURL: fmt.Sprint(repo.HTMLURL(), "/src/commit/", commit, "/", util.PathEscapeSegments(f.GetDiffFileName())),
RawURL: fmt.Sprint(repo.HTMLURL(), "/raw/commit/", commit, "/", util.PathEscapeSegments(f.GetDiffFileName())), ContentsURL: fmt.Sprint(repo.APIURL(), "/contents/", util.PathEscapeSegments(f.GetDiffFileName()), "?ref=", commit),
} RawURL: fmt.Sprint(repo.HTMLURL(), "/raw/commit/", commit, "/", util.PathEscapeSegments(f.GetDiffFileName())),
if status == "rename" {
file.PreviousFilename = f.OldName
} }
return file return file

View file

@ -24,6 +24,6 @@ func NewMigrationHTTPTransport() *http.Transport {
return &http.Transport{ return &http.Transport{
TLSClientConfig: &tls.Config{InsecureSkipVerify: setting.Migrations.SkipTLSVerify}, TLSClientConfig: &tls.Config{InsecureSkipVerify: setting.Migrations.SkipTLSVerify},
Proxy: proxy.Proxy(), Proxy: proxy.Proxy(),
DialContext: hostmatcher.NewDialContext("migration", allowList, blockList), DialContext: hostmatcher.NewDialContext("migration", allowList, blockList, setting.Proxy.ProxyURLFixed),
} }
} }

View file

@ -506,9 +506,5 @@ func Init() error {
// TODO: at the moment, if ALLOW_LOCALNETWORKS=false, ALLOWED_DOMAINS=domain.com, and domain.com has IP 127.0.0.1, then it's still allowed. // TODO: at the moment, if ALLOW_LOCALNETWORKS=false, ALLOWED_DOMAINS=domain.com, and domain.com has IP 127.0.0.1, then it's still allowed.
// if we want to block such case, the private&loopback should be added to the blockList when ALLOW_LOCALNETWORKS=false // if we want to block such case, the private&loopback should be added to the blockList when ALLOW_LOCALNETWORKS=false
if setting.Proxy.Enabled && setting.Proxy.ProxyURLFixed != nil {
allowList.AppendPattern(setting.Proxy.ProxyURLFixed.Host)
}
return nil return nil
} }

View file

@ -74,7 +74,7 @@ func createTag(ctx context.Context, gitRepo *git.Repository, rel *repo_model.Rel
commit, err := gitRepo.GetCommit(rel.Target) commit, err := gitRepo.GetCommit(rel.Target)
if err != nil { if err != nil {
return false, fmt.Errorf("createTag::GetCommit[%v]: %w", rel.Target, err) return false, err
} }
if len(msg) > 0 { if len(msg) > 0 {

View file

@ -212,7 +212,7 @@ func Init() error {
Transport: &http.Transport{ Transport: &http.Transport{
TLSClientConfig: &tls.Config{InsecureSkipVerify: setting.Webhook.SkipTLSVerify}, TLSClientConfig: &tls.Config{InsecureSkipVerify: setting.Webhook.SkipTLSVerify},
Proxy: webhookProxy(allowedHostMatcher), Proxy: webhookProxy(allowedHostMatcher),
DialContext: hostmatcher.NewDialContextWithProxy("webhook", allowedHostMatcher, nil, setting.Webhook.ProxyURLFixed), DialContext: hostmatcher.NewDialContext("webhook", allowedHostMatcher, nil, setting.Webhook.ProxyURLFixed),
}, },
} }

View file

@ -214,6 +214,24 @@ func TestAPICreateReleaseToDefaultBranchOnExistingTag(t *testing.T) {
createNewReleaseUsingAPI(t, token, owner, repo, "v0.0.1", "", "v0.0.1", "test") createNewReleaseUsingAPI(t, token, owner, repo, "v0.0.1", "", "v0.0.1", "test")
} }
func TestAPICreateReleaseGivenInvalidTarget(t *testing.T) {
defer tests.PrepareTestEnv(t)()
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1})
owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID})
session := loginUser(t, owner.LowerName)
token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeWriteRepository)
urlStr := fmt.Sprintf("/api/v1/repos/%s/%s/releases", owner.Name, repo.Name)
req := NewRequestWithJSON(t, "POST", urlStr, &api.CreateReleaseOption{
TagName: "i-point-to-an-invalid-target",
Title: "Invalid Target",
Target: "invalid-target",
}).AddTokenAuth(token)
MakeRequest(t, req, http.StatusNotFound)
}
func TestAPIGetLatestRelease(t *testing.T) { func TestAPIGetLatestRelease(t *testing.T) {
defer tests.PrepareTestEnv(t)() defer tests.PrepareTestEnv(t)()