mirror of
https://github.com/go-gitea/gitea.git
synced 2025-08-13 00:03:31 -04:00
Compare commits
6 Commits
97b70a0cd4
...
80765aab8c
Author | SHA1 | Date | |
---|---|---|---|
|
80765aab8c | ||
|
3319e9597e | ||
|
1144b1d129 | ||
|
0bb52883eb | ||
|
56ae853ca0 | ||
|
377e0139b0 |
2
Makefile
2
Makefile
@ -139,7 +139,7 @@ GO_DIRS := build cmd models modules routers services tests
|
||||
WEB_DIRS := web_src/js web_src/css
|
||||
|
||||
GO_SOURCES := $(wildcard *.go)
|
||||
GO_SOURCES += $(shell find $(GO_DIRS) -type f -name "*.go" -not -path modules/options/bindata.go -not -path modules/public/bindata.go -not -path modules/templates/bindata.go)
|
||||
GO_SOURCES += $(shell find $(GO_DIRS) -type f -name "*.go" ! -path modules/options/bindata.go ! -path modules/public/bindata.go ! -path modules/templates/bindata.go)
|
||||
GO_SOURCES += $(GENERATED_GO_DEST)
|
||||
GO_SOURCES_NO_BINDATA := $(GO_SOURCES)
|
||||
|
||||
|
@ -10,6 +10,7 @@ import (
|
||||
"encoding/base64"
|
||||
"encoding/hex"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
|
||||
"github.com/minio/sha256-simd"
|
||||
@ -19,13 +20,13 @@ import (
|
||||
func AesEncrypt(key, text []byte) ([]byte, error) {
|
||||
block, err := aes.NewCipher(key)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, fmt.Errorf("AesEncrypt invalid key: %v", err)
|
||||
}
|
||||
b := base64.StdEncoding.EncodeToString(text)
|
||||
ciphertext := make([]byte, aes.BlockSize+len(b))
|
||||
iv := ciphertext[:aes.BlockSize]
|
||||
if _, err := io.ReadFull(rand.Reader, iv); err != nil {
|
||||
return nil, err
|
||||
if _, err = io.ReadFull(rand.Reader, iv); err != nil {
|
||||
return nil, fmt.Errorf("AesEncrypt unable to read IV: %w", err)
|
||||
}
|
||||
cfb := cipher.NewCFBEncrypter(block, iv)
|
||||
cfb.XORKeyStream(ciphertext[aes.BlockSize:], []byte(b))
|
||||
@ -39,7 +40,7 @@ func AesDecrypt(key, text []byte) ([]byte, error) {
|
||||
return nil, err
|
||||
}
|
||||
if len(text) < aes.BlockSize {
|
||||
return nil, errors.New("ciphertext too short")
|
||||
return nil, errors.New("AesDecrypt ciphertext too short")
|
||||
}
|
||||
iv := text[:aes.BlockSize]
|
||||
text = text[aes.BlockSize:]
|
||||
@ -47,7 +48,7 @@ func AesDecrypt(key, text []byte) ([]byte, error) {
|
||||
cfb.XORKeyStream(text, text)
|
||||
data, err := base64.StdEncoding.DecodeString(string(text))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, fmt.Errorf("AesDecrypt invalid decrypted base64 string: %w", err)
|
||||
}
|
||||
return data, nil
|
||||
}
|
||||
@ -58,21 +59,21 @@ func EncryptSecret(key, str string) (string, error) {
|
||||
plaintext := []byte(str)
|
||||
ciphertext, err := AesEncrypt(keyHash[:], plaintext)
|
||||
if err != nil {
|
||||
return "", err
|
||||
return "", fmt.Errorf("failed to encrypt by secret: %w", err)
|
||||
}
|
||||
return hex.EncodeToString(ciphertext), nil
|
||||
}
|
||||
|
||||
// DecryptSecret decrypts a previously encrypted hex string
|
||||
func DecryptSecret(key, cipherhex string) (string, error) {
|
||||
func DecryptSecret(key, cipherHex string) (string, error) {
|
||||
keyHash := sha256.Sum256([]byte(key))
|
||||
ciphertext, err := hex.DecodeString(cipherhex)
|
||||
ciphertext, err := hex.DecodeString(cipherHex)
|
||||
if err != nil {
|
||||
return "", err
|
||||
return "", fmt.Errorf("failed to decrypt by secret, invalid hex string: %w", err)
|
||||
}
|
||||
plaintext, err := AesDecrypt(keyHash[:], ciphertext)
|
||||
if err != nil {
|
||||
return "", err
|
||||
return "", fmt.Errorf("failed to decrypt by secret, the key (maybe SECRET_KEY?) might be incorrect: %w", err)
|
||||
}
|
||||
return string(plaintext), nil
|
||||
}
|
||||
|
@ -10,14 +10,22 @@ import (
|
||||
)
|
||||
|
||||
func TestEncryptDecrypt(t *testing.T) {
|
||||
var hex string
|
||||
var str string
|
||||
|
||||
hex, _ = EncryptSecret("foo", "baz")
|
||||
str, _ = DecryptSecret("foo", hex)
|
||||
hex, err := EncryptSecret("foo", "baz")
|
||||
assert.NoError(t, err)
|
||||
str, _ := DecryptSecret("foo", hex)
|
||||
assert.Equal(t, "baz", str)
|
||||
|
||||
hex, _ = EncryptSecret("bar", "baz")
|
||||
hex, err = EncryptSecret("bar", "baz")
|
||||
assert.NoError(t, err)
|
||||
str, _ = DecryptSecret("foo", hex)
|
||||
assert.NotEqual(t, "baz", str)
|
||||
|
||||
_, err = DecryptSecret("a", "b")
|
||||
assert.ErrorContains(t, err, "invalid hex string")
|
||||
|
||||
_, err = DecryptSecret("a", "bb")
|
||||
assert.ErrorContains(t, err, "the key (maybe SECRET_KEY?) might be incorrect: AesDecrypt ciphertext too short")
|
||||
|
||||
_, err = DecryptSecret("a", "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef")
|
||||
assert.ErrorContains(t, err, "the key (maybe SECRET_KEY?) might be incorrect: AesDecrypt invalid decrypted base64 string")
|
||||
}
|
||||
|
@ -179,7 +179,6 @@ func NewFuncMap() template.FuncMap {
|
||||
|
||||
// -----------------------------------------------------------------
|
||||
// misc
|
||||
"DiffLineTypeToStr": DiffLineTypeToStr,
|
||||
"ShortSha": base.ShortSha,
|
||||
"ActionContent2Commits": ActionContent2Commits,
|
||||
"IsMultilineCommitMessage": IsMultilineCommitMessage,
|
||||
|
@ -122,19 +122,6 @@ func ActionContent2Commits(act Actioner) *repository.PushCommits {
|
||||
return push
|
||||
}
|
||||
|
||||
// DiffLineTypeToStr returns diff line type name
|
||||
func DiffLineTypeToStr(diffType int) string {
|
||||
switch diffType {
|
||||
case 2:
|
||||
return "add"
|
||||
case 3:
|
||||
return "del"
|
||||
case 4:
|
||||
return "tag"
|
||||
}
|
||||
return "same"
|
||||
}
|
||||
|
||||
// MigrationIcon returns a SVG name matching the service an issue/comment was migrated from
|
||||
func MigrationIcon(hostname string) string {
|
||||
switch hostname {
|
||||
|
17
options/license/ASWF-Digital-Assets-1.0
Normal file
17
options/license/ASWF-Digital-Assets-1.0
Normal file
@ -0,0 +1,17 @@
|
||||
ASWF Digital Assets License v1.0
|
||||
|
||||
License for <Asset Name> (the "Asset Name").
|
||||
|
||||
<Asset Name> Copyright <Year> <Asset Owner>. All rights reserved.
|
||||
|
||||
Redistribution and use of these digital assets, with or without modification, solely for education, training, research, software and hardware development, performance benchmarking (including publication of benchmark results and permitting reproducibility of the benchmark results by third parties), or software and hardware product demonstrations, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of these digital assets or any part of them must include the above copyright notice, this list of conditions and the disclaimer below.
|
||||
|
||||
2. Publications showing images derived from these digital assets must include the above copyright notice.
|
||||
|
||||
3. The names of copyright holder or the names of its contributors may NOT be used to promote or to imply endorsement, sponsorship, or affiliation with products developed or tested utilizing these digital assets or benchmarking results obtained from these digital assets, without prior written permission from copyright holder.
|
||||
|
||||
4. The assets and their output may only be referred to as the Asset Name listed above, and your use of the Asset Name shall be solely to identify the digital assets. Other than as expressly permitted by this License, you may NOT use any trade names, trademarks, service marks, or product names of the copyright holder for any purpose.
|
||||
|
||||
DISCLAIMER: THESE DIGITAL ASSETS ARE PROVIDED BY THE COPYRIGHT HOLDER "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDER BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THESE DIGITAL ASSETS, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
@ -308,6 +308,7 @@ repos = Repositories
|
||||
users = Users
|
||||
organizations = Organizations
|
||||
search = Search
|
||||
go_to = Go to
|
||||
code = Code
|
||||
search.type.tooltip = Search type
|
||||
search.fuzzy = Fuzzy
|
||||
|
@ -104,6 +104,19 @@ func (d *DiffLine) GetType() int {
|
||||
return int(d.Type)
|
||||
}
|
||||
|
||||
// GetHTMLDiffLineType returns the diff line type name for HTML
|
||||
func (d *DiffLine) GetHTMLDiffLineType() string {
|
||||
switch d.Type {
|
||||
case DiffLineAdd:
|
||||
return "add"
|
||||
case DiffLineDel:
|
||||
return "del"
|
||||
case DiffLineSection:
|
||||
return "tag"
|
||||
}
|
||||
return "same"
|
||||
}
|
||||
|
||||
// CanComment returns whether a line can get commented
|
||||
func (d *DiffLine) CanComment() bool {
|
||||
return len(d.Comments) == 0 && d.Type != DiffLineSection
|
||||
|
@ -1,6 +1,6 @@
|
||||
{{if $.IsSplitStyle}}
|
||||
{{range $k, $line := $.section.Lines}}
|
||||
<tr class="{{DiffLineTypeToStr .GetType}}-code nl-{{$k}} ol-{{$k}}">
|
||||
<tr class="{{.GetHTMLDiffLineType}}-code nl-{{$k}} ol-{{$k}}">
|
||||
{{if eq .GetType 4}}
|
||||
<td class="lines-num lines-num-old" data-line-num="{{if $line.LeftIdx}}{{$line.LeftIdx}}{{end}}">
|
||||
{{if or (eq $line.GetExpandDirection 3) (eq $line.GetExpandDirection 5)}}
|
||||
@ -44,7 +44,7 @@
|
||||
{{end}}
|
||||
{{else}}
|
||||
{{range $k, $line := $.section.Lines}}
|
||||
<tr class="{{DiffLineTypeToStr .GetType}}-code nl-{{$k}} ol-{{$k}}">
|
||||
<tr class="{{.GetHTMLDiffLineType}}-code nl-{{$k}} ol-{{$k}}">
|
||||
{{if eq .GetType 4}}
|
||||
<td colspan="2" class="lines-num">
|
||||
{{if or (eq $line.GetExpandDirection 3) (eq $line.GetExpandDirection 5)}}
|
||||
|
@ -13,7 +13,7 @@
|
||||
{{range $k, $line := $section.Lines}}
|
||||
{{$hasmatch := ne $line.Match -1}}
|
||||
{{if or (ne .GetType 2) (not $hasmatch)}}
|
||||
<tr class="{{DiffLineTypeToStr .GetType}}-code nl-{{$k}} ol-{{$k}}" data-line-type="{{DiffLineTypeToStr .GetType}}">
|
||||
<tr class="{{.GetHTMLDiffLineType}}-code nl-{{$k}} ol-{{$k}}" data-line-type="{{.GetHTMLDiffLineType}}">
|
||||
{{if eq .GetType 4}}
|
||||
<td class="lines-num lines-num-old">
|
||||
{{if or (eq $line.GetExpandDirection 3) (eq $line.GetExpandDirection 5)}}
|
||||
@ -107,7 +107,7 @@
|
||||
{{if and (eq .GetType 3) $hasmatch}}
|
||||
{{$match := index $section.Lines $line.Match}}
|
||||
{{if or (gt (len $line.Comments) 0) (gt (len $match.Comments) 0)}}
|
||||
<tr class="add-comment" data-line-type="{{DiffLineTypeToStr .GetType}}">
|
||||
<tr class="add-comment" data-line-type="{{.GetHTMLDiffLineType}}">
|
||||
<td class="add-comment-left" colspan="4">
|
||||
{{if gt (len $line.Comments) 0}}
|
||||
{{if eq $line.GetCommentSide "previous"}}
|
||||
@ -133,7 +133,7 @@
|
||||
</tr>
|
||||
{{end}}
|
||||
{{else if gt (len $line.Comments) 0}}
|
||||
<tr class="add-comment" data-line-type="{{DiffLineTypeToStr .GetType}}">
|
||||
<tr class="add-comment" data-line-type="{{.GetHTMLDiffLineType}}">
|
||||
<td class="add-comment-left" colspan="4">
|
||||
{{if gt (len $line.Comments) 0}}
|
||||
{{if eq $line.GetCommentSide "previous"}}
|
||||
|
@ -8,7 +8,7 @@
|
||||
</colgroup>
|
||||
{{range $j, $section := $file.Sections}}
|
||||
{{range $k, $line := $section.Lines}}
|
||||
<tr class="{{DiffLineTypeToStr .GetType}}-code nl-{{$k}} ol-{{$k}}" data-line-type="{{DiffLineTypeToStr .GetType}}">
|
||||
<tr class="{{.GetHTMLDiffLineType}}-code nl-{{$k}} ol-{{$k}}" data-line-type="{{.GetHTMLDiffLineType}}">
|
||||
{{if eq .GetType 4}}
|
||||
{{if $.root.AfterCommitID}}
|
||||
<td colspan="2" class="lines-num">
|
||||
@ -55,7 +55,7 @@
|
||||
{{end}}
|
||||
</tr>
|
||||
{{if gt (len $line.Comments) 0}}
|
||||
<tr class="add-comment" data-line-type="{{DiffLineTypeToStr .GetType}}">
|
||||
<tr class="add-comment" data-line-type="{{.GetHTMLDiffLineType}}">
|
||||
<td class="add-comment-left add-comment-right" colspan="5">
|
||||
{{template "repo/diff/conversation" dict "." $.root "comments" $line.Comments}}
|
||||
</td>
|
||||
|
@ -8,7 +8,8 @@
|
||||
<input type="hidden" name="assignee" value="{{$.AssigneeID}}">
|
||||
<input type="hidden" name="poster" value="{{$.PosterID}}">
|
||||
<input name="q" value="{{.Keyword}}" placeholder="{{.locale.Tr "explore.search"}}...">
|
||||
<button class="ui small icon button" type="submit" aria-label="{{.locale.Tr "explore.search"}}">
|
||||
<button id="hashtag-button" class="ui small icon button gt-hidden" data-tooltip-content="{{.locale.Tr "explore.go_to"}}">{{svg "octicon-hash"}}</button>
|
||||
<button id="search-button" class="ui small icon button" aria-label="{{.locale.Tr "explore.search"}}">
|
||||
{{svg "octicon-search"}}
|
||||
</button>
|
||||
</div>
|
||||
|
@ -78,7 +78,8 @@
|
||||
<input type="hidden" name="sort" value="{{$.SortType}}">
|
||||
<input type="hidden" name="state" value="{{$.State}}">
|
||||
<input name="q" value="{{$.Keyword}}" placeholder="{{.locale.Tr "explore.search"}}...">
|
||||
<button class="ui small icon button" type="submit" aria-label="{{.locale.Tr "explore.search"}}">{{svg "octicon-search"}}</button>
|
||||
<button id="hashtag-button" class="ui small icon button gt-hidden" data-tooltip-content="{{.locale.Tr "explore.go_to"}}">{{svg "octicon-hash"}}</button>
|
||||
<button id="search-button" class="ui small icon button" aria-label="{{.locale.Tr "explore.search"}}">{{svg "octicon-search"}}</button>
|
||||
</div>
|
||||
</form>
|
||||
<!-- Sort -->
|
||||
|
@ -1,6 +1,6 @@
|
||||
# End to end tests
|
||||
|
||||
E2e tests largely follow the same syntax as [integration tests](tests/e2e/README.md).
|
||||
E2e tests largely follow the same syntax as [integration tests](../integration).
|
||||
Whereas integration tests are intended to mock and stress the back-end, server-side code, e2e tests the interface between front-end and back-end, as well as visual regressions with both assertions and visual comparisons.
|
||||
They can be run with make commands for the appropriate backends, namely:
|
||||
```shell
|
||||
|
@ -4,6 +4,7 @@ import {showTemporaryTooltip, createTippy} from '../modules/tippy.js';
|
||||
import {hideElem, showElem, toggleElem} from '../utils/dom.js';
|
||||
import {setFileFolding} from './file-fold.js';
|
||||
import {getComboMarkdownEditor, initComboMarkdownEditor} from './comp/ComboMarkdownEditor.js';
|
||||
import {parseIssueHref} from '../utils.js';
|
||||
|
||||
const {appSubUrl, csrfToken} = window.config;
|
||||
|
||||
@ -636,3 +637,31 @@ export function initRepoIssueBranchSelect() {
|
||||
};
|
||||
$('#branch-select > .item').on('click', changeBranchSelect);
|
||||
}
|
||||
|
||||
export function initRepoIssueGotoID() {
|
||||
const issueidre = /^(?:\w+\/\w+#\d+|#\d+|\d+)$/;
|
||||
const isGlobalIssuesArea = $('.repo.name.item').length > 0; // for global issues area or repository issues area
|
||||
$('form.list-header-search').on('submit', (e) => {
|
||||
const qval = e.target.q.value;
|
||||
const aElm = document.activeElement;
|
||||
if (!$('#hashtag-button').length || aElm.id === 'search-button' || (aElm.name === 'q' && !qval.includes('#')) || (isGlobalIssuesArea && !qval.includes('/')) || !issueidre.test(qval)) return;
|
||||
const pathname = window.location.pathname;
|
||||
let gotoUrl = qval.includes('/') ? `${qval.replace('#', '/issues/')}` : `${pathname}/${qval.replace('#', '')}`;
|
||||
if (appSubUrl.length) {
|
||||
gotoUrl = qval.includes('/') ? `/${appSubUrl}/${qval.replace('#', '/issues/')}` : `/${appSubUrl}/${pathname}/${qval.replace('#', '')}`;
|
||||
}
|
||||
const {owner, repo, type, index} = parseIssueHref(gotoUrl);
|
||||
if (owner && repo && type && index) {
|
||||
e.preventDefault();
|
||||
window.location.href = gotoUrl;
|
||||
}
|
||||
});
|
||||
$('form.list-header-search input[name=q]').on('input', (e) => {
|
||||
const qval = e.target.value;
|
||||
if (isGlobalIssuesArea && qval.includes('/') && issueidre.test(qval) || !isGlobalIssuesArea && issueidre.test(qval)) {
|
||||
showElem($('#hashtag-button'));
|
||||
} else {
|
||||
hideElem($('#hashtag-button'));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -30,7 +30,7 @@ import {
|
||||
initRepoIssueWipTitle,
|
||||
initRepoPullRequestMergeInstruction,
|
||||
initRepoPullRequestAllowMaintainerEdit,
|
||||
initRepoPullRequestReview, initRepoIssueSidebarList,
|
||||
initRepoPullRequestReview, initRepoIssueSidebarList, initRepoIssueGotoID
|
||||
} from './features/repo-issue.js';
|
||||
import {
|
||||
initRepoEllipsisButton,
|
||||
@ -175,4 +175,5 @@ onDomReady(() => {
|
||||
initUserAuthWebAuthnRegister();
|
||||
initUserSettings();
|
||||
initRepoDiffView();
|
||||
initRepoIssueGotoID();
|
||||
});
|
||||
|
Loading…
x
Reference in New Issue
Block a user