From cf86abaf3cf58adf581d571c909d62145538f840 Mon Sep 17 00:00:00 2001 From: Matti R Date: Wed, 14 Oct 2020 16:45:38 -0400 Subject: [PATCH 001/205] run mysql container with same conditions as other services --- .drone.yml | 6 ------ 1 file changed, 6 deletions(-) diff --git a/.drone.yml b/.drone.yml index e3db45cd59..111469fefe 100644 --- a/.drone.yml +++ b/.drone.yml @@ -119,12 +119,6 @@ services: from_secret: gitlab_read_token depends_on: - build - when: - branch: - - master - event: - - push - - pull_request - name: mysql8 pull: default From 89b1b662b30d3af942ca66965df2db78e1ddd731 Mon Sep 17 00:00:00 2001 From: Lauris BH Date: Wed, 14 Oct 2020 23:54:56 +0300 Subject: [PATCH 002/205] Add back only missing translation for Latvian language (#13144) * Add back only missing translation for Latvian language * Backport German translations --- options/locale/locale_de-DE.ini | 6 ++++++ options/locale/locale_lv-LV.ini | 1 + 2 files changed, 7 insertions(+) diff --git a/options/locale/locale_de-DE.ini b/options/locale/locale_de-DE.ini index 0cd03ebafd..fde5b5c281 100644 --- a/options/locale/locale_de-DE.ini +++ b/options/locale/locale_de-DE.ini @@ -511,6 +511,7 @@ add_new_gpg_key=GPG-Schlüssel hinzufügen key_content_ssh_placeholder=Beginnt mit 'ssh-ed25519', 'ssh-rsa', 'ecdsa-sha2-nistp256', 'ecdsa-sha2-nistp384' oder 'ecdsa-sha2-nistp521' key_content_gpg_placeholder=Beginnt mit '-----BEGIN PGP PUBLIC KEY BLOCK-----' ssh_key_been_used=Dieser SSH-Key wird auf diesem Server bereits verwendet. +ssh_key_name_used=Ein gleichnamiger SSH-Key existiert bereits in deinem Account. gpg_key_id_used=Ein öffentlicher GPG-Schlüssel mit der gleichen ID existiert bereits. gpg_no_key_email_found=Dieser GPG-Schlüssel kann mit keiner E-Mail-Adresse deines Kontos verwendet werden. subkeys=Unterschlüssel @@ -750,6 +751,7 @@ migrate.migrating_failed=Migrieren von %s fehlgeschlagen. migrate.github.description=Migriere Daten von Github.com oder Github Enterprise. migrate.git.description=Migriere oder spiegele git-Daten von Git-Services migrate.gitlab.description=Migriere Daten von GitLab.com oder einem selbst gehostetem gitlab Server. +migrate.gitea.description=Migriere Daten von Gitea.com oder einem selbst gehostetem Gitea Server. mirror_from=Mirror von forked_from=geforkt von @@ -1219,6 +1221,8 @@ pulls.required_status_check_administrator=Als Administrator kannst du diesen Pul pulls.blocked_by_approvals=Dieser Pull-Request hat noch nicht genügend Zustimmungen. %d von %d Zustimmungen erteilt. pulls.blocked_by_rejection=Dieser Pull-Request hat Änderungen, die von einem offiziellen Reviewer angefragt wurden. pulls.blocked_by_outdated_branch=Dieser Pull Request ist blockiert, da er veraltet ist. +pulls.blocked_by_changed_protected_files_1=Diese Pull Request ist blockiert, weil er eine geschützte Datei ändert: +pulls.blocked_by_changed_protected_files_n=Diese Pull Request ist blockiert, weil er geschützte Dateien ändert: pulls.can_auto_merge_desc=Dieser Pull-Request kann automatisch zusammengeführt werden. pulls.cannot_auto_merge_desc=Dieser Pull-Request kann nicht automatisch zusammengeführt werden, da es Konflikte gibt. pulls.cannot_auto_merge_helper=Bitte manuell zusammenführen, um die Konflikte zu lösen. @@ -1766,6 +1770,7 @@ diff.review.comment=Kommentieren diff.review.approve=Genehmigen diff.review.reject=Änderung anfragen diff.committed_by=committed von +diff.protected=Geschützt releases.desc=Behalte den Überblick über Versionen und Downloads. release.releases=Releases @@ -1991,6 +1996,7 @@ dashboard.update_migration_poster_id=Migration Poster-IDs updaten dashboard.git_gc_repos=Garbage-Collection auf Repositories ausführen dashboard.resync_all_sshkeys=Die Datei '.ssh/authorized_keys' mit Gitea SSH-Schlüsseln aktualisieren. dashboard.resync_all_sshkeys.desc=(Nicht benötigt für den eingebauten SSH-Server.) +dashboard.resync_all_sshprincipals.desc=(Nicht benötigt für den eingebauten SSH-Server.) dashboard.resync_all_hooks=Synchronisiere „pre-receive“-, „update“- und „post-receive“-Hooks für alle Repositories erneut. dashboard.reinit_missing_repos=Alle Git-Repositories mit Einträgen neu einlesen dashboard.sync_external_users=Externe Benutzerdaten synchronisieren diff --git a/options/locale/locale_lv-LV.ini b/options/locale/locale_lv-LV.ini index dff2427c23..d1f5b53a28 100644 --- a/options/locale/locale_lv-LV.ini +++ b/options/locale/locale_lv-LV.ini @@ -1501,6 +1501,7 @@ settings.trust_model.committer.long=Revīzijas iesūtītāja: Uzticēties paraks settings.trust_model.committer.desc=Ticami paraksti tiks atzīmēti kā "uzticami", ja tie atbilst revīzijas iesūtītājam, citos gadījumos tie tiks atzīmēti kā "nesakrītoši". Šis nozīmē, ka Gitea būs kā revīzijas iesūtītājs parakstītām revīzijām, kur īstais revīzijas iesūtītājs tiks atīzmēts revīzijas komentāra beigās ar tekstu Co-Authored-By: un Co-Committed-By:. Noklusētajai Gitea atslēgai ir jāatbilst lietotājam datu bāzē. settings.trust_model.collaboratorcommitter=Līdzstrādnieka un revīzijas iesūtītāja settings.trust_model.collaboratorcommitter.long=Līdzstrādnieka un revīzijas iesūtītāja: Uzticēties līdzstrādnieku parakstiem, kas atbilst revīzijas iesūtītājam +settings.trust_model.collaboratorcommitter.desc=Ticami līdzstrādnieku paraksti tiks atzīmēti kā "uzticami", ja tie atbilst revīzijas iesūtītājam, citos gadījumos tie tiks atzīmēti kā "neuzticami", ja paraksts atbilst revīzijas iesūtītajam, vai "nesakrītoši", ja neatbilst. Šis nozīmē, ka Gitea būs kā revīzijas iesūtītājs parakstītām revīzijām, kur īstais revīzijas iesūtītājs tiks atīzmēts revīzijas komentāra beigās ar tekstu Co-Authored-By: un Co-Committed-By:. Noklusētajai Gitea atslēgai ir jāatbilst lietotājam datu bāzē. settings.wiki_delete=Dzēst vikivietnes datus settings.wiki_delete_desc=Vikivietnes repozitorija dzēšana ir NEATGRIEZENISKA. Vai turpināt? settings.wiki_delete_notices_1=- Šī darbība dzēsīs un atspējos repozitorija %s vikivietni. From d655cfe9688ba9209a2ef9c0e25a00ae636be478 Mon Sep 17 00:00:00 2001 From: Matti R Date: Wed, 14 Oct 2020 16:57:12 -0400 Subject: [PATCH 003/205] align mysql service settings in drone --- .drone.yml | 6 ------ 1 file changed, 6 deletions(-) diff --git a/.drone.yml b/.drone.yml index 111469fefe..872dcf750d 100644 --- a/.drone.yml +++ b/.drone.yml @@ -113,12 +113,6 @@ services: environment: MYSQL_ALLOW_EMPTY_PASSWORD: yes MYSQL_DATABASE: test - GOPROXY: off - TAGS: bindata sqlite sqlite_unlock_notify - GITLAB_READ_TOKEN: - from_secret: gitlab_read_token - depends_on: - - build - name: mysql8 pull: default From f587dc69bb89cd0161b74b1400006b2708d751d0 Mon Sep 17 00:00:00 2001 From: Lauris BH Date: Thu, 15 Oct 2020 14:57:17 +0300 Subject: [PATCH 004/205] Fix Italian language file parsing error (#13156) --- options/locale/locale_it-IT.ini | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/options/locale/locale_it-IT.ini b/options/locale/locale_it-IT.ini index ea0f93b58f..622e58b5c0 100644 --- a/options/locale/locale_it-IT.ini +++ b/options/locale/locale_it-IT.ini @@ -1037,8 +1037,7 @@ issues.close_comment_issue=Commenta e Chiudi issues.reopen_issue=Riapri issues.reopen_comment_issue=Commenta e Riapri issues.create_comment=Commento -issues.closed_at="`chiuso questo probleam %[2]s` -Contextrequest" +issues.closed_at=`chiuso questo probleam %[2]s` issues.reopened_at=`riaperto questo problema %[2]s` issues.commit_ref_at=`ha fatto riferimento a questa issue dal commit %[2]s` issues.ref_issue_from=`ha fatto riferimento a questo problema %[4]s %[2]s` From 2ec50b9514f33ee64ec40de1e63008b3ab68c56b Mon Sep 17 00:00:00 2001 From: 6543 <6543@obermui.de> Date: Fri, 16 Oct 2020 03:46:56 +0200 Subject: [PATCH 005/205] Show outdated comments in pull request (#13148) (#13162) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: zeripath Co-authored-by: Iván Valdés Co-authored-by: zeripath --- options/locale/locale_en-US.ini | 1 + .../repo/issue/view_content/comments.tmpl | 27 +++++++++++-------- web_src/less/_repository.less | 10 +++++++ 3 files changed, 27 insertions(+), 11 deletions(-) diff --git a/options/locale/locale_en-US.ini b/options/locale/locale_en-US.ini index 95ffa0b0ed..16d3874e1b 100644 --- a/options/locale/locale_en-US.ini +++ b/options/locale/locale_en-US.ini @@ -1190,6 +1190,7 @@ issues.review.remove_review_request_self = "refused to review %s" issues.review.pending = Pending issues.review.review = Review issues.review.reviewers = Reviewers +issues.review.outdated = Outdated issues.review.show_outdated = Show outdated issues.review.hide_outdated = Hide outdated issues.review.show_resolved = Show resolved diff --git a/templates/repo/issue/view_content/comments.tmpl b/templates/repo/issue/view_content/comments.tmpl index f9ae9ba071..86ce6148c1 100644 --- a/templates/repo/issue/view_content/comments.tmpl +++ b/templates/repo/issue/view_content/comments.tmpl @@ -441,29 +441,34 @@ {{$resolveDoer := (index $comms 0).ResolveDoer}} {{$isNotPending := (not (eq (index $comms 0).Review.Type 0))}} {{if or $invalid $resolved}} - - {{end}} - {{$filename}} + {{$filename}} + {{if and $invalid (not $resolved)}} + + {{$.i18n.Tr "repo.issues.review.outdated"}} + + {{end}} {{$diff := (CommentMustAsDiff (index $comms 0))}} {{if $diff}} {{$file := (index $diff.Files 0)}} -
+
@@ -475,7 +480,7 @@ {{end}} -
+
{{range $comms}} {{ $createdSubStr:= TimeSinceUnix .CreatedUnix $.Lang }} diff --git a/web_src/less/_repository.less b/web_src/less/_repository.less index ca1a87b557..619bc749ef 100644 --- a/web_src/less/_repository.less +++ b/web_src/less/_repository.less @@ -1220,6 +1220,16 @@ display: block; } } + + .tag { + color: black; + margin: 3px 0 0 5px; + padding: 2px 5px; + font-size: 12px; + border: 1px solid rgba(0, 0, 0, .1); + border-radius: 3px; + background-color: #fffbb2; + } } } From ea95a9fa15552a4124eba14fbda757bc5a9a47e7 Mon Sep 17 00:00:00 2001 From: 6543 <6543@obermui.de> Date: Fri, 16 Oct 2020 18:23:52 +0200 Subject: [PATCH 006/205] Update go-version v1.2.3 -> v1.2.4 (#13169) (#13172) Co-authored-by: zeripath Co-authored-by: zeripath --- go.mod | 2 +- go.sum | 4 ++-- vendor/github.com/hashicorp/go-version/README.md | 4 ++-- vendor/github.com/hashicorp/go-version/go.mod | 2 ++ vendor/github.com/hashicorp/go-version/version.go | 12 ++++++++---- vendor/modules.txt | 4 ++-- 6 files changed, 17 insertions(+), 11 deletions(-) diff --git a/go.mod b/go.mod index aa54ec44ed..328680c13f 100644 --- a/go.mod +++ b/go.mod @@ -123,4 +123,4 @@ require ( xorm.io/xorm v1.0.5 ) -replace github.com/hashicorp/go-version => github.com/6543/go-version v1.2.3 +replace github.com/hashicorp/go-version => github.com/6543/go-version v1.2.4 diff --git a/go.sum b/go.sum index 4e21f54584..a86a370711 100644 --- a/go.sum +++ b/go.sum @@ -48,8 +48,8 @@ gitea.com/macaron/toolbox v0.0.0-20190822013122-05ff0fc766b7 h1:N9QFoeNsUXLhl14m gitea.com/macaron/toolbox v0.0.0-20190822013122-05ff0fc766b7/go.mod h1:kgsbFPPS4P+acDYDOPDa3N4IWWOuDJt5/INKRUz7aks= gitea.com/xorm/sqlfiddle v0.0.0-20180821085327-62ce714f951a h1:lSA0F4e9A2NcQSqGqTOXqu2aRi/XEQxDCBwM8yJtE6s= gitea.com/xorm/sqlfiddle v0.0.0-20180821085327-62ce714f951a/go.mod h1:EXuID2Zs0pAQhH8yz+DNjUbjppKQzKFAn28TMYPB6IU= -github.com/6543/go-version v1.2.3 h1:uF30BawMhoQLzqBeCwhFcWM6HVxlzMHe/zXbzJeKP+o= -github.com/6543/go-version v1.2.3/go.mod h1:fcfWh4zkneEgGXe8JJptiGwp8l6JgJJgS7oTw6P83So= +github.com/6543/go-version v1.2.4 h1:MPsSnqNrM0HwA9tnmWNnsMdQMg4/u4fflARjwomoof4= +github.com/6543/go-version v1.2.4/go.mod h1:oqFAHCwtLVUTLdhQmVZWYvaHXTdsbB4SY85at64SQEo= github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= diff --git a/vendor/github.com/hashicorp/go-version/README.md b/vendor/github.com/hashicorp/go-version/README.md index 851a337beb..e19e0a9afc 100644 --- a/vendor/github.com/hashicorp/go-version/README.md +++ b/vendor/github.com/hashicorp/go-version/README.md @@ -1,6 +1,6 @@ # Versioning Library for Go -[![Build Status](https://circleci.com/gh/hashicorp/go-version/tree/master.svg?style=svg)](https://circleci.com/gh/hashicorp/go-version/tree/master) -[![GoDoc](https://godoc.org/github.com/hashicorp/go-version?status.svg)](https://godoc.org/github.com/hashicorp/go-version) +![Build Status](https://github.com/6543/go-version/workflows/Release/badge.svg) +[![GoDoc](https://godoc.org/github.com/6543/go-version?status.svg)](https://godoc.org/github.com/6543/go-version) go-version is a library for parsing versions and version constraints, and verifying versions against a set of constraints. go-version diff --git a/vendor/github.com/hashicorp/go-version/go.mod b/vendor/github.com/hashicorp/go-version/go.mod index f52ad8ac52..fb823e8f9e 100644 --- a/vendor/github.com/hashicorp/go-version/go.mod +++ b/vendor/github.com/hashicorp/go-version/go.mod @@ -1 +1,3 @@ module github.com/6543/go-version + +go 1.15 diff --git a/vendor/github.com/hashicorp/go-version/version.go b/vendor/github.com/hashicorp/go-version/version.go index 1d96a6f71b..3fb63ae802 100644 --- a/vendor/github.com/hashicorp/go-version/version.go +++ b/vendor/github.com/hashicorp/go-version/version.go @@ -18,10 +18,14 @@ var ( // The raw regular expression string used for testing the validity // of a version. const ( - VersionRegexpRaw string = `[vV]?([0-9]+(\.[0-9]+)*?)` + - `(-([0-9]+[0-9A-Za-z\-~]*(\.[0-9A-Za-z\-~]+)*)|(-?([A-Za-z\-~]+[0-9A-Za-z\-~]*(\.[0-9A-Za-z\-~]+)*)))?` + - `(\+([0-9A-Za-z\-~]+(\.[0-9A-Za-z\-~]+)*))?` + - `([\+\.\-~]g[0-9A-Fa-f]{10}$)?` + + VersionRegexpRaw string = `[vV]?` + // Optional [vV] prefix + `([0-9]+(\.[0-9]+)*?)` + // ( MajorNum ( '.' MinorNums ) *? ) + `(-` + // Followed by (optionally): ( '-' + `([0-9]+[0-9A-Za-z\-~]*(\.[0-9A-Za-z\-~]+)*)` + // Either ( PreNum String ( '.' OtherString ) * ) + `|` + + `([-\.]?([A-Za-z\-~]+[0-9A-Za-z\-~]*(\.[0-9A-Za-z\-~]+)*)))?` + // Or ( ['-' '.' ] ? ( AlphaHyphenTilde String * ( '.' String ) * ))) ? + `(\+([0-9A-Za-z\-~]+(\.[0-9A-Za-z\-~]+)*))?` + // and more Optionally: ( '+' String ( '.' String ) * ) + `([\+\.\-~]g[0-9A-Fa-f]{10}$)?` + // Optionally a: ( Punct 'g' Sha ) `?` // SemverRegexpRaw requires a separator between version and prerelease diff --git a/vendor/modules.txt b/vendor/modules.txt index 44ba090032..587d7c344a 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -426,7 +426,7 @@ github.com/hashicorp/go-cleanhttp # github.com/hashicorp/go-retryablehttp v0.6.7 ## explicit github.com/hashicorp/go-retryablehttp -# github.com/hashicorp/go-version v1.2.1 => github.com/6543/go-version v1.2.3 +# github.com/hashicorp/go-version v1.2.1 => github.com/6543/go-version v1.2.4 ## explicit github.com/hashicorp/go-version # github.com/hashicorp/hcl v1.0.0 @@ -978,4 +978,4 @@ xorm.io/xorm/log xorm.io/xorm/names xorm.io/xorm/schemas xorm.io/xorm/tags -# github.com/hashicorp/go-version => github.com/6543/go-version v1.2.3 +# github.com/hashicorp/go-version => github.com/6543/go-version v1.2.4 From e9649b39ac92fb0b994fae9d3c556a5aa156107a Mon Sep 17 00:00:00 2001 From: zeripath Date: Sat, 17 Oct 2020 02:39:35 +0100 Subject: [PATCH 007/205] Fix diff skipping lines (#13155) * Fix diff skipping lines Backport #13154 ParsePatch previously just skipped all lines that start with "+++ " or "--- " and makes no attempt to see these lines in context. This PR rewrites ParsePatch to pay attention to context and position within a patch, ensuring that --- and +++ are only skipped if appropriate. This PR also fixes several issues with incomplete files. Fix https://codeberg.org/Codeberg/Community/issues/308 Fix #13153 Signed-off-by: Andrew Thornton * Add testcase Signed-off-by: Andrew Thornton * fix comment * simplify error handling Signed-off-by: Andrew Thornton * never return io.EOF Signed-off-by: Andrew Thornton Co-authored-by: techknowlogick --- services/gitdiff/gitdiff.go | 529 ++++++++++++++++++++----------- services/gitdiff/gitdiff_test.go | 21 ++ 2 files changed, 358 insertions(+), 192 deletions(-) diff --git a/services/gitdiff/gitdiff.go b/services/gitdiff/gitdiff.go index 1882b48ed4..91105399db 100644 --- a/services/gitdiff/gitdiff.go +++ b/services/gitdiff/gitdiff.go @@ -441,91 +441,252 @@ func (diff *Diff) LoadComments(issue *models.Issue, currentUser *models.User) er const cmdDiffHead = "diff --git " -// ParsePatch builds a Diff object from a io.Reader and some -// parameters. -// TODO: move this function to gogits/git-module +// ParsePatch builds a Diff object from a io.Reader and some parameters. func ParsePatch(maxLines, maxLineCharacters, maxFiles int, reader io.Reader) (*Diff, error) { - var ( - diff = &Diff{Files: make([]*DiffFile, 0)} - curFile = &DiffFile{} - curSection = &DiffSection{ - Lines: make([]*DiffLine, 0, 10), + var curFile *DiffFile + + diff := &Diff{Files: make([]*DiffFile, 0)} + + sb := strings.Builder{} + + // OK let's set a reasonable buffer size. + // This should be let's say at least the size of maxLineCharacters or 4096 whichever is larger. + readerSize := maxLineCharacters + if readerSize < 4096 { + readerSize = 4096 + } + + input := bufio.NewReaderSize(reader, readerSize) + line, err := input.ReadString('\n') + if err != nil { + if err == io.EOF { + return diff, nil + } + return diff, err + } +parsingLoop: + for { + // 1. A patch file always begins with `diff --git ` + `a/path b/path` (possibly quoted) + // if it does not we have bad input! + if !strings.HasPrefix(line, cmdDiffHead) { + return diff, fmt.Errorf("Invalid first file line: %s", line) } - leftLine, rightLine int - lineCount int - curFileLinesCount int - curFileLFSPrefix bool + // TODO: Handle skipping first n files + if len(diff.Files) >= maxFiles { + diff.IsIncomplete = true + _, err := io.Copy(ioutil.Discard, reader) + if err != nil { + // By the definition of io.Copy this never returns io.EOF + return diff, fmt.Errorf("Copy: %v", err) + } + break parsingLoop + } + + curFile = createDiffFile(diff, line) + diff.Files = append(diff.Files, curFile) + + // 2. It is followed by one or more extended header lines: + // + // old mode + // new mode + // deleted file mode + // new file mode + // copy from + // copy to + // rename from + // rename to + // similarity index + // dissimilarity index + // index .. + // + // * 6-digit octal numbers including the file type and file permission bits. + // * does not include the a/ and b/ prefixes + // * percentage of unchanged lines for similarity, percentage of changed + // lines dissimilarity as integer rounded down with terminal %. 100% => equal files. + // * The index line includes the blob object names before and after the change. + // The is included if the file mode does not change; otherwise, separate + // lines indicate the old and the new mode. + // 3. Following this header the "standard unified" diff format header may be encountered: (but not for every case...) + // + // --- a/ + // +++ b/ + // + // With multiple hunks + // + // @@ @@ + // +added line + // -removed line + // unchanged line + // + // 4. Binary files get: + // + // Binary files a/ and b/ differ + // + // but one of a/ and b/ could be /dev/null. + curFileLoop: + for { + line, err = input.ReadString('\n') + if err != nil { + if err != io.EOF { + return diff, err + } + break parsingLoop + } + switch { + case strings.HasPrefix(line, "old mode ") || + strings.HasPrefix(line, "new mode "): + if strings.HasSuffix(line, " 160000\n") { + curFile.IsSubmodule = true + } + case strings.HasPrefix(line, "copy from "): + curFile.IsRenamed = true + curFile.Type = DiffFileCopy + case strings.HasPrefix(line, "copy to "): + curFile.IsRenamed = true + curFile.Type = DiffFileCopy + case strings.HasPrefix(line, "new file"): + curFile.Type = DiffFileAdd + curFile.IsCreated = true + if strings.HasSuffix(line, " 160000\n") { + curFile.IsSubmodule = true + } + case strings.HasPrefix(line, "deleted"): + curFile.Type = DiffFileDel + curFile.IsDeleted = true + if strings.HasSuffix(line, " 160000\n") { + curFile.IsSubmodule = true + } + case strings.HasPrefix(line, "index"): + if strings.HasSuffix(line, " 160000\n") { + curFile.IsSubmodule = true + } + case strings.HasPrefix(line, "similarity index 100%"): + curFile.Type = DiffFileRename + case strings.HasPrefix(line, "Binary"): + curFile.IsBin = true + case strings.HasPrefix(line, "--- "): + // Do nothing with this line + case strings.HasPrefix(line, "+++ "): + // Do nothing with this line + lineBytes, isFragment, err := parseHunks(curFile, maxLines, maxLineCharacters, input) + diff.TotalAddition += curFile.Addition + diff.TotalDeletion += curFile.Deletion + if err != nil { + if err != io.EOF { + return diff, err + } + break parsingLoop + } + sb.Reset() + _, _ = sb.Write(lineBytes) + for isFragment { + lineBytes, isFragment, err = input.ReadLine() + if err != nil { + // Now by the definition of ReadLine this cannot be io.EOF + return diff, fmt.Errorf("Unable to ReadLine: %v", err) + } + _, _ = sb.Write(lineBytes) + } + line = sb.String() + sb.Reset() + + break curFileLoop + } + } + + } + + // FIXME: There are numerous issues with this: + // - we might want to consider detecting encoding while parsing but... + // - we're likely to fail to get the correct encoding here anyway as we won't have enough information + // - and this doesn't really account for changes in encoding + var buf bytes.Buffer + for _, f := range diff.Files { + buf.Reset() + for _, sec := range f.Sections { + for _, l := range sec.Lines { + if l.Type == DiffLineSection { + continue + } + buf.WriteString(l.Content[1:]) + buf.WriteString("\n") + } + } + charsetLabel, err := charset.DetectEncoding(buf.Bytes()) + if charsetLabel != "UTF-8" && err == nil { + encoding, _ := stdcharset.Lookup(charsetLabel) + if encoding != nil { + d := encoding.NewDecoder() + for _, sec := range f.Sections { + for _, l := range sec.Lines { + if l.Type == DiffLineSection { + continue + } + if c, _, err := transform.String(d, l.Content[1:]); err == nil { + l.Content = l.Content[0:1] + c + } + } + } + } + } + } + + diff.NumFiles = len(diff.Files) + return diff, nil +} + +func parseHunks(curFile *DiffFile, maxLines, maxLineCharacters int, input *bufio.Reader) (lineBytes []byte, isFragment bool, err error) { + sb := strings.Builder{} + + var ( + curSection *DiffSection + curFileLinesCount int + curFileLFSPrefix bool ) - input := bufio.NewReader(reader) - isEOF := false - for !isEOF { - var linebuf bytes.Buffer - for { - b, err := input.ReadByte() - if err != nil { - if err == io.EOF { - isEOF = true - break - } else { - return nil, fmt.Errorf("ReadByte: %v", err) - } + leftLine, rightLine := 1, 1 + + for { + sb.Reset() + lineBytes, isFragment, err = input.ReadLine() + if err != nil { + if err == io.EOF { + return } - if b == '\n' { - break - } - if linebuf.Len() < maxLineCharacters { - linebuf.WriteByte(b) - } else if linebuf.Len() == maxLineCharacters { + err = fmt.Errorf("Unable to ReadLine: %v", err) + return + } + if lineBytes[0] == 'd' { + // End of hunks + return + } + + switch lineBytes[0] { + case '@': + if curFileLinesCount >= maxLines { curFile.IsIncomplete = true + continue } - } - line := linebuf.String() - if strings.HasPrefix(line, "+++ ") || strings.HasPrefix(line, "--- ") || len(line) == 0 { - continue - } - - trimLine := strings.Trim(line, "+- ") - - if trimLine == models.LFSMetaFileIdentifier { - curFileLFSPrefix = true - } - - if curFileLFSPrefix && strings.HasPrefix(trimLine, models.LFSMetaFileOidPrefix) { - oid := strings.TrimPrefix(trimLine, models.LFSMetaFileOidPrefix) - - if len(oid) == 64 { - m := &models.LFSMetaObject{Oid: oid} - count, err := models.Count(m) - - if err == nil && count > 0 { - curFile.IsBin = true - curFile.IsLFSFile = true - curSection.Lines = nil + _, _ = sb.Write(lineBytes) + for isFragment { + // This is very odd indeed - we're in a section header and the line is too long + // This really shouldn't happen... + lineBytes, isFragment, err = input.ReadLine() + if err != nil { + // Now by the definition of ReadLine this cannot be io.EOF + err = fmt.Errorf("Unable to ReadLine: %v", err) + return } + _, _ = sb.Write(lineBytes) } - } + line := sb.String() - curFileLinesCount++ - lineCount++ - - // Diff data too large, we only show the first about maxLines lines - if curFileLinesCount >= maxLines { - curFile.IsIncomplete = true - } - switch { - case line[0] == ' ': - diffLine := &DiffLine{Type: DiffLinePlain, Content: line, LeftIdx: leftLine, RightIdx: rightLine} - leftLine++ - rightLine++ - curSection.Lines = append(curSection.Lines, diffLine) - curSection.FileName = curFile.Name - continue - case line[0] == '@': + // Create a new section to represent this hunk curSection = &DiffSection{} curFile.Sections = append(curFile.Sections, curSection) + lineSectionInfo := getDiffLineSectionInfo(curFile.Name, line, leftLine-1, rightLine-1) diffLine := &DiffLine{ Type: DiffLineSection, @@ -538,148 +699,132 @@ func ParsePatch(maxLines, maxLineCharacters, maxFiles int, reader io.Reader) (*D leftLine = lineSectionInfo.LeftIdx rightLine = lineSectionInfo.RightIdx continue - case line[0] == '+': + case '\\': + if curFileLinesCount >= maxLines { + curFile.IsIncomplete = true + continue + } + // This is used only to indicate that the current file does not have a terminal newline + if !bytes.Equal(lineBytes, []byte("\\ No newline at end of file")) { + err = fmt.Errorf("Unexpected line in hunk: %s", string(lineBytes)) + return + } + // Technically this should be the end the file! + // FIXME: we should be putting a marker at the end of the file if there is no terminal new line + continue + case '+': + curFileLinesCount++ curFile.Addition++ - diff.TotalAddition++ - diffLine := &DiffLine{Type: DiffLineAdd, Content: line, RightIdx: rightLine} + if curFileLinesCount >= maxLines { + curFile.IsIncomplete = true + continue + } + diffLine := &DiffLine{Type: DiffLineAdd, RightIdx: rightLine} rightLine++ curSection.Lines = append(curSection.Lines, diffLine) - curSection.FileName = curFile.Name - continue - case line[0] == '-': + case '-': + curFileLinesCount++ curFile.Deletion++ - diff.TotalDeletion++ - diffLine := &DiffLine{Type: DiffLineDel, Content: line, LeftIdx: leftLine} + if curFileLinesCount >= maxLines { + curFile.IsIncomplete = true + continue + } + diffLine := &DiffLine{Type: DiffLineDel, LeftIdx: leftLine} if leftLine > 0 { leftLine++ } curSection.Lines = append(curSection.Lines, diffLine) - curSection.FileName = curFile.Name - case strings.HasPrefix(line, "Binary"): - curFile.IsBin = true - continue + case ' ': + curFileLinesCount++ + if curFileLinesCount >= maxLines { + curFile.IsIncomplete = true + continue + } + diffLine := &DiffLine{Type: DiffLinePlain, LeftIdx: leftLine, RightIdx: rightLine} + leftLine++ + rightLine++ + curSection.Lines = append(curSection.Lines, diffLine) + default: + // This is unexpected + err = fmt.Errorf("Unexpected line in hunk: %s", string(lineBytes)) + return } - // Get new file. - if strings.HasPrefix(line, cmdDiffHead) { - if len(diff.Files) >= maxFiles { - diff.IsIncomplete = true - _, err := io.Copy(ioutil.Discard, reader) + line := string(lineBytes) + if isFragment { + curFile.IsIncomplete = true + for isFragment { + lineBytes, isFragment, err = input.ReadLine() if err != nil { - return nil, fmt.Errorf("Copy: %v", err) + // Now by the definition of ReadLine this cannot be io.EOF + err = fmt.Errorf("Unable to ReadLine: %v", err) + return } - break } + } + curSection.Lines[len(curSection.Lines)-1].Content = line - // Note: In case file name is surrounded by double quotes (it happens only in git-shell). - // e.g. diff --git "a/xxx" "b/xxx" - var a string - var b string + // handle LFS + if line[1:] == models.LFSMetaFileIdentifier { + curFileLFSPrefix = true + } else if curFileLFSPrefix && strings.HasPrefix(line[1:], models.LFSMetaFileOidPrefix) { + oid := strings.TrimPrefix(line[1:], models.LFSMetaFileOidPrefix) + if len(oid) == 64 { + m := &models.LFSMetaObject{Oid: oid} + count, err := models.Count(m) - rd := strings.NewReader(line[len(cmdDiffHead):]) - char, _ := rd.ReadByte() - _ = rd.UnreadByte() - if char == '"' { - fmt.Fscanf(rd, "%q ", &a) - if a[0] == '\\' { - a = a[1:] - } - } else { - fmt.Fscanf(rd, "%s ", &a) - } - char, _ = rd.ReadByte() - _ = rd.UnreadByte() - if char == '"' { - fmt.Fscanf(rd, "%q", &b) - if b[0] == '\\' { - b = b[1:] - } - } else { - fmt.Fscanf(rd, "%s", &b) - } - a = a[2:] - b = b[2:] - - curFile = &DiffFile{ - Name: b, - OldName: a, - Index: len(diff.Files) + 1, - Type: DiffFileChange, - Sections: make([]*DiffSection, 0, 10), - IsRenamed: a != b, - } - diff.Files = append(diff.Files, curFile) - curFileLinesCount = 0 - leftLine = 1 - rightLine = 1 - curFileLFSPrefix = false - - // Check file diff type and is submodule. - for { - line, err := input.ReadString('\n') - if err != nil { - if err == io.EOF { - isEOF = true - } else { - return nil, fmt.Errorf("ReadString: %v", err) - } - } - - switch { - case strings.HasPrefix(line, "copy from "): - curFile.IsRenamed = true - curFile.Type = DiffFileCopy - case strings.HasPrefix(line, "copy to "): - curFile.IsRenamed = true - curFile.Type = DiffFileCopy - case strings.HasPrefix(line, "new file"): - curFile.Type = DiffFileAdd - curFile.IsCreated = true - case strings.HasPrefix(line, "deleted"): - curFile.Type = DiffFileDel - curFile.IsDeleted = true - case strings.HasPrefix(line, "index"): - curFile.Type = DiffFileChange - case strings.HasPrefix(line, "similarity index 100%"): - curFile.Type = DiffFileRename - } - if curFile.Type > 0 { - if strings.HasSuffix(line, " 160000\n") { - curFile.IsSubmodule = true - } - break + if err == nil && count > 0 { + curFile.IsBin = true + curFile.IsLFSFile = true + curSection.Lines = nil } } } } +} - // FIXME: detect encoding while parsing. - var buf bytes.Buffer - for _, f := range diff.Files { - buf.Reset() - for _, sec := range f.Sections { - for _, l := range sec.Lines { - buf.WriteString(l.Content) - buf.WriteString("\n") - } - } - charsetLabel, err := charset.DetectEncoding(buf.Bytes()) - if charsetLabel != "UTF-8" && err == nil { - encoding, _ := stdcharset.Lookup(charsetLabel) - if encoding != nil { - d := encoding.NewDecoder() - for _, sec := range f.Sections { - for _, l := range sec.Lines { - if c, _, err := transform.String(d, l.Content); err == nil { - l.Content = c - } - } - } - } - } +func createDiffFile(diff *Diff, line string) *DiffFile { + // The a/ and b/ filenames are the same unless rename/copy is involved. + // Especially, even for a creation or a deletion, /dev/null is not used + // in place of the a/ or b/ filenames. + // + // When rename/copy is involved, file1 and file2 show the name of the + // source file of the rename/copy and the name of the file that rename/copy + // produces, respectively. + // + // Path names are quoted if necessary. + // + // This means that you should always be able to determine the file name even when there + // there is potential ambiguity... + // + // but we can be simpler with our heuristics by just forcing git to prefix things nicely + curFile := &DiffFile{ + Index: len(diff.Files) + 1, + Type: DiffFileChange, + Sections: make([]*DiffSection, 0, 10), } - diff.NumFiles = len(diff.Files) - return diff, nil + + rd := strings.NewReader(line[len(cmdDiffHead):] + " ") + curFile.Type = DiffFileChange + curFile.OldName = readFileName(rd) + curFile.Name = readFileName(rd) + curFile.IsRenamed = curFile.Name != curFile.OldName + return curFile +} + +func readFileName(rd *strings.Reader) string { + var name string + char, _ := rd.ReadByte() + _ = rd.UnreadByte() + if char == '"' { + fmt.Fscanf(rd, "%q ", &name) + if name[0] == '\\' { + name = name[1:] + } + } else { + fmt.Fscanf(rd, "%s ", &name) + } + return name[2:] } // GetDiffRange builds a Diff between two commits of a repository. diff --git a/services/gitdiff/gitdiff_test.go b/services/gitdiff/gitdiff_test.go index b90ad657f6..64cd4f1c21 100644 --- a/services/gitdiff/gitdiff_test.go +++ b/services/gitdiff/gitdiff_test.go @@ -182,6 +182,27 @@ rename to a b/a a/file b/b file oldFilename: "a b/file b/a a/file", filename: "a b/a a/file b/b file", }, + { + name: "minuses-and-pluses", + gitdiff: `diff --git a/minuses-and-pluses b/minuses-and-pluses +index 6961180..9ba1a00 100644 +--- a/minuses-and-pluses ++++ b/minuses-and-pluses +@@ -1,4 +1,4 @@ +--- 1st line +-++ 2nd line +--- 3rd line +-++ 4th line ++++ 1st line ++-- 2nd line ++++ 3rd line ++-- 4th line +`, + oldFilename: "minuses-and-pluses", + filename: "minuses-and-pluses", + addition: 4, + deletion: 4, + }, } for _, testcase := range tests { From 1ba4a7ec166119672844cf8425c518d3b0a832d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=B5=B5=E6=99=BA=E8=B6=85?= <1012112796@qq.com> Date: Sat, 17 Oct 2020 23:38:34 +0800 Subject: [PATCH 008/205] fix a small nit (#13187) Signed-off-by: a1012112796 <1012112796@qq.com> --- models/error.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/models/error.go b/models/error.go index be94d78891..b2273f74c9 100644 --- a/models/error.go +++ b/models/error.go @@ -2003,7 +2003,7 @@ type ErrNotValidReviewRequest struct { // IsErrNotValidReviewRequest checks if an error is a ErrNotValidReviewRequest. func IsErrNotValidReviewRequest(err error) bool { - _, ok := err.(ErrReviewNotExist) + _, ok := err.(ErrNotValidReviewRequest) return ok } From aca13f941ccfec998eed506c256a0d72b26e64dd Mon Sep 17 00:00:00 2001 From: techknowlogick Date: Sun, 18 Oct 2020 10:52:03 -0400 Subject: [PATCH 009/205] When handling errors in storageHandler check underlying error (#13178) (#13193) Unfortunately there was a mistake in #13164 which fails to handle os.PathError wrapping an os.ErrNotExist Signed-off-by: Andrew Thornton Co-authored-by: techknowlogick Co-authored-by: zeripath --- modules/storage/minio.go | 22 +++++++++++++++++++++- routers/routes/routes.go | 19 +++++++++++++++++-- 2 files changed, 38 insertions(+), 3 deletions(-) diff --git a/modules/storage/minio.go b/modules/storage/minio.go index eb43fa96ee..b65af8ddbd 100644 --- a/modules/storage/minio.go +++ b/modules/storage/minio.go @@ -30,7 +30,7 @@ type minioObject struct { func (m *minioObject) Stat() (os.FileInfo, error) { oi, err := m.Object.Stat() if err != nil { - return nil, err + return nil, convertMinioErr(err) } return &minioFileInfo{oi}, nil @@ -58,6 +58,26 @@ type MinioStorage struct { basePath string } +func convertMinioErr(err error) error { + if err == nil { + return nil + } + errResp, ok := err.(minio.ErrorResponse) + if !ok { + return err + } + + // Convert two responses to standard analogues + switch errResp.Code { + case "NoSuchKey": + return os.ErrNotExist + case "AccessDenied": + return os.ErrPermission + } + + return err +} + // NewMinioStorage returns a minio storage func NewMinioStorage(ctx context.Context, cfg interface{}) (ObjectStorage, error) { configInterface, err := toConfig(MinioStorageConfig{}, cfg) diff --git a/routers/routes/routes.go b/routers/routes/routes.go index a09e53efc1..135c6b56a8 100644 --- a/routers/routes/routes.go +++ b/routers/routes/routes.go @@ -7,8 +7,11 @@ package routes import ( "bytes" "encoding/gob" + "errors" + "fmt" "io" "net/http" + "os" "path" "strings" "text/template" @@ -125,7 +128,13 @@ func storageHandler(storageSetting setting.Storage, prefix string, objStore stor rPath := strings.TrimPrefix(req.RequestURI, "/"+prefix) u, err := objStore.URL(rPath, path.Base(rPath)) if err != nil { - ctx.Error(500, err.Error()) + if os.IsNotExist(err) || errors.Is(err, os.ErrNotExist) { + log.Warn("Unable to find %s %s", prefix, rPath) + ctx.Error(404, "file not found") + return + } + log.Error("Error whilst getting URL for %s %s. Error: %v", prefix, rPath, err) + ctx.Error(500, fmt.Sprintf("Error whilst getting URL for %s %s", prefix, rPath)) return } http.Redirect( @@ -152,7 +161,13 @@ func storageHandler(storageSetting setting.Storage, prefix string, objStore stor //If we have matched and access to release or issue fr, err := objStore.Open(rPath) if err != nil { - ctx.Error(500, err.Error()) + if os.IsNotExist(err) || errors.Is(err, os.ErrNotExist) { + log.Warn("Unable to find %s %s", prefix, rPath) + ctx.Error(404, "file not found") + return + } + log.Error("Error whilst opening %s %s. Error: %v", prefix, rPath, err) + ctx.Error(500, fmt.Sprintf("Error whilst opening %s %s", prefix, rPath)) return } defer fr.Close() From 35d0045ce278422e0ebbe4e93286301ac6bb5bb0 Mon Sep 17 00:00:00 2001 From: a1012112796 <1012112796@qq.com> Date: Mon, 19 Oct 2020 01:13:57 +0800 Subject: [PATCH 010/205] Update CHANGELOG.md (#13200) (#13202) Co-authored-by: zeripath Co-authored-by: zeripath --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b29e4c6307..8ca56e323f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,7 +4,7 @@ This changelog goes through all the changes that have been made in each release without substantial changes to our git log; to see the highlights of what has been added to each release, please refer to the [blog](https://blog.gitea.io). -## [1.13.0-RC1](https://github.com/go-gitea/gitea/releases/tag/v1.13.0-RC1) - 2020-10-14 +## [1.13.0-RC1](https://github.com/go-gitea/gitea/releases/tag/v1.13.0-rc1) - 2020-10-14 * SECURITY * Mitigate Security vulnerability in the git hook feature (#13058) From e97466b84062b229a8ee76e1f7da8e8d21170caf Mon Sep 17 00:00:00 2001 From: techknowlogick Date: Mon, 19 Oct 2020 02:56:17 -0400 Subject: [PATCH 011/205] Fix size and clickable area on file table back link (#13205) (#13207) Fixes: https://github.com/go-gitea/gitea/issues/13038 Should backport to 1.13. Co-authored-by: silverwind --- web_src/less/_repository.less | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/web_src/less/_repository.less b/web_src/less/_repository.less index 619bc749ef..fee85a700f 100644 --- a/web_src/less/_repository.less +++ b/web_src/less/_repository.less @@ -400,6 +400,13 @@ background-color: #ffffee; } + tr.has-parent a { + display: inline-block; + padding-top: 8px; + padding-bottom: 8px; + width: calc(100% - 1.25rem); + } + .jumpable-path { color: #888888; } From c47f9a0a704e47f1758ecbbc27829a324e6b91be Mon Sep 17 00:00:00 2001 From: techknowlogick Date: Tue, 20 Oct 2020 02:10:05 -0400 Subject: [PATCH 012/205] Various arc-green fixes (#13214) (#13215) - Style search dropdown - Fix radio buttons and tweak checkboxes - Add styling for error form elements - Make borders brighter and focus more apparent - Adjust comment box border color to match Fixes: https://github.com/go-gitea/gitea/pull/12491 Co-authored-by: silverwind --- web_src/less/themes/theme-arc-green.less | 171 +++++++++++++++++------ 1 file changed, 126 insertions(+), 45 deletions(-) diff --git a/web_src/less/themes/theme-arc-green.less b/web_src/less/themes/theme-arc-green.less index 4e657d376e..2bd9bf6a4f 100644 --- a/web_src/less/themes/theme-arc-green.less +++ b/web_src/less/themes/theme-arc-green.less @@ -600,14 +600,14 @@ footer { .ui.input input { background: #404552; - border: 2px solid #353945; + border: 1px solid #4b505f; color: #dbdbdb; } .ui.input input:focus, .ui.input.focus input { background: #404552; - border: 2px solid #353945; + border: 1px solid #6a737d; color: #dbdbdb; } @@ -618,7 +618,7 @@ footer { .ui.label, .ui.label.basic { color: #dbdbdb; - background-color: #404552; + background-color: #2a2e39; } .issue.list > .item .title { @@ -734,6 +734,7 @@ a.ui.basic.green.label:hover { } .ui.form input:not([type]), +.ui.form textarea, .ui.form input[type="date"], .ui.form input[type="datetime-local"], .ui.form input[type="email"], @@ -744,13 +745,34 @@ a.ui.basic.green.label:hover { .ui.form input[type="tel"], .ui.form input[type="text"], .ui.form input[type="time"], -.ui.form input[type="url"] { +.ui.form input[type="url"], +.ui.selection.dropdown { color: #9e9e9e; background: #404552; - border: 2px solid #353945; + border: 1px solid #4b505f; +} + +.ui.form input:not([type]):hover, +.ui.form textarea:hover, +.ui.form input[type="date"]:hover, +.ui.form input[type="datetime-local"]:hover, +.ui.form input[type="email"]:hover, +.ui.form input[type="file"]:hover, +.ui.form input[type="number"]:hover, +.ui.form input[type="password"]:hover, +.ui.form input[type="search"]:hover, +.ui.form input[type="tel"]:hover, +.ui.form input[type="text"]:hover, +.ui.form input[type="time"]:hover, +.ui.form input[type="url"]:hover, +.ui.selection.dropdown:hover { + background: #404552; + border: 1px solid #4b505f; + color: #dbdbdb; } .ui.form input:not([type]):focus, +.ui.form textarea:focus, .ui.form input[type="date"]:focus, .ui.form input[type="datetime-local"]:focus, .ui.form input[type="email"]:focus, @@ -761,14 +783,66 @@ a.ui.basic.green.label:hover { .ui.form input[type="tel"]:focus, .ui.form input[type="text"]:focus, .ui.form input[type="time"]:focus, -.ui.form input[type="url"]:focus { +.ui.form input[type="url"]:focus, +.ui.selection.dropdown:focus { background: #404552; - border: 2px solid #4b505f; + border: 1px solid #6a737d; color: #dbdbdb; } +.ui.form .fields.error .field textarea, +.ui.form .fields.error .field select, +.ui.form .fields.error .field input:not([type]), +.ui.form .fields.error .field input[type="date"], +.ui.form .fields.error .field input[type="datetime-local"], +.ui.form .fields.error .field input[type="email"], +.ui.form .fields.error .field input[type="number"], +.ui.form .fields.error .field input[type="password"], +.ui.form .fields.error .field input[type="search"], +.ui.form .fields.error .field input[type="tel"], +.ui.form .fields.error .field input[type="time"], +.ui.form .fields.error .field input[type="text"], +.ui.form .fields.error .field input[type="file"], +.ui.form .fields.error .field input[type="url"], +.ui.form .field.error textarea, +.ui.form .field.error select, +.ui.form .field.error input:not([type]), +.ui.form .field.error input[type="date"], +.ui.form .field.error input[type="datetime-local"], +.ui.form .field.error input[type="email"], +.ui.form .field.error input[type="number"], +.ui.form .field.error input[type="password"], +.ui.form .field.error input[type="search"], +.ui.form .field.error input[type="tel"], +.ui.form .field.error input[type="time"], +.ui.form .field.error input[type="text"], +.ui.form .field.error input[type="file"], +.ui.form .field.error input[type="url"] { + background-color: #522; + border: 1px solid #7d3434; + color: #f9cbcb; +} + +.ui.form .field.error select:focus, +.ui.form .field.error input:not([type]):focus, +.ui.form .field.error input[type="date"]:focus, +.ui.form .field.error input[type="datetime-local"]:focus, +.ui.form .field.error input[type="email"]:focus, +.ui.form .field.error input[type="number"]:focus, +.ui.form .field.error input[type="password"]:focus, +.ui.form .field.error input[type="search"]:focus, +.ui.form .field.error input[type="tel"]:focus, +.ui.form .field.error input[type="time"]:focus, +.ui.form .field.error input[type="text"]:focus, +.ui.form .field.error input[type="file"]:focus, +.ui.form .field.error input[type="url"]:focus { + background-color: #522; + border: 1px solid #a04141; + color: #f9cbcb; +} + .ui.action.input:not([class*="left action"]) input:focus { - border-right-color: #4b505f !important; + border-right-color: #6a737d !important; } .ui.green.button, @@ -799,6 +873,20 @@ a.ui.basic.green.label:hover { color: #dbdbdb; } +.ui.search > .results { + background: #383c4a; + border-color: #4c505c; +} + +.ui.search > .results .result:hover, +.ui.category.search > .results .category .result:hover { + background: #404552; +} + +.ui.search > .results .result .title { + color: #dbdbdb; +} + .ui.table thead th, .ui.table > thead > tr > th { background: #404552; @@ -1060,17 +1148,6 @@ a.ui.basic.green.label:hover { box-shadow: 0 0 0 1px #13ae38 inset !important; } -.ui.form textarea, -.ui.form textarea:focus { - color: #dbdbdb; - background: #404552; - border: 2px solid #353945; -} - -.ui.form textarea:focus { - border: 1px solid #456580; -} - .ui .info.segment.top { background-color: #404552 !important; } @@ -1152,12 +1229,6 @@ td.blob-hunk { box-shadow: 0 2px 3px 0 rgba(34, 36, 38, .15); } -.ui.selection.dropdown { - background: #404552; - border: 1px solid #404552; - color: #9e9e9e; -} - .ui.menu .ui.dropdown .menu > .active.item { color: #dbdbdb !important; } @@ -1325,57 +1396,58 @@ input { .ui.checkbox input:checked ~ .box:after, .ui.checkbox input:checked ~ label:after { - color: #7f98ad; + color: #dbdbdb; } .ui.checkbox input:checked ~ .box:before, .ui.checkbox input:checked ~ label:before { - background: #304251; + background: #404552; opacity: 1; - color: #7f98ad; - border-color: #304251; + color: #dbdbdb; + border-color: #4b505f; } .ui.checkbox .box:hover::before, .ui.checkbox label:hover::before { - background: #304251; + background: #404552; + border-color: #4b505f; } .ui.checkbox .box:before, .ui.checkbox label:before { - background: #304251; - border: 1px solid #304251; + background: #404552; + border: 1px solid #4b505f; } .ui.checkbox label:before { - border-color: #476075; + border-color: #4b505f; } .ui.checkbox .box:active::before, .ui.checkbox label:active::before { - background: #304251; - border-color: rgba(34, 36, 38, .35); + background: #404552; + border-color: #6a737d; } .ui.checkbox input:focus ~ .box:before, .ui.checkbox input:focus ~ label:before { - border-color: #304251; - background: #304251; + border-color: #6a737d; + background: #404552; } .ui.checkbox input:checked:focus ~ .box:before, .ui.checkbox input:checked:focus ~ label:before, .ui.checkbox input:not([type="radio"]):indeterminate:focus ~ .box:before, .ui.checkbox input:not([type="radio"]):indeterminate:focus ~ label:before { - border-color: #304251; - background: #304251; + border-color: #6a737d; + background: #404552; } .ui.checkbox input:checked:focus ~ .box:after, .ui.checkbox input:checked:focus ~ label:after, .ui.checkbox input:not([type="radio"]):indeterminate:focus ~ .box:after, .ui.checkbox input:not([type="radio"]):indeterminate:focus ~ label:after { - color: #7f98ad; + color: #dbdbdb; } .ui.checkbox input:focus ~ .box:after, @@ -1384,8 +1456,17 @@ input { color: #9a9a9a; } -.ui.selection.dropdown:hover { - border: 1px solid #456580; +.ui.radio.checkbox label::after, +.ui.radio.checkbox input:checked ~ label::after, +.ui.radio.checkbox input:focus ~ label::after, +.ui.radio.checkbox input:focus:checked ~ label::after, { + background: #dbdbdb; +} + +.ui.radio.checkbox input:checked ~ label::before, +.ui.radio.checkbox input:focus ~ label::before, +.ui.radio.checkbox input:focus:checked ~ label::before { + background: none; } .ui.selection.dropdown .menu > .item { @@ -1413,7 +1494,7 @@ input { } .ui.form .dropzone { - border: 2px dashed #7f98ad; + border: 1px dashed #7f98ad; background-color: #2e323e; .dz-button { @@ -1670,7 +1751,7 @@ a.ui.labels .label:hover { .editor-toolbar { background-color: #404552; - border-color: #7f98ad; + border-color: #4b505f; } .edit-diff > div > .ui.table { @@ -1801,7 +1882,7 @@ a.ui.labels .label:hover { .CodeMirror { color: #9daccc; background-color: #2e323e; - border-color: #7f98ad; + border-color: #4b505f; border-top: 0; div.CodeMirror-cursor { From ba97c0e98bc97957d6fd9bfd3db5768813c58ff3 Mon Sep 17 00:00:00 2001 From: 6543 <6543@obermui.de> Date: Wed, 21 Oct 2020 00:39:37 +0200 Subject: [PATCH 013/205] Update heatmap fixtures to restore tests (#13224) (#13225) `the hotfix day` --- integrations/api_user_heatmap_test.go | 2 +- models/fixtures/action.yml | 2 +- models/user_heatmap_test.go | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/integrations/api_user_heatmap_test.go b/integrations/api_user_heatmap_test.go index 159d70e867..105d39e9ae 100644 --- a/integrations/api_user_heatmap_test.go +++ b/integrations/api_user_heatmap_test.go @@ -26,7 +26,7 @@ func TestUserHeatmap(t *testing.T) { var heatmap []*models.UserHeatmapData DecodeJSON(t, resp, &heatmap) var dummyheatmap []*models.UserHeatmapData - dummyheatmap = append(dummyheatmap, &models.UserHeatmapData{Timestamp: 1571616000, Contributions: 1}) + dummyheatmap = append(dummyheatmap, &models.UserHeatmapData{Timestamp: 1603152000, Contributions: 1}) assert.Equal(t, dummyheatmap, heatmap) } diff --git a/models/fixtures/action.yml b/models/fixtures/action.yml index e8a6d531f2..eb92aeedbe 100644 --- a/models/fixtures/action.yml +++ b/models/fixtures/action.yml @@ -5,7 +5,7 @@ act_user_id: 2 repo_id: 2 is_private: true - created_unix: 1571686356 + created_unix: 1603228283 - id: 2 diff --git a/models/user_heatmap_test.go b/models/user_heatmap_test.go index c2825d9ff0..c9d33db29b 100644 --- a/models/user_heatmap_test.go +++ b/models/user_heatmap_test.go @@ -17,7 +17,7 @@ func TestGetUserHeatmapDataByUser(t *testing.T) { CountResult int JSONResult string }{ - {2, 1, `[{"timestamp":1571616000,"contributions":1}]`}, + {2, 1, `[{"timestamp":1603152000,"contributions":1}]`}, {3, 0, `[]`}, } // Prepare From 198e57bc37c62635b4546b859a56b94a824aa1f3 Mon Sep 17 00:00:00 2001 From: zeripath Date: Wed, 21 Oct 2020 19:54:19 +0100 Subject: [PATCH 014/205] Return the full rejection message and errors in flash errors (#13221) (#13237) * Return the full rejection message and errors in flash errors (#13221) Signed-off-by: Andrew Thornton * Update routers/repo/pull.go Co-authored-by: John Olheiser Co-authored-by: John Olheiser --- options/locale/locale_en-US.ini | 16 ++++++--- routers/repo/branch.go | 11 ++++++- routers/repo/editor.go | 44 ++++++++++++++++++++++--- routers/repo/pull.go | 55 ++++++++++++++++++++++++++++--- routers/repo/repo.go | 3 +- routers/utils/utils.go | 6 ---- templates/base/alert.tmpl | 6 ++-- templates/base/alert_details.tmpl | 7 ++++ web_src/less/_base.less | 5 +++ 9 files changed, 128 insertions(+), 25 deletions(-) create mode 100644 templates/base/alert_details.tmpl diff --git a/options/locale/locale_en-US.ini b/options/locale/locale_en-US.ini index 16d3874e1b..18c621db67 100644 --- a/options/locale/locale_en-US.ini +++ b/options/locale/locale_en-US.ini @@ -870,9 +870,11 @@ editor.file_already_exists = A file named '%s' already exists in this repository editor.commit_empty_file_header = Commit an empty file editor.commit_empty_file_text = The file you're about to commit is empty. Proceed? editor.no_changes_to_show = There are no changes to show. -editor.fail_to_update_file = Failed to update/create file '%s' with error: %v +editor.fail_to_update_file = Failed to update/create file '%s'. +editor.fail_to_update_file_summary = Error Message: editor.push_rejected_no_message = The change was rejected by the server without a message. Please check githooks. -editor.push_rejected = The change was rejected by the server with the following message:
%s
Please check githooks. +editor.push_rejected = The change was rejected by the server. Please check githooks. +editor.push_rejected_summary = Full Rejection Message: editor.add_subdir = Add a directory… editor.unable_to_upload_files = Failed to upload files to '%s' with error: %v editor.upload_file_is_locked = File '%s' is locked by %s. @@ -1259,11 +1261,15 @@ pulls.rebase_merge_commit_pull_request = Rebase and Merge (--no-ff) pulls.squash_merge_pull_request = Squash and Merge pulls.require_signed_wont_sign = The branch requires signed commits but this merge will not be signed pulls.invalid_merge_option = You cannot use this merge option for this pull request. -pulls.merge_conflict = Merge Failed: There was a conflict whilst merging: %[1]s
%[2]s
Hint: Try a different strategy -pulls.rebase_conflict = Merge Failed: There was a conflict whilst rebasing commit: %[1]s
%[2]s
%[3]s
Hint:Try a different strategy +pulls.merge_conflict = Merge Failed: There was a conflict whilst merging. Hint: Try a different strategy +pulls.merge_conflict_summary = Error Message +pulls.rebase_conflict = Merge Failed: There was a conflict whilst rebasing commit: %[1]s. Hint: Try a different strategy +pulls.rebase_conflict_summary = Error Message +; %[2]s
%[3]s
pulls.unrelated_histories = Merge Failed: The merge head and base do not share a common history. Hint: Try a different strategy pulls.merge_out_of_date = Merge Failed: Whilst generating the merge, the base was updated. Hint: Try again. -pulls.push_rejected = Merge Failed: The push was rejected with the following message:
%s
Review the githooks for this repository +pulls.push_rejected = Merge Failed: The push was rejected. Review the githooks for this repository. +pulls.push_rejected_summary = Full Rejection Message pulls.push_rejected_no_message = Merge Failed: The push was rejected but there was no remote message.
Review the githooks for this repository pulls.open_unmerged_pull_exists = `You cannot perform a reopen operation because there is a pending pull request (#%d) with identical properties.` pulls.status_checking = Some checks are pending diff --git a/routers/repo/branch.go b/routers/repo/branch.go index 0ca77cbf6f..cd18f66777 100644 --- a/routers/repo/branch.go +++ b/routers/repo/branch.go @@ -355,7 +355,16 @@ func CreateBranch(ctx *context.Context, form auth.NewBranchForm) { if len(e.Message) == 0 { ctx.Flash.Error(ctx.Tr("repo.editor.push_rejected_no_message")) } else { - ctx.Flash.Error(ctx.Tr("repo.editor.push_rejected", utils.SanitizeFlashErrorString(e.Message))) + flashError, err := ctx.HTMLString(string(tplAlertDetails), map[string]interface{}{ + "Message": ctx.Tr("repo.editor.push_rejected"), + "Summary": ctx.Tr("repo.editor.push_rejected_summary"), + "Details": utils.SanitizeFlashErrorString(e.Message), + }) + if err != nil { + ctx.ServerError("UpdatePullRequest.HTMLString", err) + return + } + ctx.Flash.Error(flashError) } ctx.Redirect(ctx.Repo.RepoLink + "/src/" + ctx.Repo.BranchNameSubURL()) return diff --git a/routers/repo/editor.go b/routers/repo/editor.go index a08c7193f8..1ee557a4fd 100644 --- a/routers/repo/editor.go +++ b/routers/repo/editor.go @@ -293,10 +293,28 @@ func editFilePost(ctx *context.Context, form auth.EditRepoFileForm, isNewFile bo if len(errPushRej.Message) == 0 { ctx.RenderWithErr(ctx.Tr("repo.editor.push_rejected_no_message"), tplEditFile, &form) } else { - ctx.RenderWithErr(ctx.Tr("repo.editor.push_rejected", utils.SanitizeFlashErrorString(errPushRej.Message)), tplEditFile, &form) + flashError, err := ctx.HTMLString(string(tplAlertDetails), map[string]interface{}{ + "Message": ctx.Tr("repo.editor.push_rejected"), + "Summary": ctx.Tr("repo.editor.push_rejected_summary"), + "Details": utils.SanitizeFlashErrorString(errPushRej.Message), + }) + if err != nil { + ctx.ServerError("editFilePost.HTMLString", err) + return + } + ctx.RenderWithErr(flashError, tplEditFile, &form) } } else { - ctx.RenderWithErr(ctx.Tr("repo.editor.fail_to_update_file", form.TreePath, utils.SanitizeFlashErrorString(err.Error())), tplEditFile, &form) + flashError, err := ctx.HTMLString(string(tplAlertDetails), map[string]interface{}{ + "Message": ctx.Tr("repo.editor.fail_to_update_file", form.TreePath), + "Summary": ctx.Tr("repo.editor.fail_to_update_file_summary"), + "Details": utils.SanitizeFlashErrorString(err.Error()), + }) + if err != nil { + ctx.ServerError("editFilePost.HTMLString", err) + return + } + ctx.RenderWithErr(flashError, tplEditFile, &form) } } @@ -464,7 +482,16 @@ func DeleteFilePost(ctx *context.Context, form auth.DeleteRepoFileForm) { if len(errPushRej.Message) == 0 { ctx.RenderWithErr(ctx.Tr("repo.editor.push_rejected_no_message"), tplDeleteFile, &form) } else { - ctx.RenderWithErr(ctx.Tr("repo.editor.push_rejected", utils.SanitizeFlashErrorString(errPushRej.Message)), tplDeleteFile, &form) + flashError, err := ctx.HTMLString(string(tplAlertDetails), map[string]interface{}{ + "Message": ctx.Tr("repo.editor.push_rejected"), + "Summary": ctx.Tr("repo.editor.push_rejected_summary"), + "Details": utils.SanitizeFlashErrorString(errPushRej.Message), + }) + if err != nil { + ctx.ServerError("DeleteFilePost.HTMLString", err) + return + } + ctx.RenderWithErr(flashError, tplDeleteFile, &form) } } else { ctx.ServerError("DeleteRepoFile", err) @@ -656,7 +683,16 @@ func UploadFilePost(ctx *context.Context, form auth.UploadRepoFileForm) { if len(errPushRej.Message) == 0 { ctx.RenderWithErr(ctx.Tr("repo.editor.push_rejected_no_message"), tplUploadFile, &form) } else { - ctx.RenderWithErr(ctx.Tr("repo.editor.push_rejected", utils.SanitizeFlashErrorString(errPushRej.Message)), tplUploadFile, &form) + flashError, err := ctx.HTMLString(string(tplAlertDetails), map[string]interface{}{ + "Message": ctx.Tr("repo.editor.push_rejected"), + "Summary": ctx.Tr("repo.editor.push_rejected_summary"), + "Details": utils.SanitizeFlashErrorString(errPushRej.Message), + }) + if err != nil { + ctx.ServerError("UploadFilePost.HTMLString", err) + return + } + ctx.RenderWithErr(flashError, tplUploadFile, &form) } } else { // os.ErrNotExist - upload file missing in the intervening time?! diff --git a/routers/repo/pull.go b/routers/repo/pull.go index 54da7b76b7..f5c3aec0f8 100644 --- a/routers/repo/pull.go +++ b/routers/repo/pull.go @@ -723,7 +723,16 @@ func UpdatePullRequest(ctx *context.Context) { if err = pull_service.Update(issue.PullRequest, ctx.User, message); err != nil { if models.IsErrMergeConflicts(err) { conflictError := err.(models.ErrMergeConflicts) - ctx.Flash.Error(ctx.Tr("repo.pulls.merge_conflict", utils.SanitizeFlashErrorString(conflictError.StdErr), utils.SanitizeFlashErrorString(conflictError.StdOut))) + flashError, err := ctx.HTMLString(string(tplAlertDetails), map[string]interface{}{ + "Message": ctx.Tr("repo.pulls.merge_conflict"), + "Summary": ctx.Tr("repo.pulls.merge_conflict_summary"), + "Details": utils.SanitizeFlashErrorString(conflictError.StdErr) + "
" + utils.SanitizeFlashErrorString(conflictError.StdOut), + }) + if err != nil { + ctx.ServerError("UpdatePullRequest.HTMLString", err) + return + } + ctx.Flash.Error(flashError) ctx.Redirect(ctx.Repo.RepoLink + "/pulls/" + com.ToStr(issue.Index)) return } @@ -846,12 +855,30 @@ func MergePullRequest(ctx *context.Context, form auth.MergePullRequestForm) { return } else if models.IsErrMergeConflicts(err) { conflictError := err.(models.ErrMergeConflicts) - ctx.Flash.Error(ctx.Tr("repo.pulls.merge_conflict", utils.SanitizeFlashErrorString(conflictError.StdErr), utils.SanitizeFlashErrorString(conflictError.StdOut))) + flashError, err := ctx.HTMLString(string(tplAlertDetails), map[string]interface{}{ + "Message": ctx.Tr("repo.editor.merge_conflict"), + "Summary": ctx.Tr("repo.editor.merge_conflict_summary"), + "Details": utils.SanitizeFlashErrorString(conflictError.StdErr) + "
" + utils.SanitizeFlashErrorString(conflictError.StdOut), + }) + if err != nil { + ctx.ServerError("MergePullRequest.HTMLString", err) + return + } + ctx.Flash.Error(flashError) ctx.Redirect(ctx.Repo.RepoLink + "/pulls/" + com.ToStr(pr.Index)) return } else if models.IsErrRebaseConflicts(err) { conflictError := err.(models.ErrRebaseConflicts) - ctx.Flash.Error(ctx.Tr("repo.pulls.rebase_conflict", utils.SanitizeFlashErrorString(conflictError.CommitSHA), utils.SanitizeFlashErrorString(conflictError.StdErr), utils.SanitizeFlashErrorString(conflictError.StdOut))) + flashError, err := ctx.HTMLString(string(tplAlertDetails), map[string]interface{}{ + "Message": ctx.Tr("repo.pulls.rebase_conflict", utils.SanitizeFlashErrorString(conflictError.CommitSHA)), + "Summary": ctx.Tr("repo.pulls.rebase_conflict_summary"), + "Details": utils.SanitizeFlashErrorString(conflictError.StdErr) + "
" + utils.SanitizeFlashErrorString(conflictError.StdOut), + }) + if err != nil { + ctx.ServerError("MergePullRequest.HTMLString", err) + return + } + ctx.Flash.Error(flashError) ctx.Redirect(ctx.Repo.RepoLink + "/pulls/" + com.ToStr(pr.Index)) return } else if models.IsErrMergeUnrelatedHistories(err) { @@ -871,7 +898,16 @@ func MergePullRequest(ctx *context.Context, form auth.MergePullRequestForm) { if len(message) == 0 { ctx.Flash.Error(ctx.Tr("repo.pulls.push_rejected_no_message")) } else { - ctx.Flash.Error(ctx.Tr("repo.pulls.push_rejected", utils.SanitizeFlashErrorString(pushrejErr.Message))) + flashError, err := ctx.HTMLString(string(tplAlertDetails), map[string]interface{}{ + "Message": ctx.Tr("repo.pulls.push_rejected"), + "Summary": ctx.Tr("repo.pulls.push_rejected_summary"), + "Details": utils.SanitizeFlashErrorString(pushrejErr.Message), + }) + if err != nil { + ctx.ServerError("MergePullRequest.HTMLString", err) + return + } + ctx.Flash.Error(flashError) } ctx.Redirect(ctx.Repo.RepoLink + "/pulls/" + com.ToStr(pr.Index)) return @@ -986,7 +1022,16 @@ func CompareAndPullRequestPost(ctx *context.Context, form auth.CreateIssueForm) if len(message) == 0 { ctx.Flash.Error(ctx.Tr("repo.pulls.push_rejected_no_message")) } else { - ctx.Flash.Error(ctx.Tr("repo.pulls.push_rejected", utils.SanitizeFlashErrorString(pushrejErr.Message))) + flashError, err := ctx.HTMLString(string(tplAlertDetails), map[string]interface{}{ + "Message": ctx.Tr("repo.pulls.push_rejected"), + "Summary": ctx.Tr("repo.pulls.push_rejected_summary"), + "Details": utils.SanitizeFlashErrorString(pushrejErr.Message), + }) + if err != nil { + ctx.ServerError("CompareAndPullRequest.HTMLString", err) + return + } + ctx.Flash.Error(flashError) } ctx.Redirect(ctx.Repo.RepoLink + "/pulls/" + com.ToStr(pullIssue.Index)) return diff --git a/routers/repo/repo.go b/routers/repo/repo.go index 883d30a5d9..742c952f6e 100644 --- a/routers/repo/repo.go +++ b/routers/repo/repo.go @@ -24,7 +24,8 @@ import ( ) const ( - tplCreate base.TplName = "repo/create" + tplCreate base.TplName = "repo/create" + tplAlertDetails base.TplName = "base/alert_details" ) // MustBeNotEmpty render when a repo is a empty git dir diff --git a/routers/utils/utils.go b/routers/utils/utils.go index d8060ff077..f15bc1e62e 100644 --- a/routers/utils/utils.go +++ b/routers/utils/utils.go @@ -41,12 +41,6 @@ func IsValidSlackChannel(channelName string) bool { // SanitizeFlashErrorString will sanitize a flash error string func SanitizeFlashErrorString(x string) string { - runes := []rune(x) - - if len(runes) > 512 { - x = "..." + string(runes[len(runes)-512:]) - } - return strings.ReplaceAll(html.EscapeString(x), "\n", "
") } diff --git a/templates/base/alert.tmpl b/templates/base/alert.tmpl index 61b99486e2..cf886f529c 100644 --- a/templates/base/alert.tmpl +++ b/templates/base/alert.tmpl @@ -1,15 +1,15 @@ {{if .Flash.ErrorMsg}} -
+

{{.Flash.ErrorMsg | Str2html}}

{{end}} {{if .Flash.SuccessMsg}} -
+

{{.Flash.SuccessMsg | Str2html}}

{{end}} {{if .Flash.InfoMsg}} -
+

{{.Flash.InfoMsg | Str2html}}

{{end}} diff --git a/templates/base/alert_details.tmpl b/templates/base/alert_details.tmpl new file mode 100644 index 0000000000..38a2721bf8 --- /dev/null +++ b/templates/base/alert_details.tmpl @@ -0,0 +1,7 @@ +{{.Message}} +
+ {{.Summary}} + + {{.Details | Str2html}} + +
diff --git a/web_src/less/_base.less b/web_src/less/_base.less index dc4f4c6daa..765c0f9c93 100644 --- a/web_src/less/_base.less +++ b/web_src/less/_base.less @@ -1280,3 +1280,8 @@ table th[data-sortt-desc] { .ui.header > .ui.label.compact { margin-top: inherit; } + +.flash-error details code { + display: block; + text-align: left; +} From 52d333f0841be774b5ed116cd75434814bc09957 Mon Sep 17 00:00:00 2001 From: mrsdizzie Date: Wed, 21 Oct 2020 22:37:50 -0400 Subject: [PATCH 015/205] Add better error checking for inline html diff code (#13251) * Fix error in diff html rendering (#13191) * Fix error in diff html rendering Was missing an optional whitespace check in regex. Also noticed a rare case where diff.Type == Equal would be empty and thus get a newline attached. Fixed that too. Fixes #13177 * Update services/gitdiff/gitdiff.go Co-authored-by: zeripath * Update gitdiff_test.go * fmt Co-authored-by: zeripath * Add better error checking for inline html diff code (#13239) * Add better error checking for inline html diff code A better fix for #13191 which cleans up this code a bit and adds basic checking which should avoid writing broken HTML in future situations. * Update gitdiff_test.go * better regex Co-authored-by: zeripath --- services/gitdiff/gitdiff.go | 98 +++++++++++++++----------------- services/gitdiff/gitdiff_test.go | 13 ++++- 2 files changed, 58 insertions(+), 53 deletions(-) diff --git a/services/gitdiff/gitdiff.go b/services/gitdiff/gitdiff.go index 91105399db..164e1c0ca5 100644 --- a/services/gitdiff/gitdiff.go +++ b/services/gitdiff/gitdiff.go @@ -181,64 +181,60 @@ var ( removedCodePrefix = []byte(``) codeTagSuffix = []byte(``) ) -var addSpanRegex = regexp.MustCompile(`]?$`) + +// shouldWriteInline represents combinations where we manually write inline changes +func shouldWriteInline(diff diffmatchpatch.Diff, lineType DiffLineType) bool { + if true && + diff.Type == diffmatchpatch.DiffEqual || + diff.Type == diffmatchpatch.DiffInsert && lineType == DiffLineAdd || + diff.Type == diffmatchpatch.DiffDelete && lineType == DiffLineDel { + return true + } + return false +} func diffToHTML(fileName string, diffs []diffmatchpatch.Diff, lineType DiffLineType) template.HTML { buf := bytes.NewBuffer(nil) - var addSpan string - for i := range diffs { + match := "" + + for _, diff := range diffs { + if shouldWriteInline(diff, lineType) { + if len(match) > 0 { + diff.Text = match + diff.Text + match = "" + } + // Chroma HTML syntax highlighting is done before diffing individual lines in order to maintain consistency. + // Since inline changes might split in the middle of a chroma span tag, make we manually put it back together + // before writing so we don't try insert added/removed code spans in the middle of an existing chroma span + // and create broken HTML. + m := trailingSpanRegex.FindStringSubmatchIndex(diff.Text) + if m != nil { + match = diff.Text[m[0]:m[1]] + diff.Text = strings.TrimSuffix(diff.Text, match) + } + // Print an existing closing span first before opening added/remove-code span so it doesn't unintentionally close it + if strings.HasPrefix(diff.Text, "") { + buf.WriteString("") + diff.Text = strings.TrimPrefix(diff.Text, "") + } + // If we weren't able to fix it then this should avoid broken HTML by not inserting more spans below + // The previous/next diff section will contain the rest of the tag that is missing here + if strings.Count(diff.Text, "<") != strings.Count(diff.Text, ">") { + buf.WriteString(diff.Text) + continue + } + } switch { - case diffs[i].Type == diffmatchpatch.DiffEqual: - // Looking for the case where our 3rd party diff library previously detected a string difference - // in the middle of a span class because we highlight them first. This happens when added/deleted code - // also changes the chroma class name, either partially or fully. If found, just move the openining span code forward into the next section - // see TestDiffToHTML for examples - if len(addSpan) > 0 { - diffs[i].Text = addSpan + diffs[i].Text - addSpan = "" - } - m := addSpanRegex.FindStringSubmatchIndex(diffs[i].Text) - if m != nil { - addSpan = diffs[i].Text[m[0]:m[1]] - buf.WriteString(strings.TrimSuffix(diffs[i].Text, addSpan)) - } else { - addSpan = "" - buf.WriteString(getLineContent(diffs[i].Text)) - } - case diffs[i].Type == diffmatchpatch.DiffInsert && lineType == DiffLineAdd: - if len(addSpan) > 0 { - diffs[i].Text = addSpan + diffs[i].Text - addSpan = "" - } - // Print existing closing span first before opening added-code span so it doesn't unintentionally close it - if strings.HasPrefix(diffs[i].Text, "") { - buf.WriteString("") - diffs[i].Text = strings.TrimPrefix(diffs[i].Text, "") - } - m := addSpanRegex.FindStringSubmatchIndex(diffs[i].Text) - if m != nil { - addSpan = diffs[i].Text[m[0]:m[1]] - diffs[i].Text = strings.TrimSuffix(diffs[i].Text, addSpan) - } + case diff.Type == diffmatchpatch.DiffEqual: + buf.WriteString(diff.Text) + case diff.Type == diffmatchpatch.DiffInsert && lineType == DiffLineAdd: buf.Write(addedCodePrefix) - buf.WriteString(getLineContent(diffs[i].Text)) + buf.WriteString(diff.Text) buf.Write(codeTagSuffix) - case diffs[i].Type == diffmatchpatch.DiffDelete && lineType == DiffLineDel: - if len(addSpan) > 0 { - diffs[i].Text = addSpan + diffs[i].Text - addSpan = "" - } - if strings.HasPrefix(diffs[i].Text, "") { - buf.WriteString("") - diffs[i].Text = strings.TrimPrefix(diffs[i].Text, "") - } - m := addSpanRegex.FindStringSubmatchIndex(diffs[i].Text) - if m != nil { - addSpan = diffs[i].Text[m[0]:m[1]] - diffs[i].Text = strings.TrimSuffix(diffs[i].Text, addSpan) - } + case diff.Type == diffmatchpatch.DiffDelete && lineType == DiffLineDel: buf.Write(removedCodePrefix) - buf.WriteString(getLineContent(diffs[i].Text)) + buf.WriteString(diff.Text) buf.Write(codeTagSuffix) } } diff --git a/services/gitdiff/gitdiff_test.go b/services/gitdiff/gitdiff_test.go index 64cd4f1c21..e7eeca7004 100644 --- a/services/gitdiff/gitdiff_test.go +++ b/services/gitdiff/gitdiff_test.go @@ -50,7 +50,7 @@ func TestDiffToHTML(t *testing.T) { {Type: dmp.DiffEqual, Text: " {"}, }, DiffLineAdd)) - assertEqual(t, "tagURL := fmt.Sprintf("## [%s](%s/%s/%s/%s?q=&type=all&state=closed&milestone=%d) - %s", ge.Milestone\", ge.BaseURL, ge.Owner, ge.Repo, from, milestoneID, time.Now().Format("2006-01-02"))", diffToHTML("", []dmp.Diff{ + assertEqual(t, "tagURL := fmt.Sprintf("## [%s](%s/%s/%s/%s?q=&type=all&state=closed&milestone=%d) - %s", ge.Milestone\", ge.BaseURL, ge.Owner, ge.Repo, from, milestoneID, time.Now().Format("2006-01-02"))", diffToHTML("", []dmp.Diff{ {Type: dmp.DiffEqual, Text: "tagURL := fmt.Sprintf("## [%s](%s/%s/%s/%s?q=&type=all&state=closed&milestone=%d) - %s", ge.Milestone\""}, {Type: dmp.DiffInsert, Text: "f\">getGiteaTagURL(client"}, @@ -60,7 +60,7 @@ func TestDiffToHTML(t *testing.T) { {Type: dmp.DiffEqual, Text: ")"}, }, DiffLineDel)) - assertEqual(t, "r.WrapperRenderer(w, language, true, attrs, false)", diffToHTML("", []dmp.Diff{ + assertEqual(t, "r.WrapperRenderer(w, language, true, attrs, false)", diffToHTML("", []dmp.Diff{ {Type: dmp.DiffEqual, Text: "r.WrapperRenderer(w, "}, {Type: dmp.DiffDelete, Text: "language, true, attrs"}, {Type: dmp.DiffEqual, Text: ", false)"}, }, DiffLineAdd)) + + assertEqual(t, "print("// ", sys.argv)", diffToHTML("", []dmp.Diff{ + {Type: dmp.DiffEqual, Text: "print"}, + {Type: dmp.DiffInsert, Text: "("}, + {Type: dmp.DiffEqual, Text: ""// ", sys.argv"}, + {Type: dmp.DiffInsert, Text: ")"}, + }, DiffLineAdd)) } func TestParsePatch_singlefile(t *testing.T) { From d51c574350d97057c7f75c936e6b120a2f4089ed Mon Sep 17 00:00:00 2001 From: zeripath Date: Thu, 22 Oct 2020 13:59:01 +0100 Subject: [PATCH 016/205] Fix initial commit page & binary munching problem (#13249) (#13258) Backport #13249 * Fix initial commit page Unfortunately as a result of properly fixing ParsePatch the hack that used git show to get the diff for this failed. This PR fixes this using the "super-secret" empty tree ref to make the diff against. Signed-off-by: Andrew Thornton * Also fix #13248 Signed-off-by: Andrew Thornton * Update services/gitdiff/gitdiff.go Co-authored-by: 6543 <6543@obermui.de> Co-authored-by: 6543 <6543@obermui.de> --- services/gitdiff/gitdiff.go | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/services/gitdiff/gitdiff.go b/services/gitdiff/gitdiff.go index 164e1c0ca5..7acf8324c3 100644 --- a/services/gitdiff/gitdiff.go +++ b/services/gitdiff/gitdiff.go @@ -530,6 +530,8 @@ parsingLoop: break parsingLoop } switch { + case strings.HasPrefix(line, cmdDiffHead): + break curFileLoop case strings.HasPrefix(line, "old mode ") || strings.HasPrefix(line, "new mode "): if strings.HasSuffix(line, " 160000\n") { @@ -850,7 +852,14 @@ func GetDiffRangeWithWhitespaceBehavior(repoPath, beforeCommitID, afterCommitID defer cancel() var cmd *exec.Cmd if (len(beforeCommitID) == 0 || beforeCommitID == git.EmptySHA) && commit.ParentCount() == 0 { - cmd = exec.CommandContext(ctx, git.GitExecutable, "show", afterCommitID) + diffArgs := []string{"diff", "--src-prefix=\\a/", "--dst-prefix=\\b/", "-M"} + if len(whitespaceBehavior) != 0 { + diffArgs = append(diffArgs, whitespaceBehavior) + } + // append empty tree ref + diffArgs = append(diffArgs, "4b825dc642cb6eb9a060e54bf8d69288fbee4904") + diffArgs = append(diffArgs, afterCommitID) + cmd = exec.CommandContext(ctx, git.GitExecutable, diffArgs...) } else { actualBeforeCommitID := beforeCommitID if len(actualBeforeCommitID) == 0 { From ad4dde1d49d554fa2fc4d842a85ba860e1520da8 Mon Sep 17 00:00:00 2001 From: silverwind Date: Fri, 23 Oct 2020 00:55:44 +0200 Subject: [PATCH 017/205] More arc-green fixes (#13247) (#13253) - Fix various white borders - Tweak basic button style to have more contrast - Add more contrast to hover styles - Invert Matrix webhook icon May backport to 1.13. Co-authored-by: zeripath Co-authored-by: zeripath --- web_src/less/themes/theme-arc-green.less | 95 ++++++++++++++---------- 1 file changed, 57 insertions(+), 38 deletions(-) diff --git a/web_src/less/themes/theme-arc-green.less b/web_src/less/themes/theme-arc-green.less index 2bd9bf6a4f..e76f2a1bd4 100644 --- a/web_src/less/themes/theme-arc-green.less +++ b/web_src/less/themes/theme-arc-green.less @@ -384,6 +384,10 @@ } } +.repository .ui.segment.sub-menu .list .item a:hover { + color: #fff; +} + .ui.horizontal.segments > .segment { background-color: #383c4a; } @@ -535,15 +539,26 @@ a:hover { .ui.secondary.menu .link.item:hover, .ui.secondary.menu .active.item:hover, .ui.secondary.menu a.item:hover, -.ui.dropdown .menu .active.item { - color: #ffffff; +.ui.dropdown .menu .active.item, +.ui.link.menu .item:hover, +.ui.menu .dropdown.item:hover, +.ui.menu .link.item:hover, +.ui.menu a.item:hover, +.ui.menu .active.item { + color: #dbdbdb; + background: #454b5a; } .ui.menu .ui.dropdown .menu > .item { - background: #2c303a !important; color: #9e9e9e !important; } +.ui.menu .ui.dropdown .menu > .item:hover, +.ui.menu .ui.dropdown .menu > .selected.item { + color: #dbdbdb !important; + background: #454b5a !important; +} + .ui.secondary.menu .dropdown.item > .menu, .ui.text.menu .dropdown.item > .menu { border: 1px solid #434444; @@ -559,12 +574,8 @@ footer { background: #2c303a; } -.ui.menu .ui.dropdown .menu > .item:hover, -.ui.menu .ui.dropdown .menu > .selected.item { - color: #ffffff !important; -} - -.ui.dropdown .menu > .header { +.ui.dropdown .menu > .header, +.ui.dropdown .menu > .header:not(.ui) { color: #dbdbdb; } @@ -585,19 +596,6 @@ footer { background: #4b5162; } -.ui.link.menu .item:hover, -.ui.menu .dropdown.item:hover, -.ui.menu .link.item:hover, -.ui.menu a.item:hover { - color: #dbdbdb; - background: #454b5a; -} - -.ui.menu .active.item { - background: #4b5162; - color: #dbdbdb; -} - .ui.input input { background: #404552; border: 1px solid #4b505f; @@ -651,26 +649,12 @@ a.ui.basic.green.label:hover { color: #129c92; } -.ui.basic.button, -.ui.basic.buttons .button { - color: #797979; -} - .ui.basic.red.active.button, .ui.basic.red.buttons .active.button { box-shadow: 0 0 0 1px #c75252 inset !important; color: #c75252 !important; } -.ui.basic.button:focus, -.ui.basic.button:hover, -.ui.basic.buttons .button:focus, -.ui.basic.buttons .button:hover { - color: #dbdbdb; - box-shadow: 0 0 0 1px rgba(200, 200, 200, .35) inset; - background: rgba(0, 0, 0, .5); -} - .ui.menu .item { background: #404552; color: #9e9e9e; @@ -861,6 +845,22 @@ a.ui.basic.green.label:hover { color: #dbdbdb; } +.ui.basic.button, +.ui.basic.buttons .button { + color: #9e9e9e; + background: rgba(0, 0, 0, .08); + box-shadow: none; +} + +.ui.basic.button:focus, +.ui.basic.button:hover, +.ui.basic.buttons .button:focus, +.ui.basic.buttons .button:hover { + color: #dbdbdb; + background: rgba(255, 255, 255, .08); + box-shadow: none; +} + .ui.labeled.button:not([class*="left labeled"]) > .label, .ui[class*="left labeled"].button > .button { background: #404552; @@ -1040,6 +1040,7 @@ a.ui.basic.green.label:hover { .ui.dropdown .menu > .item:hover { color: #dbdbdb; + background: #353945; } .ui.dropdown .menu > .item { @@ -1130,6 +1131,15 @@ a.ui.basic.green.label:hover { background: radial-gradient(#383c4a 40%, transparent 40%) no-repeat; } +.repository.file.editor .commit-form-wrapper .commit-form { + border-color: #505667; +} + +.repository.file.editor .commit-form-wrapper .commit-form::before, +.repository.file.editor .commit-form-wrapper .commit-form::after { + border-right-color: #505667; +} + .repository .comment.form .content .form:after { border-right-color: #313c47; } @@ -1236,7 +1246,7 @@ td.blob-hunk { .ui.card, .ui.cards > .card { background: #353945; - box-shadow: 0 1px 3px 0 #4c505c, 0 0 0 1px #4c505c; + box-shadow: 0 0 0 1px #4c505c; } .ui.card > .content > .header, @@ -1707,6 +1717,7 @@ a.ui.labels .label:hover { border-color: #634343 !important; } +.organization.settings .labelspage .item, .organization.teams .repositories .item:not(:last-child), .organization.teams .members .item:not(:last-child), .organization.teams .detail .item:not(:last-child), @@ -1714,6 +1725,10 @@ a.ui.labels .label:hover { border-bottom-color: #404552; } +.organization.settings .labelspage .item a:hover { + color: #fff; +} + .ui.blue.button:active, .ui.blue.buttons .button:active { background-color: #a27558; @@ -1770,7 +1785,7 @@ a.ui.labels .label:hover { } .editor-toolbar i.separator { - border-right-color: #7f98ad; + border-right-color: #87ab63; } .repository .diff-detail-box { @@ -2058,6 +2073,10 @@ footer .container .links > * { color: #2a2e3a; } +img[src$="/img/matrix.svg"] { + filter: invert(80%); +} + #git-graph-container.monochrome #rel-container .flow-group { stroke: dimgrey; fill: dimgrey; From 39412c61bf270e5f4b371efdf7c8ea104beb2c63 Mon Sep 17 00:00:00 2001 From: 6543 <6543@obermui.de> Date: Fri, 23 Oct 2020 13:11:40 +0200 Subject: [PATCH 018/205] Migrations: Gitea should not fail just because of no apiConfig return (#13229) (#13273) * close #13227 * log it :+1: Co-authored-by: zeripath Co-authored-by: zeripath Co-authored-by: techknowlogick Co-authored-by: zeripath Co-authored-by: techknowlogick --- modules/migrations/gitea_downloader.go | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/modules/migrations/gitea_downloader.go b/modules/migrations/gitea_downloader.go index 827cbef5c2..8299c040b0 100644 --- a/modules/migrations/gitea_downloader.go +++ b/modules/migrations/gitea_downloader.go @@ -101,12 +101,13 @@ func NewGiteaDownloader(ctx context.Context, baseURL, repoPath, username, passwo // set small maxPerPage since we can only guess // (default would be 50 but this can differ) maxPerPage := 10 - // new gitea instances can tell us what maximum they have - if giteaClient.CheckServerVersionConstraint(">=1.13.0") == nil { - apiConf, _, err := giteaClient.GetGlobalAPISettings() - if err != nil { - return nil, err - } + // gitea instances >=1.13 can tell us what maximum they have + apiConf, _, err := giteaClient.GetGlobalAPISettings() + if err != nil { + log.Info("Unable to get global API settings. Ignoring these.") + log.Debug("giteaClient.GetGlobalAPISettings. Error: %v", err) + } + if apiConf != nil { maxPerPage = apiConf.MaxResponseItems } From 074f7abd95adbab524696ed9609ea3ee85948bf4 Mon Sep 17 00:00:00 2001 From: John Olheiser Date: Fri, 23 Oct 2020 11:00:20 -0500 Subject: [PATCH 019/205] Remove PAM from auth dropdown when unavailable (#13276) (#13281) Signed-off-by: jolheiser --- modules/auth/pam/pam.go | 3 +++ modules/auth/pam/pam_stub.go | 3 +++ routers/admin/auths.go | 23 +++++++++++++++-------- 3 files changed, 21 insertions(+), 8 deletions(-) diff --git a/modules/auth/pam/pam.go b/modules/auth/pam/pam.go index ca299b08ba..f21602c6b5 100644 --- a/modules/auth/pam/pam.go +++ b/modules/auth/pam/pam.go @@ -12,6 +12,9 @@ import ( "github.com/msteinert/pam" ) +// Supported is true when built with PAM +var Supported = true + // Auth pam auth service func Auth(serviceName, userName, passwd string) (string, error) { t, err := pam.StartFunc(serviceName, userName, func(s pam.Style, msg string) (string, error) { diff --git a/modules/auth/pam/pam_stub.go b/modules/auth/pam/pam_stub.go index 604799ca97..02d8da3c57 100644 --- a/modules/auth/pam/pam_stub.go +++ b/modules/auth/pam/pam_stub.go @@ -10,6 +10,9 @@ import ( "errors" ) +// Supported is false when built without PAM +var Supported = false + // Auth not supported lack of pam tag func Auth(serviceName, userName, passwd string) (string, error) { return "", errors.New("PAM not supported") diff --git a/routers/admin/auths.go b/routers/admin/auths.go index 98f6e25b1f..bae1c863e9 100644 --- a/routers/admin/auths.go +++ b/routers/admin/auths.go @@ -13,6 +13,7 @@ import ( "code.gitea.io/gitea/modules/auth" "code.gitea.io/gitea/modules/auth/ldap" "code.gitea.io/gitea/modules/auth/oauth2" + "code.gitea.io/gitea/modules/auth/pam" "code.gitea.io/gitea/modules/base" "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/log" @@ -57,14 +58,20 @@ type dropdownItem struct { } var ( - authSources = []dropdownItem{ - {models.LoginNames[models.LoginLDAP], models.LoginLDAP}, - {models.LoginNames[models.LoginDLDAP], models.LoginDLDAP}, - {models.LoginNames[models.LoginSMTP], models.LoginSMTP}, - {models.LoginNames[models.LoginPAM], models.LoginPAM}, - {models.LoginNames[models.LoginOAuth2], models.LoginOAuth2}, - {models.LoginNames[models.LoginSSPI], models.LoginSSPI}, - } + authSources = func() []dropdownItem { + items := []dropdownItem{ + {models.LoginNames[models.LoginLDAP], models.LoginLDAP}, + {models.LoginNames[models.LoginDLDAP], models.LoginDLDAP}, + {models.LoginNames[models.LoginSMTP], models.LoginSMTP}, + {models.LoginNames[models.LoginOAuth2], models.LoginOAuth2}, + {models.LoginNames[models.LoginSSPI], models.LoginSSPI}, + } + if pam.Supported { + items = append(items, dropdownItem{models.LoginNames[models.LoginPAM], models.LoginPAM}) + } + return items + }() + securityProtocols = []dropdownItem{ {models.SecurityProtocolNames[ldap.SecurityProtocolUnencrypted], ldap.SecurityProtocolUnencrypted}, {models.SecurityProtocolNames[ldap.SecurityProtocolLDAPS], ldap.SecurityProtocolLDAPS}, From e177728a823ce5974a101994c3f687a579ed8ca4 Mon Sep 17 00:00:00 2001 From: techknowlogick Date: Sat, 24 Oct 2020 01:02:36 -0400 Subject: [PATCH 020/205] Store task errors following migrations and display them (#13246) (#13287) * Store task errors following migrations and display them When migrate tasks fail store the error in the task table and ensure that they show on the status page. Fix #13242 Signed-off-by: Andrew Thornton * Update web_src/js/index.js * Hide the failed first Signed-off-by: Andrew Thornton Co-authored-by: techknowlogick Co-authored-by: zeripath --- models/task.go | 21 ++++++++++++++ modules/task/migrate.go | 39 +++++++++++++++----------- public/img/failed.png | Bin 0 -> 11009 bytes routers/repo/repo.go | 16 ----------- routers/routes/routes.go | 3 +- routers/user/task.go | 30 ++++++++++++++++++++ templates/repo/migrate/migrating.tmpl | 8 +++++- web_src/js/index.js | 19 +++++++++---- 8 files changed, 95 insertions(+), 41 deletions(-) create mode 100644 public/img/failed.png create mode 100644 routers/user/task.go diff --git a/models/task.go b/models/task.go index 43cb2d4d9a..b86314b449 100644 --- a/models/task.go +++ b/models/task.go @@ -147,6 +147,27 @@ func GetMigratingTask(repoID int64) (*Task, error) { return &task, nil } +// GetMigratingTaskByID returns the migrating task by repo's id +func GetMigratingTaskByID(id, doerID int64) (*Task, *migration.MigrateOptions, error) { + var task = Task{ + ID: id, + DoerID: doerID, + Type: structs.TaskTypeMigrateRepo, + } + has, err := x.Get(&task) + if err != nil { + return nil, nil, err + } else if !has { + return nil, nil, ErrTaskDoesNotExist{id, 0, task.Type} + } + + var opts migration.MigrateOptions + if err := json.Unmarshal([]byte(task.PayloadContent), &opts); err != nil { + return nil, nil, err + } + return &task, &opts, nil +} + // FindTaskOptions find all tasks type FindTaskOptions struct { Status int diff --git a/modules/task/migrate.go b/modules/task/migrate.go index d25decaa00..99f0435b28 100644 --- a/modules/task/migrate.go +++ b/modules/task/migrate.go @@ -20,7 +20,7 @@ import ( "code.gitea.io/gitea/modules/util" ) -func handleCreateError(owner *models.User, err error, name string) error { +func handleCreateError(owner *models.User, err error) error { switch { case models.IsErrReachLimitOfRepo(err): return fmt.Errorf("You have already reached your limit of %d repositories", owner.MaxCreationLimit()) @@ -38,8 +38,8 @@ func handleCreateError(owner *models.User, err error, name string) error { func runMigrateTask(t *models.Task) (err error) { defer func() { if e := recover(); e != nil { - err = fmt.Errorf("PANIC whilst trying to do migrate task: %v\nStacktrace: %v", err, log.Stack(2)) - log.Critical("PANIC during runMigrateTask[%d] by DoerID[%d] to RepoID[%d] for OwnerID[%d]: %v", t.ID, t.DoerID, t.RepoID, t.OwnerID, err) + err = fmt.Errorf("PANIC whilst trying to do migrate task: %v", e) + log.Critical("PANIC during runMigrateTask[%d] by DoerID[%d] to RepoID[%d] for OwnerID[%d]: %v\nStacktrace: %v", t.ID, t.DoerID, t.RepoID, t.OwnerID, e, log.Stack(2)) } if err == nil { @@ -55,7 +55,8 @@ func runMigrateTask(t *models.Task) (err error) { t.EndTime = timeutil.TimeStampNow() t.Status = structs.TaskStatusFailed t.Errors = err.Error() - if err := t.UpdateCols("status", "errors", "end_time"); err != nil { + t.RepoID = 0 + if err := t.UpdateCols("status", "errors", "repo_id", "end_time"); err != nil { log.Error("Task UpdateCols failed: %v", err) } @@ -66,8 +67,8 @@ func runMigrateTask(t *models.Task) (err error) { } }() - if err := t.LoadRepo(); err != nil { - return err + if err = t.LoadRepo(); err != nil { + return } // if repository is ready, then just finsih the task @@ -75,33 +76,35 @@ func runMigrateTask(t *models.Task) (err error) { return nil } - if err := t.LoadDoer(); err != nil { - return err + if err = t.LoadDoer(); err != nil { + return } - if err := t.LoadOwner(); err != nil { - return err + if err = t.LoadOwner(); err != nil { + return } t.StartTime = timeutil.TimeStampNow() t.Status = structs.TaskStatusRunning - if err := t.UpdateCols("start_time", "status"); err != nil { - return err + if err = t.UpdateCols("start_time", "status"); err != nil { + return } var opts *migration.MigrateOptions opts, err = t.MigrateConfig() if err != nil { - return err + return } opts.MigrateToRepoID = t.RepoID - repo, err := migrations.MigrateRepository(graceful.GetManager().HammerContext(), t.Doer, t.Owner.Name, *opts) + var repo *models.Repository + repo, err = migrations.MigrateRepository(graceful.GetManager().HammerContext(), t.Doer, t.Owner.Name, *opts) if err == nil { log.Trace("Repository migrated [%d]: %s/%s", repo.ID, t.Owner.Name, repo.Name) - return nil + return } if models.IsErrRepoAlreadyExist(err) { - return errors.New("The repository name is already used") + err = errors.New("The repository name is already used") + return } // remoteAddr may contain credentials, so we sanitize it @@ -113,5 +116,7 @@ func runMigrateTask(t *models.Task) (err error) { return fmt.Errorf("Migration failed: %v", err.Error()) } - return handleCreateError(t.Owner, err, "MigratePost") + // do not be tempted to coalesce this line with the return + err = handleCreateError(t.Owner, err) + return } diff --git a/public/img/failed.png b/public/img/failed.png new file mode 100644 index 0000000000000000000000000000000000000000..b37545f90ca3b304357516661efb9e1431fa96aa GIT binary patch literal 11009 zcmW-n1yCH#5`ZDN6Wqy<2MO+$KyVKd+_}TuCAhoW;T{O?ZoxU+;cy6UK@WMCw^h4S zyE9uW)7{hkbw{cy%V43Cp~Jz!VadsU{RV4iVS5lNGVI7roYn+u5M3nXG*DriFRFP2 z>>SNeR>uW44&mPpe;Ydpgh9~GO#|M<-=6ATcxp@OxGq-O`_#A|eH>&uKXs|nknIjWzTEo?Vb%x|DhI{A1HAck}+ypqsxa%Id@#W1#eKjb_dpKONmCv`_wn zw&e;@1S98{v48?CH&a-&kkLq_g=5beON*CaLDokI@+oJGpDM! z%$_V8@KU`kl(v4g4gSLtV{SsKngi8l<47!fMe*-?;_|+zwB?e^;N# zsqY#ig-`ussTge6awp!MP@glV@q5|kM2OK&=|~xP_a*X4BO)t!8LOYB>atv{L4hB{Ys9W<%%*dvtiyWEfKA$xhK-8>d5>R!1d#R z=0(fSJ7FouvY3*m~(g@zjST%>ITW3Z|7?hxt1!G-J>4t@`*uE6;{n}s(?9-Umsx!u>w zN*s#Qe5*g-InAX>OX##bJv09#7emhdrIYa|XHRjkXGQu=^B9wR=V>fU_tl=q{XVg7 zwY6yE{W<0#h!;9`}=ARjPICoyjQ=+stM zt{8#IyJ)NJvSQ+T9)EMK#je2OCo<93#MSmyiKL?Ypr%hsUJ7gv?;3^#kj*6$V`F4H z&q1+3k*mG?ySE#Oam^#v5nODtyf;KgFG-2{h35liYy_~ZmqaqktE->Kcq;7YlyF~Q z{JhI`JKLgGL^73{)jI=qIFI_6IV^g`V}I~>VpF|*m^k6EUu&<1?7tL&|0Z$Ib^pAR zLZTjiH1FD0NVeSiaP&0?fBR#*2xV-{iw?@=ZlIK#9nR*1qY3PNzaHFPp&wd?+xwz6}t!7}* zB~pXpXHym7FLvlDb~5s$u27JboLh_^p>*P-Tdim5#hmEnwUh3ams8<_B}|{=qNSVW znCjolp}~WFKuHqcHu3}7r|0o97umh(1RQ^KK1aykgzqoLS3-08iTIy%&|!UG{NRVE zPvvLnaps1A;uzj;m7Vq9k;kfqRs7fo6v)E(keAib6jbB2UoY|Z?&sd&GBv#qz7V}1 zM&K*`MXSFA+Sf?P(a8|_$qcCV_oaTH-x_!>_A>2H+&19bdWR6@zS$IJab}5He(I5; zs_-TIwe|Z`*H8Y}uP@=b50KY4mvdf)?x41OrXLop&XI|Qqk^p4%p?0hvgq_hxc9q+ z?<@XZZ!?~6-tUH{Rea01X_2q{)BgU5ew102##n$WifZ5#Uswp5$J&wunT!{oTU%-Q zsHT{Uu>RhJ7R5OZ*q}_CsP-$4KROv#DCDTfZsSCYy-_5!AH@7^IBl^qfPW#B#sEn{ zC?GHhO(13bu>(-lg<|hx?%)92geF(lqVK*)trQ>#4(C?gNFr4V`Ed=-7W0c(alc7f z>r4j->aQBSDFr1KSlkPl9bKpV?ElY=j!QZU{JG`rGM>uEm~Rc@w~5il*xm9b!`3tN zEZ&I|jzk>qRZ0F)DAPo)$ht64G8naJ>kQ=L-+np@`_i|D&@`)p%m&hzYa|U7G&Z}S;Gu&>_Y^C5gT98%m|Ywcc$2lzr#~{u*=3KLW?L@y`9UZfdY1$ zi^X$wdM*VM$&`5x_Wnl5{nwHmOro+K^-fdOR+oZ(9m|8g+ohSgdY$E*Xne8esPFJo z00hF{+7Lpp*PpZvXsP$c(|OYgsA4i(D{K7=zQ4!gRyDPo8|N?nkz0e4Bz7JsIU@CE z5HRdmQb(OhA8G0j)H$whB;jbO#o@TeANB|)fI%YP`s+1Ap1kP$jI8gaU77>!{ybcF zhZOzoEgt9XZp=%KZZ&#mmwCf~JZIQr^Msw|f^+KSD`U^`yxC&9yFBA22CKb%IWtVWYyX5KvJ|SQ>_hD~ zYz)sP-e{$vFjK7JrBzC+RV*5dwms-&xZcwZJQFTs85ec7KsVnNSy?drL>C>Cu2cVMd~yfw z&Q`g5S%TD+{+H?)Z>C!(!X~^}_d~6g|3o82%DLSY>I0?zr1#l`(xa)7?nHdkZMiGp@s@VJS_9^hZ&Py`*G{!nJ*7?0i9!A2$?A@fFIvL!V=&yL>(nU>D z|Jn5ESCCnwB}C8qC=Q%QnbkJPNx5Oeo_;jYyMW4tHbdZ@gdrd)SIc_efRb%8>G>V~2H=a(QNwKy7K#pr>*ppE-I=he)I>S|5@9%67vtTcjtsJDhjALHmc6S1#H?2!` z?$bR5ls@$6Io0{2hL^>hxAnD^dm65$vzdIn4e*7bi*t<~L#5(>9o;*XmX!*bx$cjUbGN%G} z?hoPSDyZh@o1fnwousO`6-y%srxwp>M|8_(yNj;i8sA^gn{&L+d}hg%yo@_5ZAHM# zN&qKLSjP{&L$HHV$ysx*8!^&DyqxVI1D3=tal{%-51`ksA`FWTR*$WtVj1qHUf!>K zDk||v*Yx}RW*W1o%Wxb4EBSK45

bqyxEqHyXI1@uH4vv_6MQBRYVgsQGS-vpm|a zvkBLa)jj>A7`fzFy?^<;a$er5L3~2qx^G{G=quyC(ZRQk2xxHZcaiQycV$CM8?OvE zH?H}(q38({h)&Cqqy*+ML|2Iu@NdF|1Q5O)(=kdt-4^+Ep1gD20V&!;EHsg;$Xs*J z1UjkZIw14zhg`831LOFS2dG8(Y2NwKs?HVK3$T%-1u}>6u|F zawLc78|8GlJDU%Rj`?zrce#te=CzY_$|VUtBACst8Aav*Z^4Ut4a6B zgqllP32?$^Q`8=zH2n*mqJouH+tt)S4?L(h~JsYnd+!ERvhQ~ z^Ntwk?fgzDUbH!(K2H5E#`T3C4f}N40G^3bLk4%!xDP&Kw3J7kVlpfjLsxXBDf2VF zJdZBA691o-=C+F-<(A2R0`#B1lb-}gHWDr?d8e%^a}R=Mn`KQM$#nJ0RQtgeY<4?G z=m_t~F#APcq&ke zkU%S3Se1^1Eh~W9cCGWI;CeN}9!cM9=Tc7;8+l$^jLEkY#7FtM(3>K0m8>iv8DW&8 zOpUXCH)1%*j*%)(N|`<#IrR1PgRlG08tKQW!p|AIG^BcXYNjeaD&rn7LELP_Eeo~q zU~0REvqoj{mqX#eJ(S@^<-PT z1bn9{MdGE#K_QrVHRo&^0*41^fg3FX&<4;Xrc(cBect9osuGnSVZPj$%ss}U&MWs{ zX&`*Ggp)M0sU}1HP{=T8C8uATm+N2RGf|tjODv<-V*BcSCWXXz)ZO?43*Sd=c{Dh1 z4>TdRe^-SUc`}}r3M6;KnFSqoDc2<8TyBdi+t6 zI1r-vT6e`o$9`j?@@hvYFJD;r1}Snh@`q7CiuR9xmThRo$eh-!)$`ej3JrUI5@A64 zQoL+#_*L3&5LI3CvJ-#+oKC@I;fAm&ds2WR|4zd614ZcER?uJh33QHh=Fy^$e0SZ> zELcI#j7#pRNL_?UJ4SERO7~w8H^-yXeR?7PP!#eX$XT|>8K@%W3+@Io0S@6hC(?uz z%-Z{^0T?zq?dFQ6RLcA$FW{9s3hj}3=ms-MFODT~c9;dB>9FU;8!Y;{1NflKX43WK z9}LsAgs4cO21Yy#yvpC!_8VtJ`0n&Zz|}bWLoFo1zaNYWJ|ZFHYJg2^sZdV_29({* z66@Fxmy@yn`hLm}AmrF+wR3sPQz|>d@~G}2F*7sx@UtWZY>Q9ADi=kV8SynA@v z_j%x-YXzu`xB56c)bYIx*Fi}@11lF(@`@a?cYAdNxFwY_^fwM0+OX-2NgN4z7(UC1 zf3Ym(a(CPAe8kBv7?K;B4Mv*Np7EWzNg>U1iCVm~KYrV3+~*eysV!w5J>W?%rT}GL zFQyP=EN0EU{a+eaEPZs5S8NHoA^B}$<-Wlo#F&IvLH-8r?r%nEbJA-DzlgUUn}o_D z`N6VZJGVV1oHnOCYfMjrm4_}D6E1YIUDI?}c;)(RTeHbRQcY_0Ls)7!AH;XB%WPQ@3 zFv{JiJlk(;fb|Yp^)y{~alBZ)L$3Kz6E%F9o(|?zp4P@{2R0VGG>Tvdo)C|H0A+N{ zh}npkI3>>MZXL|)BM-zlL9i7;+tW5D5IL~O%ZnTz*Ys%Wepk~{nj>JKd{U}lTuZaR z`_k=XH$-;6=6Qd7MBb4ZMpKgH&PHQ^#V9_2BtuX$bk4-jt1)bFVi+sH&3)wRT&~U4 zi|6-)Z;$7%(d4u_?ZxLlG+N;W3ZG%xB(Z?)EM_`s+gjroA~WE8)G7%HtCDg^hJI!= z9!{g30l!`PU6CEpII@T+SuJqlu}f#T zuai@Q$2pPBGAsNynu- zu}3w%U(8}tc9!M;XaP@u*${b?RB$D@U-vj7lSW2p#AmgMjpqQ?I=R8qREBV7RH+jX8 zd3S#E{Xa;iYpUit+inQ=s88i)ciYANkoczKQhWLnlQp~{l75keuWt6yR^96rnk;m19ka0ZhEPtqe){z2U6-dOm^-Vl}(@Bfg)~e#e=xZ z4W^f)16gpnLGM5~XT?XS<$cQ!)E7O7EmOsI124cY^|PnafCQ)Ih*n2QkMU3(`|~&A zfNyYn?17Q}_9rb>I%dn7o*fMAi-$Bslw&A#2z5-j(ftFZL2brzW9lQw%$|O(ut^nP z`*AXAFs}S_m;AyohpWM;Cdncvpg|{+-`YrD5DOuJql=bmFZ{TAA`+_0Q$rjZaaG0`FC*P|%$k()sR^%_n@qLKL2|c; zaq6y%x`NDR#u{o94zk}ZOdK<~7r;;B+5<0kqHKpLOB~e5^8{3casPGRt54N=DEhjx z&}V*q_9Uii^DKbFU@p4#qk?Gdmk|pS8)1s zZQHHeT-P0hoSN!vWB%+2G?8RCogFUhu}R&5=7U zB+eJwT76V2aD;{#|D40fwV10aD%4!%MZZ%*+5#6@T&8pc-?l<7n~rmLKk~P0yU@w; zTZE(#F3^IeMc~K@Fm7&(mc`wpy}98%2Mg5W1Y(w9Hf%nuW3j8ctLzpBu}6)6^n&eh z_vQWNuOonO&P3Rn5yZSyPa>RogGGG%gKN?Ngo2npgLKW_&lXCE@RDx&G*H+w<0t4b z*pT(n$u`-eKMh#4Cld$l!sp$ws6iRg_`@~I zeG`;UaU#s9Q@gV8K{Lwj`D;wLn=Id1(|u&?{ZP0J%E@sxk?rJTtL05WkdiHEVrQ!^ zmGn2dMU})IV;fT)@q=oAMYrI8X(b}#3>HO`Du^i8IY)ct!dcC~PLAJaOG++mDPo2r zV1`awKitRZxr?8nXt|=EfW17$$RAdOR&3&w2uDqE{Vuh8#H(qV>W-1<9Y6CWo%=x&DQ!|4<6yig0u{fsP19 z8Sc>s_ZGb8*E&GSE_2ej)QJ)u^9+@f2$|$X$glOysy6}RGx6n>o&lUH&(yxj#M3QU zSTm)q`mOwGAnt*~M3bRV(CL{`yS@UIsY7GWVgm?NY-i(WEJx=mR|Yhvd&tancrAVB zcu`ifbog}HP&Z+th>9O6q3S#HAk;StHo!`#xSVSrWtEQz86|((d+N~rlo>7N?s~># ze{#A;_K$P9RuV%^L%GDYIi8C}=ObkWM-aLChT^80S=nUL8f|>}mq{0R$YZ&?F=MA4 zz?#&s=y5aQ0Y}ONdfgYJAZ79Hy@2_SsElwE)psTHC%41m$f|0<3iS-^om$xM>v9$PFVrT9=LKqBMuD9j%z1f?JU%CFLQ1ixaIhEbl zp>m9AjI`WU5VN(_4!yU%pHo#jg5O`x{&;hB{AzGGNrG=#jqxC?v;5f{6KVC8HOs!o zEALs<=CCCY+jJGp8HO`;b6Ay6u4H}9dGRGLlh@khlkpN-?T1FG9$*~ z!9XPzo+2yPy|Z4yTe&vo)&A~?VtlY%1V7l#Nci>7)k{P+?Kbv4(0z$3aQG`tV)X0F z18}$!fM~QLgO`EHZhpW-R%Dju7 zmWx9MsPatqe!LR~ZC_xgS?!;M2dgncG2Waz9Fe(eqCpli1o1?UlB`UQny)kKpDuyHVc%FLf+|+TR$no$KG5B9XK68wl2@-xXw(#?!^o| zkV3iE%0y)l4P6*-$a1JUEiv>!7FKG1P;C7^_<(1qaCKLdpH=orog>XpCtkU%w0) z_mM>Yfm@q~Y&@AwpTShuUw8qL#4by-X|%ddtv#*>!Dzwuw~mAKV(hE5~(14|XQ%1Mvv&l|WS zjN~*6U{MjBBCC?OR!J9c2vy8D2Q(X&1rxW~tiOAz*o$&D@vJmfQ#W<~BoZ;cc)dAR z5yq)JoR(%2sBk_YFD= zf4{Iz-{#u=haU+Z-=`>YRq^tM9(cdOjZaD^W}9ECZtK948G~Pxp+nMyV3ZdxW^tEa z{Qc0^t86|H-#FvukjklT;uG4&`T=I87AW!{1PEgkr6H(W6kE|KSw%*BQIX>5I_h(D z?570+4^!s8z6|>k@<$!j<-$n!(#fRvg-(E*W)-B&$|bco)Y0&6Q^h1F@FupXaXar=}6P3zUR@B zJ-si?V42G$P_9Bh+sBV0pid@-*E(7WVn$+l0cFM!T041q@uMh9XaBTxc4gk5&71WsuLK+yc5QPL=giH(&BhK%voqOSbPC8=MDXT z-lu{O8pf{wjd<^tExCy&wEmLEi(&NY9!H-qe&c))JG@bm7zMl0d^YGyO^j$aP_A~&(X>#Qt^B+r2>W@qM{Gi#~&8Kulf?|mG=iLtfFW~>fPkgnKI?EhLA?TsnV%O^E9K|`Ya|ezf7M2TqF`o%e z-&PF4o()tctvPp=)3x3EdzI@4CalnwjcE^&;bNL2{H9$c3!Z0=S&iX|25o7DA)9>I zNvK^F%~Le(7geeO#lIH1euDAg(-ZoE-gw45`#{*p%K38(ok26zchJlR7K z3Vn7T^7RY~&*g?6Q~Il((#f6cWM^PkP>?=^BfdRhiinQQd^y}Ze1Pl_%RznKT?e}Wj+0@VAjJ)R z4@TcE_A@$@e}iVxkbVNk1gVQKt<)=WfOBPUI$pp}Tq6JDgd8;0=)-JE-;Zi_3+IP1 zs5uD&C&wyX&a0_HrTzcsdVj&a#m+7Q2O|9sOX2n_T~j9WfMPO285*&wI;O+%+D;Ana_g!ORu zUGK;bOk8xfYD%67DnL{6#ftH|!Q}HPwE&&V?_WWLN@!!%JYsl^idSD~p2*?C%RRK* z=w)p{J25@$lk05_EB4T|wCupmYK*UKQmcsOw8>lHn{NZdcW?rvSiE|+vGTMWf&Uex zPiSRRirQ?(omPh=8-ZBGEu9-l%5=F`jN<$cFpq&!V`QB4Wecmv_6H$X1|UKy>&@9G zv4WZ~2C%F*fAZOcqkdYMHtLN(@2gIP+V`8MYPCp20FfMfjvV~ZMABf3B>S1nJ+PV!JX#gt< zgp(nt_?g}*7PAv5exQzsr+(?EZDy%fs|dkwrt4@c>S#h}U{FP^!WCMpO-D@|EEBG~ zo=?S_FbA|{JgCkj!pd;gu8j|?iRmrSa(I|6vnG{o<}dlWTald zO_s^j8vBE{LlL0y|B?kGb=?P;hL=Bc{HKVj)1an{9P$<8tbEf#8TYFO>;x2oI1FM7 zYi%dpyM9yuVdwscbUKV%RXCbADL1aWBJA$jJMG2+{pnD?EDn)s8Wv~Kp0v14F)p@* z6_Y4>)BJb8n7sd=N0__hqXnBaMWpq6Kg}swbBYn+z+Ao?^7GBko6ux~-Mt4vip2LN zLzv~0vJ0@Zi$H=4iOAXZHHt9x+fs%8;Y6r7!pNi-d@LC+Gci1@7D5s!yl;xu^>-Zj zm9fmb>!fRc#>n`Y>%@liFA(Xb394;D&~>E`{)oNU;FJ7idtpwECc{yCp}BB4s_8$~ zT^@{t+0%{RG*g~Oub4(7_|O=IWMZOvhyLMQ@| zHlq9CKYU;ye#X|&g}XIY(0%ceU*UEyJ7WmR=*@|9B9!SAGk+)oW5yZQdc`sV1+Ejo z1WQ$8Uehx@J~J(Sry~xOCVlLp5p!2w6NG{|C^vDwpiVmW70QYaZ;?>GGw@{b2JTLM z?3v!*QQ132SbqsO>Oc+~&#O9Ft>INKLCULmb>XhU+t0lW?$@?B%iYVScfSW|`P^SJ z{E#sk)~gCWCy^Qhl%0+{ukt6ZAfVskS4*bR9prCsNwY%HHzZkoM_XXJ-!iL`i50k+ z@KOWa6kpHHaMqvx^h`=qjRU#jMR7{XXJ zhi}io7<4}+bg?e88}LTM%I15Iw%rCc18?oROft@_%lYh?4{Grf2IWEijfsy?6U1)1SDWJMPI1V!TX_zteigg^Y2G3h2i0}~6g;RH5ZTIVAXzb4KHF;E7l~)!OsG^>*Mr6GU z!i1Dru%>DU)e&e1*>aYXYGYcb=@fZ!0g4G7q>dHIzI9@Xo7Wm$hD0)k-s)Jw3T`lj ip&jiROR=wSD8zsWV}8L1Cs?^EoSc;M*J=slp#K48eBxaI literal 0 HcmV?d00001 diff --git a/routers/repo/repo.go b/routers/repo/repo.go index 742c952f6e..4220750328 100644 --- a/routers/repo/repo.go +++ b/routers/repo/repo.go @@ -402,19 +402,3 @@ func Download(ctx *context.Context) { ctx.ServeFile(archivePath, ctx.Repo.Repository.Name+"-"+refName+ext) } - -// Status returns repository's status -func Status(ctx *context.Context) { - task, err := models.GetMigratingTask(ctx.Repo.Repository.ID) - if err != nil { - ctx.JSON(500, map[string]interface{}{ - "err": err, - }) - return - } - - ctx.JSON(200, map[string]interface{}{ - "status": ctx.Repo.Repository.Status, - "err": task.Errors, - }) -} diff --git a/routers/routes/routes.go b/routers/routes/routes.go index 135c6b56a8..586474a661 100644 --- a/routers/routes/routes.go +++ b/routers/routes/routes.go @@ -479,6 +479,7 @@ func RegisterRoutes(m *macaron.Macaron) { m.Get("/forgot_password", user.ForgotPasswd) m.Post("/forgot_password", user.ForgotPasswdPost) m.Post("/logout", user.SignOut) + m.Get("/task/:task", user.TaskStatus) }) // ***** END: User ***** @@ -986,8 +987,6 @@ func RegisterRoutes(m *macaron.Macaron) { m.Get("/archive/*", repo.MustBeNotEmpty, reqRepoCodeReader, repo.Download) - m.Get("/status", reqRepoCodeReader, repo.Status) - m.Group("/branches", func() { m.Get("", repo.Branches) }, repo.MustBeNotEmpty, context.RepoRef(), reqRepoCodeReader) diff --git a/routers/user/task.go b/routers/user/task.go new file mode 100644 index 0000000000..a88257ee50 --- /dev/null +++ b/routers/user/task.go @@ -0,0 +1,30 @@ +// Copyright 2020 The Gitea Authors. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +package user + +import ( + "code.gitea.io/gitea/models" + "code.gitea.io/gitea/modules/context" +) + +// TaskStatus returns task's status +func TaskStatus(ctx *context.Context) { + task, opts, err := models.GetMigratingTaskByID(ctx.ParamsInt64("task"), ctx.User.ID) + if err != nil { + ctx.JSON(500, map[string]interface{}{ + "err": err, + }) + return + } + + ctx.JSON(200, map[string]interface{}{ + "status": task.Status, + "err": task.Errors, + "repo-id": task.RepoID, + "repo-name": opts.RepoName, + "start": task.StartTime, + "end": task.EndTime, + }) +} diff --git a/templates/repo/migrate/migrating.tmpl b/templates/repo/migrate/migrating.tmpl index 0057325e91..fdda33a2c7 100644 --- a/templates/repo/migrate/migrating.tmpl +++ b/templates/repo/migrate/migrating.tmpl @@ -7,11 +7,16 @@ {{template "base/alert" .}}

-
+
+
@@ -20,6 +25,7 @@

{{.i18n.Tr "repo.migrate.migrating_failed" .CloneAddr | Safe}}

+

diff --git a/web_src/js/index.js b/web_src/js/index.js index 9fafe62d3e..94238ca3d9 100644 --- a/web_src/js/index.js +++ b/web_src/js/index.js @@ -191,25 +191,32 @@ function updateIssuesMeta(url, action, issueIds, elementId) { function initRepoStatusChecker() { const migrating = $('#repo_migrating'); $('#repo_migrating_failed').hide(); + $('#repo_migrating_failed_image').hide(); if (migrating) { - const repo_name = migrating.attr('repo'); - if (typeof repo_name === 'undefined') { + const task = migrating.attr('task'); + if (typeof task === 'undefined') { return; } $.ajax({ type: 'GET', - url: `${AppSubUrl}/${repo_name}/status`, + url: `${AppSubUrl}/user/task/${task}`, data: { _csrf: csrf, }, complete(xhr) { if (xhr.status === 200) { if (xhr.responseJSON) { - if (xhr.responseJSON.status === 0) { + if (xhr.responseJSON.status === 4) { window.location.reload(); return; + } else if (xhr.responseJSON.status === 3) { + $('#repo_migrating_progress').hide(); + $('#repo_migrating').hide(); + $('#repo_migrating_failed').show(); + $('#repo_migrating_failed_image').show(); + $('#repo_migrating_failed_error').text(xhr.responseJSON.err); + return; } - setTimeout(() => { initRepoStatusChecker(); }, 2000); @@ -217,7 +224,9 @@ function initRepoStatusChecker() { } } $('#repo_migrating_progress').hide(); + $('#repo_migrating').hide(); $('#repo_migrating_failed').show(); + $('#repo_migrating_failed_image').show(); } }); } From 151daf73a6af51d0ddf28909cc98bb476274f976 Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Sun, 25 Oct 2020 16:13:26 +0800 Subject: [PATCH 021/205] Fix bug isEnd detection on getIssues/getPullRequests (#13299) (#13301) --- modules/migrations/github.go | 52 +++++++++++++++++++++--------------- modules/migrations/gitlab.go | 30 ++++++++++++++------- 2 files changed, 50 insertions(+), 32 deletions(-) diff --git a/modules/migrations/github.go b/modules/migrations/github.go index 088e54744d..7aa1e57274 100644 --- a/modules/migrations/github.go +++ b/modules/migrations/github.go @@ -65,23 +65,25 @@ func (f *GithubDownloaderV3Factory) GitServiceType() structs.GitServiceType { // GithubDownloaderV3 implements a Downloader interface to get repository informations // from github via APIv3 type GithubDownloaderV3 struct { - ctx context.Context - client *github.Client - repoOwner string - repoName string - userName string - password string - rate *github.Rate + ctx context.Context + client *github.Client + repoOwner string + repoName string + userName string + password string + rate *github.Rate + maxPerPage int } // NewGithubDownloaderV3 creates a github Downloader via github v3 API func NewGithubDownloaderV3(ctx context.Context, baseURL, userName, password, token, repoOwner, repoName string) *GithubDownloaderV3 { var downloader = GithubDownloaderV3{ - userName: userName, - password: password, - ctx: ctx, - repoOwner: repoOwner, - repoName: repoName, + userName: userName, + password: password, + ctx: ctx, + repoOwner: repoOwner, + repoName: repoName, + maxPerPage: 100, } client := &http.Client{ @@ -177,7 +179,7 @@ func (g *GithubDownloaderV3) GetTopics() ([]string, error) { // GetMilestones returns milestones func (g *GithubDownloaderV3) GetMilestones() ([]*base.Milestone, error) { - var perPage = 100 + var perPage = g.maxPerPage var milestones = make([]*base.Milestone, 0, perPage) for i := 1; ; i++ { g.sleep() @@ -233,7 +235,7 @@ func convertGithubLabel(label *github.Label) *base.Label { // GetLabels returns labels func (g *GithubDownloaderV3) GetLabels() ([]*base.Label, error) { - var perPage = 100 + var perPage = g.maxPerPage var labels = make([]*base.Label, 0, perPage) for i := 1; ; i++ { g.sleep() @@ -304,7 +306,7 @@ func (g *GithubDownloaderV3) convertGithubRelease(rel *github.RepositoryRelease) // GetReleases returns releases func (g *GithubDownloaderV3) GetReleases() ([]*base.Release, error) { - var perPage = 100 + var perPage = g.maxPerPage var releases = make([]*base.Release, 0, perPage) for i := 1; ; i++ { g.sleep() @@ -342,6 +344,9 @@ func (g *GithubDownloaderV3) GetAsset(_ string, _, id int64) (io.ReadCloser, err // GetIssues returns issues according start and limit func (g *GithubDownloaderV3) GetIssues(page, perPage int) ([]*base.Issue, bool, error) { + if perPage > g.maxPerPage { + perPage = g.maxPerPage + } opt := &github.IssueListByRepoOptions{ Sort: "created", Direction: "asc", @@ -429,7 +434,7 @@ func (g *GithubDownloaderV3) GetIssues(page, perPage int) ([]*base.Issue, bool, // GetComments returns comments according issueNumber func (g *GithubDownloaderV3) GetComments(issueNumber int64) ([]*base.Comment, error) { var ( - allComments = make([]*base.Comment, 0, 100) + allComments = make([]*base.Comment, 0, g.maxPerPage) created = "created" asc = "asc" ) @@ -437,7 +442,7 @@ func (g *GithubDownloaderV3) GetComments(issueNumber int64) ([]*base.Comment, er Sort: &created, Direction: &asc, ListOptions: github.ListOptions{ - PerPage: 100, + PerPage: g.maxPerPage, }, } for { @@ -459,7 +464,7 @@ func (g *GithubDownloaderV3) GetComments(issueNumber int64) ([]*base.Comment, er g.sleep() res, resp, err := g.client.Reactions.ListIssueCommentReactions(g.ctx, g.repoOwner, g.repoName, comment.GetID(), &github.ListOptions{ Page: i, - PerPage: 100, + PerPage: g.maxPerPage, }) if err != nil { return nil, err @@ -497,6 +502,9 @@ func (g *GithubDownloaderV3) GetComments(issueNumber int64) ([]*base.Comment, er // GetPullRequests returns pull requests according page and perPage func (g *GithubDownloaderV3) GetPullRequests(page, perPage int) ([]*base.PullRequest, bool, error) { + if perPage > g.maxPerPage { + perPage = g.maxPerPage + } opt := &github.PullRequestListOptions{ Sort: "created", Direction: "asc", @@ -650,7 +658,7 @@ func (g *GithubDownloaderV3) convertGithubReviewComments(cs []*github.PullReques g.sleep() res, resp, err := g.client.Reactions.ListPullRequestCommentReactions(g.ctx, g.repoOwner, g.repoName, c.GetID(), &github.ListOptions{ Page: i, - PerPage: 100, + PerPage: g.maxPerPage, }) if err != nil { return nil, err @@ -687,9 +695,9 @@ func (g *GithubDownloaderV3) convertGithubReviewComments(cs []*github.PullReques // GetReviews returns pull requests review func (g *GithubDownloaderV3) GetReviews(pullRequestNumber int64) ([]*base.Review, error) { - var allReviews = make([]*base.Review, 0, 100) + var allReviews = make([]*base.Review, 0, g.maxPerPage) opt := &github.ListOptions{ - PerPage: 100, + PerPage: g.maxPerPage, } for { g.sleep() @@ -703,7 +711,7 @@ func (g *GithubDownloaderV3) GetReviews(pullRequestNumber int64) ([]*base.Review r.IssueIndex = pullRequestNumber // retrieve all review comments opt2 := &github.ListOptions{ - PerPage: 100, + PerPage: g.maxPerPage, } for { g.sleep() diff --git a/modules/migrations/gitlab.go b/modules/migrations/gitlab.go index 23cd90c747..d4b725b5be 100644 --- a/modules/migrations/gitlab.go +++ b/modules/migrations/gitlab.go @@ -68,6 +68,7 @@ type GitlabDownloader struct { repoName string issueCount int64 fetchPRcomments bool + maxPerPage int } // NewGitlabDownloader creates a gitlab Downloader via gitlab API @@ -99,10 +100,11 @@ func NewGitlabDownloader(ctx context.Context, baseURL, repoPath, username, passw } return &GitlabDownloader{ - ctx: ctx, - client: gitlabClient, - repoID: gr.ID, - repoName: gr.Name, + ctx: ctx, + client: gitlabClient, + repoID: gr.ID, + repoName: gr.Name, + maxPerPage: 100, }, nil } @@ -159,7 +161,7 @@ func (g *GitlabDownloader) GetTopics() ([]string, error) { // GetMilestones returns milestones func (g *GitlabDownloader) GetMilestones() ([]*base.Milestone, error) { - var perPage = 100 + var perPage = g.maxPerPage var state = "all" var milestones = make([]*base.Milestone, 0, perPage) for i := 1; ; i++ { @@ -230,7 +232,7 @@ func (g *GitlabDownloader) normalizeColor(val string) string { // GetLabels returns labels func (g *GitlabDownloader) GetLabels() ([]*base.Label, error) { - var perPage = 100 + var perPage = g.maxPerPage var labels = make([]*base.Label, 0, perPage) for i := 1; ; i++ { ls, _, err := g.client.Labels.ListLabels(g.repoID, &gitlab.ListLabelsOptions{ListOptions: gitlab.ListOptions{ @@ -281,7 +283,7 @@ func (g *GitlabDownloader) convertGitlabRelease(rel *gitlab.Release) *base.Relea // GetReleases returns releases func (g *GitlabDownloader) GetReleases() ([]*base.Release, error) { - var perPage = 100 + var perPage = g.maxPerPage var releases = make([]*base.Release, 0, perPage) for i := 1; ; i++ { ls, _, err := g.client.Releases.ListReleases(g.repoID, &gitlab.ListReleasesOptions{ @@ -330,6 +332,10 @@ func (g *GitlabDownloader) GetIssues(page, perPage int) ([]*base.Issue, bool, er state := "all" sort := "asc" + if perPage > g.maxPerPage { + perPage = g.maxPerPage + } + opt := &gitlab.ListProjectIssuesOptions{ State: &state, Sort: &sort, @@ -401,7 +407,7 @@ func (g *GitlabDownloader) GetIssues(page, perPage int) ([]*base.Issue, bool, er // GetComments returns comments according issueNumber // TODO: figure out how to transfer comment reactions func (g *GitlabDownloader) GetComments(issueNumber int64) ([]*base.Comment, error) { - var allComments = make([]*base.Comment, 0, 100) + var allComments = make([]*base.Comment, 0, g.maxPerPage) var page = 1 var realIssueNumber int64 @@ -415,14 +421,14 @@ func (g *GitlabDownloader) GetComments(issueNumber int64) ([]*base.Comment, erro realIssueNumber = issueNumber comments, resp, err = g.client.Discussions.ListIssueDiscussions(g.repoID, int(realIssueNumber), &gitlab.ListIssueDiscussionsOptions{ Page: page, - PerPage: 100, + PerPage: g.maxPerPage, }, nil, gitlab.WithContext(g.ctx)) } else { // If this is a PR, we need to figure out the Gitlab/original PR ID to be passed below realIssueNumber = issueNumber - g.issueCount comments, resp, err = g.client.Discussions.ListMergeRequestDiscussions(g.repoID, int(realIssueNumber), &gitlab.ListMergeRequestDiscussionsOptions{ Page: page, - PerPage: 100, + PerPage: g.maxPerPage, }, nil, gitlab.WithContext(g.ctx)) } @@ -465,6 +471,10 @@ func (g *GitlabDownloader) GetComments(issueNumber int64) ([]*base.Comment, erro // GetPullRequests returns pull requests according page and perPage func (g *GitlabDownloader) GetPullRequests(page, perPage int) ([]*base.PullRequest, bool, error) { + if perPage > g.maxPerPage { + perPage = g.maxPerPage + } + opt := &gitlab.ListProjectMergeRequestsOptions{ ListOptions: gitlab.ListOptions{ PerPage: perPage, From d795bfc9646069137d607d3d4770b956e0a48f7a Mon Sep 17 00:00:00 2001 From: zeripath Date: Sun, 25 Oct 2020 23:10:09 +0000 Subject: [PATCH 022/205] When the git ref is unable to be found return broken pr (#13218) (#13303) Backport #13218 Fix #13216 Signed-off-by: Andrew Thornton --- routers/repo/pull.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/routers/repo/pull.go b/routers/repo/pull.go index f5c3aec0f8..1b3f835e4f 100644 --- a/routers/repo/pull.go +++ b/routers/repo/pull.go @@ -311,7 +311,7 @@ func PrepareMergedViewPullInfo(ctx *context.Context, issue *models.Issue) *git.C compareInfo, err := ctx.Repo.GitRepo.GetCompareInfo(ctx.Repo.Repository.RepoPath(), pull.MergeBase, pull.GetGitRefName()) if err != nil { - if strings.Contains(err.Error(), "fatal: Not a valid object name") { + if strings.Contains(err.Error(), "fatal: Not a valid object name") || strings.Contains(err.Error(), "unknown revision or path not in the working tree") { ctx.Data["IsPullRequestBroken"] = true ctx.Data["BaseTarget"] = pull.BaseBranch ctx.Data["NumCommits"] = 0 From 5da8a84328a4d45c124d28c50dd71af111a7ca8c Mon Sep 17 00:00:00 2001 From: zeripath Date: Mon, 26 Oct 2020 01:40:46 +0000 Subject: [PATCH 023/205] Fix Storage mapping (#13297) (#13307) * Fix Storage mapping (#13297) Backport #13297 This PR fixes several bugs in setting storage * The default STORAGE_TYPE should be the provided type. * The Storage config should be passed in to NewStorage as a pointer - otherwise the Mappable interface function MapTo will not be found * There was a bug in the MapTo function. Fix #13286 Signed-off-by: Andrew Thornton * add missing changes from backport #13164 Signed-off-by: Andrew Thornton Co-authored-by: Lunny Xiao --- modules/setting/storage.go | 4 ++-- modules/storage/local.go | 3 ++- modules/storage/minio.go | 26 ++++++++++++++++---------- modules/storage/storage.go | 13 +++++++++---- 4 files changed, 29 insertions(+), 17 deletions(-) diff --git a/modules/setting/storage.go b/modules/setting/storage.go index ab0598ccf8..e743d6c20c 100644 --- a/modules/setting/storage.go +++ b/modules/setting/storage.go @@ -21,7 +21,7 @@ type Storage struct { // MapTo implements the Mappable interface func (s *Storage) MapTo(v interface{}) error { - pathValue := reflect.ValueOf(v).FieldByName("Path") + pathValue := reflect.ValueOf(v).Elem().FieldByName("Path") if pathValue.IsValid() && pathValue.Kind() == reflect.String { pathValue.SetString(s.Path) } @@ -46,7 +46,7 @@ func getStorage(name, typ string, overrides ...*ini.Section) Storage { var storage Storage - storage.Type = sec.Key("STORAGE_TYPE").MustString("") + storage.Type = sec.Key("STORAGE_TYPE").MustString(typ) storage.ServeDirect = sec.Key("SERVE_DIRECT").MustBool(false) // Global Defaults diff --git a/modules/storage/local.go b/modules/storage/local.go index e270a40b77..f7ffb2ddc1 100644 --- a/modules/storage/local.go +++ b/modules/storage/local.go @@ -11,6 +11,7 @@ import ( "os" "path/filepath" + "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/util" ) @@ -39,7 +40,7 @@ func NewLocalStorage(ctx context.Context, cfg interface{}) (ObjectStorage, error return nil, err } config := configInterface.(LocalStorageConfig) - + log.Info("Creating new Local Storage at %s", config.Path) if err := os.MkdirAll(config.Path, os.ModePerm); err != nil { return nil, err } diff --git a/modules/storage/minio.go b/modules/storage/minio.go index b65af8ddbd..092b3c93c3 100644 --- a/modules/storage/minio.go +++ b/modules/storage/minio.go @@ -13,6 +13,7 @@ import ( "strings" "time" + "code.gitea.io/gitea/modules/log" "github.com/minio/minio-go/v7" "github.com/minio/minio-go/v7/pkg/credentials" ) @@ -82,16 +83,17 @@ func convertMinioErr(err error) error { func NewMinioStorage(ctx context.Context, cfg interface{}) (ObjectStorage, error) { configInterface, err := toConfig(MinioStorageConfig{}, cfg) if err != nil { - return nil, err + return nil, convertMinioErr(err) } config := configInterface.(MinioStorageConfig) + log.Info("Creating Minio storage at %s:%s with base path %s", config.Endpoint, config.Bucket, config.BasePath) minioClient, err := minio.New(config.Endpoint, &minio.Options{ Creds: credentials.NewStaticV4(config.AccessKeyID, config.SecretAccessKey, ""), Secure: config.UseSSL, }) if err != nil { - return nil, err + return nil, convertMinioErr(err) } if err := minioClient.MakeBucket(ctx, config.Bucket, minio.MakeBucketOptions{ @@ -100,7 +102,7 @@ func NewMinioStorage(ctx context.Context, cfg interface{}) (ObjectStorage, error // Check to see if we already own this bucket (which happens if you run this twice) exists, errBucketExists := minioClient.BucketExists(ctx, config.Bucket) if !exists || errBucketExists != nil { - return nil, err + return nil, convertMinioErr(err) } } @@ -121,7 +123,7 @@ func (m *MinioStorage) Open(path string) (Object, error) { var opts = minio.GetObjectOptions{} object, err := m.client.GetObject(m.ctx, m.bucket, m.buildMinioPath(path), opts) if err != nil { - return nil, err + return nil, convertMinioErr(err) } return &minioObject{object}, nil } @@ -137,7 +139,7 @@ func (m *MinioStorage) Save(path string, r io.Reader) (int64, error) { minio.PutObjectOptions{ContentType: "application/octet-stream"}, ) if err != nil { - return 0, err + return 0, convertMinioErr(err) } return uploadInfo.Size, nil } @@ -184,14 +186,17 @@ func (m *MinioStorage) Stat(path string) (os.FileInfo, error) { return nil, os.ErrNotExist } } - return nil, err + return nil, convertMinioErr(err) } return &minioFileInfo{info}, nil } // Delete delete a file func (m *MinioStorage) Delete(path string) error { - return m.client.RemoveObject(m.ctx, m.bucket, m.buildMinioPath(path), minio.RemoveObjectOptions{}) + if err := m.client.RemoveObject(m.ctx, m.bucket, m.buildMinioPath(path), minio.RemoveObjectOptions{}); err != nil { + return convertMinioErr(err) + } + return nil } // URL gets the redirect URL to a file. The presigned link is valid for 5 minutes. @@ -199,7 +204,8 @@ func (m *MinioStorage) URL(path, name string) (*url.URL, error) { reqParams := make(url.Values) // TODO it may be good to embed images with 'inline' like ServeData does, but we don't want to have to read the file, do we? reqParams.Set("response-content-disposition", "attachment; filename=\""+quoteEscaper.Replace(name)+"\"") - return m.client.PresignedGetObject(m.ctx, m.bucket, m.buildMinioPath(path), 5*time.Minute, reqParams) + u, err := m.client.PresignedGetObject(m.ctx, m.bucket, m.buildMinioPath(path), 5*time.Minute, reqParams) + return u, convertMinioErr(err) } // IterateObjects iterates across the objects in the miniostorage @@ -213,13 +219,13 @@ func (m *MinioStorage) IterateObjects(fn func(path string, obj Object) error) er }) { object, err := m.client.GetObject(lobjectCtx, m.bucket, mObjInfo.Key, opts) if err != nil { - return err + return convertMinioErr(err) } if err := func(object *minio.Object, fn func(path string, obj Object) error) error { defer object.Close() return fn(strings.TrimPrefix(m.basePath, mObjInfo.Key), &minioObject{object}) }(object, fn); err != nil { - return err + return convertMinioErr(err) } } return nil diff --git a/modules/storage/storage.go b/modules/storage/storage.go index 1fa04119c7..ec3a1c14a1 100644 --- a/modules/storage/storage.go +++ b/modules/storage/storage.go @@ -12,6 +12,7 @@ import ( "net/url" "os" + "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/setting" ) @@ -141,21 +142,25 @@ func NewStorage(typStr string, cfg interface{}) (ObjectStorage, error) { } func initAvatars() (err error) { - Avatars, err = NewStorage(setting.Avatar.Storage.Type, setting.Avatar.Storage) + log.Info("Initialising Avatar storage with type: %s", setting.Avatar.Storage.Type) + Avatars, err = NewStorage(setting.Avatar.Storage.Type, &setting.Avatar.Storage) return } func initAttachments() (err error) { - Attachments, err = NewStorage(setting.Attachment.Storage.Type, setting.Attachment.Storage) + log.Info("Initialising Attachment storage with type: %s", setting.Attachment.Storage.Type) + Attachments, err = NewStorage(setting.Attachment.Storage.Type, &setting.Attachment.Storage) return } func initLFS() (err error) { - LFS, err = NewStorage(setting.LFS.Storage.Type, setting.LFS.Storage) + log.Info("Initialising LFS storage with type: %s", setting.LFS.Storage.Type) + LFS, err = NewStorage(setting.LFS.Storage.Type, &setting.LFS.Storage) return } func initRepoAvatars() (err error) { - RepoAvatars, err = NewStorage(setting.RepoAvatar.Storage.Type, setting.RepoAvatar.Storage) + log.Info("Initialising Repository Avatar storage with type: %s", setting.RepoAvatar.Storage.Type) + RepoAvatars, err = NewStorage(setting.RepoAvatar.Storage.Type, &setting.RepoAvatar.Storage) return } From 5178aa2130e319a54761d64944408beda390f259 Mon Sep 17 00:00:00 2001 From: zeripath Date: Mon, 26 Oct 2020 11:13:39 +0000 Subject: [PATCH 024/205] Attempt to handle unready PR in tests (#13305) (#13310) Backport #13305 Signed-off-by: Andrew Thornton Co-authored-by: Lunny Xiao Co-authored-by: Lauris BH --- .../api_helper_for_declarative_test.go | 25 ++++++++++++++++--- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/integrations/api_helper_for_declarative_test.go b/integrations/api_helper_for_declarative_test.go index 51335c8216..b0031ef332 100644 --- a/integrations/api_helper_for_declarative_test.go +++ b/integrations/api_helper_for_declarative_test.go @@ -5,14 +5,17 @@ package integrations import ( + "context" "encoding/json" "fmt" "io/ioutil" "net/http" "testing" + "time" "code.gitea.io/gitea/models" "code.gitea.io/gitea/modules/auth" + "code.gitea.io/gitea/modules/queue" api "code.gitea.io/gitea/modules/structs" "github.com/stretchr/testify/assert" @@ -225,11 +228,25 @@ func doAPIMergePullRequest(ctx APITestContext, owner, repo string, index int64) Do: string(models.MergeStyleMerge), }) - if ctx.ExpectedCode != 0 { - ctx.Session.MakeRequest(t, req, ctx.ExpectedCode) - return + resp := ctx.Session.MakeRequest(t, req, NoExpectedStatus) + + if resp.Code == http.StatusMethodNotAllowed { + err := api.APIError{} + DecodeJSON(t, resp, &err) + assert.EqualValues(t, "Please try again later", err.Message) + queue.GetManager().FlushAll(context.Background(), 5*time.Second) + resp = ctx.Session.MakeRequest(t, req, NoExpectedStatus) + } + + expected := ctx.ExpectedCode + if expected == 0 { + expected = 200 + } + + if !assert.EqualValues(t, expected, resp.Code, + "Request: %s %s", req.Method, req.URL.String()) { + logUnexpectedResponse(t, resp) } - ctx.Session.MakeRequest(t, req, 200) } } From 3d272b899d77a6bff864784d8f947bc1ca90fe60 Mon Sep 17 00:00:00 2001 From: zeripath Date: Mon, 26 Oct 2020 12:14:40 +0000 Subject: [PATCH 025/205] Ensure topics added using the API are added to the repository (#13285) (#13302) Partial Backport #13285 Fix #12426 Signed-off-by: Andrew Thornton Co-authored-by: Lauris BH --- models/topic.go | 33 ++++++++++++++++++++++++++++++--- 1 file changed, 30 insertions(+), 3 deletions(-) diff --git a/models/topic.go b/models/topic.go index 0075c1702d..6be4f10295 100644 --- a/models/topic.go +++ b/models/topic.go @@ -197,10 +197,13 @@ func FindTopics(opts *FindTopicOptions) (topics []*Topic, err error) { // GetRepoTopicByName retrives topic from name for a repo if it exist func GetRepoTopicByName(repoID int64, topicName string) (*Topic, error) { + return getRepoTopicByName(x, repoID, topicName) +} +func getRepoTopicByName(e Engine, repoID int64, topicName string) (*Topic, error) { var cond = builder.NewCond() var topic Topic cond = cond.And(builder.Eq{"repo_topic.repo_id": repoID}).And(builder.Eq{"topic.name": topicName}) - sess := x.Table("topic").Where(cond) + sess := e.Table("topic").Where(cond) sess.Join("INNER", "repo_topic", "repo_topic.topic_id = topic.id") has, err := sess.Get(&topic) if has { @@ -211,7 +214,13 @@ func GetRepoTopicByName(repoID int64, topicName string) (*Topic, error) { // AddTopic adds a topic name to a repository (if it does not already have it) func AddTopic(repoID int64, topicName string) (*Topic, error) { - topic, err := GetRepoTopicByName(repoID, topicName) + sess := x.NewSession() + defer sess.Close() + if err := sess.Begin(); err != nil { + return nil, err + } + + topic, err := getRepoTopicByName(sess, repoID, topicName) if err != nil { return nil, err } @@ -220,7 +229,25 @@ func AddTopic(repoID int64, topicName string) (*Topic, error) { return topic, nil } - return addTopicByNameToRepo(x, repoID, topicName) + topic, err = addTopicByNameToRepo(sess, repoID, topicName) + if err != nil { + return nil, err + } + + topicNames := make([]string, 0, 25) + if err := sess.Select("name").Table("topic"). + Join("INNER", "repo_topic", "repo_topic.topic_id = topic.id"). + Where("repo_topic.repo_id = ?", repoID).Desc("topic.repo_count").Find(&topicNames); err != nil { + return nil, err + } + + if _, err := sess.ID(repoID).Cols("topics").Update(&Repository{ + Topics: topicNames, + }); err != nil { + return nil, err + } + + return topic, sess.Commit() } // DeleteTopic removes a topic name from a repository (if it has it) From 28133a801a41a04470ddea9170acbba7dd2126e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bogus=C5=82awski?= Date: Mon, 26 Oct 2020 14:56:14 +0100 Subject: [PATCH 026/205] Avatar autogeneration fixed (#13282) This mod fixes problem with initial avatar autogeneration and avatar autogneration after deleting previous avatar. Related: https://github.com/go-gitea/gitea/issues/13159 Fixes: 80a6b0f5bce15a641fc75f5f1ef6e42ef54424bc Author-Change-Id: IB#1105243 --- models/user.go | 4 ---- models/user_avatar.go | 5 ++--- routers/user/setting/profile.go | 6 +++++- 3 files changed, 7 insertions(+), 8 deletions(-) diff --git a/models/user.go b/models/user.go index 7248db5337..1ab417115f 100644 --- a/models/user.go +++ b/models/user.go @@ -191,9 +191,6 @@ func (u *User) BeforeUpdate() { if len(u.AvatarEmail) == 0 { u.AvatarEmail = u.Email } - if len(u.AvatarEmail) > 0 && u.Avatar == "" { - u.Avatar = base.HashEmail(u.AvatarEmail) - } } u.LowerName = strings.ToLower(u.Name) @@ -835,7 +832,6 @@ func CreateUser(u *User) (err error) { u.LowerName = strings.ToLower(u.Name) u.AvatarEmail = u.Email - u.Avatar = base.HashEmail(u.AvatarEmail) if u.Rands, err = GetUserSalt(); err != nil { return err } diff --git a/models/user_avatar.go b/models/user_avatar.go index 0a03ca7707..2f9db5c2e2 100644 --- a/models/user_avatar.go +++ b/models/user_avatar.go @@ -39,10 +39,9 @@ func (u *User) generateRandomAvatar(e Engine) error { if err != nil { return fmt.Errorf("RandomImage: %v", err) } - // NOTICE for random avatar, it still uses id as avatar name, but custom avatar use md5 - // since random image is not a user's photo, there is no security for enumable + if u.Avatar == "" { - u.Avatar = fmt.Sprintf("%d", u.ID) + u.Avatar = base.HashEmail(u.AvatarEmail) } if err := storage.SaveFrom(storage.Avatars, u.CustomAvatarRelativePath(), func(w io.Writer) error { diff --git a/routers/user/setting/profile.go b/routers/user/setting/profile.go index 1cb00aa77f..edb78031f2 100644 --- a/routers/user/setting/profile.go +++ b/routers/user/setting/profile.go @@ -121,7 +121,11 @@ func ProfilePost(ctx *context.Context, form auth.UpdateProfileForm) { func UpdateAvatarSetting(ctx *context.Context, form auth.AvatarForm, ctxUser *models.User) error { ctxUser.UseCustomAvatar = form.Source == auth.AvatarLocal if len(form.Gravatar) > 0 { - ctxUser.Avatar = base.EncodeMD5(form.Gravatar) + if form.Avatar != nil { + ctxUser.Avatar = base.EncodeMD5(form.Gravatar) + } else { + ctxUser.Avatar = "" + } ctxUser.AvatarEmail = form.Gravatar } From 47cb9b3de2ee3ca54351b4cf1a04913a36e3587f Mon Sep 17 00:00:00 2001 From: M4RKUS-11111 <73301416+M4RKUS-11111@users.noreply.github.com> Date: Tue, 27 Oct 2020 21:26:07 +0100 Subject: [PATCH 027/205] Deny wrong pull (#13308) (#13326) * Deny wrong pull (#13308) * Deny wrong pull * Update routers/api/v1/repo/pull.go Co-authored-by: zeripath Co-authored-by: Markus Co-authored-by: zeripath * CI.restart() Co-authored-by: Markus Co-authored-by: zeripath Co-authored-by: 6543 <6543@obermui.de> --- routers/api/v1/repo/pull.go | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/routers/api/v1/repo/pull.go b/routers/api/v1/repo/pull.go index e2cab70adc..b2b71180a4 100644 --- a/routers/api/v1/repo/pull.go +++ b/routers/api/v1/repo/pull.go @@ -284,6 +284,12 @@ func CreatePullRequest(ctx *context.APIContext, form api.CreatePullRequestOption // "422": // "$ref": "#/responses/validationError" + if form.Head == form.Base { + ctx.Error(http.StatusUnprocessableEntity, "BaseHeadSame", + "Invalid PullRequest: There are no changes between the head and the base") + return + } + var ( repo = ctx.Repo.Repository labelIDs []int64 From adfe13f1a2f1e2d5a01f29309b052b767fa96c61 Mon Sep 17 00:00:00 2001 From: zeripath Date: Tue, 27 Oct 2020 23:44:21 +0000 Subject: [PATCH 028/205] Add migrated pulls to pull request task queue (#13331) (#13334) * Add migrated pulls to pull request task queue Fix #13321 Signed-off-by: Andrew Thornton * Improve error reports Signed-off-by: Andrew Thornton Co-authored-by: techknowlogick Co-authored-by: techknowlogick --- modules/migrations/gitea_downloader.go | 16 ++++++++-------- modules/migrations/gitea_uploader.go | 2 ++ 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/modules/migrations/gitea_downloader.go b/modules/migrations/gitea_downloader.go index 8299c040b0..1531153f2e 100644 --- a/modules/migrations/gitea_downloader.go +++ b/modules/migrations/gitea_downloader.go @@ -47,7 +47,7 @@ func (f *GiteaDownloaderFactory) New(ctx context.Context, opts base.MigrateOptio path := strings.Split(repoNameSpace, "/") if len(path) < 2 { - return nil, fmt.Errorf("invalid path") + return nil, fmt.Errorf("invalid path: %s", repoNameSpace) } repoPath := strings.Join(path[len(path)-2:], "/") @@ -87,7 +87,7 @@ func NewGiteaDownloader(ctx context.Context, baseURL, repoPath, username, passwo gitea_sdk.SetContext(ctx), ) if err != nil { - log.Error(fmt.Sprintf("NewGiteaDownloader: %s", err.Error())) + log.Error(fmt.Sprintf("Failed to create NewGiteaDownloader for: %s. Error: %v", baseURL, err)) return nil, err } @@ -395,7 +395,7 @@ func (g *GiteaDownloader) GetIssues(page, perPage int) ([]*base.Issue, bool, err reactions, err := g.getIssueReactions(issue.Index) if err != nil { - return nil, false, fmt.Errorf("error while loading reactions: %v", err) + return nil, false, fmt.Errorf("error while loading reactions for issue #%d. Error: %v", issue.Index, err) } var assignees []string @@ -446,13 +446,13 @@ func (g *GiteaDownloader) GetComments(index int64) ([]*base.Comment, error) { // Page: i, }}) if err != nil { - return nil, fmt.Errorf("error while listing comments: %v", err) + return nil, fmt.Errorf("error while listing comments for issue #%d. Error: %v", index, err) } for _, comment := range comments { reactions, err := g.getCommentReactions(comment.ID) if err != nil { - return nil, fmt.Errorf("error while listing comment creactions: %v", err) + return nil, fmt.Errorf("error while listing reactions for comment %d in issue #%d. Error: %v", comment.ID, index, err) } allComments = append(allComments, &base.Comment{ @@ -490,7 +490,7 @@ func (g *GiteaDownloader) GetPullRequests(page, perPage int) ([]*base.PullReques State: gitea_sdk.StateAll, }) if err != nil { - return nil, false, fmt.Errorf("error while listing repos: %v", err) + return nil, false, fmt.Errorf("error while listing pull requests (page: %d, pagesize: %d). Error: %v", page, perPage, err) } for _, pr := range prs { var milestone string @@ -521,7 +521,7 @@ func (g *GiteaDownloader) GetPullRequests(page, perPage int) ([]*base.PullReques if headSHA == "" { headCommit, _, err := g.client.GetSingleCommit(g.repoOwner, g.repoName, url.PathEscape(pr.Head.Ref)) if err != nil { - return nil, false, fmt.Errorf("error while resolving git ref: %v", err) + return nil, false, fmt.Errorf("error while resolving head git ref: %s for pull #%d. Error: %v", pr.Head.Ref, pr.Index, err) } headSHA = headCommit.SHA } @@ -534,7 +534,7 @@ func (g *GiteaDownloader) GetPullRequests(page, perPage int) ([]*base.PullReques reactions, err := g.getIssueReactions(pr.Index) if err != nil { - return nil, false, fmt.Errorf("error while loading reactions: %v", err) + return nil, false, fmt.Errorf("error while loading reactions for pull #%d. Error: %v", pr.Index, err) } var assignees []string diff --git a/modules/migrations/gitea_uploader.go b/modules/migrations/gitea_uploader.go index cd1fd5cb8d..466c832754 100644 --- a/modules/migrations/gitea_uploader.go +++ b/modules/migrations/gitea_uploader.go @@ -28,6 +28,7 @@ import ( "code.gitea.io/gitea/modules/storage" "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/modules/timeutil" + "code.gitea.io/gitea/services/pull" gouuid "github.com/google/uuid" ) @@ -524,6 +525,7 @@ func (g *GiteaLocalUploader) CreatePullRequests(prs ...*base.PullRequest) error } for _, pr := range gprs { g.issues.Store(pr.Issue.Index, pr.Issue.ID) + pull.AddToTaskQueue(pr) } return nil } From 639c737648939b20290d26a38792e0a0db68b55c Mon Sep 17 00:00:00 2001 From: JustAnotherArchivist Date: Thu, 29 Oct 2020 03:14:26 +0000 Subject: [PATCH 029/205] Add deprecation notice for webhook payload's secret field (#13329) --- docs/content/doc/features/webhooks.en-us.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/content/doc/features/webhooks.en-us.md b/docs/content/doc/features/webhooks.en-us.md index ec50c013f5..f20f253745 100644 --- a/docs/content/doc/features/webhooks.en-us.md +++ b/docs/content/doc/features/webhooks.en-us.md @@ -30,6 +30,8 @@ All event pushes are POST requests. The methods currently supported are: ### Event information +**WARNING**: The `secret` field in the payload is deprecated as of Gitea 1.13.0 and will be removed in 1.14.0: https://github.com/go-gitea/gitea/issues/11755 + The following is an example of event information that will be sent by Gitea to a Payload URL: From 0b0456310f5929bef8c7a9af5d1044088bde7565 Mon Sep 17 00:00:00 2001 From: techknowlogick Date: Wed, 28 Oct 2020 23:57:15 -0400 Subject: [PATCH 030/205] Migration failure during reaction migration from gitea (#13344) (#13345) * Migrating reactions is just not that important A failure during migrating reactions should not cause failure of migration. Signed-off-by: Andrew Thornton * When checking issue reactions check the correct permission Signed-off-by: Andrew Thornton Co-authored-by: techknowlogick Co-authored-by: zeripath --- modules/migrations/gitea_downloader.go | 13 +++++++++++-- modules/migrations/migrate.go | 2 +- routers/api/v1/repo/issue_reaction.go | 2 +- 3 files changed, 13 insertions(+), 4 deletions(-) diff --git a/modules/migrations/gitea_downloader.go b/modules/migrations/gitea_downloader.go index 1531153f2e..e30c92a2fc 100644 --- a/modules/migrations/gitea_downloader.go +++ b/modules/migrations/gitea_downloader.go @@ -14,6 +14,7 @@ import ( "strings" "time" + "code.gitea.io/gitea/models" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/migrations/base" "code.gitea.io/gitea/modules/structs" @@ -395,7 +396,11 @@ func (g *GiteaDownloader) GetIssues(page, perPage int) ([]*base.Issue, bool, err reactions, err := g.getIssueReactions(issue.Index) if err != nil { - return nil, false, fmt.Errorf("error while loading reactions for issue #%d. Error: %v", issue.Index, err) + log.Warn("Unable to load reactions during migrating issue #%d to %s/%s. Error: %v", issue.Index, g.repoOwner, g.repoName, err) + if err2 := models.CreateRepositoryNotice( + fmt.Sprintf("Unable to load reactions during migrating issue #%d to %s/%s. Error: %v", issue.Index, g.repoOwner, g.repoName, err)); err2 != nil { + log.Error("create repository notice failed: ", err2) + } } var assignees []string @@ -534,7 +539,11 @@ func (g *GiteaDownloader) GetPullRequests(page, perPage int) ([]*base.PullReques reactions, err := g.getIssueReactions(pr.Index) if err != nil { - return nil, false, fmt.Errorf("error while loading reactions for pull #%d. Error: %v", pr.Index, err) + log.Warn("Unable to load reactions during migrating pull #%d to %s/%s. Error: %v", pr.Index, g.repoOwner, g.repoName, err) + if err2 := models.CreateRepositoryNotice( + fmt.Sprintf("Unable to load reactions during migrating pull #%d to %s/%s. Error: %v", pr.Index, g.repoOwner, g.repoName, err)); err2 != nil { + log.Error("create repository notice failed: ", err2) + } } var assignees []string diff --git a/modules/migrations/migrate.go b/modules/migrations/migrate.go index 191f2a5550..3c505d82b6 100644 --- a/modules/migrations/migrate.go +++ b/modules/migrations/migrate.go @@ -69,7 +69,7 @@ func MigrateRepository(ctx context.Context, doer *models.User, ownerName string, } if err2 := models.CreateRepositoryNotice(fmt.Sprintf("Migrate repository from %s failed: %v", opts.OriginalURL, err)); err2 != nil { - log.Error("create respotiry notice failed: ", err2) + log.Error("create repository notice failed: ", err2) } return nil, err } diff --git a/routers/api/v1/repo/issue_reaction.go b/routers/api/v1/repo/issue_reaction.go index 564f67e493..4ac6439d1b 100644 --- a/routers/api/v1/repo/issue_reaction.go +++ b/routers/api/v1/repo/issue_reaction.go @@ -270,7 +270,7 @@ func GetIssueReactions(ctx *context.APIContext) { return } - if !ctx.Repo.CanRead(models.UnitTypeIssues) { + if !ctx.Repo.CanReadIssuesOrPulls(issue.IsPull) { ctx.Error(http.StatusForbidden, "GetIssueReactions", errors.New("no permission to get reactions")) return } From 8e38bd154f9d39c6e3b6b991649ae0e1152a4fc3 Mon Sep 17 00:00:00 2001 From: techknowlogick Date: Thu, 29 Oct 2020 02:44:45 -0400 Subject: [PATCH 031/205] Remove obsolete change of email on profile page (#13341) (#13347) * Remove obsolete change of email on profile page The change email on the account profile page is out-of-date and unnecessary. Changing email should be done using the account page. Fix #13336 Signed-off-by: Andrew Thornton Co-authored-by: zeripath Co-authored-by: Lauris BH --- integrations/auth_ldap_test.go | 2 +- integrations/html_helper.go | 7 +++++++ modules/auth/user_form.go | 1 - routers/user/setting/profile.go | 1 - templates/user/settings/profile.tmpl | 4 ++-- 5 files changed, 10 insertions(+), 5 deletions(-) diff --git a/integrations/auth_ldap_test.go b/integrations/auth_ldap_test.go index 520a611eab..1569458418 100644 --- a/integrations/auth_ldap_test.go +++ b/integrations/auth_ldap_test.go @@ -141,7 +141,7 @@ func TestLDAPUserSignin(t *testing.T) { assert.Equal(t, u.UserName, htmlDoc.GetInputValueByName("name")) assert.Equal(t, u.FullName, htmlDoc.GetInputValueByName("full_name")) - assert.Equal(t, u.Email, htmlDoc.GetInputValueByName("email")) + assert.Equal(t, u.Email, htmlDoc.Find(`label[for="email"]`).Siblings().First().Text()) } func TestLDAPUserSync(t *testing.T) { diff --git a/integrations/html_helper.go b/integrations/html_helper.go index 823ed44851..6dc806a76e 100644 --- a/integrations/html_helper.go +++ b/integrations/html_helper.go @@ -37,6 +37,13 @@ func (doc *HTMLDoc) GetInputValueByName(name string) string { return text } +// Find gets the descendants of each element in the current set of +// matched elements, filtered by a selector. It returns a new Selection +// object containing these matched elements. +func (doc *HTMLDoc) Find(selector string) *goquery.Selection { + return doc.doc.Find(selector) +} + // GetCSRF for get CSRC token value from input func (doc *HTMLDoc) GetCSRF() string { return doc.GetInputValueByName("_csrf") diff --git a/modules/auth/user_form.go b/modules/auth/user_form.go index e657f78e6d..32fde1570e 100644 --- a/modules/auth/user_form.go +++ b/modules/auth/user_form.go @@ -199,7 +199,6 @@ func (f *AccessTokenForm) Validate(ctx *macaron.Context, errs binding.Errors) bi type UpdateProfileForm struct { Name string `binding:"AlphaDashDot;MaxSize(40)"` FullName string `binding:"MaxSize(100)"` - Email string `binding:"Required;Email;MaxSize(254)"` KeepEmailPrivate bool Website string `binding:"ValidUrl;MaxSize(255)"` Location string `binding:"MaxSize(50)"` diff --git a/routers/user/setting/profile.go b/routers/user/setting/profile.go index edb78031f2..6653230a39 100644 --- a/routers/user/setting/profile.go +++ b/routers/user/setting/profile.go @@ -91,7 +91,6 @@ func ProfilePost(ctx *context.Context, form auth.UpdateProfileForm) { } ctx.User.FullName = form.FullName - ctx.User.Email = form.Email ctx.User.KeepEmailPrivate = form.KeepEmailPrivate ctx.User.Website = form.Website ctx.User.Location = form.Location diff --git a/templates/user/settings/profile.tmpl b/templates/user/settings/profile.tmpl index 1f34e24585..ea895ecd89 100644 --- a/templates/user/settings/profile.tmpl +++ b/templates/user/settings/profile.tmpl @@ -21,9 +21,9 @@
-
+
- +

{{.SignedUser.Email}}

From f825e2a56866eb0149f2c2ba5ba8031614103aa8 Mon Sep 17 00:00:00 2001 From: zeripath Date: Thu, 29 Oct 2020 12:48:58 +0000 Subject: [PATCH 032/205] And there is another one ... (#13350) Signed-off-by: Andrew Thornton --- routers/api/v1/repo/issue_reaction.go | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/routers/api/v1/repo/issue_reaction.go b/routers/api/v1/repo/issue_reaction.go index 4ac6439d1b..596c490827 100644 --- a/routers/api/v1/repo/issue_reaction.go +++ b/routers/api/v1/repo/issue_reaction.go @@ -56,7 +56,11 @@ func GetIssueCommentReactions(ctx *context.APIContext) { return } - if !ctx.Repo.CanRead(models.UnitTypeIssues) { + if err := comment.LoadIssue(); err != nil { + ctx.Error(http.StatusInternalServerError, "comment.LoadIssue", err) + } + + if !ctx.Repo.CanReadIssuesOrPulls(comment.Issue.IsPull) { ctx.Error(http.StatusForbidden, "GetIssueCommentReactions", errors.New("no permission to get reactions")) return } From 02edb9df526c557cab69bf7f404af2da79cb5a49 Mon Sep 17 00:00:00 2001 From: zeripath Date: Fri, 30 Oct 2020 00:05:15 +0000 Subject: [PATCH 033/205] Migrations should not fail for comment reactions (#13352) (#13355) An extension to #13444 - where we now ensure that comment reaction failures do not cause migrations failure Signed-off-by: Andrew Thornton --- modules/migrations/gitea_downloader.go | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/modules/migrations/gitea_downloader.go b/modules/migrations/gitea_downloader.go index e30c92a2fc..0509c708bf 100644 --- a/modules/migrations/gitea_downloader.go +++ b/modules/migrations/gitea_downloader.go @@ -457,7 +457,11 @@ func (g *GiteaDownloader) GetComments(index int64) ([]*base.Comment, error) { for _, comment := range comments { reactions, err := g.getCommentReactions(comment.ID) if err != nil { - return nil, fmt.Errorf("error while listing reactions for comment %d in issue #%d. Error: %v", comment.ID, index, err) + log.Warn("Unable to load comment reactions during migrating issue #%d for comment %d to %s/%s. Error: %v", index, comment.ID, g.repoOwner, g.repoName, err) + if err2 := models.CreateRepositoryNotice( + fmt.Sprintf("Unable to load reactions during migrating issue #%d for comment %d to %s/%s. Error: %v", index, comment.ID, g.repoOwner, g.repoName, err)); err2 != nil { + log.Error("create repository notice failed: ", err2) + } } allComments = append(allComments, &base.Comment{ From 79d9cda9936cafa77ea504f000b8a64bd0fc3e34 Mon Sep 17 00:00:00 2001 From: zeripath Date: Fri, 30 Oct 2020 17:51:52 +0000 Subject: [PATCH 034/205] Fix links to repositories in /user/setting/repos (#13360) (#13362) * Fix links to repositories in /user/setting/repos somehow the links gained a spurious $ in the links. Signed-off-by: Andrew Thornton * And fix #13359 Signed-off-by: Andrew Thornton --- templates/repo/settings/options.tmpl | 2 +- templates/user/settings/repos.tmpl | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/templates/repo/settings/options.tmpl b/templates/repo/settings/options.tmpl index ce76a6fefa..96414731bc 100644 --- a/templates/repo/settings/options.tmpl +++ b/templates/repo/settings/options.tmpl @@ -284,7 +284,7 @@
- {{if and (not .IsMirror) (.Repository.UnitEnabled $.UnitTypePullRequests)}} + {{if not .IsMirror}}
{{$pullRequestEnabled := .Repository.UnitEnabled $.UnitTypePullRequests}} {{$prUnit := .Repository.MustGetUnit $.UnitTypePullRequests}} diff --git a/templates/user/settings/repos.tmpl b/templates/user/settings/repos.tmpl index 456647d9be..65c89b268a 100644 --- a/templates/user/settings/repos.tmpl +++ b/templates/user/settings/repos.tmpl @@ -119,7 +119,7 @@ {{else}} {{svg "octicon-repo"}} {{end}} - {{$.OwnerName}}/{{.Name}} + {{.OwnerName}}/{{.Name}} {{SizeFmt .Size}} {{if .IsFork}} {{$.i18n.Tr "repo.forked_from"}} From 77a2d756399b994b238360a0fa528ecc2bf1528c Mon Sep 17 00:00:00 2001 From: zeripath Date: Sat, 31 Oct 2020 11:51:51 +0000 Subject: [PATCH 035/205] Fix scrolling to resolved comment anchors (#13343) (#13371) * Fix scrolling to resolved comment anchors As described on discord, when the window.location.hash refers to a resolved comment then the scroll to functionality does not work. This PR fixes this. Signed-off-by: Andrew Thornton * Apply suggestions from code review Co-authored-by: silverwind Co-authored-by: techknowlogick --- web_src/js/index.js | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/web_src/js/index.js b/web_src/js/index.js index 94238ca3d9..6aedd8b549 100644 --- a/web_src/js/index.js +++ b/web_src/js/index.js @@ -1170,6 +1170,22 @@ async function initRepository() { } function initPullRequestReview() { + if (window.location.hash && window.location.hash.startsWith('#issuecomment-')) { + const commentDiv = $(window.location.hash); + if (commentDiv) { + // get the name of the parent id + const groupID = commentDiv.closest('div[id^="code-comments-"]').attr('id'); + if (groupID && groupID.startsWith('code-comments-')) { + const id = groupID.substr(14); + $(`#show-outdated-${id}`).addClass('hide'); + $(`#code-comments-${id}`).removeClass('hide'); + $(`#code-preview-${id}`).removeClass('hide'); + $(`#hide-outdated-${id}`).removeClass('hide'); + $(window).scrollTop(commentDiv.offset().top); + } + } + } + $('.show-outdated').on('click', function (e) { e.preventDefault(); const id = $(this).data('comment'); From 52b4b984a5e0f761102f37807b0834160e3abe44 Mon Sep 17 00:00:00 2001 From: silverwind Date: Sat, 31 Oct 2020 18:25:10 +0100 Subject: [PATCH 036/205] Comment Header fixes (#13356) (#13374) Apply more flexboxes on comment header and remove float hacks. Needs 1.13 backport. Fixes: https://github.com/go-gitea/gitea/issues/13316 Co-authored-by: Lauris BH Co-authored-by: Lauris BH --- templates/repo/issue/view_content.tmpl | 44 ++++++++++--------- .../repo/issue/view_content/comments.tmpl | 20 +++++---- web_src/less/_form.less | 10 ++--- web_src/less/_repository.less | 30 +++---------- web_src/less/themes/theme-arc-green.less | 2 +- 5 files changed, 44 insertions(+), 62 deletions(-) diff --git a/templates/repo/issue/view_content.tmpl b/templates/repo/issue/view_content.tmpl index 190f5117b8..9f4c641592 100644 --- a/templates/repo/issue/view_content.tmpl +++ b/templates/repo/issue/view_content.tmpl @@ -21,25 +21,27 @@ {{end}}
- {{if .Issue.OriginalAuthor }} - - - {{ .Issue.OriginalAuthor }} - - - {{ .i18n.Tr "repo.issues.commented_at" .Issue.HashTag $createdStr | Safe }} - - - {{if .Repository.OriginalURL}} ({{$.i18n.Tr "repo.migrated_from" .Repository.OriginalURL .Repository.GetOriginalURLHostname | Safe }}){{end}} - - {{else}} - - {{.Issue.Poster.GetDisplayName}} - {{.i18n.Tr "repo.issues.commented_at" .Issue.HashTag $createdStr | Safe}} - - {{end}} - {{if not $.Repository.IsArchived}} -
+
+ {{if .Issue.OriginalAuthor }} + + + {{ .Issue.OriginalAuthor }} + + + {{ .i18n.Tr "repo.issues.commented_at" .Issue.HashTag $createdStr | Safe }} + + + {{if .Repository.OriginalURL}} ({{$.i18n.Tr "repo.migrated_from" .Repository.OriginalURL .Repository.GetOriginalURLHostname | Safe }}){{end}} + + {{else}} + + {{.Issue.Poster.GetDisplayName}} + {{.i18n.Tr "repo.issues.commented_at" .Issue.HashTag $createdStr | Safe}} + + {{end}} +
+
+ {{if not $.Repository.IsArchived}} {{if gt .Issue.ShowTag 0}}
{{if eq .Issue.ShowTag 2}} @@ -51,8 +53,8 @@ {{end}} {{template "repo/issue/view_content/add_reaction" Dict "ctx" $ "ActionURL" (Printf "%s/issues/%d/reactions" $.RepoLink .Issue.Index)}} {{template "repo/issue/view_content/context_menu" Dict "ctx" $ "item" .Issue "delete" false "diff" false "IsCommentPoster" $.IsIssuePoster}} -
- {{end}} + {{end}} +
diff --git a/templates/repo/issue/view_content/comments.tmpl b/templates/repo/issue/view_content/comments.tmpl index 86ce6148c1..e3fc076b74 100644 --- a/templates/repo/issue/view_content/comments.tmpl +++ b/templates/repo/issue/view_content/comments.tmpl @@ -20,13 +20,15 @@ {{end}}
- {{if .OriginalAuthor }} - {{ .OriginalAuthor }} {{$.i18n.Tr "repo.issues.commented_at" .Issue.HashTag $createdStr | Safe}} {{if $.Repository.OriginalURL}}({{$.i18n.Tr "repo.migrated_from" $.Repository.OriginalURL $.Repository.GetOriginalURLHostname | Safe }}){{end}} - {{else}} - {{.Poster.GetDisplayName}} {{$.i18n.Tr "repo.issues.commented_at" .HashTag $createdStr | Safe}} - {{end}} - {{if not $.Repository.IsArchived}} -
+
+ {{if .OriginalAuthor }} + {{ .OriginalAuthor }} {{$.i18n.Tr "repo.issues.commented_at" .Issue.HashTag $createdStr | Safe}} {{if $.Repository.OriginalURL}}({{$.i18n.Tr "repo.migrated_from" $.Repository.OriginalURL $.Repository.GetOriginalURLHostname | Safe }}){{end}} + {{else}} + {{.Poster.GetDisplayName}} {{$.i18n.Tr "repo.issues.commented_at" .HashTag $createdStr | Safe}} + {{end}} +
+
+ {{if not $.Repository.IsArchived}} {{if eq .PosterID .Issue.PosterID }}
{{$.i18n.Tr "repo.issues.poster"}} @@ -43,8 +45,8 @@ {{end}} {{template "repo/issue/view_content/add_reaction" Dict "ctx" $ "ActionURL" (Printf "%s/comments/%d/reactions" $.RepoLink .ID)}} {{template "repo/issue/view_content/context_menu" Dict "ctx" $ "item" . "delete" true "diff" false "IsCommentPoster" (and $.IsSigned (eq $.SignedUserID .PosterID))}} -
- {{end}} + {{end}} +
diff --git a/web_src/less/_form.less b/web_src/less/_form.less index 48a8a79b21..c2fb020d7f 100644 --- a/web_src/less/_form.less +++ b/web_src/less/_form.less @@ -10,13 +10,9 @@ .ui.attached.header { background: #f0f0f0; - .right { - margin-top: -5px; - - .button { - padding: 8px 10px; - font-weight: normal; - } + .right .button { + padding: 8px 10px; + font-weight: normal; } } diff --git a/web_src/less/_repository.less b/web_src/less/_repository.less index fee85a700f..09b416c4a1 100644 --- a/web_src/less/_repository.less +++ b/web_src/less/_repository.less @@ -955,7 +955,6 @@ .tag { color: #767676; - margin-top: 3px; padding: 2px 5px; font-size: 12px; border: 1px solid rgba(0, 0, 0, .1); @@ -969,26 +968,6 @@ } } - .actions { - .item { - float: left; - - &.context { - float: none; - } - - &.tag { - margin-right: 5px; - } - - &.action { - margin-top: 6px; - padding-left: 10px; - padding-right: 3px; - } - } - } - > .content { > div:first-child { border-top-left-radius: 4px; @@ -1028,11 +1007,14 @@ left: 7px; } - .actions { - display: flex; - padding: 0 .5rem; + .header-left > * + *, + .header-right > * + * { + margin-left: .25rem; + } + .actions { a { + padding: .5rem; color: rgba(0, 0, 0, .4); &:hover { diff --git a/web_src/less/themes/theme-arc-green.less b/web_src/less/themes/theme-arc-green.less index e76f2a1bd4..89a69c241b 100644 --- a/web_src/less/themes/theme-arc-green.less +++ b/web_src/less/themes/theme-arc-green.less @@ -1124,7 +1124,7 @@ a.ui.basic.green.label:hover { .repository.view.issue .comment-list .comment .tag { color: #dbdbdb; - border-color: rgb(152, 152, 152); + border-color: #505667; } .repository.view.issue .comment-list .timeline-item .badge.badge-commit { From 3f94dffca1f5d7d82324dca2a055f5416f065fe9 Mon Sep 17 00:00:00 2001 From: zeripath Date: Sat, 31 Oct 2020 19:30:23 +0000 Subject: [PATCH 037/205] When creating line diffs do not split within an html entity (#13357) (#13375) Backport #13357 * When creating line diffs do not split within an html entity Fix #13342 Signed-off-by: Andrew Thornton * Add test case Signed-off-by: Andrew Thornton * improve test Signed-off-by: Andrew Thornton Co-authored-by: techknowlogick Co-authored-by: techknowlogick --- services/gitdiff/gitdiff.go | 84 ++++++++++++++++++++++++++++++++ services/gitdiff/gitdiff_test.go | 30 ++++++++++++ 2 files changed, 114 insertions(+) diff --git a/services/gitdiff/gitdiff.go b/services/gitdiff/gitdiff.go index 7acf8324c3..50e2f8cf1e 100644 --- a/services/gitdiff/gitdiff.go +++ b/services/gitdiff/gitdiff.go @@ -290,6 +290,9 @@ func init() { diffMatchPatch.DiffEditCost = 100 } +var unterminatedEntityRE = regexp.MustCompile(`&[^ ;]*$`) +var unstartedEntiyRE = regexp.MustCompile(`^[^ ;]*;`) + // GetComputedInlineDiffFor computes inline diff for the given line. func (diffSection *DiffSection) GetComputedInlineDiffFor(diffLine *DiffLine) template.HTML { if setting.Git.DisableDiffHighlight { @@ -329,9 +332,90 @@ func (diffSection *DiffSection) GetComputedInlineDiffFor(diffLine *DiffLine) tem diffRecord := diffMatchPatch.DiffMain(highlight.Code(diffSection.FileName, diff1[1:]), highlight.Code(diffSection.FileName, diff2[1:]), true) diffRecord = diffMatchPatch.DiffCleanupEfficiency(diffRecord) + + // Now we need to clean up the split entities + diffRecord = unsplitEntities(diffRecord) + diffRecord = diffMatchPatch.DiffCleanupEfficiency(diffRecord) + return diffToHTML(diffSection.FileName, diffRecord, diffLine.Type) } +// unsplitEntities looks for broken up html entities. It relies on records being presimplified and the data being passed in being valid html +func unsplitEntities(records []diffmatchpatch.Diff) []diffmatchpatch.Diff { + // Unsplitting entities is simple... + // + // Iterate through all be the last records because if we're the last record then there's nothing we can do + for i := 0; i+1 < len(records); i++ { + record := &records[i] + + // Look for an unterminated entity at the end of the line + unterminated := unterminatedEntityRE.FindString(record.Text) + if len(unterminated) == 0 { + continue + } + + switch record.Type { + case diffmatchpatch.DiffEqual: + // If we're an diff equal we want to give this unterminated entity to our next delete and insert + record.Text = record.Text[0 : len(record.Text)-len(unterminated)] + records[i+1].Text = unterminated + records[i+1].Text + + nextType := records[i+1].Type + + if nextType == diffmatchpatch.DiffEqual { + continue + } + + // if the next in line is a delete then we will want the thing after that to be an insert and so on. + oneAfterType := diffmatchpatch.DiffInsert + if nextType == diffmatchpatch.DiffInsert { + oneAfterType = diffmatchpatch.DiffDelete + } + + if i+2 < len(records) && records[i+2].Type == oneAfterType { + records[i+2].Text = unterminated + records[i+2].Text + } else { + records = append(records[:i+2], append([]diffmatchpatch.Diff{ + { + Type: oneAfterType, + Text: unterminated, + }}, records[i+2:]...)...) + } + case diffmatchpatch.DiffDelete: + fallthrough + case diffmatchpatch.DiffInsert: + // if we're an insert or delete we want to claim the terminal bit of the entity from the next equal in line + targetType := diffmatchpatch.DiffInsert + if record.Type == diffmatchpatch.DiffInsert { + targetType = diffmatchpatch.DiffDelete + } + next := &records[i+1] + if next.Type == diffmatchpatch.DiffEqual { + // if the next is an equal we need to snaffle the entity end off the start and add an delete/insert + if terminal := unstartedEntiyRE.FindString(next.Text); len(terminal) > 0 { + record.Text += terminal + next.Text = next.Text[len(terminal):] + records = append(records[:i+2], append([]diffmatchpatch.Diff{ + { + Type: targetType, + Text: unterminated, + }}, records[i+2:]...)...) + } + } else if next.Type == targetType { + // if the next is an insert we need to snaffle the entity end off the one after that and add it to both. + if i+2 < len(records) && records[i+2].Type == diffmatchpatch.DiffEqual { + if terminal := unstartedEntiyRE.FindString(records[i+2].Text); len(terminal) > 0 { + record.Text += terminal + next.Text += terminal + records[i+2].Text = records[i+2].Text[len(terminal):] + } + } + } + } + } + return records +} + // DiffFile represents a file diff. type DiffFile struct { Name string diff --git a/services/gitdiff/gitdiff_test.go b/services/gitdiff/gitdiff_test.go index e7eeca7004..0683997dab 100644 --- a/services/gitdiff/gitdiff_test.go +++ b/services/gitdiff/gitdiff_test.go @@ -15,6 +15,7 @@ import ( "code.gitea.io/gitea/models" "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/setting" + "github.com/sergi/go-diff/diffmatchpatch" dmp "github.com/sergi/go-diff/diffmatchpatch" "github.com/stretchr/testify/assert" "gopkg.in/ini.v1" @@ -26,6 +27,35 @@ func assertEqual(t *testing.T, s1 string, s2 template.HTML) { } } +func TestUnsplitEntities(t *testing.T) { + left := "sh "useradd -u 111 jenkins"" + right := "sh 'useradd -u $(stat -c "%u" .gitignore) jenkins'" + diffRecord := diffMatchPatch.DiffMain(left, right, true) + diffRecord = diffMatchPatch.DiffCleanupEfficiency(diffRecord) + + // Now we need to clean up the split entities + diffRecord = unsplitEntities(diffRecord) + diffRecord = diffMatchPatch.DiffCleanupEfficiency(diffRecord) + + leftRecombined := "" + rightRecombined := "" + for _, record := range diffRecord { + assert.False(t, unterminatedEntityRE.MatchString(record.Text), "") + switch record.Type { + case diffmatchpatch.DiffDelete: + leftRecombined += record.Text + case diffmatchpatch.DiffInsert: + rightRecombined += record.Text + default: + leftRecombined += record.Text + rightRecombined += record.Text + } + } + + assert.EqualValues(t, left, leftRecombined) + assert.EqualValues(t, right, rightRecombined) +} + func TestDiffToHTML(t *testing.T) { setting.Cfg = ini.Empty() assertEqual(t, "foo bar biz", diffToHTML("", []dmp.Diff{ From c3e752ae29db2093f83cea5611ffb4a97b6ad5cc Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Sun, 1 Nov 2020 15:14:39 +0800 Subject: [PATCH 038/205] Fix typo (#13380) (#13382) --- modules/notification/action/action.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/notification/action/action.go b/modules/notification/action/action.go index f7078d3493..07dbbbe4dc 100644 --- a/modules/notification/action/action.go +++ b/modules/notification/action/action.go @@ -314,7 +314,7 @@ func (a *actionNotifier) NotifySyncDeleteRef(doer *models.User, repo *models.Rep if err := models.NotifyWatchers(&models.Action{ ActUserID: repo.OwnerID, ActUser: repo.MustOwner(), - OpType: models.ActionMirrorSyncCreate, + OpType: models.ActionMirrorSyncDelete, RepoID: repo.ID, Repo: repo, IsPrivate: repo.IsPrivate, From 02259a0f3aaa257daf97fb1ec5f5c83c937a2602 Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Sun, 1 Nov 2020 23:12:50 +0800 Subject: [PATCH 039/205] Storage configuration support `[storage]` (#13314) (#13379) * Fix minio bug * Add tests for storage configuration * Change the Seek flag to keep compitable minio? * Fix test when first-byte-pos of all ranges is greater than the resource length Co-authored-by: techknowlogick Co-authored-by: techknowlogick --- integrations/integration_test.go | 29 ++++++++++++++++++----------- integrations/lfs_getobject_test.go | 3 ++- integrations/mysql.ini.tmpl | 26 ++++++++++++-------------- modules/lfs/content_store.go | 23 ++++++++++++++++++++++- modules/lfs/server.go | 8 ++++++-- modules/setting/storage.go | 6 ++---- 6 files changed, 62 insertions(+), 33 deletions(-) diff --git a/integrations/integration_test.go b/integrations/integration_test.go index 3942d54410..13a1bac370 100644 --- a/integrations/integration_test.go +++ b/integrations/integration_test.go @@ -11,7 +11,6 @@ import ( "encoding/json" "fmt" "io" - "log" "net/http" "net/http/cookiejar" "net/http/httptest" @@ -27,8 +26,10 @@ import ( "code.gitea.io/gitea/models" "code.gitea.io/gitea/modules/base" "code.gitea.io/gitea/modules/graceful" + "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/queue" "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/modules/storage" "code.gitea.io/gitea/modules/util" "code.gitea.io/gitea/routers" "code.gitea.io/gitea/routers/routes" @@ -59,6 +60,8 @@ func NewNilResponseRecorder() *NilResponseRecorder { } func TestMain(m *testing.M) { + defer log.Close() + managerCtx, cancel := context.WithCancel(context.Background()) graceful.InitManager(managerCtx) defer cancel() @@ -142,6 +145,10 @@ func initIntegrationTest() { util.RemoveAll(models.LocalCopyPath()) setting.CheckLFSVersion() setting.InitDBConfig() + if err := storage.Init(); err != nil { + fmt.Printf("Init storage failed: %v", err) + os.Exit(1) + } switch { case setting.Database.UseMySQL: @@ -149,27 +156,27 @@ func initIntegrationTest() { setting.Database.User, setting.Database.Passwd, setting.Database.Host)) defer db.Close() if err != nil { - log.Fatalf("sql.Open: %v", err) + log.Fatal("sql.Open: %v", err) } if _, err = db.Exec(fmt.Sprintf("CREATE DATABASE IF NOT EXISTS %s", setting.Database.Name)); err != nil { - log.Fatalf("db.Exec: %v", err) + log.Fatal("db.Exec: %v", err) } case setting.Database.UsePostgreSQL: db, err := sql.Open("postgres", fmt.Sprintf("postgres://%s:%s@%s/?sslmode=%s", setting.Database.User, setting.Database.Passwd, setting.Database.Host, setting.Database.SSLMode)) defer db.Close() if err != nil { - log.Fatalf("sql.Open: %v", err) + log.Fatal("sql.Open: %v", err) } dbrows, err := db.Query(fmt.Sprintf("SELECT 1 FROM pg_database WHERE datname = '%s'", setting.Database.Name)) if err != nil { - log.Fatalf("db.Query: %v", err) + log.Fatal("db.Query: %v", err) } defer dbrows.Close() if !dbrows.Next() { if _, err = db.Exec(fmt.Sprintf("CREATE DATABASE %s", setting.Database.Name)); err != nil { - log.Fatalf("db.Exec: CREATE DATABASE: %v", err) + log.Fatal("db.Exec: CREATE DATABASE: %v", err) } } // Check if we need to setup a specific schema @@ -183,18 +190,18 @@ func initIntegrationTest() { // This is a different db object; requires a different Close() defer db.Close() if err != nil { - log.Fatalf("sql.Open: %v", err) + log.Fatal("sql.Open: %v", err) } schrows, err := db.Query(fmt.Sprintf("SELECT 1 FROM information_schema.schemata WHERE schema_name = '%s'", setting.Database.Schema)) if err != nil { - log.Fatalf("db.Query: %v", err) + log.Fatal("db.Query: %v", err) } defer schrows.Close() if !schrows.Next() { // Create and setup a DB schema if _, err = db.Exec(fmt.Sprintf("CREATE SCHEMA %s", setting.Database.Schema)); err != nil { - log.Fatalf("db.Exec: CREATE SCHEMA: %v", err) + log.Fatal("db.Exec: CREATE SCHEMA: %v", err) } } @@ -203,10 +210,10 @@ func initIntegrationTest() { db, err := sql.Open("mssql", fmt.Sprintf("server=%s; port=%s; database=%s; user id=%s; password=%s;", host, port, "master", setting.Database.User, setting.Database.Passwd)) if err != nil { - log.Fatalf("sql.Open: %v", err) + log.Fatal("sql.Open: %v", err) } if _, err := db.Exec(fmt.Sprintf("If(db_id(N'%s') IS NULL) BEGIN CREATE DATABASE %s; END;", setting.Database.Name, setting.Database.Name)); err != nil { - log.Fatalf("db.Exec: %v", err) + log.Fatal("db.Exec: %v", err) } defer db.Close() } diff --git a/integrations/lfs_getobject_test.go b/integrations/lfs_getobject_test.go index 431c7ed9e8..180182dd42 100644 --- a/integrations/lfs_getobject_test.go +++ b/integrations/lfs_getobject_test.go @@ -78,6 +78,7 @@ func storeAndGetLfs(t *testing.T, content *[]byte, extraHeader *http.Header, exp } } } + resp := session.MakeRequest(t, req, expectedStatus) return resp @@ -210,7 +211,7 @@ func TestGetLFSRange(t *testing.T) { {"bytes=0-10", "123456789\n", http.StatusPartialContent}, // end-range bigger than length-1 is ignored {"bytes=0-11", "123456789\n", http.StatusPartialContent}, - {"bytes=11-", "", http.StatusPartialContent}, + {"bytes=11-", "Requested Range Not Satisfiable", http.StatusRequestedRangeNotSatisfiable}, // incorrect header value cause whole header to be ignored {"bytes=-", "123456789\n", http.StatusOK}, {"foobar", "123456789\n", http.StatusOK}, diff --git a/integrations/mysql.ini.tmpl b/integrations/mysql.ini.tmpl index b546748d17..db1051e62a 100644 --- a/integrations/mysql.ini.tmpl +++ b/integrations/mysql.ini.tmpl @@ -45,19 +45,21 @@ START_SSH_SERVER = true OFFLINE_MODE = false LFS_START_SERVER = true -LFS_CONTENT_PATH = integrations/gitea-integration-mysql/datalfs-mysql LFS_JWT_SECRET = Tv_MjmZuHqpIY6GFl12ebgkRAMt4RlWt0v4EHKSXO0w -LFS_STORE_TYPE = minio -LFS_SERVE_DIRECT = false -LFS_MINIO_ENDPOINT = minio:9000 -LFS_MINIO_ACCESS_KEY_ID = 123456 -LFS_MINIO_SECRET_ACCESS_KEY = 12345678 -LFS_MINIO_BUCKET = gitea -LFS_MINIO_LOCATION = us-east-1 -LFS_MINIO_BASE_PATH = lfs/ -LFS_MINIO_USE_SSL = false + +[lfs] +MINIO_BASE_PATH = lfs/ [attachment] +MINIO_BASE_PATH = attachments/ + +[avatars] +MINIO_BASE_PATH = avatars/ + +[repo-avatars] +MINIO_BASE_PATH = repo-avatars/ + +[storage] STORAGE_TYPE = minio SERVE_DIRECT = false MINIO_ENDPOINT = minio:9000 @@ -65,7 +67,6 @@ MINIO_ACCESS_KEY_ID = 123456 MINIO_SECRET_ACCESS_KEY = 12345678 MINIO_BUCKET = gitea MINIO_LOCATION = us-east-1 -MINIO_BASE_PATH = attachments/ MINIO_USE_SSL = false [mailer] @@ -88,9 +89,6 @@ ENABLE_NOTIFY_MAIL = true DISABLE_GRAVATAR = false ENABLE_FEDERATED_AVATAR = false -AVATAR_UPLOAD_PATH = integrations/gitea-integration-mysql/data/avatars -REPOSITORY_AVATAR_UPLOAD_PATH = integrations/gitea-integration-mysql/data/repo-avatars - [session] PROVIDER = file PROVIDER_CONFIG = integrations/gitea-integration-mysql/data/sessions diff --git a/modules/lfs/content_store.go b/modules/lfs/content_store.go index cf0a05d644..247191a1bf 100644 --- a/modules/lfs/content_store.go +++ b/modules/lfs/content_store.go @@ -8,6 +8,7 @@ import ( "crypto/sha256" "encoding/hex" "errors" + "fmt" "io" "os" @@ -21,6 +22,21 @@ var ( errSizeMismatch = errors.New("Content size does not match") ) +// ErrRangeNotSatisfiable represents an error which request range is not satisfiable. +type ErrRangeNotSatisfiable struct { + FromByte int64 +} + +func (err ErrRangeNotSatisfiable) Error() string { + return fmt.Sprintf("Requested range %d is not satisfiable", err.FromByte) +} + +// IsErrRangeNotSatisfiable returns true if the error is an ErrRangeNotSatisfiable +func IsErrRangeNotSatisfiable(err error) bool { + _, ok := err.(ErrRangeNotSatisfiable) + return ok +} + // ContentStore provides a simple file system based storage. type ContentStore struct { storage.ObjectStorage @@ -35,7 +51,12 @@ func (s *ContentStore) Get(meta *models.LFSMetaObject, fromByte int64) (io.ReadC return nil, err } if fromByte > 0 { - _, err = f.Seek(fromByte, os.SEEK_CUR) + if fromByte >= meta.Size { + return nil, ErrRangeNotSatisfiable{ + FromByte: fromByte, + } + } + _, err = f.Seek(fromByte, io.SeekStart) if err != nil { log.Error("Whilst trying to read LFS OID[%s]: Unable to seek to %d Error: %v", meta.Oid, fromByte, err) } diff --git a/modules/lfs/server.go b/modules/lfs/server.go index 2801f8410c..b093213643 100644 --- a/modules/lfs/server.go +++ b/modules/lfs/server.go @@ -191,8 +191,12 @@ func getContentHandler(ctx *context.Context) { contentStore := &ContentStore{ObjectStorage: storage.LFS} content, err := contentStore.Get(meta, fromByte) if err != nil { - // Errors are logged in contentStore.Get - writeStatus(ctx, 404) + if IsErrRangeNotSatisfiable(err) { + writeStatus(ctx, http.StatusRequestedRangeNotSatisfiable) + } else { + // Errors are logged in contentStore.Get + writeStatus(ctx, 404) + } return } defer content.Close() diff --git a/modules/setting/storage.go b/modules/setting/storage.go index e743d6c20c..27788da1ff 100644 --- a/modules/setting/storage.go +++ b/modules/setting/storage.go @@ -32,14 +32,12 @@ func (s *Storage) MapTo(v interface{}) error { } func getStorage(name, typ string, overrides ...*ini.Section) Storage { - sectionName := "storage" - if len(name) > 0 { - sectionName = sectionName + "." + typ - } + const sectionName = "storage" sec := Cfg.Section(sectionName) if len(overrides) == 0 { overrides = []*ini.Section{ + Cfg.Section(sectionName + "." + typ), Cfg.Section(sectionName + "." + name), } } From 350c10fe5bef393bee64f8ad2a7dada5353bbaa1 Mon Sep 17 00:00:00 2001 From: Cirno the Strongest <1447794+CirnoT@users.noreply.github.com> Date: Mon, 2 Nov 2020 15:05:41 +0100 Subject: [PATCH 040/205] Fix reactions on code comments (#13390) (#13401) Co-authored-by: Lunny Xiao (cherry picked from commit 06268dcf53657ffe012abe878e1127ab4f954264) --- models/issue_comment.go | 4 ++++ templates/repo/diff/comments.tmpl | 4 ++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/models/issue_comment.go b/models/issue_comment.go index 270a10e240..a5b6588fa9 100644 --- a/models/issue_comment.go +++ b/models/issue_comment.go @@ -1124,6 +1124,10 @@ func fetchCodeCommentsByReview(e Engine, issue *Issue, currentUser *User, review return nil, err } + if err := comment.LoadReactions(issue.Repo); err != nil { + return nil, err + } + if re, ok := reviews[comment.ReviewID]; ok && re != nil { // If the review is pending only the author can see the comments (except the review is set) if review.ID == 0 { diff --git a/templates/repo/diff/comments.tmpl b/templates/repo/diff/comments.tmpl index 097d437a6d..69e87a7a70 100644 --- a/templates/repo/diff/comments.tmpl +++ b/templates/repo/diff/comments.tmpl @@ -30,7 +30,7 @@
{{end}} {{end}} - {{template "repo/issue/view_content/add_reaction" Dict "ctx" $ "ActionURL" (Printf "%s/comments/%d/reactions" $.root.RepoLink .ID) }} + {{template "repo/issue/view_content/add_reaction" Dict "ctx" $.root "ActionURL" (Printf "%s/comments/%d/reactions" $.root.RepoLink .ID) }} {{template "repo/issue/view_content/context_menu" Dict "ctx" $.root "item" . "delete" true "diff" true "IsCommentPoster" (and $.root.IsSigned (eq $.root.SignedUserID .PosterID))}}
@@ -48,7 +48,7 @@ {{$reactions := .Reactions.GroupByType}} {{if $reactions}}
- {{template "repo/issue/view_content/reactions" Dict "ctx" $ "ActionURL" (Printf "%s/comments/%d/reactions" $.root.RepoLink .ID) "Reactions" $reactions}} + {{template "repo/issue/view_content/reactions" Dict "ctx" $.root "ActionURL" (Printf "%s/comments/%d/reactions" $.root.RepoLink .ID) "Reactions" $reactions}}
{{end}}
From cbdbae292531832fcaf7a35e369394dfe3e0eb6e Mon Sep 17 00:00:00 2001 From: Cirno the Strongest <1447794+CirnoT@users.noreply.github.com> Date: Tue, 3 Nov 2020 00:09:29 +0100 Subject: [PATCH 041/205] Fix 'add code comment' button being invisible all the time (#13389) (#13402) * Fix 'add code comment' button being invisible all the time * Fix off-center icon * Remove old JS hover hack * Show on full-line hover Co-authored-by: techknowlogick (cherry picked from commit 7f7e7f3ca432fa80f9f5a8a71c9c10a89ac43c4f) --- web_src/js/index.js | 10 ---------- web_src/less/_review.less | 11 +++++------ 2 files changed, 5 insertions(+), 16 deletions(-) diff --git a/web_src/js/index.js b/web_src/js/index.js index 6aedd8b549..1c479d0e7d 100644 --- a/web_src/js/index.js +++ b/web_src/js/index.js @@ -1236,16 +1236,6 @@ function initPullRequestReview() { $(this).closest('.menu').toggle('visible'); }); - $('.code-view .lines-code,.code-view .lines-num') - .on('mouseenter', function () { - const parent = $(this).closest('td'); - $(this).closest('tr').addClass( - parent.hasClass('lines-num-old') || parent.hasClass('lines-code-old') ? 'focus-lines-old' : 'focus-lines-new' - ); - }) - .on('mouseleave', function () { - $(this).closest('tr').removeClass('focus-lines-new focus-lines-old'); - }); $('.add-code-comment').on('click', function (e) { if ($(e.target).hasClass('btn-add-single')) return; // https://github.com/go-gitea/gitea/issues/4745 e.preventDefault(); diff --git a/web_src/less/_review.less b/web_src/less/_review.less index 73506f5f0b..5ba4525a2f 100644 --- a/web_src/less/_review.less +++ b/web_src/less/_review.less @@ -1,7 +1,7 @@ .ui.button.add-code-comment { font-size: 14px; height: 16px; - line-height: 16px !important; + line-height: 12px !important; padding: 0; position: relative; width: 16px; @@ -17,6 +17,10 @@ } } +.diff-file-box .lines-code:hover .ui.button.add-code-comment { + opacity: 1; +} + .add-comment-left.add-comment-right .ui.attached.header { border: 1px solid #d4d4d5; margin-top: .5em; @@ -32,11 +36,6 @@ } } -.focus-lines-new .ui.button.add-code-comment.add-code-comment-right, -.focus-lines-old .ui.button.add-code-comment.add-code-comment-left { - opacity: 1; -} - .comment-code-cloud { padding: 4px; position: relative; From 4ad10ac015bc0ecbf5c4efac13e90fd90101afbe Mon Sep 17 00:00:00 2001 From: 6543 <6543@obermui.de> Date: Tue, 3 Nov 2020 02:56:51 +0100 Subject: [PATCH 042/205] Vendor: mvdan.cc/xurls v2.1.0 -> v2.2.0 (#13407) --- go.mod | 2 +- go.sum | 4 ++-- vendor/modules.txt | 2 +- vendor/mvdan.cc/xurls/v2/README.md | 11 ++++++++--- vendor/mvdan.cc/xurls/v2/go.mod | 7 ++++++- vendor/mvdan.cc/xurls/v2/go.sum | 12 ++++++++++++ vendor/mvdan.cc/xurls/v2/schemes.go | 3 +++ vendor/mvdan.cc/xurls/v2/tlds.go | 22 +++++----------------- vendor/mvdan.cc/xurls/v2/xurls.go | 4 ++-- 9 files changed, 40 insertions(+), 27 deletions(-) diff --git a/go.mod b/go.mod index 328680c13f..0d600e3e77 100644 --- a/go.mod +++ b/go.mod @@ -117,7 +117,7 @@ require ( gopkg.in/ini.v1 v1.61.0 gopkg.in/ldap.v3 v3.0.2 gopkg.in/yaml.v2 v2.3.0 - mvdan.cc/xurls/v2 v2.1.0 + mvdan.cc/xurls/v2 v2.2.0 strk.kbt.io/projects/go/libravatar v0.0.0-20191008002943-06d1c002b251 xorm.io/builder v0.3.7 xorm.io/xorm v1.0.5 diff --git a/go.sum b/go.sum index a86a370711..bfe56cde80 100644 --- a/go.sum +++ b/go.sum @@ -768,6 +768,7 @@ github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6So github.com/rogpeppe/go-internal v1.1.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.2.2/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/rogpeppe/go-internal v1.5.2/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= github.com/rs/xid v1.2.1 h1:mhH9Nq+C1fY2l1XIpgxIiUOfNpRBYH1kKcr+qfKgjRc= github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ= github.com/rs/zerolog v1.13.0/go.mod h1:YbFCdg8HfsridGWAh22vktObvhZbQsZXe4/zB0OKkWU= @@ -1196,8 +1197,7 @@ honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWh honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= -mvdan.cc/xurls/v2 v2.1.0 h1:KaMb5GLhlcSX+e+qhbRJODnUUBvlw01jt4yrjFIHAuA= -mvdan.cc/xurls/v2 v2.1.0/go.mod h1:5GrSd9rOnKOpZaji1OZLYL/yeAAtGDlo/cFe+8K5n8E= +mvdan.cc/xurls/v2 v2.2.0/go.mod h1:EV1RMtya9D6G5DMYPGD8zTQzaHet6Jh8gFlRgGRJeO8= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= strk.kbt.io/projects/go/libravatar v0.0.0-20191008002943-06d1c002b251 h1:mUcz5b3FJbP5Cvdq7Khzn6J9OCUQJaBwgBkCR+MOwSs= strk.kbt.io/projects/go/libravatar v0.0.0-20191008002943-06d1c002b251/go.mod h1:FJGmPh3vz9jSos1L/F91iAgnC/aejc0wIIrF2ZwJxdY= diff --git a/vendor/modules.txt b/vendor/modules.txt index 587d7c344a..44315b1744 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -954,7 +954,7 @@ gopkg.in/warnings.v0 gopkg.in/yaml.v2 # gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776 gopkg.in/yaml.v3 -# mvdan.cc/xurls/v2 v2.1.0 +# mvdan.cc/xurls/v2 v2.2.0 ## explicit mvdan.cc/xurls/v2 # strk.kbt.io/projects/go/libravatar v0.0.0-20191008002943-06d1c002b251 diff --git a/vendor/mvdan.cc/xurls/v2/README.md b/vendor/mvdan.cc/xurls/v2/README.md index 07fbdb3b25..5035ced138 100644 --- a/vendor/mvdan.cc/xurls/v2/README.md +++ b/vendor/mvdan.cc/xurls/v2/README.md @@ -2,7 +2,7 @@ [![GoDoc](https://godoc.org/mvdan.cc/xurls?status.svg)](https://godoc.org/mvdan.cc/xurls) -Extract urls from text using regular expressions. Requires Go 1.12 or later. +Extract urls from text using regular expressions. Requires Go 1.13 or later. ```go import "mvdan.cc/xurls/v2" @@ -18,13 +18,18 @@ func main() { } ``` -Note that the funcs compile regexes, so avoid calling them repeatedly. +Since API is centered around [regexp.Regexp](https://golang.org/pkg/regexp/#Regexp), +many other methods are available, such as finding the [byte indexes](https://golang.org/pkg/regexp/#Regexp.FindAllIndex) +for all matches. + +Note that calling the exposed functions means compiling a regular expression, so +repeated calls should be avoided. #### cmd/xurls To install the tool globally: - go get mvdan.cc/xurls/cmd/xurls + cd $(mktemp -d); go mod init tmp; GO111MODULE=on go get mvdan.cc/xurls/v2/cmd/xurls ```shell $ echo "Do gophers live in http://golang.org?" | xurls diff --git a/vendor/mvdan.cc/xurls/v2/go.mod b/vendor/mvdan.cc/xurls/v2/go.mod index d9d334543c..593ffd508b 100644 --- a/vendor/mvdan.cc/xurls/v2/go.mod +++ b/vendor/mvdan.cc/xurls/v2/go.mod @@ -1,3 +1,8 @@ module mvdan.cc/xurls/v2 -go 1.13 +go 1.14 + +require ( + github.com/rogpeppe/go-internal v1.5.2 + gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 // indirect +) diff --git a/vendor/mvdan.cc/xurls/v2/go.sum b/vendor/mvdan.cc/xurls/v2/go.sum index e69de29bb2..f1ca78e8c3 100644 --- a/vendor/mvdan.cc/xurls/v2/go.sum +++ b/vendor/mvdan.cc/xurls/v2/go.sum @@ -0,0 +1,12 @@ +github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/rogpeppe/go-internal v1.5.2 h1:qLvObTrvO/XRCqmkKxUlOBc48bI3efyDuAZe25QiF0w= +github.com/rogpeppe/go-internal v1.5.2/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/errgo.v2 v2.1.0 h1:0vLT13EuvQ0hNvakwLuFZ/jYrLp5F3kcWHXdRggjCE8= +gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= diff --git a/vendor/mvdan.cc/xurls/v2/schemes.go b/vendor/mvdan.cc/xurls/v2/schemes.go index e8e6585f47..8fae334175 100644 --- a/vendor/mvdan.cc/xurls/v2/schemes.go +++ b/vendor/mvdan.cc/xurls/v2/schemes.go @@ -66,6 +66,7 @@ var Schemes = []string{ `dpp`, `drm`, `drop`, + `dtmi`, `dtn`, `dvb`, `ed2k`, @@ -226,6 +227,7 @@ var Schemes = []string{ `pack`, `palm`, `paparazzi`, + `payment`, `payto`, `pkcs11`, `platform`, @@ -238,6 +240,7 @@ var Schemes = []string{ `pttp`, `qb`, `query`, + `quic-transport`, `redis`, `rediss`, `reload`, diff --git a/vendor/mvdan.cc/xurls/v2/tlds.go b/vendor/mvdan.cc/xurls/v2/tlds.go index c98ce508d6..2daa29e896 100644 --- a/vendor/mvdan.cc/xurls/v2/tlds.go +++ b/vendor/mvdan.cc/xurls/v2/tlds.go @@ -57,6 +57,7 @@ var TLDs = []string{ `alsace`, `alstom`, `am`, + `amazon`, `americanexpress`, `americanfamily`, `amex`, @@ -219,7 +220,6 @@ var TLDs = []string{ `career`, `careers`, `cars`, - `cartier`, `casa`, `case`, `caseih`, @@ -252,7 +252,6 @@ var TLDs = []string{ `chintai`, `christmas`, `chrome`, - `chrysler`, `church`, `ci`, `cipriani`, @@ -366,7 +365,6 @@ var TLDs = []string{ `do`, `docs`, `doctor`, - `dodge`, `dog`, `domains`, `dot`, @@ -411,7 +409,6 @@ var TLDs = []string{ `eurovision`, `eus`, `events`, - `everbank`, `exchange`, `expert`, `exposed`, @@ -701,12 +698,10 @@ var TLDs = []string{ `kz`, `la`, `lacaixa`, - `ladbrokes`, `lamborghini`, `lamer`, `lancaster`, `lancia`, - `lancome`, `land`, `landrover`, `lanxess`, @@ -727,7 +722,6 @@ var TLDs = []string{ `lexus`, `lgbt`, `li`, - `liaison`, `lidl`, `life`, `lifeinsurance`, @@ -829,7 +823,6 @@ var TLDs = []string{ `monash`, `money`, `monster`, - `mopar`, `mormon`, `mortgage`, `moscow`, @@ -837,7 +830,6 @@ var TLDs = []string{ `motorcycles`, `mov`, `movie`, - `movistar`, `mp`, `mq`, `mr`, @@ -856,7 +848,6 @@ var TLDs = []string{ `mz`, `na`, `nab`, - `nadex`, `nagoya`, `name`, `nationwide`, @@ -958,7 +949,6 @@ var TLDs = []string{ `photography`, `photos`, `physio`, - `piaget`, `pics`, `pictet`, `pictures`, @@ -1154,13 +1144,13 @@ var TLDs = []string{ `song`, `sony`, `soy`, + `spa`, `space`, `sport`, `spot`, `spreadbetting`, `sr`, `srl`, - `srt`, `ss`, `st`, `stada`, @@ -1213,7 +1203,6 @@ var TLDs = []string{ `tech`, `technology`, `tel`, - `telefonica`, `temasek`, `tennis`, `teva`, @@ -1273,7 +1262,6 @@ var TLDs = []string{ `ua`, `ubank`, `ubs`, - `uconnect`, `ug`, `uk`, `unicom`, @@ -1309,7 +1297,6 @@ var TLDs = []string{ `virgin`, `visa`, `vision`, - `vistaprint`, `viva`, `vivo`, `vlaanderen`, @@ -1328,7 +1315,6 @@ var TLDs = []string{ `walter`, `wang`, `wanggou`, - `warman`, `watch`, `watches`, `weather`, @@ -1388,6 +1374,7 @@ var TLDs = []string{ `zuerich`, `zw`, `ελ`, + `ευ`, `бг`, `бел`, `дети`, @@ -1469,6 +1456,7 @@ var TLDs = []string{ `ไทย`, `გე`, `みんな`, + `アマゾン`, `クラウド`, `グーグル`, `コム`, @@ -1481,6 +1469,7 @@ var TLDs = []string{ `中国`, `中國`, `中文网`, + `亚马逊`, `企业`, `佛山`, `信息`, @@ -1501,7 +1490,6 @@ var TLDs = []string{ `天主教`, `娱乐`, `家電`, - `工行`, `广东`, `微博`, `慈善`, diff --git a/vendor/mvdan.cc/xurls/v2/xurls.go b/vendor/mvdan.cc/xurls/v2/xurls.go index 7244c709a0..d4462535da 100644 --- a/vendor/mvdan.cc/xurls/v2/xurls.go +++ b/vendor/mvdan.cc/xurls/v2/xurls.go @@ -19,7 +19,7 @@ const ( iriChar = letter + mark + number currency = `\p{Sc}` otherSymb = `\p{So}` - endChar = iriChar + `/\-+&~%=#` + currency + otherSymb + endChar = iriChar + `/\-_+&~%=#` + currency + otherSymb otherPunc = `\p{Po}` midChar = endChar + "_*" + otherPunc wellParen = `\([` + midChar + `]*(\([` + midChar + `]*\)[` + midChar + `]*)*\)` @@ -76,7 +76,7 @@ func relaxedExp() string { knownTLDs := anyOf(append(TLDs, PseudoTLDs...)...) site := domain + `(?i)(` + punycode + `|` + knownTLDs + `)(?-i)` hostName := `(` + site + `|` + ipAddr + `)` - webURL := hostName + port + `(/|/` + pathCont + `?|\b|(?m)$)` + webURL := hostName + port + `(/|/` + pathCont + `)?` return strictExp() + `|` + webURL } From 6086a9061b434e8f32a468826c5a03f96c171002 Mon Sep 17 00:00:00 2001 From: Wim Date: Wed, 4 Nov 2020 15:51:07 +0100 Subject: [PATCH 043/205] Add missing full names when DEFAULT_SHOW_FULL_NAME is enabled (#13424) --- templates/repo/issue/list.tmpl | 2 +- templates/repo/issue/milestone_issues.tmpl | 2 +- templates/repo/issue/view_content/pull.tmpl | 2 +- templates/repo/release/list.tmpl | 2 +- templates/repo/settings/protected_branch.tmpl | 6 +++--- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/templates/repo/issue/list.tmpl b/templates/repo/issue/list.tmpl index 49f9db13bf..881e774876 100644 --- a/templates/repo/issue/list.tmpl +++ b/templates/repo/issue/list.tmpl @@ -264,7 +264,7 @@ {{end}} {{range .Assignees}} - + {{end}} diff --git a/templates/repo/issue/milestone_issues.tmpl b/templates/repo/issue/milestone_issues.tmpl index af17fde641..2e00d12279 100644 --- a/templates/repo/issue/milestone_issues.tmpl +++ b/templates/repo/issue/milestone_issues.tmpl @@ -262,7 +262,7 @@ {{.DeadlineUnix.FormatShort}} {{end}} {{range .Assignees}} - + {{end}} diff --git a/templates/repo/issue/view_content/pull.tmpl b/templates/repo/issue/view_content/pull.tmpl index a67783ebb1..238bf099a1 100644 --- a/templates/repo/issue/view_content/pull.tmpl +++ b/templates/repo/issue/view_content/pull.tmpl @@ -15,7 +15,7 @@ {{end}} {{if .User}} - {{.User.Name}} + {{.User.GetDisplayName}} {{else if .Team}} {{$.Issue.Repo.OwnerName}}/{{.Team.Name}} {{end}} diff --git a/templates/repo/release/list.tmpl b/templates/repo/release/list.tmpl index bba6f91e7b..a4cef9381e 100644 --- a/templates/repo/release/list.tmpl +++ b/templates/repo/release/list.tmpl @@ -59,7 +59,7 @@ {{.OriginalAuthor}} {{else if .Publisher}} - {{.Publisher.Name}} + {{.Publisher.GetDisplayName}} {{else}} Ghost {{end}} diff --git a/templates/repo/settings/protected_branch.tmpl b/templates/repo/settings/protected_branch.tmpl index 57ffc74886..53a978e068 100644 --- a/templates/repo/settings/protected_branch.tmpl +++ b/templates/repo/settings/protected_branch.tmpl @@ -49,7 +49,7 @@ {{range .Users}}
- {{.Name}} + {{.GetDisplayName}}
{{end}}
@@ -99,7 +99,7 @@ {{range .Users}}
- {{.Name}} + {{.GetDisplayName}}
{{end}}
@@ -179,7 +179,7 @@ {{range .Users}}
- {{.Name}} + {{.GetDisplayName}}
{{end}}
From 3421e4b756f7491ab4490a76c4a8239896680eea Mon Sep 17 00:00:00 2001 From: mrsdizzie Date: Thu, 5 Nov 2020 11:54:03 -0500 Subject: [PATCH 044/205] Alternative fix for HTML diff entity split (#13425) (#13427) * Alternative fix for HTML diff entity split This commit both reverts PR #13357 and uses the exiting implementation alredy used for spans to fix the same issue. That PR duplicates most of logic that is already present elsewhere and still was failing for some cases. This should be simpler as it uses the existing logic that already works for s being split apart. Added both test cases as well. * Update gitdiff_test.go * fmt * entity can have uppercase letter, also add detailed comment per @zeripath --- services/gitdiff/gitdiff.go | 114 ++++++++----------------------- services/gitdiff/gitdiff_test.go | 45 ++++-------- 2 files changed, 45 insertions(+), 114 deletions(-) diff --git a/services/gitdiff/gitdiff.go b/services/gitdiff/gitdiff.go index 50e2f8cf1e..4f223fdc03 100644 --- a/services/gitdiff/gitdiff.go +++ b/services/gitdiff/gitdiff.go @@ -182,6 +182,7 @@ var ( codeTagSuffix = []byte(``) ) var trailingSpanRegex = regexp.MustCompile(`]?$`) +var entityRegex = regexp.MustCompile(`&[#]*?[0-9[:alpha:]]*$`) // shouldWriteInline represents combinations where we manually write inline changes func shouldWriteInline(diff diffmatchpatch.Diff, lineType DiffLineType) bool { @@ -205,14 +206,40 @@ func diffToHTML(fileName string, diffs []diffmatchpatch.Diff, lineType DiffLineT match = "" } // Chroma HTML syntax highlighting is done before diffing individual lines in order to maintain consistency. - // Since inline changes might split in the middle of a chroma span tag, make we manually put it back together - // before writing so we don't try insert added/removed code spans in the middle of an existing chroma span - // and create broken HTML. + // Since inline changes might split in the middle of a chroma span tag or HTML entity, make we manually put it back together + // before writing so we don't try insert added/removed code spans in the middle of one of those + // and create broken HTML. This is done by moving incomplete HTML forward until it no longer matches our pattern of + // a line ending with an incomplete HTML entity or partial/opening . + + // EX: + // diffs[{Type: dmp.DiffDelete, Text: "language}] + + // After first iteration + // diffs[{Type: dmp.DiffDelete, Text: "language"}, //write out + // {Type: dmp.DiffEqual, Text: ",}] + + // After second iteration + // {Type: dmp.DiffEqual, Text: ""}, // write out + // {Type: dmp.DiffDelete, Text: ",}] + + // Final + // {Type: dmp.DiffDelete, Text: ",}] + // end up writing , + // Instead of lass="p", + m := trailingSpanRegex.FindStringSubmatchIndex(diff.Text) if m != nil { match = diff.Text[m[0]:m[1]] diff.Text = strings.TrimSuffix(diff.Text, match) } + m = entityRegex.FindStringSubmatchIndex(diff.Text) + if m != nil { + match = diff.Text[m[0]:m[1]] + diff.Text = strings.TrimSuffix(diff.Text, match) + } // Print an existing closing span first before opening added/remove-code span so it doesn't unintentionally close it if strings.HasPrefix(diff.Text, "") { buf.WriteString("") @@ -290,9 +317,6 @@ func init() { diffMatchPatch.DiffEditCost = 100 } -var unterminatedEntityRE = regexp.MustCompile(`&[^ ;]*$`) -var unstartedEntiyRE = regexp.MustCompile(`^[^ ;]*;`) - // GetComputedInlineDiffFor computes inline diff for the given line. func (diffSection *DiffSection) GetComputedInlineDiffFor(diffLine *DiffLine) template.HTML { if setting.Git.DisableDiffHighlight { @@ -333,89 +357,11 @@ func (diffSection *DiffSection) GetComputedInlineDiffFor(diffLine *DiffLine) tem diffRecord := diffMatchPatch.DiffMain(highlight.Code(diffSection.FileName, diff1[1:]), highlight.Code(diffSection.FileName, diff2[1:]), true) diffRecord = diffMatchPatch.DiffCleanupEfficiency(diffRecord) - // Now we need to clean up the split entities - diffRecord = unsplitEntities(diffRecord) diffRecord = diffMatchPatch.DiffCleanupEfficiency(diffRecord) return diffToHTML(diffSection.FileName, diffRecord, diffLine.Type) } -// unsplitEntities looks for broken up html entities. It relies on records being presimplified and the data being passed in being valid html -func unsplitEntities(records []diffmatchpatch.Diff) []diffmatchpatch.Diff { - // Unsplitting entities is simple... - // - // Iterate through all be the last records because if we're the last record then there's nothing we can do - for i := 0; i+1 < len(records); i++ { - record := &records[i] - - // Look for an unterminated entity at the end of the line - unterminated := unterminatedEntityRE.FindString(record.Text) - if len(unterminated) == 0 { - continue - } - - switch record.Type { - case diffmatchpatch.DiffEqual: - // If we're an diff equal we want to give this unterminated entity to our next delete and insert - record.Text = record.Text[0 : len(record.Text)-len(unterminated)] - records[i+1].Text = unterminated + records[i+1].Text - - nextType := records[i+1].Type - - if nextType == diffmatchpatch.DiffEqual { - continue - } - - // if the next in line is a delete then we will want the thing after that to be an insert and so on. - oneAfterType := diffmatchpatch.DiffInsert - if nextType == diffmatchpatch.DiffInsert { - oneAfterType = diffmatchpatch.DiffDelete - } - - if i+2 < len(records) && records[i+2].Type == oneAfterType { - records[i+2].Text = unterminated + records[i+2].Text - } else { - records = append(records[:i+2], append([]diffmatchpatch.Diff{ - { - Type: oneAfterType, - Text: unterminated, - }}, records[i+2:]...)...) - } - case diffmatchpatch.DiffDelete: - fallthrough - case diffmatchpatch.DiffInsert: - // if we're an insert or delete we want to claim the terminal bit of the entity from the next equal in line - targetType := diffmatchpatch.DiffInsert - if record.Type == diffmatchpatch.DiffInsert { - targetType = diffmatchpatch.DiffDelete - } - next := &records[i+1] - if next.Type == diffmatchpatch.DiffEqual { - // if the next is an equal we need to snaffle the entity end off the start and add an delete/insert - if terminal := unstartedEntiyRE.FindString(next.Text); len(terminal) > 0 { - record.Text += terminal - next.Text = next.Text[len(terminal):] - records = append(records[:i+2], append([]diffmatchpatch.Diff{ - { - Type: targetType, - Text: unterminated, - }}, records[i+2:]...)...) - } - } else if next.Type == targetType { - // if the next is an insert we need to snaffle the entity end off the one after that and add it to both. - if i+2 < len(records) && records[i+2].Type == diffmatchpatch.DiffEqual { - if terminal := unstartedEntiyRE.FindString(records[i+2].Text); len(terminal) > 0 { - record.Text += terminal - next.Text += terminal - records[i+2].Text = records[i+2].Text[len(terminal):] - } - } - } - } - } - return records -} - // DiffFile represents a file diff. type DiffFile struct { Name string diff --git a/services/gitdiff/gitdiff_test.go b/services/gitdiff/gitdiff_test.go index 0683997dab..6e3b5b0994 100644 --- a/services/gitdiff/gitdiff_test.go +++ b/services/gitdiff/gitdiff_test.go @@ -15,7 +15,6 @@ import ( "code.gitea.io/gitea/models" "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/setting" - "github.com/sergi/go-diff/diffmatchpatch" dmp "github.com/sergi/go-diff/diffmatchpatch" "github.com/stretchr/testify/assert" "gopkg.in/ini.v1" @@ -27,35 +26,6 @@ func assertEqual(t *testing.T, s1 string, s2 template.HTML) { } } -func TestUnsplitEntities(t *testing.T) { - left := "sh "useradd -u 111 jenkins"" - right := "sh 'useradd -u $(stat -c "%u" .gitignore) jenkins'" - diffRecord := diffMatchPatch.DiffMain(left, right, true) - diffRecord = diffMatchPatch.DiffCleanupEfficiency(diffRecord) - - // Now we need to clean up the split entities - diffRecord = unsplitEntities(diffRecord) - diffRecord = diffMatchPatch.DiffCleanupEfficiency(diffRecord) - - leftRecombined := "" - rightRecombined := "" - for _, record := range diffRecord { - assert.False(t, unterminatedEntityRE.MatchString(record.Text), "") - switch record.Type { - case diffmatchpatch.DiffDelete: - leftRecombined += record.Text - case diffmatchpatch.DiffInsert: - rightRecombined += record.Text - default: - leftRecombined += record.Text - rightRecombined += record.Text - } - } - - assert.EqualValues(t, left, leftRecombined) - assert.EqualValues(t, right, rightRecombined) -} - func TestDiffToHTML(t *testing.T) { setting.Cfg = ini.Empty() assertEqual(t, "foo bar biz", diffToHTML("", []dmp.Diff{ @@ -113,6 +83,21 @@ func TestDiffToHTML(t *testing.T) { {Type: dmp.DiffEqual, Text: ""// ", sys.argv"}, {Type: dmp.DiffInsert, Text: ")"}, }, DiffLineAdd)) + + assertEqual(t, "sh 'useradd -u $(stat -c "%u" .gitignore) jenkins'", diffToHTML("", []dmp.Diff{ + {Type: dmp.DiffEqual, Text: "sh "}, + {Type: dmp.DiffDelete, Text: "4;useradd -u 111 jenkins""}, + {Type: dmp.DiffInsert, Text: "9;useradd -u $(stat -c "%u" .gitignore) jenkins'"}, + {Type: dmp.DiffEqual, Text: ";"}, + }, DiffLineAdd)) + + assertEqual(t, " <h4 class="release-list-title df ac">", diffToHTML("", []dmp.Diff{ + {Type: dmp.DiffEqual, Text: " <h"}, + {Type: dmp.DiffInsert, Text: "4 class=&#"}, + {Type: dmp.DiffEqual, Text: "3"}, + {Type: dmp.DiffInsert, Text: "4;release-list-title df ac""}, + {Type: dmp.DiffEqual, Text: ">"}, + }, DiffLineAdd)) } func TestParsePatch_singlefile(t *testing.T) { From 9aa580ce0e8791ddfcc1548c6a5ca516213bf785 Mon Sep 17 00:00:00 2001 From: 6543 <6543@obermui.de> Date: Thu, 5 Nov 2020 21:14:55 +0100 Subject: [PATCH 045/205] Replies to outdated code comments should also be outdated (#13217) (#13433) * When replying to an outdated comment it should not appear on the files page This happened because the comment took the latest commitID as its base instead of the reviewID that it was replying to. There was also no way of creating an already outdated comment - and a reply to a review on an outdated line should be outdated. Signed-off-by: Andrew Thornton * fix test Signed-off-by: Andrew Thornton Co-authored-by: techknowlogick Co-authored-by: zeripath Co-authored-by: techknowlogick --- models/issue_comment.go | 12 ++++++ services/pull/review.go | 83 +++++++++++++++++++++++++++++------------ 2 files changed, 71 insertions(+), 24 deletions(-) diff --git a/models/issue_comment.go b/models/issue_comment.go index a5b6588fa9..73cbb0566f 100644 --- a/models/issue_comment.go +++ b/models/issue_comment.go @@ -725,6 +725,7 @@ func createComment(e *xorm.Session, opts *CreateCommentOptions) (_ *Comment, err RefAction: opts.RefAction, RefIsPull: opts.RefIsPull, IsForcePush: opts.IsForcePush, + Invalidated: opts.Invalidated, } if _, err = e.Insert(comment); err != nil { return nil, err @@ -891,6 +892,7 @@ type CreateCommentOptions struct { RefAction references.XRefAction RefIsPull bool IsForcePush bool + Invalidated bool } // CreateComment creates comment of issue or commit. @@ -966,6 +968,8 @@ type FindCommentsOptions struct { ReviewID int64 Since int64 Before int64 + Line int64 + TreePath string Type CommentType } @@ -989,6 +993,12 @@ func (opts *FindCommentsOptions) toConds() builder.Cond { if opts.Type != CommentTypeUnknown { cond = cond.And(builder.Eq{"comment.type": opts.Type}) } + if opts.Line > 0 { + cond = cond.And(builder.Eq{"comment.line": opts.Line}) + } + if len(opts.TreePath) > 0 { + cond = cond.And(builder.Eq{"comment.tree_path": opts.TreePath}) + } return cond } @@ -1003,6 +1013,8 @@ func findComments(e Engine, opts FindCommentsOptions) ([]*Comment, error) { sess = opts.setSessionPagination(sess) } + // WARNING: If you change this order you will need to fix createCodeComment + return comments, sess. Asc("comment.created_unix"). Asc("comment.id"). diff --git a/services/pull/review.go b/services/pull/review.go index 99afdd73c2..f0ee234a42 100644 --- a/services/pull/review.go +++ b/services/pull/review.go @@ -122,41 +122,76 @@ func createCodeComment(doer *models.User, repo *models.Repository, issue *models } defer gitRepo.Close() - // FIXME validate treePath - // Get latest commit referencing the commented line - // No need for get commit for base branch changes + invalidated := false + head := pr.GetGitRefName() if line > 0 { - commit, err := gitRepo.LineBlame(pr.GetGitRefName(), gitRepo.Path, treePath, uint(line)) - if err == nil { - commitID = commit.ID.String() - } else if !(strings.Contains(err.Error(), "exit status 128 - fatal: no such path") || notEnoughLines.MatchString(err.Error())) { - return nil, fmt.Errorf("LineBlame[%s, %s, %s, %d]: %v", pr.GetGitRefName(), gitRepo.Path, treePath, line, err) + if reviewID != 0 { + first, err := models.FindComments(models.FindCommentsOptions{ + ReviewID: reviewID, + Line: line, + TreePath: treePath, + Type: models.CommentTypeCode, + ListOptions: models.ListOptions{ + PageSize: 1, + Page: 1, + }, + }) + if err == nil && len(first) > 0 { + commitID = first[0].CommitSHA + invalidated = first[0].Invalidated + patch = first[0].Patch + } else if err != nil && !models.IsErrCommentNotExist(err) { + return nil, fmt.Errorf("Find first comment for %d line %d path %s. Error: %v", reviewID, line, treePath, err) + } else { + review, err := models.GetReviewByID(reviewID) + if err == nil && len(review.CommitID) > 0 { + head = review.CommitID + } else if err != nil && !models.IsErrReviewNotExist(err) { + return nil, fmt.Errorf("GetReviewByID %d. Error: %v", reviewID, err) + } + } + } + + if len(commitID) == 0 { + // FIXME validate treePath + // Get latest commit referencing the commented line + // No need for get commit for base branch changes + commit, err := gitRepo.LineBlame(head, gitRepo.Path, treePath, uint(line)) + if err == nil { + commitID = commit.ID.String() + } else if !(strings.Contains(err.Error(), "exit status 128 - fatal: no such path") || notEnoughLines.MatchString(err.Error())) { + return nil, fmt.Errorf("LineBlame[%s, %s, %s, %d]: %v", pr.GetGitRefName(), gitRepo.Path, treePath, line, err) + } } } // Only fetch diff if comment is review comment - if reviewID != 0 { - headCommitID, err := gitRepo.GetRefCommitID(pr.GetGitRefName()) - if err != nil { - return nil, fmt.Errorf("GetRefCommitID[%s]: %v", pr.GetGitRefName(), err) + if len(patch) == 0 && reviewID != 0 { + if len(commitID) == 0 { + commitID, err = gitRepo.GetRefCommitID(pr.GetGitRefName()) + if err != nil { + return nil, fmt.Errorf("GetRefCommitID[%s]: %v", pr.GetGitRefName(), err) + } } + patchBuf := new(bytes.Buffer) - if err := git.GetRepoRawDiffForFile(gitRepo, pr.MergeBase, headCommitID, git.RawDiffNormal, treePath, patchBuf); err != nil { - return nil, fmt.Errorf("GetRawDiffForLine[%s, %s, %s, %s]: %v", err, gitRepo.Path, pr.MergeBase, headCommitID, treePath) + if err := git.GetRepoRawDiffForFile(gitRepo, pr.MergeBase, commitID, git.RawDiffNormal, treePath, patchBuf); err != nil { + return nil, fmt.Errorf("GetRawDiffForLine[%s, %s, %s, %s]: %v", gitRepo.Path, pr.MergeBase, commitID, treePath, err) } patch = git.CutDiffAroundLine(patchBuf, int64((&models.Comment{Line: line}).UnsignedLine()), line < 0, setting.UI.CodeCommentLines) } return models.CreateComment(&models.CreateCommentOptions{ - Type: models.CommentTypeCode, - Doer: doer, - Repo: repo, - Issue: issue, - Content: content, - LineNum: line, - TreePath: treePath, - CommitSHA: commitID, - ReviewID: reviewID, - Patch: patch, + Type: models.CommentTypeCode, + Doer: doer, + Repo: repo, + Issue: issue, + Content: content, + LineNum: line, + TreePath: treePath, + CommitSHA: commitID, + ReviewID: reviewID, + Patch: patch, + Invalidated: invalidated, }) } From 1e446bb1764216fde391cef7304ed06e2c27ec09 Mon Sep 17 00:00:00 2001 From: techknowlogick Date: Fri, 6 Nov 2020 15:42:56 -0500 Subject: [PATCH 046/205] use registry mirror for docker-in-docker (#13438) (#13445) Co-authored-by: Lauris BH Co-authored-by: Lauris BH --- .drone.yml | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/.drone.yml b/.drone.yml index 872dcf750d..a346520041 100644 --- a/.drone.yml +++ b/.drone.yml @@ -666,7 +666,6 @@ steps: event: exclude: - pull_request - --- kind: pipeline name: docker-linux-arm64-dry-run @@ -696,6 +695,9 @@ steps: tags: linux-arm64 build_args: - GOPROXY=off + environment: + PLUGIN_MIRROR: + from_secret: plugin_mirror when: event: - pull_request @@ -740,11 +742,13 @@ steps: from_secret: docker_password username: from_secret: docker_username + environment: + PLUGIN_MIRROR: + from_secret: plugin_mirror when: event: exclude: - pull_request - --- kind: pipeline name: docker-manifest From ae4955999ec012ff0edab2e9c8ca196449881ab3 Mon Sep 17 00:00:00 2001 From: 6543 <6543@obermui.de> Date: Tue, 10 Nov 2020 03:16:34 +0100 Subject: [PATCH 047/205] Fix panic bug in handling multiple references in commit (#13486) (#13487) * Fix panic bug in handling multiple references in commit (#13486) The issue lay in determining the position of matches on a second run round a commit message in FindAllIssueReferences. Fix #13483 Signed-off-by: Andrew Thornton * CI.restart() Co-authored-by: Andrew Thornton --- modules/references/references.go | 96 +++++++++++++++++++-------- modules/references/references_test.go | 28 ++++++++ 2 files changed, 95 insertions(+), 29 deletions(-) diff --git a/modules/references/references.go b/modules/references/references.go index 070c6e566a..6e0baefc6e 100644 --- a/modules/references/references.go +++ b/modules/references/references.go @@ -235,40 +235,78 @@ func findAllIssueReferencesMarkdown(content string) []*rawReference { return findAllIssueReferencesBytes(bcontent, links) } +func convertFullHTMLReferencesToShortRefs(re *regexp.Regexp, contentBytes *[]byte) { + // We will iterate through the content, rewrite and simplify full references. + // + // We want to transform something like: + // + // this is a https://ourgitea.com/git/owner/repo/issues/123456789, foo + // https://ourgitea.com/git/owner/repo/pulls/123456789 + // + // Into something like: + // + // this is a #123456789, foo + // !123456789 + + pos := 0 + for { + // re looks for something like: (\s|^|\(|\[)https://ourgitea.com/git/(owner/repo)/(issues)/(123456789)(?:\s|$|\)|\]|[:;,.?!]\s|[:;,.?!]$) + match := re.FindSubmatchIndex((*contentBytes)[pos:]) + if match == nil { + break + } + // match is a bunch of indices into the content from pos onwards so + // to simplify things let's just add pos to all of the indices in match + for i := range match { + match[i] += pos + } + + // match[0]-match[1] is whole string + // match[2]-match[3] is preamble + + // move the position to the end of the preamble + pos = match[3] + + // match[4]-match[5] is owner/repo + // now copy the owner/repo to end of the preamble + endPos := pos + match[5] - match[4] + copy((*contentBytes)[pos:endPos], (*contentBytes)[match[4]:match[5]]) + + // move the current position to the end of the newly copied owner/repo + pos = endPos + + // Now set the issue/pull marker: + // + // match[6]-match[7] == 'issues' + (*contentBytes)[pos] = '#' + if string((*contentBytes)[match[6]:match[7]]) == "pulls" { + (*contentBytes)[pos] = '!' + } + pos++ + + // Then add the issue/pull number + // + // match[8]-match[9] is the number + endPos = pos + match[9] - match[8] + copy((*contentBytes)[pos:endPos], (*contentBytes)[match[8]:match[9]]) + + // Now copy what's left at the end of the string to the new end position + copy((*contentBytes)[endPos:], (*contentBytes)[match[9]:]) + // now we reset the length + + // our new section has length endPos - match[3] + // our old section has length match[9] - match[3] + (*contentBytes) = (*contentBytes)[:len((*contentBytes))-match[9]+endPos] + pos = endPos + } +} + // FindAllIssueReferences returns a list of unvalidated references found in a string. func FindAllIssueReferences(content string) []IssueReference { // Need to convert fully qualified html references to local system to #/! short codes contentBytes := []byte(content) if re := getGiteaIssuePullPattern(); re != nil { - pos := 0 - for { - match := re.FindSubmatchIndex(contentBytes[pos:]) - if match == nil { - break - } - // match[0]-match[1] is whole string - // match[2]-match[3] is preamble - pos += match[3] - // match[4]-match[5] is owner/repo - endPos := pos + match[5] - match[4] - copy(contentBytes[pos:endPos], contentBytes[match[4]:match[5]]) - pos = endPos - // match[6]-match[7] == 'issues' - contentBytes[pos] = '#' - if string(contentBytes[match[6]:match[7]]) == "pulls" { - contentBytes[pos] = '!' - } - pos++ - // match[8]-match[9] is the number - endPos = pos + match[9] - match[8] - copy(contentBytes[pos:endPos], contentBytes[match[8]:match[9]]) - copy(contentBytes[endPos:], contentBytes[match[9]:]) - // now we reset the length - // our new section has length endPos - match[3] - // our old section has length match[9] - match[3] - contentBytes = contentBytes[:len(contentBytes)-match[9]+endPos] - pos = endPos - } + convertFullHTMLReferencesToShortRefs(re, &contentBytes) } else { log.Debug("No GiteaIssuePullPattern pattern") } diff --git a/modules/references/references_test.go b/modules/references/references_test.go index 0c4037f120..f51379e4c3 100644 --- a/modules/references/references_test.go +++ b/modules/references/references_test.go @@ -5,6 +5,7 @@ package references import ( + "regexp" "testing" "code.gitea.io/gitea/modules/setting" @@ -29,6 +30,26 @@ type testResult struct { TimeLog string } +func TestConvertFullHTMLReferencesToShortRefs(t *testing.T) { + re := regexp.MustCompile(`(\s|^|\(|\[)` + + regexp.QuoteMeta("https://ourgitea.com/git/") + + `([0-9a-zA-Z-_\.]+/[0-9a-zA-Z-_\.]+)/` + + `((?:issues)|(?:pulls))/([0-9]+)(?:\s|$|\)|\]|[:;,.?!]\s|[:;,.?!]$)`) + test := `this is a https://ourgitea.com/git/owner/repo/issues/123456789, foo +https://ourgitea.com/git/owner/repo/pulls/123456789 + And https://ourgitea.com/git/owner/repo/pulls/123 +` + expect := `this is a owner/repo#123456789, foo +owner/repo!123456789 + And owner/repo!123 +` + + contentBytes := []byte(test) + convertFullHTMLReferencesToShortRefs(re, &contentBytes) + result := string(contentBytes) + assert.EqualValues(t, expect, result) +} + func TestFindAllIssueReferences(t *testing.T) { fixtures := []testFixture{ @@ -106,6 +127,13 @@ func TestFindAllIssueReferences(t *testing.T) { {202, "user4", "repo5", "202", true, XRefActionNone, nil, nil, ""}, }, }, + { + "This http://gitea.com:3000/user4/repo5/pulls/202 yes. http://gitea.com:3000/user4/repo5/pulls/203 no", + []testResult{ + {202, "user4", "repo5", "202", true, XRefActionNone, nil, nil, ""}, + {203, "user4", "repo5", "203", true, XRefActionNone, nil, nil, ""}, + }, + }, { "This http://GiTeA.COM:3000/user4/repo6/pulls/205 yes.", []testResult{ From 797cb38a4a6e702f959dceeb35d8503133879892 Mon Sep 17 00:00:00 2001 From: 6543 <6543@obermui.de> Date: Tue, 10 Nov 2020 03:55:48 +0100 Subject: [PATCH 048/205] 2nd attempt at re-request APIMergePullRequest (#13468) (#13490) Signed-off-by: Andrew Thornton Co-authored-by: zeripath --- integrations/api_helper_for_declarative_test.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/integrations/api_helper_for_declarative_test.go b/integrations/api_helper_for_declarative_test.go index b0031ef332..b8e513958e 100644 --- a/integrations/api_helper_for_declarative_test.go +++ b/integrations/api_helper_for_declarative_test.go @@ -235,6 +235,10 @@ func doAPIMergePullRequest(ctx APITestContext, owner, repo string, index int64) DecodeJSON(t, resp, &err) assert.EqualValues(t, "Please try again later", err.Message) queue.GetManager().FlushAll(context.Background(), 5*time.Second) + req = NewRequestWithJSON(t, http.MethodPost, urlStr, &auth.MergePullRequestForm{ + MergeMessageField: "doAPIMergePullRequest Merge", + Do: string(models.MergeStyleMerge), + }) resp = ctx.Session.MakeRequest(t, req, NoExpectedStatus) } From 8049de82f98274f5efeb9de3d50d9bc98869abbd Mon Sep 17 00:00:00 2001 From: 6543 <6543@obermui.de> Date: Tue, 10 Nov 2020 09:00:20 +0100 Subject: [PATCH 049/205] Prevent panic on git blame by limiting lines to 4096 bytes at most (#13491) Fix #12440 Closes #13192 Signed-off-by: Andrew Thornton Co-authored-by: Andrew Thornton --- modules/git/blame.go | 42 ++++++++++++++++++++++++++++++++---------- 1 file changed, 32 insertions(+), 10 deletions(-) diff --git a/modules/git/blame.go b/modules/git/blame.go index 9aa77dc65b..c2129c9e1c 100644 --- a/modules/git/blame.go +++ b/modules/git/blame.go @@ -27,7 +27,7 @@ type BlameReader struct { cmd *exec.Cmd pid int64 output io.ReadCloser - scanner *bufio.Scanner + reader *bufio.Reader lastSha *string cancel context.CancelFunc } @@ -38,23 +38,30 @@ var shaLineRegex = regexp.MustCompile("^([a-z0-9]{40})") func (r *BlameReader) NextPart() (*BlamePart, error) { var blamePart *BlamePart - scanner := r.scanner + reader := r.reader if r.lastSha != nil { blamePart = &BlamePart{*r.lastSha, make([]string, 0)} } - for scanner.Scan() { - line := scanner.Text() + var line []byte + var isPrefix bool + var err error + + for err != io.EOF { + line, isPrefix, err = reader.ReadLine() + if err != nil && err != io.EOF { + return blamePart, err + } - // Skip empty lines if len(line) == 0 { + // isPrefix will be false continue } - lines := shaLineRegex.FindStringSubmatch(line) + lines := shaLineRegex.FindSubmatch(line) if lines != nil { - sha1 := lines[1] + sha1 := string(lines[1]) if blamePart == nil { blamePart = &BlamePart{sha1, make([]string, 0)} @@ -62,12 +69,27 @@ func (r *BlameReader) NextPart() (*BlamePart, error) { if blamePart.Sha != sha1 { r.lastSha = &sha1 + // need to munch to end of line... + for isPrefix { + _, isPrefix, err = reader.ReadLine() + if err != nil && err != io.EOF { + return blamePart, err + } + } return blamePart, nil } } else if line[0] == '\t' { code := line[1:] - blamePart.Lines = append(blamePart.Lines, code) + blamePart.Lines = append(blamePart.Lines, string(code)) + } + + // need to munch to end of line... + for isPrefix { + _, isPrefix, err = reader.ReadLine() + if err != nil && err != io.EOF { + return blamePart, err + } } } @@ -121,13 +143,13 @@ func createBlameReader(ctx context.Context, dir string, command ...string) (*Bla pid := process.GetManager().Add(fmt.Sprintf("GetBlame [repo_path: %s]", dir), cancel) - scanner := bufio.NewScanner(stdout) + reader := bufio.NewReader(stdout) return &BlameReader{ cmd, pid, stdout, - scanner, + reader, nil, cancel, }, nil From 5a32224a2c6ba48ed4a4f428f8fe08d3cbf7c710 Mon Sep 17 00:00:00 2001 From: techknowlogick Date: Tue, 10 Nov 2020 16:09:05 -0500 Subject: [PATCH 050/205] 1.13.0-rc2 changelog (#13503) --- CHANGELOG.md | 34 +++++++++++++++++++++++++++++++++- 1 file changed, 33 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8ca56e323f..1bcd7ce344 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,7 +4,39 @@ This changelog goes through all the changes that have been made in each release without substantial changes to our git log; to see the highlights of what has been added to each release, please refer to the [blog](https://blog.gitea.io). -## [1.13.0-RC1](https://github.com/go-gitea/gitea/releases/tag/v1.13.0-rc1) - 2020-10-14 +## [1.13.0-rc2](https://github.com/go-gitea/gitea/releases/tag/v1.13.0-rc2) - 2020-11-10 +* ENHANCEMENTS + * Return the full rejection message and errors in flash errors (#13221) (#13237) + * Remove PAM from auth dropdown when unavailable (#13276) (#13281) +* BUGFIXES + * Fix Italian language file parsing error (#13156) + * Show outdated comments in pull request (#13148) (#13162) + * Fix parsing of pre-release git version (#13169) (#13172) + * Fix diff skipping lines (#13154) (#13155) + * When handling errors in storageHandler check underlying error (#13178) (#13193) + * Fix size and clickable area on file table back link (#13205) (#13207) + * Add better error checking for inline html diff code (#13251) + * Fix initial commit page & binary munching problem (#13249) (#13258) + * Fix migrations from remote Gitea instances when configuration not set (#13229) (#13273) + * Store task errors following migrations and display them (#13246) (#13287) + * Fix bug isEnd detection on getIssues/getPullRequests (#13299) (#13301) + * When the git ref is unable to be found return broken pr (#13218) (#13303) + * Ensure topics added using the API are added to the repository (#13285) (#13302) + * Fix avatar autogeneration (#13233) (#13282) + * Add migrated pulls to pull request task queue (#13331) (#13334) + * Issue comment reactions should also check pull type on API (#13349) (#13350) + * Fix links to repositories in /user/setting/repos (#13360) (#13362) + * Remove obsolete change of email on profile page (#13341) (#13347) + * Fix scrolling to resolved comment anchors (#13343) (#13371) + * Storage configuration support `[storage]` (#13314) (#13379) + * When creating line diffs do not split within an html entity (#13357) (#13375) (#13425) (#13427) + * Fix reactions on code comments (#13390) (#13401) + * Add missing full names when DEFAULT_SHOW_FULL_NAME is enabled (#13424) + * Replies to outdated code comments should also be outdated (#13217) (#13433) + * Fix panic bug in handling multiple references in commit (#13486) (#13487) + * Prevent panic on git blame by limiting lines to 4096 bytes at most (#13470) (#13491) + +## [1.13.0-rc1](https://github.com/go-gitea/gitea/releases/tag/v1.13.0-rc1) - 2020-10-14 * SECURITY * Mitigate Security vulnerability in the git hook feature (#13058) From 1f726568925e1b410773982f9b2500bd8fc93400 Mon Sep 17 00:00:00 2001 From: 6543 <6543@obermui.de> Date: Wed, 11 Nov 2020 12:01:27 +0100 Subject: [PATCH 051/205] Migration not fail on notmigrated reactions (#13507) * Refactor: dedub code * skip Reactions with Invalid ID --- modules/migrations/gitea_downloader.go | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/modules/migrations/gitea_downloader.go b/modules/migrations/gitea_downloader.go index 0509c708bf..be062e8903 100644 --- a/modules/migrations/gitea_downloader.go +++ b/modules/migrations/gitea_downloader.go @@ -326,45 +326,44 @@ func (g *GiteaDownloader) GetAsset(_ string, relID, id int64) (io.ReadCloser, er } func (g *GiteaDownloader) getIssueReactions(index int64) ([]*base.Reaction, error) { - var reactions []*base.Reaction if err := g.client.CheckServerVersionConstraint(">=1.11"); err != nil { log.Info("GiteaDownloader: instance to old, skip getIssueReactions") - return reactions, nil + return []*base.Reaction{}, nil } rl, _, err := g.client.GetIssueReactions(g.repoOwner, g.repoName, index) if err != nil { return nil, err } - for _, reaction := range rl { - reactions = append(reactions, &base.Reaction{ - UserID: reaction.User.ID, - UserName: reaction.User.UserName, - Content: reaction.Reaction, - }) - } - return reactions, nil + return g.convertReactions(rl), nil } func (g *GiteaDownloader) getCommentReactions(commentID int64) ([]*base.Reaction, error) { - var reactions []*base.Reaction if err := g.client.CheckServerVersionConstraint(">=1.11"); err != nil { log.Info("GiteaDownloader: instance to old, skip getCommentReactions") - return reactions, nil + return []*base.Reaction{}, nil } rl, _, err := g.client.GetIssueCommentReactions(g.repoOwner, g.repoName, commentID) if err != nil { return nil, err } + return g.convertReactions(rl), nil +} + +func (g *GiteaDownloader) convertReactions(rl []*gitea_sdk.Reaction) []*base.Reaction { + var reactions []*base.Reaction for i := range rl { + if rl[i].User.ID <= 0 { + continue + } reactions = append(reactions, &base.Reaction{ UserID: rl[i].User.ID, UserName: rl[i].User.UserName, Content: rl[i].Reaction, }) } - return reactions, nil + return reactions } // GetIssues returns issues according start and limit From 122f8f86d5f6712a3b9be162aa01cb525ba4055a Mon Sep 17 00:00:00 2001 From: 6543 <6543@obermui.de> Date: Wed, 11 Nov 2020 22:47:42 +0100 Subject: [PATCH 052/205] Disallow urlencoded new lines in git protocol paths if there is a port (#13521) (#13524) Signed-off-by: Andrew Thornton Co-authored-by: zeripath --- modules/auth/repo_form.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/modules/auth/repo_form.go b/modules/auth/repo_form.go index 039b0cb583..f27812bb1b 100644 --- a/modules/auth/repo_form.go +++ b/modules/auth/repo_form.go @@ -102,6 +102,9 @@ func ParseRemoteAddr(remoteAddr, authUsername, authPassword string, user *models u.User = url.UserPassword(authUsername, authPassword) } remoteAddr = u.String() + if u.Scheme == "git" && u.Port() != "" && (strings.Contains(remoteAddr, "%0d") || strings.Contains(remoteAddr, "%0a")) { + return "", models.ErrInvalidCloneAddr{IsURLError: true} + } } else if !user.CanImportLocal() { return "", models.ErrInvalidCloneAddr{IsPermissionDenied: true} } else if !com.IsDir(remoteAddr) { From ee0097f97d80d0fe0e5fe1cb5ff4570a6a985373 Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Fri, 13 Nov 2020 09:28:32 +0800 Subject: [PATCH 053/205] Prevent git operations for inactive users (#13527) (#13536) * prevent git operations for inactive users * Some fixes * Deny push to the repositories which's owner is inactive * deny operations also when user is ProhibitLogin Co-authored-by: zeripath Co-authored-by: zeripath --- routers/private/serv.go | 45 ++++++++++++++++++++++++++++++++--------- routers/repo/http.go | 9 +++++++++ 2 files changed, 44 insertions(+), 10 deletions(-) diff --git a/routers/private/serv.go b/routers/private/serv.go index 79683c2826..2697666b87 100644 --- a/routers/private/serv.go +++ b/routers/private/serv.go @@ -61,6 +61,12 @@ func ServNoCommand(ctx *macaron.Context) { }) return } + if !user.IsActive || user.ProhibitLogin { + ctx.JSON(http.StatusForbidden, map[string]interface{}{ + "err": "Your account is disabled.", + }) + return + } results.Owner = user } ctx.JSON(http.StatusOK, &results) @@ -98,9 +104,28 @@ func ServCommand(ctx *macaron.Context) { results.RepoName = repoName[:len(repoName)-5] } + owner, err := models.GetUserByName(results.OwnerName) + if err != nil { + log.Error("Unable to get repository owner: %s/%s Error: %v", results.OwnerName, results.RepoName, err) + ctx.JSON(http.StatusInternalServerError, map[string]interface{}{ + "results": results, + "type": "InternalServerError", + "err": fmt.Sprintf("Unable to get repository owner: %s/%s %v", results.OwnerName, results.RepoName, err), + }) + return + } + if !owner.IsActive { + ctx.JSON(http.StatusForbidden, map[string]interface{}{ + "results": results, + "type": "ForbiddenError", + "err": "Repository cannot be accessed, you could retry it later", + }) + return + } + // Now get the Repository and set the results section repoExist := true - repo, err := models.GetRepositoryByOwnerAndName(results.OwnerName, results.RepoName) + repo, err := models.GetRepositoryByName(owner.ID, results.RepoName) if err != nil { if models.IsErrRepoNotExist(err) { repoExist = false @@ -127,6 +152,7 @@ func ServCommand(ctx *macaron.Context) { } if repoExist { + repo.Owner = owner repo.OwnerName = ownerName results.RepoID = repo.ID @@ -217,15 +243,6 @@ func ServCommand(ctx *macaron.Context) { // so for now use the owner of the repository results.UserName = results.OwnerName results.UserID = repo.OwnerID - if err = repo.GetOwner(); err != nil { - log.Error("Unable to get owner for repo %-v. Error: %v", repo, err) - ctx.JSON(http.StatusInternalServerError, map[string]interface{}{ - "results": results, - "type": "InternalServerError", - "err": fmt.Sprintf("Unable to get owner for repo: %s/%s.", results.OwnerName, results.RepoName), - }) - return - } if !repo.Owner.KeepEmailPrivate { results.UserEmail = repo.Owner.Email } @@ -250,6 +267,14 @@ func ServCommand(ctx *macaron.Context) { }) return } + + if !user.IsActive || user.ProhibitLogin { + ctx.JSON(http.StatusForbidden, map[string]interface{}{ + "err": "Your account is disabled.", + }) + return + } + results.UserName = user.Name if !user.KeepEmailPrivate { results.UserEmail = user.Email diff --git a/routers/repo/http.go b/routers/repo/http.go index 23f2665dfd..1de5dd9a93 100644 --- a/routers/repo/http.go +++ b/routers/repo/http.go @@ -105,6 +105,10 @@ func HTTP(ctx *context.Context) { ctx.NotFoundOrServerError("GetUserByName", models.IsErrUserNotExist, err) return } + if !owner.IsActive { + ctx.HandleText(http.StatusForbidden, "Repository cannot be accessed. You cannot push or open issues/pull-requests.") + return + } repoExist := true repo, err := models.GetRepositoryByName(owner.ID, reponame) @@ -244,6 +248,11 @@ func HTTP(ctx *context.Context) { } } + if !authUser.IsActive || authUser.ProhibitLogin { + ctx.HandleText(http.StatusForbidden, "Your account is disabled.") + return + } + if repoExist { perm, err := models.GetUserRepoPermission(repo, authUser) if err != nil { From b4d18dae19679816829d619fac2e211e08b98a2a Mon Sep 17 00:00:00 2001 From: mrsdizzie Date: Fri, 13 Nov 2020 18:05:51 -0500 Subject: [PATCH 054/205] Use existing analyzer module for language detection for highlighting (#13522) (#13551) * Use existing analyzer module for language detction for highlighting Thanks @lafriks for pointing out we can reuse existing code for more reliable language detection here. * Update modules/highlight/highlight.go Co-authored-by: Lauris BH Co-authored-by: zeripath Co-authored-by: Lauris BH Co-authored-by: techknowlogick Co-authored-by: zeripath Co-authored-by: Lauris BH Co-authored-by: techknowlogick --- modules/highlight/highlight.go | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/modules/highlight/highlight.go b/modules/highlight/highlight.go index 1a64108139..914ba8210e 100644 --- a/modules/highlight/highlight.go +++ b/modules/highlight/highlight.go @@ -13,6 +13,7 @@ import ( "strings" "sync" + "code.gitea.io/gitea/modules/analyze" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/setting" "github.com/alecthomas/chroma/formatters/html" @@ -117,9 +118,11 @@ func File(numLines int, fileName string, code []byte) map[int]string { fileName = "test." + val } - lexer := lexers.Match(fileName) + language := analyze.GetCodeLanguage(fileName, code) + + lexer := lexers.Get(language) if lexer == nil { - lexer = lexers.Analyse(string(code)) + lexer = lexers.Match(fileName) if lexer == nil { lexer = lexers.Fallback } From 159a4db30a56fd58a17ae9c9f6879303ee63f1a5 Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Sat, 14 Nov 2020 11:04:58 +0800 Subject: [PATCH 055/205] Add missed sync branch/tag webhook (#13538) (#13556) Co-authored-by: Lauris BH Co-authored-by: techknowlogick Co-authored-by: Lauris BH Co-authored-by: techknowlogick --- modules/notification/webhook/webhook.go | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/modules/notification/webhook/webhook.go b/modules/notification/webhook/webhook.go index c8b6bae724..d451b77cf4 100644 --- a/modules/notification/webhook/webhook.go +++ b/modules/notification/webhook/webhook.go @@ -797,3 +797,11 @@ func (m *webhookNotifier) NotifySyncPushCommits(pusher *models.User, repo *model log.Error("PrepareWebhooks: %v", err) } } + +func (m *webhookNotifier) NotifySyncCreateRef(pusher *models.User, repo *models.Repository, refType, refFullName string) { + m.NotifyCreateRef(pusher, repo, refType, refFullName) +} + +func (m *webhookNotifier) NotifySyncDeleteRef(pusher *models.User, repo *models.Repository, refType, refFullName string) { + m.NotifyDeleteRef(pusher, repo, refType, refFullName) +} From 9a8e02ce30a94336c58940ccc23a41dd688b8248 Mon Sep 17 00:00:00 2001 From: techknowlogick Date: Sat, 14 Nov 2020 07:12:01 -0500 Subject: [PATCH 056/205] missing quotes in default value slice (#13550) (#13557) Co-authored-by: Lunny Xiao Co-authored-by: techknowlogick Co-authored-by: Patrick Aljord Co-authored-by: Lunny Xiao --- modules/setting/repository.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/setting/repository.go b/modules/setting/repository.go index 0bb10199a8..f5237ddf0d 100644 --- a/modules/setting/repository.go +++ b/modules/setting/repository.go @@ -143,7 +143,7 @@ var ( MaxCreationLimit: -1, MirrorQueueLength: 1000, PullRequestQueueLength: 1000, - PreferredLicenses: []string{"Apache License 2.0,MIT License"}, + PreferredLicenses: []string{"Apache License 2.0", "MIT License"}, DisableHTTPGit: false, AccessControlAllowOrigin: "", UseCompatSSHURI: false, From 48fca01b0d1d7637ccdf8229f26562bca82d7f0e Mon Sep 17 00:00:00 2001 From: 6543 <6543@obermui.de> Date: Sun, 15 Nov 2020 17:29:16 +0100 Subject: [PATCH 057/205] [API] Only Return Json (#13511) (#13565) Backport #13511 Co-authored-by: zeripath --- modules/context/api.go | 58 ++++++++++++++++++++++++++++++++++ modules/context/repo.go | 3 +- routers/api/v1/api.go | 47 ++++++++++++++------------- routers/api/v1/repo/branch.go | 37 +++++++++------------- templates/swagger/v1_json.tmpl | 6 ++++ 5 files changed, 103 insertions(+), 48 deletions(-) diff --git a/modules/context/api.go b/modules/context/api.go index 772e1f8f50..228a9cf440 100644 --- a/modules/context/api.go +++ b/modules/context/api.go @@ -255,3 +255,61 @@ func (ctx *APIContext) NotFound(objs ...interface{}) { "errors": errors, }) } + +// RepoRefForAPI handles repository reference names when the ref name is not explicitly given +func RepoRefForAPI() macaron.Handler { + return func(ctx *APIContext) { + // Empty repository does not have reference information. + if ctx.Repo.Repository.IsEmpty { + return + } + + var err error + + if ctx.Repo.GitRepo == nil { + repoPath := models.RepoPath(ctx.Repo.Owner.Name, ctx.Repo.Repository.Name) + ctx.Repo.GitRepo, err = git.OpenRepository(repoPath) + if err != nil { + ctx.InternalServerError(err) + return + } + // We opened it, we should close it + defer func() { + // If it's been set to nil then assume someone else has closed it. + if ctx.Repo.GitRepo != nil { + ctx.Repo.GitRepo.Close() + } + }() + } + + refName := getRefName(ctx.Context, RepoRefAny) + + if ctx.Repo.GitRepo.IsBranchExist(refName) { + ctx.Repo.Commit, err = ctx.Repo.GitRepo.GetBranchCommit(refName) + if err != nil { + ctx.InternalServerError(err) + return + } + ctx.Repo.CommitID = ctx.Repo.Commit.ID.String() + } else if ctx.Repo.GitRepo.IsTagExist(refName) { + ctx.Repo.Commit, err = ctx.Repo.GitRepo.GetTagCommit(refName) + if err != nil { + ctx.InternalServerError(err) + return + } + ctx.Repo.CommitID = ctx.Repo.Commit.ID.String() + } else if len(refName) == 40 { + ctx.Repo.CommitID = refName + ctx.Repo.Commit, err = ctx.Repo.GitRepo.GetCommit(refName) + if err != nil { + ctx.NotFound("GetCommit", err) + return + } + } else { + ctx.NotFound(fmt.Errorf("not exist: '%s'", ctx.Params("*"))) + return + } + + ctx.Next() + } +} diff --git a/modules/context/repo.go b/modules/context/repo.go index cb2e60d263..bcad26b9cd 100644 --- a/modules/context/repo.go +++ b/modules/context/repo.go @@ -704,7 +704,6 @@ func RepoRefByType(refType RepoRefType) macaron.Handler { err error ) - // For API calls. if ctx.Repo.GitRepo == nil { repoPath := models.RepoPath(ctx.Repo.Owner.Name, ctx.Repo.Repository.Name) ctx.Repo.GitRepo, err = git.OpenRepository(repoPath) @@ -773,7 +772,7 @@ func RepoRefByType(refType RepoRefType) macaron.Handler { ctx.Repo.Commit, err = ctx.Repo.GitRepo.GetCommit(refName) if err != nil { - ctx.NotFound("GetCommit", nil) + ctx.NotFound("GetCommit", err) return } } else { diff --git a/routers/api/v1/api.go b/routers/api/v1/api.go index acd97648bf..e2becf2cff 100644 --- a/routers/api/v1/api.go +++ b/routers/api/v1/api.go @@ -191,14 +191,14 @@ func reqToken() macaron.Handler { ctx.RequireCSRF() return } - ctx.Context.Error(http.StatusUnauthorized) + ctx.Error(http.StatusUnauthorized, "reqToken", "token is required") } } func reqBasicAuth() macaron.Handler { return func(ctx *context.APIContext) { if !ctx.Context.IsBasicAuth { - ctx.Context.Error(http.StatusUnauthorized) + ctx.Error(http.StatusUnauthorized, "reqBasicAuth", "basic auth required") return } ctx.CheckForOTP() @@ -207,9 +207,9 @@ func reqBasicAuth() macaron.Handler { // reqSiteAdmin user should be the site admin func reqSiteAdmin() macaron.Handler { - return func(ctx *context.Context) { + return func(ctx *context.APIContext) { if !ctx.IsUserSiteAdmin() { - ctx.Error(http.StatusForbidden) + ctx.Error(http.StatusForbidden, "reqSiteAdmin", "user should be the site admin") return } } @@ -217,9 +217,9 @@ func reqSiteAdmin() macaron.Handler { // reqOwner user should be the owner of the repo or site admin. func reqOwner() macaron.Handler { - return func(ctx *context.Context) { + return func(ctx *context.APIContext) { if !ctx.IsUserRepoOwner() && !ctx.IsUserSiteAdmin() { - ctx.Error(http.StatusForbidden) + ctx.Error(http.StatusForbidden, "reqOwner", "user should be the owner of the repo") return } } @@ -227,9 +227,9 @@ func reqOwner() macaron.Handler { // reqAdmin user should be an owner or a collaborator with admin write of a repository, or site admin func reqAdmin() macaron.Handler { - return func(ctx *context.Context) { + return func(ctx *context.APIContext) { if !ctx.IsUserRepoAdmin() && !ctx.IsUserSiteAdmin() { - ctx.Error(http.StatusForbidden) + ctx.Error(http.StatusForbidden, "reqAdmin", "user should be an owner or a collaborator with admin write of a repository") return } } @@ -237,9 +237,9 @@ func reqAdmin() macaron.Handler { // reqRepoWriter user should have a permission to write to a repo, or be a site admin func reqRepoWriter(unitTypes ...models.UnitType) macaron.Handler { - return func(ctx *context.Context) { + return func(ctx *context.APIContext) { if !ctx.IsUserRepoWriter(unitTypes) && !ctx.IsUserRepoAdmin() && !ctx.IsUserSiteAdmin() { - ctx.Error(http.StatusForbidden) + ctx.Error(http.StatusForbidden, "reqRepoWriter", "user should have a permission to write to a repo") return } } @@ -247,9 +247,9 @@ func reqRepoWriter(unitTypes ...models.UnitType) macaron.Handler { // reqRepoReader user should have specific read permission or be a repo admin or a site admin func reqRepoReader(unitType models.UnitType) macaron.Handler { - return func(ctx *context.Context) { + return func(ctx *context.APIContext) { if !ctx.IsUserRepoReaderSpecific(unitType) && !ctx.IsUserRepoAdmin() && !ctx.IsUserSiteAdmin() { - ctx.Error(http.StatusForbidden) + ctx.Error(http.StatusForbidden, "reqRepoReader", "user should have specific read permission or be a repo admin or a site admin") return } } @@ -257,9 +257,9 @@ func reqRepoReader(unitType models.UnitType) macaron.Handler { // reqAnyRepoReader user should have any permission to read repository or permissions of site admin func reqAnyRepoReader() macaron.Handler { - return func(ctx *context.Context) { + return func(ctx *context.APIContext) { if !ctx.IsUserRepoReaderAny() && !ctx.IsUserSiteAdmin() { - ctx.Error(http.StatusForbidden) + ctx.Error(http.StatusForbidden, "reqAnyRepoReader", "user should have any permission to read repository or permissions of site admin") return } } @@ -502,7 +502,6 @@ func mustNotBeArchived(ctx *context.APIContext) { } // RegisterRoutes registers all v1 APIs routes to web application. -// FIXME: custom form error response func RegisterRoutes(m *macaron.Macaron) { bind := binding.Bind @@ -641,7 +640,7 @@ func RegisterRoutes(m *macaron.Macaron) { m.Group("/:username/:reponame", func() { m.Combo("").Get(reqAnyRepoReader(), repo.Get). Delete(reqToken(), reqOwner(), repo.Delete). - Patch(reqToken(), reqAdmin(), bind(api.EditRepoOption{}), context.RepoRef(), repo.Edit) + Patch(reqToken(), reqAdmin(), bind(api.EditRepoOption{}), context.RepoRefForAPI(), repo.Edit) m.Post("/transfer", reqOwner(), bind(api.TransferRepoOption{}), repo.Transfer) m.Combo("/notifications"). Get(reqToken(), notify.ListRepoNotifications). @@ -653,7 +652,7 @@ func RegisterRoutes(m *macaron.Macaron) { m.Combo("").Get(repo.GetHook). Patch(bind(api.EditHookOption{}), repo.EditHook). Delete(repo.DeleteHook) - m.Post("/tests", context.RepoRef(), repo.TestHook) + m.Post("/tests", context.RepoRefForAPI(), repo.TestHook) }) m.Group("/git", func() { m.Combo("").Get(repo.ListGitHooks) @@ -670,14 +669,14 @@ func RegisterRoutes(m *macaron.Macaron) { Put(reqAdmin(), bind(api.AddCollaboratorOption{}), repo.AddCollaborator). Delete(reqAdmin(), repo.DeleteCollaborator) }, reqToken()) - m.Get("/raw/*", context.RepoRefByType(context.RepoRefAny), reqRepoReader(models.UnitTypeCode), repo.GetRawFile) + m.Get("/raw/*", context.RepoRefForAPI(), reqRepoReader(models.UnitTypeCode), repo.GetRawFile) m.Get("/archive/*", reqRepoReader(models.UnitTypeCode), repo.GetArchive) m.Combo("/forks").Get(repo.ListForks). Post(reqToken(), reqRepoReader(models.UnitTypeCode), bind(api.CreateForkOption{}), repo.CreateFork) m.Group("/branches", func() { m.Get("", repo.ListBranches) - m.Get("/*", context.RepoRefByType(context.RepoRefBranch), repo.GetBranch) - m.Delete("/*", reqRepoWriter(models.UnitTypeCode), context.RepoRefByType(context.RepoRefBranch), repo.DeleteBranch) + m.Get("/*", repo.GetBranch) + m.Delete("/*", context.ReferencesGitRepo(false), reqRepoWriter(models.UnitTypeCode), repo.DeleteBranch) m.Post("", reqRepoWriter(models.UnitTypeCode), bind(api.CreateBranchRepoOption{}), repo.CreateBranch) }, reqRepoReader(models.UnitTypeCode)) m.Group("/branch_protections", func() { @@ -802,7 +801,7 @@ func RegisterRoutes(m *macaron.Macaron) { }) }, reqRepoReader(models.UnitTypeReleases)) m.Post("/mirror-sync", reqToken(), reqRepoWriter(models.UnitTypeCode), repo.MirrorSync) - m.Get("/editorconfig/:filename", context.RepoRef(), reqRepoReader(models.UnitTypeCode), repo.GetEditorconfig) + m.Get("/editorconfig/:filename", context.RepoRefForAPI(), reqRepoReader(models.UnitTypeCode), repo.GetEditorconfig) m.Group("/pulls", func() { m.Combo("").Get(bind(api.ListPullRequestsOptions{}), repo.ListPullRequests). Post(reqToken(), mustNotBeArchived, bind(api.CreatePullRequestOption{}), repo.CreatePullRequest) @@ -847,9 +846,9 @@ func RegisterRoutes(m *macaron.Macaron) { }) m.Get("/refs", repo.GetGitAllRefs) m.Get("/refs/*", repo.GetGitRefs) - m.Get("/trees/:sha", context.RepoRef(), repo.GetTree) - m.Get("/blobs/:sha", context.RepoRef(), repo.GetBlob) - m.Get("/tags/:sha", context.RepoRef(), repo.GetTag) + m.Get("/trees/:sha", context.RepoRefForAPI(), repo.GetTree) + m.Get("/blobs/:sha", context.RepoRefForAPI(), repo.GetBlob) + m.Get("/tags/:sha", context.RepoRefForAPI(), repo.GetTag) }, reqRepoReader(models.UnitTypeCode)) m.Group("/contents", func() { m.Get("", repo.GetContentsList) diff --git a/routers/api/v1/repo/branch.go b/routers/api/v1/repo/branch.go index 50ca3977a5..403b75080a 100644 --- a/routers/api/v1/repo/branch.go +++ b/routers/api/v1/repo/branch.go @@ -46,15 +46,12 @@ func GetBranch(ctx *context.APIContext) { // responses: // "200": // "$ref": "#/responses/Branch" + // "404": + // "$ref": "#/responses/notFound" - if ctx.Repo.TreePath != "" { - // if TreePath != "", then URL contained extra slashes - // (i.e. "master/subbranch" instead of "master"), so branch does - // not exist - ctx.NotFound() - return - } - branch, err := repo_module.GetBranch(ctx.Repo.Repository, ctx.Repo.BranchName) + branchName := ctx.Params("*") + + branch, err := repo_module.GetBranch(ctx.Repo.Repository, branchName) if err != nil { if git.IsErrBranchNotExist(err) { ctx.NotFound(err) @@ -70,7 +67,7 @@ func GetBranch(ctx *context.APIContext) { return } - branchProtection, err := ctx.Repo.Repository.GetBranchProtection(ctx.Repo.BranchName) + branchProtection, err := ctx.Repo.Repository.GetBranchProtection(branchName) if err != nil { ctx.Error(http.StatusInternalServerError, "GetBranchProtection", err) return @@ -113,21 +110,17 @@ func DeleteBranch(ctx *context.APIContext) { // "$ref": "#/responses/empty" // "403": // "$ref": "#/responses/error" + // "404": + // "$ref": "#/responses/notFound" - if ctx.Repo.TreePath != "" { - // if TreePath != "", then URL contained extra slashes - // (i.e. "master/subbranch" instead of "master"), so branch does - // not exist - ctx.NotFound() - return - } + branchName := ctx.Params("*") - if ctx.Repo.Repository.DefaultBranch == ctx.Repo.BranchName { + if ctx.Repo.Repository.DefaultBranch == branchName { ctx.Error(http.StatusForbidden, "DefaultBranch", fmt.Errorf("can not delete default branch")) return } - isProtected, err := ctx.Repo.Repository.IsProtectedBranch(ctx.Repo.BranchName, ctx.User) + isProtected, err := ctx.Repo.Repository.IsProtectedBranch(branchName, ctx.User) if err != nil { ctx.InternalServerError(err) return @@ -137,7 +130,7 @@ func DeleteBranch(ctx *context.APIContext) { return } - branch, err := repo_module.GetBranch(ctx.Repo.Repository, ctx.Repo.BranchName) + branch, err := repo_module.GetBranch(ctx.Repo.Repository, branchName) if err != nil { if git.IsErrBranchNotExist(err) { ctx.NotFound(err) @@ -153,7 +146,7 @@ func DeleteBranch(ctx *context.APIContext) { return } - if err := ctx.Repo.GitRepo.DeleteBranch(ctx.Repo.BranchName, git.DeleteBranchOptions{ + if err := ctx.Repo.GitRepo.DeleteBranch(branchName, git.DeleteBranchOptions{ Force: true, }); err != nil { ctx.Error(http.StatusInternalServerError, "DeleteBranch", err) @@ -163,7 +156,7 @@ func DeleteBranch(ctx *context.APIContext) { // Don't return error below this if err := repo_service.PushUpdate( &repo_service.PushUpdateOptions{ - RefFullName: git.BranchPrefix + ctx.Repo.BranchName, + RefFullName: git.BranchPrefix + branchName, OldCommitID: c.ID.String(), NewCommitID: git.EmptySHA, PusherID: ctx.User.ID, @@ -174,7 +167,7 @@ func DeleteBranch(ctx *context.APIContext) { log.Error("Update: %v", err) } - if err := ctx.Repo.Repository.AddDeletedBranch(ctx.Repo.BranchName, c.ID.String(), ctx.User.ID); err != nil { + if err := ctx.Repo.Repository.AddDeletedBranch(branchName, c.ID.String(), ctx.User.ID); err != nil { log.Warn("AddDeletedBranch: %v", err) } diff --git a/templates/swagger/v1_json.tmpl b/templates/swagger/v1_json.tmpl index e7655f02a8..96871b48c7 100644 --- a/templates/swagger/v1_json.tmpl +++ b/templates/swagger/v1_json.tmpl @@ -2541,6 +2541,9 @@ "responses": { "200": { "$ref": "#/responses/Branch" + }, + "404": { + "$ref": "#/responses/notFound" } } }, @@ -2582,6 +2585,9 @@ }, "403": { "$ref": "#/responses/error" + }, + "404": { + "$ref": "#/responses/notFound" } } } From c6ab79ee3ceec5cdb5528c5936ff0706e69289e7 Mon Sep 17 00:00:00 2001 From: silverwind Date: Tue, 17 Nov 2020 00:01:05 +0100 Subject: [PATCH 058/205] Fix Fomatic Build (#13596) Port of #13593 to 1.13 --- Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 404ead6d1e..20decf16a6 100644 --- a/Makefile +++ b/Makefile @@ -638,8 +638,8 @@ fomantic: $(FOMANTIC_DEST) $(FOMANTIC_DEST): $(FOMANTIC_CONFIGS) | node_modules rm -rf $(FOMANTIC_DEST_DIR) - cp web_src/fomantic/theme.config.less node_modules/fomantic-ui/src/theme.config - cp -r web_src/fomantic/_site/* node_modules/fomantic-ui/src/_site/ + cp -f web_src/fomantic/theme.config.less node_modules/fomantic-ui/src/theme.config + cp -fr web_src/fomantic/_site/* node_modules/fomantic-ui/src/_site/ npx gulp -f node_modules/fomantic-ui/gulpfile.js build @touch $(FOMANTIC_DEST) From ed3a4cd103a687c1c9a70e1709ac838ee8543ecf Mon Sep 17 00:00:00 2001 From: 6543 <6543@obermui.de> Date: Tue, 17 Nov 2020 08:01:33 +0100 Subject: [PATCH 059/205] Migration: Gitlab: Support Subdirectory (#13563) (#13591) Co-authored-by: techknowlogick Co-authored-by: techknowlogick --- modules/migrations/gitlab.go | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/modules/migrations/gitlab.go b/modules/migrations/gitlab.go index d4b725b5be..06f4a4ba7f 100644 --- a/modules/migrations/gitlab.go +++ b/modules/migrations/gitlab.go @@ -11,6 +11,7 @@ import ( "io" "net/http" "net/url" + "path" "strings" "time" @@ -87,6 +88,23 @@ func NewGitlabDownloader(ctx context.Context, baseURL, repoPath, username, passw return nil, err } + // split namespace and subdirectory + pathParts := strings.Split(strings.Trim(repoPath, "/"), "/") + for len(pathParts) > 2 { + if _, _, err = gitlabClient.Version.GetVersion(); err == nil { + break + } + + baseURL = path.Join(baseURL, pathParts[0]) + pathParts = pathParts[1:] + _ = gitlab.WithBaseURL(baseURL)(gitlabClient) + repoPath = strings.Join(pathParts, "/") + } + if err != nil { + log.Trace("Error could not get gitlab version: %v", err) + return nil, err + } + // Grab and store project/repo ID here, due to issues using the URL escaped path gr, _, err := gitlabClient.Projects.GetProject(repoPath, nil, nil, gitlab.WithContext(ctx)) if err != nil { From bcde51f4c27589392b7e58da68cd0228936dbeff Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Wed, 18 Nov 2020 17:59:24 +0800 Subject: [PATCH 060/205] Fix a bug when check if owner is active (#13613) --- routers/private/serv.go | 2 +- routers/repo/http.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/routers/private/serv.go b/routers/private/serv.go index 2697666b87..182fe27245 100644 --- a/routers/private/serv.go +++ b/routers/private/serv.go @@ -114,7 +114,7 @@ func ServCommand(ctx *macaron.Context) { }) return } - if !owner.IsActive { + if !owner.IsOrganization() && !owner.IsActive { ctx.JSON(http.StatusForbidden, map[string]interface{}{ "results": results, "type": "ForbiddenError", diff --git a/routers/repo/http.go b/routers/repo/http.go index 1de5dd9a93..9be0e6e3bb 100644 --- a/routers/repo/http.go +++ b/routers/repo/http.go @@ -105,7 +105,7 @@ func HTTP(ctx *context.Context) { ctx.NotFoundOrServerError("GetUserByName", models.IsErrUserNotExist, err) return } - if !owner.IsActive { + if !owner.IsOrganization() && !owner.IsActive { ctx.HandleText(http.StatusForbidden, "Repository cannot be accessed. You cannot push or open issues/pull-requests.") return } From 2f6dad2e34302ba6b2ec29216238532b053183f1 Mon Sep 17 00:00:00 2001 From: 6543 <6543@obermui.de> Date: Thu, 19 Nov 2020 03:21:21 +0100 Subject: [PATCH 061/205] API: Fix GetQueryBeforeSince (#13561) --- routers/api/v1/notify/repo.go | 2 +- routers/api/v1/notify/user.go | 2 +- routers/api/v1/repo/issue_comment.go | 4 +- routers/api/v1/repo/issue_tracked_time.go | 6 +-- routers/api/v1/utils/utils.go | 56 +++++++++++++++-------- 5 files changed, 45 insertions(+), 25 deletions(-) diff --git a/routers/api/v1/notify/repo.go b/routers/api/v1/notify/repo.go index 49b493aa4f..cc66e0f743 100644 --- a/routers/api/v1/notify/repo.go +++ b/routers/api/v1/notify/repo.go @@ -101,7 +101,7 @@ func ListRepoNotifications(ctx *context.APIContext) { before, since, err := utils.GetQueryBeforeSince(ctx) if err != nil { - ctx.InternalServerError(err) + ctx.Error(http.StatusUnprocessableEntity, "GetQueryBeforeSince", err) return } opts := models.FindNotificationOptions{ diff --git a/routers/api/v1/notify/user.go b/routers/api/v1/notify/user.go index 9c3f9b1472..373c88d372 100644 --- a/routers/api/v1/notify/user.go +++ b/routers/api/v1/notify/user.go @@ -63,7 +63,7 @@ func ListNotifications(ctx *context.APIContext) { before, since, err := utils.GetQueryBeforeSince(ctx) if err != nil { - ctx.InternalServerError(err) + ctx.Error(http.StatusUnprocessableEntity, "GetQueryBeforeSince", err) return } opts := models.FindNotificationOptions{ diff --git a/routers/api/v1/repo/issue_comment.go b/routers/api/v1/repo/issue_comment.go index bf86b42402..1206415bd2 100644 --- a/routers/api/v1/repo/issue_comment.go +++ b/routers/api/v1/repo/issue_comment.go @@ -56,7 +56,7 @@ func ListIssueComments(ctx *context.APIContext) { before, since, err := utils.GetQueryBeforeSince(ctx) if err != nil { - ctx.Error(http.StatusInternalServerError, "GetQueryBeforeSince", err) + ctx.Error(http.StatusUnprocessableEntity, "GetQueryBeforeSince", err) return } issue, err := models.GetIssueByIndex(ctx.Repo.Repository.ID, ctx.ParamsInt64(":index")) @@ -132,7 +132,7 @@ func ListRepoIssueComments(ctx *context.APIContext) { before, since, err := utils.GetQueryBeforeSince(ctx) if err != nil { - ctx.Error(http.StatusInternalServerError, "GetQueryBeforeSince", err) + ctx.Error(http.StatusUnprocessableEntity, "GetQueryBeforeSince", err) return } diff --git a/routers/api/v1/repo/issue_tracked_time.go b/routers/api/v1/repo/issue_tracked_time.go index fd437753ab..67c47d858a 100644 --- a/routers/api/v1/repo/issue_tracked_time.go +++ b/routers/api/v1/repo/issue_tracked_time.go @@ -86,7 +86,7 @@ func ListTrackedTimes(ctx *context.APIContext) { } if opts.CreatedBeforeUnix, opts.CreatedAfterUnix, err = utils.GetQueryBeforeSince(ctx); err != nil { - ctx.InternalServerError(err) + ctx.Error(http.StatusUnprocessableEntity, "GetQueryBeforeSince", err) return } @@ -491,7 +491,7 @@ func ListTrackedTimesByRepository(ctx *context.APIContext) { var err error if opts.CreatedBeforeUnix, opts.CreatedAfterUnix, err = utils.GetQueryBeforeSince(ctx); err != nil { - ctx.InternalServerError(err) + ctx.Error(http.StatusUnprocessableEntity, "GetQueryBeforeSince", err) return } @@ -554,7 +554,7 @@ func ListMyTrackedTimes(ctx *context.APIContext) { var err error if opts.CreatedBeforeUnix, opts.CreatedAfterUnix, err = utils.GetQueryBeforeSince(ctx); err != nil { - ctx.InternalServerError(err) + ctx.Error(http.StatusUnprocessableEntity, "GetQueryBeforeSince", err) return } diff --git a/routers/api/v1/utils/utils.go b/routers/api/v1/utils/utils.go index 092ea3dbb6..ad1a136db4 100644 --- a/routers/api/v1/utils/utils.go +++ b/routers/api/v1/utils/utils.go @@ -5,6 +5,7 @@ package utils import ( + "net/url" "strings" "time" @@ -15,30 +16,49 @@ import ( // GetQueryBeforeSince return parsed time (unix format) from URL query's before and since func GetQueryBeforeSince(ctx *context.APIContext) (before, since int64, err error) { - qCreatedBefore := strings.Trim(ctx.Query("before"), " ") - if qCreatedBefore != "" { - createdBefore, err := time.Parse(time.RFC3339, qCreatedBefore) - if err != nil { - return 0, 0, err - } - if !createdBefore.IsZero() { - before = createdBefore.Unix() - } + qCreatedBefore, err := prepareQueryArg(ctx, "before") + if err != nil { + return 0, 0, err } - qCreatedAfter := strings.Trim(ctx.Query("since"), " ") - if qCreatedAfter != "" { - createdAfter, err := time.Parse(time.RFC3339, qCreatedAfter) - if err != nil { - return 0, 0, err - } - if !createdAfter.IsZero() { - since = createdAfter.Unix() - } + qCreatedSince, err := prepareQueryArg(ctx, "since") + if err != nil { + return 0, 0, err + } + + before, err = parseTime(qCreatedBefore) + if err != nil { + return 0, 0, err + } + + since, err = parseTime(qCreatedSince) + if err != nil { + return 0, 0, err } return before, since, nil } +// parseTime parse time and return unix timestamp +func parseTime(value string) (int64, error) { + if len(value) != 0 { + t, err := time.Parse(time.RFC3339, value) + if err != nil { + return 0, err + } + if !t.IsZero() { + return t.Unix(), nil + } + } + return 0, nil +} + +// prepareQueryArg unescape and trim a query arg +func prepareQueryArg(ctx *context.APIContext, name string) (value string, err error) { + value, err = url.PathUnescape(ctx.Query(name)) + value = strings.Trim(value, " ") + return +} + // GetListOptions returns list options using the page and limit parameters func GetListOptions(ctx *context.APIContext) models.ListOptions { return models.ListOptions{ From e0d28e2026c5463a16bc80766d65455248a076a7 Mon Sep 17 00:00:00 2001 From: techknowlogick Date: Thu, 19 Nov 2020 11:20:12 -0500 Subject: [PATCH 062/205] finaly fix gitlab migration with subdir (#13629) (#13633) * finaly fix #13535 * add logging Co-authored-by: 6543 <6543@obermui.de> --- modules/migrations/gitlab.go | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/modules/migrations/gitlab.go b/modules/migrations/gitlab.go index 06f4a4ba7f..c510944f6f 100644 --- a/modules/migrations/gitlab.go +++ b/modules/migrations/gitlab.go @@ -90,12 +90,17 @@ func NewGitlabDownloader(ctx context.Context, baseURL, repoPath, username, passw // split namespace and subdirectory pathParts := strings.Split(strings.Trim(repoPath, "/"), "/") + var resp *gitlab.Response + u, _ := url.Parse(baseURL) for len(pathParts) > 2 { - if _, _, err = gitlabClient.Version.GetVersion(); err == nil { + _, resp, err = gitlabClient.Version.GetVersion() + if err == nil || resp != nil && resp.StatusCode == 401 { + err = nil // if no authentication given, this still should work break } - baseURL = path.Join(baseURL, pathParts[0]) + u.Path = path.Join(u.Path, pathParts[0]) + baseURL = u.String() pathParts = pathParts[1:] _ = gitlab.WithBaseURL(baseURL)(gitlabClient) repoPath = strings.Join(pathParts, "/") @@ -105,6 +110,8 @@ func NewGitlabDownloader(ctx context.Context, baseURL, repoPath, username, passw return nil, err } + log.Trace("gitlab downloader: use BaseURL: '%s' and RepoPath: '%s'", baseURL, repoPath) + // Grab and store project/repo ID here, due to issues using the URL escaped path gr, _, err := gitlabClient.Projects.GetProject(repoPath, nil, nil, gitlab.WithContext(ctx)) if err != nil { From ef7a52826db4fef2904620767576a0347c8f5089 Mon Sep 17 00:00:00 2001 From: Karl Heinz Marbaise Date: Thu, 19 Nov 2020 23:58:35 +0100 Subject: [PATCH 063/205] Fix issue/pull request list assignee filter (#13647) (#13651) * Fixes #13641 - Filtering in Pull Request kept all the time. - The URL contains all the time the assignee in cases where once a type has been selected. Signed-off-by: Karl Heinz Marbaise * Followup Fixes #13641 - Filtering in Pull Request kept all the time. - The URL contains all the time the assignee in cases where once a type has been selected. - The same behaviour was observed issues viewed via milestones. Signed-off-by: Karl Heinz Marbaise --- routers/repo/issue.go | 2 ++ templates/repo/issue/list.tmpl | 2 +- templates/repo/issue/milestone_issues.tmpl | 2 +- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/routers/repo/issue.go b/routers/repo/issue.go index 8aef322090..cbedde5760 100644 --- a/routers/repo/issue.go +++ b/routers/repo/issue.go @@ -130,6 +130,8 @@ func issues(ctx *context.Context, milestoneID, projectID int64, isPullOption uti posterID = ctx.User.ID case "mentioned": mentionedID = ctx.User.ID + case "assigned": + assigneeID = ctx.User.ID } } diff --git a/templates/repo/issue/list.tmpl b/templates/repo/issue/list.tmpl index 881e774876..d3423a1b66 100644 --- a/templates/repo/issue/list.tmpl +++ b/templates/repo/issue/list.tmpl @@ -93,7 +93,7 @@ diff --git a/templates/repo/issue/milestone_issues.tmpl b/templates/repo/issue/milestone_issues.tmpl index 2e00d12279..8d8c392564 100644 --- a/templates/repo/issue/milestone_issues.tmpl +++ b/templates/repo/issue/milestone_issues.tmpl @@ -91,7 +91,7 @@ From f2a3a9117ead84e644777e9dd77411382d17ee04 Mon Sep 17 00:00:00 2001 From: 6543 <6543@obermui.de> Date: Sun, 22 Nov 2020 17:51:39 +0100 Subject: [PATCH 064/205] * Handle incomplete diff files properly (#13668) The code for parsing diff hunks has a bug whereby a very long line in a very long diff would not be completely read leading to an unexpected character. This PR ensures that the line is completely cleared * Also allow git max line length <4096 * Add test case Fix #13602 Signed-off-by: Andrew Thornton Co-authored-by: Andrew Thornton --- services/gitdiff/gitdiff.go | 13 +++++ services/gitdiff/gitdiff_test.go | 89 +++++++++++++++++++++++++++++--- 2 files changed, 96 insertions(+), 6 deletions(-) diff --git a/services/gitdiff/gitdiff.go b/services/gitdiff/gitdiff.go index 4f223fdc03..79cd16e193 100644 --- a/services/gitdiff/gitdiff.go +++ b/services/gitdiff/gitdiff.go @@ -676,6 +676,15 @@ func parseHunks(curFile *DiffFile, maxLines, maxLineCharacters int, input *bufio leftLine, rightLine := 1, 1 for { + for isFragment { + curFile.IsIncomplete = true + _, isFragment, err = input.ReadLine() + if err != nil { + // Now by the definition of ReadLine this cannot be io.EOF + err = fmt.Errorf("Unable to ReadLine: %v", err) + return + } + } sb.Reset() lineBytes, isFragment, err = input.ReadLine() if err != nil { @@ -790,6 +799,10 @@ func parseHunks(curFile *DiffFile, maxLines, maxLineCharacters int, input *bufio } } } + if len(line) > maxLineCharacters { + curFile.IsIncomplete = true + line = line[:maxLineCharacters] + } curSection.Lines[len(curSection.Lines)-1].Content = line // handle LFS diff --git a/services/gitdiff/gitdiff_test.go b/services/gitdiff/gitdiff_test.go index 6e3b5b0994..cd7b2273cc 100644 --- a/services/gitdiff/gitdiff_test.go +++ b/services/gitdiff/gitdiff_test.go @@ -9,6 +9,7 @@ import ( "encoding/json" "fmt" "html/template" + "strconv" "strings" "testing" @@ -153,11 +154,11 @@ func TestParsePatch_singlefile(t *testing.T) { name: "really weird filename", gitdiff: `diff --git "\\a/a b/file b/a a/file" "\\b/a b/file b/a a/file" index d2186f1..f5c8ed2 100644 ---- "\\a/a b/file b/a a/file" -+++ "\\b/a b/file b/a a/file" +--- "\\a/a b/file b/a a/file" ` + ` ++++ "\\b/a b/file b/a a/file" ` + ` @@ -1,3 +1,2 @@ Create a weird file. - + ` + ` -and what does diff do here? \ No newline at end of file`, addition: 0, @@ -170,7 +171,7 @@ index d2186f1..f5c8ed2 100644 gitdiff: `diff --git "\\a/file with blanks" "\\b/file with blanks" deleted file mode 100644 index 898651a..0000000 ---- "\\a/file with blanks" +--- "\\a/file with blanks" ` + ` +++ /dev/null @@ -1,5 +0,0 @@ -a blank file @@ -263,7 +264,83 @@ index 6961180..9ba1a00 100644 }) } - var diff = `diff --git "a/README.md" "b/README.md" + // Test max lines + diffBuilder := &strings.Builder{} + + var diff = `diff --git a/newfile2 b/newfile2 +new file mode 100644 +index 0000000..6bb8f39 +--- /dev/null ++++ b/newfile2 +@@ -0,0 +1,35 @@ +` + diffBuilder.WriteString(diff) + + for i := 0; i < 35; i++ { + diffBuilder.WriteString("+line" + strconv.Itoa(i) + "\n") + } + diff = diffBuilder.String() + result, err := ParsePatch(20, setting.Git.MaxGitDiffLineCharacters, setting.Git.MaxGitDiffFiles, strings.NewReader(diff)) + if err != nil { + t.Errorf("There should not be an error: %v", err) + } + if !result.Files[0].IsIncomplete { + t.Errorf("Files should be incomplete! %v", result.Files[0]) + } + result, err = ParsePatch(40, setting.Git.MaxGitDiffLineCharacters, setting.Git.MaxGitDiffFiles, strings.NewReader(diff)) + if err != nil { + t.Errorf("There should not be an error: %v", err) + } + if result.Files[0].IsIncomplete { + t.Errorf("Files should not be incomplete! %v", result.Files[0]) + } + result, err = ParsePatch(40, 5, setting.Git.MaxGitDiffFiles, strings.NewReader(diff)) + if err != nil { + t.Errorf("There should not be an error: %v", err) + } + if !result.Files[0].IsIncomplete { + t.Errorf("Files should be incomplete! %v", result.Files[0]) + } + + // Test max characters + diff = `diff --git a/newfile2 b/newfile2 +new file mode 100644 +index 0000000..6bb8f39 +--- /dev/null ++++ b/newfile2 +@@ -0,0 +1,35 @@ +` + diffBuilder.Reset() + diffBuilder.WriteString(diff) + + for i := 0; i < 33; i++ { + diffBuilder.WriteString("+line" + strconv.Itoa(i) + "\n") + } + diffBuilder.WriteString("+line33") + for i := 0; i < 512; i++ { + diffBuilder.WriteString("0123456789ABCDEF") + } + diffBuilder.WriteByte('\n') + diffBuilder.WriteString("+line" + strconv.Itoa(34) + "\n") + diffBuilder.WriteString("+line" + strconv.Itoa(35) + "\n") + diff = diffBuilder.String() + + result, err = ParsePatch(20, 4096, setting.Git.MaxGitDiffFiles, strings.NewReader(diff)) + if err != nil { + t.Errorf("There should not be an error: %v", err) + } + if !result.Files[0].IsIncomplete { + t.Errorf("Files should be incomplete! %v", result.Files[0]) + } + result, err = ParsePatch(40, 4096, setting.Git.MaxGitDiffFiles, strings.NewReader(diff)) + if err != nil { + t.Errorf("There should not be an error: %v", err) + } + if !result.Files[0].IsIncomplete { + t.Errorf("Files should be incomplete! %v", result.Files[0]) + } + + diff = `diff --git "a/README.md" "b/README.md" --- a/README.md +++ b/README.md @@ -1,3 +1,6 @@ @@ -274,7 +351,7 @@ index 6961180..9ba1a00 100644 Docker Pulls + cut off + cut off` - result, err := ParsePatch(setting.Git.MaxGitDiffLines, setting.Git.MaxGitDiffLineCharacters, setting.Git.MaxGitDiffFiles, strings.NewReader(diff)) + result, err = ParsePatch(setting.Git.MaxGitDiffLines, setting.Git.MaxGitDiffLineCharacters, setting.Git.MaxGitDiffFiles, strings.NewReader(diff)) if err != nil { t.Errorf("ParsePatch failed: %s", err) } From 33431fcbd3e5c4a6c6bf18db3339ae331efdf3f4 Mon Sep 17 00:00:00 2001 From: 6543 <6543@obermui.de> Date: Sun, 22 Nov 2020 18:31:35 +0100 Subject: [PATCH 065/205] Validate email before inserting/updating (#13475) (#13666) * Add email validity check (#13475) * Improve error feedback for duplicate deploy keys Instead of a generic HTTP 500 error page, a flash message is rendered with the deploy key page template so inform the user that a key with the intended title already exists. * API returns 422 error when key with name exists * Add email validity checking Add email validity checking for the following routes: [Web interface] 1. User registration 2. User creation by admin 3. Adding an email through user settings [API] 1. POST /admin/users 2. PATCH /admin/users/:username 3. POST /user/emails * Add further tests * Add signup email tests * Add email validity check for linking existing account * Address PR comments * Remove unneeded DB session * Move email check to updateUser Co-authored-by: zeripath Co-authored-by: Lunny Xiao Co-authored-by: techknowlogick * skip email validation on empty string (#13627) - move validation into its own function - use a session for UpdateUserSetting * rm TODO for backport Co-authored-by: Chris Shyi Co-authored-by: zeripath Co-authored-by: Lunny Xiao Co-authored-by: techknowlogick --- integrations/api_admin_test.go | 19 +++++++++++++++++ integrations/signup_test.go | 38 +++++++++++++++++++++++++++++++++ models/error.go | 15 +++++++++++++ models/user.go | 26 +++++++++++++++++----- models/user_mail.go | 21 ++++++++++++++++++ models/user_test.go | 15 +++++++++++++ options/locale/locale_en-US.ini | 1 + routers/admin/users.go | 6 ++++++ routers/admin/users_test.go | 30 ++++++++++++++++++++++++++ routers/api/v1/admin/user.go | 3 ++- routers/api/v1/user/email.go | 4 ++++ routers/user/auth.go | 6 ++++++ routers/user/setting/account.go | 5 +++++ 13 files changed, 183 insertions(+), 6 deletions(-) diff --git a/integrations/api_admin_test.go b/integrations/api_admin_test.go index 9ff9d71493..80d6b52289 100644 --- a/integrations/api_admin_test.go +++ b/integrations/api_admin_test.go @@ -144,3 +144,22 @@ func TestAPIListUsersNonAdmin(t *testing.T) { req := NewRequestf(t, "GET", "/api/v1/admin/users?token=%s", token) session.MakeRequest(t, req, http.StatusForbidden) } + +func TestAPICreateUserInvalidEmail(t *testing.T) { + defer prepareTestEnv(t)() + adminUsername := "user1" + session := loginUser(t, adminUsername) + token := getTokenForLoggedInUser(t, session) + urlStr := fmt.Sprintf("/api/v1/admin/users?token=%s", token) + req := NewRequestWithValues(t, "POST", urlStr, map[string]string{ + "email": "invalid_email@domain.com\r\n", + "full_name": "invalid user", + "login_name": "invalidUser", + "must_change_password": "true", + "password": "password", + "send_notify": "true", + "source_id": "0", + "username": "invalidUser", + }) + session.MakeRequest(t, req, http.StatusUnprocessableEntity) +} diff --git a/integrations/signup_test.go b/integrations/signup_test.go index 02262ec853..5208a42ce5 100644 --- a/integrations/signup_test.go +++ b/integrations/signup_test.go @@ -5,10 +5,14 @@ package integrations import ( + "fmt" "net/http" + "strings" "testing" "code.gitea.io/gitea/modules/setting" + "github.com/stretchr/testify/assert" + "github.com/unknwon/i18n" ) func TestSignup(t *testing.T) { @@ -28,3 +32,37 @@ func TestSignup(t *testing.T) { req = NewRequest(t, "GET", "/exampleUser") MakeRequest(t, req, http.StatusOK) } + +func TestSignupEmail(t *testing.T) { + defer prepareTestEnv(t)() + + setting.Service.EnableCaptcha = false + + tests := []struct { + email string + wantStatus int + wantMsg string + }{ + {"exampleUser@example.com\r\n", http.StatusOK, i18n.Tr("en", "form.email_invalid", nil)}, + {"exampleUser@example.com\r", http.StatusOK, i18n.Tr("en", "form.email_invalid", nil)}, + {"exampleUser@example.com\n", http.StatusOK, i18n.Tr("en", "form.email_invalid", nil)}, + {"exampleUser@example.com", http.StatusFound, ""}, + } + + for i, test := range tests { + req := NewRequestWithValues(t, "POST", "/user/sign_up", map[string]string{ + "user_name": fmt.Sprintf("exampleUser%d", i), + "email": test.email, + "password": "examplePassword!1", + "retype": "examplePassword!1", + }) + resp := MakeRequest(t, req, test.wantStatus) + if test.wantMsg != "" { + htmlDoc := NewHTMLParser(t, resp.Body) + assert.Equal(t, + test.wantMsg, + strings.TrimSpace(htmlDoc.doc.Find(".ui.message").Text()), + ) + } + } +} diff --git a/models/error.go b/models/error.go index b2273f74c9..83354ff173 100644 --- a/models/error.go +++ b/models/error.go @@ -193,6 +193,21 @@ func (err ErrEmailAlreadyUsed) Error() string { return fmt.Sprintf("e-mail already in use [email: %s]", err.Email) } +// ErrEmailInvalid represents an error where the email address does not comply with RFC 5322 +type ErrEmailInvalid struct { + Email string +} + +// IsErrEmailInvalid checks if an error is an ErrEmailInvalid +func IsErrEmailInvalid(err error) bool { + _, ok := err.(ErrEmailInvalid) + return ok +} + +func (err ErrEmailInvalid) Error() string { + return fmt.Sprintf("e-mail invalid [email: %s]", err.Email) +} + // ErrOpenIDAlreadyUsed represents a "OpenIDAlreadyUsed" kind of error. type ErrOpenIDAlreadyUsed struct { OpenID string diff --git a/models/user.go b/models/user.go index 1ab417115f..b2abdca964 100644 --- a/models/user.go +++ b/models/user.go @@ -821,6 +821,10 @@ func CreateUser(u *User) (err error) { return ErrEmailAlreadyUsed{u.Email} } + if err = ValidateEmail(u.Email); err != nil { + return err + } + isExist, err = isEmailUsed(sess, u.Email) if err != nil { return err @@ -963,8 +967,12 @@ func checkDupEmail(e Engine, u *User) error { return nil } -func updateUser(e Engine, u *User) error { - _, err := e.ID(u.ID).AllCols().Update(u) +func updateUser(e Engine, u *User) (err error) { + u.Email = strings.ToLower(u.Email) + if err = ValidateEmail(u.Email); err != nil { + return err + } + _, err = e.ID(u.ID).AllCols().Update(u) return err } @@ -984,13 +992,21 @@ func updateUserCols(e Engine, u *User, cols ...string) error { } // UpdateUserSetting updates user's settings. -func UpdateUserSetting(u *User) error { +func UpdateUserSetting(u *User) (err error) { + sess := x.NewSession() + defer sess.Close() + if err = sess.Begin(); err != nil { + return err + } if !u.IsOrganization() { - if err := checkDupEmail(x, u); err != nil { + if err = checkDupEmail(sess, u); err != nil { return err } } - return updateUser(x, u) + if err = updateUser(sess, u); err != nil { + return err + } + return sess.Commit() } // deleteBeans deletes all given beans, beans should contain delete conditions. diff --git a/models/user_mail.go b/models/user_mail.go index 60354e23ff..29a73f13f2 100644 --- a/models/user_mail.go +++ b/models/user_mail.go @@ -8,6 +8,7 @@ package models import ( "errors" "fmt" + "net/mail" "strings" "code.gitea.io/gitea/modules/log" @@ -32,6 +33,19 @@ type EmailAddress struct { IsPrimary bool `xorm:"-"` } +// ValidateEmail check if email is a allowed address +func ValidateEmail(email string) error { + if len(email) == 0 { + return nil + } + + if _, err := mail.ParseAddress(email); err != nil { + return ErrEmailInvalid{email} + } + + return nil +} + // GetEmailAddresses returns all email addresses belongs to given user. func GetEmailAddresses(uid int64) ([]*EmailAddress, error) { emails := make([]*EmailAddress, 0, 5) @@ -143,6 +157,10 @@ func addEmailAddress(e Engine, email *EmailAddress) error { return ErrEmailAlreadyUsed{email.Email} } + if err = ValidateEmail(email.Email); err != nil { + return err + } + _, err = e.Insert(email) return err } @@ -167,6 +185,9 @@ func AddEmailAddresses(emails []*EmailAddress) error { } else if used { return ErrEmailAlreadyUsed{emails[i].Email} } + if err = ValidateEmail(emails[i].Email); err != nil { + return err + } } if _, err := x.Insert(emails); err != nil { diff --git a/models/user_test.go b/models/user_test.go index d03ef4fad4..b9fe99278c 100644 --- a/models/user_test.go +++ b/models/user_test.go @@ -346,6 +346,21 @@ func TestCreateUser(t *testing.T) { assert.NoError(t, DeleteUser(user)) } +func TestCreateUserInvalidEmail(t *testing.T) { + user := &User{ + Name: "GiteaBot", + Email: "GiteaBot@gitea.io\r\n", + Passwd: ";p['////..-++']", + IsAdmin: false, + Theme: setting.UI.DefaultTheme, + MustChangePassword: false, + } + + err := CreateUser(user) + assert.Error(t, err) + assert.True(t, IsErrEmailInvalid(err)) +} + func TestCreateUser_Issue5882(t *testing.T) { // Init settings diff --git a/options/locale/locale_en-US.ini b/options/locale/locale_en-US.ini index 18c621db67..1f5e2a35d2 100644 --- a/options/locale/locale_en-US.ini +++ b/options/locale/locale_en-US.ini @@ -366,6 +366,7 @@ org_name_been_taken = The organization name is already taken. team_name_been_taken = The team name is already taken. team_no_units_error = Allow access to at least one repository section. email_been_used = The email address is already used. +email_invalid = The email address is invalid. openid_been_used = The OpenID address '%s' is already used. username_password_incorrect = Username or password is incorrect. password_complexity = Password does not pass complexity requirements: diff --git a/routers/admin/users.go b/routers/admin/users.go index 9fb758621b..4382ee3877 100644 --- a/routers/admin/users.go +++ b/routers/admin/users.go @@ -129,6 +129,9 @@ func NewUserPost(ctx *context.Context, form auth.AdminCreateUserForm) { case models.IsErrEmailAlreadyUsed(err): ctx.Data["Err_Email"] = true ctx.RenderWithErr(ctx.Tr("form.email_been_used"), tplUserNew, &form) + case models.IsErrEmailInvalid(err): + ctx.Data["Err_Email"] = true + ctx.RenderWithErr(ctx.Tr("form.email_invalid"), tplUserNew, &form) case models.IsErrNameReserved(err): ctx.Data["Err_UserName"] = true ctx.RenderWithErr(ctx.Tr("user.form.name_reserved", err.(models.ErrNameReserved).Name), tplUserNew, &form) @@ -277,6 +280,9 @@ func EditUserPost(ctx *context.Context, form auth.AdminEditUserForm) { if models.IsErrEmailAlreadyUsed(err) { ctx.Data["Err_Email"] = true ctx.RenderWithErr(ctx.Tr("form.email_been_used"), tplUserEdit, &form) + } else if models.IsErrEmailInvalid(err) { + ctx.Data["Err_Email"] = true + ctx.RenderWithErr(ctx.Tr("form.email_invalid"), tplUserEdit, &form) } else { ctx.ServerError("UpdateUser", err) } diff --git a/routers/admin/users_test.go b/routers/admin/users_test.go index 2b36b45d49..a282507f56 100644 --- a/routers/admin/users_test.go +++ b/routers/admin/users_test.go @@ -87,3 +87,33 @@ func TestNewUserPost_MustChangePasswordFalse(t *testing.T) { assert.Equal(t, email, u.Email) assert.False(t, u.MustChangePassword) } + +func TestNewUserPost_InvalidEmail(t *testing.T) { + + models.PrepareTestEnv(t) + ctx := test.MockContext(t, "admin/users/new") + + u := models.AssertExistsAndLoadBean(t, &models.User{ + IsAdmin: true, + ID: 2, + }).(*models.User) + + ctx.User = u + + username := "gitea" + email := "gitea@gitea.io\r\n" + + form := auth.AdminCreateUserForm{ + LoginType: "local", + LoginName: "local", + UserName: username, + Email: email, + Password: "abc123ABC!=$", + SendNotify: false, + MustChangePassword: false, + } + + NewUserPost(ctx, form) + + assert.NotEmpty(t, ctx.Flash.ErrorMsg) +} diff --git a/routers/api/v1/admin/user.go b/routers/api/v1/admin/user.go index dc095f3a13..c4b52e4bd6 100644 --- a/routers/api/v1/admin/user.go +++ b/routers/api/v1/admin/user.go @@ -101,6 +101,7 @@ func CreateUser(ctx *context.APIContext, form api.CreateUserOption) { models.IsErrEmailAlreadyUsed(err) || models.IsErrNameReserved(err) || models.IsErrNameCharsNotAllowed(err) || + models.IsErrEmailInvalid(err) || models.IsErrNamePatternNotAllowed(err) { ctx.Error(http.StatusUnprocessableEntity, "", err) } else { @@ -208,7 +209,7 @@ func EditUser(ctx *context.APIContext, form api.EditUserOption) { } if err := models.UpdateUser(u); err != nil { - if models.IsErrEmailAlreadyUsed(err) { + if models.IsErrEmailAlreadyUsed(err) || models.IsErrEmailInvalid(err) { ctx.Error(http.StatusUnprocessableEntity, "", err) } else { ctx.Error(http.StatusInternalServerError, "UpdateUser", err) diff --git a/routers/api/v1/user/email.go b/routers/api/v1/user/email.go index 07fcde625e..d848f5e58d 100644 --- a/routers/api/v1/user/email.go +++ b/routers/api/v1/user/email.go @@ -5,6 +5,7 @@ package user import ( + "fmt" "net/http" "code.gitea.io/gitea/models" @@ -78,6 +79,9 @@ func AddEmail(ctx *context.APIContext, form api.CreateEmailOption) { if err := models.AddEmailAddresses(emails); err != nil { if models.IsErrEmailAlreadyUsed(err) { ctx.Error(http.StatusUnprocessableEntity, "", "Email address has been used: "+err.(models.ErrEmailAlreadyUsed).Email) + } else if models.IsErrEmailInvalid(err) { + errMsg := fmt.Sprintf("Email address %s invalid", err.(models.ErrEmailInvalid).Email) + ctx.Error(http.StatusUnprocessableEntity, "", errMsg) } else { ctx.Error(http.StatusInternalServerError, "AddEmailAddresses", err) } diff --git a/routers/user/auth.go b/routers/user/auth.go index 32b031fc74..ba6420967f 100644 --- a/routers/user/auth.go +++ b/routers/user/auth.go @@ -964,6 +964,9 @@ func LinkAccountPostRegister(ctx *context.Context, cpt *captcha.Captcha, form au case models.IsErrEmailAlreadyUsed(err): ctx.Data["Err_Email"] = true ctx.RenderWithErr(ctx.Tr("form.email_been_used"), tplLinkAccount, &form) + case models.IsErrEmailInvalid(err): + ctx.Data["Err_Email"] = true + ctx.RenderWithErr(ctx.Tr("form.email_invalid"), tplSignUp, &form) case models.IsErrNameReserved(err): ctx.Data["Err_UserName"] = true ctx.RenderWithErr(ctx.Tr("user.form.name_reserved", err.(models.ErrNameReserved).Name), tplLinkAccount, &form) @@ -1151,6 +1154,9 @@ func SignUpPost(ctx *context.Context, cpt *captcha.Captcha, form auth.RegisterFo case models.IsErrEmailAlreadyUsed(err): ctx.Data["Err_Email"] = true ctx.RenderWithErr(ctx.Tr("form.email_been_used"), tplSignUp, &form) + case models.IsErrEmailInvalid(err): + ctx.Data["Err_Email"] = true + ctx.RenderWithErr(ctx.Tr("form.email_invalid"), tplSignUp, &form) case models.IsErrNameReserved(err): ctx.Data["Err_UserName"] = true ctx.RenderWithErr(ctx.Tr("user.form.name_reserved", err.(models.ErrNameReserved).Name), tplSignUp, &form) diff --git a/routers/user/setting/account.go b/routers/user/setting/account.go index 99e20177bc..9b72e2a31a 100644 --- a/routers/user/setting/account.go +++ b/routers/user/setting/account.go @@ -179,6 +179,11 @@ func EmailPost(ctx *context.Context, form auth.AddEmailForm) { ctx.RenderWithErr(ctx.Tr("form.email_been_used"), tplSettingsAccount, &form) return + } else if models.IsErrEmailInvalid(err) { + loadAccountData(ctx) + + ctx.RenderWithErr(ctx.Tr("form.email_invalid"), tplSettingsAccount, &form) + return } ctx.ServerError("AddEmailAddress", err) return From 4c9d00cf78702aacba63cc8ad8689f9a202df58c Mon Sep 17 00:00:00 2001 From: 6543 <6543@obermui.de> Date: Mon, 23 Nov 2020 17:40:58 +0100 Subject: [PATCH 066/205] finaly fix gitlab migration with subdir 2.0 (#13646) (#13678) * final fix 2.0? * ignore Approvals for pulls if not found * CI.restart() Co-authored-by: Lauris BH Co-authored-by: Lauris BH --- modules/migrations/gitlab.go | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/modules/migrations/gitlab.go b/modules/migrations/gitlab.go index c510944f6f..b1027c4f64 100644 --- a/modules/migrations/gitlab.go +++ b/modules/migrations/gitlab.go @@ -92,7 +92,7 @@ func NewGitlabDownloader(ctx context.Context, baseURL, repoPath, username, passw pathParts := strings.Split(strings.Trim(repoPath, "/"), "/") var resp *gitlab.Response u, _ := url.Parse(baseURL) - for len(pathParts) > 2 { + for len(pathParts) >= 2 { _, resp, err = gitlabClient.Version.GetVersion() if err == nil || resp != nil && resp.StatusCode == 401 { err = nil // if no authentication given, this still should work @@ -609,8 +609,12 @@ func (g *GitlabDownloader) GetPullRequests(page, perPage int) ([]*base.PullReque // GetReviews returns pull requests review func (g *GitlabDownloader) GetReviews(pullRequestNumber int64) ([]*base.Review, error) { - state, _, err := g.client.MergeRequestApprovals.GetApprovalState(g.repoID, int(pullRequestNumber), gitlab.WithContext(g.ctx)) + state, resp, err := g.client.MergeRequestApprovals.GetApprovalState(g.repoID, int(pullRequestNumber), gitlab.WithContext(g.ctx)) if err != nil { + if resp != nil && resp.StatusCode == 404 { + log.Error(fmt.Sprintf("GitlabDownloader: while migrating a error occurred: '%s'", err.Error())) + return []*base.Review{}, nil + } return nil, err } From 7ec1c13f53f35d422343185d2ab8cf379e24c14e Mon Sep 17 00:00:00 2001 From: silverwind Date: Tue, 24 Nov 2020 18:45:24 +0100 Subject: [PATCH 067/205] CSS table fixes (#13693) Backport https://github.com/go-gitea/gitea/pull/13692 to 1.13. --- web_src/less/themes/theme-arc-green.less | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/web_src/less/themes/theme-arc-green.less b/web_src/less/themes/theme-arc-green.less index 89a69c241b..91132575dc 100644 --- a/web_src/less/themes/theme-arc-green.less +++ b/web_src/less/themes/theme-arc-green.less @@ -893,6 +893,11 @@ a.ui.basic.green.label:hover { color: #dbdbdb !important; } +.ui.ui.ui.ui.table tr.grey:not(.marked), +.ui.ui.table td.grey:not(.marked) { + background: none; +} + .repository.file.list #repo-files-table tr { background: #2a2e3a; } From a82c7d4323b498315e7261b9af7c8a6e7452a537 Mon Sep 17 00:00:00 2001 From: John Olheiser Date: Fri, 27 Nov 2020 22:55:53 -0600 Subject: [PATCH 068/205] Increment skip to avoid infini-loop (#13703) (#13727) Signed-off-by: jolheiser Co-authored-by: Lauris BH Co-authored-by: Lauris BH --- services/pull/pull.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/pull/pull.go b/services/pull/pull.go index 61af7fe9a5..c578686bd8 100644 --- a/services/pull/pull.go +++ b/services/pull/pull.go @@ -609,7 +609,7 @@ func GetCommitMessages(pr *models.PullRequest) string { } element = element.Next() } - + skip += limit } } From bdb491e76441a323ecd02c4650e2d2bf6a15d495 Mon Sep 17 00:00:00 2001 From: zeripath Date: Sat, 28 Nov 2020 21:59:32 +0000 Subject: [PATCH 069/205] Push HEAD instead of master when initialising repositories (#13719) (#13740) * Push HEAD instead of master when initialising repositories It is possible on modern gits to change the initial branch to something other than master. This breaks initialising repositories because we assume that the initial branch is going to be master unless specifically changed. This PR simply bypasses this issue by pushing the HEAD rather than the master branch. Signed-off-by: Andrew Thornton * Update modules/repository/init.go Co-authored-by: mrsdizzie Co-authored-by: mrsdizzie Co-authored-by: techknowlogick Co-authored-by: mrsdizzie Co-authored-by: techknowlogick --- modules/repository/init.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/repository/init.go b/modules/repository/init.go index 707f8f5250..9df2cd42b0 100644 --- a/modules/repository/init.go +++ b/modules/repository/init.go @@ -162,10 +162,10 @@ func initRepoCommit(tmpPath string, repo *models.Repository, u *models.User, def defaultBranch = setting.Repository.DefaultBranch } - if stdout, err := git.NewCommand("push", "origin", "master:"+defaultBranch). + if stdout, err := git.NewCommand("push", "origin", "HEAD:"+defaultBranch). SetDescription(fmt.Sprintf("initRepoCommit (git push): %s", tmpPath)). RunInDirWithEnv(tmpPath, models.InternalPushingEnvironment(u, repo)); err != nil { - log.Error("Failed to push back to master: Stdout: %s\nError: %v", stdout, err) + log.Error("Failed to push back to HEAD: Stdout: %s\nError: %v", stdout, err) return fmt.Errorf("git push: %v", err) } From 25421f08c0448d8695ea7546038db18579a82541 Mon Sep 17 00:00:00 2001 From: a1012112796 <1012112796@qq.com> Date: Sun, 29 Nov 2020 20:50:58 +0800 Subject: [PATCH 070/205] ui: show 'owner' tag for real owner (#13689) (#13743) * ui: show 'owner' tag for real owner Signed-off-by: a1012112796 <1012112796@qq.com> * Update custom/conf/app.example.ini * simplify logic fix logic fix a small bug about original author * remove system manager tag Co-authored-by: techknowlogick Co-authored-by: Lauris BH --- models/repo_permission.go | 21 +++++++++++++++++ routers/repo/issue.go | 23 +++++++++++++++++-- .../repo/issue/view_content/comments.tmpl | 2 +- 3 files changed, 43 insertions(+), 3 deletions(-) diff --git a/models/repo_permission.go b/models/repo_permission.go index 7768bb6257..138613b2e9 100644 --- a/models/repo_permission.go +++ b/models/repo_permission.go @@ -271,6 +271,27 @@ func getUserRepoPermission(e Engine, repo *Repository, user *User) (perm Permiss return } +// IsUserRealRepoAdmin check if this user is real repo admin +func IsUserRealRepoAdmin(repo *Repository, user *User) (bool, error) { + if repo.OwnerID == user.ID { + return true, nil + } + + sess := x.NewSession() + defer sess.Close() + + if err := repo.getOwner(sess); err != nil { + return false, err + } + + accessMode, err := accessLevel(sess, user, repo) + if err != nil { + return false, err + } + + return accessMode >= AccessModeAdmin, nil +} + // IsUserRepoAdmin return true if user has admin right of a repo func IsUserRepoAdmin(repo *Repository, user *User) (bool, error) { return isUserRepoAdmin(x, repo, user) diff --git a/routers/repo/issue.go b/routers/repo/issue.go index cbedde5760..3792a44a8d 100644 --- a/routers/repo/issue.go +++ b/routers/repo/issue.go @@ -979,8 +979,27 @@ func commentTag(repo *models.Repository, poster *models.User, issue *models.Issu return models.CommentTagNone, err } if perm.IsOwner() { - return models.CommentTagOwner, nil - } else if perm.CanWrite(models.UnitTypeCode) { + if !poster.IsAdmin { + return models.CommentTagOwner, nil + } + + ok, err := models.IsUserRealRepoAdmin(repo, poster) + if err != nil { + return models.CommentTagNone, err + } + + if ok { + return models.CommentTagOwner, nil + } + + if ok, err = repo.IsCollaborator(poster.ID); ok && err == nil { + return models.CommentTagWriter, nil + } + + return models.CommentTagNone, err + } + + if perm.CanWrite(models.UnitTypeCode) { return models.CommentTagWriter, nil } diff --git a/templates/repo/issue/view_content/comments.tmpl b/templates/repo/issue/view_content/comments.tmpl index e3fc076b74..2e4a6681cd 100644 --- a/templates/repo/issue/view_content/comments.tmpl +++ b/templates/repo/issue/view_content/comments.tmpl @@ -29,7 +29,7 @@
{{if not $.Repository.IsArchived}} - {{if eq .PosterID .Issue.PosterID }} + {{if or (and (eq .PosterID .Issue.PosterID) (eq .Issue.OriginalAuthorID 0)) (eq .Issue.OriginalAuthorID .OriginalAuthorID) }}
{{$.i18n.Tr "repo.issues.poster"}}
From 6e14773c44d5c85e4786c08fde32786092570385 Mon Sep 17 00:00:00 2001 From: silverwind Date: Mon, 30 Nov 2020 20:51:48 +0100 Subject: [PATCH 071/205] Fix bogus http requests on diffs (#13760) (#13761) The .blob-excerpt elements don't have these data attributes in some cases resulting in bogus http request when expanding a diff and clicking into the expanded area. This prevents those. Should backport to 1.13. Fixes: https://github.com/go-gitea/gitea/issues/13759 --- web_src/js/index.js | 1 + 1 file changed, 1 insertion(+) diff --git a/web_src/js/index.js b/web_src/js/index.js index 1c479d0e7d..2e7b13cb64 100644 --- a/web_src/js/index.js +++ b/web_src/js/index.js @@ -2089,6 +2089,7 @@ function initCodeView() { }); $(document).on('click', '.blob-excerpt', async ({currentTarget}) => { const {url, query, anchor} = currentTarget.dataset; + if (!url) return; const blob = await $.get(`${url}?${query}&anchor=${anchor}`); currentTarget.closest('tr').outerHTML = blob; }); From d475b656b1e80e0f0f67c10416fb0b6621b66d3b Mon Sep 17 00:00:00 2001 From: silverwind Date: Tue, 1 Dec 2020 02:55:38 +0100 Subject: [PATCH 072/205] Set RUN_MODE prod by default (#13765) (#13767) * Set RUN_MODE prod by default (#13765) I think it's a bad default to have "dev" as the default run mode which enables debugging and now also disables HTTP caching. It's better to just default to a value suitable for general deployments. Co-authored-by: techknowlogick * flip default in checkRunMode Co-authored-by: techknowlogick --- custom/conf/app.example.ini | 4 ++-- docker/root/etc/s6/gitea/setup | 2 +- docs/content/doc/advanced/config-cheat-sheet.en-us.md | 4 +--- docs/content/doc/installation/with-docker.en-us.md | 2 +- routers/init.go | 8 +++++--- 5 files changed, 10 insertions(+), 10 deletions(-) diff --git a/custom/conf/app.example.ini b/custom/conf/app.example.ini index dc273ced80..2c083dd9eb 100644 --- a/custom/conf/app.example.ini +++ b/custom/conf/app.example.ini @@ -8,8 +8,8 @@ APP_NAME = Gitea: Git with a cup of tea ; Change it if you run locally RUN_USER = git -; Either "dev", "prod" or "test", default is "dev" -RUN_MODE = dev +; Application run mode, affects performance and debugging. Either "dev", "prod" or "test", default is "prod" +RUN_MODE = prod [project] ; Default templates for project boards diff --git a/docker/root/etc/s6/gitea/setup b/docker/root/etc/s6/gitea/setup index 892fa7fd2b..4449420b99 100755 --- a/docker/root/etc/s6/gitea/setup +++ b/docker/root/etc/s6/gitea/setup @@ -25,7 +25,7 @@ if [ ! -f ${GITEA_CUSTOM}/conf/app.ini ]; then # Substitude the environment variables in the template APP_NAME=${APP_NAME:-"Gitea: Git with a cup of tea"} \ - RUN_MODE=${RUN_MODE:-"dev"} \ + RUN_MODE=${RUN_MODE:-"prod"} \ DOMAIN=${DOMAIN:-"localhost"} \ SSH_DOMAIN=${SSH_DOMAIN:-"localhost"} \ HTTP_PORT=${HTTP_PORT:-"3000"} \ diff --git a/docs/content/doc/advanced/config-cheat-sheet.en-us.md b/docs/content/doc/advanced/config-cheat-sheet.en-us.md index bdd872b0bf..28c957c8d4 100644 --- a/docs/content/doc/advanced/config-cheat-sheet.en-us.md +++ b/docs/content/doc/advanced/config-cheat-sheet.en-us.md @@ -36,9 +36,7 @@ Values containing `#` or `;` must be quoted using `` ` `` or `"""`. - `APP_NAME`: **Gitea: Git with a cup of tea**: Application name, used in the page title. - `RUN_USER`: **git**: The user Gitea will run as. This should be a dedicated system (non-user) account. Setting this incorrectly will cause Gitea to not start. -- `RUN_MODE`: **dev**: For performance and other purposes, change this to `prod` when - deployed to a production environment. The installation process will set this to `prod` - automatically. \[prod, dev, test\] +- `RUN_MODE`: **prod**: Application run mode, affects performance and debugging. Either "dev", "prod" or "test". ## Repository (`repository`) diff --git a/docs/content/doc/installation/with-docker.en-us.md b/docs/content/doc/installation/with-docker.en-us.md index 7d57c24975..2f38452150 100644 --- a/docs/content/doc/installation/with-docker.en-us.md +++ b/docs/content/doc/installation/with-docker.en-us.md @@ -257,7 +257,7 @@ You can configure some of Gitea's settings via environment variables: (Default values are provided in **bold**) * `APP_NAME`: **"Gitea: Git with a cup of tea"**: Application name, used in the page title. -* `RUN_MODE`: **dev**: For performance and other purposes, change this to `prod` when deployed to a production environment. +* `RUN_MODE`: **prod**: Application run mode, affects performance and debugging. Either "dev", "prod" or "test". * `DOMAIN`: **localhost**: Domain name of this server, used for the displayed http clone URL in Gitea's UI. * `SSH_DOMAIN`: **localhost**: Domain name of this server, used for the displayed ssh clone URL in Gitea's UI. If the install page is enabled, SSH Domain Server takes DOMAIN value in the form (which overwrite this setting on save). * `SSH_PORT`: **22**: SSH port displayed in clone URL. diff --git a/routers/init.go b/routers/init.go index 793033f4a4..faa84fb0c9 100644 --- a/routers/init.go +++ b/routers/init.go @@ -43,12 +43,14 @@ import ( func checkRunMode() { switch setting.Cfg.Section("").Key("RUN_MODE").String() { - case "prod": + case "dev": + git.Debug = true + case "test": + git.Debug = true + default: macaron.Env = macaron.PROD macaron.ColorLog = false setting.ProdMode = true - default: - git.Debug = true } log.Info("Run Mode: %s", strings.Title(macaron.Env)) } From 07629bd55cb9bf71459dcdf2eb3feaa5d24cfeca Mon Sep 17 00:00:00 2001 From: 6543 <6543@obermui.de> Date: Wed, 2 Dec 2020 01:28:34 +0100 Subject: [PATCH 073/205] Add Allow-/Block-List for Migrate & Mirrors (#13610) (#13776) * add black list and white list support for migrating repositories * specify log message * use blocklist/allowlist * allways use lowercase to match url * Apply allow/block * Settings: use existing "migrations" section * convert domains lower case * dont store unused value * Block private addresses for migration by default * use proposed-upstream func to detect private IP addr * add own error for blocked migration, add tests, imprufe api * fix test * fix-if-localhost-is-ipv4 * rename error & error message * rename setting options * Apply suggestions from code review Co-authored-by: Lunny Xiao Co-authored-by: zeripath Co-authored-by: techknowlogick Co-authored-by: Lunny Xiao Co-authored-by: zeripath Co-authored-by: techknowlogick --- custom/conf/app.example.ini | 8 ++ .../doc/advanced/config-cheat-sheet.en-us.md | 3 + .../doc/advanced/config-cheat-sheet.zh-cn.md | 3 + integrations/api_repo_test.go | 12 ++- models/error.go | 23 ++++++ modules/matchlist/matchlist.go | 46 ++++++++++++ modules/migrations/migrate.go | 75 ++++++++++++++++++- modules/migrations/migrate_test.go | 34 +++++++++ modules/setting/migrations.go | 22 +++++- routers/api/v1/repo/migrate.go | 2 + routers/init.go | 5 ++ 11 files changed, 229 insertions(+), 4 deletions(-) create mode 100644 modules/matchlist/matchlist.go create mode 100644 modules/migrations/migrate_test.go diff --git a/custom/conf/app.example.ini b/custom/conf/app.example.ini index 2c083dd9eb..529ccea937 100644 --- a/custom/conf/app.example.ini +++ b/custom/conf/app.example.ini @@ -1188,6 +1188,14 @@ QUEUE_CONN_STR = "addrs=127.0.0.1:6379 db=0" MAX_ATTEMPTS = 3 ; Backoff time per http/https request retry (seconds) RETRY_BACKOFF = 3 +; Allowed domains for migrating, default is blank. Blank means everything will be allowed. +; Multiple domains could be separated by commas. +ALLOWED_DOMAINS = +; Blocklist for migrating, default is blank. Multiple domains could be separated by commas. +; When ALLOWED_DOMAINS is not blank, this option will be ignored. +BLOCKED_DOMAINS = +; Allow private addresses defined by RFC 1918, RFC 1122, RFC 4632 and RFC 4291 (false by default) +ALLOW_LOCALNETWORKS = false ; default storage for attachments, lfs and avatars [storage] diff --git a/docs/content/doc/advanced/config-cheat-sheet.en-us.md b/docs/content/doc/advanced/config-cheat-sheet.en-us.md index 28c957c8d4..ca09d4f032 100644 --- a/docs/content/doc/advanced/config-cheat-sheet.en-us.md +++ b/docs/content/doc/advanced/config-cheat-sheet.en-us.md @@ -811,6 +811,9 @@ Task queue configuration has been moved to `queue.task`. However, the below conf - `MAX_ATTEMPTS`: **3**: Max attempts per http/https request on migrations. - `RETRY_BACKOFF`: **3**: Backoff time per http/https request retry (seconds) +- `ALLOWED_DOMAINS`: **\**: Domains allowlist for migrating repositories, default is blank. It means everything will be allowed. Multiple domains could be separated by commas. +- `BLOCKED_DOMAINS`: **\**: Domains blocklist for migrating repositories, default is blank. Multiple domains could be separated by commas. When `ALLOWED_DOMAINS` is not blank, this option will be ignored. +- `ALLOW_LOCALNETWORKS`: **false**: Allow private addresses defined by RFC 1918, RFC 1122, RFC 4632 and RFC 4291 ## Mirror (`mirror`) diff --git a/docs/content/doc/advanced/config-cheat-sheet.zh-cn.md b/docs/content/doc/advanced/config-cheat-sheet.zh-cn.md index 505fdcdf71..597773a0ae 100644 --- a/docs/content/doc/advanced/config-cheat-sheet.zh-cn.md +++ b/docs/content/doc/advanced/config-cheat-sheet.zh-cn.md @@ -313,6 +313,9 @@ IS_INPUT_FILE = false - `MAX_ATTEMPTS`: **3**: 在迁移过程中的 http/https 请求重试次数。 - `RETRY_BACKOFF`: **3**: 等待下一次重试的时间,单位秒。 +- `ALLOWED_DOMAINS`: **\**: 迁移仓库的域名白名单,默认为空,表示允许从任意域名迁移仓库,多个域名用逗号分隔。 +- `BLOCKED_DOMAINS`: **\**: 迁移仓库的域名黑名单,默认为空,多个域名用逗号分隔。如果 `ALLOWED_DOMAINS` 不为空,此选项将会被忽略。 +- `ALLOW_LOCALNETWORKS`: **false**: Allow private addresses defined by RFC 1918 ## LFS (`lfs`) diff --git a/integrations/api_repo_test.go b/integrations/api_repo_test.go index c8afa73ae6..1aa45984e0 100644 --- a/integrations/api_repo_test.go +++ b/integrations/api_repo_test.go @@ -309,6 +309,8 @@ func TestAPIRepoMigrate(t *testing.T) { {ctxUserID: 2, userID: 1, cloneURL: "https://github.com/go-gitea/test_repo.git", repoName: "git-bad", expectedStatus: http.StatusForbidden}, {ctxUserID: 2, userID: 3, cloneURL: "https://github.com/go-gitea/test_repo.git", repoName: "git-org", expectedStatus: http.StatusCreated}, {ctxUserID: 2, userID: 6, cloneURL: "https://github.com/go-gitea/test_repo.git", repoName: "git-bad-org", expectedStatus: http.StatusForbidden}, + {ctxUserID: 2, userID: 3, cloneURL: "https://localhost:3000/user/test_repo.git", repoName: "local-ip", expectedStatus: http.StatusUnprocessableEntity}, + {ctxUserID: 2, userID: 3, cloneURL: "https://10.0.0.1/user/test_repo.git", repoName: "private-ip", expectedStatus: http.StatusUnprocessableEntity}, } defer prepareTestEnv(t)() @@ -325,8 +327,16 @@ func TestAPIRepoMigrate(t *testing.T) { if resp.Code == http.StatusUnprocessableEntity { respJSON := map[string]string{} DecodeJSON(t, resp, &respJSON) - if assert.Equal(t, respJSON["message"], "Remote visit addressed rate limitation.") { + switch respJSON["message"] { + case "Remote visit addressed rate limitation.": t.Log("test hit github rate limitation") + case "migrate from '10.0.0.1' is not allowed: the host resolve to a private ip address '10.0.0.1'": + assert.EqualValues(t, "private-ip", testCase.repoName) + case "migrate from 'localhost:3000' is not allowed: the host resolve to a private ip address '::1'", + "migrate from 'localhost:3000' is not allowed: the host resolve to a private ip address '127.0.0.1'": + assert.EqualValues(t, "local-ip", testCase.repoName) + default: + t.Errorf("unexpected error '%v' on url '%s'", respJSON["message"], testCase.cloneURL) } } else { assert.EqualValues(t, testCase.expectedStatus, resp.Code) diff --git a/models/error.go b/models/error.go index 83354ff173..7f1eda1b14 100644 --- a/models/error.go +++ b/models/error.go @@ -1019,6 +1019,29 @@ func IsErrWontSign(err error) bool { return ok } +// ErrMigrationNotAllowed explains why a migration from an url is not allowed +type ErrMigrationNotAllowed struct { + Host string + NotResolvedIP bool + PrivateNet string +} + +func (e *ErrMigrationNotAllowed) Error() string { + if e.NotResolvedIP { + return fmt.Sprintf("migrate from '%s' is not allowed: unknown hostname", e.Host) + } + if len(e.PrivateNet) != 0 { + return fmt.Sprintf("migrate from '%s' is not allowed: the host resolve to a private ip address '%s'", e.Host, e.PrivateNet) + } + return fmt.Sprintf("migrate from '%s is not allowed'", e.Host) +} + +// IsErrMigrationNotAllowed checks if an error is a ErrMigrationNotAllowed +func IsErrMigrationNotAllowed(err error) bool { + _, ok := err.(*ErrMigrationNotAllowed) + return ok +} + // __________ .__ // \______ \____________ ____ ____ | |__ // | | _/\_ __ \__ \ / \_/ ___\| | \ diff --git a/modules/matchlist/matchlist.go b/modules/matchlist/matchlist.go new file mode 100644 index 0000000000..b65ed909dc --- /dev/null +++ b/modules/matchlist/matchlist.go @@ -0,0 +1,46 @@ +// Copyright 2019 The Gitea Authors. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +package matchlist + +import ( + "strings" + + "github.com/gobwas/glob" +) + +// Matchlist represents a block or allow list +type Matchlist struct { + ruleGlobs []glob.Glob +} + +// NewMatchlist creates a new block or allow list +func NewMatchlist(rules ...string) (*Matchlist, error) { + for i := range rules { + rules[i] = strings.ToLower(rules[i]) + } + list := Matchlist{ + ruleGlobs: make([]glob.Glob, 0, len(rules)), + } + + for _, rule := range rules { + rg, err := glob.Compile(rule) + if err != nil { + return nil, err + } + list.ruleGlobs = append(list.ruleGlobs, rg) + } + + return &list, nil +} + +// Match will matches +func (b *Matchlist) Match(u string) bool { + for _, r := range b.ruleGlobs { + if r.Match(u) { + return true + } + } + return false +} diff --git a/modules/migrations/migrate.go b/modules/migrations/migrate.go index 3c505d82b6..b3ecb8114a 100644 --- a/modules/migrations/migrate.go +++ b/modules/migrations/migrate.go @@ -8,9 +8,13 @@ package migrations import ( "context" "fmt" + "net" + "net/url" + "strings" "code.gitea.io/gitea/models" "code.gitea.io/gitea/modules/log" + "code.gitea.io/gitea/modules/matchlist" "code.gitea.io/gitea/modules/migrations/base" "code.gitea.io/gitea/modules/setting" ) @@ -20,6 +24,9 @@ type MigrateOptions = base.MigrateOptions var ( factories []base.DownloaderFactory + + allowList *matchlist.Matchlist + blockList *matchlist.Matchlist ) // RegisterDownloaderFactory registers a downloader factory @@ -27,12 +34,49 @@ func RegisterDownloaderFactory(factory base.DownloaderFactory) { factories = append(factories, factory) } +func isMigrateURLAllowed(remoteURL string) error { + u, err := url.Parse(strings.ToLower(remoteURL)) + if err != nil { + return err + } + + if strings.EqualFold(u.Scheme, "http") || strings.EqualFold(u.Scheme, "https") { + if len(setting.Migrations.AllowedDomains) > 0 { + if !allowList.Match(u.Host) { + return &models.ErrMigrationNotAllowed{Host: u.Host} + } + } else { + if blockList.Match(u.Host) { + return &models.ErrMigrationNotAllowed{Host: u.Host} + } + } + } + + if !setting.Migrations.AllowLocalNetworks { + addrList, err := net.LookupIP(strings.Split(u.Host, ":")[0]) + if err != nil { + return &models.ErrMigrationNotAllowed{Host: u.Host, NotResolvedIP: true} + } + for _, addr := range addrList { + if isIPPrivate(addr) || !addr.IsGlobalUnicast() { + return &models.ErrMigrationNotAllowed{Host: u.Host, PrivateNet: addr.String()} + } + } + } + + return nil +} + // MigrateRepository migrate repository according MigrateOptions func MigrateRepository(ctx context.Context, doer *models.User, ownerName string, opts base.MigrateOptions) (*models.Repository, error) { + err := isMigrateURLAllowed(opts.CloneAddr) + if err != nil { + return nil, err + } + var ( downloader base.Downloader uploader = NewGiteaLocalUploader(ctx, doer, ownerName, opts.RepoName) - err error ) for _, factory := range factories { @@ -308,3 +352,32 @@ func migrateRepository(downloader base.Downloader, uploader base.Uploader, opts return nil } + +// Init migrations service +func Init() error { + var err error + allowList, err = matchlist.NewMatchlist(setting.Migrations.AllowedDomains...) + if err != nil { + return fmt.Errorf("init migration allowList domains failed: %v", err) + } + + blockList, err = matchlist.NewMatchlist(setting.Migrations.BlockedDomains...) + if err != nil { + return fmt.Errorf("init migration blockList domains failed: %v", err) + } + + return nil +} + +// isIPPrivate reports whether ip is a private address, according to +// RFC 1918 (IPv4 addresses) and RFC 4193 (IPv6 addresses). +// from https://github.com/golang/go/pull/42793 +// TODO remove if https://github.com/golang/go/issues/29146 got resolved +func isIPPrivate(ip net.IP) bool { + if ip4 := ip.To4(); ip4 != nil { + return ip4[0] == 10 || + (ip4[0] == 172 && ip4[1]&0xf0 == 16) || + (ip4[0] == 192 && ip4[1] == 168) + } + return len(ip) == net.IPv6len && ip[0]&0xfe == 0xfc +} diff --git a/modules/migrations/migrate_test.go b/modules/migrations/migrate_test.go new file mode 100644 index 0000000000..3bad5cfd73 --- /dev/null +++ b/modules/migrations/migrate_test.go @@ -0,0 +1,34 @@ +// Copyright 2019 The Gitea Authors. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +package migrations + +import ( + "testing" + + "code.gitea.io/gitea/modules/setting" + + "github.com/stretchr/testify/assert" +) + +func TestMigrateWhiteBlocklist(t *testing.T) { + setting.Migrations.AllowedDomains = []string{"github.com"} + assert.NoError(t, Init()) + + err := isMigrateURLAllowed("https://gitlab.com/gitlab/gitlab.git") + assert.Error(t, err) + + err = isMigrateURLAllowed("https://github.com/go-gitea/gitea.git") + assert.NoError(t, err) + + setting.Migrations.AllowedDomains = []string{} + setting.Migrations.BlockedDomains = []string{"github.com"} + assert.NoError(t, Init()) + + err = isMigrateURLAllowed("https://gitlab.com/gitlab/gitlab.git") + assert.NoError(t, err) + + err = isMigrateURLAllowed("https://github.com/go-gitea/gitea.git") + assert.Error(t, err) +} diff --git a/modules/setting/migrations.go b/modules/setting/migrations.go index 51d6bbcf11..7808df5280 100644 --- a/modules/setting/migrations.go +++ b/modules/setting/migrations.go @@ -4,11 +4,18 @@ package setting +import ( + "strings" +) + var ( // Migrations settings Migrations = struct { - MaxAttempts int - RetryBackoff int + MaxAttempts int + RetryBackoff int + AllowedDomains []string + BlockedDomains []string + AllowLocalNetworks bool }{ MaxAttempts: 3, RetryBackoff: 3, @@ -19,4 +26,15 @@ func newMigrationsService() { sec := Cfg.Section("migrations") Migrations.MaxAttempts = sec.Key("MAX_ATTEMPTS").MustInt(Migrations.MaxAttempts) Migrations.RetryBackoff = sec.Key("RETRY_BACKOFF").MustInt(Migrations.RetryBackoff) + + Migrations.AllowedDomains = sec.Key("ALLOWED_DOMAINS").Strings(",") + for i := range Migrations.AllowedDomains { + Migrations.AllowedDomains[i] = strings.ToLower(Migrations.AllowedDomains[i]) + } + Migrations.BlockedDomains = sec.Key("BLOCKED_DOMAINS").Strings(",") + for i := range Migrations.BlockedDomains { + Migrations.BlockedDomains[i] = strings.ToLower(Migrations.BlockedDomains[i]) + } + + Migrations.AllowLocalNetworks = sec.Key("ALLOW_LOCALNETWORKS").MustBool(false) } diff --git a/routers/api/v1/repo/migrate.go b/routers/api/v1/repo/migrate.go index f9cddbb7cd..68ab7e4897 100644 --- a/routers/api/v1/repo/migrate.go +++ b/routers/api/v1/repo/migrate.go @@ -212,6 +212,8 @@ func handleMigrateError(ctx *context.APIContext, repoOwner *models.User, remoteA ctx.Error(http.StatusUnprocessableEntity, "", fmt.Sprintf("The username '%s' contains invalid characters.", err.(models.ErrNameCharsNotAllowed).Name)) case models.IsErrNamePatternNotAllowed(err): ctx.Error(http.StatusUnprocessableEntity, "", fmt.Sprintf("The pattern '%s' is not allowed in a username.", err.(models.ErrNamePatternNotAllowed).Pattern)) + case models.IsErrMigrationNotAllowed(err): + ctx.Error(http.StatusUnprocessableEntity, "", err) default: err = util.URLSanitizedError(err, remoteAddr) if strings.Contains(err.Error(), "Authentication failed") || diff --git a/routers/init.go b/routers/init.go index faa84fb0c9..34b94eb471 100644 --- a/routers/init.go +++ b/routers/init.go @@ -24,6 +24,7 @@ import ( "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/markup" "code.gitea.io/gitea/modules/markup/external" + repo_migrations "code.gitea.io/gitea/modules/migrations" "code.gitea.io/gitea/modules/notification" "code.gitea.io/gitea/modules/options" "code.gitea.io/gitea/modules/setting" @@ -174,6 +175,10 @@ func GlobalInit(ctx context.Context) { } checkRunMode() + if err := repo_migrations.Init(); err != nil { + log.Fatal("Failed to initialize repository migrations: %v", err) + } + // Now because Install will re-run GlobalInit once it has set InstallLock // we can't tell if the ssh port will remain unused until that's done. // However, see FIXME comment in install.go From f677ed628ba7e003db583e8140f951d265b5c94e Mon Sep 17 00:00:00 2001 From: techknowlogick Date: Tue, 1 Dec 2020 19:36:11 -0500 Subject: [PATCH 074/205] set git-core paths in snap (#13711) (#13781) Signed-off-by: artivis Co-authored-by: techknowlogick Co-authored-by: Jeremie Deray --- snap/snapcraft.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/snap/snapcraft.yaml b/snap/snapcraft.yaml index dd2d98a391..7914cee2c8 100644 --- a/snap/snapcraft.yaml +++ b/snap/snapcraft.yaml @@ -19,6 +19,8 @@ architectures: environment: GITEA_CUSTOM: "$SNAP_COMMON" GITEA_WORK_DIR: "$SNAP_DATA" + GIT_TEMPLATE_DIR: "$SNAP/usr/share/git-core/templates" + GIT_EXEC_PATH: "$SNAP/usr/lib/git-core" apps: gitea: From d551152582028b1e42d663cf1bc1e9a3a7e38b1e Mon Sep 17 00:00:00 2001 From: techknowlogick Date: Tue, 1 Dec 2020 23:54:26 -0500 Subject: [PATCH 075/205] 1.13.0 Changelog (#13782) Co-authored-by: 6543 <6543@obermui.de> --- CHANGELOG.md | 77 +++++++++++++++++++++++++++++----------------------- 1 file changed, 43 insertions(+), 34 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1bcd7ce344..e72d758762 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,46 +4,17 @@ This changelog goes through all the changes that have been made in each release without substantial changes to our git log; to see the highlights of what has been added to each release, please refer to the [blog](https://blog.gitea.io). -## [1.13.0-rc2](https://github.com/go-gitea/gitea/releases/tag/v1.13.0-rc2) - 2020-11-10 -* ENHANCEMENTS - * Return the full rejection message and errors in flash errors (#13221) (#13237) - * Remove PAM from auth dropdown when unavailable (#13276) (#13281) -* BUGFIXES - * Fix Italian language file parsing error (#13156) - * Show outdated comments in pull request (#13148) (#13162) - * Fix parsing of pre-release git version (#13169) (#13172) - * Fix diff skipping lines (#13154) (#13155) - * When handling errors in storageHandler check underlying error (#13178) (#13193) - * Fix size and clickable area on file table back link (#13205) (#13207) - * Add better error checking for inline html diff code (#13251) - * Fix initial commit page & binary munching problem (#13249) (#13258) - * Fix migrations from remote Gitea instances when configuration not set (#13229) (#13273) - * Store task errors following migrations and display them (#13246) (#13287) - * Fix bug isEnd detection on getIssues/getPullRequests (#13299) (#13301) - * When the git ref is unable to be found return broken pr (#13218) (#13303) - * Ensure topics added using the API are added to the repository (#13285) (#13302) - * Fix avatar autogeneration (#13233) (#13282) - * Add migrated pulls to pull request task queue (#13331) (#13334) - * Issue comment reactions should also check pull type on API (#13349) (#13350) - * Fix links to repositories in /user/setting/repos (#13360) (#13362) - * Remove obsolete change of email on profile page (#13341) (#13347) - * Fix scrolling to resolved comment anchors (#13343) (#13371) - * Storage configuration support `[storage]` (#13314) (#13379) - * When creating line diffs do not split within an html entity (#13357) (#13375) (#13425) (#13427) - * Fix reactions on code comments (#13390) (#13401) - * Add missing full names when DEFAULT_SHOW_FULL_NAME is enabled (#13424) - * Replies to outdated code comments should also be outdated (#13217) (#13433) - * Fix panic bug in handling multiple references in commit (#13486) (#13487) - * Prevent panic on git blame by limiting lines to 4096 bytes at most (#13470) (#13491) - -## [1.13.0-rc1](https://github.com/go-gitea/gitea/releases/tag/v1.13.0-rc1) - 2020-10-14 - +## [1.13.0](https://github.com/go-gitea/gitea/releases/tag/v1.13.0) - 2020-12-01 * SECURITY + * Add Allow-/Block-List for Migrate & Mirrors (#13610) (#13776) + * Prevent git operations for inactive users (#13527) (#13536) + * Disallow urlencoded new lines in git protocol paths if there is a port (#13521) (#13524) * Mitigate Security vulnerability in the git hook feature (#13058) * Disable DSA ssh keys by default (#13056) * Set TLS minimum version to 1.2 (#12689) * Use argon as default password hash algorithm (#12688) * BREAKING + * Set RUN_MODE prod by default (#13765) (#13767) * Don't replace underscores in auto-generated IDs in goldmark (#12805) * Add Primary Key to Topic and RepoTopic tables (#12639) * Disable password complexity check default (#12557) @@ -103,6 +74,40 @@ been added to each release, please refer to the [blog](https://blog.gitea.io). * Add endpoint for Branch Creation (#11607) * Add pagination headers on endpoints that support total count from database (#11145) * BUGFIXES + * Fix bogus http requests on diffs (#13760) (#13761) + * Show 'owner' tag for real owner (#13689) (#13743) + * Validate email before inserting/updating (#13475) (#13666) + * Fix issue/pull request list assignee filter (#13647) (#13651) + * Gitlab migration support for subdirectories (#13563) (#13591) + * Fix logic for preferred license setting (#13550) (#13557) + * Add missed sync branch/tag webhook (#13538) (#13556) + * Migration won't fail on non-migrated reactions (#13507) + * Fix Italian language file parsing error (#13156) + * Show outdated comments in pull request (#13148) (#13162) + * Fix parsing of pre-release git version (#13169) (#13172) + * Fix diff skipping lines (#13154) (#13155) + * When handling errors in storageHandler check underlying error (#13178) (#13193) + * Fix size and clickable area on file table back link (#13205) (#13207) + * Add better error checking for inline html diff code (#13251) + * Fix initial commit page & binary munching problem (#13249) (#13258) + * Fix migrations from remote Gitea instances when configuration not set (#13229) (#13273) + * Store task errors following migrations and display them (#13246) (#13287) + * Fix bug isEnd detection on getIssues/getPullRequests (#13299) (#13301) + * When the git ref is unable to be found return broken pr (#13218) (#13303) + * Ensure topics added using the API are added to the repository (#13285) (#13302) + * Fix avatar autogeneration (#13233) (#13282) + * Add migrated pulls to pull request task queue (#13331) (#13334) + * Issue comment reactions should also check pull type on API (#13349) (#13350) + * Fix links to repositories in /user/setting/repos (#13360) (#13362) + * Remove obsolete change of email on profile page (#13341) (#13347) + * Fix scrolling to resolved comment anchors (#13343) (#13371) + * Storage configuration support `[storage]` (#13314) (#13379) + * When creating line diffs do not split within an html entity (#13357) (#13375) (#13425) (#13427) + * Fix reactions on code comments (#13390) (#13401) + * Add missing full names when DEFAULT_SHOW_FULL_NAME is enabled (#13424) + * Replies to outdated code comments should also be outdated (#13217) (#13433) + * Fix panic bug in handling multiple references in commit (#13486) (#13487) + * Prevent panic on git blame by limiting lines to 4096 bytes at most (#13470) (#13491) * Show original author's reviews on pull summary box (#13127) * Update golangci-lint to version 1.31.0 (#13102) * Fix line break for MS teams webhook (#13081) @@ -172,6 +177,10 @@ been added to each release, please refer to the [blog](https://blog.gitea.io). * Fix Enter not working in SimpleMDE (#11564) * Fix bug about can't skip commits base on base branch (#11555) * ENHANCEMENTS + * Only Return JSON for responses (#13511) (#13565) + * Use existing analyzer module for language detection for highlighting (#13522) (#13551) + * Return the full rejection message and errors in flash errors (#13221) (#13237) + * Remove PAM from auth dropdown when unavailable (#13276) (#13281) * Add HostCertificate to sshd_config in Docker image (#13143) * Save TimeStamps for Star, Label, Follow, Watch and Collaboration to Database (#13124) * Improve error feedback for duplicate deploy keys (#13112) From 8396b792f86ec37311e490c97f7a54ed596bce37 Mon Sep 17 00:00:00 2001 From: 6543 <6543@obermui.de> Date: Wed, 2 Dec 2020 22:11:11 +0100 Subject: [PATCH 076/205] Migrations: Use Process Manager to create own Context (#13793) --- .../git_helper_for_declarative_test.go | 2 +- modules/git/git.go | 1 + modules/git/repo.go | 12 +++++++--- modules/migrations/gitea_uploader.go | 2 +- modules/repository/repo.go | 7 +++--- modules/task/migrate.go | 22 ++++++++++++++----- services/mirror/mirror_test.go | 3 ++- 7 files changed, 34 insertions(+), 15 deletions(-) diff --git a/integrations/git_helper_for_declarative_test.go b/integrations/git_helper_for_declarative_test.go index 5823ce38dc..eeccb16266 100644 --- a/integrations/git_helper_for_declarative_test.go +++ b/integrations/git_helper_for_declarative_test.go @@ -111,7 +111,7 @@ func onGiteaRun(t *testing.T, callback func(*testing.T, *url.URL), prepare ...bo func doGitClone(dstLocalPath string, u *url.URL) func(*testing.T) { return func(t *testing.T) { - assert.NoError(t, git.CloneWithArgs(u.String(), dstLocalPath, allowLFSFilters(), git.CloneRepoOptions{})) + assert.NoError(t, git.CloneWithArgs(context.Background(), u.String(), dstLocalPath, allowLFSFilters(), git.CloneRepoOptions{})) assert.True(t, com.IsExist(filepath.Join(dstLocalPath, "README.md"))) } } diff --git a/modules/git/git.go b/modules/git/git.go index a9ff923cc5..bdc8208959 100644 --- a/modules/git/git.go +++ b/modules/git/git.go @@ -32,6 +32,7 @@ var ( GitExecutable = "git" // DefaultContext is the default context to run git commands in + // will be overwritten by Init with HammerContext DefaultContext = context.Background() gitVersion *version.Version diff --git a/modules/git/repo.go b/modules/git/repo.go index 644ff09284..1ca4f094b2 100644 --- a/modules/git/repo.go +++ b/modules/git/repo.go @@ -8,6 +8,7 @@ package git import ( "bytes" "container/list" + "context" "errors" "fmt" "os" @@ -166,19 +167,24 @@ type CloneRepoOptions struct { // Clone clones original repository to target path. func Clone(from, to string, opts CloneRepoOptions) (err error) { + return CloneWithContext(DefaultContext, from, to, opts) +} + +// CloneWithContext clones original repository to target path. +func CloneWithContext(ctx context.Context, from, to string, opts CloneRepoOptions) (err error) { cargs := make([]string, len(GlobalCommandArgs)) copy(cargs, GlobalCommandArgs) - return CloneWithArgs(from, to, cargs, opts) + return CloneWithArgs(ctx, from, to, cargs, opts) } // CloneWithArgs original repository to target path. -func CloneWithArgs(from, to string, args []string, opts CloneRepoOptions) (err error) { +func CloneWithArgs(ctx context.Context, from, to string, args []string, opts CloneRepoOptions) (err error) { toDir := path.Dir(to) if err = os.MkdirAll(toDir, os.ModePerm); err != nil { return err } - cmd := NewCommandNoGlobals(args...).AddArguments("clone") + cmd := NewCommandContextNoGlobals(ctx, args...).AddArguments("clone") if opts.Mirror { cmd.AddArguments("--mirror") } diff --git a/modules/migrations/gitea_uploader.go b/modules/migrations/gitea_uploader.go index 466c832754..2cb19685fc 100644 --- a/modules/migrations/gitea_uploader.go +++ b/modules/migrations/gitea_uploader.go @@ -125,7 +125,7 @@ func (g *GiteaLocalUploader) CreateRepo(repo *base.Repository, opts base.Migrate } r.DefaultBranch = repo.DefaultBranch - r, err = repository.MigrateRepositoryGitData(g.doer, owner, r, base.MigrateOptions{ + r, err = repository.MigrateRepositoryGitData(g.ctx, owner, r, base.MigrateOptions{ RepoName: g.repoName, Description: repo.Description, OriginalURL: repo.OriginalURL, diff --git a/modules/repository/repo.go b/modules/repository/repo.go index b18dfddd2e..8ecb43ede6 100644 --- a/modules/repository/repo.go +++ b/modules/repository/repo.go @@ -5,6 +5,7 @@ package repository import ( + "context" "fmt" "path" "strings" @@ -41,7 +42,7 @@ func WikiRemoteURL(remote string) string { } // MigrateRepositoryGitData starts migrating git related data after created migrating repository -func MigrateRepositoryGitData(doer, u *models.User, repo *models.Repository, opts migration.MigrateOptions) (*models.Repository, error) { +func MigrateRepositoryGitData(ctx context.Context, u *models.User, repo *models.Repository, opts migration.MigrateOptions) (*models.Repository, error) { repoPath := models.RepoPath(u.Name, opts.RepoName) if u.IsOrganization() { @@ -61,7 +62,7 @@ func MigrateRepositoryGitData(doer, u *models.User, repo *models.Repository, opt return repo, fmt.Errorf("Failed to remove %s: %v", repoPath, err) } - if err = git.Clone(opts.CloneAddr, repoPath, git.CloneRepoOptions{ + if err = git.CloneWithContext(ctx, opts.CloneAddr, repoPath, git.CloneRepoOptions{ Mirror: true, Quiet: true, Timeout: migrateTimeout, @@ -77,7 +78,7 @@ func MigrateRepositoryGitData(doer, u *models.User, repo *models.Repository, opt return repo, fmt.Errorf("Failed to remove %s: %v", wikiPath, err) } - if err = git.Clone(wikiRemotePath, wikiPath, git.CloneRepoOptions{ + if err = git.CloneWithContext(ctx, wikiRemotePath, wikiPath, git.CloneRepoOptions{ Mirror: true, Quiet: true, Timeout: migrateTimeout, diff --git a/modules/task/migrate.go b/modules/task/migrate.go index 99f0435b28..57424abac3 100644 --- a/modules/task/migrate.go +++ b/modules/task/migrate.go @@ -5,6 +5,7 @@ package task import ( + "context" "errors" "fmt" "strings" @@ -15,6 +16,7 @@ import ( "code.gitea.io/gitea/modules/migrations" migration "code.gitea.io/gitea/modules/migrations/base" "code.gitea.io/gitea/modules/notification" + "code.gitea.io/gitea/modules/process" "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/modules/timeutil" "code.gitea.io/gitea/modules/util" @@ -82,11 +84,6 @@ func runMigrateTask(t *models.Task) (err error) { if err = t.LoadOwner(); err != nil { return } - t.StartTime = timeutil.TimeStampNow() - t.Status = structs.TaskStatusRunning - if err = t.UpdateCols("start_time", "status"); err != nil { - return - } var opts *migration.MigrateOptions opts, err = t.MigrateConfig() @@ -96,7 +93,20 @@ func runMigrateTask(t *models.Task) (err error) { opts.MigrateToRepoID = t.RepoID var repo *models.Repository - repo, err = migrations.MigrateRepository(graceful.GetManager().HammerContext(), t.Doer, t.Owner.Name, *opts) + + ctx, cancel := context.WithCancel(graceful.GetManager().ShutdownContext()) + defer cancel() + pm := process.GetManager() + pid := pm.Add(fmt.Sprintf("MigrateTask: %s/%s", t.Owner.Name, opts.RepoName), cancel) + defer pm.Remove(pid) + + t.StartTime = timeutil.TimeStampNow() + t.Status = structs.TaskStatusRunning + if err = t.UpdateCols("start_time", "status"); err != nil { + return + } + + repo, err = migrations.MigrateRepository(ctx, t.Doer, t.Owner.Name, *opts) if err == nil { log.Trace("Repository migrated [%d]: %s/%s", repo.ID, t.Owner.Name, repo.Name) return diff --git a/services/mirror/mirror_test.go b/services/mirror/mirror_test.go index 79e18885b3..ddfb6c676b 100644 --- a/services/mirror/mirror_test.go +++ b/services/mirror/mirror_test.go @@ -5,6 +5,7 @@ package mirror import ( + "context" "path/filepath" "testing" @@ -47,7 +48,7 @@ func TestRelease_MirrorDelete(t *testing.T) { }) assert.NoError(t, err) - mirror, err := repository.MigrateRepositoryGitData(user, user, mirrorRepo, opts) + mirror, err := repository.MigrateRepositoryGitData(context.Background(), user, mirrorRepo, opts) assert.NoError(t, err) gitRepo, err := git.OpenRepository(repoPath) From 0d43a2a069a058f5922cef7248d7a97fcb800179 Mon Sep 17 00:00:00 2001 From: zeripath Date: Thu, 3 Dec 2020 10:13:19 +0000 Subject: [PATCH 077/205] When reinitialising DBConfig reset the database use flags (#13796) (#13811) Backport #13796 One perennial issue is users running the install page, changing the database dialect and then suffering with issues This PR simply resets all of the database.Use flags on initDBConfig. This should prevent this issue from occuring. Fix #13788 Fix #5480 Signed-off-by: Andrew Thornton Co-authored-by: techknowlogick Co-authored-by: techknowlogick --- modules/setting/database.go | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/modules/setting/database.go b/modules/setting/database.go index 7d082d1379..3d13ee10c8 100644 --- a/modules/setting/database.go +++ b/modules/setting/database.go @@ -62,6 +62,11 @@ func InitDBConfig() { sec := Cfg.Section("database") Database.Type = sec.Key("DB_TYPE").String() defaultCharset := "utf8" + Database.UseMySQL = false + Database.UseSQLite3 = false + Database.UsePostgreSQL = false + Database.UseMSSQL = false + switch Database.Type { case "sqlite3": Database.UseSQLite3 = true From 10fff12da4d12b26779c54297605d127d1b3fb71 Mon Sep 17 00:00:00 2001 From: Jimmy Praet Date: Thu, 3 Dec 2020 21:26:47 +0100 Subject: [PATCH 078/205] Reply button is not removed when deleting a code review comment (#13824) Backport #13774 --- templates/repo/diff/box.tmpl | 128 ++++++++++++----------- templates/repo/diff/section_unified.tmpl | 58 +++++----- web_src/js/index.js | 4 + 3 files changed, 100 insertions(+), 90 deletions(-) diff --git a/templates/repo/diff/box.tmpl b/templates/repo/diff/box.tmpl index 8301dbb05d..f6e49126bf 100644 --- a/templates/repo/diff/box.tmpl +++ b/templates/repo/diff/box.tmpl @@ -166,74 +166,78 @@
{{end}} diff --git a/templates/repo/diff/section_unified.tmpl b/templates/repo/diff/section_unified.tmpl index 1a461c7ad7..d606a1d74b 100644 --- a/templates/repo/diff/section_unified.tmpl +++ b/templates/repo/diff/section_unified.tmpl @@ -39,35 +39,37 @@ diff --git a/web_src/js/index.js b/web_src/js/index.js index 2e7b13cb64..8ffd56cfbf 100644 --- a/web_src/js/index.js +++ b/web_src/js/index.js @@ -1055,7 +1055,11 @@ async function initRepository() { $.post($this.data('url'), { _csrf: csrf }).done(() => { + const $conversationHolder = $this.closest('.conversation-holder'); $(`#${$this.data('comment-id')}`).remove(); + if ($conversationHolder.length && !$conversationHolder.find('.comment').length) { + $conversationHolder.remove(); + } }); } return false; From 0d5111c5c32831cc5501d25a1cf142c6cce94903 Mon Sep 17 00:00:00 2001 From: John Olheiser Date: Thu, 3 Dec 2020 15:37:33 -0600 Subject: [PATCH 079/205] Make sure email recipients can see issue (#13820) (#13827) * Initial pass * Remove over-op Signed-off-by: jolheiser --- services/mailer/mail_issue.go | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/services/mailer/mail_issue.go b/services/mailer/mail_issue.go index 01c198984b..30b54eb6cb 100644 --- a/services/mailer/mail_issue.go +++ b/services/mailer/mail_issue.go @@ -122,7 +122,17 @@ func mailIssueCommentBatch(ctx *mailCommentContext, ids []int64, visited map[int if err != nil { return err } - // TODO: Check issue visibility for each user + + // Make sure all recipients can still see the issue + idx := 0 + for _, r := range recipients { + if ctx.Issue.Repo.CheckUnitUser(r, models.UnitTypeIssues) { + recipients[idx] = r + idx++ + } + } + recipients = recipients[:idx] + // TODO: Separate recipients by language for i18n mail templates tos := make([]string, len(recipients)) for i := range recipients { From 87997cccbb47c0219a0c0955cf09eadfef588b46 Mon Sep 17 00:00:00 2001 From: silverwind Date: Fri, 4 Dec 2020 02:21:34 +0100 Subject: [PATCH 080/205] Update font stack to bootstrap's latest (#13834) (#13837) Backport #13834 --- web_src/less/_base.less | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/web_src/less/_base.less b/web_src/less/_base.less index 765c0f9c93..5cc52ecf0e 100644 --- a/web_src/less/_base.less +++ b/web_src/less/_base.less @@ -18,8 +18,8 @@ url('../fonts/noto-color-emoji/NotoColorEmoji.ttf') format('truetype'); } -@default-fonts: -apple-system, BlinkMacSystemFont, system-ui, 'Segoe UI', Roboto, Helvetica, Arial, "Apple Color Emoji", "Segoe UI Emoji", "Noto Color Emoji", "Twemoji Mozilla"; -@monospaced-fonts: 'SF Mono', Consolas, Menlo, 'Liberation Mono', Monaco, 'Lucida Console'; +@default-fonts: system-ui, -apple-system, "BlinkMacSystemFont", "Segoe UI", "Roboto", "Helvetica Neue", "Arial", "Noto Sans", "Liberation Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji", "Twemoji Mozilla"; +@monospaced-fonts: "SFMono-Regular", "Menlo", "Monaco", "Consolas", "Liberation Mono", "Courier New", monospace; .override-fonts(@fonts) { textarea { From 798fdeae4545c1558a82d95d34165cc274080ab8 Mon Sep 17 00:00:00 2001 From: mrsdizzie Date: Thu, 3 Dec 2020 22:08:48 -0500 Subject: [PATCH 081/205] Fix crash in short link processor (#13839) (#13841) Fixes #13819 --- modules/markup/html.go | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/modules/markup/html.go b/modules/markup/html.go index f5f811b59b..500261bf8f 100644 --- a/modules/markup/html.go +++ b/modules/markup/html.go @@ -632,16 +632,18 @@ func shortLinkProcessorFull(ctx *postProcessCtx, node *html.Node, noLink bool) { // When parsing HTML, x/net/html will change all quotes which are // not used for syntax into UTF-8 quotes. So checking val[0] won't // be enough, since that only checks a single byte. - if (strings.HasPrefix(val, "“") && strings.HasSuffix(val, "”")) || - (strings.HasPrefix(val, "‘") && strings.HasSuffix(val, "’")) { - const lenQuote = len("‘") - val = val[lenQuote : len(val)-lenQuote] - } else if (strings.HasPrefix(val, "\"") && strings.HasSuffix(val, "\"")) || - (strings.HasPrefix(val, "'") && strings.HasSuffix(val, "'")) { - val = val[1 : len(val)-1] - } else if strings.HasPrefix(val, "'") && strings.HasSuffix(val, "’") { - const lenQuote = len("‘") - val = val[1 : len(val)-lenQuote] + if len(val) > 1 { + if (strings.HasPrefix(val, "“") && strings.HasSuffix(val, "”")) || + (strings.HasPrefix(val, "‘") && strings.HasSuffix(val, "’")) { + const lenQuote = len("‘") + val = val[lenQuote : len(val)-lenQuote] + } else if (strings.HasPrefix(val, "\"") && strings.HasSuffix(val, "\"")) || + (strings.HasPrefix(val, "'") && strings.HasSuffix(val, "'")) { + val = val[1 : len(val)-1] + } else if strings.HasPrefix(val, "'") && strings.HasSuffix(val, "’") { + const lenQuote = len("‘") + val = val[1 : len(val)-lenQuote] + } } props[key] = val } From 584d01cf2c3e1f5946fca03e7aa9db8d6508328e Mon Sep 17 00:00:00 2001 From: silverwind Date: Sun, 6 Dec 2020 04:13:31 +0100 Subject: [PATCH 082/205] Fix mermaid chart size (#13865) --- web_src/less/markdown/mermaid.less | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/web_src/less/markdown/mermaid.less b/web_src/less/markdown/mermaid.less index 4fc1258f03..f68b577dec 100644 --- a/web_src/less/markdown/mermaid.less +++ b/web_src/less/markdown/mermaid.less @@ -3,7 +3,8 @@ justify-content: center; align-items: center; padding: 1rem; - margin: 1rem 0; + margin: 1rem auto; + height: auto; } /* mermaid's errorRenderer seems to unavoidably spew stuff into , hide it */ From cb24cbc1fc316beffe7845d30c5ab0975e32ddb9 Mon Sep 17 00:00:00 2001 From: manuelluis Date: Sun, 6 Dec 2020 05:30:28 +0100 Subject: [PATCH 083/205] Fix branch/tag notifications in mirror sync (#13855) (#13862) Co-authored-by: Gitea Co-authored-by: 6543 <6543@obermui.de> --- services/mirror/mirror.go | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/services/mirror/mirror.go b/services/mirror/mirror.go index 5eafdab38d..34d0f0a06a 100644 --- a/services/mirror/mirror.go +++ b/services/mirror/mirror.go @@ -149,6 +149,11 @@ func parseRemoteUpdateOutput(output string) []*mirrorSyncResult { switch { case strings.HasPrefix(lines[i], " * "): // New reference + if strings.HasPrefix(lines[i], " * [new tag]") { + refName = git.TagPrefix + refName + } else if strings.HasPrefix(lines[i], " * [new branch]") { + refName = git.BranchPrefix + refName + } results = append(results, &mirrorSyncResult{ refName: refName, oldCommitID: gitShortEmptySha, @@ -434,6 +439,17 @@ func syncMirror(repoID string) { // Create reference if result.oldCommitID == gitShortEmptySha { + if tp == git.TagPrefix { + tp = "tag" + } else if tp == git.BranchPrefix { + tp = "branch" + } + commitID, err := gitRepo.GetRefCommitID(result.refName) + if err != nil { + log.Error("gitRepo.GetRefCommitID [repo_id: %s, ref_name: %s]: %v", m.RepoID, result.refName, err) + continue + } + notification.NotifySyncPushCommits(m.Repo.MustOwner(), m.Repo, result.refName, git.EmptySHA, commitID, repo_module.NewPushCommits()) notification.NotifySyncCreateRef(m.Repo.MustOwner(), m.Repo, tp, result.refName) continue } From e39ed0b1d98b312c9986969f77acad404748e004 Mon Sep 17 00:00:00 2001 From: 6543 <6543@obermui.de> Date: Tue, 8 Dec 2020 04:59:19 +0000 Subject: [PATCH 084/205] [API] return original URL of Repositories (#13885) (#13886) --- models/repo.go | 1 + 1 file changed, 1 insertion(+) diff --git a/models/repo.go b/models/repo.go index efdd7049de..5ccb974db8 100644 --- a/models/repo.go +++ b/models/repo.go @@ -426,6 +426,7 @@ func (repo *Repository) innerAPIFormat(e Engine, mode AccessMode, isParent bool) HTMLURL: repo.HTMLURL(), SSHURL: cloneLink.SSH, CloneURL: cloneLink.HTTPS, + OriginalURL: repo.SanitizedOriginalURL(), Website: repo.Website, Stars: repo.NumStars, Forks: repo.NumForks, From c0b1197a6449a2fb545c5e64b5bca3741cf8d737 Mon Sep 17 00:00:00 2001 From: a1012112796 <1012112796@qq.com> Date: Tue, 8 Dec 2020 19:58:44 +0800 Subject: [PATCH 085/205] Fix Pull Merge when tag with same name as base branch exist (#13882) (#13896) fix dst refspec error in 'Push back to upstream' when base branch have same name with a tag. fix #13851 Signed-off-by: a1012112796 <1012112796@qq.com> Co-authored-by: 6543 <6543@obermui.de> Co-authored-by: zeripath --- services/pull/merge.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/pull/merge.go b/services/pull/merge.go index e74b4b6b1e..16ee816c74 100644 --- a/services/pull/merge.go +++ b/services/pull/merge.go @@ -411,7 +411,7 @@ func rawMerge(pr *models.PullRequest, doer *models.User, mergeStyle models.Merge ) // Push back to upstream. - if err := git.NewCommand("push", "origin", baseBranch+":"+pr.BaseBranch).RunInDirTimeoutEnvPipeline(env, -1, tmpBasePath, &outbuf, &errbuf); err != nil { + if err := git.NewCommand("push", "origin", baseBranch+":refs/heads/"+pr.BaseBranch).RunInDirTimeoutEnvPipeline(env, -1, tmpBasePath, &outbuf, &errbuf); err != nil { if strings.Contains(errbuf.String(), "non-fast-forward") { return "", &git.ErrPushOutOfDate{ StdOut: outbuf.String(), From a0101c61a410bbbb7e98d9813d714472d904c365 Mon Sep 17 00:00:00 2001 From: Jimmy Praet Date: Tue, 8 Dec 2020 23:12:35 +0100 Subject: [PATCH 086/205] Fix Quote Reply button on review diff (#13830) (#13898) Backport of #13830 Co-authored-by: 6543 <6543@obermui.de> --- web_src/js/index.js | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/web_src/js/index.js b/web_src/js/index.js index 8ffd56cfbf..2e81c23a2b 100644 --- a/web_src/js/index.js +++ b/web_src/js/index.js @@ -862,25 +862,23 @@ async function initRepository() { const target = $(this).data('target'); const quote = $(`#comment-${target}`).text().replace(/\n/g, '\n> '); const content = `> ${quote}\n\n`; - - let $content; + let $simplemde = autoSimpleMDE; if ($(this).hasClass('quote-reply-diff')) { const $parent = $(this).closest('.comment-code-cloud'); $parent.find('button.comment-form-reply').trigger('click'); - $content = $parent.find('[name="content"]'); - if ($content.val() !== '') { - $content.val(`${$content.val()}\n\n${content}`); + $simplemde = $parent.find('[name="content"]').data('simplemde'); + } + if ($simplemde !== null) { + if ($simplemde.value() !== '') { + $simplemde.value(`${$simplemde.value()}\n\n${content}`); } else { - $content.val(`${content}`); - } - $content.focus(); - } else if (autoSimpleMDE !== null) { - if (autoSimpleMDE.value() !== '') { - autoSimpleMDE.value(`${autoSimpleMDE.value()}\n\n${content}`); - } else { - autoSimpleMDE.value(`${content}`); + $simplemde.value(`${content}`); } } + requestAnimationFrame(() => { + $simplemde.codemirror.focus(); + $simplemde.codemirror.setCursor($simplemde.codemirror.lineCount(), 0); + }); event.preventDefault(); }); @@ -1043,8 +1041,10 @@ async function initRepository() { $textarea.val($rawContent.text()); $simplemde.value($rawContent.text()); } - $textarea.focus(); - $simplemde.codemirror.focus(); + requestAnimationFrame(() => { + $textarea.focus(); + $simplemde.codemirror.focus(); + }); event.preventDefault(); }); From 5cdffc2b0c79913a0edb55f9cbd086578c249928 Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Wed, 9 Dec 2020 23:37:15 +0800 Subject: [PATCH 087/205] log error when login failed (#13903) (#13913) Co-authored-by: techknowlogick Co-authored-by: techknowlogick Co-authored-by: 6543 <6543@obermui.de> --- routers/user/auth.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/routers/user/auth.go b/routers/user/auth.go index ba6420967f..02cebe6a0e 100644 --- a/routers/user/auth.go +++ b/routers/user/auth.go @@ -174,12 +174,12 @@ func SignInPost(ctx *context.Context, form auth.SignInForm) { if err != nil { if models.IsErrUserNotExist(err) { ctx.RenderWithErr(ctx.Tr("form.username_password_incorrect"), tplSignIn, &form) - log.Info("Failed authentication attempt for %s from %s", form.UserName, ctx.RemoteAddr()) + log.Info("Failed authentication attempt for %s from %s: %v", form.UserName, ctx.RemoteAddr(), err) } else if models.IsErrEmailAlreadyUsed(err) { ctx.RenderWithErr(ctx.Tr("form.email_been_used"), tplSignIn, &form) - log.Info("Failed authentication attempt for %s from %s", form.UserName, ctx.RemoteAddr()) + log.Info("Failed authentication attempt for %s from %s: %v", form.UserName, ctx.RemoteAddr(), err) } else if models.IsErrUserProhibitLogin(err) { - log.Info("Failed authentication attempt for %s from %s", form.UserName, ctx.RemoteAddr()) + log.Info("Failed authentication attempt for %s from %s: %v", form.UserName, ctx.RemoteAddr(), err) ctx.Data["Title"] = ctx.Tr("auth.prohibit_login") ctx.HTML(200, "user/auth/prohibit_login") } else if models.IsErrUserInactive(err) { @@ -187,7 +187,7 @@ func SignInPost(ctx *context.Context, form auth.SignInForm) { ctx.Data["Title"] = ctx.Tr("auth.active_your_account") ctx.HTML(200, TplActivate) } else { - log.Info("Failed authentication attempt for %s from %s", form.UserName, ctx.RemoteAddr()) + log.Info("Failed authentication attempt for %s from %s: %v", form.UserName, ctx.RemoteAddr(), err) ctx.Data["Title"] = ctx.Tr("auth.prohibit_login") ctx.HTML(200, "user/auth/prohibit_login") } From 0d7cb2323fb5018ed7aa72b74169d698742a79aa Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Fri, 11 Dec 2020 23:11:32 +0800 Subject: [PATCH 088/205] Fix feishu webhook caused by API changed (#13937) (#13938) fix #13858 --- modules/webhook/feishu.go | 88 +++++++++++++++------------------------ 1 file changed, 33 insertions(+), 55 deletions(-) diff --git a/modules/webhook/feishu.go b/modules/webhook/feishu.go index 8e60dbba13..3d789e6c1f 100644 --- a/modules/webhook/feishu.go +++ b/modules/webhook/feishu.go @@ -17,11 +17,24 @@ import ( type ( // FeishuPayload represents FeishuPayload struct { - Title string `json:"title"` - Text string `json:"text"` + MsgType string `json:"msg_type"` // text / post / image / share_chat / interactive + Content struct { + Text string `json:"text"` + } `json:"content"` } ) +func newFeishuTextPayload(text string) *FeishuPayload { + return &FeishuPayload{ + MsgType: "text", + Content: struct { + Text string `json:"text"` + }{ + Text: text, + }, + } +} + // SetSecret sets the Feishu secret func (f *FeishuPayload) SetSecret(_ string) {} @@ -42,34 +55,25 @@ var ( func (f *FeishuPayload) Create(p *api.CreatePayload) (api.Payloader, error) { // created tag/branch refName := git.RefEndName(p.Ref) - title := fmt.Sprintf("[%s] %s %s created", p.Repo.FullName, p.RefType, refName) + text := fmt.Sprintf("[%s] %s %s created", p.Repo.FullName, p.RefType, refName) - return &FeishuPayload{ - Text: title, - Title: title, - }, nil + return newFeishuTextPayload(text), nil } // Delete implements PayloadConvertor Delete method func (f *FeishuPayload) Delete(p *api.DeletePayload) (api.Payloader, error) { // created tag/branch refName := git.RefEndName(p.Ref) - title := fmt.Sprintf("[%s] %s %s deleted", p.Repo.FullName, p.RefType, refName) + text := fmt.Sprintf("[%s] %s %s deleted", p.Repo.FullName, p.RefType, refName) - return &FeishuPayload{ - Text: title, - Title: title, - }, nil + return newFeishuTextPayload(text), nil } // Fork implements PayloadConvertor Fork method func (f *FeishuPayload) Fork(p *api.ForkPayload) (api.Payloader, error) { - title := fmt.Sprintf("%s is forked to %s", p.Forkee.FullName, p.Repo.FullName) + text := fmt.Sprintf("%s is forked to %s", p.Forkee.FullName, p.Repo.FullName) - return &FeishuPayload{ - Text: title, - Title: title, - }, nil + return newFeishuTextPayload(text), nil } // Push implements PayloadConvertor Push method @@ -79,9 +83,7 @@ func (f *FeishuPayload) Push(p *api.PushPayload) (api.Payloader, error) { commitDesc string ) - title := fmt.Sprintf("[%s:%s] %s", p.Repo.FullName, branchName, commitDesc) - - var text string + var text = fmt.Sprintf("[%s:%s] %s\n", p.Repo.FullName, branchName, commitDesc) // for each commit, generate attachment text for i, commit := range p.Commits { var authorName string @@ -96,40 +98,28 @@ func (f *FeishuPayload) Push(p *api.PushPayload) (api.Payloader, error) { } } - return &FeishuPayload{ - Text: text, - Title: title, - }, nil + return newFeishuTextPayload(text), nil } // Issue implements PayloadConvertor Issue method func (f *FeishuPayload) Issue(p *api.IssuePayload) (api.Payloader, error) { text, issueTitle, attachmentText, _ := getIssuesPayloadInfo(p, noneLinkFormatter, true) - return &FeishuPayload{ - Text: text + "\r\n\r\n" + attachmentText, - Title: issueTitle, - }, nil + return newFeishuTextPayload(issueTitle + "\r\n" + text + "\r\n\r\n" + attachmentText), nil } // IssueComment implements PayloadConvertor IssueComment method func (f *FeishuPayload) IssueComment(p *api.IssueCommentPayload) (api.Payloader, error) { text, issueTitle, _ := getIssueCommentPayloadInfo(p, noneLinkFormatter, true) - return &FeishuPayload{ - Text: text + "\r\n\r\n" + p.Comment.Body, - Title: issueTitle, - }, nil + return newFeishuTextPayload(issueTitle + "\r\n" + text + "\r\n\r\n" + p.Comment.Body), nil } // PullRequest implements PayloadConvertor PullRequest method func (f *FeishuPayload) PullRequest(p *api.PullRequestPayload) (api.Payloader, error) { text, issueTitle, attachmentText, _ := getPullRequestPayloadInfo(p, noneLinkFormatter, true) - return &FeishuPayload{ - Text: text + "\r\n\r\n" + attachmentText, - Title: issueTitle, - }, nil + return newFeishuTextPayload(issueTitle + "\r\n" + text + "\r\n\r\n" + attachmentText), nil } // Review implements PayloadConvertor Review method @@ -147,28 +137,19 @@ func (f *FeishuPayload) Review(p *api.PullRequestPayload, event models.HookEvent } - return &FeishuPayload{ - Text: title + "\r\n\r\n" + text, - Title: title, - }, nil + return newFeishuTextPayload(title + "\r\n\r\n" + text), nil } // Repository implements PayloadConvertor Repository method func (f *FeishuPayload) Repository(p *api.RepositoryPayload) (api.Payloader, error) { - var title string + var text string switch p.Action { case api.HookRepoCreated: - title = fmt.Sprintf("[%s] Repository created", p.Repository.FullName) - return &FeishuPayload{ - Text: title, - Title: title, - }, nil + text = fmt.Sprintf("[%s] Repository created", p.Repository.FullName) + return newFeishuTextPayload(text), nil case api.HookRepoDeleted: - title = fmt.Sprintf("[%s] Repository deleted", p.Repository.FullName) - return &FeishuPayload{ - Title: title, - Text: title, - }, nil + text = fmt.Sprintf("[%s] Repository deleted", p.Repository.FullName) + return newFeishuTextPayload(text), nil } return nil, nil @@ -178,10 +159,7 @@ func (f *FeishuPayload) Repository(p *api.RepositoryPayload) (api.Payloader, err func (f *FeishuPayload) Release(p *api.ReleasePayload) (api.Payloader, error) { text, _ := getReleasePayloadInfo(p, noneLinkFormatter, true) - return &FeishuPayload{ - Text: text, - Title: text, - }, nil + return newFeishuTextPayload(text), nil } // GetFeishuPayload converts a ding talk webhook into a FeishuPayload From 05ee88e576ba922460924d2cb9df4a9d98767664 Mon Sep 17 00:00:00 2001 From: 6543 <6543@obermui.de> Date: Sat, 12 Dec 2020 17:21:26 +0000 Subject: [PATCH 089/205] Enforce setting HEAD in wiki to master (#13950) (#13961) The default branch in wikis must be master - therefore forcibly set the HEAD to master. Fix #13846 Signed-off-by: Andrew Thornton Co-authored-by: 6543 <6543@obermui.de> Co-authored-by: zeripath --- services/wiki/wiki.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/services/wiki/wiki.go b/services/wiki/wiki.go index 5f7d26a045..67ba1abd0f 100644 --- a/services/wiki/wiki.go +++ b/services/wiki/wiki.go @@ -77,6 +77,8 @@ func InitWiki(repo *models.Repository) error { return fmt.Errorf("InitRepository: %v", err) } else if err = repo_module.CreateDelegateHooks(repo.WikiPath()); err != nil { return fmt.Errorf("createDelegateHooks: %v", err) + } else if _, err = git.NewCommand("symbolic-ref", "HEAD", git.BranchPrefix+"master").RunInDir(repo.WikiPath()); err != nil { + return fmt.Errorf("unable to set default wiki branch to master: %v", err) } return nil } From 8e8e8ee150a70e882bf4661fab84382befe29ac0 Mon Sep 17 00:00:00 2001 From: zeripath Date: Sun, 13 Dec 2020 00:01:44 +0000 Subject: [PATCH 090/205] Whenever the password is updated ensure that the hash algorithm is too (#13966) (#13967) Backport #13966 `user.HashPassword` may potentially - and in fact now likely does - change the `passwd_hash_algo` therefore whenever the `passwd` is updated, this also needs to be updated. Fix #13832 Thanks @fblaese for the hint Signed-off-by: Andrew Thornton --- cmd/admin.go | 2 +- routers/user/auth.go | 4 ++-- routers/user/setting/account.go | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/cmd/admin.go b/cmd/admin.go index 9f81f5284d..597aeb8eb1 100644 --- a/cmd/admin.go +++ b/cmd/admin.go @@ -283,7 +283,7 @@ func runChangePassword(c *cli.Context) error { } user.HashPassword(c.String("password")) - if err := models.UpdateUserCols(user, "passwd", "salt"); err != nil { + if err := models.UpdateUserCols(user, "passwd", "passwd_hash_algo", "salt"); err != nil { return err } diff --git a/routers/user/auth.go b/routers/user/auth.go index 02cebe6a0e..893cad09be 100644 --- a/routers/user/auth.go +++ b/routers/user/auth.go @@ -1496,7 +1496,7 @@ func ResetPasswdPost(ctx *context.Context) { } u.HashPassword(passwd) u.MustChangePassword = false - if err := models.UpdateUserCols(u, "must_change_password", "passwd", "rands", "salt"); err != nil { + if err := models.UpdateUserCols(u, "must_change_password", "passwd", "passwd_hash_algo", "rands", "salt"); err != nil { ctx.ServerError("UpdateUser", err) return } @@ -1572,7 +1572,7 @@ func MustChangePasswordPost(ctx *context.Context, cpt *captcha.Captcha, form aut u.HashPassword(form.Password) u.MustChangePassword = false - if err := models.UpdateUserCols(u, "must_change_password", "passwd", "salt"); err != nil { + if err := models.UpdateUserCols(u, "must_change_password", "passwd", "passwd_hash_algo", "salt"); err != nil { ctx.ServerError("UpdateUser", err) return } diff --git a/routers/user/setting/account.go b/routers/user/setting/account.go index 9b72e2a31a..4fb2e4be40 100644 --- a/routers/user/setting/account.go +++ b/routers/user/setting/account.go @@ -68,7 +68,7 @@ func AccountPost(ctx *context.Context, form auth.ChangePasswordForm) { return } ctx.User.HashPassword(form.Password) - if err := models.UpdateUserCols(ctx.User, "salt", "passwd"); err != nil { + if err := models.UpdateUserCols(ctx.User, "salt", "passwd_hash_algo", "passwd"); err != nil { ctx.ServerError("UpdateUser", err) return } From d2b308ae3594afa8c2a5f2a797c4723bc4e0e948 Mon Sep 17 00:00:00 2001 From: zeripath Date: Mon, 14 Dec 2020 12:45:33 +0000 Subject: [PATCH 091/205] Ensure template renderer is available before storage handler (#13982) `ctx.Error` requires that templates are available for this to render the error page otherwise there will be a panic at this time. This was fixed in #13164 but was not completely backported. Fix #13971 Signed-off-by: Andrew Thornton --- routers/routes/routes.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/routers/routes/routes.go b/routers/routes/routes.go index 586474a661..a7b5b5b589 100644 --- a/routers/routes/routes.go +++ b/routers/routes/routes.go @@ -223,10 +223,11 @@ func NewMacaron() *macaron.Macaron { }, )) + m.Use(templates.HTMLRenderer()) + m.Use(storageHandler(setting.Avatar.Storage, "avatars", storage.Avatars)) m.Use(storageHandler(setting.RepoAvatar.Storage, "repo-avatars", storage.RepoAvatars)) - m.Use(templates.HTMLRenderer()) mailer.InitMailRender(templates.Mailer()) localeNames, err := options.Dir("locale") From 7f85728cf9c6ab1dcec5ed1be1dc66cef24634c3 Mon Sep 17 00:00:00 2001 From: zeripath Date: Mon, 14 Dec 2020 20:35:40 +0000 Subject: [PATCH 092/205] Trim the branch prefix from action.GetBranch (#13981) (#13986) Backport #13981 #13882 has revealed that the refname of an action is actually only a refname pattern and necessarily a branch. For examplem pushing to refs/heads/master will result in action with refname refs/heads/master but pushing to master will result in a refname master. The simplest solution to providing a fix here is to trim the prefix therefore this PR proposes this. Signed-off-by: Andrew Thornton Co-authored-by: a1012112796 <1012112796@qq.com> Co-authored-by: a1012112796 <1012112796@qq.com> --- models/action.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/models/action.go b/models/action.go index f4d163afa3..2b244fe90e 100644 --- a/models/action.go +++ b/models/action.go @@ -13,6 +13,7 @@ import ( "time" "code.gitea.io/gitea/modules/base" + "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/timeutil" @@ -243,7 +244,7 @@ func (a *Action) getCommentLink(e Engine) string { // GetBranch returns the action's repository branch. func (a *Action) GetBranch() string { - return a.RefName + return strings.TrimPrefix(a.RefName, git.BranchPrefix) } // GetContent returns the action's content. From a728d1e046d8d831276eea4ab7f84f700a76f34d Mon Sep 17 00:00:00 2001 From: Jimmy Praet Date: Wed, 16 Dec 2020 11:50:30 +0100 Subject: [PATCH 093/205] always use headCommitID for review comment diff (#14011) --- services/pull/review.go | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/services/pull/review.go b/services/pull/review.go index f0ee234a42..6781136061 100644 --- a/services/pull/review.go +++ b/services/pull/review.go @@ -167,16 +167,16 @@ func createCodeComment(doer *models.User, repo *models.Repository, issue *models // Only fetch diff if comment is review comment if len(patch) == 0 && reviewID != 0 { - if len(commitID) == 0 { - commitID, err = gitRepo.GetRefCommitID(pr.GetGitRefName()) - if err != nil { - return nil, fmt.Errorf("GetRefCommitID[%s]: %v", pr.GetGitRefName(), err) - } + headCommitID, err := gitRepo.GetRefCommitID(pr.GetGitRefName()) + if err != nil { + return nil, fmt.Errorf("GetRefCommitID[%s]: %v", pr.GetGitRefName(), err) + } + if len(commitID) == 0 { + commitID = headCommitID } - patchBuf := new(bytes.Buffer) - if err := git.GetRepoRawDiffForFile(gitRepo, pr.MergeBase, commitID, git.RawDiffNormal, treePath, patchBuf); err != nil { - return nil, fmt.Errorf("GetRawDiffForLine[%s, %s, %s, %s]: %v", gitRepo.Path, pr.MergeBase, commitID, treePath, err) + if err := git.GetRepoRawDiffForFile(gitRepo, pr.MergeBase, headCommitID, git.RawDiffNormal, treePath, patchBuf); err != nil { + return nil, fmt.Errorf("GetRawDiffForLine[%s, %s, %s, %s]: %v", gitRepo.Path, pr.MergeBase, headCommitID, treePath, err) } patch = git.CutDiffAroundLine(patchBuf, int64((&models.Comment{Line: line}).UnsignedLine()), line < 0, setting.UI.CodeCommentLines) } From 90dfe445c22ed5fbd751ecdcfce15879ad24b707 Mon Sep 17 00:00:00 2001 From: Cirno the Strongest <1447794+CirnoT@users.noreply.github.com> Date: Wed, 16 Dec 2020 18:24:02 +0100 Subject: [PATCH 094/205] Send webhook when tag is removed via Web UI (#14015) (#14019) * Send webhook when tag is removed via Web UI * Stray code (cherry picked from commit 53308de0bf6880798666a98cbc2df6c7be527f50) * Fix for 1.13 --- services/release/release.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/services/release/release.go b/services/release/release.go index c36e2126ed..82239420ca 100644 --- a/services/release/release.go +++ b/services/release/release.go @@ -142,6 +142,10 @@ func DeleteReleaseByID(id int64, doer *models.User, delTag bool) error { return fmt.Errorf("git tag -d: %v", err) } + notification.NotifyPushCommits( + doer, repo, git.TagPrefix+rel.TagName, rel.Sha1, git.EmptySHA, repository.NewPushCommits()) + notification.NotifyDeleteRef(doer, repo, "tag", git.TagPrefix+rel.TagName) + if err := models.DeleteReleaseByID(id); err != nil { return fmt.Errorf("DeleteReleaseByID: %v", err) } From 78b9ef35869be8e27af43717853425fcd7b3dcbf Mon Sep 17 00:00:00 2001 From: 6543 <6543@obermui.de> Date: Wed, 16 Dec 2020 20:15:58 +0000 Subject: [PATCH 095/205] Add emoji in label to project boards (#13978) (#14021) * Update view.tmpl Added rendering of emoji to project label * Add RenderEmojiPlain to the title and remove has-emoji Co-authored-by: zeripath Co-authored-by: Rakshith Ravi Co-authored-by: zeripath --- templates/repo/projects/view.tmpl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/templates/repo/projects/view.tmpl b/templates/repo/projects/view.tmpl index c25a05c5c7..beb9fea7b6 100644 --- a/templates/repo/projects/view.tmpl +++ b/templates/repo/projects/view.tmpl @@ -130,7 +130,7 @@
{{ range .Labels }} - {{.Name}} + {{.Name | RenderEmoji}} {{ end }}
From 4f296f7436e35af0b72c03e01b6cca46266052c8 Mon Sep 17 00:00:00 2001 From: mrsdizzie Date: Thu, 17 Dec 2020 11:39:12 -0500 Subject: [PATCH 096/205] Don't use simpleMDE editor on mobile devices for 1.13 (#14029) * Don't use simpleMDE editor on mobile devices simpleMDE doesn't work properly on mobile devices -- We've replaced it with the slightly more working easyMDE in 1.14 but since that change can't be backported to 1.13 we will just disable the editor on mobile here. * make isMobile function per code review -- disable simpleMDE for code review and replies * Fix issue with plain text and wiki Co-authored-by: silverwind --- web_src/js/index.js | 43 ++++++++++++++++++++++++++++++++----------- web_src/js/utils.js | 5 +++++ 2 files changed, 37 insertions(+), 11 deletions(-) diff --git a/web_src/js/index.js b/web_src/js/index.js index 2e81c23a2b..f007f32fb0 100644 --- a/web_src/js/index.js +++ b/web_src/js/index.js @@ -25,6 +25,7 @@ import ActivityTopAuthors from './components/ActivityTopAuthors.vue'; import {initNotificationsTable, initNotificationCount} from './features/notification.js'; import {createCodeEditor} from './features/codeeditor.js'; import {svg, svgs} from './svg.js'; +import {isMobile} from './utils.js'; const {AppSubUrl, StaticUrlPrefix, csrf} = window.config; @@ -385,8 +386,14 @@ function initCommentForm() { if ($('.comment.form').length === 0) { return; } - autoSimpleMDE = setCommentSimpleMDE($('.comment.form textarea:not(.review-textarea)')); + + // Don't use simpleMDE on mobile due to multiple bug reports which go unfixed + // Other sections rely on it being initialized so just set it back to text area here + if (isMobile()) { + autoSimpleMDE.toTextArea(); + } + initBranchSelector(); initCommentPreviewTab($('.comment.form')); initImagePaste($('.comment.form textarea')); @@ -1214,16 +1221,21 @@ function initPullRequestReview() { const form = $(this).parent().find('.comment-form'); form.removeClass('hide'); const $textarea = form.find('textarea'); - let $simplemde; - if ($textarea.data('simplemde')) { - $simplemde = $textarea.data('simplemde'); + if (!isMobile()) { + let $simplemde; + if ($textarea.data('simplemde')) { + $simplemde = $textarea.data('simplemde'); + } else { + attachTribute($textarea.get(), {mentions: true, emoji: true}); + $simplemde = setCommentSimpleMDE($textarea); + $textarea.data('simplemde', $simplemde); + } + $textarea.focus(); + $simplemde.codemirror.focus(); } else { attachTribute($textarea.get(), {mentions: true, emoji: true}); - $simplemde = setCommentSimpleMDE($textarea); - $textarea.data('simplemde', $simplemde); + $textarea.focus(); } - $textarea.focus(); - $simplemde.codemirror.focus(); assingMenuAttributes(form.find('.menu')); }); // The following part is only for diff views @@ -1290,9 +1302,13 @@ function initPullRequestReview() { const $textarea = commentCloud.find('textarea'); attachTribute($textarea.get(), {mentions: true, emoji: true}); - const $simplemde = setCommentSimpleMDE($textarea); - $textarea.focus(); - $simplemde.codemirror.focus(); + if (!isMobile()) { + const $simplemde = setCommentSimpleMDE($textarea); + $textarea.focus(); + $simplemde.codemirror.focus(); + } else { + $textarea.focus(); + } }); } @@ -1338,6 +1354,10 @@ function initWikiForm() { const $editArea = $('.repository.wiki textarea#edit_area'); let sideBySideChanges = 0; let sideBySideTimeout = null; + if ($editArea.length > 0 && isMobile) { + $editArea.css('display', 'inline-block'); + return; + } if ($editArea.length > 0) { const simplemde = new SimpleMDE({ autoDownloadFontAwesome: false, @@ -1433,6 +1453,7 @@ function initWikiForm() { name: 'revert-to-textarea', action(e) { e.toTextArea(); + $editArea.css('display', 'inline-block'); }, className: 'fa fa-file', title: 'Revert to simple textarea', diff --git a/web_src/js/utils.js b/web_src/js/utils.js index d5f921f8dc..1b1e1085a5 100644 --- a/web_src/js/utils.js +++ b/web_src/js/utils.js @@ -19,6 +19,11 @@ export function isDarkTheme() { return document.documentElement.classList.contains('theme-arc-green'); } +// returns if mobile device +export function isMobile() { + return /Mobi/.test(navigator.userAgent); +} + // removes duplicate elements in an array export function uniq(arr) { return Array.from(new Set(arr)); From b8a2cd9f407a59f1e457a2ea939060c3881b7e1a Mon Sep 17 00:00:00 2001 From: zeripath Date: Thu, 17 Dec 2020 20:06:51 +0000 Subject: [PATCH 097/205] Always wait for the cmd to finish (#14006) (#14039) Backport #14006 After cancelling the context we still need to wait for the command to finish otherwise zombie processes may occur Fix #13987 --- modules/git/command.go | 1 + 1 file changed, 1 insertion(+) diff --git a/modules/git/command.go b/modules/git/command.go index d40c0bfa23..c9d1732416 100644 --- a/modules/git/command.go +++ b/modules/git/command.go @@ -153,6 +153,7 @@ func (c *Command) RunInDirTimeoutEnvFullPipelineFunc(env []string, timeout time. err := fn(ctx, cancel) if err != nil { cancel() + _ = cmd.Wait() return err } } From df11075389fdf86e04a09168c68e82d80ec83812 Mon Sep 17 00:00:00 2001 From: 6543 <6543@obermui.de> Date: Thu, 17 Dec 2020 21:32:24 +0000 Subject: [PATCH 098/205] HotFix: Hide private partisipation in Orgs (#13994) (#14031) * HotFix: Hide private partisipation in Orgs Co-authored-by: zeripath --- models/user.go | 1 + routers/api/v1/org/org.go | 31 ++++++++++++++++++++----------- routers/api/v1/utils/utils.go | 19 +++++++++++++++++++ 3 files changed, 40 insertions(+), 11 deletions(-) diff --git a/models/user.go b/models/user.go index b2abdca964..dc3b4142bf 100644 --- a/models/user.go +++ b/models/user.go @@ -551,6 +551,7 @@ func (u *User) GetOwnedOrganizations() (err error) { } // GetOrganizations returns paginated organizations that user belongs to. +// TODO: does not respect All and show orgs you privately participate func (u *User) GetOrganizations(opts *SearchOrganizationsOptions) error { sess := x.NewSession() defer sess.Close() diff --git a/routers/api/v1/org/org.go b/routers/api/v1/org/org.go index 987f141078..ca3e10173b 100644 --- a/routers/api/v1/org/org.go +++ b/routers/api/v1/org/org.go @@ -17,19 +17,28 @@ import ( "code.gitea.io/gitea/routers/api/v1/utils" ) -func listUserOrgs(ctx *context.APIContext, u *models.User, all bool) { - if err := u.GetOrganizations(&models.SearchOrganizationsOptions{ - ListOptions: utils.GetListOptions(ctx), - All: all, - }); err != nil { - ctx.Error(http.StatusInternalServerError, "GetOrganizations", err) +func listUserOrgs(ctx *context.APIContext, u *models.User) { + + listOptions := utils.GetListOptions(ctx) + showPrivate := ctx.IsSigned && (ctx.User.IsAdmin || ctx.User.ID == u.ID) + + orgs, err := models.GetOrgsByUserID(u.ID, showPrivate) + if err != nil { + ctx.Error(http.StatusInternalServerError, "GetOrgsByUserID", err) return } + maxResults := len(orgs) - apiOrgs := make([]*api.Organization, len(u.Orgs)) - for i := range u.Orgs { - apiOrgs[i] = convert.ToOrganization(u.Orgs[i]) + orgs = utils.PaginateUserSlice(orgs, listOptions.Page, listOptions.PageSize) + + apiOrgs := make([]*api.Organization, len(orgs)) + for i := range orgs { + apiOrgs[i] = convert.ToOrganization(orgs[i]) } + + ctx.SetLinkHeader(int(maxResults), listOptions.PageSize) + ctx.Header().Set("X-Total-Count", fmt.Sprintf("%d", maxResults)) + ctx.Header().Set("Access-Control-Expose-Headers", "X-Total-Count, Link") ctx.JSON(http.StatusOK, &apiOrgs) } @@ -53,7 +62,7 @@ func ListMyOrgs(ctx *context.APIContext) { // "200": // "$ref": "#/responses/OrganizationList" - listUserOrgs(ctx, ctx.User, true) + listUserOrgs(ctx, ctx.User) } // ListUserOrgs list user's orgs @@ -85,7 +94,7 @@ func ListUserOrgs(ctx *context.APIContext) { if ctx.Written() { return } - listUserOrgs(ctx, u, ctx.User != nil && (ctx.User.IsAdmin || ctx.User.ID == u.ID)) + listUserOrgs(ctx, u) } // GetAll return list of all public organizations diff --git a/routers/api/v1/utils/utils.go b/routers/api/v1/utils/utils.go index ad1a136db4..5732ea7f7d 100644 --- a/routers/api/v1/utils/utils.go +++ b/routers/api/v1/utils/utils.go @@ -66,3 +66,22 @@ func GetListOptions(ctx *context.APIContext) models.ListOptions { PageSize: convert.ToCorrectPageSize(ctx.QueryInt("limit")), } } + +// PaginateUserSlice cut a slice of Users as per pagination options +// TODO: make it generic +func PaginateUserSlice(items []*models.User, page, pageSize int) []*models.User { + if page != 0 { + page-- + } + + if page*pageSize >= len(items) { + return items[len(items):] + } + + items = items[page*pageSize:] + + if len(items) > pageSize { + return items[:pageSize] + } + return items +} From 96d41287e5f4b9932ca38b404779a08a23eae266 Mon Sep 17 00:00:00 2001 From: 6543 <6543@obermui.de> Date: Fri, 18 Dec 2020 13:38:47 +0000 Subject: [PATCH 099/205] [API] GetCombinedCommitStatusByRef always return json & swagger doc fixes (#14047) * Fix swagger docs * always return json --- routers/api/v1/repo/status.go | 6 +- routers/api/v1/swagger/repo.go | 7 ++ templates/swagger/v1_json.tmpl | 128 ++++++++++++++++++++++++++++++++- 3 files changed, 136 insertions(+), 5 deletions(-) diff --git a/routers/api/v1/repo/status.go b/routers/api/v1/repo/status.go index 69661dca91..22e78d060c 100644 --- a/routers/api/v1/repo/status.go +++ b/routers/api/v1/repo/status.go @@ -244,7 +244,7 @@ type combinedCommitStatus struct { // GetCombinedCommitStatusByRef returns the combined status for any given commit hash func GetCombinedCommitStatusByRef(ctx *context.APIContext) { - // swagger:operation GET /repos/{owner}/{repo}/commits/{ref}/statuses repository repoGetCombinedStatusByRef + // swagger:operation GET /repos/{owner}/{repo}/commits/{ref}/status repository repoGetCombinedStatusByRef // --- // summary: Get a commit's combined status, by branch/tag/commit reference // produces: @@ -272,7 +272,7 @@ func GetCombinedCommitStatusByRef(ctx *context.APIContext) { // required: false // responses: // "200": - // "$ref": "#/responses/Status" + // "$ref": "#/responses/CombinedStatus" // "400": // "$ref": "#/responses/error" @@ -292,7 +292,7 @@ func GetCombinedCommitStatusByRef(ctx *context.APIContext) { } if len(statuses) == 0 { - ctx.Status(http.StatusOK) + ctx.JSON(http.StatusOK, &api.CombinedStatus{}) return } diff --git a/routers/api/v1/swagger/repo.go b/routers/api/v1/swagger/repo.go index bce9e45c37..76c9ac608b 100644 --- a/routers/api/v1/swagger/repo.go +++ b/routers/api/v1/swagger/repo.go @@ -309,3 +309,10 @@ type swaggerLanguageStatistics struct { // in: body Body map[string]int64 `json:"body"` } + +// CombinedStatus +// swagger:response CombinedStatus +type swaggerCombinedStatus struct { + // in: body + Body api.CombinedStatus `json:"body"` +} diff --git a/templates/swagger/v1_json.tmpl b/templates/swagger/v1_json.tmpl index 96871b48c7..10c9c24f89 100644 --- a/templates/swagger/v1_json.tmpl +++ b/templates/swagger/v1_json.tmpl @@ -2829,7 +2829,7 @@ } } }, - "/repos/{owner}/{repo}/commits/{ref}/statuses": { + "/repos/{owner}/{repo}/commits/{ref}/status": { "get": { "produces": [ "application/json" @@ -2870,7 +2870,88 @@ ], "responses": { "200": { - "$ref": "#/responses/Status" + "$ref": "#/responses/CombinedStatus" + }, + "400": { + "$ref": "#/responses/error" + } + } + } + }, + "/repos/{owner}/{repo}/commits/{ref}/statuses": { + "get": { + "produces": [ + "application/json" + ], + "tags": [ + "repository" + ], + "summary": "Get a commit's statuses, by branch/tag/commit reference", + "operationId": "repoListStatusesByRef", + "parameters": [ + { + "type": "string", + "description": "owner of the repo", + "name": "owner", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "name of the repo", + "name": "repo", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "name of branch/tag/commit", + "name": "ref", + "in": "path", + "required": true + }, + { + "enum": [ + "oldest", + "recentupdate", + "leastupdate", + "leastindex", + "highestindex" + ], + "type": "string", + "description": "type of sort", + "name": "sort", + "in": "query" + }, + { + "enum": [ + "pending", + "success", + "error", + "failure", + "warning" + ], + "type": "string", + "description": "type of state", + "name": "state", + "in": "query" + }, + { + "type": "integer", + "description": "page number of results to return (1-based)", + "name": "page", + "in": "query" + }, + { + "type": "integer", + "description": "page size of results", + "name": "limit", + "in": "query" + } + ], + "responses": { + "200": { + "$ref": "#/responses/StatusList" }, "400": { "$ref": "#/responses/error" @@ -11240,6 +11321,43 @@ }, "x-go-package": "code.gitea.io/gitea/modules/structs" }, + "CombinedStatus": { + "description": "CombinedStatus holds the combined state of several statuses for a single commit", + "type": "object", + "properties": { + "commit_url": { + "type": "string", + "x-go-name": "CommitURL" + }, + "repository": { + "$ref": "#/definitions/Repository" + }, + "sha": { + "type": "string", + "x-go-name": "SHA" + }, + "state": { + "$ref": "#/definitions/StatusState" + }, + "statuses": { + "type": "array", + "items": { + "$ref": "#/definitions/Status" + }, + "x-go-name": "Statuses" + }, + "total_count": { + "type": "integer", + "format": "int64", + "x-go-name": "TotalCount" + }, + "url": { + "type": "string", + "x-go-name": "URL" + } + }, + "x-go-package": "code.gitea.io/gitea/modules/structs" + }, "Comment": { "description": "Comment represents a comment on a commit or issue", "type": "object", @@ -15532,6 +15650,12 @@ } } }, + "CombinedStatus": { + "description": "CombinedStatus", + "schema": { + "$ref": "#/definitions/CombinedStatus" + } + }, "Comment": { "description": "Comment", "schema": { From 55d7e53d99e968e56117b31a27b391b6a5a8e182 Mon Sep 17 00:00:00 2001 From: silverwind Date: Fri, 18 Dec 2020 17:19:43 +0100 Subject: [PATCH 100/205] Fix panic in BasicAuthDecode (#14046) (#14048) * Fix panic in BasicAuthDecode If the string does not contain ":" that function would run into an `index out of range [1] with length 1` error. prevent that. * Update BasicAuthDecode() Co-authored-by: 6543 <6543@obermui.de> Co-authored-by: 6543 <6543@obermui.de> Co-authored-by: zeripath --- modules/base/tool.go | 6 ++++++ modules/base/tool_test.go | 6 ++++++ 2 files changed, 12 insertions(+) diff --git a/modules/base/tool.go b/modules/base/tool.go index a21fd9b0f4..522fd3d0fa 100644 --- a/modules/base/tool.go +++ b/modules/base/tool.go @@ -10,6 +10,7 @@ import ( "crypto/sha256" "encoding/base64" "encoding/hex" + "errors" "fmt" "net/http" "net/url" @@ -65,6 +66,11 @@ func BasicAuthDecode(encoded string) (string, string, error) { } auth := strings.SplitN(string(s), ":", 2) + + if len(auth) != 2 { + return "", "", errors.New("invalid basic authentication") + } + return auth[0], auth[1], nil } diff --git a/modules/base/tool_test.go b/modules/base/tool_test.go index f765fd0db0..d2187facd7 100644 --- a/modules/base/tool_test.go +++ b/modules/base/tool_test.go @@ -46,6 +46,12 @@ func TestBasicAuthDecode(t *testing.T) { assert.NoError(t, err) assert.Equal(t, "foo", user) assert.Equal(t, "bar", pass) + + _, _, err = BasicAuthDecode("aW52YWxpZA==") + assert.Error(t, err) + + _, _, err = BasicAuthDecode("invalid") + assert.Error(t, err) } func TestBasicAuthEncode(t *testing.T) { From 70038719bf29b19c0be8d06df47984b104693c04 Mon Sep 17 00:00:00 2001 From: techknowlogick Date: Mon, 21 Dec 2020 01:02:40 -0500 Subject: [PATCH 101/205] dep: update crypto. info: https://golangtutorial.dev/news/fix-in-crypto-package/ (#14078) --- go.mod | 2 +- go.sum | 5 ++ vendor/golang.org/x/crypto/acme/acme.go | 4 ++ vendor/golang.org/x/crypto/acme/jws.go | 69 +++++++++++++++++-- vendor/golang.org/x/crypto/acme/rfc8555.go | 33 +++++++-- vendor/golang.org/x/crypto/acme/types.go | 25 +++++++ .../x/crypto/argon2/blamka_amd64.go | 2 +- .../golang.org/x/crypto/argon2/blamka_amd64.s | 2 +- .../golang.org/x/crypto/argon2/blamka_ref.go | 2 +- .../x/crypto/blake2b/blake2bAVX2_amd64.go | 2 +- .../x/crypto/blake2b/blake2bAVX2_amd64.s | 2 +- .../x/crypto/blake2b/blake2b_amd64.go | 2 +- .../x/crypto/blake2b/blake2b_amd64.s | 2 +- .../x/crypto/blake2b/blake2b_ref.go | 2 +- .../x/crypto/chacha20/chacha_arm64.go | 2 +- .../x/crypto/chacha20/chacha_arm64.s | 2 +- .../x/crypto/chacha20/chacha_noasm.go | 2 +- .../x/crypto/chacha20/chacha_ppc64le.go | 2 +- .../x/crypto/chacha20/chacha_ppc64le.s | 2 +- .../x/crypto/chacha20/chacha_s390x.go | 2 +- .../x/crypto/chacha20/chacha_s390x.s | 2 +- .../x/crypto/curve25519/curve25519_amd64.go | 2 +- .../x/crypto/curve25519/curve25519_amd64.s | 2 +- .../x/crypto/curve25519/curve25519_noasm.go | 2 +- .../x/crypto/internal/subtle/aliasing.go | 2 +- ...iasing_appengine.go => aliasing_purego.go} | 2 +- .../golang.org/x/crypto/poly1305/mac_noasm.go | 2 +- .../golang.org/x/crypto/poly1305/sum_amd64.go | 2 +- .../golang.org/x/crypto/poly1305/sum_amd64.s | 2 +- .../x/crypto/poly1305/sum_ppc64le.go | 2 +- .../x/crypto/poly1305/sum_ppc64le.s | 2 +- .../golang.org/x/crypto/poly1305/sum_s390x.go | 2 +- .../golang.org/x/crypto/poly1305/sum_s390x.s | 2 +- vendor/golang.org/x/crypto/ssh/client_auth.go | 2 +- vendor/golang.org/x/crypto/ssh/kex.go | 13 +--- vendor/golang.org/x/crypto/ssh/server.go | 4 ++ vendor/modules.txt | 2 +- 37 files changed, 162 insertions(+), 51 deletions(-) rename vendor/golang.org/x/crypto/internal/subtle/{aliasing_appengine.go => aliasing_purego.go} (98%) diff --git a/go.mod b/go.mod index 0d600e3e77..58ae699672 100644 --- a/go.mod +++ b/go.mod @@ -104,7 +104,7 @@ require ( github.com/yuin/goldmark-meta v0.0.0-20191126180153-f0638e958b60 go.jolheiser.com/hcaptcha v0.0.4 go.jolheiser.com/pwn v0.0.3 - golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a + golang.org/x/crypto v0.0.0-20201217014255-9d1352758620 golang.org/x/net v0.0.0-20200904194848-62affa334b73 golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d golang.org/x/sys v0.0.0-20200918174421-af09f7315aff diff --git a/go.sum b/go.sum index bfe56cde80..975e6585f7 100644 --- a/go.sum +++ b/go.sum @@ -939,6 +939,8 @@ golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPh golang.org/x/crypto v0.0.0-20200709230013-948cd5f35899/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a h1:vclmkQCjlDX5OydZ9wv8rBCcS0QyQY66Mpf/7BZbInM= golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20201217014255-9d1352758620 h1:3wPMTskHO3+O6jqTEXyFcsnuxMQOqYSaHsDxcbUXpqA= +golang.org/x/crypto v0.0.0-20201217014255-9d1352758620/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -1053,6 +1055,8 @@ golang.org/x/sys v0.0.0-20200413165638-669c56c373c4/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200918174421-af09f7315aff h1:1CPUrky56AcgSpxz/KfgzQWzfG09u5YOL8MvPYBlrL8= golang.org/x/sys v0.0.0-20200918174421-af09f7315aff/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/term v0.0.0-20201117132131-f5c789dd3221 h1:/ZHdbVpdR/jk3g30/d4yUL0JU9kksj8+F/bnQUVLGDM= +golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= @@ -1197,6 +1201,7 @@ honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWh honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= +mvdan.cc/xurls/v2 v2.2.0 h1:NSZPykBXJFCetGZykLAxaL6SIpvbVy/UFEniIfHAa8A= mvdan.cc/xurls/v2 v2.2.0/go.mod h1:EV1RMtya9D6G5DMYPGD8zTQzaHet6Jh8gFlRgGRJeO8= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= strk.kbt.io/projects/go/libravatar v0.0.0-20191008002943-06d1c002b251 h1:mUcz5b3FJbP5Cvdq7Khzn6J9OCUQJaBwgBkCR+MOwSs= diff --git a/vendor/golang.org/x/crypto/acme/acme.go b/vendor/golang.org/x/crypto/acme/acme.go index 6e6c9d1319..174cfe8b41 100644 --- a/vendor/golang.org/x/crypto/acme/acme.go +++ b/vendor/golang.org/x/crypto/acme/acme.go @@ -363,6 +363,10 @@ func AcceptTOS(tosURL string) bool { return true } // Also see Error's Instance field for when a CA requires already registered accounts to agree // to an updated Terms of Service. func (c *Client) Register(ctx context.Context, acct *Account, prompt func(tosURL string) bool) (*Account, error) { + if c.Key == nil { + return nil, errors.New("acme: client.Key must be set to Register") + } + dir, err := c.Discover(ctx) if err != nil { return nil, err diff --git a/vendor/golang.org/x/crypto/acme/jws.go b/vendor/golang.org/x/crypto/acme/jws.go index 76e3fdacf1..04f509f0f0 100644 --- a/vendor/golang.org/x/crypto/acme/jws.go +++ b/vendor/golang.org/x/crypto/acme/jws.go @@ -7,17 +7,31 @@ package acme import ( "crypto" "crypto/ecdsa" + "crypto/hmac" "crypto/rand" "crypto/rsa" "crypto/sha256" + "crypto/sha512" _ "crypto/sha512" // need for EC keys "encoding/asn1" "encoding/base64" "encoding/json" + "errors" "fmt" + "hash" "math/big" ) +// MACAlgorithm represents a JWS MAC signature algorithm. +// See https://tools.ietf.org/html/rfc7518#section-3.1 for more details. +type MACAlgorithm string + +const ( + MACAlgorithmHS256 = MACAlgorithm("HS256") + MACAlgorithmHS384 = MACAlgorithm("HS384") + MACAlgorithmHS512 = MACAlgorithm("HS512") +) + // keyID is the account identity provided by a CA during registration. type keyID string @@ -31,6 +45,14 @@ const noKeyID = keyID("") // See https://tools.ietf.org/html/rfc8555#section-6.3 for more details. const noPayload = "" +// jsonWebSignature can be easily serialized into a JWS following +// https://tools.ietf.org/html/rfc7515#section-3.2. +type jsonWebSignature struct { + Protected string `json:"protected"` + Payload string `json:"payload"` + Sig string `json:"signature"` +} + // jwsEncodeJSON signs claimset using provided key and a nonce. // The result is serialized in JSON format containing either kid or jwk // fields based on the provided keyID value. @@ -71,12 +93,7 @@ func jwsEncodeJSON(claimset interface{}, key crypto.Signer, kid keyID, nonce, ur if err != nil { return nil, err } - - enc := struct { - Protected string `json:"protected"` - Payload string `json:"payload"` - Sig string `json:"signature"` - }{ + enc := jsonWebSignature{ Protected: phead, Payload: payload, Sig: base64.RawURLEncoding.EncodeToString(sig), @@ -84,6 +101,32 @@ func jwsEncodeJSON(claimset interface{}, key crypto.Signer, kid keyID, nonce, ur return json.Marshal(&enc) } +// jwsWithMAC creates and signs a JWS using the given key and algorithm. +// "rawProtected" and "rawPayload" should not be base64-URL-encoded. +func jwsWithMAC(key []byte, alg MACAlgorithm, rawProtected, rawPayload []byte) (*jsonWebSignature, error) { + if len(key) == 0 { + return nil, errors.New("acme: cannot sign JWS with an empty MAC key") + } + protected := base64.RawURLEncoding.EncodeToString(rawProtected) + payload := base64.RawURLEncoding.EncodeToString(rawPayload) + + // Only HMACs are currently supported. + hmac, err := newHMAC(key, alg) + if err != nil { + return nil, err + } + if _, err := hmac.Write([]byte(protected + "." + payload)); err != nil { + return nil, err + } + mac := hmac.Sum(nil) + + return &jsonWebSignature{ + Protected: protected, + Payload: payload, + Sig: base64.RawURLEncoding.EncodeToString(mac), + }, nil +} + // jwkEncode encodes public part of an RSA or ECDSA key into a JWK. // The result is also suitable for creating a JWK thumbprint. // https://tools.ietf.org/html/rfc7517 @@ -175,6 +218,20 @@ func jwsHasher(pub crypto.PublicKey) (string, crypto.Hash) { return "", 0 } +// newHMAC returns an appropriate HMAC for the given MACAlgorithm. +func newHMAC(key []byte, alg MACAlgorithm) (hash.Hash, error) { + switch alg { + case MACAlgorithmHS256: + return hmac.New(sha256.New, key), nil + case MACAlgorithmHS384: + return hmac.New(sha512.New384, key), nil + case MACAlgorithmHS512: + return hmac.New(sha512.New, key), nil + default: + return nil, fmt.Errorf("acme: unsupported MAC algorithm: %v", alg) + } +} + // JWKThumbprint creates a JWK thumbprint out of pub // as specified in https://tools.ietf.org/html/rfc7638. func JWKThumbprint(pub crypto.PublicKey) (string, error) { diff --git a/vendor/golang.org/x/crypto/acme/rfc8555.go b/vendor/golang.org/x/crypto/acme/rfc8555.go index dfb57a66fd..ceb239d72a 100644 --- a/vendor/golang.org/x/crypto/acme/rfc8555.go +++ b/vendor/golang.org/x/crypto/acme/rfc8555.go @@ -5,6 +5,7 @@ package acme import ( + "bytes" "context" "crypto" "encoding/base64" @@ -37,22 +38,32 @@ func (c *Client) DeactivateReg(ctx context.Context) error { return nil } -// registerRFC is quivalent to c.Register but for CAs implementing RFC 8555. +// registerRFC is equivalent to c.Register but for CAs implementing RFC 8555. // It expects c.Discover to have already been called. -// TODO: Implement externalAccountBinding. func (c *Client) registerRFC(ctx context.Context, acct *Account, prompt func(tosURL string) bool) (*Account, error) { c.cacheMu.Lock() // guard c.kid access defer c.cacheMu.Unlock() req := struct { - TermsAgreed bool `json:"termsOfServiceAgreed,omitempty"` - Contact []string `json:"contact,omitempty"` + TermsAgreed bool `json:"termsOfServiceAgreed,omitempty"` + Contact []string `json:"contact,omitempty"` + ExternalAccountBinding *jsonWebSignature `json:"externalAccountBinding,omitempty"` }{ Contact: acct.Contact, } if c.dir.Terms != "" { req.TermsAgreed = prompt(c.dir.Terms) } + + // set 'externalAccountBinding' field if requested + if acct.ExternalAccountBinding != nil { + eabJWS, err := c.encodeExternalAccountBinding(acct.ExternalAccountBinding) + if err != nil { + return nil, fmt.Errorf("acme: failed to encode external account binding: %v", err) + } + req.ExternalAccountBinding = eabJWS + } + res, err := c.post(ctx, c.Key, c.dir.RegURL, req, wantStatus( http.StatusOK, // account with this key already registered http.StatusCreated, // new account created @@ -75,7 +86,19 @@ func (c *Client) registerRFC(ctx context.Context, acct *Account, prompt func(tos return a, nil } -// updateGegRFC is equivalent to c.UpdateReg but for CAs implementing RFC 8555. +// encodeExternalAccountBinding will encode an external account binding stanza +// as described in https://tools.ietf.org/html/rfc8555#section-7.3.4. +func (c *Client) encodeExternalAccountBinding(eab *ExternalAccountBinding) (*jsonWebSignature, error) { + jwk, err := jwkEncode(c.Key.Public()) + if err != nil { + return nil, err + } + var rProtected bytes.Buffer + fmt.Fprintf(&rProtected, `{"alg":%q,"kid":%q,"url":%q}`, eab.Algorithm, eab.KID, c.dir.RegURL) + return jwsWithMAC(eab.Key, eab.Algorithm, rProtected.Bytes(), []byte(jwk)) +} + +// updateRegRFC is equivalent to c.UpdateReg but for CAs implementing RFC 8555. // It expects c.Discover to have already been called. func (c *Client) updateRegRFC(ctx context.Context, a *Account) (*Account, error) { url := string(c.accountKID(ctx)) diff --git a/vendor/golang.org/x/crypto/acme/types.go b/vendor/golang.org/x/crypto/acme/types.go index e959cafc82..4d89fed8cb 100644 --- a/vendor/golang.org/x/crypto/acme/types.go +++ b/vendor/golang.org/x/crypto/acme/types.go @@ -199,6 +199,31 @@ type Account struct { // // It is non-RFC 8555 compliant and is obsoleted by OrdersURL. Certificates string + + // ExternalAccountBinding represents an arbitrary binding to an account of + // the CA which the ACME server is tied to. + // See https://tools.ietf.org/html/rfc8555#section-7.3.4 for more details. + ExternalAccountBinding *ExternalAccountBinding +} + +// ExternalAccountBinding contains the data needed to form a request with +// an external account binding. +// See https://tools.ietf.org/html/rfc8555#section-7.3.4 for more details. +type ExternalAccountBinding struct { + // KID is the Key ID of the symmetric MAC key that the CA provides to + // identify an external account from ACME. + KID string + + // Key is the bytes of the symmetric key that the CA provides to identify + // the account. Key must correspond to the KID. + Key []byte + + // Algorithm used to sign the JWS. + Algorithm MACAlgorithm +} + +func (e *ExternalAccountBinding) String() string { + return fmt.Sprintf("&{KID: %q, Key: redacted, Algorithm: %v}", e.KID, e.Algorithm) } // Directory is ACME server discovery data. diff --git a/vendor/golang.org/x/crypto/argon2/blamka_amd64.go b/vendor/golang.org/x/crypto/argon2/blamka_amd64.go index 2fc1ec0312..1108e11447 100644 --- a/vendor/golang.org/x/crypto/argon2/blamka_amd64.go +++ b/vendor/golang.org/x/crypto/argon2/blamka_amd64.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// +build amd64,!gccgo,!appengine +// +build amd64,gc,!purego package argon2 diff --git a/vendor/golang.org/x/crypto/argon2/blamka_amd64.s b/vendor/golang.org/x/crypto/argon2/blamka_amd64.s index 74a6e7332a..c4c84f07a0 100644 --- a/vendor/golang.org/x/crypto/argon2/blamka_amd64.s +++ b/vendor/golang.org/x/crypto/argon2/blamka_amd64.s @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// +build amd64,!gccgo,!appengine +// +build amd64,gc,!purego #include "textflag.h" diff --git a/vendor/golang.org/x/crypto/argon2/blamka_ref.go b/vendor/golang.org/x/crypto/argon2/blamka_ref.go index baf7b551da..4a963c7808 100644 --- a/vendor/golang.org/x/crypto/argon2/blamka_ref.go +++ b/vendor/golang.org/x/crypto/argon2/blamka_ref.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// +build !amd64 appengine gccgo +// +build !amd64 purego !gc package argon2 diff --git a/vendor/golang.org/x/crypto/blake2b/blake2bAVX2_amd64.go b/vendor/golang.org/x/crypto/blake2b/blake2bAVX2_amd64.go index 4d31dd0fdc..8a893fdfff 100644 --- a/vendor/golang.org/x/crypto/blake2b/blake2bAVX2_amd64.go +++ b/vendor/golang.org/x/crypto/blake2b/blake2bAVX2_amd64.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// +build go1.7,amd64,!gccgo,!appengine +// +build go1.7,amd64,gc,!purego package blake2b diff --git a/vendor/golang.org/x/crypto/blake2b/blake2bAVX2_amd64.s b/vendor/golang.org/x/crypto/blake2b/blake2bAVX2_amd64.s index 5593b1b3dc..8608a7f7d1 100644 --- a/vendor/golang.org/x/crypto/blake2b/blake2bAVX2_amd64.s +++ b/vendor/golang.org/x/crypto/blake2b/blake2bAVX2_amd64.s @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// +build go1.7,amd64,!gccgo,!appengine +// +build go1.7,amd64,gc,!purego #include "textflag.h" diff --git a/vendor/golang.org/x/crypto/blake2b/blake2b_amd64.go b/vendor/golang.org/x/crypto/blake2b/blake2b_amd64.go index 30e2fcd581..a52c887fcb 100644 --- a/vendor/golang.org/x/crypto/blake2b/blake2b_amd64.go +++ b/vendor/golang.org/x/crypto/blake2b/blake2b_amd64.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// +build !go1.7,amd64,!gccgo,!appengine +// +build !go1.7,amd64,gc,!purego package blake2b diff --git a/vendor/golang.org/x/crypto/blake2b/blake2b_amd64.s b/vendor/golang.org/x/crypto/blake2b/blake2b_amd64.s index 578e947b3b..1f4c6a9279 100644 --- a/vendor/golang.org/x/crypto/blake2b/blake2b_amd64.s +++ b/vendor/golang.org/x/crypto/blake2b/blake2b_amd64.s @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// +build amd64,!gccgo,!appengine +// +build amd64,gc,!purego #include "textflag.h" diff --git a/vendor/golang.org/x/crypto/blake2b/blake2b_ref.go b/vendor/golang.org/x/crypto/blake2b/blake2b_ref.go index da156a1ba6..8597457781 100644 --- a/vendor/golang.org/x/crypto/blake2b/blake2b_ref.go +++ b/vendor/golang.org/x/crypto/blake2b/blake2b_ref.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// +build !amd64 appengine gccgo +// +build !amd64 purego !gc package blake2b diff --git a/vendor/golang.org/x/crypto/chacha20/chacha_arm64.go b/vendor/golang.org/x/crypto/chacha20/chacha_arm64.go index b799e440b4..c474e5a804 100644 --- a/vendor/golang.org/x/crypto/chacha20/chacha_arm64.go +++ b/vendor/golang.org/x/crypto/chacha20/chacha_arm64.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// +build go1.11,!gccgo,!purego +// +build go1.11,gc,!purego package chacha20 diff --git a/vendor/golang.org/x/crypto/chacha20/chacha_arm64.s b/vendor/golang.org/x/crypto/chacha20/chacha_arm64.s index 891481539a..8fb49a13e3 100644 --- a/vendor/golang.org/x/crypto/chacha20/chacha_arm64.s +++ b/vendor/golang.org/x/crypto/chacha20/chacha_arm64.s @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// +build go1.11,!gccgo,!purego +// +build go1.11,gc,!purego #include "textflag.h" diff --git a/vendor/golang.org/x/crypto/chacha20/chacha_noasm.go b/vendor/golang.org/x/crypto/chacha20/chacha_noasm.go index 4635307b8f..3e8a609fbd 100644 --- a/vendor/golang.org/x/crypto/chacha20/chacha_noasm.go +++ b/vendor/golang.org/x/crypto/chacha20/chacha_noasm.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// +build !arm64,!s390x,!ppc64le arm64,!go1.11 gccgo purego +// +build !arm64,!s390x,!ppc64le arm64,!go1.11 !gc purego package chacha20 diff --git a/vendor/golang.org/x/crypto/chacha20/chacha_ppc64le.go b/vendor/golang.org/x/crypto/chacha20/chacha_ppc64le.go index b799330341..2806c6325d 100644 --- a/vendor/golang.org/x/crypto/chacha20/chacha_ppc64le.go +++ b/vendor/golang.org/x/crypto/chacha20/chacha_ppc64le.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// +build !gccgo,!purego +// +build gc,!purego package chacha20 diff --git a/vendor/golang.org/x/crypto/chacha20/chacha_ppc64le.s b/vendor/golang.org/x/crypto/chacha20/chacha_ppc64le.s index 23c6021643..3dad4b2fa2 100644 --- a/vendor/golang.org/x/crypto/chacha20/chacha_ppc64le.s +++ b/vendor/golang.org/x/crypto/chacha20/chacha_ppc64le.s @@ -19,7 +19,7 @@ // The differences in this and the original implementation are // due to the calling conventions and initialization of constants. -// +build !gccgo,!purego +// +build gc,!purego #include "textflag.h" diff --git a/vendor/golang.org/x/crypto/chacha20/chacha_s390x.go b/vendor/golang.org/x/crypto/chacha20/chacha_s390x.go index a9244bdf4d..a0774dde1c 100644 --- a/vendor/golang.org/x/crypto/chacha20/chacha_s390x.go +++ b/vendor/golang.org/x/crypto/chacha20/chacha_s390x.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// +build !gccgo,!purego +// +build gc,!purego package chacha20 diff --git a/vendor/golang.org/x/crypto/chacha20/chacha_s390x.s b/vendor/golang.org/x/crypto/chacha20/chacha_s390x.s index 89c658c410..818161189b 100644 --- a/vendor/golang.org/x/crypto/chacha20/chacha_s390x.s +++ b/vendor/golang.org/x/crypto/chacha20/chacha_s390x.s @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// +build !gccgo,!purego +// +build gc,!purego #include "go_asm.h" #include "textflag.h" diff --git a/vendor/golang.org/x/crypto/curve25519/curve25519_amd64.go b/vendor/golang.org/x/crypto/curve25519/curve25519_amd64.go index 5120b779b9..877b6de292 100644 --- a/vendor/golang.org/x/crypto/curve25519/curve25519_amd64.go +++ b/vendor/golang.org/x/crypto/curve25519/curve25519_amd64.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// +build amd64,!gccgo,!appengine,!purego +// +build amd64,gc,!purego package curve25519 diff --git a/vendor/golang.org/x/crypto/curve25519/curve25519_amd64.s b/vendor/golang.org/x/crypto/curve25519/curve25519_amd64.s index 0250c88859..6c53380926 100644 --- a/vendor/golang.org/x/crypto/curve25519/curve25519_amd64.s +++ b/vendor/golang.org/x/crypto/curve25519/curve25519_amd64.s @@ -5,7 +5,7 @@ // This code was translated into a form compatible with 6a from the public // domain sources in SUPERCOP: https://bench.cr.yp.to/supercop.html -// +build amd64,!gccgo,!appengine,!purego +// +build amd64,gc,!purego #define REDMASK51 0x0007FFFFFFFFFFFF diff --git a/vendor/golang.org/x/crypto/curve25519/curve25519_noasm.go b/vendor/golang.org/x/crypto/curve25519/curve25519_noasm.go index 047d49afc2..80d3300af5 100644 --- a/vendor/golang.org/x/crypto/curve25519/curve25519_noasm.go +++ b/vendor/golang.org/x/crypto/curve25519/curve25519_noasm.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// +build !amd64 gccgo appengine purego +// +build !amd64 !gc purego package curve25519 diff --git a/vendor/golang.org/x/crypto/internal/subtle/aliasing.go b/vendor/golang.org/x/crypto/internal/subtle/aliasing.go index f38797bfa1..281c27ef02 100644 --- a/vendor/golang.org/x/crypto/internal/subtle/aliasing.go +++ b/vendor/golang.org/x/crypto/internal/subtle/aliasing.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// +build !appengine +// +build !purego // Package subtle implements functions that are often useful in cryptographic // code but require careful thought to use correctly. diff --git a/vendor/golang.org/x/crypto/internal/subtle/aliasing_appengine.go b/vendor/golang.org/x/crypto/internal/subtle/aliasing_purego.go similarity index 98% rename from vendor/golang.org/x/crypto/internal/subtle/aliasing_appengine.go rename to vendor/golang.org/x/crypto/internal/subtle/aliasing_purego.go index 0cc4a8a642..e20a296592 100644 --- a/vendor/golang.org/x/crypto/internal/subtle/aliasing_appengine.go +++ b/vendor/golang.org/x/crypto/internal/subtle/aliasing_purego.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// +build appengine +// +build purego // Package subtle implements functions that are often useful in cryptographic // code but require careful thought to use correctly. diff --git a/vendor/golang.org/x/crypto/poly1305/mac_noasm.go b/vendor/golang.org/x/crypto/poly1305/mac_noasm.go index d118f30ed5..af6c94f921 100644 --- a/vendor/golang.org/x/crypto/poly1305/mac_noasm.go +++ b/vendor/golang.org/x/crypto/poly1305/mac_noasm.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// +build !amd64,!ppc64le,!s390x gccgo purego +// +build !amd64,!ppc64le,!s390x !gc purego package poly1305 diff --git a/vendor/golang.org/x/crypto/poly1305/sum_amd64.go b/vendor/golang.org/x/crypto/poly1305/sum_amd64.go index 99e5a1d50e..cf3a69ed3b 100644 --- a/vendor/golang.org/x/crypto/poly1305/sum_amd64.go +++ b/vendor/golang.org/x/crypto/poly1305/sum_amd64.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// +build !gccgo,!purego +// +build gc,!purego package poly1305 diff --git a/vendor/golang.org/x/crypto/poly1305/sum_amd64.s b/vendor/golang.org/x/crypto/poly1305/sum_amd64.s index 8d394a212e..2cb0373140 100644 --- a/vendor/golang.org/x/crypto/poly1305/sum_amd64.s +++ b/vendor/golang.org/x/crypto/poly1305/sum_amd64.s @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// +build !gccgo,!purego +// +build gc,!purego #include "textflag.h" diff --git a/vendor/golang.org/x/crypto/poly1305/sum_ppc64le.go b/vendor/golang.org/x/crypto/poly1305/sum_ppc64le.go index 2e7a120b19..cb4b7185dc 100644 --- a/vendor/golang.org/x/crypto/poly1305/sum_ppc64le.go +++ b/vendor/golang.org/x/crypto/poly1305/sum_ppc64le.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// +build !gccgo,!purego +// +build gc,!purego package poly1305 diff --git a/vendor/golang.org/x/crypto/poly1305/sum_ppc64le.s b/vendor/golang.org/x/crypto/poly1305/sum_ppc64le.s index 4e02813879..5cd7494b21 100644 --- a/vendor/golang.org/x/crypto/poly1305/sum_ppc64le.s +++ b/vendor/golang.org/x/crypto/poly1305/sum_ppc64le.s @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// +build !gccgo,!purego +// +build gc,!purego #include "textflag.h" diff --git a/vendor/golang.org/x/crypto/poly1305/sum_s390x.go b/vendor/golang.org/x/crypto/poly1305/sum_s390x.go index 958fedc079..188a665e12 100644 --- a/vendor/golang.org/x/crypto/poly1305/sum_s390x.go +++ b/vendor/golang.org/x/crypto/poly1305/sum_s390x.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// +build !gccgo,!purego +// +build gc,!purego package poly1305 diff --git a/vendor/golang.org/x/crypto/poly1305/sum_s390x.s b/vendor/golang.org/x/crypto/poly1305/sum_s390x.s index 0fa9ee6e0b..bdd882c606 100644 --- a/vendor/golang.org/x/crypto/poly1305/sum_s390x.s +++ b/vendor/golang.org/x/crypto/poly1305/sum_s390x.s @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// +build !gccgo,!purego +// +build gc,!purego #include "textflag.h" diff --git a/vendor/golang.org/x/crypto/ssh/client_auth.go b/vendor/golang.org/x/crypto/ssh/client_auth.go index f3265655ee..c611aeb684 100644 --- a/vendor/golang.org/x/crypto/ssh/client_auth.go +++ b/vendor/golang.org/x/crypto/ssh/client_auth.go @@ -471,7 +471,7 @@ func (cb KeyboardInteractiveChallenge) auth(session []byte, user string, c packe } if len(answers) != len(prompts) { - return authFailure, nil, errors.New("ssh: not enough answers from keyboard-interactive callback") + return authFailure, nil, fmt.Errorf("ssh: incorrect number of answers from keyboard-interactive callback %d (expected %d)", len(answers), len(prompts)) } responseLength := 1 + 4 for _, a := range answers { diff --git a/vendor/golang.org/x/crypto/ssh/kex.go b/vendor/golang.org/x/crypto/ssh/kex.go index 7eedb209fa..766e929397 100644 --- a/vendor/golang.org/x/crypto/ssh/kex.go +++ b/vendor/golang.org/x/crypto/ssh/kex.go @@ -557,8 +557,6 @@ type dhGEXSHA struct { hashFunc crypto.Hash } -const numMRTests = 64 - const ( dhGroupExchangeMinimumBits = 2048 dhGroupExchangePreferredBits = 2048 @@ -602,15 +600,8 @@ func (gex dhGEXSHA) Client(c packetConn, randSource io.Reader, magics *handshake gex.p = kexDHGexGroup.P gex.g = kexDHGexGroup.G - // Check if p is safe by verifing that p and (p-1)/2 are primes - one := big.NewInt(1) - var pHalf = &big.Int{} - pHalf.Rsh(gex.p, 1) - if !gex.p.ProbablyPrime(numMRTests) || !pHalf.ProbablyPrime(numMRTests) { - return nil, fmt.Errorf("ssh: server provided gex p is not safe") - } - // Check if g is safe by verifing that g > 1 and g < p - 1 + one := big.NewInt(1) var pMinusOne = &big.Int{} pMinusOne.Sub(gex.p, one) if gex.g.Cmp(one) != 1 && gex.g.Cmp(pMinusOne) != -1 { @@ -618,6 +609,8 @@ func (gex dhGEXSHA) Client(c packetConn, randSource io.Reader, magics *handshake } // Send GexInit + var pHalf = &big.Int{} + pHalf.Rsh(gex.p, 1) x, err := rand.Int(randSource, pHalf) if err != nil { return nil, err diff --git a/vendor/golang.org/x/crypto/ssh/server.go b/vendor/golang.org/x/crypto/ssh/server.go index 7d42a8c88d..b6911e8306 100644 --- a/vendor/golang.org/x/crypto/ssh/server.go +++ b/vendor/golang.org/x/crypto/ssh/server.go @@ -572,6 +572,10 @@ userAuthLoop: perms = candidate.perms } case "gssapi-with-mic": + if config.GSSAPIWithMICConfig == nil { + authErr = errors.New("ssh: gssapi-with-mic auth not configured") + break + } gssapiConfig := config.GSSAPIWithMICConfig userAuthRequestGSSAPI, err := parseGSSAPIPayload(userAuthReq.Payload) if err != nil { diff --git a/vendor/modules.txt b/vendor/modules.txt index 44315b1744..1bbba9cfe0 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -778,7 +778,7 @@ go.mongodb.org/mongo-driver/bson/bsonrw go.mongodb.org/mongo-driver/bson/bsontype go.mongodb.org/mongo-driver/bson/primitive go.mongodb.org/mongo-driver/x/bsonx/bsoncore -# golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a +# golang.org/x/crypto v0.0.0-20201217014255-9d1352758620 ## explicit golang.org/x/crypto/acme golang.org/x/crypto/acme/autocert From 661e3e2bdcb6eff243c86daceed79cd4a552dd08 Mon Sep 17 00:00:00 2001 From: 6543 <6543@obermui.de> Date: Mon, 21 Dec 2020 22:56:18 +0000 Subject: [PATCH 102/205] Fix storage config implementation (#14091) (#14095) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The design is very flexible, but not implemented correctly. This commit fixes several issues: * Costom storage type stated in https://docs.gitea.io/en-us/config-cheat-sheet/#storage-storage not working * [storage.attachments], [storage.minio] section not respected Signed-off-by: 胡玮文 Co-authored-by: 胡玮文 --- modules/setting/storage.go | 34 +++---- modules/setting/storage_test.go | 164 ++++++++++++++++++++++++++++++++ 2 files changed, 177 insertions(+), 21 deletions(-) create mode 100644 modules/setting/storage_test.go diff --git a/modules/setting/storage.go b/modules/setting/storage.go index 27788da1ff..43890371fa 100644 --- a/modules/setting/storage.go +++ b/modules/setting/storage.go @@ -31,22 +31,10 @@ func (s *Storage) MapTo(v interface{}) error { return nil } -func getStorage(name, typ string, overrides ...*ini.Section) Storage { +func getStorage(name, typ string, targetSec *ini.Section) Storage { const sectionName = "storage" sec := Cfg.Section(sectionName) - if len(overrides) == 0 { - overrides = []*ini.Section{ - Cfg.Section(sectionName + "." + typ), - Cfg.Section(sectionName + "." + name), - } - } - - var storage Storage - - storage.Type = sec.Key("STORAGE_TYPE").MustString(typ) - storage.ServeDirect = sec.Key("SERVE_DIRECT").MustBool(false) - // Global Defaults sec.Key("MINIO_ENDPOINT").MustString("localhost:9000") sec.Key("MINIO_ACCESS_KEY_ID").MustString("") @@ -55,18 +43,22 @@ func getStorage(name, typ string, overrides ...*ini.Section) Storage { sec.Key("MINIO_LOCATION").MustString("us-east-1") sec.Key("MINIO_USE_SSL").MustBool(false) - storage.Section = sec - - for _, override := range overrides { - for _, key := range storage.Section.Keys() { - if !override.HasKey(key.Name()) { - _, _ = override.NewKey(key.Name(), key.Value()) + nameSec := Cfg.Section(sectionName + "." + name) + typeSec := Cfg.Section(sectionName + "." + typ) + for _, override := range []*ini.Section{nameSec, typeSec, sec} { + for _, key := range override.Keys() { + if !targetSec.HasKey(key.Name()) { + _, _ = targetSec.NewKey(key.Name(), key.Value()) } } - storage.ServeDirect = override.Key("SERVE_DIRECT").MustBool(false) - storage.Section = override } + var storage Storage + storage.Section = targetSec + + storage.Type = typeSec.Key("STORAGE_TYPE").MustString(typ) + storage.ServeDirect = storage.Section.Key("SERVE_DIRECT").MustBool(false) + // Specific defaults storage.Path = storage.Section.Key("PATH").MustString(filepath.Join(AppDataPath, name)) if !filepath.IsAbs(storage.Path) { diff --git a/modules/setting/storage_test.go b/modules/setting/storage_test.go new file mode 100644 index 0000000000..00c255a9c9 --- /dev/null +++ b/modules/setting/storage_test.go @@ -0,0 +1,164 @@ +// Copyright 2020 The Gitea Authors. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +package setting + +import ( + "testing" + + "github.com/stretchr/testify/assert" + ini "gopkg.in/ini.v1" +) + +func Test_getStorageCustomType(t *testing.T) { + iniStr := ` +[attachment] +STORAGE_TYPE = my_minio +MINIO_BUCKET = gitea-attachment + +[storage.my_minio] +STORAGE_TYPE = minio +MINIO_ENDPOINT = my_minio:9000 +` + Cfg, _ = ini.Load([]byte(iniStr)) + + sec := Cfg.Section("attachment") + storageType := sec.Key("STORAGE_TYPE").MustString("") + storage := getStorage("attachments", storageType, sec) + + assert.EqualValues(t, "minio", storage.Type) + assert.EqualValues(t, "my_minio:9000", storage.Section.Key("MINIO_ENDPOINT").String()) + assert.EqualValues(t, "gitea-attachment", storage.Section.Key("MINIO_BUCKET").String()) +} + +func Test_getStorageNameSectionOverridesTypeSection(t *testing.T) { + iniStr := ` +[attachment] +STORAGE_TYPE = minio + +[storage.attachments] +MINIO_BUCKET = gitea-attachment + +[storage.minio] +MINIO_BUCKET = gitea +` + Cfg, _ = ini.Load([]byte(iniStr)) + + sec := Cfg.Section("attachment") + storageType := sec.Key("STORAGE_TYPE").MustString("") + storage := getStorage("attachments", storageType, sec) + + assert.EqualValues(t, "minio", storage.Type) + assert.EqualValues(t, "gitea-attachment", storage.Section.Key("MINIO_BUCKET").String()) +} + +func Test_getStorageTypeSectionOverridesStorageSection(t *testing.T) { + iniStr := ` +[attachment] +STORAGE_TYPE = minio + +[storage.minio] +MINIO_BUCKET = gitea-minio + +[storage] +MINIO_BUCKET = gitea +` + Cfg, _ = ini.Load([]byte(iniStr)) + + sec := Cfg.Section("attachment") + storageType := sec.Key("STORAGE_TYPE").MustString("") + storage := getStorage("attachments", storageType, sec) + + assert.EqualValues(t, "minio", storage.Type) + assert.EqualValues(t, "gitea-minio", storage.Section.Key("MINIO_BUCKET").String()) +} + +func Test_getStorageSpecificOverridesStorage(t *testing.T) { + iniStr := ` +[attachment] +MINIO_BUCKET = gitea-attachment + +[storage.attachments] +MINIO_BUCKET = gitea +` + Cfg, _ = ini.Load([]byte(iniStr)) + + sec := Cfg.Section("attachment") + storageType := sec.Key("STORAGE_TYPE").MustString("") + storage := getStorage("attachments", storageType, sec) + + assert.EqualValues(t, "gitea-attachment", storage.Section.Key("MINIO_BUCKET").String()) +} + +func Test_getStorageGetDefaults(t *testing.T) { + Cfg, _ = ini.Load([]byte("")) + + sec := Cfg.Section("attachment") + storageType := sec.Key("STORAGE_TYPE").MustString("") + storage := getStorage("attachments", storageType, sec) + + assert.EqualValues(t, "gitea", storage.Section.Key("MINIO_BUCKET").String()) +} + +func Test_getStorageMultipleName(t *testing.T) { + iniStr := ` +[lfs] +MINIO_BUCKET = gitea-lfs + +[attachment] +MINIO_BUCKET = gitea-attachment + +[storage] +MINIO_BUCKET = gitea-storage +` + Cfg, _ = ini.Load([]byte(iniStr)) + + { + sec := Cfg.Section("attachment") + storageType := sec.Key("STORAGE_TYPE").MustString("") + storage := getStorage("attachments", storageType, sec) + + assert.EqualValues(t, "gitea-attachment", storage.Section.Key("MINIO_BUCKET").String()) + } + { + sec := Cfg.Section("lfs") + storageType := sec.Key("STORAGE_TYPE").MustString("") + storage := getStorage("lfs", storageType, sec) + + assert.EqualValues(t, "gitea-lfs", storage.Section.Key("MINIO_BUCKET").String()) + } + { + sec := Cfg.Section("avatar") + storageType := sec.Key("STORAGE_TYPE").MustString("") + storage := getStorage("avatars", storageType, sec) + + assert.EqualValues(t, "gitea-storage", storage.Section.Key("MINIO_BUCKET").String()) + } +} + +func Test_getStorageUseOtherNameAsType(t *testing.T) { + iniStr := ` +[attachment] +STORAGE_TYPE = lfs + +[storage.lfs] +MINIO_BUCKET = gitea-storage +` + Cfg, _ = ini.Load([]byte(iniStr)) + + { + sec := Cfg.Section("attachment") + storageType := sec.Key("STORAGE_TYPE").MustString("") + storage := getStorage("attachments", storageType, sec) + + assert.EqualValues(t, "gitea-storage", storage.Section.Key("MINIO_BUCKET").String()) + } + { + sec := Cfg.Section("lfs") + storageType := sec.Key("STORAGE_TYPE").MustString("") + storage := getStorage("lfs", storageType, sec) + + assert.EqualValues(t, "gitea-storage", storage.Section.Key("MINIO_BUCKET").String()) + } +} From fae18bdac0a6a291ea6d06b77fe568bda6e87cf7 Mon Sep 17 00:00:00 2001 From: 6543 <6543@obermui.de> Date: Tue, 22 Dec 2020 07:13:57 +0000 Subject: [PATCH 103/205] more test case for STORAGE_TYPE overrides (and fixes) (#14096) (#14104) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: 胡玮文 Co-authored-by: 胡玮文 --- modules/setting/storage.go | 32 ++++++++++++++++++++++++-------- modules/setting/storage_test.go | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 57 insertions(+), 8 deletions(-) diff --git a/modules/setting/storage.go b/modules/setting/storage.go index 43890371fa..3ab08d8d2a 100644 --- a/modules/setting/storage.go +++ b/modules/setting/storage.go @@ -43,20 +43,36 @@ func getStorage(name, typ string, targetSec *ini.Section) Storage { sec.Key("MINIO_LOCATION").MustString("us-east-1") sec.Key("MINIO_USE_SSL").MustBool(false) - nameSec := Cfg.Section(sectionName + "." + name) - typeSec := Cfg.Section(sectionName + "." + typ) - for _, override := range []*ini.Section{nameSec, typeSec, sec} { + var storage Storage + storage.Section = targetSec + storage.Type = typ + + overrides := make([]*ini.Section, 0, 3) + nameSec, err := Cfg.GetSection(sectionName + "." + name) + if err == nil { + overrides = append(overrides, nameSec) + } + + typeSec, err := Cfg.GetSection(sectionName + "." + typ) + if err == nil { + overrides = append(overrides, typeSec) + nextType := typeSec.Key("STORAGE_TYPE").String() + if len(nextType) > 0 { + storage.Type = nextType // Support custom STORAGE_TYPE + } + } + overrides = append(overrides, sec) + + for _, override := range overrides { for _, key := range override.Keys() { if !targetSec.HasKey(key.Name()) { _, _ = targetSec.NewKey(key.Name(), key.Value()) } } + if len(storage.Type) == 0 { + storage.Type = override.Key("STORAGE_TYPE").String() + } } - - var storage Storage - storage.Section = targetSec - - storage.Type = typeSec.Key("STORAGE_TYPE").MustString(typ) storage.ServeDirect = storage.Section.Key("SERVE_DIRECT").MustBool(false) // Specific defaults diff --git a/modules/setting/storage_test.go b/modules/setting/storage_test.go index 00c255a9c9..ffd8b7aa01 100644 --- a/modules/setting/storage_test.go +++ b/modules/setting/storage_test.go @@ -77,10 +77,14 @@ MINIO_BUCKET = gitea func Test_getStorageSpecificOverridesStorage(t *testing.T) { iniStr := ` [attachment] +STORAGE_TYPE = minio MINIO_BUCKET = gitea-attachment [storage.attachments] MINIO_BUCKET = gitea + +[storage] +STORAGE_TYPE = local ` Cfg, _ = ini.Load([]byte(iniStr)) @@ -88,6 +92,7 @@ MINIO_BUCKET = gitea storageType := sec.Key("STORAGE_TYPE").MustString("") storage := getStorage("attachments", storageType, sec) + assert.EqualValues(t, "minio", storage.Type) assert.EqualValues(t, "gitea-attachment", storage.Section.Key("MINIO_BUCKET").String()) } @@ -162,3 +167,31 @@ MINIO_BUCKET = gitea-storage assert.EqualValues(t, "gitea-storage", storage.Section.Key("MINIO_BUCKET").String()) } } + +func Test_getStorageInheritStorageType(t *testing.T) { + iniStr := ` +[storage] +STORAGE_TYPE = minio +` + Cfg, _ = ini.Load([]byte(iniStr)) + + sec := Cfg.Section("attachment") + storageType := sec.Key("STORAGE_TYPE").MustString("") + storage := getStorage("attachments", storageType, sec) + + assert.EqualValues(t, "minio", storage.Type) +} + +func Test_getStorageInheritNameSectionType(t *testing.T) { + iniStr := ` +[storage.attachments] +STORAGE_TYPE = minio +` + Cfg, _ = ini.Load([]byte(iniStr)) + + sec := Cfg.Section("attachment") + storageType := sec.Key("STORAGE_TYPE").MustString("") + storage := getStorage("attachments", storageType, sec) + + assert.EqualValues(t, "minio", storage.Type) +} From bf1441b1e126b315bb14f2c56a2515d43f909384 Mon Sep 17 00:00:00 2001 From: zeripath Date: Thu, 24 Dec 2020 21:54:15 +0000 Subject: [PATCH 104/205] Ensure that search term and page are not lost on adoption page-turn (#14133) (#14143) Backport #14133 Fix #14111 Signed-off-by: Andrew Thornton --- routers/admin/repos.go | 11 ++++++++++- templates/admin/repo/unadopted.tmpl | 4 ++++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/routers/admin/repos.go b/routers/admin/repos.go index 10abaf9547..f100ca0642 100644 --- a/routers/admin/repos.go +++ b/routers/admin/repos.go @@ -5,6 +5,8 @@ package admin import ( + "net/url" + "strconv" "strings" "code.gitea.io/gitea/models" @@ -71,6 +73,8 @@ func UnadoptedRepos(ctx *context.Context) { opts.Page = 1 } + ctx.Data["CurrentPage"] = opts.Page + doSearch := ctx.QueryBool("search") ctx.Data["search"] = doSearch @@ -79,6 +83,7 @@ func UnadoptedRepos(ctx *context.Context) { if !doSearch { pager := context.NewPagination(0, opts.PageSize, opts.Page, 5) pager.SetDefaultParams(ctx) + pager.AddParam(ctx, "search", "search") ctx.Data["Page"] = pager ctx.HTML(200, tplUnadoptedRepos) return @@ -92,6 +97,7 @@ func UnadoptedRepos(ctx *context.Context) { ctx.Data["Dirs"] = repoNames pager := context.NewPagination(int(count), opts.PageSize, opts.Page, 5) pager.SetDefaultParams(ctx) + pager.AddParam(ctx, "search", "search") ctx.Data["Page"] = pager ctx.HTML(200, tplUnadoptedRepos) } @@ -100,6 +106,9 @@ func UnadoptedRepos(ctx *context.Context) { func AdoptOrDeleteRepository(ctx *context.Context) { dir := ctx.Query("id") action := ctx.Query("action") + page := ctx.QueryInt("page") + q := ctx.Query("q") + dirSplit := strings.SplitN(dir, "/", 2) if len(dirSplit) != 2 { ctx.Redirect(setting.AppSubURL + "/admin/repos") @@ -141,5 +150,5 @@ func AdoptOrDeleteRepository(ctx *context.Context) { } ctx.Flash.Success(ctx.Tr("repo.delete_preexisting_success", dir)) } - ctx.Redirect(setting.AppSubURL + "/admin/repos/unadopted") + ctx.Redirect(setting.AppSubURL + "/admin/repos/unadopted?search=true&q=" + url.QueryEscape(q) + "&page=" + strconv.Itoa(page)) } diff --git a/templates/admin/repo/unadopted.tmpl b/templates/admin/repo/unadopted.tmpl index 7a046c6026..38dddf38dc 100644 --- a/templates/admin/repo/unadopted.tmpl +++ b/templates/admin/repo/unadopted.tmpl @@ -41,6 +41,8 @@ {{$.CsrfTokenHtml}} + +
@@ -66,6 +68,8 @@ {{$.CsrfTokenHtml}} + +
From 205be63bc17242973187f042d94d815107b4bab8 Mon Sep 17 00:00:00 2001 From: Daniil Pankratov Date: Fri, 25 Dec 2020 15:02:52 +0300 Subject: [PATCH 105/205] Fix creation OAuth2 auth source from CLI. (#14146) Fix #8356 --- models/oauth2.go | 12 +++++++++++- modules/auth/oauth2/oauth2.go | 5 +++++ routers/user/auth.go | 13 +++++++++++-- 3 files changed, 27 insertions(+), 3 deletions(-) diff --git a/models/oauth2.go b/models/oauth2.go index ccf24eb35d..21a6f995c7 100644 --- a/models/oauth2.go +++ b/models/oauth2.go @@ -119,8 +119,18 @@ func InitOAuth2() error { if err := oauth2.Init(x); err != nil { return err } - loginSources, _ := GetActiveOAuth2ProviderLoginSources() + return initOAuth2LoginSources() +} +// ResetOAuth2 clears existing OAuth2 providers and loads them from DB +func ResetOAuth2() error { + oauth2.ClearProviders() + return initOAuth2LoginSources() +} + +// initOAuth2LoginSources is used to load and register all active OAuth2 providers +func initOAuth2LoginSources() error { + loginSources, _ := GetActiveOAuth2ProviderLoginSources() for _, source := range loginSources { oAuth2Config := source.OAuth2() err := oauth2.RegisterProvider(source.Name, oAuth2Config.Provider, oAuth2Config.ClientID, oAuth2Config.ClientSecret, oAuth2Config.OpenIDConnectAutoDiscoveryURL, oAuth2Config.CustomURLMapping) diff --git a/modules/auth/oauth2/oauth2.go b/modules/auth/oauth2/oauth2.go index 2c982e1dca..932246d06d 100644 --- a/modules/auth/oauth2/oauth2.go +++ b/modules/auth/oauth2/oauth2.go @@ -118,6 +118,11 @@ func RemoveProvider(providerName string) { delete(goth.GetProviders(), providerName) } +// ClearProviders clears all OAuth2 providers from the goth lib +func ClearProviders() { + goth.ClearProviders() +} + // used to create different types of goth providers func createProvider(providerName, providerType, clientID, clientSecret, openIDConnectAutoDiscoveryURL string, customURLMapping *CustomURLMapping) (goth.Provider, error) { callbackURL := setting.AppURL + "user/oauth2/" + url.PathEscape(providerName) + "/callback" diff --git a/routers/user/auth.go b/routers/user/auth.go index 893cad09be..c5542456a1 100644 --- a/routers/user/auth.go +++ b/routers/user/auth.go @@ -570,8 +570,17 @@ func SignInOAuth(ctx *context.Context) { return } - err = oauth2.Auth(loginSource.Name, ctx.Req.Request, ctx.Resp) - if err != nil { + if err = oauth2.Auth(loginSource.Name, ctx.Req.Request, ctx.Resp); err != nil { + if strings.Contains(err.Error(), "no provider for ") { + if err = models.ResetOAuth2(); err != nil { + ctx.ServerError("SignIn", err) + return + } + if err = oauth2.Auth(loginSource.Name, ctx.Req.Request, ctx.Resp); err != nil { + ctx.ServerError("SignIn", err) + } + return + } ctx.ServerError("SignIn", err) } // redirect is done in oauth2.Auth From 206b66a18467690b973bb159c3054dab3e96598a Mon Sep 17 00:00:00 2001 From: zeripath Date: Sat, 26 Dec 2020 22:15:42 +0000 Subject: [PATCH 106/205] Fix escaping issue in diff (#14154) Ensure that linecontent is escaped before passing to template.HTML Signed-off-by: Andrew Thornton --- services/gitdiff/gitdiff.go | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/services/gitdiff/gitdiff.go b/services/gitdiff/gitdiff.go index 79cd16e193..81b92f7168 100644 --- a/services/gitdiff/gitdiff.go +++ b/services/gitdiff/gitdiff.go @@ -10,6 +10,7 @@ import ( "bytes" "context" "fmt" + "html" "html/template" "io" "io/ioutil" @@ -164,9 +165,9 @@ func getDiffLineSectionInfo(treePath, line string, lastLeftIdx, lastRightIdx int // escape a line's content or return
needed for copy/paste purposes func getLineContent(content string) string { if len(content) > 0 { - return content + return html.EscapeString(content) } - return "\n" + return "
" } // DiffSection represents a section of a DiffFile. @@ -357,8 +358,6 @@ func (diffSection *DiffSection) GetComputedInlineDiffFor(diffLine *DiffLine) tem diffRecord := diffMatchPatch.DiffMain(highlight.Code(diffSection.FileName, diff1[1:]), highlight.Code(diffSection.FileName, diff2[1:]), true) diffRecord = diffMatchPatch.DiffCleanupEfficiency(diffRecord) - diffRecord = diffMatchPatch.DiffCleanupEfficiency(diffRecord) - return diffToHTML(diffSection.FileName, diffRecord, diffLine.Type) } From 4a738a8f1601d6c13dc6699d3c6985ed57eee802 Mon Sep 17 00:00:00 2001 From: 6543 <6543@obermui.de> Date: Sun, 27 Dec 2020 02:57:06 +0000 Subject: [PATCH 107/205] Migration: drop too long repo topics (#14152) (#14155) * Migration: drop to long repo topics * Update modules/migrations/gitea_uploader.go --- modules/migrations/gitea_uploader.go | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/modules/migrations/gitea_uploader.go b/modules/migrations/gitea_uploader.go index 2cb19685fc..334ddad54f 100644 --- a/modules/migrations/gitea_uploader.go +++ b/modules/migrations/gitea_uploader.go @@ -154,6 +154,15 @@ func (g *GiteaLocalUploader) Close() { // CreateTopics creates topics func (g *GiteaLocalUploader) CreateTopics(topics ...string) error { + // ignore topics to long for the db + c := 0 + for i := range topics { + if len(topics[i]) <= 25 { + topics[c] = topics[i] + c++ + } + } + topics = topics[:c] return models.SaveTopics(g.repo.ID, topics...) } From 182be906552cf990a222584de51c0b72e46ce85a Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Tue, 29 Dec 2020 01:08:55 +0800 Subject: [PATCH 108/205] Fix bug of link query order on markdown render (#14156) (#14171) * Fix bug of link query order on markdown render * Fix bluemonday bug and fix one wrong test Co-authored-by: 6543 <6543@obermui.de> Co-authored-by: 6543 <6543@obermui.de> --- go.mod | 2 + go.sum | 5 +- modules/markup/html_test.go | 2 +- .../microcosm-cc/bluemonday/sanitize.go | 97 +++++++++++++++---- vendor/modules.txt | 3 +- 5 files changed, 84 insertions(+), 25 deletions(-) diff --git a/go.mod b/go.mod index 58ae699672..87f82c0e62 100644 --- a/go.mod +++ b/go.mod @@ -124,3 +124,5 @@ require ( ) replace github.com/hashicorp/go-version => github.com/6543/go-version v1.2.4 + +replace github.com/microcosm-cc/bluemonday => github.com/lunny/bluemonday v1.0.5-0.20201227154428-ca34796141e8 diff --git a/go.sum b/go.sum index 975e6585f7..04a652f2a8 100644 --- a/go.sum +++ b/go.sum @@ -598,6 +598,8 @@ github.com/lib/pq v1.3.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.7.0/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= github.com/lib/pq v1.8.1-0.20200908161135-083382b7e6fc h1:ERSU1OvZ6MdWhHieo2oT7xwR/HCksqKdgK6iYPU5pHI= github.com/lib/pq v1.8.1-0.20200908161135-083382b7e6fc/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= +github.com/lunny/bluemonday v1.0.5-0.20201227154428-ca34796141e8 h1:1omo92DLtxQu6VwVPSZAmduHaK5zssed6cvkHyl1XOg= +github.com/lunny/bluemonday v1.0.5-0.20201227154428-ca34796141e8/go.mod h1:8iwZnFn2CDDNZ0r6UXhF4xawGvzaqzCRa1n3/lO3W2w= github.com/lunny/dingtalk_webhook v0.0.0-20171025031554-e3534c89ef96 h1:uNwtsDp7ci48vBTTxDuwcoTXz4lwtDTe7TjCQ0noaWY= github.com/lunny/dingtalk_webhook v0.0.0-20171025031554-e3534c89ef96/go.mod h1:mmIfjCSQlGYXmJ95jFN84AkQFnVABtKuJL8IrzwvUKQ= github.com/lunny/log v0.0.0-20160921050905-7887c61bf0de h1:nyxwRdWHAVxpFcDThedEgQ07DbcRc5xgNObtbTp76fk= @@ -649,8 +651,6 @@ github.com/mgechev/revive v1.0.3-0.20200921231451-246eac737dc7 h1:ydVkpU/M4/c45y github.com/mgechev/revive v1.0.3-0.20200921231451-246eac737dc7/go.mod h1:no/hfevHbndpXR5CaJahkYCfM/FFpmM/dSOwFGU7Z1o= github.com/mholt/archiver/v3 v3.3.0 h1:vWjhY8SQp5yzM9P6OJ/eZEkmi3UAbRrxCq48MxjAzig= github.com/mholt/archiver/v3 v3.3.0/go.mod h1:YnQtqsp+94Rwd0D/rk5cnLrxusUBUXg+08Ebtr1Mqao= -github.com/microcosm-cc/bluemonday v1.0.3-0.20191119130333-0a75d7616912 h1:hJde9rA24hlTcAYSwJoXpDUyGtfKQ/jsofw+WaDqGrI= -github.com/microcosm-cc/bluemonday v1.0.3-0.20191119130333-0a75d7616912/go.mod h1:8iwZnFn2CDDNZ0r6UXhF4xawGvzaqzCRa1n3/lO3W2w= github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= github.com/minio/md5-simd v1.1.0 h1:QPfiOqlZH+Cj9teu0t9b1nTBfPbyTl16Of5MeuShdK4= github.com/minio/md5-simd v1.1.0/go.mod h1:XpBqgZULrMYD3R+M28PcmP0CkI7PEMzB3U77ZrKZ0Gw= @@ -937,7 +937,6 @@ golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073/go.mod h1:LzIPMQfyMNhhGPh golang.org/x/crypto v0.0.0-20200323165209-0ec3e9974c59/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200709230013-948cd5f35899/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a h1:vclmkQCjlDX5OydZ9wv8rBCcS0QyQY66Mpf/7BZbInM= golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20201217014255-9d1352758620 h1:3wPMTskHO3+O6jqTEXyFcsnuxMQOqYSaHsDxcbUXpqA= golang.org/x/crypto v0.0.0-20201217014255-9d1352758620/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= diff --git a/modules/markup/html_test.go b/modules/markup/html_test.go index a018d74840..a3c273e628 100644 --- a/modules/markup/html_test.go +++ b/modules/markup/html_test.go @@ -142,7 +142,7 @@ func TestRender_links(t *testing.T) { `

ftp://gitea.com/file.txt

`) test( "magnet:?xt=urn:btih:5dee65101db281ac9c46344cd6b175cdcadabcde&dn=download", - `

magnet:?xt=urn:btih:5dee65101db281ac9c46344cd6b175cdcadabcde&dn=download

`) + `

magnet:?xt=urn:btih:5dee65101db281ac9c46344cd6b175cdcadabcde&dn=download

`) // Test that should *not* be turned into URL test( diff --git a/vendor/github.com/microcosm-cc/bluemonday/sanitize.go b/vendor/github.com/microcosm-cc/bluemonday/sanitize.go index 771fc2c2fa..a58333aa65 100644 --- a/vendor/github.com/microcosm-cc/bluemonday/sanitize.go +++ b/vendor/github.com/microcosm-cc/bluemonday/sanitize.go @@ -122,22 +122,79 @@ func escapeUrlComponent(val string) string { return w.String() } -func sanitizedUrl(val string) (string, error) { +// Query represents a query +type Query struct { + Key string + Value string +} + +func parseQuery(query string) (values []Query, err error) { + for query != "" { + key := query + if i := strings.IndexAny(key, "&;"); i >= 0 { + key, query = key[:i], key[i+1:] + } else { + query = "" + } + if key == "" { + continue + } + value := "" + if i := strings.Index(key, "="); i >= 0 { + key, value = key[:i], key[i+1:] + } + key, err1 := url.QueryUnescape(key) + if err1 != nil { + if err == nil { + err = err1 + } + continue + } + value, err1 = url.QueryUnescape(value) + if err1 != nil { + if err == nil { + err = err1 + } + continue + } + values = append(values, Query{ + Key: key, + Value: value, + }) + } + return values, err +} + +func encodeQueries(queries []Query) string { + var b strings.Builder + for i, query := range queries { + b.WriteString(url.QueryEscape(query.Key)) + b.WriteString("=") + b.WriteString(url.QueryEscape(query.Value)) + if i < len(queries)-1 { + b.WriteString("&") + } + } + return b.String() +} + +func sanitizedURL(val string) (string, error) { u, err := url.Parse(val) if err != nil { return "", err } - // sanitize the url query params - sanitizedQueryValues := make(url.Values, 0) - queryValues := u.Query() - for k, vals := range queryValues { - sk := html.EscapeString(k) - for _, v := range vals { - sv := escapeUrlComponent(v) - sanitizedQueryValues.Set(sk, sv) - } + + // we use parseQuery but not u.Query to keep the order not change because + // url.Values is a map which has a random order. + queryValues, err := parseQuery(u.RawQuery) + if err != nil { + return "", err } - u.RawQuery = sanitizedQueryValues.Encode() + // sanitize the url query params + for i, query := range queryValues { + queryValues[i].Key = html.EscapeString(query.Key) + } + u.RawQuery = encodeQueries(queryValues) // u.String() will also sanitize host/scheme/user/pass return u.String(), nil } @@ -158,7 +215,7 @@ func (p *Policy) writeLinkableBuf(buff *bytes.Buffer, token *html.Token) { tokenBuff.WriteString(html.EscapeString(attr.Val)) continue } - u, err := sanitizedUrl(u) + u, err := sanitizedURL(u) if err == nil { tokenBuff.WriteString(u) } else { @@ -390,10 +447,10 @@ func (p *Policy) sanitizeAttrs( hasStylePolicies = true } // no specific element policy found, look for a pattern match - if !hasStylePolicies{ - for k, v := range p.elsMatchingAndStyles{ + if !hasStylePolicies { + for k, v := range p.elsMatchingAndStyles { if k.MatchString(elementName) { - if len(v) > 0{ + if len(v) > 0 { hasStylePolicies = true break } @@ -669,14 +726,14 @@ func (p *Policy) sanitizeAttrs( func (p *Policy) sanitizeStyles(attr html.Attribute, elementName string) html.Attribute { sps := p.elsAndStyles[elementName] - if len(sps) == 0{ + if len(sps) == 0 { sps = map[string]stylePolicy{} // check for any matching elements, if we don't already have a policy found // if multiple matches are found they will be overwritten, it's best // to not have overlapping matchers - for regex, policies :=range p.elsMatchingAndStyles{ - if regex.MatchString(elementName){ - for k, v := range policies{ + for regex, policies := range p.elsMatchingAndStyles { + if regex.MatchString(elementName) { + for k, v := range policies { sps[k] = v } } @@ -874,7 +931,7 @@ func removeUnicode(value string) string { return substitutedValue } -func (p *Policy) matchRegex(elementName string ) (map[string]attrPolicy, bool) { +func (p *Policy) matchRegex(elementName string) (map[string]attrPolicy, bool) { aps := make(map[string]attrPolicy, 0) matched := false for regex, attrs := range p.elsMatchingAndAttrs { diff --git a/vendor/modules.txt b/vendor/modules.txt index 1bbba9cfe0..be206facda 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -566,7 +566,7 @@ github.com/mgechev/revive/rule # github.com/mholt/archiver/v3 v3.3.0 ## explicit github.com/mholt/archiver/v3 -# github.com/microcosm-cc/bluemonday v1.0.3-0.20191119130333-0a75d7616912 +# github.com/microcosm-cc/bluemonday v1.0.3-0.20191119130333-0a75d7616912 => github.com/lunny/bluemonday v1.0.5-0.20201227154428-ca34796141e8 ## explicit github.com/microcosm-cc/bluemonday # github.com/minio/md5-simd v1.1.0 @@ -979,3 +979,4 @@ xorm.io/xorm/names xorm.io/xorm/schemas xorm.io/xorm/tags # github.com/hashicorp/go-version => github.com/6543/go-version v1.2.4 +# github.com/microcosm-cc/bluemonday => github.com/lunny/bluemonday v1.0.5-0.20201227154428-ca34796141e8 From afa7f22dd831e0502a864f167d21d01f8fe5ae70 Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Tue, 29 Dec 2020 01:36:22 +0800 Subject: [PATCH 109/205] Add changelog for v1.13.1 (#14172) * Add changelog for v1.13.1 * Update CHANGELOG.md Co-authored-by: John Olheiser * Update CHANGELOG.md * Update CHANGELOG.md Co-authored-by: John Olheiser * Update CHANGELOG.md Co-authored-by: John Olheiser * Update CHANGELOG.md Co-authored-by: John Olheiser Co-authored-by: zeripath Co-authored-by: techknowlogick --- CHANGELOG.md | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index e72d758762..020212043f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,42 @@ This changelog goes through all the changes that have been made in each release without substantial changes to our git log; to see the highlights of what has been added to each release, please refer to the [blog](https://blog.gitea.io). +## [1.13.1](https://github.com/go-gitea/gitea/releases/tag/v1.13.1) - 2020-12-29 + +* SECURITY + * Hide private participation in Orgs (#13994) (#14031) + * Fix escaping issue in diff (#14153) (#14154) +* BUGFIXES + * Fix bug of link query order on markdown render (#14156) (#14171) + * Drop long repo topics during migration (#14152) (#14155) + * Ensure that search term and page are not lost on adoption page-turn (#14133) (#14143) + * Fix storage config implementation (#14091) (#14095) + * Fix panic in BasicAuthDecode (#14046) (#14048) + * Always wait for the cmd to finish (#14006) (#14039) + * Don't use simpleMDE editor on mobile devices for 1.13 (#14029) + * Fix incorrect review comment diffs (#14002) (#14011) + * Trim the branch prefix from action.GetBranch (#13981) (#13986) + * Ensure template renderer is available before storage handler (#13164) (#13982) + * Whenever the password is updated ensure that the hash algorithm is too (#13966) (#13967) + * Enforce setting HEAD in wiki to master (#13950) (#13961) + * Fix feishu webhook caused by API changed (#13938) + * Fix Quote Reply button on review diff (#13830) (#13898) + * Fix Pull Merge when tag with same name as base branch exist (#13882) (#13896) + * Fix mermaid chart size (#13865) + * Fix branch/tag notifications in mirror sync (#13855) (#13862) + * Fix crash in short link processor (#13839) (#13841) + * Update font stack to bootstrap's latest (#13834) (#13837) + * Make sure email recipients can see issue (#13820) (#13827) + * Reply button is not removed when deleting a code review comment (#13824) + * When reinitialising DBConfig reset the database use flags (#13796) (#13811) +* ENHANCEMENTS + * Add emoji in label to project boards (#13978) (#14021) + * Send webhook when tag is removed via Web UI (#14015) (#14019) + * Use Process Manager to create own Context (#13792) (#13793) +* API + * GetCombinedCommitStatusByRef always return json & swagger doc fixes (#14047) + * Return original URL of Repositories (#13885) (#13886) + ## [1.13.0](https://github.com/go-gitea/gitea/releases/tag/v1.13.0) - 2020-12-01 * SECURITY * Add Allow-/Block-List for Migrate & Mirrors (#13610) (#13776) From 58c105d4bf962711b084cdedb253cf4a30c54c7d Mon Sep 17 00:00:00 2001 From: zeripath Date: Thu, 31 Dec 2020 13:03:56 +0000 Subject: [PATCH 110/205] Check for notExist on profile repository page (#14197) (#14203) Backport #14197 Fix #14189 --- routers/user/setting/profile.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/routers/user/setting/profile.go b/routers/user/setting/profile.go index 6653230a39..6caa1143ec 100644 --- a/routers/user/setting/profile.go +++ b/routers/user/setting/profile.go @@ -227,6 +227,9 @@ func Repos(ctx *context.Context) { root := filepath.Join(models.UserPath(ctxUser.Name)) if err := filepath.Walk(root, func(path string, info os.FileInfo, err error) error { if err != nil { + if os.IsNotExist(err) { + return nil + } return err } if !info.IsDir() || path == root { From 5568dd64751b93da09ea43885ded7861d556f0b0 Mon Sep 17 00:00:00 2001 From: a1012112796 <1012112796@qq.com> Date: Fri, 1 Jan 2021 22:14:49 +0800 Subject: [PATCH 111/205] fix branch selector on new issue page (#14194) (#14207) fix #14185 Signed-off-by: a1012112796 <1012112796@qq.com> Co-authored-by: Lunny Xiao --- templates/repo/issue/branch_selector_field.tmpl | 4 ++-- web_src/js/index.js | 5 +++++ 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/templates/repo/issue/branch_selector_field.tmpl b/templates/repo/issue/branch_selector_field.tmpl index b59c57cb56..76759890ce 100644 --- a/templates/repo/issue/branch_selector_field.tmpl +++ b/templates/repo/issue/branch_selector_field.tmpl @@ -31,7 +31,7 @@
-
- {{if and $resolved (eq $line.GetCommentSide "previous")}} -
- {{$resolveDoer.Name}} {{$.i18n.Tr "repo.issues.review.resolved_by"}} - - -
- {{end}} - {{if eq $line.GetCommentSide "previous"}} -
-
- - {{ template "repo/diff/comments" dict "root" $ "comments" $line.Comments}} - -
- {{template "repo/diff/comment_form_datahandler" dict "reply" (index $line.Comments 0).ReviewID "hidden" true "root" $ "comment" (index $line.Comments 0)}} - {{if and $.CanMarkConversation $isNotPending}} - - {{end}} -
- {{end}} + + + {{end}} + {{if eq $line.GetCommentSide "previous"}} +
+
+ + {{ template "repo/diff/comments" dict "root" $ "comments" $line.Comments}} + +
+ {{template "repo/diff/comment_form_datahandler" dict "reply" (index $line.Comments 0).ReviewID "hidden" true "root" $ "comment" (index $line.Comments 0)}} + {{if and $.CanMarkConversation $isNotPending}} + + {{end}} +
+ {{end}} +
- {{if and $resolved (eq $line.GetCommentSide "proposed")}} -
- {{$resolveDoer.Name}} {{$.i18n.Tr "repo.issues.review.resolved_by"}} - - -
- {{end}} - {{if eq $line.GetCommentSide "proposed"}} -
-
- - {{ template "repo/diff/comments" dict "root" $ "comments" $line.Comments}} - -
- {{template "repo/diff/comment_form_datahandler" dict "reply" (index $line.Comments 0).ReviewID "hidden" true "root" $ "comment" (index $line.Comments 0)}} - {{if and $.CanMarkConversation $isNotPending}} - - {{end}} -
- {{end}} + + + {{end}} + {{if eq $line.GetCommentSide "proposed"}} +
+
+ + {{ template "repo/diff/comments" dict "root" $ "comments" $line.Comments}} + +
+ {{template "repo/diff/comment_form_datahandler" dict "reply" (index $line.Comments 0).ReviewID "hidden" true "root" $ "comment" (index $line.Comments 0)}} + {{if and $.CanMarkConversation $isNotPending}} + + {{end}} +
+ {{end}} +
- {{if $resolved}} -
- {{$resolveDoer.Name}} {{$.root.i18n.Tr "repo.issues.review.resolved_by"}} - - -
- {{end}} -
-
- - {{ template "repo/diff/comments" dict "root" $.root "comments" $line.Comments}} - -
- {{template "repo/diff/comment_form_datahandler" dict "hidden" true "reply" (index $line.Comments 0).ReviewID "root" $.root "comment" (index $line.Comments 0)}} - {{if and $.root.CanMarkConversation $isNotPending}} - +
+ {{if $resolved}} +
+ {{$resolveDoer.Name}} {{$.root.i18n.Tr "repo.issues.review.resolved_by"}} + + +
{{end}} +
+
+ + {{ template "repo/diff/comments" dict "root" $.root "comments" $line.Comments}} + +
+ {{template "repo/diff/comment_form_datahandler" dict "hidden" true "reply" (index $line.Comments 0).ReviewID "root" $.root "comment" (index $line.Comments 0)}} + {{if and $.root.CanMarkConversation $isNotPending}} + + {{end}} +
Date: Sat, 23 Jan 2021 03:03:29 +0100 Subject: [PATCH 128/205] [Backport] Fix Deadlock & Delete affected reactions on comment deletion (#14392) (#14425) * Enhance Ghost comment mitigation Settings (#14392) * refactor models.DeleteComment and delete related reactions too * use deleteComment for UserDeleteWithCommentsMaxDays in DeleteUser * Resolve Fixme & fix potential deadlock * rm refactor * make diff eaven less --- models/admin.go | 2 +- models/issue_assignees.go | 2 +- models/issue_comment.go | 4 ++++ models/issue_reaction.go | 12 ++++++++---- models/user.go | 17 +++++++++-------- 5 files changed, 23 insertions(+), 14 deletions(-) diff --git a/models/admin.go b/models/admin.go index 903e35b0c9..b14f0e93fd 100644 --- a/models/admin.go +++ b/models/admin.go @@ -77,7 +77,7 @@ func removeStorageWithNotice(e Engine, bucket storage.ObjectStorage, title, path if err := bucket.Delete(path); err != nil { desc := fmt.Sprintf("%s [%s]: %v", title, path, err) log.Warn(title+" [%s]: %v", path, err) - if err = createNotice(x, NoticeRepository, desc); err != nil { + if err = createNotice(e, NoticeRepository, desc); err != nil { log.Error("CreateRepositoryNotice: %v", err) } } diff --git a/models/issue_assignees.go b/models/issue_assignees.go index 05e1797c19..6716f2fc70 100644 --- a/models/issue_assignees.go +++ b/models/issue_assignees.go @@ -82,7 +82,7 @@ func isUserAssignedToIssue(e Engine, issue *Issue, user *User) (isAssigned bool, } // ClearAssigneeByUserID deletes all assignments of an user -func clearAssigneeByUserID(sess *xorm.Session, userID int64) (err error) { +func clearAssigneeByUserID(sess Engine, userID int64) (err error) { _, err = sess.Delete(&IssueAssignees{AssigneeID: userID}) return } diff --git a/models/issue_comment.go b/models/issue_comment.go index 73cbb0566f..b2a21e0f5b 100644 --- a/models/issue_comment.go +++ b/models/issue_comment.go @@ -1077,6 +1077,10 @@ func DeleteComment(comment *Comment, doer *User) error { return err } + if err := deleteReaction(sess, &ReactionOptions{Comment: comment}); err != nil { + return err + } + return sess.Commit() } diff --git a/models/issue_reaction.go b/models/issue_reaction.go index 50b9d6848a..1f1a483996 100644 --- a/models/issue_reaction.go +++ b/models/issue_reaction.go @@ -178,11 +178,15 @@ func CreateCommentReaction(doer *User, issue *Issue, comment *Comment, content s }) } -func deleteReaction(e *xorm.Session, opts *ReactionOptions) error { +func deleteReaction(e Engine, opts *ReactionOptions) error { reaction := &Reaction{ - Type: opts.Type, - UserID: opts.Doer.ID, - IssueID: opts.Issue.ID, + Type: opts.Type, + } + if opts.Doer != nil { + reaction.UserID = opts.Doer.ID + } + if opts.Issue != nil { + reaction.IssueID = opts.Issue.ID } if opts.Comment != nil { reaction.CommentID = opts.Comment.ID diff --git a/models/user.go b/models/user.go index dc3b4142bf..f35d2e5c6b 100644 --- a/models/user.go +++ b/models/user.go @@ -40,7 +40,6 @@ import ( "golang.org/x/crypto/scrypt" "golang.org/x/crypto/ssh" "xorm.io/builder" - "xorm.io/xorm" ) // UserType defines the user type @@ -1020,8 +1019,7 @@ func deleteBeans(e Engine, beans ...interface{}) (err error) { return nil } -// FIXME: need some kind of mechanism to record failure. HINT: system notice -func deleteUser(e *xorm.Session, u *User) error { +func deleteUser(e Engine, u *User) error { // Note: A user owns any repository or belongs to any organization // cannot perform delete operation. @@ -1135,18 +1133,21 @@ func deleteUser(e *xorm.Session, u *User) error { return fmt.Errorf("Delete: %v", err) } - // FIXME: system notice // Note: There are something just cannot be roll back, // so just keep error logs of those operations. path := UserPath(u.Name) - if err := util.RemoveAll(path); err != nil { - return fmt.Errorf("Failed to RemoveAll %s: %v", path, err) + if err = util.RemoveAll(path); err != nil { + err = fmt.Errorf("Failed to RemoveAll %s: %v", path, err) + _ = createNotice(e, NoticeTask, fmt.Sprintf("delete user '%s': %v", u.Name, err)) + return err } if len(u.Avatar) > 0 { avatarPath := u.CustomAvatarRelativePath() - if err := storage.Avatars.Delete(avatarPath); err != nil { - return fmt.Errorf("Failed to remove %s: %v", avatarPath, err) + if err = storage.Avatars.Delete(avatarPath); err != nil { + err = fmt.Errorf("Failed to remove %s: %v", avatarPath, err) + _ = createNotice(e, NoticeTask, fmt.Sprintf("delete user '%s': %v", u.Name, err)) + return err } } From dd827d6f2f4ab4acd637101b94e8e853f39d6b34 Mon Sep 17 00:00:00 2001 From: 6543 <6543@obermui.de> Date: Sat, 23 Jan 2021 03:55:52 +0100 Subject: [PATCH 129/205] Fix lfs preview bug (#14428) (#14433) Co-authored-by: Lunny Xiao --- routers/repo/view.go | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/routers/repo/view.go b/routers/repo/view.go index 2df5b30ce8..8055cba7f9 100644 --- a/routers/repo/view.go +++ b/routers/repo/view.go @@ -10,6 +10,7 @@ import ( "encoding/base64" "fmt" gotemplate "html/template" + "io" "io/ioutil" "net/url" "path" @@ -420,7 +421,9 @@ func renderFile(ctx *context.Context, entry *git.TreeEntry, treeLink, rawLink st buf = make([]byte, 1024) n, err = dataRc.Read(buf) - if err != nil { + // Error EOF don't mean there is an error, it just means we read to + // the end + if err != nil && err != io.EOF { ctx.ServerError("Data", err) return } From 841efac895722f9b4575fce2febcef0a6d45f187 Mon Sep 17 00:00:00 2001 From: zeripath Date: Sat, 23 Jan 2021 04:11:57 +0000 Subject: [PATCH 130/205] ensure timeout error is shown on u2f timeout (#14417) (#14431) Backport #14417 Signed-off-by: Andrew Thornton Co-authored-by: Lunny Xiao Co-authored-by: 6543 <6543@obermui.de> --- templates/user/auth/u2f_error.tmpl | 2 +- web_src/js/index.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/templates/user/auth/u2f_error.tmpl b/templates/user/auth/u2f_error.tmpl index e30b064720..5bda372fe8 100644 --- a/templates/user/auth/u2f_error.tmpl +++ b/templates/user/auth/u2f_error.tmpl @@ -20,7 +20,7 @@
{{.i18n.Tr "u2f_error_4"}}
-
+
{{.i18n.Tr "u2f_error_5"}}
diff --git a/web_src/js/index.js b/web_src/js/index.js index 8917ffda6f..d42827f13b 100644 --- a/web_src/js/index.js +++ b/web_src/js/index.js @@ -2198,7 +2198,7 @@ function u2fError(errorType) { 2: $('#u2f-error-2'), 3: $('#u2f-error-3'), 4: $('#u2f-error-4'), - 5: $('.u2f-error-5') + 5: $('.u2f_error_5') }; u2fErrors[errorType].removeClass('hide'); From 00dc35e2de02e558dcdbd3911ce3d9b27fddf421 Mon Sep 17 00:00:00 2001 From: 6543 <6543@obermui.de> Date: Sat, 23 Jan 2021 12:33:03 +0100 Subject: [PATCH 131/205] Fix migration v141 (#14387) (#14388) * Fix mig 141 * temporary fix dump --- models/migrations/v141.go | 2 +- models/models.go | 13 +++++++++++-- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/models/migrations/v141.go b/models/migrations/v141.go index b5824ecd48..ab05698b8c 100644 --- a/models/migrations/v141.go +++ b/models/migrations/v141.go @@ -12,7 +12,7 @@ import ( func addKeepActivityPrivateUserColumn(x *xorm.Engine) error { type User struct { - KeepActivityPrivate bool + KeepActivityPrivate bool `xorm:"NOT NULL DEFAULT false"` } if err := x.Sync2(new(User)); err != nil { diff --git a/models/models.go b/models/models.go index f12a4e8b30..4e3d1b8ff6 100644 --- a/models/models.go +++ b/models/models.go @@ -15,12 +15,14 @@ import ( "code.gitea.io/gitea/modules/setting" - // Needed for the MySQL driver - _ "github.com/go-sql-driver/mysql" + "xorm.io/builder" "xorm.io/xorm" "xorm.io/xorm/names" "xorm.io/xorm/schemas" + // Needed for the MySQL driver + _ "github.com/go-sql-driver/mysql" + // Needed for the Postgresql driver _ "github.com/lib/pq" @@ -312,6 +314,13 @@ func DumpDatabase(filePath string, dbType string) error { tbs = append(tbs, t) } + // temporary fix for v1.13.x (https://github.com/go-gitea/gitea/issues/14069) + if _, err := x.Where(builder.IsNull{"keep_activity_private"}). + Cols("keep_activity_private"). + Update(User{KeepActivityPrivate: false}); err != nil { + return err + } + type Version struct { ID int64 `xorm:"pk autoincr"` Version int64 From 2595c708684d63e3e0bdd37565a20b166956a9e6 Mon Sep 17 00:00:00 2001 From: 6543 <6543@obermui.de> Date: Mon, 25 Jan 2021 00:36:16 +0100 Subject: [PATCH 132/205] ChangeUserName: rename user files back on DB issue (#14447) --- models/user.go | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/models/user.go b/models/user.go index f35d2e5c6b..f8e0ae8cba 100644 --- a/models/user.go +++ b/models/user.go @@ -922,6 +922,7 @@ func VerifyActiveEmailCode(code, email string) *EmailAddress { // ChangeUserName changes all corresponding setting from old user name to new one. func ChangeUserName(u *User, newUserName string) (err error) { + oldUserName := u.Name if err = IsUsableUsername(newUserName); err != nil { return err } @@ -939,16 +940,24 @@ func ChangeUserName(u *User, newUserName string) (err error) { return err } - if _, err = sess.Exec("UPDATE `repository` SET owner_name=? WHERE owner_name=?", newUserName, u.Name); err != nil { + if _, err = sess.Exec("UPDATE `repository` SET owner_name=? WHERE owner_name=?", newUserName, oldUserName); err != nil { return fmt.Errorf("Change repo owner name: %v", err) } // Do not fail if directory does not exist - if err = os.Rename(UserPath(u.Name), UserPath(newUserName)); err != nil && !os.IsNotExist(err) { + if err = os.Rename(UserPath(oldUserName), UserPath(newUserName)); err != nil && !os.IsNotExist(err) { return fmt.Errorf("Rename user directory: %v", err) } - return sess.Commit() + if err = sess.Commit(); err != nil { + if err2 := os.Rename(UserPath(newUserName), UserPath(oldUserName)); err2 != nil && !os.IsNotExist(err2) { + log.Critical("Unable to rollback directory change during failed username change from: %s to: %s. DB Error: %v. Filesystem Error: %v", oldUserName, newUserName, err, err2) + return fmt.Errorf("failed to rollback directory change during failed username change from: %s to: %s. DB Error: %w. Filesystem Error: %v", oldUserName, newUserName, err, err2) + } + return err + } + + return nil } // checkDupEmail checks whether there are the same email with the user From 8ff4f82e059c16cfa237e04977b9a033049205fb Mon Sep 17 00:00:00 2001 From: 6543 <6543@obermui.de> Date: Thu, 28 Jan 2021 16:14:57 +0100 Subject: [PATCH 133/205] update code.gitea.io/sdk/gitea v0.13.1 -> v0.13.2 (#14497) --- go.mod | 2 +- go.sum | 4 +- vendor/code.gitea.io/sdk/gitea/admin_cron.go | 4 +- vendor/code.gitea.io/sdk/gitea/client.go | 2 +- vendor/code.gitea.io/sdk/gitea/go.mod | 2 +- vendor/code.gitea.io/sdk/gitea/issue.go | 6 +-- .../code.gitea.io/sdk/gitea/issue_comment.go | 2 +- vendor/code.gitea.io/sdk/gitea/issue_label.go | 2 +- .../code.gitea.io/sdk/gitea/issue_reaction.go | 12 +++--- .../sdk/gitea/issue_subscription.go | 8 ++-- .../sdk/gitea/issue_tracked_time.go | 14 +++---- .../code.gitea.io/sdk/gitea/notifications.go | 24 ++++++----- vendor/code.gitea.io/sdk/gitea/oauth2.go | 10 ++--- vendor/code.gitea.io/sdk/gitea/pull.go | 4 +- vendor/code.gitea.io/sdk/gitea/pull_review.go | 12 +++--- vendor/code.gitea.io/sdk/gitea/release.go | 2 +- vendor/code.gitea.io/sdk/gitea/repo.go | 40 +++++++++++++++++-- vendor/code.gitea.io/sdk/gitea/repo_branch.go | 4 +- .../sdk/gitea/repo_branch_protection.go | 10 ++--- vendor/code.gitea.io/sdk/gitea/repo_commit.go | 5 ++- vendor/code.gitea.io/sdk/gitea/repo_file.go | 2 +- .../code.gitea.io/sdk/gitea/repo_migrate.go | 19 ++++++--- .../code.gitea.io/sdk/gitea/repo_transfer.go | 2 +- vendor/code.gitea.io/sdk/gitea/settings.go | 8 ++-- vendor/code.gitea.io/sdk/gitea/version.go | 26 ++++++++++++ vendor/modules.txt | 2 +- 26 files changed, 151 insertions(+), 77 deletions(-) diff --git a/go.mod b/go.mod index 87f82c0e62..08dfe1ae5c 100644 --- a/go.mod +++ b/go.mod @@ -4,7 +4,7 @@ go 1.14 require ( code.gitea.io/gitea-vet v0.2.1 - code.gitea.io/sdk/gitea v0.13.1 + code.gitea.io/sdk/gitea v0.13.2 gitea.com/lunny/levelqueue v0.3.0 gitea.com/macaron/binding v0.0.0-20190822013154-a5f53841ed2b gitea.com/macaron/cache v0.0.0-20190822004001-a6e7fee4ee76 diff --git a/go.sum b/go.sum index 04a652f2a8..e674b9e231 100644 --- a/go.sum +++ b/go.sum @@ -15,8 +15,8 @@ cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2k cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= code.gitea.io/gitea-vet v0.2.1 h1:b30by7+3SkmiftK0RjuXqFvZg2q4p68uoPGuxhzBN0s= code.gitea.io/gitea-vet v0.2.1/go.mod h1:zcNbT/aJEmivCAhfmkHOlT645KNOf9W2KnkLgFjGGfE= -code.gitea.io/sdk/gitea v0.13.1 h1:Y7bpH2iO6Q0KhhMJfjP/LZ0AmiYITeRQlCD8b0oYqhk= -code.gitea.io/sdk/gitea v0.13.1/go.mod h1:z3uwDV/b9Ls47NGukYM9XhnHtqPh/J+t40lsUrR6JDY= +code.gitea.io/sdk/gitea v0.13.2 h1:wAnT/J7Z62q3fJXbgnecoaOBh8CM1Qq0/DakWxiv4yA= +code.gitea.io/sdk/gitea v0.13.2/go.mod h1:lee2y8LeV3kQb2iK+hHlMqoadL4bp27QOkOV/hawLKg= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= gitea.com/lunny/levelqueue v0.3.0 h1:MHn1GuSZkxvVEDMyAPqlc7A3cOW+q8RcGhRgH/xtm6I= gitea.com/lunny/levelqueue v0.3.0/go.mod h1:HBqmLbz56JWpfEGG0prskAV97ATNRoj5LDmPicD22hU= diff --git a/vendor/code.gitea.io/sdk/gitea/admin_cron.go b/vendor/code.gitea.io/sdk/gitea/admin_cron.go index 72f77e55ee..99006b696b 100644 --- a/vendor/code.gitea.io/sdk/gitea/admin_cron.go +++ b/vendor/code.gitea.io/sdk/gitea/admin_cron.go @@ -25,7 +25,7 @@ type ListCronTaskOptions struct { // ListCronTasks list available cron tasks func (c *Client) ListCronTasks(opt ListCronTaskOptions) ([]*CronTask, *Response, error) { - if err := c.CheckServerVersionConstraint(">=1.13.0"); err != nil { + if err := c.checkServerVersionGreaterThanOrEqual(version1_13_0); err != nil { return nil, nil, err } opt.setDefaults() @@ -36,7 +36,7 @@ func (c *Client) ListCronTasks(opt ListCronTaskOptions) ([]*CronTask, *Response, // RunCronTasks run a cron task func (c *Client) RunCronTasks(task string) (*Response, error) { - if err := c.CheckServerVersionConstraint(">=1.13.0"); err != nil { + if err := c.checkServerVersionGreaterThanOrEqual(version1_13_0); err != nil { return nil, err } _, resp, err := c.getResponse("POST", fmt.Sprintf("/admin/cron/%s", task), jsonHeader, nil) diff --git a/vendor/code.gitea.io/sdk/gitea/client.go b/vendor/code.gitea.io/sdk/gitea/client.go index ca5ee35334..e08bc9edd8 100644 --- a/vendor/code.gitea.io/sdk/gitea/client.go +++ b/vendor/code.gitea.io/sdk/gitea/client.go @@ -56,7 +56,7 @@ func NewClient(url string, options ...func(*Client)) (*Client, error) { for _, opt := range options { opt(client) } - if err := client.CheckServerVersionConstraint(">=1.10"); err != nil { + if err := client.checkServerVersionGreaterThanOrEqual(version1_10_0); err != nil { return nil, err } return client, nil diff --git a/vendor/code.gitea.io/sdk/gitea/go.mod b/vendor/code.gitea.io/sdk/gitea/go.mod index 7b0d75fd34..fe2a46ae06 100644 --- a/vendor/code.gitea.io/sdk/gitea/go.mod +++ b/vendor/code.gitea.io/sdk/gitea/go.mod @@ -3,6 +3,6 @@ module code.gitea.io/sdk/gitea go 1.12 require ( - github.com/hashicorp/go-version v1.2.0 + github.com/hashicorp/go-version v1.2.1 github.com/stretchr/testify v1.4.0 ) diff --git a/vendor/code.gitea.io/sdk/gitea/issue.go b/vendor/code.gitea.io/sdk/gitea/issue.go index 1b09b3f796..7eef447119 100644 --- a/vendor/code.gitea.io/sdk/gitea/issue.go +++ b/vendor/code.gitea.io/sdk/gitea/issue.go @@ -121,7 +121,7 @@ func (c *Client) ListIssues(opt ListIssueOption) ([]*Issue, *Response, error) { link, _ := url.Parse("/repos/issues/search") link.RawQuery = opt.QueryEncode() resp, err := c.getParsedResponse("GET", link.String(), jsonHeader, nil, &issues) - if e := c.CheckServerVersionConstraint(">=1.12.0"); e != nil { + if e := c.checkServerVersionGreaterThanOrEqual(version1_12_0); e != nil { for i := 0; i < len(issues); i++ { if issues[i].Repository != nil { issues[i].Repository.Owner = strings.Split(issues[i].Repository.FullName, "/")[0] @@ -139,7 +139,7 @@ func (c *Client) ListRepoIssues(owner, repo string, opt ListIssueOption) ([]*Iss link, _ := url.Parse(fmt.Sprintf("/repos/%s/%s/issues", owner, repo)) link.RawQuery = opt.QueryEncode() resp, err := c.getParsedResponse("GET", link.String(), jsonHeader, nil, &issues) - if e := c.CheckServerVersionConstraint(">=1.12.0"); e != nil { + if e := c.checkServerVersionGreaterThanOrEqual(version1_12_0); e != nil { for i := 0; i < len(issues); i++ { if issues[i].Repository != nil { issues[i].Repository.Owner = strings.Split(issues[i].Repository.FullName, "/")[0] @@ -153,7 +153,7 @@ func (c *Client) ListRepoIssues(owner, repo string, opt ListIssueOption) ([]*Iss func (c *Client) GetIssue(owner, repo string, index int64) (*Issue, *Response, error) { issue := new(Issue) resp, err := c.getParsedResponse("GET", fmt.Sprintf("/repos/%s/%s/issues/%d", owner, repo, index), nil, nil, issue) - if e := c.CheckServerVersionConstraint(">=1.12.0"); e != nil && issue.Repository != nil { + if e := c.checkServerVersionGreaterThanOrEqual(version1_12_0); e != nil && issue.Repository != nil { issue.Repository.Owner = strings.Split(issue.Repository.FullName, "/")[0] } return issue, resp, err diff --git a/vendor/code.gitea.io/sdk/gitea/issue_comment.go b/vendor/code.gitea.io/sdk/gitea/issue_comment.go index 50b3532645..4eff850d13 100644 --- a/vendor/code.gitea.io/sdk/gitea/issue_comment.go +++ b/vendor/code.gitea.io/sdk/gitea/issue_comment.go @@ -68,7 +68,7 @@ func (c *Client) ListRepoIssueComments(owner, repo string, opt ListIssueCommentO // GetIssueComment get a comment for a given repo by id. func (c *Client) GetIssueComment(owner, repo string, id int64) (*Comment, *Response, error) { comment := new(Comment) - if err := c.CheckServerVersionConstraint(">=1.12.0"); err != nil { + if err := c.checkServerVersionGreaterThanOrEqual(version1_12_0); err != nil { return comment, nil, err } resp, err := c.getParsedResponse("GET", fmt.Sprintf("/repos/%s/%s/issues/comments/%d", owner, repo, id), nil, nil, &comment) diff --git a/vendor/code.gitea.io/sdk/gitea/issue_label.go b/vendor/code.gitea.io/sdk/gitea/issue_label.go index 1eb3c744f7..b664dacd1f 100644 --- a/vendor/code.gitea.io/sdk/gitea/issue_label.go +++ b/vendor/code.gitea.io/sdk/gitea/issue_label.go @@ -71,7 +71,7 @@ func (c *Client) CreateLabel(owner, repo string, opt CreateLabelOption) (*Label, return nil, nil, err } if len(opt.Color) == 6 { - if err := c.CheckServerVersionConstraint(">=1.12.0"); err != nil { + if err := c.checkServerVersionGreaterThanOrEqual(version1_12_0); err != nil { opt.Color = "#" + opt.Color } } diff --git a/vendor/code.gitea.io/sdk/gitea/issue_reaction.go b/vendor/code.gitea.io/sdk/gitea/issue_reaction.go index a70209a0e3..4ec203c594 100644 --- a/vendor/code.gitea.io/sdk/gitea/issue_reaction.go +++ b/vendor/code.gitea.io/sdk/gitea/issue_reaction.go @@ -20,7 +20,7 @@ type Reaction struct { // GetIssueReactions get a list reactions of an issue func (c *Client) GetIssueReactions(owner, repo string, index int64) ([]*Reaction, *Response, error) { - if err := c.CheckServerVersionConstraint(">=1.11.0"); err != nil { + if err := c.checkServerVersionGreaterThanOrEqual(version1_11_0); err != nil { return nil, nil, err } reactions := make([]*Reaction, 0, 10) @@ -30,7 +30,7 @@ func (c *Client) GetIssueReactions(owner, repo string, index int64) ([]*Reaction // GetIssueCommentReactions get a list of reactions from a comment of an issue func (c *Client) GetIssueCommentReactions(owner, repo string, commentID int64) ([]*Reaction, *Response, error) { - if err := c.CheckServerVersionConstraint(">=1.11.0"); err != nil { + if err := c.checkServerVersionGreaterThanOrEqual(version1_11_0); err != nil { return nil, nil, err } reactions := make([]*Reaction, 0, 10) @@ -45,7 +45,7 @@ type editReactionOption struct { // PostIssueReaction add a reaction to an issue func (c *Client) PostIssueReaction(owner, repo string, index int64, reaction string) (*Reaction, *Response, error) { - if err := c.CheckServerVersionConstraint(">=1.11.0"); err != nil { + if err := c.checkServerVersionGreaterThanOrEqual(version1_11_0); err != nil { return nil, nil, err } reactionResponse := new(Reaction) @@ -61,7 +61,7 @@ func (c *Client) PostIssueReaction(owner, repo string, index int64, reaction str // DeleteIssueReaction remove a reaction from an issue func (c *Client) DeleteIssueReaction(owner, repo string, index int64, reaction string) (*Response, error) { - if err := c.CheckServerVersionConstraint(">=1.11.0"); err != nil { + if err := c.checkServerVersionGreaterThanOrEqual(version1_11_0); err != nil { return nil, err } body, err := json.Marshal(&editReactionOption{Reaction: reaction}) @@ -74,7 +74,7 @@ func (c *Client) DeleteIssueReaction(owner, repo string, index int64, reaction s // PostIssueCommentReaction add a reaction to a comment of an issue func (c *Client) PostIssueCommentReaction(owner, repo string, commentID int64, reaction string) (*Reaction, *Response, error) { - if err := c.CheckServerVersionConstraint(">=1.11.0"); err != nil { + if err := c.checkServerVersionGreaterThanOrEqual(version1_11_0); err != nil { return nil, nil, err } reactionResponse := new(Reaction) @@ -90,7 +90,7 @@ func (c *Client) PostIssueCommentReaction(owner, repo string, commentID int64, r // DeleteIssueCommentReaction remove a reaction from a comment of an issue func (c *Client) DeleteIssueCommentReaction(owner, repo string, commentID int64, reaction string) (*Response, error) { - if err := c.CheckServerVersionConstraint(">=1.11.0"); err != nil { + if err := c.checkServerVersionGreaterThanOrEqual(version1_11_0); err != nil { return nil, err } body, err := json.Marshal(&editReactionOption{Reaction: reaction}) diff --git a/vendor/code.gitea.io/sdk/gitea/issue_subscription.go b/vendor/code.gitea.io/sdk/gitea/issue_subscription.go index 52e67ed44d..0af4228c60 100644 --- a/vendor/code.gitea.io/sdk/gitea/issue_subscription.go +++ b/vendor/code.gitea.io/sdk/gitea/issue_subscription.go @@ -11,7 +11,7 @@ import ( // GetIssueSubscribers get list of users who subscribed on an issue func (c *Client) GetIssueSubscribers(owner, repo string, index int64) ([]*User, *Response, error) { - if err := c.CheckServerVersionConstraint(">=1.11.0"); err != nil { + if err := c.checkServerVersionGreaterThanOrEqual(version1_11_0); err != nil { return nil, nil, err } subscribers := make([]*User, 0, 10) @@ -21,7 +21,7 @@ func (c *Client) GetIssueSubscribers(owner, repo string, index int64) ([]*User, // AddIssueSubscription Subscribe user to issue func (c *Client) AddIssueSubscription(owner, repo string, index int64, user string) (*Response, error) { - if err := c.CheckServerVersionConstraint(">=1.11.0"); err != nil { + if err := c.checkServerVersionGreaterThanOrEqual(version1_11_0); err != nil { return nil, err } status, resp, err := c.getStatusCode("PUT", fmt.Sprintf("/repos/%s/%s/issues/%d/subscriptions/%s", owner, repo, index, user), nil, nil) @@ -39,7 +39,7 @@ func (c *Client) AddIssueSubscription(owner, repo string, index int64, user stri // DeleteIssueSubscription unsubscribe user from issue func (c *Client) DeleteIssueSubscription(owner, repo string, index int64, user string) (*Response, error) { - if err := c.CheckServerVersionConstraint(">=1.11.0"); err != nil { + if err := c.checkServerVersionGreaterThanOrEqual(version1_11_0); err != nil { return nil, err } status, resp, err := c.getStatusCode("DELETE", fmt.Sprintf("/repos/%s/%s/issues/%d/subscriptions/%s", owner, repo, index, user), nil, nil) @@ -57,7 +57,7 @@ func (c *Client) DeleteIssueSubscription(owner, repo string, index int64, user s // CheckIssueSubscription check if current user is subscribed to an issue func (c *Client) CheckIssueSubscription(owner, repo string, index int64) (*WatchInfo, *Response, error) { - if err := c.CheckServerVersionConstraint(">=1.12.0"); err != nil { + if err := c.checkServerVersionGreaterThanOrEqual(version1_12_0); err != nil { return nil, nil, err } wi := new(WatchInfo) diff --git a/vendor/code.gitea.io/sdk/gitea/issue_tracked_time.go b/vendor/code.gitea.io/sdk/gitea/issue_tracked_time.go index 481c831d7b..9a9922e665 100644 --- a/vendor/code.gitea.io/sdk/gitea/issue_tracked_time.go +++ b/vendor/code.gitea.io/sdk/gitea/issue_tracked_time.go @@ -27,7 +27,7 @@ type TrackedTime struct { // GetUserTrackedTimes list tracked times of a user func (c *Client) GetUserTrackedTimes(owner, repo, user string) ([]*TrackedTime, *Response, error) { - if err := c.CheckServerVersionConstraint(">=1.11.0"); err != nil { + if err := c.checkServerVersionGreaterThanOrEqual(version1_11_0); err != nil { return nil, nil, err } times := make([]*TrackedTime, 0, 10) @@ -37,7 +37,7 @@ func (c *Client) GetUserTrackedTimes(owner, repo, user string) ([]*TrackedTime, // GetRepoTrackedTimes list tracked times of a repository func (c *Client) GetRepoTrackedTimes(owner, repo string) ([]*TrackedTime, *Response, error) { - if err := c.CheckServerVersionConstraint(">=1.11.0"); err != nil { + if err := c.checkServerVersionGreaterThanOrEqual(version1_11_0); err != nil { return nil, nil, err } times := make([]*TrackedTime, 0, 10) @@ -47,7 +47,7 @@ func (c *Client) GetRepoTrackedTimes(owner, repo string) ([]*TrackedTime, *Respo // GetMyTrackedTimes list tracked times of the current user func (c *Client) GetMyTrackedTimes() ([]*TrackedTime, *Response, error) { - if err := c.CheckServerVersionConstraint(">=1.11.0"); err != nil { + if err := c.checkServerVersionGreaterThanOrEqual(version1_11_0); err != nil { return nil, nil, err } times := make([]*TrackedTime, 0, 10) @@ -75,7 +75,7 @@ func (opt AddTimeOption) Validate() error { // AddTime adds time to issue with the given index func (c *Client) AddTime(owner, repo string, index int64, opt AddTimeOption) (*TrackedTime, *Response, error) { - if err := c.CheckServerVersionConstraint(">=1.11.0"); err != nil { + if err := c.checkServerVersionGreaterThanOrEqual(version1_11_0); err != nil { return nil, nil, err } if err := opt.Validate(); err != nil { @@ -99,7 +99,7 @@ type ListTrackedTimesOptions struct { // ListTrackedTimes list tracked times of a single issue for a given repository func (c *Client) ListTrackedTimes(owner, repo string, index int64, opt ListTrackedTimesOptions) ([]*TrackedTime, *Response, error) { - if err := c.CheckServerVersionConstraint(">=1.11.0"); err != nil { + if err := c.checkServerVersionGreaterThanOrEqual(version1_11_0); err != nil { return nil, nil, err } opt.setDefaults() @@ -110,7 +110,7 @@ func (c *Client) ListTrackedTimes(owner, repo string, index int64, opt ListTrack // ResetIssueTime reset tracked time of a single issue for a given repository func (c *Client) ResetIssueTime(owner, repo string, index int64) (*Response, error) { - if err := c.CheckServerVersionConstraint(">=1.11.0"); err != nil { + if err := c.checkServerVersionGreaterThanOrEqual(version1_11_0); err != nil { return nil, err } _, resp, err := c.getResponse("DELETE", fmt.Sprintf("/repos/%s/%s/issues/%d/times", owner, repo, index), nil, nil) @@ -119,7 +119,7 @@ func (c *Client) ResetIssueTime(owner, repo string, index int64) (*Response, err // DeleteTime delete a specific tracked time by id of a single issue for a given repository func (c *Client) DeleteTime(owner, repo string, index, timeID int64) (*Response, error) { - if err := c.CheckServerVersionConstraint(">=1.11.0"); err != nil { + if err := c.checkServerVersionGreaterThanOrEqual(version1_11_0); err != nil { return nil, err } _, resp, err := c.getResponse("DELETE", fmt.Sprintf("/repos/%s/%s/issues/%d/times/%d", owner, repo, index, timeID), nil, nil) diff --git a/vendor/code.gitea.io/sdk/gitea/notifications.go b/vendor/code.gitea.io/sdk/gitea/notifications.go index 515a0d4a71..30b6b6d01c 100644 --- a/vendor/code.gitea.io/sdk/gitea/notifications.go +++ b/vendor/code.gitea.io/sdk/gitea/notifications.go @@ -8,6 +8,12 @@ import ( "fmt" "net/url" "time" + + "github.com/hashicorp/go-version" +) + +var ( + version1_12_3, _ = version.NewVersion("1.12.3") ) // NotificationThread expose Notification on API @@ -75,7 +81,7 @@ func (opt *ListNotificationOptions) QueryEncode() string { // Validate the CreateUserOption struct func (opt ListNotificationOptions) Validate(c *Client) error { if len(opt.Status) != 0 { - return c.CheckServerVersionConstraint(">=1.12.3") + return c.checkServerVersionGreaterThanOrEqual(version1_12_3) } return nil } @@ -98,14 +104,14 @@ func (opt *MarkNotificationOptions) QueryEncode() string { // Validate the CreateUserOption struct func (opt MarkNotificationOptions) Validate(c *Client) error { if len(opt.Status) != 0 || len(opt.ToStatus) != 0 { - return c.CheckServerVersionConstraint(">=1.12.3") + return c.checkServerVersionGreaterThanOrEqual(version1_12_3) } return nil } // CheckNotifications list users's notification threads func (c *Client) CheckNotifications() (int64, *Response, error) { - if err := c.CheckServerVersionConstraint(">=1.12.0"); err != nil { + if err := c.checkServerVersionGreaterThanOrEqual(version1_12_0); err != nil { return 0, nil, err } new := struct { @@ -118,7 +124,7 @@ func (c *Client) CheckNotifications() (int64, *Response, error) { // GetNotification get notification thread by ID func (c *Client) GetNotification(id int64) (*NotificationThread, *Response, error) { - if err := c.CheckServerVersionConstraint(">=1.12.0"); err != nil { + if err := c.checkServerVersionGreaterThanOrEqual(version1_12_0); err != nil { return nil, nil, err } thread := new(NotificationThread) @@ -129,7 +135,7 @@ func (c *Client) GetNotification(id int64) (*NotificationThread, *Response, erro // ReadNotification mark notification thread as read by ID // It optionally takes a second argument if status has to be set other than 'read' func (c *Client) ReadNotification(id int64, status ...NotifyStatus) (*Response, error) { - if err := c.CheckServerVersionConstraint(">=1.12.0"); err != nil { + if err := c.checkServerVersionGreaterThanOrEqual(version1_12_0); err != nil { return nil, err } link := fmt.Sprintf("/notifications/threads/%d", id) @@ -142,7 +148,7 @@ func (c *Client) ReadNotification(id int64, status ...NotifyStatus) (*Response, // ListNotifications list users's notification threads func (c *Client) ListNotifications(opt ListNotificationOptions) ([]*NotificationThread, *Response, error) { - if err := c.CheckServerVersionConstraint(">=1.12.0"); err != nil { + if err := c.checkServerVersionGreaterThanOrEqual(version1_12_0); err != nil { return nil, nil, err } if err := opt.Validate(c); err != nil { @@ -157,7 +163,7 @@ func (c *Client) ListNotifications(opt ListNotificationOptions) ([]*Notification // ReadNotifications mark notification threads as read func (c *Client) ReadNotifications(opt MarkNotificationOptions) (*Response, error) { - if err := c.CheckServerVersionConstraint(">=1.12.0"); err != nil { + if err := c.checkServerVersionGreaterThanOrEqual(version1_12_0); err != nil { return nil, err } if err := opt.Validate(c); err != nil { @@ -171,7 +177,7 @@ func (c *Client) ReadNotifications(opt MarkNotificationOptions) (*Response, erro // ListRepoNotifications list users's notification threads on a specific repo func (c *Client) ListRepoNotifications(owner, reponame string, opt ListNotificationOptions) ([]*NotificationThread, *Response, error) { - if err := c.CheckServerVersionConstraint(">=1.12.0"); err != nil { + if err := c.checkServerVersionGreaterThanOrEqual(version1_12_0); err != nil { return nil, nil, err } if err := opt.Validate(c); err != nil { @@ -186,7 +192,7 @@ func (c *Client) ListRepoNotifications(owner, reponame string, opt ListNotificat // ReadRepoNotifications mark notification threads as read on a specific repo func (c *Client) ReadRepoNotifications(owner, reponame string, opt MarkNotificationOptions) (*Response, error) { - if err := c.CheckServerVersionConstraint(">=1.12.0"); err != nil { + if err := c.checkServerVersionGreaterThanOrEqual(version1_12_0); err != nil { return nil, err } if err := opt.Validate(c); err != nil { diff --git a/vendor/code.gitea.io/sdk/gitea/oauth2.go b/vendor/code.gitea.io/sdk/gitea/oauth2.go index 80b1547405..bbdfdafb67 100644 --- a/vendor/code.gitea.io/sdk/gitea/oauth2.go +++ b/vendor/code.gitea.io/sdk/gitea/oauth2.go @@ -34,7 +34,7 @@ type CreateOauth2Option struct { // CreateOauth2 create an Oauth2 Application and returns a completed Oauth2 object. func (c *Client) CreateOauth2(opt CreateOauth2Option) (*Oauth2, *Response, error) { - if err := c.CheckServerVersionConstraint(">=1.12.0"); err != nil { + if err := c.checkServerVersionGreaterThanOrEqual(version1_12_0); err != nil { return nil, nil, err } body, err := json.Marshal(&opt) @@ -48,7 +48,7 @@ func (c *Client) CreateOauth2(opt CreateOauth2Option) (*Oauth2, *Response, error // UpdateOauth2 a specific Oauth2 Application by ID and return a completed Oauth2 object. func (c *Client) UpdateOauth2(oauth2id int64, opt CreateOauth2Option) (*Oauth2, *Response, error) { - if err := c.CheckServerVersionConstraint(">=1.12.0"); err != nil { + if err := c.checkServerVersionGreaterThanOrEqual(version1_12_0); err != nil { return nil, nil, err } body, err := json.Marshal(&opt) @@ -62,7 +62,7 @@ func (c *Client) UpdateOauth2(oauth2id int64, opt CreateOauth2Option) (*Oauth2, // GetOauth2 a specific Oauth2 Application by ID. func (c *Client) GetOauth2(oauth2id int64) (*Oauth2, *Response, error) { - if err := c.CheckServerVersionConstraint(">=1.12.0"); err != nil { + if err := c.checkServerVersionGreaterThanOrEqual(version1_12_0); err != nil { return nil, nil, err } oauth2s := &Oauth2{} @@ -72,7 +72,7 @@ func (c *Client) GetOauth2(oauth2id int64) (*Oauth2, *Response, error) { // ListOauth2 all of your Oauth2 Applications. func (c *Client) ListOauth2(opt ListOauth2Option) ([]*Oauth2, *Response, error) { - if err := c.CheckServerVersionConstraint(">=1.12.0"); err != nil { + if err := c.checkServerVersionGreaterThanOrEqual(version1_12_0); err != nil { return nil, nil, err } opt.setDefaults() @@ -83,7 +83,7 @@ func (c *Client) ListOauth2(opt ListOauth2Option) ([]*Oauth2, *Response, error) // DeleteOauth2 delete an Oauth2 application by ID func (c *Client) DeleteOauth2(oauth2id int64) (*Response, error) { - if err := c.CheckServerVersionConstraint(">=1.12.0"); err != nil { + if err := c.checkServerVersionGreaterThanOrEqual(version1_12_0); err != nil { return nil, err } _, resp, err := c.getResponse("DELETE", fmt.Sprintf("/user/applications/oauth2/%d", oauth2id), nil, nil) diff --git a/vendor/code.gitea.io/sdk/gitea/pull.go b/vendor/code.gitea.io/sdk/gitea/pull.go index 24d70e2faf..c41ab3b018 100644 --- a/vendor/code.gitea.io/sdk/gitea/pull.go +++ b/vendor/code.gitea.io/sdk/gitea/pull.go @@ -160,7 +160,7 @@ func (opt EditPullRequestOption) Validate(c *Client) error { return fmt.Errorf("title is empty") } if len(opt.Base) != 0 { - if err := c.CheckServerVersionConstraint(">=1.12.0"); err != nil { + if err := c.checkServerVersionGreaterThanOrEqual(version1_12_0); err != nil { return fmt.Errorf("can not change base gitea to old") } } @@ -229,7 +229,7 @@ func (c *Client) IsPullRequestMerged(owner, repo string, index int64) (bool, *Re // getPullRequestDiffOrPatch gets the patch or diff file as bytes for a PR func (c *Client) getPullRequestDiffOrPatch(owner, repo, kind string, index int64) ([]byte, *Response, error) { - if err := c.CheckServerVersionConstraint(">=1.13.0"); err != nil { + if err := c.checkServerVersionGreaterThanOrEqual(version1_13_0); err != nil { r, _, err2 := c.GetRepo(owner, repo) if err2 != nil { return nil, nil, err diff --git a/vendor/code.gitea.io/sdk/gitea/pull_review.go b/vendor/code.gitea.io/sdk/gitea/pull_review.go index e44dc7df58..fc0c22c2d7 100644 --- a/vendor/code.gitea.io/sdk/gitea/pull_review.go +++ b/vendor/code.gitea.io/sdk/gitea/pull_review.go @@ -132,7 +132,7 @@ func (opt CreatePullReviewComment) Validate() error { // ListPullReviews lists all reviews of a pull request func (c *Client) ListPullReviews(owner, repo string, index int64, opt ListPullReviewsOptions) ([]*PullReview, *Response, error) { - if err := c.CheckServerVersionConstraint(">=1.12.0"); err != nil { + if err := c.checkServerVersionGreaterThanOrEqual(version1_12_0); err != nil { return nil, nil, err } opt.setDefaults() @@ -147,7 +147,7 @@ func (c *Client) ListPullReviews(owner, repo string, index int64, opt ListPullRe // GetPullReview gets a specific review of a pull request func (c *Client) GetPullReview(owner, repo string, index, id int64) (*PullReview, *Response, error) { - if err := c.CheckServerVersionConstraint(">=1.12.0"); err != nil { + if err := c.checkServerVersionGreaterThanOrEqual(version1_12_0); err != nil { return nil, nil, err } @@ -158,7 +158,7 @@ func (c *Client) GetPullReview(owner, repo string, index, id int64) (*PullReview // ListPullReviewComments lists all comments of a pull request review func (c *Client) ListPullReviewComments(owner, repo string, index, id int64) ([]*PullReviewComment, *Response, error) { - if err := c.CheckServerVersionConstraint(">=1.12.0"); err != nil { + if err := c.checkServerVersionGreaterThanOrEqual(version1_12_0); err != nil { return nil, nil, err } rcl := make([]*PullReviewComment, 0, 4) @@ -170,7 +170,7 @@ func (c *Client) ListPullReviewComments(owner, repo string, index, id int64) ([] // DeletePullReview delete a specific review from a pull request func (c *Client) DeletePullReview(owner, repo string, index, id int64) (*Response, error) { - if err := c.CheckServerVersionConstraint(">=1.12.0"); err != nil { + if err := c.checkServerVersionGreaterThanOrEqual(version1_12_0); err != nil { return nil, err } @@ -180,7 +180,7 @@ func (c *Client) DeletePullReview(owner, repo string, index, id int64) (*Respons // CreatePullReview create a review to an pull request func (c *Client) CreatePullReview(owner, repo string, index int64, opt CreatePullReviewOptions) (*PullReview, *Response, error) { - if err := c.CheckServerVersionConstraint(">=1.12.0"); err != nil { + if err := c.checkServerVersionGreaterThanOrEqual(version1_12_0); err != nil { return nil, nil, err } if err := opt.Validate(); err != nil { @@ -200,7 +200,7 @@ func (c *Client) CreatePullReview(owner, repo string, index int64, opt CreatePul // SubmitPullReview submit a pending review to an pull request func (c *Client) SubmitPullReview(owner, repo string, index, id int64, opt SubmitPullReviewOptions) (*PullReview, *Response, error) { - if err := c.CheckServerVersionConstraint(">=1.12.0"); err != nil { + if err := c.checkServerVersionGreaterThanOrEqual(version1_12_0); err != nil { return nil, nil, err } if err := opt.Validate(); err != nil { diff --git a/vendor/code.gitea.io/sdk/gitea/release.go b/vendor/code.gitea.io/sdk/gitea/release.go index 3440f1c61b..d8d28c5bd7 100644 --- a/vendor/code.gitea.io/sdk/gitea/release.go +++ b/vendor/code.gitea.io/sdk/gitea/release.go @@ -57,7 +57,7 @@ func (c *Client) GetRelease(user, repo string, id int64) (*Release, *Response, e // GetReleaseByTag get a release of a repository by tag func (c *Client) GetReleaseByTag(user, repo string, tag string) (*Release, *Response, error) { - if c.CheckServerVersionConstraint(">=1.13.0") != nil { + if c.checkServerVersionGreaterThanOrEqual(version1_13_0) != nil { return c.fallbackGetReleaseByTag(user, repo, tag) } r := new(Release) diff --git a/vendor/code.gitea.io/sdk/gitea/repo.go b/vendor/code.gitea.io/sdk/gitea/repo.go index c432724873..a09f5a651b 100644 --- a/vendor/code.gitea.io/sdk/gitea/repo.go +++ b/vendor/code.gitea.io/sdk/gitea/repo.go @@ -73,6 +73,20 @@ const ( RepoTypeMirror RepoType = "mirror" ) +// TrustModel represent how git signatures are handled in a repository +type TrustModel string + +const ( + // TrustModelDefault use TM set by global config + TrustModelDefault TrustModel = "default" + // TrustModelCollaborator gpg signature has to be owned by a repo collaborator + TrustModelCollaborator TrustModel = "collaborator" + // TrustModelCommitter gpg signature has to match committer + TrustModelCommitter TrustModel = "committer" + // TrustModelCollaboratorCommitter gpg signature has to match committer and owned by a repo collaborator + TrustModelCollaboratorCommitter TrustModel = "collaboratorcommitter" +) + // ListReposOptions options for listing repositories type ListReposOptions struct { ListOptions @@ -224,7 +238,7 @@ func (c *Client) SearchRepos(opt SearchRepoOptions) ([]*Repository, *Response, e } else { link.RawQuery = opt.QueryEncode() // IsPrivate only works on gitea >= 1.12.0 - if err := c.CheckServerVersionConstraint(">=1.12.0"); err != nil && opt.IsPrivate != nil { + if err := c.checkServerVersionGreaterThanOrEqual(version1_12_0); err != nil && opt.IsPrivate != nil { if *opt.IsPrivate { // private repos only not supported on gitea <= 1.11.x return nil, nil, err @@ -249,6 +263,8 @@ type CreateRepoOption struct { IssueLabels string `json:"issue_labels"` // Whether the repository should be auto-intialized? AutoInit bool `json:"auto_init"` + // Whether the repository is template + Template bool `json:"template"` // Gitignores to use Gitignores string `json:"gitignores"` // License to use @@ -257,19 +273,35 @@ type CreateRepoOption struct { Readme string `json:"readme"` // DefaultBranch of the repository (used when initializes and in template) DefaultBranch string `json:"default_branch"` + // TrustModel of the repository + TrustModel TrustModel `json:"trust_model"` } // Validate the CreateRepoOption struct -func (opt CreateRepoOption) Validate() error { +func (opt CreateRepoOption) Validate(c *Client) error { if len(strings.TrimSpace(opt.Name)) == 0 { return fmt.Errorf("name is empty") } + if len(opt.Name) > 100 { + return fmt.Errorf("name has more than 100 chars") + } + if len(opt.Description) > 255 { + return fmt.Errorf("name has more than 255 chars") + } + if len(opt.DefaultBranch) > 100 { + return fmt.Errorf("name has more than 100 chars") + } + if len(opt.TrustModel) != 0 { + if err := c.CheckServerVersionConstraint(">=1.13.0"); err != nil { + return err + } + } return nil } // CreateRepo creates a repository for authenticated user. func (c *Client) CreateRepo(opt CreateRepoOption) (*Repository, *Response, error) { - if err := opt.Validate(); err != nil { + if err := opt.Validate(c); err != nil { return nil, nil, err } body, err := json.Marshal(&opt) @@ -283,7 +315,7 @@ func (c *Client) CreateRepo(opt CreateRepoOption) (*Repository, *Response, error // CreateOrgRepo creates an organization repository for authenticated user. func (c *Client) CreateOrgRepo(org string, opt CreateRepoOption) (*Repository, *Response, error) { - if err := opt.Validate(); err != nil { + if err := opt.Validate(c); err != nil { return nil, nil, err } body, err := json.Marshal(&opt) diff --git a/vendor/code.gitea.io/sdk/gitea/repo_branch.go b/vendor/code.gitea.io/sdk/gitea/repo_branch.go index 0d6249e7d0..6b0eec27e9 100644 --- a/vendor/code.gitea.io/sdk/gitea/repo_branch.go +++ b/vendor/code.gitea.io/sdk/gitea/repo_branch.go @@ -84,7 +84,7 @@ func (c *Client) GetRepoBranch(user, repo, branch string) (*Branch, *Response, e // DeleteRepoBranch delete a branch in a repository func (c *Client) DeleteRepoBranch(user, repo, branch string) (bool, *Response, error) { - if err := c.CheckServerVersionConstraint(">=1.12.0"); err != nil { + if err := c.checkServerVersionGreaterThanOrEqual(version1_12_0); err != nil { return false, nil, err } status, resp, err := c.getStatusCode("DELETE", fmt.Sprintf("/repos/%s/%s/branches/%s", user, repo, branch), nil, nil) @@ -118,7 +118,7 @@ func (opt CreateBranchOption) Validate() error { // CreateBranch creates a branch for a user's repository func (c *Client) CreateBranch(owner, repo string, opt CreateBranchOption) (*Branch, *Response, error) { - if err := c.CheckServerVersionConstraint(">=1.13.0"); err != nil { + if err := c.checkServerVersionGreaterThanOrEqual(version1_13_0); err != nil { return nil, nil, err } if err := opt.Validate(); err != nil { diff --git a/vendor/code.gitea.io/sdk/gitea/repo_branch_protection.go b/vendor/code.gitea.io/sdk/gitea/repo_branch_protection.go index f4d47deda3..1e520807a1 100644 --- a/vendor/code.gitea.io/sdk/gitea/repo_branch_protection.go +++ b/vendor/code.gitea.io/sdk/gitea/repo_branch_protection.go @@ -92,7 +92,7 @@ type ListBranchProtectionsOptions struct { // ListBranchProtections list branch protections for a repo func (c *Client) ListBranchProtections(owner, repo string, opt ListBranchProtectionsOptions) ([]*BranchProtection, *Response, error) { - if err := c.CheckServerVersionConstraint(">=1.12.0"); err != nil { + if err := c.checkServerVersionGreaterThanOrEqual(version1_12_0); err != nil { return nil, nil, err } bps := make([]*BranchProtection, 0, opt.PageSize) @@ -104,7 +104,7 @@ func (c *Client) ListBranchProtections(owner, repo string, opt ListBranchProtect // GetBranchProtection gets a branch protection func (c *Client) GetBranchProtection(owner, repo, name string) (*BranchProtection, *Response, error) { - if err := c.CheckServerVersionConstraint(">=1.12.0"); err != nil { + if err := c.checkServerVersionGreaterThanOrEqual(version1_12_0); err != nil { return nil, nil, err } bp := new(BranchProtection) @@ -114,7 +114,7 @@ func (c *Client) GetBranchProtection(owner, repo, name string) (*BranchProtectio // CreateBranchProtection creates a branch protection for a repo func (c *Client) CreateBranchProtection(owner, repo string, opt CreateBranchProtectionOption) (*BranchProtection, *Response, error) { - if err := c.CheckServerVersionConstraint(">=1.12.0"); err != nil { + if err := c.checkServerVersionGreaterThanOrEqual(version1_12_0); err != nil { return nil, nil, err } bp := new(BranchProtection) @@ -128,7 +128,7 @@ func (c *Client) CreateBranchProtection(owner, repo string, opt CreateBranchProt // EditBranchProtection edits a branch protection for a repo func (c *Client) EditBranchProtection(owner, repo, name string, opt EditBranchProtectionOption) (*BranchProtection, *Response, error) { - if err := c.CheckServerVersionConstraint(">=1.12.0"); err != nil { + if err := c.checkServerVersionGreaterThanOrEqual(version1_12_0); err != nil { return nil, nil, err } bp := new(BranchProtection) @@ -142,7 +142,7 @@ func (c *Client) EditBranchProtection(owner, repo, name string, opt EditBranchPr // DeleteBranchProtection deletes a branch protection for a repo func (c *Client) DeleteBranchProtection(owner, repo, name string) (*Response, error) { - if err := c.CheckServerVersionConstraint(">=1.12.0"); err != nil { + if err := c.checkServerVersionGreaterThanOrEqual(version1_12_0); err != nil { return nil, err } _, resp, err := c.getResponse("DELETE", fmt.Sprintf("/repos/%s/%s/branch_protections/%s", owner, repo, name), jsonHeader, nil) diff --git a/vendor/code.gitea.io/sdk/gitea/repo_commit.go b/vendor/code.gitea.io/sdk/gitea/repo_commit.go index e17d0030b9..4b90b9cb65 100644 --- a/vendor/code.gitea.io/sdk/gitea/repo_commit.go +++ b/vendor/code.gitea.io/sdk/gitea/repo_commit.go @@ -19,8 +19,9 @@ type Identity struct { // CommitMeta contains meta information of a commit in terms of API. type CommitMeta struct { - URL string `json:"url"` - SHA string `json:"sha"` + URL string `json:"url"` + SHA string `json:"sha"` + Created time.Time `json:"created"` } // CommitUser contains information of a user in the context of a commit. diff --git a/vendor/code.gitea.io/sdk/gitea/repo_file.go b/vendor/code.gitea.io/sdk/gitea/repo_file.go index 94f216fdf9..b104980a8d 100644 --- a/vendor/code.gitea.io/sdk/gitea/repo_file.go +++ b/vendor/code.gitea.io/sdk/gitea/repo_file.go @@ -182,7 +182,7 @@ func (c *Client) DeleteFile(owner, repo, filepath string, opt DeleteFileOptions) func (c *Client) setDefaultBranchForOldVersions(owner, repo, branch string) (string, error) { if len(branch) == 0 { // Gitea >= 1.12.0 Use DefaultBranch on "", mimic this for older versions - if c.CheckServerVersionConstraint(">=1.12.0") != nil { + if c.checkServerVersionGreaterThanOrEqual(version1_12_0) != nil { r, _, err := c.GetRepo(owner, repo) if err != nil { return "", err diff --git a/vendor/code.gitea.io/sdk/gitea/repo_migrate.go b/vendor/code.gitea.io/sdk/gitea/repo_migrate.go index 583d800d36..518c6ae649 100644 --- a/vendor/code.gitea.io/sdk/gitea/repo_migrate.go +++ b/vendor/code.gitea.io/sdk/gitea/repo_migrate.go @@ -20,10 +20,10 @@ const ( GitServiceGithub GitServiceType = "github" // GitServiceGitlab represents a gitlab service GitServiceGitlab GitServiceType = "gitlab" + // GitServiceGitea represents a gitea service + GitServiceGitea GitServiceType = "gitea" // Not supported jet - // // GitServiceGitea represents a gitea service - // GitServiceGitea GitServiceType = "gitea" // // GitServiceGogs represents a gogs service // GitServiceGogs GitServiceType = "gogs" ) @@ -51,7 +51,7 @@ type MigrateRepoOption struct { } // Validate the MigrateRepoOption struct -func (opt *MigrateRepoOption) Validate() error { +func (opt *MigrateRepoOption) Validate(c *Client) error { // check user options if len(opt.CloneAddr) == 0 { return fmt.Errorf("CloneAddr required") @@ -69,6 +69,15 @@ func (opt *MigrateRepoOption) Validate() error { if len(opt.AuthToken) == 0 { return fmt.Errorf("github require token authentication") } + case GitServiceGitlab, GitServiceGitea: + if len(opt.AuthToken) == 0 { + return fmt.Errorf("%s require token authentication", opt.Service) + } + // Gitlab is supported since 1.12.0 but api cant handle it until 1.13.0 + // https://github.com/go-gitea/gitea/pull/12672 + if c.checkServerVersionGreaterThanOrEqual(version1_13_0) != nil { + return fmt.Errorf("migrate from service %s need gitea >= 1.13.0", opt.Service) + } } return nil } @@ -78,11 +87,11 @@ func (opt *MigrateRepoOption) Validate() error { // To migrate a repository for a organization, the authenticated user must be a // owner of the specified organization. func (c *Client) MigrateRepo(opt MigrateRepoOption) (*Repository, *Response, error) { - if err := opt.Validate(); err != nil { + if err := opt.Validate(c); err != nil { return nil, nil, err } - if err := c.CheckServerVersionConstraint(">=1.13.0"); err != nil { + if err := c.checkServerVersionGreaterThanOrEqual(version1_13_0); err != nil { if len(opt.AuthToken) != 0 { // gitea <= 1.12 dont understand AuthToken opt.AuthUsername = opt.AuthToken diff --git a/vendor/code.gitea.io/sdk/gitea/repo_transfer.go b/vendor/code.gitea.io/sdk/gitea/repo_transfer.go index aedb0e5269..d8d661bc44 100644 --- a/vendor/code.gitea.io/sdk/gitea/repo_transfer.go +++ b/vendor/code.gitea.io/sdk/gitea/repo_transfer.go @@ -20,7 +20,7 @@ type TransferRepoOption struct { // TransferRepo transfers the ownership of a repository func (c *Client) TransferRepo(owner, reponame string, opt TransferRepoOption) (*Repository, *Response, error) { - if err := c.CheckServerVersionConstraint(">=1.12.0"); err != nil { + if err := c.checkServerVersionGreaterThanOrEqual(version1_12_0); err != nil { return nil, nil, err } body, err := json.Marshal(&opt) diff --git a/vendor/code.gitea.io/sdk/gitea/settings.go b/vendor/code.gitea.io/sdk/gitea/settings.go index 9c39e4e215..9fa0a7ae7e 100644 --- a/vendor/code.gitea.io/sdk/gitea/settings.go +++ b/vendor/code.gitea.io/sdk/gitea/settings.go @@ -33,7 +33,7 @@ type GlobalAttachmentSettings struct { // GetGlobalUISettings get global ui settings witch are exposed by API func (c *Client) GetGlobalUISettings() (*GlobalUISettings, *Response, error) { - if err := c.CheckServerVersionConstraint(">=1.13.0"); err != nil { + if err := c.checkServerVersionGreaterThanOrEqual(version1_13_0); err != nil { return nil, nil, err } conf := new(GlobalUISettings) @@ -43,7 +43,7 @@ func (c *Client) GetGlobalUISettings() (*GlobalUISettings, *Response, error) { // GetGlobalRepoSettings get global repository settings witch are exposed by API func (c *Client) GetGlobalRepoSettings() (*GlobalRepoSettings, *Response, error) { - if err := c.CheckServerVersionConstraint(">=1.13.0"); err != nil { + if err := c.checkServerVersionGreaterThanOrEqual(version1_13_0); err != nil { return nil, nil, err } conf := new(GlobalRepoSettings) @@ -53,7 +53,7 @@ func (c *Client) GetGlobalRepoSettings() (*GlobalRepoSettings, *Response, error) // GetGlobalAPISettings get global api settings witch are exposed by it func (c *Client) GetGlobalAPISettings() (*GlobalAPISettings, *Response, error) { - if err := c.CheckServerVersionConstraint(">=1.13.0"); err != nil { + if err := c.checkServerVersionGreaterThanOrEqual(version1_13_0); err != nil { return nil, nil, err } conf := new(GlobalAPISettings) @@ -63,7 +63,7 @@ func (c *Client) GetGlobalAPISettings() (*GlobalAPISettings, *Response, error) { // GetGlobalAttachmentSettings get global repository settings witch are exposed by API func (c *Client) GetGlobalAttachmentSettings() (*GlobalAttachmentSettings, *Response, error) { - if err := c.CheckServerVersionConstraint(">=1.13.0"); err != nil { + if err := c.checkServerVersionGreaterThanOrEqual(version1_13_0); err != nil { return nil, nil, err } conf := new(GlobalAttachmentSettings) diff --git a/vendor/code.gitea.io/sdk/gitea/version.go b/vendor/code.gitea.io/sdk/gitea/version.go index 57c64dc410..747117ccc2 100644 --- a/vendor/code.gitea.io/sdk/gitea/version.go +++ b/vendor/code.gitea.io/sdk/gitea/version.go @@ -42,6 +42,32 @@ func (c *Client) CheckServerVersionConstraint(constraint string) error { return nil } +// predefined versions only have to be parsed by library once +var ( + version1_10_0, _ = version.NewVersion("1.10.0") + version1_11_0, _ = version.NewVersion("1.11.0") + version1_12_0, _ = version.NewVersion("1.12.0") + version1_13_0, _ = version.NewVersion("1.13.0") +) + +// checkServerVersionGreaterThanOrEqual is internally used to speed up things and ignore issues with prerelease +func (c *Client) checkServerVersionGreaterThanOrEqual(v *version.Version) error { + c.versionLock.RLock() + if c.serverVersion == nil { + c.versionLock.RUnlock() + if err := c.loadClientServerVersion(); err != nil { + return err + } + } else { + c.versionLock.RUnlock() + } + + if !c.serverVersion.GreaterThanOrEqual(v) { + return fmt.Errorf("gitea server at %s is older than %s", c.url, v.Original()) + } + return nil +} + // loadClientServerVersion init the serverVersion variable func (c *Client) loadClientServerVersion() error { c.versionLock.Lock() diff --git a/vendor/modules.txt b/vendor/modules.txt index be206facda..11373e3504 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -4,7 +4,7 @@ cloud.google.com/go/compute/metadata ## explicit code.gitea.io/gitea-vet code.gitea.io/gitea-vet/checks -# code.gitea.io/sdk/gitea v0.13.1 +# code.gitea.io/sdk/gitea v0.13.2 ## explicit code.gitea.io/sdk/gitea # gitea.com/lunny/levelqueue v0.3.0 From 9569607abbcf7aee7d8353dc1ff32c9116081851 Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Fri, 29 Jan 2021 22:37:20 +0800 Subject: [PATCH 134/205] Fix wiki preview (#14515) Co-authored-by: Lauris BH --- web_src/js/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web_src/js/index.js b/web_src/js/index.js index d42827f13b..2bfa691d63 100644 --- a/web_src/js/index.js +++ b/web_src/js/index.js @@ -1359,7 +1359,7 @@ function initWikiForm() { const $editArea = $('.repository.wiki textarea#edit_area'); let sideBySideChanges = 0; let sideBySideTimeout = null; - if ($editArea.length > 0 && isMobile) { + if ($editArea.length > 0 && isMobile()) { $editArea.css('display', 'inline-block'); return; } From 446c06b81794a7f71d2890812d0d9ff8b044395e Mon Sep 17 00:00:00 2001 From: 6543 <6543@obermui.de> Date: Sat, 30 Jan 2021 20:47:11 +0100 Subject: [PATCH 135/205] Set the name Mapper in migrations (#14526) (#14529) Migrations currently uses the default Xorm mapper which is not the same as the mapper Gitea actually uses. This means that there is a difference between the struct parsing and mapping to database tables in migrations as compared to normal Sync2. This was the cause for the catastrophic problem in v168 - untagged fields are not mapped in the same way in migrations as compared to outside of migrations. This is also likely the cause of some weird subtle failures in other migrations as any untagged field may not be being mapped exactly the same way. This PR suggests that we ensure that the mapper is set at the start of the migrations code - but also enforces a strict clean mapper between each migration. Signed-off-by: Andrew Thornton Co-authored-by: zeripath --- models/migrations/migrations.go | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/models/migrations/migrations.go b/models/migrations/migrations.go index 0efcce30a9..5cb85cc18c 100644 --- a/models/migrations/migrations.go +++ b/models/migrations/migrations.go @@ -16,6 +16,7 @@ import ( "code.gitea.io/gitea/modules/setting" "xorm.io/xorm" + "xorm.io/xorm/names" ) const minDBVersion = 70 // Gitea 1.5.3 @@ -296,6 +297,8 @@ func EnsureUpToDate(x *xorm.Engine) error { // Migrate database to current version func Migrate(x *xorm.Engine) error { + // Set a new clean the default mapper to GonicMapper as that is the default for Gitea. + x.SetMapper(names.GonicMapper{}) if err := x.Sync(new(Version)); err != nil { return fmt.Errorf("sync: %v", err) } @@ -334,6 +337,8 @@ Please try upgrading to a lower version first (suggested v1.6.4), then upgrade t // Migrate for i, m := range migrations[v-minDBVersion:] { log.Info("Migration[%d]: %s", v+int64(i), m.Description()) + // Reset the mapper between each migration - migrations are not supposed to depend on each other + x.SetMapper(names.GonicMapper{}) if err = m.Migrate(x); err != nil { return fmt.Errorf("do migrate: %v", err) } From 7dddf2186ba05ba1260da4fa4873034d3362164c Mon Sep 17 00:00:00 2001 From: Stefan <57448158+root360-StefanHeitmueller@users.noreply.github.com> Date: Sat, 30 Jan 2021 20:57:31 +0100 Subject: [PATCH 136/205] configure internal ssh server w/ macs and ciphers, backport of #14523 (#14530) --- modules/ssh/ssh.go | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/modules/ssh/ssh.go b/modules/ssh/ssh.go index 7a449dd41b..13e69a0f3d 100644 --- a/modules/ssh/ssh.go +++ b/modules/ssh/ssh.go @@ -196,13 +196,17 @@ func publicKeyHandler(ctx ssh.Context, key ssh.PublicKey) bool { // Listen starts a SSH server listens on given port. func Listen(host string, port int, ciphers []string, keyExchanges []string, macs []string) { - // TODO: Handle ciphers, keyExchanges, and macs - srv := ssh.Server{ Addr: fmt.Sprintf("%s:%d", host, port), PublicKeyHandler: publicKeyHandler, Handler: sessionHandler, - + ServerConfigCallback: func(ctx ssh.Context) *gossh.ServerConfig { + config := &gossh.ServerConfig{} + config.KeyExchanges = keyExchanges + config.MACs = macs + config.Ciphers = ciphers + return config + }, // We need to explicitly disable the PtyCallback so text displays // properly. PtyCallback: func(ctx ssh.Context, pty ssh.Pty) bool { From 014313134f72ebb2ca57eb2e5cd42726231f8fff Mon Sep 17 00:00:00 2001 From: 6543 <6543@obermui.de> Date: Tue, 2 Feb 2021 00:11:05 +0100 Subject: [PATCH 137/205] Changelog v1.13.2 (#14535) --- CHANGELOG.md | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 020212043f..553db3c07c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,38 @@ This changelog goes through all the changes that have been made in each release without substantial changes to our git log; to see the highlights of what has been added to each release, please refer to the [blog](https://blog.gitea.io). +## [1.13.2](https://github.com/go-gitea/gitea/releases/tag/v1.13.2) - 2021-01-31 + +* SECURITY + * Prevent panic on fuzzer provided string (#14405) (#14409) + * Add secure/httpOnly attributes to the lang cookie (#14279) (#14280) +* API + * If release publisher is deleted use ghost user (#14375) +* BUGFIXES + * Internal ssh server respect Ciphers, MACs and KeyExchanges settings (#14523) (#14530) + * Set the name Mapper in migrations (#14526) (#14529) + * Fix wiki preview (#14515) + * Update code.gitea.io/sdk/gitea v0.13.1 -> v0.13.2 (#14497) + * ChangeUserName: rename user files back on DB issue (#14447) + * Fix lfs preview bug (#14428) (#14433) + * Ensure timeout error is shown on u2f timeout (#14417) (#14431) + * Fix Deadlock & Delete affected reactions on comment deletion (#14392) (#14425) + * Use path not filepath in routers/editor (#14390) (#14396) + * Check if label template exist first (#14384) (#14389) + * Fix migration v141 (#14387) (#14388) + * Use Request.URL.RequestURI() for fcgi (#14347) + * Use ServerError provided by Context (#14333) (#14345) + * Fix edit-label form init (#14337) + * Fix mailIssueCommentBatch for pull request (#14252) (#14296) + * Render links for commit hashes followed by comma (#14224) (#14227) + * Send notifications for mentions in pulls, issues, (code-)comments (#14218) (#14221) + * Fix avatar bugs (#14217) (#14220) + * Ensure that schema search path is set with every connection on postgres (#14131) (#14216) + * Fix dashboard issues labels filter bug (#14210) (#14214) + * When visit /favicon.ico but the static file is not exist return 404 but not continue to handle the route (#14211) (#14213) + * Fix branch selector on new issue page (#14194) (#14207) + * Check for notExist on profile repository page (#14197) (#14203) + ## [1.13.1](https://github.com/go-gitea/gitea/releases/tag/v1.13.1) - 2020-12-29 * SECURITY From da7a525c5c96e97126d5932f3a08fabfaef11b46 Mon Sep 17 00:00:00 2001 From: Anton Khimich Date: Thu, 4 Feb 2021 15:28:48 -0500 Subject: [PATCH 138/205] Fix GPG key deletion during account deletion (#14561) (#14569) Per #14531, deleting a user account will delete the user's GPG keys from the `gpg_key` table but not from `gpg_key_import`, which causes an error when creating an account with the same email and attempting to re-add the same key. This commit deletes all entries from `gpg_key_import` that match any GPG key IDs belonging to the user. Co-authored-by: Anton Khimich --- models/gpg_key.go | 6 +++++- models/user.go | 10 ++++++++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/models/gpg_key.go b/models/gpg_key.go index b944fdcbff..3e8ddd9621 100644 --- a/models/gpg_key.go +++ b/models/gpg_key.go @@ -65,7 +65,11 @@ func (key *GPGKey) AfterLoad(session *xorm.Session) { // ListGPGKeys returns a list of public keys belongs to given user. func ListGPGKeys(uid int64, listOptions ListOptions) ([]*GPGKey, error) { - sess := x.Where("owner_id=? AND primary_key_id=''", uid) + return listGPGKeys(x, uid, listOptions) +} + +func listGPGKeys(e Engine, uid int64, listOptions ListOptions) ([]*GPGKey, error) { + sess := e.Table(&GPGKey{}).Where("owner_id=? AND primary_key_id=''", uid) if listOptions.Page != 0 { sess = listOptions.setSessionPagination(sess) } diff --git a/models/user.go b/models/user.go index f8e0ae8cba..9cd074a420 100644 --- a/models/user.go +++ b/models/user.go @@ -1122,6 +1122,16 @@ func deleteUser(e Engine, u *User) error { // ***** END: PublicKey ***** // ***** START: GPGPublicKey ***** + keys, err := listGPGKeys(e, u.ID, ListOptions{}) + if err != nil { + return fmt.Errorf("ListGPGKeys: %v", err) + } + // Delete GPGKeyImport(s). + for _, key := range keys { + if _, err = e.Delete(&GPGKeyImport{KeyID: key.KeyID}); err != nil { + return fmt.Errorf("deleteGPGKeyImports: %v", err) + } + } if _, err = e.Delete(&GPGKey{OwnerID: u.ID}); err != nil { return fmt.Errorf("deleteGPGKeys: %v", err) } From d0174d45ed313a8ba61069486834ae292ce8c103 Mon Sep 17 00:00:00 2001 From: 6543 <6543@obermui.de> Date: Fri, 5 Feb 2021 22:11:15 +0100 Subject: [PATCH 139/205] Fix bug about ListOptions and stars/watchers pagnation (#14556) (#14573) * Fix bug about ListOptions and stars/watchers pagnation * fix unit test --- models/commit_status_test.go | 2 +- models/list_options.go | 10 +++++----- routers/repo/view.go | 6 +++++- 3 files changed, 11 insertions(+), 7 deletions(-) diff --git a/models/commit_status_test.go b/models/commit_status_test.go index 90d72cd74d..57b97f6606 100644 --- a/models/commit_status_test.go +++ b/models/commit_status_test.go @@ -18,7 +18,7 @@ func TestGetCommitStatuses(t *testing.T) { sha1 := "1234123412341234123412341234123412341234" - statuses, maxResults, err := GetCommitStatuses(repo1, sha1, &CommitStatusOptions{}) + statuses, maxResults, err := GetCommitStatuses(repo1, sha1, &CommitStatusOptions{ListOptions: ListOptions{Page: 1, PageSize: 50}}) assert.NoError(t, err) assert.Equal(t, int(maxResults), 5) assert.Len(t, statuses, 5) diff --git a/models/list_options.go b/models/list_options.go index 0912355352..9cccd05465 100644 --- a/models/list_options.go +++ b/models/list_options.go @@ -16,13 +16,13 @@ type ListOptions struct { Page int // start from 1 } -func (opts ListOptions) getPaginatedSession() *xorm.Session { +func (opts *ListOptions) getPaginatedSession() *xorm.Session { opts.setDefaultValues() return x.Limit(opts.PageSize, (opts.Page-1)*opts.PageSize) } -func (opts ListOptions) setSessionPagination(sess *xorm.Session) *xorm.Session { +func (opts *ListOptions) setSessionPagination(sess *xorm.Session) *xorm.Session { opts.setDefaultValues() if opts.PageSize <= 0 { @@ -31,21 +31,21 @@ func (opts ListOptions) setSessionPagination(sess *xorm.Session) *xorm.Session { return sess.Limit(opts.PageSize, (opts.Page-1)*opts.PageSize) } -func (opts ListOptions) setEnginePagination(e Engine) Engine { +func (opts *ListOptions) setEnginePagination(e Engine) Engine { opts.setDefaultValues() return e.Limit(opts.PageSize, (opts.Page-1)*opts.PageSize) } // GetStartEnd returns the start and end of the ListOptions -func (opts ListOptions) GetStartEnd() (start, end int) { +func (opts *ListOptions) GetStartEnd() (start, end int) { opts.setDefaultValues() start = (opts.Page - 1) * opts.PageSize end = start + opts.Page return } -func (opts ListOptions) setDefaultValues() { +func (opts *ListOptions) setDefaultValues() { if opts.PageSize <= 0 { opts.PageSize = setting.API.DefaultPagingNum } diff --git a/routers/repo/view.go b/routers/repo/view.go index 8055cba7f9..06bcd1dbda 100644 --- a/routers/repo/view.go +++ b/routers/repo/view.go @@ -692,7 +692,10 @@ func RenderUserCards(ctx *context.Context, total int, getter func(opts models.Li pager := context.NewPagination(total, models.ItemsPerPage, page, 5) ctx.Data["Page"] = pager - items, err := getter(models.ListOptions{Page: pager.Paginater.Current()}) + items, err := getter(models.ListOptions{ + Page: pager.Paginater.Current(), + PageSize: models.ItemsPerPage, + }) if err != nil { ctx.ServerError("getter", err) return @@ -723,6 +726,7 @@ func Stars(ctx *context.Context) { func Forks(ctx *context.Context) { ctx.Data["Title"] = ctx.Tr("repos.forks") + // TODO: need pagination forks, err := ctx.Repo.Repository.GetForks(models.ListOptions{}) if err != nil { ctx.ServerError("GetForks", err) From 82637c240aa3b0e0bf290d35b2014953edec5b6e Mon Sep 17 00:00:00 2001 From: zeripath Date: Mon, 8 Feb 2021 01:25:30 +0000 Subject: [PATCH 140/205] Accept multiple SSH keys in single LDAP SSHPublicKey attribute (#13989) (#14607) Backport #13989 Fix #13984 Fix #14566 Signed-off-by: Andrew Thornton --- integrations/auth_ldap_test.go | 2 +- models/user.go | 30 +++++++++++---- models/user_test.go | 68 ++++++++++++++++++++++++++++++++++ 3 files changed, 91 insertions(+), 9 deletions(-) diff --git a/integrations/auth_ldap_test.go b/integrations/auth_ldap_test.go index 1569458418..8ce5c587fe 100644 --- a/integrations/auth_ldap_test.go +++ b/integrations/auth_ldap_test.go @@ -237,6 +237,6 @@ func TestLDAPUserSSHKeySync(t *testing.T) { syncedKeys[i] = strings.TrimSpace(divs.Eq(i).Text()) } - assert.ElementsMatch(t, u.SSHKeys, syncedKeys) + assert.ElementsMatch(t, u.SSHKeys, syncedKeys, "Unequal number of keys synchronized for user: %s", u.UserName) } } diff --git a/models/user.go b/models/user.go index 9cd074a420..af5f36ec17 100644 --- a/models/user.go +++ b/models/user.go @@ -1622,20 +1622,34 @@ func deleteKeysMarkedForDeletion(keys []string) (bool, error) { func addLdapSSHPublicKeys(usr *User, s *LoginSource, sshPublicKeys []string) bool { var sshKeysNeedUpdate bool for _, sshKey := range sshPublicKeys { - _, _, _, _, err := ssh.ParseAuthorizedKey([]byte(sshKey)) - if err == nil { - sshKeyName := fmt.Sprintf("%s-%s", s.Name, sshKey[0:40]) - if _, err := AddPublicKey(usr.ID, sshKeyName, sshKey, s.ID); err != nil { + var err error + found := false + keys := []byte(sshKey) + loop: + for len(keys) > 0 && err == nil { + var out ssh.PublicKey + // We ignore options as they are not relevant to Gitea + out, _, _, keys, err = ssh.ParseAuthorizedKey(keys) + if err != nil { + break loop + } + found = true + marshalled := string(ssh.MarshalAuthorizedKey(out)) + marshalled = marshalled[:len(marshalled)-1] + sshKeyName := fmt.Sprintf("%s-%s", s.Name, ssh.FingerprintSHA256(out)) + + if _, err := AddPublicKey(usr.ID, sshKeyName, marshalled, s.ID); err != nil { if IsErrKeyAlreadyExist(err) { - log.Trace("addLdapSSHPublicKeys[%s]: LDAP Public SSH Key %s already exists for user", s.Name, usr.Name) + log.Trace("addLdapSSHPublicKeys[%s]: LDAP Public SSH Key %s already exists for user", sshKeyName, usr.Name) } else { - log.Error("addLdapSSHPublicKeys[%s]: Error adding LDAP Public SSH Key for user %s: %v", s.Name, usr.Name, err) + log.Error("addLdapSSHPublicKeys[%s]: Error adding LDAP Public SSH Key for user %s: %v", sshKeyName, usr.Name, err) } } else { - log.Trace("addLdapSSHPublicKeys[%s]: Added LDAP Public SSH Key for user %s", s.Name, usr.Name) + log.Trace("addLdapSSHPublicKeys[%s]: Added LDAP Public SSH Key for user %s", sshKeyName, usr.Name) sshKeysNeedUpdate = true } - } else { + } + if !found && err != nil { log.Warn("addLdapSSHPublicKeys[%s]: Skipping invalid LDAP Public SSH Key for user %s: %v", s.Name, usr.Name, sshKey) } } diff --git a/models/user_test.go b/models/user_test.go index b9fe99278c..681b585d4d 100644 --- a/models/user_test.go +++ b/models/user_test.go @@ -421,3 +421,71 @@ func TestGetMaileableUsersByIDs(t *testing.T) { assert.Equal(t, results[1].ID, 4) } } + +func TestAddLdapSSHPublicKeys(t *testing.T) { + assert.NoError(t, PrepareTestDatabase()) + + user := AssertExistsAndLoadBean(t, &User{ID: 2}).(*User) + s := &LoginSource{ID: 1} + + testCases := []struct { + keyString string + number int + keyContents []string + }{ + { + keyString: "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQC4cn+iXnA4KvcQYSV88vGn0Yi91vG47t1P7okprVmhNTkipNRIHWr6WdCO4VDr/cvsRkuVJAsLO2enwjGWWueOO6BodiBgyAOZ/5t5nJNMCNuLGT5UIo/RI1b0WRQwxEZTRjt6mFNw6lH14wRd8ulsr9toSWBPMOGWoYs1PDeDL0JuTjL+tr1SZi/EyxCngpYszKdXllJEHyI79KQgeD0Vt3pTrkbNVTOEcCNqZePSVmUH8X8Vhugz3bnE0/iE9Pb5fkWO9c4AnM1FgI/8Bvp27Fw2ShryIXuR6kKvUqhVMTuOSDHwu6A8jLE5Owt3GAYugDpDYuwTVNGrHLXKpPzrGGPE/jPmaLCMZcsdkec95dYeU3zKODEm8UQZFhmJmDeWVJ36nGrGZHL4J5aTTaeFUJmmXDaJYiJ+K2/ioKgXqnXvltu0A9R8/LGy4nrTJRr4JMLuJFoUXvGm1gXQ70w2LSpk6yl71RNC0hCtsBe8BP8IhYCM0EP5jh7eCMQZNvM= nocomment\n", + number: 1, + keyContents: []string{ + "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQC4cn+iXnA4KvcQYSV88vGn0Yi91vG47t1P7okprVmhNTkipNRIHWr6WdCO4VDr/cvsRkuVJAsLO2enwjGWWueOO6BodiBgyAOZ/5t5nJNMCNuLGT5UIo/RI1b0WRQwxEZTRjt6mFNw6lH14wRd8ulsr9toSWBPMOGWoYs1PDeDL0JuTjL+tr1SZi/EyxCngpYszKdXllJEHyI79KQgeD0Vt3pTrkbNVTOEcCNqZePSVmUH8X8Vhugz3bnE0/iE9Pb5fkWO9c4AnM1FgI/8Bvp27Fw2ShryIXuR6kKvUqhVMTuOSDHwu6A8jLE5Owt3GAYugDpDYuwTVNGrHLXKpPzrGGPE/jPmaLCMZcsdkec95dYeU3zKODEm8UQZFhmJmDeWVJ36nGrGZHL4J5aTTaeFUJmmXDaJYiJ+K2/ioKgXqnXvltu0A9R8/LGy4nrTJRr4JMLuJFoUXvGm1gXQ70w2LSpk6yl71RNC0hCtsBe8BP8IhYCM0EP5jh7eCMQZNvM=", + }, + }, + { + keyString: `ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQC4cn+iXnA4KvcQYSV88vGn0Yi91vG47t1P7okprVmhNTkipNRIHWr6WdCO4VDr/cvsRkuVJAsLO2enwjGWWueOO6BodiBgyAOZ/5t5nJNMCNuLGT5UIo/RI1b0WRQwxEZTRjt6mFNw6lH14wRd8ulsr9toSWBPMOGWoYs1PDeDL0JuTjL+tr1SZi/EyxCngpYszKdXllJEHyI79KQgeD0Vt3pTrkbNVTOEcCNqZePSVmUH8X8Vhugz3bnE0/iE9Pb5fkWO9c4AnM1FgI/8Bvp27Fw2ShryIXuR6kKvUqhVMTuOSDHwu6A8jLE5Owt3GAYugDpDYuwTVNGrHLXKpPzrGGPE/jPmaLCMZcsdkec95dYeU3zKODEm8UQZFhmJmDeWVJ36nGrGZHL4J5aTTaeFUJmmXDaJYiJ+K2/ioKgXqnXvltu0A9R8/LGy4nrTJRr4JMLuJFoUXvGm1gXQ70w2LSpk6yl71RNC0hCtsBe8BP8IhYCM0EP5jh7eCMQZNvM= nocomment +ssh-dss AAAAB3NzaC1kc3MAAACBAOChCC7lf6Uo9n7BmZ6M8St19PZf4Tn59NriyboW2x/DZuYAz3ibZ2OkQ3S0SqDIa0HXSEJ1zaExQdmbO+Ux/wsytWZmCczWOVsaszBZSl90q8UnWlSH6P+/YA+RWJm5SFtuV9PtGIhyZgoNuz5kBQ7K139wuQsecdKktISwTakzAAAAFQCzKsO2JhNKlL+wwwLGOcLffoAmkwAAAIBpK7/3xvduajLBD/9vASqBQIHrgK2J+wiQnIb/Wzy0UsVmvfn8A+udRbBo+csM8xrSnlnlJnjkJS3qiM5g+eTwsLIV1IdKPEwmwB+VcP53Cw6lSyWyJcvhFb0N6s08NZysLzvj0N+ZC/FnhKTLzIyMtkHf/IrPCwlM+pV/M/96YgAAAIEAqQcGn9CKgzgPaguIZooTAOQdvBLMI5y0bQjOW6734XOpqQGf/Kra90wpoasLKZjSYKNPjE+FRUOrStLrxcNs4BeVKhy2PYTRnybfYVk1/dmKgH6P1YSRONsGKvTsH6c5IyCRG0ncCgYeF8tXppyd642982daopE7zQ/NPAnJfag= nocomment`, + number: 2, + keyContents: []string{ + "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQC4cn+iXnA4KvcQYSV88vGn0Yi91vG47t1P7okprVmhNTkipNRIHWr6WdCO4VDr/cvsRkuVJAsLO2enwjGWWueOO6BodiBgyAOZ/5t5nJNMCNuLGT5UIo/RI1b0WRQwxEZTRjt6mFNw6lH14wRd8ulsr9toSWBPMOGWoYs1PDeDL0JuTjL+tr1SZi/EyxCngpYszKdXllJEHyI79KQgeD0Vt3pTrkbNVTOEcCNqZePSVmUH8X8Vhugz3bnE0/iE9Pb5fkWO9c4AnM1FgI/8Bvp27Fw2ShryIXuR6kKvUqhVMTuOSDHwu6A8jLE5Owt3GAYugDpDYuwTVNGrHLXKpPzrGGPE/jPmaLCMZcsdkec95dYeU3zKODEm8UQZFhmJmDeWVJ36nGrGZHL4J5aTTaeFUJmmXDaJYiJ+K2/ioKgXqnXvltu0A9R8/LGy4nrTJRr4JMLuJFoUXvGm1gXQ70w2LSpk6yl71RNC0hCtsBe8BP8IhYCM0EP5jh7eCMQZNvM=", + "ssh-dss AAAAB3NzaC1kc3MAAACBAOChCC7lf6Uo9n7BmZ6M8St19PZf4Tn59NriyboW2x/DZuYAz3ibZ2OkQ3S0SqDIa0HXSEJ1zaExQdmbO+Ux/wsytWZmCczWOVsaszBZSl90q8UnWlSH6P+/YA+RWJm5SFtuV9PtGIhyZgoNuz5kBQ7K139wuQsecdKktISwTakzAAAAFQCzKsO2JhNKlL+wwwLGOcLffoAmkwAAAIBpK7/3xvduajLBD/9vASqBQIHrgK2J+wiQnIb/Wzy0UsVmvfn8A+udRbBo+csM8xrSnlnlJnjkJS3qiM5g+eTwsLIV1IdKPEwmwB+VcP53Cw6lSyWyJcvhFb0N6s08NZysLzvj0N+ZC/FnhKTLzIyMtkHf/IrPCwlM+pV/M/96YgAAAIEAqQcGn9CKgzgPaguIZooTAOQdvBLMI5y0bQjOW6734XOpqQGf/Kra90wpoasLKZjSYKNPjE+FRUOrStLrxcNs4BeVKhy2PYTRnybfYVk1/dmKgH6P1YSRONsGKvTsH6c5IyCRG0ncCgYeF8tXppyd642982daopE7zQ/NPAnJfag=", + }, + }, + { + keyString: `ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQC4cn+iXnA4KvcQYSV88vGn0Yi91vG47t1P7okprVmhNTkipNRIHWr6WdCO4VDr/cvsRkuVJAsLO2enwjGWWueOO6BodiBgyAOZ/5t5nJNMCNuLGT5UIo/RI1b0WRQwxEZTRjt6mFNw6lH14wRd8ulsr9toSWBPMOGWoYs1PDeDL0JuTjL+tr1SZi/EyxCngpYszKdXllJEHyI79KQgeD0Vt3pTrkbNVTOEcCNqZePSVmUH8X8Vhugz3bnE0/iE9Pb5fkWO9c4AnM1FgI/8Bvp27Fw2ShryIXuR6kKvUqhVMTuOSDHwu6A8jLE5Owt3GAYugDpDYuwTVNGrHLXKpPzrGGPE/jPmaLCMZcsdkec95dYeU3zKODEm8UQZFhmJmDeWVJ36nGrGZHL4J5aTTaeFUJmmXDaJYiJ+K2/ioKgXqnXvltu0A9R8/LGy4nrTJRr4JMLuJFoUXvGm1gXQ70w2LSpk6yl71RNC0hCtsBe8BP8IhYCM0EP5jh7eCMQZNvM= nocomment +# comment asmdna,ndp +ssh-dss AAAAB3NzaC1kc3MAAACBAOChCC7lf6Uo9n7BmZ6M8St19PZf4Tn59NriyboW2x/DZuYAz3ibZ2OkQ3S0SqDIa0HXSEJ1zaExQdmbO+Ux/wsytWZmCczWOVsaszBZSl90q8UnWlSH6P+/YA+RWJm5SFtuV9PtGIhyZgoNuz5kBQ7K139wuQsecdKktISwTakzAAAAFQCzKsO2JhNKlL+wwwLGOcLffoAmkwAAAIBpK7/3xvduajLBD/9vASqBQIHrgK2J+wiQnIb/Wzy0UsVmvfn8A+udRbBo+csM8xrSnlnlJnjkJS3qiM5g+eTwsLIV1IdKPEwmwB+VcP53Cw6lSyWyJcvhFb0N6s08NZysLzvj0N+ZC/FnhKTLzIyMtkHf/IrPCwlM+pV/M/96YgAAAIEAqQcGn9CKgzgPaguIZooTAOQdvBLMI5y0bQjOW6734XOpqQGf/Kra90wpoasLKZjSYKNPjE+FRUOrStLrxcNs4BeVKhy2PYTRnybfYVk1/dmKgH6P1YSRONsGKvTsH6c5IyCRG0ncCgYeF8tXppyd642982daopE7zQ/NPAnJfag= nocomment`, + number: 2, + keyContents: []string{ + "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQC4cn+iXnA4KvcQYSV88vGn0Yi91vG47t1P7okprVmhNTkipNRIHWr6WdCO4VDr/cvsRkuVJAsLO2enwjGWWueOO6BodiBgyAOZ/5t5nJNMCNuLGT5UIo/RI1b0WRQwxEZTRjt6mFNw6lH14wRd8ulsr9toSWBPMOGWoYs1PDeDL0JuTjL+tr1SZi/EyxCngpYszKdXllJEHyI79KQgeD0Vt3pTrkbNVTOEcCNqZePSVmUH8X8Vhugz3bnE0/iE9Pb5fkWO9c4AnM1FgI/8Bvp27Fw2ShryIXuR6kKvUqhVMTuOSDHwu6A8jLE5Owt3GAYugDpDYuwTVNGrHLXKpPzrGGPE/jPmaLCMZcsdkec95dYeU3zKODEm8UQZFhmJmDeWVJ36nGrGZHL4J5aTTaeFUJmmXDaJYiJ+K2/ioKgXqnXvltu0A9R8/LGy4nrTJRr4JMLuJFoUXvGm1gXQ70w2LSpk6yl71RNC0hCtsBe8BP8IhYCM0EP5jh7eCMQZNvM=", + "ssh-dss AAAAB3NzaC1kc3MAAACBAOChCC7lf6Uo9n7BmZ6M8St19PZf4Tn59NriyboW2x/DZuYAz3ibZ2OkQ3S0SqDIa0HXSEJ1zaExQdmbO+Ux/wsytWZmCczWOVsaszBZSl90q8UnWlSH6P+/YA+RWJm5SFtuV9PtGIhyZgoNuz5kBQ7K139wuQsecdKktISwTakzAAAAFQCzKsO2JhNKlL+wwwLGOcLffoAmkwAAAIBpK7/3xvduajLBD/9vASqBQIHrgK2J+wiQnIb/Wzy0UsVmvfn8A+udRbBo+csM8xrSnlnlJnjkJS3qiM5g+eTwsLIV1IdKPEwmwB+VcP53Cw6lSyWyJcvhFb0N6s08NZysLzvj0N+ZC/FnhKTLzIyMtkHf/IrPCwlM+pV/M/96YgAAAIEAqQcGn9CKgzgPaguIZooTAOQdvBLMI5y0bQjOW6734XOpqQGf/Kra90wpoasLKZjSYKNPjE+FRUOrStLrxcNs4BeVKhy2PYTRnybfYVk1/dmKgH6P1YSRONsGKvTsH6c5IyCRG0ncCgYeF8tXppyd642982daopE7zQ/NPAnJfag=", + }, + }, + { + keyString: `ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQC4cn+iXnA4KvcQYSV88vGn0Yi91vG47t1P7okprVmhNTkipNRIHWr6WdCO4VDr/cvsRkuVJAsLO2enwjGWWueOO6BodiBgyAOZ/5t5nJNMCNuLGT5UIo/RI1b0WRQwxEZTRjt6mFNw6lH14wRd8ulsr9toSWBPMOGWoYs1PDeDL0JuTjL+tr1SZi/EyxCngpYszKdXllJEHyI79KQgeD0Vt3pTrkbNVTOEcCNqZePSVmUH8X8Vhugz3bnE0/iE9Pb5fkWO9c4AnM1FgI/8Bvp27Fw2ShryIXuR6kKvUqhVMTuOSDHwu6A8jLE5Owt3GAYugDpDYuwTVNGrHLXKpPzrGGPE/jPmaLCMZcsdkec95dYeU3zKODEm8UQZFhmJmDeWVJ36nGrGZHL4J5aTTaeFUJmmXDaJYiJ+K2/ioKgXqnXvltu0A9R8/LGy4nrTJRr4JMLuJFoUXvGm1gXQ70w2LSpk6yl71RNC0hCtsBe8BP8IhYCM0EP5jh7eCMQZNvM= nocomment +382488320jasdj1lasmva/vasodifipi4193-fksma.cm +ssh-dss AAAAB3NzaC1kc3MAAACBAOChCC7lf6Uo9n7BmZ6M8St19PZf4Tn59NriyboW2x/DZuYAz3ibZ2OkQ3S0SqDIa0HXSEJ1zaExQdmbO+Ux/wsytWZmCczWOVsaszBZSl90q8UnWlSH6P+/YA+RWJm5SFtuV9PtGIhyZgoNuz5kBQ7K139wuQsecdKktISwTakzAAAAFQCzKsO2JhNKlL+wwwLGOcLffoAmkwAAAIBpK7/3xvduajLBD/9vASqBQIHrgK2J+wiQnIb/Wzy0UsVmvfn8A+udRbBo+csM8xrSnlnlJnjkJS3qiM5g+eTwsLIV1IdKPEwmwB+VcP53Cw6lSyWyJcvhFb0N6s08NZysLzvj0N+ZC/FnhKTLzIyMtkHf/IrPCwlM+pV/M/96YgAAAIEAqQcGn9CKgzgPaguIZooTAOQdvBLMI5y0bQjOW6734XOpqQGf/Kra90wpoasLKZjSYKNPjE+FRUOrStLrxcNs4BeVKhy2PYTRnybfYVk1/dmKgH6P1YSRONsGKvTsH6c5IyCRG0ncCgYeF8tXppyd642982daopE7zQ/NPAnJfag= nocomment`, + number: 2, + keyContents: []string{ + "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQC4cn+iXnA4KvcQYSV88vGn0Yi91vG47t1P7okprVmhNTkipNRIHWr6WdCO4VDr/cvsRkuVJAsLO2enwjGWWueOO6BodiBgyAOZ/5t5nJNMCNuLGT5UIo/RI1b0WRQwxEZTRjt6mFNw6lH14wRd8ulsr9toSWBPMOGWoYs1PDeDL0JuTjL+tr1SZi/EyxCngpYszKdXllJEHyI79KQgeD0Vt3pTrkbNVTOEcCNqZePSVmUH8X8Vhugz3bnE0/iE9Pb5fkWO9c4AnM1FgI/8Bvp27Fw2ShryIXuR6kKvUqhVMTuOSDHwu6A8jLE5Owt3GAYugDpDYuwTVNGrHLXKpPzrGGPE/jPmaLCMZcsdkec95dYeU3zKODEm8UQZFhmJmDeWVJ36nGrGZHL4J5aTTaeFUJmmXDaJYiJ+K2/ioKgXqnXvltu0A9R8/LGy4nrTJRr4JMLuJFoUXvGm1gXQ70w2LSpk6yl71RNC0hCtsBe8BP8IhYCM0EP5jh7eCMQZNvM=", + "ssh-dss AAAAB3NzaC1kc3MAAACBAOChCC7lf6Uo9n7BmZ6M8St19PZf4Tn59NriyboW2x/DZuYAz3ibZ2OkQ3S0SqDIa0HXSEJ1zaExQdmbO+Ux/wsytWZmCczWOVsaszBZSl90q8UnWlSH6P+/YA+RWJm5SFtuV9PtGIhyZgoNuz5kBQ7K139wuQsecdKktISwTakzAAAAFQCzKsO2JhNKlL+wwwLGOcLffoAmkwAAAIBpK7/3xvduajLBD/9vASqBQIHrgK2J+wiQnIb/Wzy0UsVmvfn8A+udRbBo+csM8xrSnlnlJnjkJS3qiM5g+eTwsLIV1IdKPEwmwB+VcP53Cw6lSyWyJcvhFb0N6s08NZysLzvj0N+ZC/FnhKTLzIyMtkHf/IrPCwlM+pV/M/96YgAAAIEAqQcGn9CKgzgPaguIZooTAOQdvBLMI5y0bQjOW6734XOpqQGf/Kra90wpoasLKZjSYKNPjE+FRUOrStLrxcNs4BeVKhy2PYTRnybfYVk1/dmKgH6P1YSRONsGKvTsH6c5IyCRG0ncCgYeF8tXppyd642982daopE7zQ/NPAnJfag=", + }, + }, + } + + for i, kase := range testCases { + s.ID = int64(i) + 20 + addLdapSSHPublicKeys(user, s, []string{kase.keyString}) + keys, err := ListPublicLdapSSHKeys(user.ID, s.ID) + assert.NoError(t, err) + if err != nil { + continue + } + assert.Equal(t, kase.number, len(keys)) + + for _, key := range keys { + assert.Contains(t, kase.keyContents, key.Content) + } + for _, key := range keys { + DeletePublicKey(user, key.ID) + } + } +} From 101fb0d7e2ee90424e7fc27f7d11087a2a480875 Mon Sep 17 00:00:00 2001 From: zeripath Date: Sat, 13 Feb 2021 17:25:47 +0000 Subject: [PATCH 141/205] Do not assume all 40 char strings are SHA1s (#14624) (#14648) Backport #14624 GetCommit() assumes that all 40 char strings are SHA1s. This leads to an error if you try to do a PR on a branch which is 40 characters long. This PR attempts the SHA first - and if it fails will switch to using rev-parse. Fix #14470 Signed-off-by: Andrew Thornton --- modules/git/repo_commit.go | 26 +++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/modules/git/repo_commit.go b/modules/git/repo_commit.go index c9a5efb24e..a00e59edb8 100644 --- a/modules/git/repo_commit.go +++ b/modules/git/repo_commit.go @@ -129,19 +129,23 @@ func (repo *Repository) getCommit(id SHA1) (*Commit, error) { // ConvertToSHA1 returns a Hash object from a potential ID string func (repo *Repository) ConvertToSHA1(commitID string) (SHA1, error) { - if len(commitID) != 40 { - var err error - actualCommitID, err := NewCommand("rev-parse", "--verify", commitID).RunInDir(repo.Path) - if err != nil { - if strings.Contains(err.Error(), "unknown revision or path") || - strings.Contains(err.Error(), "fatal: Needed a single revision") { - return SHA1{}, ErrNotExist{commitID, ""} - } - return SHA1{}, err + if len(commitID) == 40 { + sha1, err := NewIDFromString(commitID) + if err == nil { + return sha1, nil } - commitID = actualCommitID } - return NewIDFromString(commitID) + + actualCommitID, err := NewCommand("rev-parse", "--verify", commitID).RunInDir(repo.Path) + if err != nil { + if strings.Contains(err.Error(), "unknown revision or path") || + strings.Contains(err.Error(), "fatal: Needed a single revision") { + return SHA1{}, ErrNotExist{commitID, ""} + } + return SHA1{}, err + } + + return NewIDFromString(actualCommitID) } // GetCommit returns commit object of by ID string. From a1b74c55092b846f08a3432b313abcc4994b7259 Mon Sep 17 00:00:00 2001 From: zeripath Date: Sat, 13 Feb 2021 18:34:47 +0000 Subject: [PATCH 142/205] Allow org labels to be set with issue templates (#14593) (#14647) Backport #14593 Fix #13688 Signed-off-by: Andrew Thornton Co-authored-by: Lunny Xiao --- routers/repo/issue.go | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/routers/repo/issue.go b/routers/repo/issue.go index c24f7520de..e1868601c4 100644 --- a/routers/repo/issue.go +++ b/routers/repo/issue.go @@ -725,6 +725,14 @@ func setTemplateIfExists(ctx *context.Context, ctxDataKey string, possibleDirs [ ctx.Data[ctxDataKey] = templateBody labelIDs := make([]string, 0, len(meta.Labels)) if repoLabels, err := models.GetLabelsByRepoID(ctx.Repo.Repository.ID, "", models.ListOptions{}); err == nil { + ctx.Data["Labels"] = repoLabels + if ctx.Repo.Owner.IsOrganization() { + if orgLabels, err := models.GetLabelsByOrgID(ctx.Repo.Owner.ID, ctx.Query("sort"), models.ListOptions{}); err == nil { + ctx.Data["OrgLabels"] = orgLabels + repoLabels = append(repoLabels, orgLabels...) + } + } + for _, metaLabel := range meta.Labels { for _, repoLabel := range repoLabels { if strings.EqualFold(repoLabel.Name, metaLabel) { @@ -734,7 +742,6 @@ func setTemplateIfExists(ctx *context.Context, ctxDataKey string, possibleDirs [ } } } - ctx.Data["Labels"] = repoLabels } ctx.Data["HasSelectedLabel"] = len(labelIDs) > 0 ctx.Data["label_ids"] = strings.Join(labelIDs, ",") From c0320065b67439f1c87130a3fcd2f821fc7722bd Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Sun, 14 Feb 2021 04:19:33 +0800 Subject: [PATCH 143/205] Turn default hash password algorightm back to pbkdf2 from argon2 until we found a better one (#14673) (#14675) * Turn default hash password algorightm back to pbkdf2 from argon2 until we found a better one * Add a warning on document Co-authored-by: zeripath --- custom/conf/app.example.ini | 2 +- docs/content/doc/advanced/config-cheat-sheet.en-us.md | 2 +- modules/setting/setting.go | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/custom/conf/app.example.ini b/custom/conf/app.example.ini index f060f13c58..a3349f9865 100644 --- a/custom/conf/app.example.ini +++ b/custom/conf/app.example.ini @@ -548,7 +548,7 @@ ONLY_ALLOW_PUSH_IF_GITEA_ENVIRONMENT_SET = true ;Classes include "lower,upper,digit,spec" PASSWORD_COMPLEXITY = off ; Password Hash algorithm, either "argon2", "pbkdf2", "scrypt" or "bcrypt" -PASSWORD_HASH_ALGO = argon2 +PASSWORD_HASH_ALGO = pbkdf2 ; Set false to allow JavaScript to read CSRF cookie CSRF_COOKIE_HTTP_ONLY = true ; Validate against https://haveibeenpwned.com/Passwords to see if a password has been exposed diff --git a/docs/content/doc/advanced/config-cheat-sheet.en-us.md b/docs/content/doc/advanced/config-cheat-sheet.en-us.md index ca09d4f032..77464a509a 100644 --- a/docs/content/doc/advanced/config-cheat-sheet.en-us.md +++ b/docs/content/doc/advanced/config-cheat-sheet.en-us.md @@ -402,7 +402,7 @@ relation to port exhaustion. - `IMPORT_LOCAL_PATHS`: **false**: Set to `false` to prevent all users (including admin) from importing local path on server. - `INTERNAL_TOKEN`: **\**: Secret used to validate communication within Gitea binary. - `INTERNAL_TOKEN_URI`: ****: Instead of defining internal token in the configuration, this configuration option can be used to give Gitea a path to a file that contains the internal token (example value: `file:/etc/gitea/internal_token`) -- `PASSWORD_HASH_ALGO`: **argon2**: The hash algorithm to use \[argon2, pbkdf2, scrypt, bcrypt\]. +- `PASSWORD_HASH_ALGO`: **pbkdf2**: The hash algorithm to use \[argon2, pbkdf2, scrypt, bcrypt\], argon2 will spend more memory than others. - `CSRF_COOKIE_HTTP_ONLY`: **true**: Set false to allow JavaScript to read CSRF cookie. - `MIN_PASSWORD_LENGTH`: **6**: Minimum password length for new users. - `PASSWORD_COMPLEXITY`: **off**: Comma separated list of character classes required to pass minimum complexity. If left empty or no valid values are specified, checking is disabled (off): diff --git a/modules/setting/setting.go b/modules/setting/setting.go index 7ae8bb352d..77a18e3593 100644 --- a/modules/setting/setting.go +++ b/modules/setting/setting.go @@ -771,7 +771,7 @@ func NewContext() { ImportLocalPaths = sec.Key("IMPORT_LOCAL_PATHS").MustBool(false) DisableGitHooks = sec.Key("DISABLE_GIT_HOOKS").MustBool(true) OnlyAllowPushIfGiteaEnvironmentSet = sec.Key("ONLY_ALLOW_PUSH_IF_GITEA_ENVIRONMENT_SET").MustBool(true) - PasswordHashAlgo = sec.Key("PASSWORD_HASH_ALGO").MustString("argon2") + PasswordHashAlgo = sec.Key("PASSWORD_HASH_ALGO").MustString("pbkdf2") CSRFCookieHTTPOnly = sec.Key("CSRF_COOKIE_HTTP_ONLY").MustBool(true) PasswordCheckPwn = sec.Key("PASSWORD_CHECK_PWN").MustBool(false) From f305cffcaf61ecfba7d5e6c28492ca640da1c98d Mon Sep 17 00:00:00 2001 From: zeripath Date: Sun, 14 Feb 2021 00:50:50 +0000 Subject: [PATCH 144/205] Prevent race in PersistableChannelUniqueQueue.Has (#14651) (#14676) Backport #14651 There is potentially a race with a slow starting internal queue causing a NPE if Has is checked before the internal queue has been setup. This PR adds a lock on the Has() fn. Fix #14311 Signed-off-by: Andrew Thornton Co-authored-by: 6543 <6543@obermui.de> --- modules/queue/unique_queue_disk_channel.go | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/modules/queue/unique_queue_disk_channel.go b/modules/queue/unique_queue_disk_channel.go index 71049f3259..4a69b43eae 100644 --- a/modules/queue/unique_queue_disk_channel.go +++ b/modules/queue/unique_queue_disk_channel.go @@ -149,6 +149,11 @@ func (q *PersistableChannelUniqueQueue) Has(data Data) (bool, error) { if err != nil || has { return has, err } + q.lock.Lock() + defer q.lock.Unlock() + if q.internal == nil { + return false, nil + } return q.internal.(UniqueQueue).Has(data) } From d3200db041a8b26169a4ec4b793fcbd1044370c1 Mon Sep 17 00:00:00 2001 From: zeripath Date: Sun, 14 Feb 2021 22:44:26 +0000 Subject: [PATCH 145/205] HasPreviousCommit causes recursive load of commits unnecessarily (#14598) (#14649) This PR improves HasPreviousCommit to prevent the automatic and recursive loading of previous commits using git merge-base --is-ancestor and git rev-list Fix #13684 Signed-off-by: Andrew Thornton Co-authored-by: 6543 <6543@obermui.de> --- modules/git/commit.go | 44 +++++++++++++++++++++++++++---------------- 1 file changed, 28 insertions(+), 16 deletions(-) diff --git a/modules/git/commit.go b/modules/git/commit.go index 6d2bc2b02c..b7d2c3a9f3 100644 --- a/modules/git/commit.go +++ b/modules/git/commit.go @@ -9,6 +9,7 @@ import ( "bufio" "bytes" "container/list" + "errors" "fmt" "image" "image/color" @@ -17,6 +18,7 @@ import ( _ "image/png" // for processing png images "io" "net/http" + "os/exec" "strconv" "strings" @@ -309,23 +311,33 @@ func (c *Commit) CommitsBefore() (*list.List, error) { // HasPreviousCommit returns true if a given commitHash is contained in commit's parents func (c *Commit) HasPreviousCommit(commitHash SHA1) (bool, error) { - for i := 0; i < c.ParentCount(); i++ { - commit, err := c.Parent(i) - if err != nil { - return false, err - } - if commit.ID == commitHash { - return true, nil - } - commitInParentCommit, err := commit.HasPreviousCommit(commitHash) - if err != nil { - return false, err - } - if commitInParentCommit { - return true, nil - } + this := c.ID.String() + that := commitHash.String() + + if this == that { + return false, nil } - return false, nil + + if err := CheckGitVersionConstraint(">= 1.8.0"); err == nil { + _, err := NewCommand("merge-base", "--is-ancestor", that, this).RunInDir(c.repo.Path) + if err == nil { + return true, nil + } + var exitError *exec.ExitError + if errors.As(err, &exitError) { + if exitError.ProcessState.ExitCode() == 1 && len(exitError.Stderr) == 0 { + return false, nil + } + } + return false, err + } + + result, err := NewCommand("rev-list", "--ancestry-path", "-n1", that+".."+this, "--").RunInDir(c.repo.Path) + if err != nil { + return false, err + } + + return len(strings.TrimSpace(result)) > 0, nil } // CommitsBeforeLimit returns num commits before current revision From ad6084a222c0091719e7837d6fca85c3a8035e7e Mon Sep 17 00:00:00 2001 From: zeripath Date: Sun, 14 Feb 2021 23:30:07 +0000 Subject: [PATCH 146/205] Fix broken spans in diffs (#14678) (#14683) Backport #14678 Gitea runs diff on highlighted code fragment for each line in order to provide code highlight diffs. Unfortunately this diff algorithm is not aware that span tags and entities are atomic and cannot be split. The current fixup code makes some attempt to fix these broken tags however, it cannot handle situations where a tag is split over multiple blocks. This PR provides a more algorithmic fixup mechanism whereby spans and entities are completely coalesced into their respective blocks. This may result in a incompletely reduced diff but - it will definitely prevent the broken entities and spans that are currently possible. As a result of this fixup several inconsistencies were discovered in our testcases and these were also fixed. Fix #14231 Signed-off-by: Andrew Thornton Co-authored-by: 6543 <6543@obermui.de> --- services/gitdiff/gitdiff.go | 210 +++++++++++++++++++++++++++++++ services/gitdiff/gitdiff_test.go | 24 +++- 2 files changed, 228 insertions(+), 6 deletions(-) diff --git a/services/gitdiff/gitdiff.go b/services/gitdiff/gitdiff.go index 81b92f7168..49fa77613b 100644 --- a/services/gitdiff/gitdiff.go +++ b/services/gitdiff/gitdiff.go @@ -182,6 +182,8 @@ var ( removedCodePrefix = []byte(``) codeTagSuffix = []byte(``) ) + +var unfinishedtagRegex = regexp.MustCompile(`<[^>]*$`) var trailingSpanRegex = regexp.MustCompile(`]?$`) var entityRegex = regexp.MustCompile(`&[#]*?[0-9[:alpha:]]*$`) @@ -196,10 +198,218 @@ func shouldWriteInline(diff diffmatchpatch.Diff, lineType DiffLineType) bool { return false } +func fixupBrokenSpans(diffs []diffmatchpatch.Diff) []diffmatchpatch.Diff { + + // Create a new array to store our fixed up blocks + fixedup := make([]diffmatchpatch.Diff, 0, len(diffs)) + + // semantically label some numbers + const insert, delete, equal = 0, 1, 2 + + // record the positions of the last type of each block in the fixedup blocks + last := []int{-1, -1, -1} + operation := []diffmatchpatch.Operation{diffmatchpatch.DiffInsert, diffmatchpatch.DiffDelete, diffmatchpatch.DiffEqual} + + // create a writer for insert and deletes + toWrite := []strings.Builder{ + {}, + {}, + } + + // make some flags for insert and delete + unfinishedTag := []bool{false, false} + unfinishedEnt := []bool{false, false} + + // store stores the provided text in the writer for the typ + store := func(text string, typ int) { + (&(toWrite[typ])).WriteString(text) + } + + // hasStored returns true if there is stored content + hasStored := func(typ int) bool { + return (&toWrite[typ]).Len() > 0 + } + + // stored will return that content + stored := func(typ int) string { + return (&toWrite[typ]).String() + } + + // empty will empty the stored content + empty := func(typ int) { + (&toWrite[typ]).Reset() + } + + // pop will remove the stored content appending to a diff block for that typ + pop := func(typ int, fixedup []diffmatchpatch.Diff) []diffmatchpatch.Diff { + if hasStored(typ) { + if last[typ] > last[equal] { + fixedup[last[typ]].Text += stored(typ) + } else { + fixedup = append(fixedup, diffmatchpatch.Diff{ + Type: operation[typ], + Text: stored(typ), + }) + } + empty(typ) + } + return fixedup + } + + // Now we walk the provided diffs and check the type of each block in turn + for _, diff := range diffs { + + typ := delete // flag for handling insert or delete typs + switch diff.Type { + case diffmatchpatch.DiffEqual: + // First check if there is anything stored + if hasStored(insert) || hasStored(delete) { + // There are two reasons for storing content: + // 1. Unfinished Entity <- Could be more efficient here by not doing this if we're looking for a tag + if unfinishedEnt[insert] || unfinishedEnt[delete] { + // we look for a ';' to finish an entity + idx := strings.IndexRune(diff.Text, ';') + if idx >= 0 { + // if we find a ';' store the preceding content to both insert and delete + store(diff.Text[:idx+1], insert) + store(diff.Text[:idx+1], delete) + + // and remove it from this block + diff.Text = diff.Text[idx+1:] + + // reset the ent flags + unfinishedEnt[insert] = false + unfinishedEnt[delete] = false + } else { + // otherwise store it all on insert and delete + store(diff.Text, insert) + store(diff.Text, delete) + // and empty this block + diff.Text = "" + } + } + // 2. Unfinished Tag + if unfinishedTag[insert] || unfinishedTag[delete] { + // we look for a '>' to finish a tag + idx := strings.IndexRune(diff.Text, '>') + if idx >= 0 { + store(diff.Text[:idx+1], insert) + store(diff.Text[:idx+1], delete) + diff.Text = diff.Text[idx+1:] + unfinishedTag[insert] = false + unfinishedTag[delete] = false + } else { + store(diff.Text, insert) + store(diff.Text, delete) + diff.Text = "" + } + } + + // If we've completed the required tag/entities + if !(unfinishedTag[insert] || unfinishedTag[delete] || unfinishedEnt[insert] || unfinishedEnt[delete]) { + // pop off the stack + fixedup = pop(insert, fixedup) + fixedup = pop(delete, fixedup) + } + + // If that has left this diff block empty then shortcut + if len(diff.Text) == 0 { + continue + } + } + + // check if this block ends in an unfinished tag? + idx := unfinishedtagRegex.FindStringIndex(diff.Text) + if idx != nil { + unfinishedTag[insert] = true + unfinishedTag[delete] = true + } else { + // otherwise does it end in an unfinished entity? + idx = entityRegex.FindStringIndex(diff.Text) + if idx != nil { + unfinishedEnt[insert] = true + unfinishedEnt[delete] = true + } + } + + // If there is an unfinished component + if idx != nil { + // Store the fragment + store(diff.Text[idx[0]:], insert) + store(diff.Text[idx[0]:], delete) + // and remove it from this block + diff.Text = diff.Text[:idx[0]] + } + + // If that hasn't left the block empty + if len(diff.Text) > 0 { + // store the position of the last equal block and store it in our diffs + last[equal] = len(fixedup) + fixedup = append(fixedup, diff) + } + continue + case diffmatchpatch.DiffInsert: + typ = insert + fallthrough + case diffmatchpatch.DiffDelete: + // First check if there is anything stored for this type + if hasStored(typ) { + // if there is prepend it to this block, empty the storage and reset our flags + diff.Text = stored(typ) + diff.Text + empty(typ) + unfinishedEnt[typ] = false + unfinishedTag[typ] = false + } + + // check if this block ends in an unfinished tag + idx := unfinishedtagRegex.FindStringIndex(diff.Text) + if idx != nil { + unfinishedTag[typ] = true + } else { + // otherwise does it end in an unfinished entity + idx = entityRegex.FindStringIndex(diff.Text) + if idx != nil { + unfinishedEnt[typ] = true + } + } + + // If there is an unfinished component + if idx != nil { + // Store the fragment + store(diff.Text[idx[0]:], typ) + // and remove it from this block + diff.Text = diff.Text[:idx[0]] + } + + // If that hasn't left the block empty + if len(diff.Text) > 0 { + // if the last block of this type was after the last equal block + if last[typ] > last[equal] { + // store this blocks content on that block + fixedup[last[typ]].Text += diff.Text + } else { + // otherwise store the position of the last block of this type and store the block + last[typ] = len(fixedup) + fixedup = append(fixedup, diff) + } + } + continue + } + } + + // pop off any remaining stored content + fixedup = pop(insert, fixedup) + fixedup = pop(delete, fixedup) + + return fixedup +} + func diffToHTML(fileName string, diffs []diffmatchpatch.Diff, lineType DiffLineType) template.HTML { buf := bytes.NewBuffer(nil) match := "" + diffs = fixupBrokenSpans(diffs) + for _, diff := range diffs { if shouldWriteInline(diff, lineType) { if len(match) > 0 { diff --git a/services/gitdiff/gitdiff_test.go b/services/gitdiff/gitdiff_test.go index cd7b2273cc..a832a5d94f 100644 --- a/services/gitdiff/gitdiff_test.go +++ b/services/gitdiff/gitdiff_test.go @@ -15,6 +15,7 @@ import ( "code.gitea.io/gitea/models" "code.gitea.io/gitea/modules/git" + "code.gitea.io/gitea/modules/highlight" "code.gitea.io/gitea/modules/setting" dmp "github.com/sergi/go-diff/diffmatchpatch" "github.com/stretchr/testify/assert" @@ -23,7 +24,7 @@ import ( func assertEqual(t *testing.T, s1 string, s2 template.HTML) { if s1 != string(s2) { - t.Errorf("%s should be equal %s", s2, s1) + t.Errorf("Did not receive expected results:\nExpected: %s\nActual: %s", s1, s2) } } @@ -61,7 +62,7 @@ func TestDiffToHTML(t *testing.T) { {Type: dmp.DiffEqual, Text: ")"}, }, DiffLineDel)) - assertEqual(t, "r.WrapperRenderer(w, language, true, attrs, false)", diffToHTML("", []dmp.Diff{ + assertEqual(t, "r.WrapperRenderer(w, language, true, attrs, false)", diffToHTML("", []dmp.Diff{ {Type: dmp.DiffEqual, Text: "r.WrapperRenderer(w, "}, {Type: dmp.DiffDelete, Text: "language, false)"}, }, DiffLineDel)) - assertEqual(t, "language, true, attrs, false)", diffToHTML("", []dmp.Diff{ + assertEqual(t, "language, true, attrs, false)", diffToHTML("", []dmp.Diff{ {Type: dmp.DiffInsert, Text: "language, true, attrs"}, {Type: dmp.DiffEqual, Text: ", false)"}, }, DiffLineAdd)) - assertEqual(t, "print("// ", sys.argv)", diffToHTML("", []dmp.Diff{ + assertEqual(t, "print("// ", sys.argv)", diffToHTML("", []dmp.Diff{ {Type: dmp.DiffEqual, Text: "print"}, {Type: dmp.DiffInsert, Text: ")"}, }, DiffLineAdd)) - assertEqual(t, "sh 'useradd -u $(stat -c "%u" .gitignore) jenkins'", diffToHTML("", []dmp.Diff{ + assertEqual(t, "sh 'useradd -u $(stat -c "%u" .gitignore) jenkins'", diffToHTML("", []dmp.Diff{ {Type: dmp.DiffEqual, Text: "sh "}, {Type: dmp.DiffDelete, Text: "4;useradd -u 111 jenkins""}, {Type: dmp.DiffInsert, Text: "9;useradd -u $(stat -c "%u" .gitignore) jenkins'"}, {Type: dmp.DiffEqual, Text: ";"}, }, DiffLineAdd)) - assertEqual(t, " <h4 class="release-list-title df ac">", diffToHTML("", []dmp.Diff{ + assertEqual(t, " <h4 class="release-list-title df ac">", diffToHTML("", []dmp.Diff{ {Type: dmp.DiffEqual, Text: " <h"}, {Type: dmp.DiffInsert, Text: "4 class=&#"}, {Type: dmp.DiffEqual, Text: "3"}, @@ -462,3 +463,14 @@ func TestGetDiffRangeWithWhitespaceBehavior(t *testing.T) { } } } + +func TestDiffToHTML_14231(t *testing.T) { + setting.Cfg = ini.Empty() + diffRecord := diffMatchPatch.DiffMain(highlight.Code("main.v", " run()\n"), highlight.Code("main.v", " run(db)\n"), true) + diffRecord = diffMatchPatch.DiffCleanupEfficiency(diffRecord) + + expected := ` run(db)` + output := diffToHTML("main.v", diffRecord, DiffLineAdd) + + assertEqual(t, expected, output) +} From cdff144f76a70d61a6795ffe88d691c6e2b11f47 Mon Sep 17 00:00:00 2001 From: a1012112796 <1012112796@qq.com> Date: Tue, 23 Feb 2021 07:22:49 +0800 Subject: [PATCH 147/205] Fix double alert in oauth2 application edit view (#14764) (#14768) Signed-off-by: a1012112796 <1012112796@qq.com> --- templates/user/settings/applications_oauth2_edit.tmpl | 1 - 1 file changed, 1 deletion(-) diff --git a/templates/user/settings/applications_oauth2_edit.tmpl b/templates/user/settings/applications_oauth2_edit.tmpl index c978ad5c2c..c49f7ffd9e 100644 --- a/templates/user/settings/applications_oauth2_edit.tmpl +++ b/templates/user/settings/applications_oauth2_edit.tmpl @@ -7,7 +7,6 @@ {{.i18n.Tr "settings.edit_oauth2_application"}}
- {{template "base/alert" .}}

{{.i18n.Tr "settings.oauth2_application_create_description"}}

From edef62e69ec2a54a870530a81b20a3cc7ca71dbd Mon Sep 17 00:00:00 2001 From: 6543 <6543@obermui.de> Date: Thu, 25 Feb 2021 08:49:27 +0100 Subject: [PATCH 148/205] Backport: Repo Transfer permission checks (#14792) (#14794) * Backport: Repo Transfer permission checks (#14792) * update tests --- integrations/api_repo_test.go | 2 +- routers/api/v1/repo/transfer.go | 7 ++++++- routers/repo/setting.go | 5 ++++- services/repository/transfer.go | 28 ++++++++++++++++++++++++++++ 4 files changed, 39 insertions(+), 3 deletions(-) diff --git a/integrations/api_repo_test.go b/integrations/api_repo_test.go index 1aa45984e0..7cabd51add 100644 --- a/integrations/api_repo_test.go +++ b/integrations/api_repo_test.go @@ -445,7 +445,7 @@ func TestAPIRepoTransfer(t *testing.T) { expectedStatus int }{ {ctxUserID: 1, newOwner: "user2", teams: nil, expectedStatus: http.StatusAccepted}, - {ctxUserID: 2, newOwner: "user1", teams: nil, expectedStatus: http.StatusAccepted}, + {ctxUserID: 2, newOwner: "user1", teams: nil, expectedStatus: http.StatusForbidden}, {ctxUserID: 2, newOwner: "user6", teams: nil, expectedStatus: http.StatusForbidden}, {ctxUserID: 1, newOwner: "user2", teams: &[]int64{2}, expectedStatus: http.StatusUnprocessableEntity}, {ctxUserID: 1, newOwner: "user3", teams: &[]int64{5}, expectedStatus: http.StatusForbidden}, diff --git a/routers/api/v1/repo/transfer.go b/routers/api/v1/repo/transfer.go index b1271b7721..b52f16f906 100644 --- a/routers/api/v1/repo/transfer.go +++ b/routers/api/v1/repo/transfer.go @@ -93,7 +93,12 @@ func Transfer(ctx *context.APIContext, opts api.TransferRepoOption) { } } - if err = repo_service.TransferOwnership(ctx.User, newOwner, ctx.Repo.Repository, teams); err != nil { + if err = repo_service.StartRepositoryTransfer(ctx.User, newOwner, ctx.Repo.Repository, teams); err != nil { + if models.IsErrCancelled(err) { + ctx.Error(http.StatusForbidden, "transfer", "user has no right to create repo for new owner") + return + } + ctx.InternalServerError(err) return } diff --git a/routers/repo/setting.go b/routers/repo/setting.go index e4f8adc38f..e722cd8c28 100644 --- a/routers/repo/setting.go +++ b/routers/repo/setting.go @@ -475,9 +475,12 @@ func SettingsPost(ctx *context.Context, form auth.RepoSettingForm) { ctx.Repo.GitRepo.Close() ctx.Repo.GitRepo = nil } - if err = repo_service.TransferOwnership(ctx.User, newOwner, repo, nil); err != nil { + if err = repo_service.StartRepositoryTransfer(ctx.User, newOwner, repo, nil); err != nil { if models.IsErrRepoAlreadyExist(err) { ctx.RenderWithErr(ctx.Tr("repo.settings.new_owner_has_same_repo"), tplSettingsOptions, nil) + } else if models.IsErrCancelled(err) { + // this err msg is not translated, since it was introduced in a backport + ctx.RenderWithErr("user has no right to create repo for new owner", tplSettingsOptions, nil) } else { ctx.ServerError("TransferOwnership", err) } diff --git a/services/repository/transfer.go b/services/repository/transfer.go index d34c812b86..a80f8635bb 100644 --- a/services/repository/transfer.go +++ b/services/repository/transfer.go @@ -72,3 +72,31 @@ func ChangeRepositoryName(doer *models.User, repo *models.Repository, newRepoNam return nil } + +// StartRepositoryTransfer transfer a repo from one owner to a new one. +// it make repository into pending transfer state, if doer can not create repo for new owner. +func StartRepositoryTransfer(doer, newOwner *models.User, repo *models.Repository, teams []*models.Team) error { + if repo.Status != models.RepositoryReady { + return fmt.Errorf("repository is not ready for transfer") + } + + // Admin is always allowed to transfer + if doer.IsAdmin { + return TransferOwnership(doer, newOwner, repo, teams) + } + + // If new owner is an org and user can create repos he can transfer directly too + if newOwner.IsOrganization() { + allowed, err := models.CanCreateOrgRepo(newOwner.ID, doer.ID) + if err != nil { + return err + } + if allowed { + return TransferOwnership(doer, newOwner, repo, teams) + } + } + + // Block Transfer, new feature will come in v1.14.0 + // https://github.com/go-gitea/gitea/pull/14792 + return models.ErrCancelled{} +} From 8f389c5dfae48013d215b1410664c70f31707821 Mon Sep 17 00:00:00 2001 From: 6543 <6543@obermui.de> Date: Thu, 25 Feb 2021 15:29:03 +0100 Subject: [PATCH 149/205] Build for only available darwin target (#14771) (#14798) Co-authored-by: techknowlogick --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 20decf16a6..ab5fd9a5dd 100644 --- a/Makefile +++ b/Makefile @@ -585,7 +585,7 @@ release-darwin: | $(DIST_DIRS) @hash xgo > /dev/null 2>&1; if [ $$? -ne 0 ]; then \ GO111MODULE=off $(GO) get -u src.techknowlogick.com/xgo; \ fi - CGO_CFLAGS="$(CGO_CFLAGS)" GO111MODULE=off xgo -go $(XGO_VERSION) -dest $(DIST)/binaries -tags 'netgo osusergo $(TAGS)' -ldflags '$(LDFLAGS)' -targets 'darwin/*' -out gitea-$(VERSION) . + CGO_CFLAGS="$(CGO_CFLAGS)" GO111MODULE=off xgo -go $(XGO_VERSION) -dest $(DIST)/binaries -tags 'netgo osusergo $(TAGS)' -ldflags '$(LDFLAGS)' -targets 'darwin/amd64' -out gitea-$(VERSION) . ifeq ($(CI),drone) cp /build/* $(DIST)/binaries endif From 77ce08976d74103e16ffd96df7d012abf7f69dc4 Mon Sep 17 00:00:00 2001 From: 6543 <6543@obermui.de> Date: Fri, 26 Feb 2021 10:08:09 +0100 Subject: [PATCH 150/205] Re-enable transfer repo back from org to user account (#14807) * re-enable transfer repo back from org to user account * add test case --- integrations/api_repo_test.go | 1 + services/repository/transfer.go | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/integrations/api_repo_test.go b/integrations/api_repo_test.go index 7cabd51add..8798fe0914 100644 --- a/integrations/api_repo_test.go +++ b/integrations/api_repo_test.go @@ -450,6 +450,7 @@ func TestAPIRepoTransfer(t *testing.T) { {ctxUserID: 1, newOwner: "user2", teams: &[]int64{2}, expectedStatus: http.StatusUnprocessableEntity}, {ctxUserID: 1, newOwner: "user3", teams: &[]int64{5}, expectedStatus: http.StatusForbidden}, {ctxUserID: 1, newOwner: "user3", teams: &[]int64{2}, expectedStatus: http.StatusAccepted}, + {ctxUserID: 2, newOwner: "user2", teams: nil, expectedStatus: http.StatusAccepted}, } defer prepareTestEnv(t)() diff --git a/services/repository/transfer.go b/services/repository/transfer.go index a80f8635bb..05f7a56b01 100644 --- a/services/repository/transfer.go +++ b/services/repository/transfer.go @@ -80,8 +80,8 @@ func StartRepositoryTransfer(doer, newOwner *models.User, repo *models.Repositor return fmt.Errorf("repository is not ready for transfer") } - // Admin is always allowed to transfer - if doer.IsAdmin { + // Admin is always allowed to transfer || user transfer repo back to his account + if doer.IsAdmin || doer.ID == newOwner.ID { return TransferOwnership(doer, newOwner, repo, teams) } From 90bf1e7961cf428c378e93726dcb7f2cb6da24c1 Mon Sep 17 00:00:00 2001 From: zeripath Date: Fri, 26 Feb 2021 10:44:45 +0000 Subject: [PATCH 151/205] Disable broken OAuth2 providers at startup (#14802) (#14811) Backport #14802 Instead of causing a log.Fatal, we should handle broken OAuth2 providers by disabling them. Fix #8930 Signed-off-by: Andrew Thornton Co-authored-by: techknowlogick --- models/oauth2.go | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/models/oauth2.go b/models/oauth2.go index 21a6f995c7..3869710d86 100644 --- a/models/oauth2.go +++ b/models/oauth2.go @@ -8,6 +8,7 @@ import ( "sort" "code.gitea.io/gitea/modules/auth/oauth2" + "code.gitea.io/gitea/modules/log" ) // OAuth2Provider describes the display values of a single OAuth2 provider @@ -135,7 +136,12 @@ func initOAuth2LoginSources() error { oAuth2Config := source.OAuth2() err := oauth2.RegisterProvider(source.Name, oAuth2Config.Provider, oAuth2Config.ClientID, oAuth2Config.ClientSecret, oAuth2Config.OpenIDConnectAutoDiscoveryURL, oAuth2Config.CustomURLMapping) if err != nil { - return err + log.Critical("Unable to register source: %s due to Error: %v. This source will be disabled.", source.Name, err) + source.IsActived = false + if err = UpdateSource(source); err != nil { + log.Critical("Unable to update source %s to disable it. Error: %v", err) + return err + } } } return nil From be25afc6def888f9ec83b3e8ebe1c1fed216b19a Mon Sep 17 00:00:00 2001 From: zeripath Date: Sun, 28 Feb 2021 13:19:51 +0000 Subject: [PATCH 152/205] Fix a couple of CommentAsPatch issues. (#14804) (#14820) Backport #14804 * CutDiffAroundLine makes the incorrect assumption that `---` and `+++` always represent part of the header of a diff. This PR adds a flag to its parsing to prevent this problem and adds a streaming parsing technique to CutDiffAroundLine using an io.pipe instead of just sending data to an unbounded buffer. Fix #14711 * Handle unquoted comment patch files When making comment patches unfortunately the patch does not always quote the filename This makes the diff --git header ambiguous again. This PR finally adds handling for ambiguity in to parse patch Fix #14812 * Add in testing for no error There is no way currently for CutDiffAroundLine in this test to cause an error however, it should still be tested. Signed-off-by: Andrew Thornton --- modules/git/diff.go | 30 ++++++--- modules/git/diff_test.go | 64 +++++++++++++++++-- modules/migrations/gitea_uploader.go | 22 ++++--- services/gitdiff/gitdiff.go | 95 ++++++++++++++++++++++++++-- services/gitdiff/gitdiff_test.go | 76 +++++++++++++++++++--- services/pull/review.go | 24 +++++-- 6 files changed, 270 insertions(+), 41 deletions(-) diff --git a/modules/git/diff.go b/modules/git/diff.go index 6f876e4964..6faad1c3c0 100644 --- a/modules/git/diff.go +++ b/modules/git/diff.go @@ -125,30 +125,39 @@ var hunkRegex = regexp.MustCompile(`^@@ -(?P[0-9]+)(,(?P[0-9]+ const cmdDiffHead = "diff --git " -func isHeader(lof string) bool { - return strings.HasPrefix(lof, cmdDiffHead) || strings.HasPrefix(lof, "---") || strings.HasPrefix(lof, "+++") +func isHeader(lof string, inHunk bool) bool { + return strings.HasPrefix(lof, cmdDiffHead) || (!inHunk && (strings.HasPrefix(lof, "---") || strings.HasPrefix(lof, "+++"))) } // CutDiffAroundLine cuts a diff of a file in way that only the given line + numberOfLine above it will be shown // it also recalculates hunks and adds the appropriate headers to the new diff. // Warning: Only one-file diffs are allowed. -func CutDiffAroundLine(originalDiff io.Reader, line int64, old bool, numbersOfLine int) string { +func CutDiffAroundLine(originalDiff io.Reader, line int64, old bool, numbersOfLine int) (string, error) { if line == 0 || numbersOfLine == 0 { // no line or num of lines => no diff - return "" + return "", nil } + scanner := bufio.NewScanner(originalDiff) hunk := make([]string, 0) + // begin is the start of the hunk containing searched line // end is the end of the hunk ... // currentLine is the line number on the side of the searched line (differentiated by old) // otherLine is the line number on the opposite side of the searched line (differentiated by old) var begin, end, currentLine, otherLine int64 var headerLines int + + inHunk := false + for scanner.Scan() { lof := scanner.Text() // Add header to enable parsing - if isHeader(lof) { + + if isHeader(lof, inHunk) { + if strings.HasPrefix(lof, cmdDiffHead) { + inHunk = false + } hunk = append(hunk, lof) headerLines++ } @@ -157,6 +166,7 @@ func CutDiffAroundLine(originalDiff io.Reader, line int64, old bool, numbersOfLi } // Detect "hunk" with contains commented lof if strings.HasPrefix(lof, "@@") { + inHunk = true // Already got our hunk. End of hunk detected! if len(hunk) > headerLines { break @@ -213,15 +223,19 @@ func CutDiffAroundLine(originalDiff io.Reader, line int64, old bool, numbersOfLi } } } + err := scanner.Err() + if err != nil { + return "", err + } // No hunk found if currentLine == 0 { - return "" + return "", nil } // headerLines + hunkLine (1) = totalNonCodeLines if len(hunk)-headerLines-1 <= numbersOfLine { // No need to cut the hunk => return existing hunk - return strings.Join(hunk, "\n") + return strings.Join(hunk, "\n"), nil } var oldBegin, oldNumOfLines, newBegin, newNumOfLines int64 if old { @@ -256,5 +270,5 @@ func CutDiffAroundLine(originalDiff io.Reader, line int64, old bool, numbersOfLi // construct the new hunk header newHunk[headerLines] = fmt.Sprintf("@@ -%d,%d +%d,%d @@", oldBegin, oldNumOfLines, newBegin, newNumOfLines) - return strings.Join(newHunk, "\n") + return strings.Join(newHunk, "\n"), nil } diff --git a/modules/git/diff_test.go b/modules/git/diff_test.go index 4258abfe50..363ff0b970 100644 --- a/modules/git/diff_test.go +++ b/modules/git/diff_test.go @@ -23,8 +23,28 @@ const exampleDiff = `diff --git a/README.md b/README.md + cut off + cut off` +const breakingDiff = `diff --git a/aaa.sql b/aaa.sql +index d8e4c92..19dc8ad 100644 +--- a/aaa.sql ++++ b/aaa.sql +@@ -1,9 +1,10 @@ + --some comment +--- some comment 5 ++--some coment 2 ++-- some comment 3 + create or replace procedure test(p1 varchar2) + is + begin +---new comment + dbms_output.put_line(p1); ++--some other comment + end; + / +` + func TestCutDiffAroundLine(t *testing.T) { - result := CutDiffAroundLine(strings.NewReader(exampleDiff), 4, false, 3) + result, err := CutDiffAroundLine(strings.NewReader(exampleDiff), 4, false, 3) + assert.NoError(t, err) resultByLine := strings.Split(result, "\n") assert.Len(t, resultByLine, 7) // Check if headers got transferred @@ -37,18 +57,50 @@ func TestCutDiffAroundLine(t *testing.T) { assert.Equal(t, "+ Build Status", resultByLine[4]) // Must be same result as before since old line 3 == new line 5 - newResult := CutDiffAroundLine(strings.NewReader(exampleDiff), 3, true, 3) + newResult, err := CutDiffAroundLine(strings.NewReader(exampleDiff), 3, true, 3) + assert.NoError(t, err) assert.Equal(t, result, newResult, "Must be same result as before since old line 3 == new line 5") - newResult = CutDiffAroundLine(strings.NewReader(exampleDiff), 6, false, 300) + newResult, err = CutDiffAroundLine(strings.NewReader(exampleDiff), 6, false, 300) + assert.NoError(t, err) assert.Equal(t, exampleDiff, newResult) - emptyResult := CutDiffAroundLine(strings.NewReader(exampleDiff), 6, false, 0) + emptyResult, err := CutDiffAroundLine(strings.NewReader(exampleDiff), 6, false, 0) + assert.NoError(t, err) assert.Empty(t, emptyResult) // Line is out of scope - emptyResult = CutDiffAroundLine(strings.NewReader(exampleDiff), 434, false, 0) + emptyResult, err = CutDiffAroundLine(strings.NewReader(exampleDiff), 434, false, 0) + assert.NoError(t, err) assert.Empty(t, emptyResult) + + // Handle minus diffs properly + minusDiff, err := CutDiffAroundLine(strings.NewReader(breakingDiff), 2, false, 4) + assert.NoError(t, err) + + expected := `diff --git a/aaa.sql b/aaa.sql +--- a/aaa.sql ++++ b/aaa.sql +@@ -1,9 +1,10 @@ + --some comment +--- some comment 5 ++--some coment 2` + assert.Equal(t, expected, minusDiff) + + // Handle minus diffs properly + minusDiff, err = CutDiffAroundLine(strings.NewReader(breakingDiff), 3, false, 4) + assert.NoError(t, err) + + expected = `diff --git a/aaa.sql b/aaa.sql +--- a/aaa.sql ++++ b/aaa.sql +@@ -1,9 +1,10 @@ + --some comment +--- some comment 5 ++--some coment 2 ++-- some comment 3` + + assert.Equal(t, expected, minusDiff) } func BenchmarkCutDiffAroundLine(b *testing.B) { @@ -69,7 +121,7 @@ func ExampleCutDiffAroundLine() { Docker Pulls + cut off + cut off` - result := CutDiffAroundLine(strings.NewReader(diff), 4, false, 3) + result, _ := CutDiffAroundLine(strings.NewReader(diff), 4, false, 3) println(result) } diff --git a/modules/migrations/gitea_uploader.go b/modules/migrations/gitea_uploader.go index 334ddad54f..a496aa60f4 100644 --- a/modules/migrations/gitea_uploader.go +++ b/modules/migrations/gitea_uploader.go @@ -6,7 +6,6 @@ package migrations import ( - "bytes" "context" "fmt" "io" @@ -811,13 +810,20 @@ func (g *GiteaLocalUploader) CreateReviews(reviews ...*base.Review) error { } var patch string - patchBuf := new(bytes.Buffer) - if err := git.GetRepoRawDiffForFile(g.gitRepo, pr.MergeBase, headCommitID, git.RawDiffNormal, comment.TreePath, patchBuf); err != nil { - // We should ignore the error since the commit maybe removed when force push to the pull request - log.Warn("GetRepoRawDiffForFile failed when migrating [%s, %s, %s, %s]: %v", g.gitRepo.Path, pr.MergeBase, headCommitID, comment.TreePath, err) - } else { - patch = git.CutDiffAroundLine(patchBuf, int64((&models.Comment{Line: int64(line + comment.Position - 1)}).UnsignedLine()), line < 0, setting.UI.CodeCommentLines) - } + reader, writer := io.Pipe() + defer func() { + _ = reader.Close() + _ = writer.Close() + }() + go func() { + if err := git.GetRepoRawDiffForFile(g.gitRepo, pr.MergeBase, headCommitID, git.RawDiffNormal, comment.TreePath, writer); err != nil { + // We should ignore the error since the commit maybe removed when force push to the pull request + log.Warn("GetRepoRawDiffForFile failed when migrating [%s, %s, %s, %s]: %v", g.gitRepo.Path, pr.MergeBase, headCommitID, comment.TreePath, err) + } + _ = writer.Close() + }() + + patch, _ = git.CutDiffAroundLine(reader, int64((&models.Comment{Line: int64(line + comment.Position - 1)}).UnsignedLine()), line < 0, setting.UI.CodeCommentLines) var c = models.Comment{ Type: models.CommentTypeCode, diff --git a/services/gitdiff/gitdiff.go b/services/gitdiff/gitdiff.go index 49fa77613b..beb75c05e8 100644 --- a/services/gitdiff/gitdiff.go +++ b/services/gitdiff/gitdiff.go @@ -583,6 +583,7 @@ type DiffFile struct { IsBin bool IsLFSFile bool IsRenamed bool + IsAmbiguous bool IsSubmodule bool Sections []*DiffSection IsIncomplete bool @@ -776,12 +777,32 @@ parsingLoop: if strings.HasSuffix(line, " 160000\n") { curFile.IsSubmodule = true } + case strings.HasPrefix(line, "rename from "): + curFile.IsRenamed = true + curFile.Type = DiffFileRename + if curFile.IsAmbiguous { + curFile.OldName = line[len("rename from ") : len(line)-1] + } + case strings.HasPrefix(line, "rename to "): + curFile.IsRenamed = true + curFile.Type = DiffFileRename + if curFile.IsAmbiguous { + curFile.Name = line[len("rename to ") : len(line)-1] + curFile.IsAmbiguous = false + } case strings.HasPrefix(line, "copy from "): curFile.IsRenamed = true curFile.Type = DiffFileCopy + if curFile.IsAmbiguous { + curFile.OldName = line[len("copy from ") : len(line)-1] + } case strings.HasPrefix(line, "copy to "): curFile.IsRenamed = true curFile.Type = DiffFileCopy + if curFile.IsAmbiguous { + curFile.Name = line[len("copy to ") : len(line)-1] + curFile.IsAmbiguous = false + } case strings.HasPrefix(line, "new file"): curFile.Type = DiffFileAdd curFile.IsCreated = true @@ -803,9 +824,35 @@ parsingLoop: case strings.HasPrefix(line, "Binary"): curFile.IsBin = true case strings.HasPrefix(line, "--- "): - // Do nothing with this line + // Handle ambiguous filenames + if curFile.IsAmbiguous { + if len(line) > 6 && line[4] == 'a' { + curFile.OldName = line[6 : len(line)-1] + if line[len(line)-2] == '\t' { + curFile.OldName = curFile.OldName[:len(curFile.OldName)-1] + } + } else { + curFile.OldName = "" + } + } + // Otherwise do nothing with this line case strings.HasPrefix(line, "+++ "): - // Do nothing with this line + // Handle ambiguous filenames + if curFile.IsAmbiguous { + if len(line) > 6 && line[4] == 'b' { + curFile.Name = line[6 : len(line)-1] + if line[len(line)-2] == '\t' { + curFile.Name = curFile.Name[:len(curFile.Name)-1] + } + if curFile.OldName == "" { + curFile.OldName = curFile.Name + } + } else { + curFile.Name = curFile.OldName + } + curFile.IsAmbiguous = false + } + // Otherwise do nothing with this line, but now switch to parsing hunks lineBytes, isFragment, err := parseHunks(curFile, maxLines, maxLineCharacters, input) diff.TotalAddition += curFile.Addition diff.TotalDeletion += curFile.Deletion @@ -1056,13 +1103,33 @@ func createDiffFile(diff *Diff, line string) *DiffFile { rd := strings.NewReader(line[len(cmdDiffHead):] + " ") curFile.Type = DiffFileChange - curFile.OldName = readFileName(rd) - curFile.Name = readFileName(rd) + oldNameAmbiguity := false + newNameAmbiguity := false + + curFile.OldName, oldNameAmbiguity = readFileName(rd) + curFile.Name, newNameAmbiguity = readFileName(rd) + if oldNameAmbiguity && newNameAmbiguity { + curFile.IsAmbiguous = true + // OK we should bet that the oldName and the newName are the same if they can be made to be same + // So we need to start again ... + if (len(line)-len(cmdDiffHead)-1)%2 == 0 { + // diff --git a/b b/b b/b b/b b/b b/b + // + midpoint := (len(line) + len(cmdDiffHead) - 1) / 2 + new, old := line[len(cmdDiffHead):midpoint], line[midpoint+1:] + if len(new) > 2 && len(old) > 2 && new[2:] == old[2:] { + curFile.OldName = old[2:] + curFile.Name = old[2:] + } + } + } + curFile.IsRenamed = curFile.Name != curFile.OldName return curFile } -func readFileName(rd *strings.Reader) string { +func readFileName(rd *strings.Reader) (string, bool) { + ambiguity := false var name string char, _ := rd.ReadByte() _ = rd.UnreadByte() @@ -1072,9 +1139,24 @@ func readFileName(rd *strings.Reader) string { name = name[1:] } } else { + // This technique is potentially ambiguous it may not be possible to uniquely identify the filenames from the diff line alone + ambiguity = true fmt.Fscanf(rd, "%s ", &name) + char, _ := rd.ReadByte() + _ = rd.UnreadByte() + for !(char == 0 || char == '"' || char == 'b') { + var suffix string + fmt.Fscanf(rd, "%s ", &suffix) + name += " " + suffix + char, _ = rd.ReadByte() + _ = rd.UnreadByte() + } } - return name[2:] + if len(name) < 2 { + log.Error("Unable to determine name from reader: %v", rd) + return "", true + } + return name[2:], ambiguity } // GetDiffRange builds a Diff between two commits of a repository. @@ -1185,6 +1267,7 @@ func CommentAsDiff(c *models.Comment) (*Diff, error) { diff, err := ParsePatch(setting.Git.MaxGitDiffLines, setting.Git.MaxGitDiffLineCharacters, setting.Git.MaxGitDiffFiles, strings.NewReader(c.Patch)) if err != nil { + log.Error("Unable to parse patch: %v", err) return nil, err } if len(diff.Files) == 0 { diff --git a/services/gitdiff/gitdiff_test.go b/services/gitdiff/gitdiff_test.go index a832a5d94f..2f92a01694 100644 --- a/services/gitdiff/gitdiff_test.go +++ b/services/gitdiff/gitdiff_test.go @@ -208,6 +208,66 @@ rename to a b/a a/file b/b file oldFilename: "a b/file b/a a/file", filename: "a b/a a/file b/b file", }, + { + name: "ambiguous deleted", + gitdiff: `diff --git a/b b/b b/b b/b +deleted file mode 100644 +index 92e798b..0000000 +--- a/b b/b` + "\t" + ` ++++ /dev/null +@@ -1 +0,0 @@ +-b b/b +`, + oldFilename: "b b/b", + filename: "b b/b", + addition: 0, + deletion: 1, + }, + { + name: "ambiguous addition", + gitdiff: `diff --git a/b b/b b/b b/b +new file mode 100644 +index 0000000..92e798b +--- /dev/null ++++ b/b b/b` + "\t" + ` +@@ -0,0 +1 @@ ++b b/b +`, + oldFilename: "b b/b", + filename: "b b/b", + addition: 1, + deletion: 0, + }, + { + name: "rename", + gitdiff: `diff --git a/b b/b b/b b/b b/b b/b +similarity index 100% +rename from b b/b b/b b/b b/b +rename to b +`, + oldFilename: "b b/b b/b b/b b/b", + filename: "b", + }, + { + name: "ambiguous 1", + gitdiff: `diff --git a/b b/b b/b b/b b/b b/b +similarity index 100% +rename from b b/b b/b b/b b/b +rename to b +`, + oldFilename: "b b/b b/b b/b b/b", + filename: "b", + }, + { + name: "ambiguous 2", + gitdiff: `diff --git a/b b/b b/b b/b b/b b/b +similarity index 100% +rename from b b/b b/b b/b +rename to b b/b +`, + oldFilename: "b b/b b/b b/b", + filename: "b b/b", + }, { name: "minuses-and-pluses", gitdiff: `diff --git a/minuses-and-pluses b/minuses-and-pluses @@ -235,32 +295,32 @@ index 6961180..9ba1a00 100644 t.Run(testcase.name, func(t *testing.T) { got, err := ParsePatch(setting.Git.MaxGitDiffLines, setting.Git.MaxGitDiffLineCharacters, setting.Git.MaxGitDiffFiles, strings.NewReader(testcase.gitdiff)) if (err != nil) != testcase.wantErr { - t.Errorf("ParsePatch() error = %v, wantErr %v", err, testcase.wantErr) + t.Errorf("ParsePatch(%q) error = %v, wantErr %v", testcase.name, err, testcase.wantErr) return } gotMarshaled, _ := json.MarshalIndent(got, " ", " ") if got.NumFiles != 1 { - t.Errorf("ParsePath() did not receive 1 file:\n%s", string(gotMarshaled)) + t.Errorf("ParsePath(%q) did not receive 1 file:\n%s", testcase.name, string(gotMarshaled)) return } if got.TotalAddition != testcase.addition { - t.Errorf("ParsePath() does not have correct totalAddition %d, wanted %d", got.TotalAddition, testcase.addition) + t.Errorf("ParsePath(%q) does not have correct totalAddition %d, wanted %d", testcase.name, got.TotalAddition, testcase.addition) } if got.TotalDeletion != testcase.deletion { - t.Errorf("ParsePath() did not have correct totalDeletion %d, wanted %d", got.TotalDeletion, testcase.deletion) + t.Errorf("ParsePath(%q) did not have correct totalDeletion %d, wanted %d", testcase.name, got.TotalDeletion, testcase.deletion) } file := got.Files[0] if file.Addition != testcase.addition { - t.Errorf("ParsePath() does not have correct file addition %d, wanted %d", file.Addition, testcase.addition) + t.Errorf("ParsePath(%q) does not have correct file addition %d, wanted %d", testcase.name, file.Addition, testcase.addition) } if file.Deletion != testcase.deletion { - t.Errorf("ParsePath() did not have correct file deletion %d, wanted %d", file.Deletion, testcase.deletion) + t.Errorf("ParsePath(%q) did not have correct file deletion %d, wanted %d", testcase.name, file.Deletion, testcase.deletion) } if file.OldName != testcase.oldFilename { - t.Errorf("ParsePath() did not have correct OldName %s, wanted %s", file.OldName, testcase.oldFilename) + t.Errorf("ParsePath(%q) did not have correct OldName %q, wanted %q", testcase.name, file.OldName, testcase.oldFilename) } if file.Name != testcase.filename { - t.Errorf("ParsePath() did not have correct Name %s, wanted %s", file.Name, testcase.filename) + t.Errorf("ParsePath(%q) did not have correct Name %q, wanted %q", testcase.name, file.Name, testcase.filename) } }) } diff --git a/services/pull/review.go b/services/pull/review.go index 8994a9e78a..08168fa40a 100644 --- a/services/pull/review.go +++ b/services/pull/review.go @@ -6,13 +6,14 @@ package pull import ( - "bytes" "fmt" + "io" "regexp" "strings" "code.gitea.io/gitea/models" "code.gitea.io/gitea/modules/git" + "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/notification" "code.gitea.io/gitea/modules/setting" ) @@ -179,11 +180,24 @@ func createCodeComment(doer *models.User, repo *models.Repository, issue *models if len(commitID) == 0 { commitID = headCommitID } - patchBuf := new(bytes.Buffer) - if err := git.GetRepoRawDiffForFile(gitRepo, pr.MergeBase, headCommitID, git.RawDiffNormal, treePath, patchBuf); err != nil { - return nil, fmt.Errorf("GetRawDiffForLine[%s, %s, %s, %s]: %v", gitRepo.Path, pr.MergeBase, headCommitID, treePath, err) + reader, writer := io.Pipe() + defer func() { + _ = reader.Close() + _ = writer.Close() + }() + go func() { + if err := git.GetRepoRawDiffForFile(gitRepo, pr.MergeBase, headCommitID, git.RawDiffNormal, treePath, writer); err != nil { + _ = writer.CloseWithError(fmt.Errorf("GetRawDiffForLine[%s, %s, %s, %s]: %v", gitRepo.Path, pr.MergeBase, headCommitID, treePath, err)) + return + } + _ = writer.Close() + }() + + patch, err = git.CutDiffAroundLine(reader, int64((&models.Comment{Line: line}).UnsignedLine()), line < 0, setting.UI.CodeCommentLines) + if err != nil { + log.Error("Error whilst generating patch: %v", err) + return nil, err } - patch = git.CutDiffAroundLine(patchBuf, int64((&models.Comment{Line: line}).UnsignedLine()), line < 0, setting.UI.CodeCommentLines) } return models.CreateComment(&models.CreateCommentOptions{ Type: models.CommentTypeCode, From 4558eeb21a8249fc6d89d2b05d134bcfde6aaac6 Mon Sep 17 00:00:00 2001 From: zeripath Date: Mon, 1 Mar 2021 15:12:48 +0000 Subject: [PATCH 153/205] Set HCaptchaSiteKey on Link Account pages (#14834) (#14839) Backport #14834 When using HCaptcha on link account pages the site key needs to be passed in. This PR ensures that HCaptchaSiteKey is set in the data. Fix #14766 Signed-off-by: Andrew Thornton --- routers/user/auth.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/routers/user/auth.go b/routers/user/auth.go index c5542456a1..6544c51f88 100644 --- a/routers/user/auth.go +++ b/routers/user/auth.go @@ -746,6 +746,7 @@ func LinkAccount(ctx *context.Context) { ctx.Data["CaptchaType"] = setting.Service.CaptchaType ctx.Data["RecaptchaURL"] = setting.Service.RecaptchaURL ctx.Data["RecaptchaSitekey"] = setting.Service.RecaptchaSitekey + ctx.Data["HcaptchaSitekey"] = setting.Service.HcaptchaSitekey ctx.Data["DisableRegistration"] = setting.Service.DisableRegistration ctx.Data["ShowRegistrationButton"] = false @@ -797,6 +798,7 @@ func LinkAccountPostSignIn(ctx *context.Context, signInForm auth.SignInForm) { ctx.Data["RecaptchaURL"] = setting.Service.RecaptchaURL ctx.Data["CaptchaType"] = setting.Service.CaptchaType ctx.Data["RecaptchaSitekey"] = setting.Service.RecaptchaSitekey + ctx.Data["HcaptchaSitekey"] = setting.Service.HcaptchaSitekey ctx.Data["DisableRegistration"] = setting.Service.DisableRegistration ctx.Data["ShowRegistrationButton"] = false @@ -881,6 +883,7 @@ func LinkAccountPostRegister(ctx *context.Context, cpt *captcha.Captcha, form au ctx.Data["RecaptchaURL"] = setting.Service.RecaptchaURL ctx.Data["CaptchaType"] = setting.Service.CaptchaType ctx.Data["RecaptchaSitekey"] = setting.Service.RecaptchaSitekey + ctx.Data["HcaptchaSitekey"] = setting.Service.HcaptchaSitekey ctx.Data["DisableRegistration"] = setting.Service.DisableRegistration ctx.Data["ShowRegistrationButton"] = false From d9d2e8f1e840c990259d911c634780d1644233cd Mon Sep 17 00:00:00 2001 From: zeripath Date: Tue, 2 Mar 2021 13:44:14 +0000 Subject: [PATCH 154/205] When Deleting Repository only explicitly close PRs whose base is not this repository (#14823) (#14842) Backport #14823 When Deleting Repository only explicitly close PRs whose base is not this repository Fix #14775 Signed-off-by: Andrew Thornton --- services/pull/pull.go | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/services/pull/pull.go b/services/pull/pull.go index c3c9b9f930..0b753e4689 100644 --- a/services/pull/pull.go +++ b/services/pull/pull.go @@ -475,7 +475,7 @@ func CloseBranchPulls(doer *models.User, repoID int64, branch string) error { return nil } -// CloseRepoBranchesPulls close all pull requests which head branches are in the given repository +// CloseRepoBranchesPulls close all pull requests which head branches are in the given repository, but only whose base repo is not in the given repository func CloseRepoBranchesPulls(doer *models.User, repo *models.Repository) error { branches, err := git.GetBranchesByPath(repo.RepoPath()) if err != nil { @@ -494,6 +494,11 @@ func CloseRepoBranchesPulls(doer *models.User, repo *models.Repository) error { } for _, pr := range prs { + // If the base repository for this pr is this repository there is no need to close it + // as it is going to be deleted anyway + if pr.BaseRepoID == repo.ID { + continue + } if err = issue_service.ChangeStatus(pr.Issue, doer, true); err != nil && !models.IsErrPullWasClosed(err) { errs = append(errs, err) } From 26628aa1d1bdacdbbca97d7dd2dca11972cde1c7 Mon Sep 17 00:00:00 2001 From: zeripath Date: Wed, 3 Mar 2021 21:17:34 +0000 Subject: [PATCH 155/205] Fix display since time round (#14226) (#14873) Backport #14226 * Fix display since time round * Fix since time * Fix tests Co-authored-by: Lunny Xiao --- modules/timeutil/since.go | 97 +++++++++++++++++++++++++++++++++- modules/timeutil/since_test.go | 92 ++++++++++++++++++++------------ 2 files changed, 152 insertions(+), 37 deletions(-) diff --git a/modules/timeutil/since.go b/modules/timeutil/since.go index e6c29c19ff..c0240907ae 100644 --- a/modules/timeutil/since.go +++ b/modules/timeutil/since.go @@ -7,6 +7,7 @@ package timeutil import ( "fmt" "html/template" + "math" "strings" "time" @@ -25,7 +26,11 @@ const ( Year = 12 * Month ) -func computeTimeDiff(diff int64, lang string) (int64, string) { +func round(s float64) int64 { + return int64(math.Round(s)) +} + +func computeTimeDiffFloor(diff int64, lang string) (int64, string) { diffStr := "" switch { case diff <= 0: @@ -83,6 +88,94 @@ func computeTimeDiff(diff int64, lang string) (int64, string) { return diff, diffStr } +func computeTimeDiff(diff int64, lang string) (int64, string) { + diffStr := "" + switch { + case diff <= 0: + diff = 0 + diffStr = i18n.Tr(lang, "tool.now") + case diff < 2: + diff = 0 + diffStr = i18n.Tr(lang, "tool.1s") + case diff < 1*Minute: + diffStr = i18n.Tr(lang, "tool.seconds", diff) + diff = 0 + + case diff < Minute+Minute/2: + diff -= 1 * Minute + diffStr = i18n.Tr(lang, "tool.1m") + case diff < 1*Hour: + minutes := round(float64(diff) / Minute) + if minutes > 1 { + diffStr = i18n.Tr(lang, "tool.minutes", minutes) + } else { + diffStr = i18n.Tr(lang, "tool.1m") + } + diff -= diff / Minute * Minute + + case diff < Hour+Hour/2: + diff -= 1 * Hour + diffStr = i18n.Tr(lang, "tool.1h") + case diff < 1*Day: + hours := round(float64(diff) / Hour) + if hours > 1 { + diffStr = i18n.Tr(lang, "tool.hours", hours) + } else { + diffStr = i18n.Tr(lang, "tool.1h") + } + diff -= diff / Hour * Hour + + case diff < Day+Day/2: + diff -= 1 * Day + diffStr = i18n.Tr(lang, "tool.1d") + case diff < 1*Week: + days := round(float64(diff) / Day) + if days > 1 { + diffStr = i18n.Tr(lang, "tool.days", days) + } else { + diffStr = i18n.Tr(lang, "tool.1d") + } + diff -= diff / Day * Day + + case diff < Week+Week/2: + diff -= 1 * Week + diffStr = i18n.Tr(lang, "tool.1w") + case diff < 1*Month: + weeks := round(float64(diff) / Week) + if weeks > 1 { + diffStr = i18n.Tr(lang, "tool.weeks", weeks) + } else { + diffStr = i18n.Tr(lang, "tool.1w") + } + diff -= diff / Week * Week + + case diff < 1*Month+Month/2: + diff -= 1 * Month + diffStr = i18n.Tr(lang, "tool.1mon") + case diff < 1*Year: + months := round(float64(diff) / Month) + if months > 1 { + diffStr = i18n.Tr(lang, "tool.months", months) + } else { + diffStr = i18n.Tr(lang, "tool.1mon") + } + diff -= diff / Month * Month + + case diff < Year+Year/2: + diff -= 1 * Year + diffStr = i18n.Tr(lang, "tool.1y") + default: + years := round(float64(diff) / Year) + if years > 1 { + diffStr = i18n.Tr(lang, "tool.years", years) + } else { + diffStr = i18n.Tr(lang, "tool.1y") + } + diff -= (diff / Year) * Year + } + return diff, diffStr +} + // MinutesToFriendly returns a user friendly string with number of minutes // converted to hours and minutes. func MinutesToFriendly(minutes int, lang string) string { @@ -111,7 +204,7 @@ func timeSincePro(then, now time.Time, lang string) string { break } - diff, diffStr = computeTimeDiff(diff, lang) + diff, diffStr = computeTimeDiffFloor(diff, lang) timeStr += ", " + diffStr } return strings.TrimPrefix(timeStr, ", ") diff --git a/modules/timeutil/since_test.go b/modules/timeutil/since_test.go index 65d481a6aa..f65940d6df 100644 --- a/modules/timeutil/since_test.go +++ b/modules/timeutil/since_test.go @@ -5,6 +5,7 @@ package timeutil import ( + "fmt" "os" "testing" "time" @@ -47,27 +48,39 @@ func TestTimeSince(t *testing.T) { // test that each diff in `diffs` yields the expected string test := func(expected string, diffs ...time.Duration) { - for _, diff := range diffs { - actual := timeSince(BaseDate, BaseDate.Add(diff), "en") - assert.Equal(t, i18n.Tr("en", "tool.ago", expected), actual) - actual = timeSince(BaseDate.Add(diff), BaseDate, "en") - assert.Equal(t, i18n.Tr("en", "tool.from_now", expected), actual) - } + t.Run(expected, func(t *testing.T) { + for _, diff := range diffs { + actual := timeSince(BaseDate, BaseDate.Add(diff), "en") + assert.Equal(t, i18n.Tr("en", "tool.ago", expected), actual) + actual = timeSince(BaseDate.Add(diff), BaseDate, "en") + assert.Equal(t, i18n.Tr("en", "tool.from_now", expected), actual) + } + }) } test("1 second", time.Second, time.Second+50*time.Millisecond) test("2 seconds", 2*time.Second, 2*time.Second+50*time.Millisecond) - test("1 minute", time.Minute, time.Minute+30*time.Second) - test("2 minutes", 2*time.Minute, 2*time.Minute+30*time.Second) - test("1 hour", time.Hour, time.Hour+30*time.Minute) - test("2 hours", 2*time.Hour, 2*time.Hour+30*time.Minute) - test("1 day", DayDur, DayDur+12*time.Hour) - test("2 days", 2*DayDur, 2*DayDur+12*time.Hour) + test("1 minute", time.Minute, time.Minute+29*time.Second) + test("2 minutes", 2*time.Minute, time.Minute+30*time.Second) + test("2 minutes", 2*time.Minute, 2*time.Minute+29*time.Second) + test("1 hour", time.Hour, time.Hour+29*time.Minute) + test("2 hours", 2*time.Hour, time.Hour+30*time.Minute) + test("2 hours", 2*time.Hour, 2*time.Hour+29*time.Minute) + test("3 hours", 3*time.Hour, 2*time.Hour+30*time.Minute) + test("1 day", DayDur, DayDur+11*time.Hour) + test("2 days", 2*DayDur, DayDur+12*time.Hour) + test("2 days", 2*DayDur, 2*DayDur+11*time.Hour) + test("3 days", 3*DayDur, 2*DayDur+12*time.Hour) test("1 week", WeekDur, WeekDur+3*DayDur) + test("2 weeks", 2*WeekDur, WeekDur+4*DayDur) test("2 weeks", 2*WeekDur, 2*WeekDur+3*DayDur) - test("1 month", MonthDur, MonthDur+15*DayDur) - test("2 months", 2*MonthDur, 2*MonthDur+15*DayDur) - test("1 year", YearDur, YearDur+6*MonthDur) - test("2 years", 2*YearDur, 2*YearDur+6*MonthDur) + test("3 weeks", 3*WeekDur, 2*WeekDur+4*DayDur) + test("1 month", MonthDur, MonthDur+14*DayDur) + test("2 months", 2*MonthDur, MonthDur+15*DayDur) + test("2 months", 2*MonthDur, 2*MonthDur+14*DayDur) + test("1 year", YearDur, YearDur+5*MonthDur) + test("2 years", 2*YearDur, YearDur+6*MonthDur) + test("2 years", 2*YearDur, 2*YearDur+5*MonthDur) + test("3 years", 3*YearDur, 2*YearDur+6*MonthDur) } func TestTimeSincePro(t *testing.T) { @@ -114,11 +127,11 @@ func TestHtmlTimeSince(t *testing.T) { } test("1 second", time.Second) test("3 minutes", 3*time.Minute+5*time.Second) - test("1 day", DayDur+18*time.Hour) - test("1 week", WeekDur+6*DayDur) - test("3 months", 3*MonthDur+3*WeekDur) + test("1 day", DayDur+11*time.Hour) + test("1 week", WeekDur+3*DayDur) + test("3 months", 3*MonthDur+2*WeekDur) test("2 years", 2*YearDur) - test("3 years", 3*YearDur+11*MonthDur+4*WeekDur) + test("3 years", 2*YearDur+11*MonthDur+4*WeekDur) } func TestComputeTimeDiff(t *testing.T) { @@ -126,26 +139,35 @@ func TestComputeTimeDiff(t *testing.T) { // computeTimeDiff(base + offset) == (offset, str) test := func(base int64, str string, offsets ...int64) { for _, offset := range offsets { - diff, diffStr := computeTimeDiff(base+offset, "en") - assert.Equal(t, offset, diff) - assert.Equal(t, str, diffStr) + t.Run(fmt.Sprintf("%s:%d", str, offset), func(t *testing.T) { + diff, diffStr := computeTimeDiff(base+offset, "en") + assert.Equal(t, offset, diff) + assert.Equal(t, str, diffStr) + }) } } test(0, "now", 0) test(1, "1 second", 0) test(2, "2 seconds", 0) - test(Minute, "1 minute", 0, 1, 30, Minute-1) - test(2*Minute, "2 minutes", 0, Minute-1) - test(Hour, "1 hour", 0, 1, Hour-1) - test(5*Hour, "5 hours", 0, Hour-1) - test(Day, "1 day", 0, 1, Day-1) - test(5*Day, "5 days", 0, Day-1) - test(Week, "1 week", 0, 1, Week-1) - test(3*Week, "3 weeks", 0, 4*Day+25000) - test(Month, "1 month", 0, 1, Month-1) - test(10*Month, "10 months", 0, Month-1) - test(Year, "1 year", 0, Year-1) - test(3*Year, "3 years", 0, Year-1) + test(Minute, "1 minute", 0, 1, 29) + test(Minute, "2 minutes", 30, Minute-1) + test(2*Minute, "2 minutes", 0, 29) + test(2*Minute, "3 minutes", 30, Minute-1) + test(Hour, "1 hour", 0, 1, 29*Minute) + test(Hour, "2 hours", 30*Minute, Hour-1) + test(5*Hour, "5 hours", 0, 29*Minute) + test(Day, "1 day", 0, 1, 11*Hour) + test(Day, "2 days", 12*Hour, Day-1) + test(5*Day, "5 days", 0, 11*Hour) + test(Week, "1 week", 0, 1, 3*Day) + test(Week, "2 weeks", 4*Day, Week-1) + test(3*Week, "3 weeks", 0, 3*Day) + test(Month, "1 month", 0, 1) + test(Month, "2 months", 16*Day, Month-1) + test(10*Month, "10 months", 0, 13*Day) + test(Year, "1 year", 0, 179*Day) + test(Year, "2 years", 180*Day, Year-1) + test(3*Year, "3 years", 0, 179*Day) } func TestMinutesToFriendly(t *testing.T) { From 7e85cba3e500c8548e7e21ad61bbb4c092c16503 Mon Sep 17 00:00:00 2001 From: 6543 <6543@obermui.de> Date: Wed, 3 Mar 2021 22:54:32 +0100 Subject: [PATCH 156/205] Print usefull error if SQLite is used in settings but not supported (#14476) (#14874) * move log output to points where they are relefant * check explicit of sqlite3 in settings --- routers/init.go | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/routers/init.go b/routers/init.go index 608db79cb0..8265c55852 100644 --- a/routers/init.go +++ b/routers/init.go @@ -133,12 +133,19 @@ func GlobalInit(ctx context.Context) { log.Trace("AppWorkPath: %s", setting.AppWorkPath) log.Trace("Custom path: %s", setting.CustomPath) log.Trace("Log path: %s", setting.LogRootPath) + checkRunMode() // Setup i18n InitLocales() NewServices() + if setting.EnableSQLite3 { + log.Info("SQLite3 Supported") + } else if setting.Database.UseSQLite3 { + log.Fatal("SQLite3 is set in settings but NOT Supported") + } + if setting.InstallLock { highlight.NewContext() external.RegisterParsers() @@ -172,10 +179,6 @@ func GlobalInit(ctx context.Context) { } eventsource.GetManager().Init() } - if setting.EnableSQLite3 { - log.Info("SQLite3 Supported") - } - checkRunMode() if err := repo_migrations.Init(); err != nil { log.Fatal("Failed to initialize repository migrations: %v", err) From e663f7459a85ea73e1b0501a18071112a0ed4fee Mon Sep 17 00:00:00 2001 From: zeripath Date: Thu, 4 Mar 2021 11:53:28 +0000 Subject: [PATCH 157/205] Fix paging of file commit logs (#14831) (#14879) Backport #14831 Unfortunately `git log revision ... --skip=x -- path` skips the number of commits not the number of commits relating to the path. This PR changes the function to have a reader that reads and skips the necessary number of commits by hand instead. Fix #8716 Signed-off-by: Andrew Thornton Co-authored-by: 6543 <6543@obermui.de> Co-authored-by: 6543 <6543@obermui.de> --- modules/git/repo_commit.go | 39 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 37 insertions(+), 2 deletions(-) diff --git a/modules/git/repo_commit.go b/modules/git/repo_commit.go index a00e59edb8..70fe6fbcdb 100644 --- a/modules/git/repo_commit.go +++ b/modules/git/repo_commit.go @@ -9,6 +9,8 @@ import ( "bytes" "container/list" "fmt" + "io" + "io/ioutil" "strconv" "strings" @@ -327,8 +329,41 @@ func (repo *Repository) FileCommitsCount(revision, file string) (int64, error) { // CommitsByFileAndRange return the commits according revison file and the page func (repo *Repository) CommitsByFileAndRange(revision, file string, page int) (*list.List, error) { - stdout, err := NewCommand("log", revision, "--follow", "--skip="+strconv.Itoa((page-1)*50), - "--max-count="+strconv.Itoa(CommitsRangeSize), prettyLogFormat, "--", file).RunInDirBytes(repo.Path) + skip := (page - 1) * CommitsRangeSize + + stdoutReader, stdoutWriter := io.Pipe() + defer func() { + _ = stdoutReader.Close() + _ = stdoutWriter.Close() + }() + go func() { + stderr := strings.Builder{} + err := NewCommand("log", revision, "--follow", + "--max-count="+strconv.Itoa(CommitsRangeSize*page), + prettyLogFormat, "--", file). + RunInDirPipeline(repo.Path, stdoutWriter, &stderr) + if err != nil { + if stderr.Len() > 0 { + err = fmt.Errorf("%v - %s", err, stderr.String()) + } + _ = stdoutWriter.CloseWithError(err) + } else { + _ = stdoutWriter.Close() + } + }() + + if skip > 0 { + _, err := io.CopyN(ioutil.Discard, stdoutReader, int64(skip*41)) + if err != nil { + if err == io.EOF { + return list.New(), nil + } + _ = stdoutReader.CloseWithError(err) + return nil, err + } + } + + stdout, err := ioutil.ReadAll(stdoutReader) if err != nil { return nil, err } From 98b3d8d5e178807c770298f39624e78facbb8017 Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Thu, 4 Mar 2021 22:42:57 +0800 Subject: [PATCH 158/205] Add changelog for v1.13.3 (#14877) Add changelog for v1.13.3 Co-authored-by: zeripath Co-authored-by: 6543 <6543@obermui.de> Co-authored-by: techknowlogick --- CHANGELOG.md | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 553db3c07c..f0c90c655b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,29 @@ This changelog goes through all the changes that have been made in each release without substantial changes to our git log; to see the highlights of what has been added to each release, please refer to the [blog](https://blog.gitea.io). +## [1.13.3](https://github.com/go-gitea/gitea/releases/tag/v1.13.3) - 2021-03-04 + +* BREAKING + * Turn default hash password algorithm back to pbkdf2 from argon2 until we find a better one (#14673) (#14675) +* BUGFIXES + * Fix paging of file commit logs (#14831) (#14879) + * Print useful error if SQLite is used in settings but not supported (#14476) (#14874) + * Fix display since time round (#14226) (#14873) + * When Deleting Repository only explicitly close PRs whose base is not this repository (#14823) (#14842) + * Set HCaptchaSiteKey on Link Account pages (#14834) (#14839) + * Fix a couple of CommentAsPatch issues. (#14804) (#14820) + * Disable broken OAuth2 providers at startup (#14802) (#14811) + * Repo Transfer permission checks (#14792) (#14794) + * Fix double alert in oauth2 application edit view (#14764) (#14768) + * Fix broken spans in diffs (#14678) (#14683) + * Prevent race in PersistableChannelUniqueQueue.Has (#14651) (#14676) + * HasPreviousCommit causes recursive load of commits unnecessarily (#14598) (#14649) + * Do not assume all 40 char strings are SHA1s (#14624) (#14648) + * Allow org labels to be set with issue templates (#14593) (#14647) + * Accept multiple SSH keys in single LDAP SSHPublicKey attribute (#13989) (#14607) + * Fix bug about ListOptions and stars/watchers pagnation (#14556) (#14573) + * Fix GPG key deletion during account deletion (#14561) (#14569) + ## [1.13.2](https://github.com/go-gitea/gitea/releases/tag/v1.13.2) - 2021-01-31 * SECURITY From 8a6acbbc129c41bad4663e7ab3d89fd76b818981 Mon Sep 17 00:00:00 2001 From: 6543 <6543@obermui.de> Date: Thu, 4 Mar 2021 21:28:28 +0100 Subject: [PATCH 159/205] IsUserAllowedToUpdate should igonre if user is nil (#14886) --- services/pull/update.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/services/pull/update.go b/services/pull/update.go index 0829b1c5d6..f4f7859a49 100644 --- a/services/pull/update.go +++ b/services/pull/update.go @@ -48,6 +48,9 @@ func Update(pull *models.PullRequest, doer *models.User, message string) error { // IsUserAllowedToUpdate check if user is allowed to update PR with given permissions and branch protections func IsUserAllowedToUpdate(pull *models.PullRequest, user *models.User) (bool, error) { + if user == nil { + return false, nil + } headRepoPerm, err := models.GetUserRepoPermission(pull.HeadRepo, user) if err != nil { return false, err From 8456700411d1caaefe8a07c24aa71ae03d8e28f1 Mon Sep 17 00:00:00 2001 From: 6543 <6543@obermui.de> Date: Thu, 4 Mar 2021 22:10:15 +0100 Subject: [PATCH 160/205] [Docs] Fix how lfs data path is set (#14855) (#14884) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix docs: lfs data path * DEPRECATED | 已废弃 Co-authored-by: techknowlogick Co-authored-by: Lunny Xiao --- docs/content/doc/advanced/config-cheat-sheet.en-us.md | 4 ++-- docs/content/doc/advanced/config-cheat-sheet.zh-cn.md | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/docs/content/doc/advanced/config-cheat-sheet.en-us.md b/docs/content/doc/advanced/config-cheat-sheet.en-us.md index 77464a509a..4d88f2f102 100644 --- a/docs/content/doc/advanced/config-cheat-sheet.en-us.md +++ b/docs/content/doc/advanced/config-cheat-sheet.en-us.md @@ -276,7 +276,7 @@ Values containing `#` or `;` must be quoted using `` ` `` or `"""`. - `LANDING_PAGE`: **home**: Landing page for unauthenticated users \[home, explore, organizations, login\]. - `LFS_START_SERVER`: **false**: Enables git-lfs support. -- `LFS_CONTENT_PATH`: **%(APP_DATA_PATH)/lfs**: Default LFS content path. (if it is on local storage.) +- `LFS_CONTENT_PATH`: **%(APP_DATA_PATH)/lfs**: DEPRECATED: Default LFS content path. (if it is on local storage.) - `LFS_JWT_SECRET`: **\**: LFS authentication secret, change this a unique string. - `LFS_HTTP_AUTH_EXPIRY`: **20m**: LFS authentication validity period in time.Duration, pushes taking longer than this may fail. - `LFS_MAX_FILE_SIZE`: **0**: Maximum allowed LFS file size in bytes (Set to 0 for no limit). @@ -828,7 +828,7 @@ is `data/lfs` and the default of `MINIO_BASE_PATH` is `lfs/`. - `STORAGE_TYPE`: **local**: Storage type for lfs, `local` for local disk or `minio` for s3 compatible object storage service or other name defined with `[storage.xxx]` - `SERVE_DIRECT`: **false**: Allows the storage driver to redirect to authenticated URLs to serve files directly. Currently, only Minio/S3 is supported via signed URLs, local does nothing. -- `CONTENT_PATH`: **./data/lfs**: Where to store LFS files, only available when `STORAGE_TYPE` is `local`. +- `PATH`: **./data/lfs**: Where to store LFS files, only available when `STORAGE_TYPE` is `local`. If not set it fall back to deprecated LFS_CONTENT_PATH value in [server] section. - `MINIO_ENDPOINT`: **localhost:9000**: Minio endpoint to connect only available when `STORAGE_TYPE` is `minio` - `MINIO_ACCESS_KEY_ID`: Minio accessKeyID to connect only available when `STORAGE_TYPE` is `minio` - `MINIO_SECRET_ACCESS_KEY`: Minio secretAccessKey to connect only available when `STORAGE_TYPE is` `minio` diff --git a/docs/content/doc/advanced/config-cheat-sheet.zh-cn.md b/docs/content/doc/advanced/config-cheat-sheet.zh-cn.md index 597773a0ae..25d24c90bd 100644 --- a/docs/content/doc/advanced/config-cheat-sheet.zh-cn.md +++ b/docs/content/doc/advanced/config-cheat-sheet.zh-cn.md @@ -73,6 +73,7 @@ menu: - `LFS_START_SERVER`: 是否启用 git-lfs 支持. 可以为 `true` 或 `false`, 默认是 `false`。 - `LFS_JWT_SECRET`: LFS 认证密钥,改成自己的。 +- `LFS_CONTENT_PATH`: **已废弃**, 存放 lfs 命令上传的文件的地方,默认是 `data/lfs`。 ## Database (`database`) @@ -323,7 +324,7 @@ LFS 的存储配置。 如果 `STORAGE_TYPE` 为空,则此配置将从 `[stora - `STORAGE_TYPE`: **local**: LFS 的存储类型,`local` 将存储到磁盘,`minio` 将存储到 s3 兼容的对象服务。 - `SERVE_DIRECT`: **false**: 允许直接重定向到存储系统。当前,仅 Minio/S3 是支持的。 -- `CONTENT_PATH`: 存放 lfs 命令上传的文件的地方,默认是 `data/lfs`。 +- `PATH`: 存放 lfs 命令上传的文件的地方,默认是 `data/lfs`。 - `MINIO_ENDPOINT`: **localhost:9000**: Minio 地址,仅当 `LFS_STORAGE_TYPE` 为 `minio` 时有效。 - `MINIO_ACCESS_KEY_ID`: Minio accessKeyID,仅当 `LFS_STORAGE_TYPE` 为 `minio` 时有效。 - `MINIO_SECRET_ACCESS_KEY`: Minio secretAccessKey,仅当 `LFS_STORAGE_TYPE` 为 `minio` 时有效。 From 7d3e174906a24552f32ea5215910bab9cebeafa4 Mon Sep 17 00:00:00 2001 From: John Olheiser Date: Fri, 5 Mar 2021 15:54:01 -0600 Subject: [PATCH 161/205] Signed-off-by: jolheiser (#14898) (#14899) --- web_src/js/features/contextpopup.js | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/web_src/js/features/contextpopup.js b/web_src/js/features/contextpopup.js index a9a0ceee3b..c16820cf1f 100644 --- a/web_src/js/features/contextpopup.js +++ b/web_src/js/features/contextpopup.js @@ -1,3 +1,4 @@ +import {htmlEscape} from 'escape-goat'; import {svg} from '../svg.js'; const {AppSubUrl} = window.config; @@ -31,7 +32,7 @@ function issuePopup(owner, repo, index, $element) { if ((red * 0.299 + green * 0.587 + blue * 0.114) > 125) { color = '#000000'; } - labels += `
${label.name}
`; + labels += `
${htmlEscape(label.name)}
`; } if (labels.length > 0) { labels = `

${labels}

`; @@ -64,9 +65,9 @@ function issuePopup(owner, repo, index, $element) { }, html: `
-

${issue.repository.full_name} on ${createdAt}

-

${svg(octicon)} ${issue.title} #${index}

-

${body}

+

${htmlEscape(issue.repository.full_name)} on ${createdAt}

+

${svg(octicon)} ${htmlEscape(issue.title)} #${index}

+

${htmlEscape(body)}

${labels}
` From 74dc22358b1935024c03f51013283af562293729 Mon Sep 17 00:00:00 2001 From: 6543 <6543@obermui.de> Date: Sat, 6 Mar 2021 04:12:11 +0100 Subject: [PATCH 162/205] When transfering repository and database transaction failed, rollback the renames (#14864) (#14902) Fix #14821 Co-authored-by: Andrew Thornton Co-authored-by: 6543 <6543@obermui.de> Co-authored-by: Lunny Xiao Co-authored-by: Andrew Thornton --- models/repo.go | 48 ++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 42 insertions(+), 6 deletions(-) diff --git a/models/repo.go b/models/repo.go index c11265f938..8c6d8b9ee3 100644 --- a/models/repo.go +++ b/models/repo.go @@ -1290,11 +1290,44 @@ func IncrementRepoForkNum(ctx DBContext, repoID int64) error { } // TransferOwnership transfers all corresponding setting from old user to new one. -func TransferOwnership(doer *User, newOwnerName string, repo *Repository) error { +func TransferOwnership(doer *User, newOwnerName string, repo *Repository) (err error) { + repoRenamed := false + wikiRenamed := false + oldOwnerName := doer.Name + + defer func() { + if !repoRenamed && !wikiRenamed { + return + } + + recoverErr := recover() + if err == nil && recoverErr == nil { + return + } + + if repoRenamed { + if err := os.Rename(RepoPath(newOwnerName, repo.Name), RepoPath(oldOwnerName, repo.Name)); err != nil { + log.Critical("Unable to move repository %s/%s directory from %s back to correct place %s: %v", oldOwnerName, repo.Name, RepoPath(newOwnerName, repo.Name), RepoPath(oldOwnerName, repo.Name), err) + } + } + + if wikiRenamed { + if err := os.Rename(WikiPath(newOwnerName, repo.Name), WikiPath(oldOwnerName, repo.Name)); err != nil { + log.Critical("Unable to move wiki for repository %s/%s directory from %s back to correct place %s: %v", oldOwnerName, repo.Name, WikiPath(newOwnerName, repo.Name), WikiPath(oldOwnerName, repo.Name), err) + } + } + + if recoverErr != nil { + log.Error("Panic within TransferOwnership: %v\n%s", recoverErr, log.Stack(2)) + panic(recoverErr) + } + }() + newOwner, err := GetUserByName(newOwnerName) if err != nil { return fmt.Errorf("get new owner '%s': %v", newOwnerName, err) } + newOwnerName = newOwner.Name // ensure capitalisation matches // Check if new owner has repository with same name. has, err := IsRepositoryExist(newOwner, repo.Name) @@ -1311,6 +1344,7 @@ func TransferOwnership(doer *User, newOwnerName string, repo *Repository) error } oldOwner := repo.Owner + oldOwnerName = oldOwner.Name // Note: we have to set value here to make sure recalculate accesses is based on // new owner. @@ -1370,9 +1404,9 @@ func TransferOwnership(doer *User, newOwnerName string, repo *Repository) error } // Update repository count. - if _, err = sess.Exec("UPDATE `user` SET num_repos=num_repos+1 WHERE id=?", newOwner.ID); err != nil { + if _, err := sess.Exec("UPDATE `user` SET num_repos=num_repos+1 WHERE id=?", newOwner.ID); err != nil { return fmt.Errorf("increase new owner repository count: %v", err) - } else if _, err = sess.Exec("UPDATE `user` SET num_repos=num_repos-1 WHERE id=?", oldOwner.ID); err != nil { + } else if _, err := sess.Exec("UPDATE `user` SET num_repos=num_repos-1 WHERE id=?", oldOwner.ID); err != nil { return fmt.Errorf("decrease old owner repository count: %v", err) } @@ -1382,7 +1416,7 @@ func TransferOwnership(doer *User, newOwnerName string, repo *Repository) error // Remove watch for organization. if oldOwner.IsOrganization() { - if err = watchRepo(sess, oldOwner.ID, repo.ID, false); err != nil { + if err := watchRepo(sess, oldOwner.ID, repo.ID, false); err != nil { return fmt.Errorf("watchRepo [false]: %v", err) } } @@ -1394,16 +1428,18 @@ func TransferOwnership(doer *User, newOwnerName string, repo *Repository) error return fmt.Errorf("Failed to create dir %s: %v", dir, err) } - if err = os.Rename(RepoPath(oldOwner.Name, repo.Name), RepoPath(newOwner.Name, repo.Name)); err != nil { + if err := os.Rename(RepoPath(oldOwner.Name, repo.Name), RepoPath(newOwner.Name, repo.Name)); err != nil { return fmt.Errorf("rename repository directory: %v", err) } + repoRenamed = true // Rename remote wiki repository to new path and delete local copy. wikiPath := WikiPath(oldOwner.Name, repo.Name) if com.IsExist(wikiPath) { - if err = os.Rename(wikiPath, WikiPath(newOwner.Name, repo.Name)); err != nil { + if err := os.Rename(wikiPath, WikiPath(newOwner.Name, repo.Name)); err != nil { return fmt.Errorf("rename repository wiki: %v", err) } + wikiRenamed = true } // If there was previously a redirect at this location, remove it. From da80e90ac8b12e89be440bc45177230706c43920 Mon Sep 17 00:00:00 2001 From: 6543 <6543@obermui.de> Date: Sat, 6 Mar 2021 05:07:03 +0100 Subject: [PATCH 163/205] Fix race in local storage (#14888) (#14901) LocalStorage should only put completed files in position Signed-off-by: Andrew Thornton Co-authored-by: zeripath Co-authored-by: techknowlogick --- modules/storage/local.go | 50 +++++++++++++++++++++++++++++++--------- 1 file changed, 39 insertions(+), 11 deletions(-) diff --git a/modules/storage/local.go b/modules/storage/local.go index f7ffb2ddc1..84bf0c6627 100644 --- a/modules/storage/local.go +++ b/modules/storage/local.go @@ -7,6 +7,7 @@ package storage import ( "context" "io" + "io/ioutil" "net/url" "os" "path/filepath" @@ -24,13 +25,15 @@ const LocalStorageType Type = "local" // LocalStorageConfig represents the configuration for a local storage type LocalStorageConfig struct { - Path string `ini:"PATH"` + Path string `ini:"PATH"` + TemporaryPath string `ini:"TEMPORARY_PATH"` } // LocalStorage represents a local files storage type LocalStorage struct { - ctx context.Context - dir string + ctx context.Context + dir string + tmpdir string } // NewLocalStorage returns a local files @@ -45,9 +48,14 @@ func NewLocalStorage(ctx context.Context, cfg interface{}) (ObjectStorage, error return nil, err } + if config.TemporaryPath == "" { + config.TemporaryPath = config.Path + "/tmp" + } + return &LocalStorage{ - ctx: ctx, - dir: config.Path, + ctx: ctx, + dir: config.Path, + tmpdir: config.TemporaryPath, }, nil } @@ -63,17 +71,37 @@ func (l *LocalStorage) Save(path string, r io.Reader) (int64, error) { return 0, err } - // always override - if err := util.Remove(p); err != nil { + // Create a temporary file to save to + if err := os.MkdirAll(l.tmpdir, os.ModePerm); err != nil { return 0, err } - - f, err := os.Create(p) + tmp, err := ioutil.TempFile(l.tmpdir, "upload-*") if err != nil { return 0, err } - defer f.Close() - return io.Copy(f, r) + tmpRemoved := false + defer func() { + if !tmpRemoved { + _ = util.Remove(tmp.Name()) + } + }() + + n, err := io.Copy(tmp, r) + if err != nil { + return 0, err + } + + if err := tmp.Close(); err != nil { + return 0, err + } + + if err := os.Rename(tmp.Name(), p); err != nil { + return 0, err + } + + tmpRemoved = true + + return n, nil } // Stat returns the info of the file From 8e792986bb3e60abb087188fba3d02ba3d7e832b Mon Sep 17 00:00:00 2001 From: 6543 <6543@obermui.de> Date: Sat, 6 Mar 2021 06:13:38 +0100 Subject: [PATCH 164/205] Fix a couple of issues with a feeds (#14897) (#14903) Backport (#14897) witch fix couple of issues with feeds --- modules/templates/helper.go | 5 +++++ templates/user/dashboard/feeds.tmpl | 3 ++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/modules/templates/helper.go b/modules/templates/helper.go index 63be27d987..cd6f28fa0e 100644 --- a/modules/templates/helper.go +++ b/modules/templates/helper.go @@ -689,6 +689,11 @@ func ActionIcon(opType models.ActionType) string { // ActionContent2Commits converts action content to push commits func ActionContent2Commits(act Actioner) *repository.PushCommits { push := repository.NewPushCommits() + + if act == nil || act.GetContent() == "" { + return push + } + if err := json.Unmarshal([]byte(act.GetContent()), push); err != nil { log.Error("json.Unmarshal:\n%s\nERROR: %v", act.GetContent(), err) } diff --git a/templates/user/dashboard/feeds.tmpl b/templates/user/dashboard/feeds.tmpl index 739caeba5f..2748ea4022 100644 --- a/templates/user/dashboard/feeds.tmpl +++ b/templates/user/dashboard/feeds.tmpl @@ -96,7 +96,8 @@ {{index .GetIssueInfos 1 | RenderEmoji}} {{else if or (eq .GetOpType 10) (eq .GetOpType 21) (eq .GetOpType 22) (eq .GetOpType 23)}} {{.GetIssueTitle | RenderEmoji}} -

{{index .GetIssueInfos 1 | RenderEmoji}}

+ {{$comment := index .GetIssueInfos 1}} + {{if gt (len $comment) 0}}

{{$comment | RenderEmoji}}

{{end}} {{else if eq .GetOpType 11}}

{{index .GetIssueInfos 1}}

{{else if or (eq .GetOpType 12) (eq .GetOpType 13) (eq .GetOpType 14) (eq .GetOpType 15)}} From 8dad47a94af28bec403c4551d2ea265e4b98df5f Mon Sep 17 00:00:00 2001 From: zeripath Date: Sat, 6 Mar 2021 22:53:37 +0000 Subject: [PATCH 165/205] Fix race in LFS ContentStore.Put(...) (#14895) (#14913) Backport #14895 Continuing on from #14888 The previous implementation has race whereby an incomplete upload or hash mismatch upload can end up in the ContentStore. This PR moves the validation into the reader so that if there is a hash error or size mismatch the reader will return with an error instead of an io.EOF causing the storage to abort the storage. Signed-off-by: Andrew Thornton --- modules/lfs/content_store.go | 62 +++++++++++++++++++++++++++++------- 1 file changed, 51 insertions(+), 11 deletions(-) diff --git a/modules/lfs/content_store.go b/modules/lfs/content_store.go index 247191a1bf..788ef5b9a6 100644 --- a/modules/lfs/content_store.go +++ b/modules/lfs/content_store.go @@ -9,6 +9,7 @@ import ( "encoding/hex" "errors" "fmt" + "hash" "io" "os" @@ -66,15 +67,20 @@ func (s *ContentStore) Get(meta *models.LFSMetaObject, fromByte int64) (io.ReadC // Put takes a Meta object and an io.Reader and writes the content to the store. func (s *ContentStore) Put(meta *models.LFSMetaObject, r io.Reader) error { - hash := sha256.New() - rd := io.TeeReader(r, hash) p := meta.RelativePath() - written, err := s.Save(p, rd) + + // Wrap the provided reader with an inline hashing and size checker + wrappedRd := newHashingReader(meta.Size, meta.Oid, r) + + // now pass the wrapped reader to Save - if there is a size mismatch or hash mismatch then + // the errors returned by the newHashingReader should percolate up to here + written, err := s.Save(p, wrappedRd) if err != nil { log.Error("Whilst putting LFS OID[%s]: Failed to copy to tmpPath: %s Error: %v", meta.Oid, p, err) return err } + // This shouldn't happen but it is sensible to test if written != meta.Size { if err := s.Delete(p); err != nil { log.Error("Cleaning the LFS OID[%s] failed: %v", meta.Oid, err) @@ -82,14 +88,6 @@ func (s *ContentStore) Put(meta *models.LFSMetaObject, r io.Reader) error { return errSizeMismatch } - shaStr := hex.EncodeToString(hash.Sum(nil)) - if shaStr != meta.Oid { - if err := s.Delete(p); err != nil { - log.Error("Cleaning the LFS OID[%s] failed: %v", meta.Oid, err) - } - return errHashMismatch - } - return nil } @@ -118,3 +116,45 @@ func (s *ContentStore) Verify(meta *models.LFSMetaObject) (bool, error) { return true, nil } + +type hashingReader struct { + internal io.Reader + currentSize int64 + expectedSize int64 + hash hash.Hash + expectedHash string +} + +func (r *hashingReader) Read(b []byte) (int, error) { + n, err := r.internal.Read(b) + + if n > 0 { + r.currentSize += int64(n) + wn, werr := r.hash.Write(b[:n]) + if wn != n || werr != nil { + return n, werr + } + } + + if err != nil && err == io.EOF { + if r.currentSize != r.expectedSize { + return n, errSizeMismatch + } + + shaStr := hex.EncodeToString(r.hash.Sum(nil)) + if shaStr != r.expectedHash { + return n, errHashMismatch + } + } + + return n, err +} + +func newHashingReader(expectedSize int64, expectedHash string, reader io.Reader) *hashingReader { + return &hashingReader{ + internal: reader, + expectedSize: expectedSize, + expectedHash: expectedHash, + hash: sha256.New(), + } +} From 75496b9ff507ca5e9b7665f888f1156485e6532d Mon Sep 17 00:00:00 2001 From: 6543 <6543@obermui.de> Date: Sun, 7 Mar 2021 16:02:54 +0100 Subject: [PATCH 166/205] Changelog v1.13.4 (#14917) * Changelog v1.13.4 * nit --- CHANGELOG.md | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index f0c90c655b..4f0e1ac767 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,19 @@ This changelog goes through all the changes that have been made in each release without substantial changes to our git log; to see the highlights of what has been added to each release, please refer to the [blog](https://blog.gitea.io). +## [1.13.4](https://github.com/go-gitea/gitea/releases/tag/v1.13.4) - 2021-03-07 + +* SECURITY + * Fix issue popups (#14898) (#14899) +* BUGFIXES + * Fix race in LFS ContentStore.Put(...) (#14895) (#14913) + * Fix a couple of issues with a feeds (#14897) (#14903) + * When transfering repository and database transaction failed, rollback the renames (#14864) (#14902) + * Fix race in local storage (#14888) (#14901) + * Fix 500 on pull view page if user is not loged in (#14885) (#14886) +* DOCS + * Fix how lfs data path is set (#14855) (#14884) + ## [1.13.3](https://github.com/go-gitea/gitea/releases/tag/v1.13.3) - 2021-03-04 * BREAKING From 906ecfd173a70650250288d7b0a6730aaeddd14f Mon Sep 17 00:00:00 2001 From: zeripath Date: Mon, 8 Mar 2021 13:50:57 +0000 Subject: [PATCH 167/205] Re-enable import local paths after reversion from #13610 (#14925) (#14927) Backport #14925 PR #13610 unfortunately disabled importing repositories from local paths. This PR restores this functionality. Fix #14700 Signed-off-by: Andrew Thornton --- modules/migrations/migrate.go | 7 +++++++ modules/migrations/migrate_test.go | 12 ++++++++++++ 2 files changed, 19 insertions(+) diff --git a/modules/migrations/migrate.go b/modules/migrations/migrate.go index b3ecb8114a..bb1b572e74 100644 --- a/modules/migrations/migrate.go +++ b/modules/migrations/migrate.go @@ -52,6 +52,13 @@ func isMigrateURLAllowed(remoteURL string) error { } } + if u.Host == "" { + if !setting.ImportLocalPaths { + return &models.ErrMigrationNotAllowed{Host: ""} + } + return nil + } + if !setting.Migrations.AllowLocalNetworks { addrList, err := net.LookupIP(strings.Split(u.Host, ":")[0]) if err != nil { diff --git a/modules/migrations/migrate_test.go b/modules/migrations/migrate_test.go index 3bad5cfd73..e8b71bb325 100644 --- a/modules/migrations/migrate_test.go +++ b/modules/migrations/migrate_test.go @@ -31,4 +31,16 @@ func TestMigrateWhiteBlocklist(t *testing.T) { err = isMigrateURLAllowed("https://github.com/go-gitea/gitea.git") assert.Error(t, err) + + old := setting.ImportLocalPaths + setting.ImportLocalPaths = false + + err = isMigrateURLAllowed("/home/foo/bar/goo") + assert.Error(t, err) + + setting.ImportLocalPaths = true + err = isMigrateURLAllowed("/home/foo/bar/goo") + assert.NoError(t, err) + + setting.ImportLocalPaths = old } From 05ac72cf33e2e3baac4e0dc0fd83ca87292a4a91 Mon Sep 17 00:00:00 2001 From: "fnetX (aka fralix)" Date: Mon, 8 Mar 2021 17:50:13 +0100 Subject: [PATCH 168/205] Add "captcha" to list of reserved usernames (#14930) Signed-off-by: Otto Richter --- models/user.go | 1 + 1 file changed, 1 insertion(+) diff --git a/models/user.go b/models/user.go index af5f36ec17..01d1a485c9 100644 --- a/models/user.go +++ b/models/user.go @@ -727,6 +727,7 @@ var ( "assets", "attachments", "avatars", + "captcha", "commits", "debug", "error", From 33c2c49627455bd19d411ecd858c2ca2eceab731 Mon Sep 17 00:00:00 2001 From: 6543 <6543@obermui.de> Date: Fri, 12 Mar 2021 01:54:18 +0100 Subject: [PATCH 169/205] Prevent panic when editing forked repos by API (#14960) (#14963) When editing forked repos using the API the BaseRepository needs to loaded in order to check its visibility otherwise there will be NPE panic. Fix #14956 Signed-off-by: Andrew Thornton Co-authored-by: zeripath --- routers/api/v1/repo/repo.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/routers/api/v1/repo/repo.go b/routers/api/v1/repo/repo.go index 116e413125..53ec0618ce 100644 --- a/routers/api/v1/repo/repo.go +++ b/routers/api/v1/repo/repo.go @@ -539,6 +539,10 @@ func updateBasicProperties(ctx *context.APIContext, opts api.EditRepoOption) err if opts.Private != nil { // Visibility of forked repository is forced sync with base repository. if repo.IsFork { + if err := repo.GetBaseRepo(); err != nil { + ctx.Error(http.StatusInternalServerError, "Unable to load base repository", err) + return err + } *opts.Private = repo.BaseRepo.IsPrivate } From 3e7dccdf476758e6e8bfe18044588e36b5d22884 Mon Sep 17 00:00:00 2001 From: zeripath Date: Fri, 12 Mar 2021 17:12:14 +0000 Subject: [PATCH 170/205] Fix excluding more than two labels on issues list (#14962) (#14973) Backport #14962 Fix #14840 Signed-off-by: Andrew Thornton Co-authored-by: Norwin Roosen Co-authored-by: jaqra <48099350+jaqra@users.noreply.github.com> Co-authored-by: Norwin Roosen Co-authored-by: jaqra <48099350+jaqra@users.noreply.github.com> --- templates/repo/issue/milestone_issues.tmpl | 2 +- web_src/js/index.js | 30 +++++++++------------- 2 files changed, 13 insertions(+), 19 deletions(-) diff --git a/templates/repo/issue/milestone_issues.tmpl b/templates/repo/issue/milestone_issues.tmpl index 8d8c392564..28b11ad6d0 100644 --- a/templates/repo/issue/milestone_issues.tmpl +++ b/templates/repo/issue/milestone_issues.tmpl @@ -63,7 +63,7 @@ {{.i18n.Tr "repo.issues.filter_label_exclude" | Safe}} {{.i18n.Tr "repo.issues.filter_label_no_select"}} {{range .Labels}} - {{if .IsExcluded}}{{svg "octicon-circle-slash"}}{{else if contain $.SelLabelIDs .ID}}{{svg "octicon-check"}}{{end}} {{.Name | RenderEmoji}} + {{if .IsExcluded}}{{svg "octicon-circle-slash"}}{{else if contain $.SelLabelIDs .ID}}{{svg "octicon-check"}}{{end}} {{.Name | RenderEmoji}} {{end}}
diff --git a/web_src/js/index.js b/web_src/js/index.js index 2bfa691d63..b7a31c575b 100644 --- a/web_src/js/index.js +++ b/web_src/js/index.js @@ -3592,18 +3592,21 @@ function initIssueList() { fullTextSearch: true }); + function excludeLabel (item) { + const href = $(item).attr('href'); + const id = $(item).data('label-id'); + + const regStr = `labels=((?:-?[0-9]+%2c)*)(${id})((?:%2c-?[0-9]+)*)&`; + const newStr = 'labels=$1-$2$3&'; + + window.location = href.replace(new RegExp(regStr), newStr); + } + $('.menu a.label-filter-item').each(function () { $(this).on('click', function (e) { if (e.altKey) { e.preventDefault(); - - const href = $(this).attr('href'); - const id = $(this).data('label-id'); - - const regStr = `labels=(-?[0-9]+%2c)*(${id})(%2c-?[0-9]+)*&`; - const newStr = 'labels=$1-$2$3&'; - - window.location = href.replace(new RegExp(regStr), newStr); + excludeLabel(this); } }); }); @@ -3611,17 +3614,8 @@ function initIssueList() { $('.menu .ui.dropdown.label-filter').on('keydown', (e) => { if (e.altKey && e.keyCode === 13) { const selectedItems = $('.menu .ui.dropdown.label-filter .menu .item.selected'); - if (selectedItems.length > 0) { - const item = $(selectedItems[0]); - - const href = item.attr('href'); - const id = item.data('label-id'); - - const regStr = `labels=(-?[0-9]+%2c)*(${id})(%2c-?[0-9]+)*&`; - const newStr = 'labels=$1-$2$3&'; - - window.location = href.replace(new RegExp(regStr), newStr); + excludeLabel($(selectedItems[0])); } } }); From e3c44923d76ef2e4e6b92ec8700ed42663776e0c Mon Sep 17 00:00:00 2001 From: Norwin Date: Fri, 12 Mar 2021 20:39:05 +0000 Subject: [PATCH 171/205] fix release mail html template (#14976) was missing an --- templates/mail/release.tmpl | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/templates/mail/release.tmpl b/templates/mail/release.tmpl index bb0eb17a56..04b8c3bf51 100644 --- a/templates/mail/release.tmpl +++ b/templates/mail/release.tmpl @@ -12,8 +12,10 @@ -

@{{.Release.Publisher.Name}} released {{.Release.TagName}} - in {{.Release.Repo.FullName}}

+

+ @{{.Release.Publisher.Name}} released {{.Release.TagName}} + in {{.Release.Repo.FullName}} +

Title: {{.Release.Title}}

Note:
From 3231b70043039d1acd722115acf0e3022a81ca85 Mon Sep 17 00:00:00 2001 From: Norwin Date: Sat, 13 Mar 2021 03:05:56 +0000 Subject: [PATCH 172/205] check if original author is set (#14972) Co-authored-by: 6543 <6543@obermui.de> --- templates/repo/issue/view_content/comments.tmpl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/templates/repo/issue/view_content/comments.tmpl b/templates/repo/issue/view_content/comments.tmpl index 2e4a6681cd..db2e4f8105 100644 --- a/templates/repo/issue/view_content/comments.tmpl +++ b/templates/repo/issue/view_content/comments.tmpl @@ -29,7 +29,7 @@

{{if not $.Repository.IsArchived}} - {{if or (and (eq .PosterID .Issue.PosterID) (eq .Issue.OriginalAuthorID 0)) (eq .Issue.OriginalAuthorID .OriginalAuthorID) }} + {{if or (and (eq .PosterID .Issue.PosterID) (eq .Issue.OriginalAuthorID 0)) (and (eq .Issue.OriginalAuthorID .OriginalAuthorID) (not (eq .OriginalAuthorID 0))) }}
{{$.i18n.Tr "repo.issues.poster"}}
From 71a2adbf10f0f3df9d9f2ab59c51bbcb19c00c4b Mon Sep 17 00:00:00 2001 From: zeripath Date: Sat, 13 Mar 2021 09:54:53 +0000 Subject: [PATCH 173/205] Fix Anchor jumping with escaped query components (#14969) (#14977) Backport #14969 Fix #14968 Signed-off-by: Andrew Thornton --- web_src/js/markdown/anchors.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web_src/js/markdown/anchors.js b/web_src/js/markdown/anchors.js index b7d0a1f608..62bf8c83c3 100644 --- a/web_src/js/markdown/anchors.js +++ b/web_src/js/markdown/anchors.js @@ -5,7 +5,7 @@ const headingSelector = '.markdown h1, .markdown h2, .markdown h3, .markdown h4, function scrollToAnchor() { if (document.querySelector(':target')) return; if (!window.location.hash || window.location.hash.length <= 1) return; - const id = window.location.hash.substring(1); + const id = decodeURIComponent(window.location.hash.substring(1)); const el = document.getElementById(`user-content-${id}`); if (el) { el.scrollIntoView(); From c965ed6529872518595098824b42e4471b59c82a Mon Sep 17 00:00:00 2001 From: zeripath Date: Mon, 15 Mar 2021 04:34:56 +0000 Subject: [PATCH 174/205] Make sure sibling images get a link too (#14979) (#14995) Backport #14979 Due a problem with the ast.Walker in the our transformer in goldmark an image with a sibling image will not be transformed to gain a parent link. This PR fixes this. Fix #12925 Signed-off-by: Andrew Thornton --- modules/markup/markdown/goldmark.go | 33 +++++++++++++++++++++++- modules/markup/markdown/markdown_test.go | 11 ++++++++ 2 files changed, 43 insertions(+), 1 deletion(-) diff --git a/modules/markup/markdown/goldmark.go b/modules/markup/markdown/goldmark.go index 9447424644..b1f5d58d48 100644 --- a/modules/markup/markdown/goldmark.go +++ b/modules/markup/markdown/goldmark.go @@ -10,6 +10,7 @@ import ( "regexp" "strings" + "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/markup" "code.gitea.io/gitea/modules/markup/common" "code.gitea.io/gitea/modules/setting" @@ -101,11 +102,41 @@ func (g *ASTTransformer) Transform(node *ast.Document, reader text.Reader, pc pa parent := n.Parent() // Create a link around image only if parent is not already a link if _, ok := parent.(*ast.Link); !ok && parent != nil { + next := n.NextSibling() + + // Create a link wrapper wrap := ast.NewLink() wrap.Destination = link wrap.Title = v.Title + + // Duplicate the current image node + image := ast.NewImage(ast.NewLink()) + image.Destination = link + image.Title = v.Title + for _, attr := range v.Attributes() { + image.SetAttribute(attr.Name, attr.Value) + } + for child := v.FirstChild(); child != nil; { + next := child.NextSibling() + image.AppendChild(image, child) + child = next + } + + // Append our duplicate image to the wrapper link + wrap.AppendChild(wrap, image) + + // Wire in the next sibling + wrap.SetNextSibling(next) + + // Replace the current node with the wrapper link parent.ReplaceChild(parent, n, wrap) - wrap.AppendChild(wrap, n) + + // But most importantly ensure the next sibling is still on the old image too + v.SetNextSibling(next) + + } else { + log.Debug("ast.Image: %s has parent: %v", link, parent) + } case *ast.Link: // Links need their href to munged to be a real value diff --git a/modules/markup/markdown/markdown_test.go b/modules/markup/markdown/markdown_test.go index 7f27a43a7d..176bf4baad 100644 --- a/modules/markup/markdown/markdown_test.go +++ b/modules/markup/markdown/markdown_test.go @@ -308,3 +308,14 @@ func TestRender_RenderParagraphs(t *testing.T) { test(t, "A\n\nB\nC\n", 2) test(t, "A\n\n\nB\nC\n", 2) } + +func TestRenderSiblingImages_Issue12925(t *testing.T) { + testcase := `![image1](/image1) +![image2](/image2) +` + expected := `

image1
+image2

+` + res := string(RenderRaw([]byte(testcase), "", false)) + assert.Equal(t, expected, res) +} From fff66eb016a61e0f0403d48bb4cec4673a477c4f Mon Sep 17 00:00:00 2001 From: Norwin Date: Mon, 15 Mar 2021 15:01:04 +0000 Subject: [PATCH 175/205] API: fix set milestone on PR creation (#14981) (#15001) * API: fix set milestone on PR creation pr creation via API failed with 404, because we searched for milestoneID 0, due to uninitialized var usage D: * add tests Co-authored-by: 6543 <6543@obermui.de> Co-authored-by: 6543 <6543@obermui.de> --- integrations/api_pull_test.go | 73 +++++++++++++++++++++++++++++++++- models/fixtures/label.yml | 8 ++++ models/fixtures/milestone.yml | 8 ++++ models/fixtures/repository.yml | 1 + routers/api/v1/repo/pull.go | 4 +- 5 files changed, 90 insertions(+), 4 deletions(-) diff --git a/integrations/api_pull_test.go b/integrations/api_pull_test.go index 61daf917ff..4e7cca2239 100644 --- a/integrations/api_pull_test.go +++ b/integrations/api_pull_test.go @@ -74,8 +74,79 @@ func TestAPICreatePullSuccess(t *testing.T) { Base: "master", Title: "create a failure pr", }) - session.MakeRequest(t, req, 201) + session.MakeRequest(t, req, http.StatusUnprocessableEntity) // second request should fail +} + +func TestAPICreatePullWithFieldsSuccess(t *testing.T) { + defer prepareTestEnv(t)() + // repo10 have code, pulls units. + repo10 := models.AssertExistsAndLoadBean(t, &models.Repository{ID: 10}).(*models.Repository) + owner10 := models.AssertExistsAndLoadBean(t, &models.User{ID: repo10.OwnerID}).(*models.User) + // repo11 only have code unit but should still create pulls + repo11 := models.AssertExistsAndLoadBean(t, &models.Repository{ID: 11}).(*models.Repository) + owner11 := models.AssertExistsAndLoadBean(t, &models.User{ID: repo11.OwnerID}).(*models.User) + + session := loginUser(t, owner11.Name) + token := getTokenForLoggedInUser(t, session) + + opts := &api.CreatePullRequestOption{ + Head: fmt.Sprintf("%s:master", owner11.Name), + Base: "master", + Title: "create a failure pr", + Body: "foobaaar", + Milestone: 5, + Assignees: []string{owner10.Name}, + Labels: []int64{5}, + } + + req := NewRequestWithJSON(t, http.MethodPost, fmt.Sprintf("/api/v1/repos/%s/%s/pulls?token=%s", owner10.Name, repo10.Name, token), opts) + + res := session.MakeRequest(t, req, 201) + pull := new(api.PullRequest) + DecodeJSON(t, res, pull) + + assert.NotNil(t, pull.Milestone) + assert.EqualValues(t, opts.Milestone, pull.Milestone.ID) + if assert.Len(t, pull.Assignees, 1) { + assert.EqualValues(t, opts.Assignees[0], owner10.Name) + } + assert.NotNil(t, pull.Labels) + assert.EqualValues(t, opts.Labels[0], pull.Labels[0].ID) +} + +func TestAPICreatePullWithFieldsFailure(t *testing.T) { + defer prepareTestEnv(t)() + // repo10 have code, pulls units. + repo10 := models.AssertExistsAndLoadBean(t, &models.Repository{ID: 10}).(*models.Repository) + owner10 := models.AssertExistsAndLoadBean(t, &models.User{ID: repo10.OwnerID}).(*models.User) + // repo11 only have code unit but should still create pulls + repo11 := models.AssertExistsAndLoadBean(t, &models.Repository{ID: 11}).(*models.Repository) + owner11 := models.AssertExistsAndLoadBean(t, &models.User{ID: repo11.OwnerID}).(*models.User) + + session := loginUser(t, owner11.Name) + token := getTokenForLoggedInUser(t, session) + + opts := &api.CreatePullRequestOption{ + Head: fmt.Sprintf("%s:master", owner11.Name), + Base: "master", + } + + req := NewRequestWithJSON(t, http.MethodPost, fmt.Sprintf("/api/v1/repos/%s/%s/pulls?token=%s", owner10.Name, repo10.Name, token), opts) + session.MakeRequest(t, req, http.StatusUnprocessableEntity) + opts.Title = "is required" + + opts.Milestone = 666 + session.MakeRequest(t, req, http.StatusUnprocessableEntity) + opts.Milestone = 5 + + opts.Assignees = []string{"qweruqweroiuyqweoiruywqer"} + session.MakeRequest(t, req, http.StatusUnprocessableEntity) + opts.Assignees = []string{owner10.LoginName} + + opts.Labels = []int64{55555} + session.MakeRequest(t, req, http.StatusUnprocessableEntity) + opts.Labels = []int64{5} } func TestAPIEditPull(t *testing.T) { diff --git a/models/fixtures/label.yml b/models/fixtures/label.yml index 3ad82eebed..1b7ce74681 100644 --- a/models/fixtures/label.yml +++ b/models/fixtures/label.yml @@ -33,3 +33,11 @@ num_issues: 1 num_closed_issues: 0 +- + id: 5 + repo_id: 10 + org_id: 0 + name: pull-test-label + color: '#000000' + num_issues: 0 + num_closed_issues: 0 diff --git a/models/fixtures/milestone.yml b/models/fixtures/milestone.yml index b9894a1009..2cd994e63a 100644 --- a/models/fixtures/milestone.yml +++ b/models/fixtures/milestone.yml @@ -29,3 +29,11 @@ content: content random is_closed: false num_issues: 0 + +- + id: 5 + repo_id: 10 + name: milestone of repo 10 + content: for testing with PRs + is_closed: false + num_issues: 0 diff --git a/models/fixtures/repository.yml b/models/fixtures/repository.yml index a44e480270..d6dc099e5c 100644 --- a/models/fixtures/repository.yml +++ b/models/fixtures/repository.yml @@ -146,6 +146,7 @@ num_closed_issues: 0 num_pulls: 1 num_closed_pulls: 0 + num_milestones: 1 is_mirror: false num_forks: 1 status: 0 diff --git a/routers/api/v1/repo/pull.go b/routers/api/v1/repo/pull.go index b2b71180a4..75b837b3a4 100644 --- a/routers/api/v1/repo/pull.go +++ b/routers/api/v1/repo/pull.go @@ -293,7 +293,6 @@ func CreatePullRequest(ctx *context.APIContext, form api.CreatePullRequestOption var ( repo = ctx.Repo.Repository labelIDs []int64 - assigneeID int64 milestoneID int64 ) @@ -354,7 +353,7 @@ func CreatePullRequest(ctx *context.APIContext, form api.CreatePullRequestOption } if form.Milestone > 0 { - milestone, err := models.GetMilestoneByRepoID(ctx.Repo.Repository.ID, milestoneID) + milestone, err := models.GetMilestoneByRepoID(ctx.Repo.Repository.ID, form.Milestone) if err != nil { if models.IsErrMilestoneNotExist(err) { ctx.NotFound() @@ -378,7 +377,6 @@ func CreatePullRequest(ctx *context.APIContext, form api.CreatePullRequestOption PosterID: ctx.User.ID, Poster: ctx.User, MilestoneID: milestoneID, - AssigneeID: assigneeID, IsPull: true, Content: form.Body, DeadlineUnix: deadlineUnix, From 8c461eb261c060811859600c37ad980a7189bd2d Mon Sep 17 00:00:00 2001 From: zeripath Date: Wed, 17 Mar 2021 08:58:58 +0000 Subject: [PATCH 176/205] Fix several render issues (#14986) (#15013) Backport #14986 * Fix an issue with panics related to attributes * Wrap goldmark render in a recovery function * Reduce memory use in render emoji * Use a pipe for rendering goldmark - still needs more work and a limiter Signed-off-by: Andrew Thornton Co-authored-by: Lauris BH --- modules/emoji/emoji.go | 75 +++++++++++------ modules/emoji/emoji_test.go | 33 ++++++++ modules/markup/html.go | 24 ++++-- modules/markup/markdown/goldmark.go | 6 ++ modules/markup/markdown/markdown.go | 102 +++++++++++++++++++++-- modules/markup/markdown/markdown_test.go | 20 +++++ 6 files changed, 216 insertions(+), 44 deletions(-) diff --git a/modules/emoji/emoji.go b/modules/emoji/emoji.go index 169ee0a182..01fb764ce3 100644 --- a/modules/emoji/emoji.go +++ b/modules/emoji/emoji.go @@ -30,6 +30,9 @@ var ( // aliasMap provides a map of the alias to its emoji data. aliasMap map[string]int + // emptyReplacer is the string replacer for emoji codes. + emptyReplacer *strings.Replacer + // codeReplacer is the string replacer for emoji codes. codeReplacer *strings.Replacer @@ -49,6 +52,7 @@ func loadMap() { // process emoji codes and aliases codePairs := make([]string, 0) + emptyPairs := make([]string, 0) aliasPairs := make([]string, 0) // sort from largest to small so we match combined emoji first @@ -64,6 +68,7 @@ func loadMap() { // setup codes codeMap[e.Emoji] = i codePairs = append(codePairs, e.Emoji, ":"+e.Aliases[0]+":") + emptyPairs = append(emptyPairs, e.Emoji, e.Emoji) // setup aliases for _, a := range e.Aliases { @@ -77,6 +82,7 @@ func loadMap() { } // create replacers + emptyReplacer = strings.NewReplacer(emptyPairs...) codeReplacer = strings.NewReplacer(codePairs...) aliasReplacer = strings.NewReplacer(aliasPairs...) }) @@ -127,38 +133,53 @@ func ReplaceAliases(s string) string { return aliasReplacer.Replace(s) } +type rememberSecondWriteWriter struct { + pos int + idx int + end int + writecount int +} + +func (n *rememberSecondWriteWriter) Write(p []byte) (int, error) { + n.writecount++ + if n.writecount == 2 { + n.idx = n.pos + n.end = n.pos + len(p) + } + n.pos += len(p) + return len(p), nil +} + +func (n *rememberSecondWriteWriter) WriteString(s string) (int, error) { + n.writecount++ + if n.writecount == 2 { + n.idx = n.pos + n.end = n.pos + len(s) + } + n.pos += len(s) + return len(s), nil +} + // FindEmojiSubmatchIndex returns index pair of longest emoji in a string func FindEmojiSubmatchIndex(s string) []int { loadMap() - found := make(map[int]int) - keys := make([]int, 0) + secondWriteWriter := rememberSecondWriteWriter{} - //see if there are any emoji in string before looking for position of specific ones - //no performance difference when there is a match but 10x faster when there are not - if s == ReplaceCodes(s) { + // A faster and clean implementation would copy the trie tree formation in strings.NewReplacer but + // we can be lazy here. + // + // The implementation of strings.Replacer.WriteString is such that the first index of the emoji + // submatch is simply the second thing that is written to WriteString in the writer. + // + // Therefore we can simply take the index of the second write as our first emoji + // + // FIXME: just copy the trie implementation from strings.NewReplacer + _, _ = emptyReplacer.WriteString(&secondWriteWriter, s) + + // if we wrote less than twice then we never "replaced" + if secondWriteWriter.writecount < 2 { return nil } - // get index of first emoji occurrence while also checking for longest combination - for j := range GemojiData { - i := strings.Index(s, GemojiData[j].Emoji) - if i != -1 { - if _, ok := found[i]; !ok { - if len(keys) == 0 || i < keys[0] { - found[i] = j - keys = []int{i} - } - if i == 0 { - break - } - } - } - } - - if len(keys) > 0 { - index := keys[0] - return []int{index, index + len(GemojiData[found[index]].Emoji)} - } - - return nil + return []int{secondWriteWriter.idx, secondWriteWriter.end} } diff --git a/modules/emoji/emoji_test.go b/modules/emoji/emoji_test.go index 3eca3a8d8a..def252896f 100644 --- a/modules/emoji/emoji_test.go +++ b/modules/emoji/emoji_test.go @@ -8,6 +8,8 @@ package emoji import ( "reflect" "testing" + + "github.com/stretchr/testify/assert" ) func TestDumpInfo(t *testing.T) { @@ -65,3 +67,34 @@ func TestReplacers(t *testing.T) { } } } + +func TestFindEmojiSubmatchIndex(t *testing.T) { + type testcase struct { + teststring string + expected []int + } + + testcases := []testcase{ + { + "\U0001f44d", + []int{0, len("\U0001f44d")}, + }, + { + "\U0001f44d +1 \U0001f44d \U0001f37a", + []int{0, 4}, + }, + { + " \U0001f44d", + []int{1, 1 + len("\U0001f44d")}, + }, + { + string([]byte{'\u0001'}) + "\U0001f44d", + []int{1, 1 + len("\U0001f44d")}, + }, + } + + for _, kase := range testcases { + actual := FindEmojiSubmatchIndex(kase.teststring) + assert.Equal(t, kase.expected, actual) + } +} diff --git a/modules/markup/html.go b/modules/markup/html.go index 1d4a9be58c..a81b03f071 100644 --- a/modules/markup/html.go +++ b/modules/markup/html.go @@ -298,19 +298,27 @@ func RenderEmoji( return ctx.postProcess(rawHTML) } +var tagCleaner = regexp.MustCompile(`<((?:/?\w+/\w+)|(?:/[\w ]+/)|(/?[hH][tT][mM][lL][ />]))`) +var nulCleaner = strings.NewReplacer("\000", "") + func (ctx *postProcessCtx) postProcess(rawHTML []byte) ([]byte, error) { if ctx.procs == nil { ctx.procs = defaultProcessors } // give a generous extra 50 bytes - res := make([]byte, 0, len(rawHTML)+50) - res = append(res, ""...) - res = append(res, rawHTML...) - res = append(res, ""...) + res := bytes.NewBuffer(make([]byte, 0, len(rawHTML)+50)) + // prepend "" + _, _ = res.WriteString("") + + // Strip out nuls - they're always invalid + _, _ = nulCleaner.WriteString(res, string(tagCleaner.ReplaceAll(rawHTML, []byte("<$1")))) + + // close the tags + _, _ = res.WriteString("") // parse the HTML - nodes, err := html.ParseFragment(bytes.NewReader(res), nil) + nodes, err := html.ParseFragment(res, nil) if err != nil { return nil, &postProcessError{"invalid HTML", err} } @@ -347,17 +355,17 @@ func (ctx *postProcessCtx) postProcess(rawHTML []byte) ([]byte, error) { // Create buffer in which the data will be placed again. We know that the // length will be at least that of res; to spare a few alloc+copy, we // reuse res, resetting its length to 0. - buf := bytes.NewBuffer(res[:0]) + res.Reset() // Render everything to buf. for _, node := range nodes { - err = html.Render(buf, node) + err = html.Render(res, node) if err != nil { return nil, &postProcessError{"error rendering processed HTML", err} } } // Everything done successfully, return parsed data. - return buf.Bytes(), nil + return res.Bytes(), nil } func (ctx *postProcessCtx) visitNode(node *html.Node, visitText bool) { diff --git a/modules/markup/markdown/goldmark.go b/modules/markup/markdown/goldmark.go index b1f5d58d48..48544b89ab 100644 --- a/modules/markup/markdown/goldmark.go +++ b/modules/markup/markdown/goldmark.go @@ -77,6 +77,12 @@ func (g *ASTTransformer) Transform(node *ast.Document, reader text.Reader, pc pa header.ID = util.BytesToReadOnlyString(id.([]byte)) } toc = append(toc, header) + } else { + for _, attr := range v.Attributes() { + if _, ok := attr.Value.([]byte); !ok { + v.SetAttribute(attr.Name, []byte(fmt.Sprintf("%v", attr.Value))) + } + } } case *ast.Image: // Images need two things: diff --git a/modules/markup/markdown/markdown.go b/modules/markup/markdown/markdown.go index 999ae52bb5..93235d77e5 100644 --- a/modules/markup/markdown/markdown.go +++ b/modules/markup/markdown/markdown.go @@ -6,7 +6,8 @@ package markdown import ( - "bytes" + "fmt" + "io" "strings" "sync" @@ -18,7 +19,7 @@ import ( chromahtml "github.com/alecthomas/chroma/formatters/html" "github.com/yuin/goldmark" - "github.com/yuin/goldmark-highlighting" + highlighting "github.com/yuin/goldmark-highlighting" meta "github.com/yuin/goldmark-meta" "github.com/yuin/goldmark/extension" "github.com/yuin/goldmark/parser" @@ -34,6 +35,44 @@ var urlPrefixKey = parser.NewContextKey() var isWikiKey = parser.NewContextKey() var renderMetasKey = parser.NewContextKey() +type closesWithError interface { + io.WriteCloser + CloseWithError(err error) error +} + +type limitWriter struct { + w closesWithError + sum int64 + limit int64 +} + +// Write implements the standard Write interface: +func (l *limitWriter) Write(data []byte) (int, error) { + leftToWrite := l.limit - l.sum + if leftToWrite < int64(len(data)) { + n, err := l.w.Write(data[:leftToWrite]) + l.sum += int64(n) + if err != nil { + return n, err + } + _ = l.w.Close() + return n, fmt.Errorf("Rendered content too large - truncating render") + } + n, err := l.w.Write(data) + l.sum += int64(n) + return n, err +} + +// Close closes the writer +func (l *limitWriter) Close() error { + return l.w.Close() +} + +// CloseWithError closes the writer +func (l *limitWriter) CloseWithError(err error) error { + return l.w.CloseWithError(err) +} + // NewGiteaParseContext creates a parser.Context with the gitea context set func NewGiteaParseContext(urlPrefix string, metas map[string]string, isWiki bool) parser.Context { pc := parser.NewContext(parser.WithIDs(newPrefixedIDs())) @@ -43,8 +82,8 @@ func NewGiteaParseContext(urlPrefix string, metas map[string]string, isWiki bool return pc } -// render renders Markdown to HTML without handling special links. -func render(body []byte, urlPrefix string, metas map[string]string, wikiMarkdown bool) []byte { +// actualRender renders Markdown to HTML without handling special links. +func actualRender(body []byte, urlPrefix string, metas map[string]string, wikiMarkdown bool) []byte { once.Do(func() { converter = goldmark.New( goldmark.WithExtensions(extension.Table, @@ -119,12 +158,57 @@ func render(body []byte, urlPrefix string, metas map[string]string, wikiMarkdown }) - pc := NewGiteaParseContext(urlPrefix, metas, wikiMarkdown) - var buf bytes.Buffer - if err := converter.Convert(giteautil.NormalizeEOL(body), &buf, parser.WithContext(pc)); err != nil { - log.Error("Unable to render: %v", err) + rd, wr := io.Pipe() + defer func() { + _ = rd.Close() + _ = wr.Close() + }() + + lw := &limitWriter{ + w: wr, + limit: setting.UI.MaxDisplayFileSize * 3, } - return markup.SanitizeReader(&buf).Bytes() + + // FIXME: should we include a timeout that closes the pipe to abort the parser and sanitizer if it takes too long? + go func() { + defer func() { + err := recover() + if err == nil { + return + } + + log.Warn("Unable to render markdown due to panic in goldmark: %v", err) + if log.IsDebug() { + log.Debug("Panic in markdown: %v\n%s", err, string(log.Stack(2))) + } + _ = lw.CloseWithError(fmt.Errorf("%v", err)) + }() + + pc := NewGiteaParseContext(urlPrefix, metas, wikiMarkdown) + if err := converter.Convert(giteautil.NormalizeEOL(body), lw, parser.WithContext(pc)); err != nil { + log.Error("Unable to render: %v", err) + _ = lw.CloseWithError(err) + return + } + _ = lw.Close() + }() + return markup.SanitizeReader(rd).Bytes() +} + +func render(body []byte, urlPrefix string, metas map[string]string, wikiMarkdown bool) (ret []byte) { + defer func() { + err := recover() + if err == nil { + return + } + + log.Warn("Unable to render markdown due to panic in goldmark - will return sanitized raw bytes") + if log.IsDebug() { + log.Debug("Panic in markdown: %v\n%s", err, string(log.Stack(2))) + } + ret = markup.SanitizeBytes(body) + }() + return actualRender(body, urlPrefix, metas, wikiMarkdown) } var ( diff --git a/modules/markup/markdown/markdown_test.go b/modules/markup/markdown/markdown_test.go index 176bf4baad..d5b211b3e0 100644 --- a/modules/markup/markdown/markdown_test.go +++ b/modules/markup/markdown/markdown_test.go @@ -309,6 +309,25 @@ func TestRender_RenderParagraphs(t *testing.T) { test(t, "A\n\n\nB\nC\n", 2) } +func TestMarkdownRenderRaw(t *testing.T) { + testcases := [][]byte{ + { // clusterfuzz_testcase_minimized_fuzz_markdown_render_raw_6267570554535936 + 0x2a, 0x20, 0x2d, 0x0a, 0x09, 0x20, 0x60, 0x5b, 0x0a, 0x09, 0x20, 0x60, + 0x5b, + }, + { // clusterfuzz_testcase_minimized_fuzz_markdown_render_raw_6278827345051648 + 0x2d, 0x20, 0x2d, 0x0d, 0x09, 0x60, 0x0d, 0x09, 0x60, + }, + { // clusterfuzz_testcase_minimized_fuzz_markdown_render_raw_6016973788020736[] = { + 0x7b, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x3d, 0x35, 0x7d, 0x0a, 0x3d, + }, + } + + for _, testcase := range testcases { + _ = RenderRaw(testcase, "", false) + } +} + func TestRenderSiblingImages_Issue12925(t *testing.T) { testcase := `![image1](/image1) ![image2](/image2) @@ -318,4 +337,5 @@ func TestRenderSiblingImages_Issue12925(t *testing.T) { ` res := string(RenderRaw([]byte(testcase), "", false)) assert.Equal(t, expected, res) + } From 645c0d8abd530e2725b6c6db0d3f3e28c807a829 Mon Sep 17 00:00:00 2001 From: 6543 <6543@obermui.de> Date: Thu, 18 Mar 2021 23:21:33 +0100 Subject: [PATCH 177/205] another clusterfuzz spotted issue (#15032) (#15034) Signed-off-by: Andrew Thornton Co-authored-by: zeripath --- modules/markup/html.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/markup/html.go b/modules/markup/html.go index a81b03f071..c2e574e3b2 100644 --- a/modules/markup/html.go +++ b/modules/markup/html.go @@ -298,7 +298,7 @@ func RenderEmoji( return ctx.postProcess(rawHTML) } -var tagCleaner = regexp.MustCompile(`<((?:/?\w+/\w+)|(?:/[\w ]+/)|(/?[hH][tT][mM][lL][ />]))`) +var tagCleaner = regexp.MustCompile(`<((?:/?\w+/\w+)|(?:/[\w ]+/)|(/?[hH][tT][mM][lL][ />])|(/?[hH][eE][aA][dD][ />]))`) var nulCleaner = strings.NewReplacer("\000", "") func (ctx *postProcessCtx) postProcess(rawHTML []byte) ([]byte, error) { From 909f2be99d0c699f506f463bb6238378f12c0dc1 Mon Sep 17 00:00:00 2001 From: zeripath Date: Fri, 19 Mar 2021 03:23:58 +0000 Subject: [PATCH 178/205] Fix postgres ID sequences broken by recreate-table (#15015) (#15029) Backport #15015 Unfortunately there is a subtle problem with recreatetable on postgres which leads to the sequences not being renamed and not being left at 0. Fix #14725 Signed-off-by: Andrew Thornton --- cmd/doctor.go | 17 +++++++++ models/consistency.go | 61 +++++++++++++++++++++++++++++++ models/migrations/migrations.go | 63 ++++++++++++++++++++++++++++++++- 3 files changed, 140 insertions(+), 1 deletion(-) diff --git a/cmd/doctor.go b/cmd/doctor.go index 2ca2bb5e70..5ba0451110 100644 --- a/cmd/doctor.go +++ b/cmd/doctor.go @@ -670,6 +670,23 @@ func runDoctorCheckDBConsistency(ctx *cli.Context) ([]string, error) { } } + if setting.Database.UsePostgreSQL { + count, err = models.CountBadSequences() + if err != nil { + return nil, err + } + if count > 0 { + if ctx.Bool("fix") { + err := models.FixBadSequences() + if err != nil { + return nil, err + } + results = append(results, fmt.Sprintf("%d sequences updated", count)) + } else { + results = append(results, fmt.Sprintf("%d sequences with incorrect values", count)) + } + } + } //ToDo: function to recalc all counters return results, nil diff --git a/models/consistency.go b/models/consistency.go index fbb99ca80c..0c62d4dc24 100644 --- a/models/consistency.go +++ b/models/consistency.go @@ -5,10 +5,13 @@ package models import ( + "fmt" "reflect" + "regexp" "strings" "testing" + "code.gitea.io/gitea/modules/setting" "github.com/stretchr/testify/assert" "xorm.io/builder" ) @@ -295,3 +298,61 @@ func FixNullArchivedRepository() (int64, error) { IsArchived: false, }) } + +// CountBadSequences looks for broken sequences from recreate-table mistakes +func CountBadSequences() (int64, error) { + if !setting.Database.UsePostgreSQL { + return 0, nil + } + + sess := x.NewSession() + defer sess.Close() + + var sequences []string + schema := sess.Engine().Dialect().URI().Schema + + sess.Engine().SetSchema("") + if err := sess.Table("information_schema.sequences").Cols("sequence_name").Where("sequence_name LIKE 'tmp_recreate__%_id_seq%' AND sequence_catalog = ?", setting.Database.Name).Find(&sequences); err != nil { + return 0, err + } + sess.Engine().SetSchema(schema) + + return int64(len(sequences)), nil +} + +// FixBadSequences fixes for broken sequences from recreate-table mistakes +func FixBadSequences() error { + if !setting.Database.UsePostgreSQL { + return nil + } + + sess := x.NewSession() + defer sess.Close() + if err := sess.Begin(); err != nil { + return err + } + + var sequences []string + schema := sess.Engine().Dialect().URI().Schema + + sess.Engine().SetSchema("") + if err := sess.Table("information_schema.sequences").Cols("sequence_name").Where("sequence_name LIKE 'tmp_recreate__%_id_seq%' AND sequence_catalog = ?", setting.Database.Name).Find(&sequences); err != nil { + return err + } + sess.Engine().SetSchema(schema) + + sequenceRegexp := regexp.MustCompile(`tmp_recreate__(\w+)_id_seq.*`) + + for _, sequence := range sequences { + tableName := sequenceRegexp.FindStringSubmatch(sequence)[1] + newSequenceName := tableName + "_id_seq" + if _, err := sess.Exec(fmt.Sprintf("ALTER SEQUENCE `%s` RENAME TO `%s`", sequence, newSequenceName)); err != nil { + return err + } + if _, err := sess.Exec(fmt.Sprintf("SELECT setval('%s', COALESCE((SELECT MAX(id)+1 FROM `%s`), 1), false)", newSequenceName, tableName)); err != nil { + return err + } + } + + return sess.Commit() +} diff --git a/models/migrations/migrations.go b/models/migrations/migrations.go index 5cb85cc18c..d16f8c7ec9 100644 --- a/models/migrations/migrations.go +++ b/models/migrations/migrations.go @@ -516,6 +516,31 @@ func recreateTable(sess *xorm.Session, bean interface{}) error { return err } case setting.Database.UsePostgreSQL: + var originalSequences []string + type sequenceData struct { + LastValue int `xorm:"'last_value'"` + IsCalled bool `xorm:"'is_called'"` + } + sequenceMap := map[string]sequenceData{} + + schema := sess.Engine().Dialect().URI().Schema + sess.Engine().SetSchema("") + if err := sess.Table("information_schema.sequences").Cols("sequence_name").Where("sequence_name LIKE ? || '_%' AND sequence_catalog = ?", tableName, setting.Database.Name).Find(&originalSequences); err != nil { + log.Error("Unable to rename %s to %s. Error: %v", tempTableName, tableName, err) + return err + } + sess.Engine().SetSchema(schema) + + for _, sequence := range originalSequences { + sequenceData := sequenceData{} + if _, err := sess.Table(sequence).Cols("last_value", "is_called").Get(&sequenceData); err != nil { + log.Error("Unable to get last_value and is_called from %s. Error: %v", sequence, err) + return err + } + sequenceMap[sequence] = sequenceData + + } + // CASCADE causes postgres to drop all the constraints on the old table if _, err := sess.Exec(fmt.Sprintf("DROP TABLE `%s` CASCADE", tableName)); err != nil { log.Error("Unable to drop old table %s. Error: %v", tableName, err) @@ -529,7 +554,6 @@ func recreateTable(sess *xorm.Session, bean interface{}) error { } var indices []string - schema := sess.Engine().Dialect().URI().Schema sess.Engine().SetSchema("") if err := sess.Table("pg_indexes").Cols("indexname").Where("tablename = ? ", tableName).Find(&indices); err != nil { log.Error("Unable to rename %s to %s. Error: %v", tempTableName, tableName, err) @@ -545,6 +569,43 @@ func recreateTable(sess *xorm.Session, bean interface{}) error { } } + var sequences []string + sess.Engine().SetSchema("") + if err := sess.Table("information_schema.sequences").Cols("sequence_name").Where("sequence_name LIKE 'tmp_recreate__' || ? || '_%' AND sequence_catalog = ?", tableName, setting.Database.Name).Find(&sequences); err != nil { + log.Error("Unable to rename %s to %s. Error: %v", tempTableName, tableName, err) + return err + } + sess.Engine().SetSchema(schema) + + for _, sequence := range sequences { + newSequenceName := strings.Replace(sequence, "tmp_recreate__", "", 1) + if _, err := sess.Exec(fmt.Sprintf("ALTER SEQUENCE `%s` RENAME TO `%s`", sequence, newSequenceName)); err != nil { + log.Error("Unable to rename %s sequence to %s. Error: %v", sequence, newSequenceName, err) + return err + } + val, ok := sequenceMap[newSequenceName] + if newSequenceName == tableName+"_id_seq" { + if ok && val.LastValue != 0 { + if _, err := sess.Exec(fmt.Sprintf("SELECT setval('%s', %d, %t)", newSequenceName, val.LastValue, val.IsCalled)); err != nil { + log.Error("Unable to reset %s to %d. Error: %v", newSequenceName, val, err) + return err + } + } else { + // We're going to try to guess this + if _, err := sess.Exec(fmt.Sprintf("SELECT setval('%s', COALESCE((SELECT MAX(id)+1 FROM `%s`), 1), false)", newSequenceName, tableName)); err != nil { + log.Error("Unable to reset %s. Error: %v", newSequenceName, err) + return err + } + } + } else if ok { + if _, err := sess.Exec(fmt.Sprintf("SELECT setval('%s', %d, %t)", newSequenceName, val.LastValue, val.IsCalled)); err != nil { + log.Error("Unable to reset %s to %d. Error: %v", newSequenceName, val, err) + return err + } + } + + } + case setting.Database.UseMSSQL: // MSSQL will drop all the constraints on the old table if _, err := sess.Exec(fmt.Sprintf("DROP TABLE `%s`", tableName)); err != nil { From 70e4134130331bda3bb1873c6099d8e63c468a2d Mon Sep 17 00:00:00 2001 From: 6543 <6543@obermui.de> Date: Fri, 19 Mar 2021 22:13:39 +0100 Subject: [PATCH 179/205] Delete Labels & IssueLabels on Repo Delete too (#15039) (#15051) * Doctor: find IssueLabels without existing label * Repo Delete: delete labels & issue_labels too --- cmd/doctor.go | 16 ++++++++++++++++ models/consistency.go | 18 ++++++++++++++++++ models/issue_label.go | 12 ++++++++++++ models/repo.go | 4 ++++ 4 files changed, 50 insertions(+) diff --git a/cmd/doctor.go b/cmd/doctor.go index 5ba0451110..3c271f131f 100644 --- a/cmd/doctor.go +++ b/cmd/doctor.go @@ -606,6 +606,22 @@ func runDoctorCheckDBConsistency(ctx *cli.Context) ([]string, error) { } } + // find IssueLabels without existing label + count, err = models.CountOrphanedIssueLabels() + if err != nil { + return nil, err + } + if count > 0 { + if ctx.Bool("fix") { + if err = models.DeleteOrphanedIssueLabels(); err != nil { + return nil, err + } + results = append(results, fmt.Sprintf("%d issue_labels without existing label deleted", count)) + } else { + results = append(results, fmt.Sprintf("%d issue_labels without existing label", count)) + } + } + //find issues without existing repository count, err = models.CountOrphanedIssues() if err != nil { diff --git a/models/consistency.go b/models/consistency.go index 0c62d4dc24..3a5c4cae50 100644 --- a/models/consistency.go +++ b/models/consistency.go @@ -224,6 +224,24 @@ func DeleteOrphanedLabels() error { return nil } +// CountOrphanedIssueLabels return count of IssueLabels witch have no label behind anymore +func CountOrphanedIssueLabels() (int64, error) { + return x.Table("issue_label"). + Join("LEFT", "label", "issue_label.label_id = label.id"). + Where(builder.IsNull{"label.id"}).Count() +} + +// DeleteOrphanedIssueLabels delete IssueLabels witch have no label behind anymore +func DeleteOrphanedIssueLabels() error { + + _, err := x.In("id", builder.Select("issue_label.id").From("issue_label"). + Join("LEFT", "label", "issue_label.label_id = label.id"). + Where(builder.IsNull{"label.id"})). + Delete(IssueLabel{}) + + return err +} + // CountOrphanedIssues count issues without a repo func CountOrphanedIssues() (int64, error) { return x.Table("issue"). diff --git a/models/issue_label.go b/models/issue_label.go index 54b286fe7e..6d519aa8cd 100644 --- a/models/issue_label.go +++ b/models/issue_label.go @@ -764,3 +764,15 @@ func DeleteIssueLabel(issue *Issue, label *Label, doer *User) (err error) { return sess.Commit() } + +func deleteLabelsByRepoID(sess Engine, repoID int64) error { + deleteCond := builder.Select("id").From("label").Where(builder.Eq{"label.repo_id": repoID}) + + if _, err := sess.In("label_id", deleteCond). + Delete(&IssueLabel{}); err != nil { + return err + } + + _, err := sess.Delete(&Label{RepoID: repoID}) + return err +} diff --git a/models/repo.go b/models/repo.go index 8c6d8b9ee3..6d6f61597b 100644 --- a/models/repo.go +++ b/models/repo.go @@ -1729,6 +1729,10 @@ func DeleteRepository(doer *User, uid, repoID int64) error { return fmt.Errorf("deleteBeans: %v", err) } + if err := deleteLabelsByRepoID(sess, repoID); err != nil { + return err + } + // Delete Issues and related objects var attachmentPaths []string if attachmentPaths, err = deleteIssuesByRepoID(sess, repoID); err != nil { From a461d90415d0ab216da83e990a3f5d9849421f6f Mon Sep 17 00:00:00 2001 From: 6543 <6543@obermui.de> Date: Sat, 20 Mar 2021 02:37:53 +0100 Subject: [PATCH 180/205] Fix bug when upload on web (#15042) (#15055) * Fix bug when upload on web * move into own function Co-authored-by: 6543 <6543@obermui.de> Co-authored-by: zeripath Co-authored-by: Lunny Xiao Co-authored-by: zeripath --- modules/repofiles/upload.go | 50 +++++++++++++++++++++---------------- 1 file changed, 28 insertions(+), 22 deletions(-) diff --git a/modules/repofiles/upload.go b/modules/repofiles/upload.go index e3ec48ec0f..1659b4abd8 100644 --- a/modules/repofiles/upload.go +++ b/modules/repofiles/upload.go @@ -120,7 +120,6 @@ func UploadRepoFiles(repo *models.Repository, doer *models.User, opts *UploadRep return err } infos[i] = uploadInfo - } else if objectHash, err = t.HashObject(file); err != nil { return err } @@ -128,7 +127,6 @@ func UploadRepoFiles(repo *models.Repository, doer *models.User, opts *UploadRep // Add the object to the index if err := t.AddObjectToIndex("100644", objectHash, path.Join(opts.TreePath, uploadInfo.upload.Name)); err != nil { return err - } } @@ -165,28 +163,10 @@ func UploadRepoFiles(repo *models.Repository, doer *models.User, opts *UploadRep // OK now we can insert the data into the store - there's no way to clean up the store // once it's in there, it's in there. contentStore := &lfs.ContentStore{ObjectStorage: storage.LFS} - for _, uploadInfo := range infos { - if uploadInfo.lfsMetaObject == nil { - continue - } - exist, err := contentStore.Exists(uploadInfo.lfsMetaObject) - if err != nil { + for _, info := range infos { + if err := uploadToLFSContentStore(info, contentStore); err != nil { return cleanUpAfterFailure(&infos, t, err) } - if !exist { - file, err := os.Open(uploadInfo.upload.LocalPath()) - if err != nil { - return cleanUpAfterFailure(&infos, t, err) - } - defer file.Close() - // FIXME: Put regenerates the hash and copies the file over. - // I guess this strictly ensures the soundness of the store but this is inefficient. - if err := contentStore.Put(uploadInfo.lfsMetaObject, file); err != nil { - // OK Now we need to cleanup - // Can't clean up the store, once uploaded there they're there. - return cleanUpAfterFailure(&infos, t, err) - } - } } // Then push this tree to NewBranch @@ -196,3 +176,29 @@ func UploadRepoFiles(repo *models.Repository, doer *models.User, opts *UploadRep return models.DeleteUploads(uploads...) } + +func uploadToLFSContentStore(info uploadInfo, contentStore *lfs.ContentStore) error { + if info.lfsMetaObject == nil { + return nil + } + exist, err := contentStore.Exists(info.lfsMetaObject) + if err != nil { + return err + } + if !exist { + file, err := os.Open(info.upload.LocalPath()) + if err != nil { + return err + } + + defer file.Close() + // FIXME: Put regenerates the hash and copies the file over. + // I guess this strictly ensures the soundness of the store but this is inefficient. + if err := contentStore.Put(info.lfsMetaObject, file); err != nil { + // OK Now we need to cleanup + // Can't clean up the store, once uploaded there they're there. + return err + } + } + return nil +} From 7a85e228d847097e0f3f617a346f35d4c488271f Mon Sep 17 00:00:00 2001 From: zeripath Date: Sat, 20 Mar 2021 10:31:28 +0000 Subject: [PATCH 181/205] Update to goldmark 1.3.3 (#15059) (#15061) Backport #15059 Signed-off-by: Andrew Thornton --- go.mod | 2 +- go.sum | 2 + vendor/github.com/yuin/goldmark/README.md | 90 ++++- vendor/github.com/yuin/goldmark/ast/ast.go | 28 +- vendor/github.com/yuin/goldmark/ast/block.go | 23 +- vendor/github.com/yuin/goldmark/ast/inline.go | 2 +- .../yuin/goldmark/extension/ast/footnote.go | 35 +- .../yuin/goldmark/extension/footnote.go | 382 ++++++++++++++++-- .../yuin/goldmark/extension/linkify.go | 24 +- .../yuin/goldmark/extension/table.go | 117 +++++- vendor/github.com/yuin/goldmark/go.mod | 2 +- .../yuin/goldmark/parser/code_block.go | 17 + .../yuin/goldmark/parser/fcode_block.go | 4 + .../github.com/yuin/goldmark/parser/link.go | 8 - .../github.com/yuin/goldmark/parser/parser.go | 12 + .../yuin/goldmark/parser/raw_html.go | 9 +- vendor/github.com/yuin/goldmark/util/util.go | 16 +- vendor/modules.txt | 2 +- 18 files changed, 683 insertions(+), 92 deletions(-) diff --git a/go.mod b/go.mod index 08dfe1ae5c..05a5083f22 100644 --- a/go.mod +++ b/go.mod @@ -99,7 +99,7 @@ require ( github.com/urfave/cli v1.20.0 github.com/xanzy/go-gitlab v0.37.0 github.com/yohcop/openid-go v1.0.0 - github.com/yuin/goldmark v1.2.1 + github.com/yuin/goldmark v1.3.3 github.com/yuin/goldmark-highlighting v0.0.0-20200307114337-60d527fdb691 github.com/yuin/goldmark-meta v0.0.0-20191126180153-f0638e958b60 go.jolheiser.com/hcaptcha v0.0.4 diff --git a/go.sum b/go.sum index e674b9e231..be02d44c87 100644 --- a/go.sum +++ b/go.sum @@ -887,6 +887,8 @@ github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1 h1:ruQGxdhGHe7FWOJPT0mKs5+pD2Xs1Bm/kdGlHO04FmM= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.3.3 h1:37BdQwPx8VOSic8eDSWee6QL9mRpZRm9VJp/QugNrW0= +github.com/yuin/goldmark v1.3.3/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/yuin/goldmark-highlighting v0.0.0-20200307114337-60d527fdb691 h1:VWSxtAiQNh3zgHJpdpkpVYjTPqRE3P6UZCOPa1nRDio= github.com/yuin/goldmark-highlighting v0.0.0-20200307114337-60d527fdb691/go.mod h1:YLF3kDffRfUH/bTxOxHhV6lxwIB3Vfj91rEwNMS9MXo= github.com/yuin/goldmark-meta v0.0.0-20191126180153-f0638e958b60 h1:gZucqLjL1eDzVWrXj4uiWeMbAopJlBR2mKQAsTGdPwo= diff --git a/vendor/github.com/yuin/goldmark/README.md b/vendor/github.com/yuin/goldmark/README.md index 8cf7c5a0eb..f5a998d2b5 100644 --- a/vendor/github.com/yuin/goldmark/README.md +++ b/vendor/github.com/yuin/goldmark/README.md @@ -1,7 +1,7 @@ goldmark ========================================== -[![http://godoc.org/github.com/yuin/goldmark](https://godoc.org/github.com/yuin/goldmark?status.svg)](http://godoc.org/github.com/yuin/goldmark) +[![https://pkg.go.dev/github.com/yuin/goldmark](https://pkg.go.dev/badge/github.com/yuin/goldmark.svg)](https://pkg.go.dev/github.com/yuin/goldmark) [![https://github.com/yuin/goldmark/actions?query=workflow:test](https://github.com/yuin/goldmark/workflows/test/badge.svg?branch=master&event=push)](https://github.com/yuin/goldmark/actions?query=workflow:test) [![https://coveralls.io/github/yuin/goldmark](https://coveralls.io/repos/github/yuin/goldmark/badge.svg?branch=master)](https://coveralls.io/github/yuin/goldmark) [![https://goreportcard.com/report/github.com/yuin/goldmark](https://goreportcard.com/badge/github.com/yuin/goldmark)](https://goreportcard.com/report/github.com/yuin/goldmark) @@ -173,6 +173,7 @@ Parser and Renderer options - This extension enables Table, Strikethrough, Linkify and TaskList. - This extension does not filter tags defined in [6.11: Disallowed Raw HTML (extension)](https://github.github.com/gfm/#disallowed-raw-html-extension-). If you need to filter HTML tags, see [Security](#security). + - If you need to parse github emojis, you can use [goldmark-emoji](https://github.com/yuin/goldmark-emoji) extension. - `extension.DefinitionList` - [PHP Markdown Extra: Definition lists](https://michelf.ca/projects/php-markdown/extra/#def-list) - `extension.Footnote` @@ -279,13 +280,96 @@ markdown := goldmark.New( []byte("https:"), }), extension.WithLinkifyURLRegexp( - xurls.Strict(), + xurls.Strict, ), ), ), ) ``` +### Footnotes extension + +The Footnote extension implements [PHP Markdown Extra: Footnotes](https://michelf.ca/projects/php-markdown/extra/#footnotes). + +This extension has some options: + +| Functional option | Type | Description | +| ----------------- | ---- | ----------- | +| `extension.WithFootnoteIDPrefix` | `[]byte` | a prefix for the id attributes.| +| `extension.WithFootnoteIDPrefixFunction` | `func(gast.Node) []byte` | a function that determines the id attribute for given Node.| +| `extension.WithFootnoteLinkTitle` | `[]byte` | an optional title attribute for footnote links.| +| `extension.WithFootnoteBacklinkTitle` | `[]byte` | an optional title attribute for footnote backlinks. | +| `extension.WithFootnoteLinkClass` | `[]byte` | a class for footnote links. This defaults to `footnote-ref`. | +| `extension.WithFootnoteBacklinkClass` | `[]byte` | a class for footnote backlinks. This defaults to `footnote-backref`. | +| `extension.WithFootnoteBacklinkHTML` | `[]byte` | a class for footnote backlinks. This defaults to `↩︎`. | + +Some options can have special substitutions. Occurances of “^^” in the string will be replaced by the corresponding footnote number in the HTML output. Occurances of “%%” will be replaced by a number for the reference (footnotes can have multiple references). + +`extension.WithFootnoteIDPrefix` and `extension.WithFootnoteIDPrefixFunction` are useful if you have multiple Markdown documents displayed inside one HTML document to avoid footnote ids to clash each other. + +`extension.WithFootnoteIDPrefix` sets fixed id prefix, so you may write codes like the following: + +```go +for _, path := range files { + source := readAll(path) + prefix := getPrefix(path) + + markdown := goldmark.New( + goldmark.WithExtensions( + NewFootnote( + WithFootnoteIDPrefix([]byte(path)), + ), + ), + ) + var b bytes.Buffer + err := markdown.Convert(source, &b) + if err != nil { + t.Error(err.Error()) + } +} +``` + +`extension.WithFootnoteIDPrefixFunction` determines an id prefix by calling given function, so you may write codes like the following: + +```go +markdown := goldmark.New( + goldmark.WithExtensions( + NewFootnote( + WithFootnoteIDPrefixFunction(func(n gast.Node) []byte { + v, ok := n.OwnerDocument().Meta()["footnote-prefix"] + if ok { + return util.StringToReadOnlyBytes(v.(string)) + } + return nil + }), + ), + ), +) + +for _, path := range files { + source := readAll(path) + var b bytes.Buffer + + doc := markdown.Parser().Parse(text.NewReader(source)) + doc.Meta()["footnote-prefix"] = getPrefix(path) + err := markdown.Renderer().Render(&b, source, doc) +} +``` + +You can use [goldmark-meta](https://github.com/yuin/goldmark-meta) to define a id prefix in the markdown document: + + +```markdown +--- +title: document title +slug: article1 +footnote-prefix: article1 +--- + +# My article + +``` + Security -------------------- By default, goldmark does not render raw HTML or potentially-dangerous URLs. @@ -336,6 +420,8 @@ Extensions extension for the goldmark Markdown parser. - [goldmark-highlighting](https://github.com/yuin/goldmark-highlighting): A syntax-highlighting extension for the goldmark markdown parser. +- [goldmark-emoji](https://github.com/yuin/goldmark-emoji): An emoji + extension for the goldmark Markdown parser. - [goldmark-mathjax](https://github.com/litao91/goldmark-mathjax): Mathjax support for the goldmark markdown parser goldmark internal(for extension developers) diff --git a/vendor/github.com/yuin/goldmark/ast/ast.go b/vendor/github.com/yuin/goldmark/ast/ast.go index 66059e94cc..3719ebbd8d 100644 --- a/vendor/github.com/yuin/goldmark/ast/ast.go +++ b/vendor/github.com/yuin/goldmark/ast/ast.go @@ -45,11 +45,6 @@ type Attribute struct { Value interface{} } -var attrNameIDS = []byte("#") -var attrNameID = []byte("id") -var attrNameClassS = []byte(".") -var attrNameClass = []byte("class") - // A Node interface defines basic AST node functionalities. type Node interface { // Type returns a type of this node. @@ -116,6 +111,11 @@ type Node interface { // tail of the children. InsertAfter(self, v1, insertee Node) + // OwnerDocument returns this node's owner document. + // If this node is not a child of the Document node, OwnerDocument + // returns nil. + OwnerDocument() *Document + // Dump dumps an AST tree structure to stdout. // This function completely aimed for debugging. // level is a indent level. Implementer should indent informations with @@ -169,7 +169,7 @@ type Node interface { RemoveAttributes() } -// A BaseNode struct implements the Node interface. +// A BaseNode struct implements the Node interface partialliy. type BaseNode struct { firstChild Node lastChild Node @@ -358,6 +358,22 @@ func (n *BaseNode) InsertBefore(self, v1, insertee Node) { } } +// OwnerDocument implements Node.OwnerDocument +func (n *BaseNode) OwnerDocument() *Document { + d := n.Parent() + for { + p := d.Parent() + if p == nil { + if v, ok := d.(*Document); ok { + return v + } + break + } + d = p + } + return nil +} + // Text implements Node.Text . func (n *BaseNode) Text(source []byte) []byte { var buf bytes.Buffer diff --git a/vendor/github.com/yuin/goldmark/ast/block.go b/vendor/github.com/yuin/goldmark/ast/block.go index f5bca33fe9..fc0b3c2e02 100644 --- a/vendor/github.com/yuin/goldmark/ast/block.go +++ b/vendor/github.com/yuin/goldmark/ast/block.go @@ -7,7 +7,7 @@ import ( textm "github.com/yuin/goldmark/text" ) -// A BaseBlock struct implements the Node interface. +// A BaseBlock struct implements the Node interface partialliy. type BaseBlock struct { BaseNode blankPreviousLines bool @@ -50,6 +50,8 @@ func (b *BaseBlock) SetLines(v *textm.Segments) { // A Document struct is a root node of Markdown text. type Document struct { BaseBlock + + meta map[string]interface{} } // KindDocument is a NodeKind of the Document node. @@ -70,10 +72,29 @@ func (n *Document) Kind() NodeKind { return KindDocument } +// OwnerDocument implements Node.OwnerDocument +func (n *Document) OwnerDocument() *Document { + return n +} + +// Meta returns metadata of this document. +func (n *Document) Meta() map[string]interface{} { + if n.meta == nil { + n.meta = map[string]interface{}{} + } + return n.meta +} + +// SetMeta sets given metadata to this document. +func (n *Document) SetMeta(meta map[string]interface{}) { + n.meta = meta +} + // NewDocument returns a new Document node. func NewDocument() *Document { return &Document{ BaseBlock: BaseBlock{}, + meta: nil, } } diff --git a/vendor/github.com/yuin/goldmark/ast/inline.go b/vendor/github.com/yuin/goldmark/ast/inline.go index 23dcad4bc9..b221695bd7 100644 --- a/vendor/github.com/yuin/goldmark/ast/inline.go +++ b/vendor/github.com/yuin/goldmark/ast/inline.go @@ -8,7 +8,7 @@ import ( "github.com/yuin/goldmark/util" ) -// A BaseInline struct implements the Node interface. +// A BaseInline struct implements the Node interface partialliy. type BaseInline struct { BaseNode } diff --git a/vendor/github.com/yuin/goldmark/extension/ast/footnote.go b/vendor/github.com/yuin/goldmark/extension/ast/footnote.go index 835f8478b3..dedbab4f8b 100644 --- a/vendor/github.com/yuin/goldmark/extension/ast/footnote.go +++ b/vendor/github.com/yuin/goldmark/extension/ast/footnote.go @@ -2,6 +2,7 @@ package ast import ( "fmt" + gast "github.com/yuin/goldmark/ast" ) @@ -9,13 +10,15 @@ import ( // (PHP Markdown Extra) text. type FootnoteLink struct { gast.BaseInline - Index int + Index int + RefCount int } // Dump implements Node.Dump. func (n *FootnoteLink) Dump(source []byte, level int) { m := map[string]string{} m["Index"] = fmt.Sprintf("%v", n.Index) + m["RefCount"] = fmt.Sprintf("%v", n.RefCount) gast.DumpHelper(n, source, level, m, nil) } @@ -30,36 +33,40 @@ func (n *FootnoteLink) Kind() gast.NodeKind { // NewFootnoteLink returns a new FootnoteLink node. func NewFootnoteLink(index int) *FootnoteLink { return &FootnoteLink{ - Index: index, + Index: index, + RefCount: 0, } } -// A FootnoteBackLink struct represents a link to a footnote of Markdown +// A FootnoteBacklink struct represents a link to a footnote of Markdown // (PHP Markdown Extra) text. -type FootnoteBackLink struct { +type FootnoteBacklink struct { gast.BaseInline - Index int + Index int + RefCount int } // Dump implements Node.Dump. -func (n *FootnoteBackLink) Dump(source []byte, level int) { +func (n *FootnoteBacklink) Dump(source []byte, level int) { m := map[string]string{} m["Index"] = fmt.Sprintf("%v", n.Index) + m["RefCount"] = fmt.Sprintf("%v", n.RefCount) gast.DumpHelper(n, source, level, m, nil) } -// KindFootnoteBackLink is a NodeKind of the FootnoteBackLink node. -var KindFootnoteBackLink = gast.NewNodeKind("FootnoteBackLink") +// KindFootnoteBacklink is a NodeKind of the FootnoteBacklink node. +var KindFootnoteBacklink = gast.NewNodeKind("FootnoteBacklink") // Kind implements Node.Kind. -func (n *FootnoteBackLink) Kind() gast.NodeKind { - return KindFootnoteBackLink +func (n *FootnoteBacklink) Kind() gast.NodeKind { + return KindFootnoteBacklink } -// NewFootnoteBackLink returns a new FootnoteBackLink node. -func NewFootnoteBackLink(index int) *FootnoteBackLink { - return &FootnoteBackLink{ - Index: index, +// NewFootnoteBacklink returns a new FootnoteBacklink node. +func NewFootnoteBacklink(index int) *FootnoteBacklink { + return &FootnoteBacklink{ + Index: index, + RefCount: 0, } } diff --git a/vendor/github.com/yuin/goldmark/extension/footnote.go b/vendor/github.com/yuin/goldmark/extension/footnote.go index ede72db878..62f5ee61c6 100644 --- a/vendor/github.com/yuin/goldmark/extension/footnote.go +++ b/vendor/github.com/yuin/goldmark/extension/footnote.go @@ -2,6 +2,8 @@ package extension import ( "bytes" + "strconv" + "github.com/yuin/goldmark" gast "github.com/yuin/goldmark/ast" "github.com/yuin/goldmark/extension/ast" @@ -10,10 +12,10 @@ import ( "github.com/yuin/goldmark/renderer/html" "github.com/yuin/goldmark/text" "github.com/yuin/goldmark/util" - "strconv" ) var footnoteListKey = parser.NewContextKey() +var footnoteLinkListKey = parser.NewContextKey() type footnoteBlockParser struct { } @@ -164,7 +166,20 @@ func (s *footnoteParser) Parse(parent gast.Node, block text.Reader, pc parser.Co return nil } - return ast.NewFootnoteLink(index) + fnlink := ast.NewFootnoteLink(index) + var fnlist []*ast.FootnoteLink + if tmp := pc.Get(footnoteLinkListKey); tmp != nil { + fnlist = tmp.([]*ast.FootnoteLink) + } else { + fnlist = []*ast.FootnoteLink{} + pc.Set(footnoteLinkListKey, fnlist) + } + pc.Set(footnoteLinkListKey, append(fnlist, fnlink)) + if line[0] == '!' { + parent.AppendChild(parent, gast.NewTextSegment(text.NewSegment(segment.Start, segment.Start+1))) + } + + return fnlink } type footnoteASTTransformer struct { @@ -180,23 +195,46 @@ func NewFootnoteASTTransformer() parser.ASTTransformer { func (a *footnoteASTTransformer) Transform(node *gast.Document, reader text.Reader, pc parser.Context) { var list *ast.FootnoteList - if tlist := pc.Get(footnoteListKey); tlist != nil { - list = tlist.(*ast.FootnoteList) - } else { + var fnlist []*ast.FootnoteLink + if tmp := pc.Get(footnoteListKey); tmp != nil { + list = tmp.(*ast.FootnoteList) + } + if tmp := pc.Get(footnoteLinkListKey); tmp != nil { + fnlist = tmp.([]*ast.FootnoteLink) + } + + pc.Set(footnoteListKey, nil) + pc.Set(footnoteLinkListKey, nil) + + if list == nil { return } - pc.Set(footnoteListKey, nil) + + counter := map[int]int{} + if fnlist != nil { + for _, fnlink := range fnlist { + if fnlink.Index >= 0 { + counter[fnlink.Index]++ + } + } + for _, fnlink := range fnlist { + fnlink.RefCount = counter[fnlink.Index] + } + } for footnote := list.FirstChild(); footnote != nil; { var container gast.Node = footnote next := footnote.NextSibling() if fc := container.LastChild(); fc != nil && gast.IsParagraph(fc) { container = fc } - index := footnote.(*ast.Footnote).Index + fn := footnote.(*ast.Footnote) + index := fn.Index if index < 0 { list.RemoveChild(list, footnote) } else { - container.AppendChild(container, ast.NewFootnoteBackLink(index)) + backLink := ast.NewFootnoteBacklink(index) + backLink.RefCount = counter[index] + container.AppendChild(container, backLink) } footnote = next } @@ -214,19 +252,250 @@ func (a *footnoteASTTransformer) Transform(node *gast.Document, reader text.Read node.AppendChild(node, list) } +// FootnoteConfig holds configuration values for the footnote extension. +// +// Link* and Backlink* configurations have some variables: +// Occurrances of “^^” in the string will be replaced by the +// corresponding footnote number in the HTML output. +// Occurrances of “%%” will be replaced by a number for the +// reference (footnotes can have multiple references). +type FootnoteConfig struct { + html.Config + + // IDPrefix is a prefix for the id attributes generated by footnotes. + IDPrefix []byte + + // IDPrefix is a function that determines the id attribute for given Node. + IDPrefixFunction func(gast.Node) []byte + + // LinkTitle is an optional title attribute for footnote links. + LinkTitle []byte + + // BacklinkTitle is an optional title attribute for footnote backlinks. + BacklinkTitle []byte + + // LinkClass is a class for footnote links. + LinkClass []byte + + // BacklinkClass is a class for footnote backlinks. + BacklinkClass []byte + + // BacklinkHTML is an HTML content for footnote backlinks. + BacklinkHTML []byte +} + +// FootnoteOption interface is a functional option interface for the extension. +type FootnoteOption interface { + renderer.Option + // SetFootnoteOption sets given option to the extension. + SetFootnoteOption(*FootnoteConfig) +} + +// NewFootnoteConfig returns a new Config with defaults. +func NewFootnoteConfig() FootnoteConfig { + return FootnoteConfig{ + Config: html.NewConfig(), + LinkTitle: []byte(""), + BacklinkTitle: []byte(""), + LinkClass: []byte("footnote-ref"), + BacklinkClass: []byte("footnote-backref"), + BacklinkHTML: []byte("↩︎"), + } +} + +// SetOption implements renderer.SetOptioner. +func (c *FootnoteConfig) SetOption(name renderer.OptionName, value interface{}) { + switch name { + case optFootnoteIDPrefixFunction: + c.IDPrefixFunction = value.(func(gast.Node) []byte) + case optFootnoteIDPrefix: + c.IDPrefix = value.([]byte) + case optFootnoteLinkTitle: + c.LinkTitle = value.([]byte) + case optFootnoteBacklinkTitle: + c.BacklinkTitle = value.([]byte) + case optFootnoteLinkClass: + c.LinkClass = value.([]byte) + case optFootnoteBacklinkClass: + c.BacklinkClass = value.([]byte) + case optFootnoteBacklinkHTML: + c.BacklinkHTML = value.([]byte) + default: + c.Config.SetOption(name, value) + } +} + +type withFootnoteHTMLOptions struct { + value []html.Option +} + +func (o *withFootnoteHTMLOptions) SetConfig(c *renderer.Config) { + if o.value != nil { + for _, v := range o.value { + v.(renderer.Option).SetConfig(c) + } + } +} + +func (o *withFootnoteHTMLOptions) SetFootnoteOption(c *FootnoteConfig) { + if o.value != nil { + for _, v := range o.value { + v.SetHTMLOption(&c.Config) + } + } +} + +// WithFootnoteHTMLOptions is functional option that wraps goldmark HTMLRenderer options. +func WithFootnoteHTMLOptions(opts ...html.Option) FootnoteOption { + return &withFootnoteHTMLOptions{opts} +} + +const optFootnoteIDPrefix renderer.OptionName = "FootnoteIDPrefix" + +type withFootnoteIDPrefix struct { + value []byte +} + +func (o *withFootnoteIDPrefix) SetConfig(c *renderer.Config) { + c.Options[optFootnoteIDPrefix] = o.value +} + +func (o *withFootnoteIDPrefix) SetFootnoteOption(c *FootnoteConfig) { + c.IDPrefix = o.value +} + +// WithFootnoteIDPrefix is a functional option that is a prefix for the id attributes generated by footnotes. +func WithFootnoteIDPrefix(a []byte) FootnoteOption { + return &withFootnoteIDPrefix{a} +} + +const optFootnoteIDPrefixFunction renderer.OptionName = "FootnoteIDPrefixFunction" + +type withFootnoteIDPrefixFunction struct { + value func(gast.Node) []byte +} + +func (o *withFootnoteIDPrefixFunction) SetConfig(c *renderer.Config) { + c.Options[optFootnoteIDPrefixFunction] = o.value +} + +func (o *withFootnoteIDPrefixFunction) SetFootnoteOption(c *FootnoteConfig) { + c.IDPrefixFunction = o.value +} + +// WithFootnoteIDPrefixFunction is a functional option that is a prefix for the id attributes generated by footnotes. +func WithFootnoteIDPrefixFunction(a func(gast.Node) []byte) FootnoteOption { + return &withFootnoteIDPrefixFunction{a} +} + +const optFootnoteLinkTitle renderer.OptionName = "FootnoteLinkTitle" + +type withFootnoteLinkTitle struct { + value []byte +} + +func (o *withFootnoteLinkTitle) SetConfig(c *renderer.Config) { + c.Options[optFootnoteLinkTitle] = o.value +} + +func (o *withFootnoteLinkTitle) SetFootnoteOption(c *FootnoteConfig) { + c.LinkTitle = o.value +} + +// WithFootnoteLinkTitle is a functional option that is an optional title attribute for footnote links. +func WithFootnoteLinkTitle(a []byte) FootnoteOption { + return &withFootnoteLinkTitle{a} +} + +const optFootnoteBacklinkTitle renderer.OptionName = "FootnoteBacklinkTitle" + +type withFootnoteBacklinkTitle struct { + value []byte +} + +func (o *withFootnoteBacklinkTitle) SetConfig(c *renderer.Config) { + c.Options[optFootnoteBacklinkTitle] = o.value +} + +func (o *withFootnoteBacklinkTitle) SetFootnoteOption(c *FootnoteConfig) { + c.BacklinkTitle = o.value +} + +// WithFootnoteBacklinkTitle is a functional option that is an optional title attribute for footnote backlinks. +func WithFootnoteBacklinkTitle(a []byte) FootnoteOption { + return &withFootnoteBacklinkTitle{a} +} + +const optFootnoteLinkClass renderer.OptionName = "FootnoteLinkClass" + +type withFootnoteLinkClass struct { + value []byte +} + +func (o *withFootnoteLinkClass) SetConfig(c *renderer.Config) { + c.Options[optFootnoteLinkClass] = o.value +} + +func (o *withFootnoteLinkClass) SetFootnoteOption(c *FootnoteConfig) { + c.LinkClass = o.value +} + +// WithFootnoteLinkClass is a functional option that is a class for footnote links. +func WithFootnoteLinkClass(a []byte) FootnoteOption { + return &withFootnoteLinkClass{a} +} + +const optFootnoteBacklinkClass renderer.OptionName = "FootnoteBacklinkClass" + +type withFootnoteBacklinkClass struct { + value []byte +} + +func (o *withFootnoteBacklinkClass) SetConfig(c *renderer.Config) { + c.Options[optFootnoteBacklinkClass] = o.value +} + +func (o *withFootnoteBacklinkClass) SetFootnoteOption(c *FootnoteConfig) { + c.BacklinkClass = o.value +} + +// WithFootnoteBacklinkClass is a functional option that is a class for footnote backlinks. +func WithFootnoteBacklinkClass(a []byte) FootnoteOption { + return &withFootnoteBacklinkClass{a} +} + +const optFootnoteBacklinkHTML renderer.OptionName = "FootnoteBacklinkHTML" + +type withFootnoteBacklinkHTML struct { + value []byte +} + +func (o *withFootnoteBacklinkHTML) SetConfig(c *renderer.Config) { + c.Options[optFootnoteBacklinkHTML] = o.value +} + +func (o *withFootnoteBacklinkHTML) SetFootnoteOption(c *FootnoteConfig) { + c.BacklinkHTML = o.value +} + +// WithFootnoteBacklinkHTML is an HTML content for footnote backlinks. +func WithFootnoteBacklinkHTML(a []byte) FootnoteOption { + return &withFootnoteBacklinkHTML{a} +} + // FootnoteHTMLRenderer is a renderer.NodeRenderer implementation that // renders FootnoteLink nodes. type FootnoteHTMLRenderer struct { - html.Config + FootnoteConfig } // NewFootnoteHTMLRenderer returns a new FootnoteHTMLRenderer. -func NewFootnoteHTMLRenderer(opts ...html.Option) renderer.NodeRenderer { +func NewFootnoteHTMLRenderer(opts ...FootnoteOption) renderer.NodeRenderer { r := &FootnoteHTMLRenderer{ - Config: html.NewConfig(), + FootnoteConfig: NewFootnoteConfig(), } for _, opt := range opts { - opt.SetHTMLOption(&r.Config) + opt.SetFootnoteOption(&r.FootnoteConfig) } return r } @@ -234,7 +503,7 @@ func NewFootnoteHTMLRenderer(opts ...html.Option) renderer.NodeRenderer { // RegisterFuncs implements renderer.NodeRenderer.RegisterFuncs. func (r *FootnoteHTMLRenderer) RegisterFuncs(reg renderer.NodeRendererFuncRegisterer) { reg.Register(ast.KindFootnoteLink, r.renderFootnoteLink) - reg.Register(ast.KindFootnoteBackLink, r.renderFootnoteBackLink) + reg.Register(ast.KindFootnoteBacklink, r.renderFootnoteBacklink) reg.Register(ast.KindFootnote, r.renderFootnote) reg.Register(ast.KindFootnoteList, r.renderFootnoteList) } @@ -243,25 +512,45 @@ func (r *FootnoteHTMLRenderer) renderFootnoteLink(w util.BufWriter, source []byt if entering { n := node.(*ast.FootnoteLink) is := strconv.Itoa(n.Index) - _, _ = w.WriteString(``) + _, _ = w.WriteString(`" class="`) + _, _ = w.Write(applyFootnoteTemplate(r.FootnoteConfig.LinkClass, + n.Index, n.RefCount)) + if len(r.FootnoteConfig.LinkTitle) > 0 { + _, _ = w.WriteString(`" title="`) + _, _ = w.Write(util.EscapeHTML(applyFootnoteTemplate(r.FootnoteConfig.LinkTitle, n.Index, n.RefCount))) + } + _, _ = w.WriteString(`" role="doc-noteref">`) + _, _ = w.WriteString(is) _, _ = w.WriteString(``) } return gast.WalkContinue, nil } -func (r *FootnoteHTMLRenderer) renderFootnoteBackLink(w util.BufWriter, source []byte, node gast.Node, entering bool) (gast.WalkStatus, error) { +func (r *FootnoteHTMLRenderer) renderFootnoteBacklink(w util.BufWriter, source []byte, node gast.Node, entering bool) (gast.WalkStatus, error) { if entering { - n := node.(*ast.FootnoteBackLink) + n := node.(*ast.FootnoteBacklink) is := strconv.Itoa(n.Index) - _, _ = w.WriteString(` `) - _, _ = w.WriteString("↩︎") + _, _ = w.WriteString(`" class="`) + _, _ = w.Write(applyFootnoteTemplate(r.FootnoteConfig.BacklinkClass, n.Index, n.RefCount)) + if len(r.FootnoteConfig.BacklinkTitle) > 0 { + _, _ = w.WriteString(`" title="`) + _, _ = w.Write(util.EscapeHTML(applyFootnoteTemplate(r.FootnoteConfig.BacklinkTitle, n.Index, n.RefCount))) + } + _, _ = w.WriteString(`" role="doc-backlink">`) + _, _ = w.Write(applyFootnoteTemplate(r.FootnoteConfig.BacklinkHTML, n.Index, n.RefCount)) _, _ = w.WriteString(``) } return gast.WalkContinue, nil @@ -271,7 +560,9 @@ func (r *FootnoteHTMLRenderer) renderFootnote(w util.BufWriter, source []byte, n n := node.(*ast.Footnote) is := strconv.Itoa(n.Index) if entering { - _, _ = w.WriteString(`
  • \^{}\[\]` + "`" + `]*)?`) +var wwwURLRegxp = regexp.MustCompile(`^www\.[-a-zA-Z0-9@:%._\+~#=]{1,256}\.[a-z]+(?:[/#?][-a-zA-Z0-9@:%_\+.~#!?&/=\(\);,'">\^{}\[\]` + "`" + `]*)?`) -var urlRegexp = regexp.MustCompile(`^(?:http|https|ftp):\/\/(?:www\.)?[-a-zA-Z0-9@:%._\+~#=]{2,256}\.[a-z]+(?:(?:/|[#?])[-a-zA-Z0-9@:%_+.~#$!?&//=\(\);,'">\^{}\[\]` + "`" + `]*)?`) +var urlRegexp = regexp.MustCompile(`^(?:http|https|ftp)://[-a-zA-Z0-9@:%._\+~#=]{1,256}\.[a-z]+(?::\d+)?(?:[/#?][-a-zA-Z0-9@:%_+.~#$!?&/=\(\);,'">\^{}\[\]` + "`" + `]*)?`) // An LinkifyConfig struct is a data structure that holds configuration of the // Linkify extension. @@ -24,10 +24,12 @@ type LinkifyConfig struct { EmailRegexp *regexp.Regexp } -const optLinkifyAllowedProtocols parser.OptionName = "LinkifyAllowedProtocols" -const optLinkifyURLRegexp parser.OptionName = "LinkifyURLRegexp" -const optLinkifyWWWRegexp parser.OptionName = "LinkifyWWWRegexp" -const optLinkifyEmailRegexp parser.OptionName = "LinkifyEmailRegexp" +const ( + optLinkifyAllowedProtocols parser.OptionName = "LinkifyAllowedProtocols" + optLinkifyURLRegexp parser.OptionName = "LinkifyURLRegexp" + optLinkifyWWWRegexp parser.OptionName = "LinkifyWWWRegexp" + optLinkifyEmailRegexp parser.OptionName = "LinkifyEmailRegexp" +) // SetOption implements SetOptioner. func (c *LinkifyConfig) SetOption(name parser.OptionName, value interface{}) { @@ -156,10 +158,12 @@ func (s *linkifyParser) Trigger() []byte { return []byte{' ', '*', '_', '~', '('} } -var protoHTTP = []byte("http:") -var protoHTTPS = []byte("https:") -var protoFTP = []byte("ftp:") -var domainWWW = []byte("www.") +var ( + protoHTTP = []byte("http:") + protoHTTPS = []byte("https:") + protoFTP = []byte("ftp:") + domainWWW = []byte("www.") +) func (s *linkifyParser) Parse(parent ast.Node, block text.Reader, pc parser.Context) ast.Node { if pc.IsInLinkLabel() { diff --git a/vendor/github.com/yuin/goldmark/extension/table.go b/vendor/github.com/yuin/goldmark/extension/table.go index f0e994e838..c637b99f04 100644 --- a/vendor/github.com/yuin/goldmark/extension/table.go +++ b/vendor/github.com/yuin/goldmark/extension/table.go @@ -15,6 +15,14 @@ import ( "github.com/yuin/goldmark/util" ) +var escapedPipeCellListKey = parser.NewContextKey() + +type escapedPipeCell struct { + Cell *ast.TableCell + Pos []int + Transformed bool +} + // TableCellAlignMethod indicates how are table cells aligned in HTML format.indicates how are table cells aligned in HTML format. type TableCellAlignMethod int @@ -148,7 +156,7 @@ func (b *tableParagraphTransformer) Transform(node *gast.Paragraph, reader text. if alignments == nil { continue } - header := b.parseRow(lines.At(i-1), alignments, true, reader) + header := b.parseRow(lines.At(i-1), alignments, true, reader, pc) if header == nil || len(alignments) != header.ChildCount() { return } @@ -156,7 +164,7 @@ func (b *tableParagraphTransformer) Transform(node *gast.Paragraph, reader text. table.Alignments = alignments table.AppendChild(table, ast.NewTableHeader(header)) for j := i + 1; j < lines.Len(); j++ { - table.AppendChild(table, b.parseRow(lines.At(j), alignments, false, reader)) + table.AppendChild(table, b.parseRow(lines.At(j), alignments, false, reader, pc)) } node.Lines().SetSliced(0, i-1) node.Parent().InsertAfter(node.Parent(), node, table) @@ -170,7 +178,7 @@ func (b *tableParagraphTransformer) Transform(node *gast.Paragraph, reader text. } } -func (b *tableParagraphTransformer) parseRow(segment text.Segment, alignments []ast.Alignment, isHeader bool, reader text.Reader) *ast.TableRow { +func (b *tableParagraphTransformer) parseRow(segment text.Segment, alignments []ast.Alignment, isHeader bool, reader text.Reader, pc parser.Context) *ast.TableRow { source := reader.Source() line := segment.Value(source) pos := 0 @@ -194,18 +202,39 @@ func (b *tableParagraphTransformer) parseRow(segment text.Segment, alignments [] } else { alignment = alignments[i] } - closure := util.FindClosure(line[pos:], byte(0), '|', true, false) - if closure < 0 { - closure = len(line[pos:]) - } + + var escapedCell *escapedPipeCell node := ast.NewTableCell() - seg := text.NewSegment(segment.Start+pos, segment.Start+pos+closure) + node.Alignment = alignment + hasBacktick := false + closure := pos + for ; closure < limit; closure++ { + if line[closure] == '`' { + hasBacktick = true + } + if line[closure] == '|' { + if closure == 0 || line[closure-1] != '\\' { + break + } else if hasBacktick { + if escapedCell == nil { + escapedCell = &escapedPipeCell{node, []int{}, false} + escapedList := pc.ComputeIfAbsent(escapedPipeCellListKey, + func() interface{} { + return []*escapedPipeCell{} + }).([]*escapedPipeCell) + escapedList = append(escapedList, escapedCell) + pc.Set(escapedPipeCellListKey, escapedList) + } + escapedCell.Pos = append(escapedCell.Pos, segment.Start+closure-1) + } + } + } + seg := text.NewSegment(segment.Start+pos, segment.Start+closure) seg = seg.TrimLeftSpace(source) seg = seg.TrimRightSpace(source) node.Lines().Append(seg) - node.Alignment = alignment row.AppendChild(row, node) - pos += closure + 1 + pos = closure + 1 } for ; i < len(alignments); i++ { row.AppendChild(row, ast.NewTableCell()) @@ -243,6 +272,61 @@ func (b *tableParagraphTransformer) parseDelimiter(segment text.Segment, reader return alignments } +type tableASTTransformer struct { +} + +var defaultTableASTTransformer = &tableASTTransformer{} + +// NewTableASTTransformer returns a parser.ASTTransformer for tables. +func NewTableASTTransformer() parser.ASTTransformer { + return defaultTableASTTransformer +} + +func (a *tableASTTransformer) Transform(node *gast.Document, reader text.Reader, pc parser.Context) { + lst := pc.Get(escapedPipeCellListKey) + if lst == nil { + return + } + pc.Set(escapedPipeCellListKey, nil) + for _, v := range lst.([]*escapedPipeCell) { + if v.Transformed { + continue + } + _ = gast.Walk(v.Cell, func(n gast.Node, entering bool) (gast.WalkStatus, error) { + if !entering || n.Kind() != gast.KindCodeSpan { + return gast.WalkContinue, nil + } + + for c := n.FirstChild(); c != nil; { + next := c.NextSibling() + if c.Kind() != gast.KindText { + c = next + continue + } + parent := c.Parent() + ts := &c.(*gast.Text).Segment + n := c + for _, v := range lst.([]*escapedPipeCell) { + for _, pos := range v.Pos { + if ts.Start <= pos && pos < ts.Stop { + segment := n.(*gast.Text).Segment + n1 := gast.NewRawTextSegment(segment.WithStop(pos)) + n2 := gast.NewRawTextSegment(segment.WithStart(pos + 1)) + parent.InsertAfter(parent, n, n1) + parent.InsertAfter(parent, n1, n2) + parent.RemoveChild(parent, n) + n = n2 + v.Transformed = true + } + } + } + c = next + } + return gast.WalkContinue, nil + }) + } +} + // TableHTMLRenderer is a renderer.NodeRenderer implementation that // renders Table nodes. type TableHTMLRenderer struct { @@ -419,7 +503,7 @@ func (r *TableHTMLRenderer) renderTableCell(w util.BufWriter, source []byte, nod cob.AppendByte(';') } style := fmt.Sprintf("text-align:%s", n.Alignment.String()) - cob.Append(util.StringToReadOnlyBytes(style)) + cob.AppendString(style) n.SetAttributeString("style", cob.Bytes()) } } @@ -454,9 +538,14 @@ func NewTable(opts ...TableOption) goldmark.Extender { } func (e *table) Extend(m goldmark.Markdown) { - m.Parser().AddOptions(parser.WithParagraphTransformers( - util.Prioritized(NewTableParagraphTransformer(), 200), - )) + m.Parser().AddOptions( + parser.WithParagraphTransformers( + util.Prioritized(NewTableParagraphTransformer(), 200), + ), + parser.WithASTTransformers( + util.Prioritized(defaultTableASTTransformer, 0), + ), + ) m.Renderer().AddOptions(renderer.WithNodeRenderers( util.Prioritized(NewTableHTMLRenderer(e.options...), 500), )) diff --git a/vendor/github.com/yuin/goldmark/go.mod b/vendor/github.com/yuin/goldmark/go.mod index a10efcad52..f76c1766fc 100644 --- a/vendor/github.com/yuin/goldmark/go.mod +++ b/vendor/github.com/yuin/goldmark/go.mod @@ -1,3 +1,3 @@ module github.com/yuin/goldmark -go 1.13 +go 1.15 diff --git a/vendor/github.com/yuin/goldmark/parser/code_block.go b/vendor/github.com/yuin/goldmark/parser/code_block.go index d02c21fc71..4b1863929f 100644 --- a/vendor/github.com/yuin/goldmark/parser/code_block.go +++ b/vendor/github.com/yuin/goldmark/parser/code_block.go @@ -49,6 +49,12 @@ func (b *codeBlockParser) Continue(node ast.Node, reader text.Reader, pc Context } reader.AdvanceAndSetPadding(pos, padding) _, segment = reader.PeekLine() + + // if code block line starts with a tab, keep a tab as it is. + if segment.Padding != 0 { + preserveLeadingTabInCodeBlock(&segment, reader) + } + node.Lines().Append(segment) reader.Advance(segment.Len() - 1) return Continue | NoChildren @@ -77,3 +83,14 @@ func (b *codeBlockParser) CanInterruptParagraph() bool { func (b *codeBlockParser) CanAcceptIndentedLine() bool { return true } + +func preserveLeadingTabInCodeBlock(segment *text.Segment, reader text.Reader) { + offsetWithPadding := reader.LineOffset() + sl, ss := reader.Position() + reader.SetPosition(sl, text.NewSegment(ss.Start-1, ss.Stop)) + if offsetWithPadding == reader.LineOffset() { + segment.Padding = 0 + segment.Start-- + } + reader.SetPosition(sl, ss) +} diff --git a/vendor/github.com/yuin/goldmark/parser/fcode_block.go b/vendor/github.com/yuin/goldmark/parser/fcode_block.go index f5b83eef7b..4801449194 100644 --- a/vendor/github.com/yuin/goldmark/parser/fcode_block.go +++ b/vendor/github.com/yuin/goldmark/parser/fcode_block.go @@ -71,6 +71,10 @@ func (b *fencedCodeBlockParser) Open(parent ast.Node, reader text.Reader, pc Con func (b *fencedCodeBlockParser) Continue(node ast.Node, reader text.Reader, pc Context) State { line, segment := reader.PeekLine() fdata := pc.Get(fencedCodeBlockInfoKey).(*fenceData) + // if code block line starts with a tab, keep a tab as it is. + if segment.Padding != 0 { + preserveLeadingTabInCodeBlock(&segment, reader) + } w, pos := util.IndentWidth(line, reader.LineOffset()) if w < 4 { i := pos diff --git a/vendor/github.com/yuin/goldmark/parser/link.go b/vendor/github.com/yuin/goldmark/parser/link.go index e7c6966f3d..c36cce5d90 100644 --- a/vendor/github.com/yuin/goldmark/parser/link.go +++ b/vendor/github.com/yuin/goldmark/parser/link.go @@ -2,7 +2,6 @@ package parser import ( "fmt" - "regexp" "strings" "github.com/yuin/goldmark/ast" @@ -113,8 +112,6 @@ func (s *linkParser) Trigger() []byte { return []byte{'!', '[', ']'} } -var linkDestinationRegexp = regexp.MustCompile(`\s*([^\s].+)`) -var linkTitleRegexp = regexp.MustCompile(`\s+(\)|["'\(].+)`) var linkBottom = NewContextKey() func (s *linkParser) Parse(parent ast.Node, block text.Reader, pc Context) ast.Node { @@ -293,20 +290,17 @@ func (s *linkParser) parseLink(parent ast.Node, last *linkLabelState, block text func parseLinkDestination(block text.Reader) ([]byte, bool) { block.SkipSpaces() line, _ := block.PeekLine() - buf := []byte{} if block.Peek() == '<' { i := 1 for i < len(line) { c := line[i] if c == '\\' && i < len(line)-1 && util.IsPunct(line[i+1]) { - buf = append(buf, '\\', line[i+1]) i += 2 continue } else if c == '>' { block.Advance(i + 1) return line[1:i], true } - buf = append(buf, c) i++ } return nil, false @@ -316,7 +310,6 @@ func parseLinkDestination(block text.Reader) ([]byte, bool) { for i < len(line) { c := line[i] if c == '\\' && i < len(line)-1 && util.IsPunct(line[i+1]) { - buf = append(buf, '\\', line[i+1]) i += 2 continue } else if c == '(' { @@ -329,7 +322,6 @@ func parseLinkDestination(block text.Reader) ([]byte, bool) { } else if util.IsSpace(c) { break } - buf = append(buf, c) i++ } block.Advance(i) diff --git a/vendor/github.com/yuin/goldmark/parser/parser.go b/vendor/github.com/yuin/goldmark/parser/parser.go index def13db666..e58b5ee936 100644 --- a/vendor/github.com/yuin/goldmark/parser/parser.go +++ b/vendor/github.com/yuin/goldmark/parser/parser.go @@ -138,6 +138,9 @@ type Context interface { // Get returns a value associated with the given key. Get(ContextKey) interface{} + // ComputeIfAbsent computes a value if a value associated with the given key is absent and returns the value. + ComputeIfAbsent(ContextKey, func() interface{}) interface{} + // Set sets the given value to the context. Set(ContextKey, interface{}) @@ -252,6 +255,15 @@ func (p *parseContext) Get(key ContextKey) interface{} { return p.store[key] } +func (p *parseContext) ComputeIfAbsent(key ContextKey, f func() interface{}) interface{} { + v := p.store[key] + if v == nil { + v = f() + p.store[key] = v + } + return v +} + func (p *parseContext) Set(key ContextKey, value interface{}) { p.store[key] = value } diff --git a/vendor/github.com/yuin/goldmark/parser/raw_html.go b/vendor/github.com/yuin/goldmark/parser/raw_html.go index d7ba414ff2..7fd696cc2c 100644 --- a/vendor/github.com/yuin/goldmark/parser/raw_html.go +++ b/vendor/github.com/yuin/goldmark/parser/raw_html.go @@ -2,10 +2,11 @@ package parser import ( "bytes" + "regexp" + "github.com/yuin/goldmark/ast" "github.com/yuin/goldmark/text" "github.com/yuin/goldmark/util" - "regexp" ) type rawHTMLParser struct { @@ -67,8 +68,6 @@ func (s *rawHTMLParser) parseSingleLineRegexp(reg *regexp.Regexp, block text.Rea return node } -var dummyMatch = [][]byte{} - func (s *rawHTMLParser) parseMultiLineRegexp(reg *regexp.Regexp, block text.Reader, pc Context) ast.Node { sline, ssegment := block.Position() if block.Match(reg) { @@ -102,7 +101,3 @@ func (s *rawHTMLParser) parseMultiLineRegexp(reg *regexp.Regexp, block text.Read } return nil } - -func (s *rawHTMLParser) CloseBlock(parent ast.Node, pc Context) { - // nothing to do -} diff --git a/vendor/github.com/yuin/goldmark/util/util.go b/vendor/github.com/yuin/goldmark/util/util.go index fc1438dc19..3ec73f54f3 100644 --- a/vendor/github.com/yuin/goldmark/util/util.go +++ b/vendor/github.com/yuin/goldmark/util/util.go @@ -37,6 +37,12 @@ func (b *CopyOnWriteBuffer) Write(value []byte) { b.buffer = append(b.buffer, value...) } +// WriteString writes given string to the buffer. +// WriteString allocate new buffer and clears it at the first time. +func (b *CopyOnWriteBuffer) WriteString(value string) { + b.Write(StringToReadOnlyBytes(value)) +} + // Append appends given bytes to the buffer. // Append copy buffer at the first time. func (b *CopyOnWriteBuffer) Append(value []byte) { @@ -49,6 +55,12 @@ func (b *CopyOnWriteBuffer) Append(value []byte) { b.buffer = append(b.buffer, value...) } +// AppendString appends given string to the buffer. +// AppendString copy buffer at the first time. +func (b *CopyOnWriteBuffer) AppendString(value string) { + b.Append(StringToReadOnlyBytes(value)) +} + // WriteByte writes the given byte to the buffer. // WriteByte allocate new buffer and clears it at the first time. func (b *CopyOnWriteBuffer) WriteByte(c byte) { @@ -804,7 +816,7 @@ func IsPunct(c byte) bool { return punctTable[c] == 1 } -// IsPunct returns true if the given rune is a punctuation, otherwise false. +// IsPunctRune returns true if the given rune is a punctuation, otherwise false. func IsPunctRune(r rune) bool { return int32(r) <= 256 && IsPunct(byte(r)) || unicode.IsPunct(r) } @@ -814,7 +826,7 @@ func IsSpace(c byte) bool { return spaceTable[c] == 1 } -// IsSpace returns true if the given rune is a space, otherwise false. +// IsSpaceRune returns true if the given rune is a space, otherwise false. func IsSpaceRune(r rune) bool { return int32(r) <= 256 && IsSpace(byte(r)) || unicode.IsSpace(r) } diff --git a/vendor/modules.txt b/vendor/modules.txt index 11373e3504..c05df2988b 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -745,7 +745,7 @@ github.com/xi2/xz # github.com/yohcop/openid-go v1.0.0 ## explicit github.com/yohcop/openid-go -# github.com/yuin/goldmark v1.2.1 +# github.com/yuin/goldmark v1.3.3 ## explicit github.com/yuin/goldmark github.com/yuin/goldmark/ast From d7a3bcdd70bf9152ea5a153cb1dd9d0c370e4792 Mon Sep 17 00:00:00 2001 From: 6543 <6543@obermui.de> Date: Sun, 21 Mar 2021 15:05:21 +0100 Subject: [PATCH 182/205] Changelog v1.13.5 (#15084) --- CHANGELOG.md | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4f0e1ac767..c91334d934 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,27 @@ This changelog goes through all the changes that have been made in each release without substantial changes to our git log; to see the highlights of what has been added to each release, please refer to the [blog](https://blog.gitea.io). +## [1.13.5](https://github.com/go-gitea/gitea/releases/tag/v1.13.5) - 2021-03-21 + +* SECURITY + * Update to goldmark 1.3.3 (#15059) (#15061) +* API + * Fix set milestone on PR creation (#14981) (#15001) + * Prevent panic when editing forked repos by API (#14960) (#14963) +* BUGFIXES + * Fix bug when upload on web (#15042) (#15055) + * Delete Labels & IssueLabels on Repo Delete too (#15039) (#15051) + * another clusterfuzz spotted issue (#15032) (#15034) + * Fix postgres ID sequences broken by recreate-table (#15015) (#15029) + * Fix several render issues (#14986) (#15013) + * Make sure sibling images get a link too (#14979) (#14995) + * Fix Anchor jumping with escaped query components (#14969) (#14977) + * fix release mail html template (#14976) + * Fix excluding more than two labels on issues list (#14962) (#14973) + * don't mark each comment poster as OP (#14971) (#14972) + * Add "captcha" to list of reserved usernames (#14930) + * Re-enable import local paths after reversion from #13610 (#14925) (#14927) + ## [1.13.4](https://github.com/go-gitea/gitea/releases/tag/v1.13.4) - 2021-03-07 * SECURITY From b0819efaeae1fb03a199d936af4cc475e71fcaf7 Mon Sep 17 00:00:00 2001 From: zeripath Date: Sun, 21 Mar 2021 15:16:07 +0000 Subject: [PATCH 183/205] Place wrapper around comment as diff to catch panics (#15085) (#15086) * Place wrapper around comment as diff to prevent panics * propagate the panic up Signed-off-by: Andrew Thornton --- services/gitdiff/gitdiff.go | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/services/gitdiff/gitdiff.go b/services/gitdiff/gitdiff.go index beb75c05e8..0d95817a44 100644 --- a/services/gitdiff/gitdiff.go +++ b/services/gitdiff/gitdiff.go @@ -1282,6 +1282,16 @@ func CommentAsDiff(c *models.Comment) (*Diff, error) { // CommentMustAsDiff executes AsDiff and logs the error instead of returning func CommentMustAsDiff(c *models.Comment) *Diff { + if c == nil { + return nil + } + defer func() { + if err := recover(); err != nil { + stack := log.Stack(2) + log.Error("PANIC whilst retrieving diff for comment[%d] Error: %v\nStack: %s", c.ID, err, stack) + panic(fmt.Errorf("PANIC whilst retrieving diff for comment[%d] Error: %v\nStack: %s", c.ID, err, stack)) + } + }() diff, err := CommentAsDiff(c) if err != nil { log.Warn("CommentMustAsDiff: %v", err) From 2f09e5775f1e9a7388cde03c70edd1957f619f1b Mon Sep 17 00:00:00 2001 From: silverwind Date: Sun, 21 Mar 2021 18:03:52 +0100 Subject: [PATCH 184/205] Fix markdown rendering in milestone content (#15056) (#15092) - Add missing markdown class for rendered markdown. - Increase font size of milestone name in list. Fixes: https://github.com/go-gitea/gitea/issues/15046 --- templates/repo/issue/milestone_issues.tmpl | 4 ++-- templates/repo/issue/milestones.tmpl | 4 ++-- web_src/less/_repository.less | 1 + 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/templates/repo/issue/milestone_issues.tmpl b/templates/repo/issue/milestone_issues.tmpl index 28b11ad6d0..e89131f151 100644 --- a/templates/repo/issue/milestone_issues.tmpl +++ b/templates/repo/issue/milestone_issues.tmpl @@ -4,8 +4,8 @@
    -

    {{.Milestone.Name}}

    -
    +

    {{.Milestone.Name}}

    +
    {{.Milestone.RenderedContent|Str2html}}
    diff --git a/templates/repo/issue/milestones.tmpl b/templates/repo/issue/milestones.tmpl index bb42a9c73d..94c0600efc 100644 --- a/templates/repo/issue/milestones.tmpl +++ b/templates/repo/issue/milestones.tmpl @@ -43,7 +43,7 @@
    {{range .Milestones}}
  • - {{svg "octicon-milestone"}} {{.Name}} + {{svg "octicon-milestone" 16 "mr-2"}} {{.Name}}
    @@ -80,7 +80,7 @@
    {{end}} {{if .Content}} -
    +
    {{.RenderedContent|Str2html}}
    {{end}} diff --git a/web_src/less/_repository.less b/web_src/less/_repository.less index 09b416c4a1..5e6081a636 100644 --- a/web_src/less/_repository.less +++ b/web_src/less/_repository.less @@ -1320,6 +1320,7 @@ padding-top: 5px; padding-right: 10px; color: #000000; + font-size: 1.5rem; &:hover { color: #4078c0; From a6290f603fc124e6208e35f8785d1b8cba2b571f Mon Sep 17 00:00:00 2001 From: a1012112796 <1012112796@qq.com> Date: Tue, 23 Mar 2021 03:15:44 +0800 Subject: [PATCH 185/205] fix #15104 (#15106) Signed-off-by: a1012112796 <1012112796@qq.com> --- modules/convert/user.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/modules/convert/user.go b/modules/convert/user.go index c75a8aac52..7186d42dc0 100644 --- a/modules/convert/user.go +++ b/modules/convert/user.go @@ -13,6 +13,10 @@ import ( // ToUser convert models.User to api.User // signed shall only be set if requester is logged in. authed shall only be set if user is site admin or user himself func ToUser(user *models.User, signed, authed bool) *api.User { + if user == nil { + return nil + } + result := &api.User{ ID: user.ID, UserName: user.Name, From 6198403fbc4e6d2ba497eecd54b113a7752399b2 Mon Sep 17 00:00:00 2001 From: zeripath Date: Mon, 22 Mar 2021 20:27:21 +0000 Subject: [PATCH 186/205] Fix another clusterfuzz identified issue (#15096) (#15114) Backport #15096 Signed-off-by: Andrew Thornton Co-authored-by: techknowlogick --- modules/markup/html.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/markup/html.go b/modules/markup/html.go index c2e574e3b2..b462b6b34b 100644 --- a/modules/markup/html.go +++ b/modules/markup/html.go @@ -312,7 +312,7 @@ func (ctx *postProcessCtx) postProcess(rawHTML []byte) ([]byte, error) { _, _ = res.WriteString("") // Strip out nuls - they're always invalid - _, _ = nulCleaner.WriteString(res, string(tagCleaner.ReplaceAll(rawHTML, []byte("<$1")))) + _, _ = res.Write(tagCleaner.ReplaceAll([]byte(nulCleaner.Replace(string(rawHTML))), []byte("<$1"))) // close the tags _, _ = res.WriteString("") From 151bedab524a0844758d48bcab5b44a099976c23 Mon Sep 17 00:00:00 2001 From: 6543 <6543@obermui.de> Date: Tue, 23 Mar 2021 19:45:06 +0100 Subject: [PATCH 187/205] Fix bug on avatar middleware (#15125) Co-authored-by: Lunny Xiao --- routers/routes/routes.go | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/routers/routes/routes.go b/routers/routes/routes.go index bdde8216c4..78468476e3 100644 --- a/routers/routes/routes.go +++ b/routers/routes/routes.go @@ -13,6 +13,7 @@ import ( "net/http" "os" "path" + "path/filepath" "strings" "text/template" "time" @@ -152,12 +153,21 @@ func storageHandler(storageSetting setting.Storage, prefix string, objStore stor return } - if !strings.HasPrefix(req.URL.RequestURI(), "/"+prefix) { + prefix := strings.Trim(prefix, "/") + + if !strings.HasPrefix(req.URL.EscapedPath(), "/"+prefix+"/") { return } + rPath := strings.TrimPrefix(req.URL.EscapedPath(), "/"+prefix+"/") - rPath := strings.TrimPrefix(req.URL.RequestURI(), "/"+prefix) rPath = strings.TrimPrefix(rPath, "/") + if rPath == "" { + ctx.Error(404, "file not found") + return + } + rPath = path.Clean("/" + filepath.ToSlash(rPath)) + rPath = rPath[1:] + //If we have matched and access to release or issue fr, err := objStore.Open(rPath) if err != nil { From 6dfa92bb1ca97d4e93e07dd5c289a8035761d89c Mon Sep 17 00:00:00 2001 From: 6543 <6543@obermui.de> Date: Tue, 23 Mar 2021 20:44:50 +0100 Subject: [PATCH 188/205] Changelog v1.13.6 (#15129) --- CHANGELOG.md | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c91334d934..64f752eb03 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,16 @@ This changelog goes through all the changes that have been made in each release without substantial changes to our git log; to see the highlights of what has been added to each release, please refer to the [blog](https://blog.gitea.io). +## [1.13.6](https://github.com/go-gitea/gitea/releases/tag/v1.13.6) - 2021-03-23 + +* SECURITY + * Fix bug on avatar middleware (#15124) (#15125) + * Fix another clusterfuzz identified issue (#15096) (#15114) +* API + * Fix nil exeption for get pull reviews API #15104 (#15106) +* BUGFIXES + * Fix markdown rendering in milestone content (#15056) (#15092) + ## [1.13.5](https://github.com/go-gitea/gitea/releases/tag/v1.13.5) - 2021-03-21 * SECURITY @@ -228,7 +238,7 @@ been added to each release, please refer to the [blog](https://blog.gitea.io). * Fix scrolling to resolved comment anchors (#13343) (#13371) * Storage configuration support `[storage]` (#13314) (#13379) * When creating line diffs do not split within an html entity (#13357) (#13375) (#13425) (#13427) - * Fix reactions on code comments (#13390) (#13401) + * Fix reactions on code comments (#13390) (#13401) * Add missing full names when DEFAULT_SHOW_FULL_NAME is enabled (#13424) * Replies to outdated code comments should also be outdated (#13217) (#13433) * Fix panic bug in handling multiple references in commit (#13486) (#13487) From 4f47bf5346db1d2b3155b6136309b0fa80a3a517 Mon Sep 17 00:00:00 2001 From: sotho Date: Fri, 26 Mar 2021 07:01:32 +0100 Subject: [PATCH 189/205] Fix wrong user returned in API (#15139) (#15150) * Fix wrong user returned in API (#15139) The API call: GET /repos/{owner}/{repo}/pulls/{index}/reviews/{id}/comments returns always the reviewer, but should return the poster. Co-authored-by: 6543 <6543@obermui.de> Co-authored-by: zeripath * rm regression Co-authored-by: 6543 <6543@obermui.de> Co-authored-by: zeripath --- modules/convert/pull_review.go | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/modules/convert/pull_review.go b/modules/convert/pull_review.go index 032d3617fc..d98651a394 100644 --- a/modules/convert/pull_review.go +++ b/modules/convert/pull_review.go @@ -83,18 +83,17 @@ func ToPullReviewCommentList(review *models.Review, doer *models.User) ([]*api.P apiComments := make([]*api.PullReviewComment, 0, len(review.CodeComments)) - auth := false - if doer != nil { - auth = doer.IsAdmin || doer.ID == review.ReviewerID - } - for _, lines := range review.CodeComments { for _, comments := range lines { for _, comment := range comments { + auth := false + if doer != nil { + auth = doer.IsAdmin || doer.ID == comment.Poster.ID + } apiComment := &api.PullReviewComment{ ID: comment.ID, Body: comment.Content, - Reviewer: ToUser(review.Reviewer, doer != nil, auth), + Reviewer: ToUser(comment.Poster, doer != nil, auth), ReviewID: review.ID, Created: comment.CreatedUnix.AsTime(), Updated: comment.UpdatedUnix.AsTime(), From 8d4f8ebf3105811f9d4fe6338f32ecc5c0b76452 Mon Sep 17 00:00:00 2001 From: zeripath Date: Fri, 26 Mar 2021 23:53:51 +0000 Subject: [PATCH 190/205] Clusterfuzz found another way (#15160) (#15169) Backport #15160 Clusterfuzz found another way so I found another way to stop it Signed-off-by: Andrew Thornton --- modules/markup/html.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/markup/html.go b/modules/markup/html.go index b462b6b34b..3d218c407e 100644 --- a/modules/markup/html.go +++ b/modules/markup/html.go @@ -298,7 +298,7 @@ func RenderEmoji( return ctx.postProcess(rawHTML) } -var tagCleaner = regexp.MustCompile(`<((?:/?\w+/\w+)|(?:/[\w ]+/)|(/?[hH][tT][mM][lL][ />])|(/?[hH][eE][aA][dD][ />]))`) +var tagCleaner = regexp.MustCompile(`<((?:/?\w+/\w+)|(?:/[\w ]+/)|(/?[hH][tT][mM][lL]\b)|(/?[hH][eE][aA][dD]\b))`) var nulCleaner = strings.NewReplacer("\000", "") func (ctx *postProcessCtx) postProcess(rawHTML []byte) ([]byte, error) { From 1062931cf19462cf5ff8d4f14eeead6c6fc58173 Mon Sep 17 00:00:00 2001 From: zeripath Date: Thu, 1 Apr 2021 19:30:44 +0100 Subject: [PATCH 191/205] Prevent NPE in CommentMustAsDiff if no hunk header (#1519) (#15201) Backport #15199 I do not understand how this can happen or why. There is an apparent possibility for a comment.Patch to be missing a hunk header - this should not happen and do not understand how. But it appears to happen on 1.13 at least in some case. This PR will simply add a new section if the cursection is empty thus preventing the NPE. Fix #15198 Signed-off-by: Andrew Thornton --- services/gitdiff/gitdiff.go | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/services/gitdiff/gitdiff.go b/services/gitdiff/gitdiff.go index 0d95817a44..aeb70bf683 100644 --- a/services/gitdiff/gitdiff.go +++ b/services/gitdiff/gitdiff.go @@ -1014,6 +1014,11 @@ func parseHunks(curFile *DiffFile, maxLines, maxLineCharacters int, input *bufio } diffLine := &DiffLine{Type: DiffLineAdd, RightIdx: rightLine} rightLine++ + if curSection == nil { + // Create a new section to represent this hunk + curSection = &DiffSection{} + curFile.Sections = append(curFile.Sections, curSection) + } curSection.Lines = append(curSection.Lines, diffLine) case '-': curFileLinesCount++ @@ -1026,6 +1031,11 @@ func parseHunks(curFile *DiffFile, maxLines, maxLineCharacters int, input *bufio if leftLine > 0 { leftLine++ } + if curSection == nil { + // Create a new section to represent this hunk + curSection = &DiffSection{} + curFile.Sections = append(curFile.Sections, curSection) + } curSection.Lines = append(curSection.Lines, diffLine) case ' ': curFileLinesCount++ @@ -1036,6 +1046,11 @@ func parseHunks(curFile *DiffFile, maxLines, maxLineCharacters int, input *bufio diffLine := &DiffLine{Type: DiffLinePlain, LeftIdx: leftLine, RightIdx: rightLine} leftLine++ rightLine++ + if curSection == nil { + // Create a new section to represent this hunk + curSection = &DiffSection{} + curFile.Sections = append(curFile.Sections, curSection) + } curSection.Lines = append(curSection.Lines, diffLine) default: // This is unexpected From 1a26f6c7abef670be624c38f626acd1dee5c2bfa Mon Sep 17 00:00:00 2001 From: zeripath Date: Thu, 1 Apr 2021 23:50:12 +0100 Subject: [PATCH 192/205] Speed up `enry.IsVendor` (#15213) (#15246) Backport #15213 `enry.IsVendor` is kinda slow as it simply iterates across all regexps. This PR ajdusts the regexps to combine them to make this process a little quicker. Related #15143 Signed-off-by: Andrew Thornton --- modules/analyze/vendor.go | 70 ++++++++++++++++++++++++++ modules/analyze/vendor_test.go | 42 ++++++++++++++++ modules/git/repo_language_stats.go | 2 +- modules/indexer/code/bleve.go | 2 +- modules/indexer/code/elastic_search.go | 2 +- 5 files changed, 115 insertions(+), 3 deletions(-) create mode 100644 modules/analyze/vendor.go create mode 100644 modules/analyze/vendor_test.go diff --git a/modules/analyze/vendor.go b/modules/analyze/vendor.go new file mode 100644 index 0000000000..12ae8dbd80 --- /dev/null +++ b/modules/analyze/vendor.go @@ -0,0 +1,70 @@ +// Copyright 2021 The Gitea Authors. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +package analyze + +import ( + "regexp" + "sort" + "strings" + + "github.com/go-enry/go-enry/v2/data" +) + +var isVendorRegExp *regexp.Regexp + +func init() { + matchers := data.VendorMatchers + + caretStrings := make([]string, 0, 10) + caretShareStrings := make([]string, 0, 10) + + matcherStrings := make([]string, 0, len(matchers)) + for _, matcher := range matchers { + str := matcher.String() + if str[0] == '^' { + caretStrings = append(caretStrings, str[1:]) + } else if str[0:5] == "(^|/)" { + caretShareStrings = append(caretShareStrings, str[5:]) + } else { + matcherStrings = append(matcherStrings, str) + } + } + + sort.Strings(caretShareStrings) + sort.Strings(caretStrings) + sort.Strings(matcherStrings) + + sb := &strings.Builder{} + sb.WriteString("(?:^(?:") + sb.WriteString(caretStrings[0]) + for _, matcher := range caretStrings[1:] { + sb.WriteString(")|(?:") + sb.WriteString(matcher) + } + sb.WriteString("))") + sb.WriteString("|") + sb.WriteString("(?:(?:^|/)(?:") + sb.WriteString(caretShareStrings[0]) + for _, matcher := range caretShareStrings[1:] { + sb.WriteString(")|(?:") + sb.WriteString(matcher) + } + sb.WriteString("))") + sb.WriteString("|") + sb.WriteString("(?:") + sb.WriteString(matcherStrings[0]) + for _, matcher := range matcherStrings[1:] { + sb.WriteString(")|(?:") + sb.WriteString(matcher) + } + sb.WriteString(")") + combined := sb.String() + isVendorRegExp = regexp.MustCompile(combined) +} + +// IsVendor returns whether or not path is a vendor path. +func IsVendor(path string) bool { + return isVendorRegExp.MatchString(path) +} diff --git a/modules/analyze/vendor_test.go b/modules/analyze/vendor_test.go new file mode 100644 index 0000000000..2784e49d34 --- /dev/null +++ b/modules/analyze/vendor_test.go @@ -0,0 +1,42 @@ +// Copyright 2021 The Gitea Authors. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +package analyze + +import "testing" + +func TestIsVendor(t *testing.T) { + tests := []struct { + path string + want bool + }{ + {"cache/", true}, + {"random/cache/", true}, + {"cache", false}, + {"dependencies/", true}, + {"Dependencies/", true}, + {"dependency/", false}, + {"dist/", true}, + {"dist", false}, + {"random/dist/", true}, + {"random/dist", false}, + {"deps/", true}, + {"configure", true}, + {"a/configure", true}, + {"config.guess", true}, + {"config.guess/", false}, + {".vscode/", true}, + {"doc/_build/", true}, + {"a/docs/_build/", true}, + {"a/dasdocs/_build-vsdoc.js", true}, + {"a/dasdocs/_build-vsdoc.j", false}, + } + for _, tt := range tests { + t.Run(tt.path, func(t *testing.T) { + if got := IsVendor(tt.path); got != tt.want { + t.Errorf("IsVendor() = %v, want %v", got, tt.want) + } + }) + } +} diff --git a/modules/git/repo_language_stats.go b/modules/git/repo_language_stats.go index b721b996e4..573cf5df6a 100644 --- a/modules/git/repo_language_stats.go +++ b/modules/git/repo_language_stats.go @@ -44,7 +44,7 @@ func (repo *Repository) GetLanguageStats(commitID string) (map[string]int64, err sizes := make(map[string]int64) err = tree.Files().ForEach(func(f *object.File) error { - if f.Size == 0 || enry.IsVendor(f.Name) || enry.IsDotFile(f.Name) || + if f.Size == 0 || analyze.IsVendor(f.Name) || enry.IsDotFile(f.Name) || enry.IsDocumentation(f.Name) || enry.IsConfiguration(f.Name) { return nil } diff --git a/modules/indexer/code/bleve.go b/modules/indexer/code/bleve.go index 9caa6528f7..7458717ccc 100644 --- a/modules/indexer/code/bleve.go +++ b/modules/indexer/code/bleve.go @@ -175,7 +175,7 @@ func NewBleveIndexer(indexDir string) (*BleveIndexer, bool, error) { func (b *BleveIndexer) addUpdate(commitSha string, update fileUpdate, repo *models.Repository, batch rupture.FlushingBatch) error { // Ignore vendored files in code search - if setting.Indexer.ExcludeVendored && enry.IsVendor(update.Filename) { + if setting.Indexer.ExcludeVendored && analyze.IsVendor(update.Filename) { return nil } diff --git a/modules/indexer/code/elastic_search.go b/modules/indexer/code/elastic_search.go index 08b20b80a0..fd37462054 100644 --- a/modules/indexer/code/elastic_search.go +++ b/modules/indexer/code/elastic_search.go @@ -170,7 +170,7 @@ func (b *ElasticSearchIndexer) init() (bool, error) { func (b *ElasticSearchIndexer) addUpdate(sha string, update fileUpdate, repo *models.Repository) ([]elastic.BulkableRequest, error) { // Ignore vendored files in code search - if setting.Indexer.ExcludeVendored && enry.IsVendor(update.Filename) { + if setting.Indexer.ExcludeVendored && analyze.IsVendor(update.Filename) { return nil, nil } From 0d7afb02c0c354550cb1e45f7057f23d90e03cb6 Mon Sep 17 00:00:00 2001 From: a1012112796 <1012112796@qq.com> Date: Fri, 2 Apr 2021 11:30:14 +0800 Subject: [PATCH 193/205] response 404 for diff/patch of a commit that not exist (#15221) (#15238) * response 404 for diff/patch of a commit that not exist fix #15217 Signed-off-by: a1012112796 <1012112796@qq.com> * Update routers/repo/commit.go Co-authored-by: silverwind * use ctx.NotFound() Co-authored-by: zeripath Co-authored-by: silverwind Co-authored-by: zeripath Co-authored-by: silverwind Co-authored-by: 6543 <6543@obermui.de> --- modules/git/diff.go | 2 +- routers/repo/commit.go | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/modules/git/diff.go b/modules/git/diff.go index 6faad1c3c0..5da53568e5 100644 --- a/modules/git/diff.go +++ b/modules/git/diff.go @@ -47,7 +47,7 @@ func GetRawDiffForFile(repoPath, startCommit, endCommit string, diffType RawDiff func GetRepoRawDiffForFile(repo *Repository, startCommit, endCommit string, diffType RawDiffType, file string, writer io.Writer) error { commit, err := repo.GetCommit(endCommit) if err != nil { - return fmt.Errorf("GetCommit: %v", err) + return err } fileArgs := make([]string, 0) if len(file) > 0 { diff --git a/routers/repo/commit.go b/routers/repo/commit.go index d9547cc51d..11329727e4 100644 --- a/routers/repo/commit.go +++ b/routers/repo/commit.go @@ -6,6 +6,7 @@ package repo import ( + "errors" "path" "strings" @@ -341,6 +342,11 @@ func RawDiff(ctx *context.Context) { git.RawDiffType(ctx.Params(":ext")), ctx.Resp, ); err != nil { + if git.IsErrNotExist(err) { + ctx.NotFound("GetRawDiff", + errors.New("commit "+ctx.Params(":sha")+" does not exist.")) + return + } ctx.ServerError("GetRawDiff", err) return } From 558b0005ffbc3f2b0a58ad32621ec5f4983c7fcb Mon Sep 17 00:00:00 2001 From: techknowlogick Date: Sat, 3 Apr 2021 00:27:14 -0400 Subject: [PATCH 194/205] update golang libraries (#15258) (#15260) --- go.mod | 6 +- go.sum | 13 +- vendor/golang.org/x/net/context/go17.go | 1 + vendor/golang.org/x/net/context/go19.go | 1 + vendor/golang.org/x/net/context/pre_go17.go | 1 + vendor/golang.org/x/net/context/pre_go19.go | 1 + vendor/golang.org/x/net/html/const.go | 2 +- vendor/golang.org/x/net/html/foreign.go | 119 +- vendor/golang.org/x/net/html/parse.go | 15 +- vendor/golang.org/x/net/html/render.go | 2 +- vendor/golang.org/x/net/idna/idna10.0.0.go | 1 + vendor/golang.org/x/net/idna/idna9.0.0.go | 1 + vendor/golang.org/x/net/idna/tables10.0.0.go | 1 + vendor/golang.org/x/net/idna/tables11.0.0.go | 1 + .../idna/{tables12.00.go => tables12.0.0.go} | 3 +- vendor/golang.org/x/net/idna/tables13.0.0.go | 4840 ++++ vendor/golang.org/x/net/idna/tables9.0.0.go | 1 + vendor/golang.org/x/net/publicsuffix/table.go | 20162 ++++++++-------- vendor/golang.org/x/sys/cpu/asm_aix_ppc64.s | 2 +- vendor/golang.org/x/sys/cpu/cpu.go | 60 +- vendor/golang.org/x/sys/cpu/cpu_aix.go | 1 + vendor/golang.org/x/sys/cpu/cpu_arm64.go | 39 +- vendor/golang.org/x/sys/cpu/cpu_arm64.s | 2 +- vendor/golang.org/x/sys/cpu/cpu_gc_arm64.go | 3 +- vendor/golang.org/x/sys/cpu/cpu_gc_s390x.go | 3 +- vendor/golang.org/x/sys/cpu/cpu_gc_x86.go | 3 +- .../golang.org/x/sys/cpu/cpu_gccgo_arm64.go | 1 + .../golang.org/x/sys/cpu/cpu_gccgo_s390x.go | 1 + vendor/golang.org/x/sys/cpu/cpu_gccgo_x86.go | 1 + vendor/golang.org/x/sys/cpu/cpu_linux.go | 1 + .../golang.org/x/sys/cpu/cpu_linux_mips64x.go | 1 + .../golang.org/x/sys/cpu/cpu_linux_noinit.go | 1 + .../golang.org/x/sys/cpu/cpu_linux_ppc64x.go | 1 + .../golang.org/x/sys/cpu/cpu_linux_s390x.go | 121 +- vendor/golang.org/x/sys/cpu/cpu_mips64x.go | 1 + vendor/golang.org/x/sys/cpu/cpu_mipsx.go | 1 + .../golang.org/x/sys/cpu/cpu_netbsd_arm64.go | 173 + vendor/golang.org/x/sys/cpu/cpu_other_arm.go | 1 + .../golang.org/x/sys/cpu/cpu_other_arm64.go | 3 +- .../golang.org/x/sys/cpu/cpu_other_mips64x.go | 13 + vendor/golang.org/x/sys/cpu/cpu_ppc64x.go | 1 + vendor/golang.org/x/sys/cpu/cpu_riscv64.go | 1 + vendor/golang.org/x/sys/cpu/cpu_s390x.go | 150 +- vendor/golang.org/x/sys/cpu/cpu_s390x.s | 2 +- vendor/golang.org/x/sys/cpu/cpu_wasm.go | 1 + vendor/golang.org/x/sys/cpu/cpu_x86.go | 52 +- vendor/golang.org/x/sys/cpu/cpu_x86.s | 2 +- vendor/golang.org/x/sys/cpu/cpu_zos.go | 10 + vendor/golang.org/x/sys/cpu/cpu_zos_s390x.go | 25 + .../golang.org/x/sys/cpu/syscall_aix_gccgo.go | 4 +- .../x/sys/cpu/syscall_aix_ppc64_gc.go | 4 +- vendor/golang.org/x/sys/unix/aliases.go | 3 +- vendor/golang.org/x/sys/unix/asm_aix_ppc64.s | 2 +- .../unix/{asm_freebsd_386.s => asm_bsd_386.s} | 12 +- .../{asm_openbsd_amd64.s => asm_bsd_amd64.s} | 10 +- .../unix/{asm_freebsd_arm.s => asm_bsd_arm.s} | 10 +- .../{asm_netbsd_amd64.s => asm_bsd_arm64.s} | 10 +- vendor/golang.org/x/sys/unix/asm_darwin_386.s | 29 - .../golang.org/x/sys/unix/asm_darwin_amd64.s | 29 - vendor/golang.org/x/sys/unix/asm_darwin_arm.s | 30 - .../golang.org/x/sys/unix/asm_darwin_arm64.s | 30 - .../x/sys/unix/asm_dragonfly_amd64.s | 29 - .../golang.org/x/sys/unix/asm_freebsd_amd64.s | 29 - .../golang.org/x/sys/unix/asm_freebsd_arm64.s | 29 - vendor/golang.org/x/sys/unix/asm_linux_386.s | 2 +- .../golang.org/x/sys/unix/asm_linux_amd64.s | 2 +- vendor/golang.org/x/sys/unix/asm_linux_arm.s | 2 +- .../golang.org/x/sys/unix/asm_linux_arm64.s | 2 +- .../golang.org/x/sys/unix/asm_linux_mips64x.s | 2 +- .../golang.org/x/sys/unix/asm_linux_mipsx.s | 2 +- .../golang.org/x/sys/unix/asm_linux_ppc64x.s | 2 +- .../golang.org/x/sys/unix/asm_linux_riscv64.s | 2 +- .../golang.org/x/sys/unix/asm_linux_s390x.s | 2 +- vendor/golang.org/x/sys/unix/asm_netbsd_386.s | 29 - vendor/golang.org/x/sys/unix/asm_netbsd_arm.s | 29 - .../golang.org/x/sys/unix/asm_netbsd_arm64.s | 29 - .../golang.org/x/sys/unix/asm_openbsd_386.s | 29 - .../golang.org/x/sys/unix/asm_openbsd_arm.s | 29 - .../golang.org/x/sys/unix/asm_openbsd_arm64.s | 29 - .../x/sys/unix/asm_openbsd_mips64.s | 2 +- .../golang.org/x/sys/unix/asm_solaris_amd64.s | 2 +- vendor/golang.org/x/sys/unix/asm_zos_s390x.s | 426 + vendor/golang.org/x/sys/unix/cap_freebsd.go | 1 + vendor/golang.org/x/sys/unix/constants.go | 3 +- vendor/golang.org/x/sys/unix/dev_aix_ppc.go | 4 +- vendor/golang.org/x/sys/unix/dev_aix_ppc64.go | 4 +- vendor/golang.org/x/sys/unix/dev_zos.go | 29 + vendor/golang.org/x/sys/unix/dirent.go | 1 + vendor/golang.org/x/sys/unix/endian_big.go | 3 +- vendor/golang.org/x/sys/unix/endian_little.go | 3 +- vendor/golang.org/x/sys/unix/env_unix.go | 3 +- vendor/golang.org/x/sys/unix/epoll_zos.go | 221 + vendor/golang.org/x/sys/unix/fcntl.go | 1 + .../x/sys/unix/fcntl_linux_32bit.go | 5 +- vendor/golang.org/x/sys/unix/fdset.go | 1 + vendor/golang.org/x/sys/unix/fstatfs_zos.go | 164 + vendor/golang.org/x/sys/unix/gccgo.go | 6 +- vendor/golang.org/x/sys/unix/gccgo_c.c | 6 + .../x/sys/unix/gccgo_linux_amd64.go | 1 + vendor/golang.org/x/sys/unix/ioctl.go | 1 + vendor/golang.org/x/sys/unix/ioctl_zos.go | 74 + vendor/golang.org/x/sys/unix/mkall.sh | 2 +- vendor/golang.org/x/sys/unix/mkerrors.sh | 44 +- vendor/golang.org/x/sys/unix/pagesize_unix.go | 1 + vendor/golang.org/x/sys/unix/ptrace_darwin.go | 12 + vendor/golang.org/x/sys/unix/ptrace_ios.go | 12 + vendor/golang.org/x/sys/unix/race.go | 1 + vendor/golang.org/x/sys/unix/race0.go | 3 +- .../x/sys/unix/readdirent_getdents.go | 1 + .../x/sys/unix/readdirent_getdirentries.go | 1 + vendor/golang.org/x/sys/unix/sockcmsg_unix.go | 3 +- .../x/sys/unix/sockcmsg_unix_other.go | 13 +- vendor/golang.org/x/sys/unix/str.go | 1 + vendor/golang.org/x/sys/unix/syscall.go | 46 +- vendor/golang.org/x/sys/unix/syscall_aix.go | 29 +- .../golang.org/x/sys/unix/syscall_aix_ppc.go | 4 +- .../x/sys/unix/syscall_aix_ppc64.go | 4 +- vendor/golang.org/x/sys/unix/syscall_bsd.go | 28 +- .../x/sys/unix/syscall_darwin.1_12.go | 1 + .../x/sys/unix/syscall_darwin.1_13.go | 2 +- .../golang.org/x/sys/unix/syscall_darwin.go | 159 +- .../x/sys/unix/syscall_darwin_386.go | 8 +- .../x/sys/unix/syscall_darwin_amd64.go | 8 +- .../x/sys/unix/syscall_darwin_arm.go | 6 +- .../x/sys/unix/syscall_darwin_arm64.go | 10 +- .../x/sys/unix/syscall_darwin_libSystem.go | 1 + .../x/sys/unix/syscall_dragonfly.go | 40 +- .../x/sys/unix/syscall_dragonfly_amd64.go | 1 + .../golang.org/x/sys/unix/syscall_freebsd.go | 36 +- .../x/sys/unix/syscall_freebsd_386.go | 1 + .../x/sys/unix/syscall_freebsd_amd64.go | 1 + .../x/sys/unix/syscall_freebsd_arm.go | 1 + .../x/sys/unix/syscall_freebsd_arm64.go | 1 + .../golang.org/x/sys/unix/syscall_illumos.go | 61 +- vendor/golang.org/x/sys/unix/syscall_linux.go | 226 +- .../x/sys/unix/syscall_linux_386.go | 10 +- .../x/sys/unix/syscall_linux_amd64.go | 3 +- .../x/sys/unix/syscall_linux_amd64_gc.go | 4 +- .../x/sys/unix/syscall_linux_arm.go | 11 +- .../x/sys/unix/syscall_linux_arm64.go | 3 +- .../golang.org/x/sys/unix/syscall_linux_gc.go | 3 +- .../x/sys/unix/syscall_linux_gc_386.go | 3 +- .../x/sys/unix/syscall_linux_gc_arm.go | 3 +- .../x/sys/unix/syscall_linux_gccgo_386.go | 1 + .../x/sys/unix/syscall_linux_gccgo_arm.go | 1 + .../x/sys/unix/syscall_linux_mips64x.go | 3 +- .../x/sys/unix/syscall_linux_mipsx.go | 9 +- .../x/sys/unix/syscall_linux_ppc64x.go | 5 +- .../x/sys/unix/syscall_linux_riscv64.go | 3 +- .../x/sys/unix/syscall_linux_s390x.go | 5 +- .../x/sys/unix/syscall_linux_sparc64.go | 5 +- .../golang.org/x/sys/unix/syscall_netbsd.go | 40 +- .../x/sys/unix/syscall_netbsd_386.go | 1 + .../x/sys/unix/syscall_netbsd_amd64.go | 1 + .../x/sys/unix/syscall_netbsd_arm.go | 1 + .../x/sys/unix/syscall_netbsd_arm64.go | 1 + .../golang.org/x/sys/unix/syscall_openbsd.go | 23 +- .../x/sys/unix/syscall_openbsd_386.go | 1 + .../x/sys/unix/syscall_openbsd_amd64.go | 1 + .../x/sys/unix/syscall_openbsd_arm.go | 1 + .../x/sys/unix/syscall_openbsd_arm64.go | 1 + .../golang.org/x/sys/unix/syscall_solaris.go | 30 +- .../x/sys/unix/syscall_solaris_amd64.go | 1 + vendor/golang.org/x/sys/unix/syscall_unix.go | 1 + .../golang.org/x/sys/unix/syscall_unix_gc.go | 5 +- .../x/sys/unix/syscall_unix_gc_ppc64x.go | 3 +- .../x/sys/unix/syscall_zos_s390x.go | 1781 ++ vendor/golang.org/x/sys/unix/timestruct.go | 29 +- vendor/golang.org/x/sys/unix/xattr_bsd.go | 1 + .../golang.org/x/sys/unix/zerrors_aix_ppc.go | 1 + .../x/sys/unix/zerrors_aix_ppc64.go | 1 + .../x/sys/unix/zerrors_darwin_386.go | 3 + .../x/sys/unix/zerrors_darwin_amd64.go | 90 +- .../x/sys/unix/zerrors_darwin_arm.go | 3 + .../x/sys/unix/zerrors_darwin_arm64.go | 90 +- .../x/sys/unix/zerrors_dragonfly_amd64.go | 139 +- .../x/sys/unix/zerrors_freebsd_386.go | 7 + .../x/sys/unix/zerrors_freebsd_amd64.go | 7 + .../x/sys/unix/zerrors_freebsd_arm.go | 16 + .../x/sys/unix/zerrors_freebsd_arm64.go | 7 + vendor/golang.org/x/sys/unix/zerrors_linux.go | 289 +- .../x/sys/unix/zerrors_linux_386.go | 15 +- .../x/sys/unix/zerrors_linux_amd64.go | 15 +- .../x/sys/unix/zerrors_linux_arm.go | 15 +- .../x/sys/unix/zerrors_linux_arm64.go | 18 +- .../x/sys/unix/zerrors_linux_mips.go | 15 +- .../x/sys/unix/zerrors_linux_mips64.go | 15 +- .../x/sys/unix/zerrors_linux_mips64le.go | 15 +- .../x/sys/unix/zerrors_linux_mipsle.go | 15 +- .../x/sys/unix/zerrors_linux_ppc64.go | 15 +- .../x/sys/unix/zerrors_linux_ppc64le.go | 15 +- .../x/sys/unix/zerrors_linux_riscv64.go | 15 +- .../x/sys/unix/zerrors_linux_s390x.go | 15 +- .../x/sys/unix/zerrors_linux_sparc64.go | 15 +- .../x/sys/unix/zerrors_netbsd_386.go | 1 + .../x/sys/unix/zerrors_netbsd_amd64.go | 1 + .../x/sys/unix/zerrors_netbsd_arm.go | 1 + .../x/sys/unix/zerrors_netbsd_arm64.go | 1 + .../x/sys/unix/zerrors_openbsd_386.go | 1 + .../x/sys/unix/zerrors_openbsd_amd64.go | 1 + .../x/sys/unix/zerrors_openbsd_arm.go | 1 + .../x/sys/unix/zerrors_openbsd_arm64.go | 1 + .../x/sys/unix/zerrors_openbsd_mips64.go | 1 + .../x/sys/unix/zerrors_solaris_amd64.go | 23 +- .../x/sys/unix/zerrors_zos_s390x.go | 832 + .../x/sys/unix/zptrace_armnn_linux.go | 1 + .../x/sys/unix/zptrace_mipsnn_linux.go | 1 + .../x/sys/unix/zptrace_mipsnnle_linux.go | 1 + .../x/sys/unix/zptrace_x86_linux.go | 1 + .../golang.org/x/sys/unix/zsyscall_aix_ppc.go | 1 + .../x/sys/unix/zsyscall_aix_ppc64.go | 1 + .../x/sys/unix/zsyscall_aix_ppc64_gc.go | 4 +- .../x/sys/unix/zsyscall_aix_ppc64_gccgo.go | 4 +- .../x/sys/unix/zsyscall_darwin_386.1_13.go | 3 +- .../x/sys/unix/zsyscall_darwin_386.go | 212 +- .../x/sys/unix/zsyscall_darwin_386.s | 8 +- .../x/sys/unix/zsyscall_darwin_amd64.1_13.go | 3 +- .../x/sys/unix/zsyscall_darwin_amd64.go | 212 +- .../x/sys/unix/zsyscall_darwin_amd64.s | 8 +- .../x/sys/unix/zsyscall_darwin_arm.1_13.go | 3 +- .../x/sys/unix/zsyscall_darwin_arm.go | 183 +- .../x/sys/unix/zsyscall_darwin_arm.s | 4 +- .../x/sys/unix/zsyscall_darwin_arm64.1_13.go | 3 +- .../x/sys/unix/zsyscall_darwin_arm64.go | 197 +- .../x/sys/unix/zsyscall_darwin_arm64.s | 6 +- .../x/sys/unix/zsyscall_dragonfly_amd64.go | 45 +- .../x/sys/unix/zsyscall_freebsd_386.go | 1 + .../x/sys/unix/zsyscall_freebsd_amd64.go | 1 + .../x/sys/unix/zsyscall_freebsd_arm.go | 1 + .../x/sys/unix/zsyscall_freebsd_arm64.go | 1 + .../x/sys/unix/zsyscall_illumos_amd64.go | 26 +- .../golang.org/x/sys/unix/zsyscall_linux.go | 11 + .../x/sys/unix/zsyscall_linux_386.go | 1 + .../x/sys/unix/zsyscall_linux_amd64.go | 1 + .../x/sys/unix/zsyscall_linux_arm.go | 1 + .../x/sys/unix/zsyscall_linux_arm64.go | 1 + .../x/sys/unix/zsyscall_linux_mips.go | 1 + .../x/sys/unix/zsyscall_linux_mips64.go | 1 + .../x/sys/unix/zsyscall_linux_mips64le.go | 1 + .../x/sys/unix/zsyscall_linux_mipsle.go | 1 + .../x/sys/unix/zsyscall_linux_ppc64.go | 1 + .../x/sys/unix/zsyscall_linux_ppc64le.go | 1 + .../x/sys/unix/zsyscall_linux_riscv64.go | 1 + .../x/sys/unix/zsyscall_linux_s390x.go | 1 + .../x/sys/unix/zsyscall_linux_sparc64.go | 1 + .../x/sys/unix/zsyscall_netbsd_386.go | 11 + .../x/sys/unix/zsyscall_netbsd_amd64.go | 11 + .../x/sys/unix/zsyscall_netbsd_arm.go | 11 + .../x/sys/unix/zsyscall_netbsd_arm64.go | 11 + .../x/sys/unix/zsyscall_openbsd_386.go | 1 + .../x/sys/unix/zsyscall_openbsd_amd64.go | 1 + .../x/sys/unix/zsyscall_openbsd_arm.go | 1 + .../x/sys/unix/zsyscall_openbsd_arm64.go | 1 + .../x/sys/unix/zsyscall_openbsd_mips64.go | 1 + .../x/sys/unix/zsyscall_solaris_amd64.go | 33 +- .../x/sys/unix/zsyscall_zos_s390x.go | 1217 + .../x/sys/unix/zsysctl_openbsd_386.go | 1 + .../x/sys/unix/zsysctl_openbsd_amd64.go | 1 + .../x/sys/unix/zsysctl_openbsd_arm.go | 1 + .../x/sys/unix/zsysctl_openbsd_arm64.go | 1 + .../x/sys/unix/zsysctl_openbsd_mips64.go | 1 + .../x/sys/unix/zsysnum_darwin_386.go | 438 + .../x/sys/unix/zsysnum_darwin_amd64.go | 440 + .../x/sys/unix/zsysnum_darwin_arm.go | 438 + .../x/sys/unix/zsysnum_darwin_arm64.go | 438 + .../x/sys/unix/zsysnum_dragonfly_amd64.go | 256 +- .../x/sys/unix/zsysnum_freebsd_386.go | 1 + .../x/sys/unix/zsysnum_freebsd_amd64.go | 1 + .../x/sys/unix/zsysnum_freebsd_arm.go | 1 + .../x/sys/unix/zsysnum_freebsd_arm64.go | 1 + .../x/sys/unix/zsysnum_linux_386.go | 4 + .../x/sys/unix/zsysnum_linux_amd64.go | 4 + .../x/sys/unix/zsysnum_linux_arm.go | 4 + .../x/sys/unix/zsysnum_linux_arm64.go | 4 + .../x/sys/unix/zsysnum_linux_mips.go | 4 + .../x/sys/unix/zsysnum_linux_mips64.go | 4 + .../x/sys/unix/zsysnum_linux_mips64le.go | 4 + .../x/sys/unix/zsysnum_linux_mipsle.go | 4 + .../x/sys/unix/zsysnum_linux_ppc64.go | 4 + .../x/sys/unix/zsysnum_linux_ppc64le.go | 4 + .../x/sys/unix/zsysnum_linux_riscv64.go | 4 + .../x/sys/unix/zsysnum_linux_s390x.go | 4 + .../x/sys/unix/zsysnum_linux_sparc64.go | 4 + .../x/sys/unix/zsysnum_netbsd_386.go | 1 + .../x/sys/unix/zsysnum_netbsd_amd64.go | 1 + .../x/sys/unix/zsysnum_netbsd_arm.go | 1 + .../x/sys/unix/zsysnum_netbsd_arm64.go | 1 + .../x/sys/unix/zsysnum_openbsd_386.go | 1 + .../x/sys/unix/zsysnum_openbsd_amd64.go | 1 + .../x/sys/unix/zsysnum_openbsd_arm.go | 1 + .../x/sys/unix/zsysnum_openbsd_arm64.go | 1 + .../x/sys/unix/zsysnum_openbsd_mips64.go | 1 + .../x/sys/unix/zsysnum_zos_s390x.go | 2670 ++ .../golang.org/x/sys/unix/ztypes_aix_ppc.go | 2 + .../golang.org/x/sys/unix/ztypes_aix_ppc64.go | 2 + .../x/sys/unix/ztypes_darwin_386.go | 34 +- .../x/sys/unix/ztypes_darwin_amd64.go | 53 +- .../x/sys/unix/ztypes_darwin_arm.go | 41 +- .../x/sys/unix/ztypes_darwin_arm64.go | 53 +- .../x/sys/unix/ztypes_dragonfly_amd64.go | 48 +- .../x/sys/unix/ztypes_freebsd_386.go | 11 + .../x/sys/unix/ztypes_freebsd_amd64.go | 11 + .../x/sys/unix/ztypes_freebsd_arm.go | 11 + .../x/sys/unix/ztypes_freebsd_arm64.go | 11 + .../x/sys/unix/ztypes_illumos_amd64.go | 40 + vendor/golang.org/x/sys/unix/ztypes_linux.go | 2528 +- .../golang.org/x/sys/unix/ztypes_linux_386.go | 18 +- .../x/sys/unix/ztypes_linux_amd64.go | 19 +- .../golang.org/x/sys/unix/ztypes_linux_arm.go | 19 +- .../x/sys/unix/ztypes_linux_arm64.go | 19 +- .../x/sys/unix/ztypes_linux_mips.go | 19 +- .../x/sys/unix/ztypes_linux_mips64.go | 19 +- .../x/sys/unix/ztypes_linux_mips64le.go | 19 +- .../x/sys/unix/ztypes_linux_mipsle.go | 19 +- .../x/sys/unix/ztypes_linux_ppc64.go | 19 +- .../x/sys/unix/ztypes_linux_ppc64le.go | 19 +- .../x/sys/unix/ztypes_linux_riscv64.go | 19 +- .../x/sys/unix/ztypes_linux_s390x.go | 19 +- .../x/sys/unix/ztypes_linux_sparc64.go | 19 +- .../x/sys/unix/ztypes_netbsd_386.go | 2 + .../x/sys/unix/ztypes_netbsd_amd64.go | 2 + .../x/sys/unix/ztypes_netbsd_arm.go | 2 + .../x/sys/unix/ztypes_netbsd_arm64.go | 2 + .../x/sys/unix/ztypes_openbsd_386.go | 2 + .../x/sys/unix/ztypes_openbsd_amd64.go | 2 + .../x/sys/unix/ztypes_openbsd_arm.go | 2 + .../x/sys/unix/ztypes_openbsd_arm64.go | 2 + .../x/sys/unix/ztypes_openbsd_mips64.go | 2 + .../x/sys/unix/ztypes_solaris_amd64.go | 33 +- .../golang.org/x/sys/unix/ztypes_zos_s390x.go | 402 + .../golang.org/x/sys/windows/dll_windows.go | 3 +- .../golang.org/x/sys/windows/exec_windows.go | 35 + .../x/sys/windows/memory_windows.go | 20 +- vendor/golang.org/x/sys/windows/mkerrors.bash | 7 + .../x/sys/windows/security_windows.go | 27 +- vendor/golang.org/x/sys/windows/service.go | 6 + .../x/sys/windows/setupapierrors_windows.go | 100 + .../golang.org/x/sys/windows/svc/security.go | 49 + .../golang.org/x/sys/windows/svc/service.go | 12 +- .../svc/{sys_386.s => sys_windows_386.s} | 2 - .../svc/{sys_amd64.s => sys_windows_amd64.s} | 2 - .../svc/{sys_arm.s => sys_windows_arm.s} | 16 +- .../x/sys/windows/svc/sys_windows_arm64.s | 31 + vendor/golang.org/x/sys/windows/syscall.go | 46 +- .../x/sys/windows/syscall_windows.go | 261 +- .../golang.org/x/sys/windows/types_windows.go | 1040 +- .../x/sys/windows/types_windows_arm64.go | 34 + .../x/sys/windows/zerrors_windows.go | 2619 +- .../x/sys/windows/zsyscall_windows.go | 6742 +++--- vendor/modules.txt | 6 +- 350 files changed, 37016 insertions(+), 16328 deletions(-) rename vendor/golang.org/x/net/idna/{tables12.00.go => tables12.0.0.go} (99%) create mode 100644 vendor/golang.org/x/net/idna/tables13.0.0.go create mode 100644 vendor/golang.org/x/sys/cpu/cpu_netbsd_arm64.go create mode 100644 vendor/golang.org/x/sys/cpu/cpu_other_mips64x.go create mode 100644 vendor/golang.org/x/sys/cpu/cpu_zos.go create mode 100644 vendor/golang.org/x/sys/cpu/cpu_zos_s390x.go rename vendor/golang.org/x/sys/unix/{asm_freebsd_386.s => asm_bsd_386.s} (68%) rename vendor/golang.org/x/sys/unix/{asm_openbsd_amd64.s => asm_bsd_amd64.s} (71%) rename vendor/golang.org/x/sys/unix/{asm_freebsd_arm.s => asm_bsd_arm.s} (73%) rename vendor/golang.org/x/sys/unix/{asm_netbsd_amd64.s => asm_bsd_arm64.s} (73%) delete mode 100644 vendor/golang.org/x/sys/unix/asm_darwin_386.s delete mode 100644 vendor/golang.org/x/sys/unix/asm_darwin_amd64.s delete mode 100644 vendor/golang.org/x/sys/unix/asm_darwin_arm.s delete mode 100644 vendor/golang.org/x/sys/unix/asm_darwin_arm64.s delete mode 100644 vendor/golang.org/x/sys/unix/asm_dragonfly_amd64.s delete mode 100644 vendor/golang.org/x/sys/unix/asm_freebsd_amd64.s delete mode 100644 vendor/golang.org/x/sys/unix/asm_freebsd_arm64.s delete mode 100644 vendor/golang.org/x/sys/unix/asm_netbsd_386.s delete mode 100644 vendor/golang.org/x/sys/unix/asm_netbsd_arm.s delete mode 100644 vendor/golang.org/x/sys/unix/asm_netbsd_arm64.s delete mode 100644 vendor/golang.org/x/sys/unix/asm_openbsd_386.s delete mode 100644 vendor/golang.org/x/sys/unix/asm_openbsd_arm.s delete mode 100644 vendor/golang.org/x/sys/unix/asm_openbsd_arm64.s create mode 100644 vendor/golang.org/x/sys/unix/asm_zos_s390x.s create mode 100644 vendor/golang.org/x/sys/unix/dev_zos.go create mode 100644 vendor/golang.org/x/sys/unix/epoll_zos.go create mode 100644 vendor/golang.org/x/sys/unix/fstatfs_zos.go create mode 100644 vendor/golang.org/x/sys/unix/ioctl_zos.go create mode 100644 vendor/golang.org/x/sys/unix/ptrace_darwin.go create mode 100644 vendor/golang.org/x/sys/unix/ptrace_ios.go create mode 100644 vendor/golang.org/x/sys/unix/syscall_zos_s390x.go create mode 100644 vendor/golang.org/x/sys/unix/zerrors_zos_s390x.go create mode 100644 vendor/golang.org/x/sys/unix/zsyscall_zos_s390x.go create mode 100644 vendor/golang.org/x/sys/unix/zsysnum_darwin_386.go create mode 100644 vendor/golang.org/x/sys/unix/zsysnum_darwin_amd64.go create mode 100644 vendor/golang.org/x/sys/unix/zsysnum_darwin_arm.go create mode 100644 vendor/golang.org/x/sys/unix/zsysnum_darwin_arm64.go create mode 100644 vendor/golang.org/x/sys/unix/zsysnum_zos_s390x.go create mode 100644 vendor/golang.org/x/sys/unix/ztypes_illumos_amd64.go create mode 100644 vendor/golang.org/x/sys/unix/ztypes_zos_s390x.go create mode 100644 vendor/golang.org/x/sys/windows/setupapierrors_windows.go rename vendor/golang.org/x/sys/windows/svc/{sys_386.s => sys_windows_386.s} (98%) rename vendor/golang.org/x/sys/windows/svc/{sys_amd64.s => sys_windows_amd64.s} (98%) rename vendor/golang.org/x/sys/windows/svc/{sys_arm.s => sys_windows_arm.s} (82%) create mode 100644 vendor/golang.org/x/sys/windows/svc/sys_windows_arm64.s create mode 100644 vendor/golang.org/x/sys/windows/types_windows_arm64.go diff --git a/go.mod b/go.mod index 05a5083f22..27ea79e9c9 100644 --- a/go.mod +++ b/go.mod @@ -70,7 +70,7 @@ require ( github.com/mgechev/dots v0.0.0-20190921121421-c36f7dcfbb81 github.com/mgechev/revive v1.0.3-0.20200921231451-246eac737dc7 github.com/mholt/archiver/v3 v3.3.0 - github.com/microcosm-cc/bluemonday v1.0.3-0.20191119130333-0a75d7616912 + github.com/microcosm-cc/bluemonday v1.0.5 github.com/minio/minio-go/v7 v7.0.4 github.com/mitchellh/go-homedir v1.1.0 github.com/msteinert/pam v0.0.0-20151204160544-02ccfbfaf0cc @@ -105,9 +105,9 @@ require ( go.jolheiser.com/hcaptcha v0.0.4 go.jolheiser.com/pwn v0.0.3 golang.org/x/crypto v0.0.0-20201217014255-9d1352758620 - golang.org/x/net v0.0.0-20200904194848-62affa334b73 + golang.org/x/net v0.0.0-20210331212208-0fccb6fa2b5c golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d - golang.org/x/sys v0.0.0-20200918174421-af09f7315aff + golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44 golang.org/x/text v0.3.3 golang.org/x/time v0.0.0-20200630173020-3af7569d3a1e // indirect golang.org/x/tools v0.0.0-20200921210052-fa0125251cc4 diff --git a/go.sum b/go.sum index be02d44c87..c6bc99578d 100644 --- a/go.sum +++ b/go.sum @@ -885,7 +885,6 @@ github.com/yuin/goldmark v1.1.7/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9dec github.com/yuin/goldmark v1.1.22/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -github.com/yuin/goldmark v1.2.1 h1:ruQGxdhGHe7FWOJPT0mKs5+pD2Xs1Bm/kdGlHO04FmM= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.3.3 h1:37BdQwPx8VOSic8eDSWee6QL9mRpZRm9VJp/QugNrW0= github.com/yuin/goldmark v1.3.3/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= @@ -997,8 +996,8 @@ golang.org/x/net v0.0.0-20200602114024-627f9648deb9/go.mod h1:qpuaurCH72eLCgpAm/ golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= -golang.org/x/net v0.0.0-20200904194848-62affa334b73 h1:MXfv8rhZWmFeqX3GNZRsd6vOLoaCHjYEX3qkRo3YBUA= -golang.org/x/net v0.0.0-20200904194848-62affa334b73/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20210331212208-0fccb6fa2b5c h1:KHUzaHIpjWVlVVNh65G3hhuj3KB1HnjY6Cq5cTvRQT8= +golang.org/x/net v0.0.0-20210331212208-0fccb6fa2b5c/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/oauth2 v0.0.0-20180620175406-ef147856a6dd/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20181106182150-f42d05182288/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= @@ -1054,10 +1053,12 @@ golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200413165638-669c56c373c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200918174421-af09f7315aff h1:1CPUrky56AcgSpxz/KfgzQWzfG09u5YOL8MvPYBlrL8= -golang.org/x/sys v0.0.0-20200918174421-af09f7315aff/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/term v0.0.0-20201117132131-f5c789dd3221 h1:/ZHdbVpdR/jk3g30/d4yUL0JU9kksj8+F/bnQUVLGDM= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44 h1:Bli41pIlzTzf3KEY06n+xnzK/BESIg2ze4Pgfh/aI8c= +golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1 h1:v+OssWQX+hTHEmOBgwxdZxK4zHq3yOs8F9J7mk0PY8E= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= diff --git a/vendor/golang.org/x/net/context/go17.go b/vendor/golang.org/x/net/context/go17.go index d20f52b7de..344bd14334 100644 --- a/vendor/golang.org/x/net/context/go17.go +++ b/vendor/golang.org/x/net/context/go17.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build go1.7 // +build go1.7 package context diff --git a/vendor/golang.org/x/net/context/go19.go b/vendor/golang.org/x/net/context/go19.go index d88bd1db12..64d31ecc3e 100644 --- a/vendor/golang.org/x/net/context/go19.go +++ b/vendor/golang.org/x/net/context/go19.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build go1.9 // +build go1.9 package context diff --git a/vendor/golang.org/x/net/context/pre_go17.go b/vendor/golang.org/x/net/context/pre_go17.go index 0f35592df5..5270db5db7 100644 --- a/vendor/golang.org/x/net/context/pre_go17.go +++ b/vendor/golang.org/x/net/context/pre_go17.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !go1.7 // +build !go1.7 package context diff --git a/vendor/golang.org/x/net/context/pre_go19.go b/vendor/golang.org/x/net/context/pre_go19.go index b105f80be4..1f9715341f 100644 --- a/vendor/golang.org/x/net/context/pre_go19.go +++ b/vendor/golang.org/x/net/context/pre_go19.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !go1.9 // +build !go1.9 package context diff --git a/vendor/golang.org/x/net/html/const.go b/vendor/golang.org/x/net/html/const.go index 73804d3472..ff7acf2d5b 100644 --- a/vendor/golang.org/x/net/html/const.go +++ b/vendor/golang.org/x/net/html/const.go @@ -52,7 +52,7 @@ var isSpecialElementMap = map[string]bool{ "iframe": true, "img": true, "input": true, - "keygen": true, + "keygen": true, // "keygen" has been removed from the spec, but are kept here for backwards compatibility. "li": true, "link": true, "listing": true, diff --git a/vendor/golang.org/x/net/html/foreign.go b/vendor/golang.org/x/net/html/foreign.go index 74774c458a..9da9e9dc42 100644 --- a/vendor/golang.org/x/net/html/foreign.go +++ b/vendor/golang.org/x/net/html/foreign.go @@ -161,65 +161,62 @@ var mathMLAttributeAdjustments = map[string]string{ } var svgAttributeAdjustments = map[string]string{ - "attributename": "attributeName", - "attributetype": "attributeType", - "basefrequency": "baseFrequency", - "baseprofile": "baseProfile", - "calcmode": "calcMode", - "clippathunits": "clipPathUnits", - "contentscripttype": "contentScriptType", - "contentstyletype": "contentStyleType", - "diffuseconstant": "diffuseConstant", - "edgemode": "edgeMode", - "externalresourcesrequired": "externalResourcesRequired", - "filterunits": "filterUnits", - "glyphref": "glyphRef", - "gradienttransform": "gradientTransform", - "gradientunits": "gradientUnits", - "kernelmatrix": "kernelMatrix", - "kernelunitlength": "kernelUnitLength", - "keypoints": "keyPoints", - "keysplines": "keySplines", - "keytimes": "keyTimes", - "lengthadjust": "lengthAdjust", - "limitingconeangle": "limitingConeAngle", - "markerheight": "markerHeight", - "markerunits": "markerUnits", - "markerwidth": "markerWidth", - "maskcontentunits": "maskContentUnits", - "maskunits": "maskUnits", - "numoctaves": "numOctaves", - "pathlength": "pathLength", - "patterncontentunits": "patternContentUnits", - "patterntransform": "patternTransform", - "patternunits": "patternUnits", - "pointsatx": "pointsAtX", - "pointsaty": "pointsAtY", - "pointsatz": "pointsAtZ", - "preservealpha": "preserveAlpha", - "preserveaspectratio": "preserveAspectRatio", - "primitiveunits": "primitiveUnits", - "refx": "refX", - "refy": "refY", - "repeatcount": "repeatCount", - "repeatdur": "repeatDur", - "requiredextensions": "requiredExtensions", - "requiredfeatures": "requiredFeatures", - "specularconstant": "specularConstant", - "specularexponent": "specularExponent", - "spreadmethod": "spreadMethod", - "startoffset": "startOffset", - "stddeviation": "stdDeviation", - "stitchtiles": "stitchTiles", - "surfacescale": "surfaceScale", - "systemlanguage": "systemLanguage", - "tablevalues": "tableValues", - "targetx": "targetX", - "targety": "targetY", - "textlength": "textLength", - "viewbox": "viewBox", - "viewtarget": "viewTarget", - "xchannelselector": "xChannelSelector", - "ychannelselector": "yChannelSelector", - "zoomandpan": "zoomAndPan", + "attributename": "attributeName", + "attributetype": "attributeType", + "basefrequency": "baseFrequency", + "baseprofile": "baseProfile", + "calcmode": "calcMode", + "clippathunits": "clipPathUnits", + "diffuseconstant": "diffuseConstant", + "edgemode": "edgeMode", + "filterunits": "filterUnits", + "glyphref": "glyphRef", + "gradienttransform": "gradientTransform", + "gradientunits": "gradientUnits", + "kernelmatrix": "kernelMatrix", + "kernelunitlength": "kernelUnitLength", + "keypoints": "keyPoints", + "keysplines": "keySplines", + "keytimes": "keyTimes", + "lengthadjust": "lengthAdjust", + "limitingconeangle": "limitingConeAngle", + "markerheight": "markerHeight", + "markerunits": "markerUnits", + "markerwidth": "markerWidth", + "maskcontentunits": "maskContentUnits", + "maskunits": "maskUnits", + "numoctaves": "numOctaves", + "pathlength": "pathLength", + "patterncontentunits": "patternContentUnits", + "patterntransform": "patternTransform", + "patternunits": "patternUnits", + "pointsatx": "pointsAtX", + "pointsaty": "pointsAtY", + "pointsatz": "pointsAtZ", + "preservealpha": "preserveAlpha", + "preserveaspectratio": "preserveAspectRatio", + "primitiveunits": "primitiveUnits", + "refx": "refX", + "refy": "refY", + "repeatcount": "repeatCount", + "repeatdur": "repeatDur", + "requiredextensions": "requiredExtensions", + "requiredfeatures": "requiredFeatures", + "specularconstant": "specularConstant", + "specularexponent": "specularExponent", + "spreadmethod": "spreadMethod", + "startoffset": "startOffset", + "stddeviation": "stdDeviation", + "stitchtiles": "stitchTiles", + "surfacescale": "surfaceScale", + "systemlanguage": "systemLanguage", + "tablevalues": "tableValues", + "targetx": "targetX", + "targety": "targetY", + "textlength": "textLength", + "viewbox": "viewBox", + "viewtarget": "viewTarget", + "xchannelselector": "xChannelSelector", + "ychannelselector": "yChannelSelector", + "zoomandpan": "zoomAndPan", } diff --git a/vendor/golang.org/x/net/html/parse.go b/vendor/golang.org/x/net/html/parse.go index 2cd12fc816..f91466f7cd 100644 --- a/vendor/golang.org/x/net/html/parse.go +++ b/vendor/golang.org/x/net/html/parse.go @@ -728,7 +728,13 @@ func inHeadNoscriptIM(p *parser) bool { return inBodyIM(p) case a.Basefont, a.Bgsound, a.Link, a.Meta, a.Noframes, a.Style: return inHeadIM(p) - case a.Head, a.Noscript: + case a.Head: + // Ignore the token. + return true + case a.Noscript: + // Don't let the tokenizer go into raw text mode even when a