mirror of
https://github.com/go-gitea/gitea.git
synced 2026-09-28 13:25:23 +02:00
Merge branch 'main' into ssh-mirror-migrations
Signed-off-by: pomidorry <106489913+Pomidorry@users.noreply.github.com>
This commit is contained in:
@@ -0,0 +1,29 @@
|
||||
// Copyright 2026 The Gitea Authors. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package actions
|
||||
|
||||
import (
|
||||
"crypto/hmac"
|
||||
"crypto/sha256"
|
||||
"encoding/binary"
|
||||
"io"
|
||||
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
)
|
||||
|
||||
type tagType string
|
||||
|
||||
// BuildSignature builds a hmac signature for the input values.
|
||||
// "tag" is an internal pre-defined static string to distinguish the signatures for different purpose.
|
||||
func BuildSignature(tag tagType, vals ...string) []byte {
|
||||
m := hmac.New(sha256.New, setting.GetGeneralTokenSigningSecret())
|
||||
_, _ = io.WriteString(m, string(tag))
|
||||
var buf8 [8]byte
|
||||
for _, v := range vals {
|
||||
binary.LittleEndian.PutUint64(buf8[:], uint64(len(v)))
|
||||
_, _ = m.Write(buf8[:])
|
||||
_, _ = io.WriteString(m, v)
|
||||
}
|
||||
return m.Sum(nil)
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
// Copyright 2026 The Gitea Authors. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package actions
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestBuildSignature(t *testing.T) {
|
||||
a := BuildSignature("v0", "x")
|
||||
b := BuildSignature("v0", "x")
|
||||
assert.Equal(t, a, b)
|
||||
|
||||
a = BuildSignature("v0", "x", "yz")
|
||||
b = BuildSignature("v0", "xy", "z")
|
||||
assert.NotEqual(t, a, b)
|
||||
|
||||
a = BuildSignature("v1", "x")
|
||||
b = BuildSignature("v2", "x")
|
||||
assert.NotEqual(t, a, b)
|
||||
|
||||
a = BuildSignature("v0", "x")
|
||||
b = BuildSignature("v0x")
|
||||
assert.NotEqual(t, a, b)
|
||||
|
||||
a = BuildSignature("v0", "", "x")
|
||||
b = BuildSignature("v0", "x", "")
|
||||
assert.NotEqual(t, a, b)
|
||||
|
||||
a = BuildSignature("v0")
|
||||
b = BuildSignature("v0")
|
||||
assert.Equal(t, a, b)
|
||||
}
|
||||
@@ -22,7 +22,7 @@ func TestRenderCodePreview(t *testing.T) {
|
||||
},
|
||||
})
|
||||
test := func(input, expected string) {
|
||||
buffer, err := markup.RenderString(markup.NewTestRenderContext().WithMarkupType(markdown.MarkupName), input)
|
||||
buffer, err := testRenderString(markup.NewTestRenderContext().WithMarkupType(markdown.MarkupName), input)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, strings.TrimSpace(expected), strings.TrimSpace(buffer))
|
||||
}
|
||||
|
||||
@@ -24,10 +24,16 @@ var (
|
||||
localMetas = map[string]string{"user": testRepoOwnerName, "repo": testRepoName}
|
||||
)
|
||||
|
||||
func testRenderString(ctx *markup.RenderContext, content string) (string, error) {
|
||||
var buf strings.Builder
|
||||
err := markup.Render(ctx, strings.NewReader(content), &buf)
|
||||
return buf.String(), err
|
||||
}
|
||||
|
||||
func TestRender_Commits(t *testing.T) {
|
||||
test := func(input, expected string) {
|
||||
rctx := markup.NewTestRenderContext(markup.TestAppURL, localMetas).WithRelativePath("a.md")
|
||||
buffer, err := markup.RenderString(rctx, input)
|
||||
buffer, err := testRenderString(rctx, input)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, strings.TrimSpace(expected), strings.TrimSpace(buffer))
|
||||
}
|
||||
@@ -75,7 +81,7 @@ func TestRender_CrossReferences(t *testing.T) {
|
||||
defer testModule.MockVariableValue(&markup.RenderBehaviorForTesting.DisableAdditionalAttributes, true)()
|
||||
test := func(input, expected string) {
|
||||
rctx := markup.NewTestRenderContext(markup.TestAppURL, localMetas).WithRelativePath("a.md")
|
||||
buffer, err := markup.RenderString(rctx, input)
|
||||
buffer, err := testRenderString(rctx, input)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, strings.TrimSpace(expected), strings.TrimSpace(buffer))
|
||||
}
|
||||
@@ -119,7 +125,7 @@ func TestRender_links(t *testing.T) {
|
||||
setting.AppURL = markup.TestAppURL
|
||||
defer testModule.MockVariableValue(&markup.RenderBehaviorForTesting.DisableAdditionalAttributes, true)()
|
||||
test := func(input, expected string) {
|
||||
buffer, err := markup.RenderString(markup.NewTestRenderContext().WithRelativePath("a.md"), input)
|
||||
buffer, err := testRenderString(markup.NewTestRenderContext().WithRelativePath("a.md"), input)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, strings.TrimSpace(expected), strings.TrimSpace(buffer))
|
||||
}
|
||||
@@ -234,7 +240,7 @@ func TestRender_email(t *testing.T) {
|
||||
setting.AppURL = markup.TestAppURL
|
||||
defer testModule.MockVariableValue(&markup.RenderBehaviorForTesting.DisableAdditionalAttributes, true)()
|
||||
test := func(input, expected string) {
|
||||
res, err := markup.RenderString(markup.NewTestRenderContext().WithRelativePath("a.md"), input)
|
||||
res, err := testRenderString(markup.NewTestRenderContext().WithRelativePath("a.md"), input)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, strings.TrimSpace(expected), strings.TrimSpace(res), "input: %s", input)
|
||||
}
|
||||
@@ -321,7 +327,7 @@ func TestRender_emoji(t *testing.T) {
|
||||
|
||||
test := func(input, expected string) {
|
||||
expected = strings.ReplaceAll(expected, "&", "&")
|
||||
buffer, err := markup.RenderString(markup.NewTestRenderContext().WithRelativePath("a.md"), input)
|
||||
buffer, err := testRenderString(markup.NewTestRenderContext().WithRelativePath("a.md"), input)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, strings.TrimSpace(expected), strings.TrimSpace(buffer))
|
||||
}
|
||||
|
||||
@@ -119,12 +119,33 @@ func (r *HTMLRenderer) RegisterFuncs(reg renderer.NodeRendererFuncRegisterer) {
|
||||
reg.Register(KindDetails, r.renderDetails)
|
||||
reg.Register(KindSummary, r.renderSummary)
|
||||
reg.Register(ast.KindCodeSpan, r.renderCodeSpan)
|
||||
reg.Register(ast.KindCodeBlock, r.renderCodeBlock)
|
||||
reg.Register(KindAttention, r.renderAttention)
|
||||
reg.Register(KindTaskCheckBoxListItem, r.renderTaskCheckBoxListItem)
|
||||
reg.Register(east.KindTaskCheckBox, r.renderTaskCheckBox)
|
||||
reg.Register(KindRawHTML, r.renderRawHTML)
|
||||
}
|
||||
|
||||
// renderCodeBlock wraps indented code blocks like the fenced renderer
|
||||
func (r *HTMLRenderer) renderCodeBlock(w util.BufWriter, source []byte, n ast.Node, entering bool) (ast.WalkStatus, error) {
|
||||
if entering {
|
||||
opening := r.renderInternal.ProtectSafeAttrs(`<div class="code-block-container code-overflow-scroll"><pre class="code-block"><code>`)
|
||||
if _, err := w.WriteString(string(opening)); err != nil {
|
||||
return ast.WalkStop, err
|
||||
}
|
||||
lines := n.Lines()
|
||||
for i := 0; i < lines.Len(); i++ {
|
||||
line := lines.At(i)
|
||||
r.Writer.RawWrite(w, line.Value(source))
|
||||
}
|
||||
} else {
|
||||
if _, err := w.WriteString("</code></pre></div>"); err != nil {
|
||||
return ast.WalkStop, err
|
||||
}
|
||||
}
|
||||
return ast.WalkContinue, nil
|
||||
}
|
||||
|
||||
func (r *HTMLRenderer) renderDocument(w util.BufWriter, source []byte, node ast.Node, entering bool) (ast.WalkStatus, error) {
|
||||
n := node.(*ast.Document)
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@ import (
|
||||
"io"
|
||||
"strings"
|
||||
|
||||
"code.gitea.io/gitea/modules/htmlutil"
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
"code.gitea.io/gitea/modules/markup"
|
||||
"code.gitea.io/gitea/modules/markup/common"
|
||||
@@ -266,7 +267,9 @@ func Render(ctx *markup.RenderContext, input io.Reader, output io.Writer) error
|
||||
func RenderString(ctx *markup.RenderContext, content string) (template.HTML, error) {
|
||||
var buf strings.Builder
|
||||
if err := Render(ctx, strings.NewReader(content), &buf); err != nil {
|
||||
return "", err
|
||||
log.Warn("Unable to RenderString: %v, content: %s", err, giteautil.TruncateRunes(content, 200))
|
||||
err = nil
|
||||
return htmlutil.EscapeString(content), err
|
||||
}
|
||||
return template.HTML(buf.String()), nil
|
||||
}
|
||||
|
||||
@@ -601,7 +601,7 @@ func TestMarkdownUlDir(t *testing.T) {
|
||||
`, string(result))
|
||||
}
|
||||
|
||||
func TestMarkdownFencedCodeBlock(t *testing.T) {
|
||||
func TestMarkdownCodeBlock(t *testing.T) {
|
||||
testRender := func(input, expected string) {
|
||||
buffer, err := markdown.RenderString(markup.NewTestRenderContext(), input)
|
||||
assert.NoError(t, err)
|
||||
@@ -618,4 +618,6 @@ func TestMarkdownFencedCodeBlock(t *testing.T) {
|
||||
testRender("```js:app.ts\ncode\n```", jsCommon)
|
||||
testRender("```js,ignore\ncode\n```", jsCommon)
|
||||
testRender("```js ignore\ncode\n```", jsCommon)
|
||||
testRender(" code\n", prefix+`<code>code`+nl+`</code>`+suffix)
|
||||
testRender(" <script>alert(1)</script>\n", prefix+`<code><script>alert(1)</script>`+nl+`</code>`+suffix)
|
||||
}
|
||||
|
||||
@@ -198,15 +198,6 @@ func Render(rctx *RenderContext, origInput io.Reader, output io.Writer) error {
|
||||
return RenderWithRenderer(rctx, renderer, input, output)
|
||||
}
|
||||
|
||||
// RenderString renders Markup string to HTML with all specific handling stuff and return string
|
||||
func RenderString(ctx *RenderContext, content string) (string, error) {
|
||||
var buf strings.Builder
|
||||
if err := Render(ctx, strings.NewReader(content), &buf); err != nil {
|
||||
return "", err
|
||||
}
|
||||
return buf.String(), nil
|
||||
}
|
||||
|
||||
func RenderIFrame(ctx *RenderContext, opts *ExternalRendererOptions, output io.Writer) error {
|
||||
ownerName, repoName := ctx.RenderOptions.Metas["user"], ctx.RenderOptions.Metas["repo"]
|
||||
refSubURL := ctx.RenderOptions.Metas["RefTypeNameSubURL"]
|
||||
|
||||
@@ -237,7 +237,7 @@ var (
|
||||
AddCoCommitterTrailers: true,
|
||||
RetargetChildrenOnMerge: true,
|
||||
DelayCheckForInactiveDays: 7,
|
||||
DefaultTitleSource: RepoPRTitleSourceFirstCommit,
|
||||
DefaultTitleSource: RepoPRTitleSourceAuto,
|
||||
},
|
||||
|
||||
// Issue settings
|
||||
|
||||
+4
-7
@@ -155,7 +155,6 @@ func sessionHandler(session ssh.Session) {
|
||||
process.SetSysProcAttribute(cmd)
|
||||
|
||||
wg := &sync.WaitGroup{}
|
||||
wg.Add(2)
|
||||
|
||||
if err = cmd.Start(); err != nil {
|
||||
log.Error("SSH: Start: %v", err)
|
||||
@@ -169,21 +168,19 @@ func sessionHandler(session ssh.Session) {
|
||||
}
|
||||
}()
|
||||
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
wg.Go(func() {
|
||||
defer stdout.Close()
|
||||
if _, err := io.Copy(session, stdout); err != nil {
|
||||
log.Error("Failed to write stdout to session. %s", err)
|
||||
}
|
||||
}()
|
||||
})
|
||||
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
wg.Go(func() {
|
||||
defer stderr.Close()
|
||||
if _, err := io.Copy(session.Stderr(), stderr); err != nil {
|
||||
log.Error("Failed to write stderr to session. %s", err)
|
||||
}
|
||||
}()
|
||||
})
|
||||
|
||||
// Ensure all the output has been written before we wait on the command
|
||||
// to exit.
|
||||
|
||||
@@ -54,17 +54,14 @@ func TestScopedTemplateSetFuncMap(t *testing.T) {
|
||||
out1 := bytes.Buffer{}
|
||||
out2 := bytes.Buffer{}
|
||||
wg := sync.WaitGroup{}
|
||||
wg.Add(2)
|
||||
go func() {
|
||||
wg.Go(func() {
|
||||
err := ts.newExecutor(funcMap1).Execute(&out1, nil)
|
||||
assert.NoError(t, err)
|
||||
wg.Done()
|
||||
}()
|
||||
go func() {
|
||||
})
|
||||
wg.Go(func() {
|
||||
err := ts.newExecutor(funcMap2).Execute(&out2, nil)
|
||||
assert.NoError(t, err)
|
||||
wg.Done()
|
||||
}()
|
||||
})
|
||||
wg.Wait()
|
||||
assert.Equal(t, "base1\ntest1\nbase1\ntest1", out1.String())
|
||||
assert.Equal(t, "base2\ntest2\nbase2\ntest2", out2.String())
|
||||
|
||||
@@ -121,23 +121,7 @@ func (ut *RenderUtils) RenderIssueSimpleTitle(text string) template.HTML {
|
||||
return ret
|
||||
}
|
||||
|
||||
func (ut *RenderUtils) RenderLabelWithLink(label *issues_model.Label, link any) template.HTML {
|
||||
var attrHref template.HTML
|
||||
switch link.(type) {
|
||||
case template.URL, string:
|
||||
attrHref = htmlutil.HTMLFormat(`href="%s"`, link)
|
||||
default:
|
||||
panic(fmt.Sprintf("unexpected type %T for link", link))
|
||||
}
|
||||
return ut.renderLabelWithTag(label, "a", attrHref)
|
||||
}
|
||||
|
||||
func (ut *RenderUtils) RenderLabel(label *issues_model.Label) template.HTML {
|
||||
return ut.renderLabelWithTag(label, "span", "")
|
||||
}
|
||||
|
||||
// RenderLabel renders a label
|
||||
func (ut *RenderUtils) renderLabelWithTag(label *issues_model.Label, tagName, tagAttrs template.HTML) template.HTML {
|
||||
locale := ut.ctx.Value(translation.ContextKey).(translation.Locale)
|
||||
var extraCSSClasses string
|
||||
textColor := util.ContrastColor(label.Color)
|
||||
@@ -151,8 +135,8 @@ func (ut *RenderUtils) renderLabelWithTag(label *issues_model.Label, tagName, ta
|
||||
|
||||
if labelScope == "" {
|
||||
// Regular label
|
||||
return htmlutil.HTMLFormat(`<%s %s class="ui label %s" style="color: %s !important; background-color: %s !important;" data-tooltip-content title="%s"><span class="gt-ellipsis">%s</span></%s>`,
|
||||
tagName, tagAttrs, extraCSSClasses, textColor, label.Color, descriptionText, ut.RenderEmoji(label.Name), tagName)
|
||||
return htmlutil.HTMLFormat(`<span class="ui label %s" style="color: %s !important; background-color: %s !important;" data-tooltip-content title="%s"><span class="gt-ellipsis">%s</span></span>`,
|
||||
extraCSSClasses, textColor, label.Color, descriptionText, ut.RenderEmoji(label.Name))
|
||||
}
|
||||
|
||||
// Scoped label
|
||||
@@ -187,29 +171,25 @@ func (ut *RenderUtils) renderLabelWithTag(label *issues_model.Label, tagName, ta
|
||||
|
||||
if label.ExclusiveOrder > 0 {
|
||||
// <scope> | <label> | <order>
|
||||
return htmlutil.HTMLFormat(`<%s %s class="ui label %s scope-parent" data-tooltip-content title="%s">`+
|
||||
return htmlutil.HTMLFormat(`<span class="ui label %s scope-parent" data-tooltip-content title="%s">`+
|
||||
`<div class="ui label scope-left" style="color: %s !important; background-color: %s !important">%s</div>`+
|
||||
`<div class="ui label scope-middle" style="color: %s !important; background-color: %s !important">%s</div>`+
|
||||
`<div class="ui label scope-right">%d</div>`+
|
||||
`</%s>`,
|
||||
tagName, tagAttrs,
|
||||
`</span>`,
|
||||
extraCSSClasses, descriptionText,
|
||||
textColor, scopeColor, scopeHTML,
|
||||
textColor, itemColor, itemHTML,
|
||||
label.ExclusiveOrder,
|
||||
tagName)
|
||||
label.ExclusiveOrder)
|
||||
}
|
||||
|
||||
// <scope> | <label>
|
||||
return htmlutil.HTMLFormat(`<%s %s class="ui label %s scope-parent" data-tooltip-content title="%s">`+
|
||||
return htmlutil.HTMLFormat(`<span class="ui label %s scope-parent" data-tooltip-content title="%s">`+
|
||||
`<div class="ui label scope-left" style="color: %s !important; background-color: %s !important">%s</div>`+
|
||||
`<div class="ui label scope-right" style="color: %s !important; background-color: %s !important">%s</div>`+
|
||||
`</%s>`,
|
||||
tagName, tagAttrs,
|
||||
`</span>`,
|
||||
extraCSSClasses, descriptionText,
|
||||
textColor, scopeColor, scopeHTML,
|
||||
textColor, itemColor, itemHTML,
|
||||
tagName)
|
||||
textColor, itemColor, itemHTML)
|
||||
}
|
||||
|
||||
// RenderEmoji renders html text with emoji post processors
|
||||
@@ -246,18 +226,19 @@ func (ut *RenderUtils) MarkdownToHtml(input string) template.HTML { //nolint:rev
|
||||
func (ut *RenderUtils) RenderLabels(labels []*issues_model.Label, repoLink string, issue *issues_model.Issue) template.HTML {
|
||||
isPullRequest := issue != nil && issue.IsPull
|
||||
baseLink := fmt.Sprintf("%s/%s", repoLink, util.Iif(isPullRequest, "pulls", "issues"))
|
||||
var htmlCode strings.Builder
|
||||
htmlCode.WriteString(`<span class="labels-list">`)
|
||||
var htmlCode htmlutil.HTMLBuilder
|
||||
htmlCode.WriteHTML(`<span class="labels-list">`)
|
||||
for _, label := range labels {
|
||||
// Protect against nil value in labels - shouldn't happen but would cause a panic if so
|
||||
if label == nil {
|
||||
continue
|
||||
}
|
||||
link := fmt.Sprintf("%s?labels=%d", baseLink, label.ID)
|
||||
htmlCode.WriteString(string(ut.RenderLabelWithLink(label, template.URL(link))))
|
||||
htmlCode.WriteFormat(`<a class="item" href="%s?labels=%d">`, baseLink, label.ID)
|
||||
htmlCode.WriteHTML(ut.RenderLabel(label))
|
||||
htmlCode.WriteHTML("</a>")
|
||||
}
|
||||
htmlCode.WriteString("</span>")
|
||||
return template.HTML(htmlCode.String())
|
||||
htmlCode.WriteHTML("</span>")
|
||||
return htmlCode.HTMLString()
|
||||
}
|
||||
|
||||
func (ut *RenderUtils) RenderThemeItem(info *webtheme.ThemeMetaInfo, iconSize int) template.HTML {
|
||||
|
||||
@@ -206,16 +206,15 @@ func TestRenderLabels(t *testing.T) {
|
||||
expected = `/owner/repo/pulls?labels=123`
|
||||
assert.Contains(t, ut.RenderLabels([]*issues.Label{label}, "/owner/repo", issue), expected)
|
||||
|
||||
expectedLabel := `<a href="<>" class="ui label " style="color: #fff !important; background-color: label-color !important;" data-tooltip-content title=""><span class="gt-ellipsis">label-name</span></a>`
|
||||
assert.Equal(t, expectedLabel, string(ut.RenderLabelWithLink(label, "<>")))
|
||||
assert.Equal(t, expectedLabel, string(ut.RenderLabelWithLink(label, template.URL("<>"))))
|
||||
expectedLabel := `<span class="ui label " style="color: #fff !important; background-color: label-color !important;" data-tooltip-content title=""><span class="gt-ellipsis">label-name</span></span>`
|
||||
assert.Equal(t, expectedLabel, string(ut.RenderLabel(label)))
|
||||
|
||||
label = &issues.Label{ID: 123, Name: "</>", Exclusive: true}
|
||||
expectedLabel = `<a href="" class="ui label scope-parent" data-tooltip-content title=""><div class="ui label scope-left" style="color: #fff !important; background-color: #000000 !important"><</div><div class="ui label scope-right" style="color: #fff !important; background-color: #000000 !important">></div></a>`
|
||||
assert.Equal(t, expectedLabel, string(ut.RenderLabelWithLink(label, "")))
|
||||
expectedLabel = `<span class="ui label scope-parent" data-tooltip-content title=""><div class="ui label scope-left" style="color: #fff !important; background-color: #000000 !important"><</div><div class="ui label scope-right" style="color: #fff !important; background-color: #000000 !important">></div></span>`
|
||||
assert.Equal(t, expectedLabel, string(ut.RenderLabel(label)))
|
||||
label = &issues.Label{ID: 123, Name: "</>", Exclusive: true, ExclusiveOrder: 1}
|
||||
expectedLabel = `<a href="" class="ui label scope-parent" data-tooltip-content title=""><div class="ui label scope-left" style="color: #fff !important; background-color: #000000 !important"><</div><div class="ui label scope-middle" style="color: #fff !important; background-color: #000000 !important">></div><div class="ui label scope-right">1</div></a>`
|
||||
assert.Equal(t, expectedLabel, string(ut.RenderLabelWithLink(label, "")))
|
||||
expectedLabel = `<span class="ui label scope-parent" data-tooltip-content title=""><div class="ui label scope-left" style="color: #fff !important; background-color: #000000 !important"><</div><div class="ui label scope-middle" style="color: #fff !important; background-color: #000000 !important">></div><div class="ui label scope-right">1</div></span>`
|
||||
assert.Equal(t, expectedLabel, string(ut.RenderLabel(label)))
|
||||
}
|
||||
|
||||
func TestUserMention(t *testing.T) {
|
||||
|
||||
Reference in New Issue
Block a user