Compare commits

...

42 Commits

Author SHA1 Message Date
zeripath
bab7d885aa Changelog for 1.16.5 (#19189)
* Changelog for 1.16.5

 ## [1.16.5](https://github.com/go-gitea/gitea/releases/tag/1.16.5) - 2022-03-23

Signed-off-by: Andrew Thornton <art27@cantab.net>
Co-authored-by: 6543 <6543@obermui.de>
2022-03-24 01:13:52 +01:00
6543
42229dc0b8 Fix showing issues in your repositories (#18916) (#19191)
- Make a restriction on which issues can be shown based on if you the user or team has write permission to the repository.
- Fixes a issue whereby you wouldn't see any associated issues with a specific team on a organization if you wasn't a member(fixed by zeroing the User{ID} in the options).
- Resolves #18913

Co-authored-by: Gusted <williamzijl7@hotmail.com>
2022-03-24 00:36:38 +01:00
zeripath
e3d8e92bdc Prevent redirect to Host (2) (#19175) (#19186)
Backport #19175

Unhelpfully Locations starting with `/\` will be converted by the
browser to `//` because ... well I do not fully understand. Certainly
the RFCs and MDN do not indicate that this would be expected. Providing
"compatibility" with the (mis)behaviour of a certain proprietary OS is
my suspicion. However, we clearly have to protect against this.

Therefore we should reject redirection locations that match the regular
expression: `^/[\\\\/]+`

Reference #9678

Signed-off-by: Andrew Thornton <art27@cantab.net>
2022-03-23 20:01:23 +00:00
zeripath
6fc73a8433 Fix compare link in active feeds for new branch (#19149) (#19185)
Backport #19149

When a new branch is pushed the old SHA is always listed as the empty sha and thus the compare link that is created does not work correctly.

Therefore when creating the compare link for new branches:

1. Attempt to get the parent of the first commit and use that as the basis
for the compare link.
2. If this is not possible make a comparison to the default branch
3. Finally if that is not possible simply do not show a compare link.

However, there are multiple broken compare links remaining therefore, in order for these to not break we will simply make the compare link redirect to the default branch.

Fix #19144

Signed-off-by: a1012112796 <1012112796@qq.com>
Signed-off-by: Andrew Thornton <art27@cantab.net>

Co-authored-by: Andrew Thornton <art27@cantab.net>
Co-authored-by: a1012112796 <1012112796@qq.com>
2022-03-23 19:04:50 +00:00
zeripath
b1a0a78a51 Redirect .wiki/* ui link to /wiki (#18831) (#19184)
Backport #18831

Redirect .wiki/* ui link to /wiki

fix #18590

Signed-off-by: a1012112796 <1012112796@qq.com>
Signed-off-by: Andrew Thornton <art27@cantab.net>

Co-authored-by: Andrew Thornton <art27@cantab.net>
Co-authored-by: a1012112796 <1012112796@qq.com>
2022-03-23 16:46:08 +00:00
Andrew Thornton
9c7d8b3096 Prevent start panic due to missing DotEscape function
Unfortunately #19169 causing a panic at startup in prod mode. This was hidden by dev
mode because the templates are compiled dynamically there. The issue is that DotEscape
is not in the original FuncMap at the time of compilation which causes a panic.

Ref #19169

Signed-off-by: Andrew Thornton <art27@cantab.net>
2022-03-23 16:09:57 +00:00
zeripath
93feb1a666 Fix the bug: deploy key with write access can not push (#19010) (#19182)
Backport #19010

Use DeployKeyID to replace the IsDeployKey, then CanWriteCode uses the DeployKeyID to check the write permission.

Fix #19009

Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
2022-03-23 13:44:41 +00:00
zeripath
bb0e2121a3 Try to prevent autolinking of displaynames by email readers (#19169) (#19183)
Backport #19169

Unfortunately many email readers will (helpfully) detect url or url-like names and
automatically create links to them, even in HTML emails. This is not ideal when
usernames can have dots in them.

This PR tries to prevent this behaviour by sticking ZWJ characters between dots and
also set the meta tag to prevent format detection.

Not every email template has been changed in this way - just the activation emails but
it may be that we should be setting the above meta tag in all of our emails too.

Signed-off-by: Andrew Thornton <art27@cantab.net>
2022-03-23 15:18:11 +02:00
zeripath
d21b7fd3af Clean paths when looking in Storage (#19124) (#19179)
Backport #19124

* Clean paths when looking in Storage

Ensure paths are clean for minio aswell as local storage.

Use url.Path not RequestURI/EscapedPath in storageHandler.

Signed-off-by: Andrew Thornton <art27@cantab.net>

* Apply suggestions from code review

Co-authored-by: Lauris BH <lauris@nix.lv>
2022-03-23 09:23:00 +00:00
Norwin
743553f3e9 Cleanup protected branches when deleting users & teams (#19158) (#19174)
* Clean up protected_branches when deleting user

fixes #19094

* Clean up protected_branches when deleting teams

* fix issue

Co-authored-by: Lauris BH <lauris@nix.lv>

Co-authored-by: Lauris BH <lauris@nix.lv>
Co-authored-by: zeripath <art27@cantab.net>
Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
2022-03-23 13:56:53 +08:00
zeripath
a3ccbb5b7f Ensure that setting.LocalURL always has a trailing slash (#19171) (#19177)
Backport #19171

Fix #19166

Signed-off-by: Andrew Thornton <art27@cantab.net>

Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>
2022-03-23 12:56:52 +08:00
zeripath
4b7cb813e6 Use the new/choose link for New Issue on project page (#19172) (#19176)
Backport #19172

Extend issues/new/choose to pass the project id and change New Issue
link on project page to use new/choose

Fix #19170

Signed-off-by: Andrew Thornton <art27@cantab.net>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>

Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
2022-03-23 09:41:12 +08:00
zeripath
23b8214549 Use IterateBufferSize whilst querying repositories during adoption check (#19140) (#19160)
Backport #19140

The adoption page checks directories to see if they are repositories by querying the
db on a per user basis. This can lead to problems if a user has a large number of
repositories or putative repositories.

This PR changes the buffering to check the db in IterataeBufferSize batches instead.

Fix #19137

Signed-off-by: Andrew Thornton <art27@cantab.net>
2022-03-22 09:11:22 +08:00
zeripath
08feb6b664 Ensure isSSH is set whenever DISABLE_HTTP_GIT is set (#19028) (#19146)
Backport #19028

When DISABLE_HTTP_GIT is set we should always show the SSH button

Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>
Co-authored-by: techknowlogick <techknowlogick@gitea.io>
2022-03-21 08:59:55 +08:00
Abheek Dhawan
1aa5dc75df Use custom favicon when viewing static files if it exists (#19130) (#19152)
Redirect `/favicon.ico` to `/assets/img/favicon.png`.

Fix #19109

Co-authored-by: zeripath <art27@cantab.net>
2022-03-20 20:28:35 -04:00
Gusted
ee234aff61 Fix NPE /repos/issues/search when not signed in (#19154) (#19155)
- Backport #19154

  - Don't panic when on `/repos/issues/search?{created,assigned,mentioned,review_requested}=true` when client didn't pass any authentication.
  - Resolves #19115
2022-03-20 22:42:31 +01:00
zeripath
a3f3e310fb Fix wrong scopes caused by empty scope input (#19029) (#19145)
Backport #19029
Fix #18972 Gitea prepends requested openid scope with + after updating authentication source
2022-03-21 03:13:18 +08:00
zeripath
ea56bdca5f Fix the editor height in review box (#19003) (#19147)
Backport #19003

Fix the height problem in  https://github.com/go-gitea/gitea/pull/18862#issuecomment-1059329539

Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
2022-03-20 10:29:49 +08:00
zeripath
45c836badc Do not send notification emails to inactive users (#19131) (#19139)
Backport #19131
Backport #19142

Emails should not be sent to inactive users except for Activate and ResetPassword
messages.

Fix #18950

Signed-off-by: Andrew Thornton <art27@cantab.net>
2022-03-19 18:33:32 +00:00
techknowlogick
f9ea4ab69a Bump to build with go1.18 (#19120 et al) (#19127)
Backport #19120 
Backport #19099 
Backport #18874 
Backport #18420
Backport #19128
Backport #18270 

Bump to build with go1.18

Co-authored-by: techknowlogick <techknowlogick@gitea.io>
Signed-off-by: Andrew Thornton <art27@cantab.net>
Co-authored-by: silverwind <me@silverwind.io>
Co-authored-by: 6543 <6543@obermui.de>
Co-authored-by: zeripath <art27@cantab.net>
Co-authored-by: Jelle Hulter <jellehulter@gmail.com>
2022-03-19 18:46:47 +01:00
zeripath
e6d46eeb55 Make migrations SKIP_TLS_VERIFY apply to git too (#19132) (#19141)
Backport #19132

Make SKIP_TLS_VERIFY apply to git data migrations too through adding the `-c http.sslVerify=false` option to the git clone command.

Fix #18998

Signed-off-by: Andrew Thornton <art27@cantab.net>
2022-03-19 16:20:26 +00:00
zeripath
5bb0c92b6c Do not send activation email if manual confirm is set (#19119) (#19122)
Backport #19119

If the mailer is configured then even if Manual confirm is set an activation email
is still being sent because `handleUserCreated` is not checking for this case.

Fix #17263

Signed-off-by: Andrew Thornton <art27@cantab.net>
2022-03-19 14:20:42 +00:00
Gusted
c1e6be47d7 Update golang.org/x/crypto (#19097) (#19098)
Backport #19097

* Update golang.org/x/crypto (#19097)

- Backport #19097

* Fix deprecation notice

* Backport workaround removal
2022-03-19 12:16:15 +00:00
Lunny Xiao
79a5e68816 Handle email address not exist (#19089) (#19121)
Backport #19089

* Handle email address not exist. (#19089)

* Fix lint about strings.Title

Co-authored-by: KN4CK3R <admin@oldschoolhack.me>
2022-03-19 11:35:23 +00:00
Gusted
9bcbbd419f Update json-iterator (#18644) (#19100)
- Backport #18644
2022-03-15 17:29:06 -04:00
6543
f460b7543e Changelog v1.16.4 (#19081) 2022-03-14 21:55:33 +01:00
6543
1cb649525d Restrict email address validation (#17688) (#19085)
Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>
2022-03-14 20:51:58 +01:00
6543
99861e3e06 Fix lfs bug (#19072) (#19080)
Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>
2022-03-14 15:59:54 +01:00
Gusted
66b8a43e5f Refactor mirror code & fix StartToMirror (#18904) (#19075)
- Backport #18904.
2022-03-14 20:04:41 +08:00
zeripath
d285905826 Update the webauthn_credential_id_sequence in Postgres (#19048) (#19060)
Backport #19048

There is (yet) another problem with v210 in that Postgres will silently allow preset
ID insertions ... but it will not update the sequence value.

This PR simply adds a little step to the end of the v210 migration to update the
sequence number.

Users who have already migrated who find that they cannot insert new
webauthn_credentials into the DB can either run:

```bash
gitea doctor recreate-table webauthn_credential
```

or

```bash
SELECT setval('webauthn_credential_id_seq', COALESCE((SELECT MAX(id)+1 FROM `webauthn_credential`), 1), false)
```

which will fix the bad sequence.

Fix #19012

Signed-off-by: Andrew Thornton <art27@cantab.net>

Co-authored-by: 6543 <6543@obermui.de>
2022-03-13 12:02:19 +08:00
zeripath
4df2320ba6 Prevent 500 when there is an error during new auth source post (#19041) (#19059)
Backport #19041

Fix #19036

Signed-off-by: Andrew Thornton <art27@cantab.net>
2022-03-13 03:42:31 +01:00
zeripath
0fe99cc00c If rendering has failed due to a net.OpError stop rendering (attempt 2) (#19049) (#19056)
Backport #19049

Unfortunately #18642 does not work because a `*net.OpError` does not implement
the `Is` interface to make `errors.Is` work correctly - thus leading to the
irritating conclusion that a `*net.OpError` is not a `*net.OpError`.

Here we keep the `errors.Is` because presumably this will be fixed at
some point in the golang main source code but also we add a simply type
cast to also check.

Fix #18629

Signed-off-by: Andrew Thornton <art27@cantab.net>
2022-03-10 22:13:55 +01:00
Norwin
580401ecbf Fix flag validation (#19046) (#19051)
Regression from #5785
2022-03-10 20:23:55 +00:00
zeripath
7aa29720f0 Improve SyncMirrors logging (#19045) (#19050)
Backport #19045

Yet another issue has come up where the logging from SyncMirrors does not provide
enough context. This PR adds more context to these logging events.

Related #19038

Signed-off-by: Andrew Thornton <art27@cantab.net>
2022-03-10 16:06:35 +01:00
6543
3e5c844a77 fix pam authorization (#19040) (#19047)
Backport #19040 

The PAM module has previously only checked the results of the authentication module.

However, in normal PAM practice most users will expect account module authorization to also be checked. Without doing this check in almost every configuration expired accounts and accounts with expired passwords will still be able to login.

This is likely to represent a significant gotcha in most configurations and cause most users configurations to be potentially insecure. Therefore we should add in the account authorization check.

## ⚠️ **BREAKING** ⚠️ 

Users of the PAM module who rely on account modules not being checked will need to change their PAM configuration.

However, as it is likely that the vast majority of users of PAM will be expecting account authorization to be checked in addition to authentication we should make this breaking change to make the default behaviour correct for the majority.

---

I suggest we backport this despite the BREAKING nature because of the surprising nature of this.

Thanks to @ysf for bringing this to our attention.


Co-authored-by: zeripath <art27@cantab.net>
Co-authored-by: ysf <34326+ysf@users.noreply.github.com>
2022-03-10 08:15:35 +00:00
zeripath
4047c5c068 Ignore missing comment for user notifications (#18954) (#19043) 2022-03-10 01:48:27 -05:00
zeripath
03d924238c Set rel="nofollow noindex" on new issue links (#19023) (#19042)
Backport #19023

Fix #19018

Signed-off-by: Andrew Thornton <art27@cantab.net>
2022-03-09 23:01:30 +00:00
Lunny Xiao
bc1248ed9e Upgrading binding package (#19034) (#19035)
Backport #19034

Fix #18855
2022-03-09 18:07:46 +00:00
zeripath
dd52c08b74 Don't show context cancelled errors in attribute reader (#19006) (#19027)
Backport #19006

Fix #18997

Signed-off-by: Andrew Thornton <art27@cantab.net>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>

Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
2022-03-08 19:20:37 +08:00
Lunny Xiao
b811b819e2 Fix update hint bug (#19002) 2022-03-04 18:28:17 +00:00
Otto Richter (fnetX)
da985b25ce Fix potential assignee query for repo (#18994) (#18999)
* Fix potential assignee query for repo

* Add tests for `GetRepoAssignees`

- As per https://github.com/go-gitea/gitea/pull/18994#issuecomment-1058506640

Co-authored-by: Gusted <williamzijl7@hotmail.com>
2022-03-05 00:12:34 +08:00
6543
ae9c51df7c allow overwrite artifacts for github releases (#18987) (#18988) 2022-03-03 16:18:55 +01:00
98 changed files with 1985 additions and 713 deletions

View File

@@ -25,7 +25,7 @@ steps:
- make deps-frontend
- name: deps-backend
image: golang:1.17
image: golang:1.18
pull: always
commands:
- make deps-backend
@@ -49,11 +49,14 @@ steps:
GOSUMDB: sum.golang.org
TAGS: bindata sqlite sqlite_unlock_notify
depends_on: [deps-backend]
volumes:
- name: deps
path: /go
- name: lint-backend-windows
image: gitea/test_env:linux-amd64 # https://gitea.com/gitea/test-env
commands:
- make golangci-lint vet
- make golangci-lint-windows vet
environment:
GOPROXY: https://goproxy.cn # proxy.golang.org is blocked in China, this proxy is not
GOSUMDB: sum.golang.org
@@ -61,6 +64,9 @@ steps:
GOOS: windows
GOARCH: amd64
depends_on: [deps-backend]
volumes:
- name: deps
path: /go
- name: lint-backend-gogit
image: gitea/test_env:linux-amd64 # https://gitea.com/gitea/test-env
@@ -71,6 +77,9 @@ steps:
GOSUMDB: sum.golang.org
TAGS: bindata gogit sqlite sqlite_unlock_notify
depends_on: [deps-backend]
volumes:
- name: deps
path: /go
- name: checks-frontend
image: node:16
@@ -79,7 +88,7 @@ steps:
depends_on: [deps-frontend]
- name: checks-backend
image: golang:1.17
image: golang:1.18
commands:
- make checks-backend
depends_on: [deps-backend]
@@ -100,7 +109,7 @@ steps:
depends_on: [test-frontend]
- name: build-backend-no-gcc
image: golang:1.16 # this step is kept as the lowest version of golang that we support
image: golang:1.17 # this step is kept as the lowest version of golang that we support
pull: always
environment:
GO111MODULE: on
@@ -113,7 +122,7 @@ steps:
path: /go
- name: build-backend-arm64
image: golang:1.17
image: golang:1.18
environment:
GO111MODULE: on
GOPROXY: https://goproxy.cn
@@ -129,7 +138,7 @@ steps:
path: /go
- name: build-backend-windows
image: golang:1.17
image: golang:1.18
environment:
GO111MODULE: on
GOPROXY: https://goproxy.cn
@@ -144,7 +153,7 @@ steps:
path: /go
- name: build-backend-386
image: golang:1.17
image: golang:1.18
environment:
GO111MODULE: on
GOPROXY: https://goproxy.cn
@@ -233,7 +242,7 @@ steps:
- pull_request
- name: deps-backend
image: golang:1.17
image: golang:1.18
pull: always
commands:
- make deps-backend
@@ -350,7 +359,7 @@ steps:
path: /go
- name: generate-coverage
image: golang:1.17
image: golang:1.18
commands:
- make coverage
environment:
@@ -425,7 +434,7 @@ steps:
- pull_request
- name: deps-backend
image: golang:1.17
image: golang:1.18
pull: always
commands:
- make deps-backend
@@ -567,7 +576,7 @@ trigger:
steps:
- name: download
image: golang:1.17
image: golang:1.18
pull: always
commands:
- timeout -s ABRT 40m make generate-license generate-gitignore
@@ -628,7 +637,7 @@ steps:
- make deps-frontend
- name: deps-backend
image: golang:1.17
image: golang:1.18
pull: always
commands:
- make deps-backend
@@ -637,7 +646,7 @@ steps:
path: /go
- name: static
image: techknowlogick/xgo:go-1.17.x
image: techknowlogick/xgo:go-1.18.x
pull: always
commands:
- curl -sL https://deb.nodesource.com/setup_16.x | bash - && apt-get install -y nodejs
@@ -746,7 +755,7 @@ steps:
- make deps-frontend
- name: deps-backend
image: golang:1.17
image: golang:1.18
pull: always
commands:
- make deps-backend
@@ -755,7 +764,7 @@ steps:
path: /go
- name: static
image: techknowlogick/xgo:go-1.17.x
image: techknowlogick/xgo:go-1.18.x
pull: always
commands:
- curl -sL https://deb.nodesource.com/setup_16.x | bash - && apt-get install -y nodejs
@@ -804,11 +813,12 @@ steps:
depends_on: [gpg-sign]
- name: github
image: plugins/github-release:1
image: plugins/github-release:latest
pull: always
settings:
files:
- "dist/release/*"
file_exists: overwrite
environment:
GITHUB_TOKEN:
from_secret: github_token

View File

@@ -13,7 +13,7 @@ linters:
#- gocyclo # The cyclomatic complexety of a lot of functions is too high, we should refactor those another time.
- gofmt
- misspell
- gocritic
#- gocritic # TODO: disabled until fixed with go 1.18
- bidichk
- ineffassign
- revive
@@ -22,7 +22,7 @@ linters:
fast: false
run:
timeout: 3m
timeout: 10m
skip-dirs:
- node_modules
- public
@@ -61,6 +61,9 @@ linters-settings:
- name: errorf
- name: duplicated-imports
- name: modifies-value-receiver
gofumpt:
extra-rules: true
lang-version: 1.18
issues:
exclude-rules:
@@ -148,3 +151,11 @@ issues:
- path: models/user/openid.go
linters:
- golint
- linters: staticcheck
text: "strings.Title is deprecated: The rule Title uses for word boundaries does not handle Unicode punctuation properly. Use golang.org/x/text/cases instead."
- linters: staticcheck
text: "util.FindClosure is deprecated: This function can not handle newlines. Many elements can be existed over multiple lines(e.g. link labels). Use text.Reader.FindClosure."
- linters: staticcheck
text: "gossh.SigAlgoRSASHA2256 is deprecated: use KeyAlgoRSASHA256."
- linters: staticcheck
text: "gossh.SigAlgoRSASHA2512 is deprecated: use KeyAlgoRSASHA512."

View File

@@ -4,6 +4,59 @@ 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.16.5](https://github.com/go-gitea/gitea/releases/tag/1.16.5) - 2022-03-23
* BREAKING
* Bump to build with go1.18 (#19120 et al) (#19127)
* SECURITY
* Prevent redirect to Host (2) (#19175) (#19186)
* Try to prevent autolinking of displaynames by email readers (#19169) (#19183)
* Clean paths when looking in Storage (#19124) (#19179)
* Do not send notification emails to inactive users (#19131) (#19139)
* Do not send activation email if manual confirm is set (#19119) (#19122)
* ENHANCEMENTS
* Use the new/choose link for New Issue on project page (#19172) (#19176)
* BUGFIXES
* Fix showing issues in your repositories (#18916) (#19191)
* Fix compare link in active feeds for new branch (#19149) (#19185)
* Redirect .wiki/* ui link to /wiki (#18831) (#19184)
* Ensure deploy keys with write access can push (#19010) (#19182)
* Ensure that setting.LocalURL always has a trailing slash (#19171) (#19177)
* Cleanup protected branches when deleting users & teams (#19158) (#19174)
* Use IterateBufferSize whilst querying repositories during adoption check (#19140) (#19160)
* Fix NPE /repos/issues/search when not signed in (#19154) (#19155)
* Use custom favicon when viewing static files if it exists (#19130) (#19152)
* Fix the editor height in review box (#19003) (#19147)
* Ensure isSSH is set whenever DISABLE_HTTP_GIT is set (#19028) (#19146)
* Fix wrong scopes caused by empty scope input (#19029) (#19145)
* Make migrations SKIP_TLS_VERIFY apply to git too (#19132) (#19141)
* Handle email address not exist (#19089) (#19121)
* MISC
* Update json-iterator to allow compilation with go1.18 (#18644) (#19100)
* Update golang.org/x/crypto (#19097) (#19098)
## [1.16.4](https://github.com/go-gitea/gitea/releases/tag/v1.16.4) - 2022-03-14
* SECURITY
* Restrict email address validation (#17688) (#19085)
* Fix lfs bug (#19072) (#19080)
* ENHANCEMENTS
* Improve SyncMirrors logging (#19045) (#19050)
* BUGFIXES
* Refactor mirror code & fix `StartToMirror` (#18904) (#19075)
* Update the webauthn_credential_id_sequence in Postgres (#19048) (#19060)
* Prevent 500 when there is an error during new auth source post (#19041) (#19059)
* If rendering has failed due to a net.OpError stop rendering (attempt 2) (#19049) (#19056)
* Fix flag validation (#19046) (#19051)
* Add pam account authorization check (#19040) (#19047)
* Ignore missing comment for user notifications (#18954) (#19043)
* Set `rel="nofollow noindex"` on new issue links (#19023) (#19042)
* Upgrading binding package (#19034) (#19035)
* Don't show context cancelled errors in attribute reader (#19006) (#19027)
* Fix update hint bug (#18996) (#19002)
* MISC
* Fix potential assignee query for repo (#18994) (#18999)
## [1.16.3](https://github.com/go-gitea/gitea/releases/tag/v1.16.3) - 2022-03-02
* SECURITY

View File

@@ -1,7 +1,5 @@
###################################
#Build stage - temporarily using techknowlogick image until we upgrade to latest official alpine/go image
FROM techknowlogick/go:1.17-alpine3.13 AS build-env
#Build stage
FROM golang:1.18-alpine3.15 AS build-env
ARG GOPROXY
ENV GOPROXY ${GOPROXY:-direct}

View File

@@ -1,7 +1,5 @@
###################################
#Build stage - temporarily using techknowlogick image until we upgrade to latest official alpine/go image
FROM techknowlogick/go:1.17-alpine3.13 AS build-env
#Build stage
FROM golang:1.18-alpine3.15 AS build-env
ARG GOPROXY
ENV GOPROXY ${GOPROXY:-direct}

View File

@@ -24,10 +24,19 @@ SHASUM ?= shasum -a 256
HAS_GO = $(shell hash $(GO) > /dev/null 2>&1 && echo "GO" || echo "NOGO" )
COMMA := ,
XGO_VERSION := go-1.17.x
MIN_GO_VERSION := 001016000
XGO_VERSION := go-1.18.x
MIN_GO_VERSION := 001017000
MIN_NODE_VERSION := 012017000
MIN_GOLANGCI_LINT_VERSION := 001043000
AIR_PACKAGE ?= github.com/cosmtrek/air@v1.29.0
EDITORCONFIG_CHECKER_PACKAGE ?= github.com/editorconfig-checker/editorconfig-checker/cmd/editorconfig-checker@2.4.0
ERRCHECK_PACKAGE ?= github.com/kisielk/errcheck@v1.6.0
GOFUMPT_PACKAGE ?= mvdan.cc/gofumpt@v0.3.0
GOLANGCI_LINT_PACKAGE ?= github.com/golangci/golangci-lint/cmd/golangci-lint@v1.44.2
GXZ_PAGAGE ?= github.com/ulikunitz/xz/cmd/gxz@v0.5.10
MISSPELL_PACKAGE ?= github.com/client9/misspell/cmd/misspell@v0.3.4
SWAGGER_PACKAGE ?= github.com/go-swagger/go-swagger/cmd/swagger@v0.29.0
XGO_PACKAGE ?= src.techknowlogick.com/xgo@latest
DOCKER_IMAGE ?= gitea/gitea
DOCKER_TAG ?= latest
@@ -125,8 +134,6 @@ ifeq ($(filter $(TAGS_SPLIT),bindata),bindata)
GO_SOURCES += $(BINDATA_DEST)
endif
#To update swagger use: GO111MODULE=on go get -u github.com/go-swagger/go-swagger/cmd/swagger
SWAGGER := $(GO) run github.com/go-swagger/go-swagger/cmd/swagger
SWAGGER_SPEC := templates/swagger/v1_json.tmpl
SWAGGER_SPEC_S_TMPL := s|"basePath": *"/api/v1"|"basePath": "{{AppSubUrl \| JSEscape \| Safe}}/api/v1"|g
SWAGGER_SPEC_S_JSON := s|"basePath": *"{{AppSubUrl \| JSEscape \| Safe}}/api/v1"|"basePath": "/api/v1"|g
@@ -234,8 +241,8 @@ clean:
.PHONY: fmt
fmt:
@echo "Running gitea-fmt(with gofmt)..."
@$(GO) run build/code-batch-process.go gitea-fmt -s -w '{file-list}'
@echo "Running gitea-fmt (with gofumpt)..."
@MISSPELL_PACKAGE=$(MISSPELL_PACKAGE) GOFUMPT_PACKAGE=$(GOFUMPT_PACKAGE) $(GO) run build/code-batch-process.go gitea-fmt -w '{file-list}'
.PHONY: vet
vet:
@@ -254,7 +261,7 @@ endif
.PHONY: generate-swagger
generate-swagger:
$(SWAGGER) generate spec -x "$(SWAGGER_EXCLUDE)" -o './$(SWAGGER_SPEC)'
$(GO) run $(SWAGGER_PACKAGE) generate spec -x "$(SWAGGER_EXCLUDE)" -o './$(SWAGGER_SPEC)'
$(SED_INPLACE) '$(SWAGGER_SPEC_S_TMPL)' './$(SWAGGER_SPEC)'
$(SED_INPLACE) $(SWAGGER_NEWLINE_COMMAND) './$(SWAGGER_SPEC)'
@@ -270,21 +277,18 @@ swagger-check: generate-swagger
.PHONY: swagger-validate
swagger-validate:
$(SED_INPLACE) '$(SWAGGER_SPEC_S_JSON)' './$(SWAGGER_SPEC)'
$(SWAGGER) validate './$(SWAGGER_SPEC)'
$(GO) run $(SWAGGER_PACKAGE) validate './$(SWAGGER_SPEC)'
$(SED_INPLACE) '$(SWAGGER_SPEC_S_TMPL)' './$(SWAGGER_SPEC)'
.PHONY: errcheck
errcheck:
@hash errcheck > /dev/null 2>&1; if [ $$? -ne 0 ]; then \
$(GO) install github.com/kisielk/errcheck@8ddee489636a8311a376fc92e27a6a13c6658344; \
fi
@echo "Running errcheck..."
@errcheck $(GO_PACKAGES)
$(GO) run $(ERRCHECK_PACKAGE) $(GO_PACKAGES)
.PHONY: fmt-check
fmt-check:
# get all go files and run gitea-fmt (with gofmt) on them
@diff=$$($(GO) run build/code-batch-process.go gitea-fmt -s -d '{file-list}'); \
@diff=$$(MISSPELL_PACKAGE=$(MISSPELL_PACKAGE) GOFUMPT_PACKAGE=$(GOFUMPT_PACKAGE) $(GO) run build/code-batch-process.go gitea-fmt -l '{file-list}'); \
if [ -n "$$diff" ]; then \
echo "Please run 'make fmt' and commit the result:"; \
echo "$${diff}"; \
@@ -323,10 +327,7 @@ watch-frontend: node-check node_modules
.PHONY: watch-backend
watch-backend: go-check
@hash air > /dev/null 2>&1; if [ $$? -ne 0 ]; then \
$(GO) install github.com/cosmtrek/air@bedc18201271882c2be66d216d0e1a275b526ec4; \
fi
air -c .air.toml
$(GO) run $(AIR_PACKAGE) -c .air.toml
.PHONY: test
test: test-frontend test-backend
@@ -599,12 +600,9 @@ $(DIST_DIRS):
.PHONY: release-windows
release-windows: | $(DIST_DIRS)
@hash xgo > /dev/null 2>&1; if [ $$? -ne 0 ]; then \
$(GO) install src.techknowlogick.com/xgo@latest; \
fi
CGO_CFLAGS="$(CGO_CFLAGS)" xgo -go $(XGO_VERSION) -buildmode exe -dest $(DIST)/binaries -tags 'netgo osusergo $(TAGS)' -ldflags '-linkmode external -extldflags "-static" $(LDFLAGS)' -targets 'windows/*' -out gitea-$(VERSION) .
CGO_CFLAGS="$(CGO_CFLAGS)" $(GO) run $(XGO_PACKAGE) -go $(XGO_VERSION) -buildmode exe -dest $(DIST)/binaries -tags 'netgo osusergo $(TAGS)' -ldflags '-linkmode external -extldflags "-static" $(LDFLAGS)' -targets 'windows/*' -out gitea-$(VERSION) .
ifeq (,$(findstring gogit,$(TAGS)))
CGO_CFLAGS="$(CGO_CFLAGS)" xgo -go $(XGO_VERSION) -buildmode exe -dest $(DIST)/binaries -tags 'netgo osusergo gogit $(TAGS)' -ldflags '-linkmode external -extldflags "-static" $(LDFLAGS)' -targets 'windows/*' -out gitea-$(VERSION)-gogit .
CGO_CFLAGS="$(CGO_CFLAGS)" $(GO) run $(XGO_PACKAGE) -go $(XGO_VERSION) -buildmode exe -dest $(DIST)/binaries -tags 'netgo osusergo gogit $(TAGS)' -ldflags '-linkmode external -extldflags "-static" $(LDFLAGS)' -targets 'windows/*' -out gitea-$(VERSION)-gogit .
endif
ifeq ($(CI),drone)
cp /build/* $(DIST)/binaries
@@ -612,20 +610,14 @@ endif
.PHONY: release-linux
release-linux: | $(DIST_DIRS)
@hash xgo > /dev/null 2>&1; if [ $$? -ne 0 ]; then \
$(GO) install src.techknowlogick.com/xgo@latest; \
fi
CGO_CFLAGS="$(CGO_CFLAGS)" xgo -go $(XGO_VERSION) -dest $(DIST)/binaries -tags 'netgo osusergo $(TAGS)' -ldflags '-linkmode external -extldflags "-static" $(LDFLAGS)' -targets '$(LINUX_ARCHS)' -out gitea-$(VERSION) .
CGO_CFLAGS="$(CGO_CFLAGS)" $(GO) run $(XGO_PACKAGE) -go $(XGO_VERSION) -dest $(DIST)/binaries -tags 'netgo osusergo $(TAGS)' -ldflags '-linkmode external -extldflags "-static" $(LDFLAGS)' -targets '$(LINUX_ARCHS)' -out gitea-$(VERSION) .
ifeq ($(CI),drone)
cp /build/* $(DIST)/binaries
endif
.PHONY: release-darwin
release-darwin: | $(DIST_DIRS)
@hash xgo > /dev/null 2>&1; if [ $$? -ne 0 ]; then \
$(GO) install src.techknowlogick.com/xgo@latest; \
fi
CGO_CFLAGS="$(CGO_CFLAGS)" xgo -go $(XGO_VERSION) -dest $(DIST)/binaries -tags 'netgo osusergo $(TAGS)' -ldflags '$(LDFLAGS)' -targets 'darwin-10.12/amd64,darwin-10.12/arm64' -out gitea-$(VERSION) .
CGO_CFLAGS="$(CGO_CFLAGS)" $(GO) run $(XGO_PACKAGE) -go $(XGO_VERSION) -dest $(DIST)/binaries -tags 'netgo osusergo $(TAGS)' -ldflags '$(LDFLAGS)' -targets 'darwin-10.12/amd64,darwin-10.12/arm64' -out gitea-$(VERSION) .
ifeq ($(CI),drone)
cp /build/* $(DIST)/binaries
endif
@@ -640,10 +632,7 @@ release-check: | $(DIST_DIRS)
.PHONY: release-compress
release-compress: | $(DIST_DIRS)
@hash gxz > /dev/null 2>&1; if [ $$? -ne 0 ]; then \
$(GO) install github.com/ulikunitz/xz/cmd/gxz@v0.5.10; \
fi
cd $(DIST)/release/; for file in `find . -type f -name "*"`; do echo "compressing $${file}" && gxz -k -9 $${file}; done;
cd $(DIST)/release/; for file in `find . -type f -name "*"`; do echo "compressing $${file}" && $(GO) run $(GXZ_PAGAGE) -k -9 $${file}; done;
.PHONY: release-sources
release-sources: | $(DIST_DIRS)
@@ -673,6 +662,15 @@ deps-frontend: node_modules
.PHONY: deps-backend
deps-backend:
$(GO) mod download
$(GO) install $(AIR_PACKAGE)
$(GO) install $(EDITORCONFIG_CHECKER_PACKAGE)
$(GO) install $(ERRCHECK_PACKAGE)
$(GO) install $(GOFUMPT_PACKAGE)
$(GO) install $(GOLANGCI_LINT_PACKAGE)
$(GO) install $(GXZ_PAGAGE)
$(GO) install $(MISSPELL_PACKAGE)
$(GO) install $(SWAGGER_PACKAGE)
$(GO) install $(XGO_PACKAGE)
node_modules: package-lock.json
npm install --no-save
@@ -766,22 +764,19 @@ pr\#%: clean-all
$(GO) run contrib/pr/checkout.go $*
.PHONY: golangci-lint
golangci-lint: golangci-lint-check
golangci-lint run --timeout 10m
golangci-lint:
$(GO) run $(GOLANGCI_LINT_PACKAGE) run
.PHONY: golangci-lint-check
golangci-lint-check:
$(eval GOLANGCI_LINT_VERSION := $(shell printf "%03d%03d%03d" $(shell golangci-lint --version | grep -Eo '[0-9]+\.[0-9.]+' | tr '.' ' ');))
$(eval MIN_GOLANGCI_LINT_VER_FMT := $(shell printf "%g.%g.%g" $(shell echo $(MIN_GOLANGCI_LINT_VERSION) | grep -o ...)))
@hash golangci-lint > /dev/null 2>&1; if [ $$? -ne 0 ]; then \
echo "Downloading golangci-lint v${MIN_GOLANGCI_LINT_VER_FMT}"; \
export BINARY="golangci-lint"; \
curl -sfL "https://raw.githubusercontent.com/golangci/golangci-lint/v${MIN_GOLANGCI_LINT_VER_FMT}/install.sh" | sh -s -- -b $(GOPATH)/bin v$(MIN_GOLANGCI_LINT_VER_FMT); \
elif [ "$(GOLANGCI_LINT_VERSION)" -lt "$(MIN_GOLANGCI_LINT_VERSION)" ]; then \
echo "Downloading newer version of golangci-lint v${MIN_GOLANGCI_LINT_VER_FMT}"; \
export BINARY="golangci-lint"; \
curl -sfL "https://raw.githubusercontent.com/golangci/golangci-lint/v${MIN_GOLANGCI_LINT_VER_FMT}/install.sh" | sh -s -- -b $(GOPATH)/bin v$(MIN_GOLANGCI_LINT_VER_FMT); \
fi
# workaround step for the lint-backend-windows CI task because 'go run' can not
# have distinct GOOS/GOARCH for its build and run steps
.PHONY: golangci-lint-windows
golangci-lint-windows:
@GOOS= GOARCH= $(GO) install $(GOLANGCI_LINT_PACKAGE)
golangci-lint run
.PHONY: editorconfig-checker
editorconfig-checker:
$(GO) run $(EDITORCONFIG_CHECKER_PACKAGE) templates
.PHONY: docker
docker:

View File

@@ -73,7 +73,7 @@ or if SQLite support is required:
The `build` target is split into two sub-targets:
- `make backend` which requires [Go 1.16](https://golang.org/dl/) or greater.
- `make backend` which requires [Go 1.17](https://go.dev/dl/) or greater.
- `make frontend` which requires [Node.js LTS](https://nodejs.org/en/download/) or greater and Internet connectivity to download npm dependencies.
When building from the official source tarballs which include pre-built frontend files, the `frontend` target will not be triggered, making it possible to build without Node.js and Internet connectivity.

View File

@@ -40,7 +40,7 @@ func passThroughCmd(cmd string, args []string) error {
}
c := exec.Cmd{
Path: foundCmd,
Args: args,
Args: append([]string{cmd}, args...),
Stdin: os.Stdin,
Stdout: os.Stdout,
Stderr: os.Stderr,
@@ -270,9 +270,10 @@ func main() {
if containsString(subArgs, "-w") {
cmdErrors = append(cmdErrors, giteaFormatGoImports(files))
}
cmdErrors = append(cmdErrors, passThroughCmd("gofmt", substArgs))
cmdErrors = append(cmdErrors, giteaFormatGoImports(files, containsString(subArgs, "-l"), containsString(subArgs, "-w")))
cmdErrors = append(cmdErrors, passThroughCmd("go", append([]string{"run", os.Getenv("GOFUMPT_PACKAGE"), "-extra", "-lang", "1.17"}, substArgs...)))
case "misspell":
cmdErrors = append(cmdErrors, passThroughCmd("misspell", substArgs))
cmdErrors = append(cmdErrors, passThroughCmd("go", append([]string{"run", os.Getenv("MISSPELL_PACKAGE")}, substArgs...)))
default:
log.Fatalf("unknown cmd: %s %v", subCmd, subArgs)
}

View File

@@ -31,7 +31,7 @@ func argsSet(c *cli.Context, args ...string) error {
return errors.New(a + " is not set")
}
if util.IsEmptyString(a) {
if util.IsEmptyString(c.String(a)) {
return errors.New(a + " is required")
}
}

View File

@@ -185,7 +185,7 @@ Gitea or set your environment appropriately.`, "")
reponame := os.Getenv(models.EnvRepoName)
userID, _ := strconv.ParseInt(os.Getenv(models.EnvPusherID), 10, 64)
prID, _ := strconv.ParseInt(os.Getenv(models.EnvPRID), 10, 64)
isDeployKey, _ := strconv.ParseBool(os.Getenv(models.EnvIsDeployKey))
deployKeyID, _ := strconv.ParseInt(os.Getenv(models.EnvDeployKeyID), 10, 64)
hookOptions := private.HookOptions{
UserID: userID,
@@ -194,7 +194,7 @@ Gitea or set your environment appropriately.`, "")
GitQuarantinePath: os.Getenv(private.GitQuarantinePath),
GitPushOptions: pushOptions(),
PullRequestID: prID,
IsDeployKey: isDeployKey,
DeployKeyID: deployKeyID,
}
scanner := bufio.NewScanner(os.Stdin)

View File

@@ -243,7 +243,7 @@ func runServ(c *cli.Context) error {
os.Setenv(models.EnvPusherID, strconv.FormatInt(results.UserID, 10))
os.Setenv(models.EnvRepoID, strconv.FormatInt(results.RepoID, 10))
os.Setenv(models.EnvPRID, fmt.Sprintf("%d", 0))
os.Setenv(models.EnvIsDeployKey, fmt.Sprintf("%t", results.IsDeployKey))
os.Setenv(models.EnvDeployKeyID, fmt.Sprintf("%d", results.DeployKeyID))
os.Setenv(models.EnvKeyID, fmt.Sprintf("%d", results.KeyID))
os.Setenv(models.EnvAppURL, setting.AppURL)

View File

@@ -18,9 +18,9 @@ params:
description: Git with a cup of tea
author: The Gitea Authors
website: https://docs.gitea.io
version: 1.16.0
minGoVersion: 1.16
goVersion: 1.17
version: 1.16.4
minGoVersion: 1.17
goVersion: 1.18
minNodeVersion: 12.17
outputs:

View File

@@ -42,7 +42,7 @@ To maintain understandable code and avoid circular dependencies it is important
- `modules/setting`: Store all system configurations read from ini files and has been referenced by everywhere. But they should be used as function parameters when possible.
- `modules/git`: Package to interactive with `Git` command line or Gogit package.
- `public`: Compiled frontend files (javascript, images, css, etc.)
- `routers`: Handling of server requests. As it uses other Gitea packages to serve the request, other packages (models, modules or services) shall not depend on routers.
- `routers`: Handling of server requests. As it uses other Gitea packages to serve the request, other packages (models, modules or services) must not depend on routers.
- `routers/api` Contains routers for `/api/v1` aims to handle RESTful API requests.
- `routers/install` Could only respond when system is in INSTALL mode (INSTALL_LOCK=false).
- `routers/private` will only be invoked by internal sub commands, especially `serv` and `hooks`.
@@ -106,10 +106,20 @@ i.e. `servcies/user`, `models/repository`.
Since there are some packages which use the same package name, it is possible that you find packages like `modules/user`, `models/user`, and `services/user`. When these packages are imported in one Go file, it's difficult to know which package we are using and if it's a variable name or an import name. So, we always recommend to use import aliases. To differ from package variables which are commonly in camelCase, just use **snake_case** for import aliases.
i.e. `import user_service "code.gitea.io/gitea/services/user"`
### Important Gotchas
- Never write `x.Update(exemplar)` without an explicit `WHERE` clause:
- This will cause all rows in the table to be updated with the non-zero values of the exemplar - including IDs.
- You should usually write `x.ID(id).Update(exemplar)`.
- If during a migration you are inserting into a table using `x.Insert(exemplar)` where the ID is preset:
- You will need to ``SET IDENTITY_INSERT `table` ON`` for the MSSQL variant (the migration will fail otherwise)
- However, you will also need to update the id sequence for postgres - the migration will silently pass here but later insertions will fail:
``SELECT setval('table_name_id_seq', COALESCE((SELECT MAX(id)+1 FROM `table_name`), 1), false)``
### Future Tasks
Currently, we are creating some refactors to do the following things:
- Correct that codes which doesn't follow the rules.
- There are too many files in `models`, so we are moving some of them into a sub package `models/xxx`.
- Some `modules` sub packages should be moved to `services` because they depends on `models`.
- Some `modules` sub packages should be moved to `services` because they depend on `models`.

277
go.mod
View File

@@ -1,33 +1,24 @@
module code.gitea.io/gitea
go 1.16
go 1.17
require (
cloud.google.com/go v0.78.0 // indirect
cloud.google.com/go v0.99.0 // indirect
code.gitea.io/gitea-vet v0.2.1
code.gitea.io/sdk/gitea v0.15.1
gitea.com/go-chi/binding v0.0.0-20211013065440-d16dc407c2be
gitea.com/go-chi/binding v0.0.0-20220309004920-114340dabecb
gitea.com/go-chi/cache v0.0.0-20211013020926-78790b11abf1
gitea.com/go-chi/captcha v0.0.0-20211013065431-70641c1a35d5
gitea.com/go-chi/session v0.0.0-20211218221615-e3605d8b28b8
gitea.com/lunny/levelqueue v0.4.1
github.com/42wim/sshsig v0.0.0-20211121163825-841cf5bbc121
github.com/Microsoft/go-winio v0.5.0 // indirect
github.com/NYTimes/gziphandler v1.1.1
github.com/ProtonMail/go-crypto v0.0.0-20210705153151-cc34b1f6908b // indirect
github.com/PuerkitoBio/goquery v1.7.0
github.com/alecthomas/chroma v0.9.4
github.com/andybalholm/brotli v1.0.3 // indirect
github.com/andybalholm/cascadia v1.2.0 // indirect
github.com/blevesearch/bleve/v2 v2.3.0
github.com/boombuler/barcode v1.0.1 // indirect
github.com/bradfitz/gomemcache v0.0.0-20190913173617-a41fca850d0b // indirect
github.com/caddyserver/certmagic v0.15.2
github.com/PuerkitoBio/goquery v1.8.0
github.com/alecthomas/chroma v0.10.0
github.com/blevesearch/bleve/v2 v2.3.1
github.com/caddyserver/certmagic v0.15.4
github.com/chi-middleware/proxy v1.1.1
github.com/couchbase/go-couchbase v0.0.0-20210224140812-5740cd35f448 // indirect
github.com/couchbase/gomemcached v0.1.2 // indirect
github.com/couchbase/goutils v0.0.0-20210118111533-e33d3ffb5401 // indirect
github.com/denisenkom/go-mssqldb v0.10.0
github.com/denisenkom/go-mssqldb v0.12.0
github.com/djherbis/buffer v1.2.0
github.com/djherbis/nio/v3 v3.0.1
github.com/duo-labs/webauthn v0.0.0-20220122034320-81aea484c951
@@ -36,8 +27,7 @@ require (
github.com/emirpasic/gods v1.12.0
github.com/ethantkoenig/rupture v1.0.0
github.com/gliderlabs/ssh v0.3.3
github.com/go-asn1-ber/asn1-ber v1.5.3 // indirect
github.com/go-chi/chi/v5 v5.0.4
github.com/go-chi/chi/v5 v5.0.7
github.com/go-chi/cors v1.2.0
github.com/go-enry/go-enry/v2 v2.7.1
github.com/go-git/go-billy/v5 v5.3.1
@@ -51,87 +41,66 @@ require (
github.com/gogs/chardet v0.0.0-20191104214054-4b6791f73a28
github.com/gogs/cron v0.0.0-20171120032916-9f6c956d3e14
github.com/gogs/go-gogs-client v0.0.0-20210131175652-1d7215cd8d85
github.com/golang-jwt/jwt/v4 v4.2.0
github.com/golang/snappy v0.0.4 // indirect
github.com/golang-jwt/jwt/v4 v4.3.0
github.com/google/go-github/v39 v39.2.0
github.com/google/uuid v1.3.0
github.com/gorilla/feeds v1.1.1
github.com/gorilla/mux v1.8.0 // indirect
github.com/gorilla/sessions v1.2.1
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
github.com/hashicorp/go-retryablehttp v0.7.0 // indirect
github.com/hashicorp/go-version v1.3.1
github.com/hashicorp/go-version v1.4.0
github.com/hashicorp/golang-lru v0.5.4
github.com/huandu/xstrings v1.3.2
github.com/jaytaylor/html2text v0.0.0-20200412013138-3577fbdbcff7
github.com/json-iterator/go v1.1.11
github.com/json-iterator/go v1.1.12
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51
github.com/kevinburke/ssh_config v1.1.0 // indirect
github.com/keybase/go-crypto v0.0.0-20200123153347-de78d2cb44f4
github.com/klauspost/compress v1.13.1
github.com/klauspost/compress v1.13.6
github.com/klauspost/cpuid/v2 v2.0.9
github.com/klauspost/pgzip v1.2.5 // indirect
github.com/lib/pq v1.10.2
github.com/lunny/dingtalk_webhook v0.0.0-20171025031554-e3534c89ef96
github.com/markbates/goth v1.68.0
github.com/mattn/go-isatty v0.0.13
github.com/mattn/go-runewidth v0.0.13 // indirect
github.com/mattn/go-sqlite3 v1.14.8
github.com/mholt/archiver/v3 v3.5.0
github.com/microcosm-cc/bluemonday v1.0.16
github.com/minio/md5-simd v1.1.2 // indirect
github.com/minio/minio-go/v7 v7.0.12
github.com/minio/sha256-simd v1.0.0 // indirect
github.com/mrjones/oauth v0.0.0-20190623134757-126b35219450 // indirect
github.com/msteinert/pam v0.0.0-20201130170657-e61372126161
github.com/markbates/goth v1.69.0
github.com/mattn/go-isatty v0.0.14
github.com/mattn/go-sqlite3 v1.14.12
github.com/mholt/archiver/v3 v3.5.1
github.com/microcosm-cc/bluemonday v1.0.18
github.com/minio/minio-go/v7 v7.0.23
github.com/msteinert/pam v1.0.0
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646
github.com/niklasfasching/go-org v1.6.1
github.com/olekukonko/tablewriter v0.0.5 // indirect
github.com/niklasfasching/go-org v1.6.2
github.com/oliamb/cutter v0.2.2
github.com/olivere/elastic/v7 v7.0.25
github.com/pelletier/go-toml v1.9.0 // indirect
github.com/pierrec/lz4/v4 v4.1.8 // indirect
github.com/olivere/elastic/v7 v7.0.31
github.com/pkg/errors v0.9.1
github.com/pquerna/otp v1.3.0
github.com/prometheus/client_golang v1.11.0
github.com/quasoft/websspi v1.0.0
github.com/rs/xid v1.3.0 // indirect
github.com/russross/blackfriday/v2 v2.1.0 // indirect
github.com/prometheus/client_golang v1.12.1
github.com/quasoft/websspi v1.1.2
github.com/sergi/go-diff v1.2.0
github.com/shurcooL/httpfs v0.0.0-20190707220628-8d4bc4ba7749 // indirect
github.com/shurcooL/vfsgen v0.0.0-20200824052919-0d455de96546
github.com/ssor/bom v0.0.0-20170718123548-6386211fdfcf // indirect
github.com/stretchr/testify v1.7.0
github.com/syndtr/goleveldb v1.0.0
github.com/tstranex/u2f v1.0.0
github.com/ulikunitz/xz v0.5.10 // indirect
github.com/unknwon/com v1.0.1
github.com/unknwon/i18n v0.0.0-20210321134014-0ebbf2df1c44
github.com/unknwon/paginater v0.0.0-20200328080006-042474bd0eae
github.com/unrolled/render v1.4.0
github.com/urfave/cli v1.22.5
github.com/xanzy/go-gitlab v0.50.1
github.com/xanzy/go-gitlab v0.58.0
github.com/yohcop/openid-go v1.0.0
github.com/yuin/goldmark v1.4.0
github.com/yuin/goldmark-highlighting v0.0.0-20210516132338-9216f9c5aa01
github.com/yuin/goldmark-meta v1.0.0
go.etcd.io/bbolt v1.3.6 // indirect
github.com/yuin/goldmark v1.4.8
github.com/yuin/goldmark-highlighting v0.0.0-20220208100518-594be1970594
github.com/yuin/goldmark-meta v1.1.0
go.jolheiser.com/hcaptcha v0.0.4
go.jolheiser.com/pwn v0.0.3
go.uber.org/atomic v1.9.0 // indirect
go.uber.org/multierr v1.7.0 // indirect
go.uber.org/zap v1.19.0 // indirect
golang.org/x/crypto v0.0.0-20211117183948-ae814b36b871
golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd
golang.org/x/oauth2 v0.0.0-20210628180205-a41e5a781914
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e
go.uber.org/multierr v1.8.0 // indirect
go.uber.org/zap v1.21.0 // indirect
golang.org/x/crypto v0.0.0-20220315160706-3147a52a75dd
golang.org/x/net v0.0.0-20220225172249-27dd8689420f
golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b
golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9
golang.org/x/text v0.3.7
golang.org/x/time v0.0.0-20210611083556-38a9dc6acbc6 // indirect
golang.org/x/tools v0.1.0
google.golang.org/protobuf v1.27.1 // indirect
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect
golang.org/x/tools v0.1.9
gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df
gopkg.in/ini.v1 v1.62.0
gopkg.in/ini.v1 v1.66.2
gopkg.in/yaml.v2 v2.4.0
mvdan.cc/xurls/v2 v2.2.0
strk.kbt.io/projects/go/libravatar v0.0.0-20191008002943-06d1c002b251
@@ -139,6 +108,180 @@ require (
xorm.io/xorm v1.2.5
)
require (
github.com/Azure/go-ntlmssp v0.0.0-20211209120228-48547f28849e // indirect
github.com/Microsoft/go-winio v0.5.2 // indirect
github.com/ProtonMail/go-crypto v0.0.0-20220113124808-70ae35bab23f // indirect
github.com/PuerkitoBio/purell v1.1.1 // indirect
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 // indirect
github.com/RoaringBitmap/roaring v0.9.4 // indirect
github.com/acomagu/bufpipe v1.0.3 // indirect
github.com/andybalholm/brotli v1.0.4 // indirect
github.com/andybalholm/cascadia v1.3.1 // indirect
github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be // indirect
github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d // indirect
github.com/aymerick/douceur v0.2.0 // indirect
github.com/beorn7/perks v1.0.1 // indirect
github.com/bgentry/speakeasy v0.1.0 // indirect
github.com/bits-and-blooms/bitset v1.2.1 // indirect
github.com/blevesearch/bleve_index_api v1.0.1 // indirect
github.com/blevesearch/go-porterstemmer v1.0.3 // indirect
github.com/blevesearch/mmap-go v1.0.3 // indirect
github.com/blevesearch/scorch_segment_api/v2 v2.1.0 // indirect
github.com/blevesearch/segment v0.9.0 // indirect
github.com/blevesearch/snowballstem v0.9.0 // indirect
github.com/blevesearch/upsidedown_store_api v1.0.1 // indirect
github.com/blevesearch/vellum v1.0.7 // indirect
github.com/blevesearch/zapx/v11 v11.3.3 // indirect
github.com/blevesearch/zapx/v12 v12.3.3 // indirect
github.com/blevesearch/zapx/v13 v13.3.3 // indirect
github.com/blevesearch/zapx/v14 v14.3.3 // indirect
github.com/blevesearch/zapx/v15 v15.3.3 // indirect
github.com/boombuler/barcode v1.0.1 // indirect
github.com/bradfitz/gomemcache v0.0.0-20190913173617-a41fca850d0b // indirect
github.com/census-instrumentation/opencensus-proto v0.3.0 // indirect
github.com/cespare/xxhash/v2 v2.1.2 // indirect
github.com/cloudflare/cfssl v1.6.1 // indirect
github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4 // indirect
github.com/cncf/xds/go v0.0.0-20211130200136-a8f946100490 // indirect
github.com/coreos/go-semver v0.3.0 // indirect
github.com/coreos/go-systemd/v22 v22.3.2 // indirect
github.com/couchbase/go-couchbase v0.0.0-20210224140812-5740cd35f448 // indirect
github.com/couchbase/gomemcached v0.1.2 // indirect
github.com/couchbase/goutils v0.0.0-20210118111533-e33d3ffb5401 // indirect
github.com/cpuguy83/go-md2man/v2 v2.0.1 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
github.com/dlclark/regexp2 v1.4.0 // indirect
github.com/dsnet/compress v0.0.2-0.20210315054119-f66993602bf5 // indirect
github.com/envoyproxy/go-control-plane v0.10.1 // indirect
github.com/envoyproxy/protoc-gen-validate v0.6.2 // indirect
github.com/felixge/httpsnoop v1.0.2 // indirect
github.com/form3tech-oss/jwt-go v3.2.3+incompatible // indirect
github.com/fsnotify/fsnotify v1.5.1 // indirect
github.com/fullstorydev/grpcurl v1.8.1 // indirect
github.com/fxamacker/cbor/v2 v2.4.0 // indirect
github.com/go-asn1-ber/asn1-ber v1.5.3 // indirect
github.com/go-enry/go-oniguruma v1.2.1 // indirect
github.com/go-git/gcfg v1.5.0 // indirect
github.com/go-openapi/analysis v0.21.2 // indirect
github.com/go-openapi/errors v0.20.2 // indirect
github.com/go-openapi/inflect v0.19.0 // indirect
github.com/go-openapi/jsonpointer v0.19.5 // indirect
github.com/go-openapi/jsonreference v0.19.6 // indirect
github.com/go-openapi/loads v0.21.0 // indirect
github.com/go-openapi/runtime v0.21.1 // indirect
github.com/go-openapi/spec v0.20.4 // indirect
github.com/go-openapi/strfmt v0.21.1 // indirect
github.com/go-openapi/swag v0.19.15 // indirect
github.com/go-openapi/validate v0.20.3 // indirect
github.com/go-stack/stack v1.8.1 // indirect
github.com/goccy/go-json v0.9.5 // indirect
github.com/gogo/protobuf v1.3.2 // indirect
github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9 // indirect
github.com/golang-sql/sqlexp v0.0.0-20170517235910-f1bb20e5a188 // indirect
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
github.com/golang/mock v1.6.0 // indirect
github.com/golang/protobuf v1.5.2 // indirect
github.com/golang/snappy v0.0.4 // indirect
github.com/google/btree v1.0.1 // indirect
github.com/google/certificate-transparency-go v1.1.2-0.20210511102531-373a877eec92 // indirect
github.com/google/go-querystring v1.1.0 // indirect
github.com/gorilla/css v1.0.0 // indirect
github.com/gorilla/handlers v1.5.1 // indirect
github.com/gorilla/mux v1.8.0 // indirect
github.com/gorilla/securecookie v1.1.1 // indirect
github.com/gorilla/websocket v1.4.2 // indirect
github.com/grpc-ecosystem/go-grpc-middleware v1.3.0 // indirect
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 // indirect
github.com/grpc-ecosystem/grpc-gateway v1.16.0 // indirect
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
github.com/hashicorp/go-retryablehttp v0.7.0 // indirect
github.com/hashicorp/hcl v1.0.0 // indirect
github.com/imdario/mergo v0.3.12 // indirect
github.com/inconshreveable/mousetrap v1.0.0 // indirect
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect
github.com/jessevdk/go-flags v1.5.0 // indirect
github.com/jhump/protoreflect v1.8.2 // indirect
github.com/jonboulle/clockwork v0.2.2 // indirect
github.com/josharian/intern v1.0.0 // indirect
github.com/kevinburke/ssh_config v1.1.0 // indirect
github.com/kr/pretty v0.3.0 // indirect
github.com/kr/text v0.2.0 // indirect
github.com/libdns/libdns v0.2.1 // indirect
github.com/magiconair/properties v1.8.5 // indirect
github.com/mailru/easyjson v0.7.7 // indirect
github.com/markbates/going v1.0.0 // indirect
github.com/mattn/go-runewidth v0.0.13 // indirect
github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect
github.com/mholt/acmez v1.0.2 // indirect
github.com/miekg/dns v1.1.46 // indirect
github.com/minio/md5-simd v1.1.2 // indirect
github.com/minio/sha256-simd v1.0.0 // indirect
github.com/mitchellh/go-homedir v1.1.0 // indirect
github.com/mitchellh/mapstructure v1.4.3 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/mrjones/oauth v0.0.0-20190623134757-126b35219450 // indirect
github.com/mschoch/smat v0.2.0 // indirect
github.com/nwaples/rardecode v1.1.3 // indirect
github.com/oklog/ulid v1.3.1 // indirect
github.com/olekukonko/tablewriter v0.0.5 // indirect
github.com/pelletier/go-toml v1.9.4 // indirect
github.com/pierrec/lz4/v4 v4.1.14 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/prometheus/client_model v0.2.0 // indirect
github.com/prometheus/common v0.32.1 // indirect
github.com/prometheus/procfs v0.7.3 // indirect
github.com/rivo/uniseg v0.2.0 // indirect
github.com/rogpeppe/go-internal v1.8.1 // indirect
github.com/rs/xid v1.3.0 // indirect
github.com/russross/blackfriday/v2 v2.1.0 // indirect
github.com/shurcooL/httpfs v0.0.0-20190707220628-8d4bc4ba7749 // indirect
github.com/sirupsen/logrus v1.8.1 // indirect
github.com/soheilhy/cmux v0.1.5 // indirect
github.com/spf13/afero v1.8.0 // indirect
github.com/spf13/cast v1.4.1 // indirect
github.com/spf13/cobra v1.3.0 // indirect
github.com/spf13/jwalterweatherman v1.1.0 // indirect
github.com/spf13/pflag v1.0.5 // indirect
github.com/spf13/viper v1.10.1 // indirect
github.com/ssor/bom v0.0.0-20170718123548-6386211fdfcf // indirect
github.com/steveyen/gtreap v0.1.0 // indirect
github.com/subosito/gotenv v1.2.0 // indirect
github.com/tmc/grpc-websocket-proxy v0.0.0-20201229170055-e5319fda7802 // indirect
github.com/toqueteos/webbrowser v1.2.0 // indirect
github.com/ulikunitz/xz v0.5.10 // indirect
github.com/x448/float16 v0.8.4 // indirect
github.com/xanzy/ssh-agent v0.3.1 // indirect
github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8 // indirect
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2 // indirect
go.etcd.io/bbolt v1.3.6 // indirect
go.etcd.io/etcd/api/v3 v3.5.1 // indirect
go.etcd.io/etcd/client/pkg/v3 v3.5.1 // indirect
go.etcd.io/etcd/client/v2 v2.305.1 // indirect
go.etcd.io/etcd/client/v3 v3.5.0-alpha.0 // indirect
go.etcd.io/etcd/etcdctl/v3 v3.5.0-alpha.0 // indirect
go.etcd.io/etcd/pkg/v3 v3.5.0-alpha.0 // indirect
go.etcd.io/etcd/raft/v3 v3.5.0-alpha.0 // indirect
go.etcd.io/etcd/server/v3 v3.5.0-alpha.0 // indirect
go.etcd.io/etcd/tests/v3 v3.5.0-alpha.0 // indirect
go.etcd.io/etcd/v3 v3.5.0-alpha.0 // indirect
go.mongodb.org/mongo-driver v1.8.2 // indirect
golang.org/x/mod v0.5.1 // indirect
golang.org/x/time v0.0.0-20220224211638-0e9765cccd65 // indirect
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect
google.golang.org/appengine v1.6.7 // indirect
google.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa // indirect
google.golang.org/grpc v1.43.0 // indirect
google.golang.org/protobuf v1.27.1 // indirect
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect
gopkg.in/cheggaaa/pb.v1 v1.0.28 // indirect
gopkg.in/warnings.v0 v0.1.2 // indirect
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect
sigs.k8s.io/yaml v1.2.0 // indirect
)
replace github.com/hashicorp/go-version => github.com/6543/go-version v1.3.1
replace github.com/markbates/goth v1.68.0 => github.com/zeripath/goth v1.68.1-0.20220109111530-754359885dce

864
go.sum
View File

File diff suppressed because it is too large Load Diff

View File

@@ -47,7 +47,7 @@ func TestAPIPrivateServ(t *testing.T) {
results, err := private.ServCommand(ctx, 1, "user2", "repo1", perm.AccessModeWrite, "git-upload-pack", "")
assert.NoError(t, err)
assert.False(t, results.IsWiki)
assert.False(t, results.IsDeployKey)
assert.Zero(t, results.DeployKeyID)
assert.Equal(t, int64(1), results.KeyID)
assert.Equal(t, "user2@localhost", results.KeyName)
assert.Equal(t, "user2", results.UserName)
@@ -70,7 +70,7 @@ func TestAPIPrivateServ(t *testing.T) {
results, err = private.ServCommand(ctx, 1, "user15", "big_test_public_1", perm.AccessModeRead, "git-upload-pack", "")
assert.NoError(t, err)
assert.False(t, results.IsWiki)
assert.False(t, results.IsDeployKey)
assert.Zero(t, results.DeployKeyID)
assert.Equal(t, int64(1), results.KeyID)
assert.Equal(t, "user2@localhost", results.KeyName)
assert.Equal(t, "user2", results.UserName)
@@ -92,7 +92,7 @@ func TestAPIPrivateServ(t *testing.T) {
results, err = private.ServCommand(ctx, deployKey.KeyID, "user15", "big_test_private_1", perm.AccessModeRead, "git-upload-pack", "")
assert.NoError(t, err)
assert.False(t, results.IsWiki)
assert.True(t, results.IsDeployKey)
assert.NotZero(t, results.DeployKeyID)
assert.Equal(t, deployKey.KeyID, results.KeyID)
assert.Equal(t, "test-deploy", results.KeyName)
assert.Equal(t, "user15", results.UserName)
@@ -129,7 +129,7 @@ func TestAPIPrivateServ(t *testing.T) {
results, err = private.ServCommand(ctx, deployKey.KeyID, "user15", "big_test_private_2", perm.AccessModeRead, "git-upload-pack", "")
assert.NoError(t, err)
assert.False(t, results.IsWiki)
assert.True(t, results.IsDeployKey)
assert.NotZero(t, results.DeployKeyID)
assert.Equal(t, deployKey.KeyID, results.KeyID)
assert.Equal(t, "test-deploy", results.KeyName)
assert.Equal(t, "user15", results.UserName)
@@ -142,7 +142,7 @@ func TestAPIPrivateServ(t *testing.T) {
results, err = private.ServCommand(ctx, deployKey.KeyID, "user15", "big_test_private_2", perm.AccessModeWrite, "git-upload-pack", "")
assert.NoError(t, err)
assert.False(t, results.IsWiki)
assert.True(t, results.IsDeployKey)
assert.NotZero(t, results.DeployKeyID)
assert.Equal(t, deployKey.KeyID, results.KeyID)
assert.Equal(t, "test-deploy", results.KeyName)
assert.Equal(t, "user15", results.UserName)

View File

@@ -58,7 +58,7 @@ func (key *DeployKey) GetContent() error {
return nil
}
// IsReadOnly checks if the key can only be used for read operations
// IsReadOnly checks if the key can only be used for read operations, used by template
func (key *DeployKey) IsReadOnly() bool {
return key.Mode == perm.AccessModeRead
}
@@ -203,12 +203,6 @@ func UpdateDeployKeyCols(key *DeployKey, cols ...string) error {
return err
}
// UpdateDeployKey updates deploy key information.
func UpdateDeployKey(key *DeployKey) error {
_, err := db.GetEngine(db.DefaultContext).ID(key.ID).AllCols().Update(key)
return err
}
// ListDeployKeysOptions are options for ListDeployKeys
type ListDeployKeysOptions struct {
db.ListOptions

View File

@@ -23,8 +23,8 @@ const (
EnvPusherName = "GITEA_PUSHER_NAME"
EnvPusherEmail = "GITEA_PUSHER_EMAIL"
EnvPusherID = "GITEA_PUSHER_ID"
EnvKeyID = "GITEA_KEY_ID"
EnvIsDeployKey = "GITEA_IS_DEPLOY_KEY"
EnvKeyID = "GITEA_KEY_ID" // public key ID
EnvDeployKeyID = "GITEA_DEPLOY_KEY_ID"
EnvPRID = "GITEA_PR_ID"
EnvIsInternal = "GITEA_INTERNAL_PUSH"
EnvAppURL = "GITEA_ROOT_URL"

View File

@@ -1551,6 +1551,7 @@ const (
FilterModeCreate
FilterModeMention
FilterModeReviewRequested
FilterModeYourRepositories
)
func parseCountResult(results []map[string][]byte) int64 {
@@ -1695,6 +1696,7 @@ type UserIssueStatsOptions struct {
IssueIDs []int64
IsArchived util.OptionalBool
LabelIDs []int64
RepoCond builder.Cond
Org *Organization
Team *Team
}
@@ -1712,6 +1714,9 @@ func GetUserIssueStats(opts UserIssueStatsOptions) (*IssueStats, error) {
if len(opts.IssueIDs) > 0 {
cond = cond.And(builder.In("issue.id", opts.IssueIDs))
}
if opts.RepoCond != nil {
cond = cond.And(opts.RepoCond)
}
if opts.UserID > 0 {
cond = cond.And(issuePullAccessibleRepoCond("issue.repo_id", opts.UserID, opts.Org, opts.Team, opts.IsPull))
@@ -1733,7 +1738,7 @@ func GetUserIssueStats(opts UserIssueStatsOptions) (*IssueStats, error) {
}
switch opts.FilterMode {
case FilterModeAll:
case FilterModeAll, FilterModeYourRepositories:
stats.OpenCount, err = sess(cond).
And("issue.is_closed = ?", false).
Count(new(Issue))

View File

@@ -193,12 +193,13 @@ func LFSAutoAssociate(metas []*LFSMetaObject, user *user_model.User, repoID int6
// admin can associate any LFS object to any repository, and we do not care about errors (eg: duplicated unique key),
// even if error occurs, it won't hurt users and won't make things worse
for i := range metas {
p := lfs.Pointer{Oid: metas[i].Oid, Size: metas[i].Size}
_, err = sess.Insert(&LFSMetaObject{
Pointer: lfs.Pointer{Oid: metas[i].Oid, Size: metas[i].Size},
Pointer: p,
RepositoryID: repoID,
})
if err != nil {
log.Warn("failed to insert LFS meta object into database, err=%v", err)
log.Warn("failed to insert LFS meta object %-v for repo_id: %d into database, err=%v", p, repoID, err)
}
}
}

View File

@@ -174,5 +174,11 @@ func remigrateU2FCredentials(x *xorm.Engine) error {
regs = regs[:0]
}
if x.Dialect().URI().DBType == schemas.POSTGRES {
if _, err := x.Exec("SELECT setval('webauthn_credential_id_seq', COALESCE((SELECT MAX(id)+1 FROM `webauthn_credential`), 1), false)"); err != nil {
return err
}
}
return nil
}

View File

@@ -498,14 +498,15 @@ func (n *Notification) APIURL() string {
type NotificationList []*Notification
// LoadAttributes load Repo Issue User and Comment if not loaded
func (nl NotificationList) LoadAttributes() (err error) {
func (nl NotificationList) LoadAttributes() error {
var err error
for i := 0; i < len(nl); i++ {
err = nl[i].LoadAttributes()
if err != nil && !IsErrCommentNotExist(err) {
return
return err
}
}
return
return nil
}
func (nl NotificationList) getPendingRepoIDs() []int64 {

View File

@@ -19,6 +19,7 @@ import (
user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/util"
"xorm.io/builder"
)
@@ -776,8 +777,45 @@ func DeleteTeam(t *Team) error {
return err
}
if err := t.removeAllRepositories(ctx); err != nil {
return err
// update branch protections
{
protections := make([]*ProtectedBranch, 0, 10)
err := sess.In("repo_id",
builder.Select("id").From("repository").Where(builder.Eq{"owner_id": t.OrgID})).
Find(&protections)
if err != nil {
return fmt.Errorf("findProtectedBranches: %v", err)
}
for _, p := range protections {
var matched1, matched2, matched3 bool
if len(p.WhitelistTeamIDs) != 0 {
p.WhitelistTeamIDs, matched1 = util.RemoveIDFromList(
p.WhitelistTeamIDs, t.ID)
}
if len(p.ApprovalsWhitelistTeamIDs) != 0 {
p.ApprovalsWhitelistTeamIDs, matched2 = util.RemoveIDFromList(
p.ApprovalsWhitelistTeamIDs, t.ID)
}
if len(p.MergeWhitelistTeamIDs) != 0 {
p.MergeWhitelistTeamIDs, matched3 = util.RemoveIDFromList(
p.MergeWhitelistTeamIDs, t.ID)
}
if matched1 || matched2 || matched3 {
if _, err = sess.ID(p.ID).Cols(
"whitelist_team_i_ds",
"merge_whitelist_team_i_ds",
"approvals_whitelist_team_i_ds",
).Update(p); err != nil {
return fmt.Errorf("updateProtectedBranches: %v", err)
}
}
}
}
if !t.IncludesAllRepositories {
if err := t.removeAllRepositories(ctx); err != nil {
return err
}
}
// Delete team-user.

View File

@@ -153,7 +153,7 @@ func getRepoAssignees(ctx context.Context, repo *repo_model.Repository) (_ []*us
userIDs := make([]int64, 0, 10)
if err = e.Table("access").
Where("repo_id = ? AND mode >= ?", repo.ID, perm.AccessModeWrite).
Select("id").
Select("user_id").
Find(&userIDs); err != nil {
return nil, err
}

View File

@@ -167,3 +167,21 @@ func TestLinkedRepository(t *testing.T) {
})
}
}
func TestRepoAssignees(t *testing.T) {
assert.NoError(t, unittest.PrepareTestDatabase())
repo2 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 2}).(*repo_model.Repository)
users, err := GetRepoAssignees(repo2)
assert.NoError(t, err)
assert.Len(t, users, 1)
assert.Equal(t, users[0].ID, int64(2))
repo21 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 21}).(*repo_model.Repository)
users, err = GetRepoAssignees(repo21)
assert.NoError(t, err)
assert.Len(t, users, 3)
assert.Equal(t, users[0].ID, int64(15))
assert.Equal(t, users[1].ID, int64(18))
assert.Equal(t, users[2].ID, int64(16))
}

View File

@@ -18,6 +18,7 @@ import (
user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/structs"
"code.gitea.io/gitea/modules/util"
"xorm.io/builder"
)
@@ -130,6 +131,50 @@ func DeleteUser(ctx context.Context, u *user_model.User) (err error) {
}
}
// ***** START: Branch Protections *****
{
const batchSize = 50
for start := 0; ; start += batchSize {
protections := make([]*ProtectedBranch, 0, batchSize)
// @perf: We can't filter on DB side by u.ID, as those IDs are serialized as JSON strings.
// We could filter down with `WHERE repo_id IN (reposWithPushPermission(u))`,
// though that query will be quite complex and tricky to maintain (compare `getRepoAssignees()`).
// Also, as we didn't update branch protections when removing entries from `access` table,
// it's safer to iterate all protected branches.
if err = e.Limit(batchSize, start).Find(&protections); err != nil {
return fmt.Errorf("findProtectedBranches: %v", err)
}
if len(protections) == 0 {
break
}
for _, p := range protections {
var matched1, matched2, matched3 bool
if len(p.WhitelistUserIDs) != 0 {
p.WhitelistUserIDs, matched1 = util.RemoveIDFromList(
p.WhitelistUserIDs, u.ID)
}
if len(p.ApprovalsWhitelistUserIDs) != 0 {
p.ApprovalsWhitelistUserIDs, matched2 = util.RemoveIDFromList(
p.ApprovalsWhitelistUserIDs, u.ID)
}
if len(p.MergeWhitelistUserIDs) != 0 {
p.MergeWhitelistUserIDs, matched3 = util.RemoveIDFromList(
p.MergeWhitelistUserIDs, u.ID)
}
if matched1 || matched2 || matched3 {
if _, err = e.ID(p.ID).Cols(
"whitelist_user_i_ds",
"merge_whitelist_user_i_ds",
"approvals_whitelist_user_i_ds",
).Update(p); err != nil {
return fmt.Errorf("updateProtectedBranches: %v", err)
}
}
}
}
}
// ***** END: Branch Protections *****
// ***** START: PublicKey *****
if _, err = e.Delete(&asymkey_model.PublicKey{OwnerID: u.ID}); err != nil {
return fmt.Errorf("deletePublicKeys: %v", err)

View File

@@ -10,6 +10,7 @@ import (
"errors"
"fmt"
"net/mail"
"regexp"
"strings"
"code.gitea.io/gitea/models/db"
@@ -21,10 +22,23 @@ import (
"xorm.io/builder"
)
var (
// ErrEmailNotActivated e-mail address has not been activated error
ErrEmailNotActivated = errors.New("E-mail address has not been activated")
)
// ErrEmailNotActivated e-mail address has not been activated error
var ErrEmailNotActivated = errors.New("e-mail address has not been activated")
// ErrEmailCharIsNotSupported e-mail address contains unsupported character
type ErrEmailCharIsNotSupported struct {
Email string
}
// IsErrEmailCharIsNotSupported checks if an error is an ErrEmailCharIsNotSupported
func IsErrEmailCharIsNotSupported(err error) bool {
_, ok := err.(ErrEmailCharIsNotSupported)
return ok
}
func (err ErrEmailCharIsNotSupported) Error() string {
return fmt.Sprintf("e-mail address contains unsupported character [email: %s]", err.Email)
}
// ErrEmailInvalid represents an error where the email address does not comply with RFC 5322
type ErrEmailInvalid struct {
@@ -108,12 +122,24 @@ func (email *EmailAddress) BeforeInsert() {
}
}
var emailRegexp = regexp.MustCompile("^[a-zA-Z0-9.!#$%&'*+-/=?^_`{|}~]*@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$")
// ValidateEmail check if email is a allowed address
func ValidateEmail(email string) error {
if len(email) == 0 {
return nil
}
if !emailRegexp.MatchString(email) {
return ErrEmailCharIsNotSupported{email}
}
if !(email[0] >= 'a' && email[0] <= 'z') &&
!(email[0] >= 'A' && email[0] <= 'Z') &&
!(email[0] >= '0' && email[0] <= '9') {
return ErrEmailInvalid{email}
}
if _, err := mail.ParseAddress(email); err != nil {
return ErrEmailInvalid{email}
}

View File

@@ -252,3 +252,58 @@ func TestListEmails(t *testing.T) {
assert.Len(t, emails, 5)
assert.Greater(t, count, int64(len(emails)))
}
func TestEmailAddressValidate(t *testing.T) {
kases := map[string]error{
"abc@gmail.com": nil,
"132@hotmail.com": nil,
"1-3-2@test.org": nil,
"1.3.2@test.org": nil,
"a_123@test.org.cn": nil,
`first.last@iana.org`: nil,
`first!last@iana.org`: nil,
`first#last@iana.org`: nil,
`first$last@iana.org`: nil,
`first%last@iana.org`: nil,
`first&last@iana.org`: nil,
`first'last@iana.org`: nil,
`first*last@iana.org`: nil,
`first+last@iana.org`: nil,
`first/last@iana.org`: nil,
`first=last@iana.org`: nil,
`first?last@iana.org`: nil,
`first^last@iana.org`: nil,
"first`last@iana.org": nil,
`first{last@iana.org`: nil,
`first|last@iana.org`: nil,
`first}last@iana.org`: nil,
`first~last@iana.org`: nil,
`first;last@iana.org`: ErrEmailCharIsNotSupported{`first;last@iana.org`},
".233@qq.com": ErrEmailInvalid{".233@qq.com"},
"!233@qq.com": ErrEmailInvalid{"!233@qq.com"},
"#233@qq.com": ErrEmailInvalid{"#233@qq.com"},
"$233@qq.com": ErrEmailInvalid{"$233@qq.com"},
"%233@qq.com": ErrEmailInvalid{"%233@qq.com"},
"&233@qq.com": ErrEmailInvalid{"&233@qq.com"},
"'233@qq.com": ErrEmailInvalid{"'233@qq.com"},
"*233@qq.com": ErrEmailInvalid{"*233@qq.com"},
"+233@qq.com": ErrEmailInvalid{"+233@qq.com"},
"/233@qq.com": ErrEmailInvalid{"/233@qq.com"},
"=233@qq.com": ErrEmailInvalid{"=233@qq.com"},
"?233@qq.com": ErrEmailInvalid{"?233@qq.com"},
"^233@qq.com": ErrEmailInvalid{"^233@qq.com"},
"`233@qq.com": ErrEmailInvalid{"`233@qq.com"},
"{233@qq.com": ErrEmailInvalid{"{233@qq.com"},
"|233@qq.com": ErrEmailInvalid{"|233@qq.com"},
"}233@qq.com": ErrEmailInvalid{"}233@qq.com"},
"~233@qq.com": ErrEmailInvalid{"~233@qq.com"},
";233@qq.com": ErrEmailCharIsNotSupported{";233@qq.com"},
"Foo <foo@bar.com>": ErrEmailCharIsNotSupported{"Foo <foo@bar.com>"},
string([]byte{0xE2, 0x84, 0xAA}): ErrEmailCharIsNotSupported{string([]byte{0xE2, 0x84, 0xAA})},
}
for kase, err := range kases {
t.Run(kase, func(t *testing.T) {
assert.EqualValues(t, err, ValidateEmail(kase))
})
}
}

View File

@@ -644,6 +644,15 @@ func CreateUser(u *User, overwriteDefault ...*CreateUserOverwriteOptions) (err e
u.Visibility = overwriteDefault[0].Visibility
}
// validate data
if err := validateUser(u); err != nil {
return err
}
if err := ValidateEmail(u.Email); err != nil {
return err
}
ctx, committer, err := db.TxContext()
if err != nil {
return err
@@ -652,11 +661,6 @@ func CreateUser(u *User, overwriteDefault ...*CreateUserOverwriteOptions) (err e
sess := db.GetEngine(ctx)
// validate data
if err := validateUser(u); err != nil {
return err
}
isExist, err := isUserExist(sess, 0, u.Name)
if err != nil {
return err

View File

@@ -232,7 +232,7 @@ func TestCreateUserInvalidEmail(t *testing.T) {
err := CreateUser(user)
assert.Error(t, err)
assert.True(t, IsErrEmailInvalid(err))
assert.True(t, IsErrEmailCharIsNotSupported(err))
}
func TestCreateUserEmailAlreadyUsed(t *testing.T) {

View File

@@ -35,6 +35,10 @@ func Auth(serviceName, userName, passwd string) (string, error) {
if err = t.Authenticate(0); err != nil {
return "", err
}
if err = t.AcctMgmt(0); err != nil {
return "", err
}
// PAM login names might suffer transformations in the PAM stack.
// We should take whatever the PAM stack returns for it.

View File

@@ -181,6 +181,12 @@ func (ctx *Context) RedirectToFirst(location ...string) {
continue
}
// Unfortunately browsers consider a redirect Location with preceding "//" and "/\" as meaning redirect to "http(s)://REST_OF_PATH"
// Therefore we should ignore these redirect locations to prevent open redirects
if len(loc) > 1 && loc[0] == '/' && (loc[1] == '/' || loc[1] == '\\') {
continue
}
u, err := url.Parse(loc)
if err != nil || ((u.Scheme != "" || u.Host != "") && !strings.HasPrefix(strings.ToLower(loc), strings.ToLower(setting.AppURL))) {
continue
@@ -266,7 +272,7 @@ func (ctx *Context) ServerError(logMsg string, logErr error) {
func (ctx *Context) serverErrorInternal(logMsg string, logErr error) {
if logErr != nil {
log.ErrorWithSkip(2, "%s: %v", logMsg, logErr)
if errors.Is(logErr, &net.OpError{}) {
if _, ok := logErr.(*net.OpError); ok || errors.Is(logErr, &net.OpError{}) {
// This is an error within the underlying connection
// and further rendering will not work so just return
return

View File

@@ -440,6 +440,26 @@ func RepoAssignment(ctx *Context) (cancel context.CancelFunc) {
ctx.Repo.Owner = owner
ctx.Data["Username"] = ctx.Repo.Owner.Name
// redirect link to wiki
if strings.HasSuffix(repoName, ".wiki") {
// ctx.Req.URL.Path does not have the preceding appSubURL - any redirect must have this added
// Now we happen to know that all of our paths are: /:username/:reponame/whatever_else
originalRepoName := ctx.Params(":reponame")
redirectRepoName := strings.TrimSuffix(repoName, ".wiki")
redirectRepoName += originalRepoName[len(redirectRepoName)+5:]
redirectPath := strings.Replace(
ctx.Req.URL.EscapedPath(),
url.PathEscape(userName)+"/"+url.PathEscape(originalRepoName),
url.PathEscape(userName)+"/"+url.PathEscape(redirectRepoName)+"/wiki",
1,
)
if ctx.Req.URL.RawQuery != "" {
redirectPath += "?" + ctx.Req.URL.RawQuery
}
ctx.Redirect(path.Join(setting.AppSubURL, redirectPath))
return
}
// Get repository.
repo, err := repo_model.GetRepositoryByName(owner.ID, repoName)
if err != nil {

View File

@@ -97,15 +97,16 @@ func (repo *Repository) IsEmpty() (bool, error) {
// CloneRepoOptions options when clone a repository
type CloneRepoOptions struct {
Timeout time.Duration
Mirror bool
Bare bool
Quiet bool
Branch string
Shared bool
NoCheckout bool
Depth int
Filter string
Timeout time.Duration
Mirror bool
Bare bool
Quiet bool
Branch string
Shared bool
NoCheckout bool
Depth int
Filter string
SkipTLSVerify bool
}
// Clone clones original repository to target path.
@@ -128,6 +129,9 @@ func CloneWithArgs(ctx context.Context, from, to string, args []string, opts Clo
}
cmd := NewCommandContextNoGlobals(ctx, args...).AddArguments("clone")
if opts.SkipTLSVerify {
cmd.AddArguments("-c", "http.sslVerify=false")
}
if opts.Mirror {
cmd.AddArguments("--mirror")
}

View File

@@ -191,7 +191,9 @@ func (c *CheckAttributeReader) Run() error {
}
return nil
})
if err != nil && c.ctx.Err() != nil && err.Error() != "signal: killed" {
if err != nil && // If there is an error we need to return but:
c.ctx.Err() != err && // 1. Ignore the context error if the context is cancelled or exceeds the deadline (RunWithContext could return c.ctx.Err() which is Canceled or DeadlineExceeded)
err.Error() != "signal: killed" { // 2. We should not pass up errors due to the program being killed
return fmt.Errorf("failed to run attr-check. Error: %w\nStderr: %s", err, stdErr.String())
}
return nil

View File

@@ -40,20 +40,19 @@ steps:
- go test -v -race -coverprofile=coverage.txt -covermode=atomic
`,
want: []string{
`<span class="nt">kind</span><span class="p">:</span><span class="w"> </span><span class="l">pipeline</span>`,
`<span class="w"></span><span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l">default</span>`,
`<span class="w">
</span>`,
`<span class="w"></span><span class="nt">steps</span><span class="p">:</span>`,
`<span class="w"></span>- <span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l">test</span>`,
`<span class="w"> </span><span class="nt">image</span><span class="p">:</span><span class="w"> </span><span class="l">golang:1.13</span>`,
`<span class="w"> </span><span class="nt">environment</span><span class="p">:</span>`,
`<span class="w"></span><span class="w"> </span><span class="nt">GOPROXY</span><span class="p">:</span><span class="w"> </span><span class="l">https://goproxy.cn</span>`,
`<span class="w"> </span><span class="nt">commands</span><span class="p">:</span>`,
`<span class="w"></span><span class="w"> </span>- <span class="l">go get -u</span>`,
`<span class="w"> </span>- <span class="l">go build -v</span>`,
`<span class="w"> </span>- <span class="l">go test -v -race -coverprofile=coverage.txt -covermode=atomic</span><span class="w">
</span>`,
`<span class="line"><span class="cl"><span class="nt">kind</span><span class="p">:</span><span class="w"> </span><span class="l">pipeline</span>`,
`</span></span><span class="line"><span class="cl"><span class="w"></span><span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l">default</span>`,
`</span></span><span class="line"><span class="cl">`,
`</span></span><span class="line"><span class="cl"><span class="w"></span><span class="nt">steps</span><span class="p">:</span>`,
`</span></span><span class="line"><span class="cl"><span class="w"></span>- <span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l">test</span>`,
`</span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nt">image</span><span class="p">:</span><span class="w"> </span><span class="l">golang:1.13</span>`,
`</span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nt">environment</span><span class="p">:</span>`,
`</span></span><span class="line"><span class="cl"><span class="w"></span><span class="w"> </span><span class="nt">GOPROXY</span><span class="p">:</span><span class="w"> </span><span class="l">https://goproxy.cn</span>`,
`</span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nt">commands</span><span class="p">:</span>`,
`</span></span><span class="line"><span class="cl"><span class="w"></span><span class="w"> </span>- <span class="l">go get -u</span>`,
`</span></span><span class="line"><span class="cl"><span class="w"> </span>- <span class="l">go build -v</span>`,
`</span></span><span class="line"><span class="cl"><span class="w"> </span>- <span class="l">go test -v -race -coverprofile=coverage.txt -covermode=atomic</span><span class="w">
</span></span></span>`,
`<span class="w">
</span>`,
},
@@ -76,20 +75,19 @@ steps:
- go test -v -race -coverprofile=coverage.txt -covermode=atomic
`,
want: []string{
`<span class="nt">kind</span><span class="p">:</span><span class="w"> </span><span class="l">pipeline</span>`,
`<span class="w"></span><span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l">default </span>`,
`<span class="w">
</span>`,
`<span class="w"></span><span class="nt">steps</span><span class="p">:</span>`,
`<span class="w"></span>- <span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l">test</span>`,
`<span class="w"> </span><span class="nt">image</span><span class="p">:</span><span class="w"> </span><span class="l">golang:1.13</span>`,
`<span class="w"> </span><span class="nt">environment</span><span class="p">:</span>`,
`<span class="w"></span><span class="w"> </span><span class="nt">GOPROXY</span><span class="p">:</span><span class="w"> </span><span class="l">https://goproxy.cn</span>`,
`<span class="w"> </span><span class="nt">commands</span><span class="p">:</span>`,
`<span class="w"></span><span class="w"> </span>- <span class="l">go get -u</span>`,
`<span class="w"> </span>- <span class="l">go build -v</span>`,
`<span class="w"> </span>- <span class="l">go test -v -race -coverprofile=coverage.txt -covermode=atomic</span>`,
`<span class="w"> </span>`,
`<span class="line"><span class="cl"><span class="nt">kind</span><span class="p">:</span><span class="w"> </span><span class="l">pipeline</span>`,
`</span></span><span class="line"><span class="cl"><span class="w"></span><span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l">default </span>`,
`</span></span><span class="line"><span class="cl">`,
`</span></span><span class="line"><span class="cl"><span class="w"></span><span class="nt">steps</span><span class="p">:</span>`,
`</span></span><span class="line"><span class="cl"><span class="w"></span>- <span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l">test</span>`,
`</span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nt">image</span><span class="p">:</span><span class="w"> </span><span class="l">golang:1.13</span>`,
`</span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nt">environment</span><span class="p">:</span>`,
`</span></span><span class="line"><span class="cl"><span class="w"></span><span class="w"> </span><span class="nt">GOPROXY</span><span class="p">:</span><span class="w"> </span><span class="l">https://goproxy.cn</span>`,
`</span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nt">commands</span><span class="p">:</span>`,
`</span></span><span class="line"><span class="cl"><span class="w"></span><span class="w"> </span>- <span class="l">go get -u</span>`,
`</span></span><span class="line"><span class="cl"><span class="w"> </span>- <span class="l">go build -v</span>`,
`</span></span><span class="line"><span class="cl"><span class="w"> </span>- <span class="l">go test -v -race -coverprofile=coverage.txt -covermode=atomic</span>`,
`</span></span><span class="line"><span class="cl"><span class="w"> </span></span></span>`,
},
},
}

View File

@@ -8,8 +8,6 @@ import (
"net"
"path/filepath"
"strings"
"code.gitea.io/gitea/modules/util"
)
// HostMatchList is used to check if a host or IP is in a list.
@@ -104,11 +102,11 @@ func (hl *HostMatchList) checkIP(ip net.IP) bool {
for _, builtin := range hl.builtins {
switch builtin {
case MatchBuiltinExternal:
if ip.IsGlobalUnicast() && !util.IsIPPrivate(ip) {
if ip.IsGlobalUnicast() && !ip.IsPrivate() {
return true
}
case MatchBuiltinPrivate:
if util.IsIPPrivate(ip) {
if ip.IsPrivate() {
return true
}
case MatchBuiltinLoopback:

View File

@@ -14,6 +14,8 @@ import (
"regexp"
"strconv"
"strings"
"code.gitea.io/gitea/modules/log"
)
const (
@@ -111,6 +113,17 @@ func (p Pointer) RelativePath() string {
return path.Join(p.Oid[0:2], p.Oid[2:4], p.Oid[4:])
}
// ColorFormat provides a basic color format for a Team
func (p Pointer) ColorFormat(s fmt.State) {
if p.Oid == "" && p.Size == 0 {
log.ColorFprintf(s, "<empty>")
return
}
log.ColorFprintf(s, "%s:%d",
log.NewColoredIDValue(p.Oid),
p.Size)
}
// GeneratePointer generates a pointer for arbitrary content
func GeneratePointer(content io.Reader) (Pointer, error) {
h := sha256.New()

View File

@@ -205,7 +205,7 @@ func (b *footnoteBlockParser) Open(parent ast.Node, reader text.Reader, pc parse
}
open := pos + 1
closes := 0
closure := util.FindClosure(line[pos+1:], '[', ']', false, false)
closure := util.FindClosure(line[pos+1:], '[', ']', false, false) //nolint
closes = pos + 1 + closure
next := closes + 1
if closure > -1 {
@@ -296,7 +296,7 @@ func (s *footnoteParser) Parse(parent ast.Node, block text.Reader, pc parser.Con
return nil
}
open := pos
closure := util.FindClosure(line[pos:], '[', ']', false, false)
closure := util.FindClosure(line[pos:], '[', ']', false, false) //nolint
if closure < 0 {
return nil
}

View File

@@ -77,9 +77,9 @@ func HelloWorld() {
}
#+end_src
`, `<div class="src src-go">
<pre><code class="chroma language-go"><span class="c1">// HelloWorld prints &#34;Hello World&#34;
</span><span class="c1"></span><span class="kd">func</span> <span class="nf">HelloWorld</span><span class="p">()</span> <span class="p">{</span>
<span class="nx">fmt</span><span class="p">.</span><span class="nf">Println</span><span class="p">(</span><span class="s">&#34;Hello World&#34;</span><span class="p">)</span>
<span class="p">}</span></code></pre>
<pre><code class="chroma language-go"><span class="line"><span class="cl"><span class="c1">// HelloWorld prints &#34;Hello World&#34;
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="kd">func</span> <span class="nf">HelloWorld</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nx">fmt</span><span class="p">.</span><span class="nf">Println</span><span class="p">(</span><span class="s">&#34;Hello World&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span></span></span></code></pre>
</div>`)
}

View File

@@ -56,7 +56,7 @@ type HookOptions struct {
GitQuarantinePath string
GitPushOptions GitPushOptions
PullRequestID int64
IsDeployKey bool
DeployKeyID int64 // if the pusher is a DeployKey, then UserID is the repo's org user.
IsWiki bool
}

View File

@@ -46,9 +46,9 @@ func ServNoCommand(ctx context.Context, keyID int64) (*asymkey_model.PublicKey,
// ServCommandResults are the results of a call to the private route serv
type ServCommandResults struct {
IsWiki bool
IsDeployKey bool
KeyID int64
KeyName string
DeployKeyID int64
KeyID int64 // public key
KeyName string // this field is ambiguous, it can be the name of DeployKey, or the name of the PublicKey
UserName string
UserEmail string
UserID int64

View File

@@ -43,7 +43,7 @@ var defaultTransformers = []transformer{
{Name: "PASCAL", Transform: xstrings.ToCamelCase},
{Name: "LOWER", Transform: strings.ToLower},
{Name: "UPPER", Transform: strings.ToUpper},
{Name: "TITLE", Transform: strings.Title},
{Name: "TITLE", Transform: strings.Title}, // nolint
}
func generateExpansion(src string, templateRepo, generateRepo *repo_model.Repository) string {
@@ -62,7 +62,7 @@ func generateExpansion(src string, templateRepo, generateRepo *repo_model.Reposi
{Name: "TEMPLATE_SSH_URL", Value: templateRepo.CloneLink().SSH, Transformers: nil},
}
var expansionMap = make(map[string]string)
expansionMap := make(map[string]string)
for _, e := range expansions {
expansionMap[e.Name] = e.Value
for _, tr := range e.Transformers {
@@ -159,7 +159,7 @@ func generateRepoCommit(repo, templateRepo, generateRepo *repo_model.Repository,
if err := os.WriteFile(path,
[]byte(generateExpansion(string(content), templateRepo, generateRepo)),
0644); err != nil {
0o644); err != nil {
return err
}
break

View File

@@ -72,9 +72,10 @@ func MigrateRepositoryGitData(ctx context.Context, u *user_model.User,
}
if err = git.CloneWithContext(ctx, opts.CloneAddr, repoPath, git.CloneRepoOptions{
Mirror: true,
Quiet: true,
Timeout: migrateTimeout,
Mirror: true,
Quiet: true,
Timeout: migrateTimeout,
SkipTLSVerify: setting.Migrations.SkipTLSVerify,
}); err != nil {
return repo, fmt.Errorf("Clone: %v", err)
}
@@ -88,10 +89,11 @@ func MigrateRepositoryGitData(ctx context.Context, u *user_model.User,
}
if err = git.CloneWithContext(ctx, wikiRemotePath, wikiPath, git.CloneRepoOptions{
Mirror: true,
Quiet: true,
Timeout: migrateTimeout,
Branch: "master",
Mirror: true,
Quiet: true,
Timeout: migrateTimeout,
Branch: "master",
SkipTLSVerify: setting.Migrations.SkipTLSVerify,
}); err != nil {
log.Warn("Clone wiki: %v", err)
if err := util.RemoveAll(wikiPath); err != nil {
@@ -254,7 +256,7 @@ func SyncReleasesWithTags(repo *repo_model.Repository, gitRepo *git.Repository)
opts.Page = page
rels, err := models.GetReleasesByRepoID(repo.ID, opts)
if err != nil {
return fmt.Errorf("GetReleasesByRepoID: %v", err)
return fmt.Errorf("unable to GetReleasesByRepoID in Repo[%d:%s/%s]: %w", repo.ID, repo.OwnerName, repo.Name, err)
}
if len(rels) == 0 {
break
@@ -265,11 +267,11 @@ func SyncReleasesWithTags(repo *repo_model.Repository, gitRepo *git.Repository)
}
commitID, err := gitRepo.GetTagCommitID(rel.TagName)
if err != nil && !git.IsErrNotExist(err) {
return fmt.Errorf("GetTagCommitID: %s: %v", rel.TagName, err)
return fmt.Errorf("unable to GetTagCommitID for %q in Repo[%d:%s/%s]: %w", rel.TagName, repo.ID, repo.OwnerName, repo.Name, err)
}
if git.IsErrNotExist(err) || commitID != rel.Sha1 {
if err := models.PushUpdateDeleteTag(repo, rel.TagName); err != nil {
return fmt.Errorf("PushUpdateDeleteTag: %s: %v", rel.TagName, err)
return fmt.Errorf("unable to PushUpdateDeleteTag: %q in Repo[%d:%s/%s]: %w", rel.TagName, repo.ID, repo.OwnerName, repo.Name, err)
}
} else {
existingRelTags[strings.ToLower(rel.TagName)] = struct{}{}
@@ -278,12 +280,12 @@ func SyncReleasesWithTags(repo *repo_model.Repository, gitRepo *git.Repository)
}
tags, err := gitRepo.GetTags(0, 0)
if err != nil {
return fmt.Errorf("GetTags: %v", err)
return fmt.Errorf("unable to GetTags in Repo[%d:%s/%s]: %w", repo.ID, repo.OwnerName, repo.Name, err)
}
for _, tagName := range tags {
if _, ok := existingRelTags[strings.ToLower(tagName)]; !ok {
if err := PushUpdateAddTag(repo, gitRepo, tagName); err != nil {
return fmt.Errorf("pushUpdateAddTag: %v", err)
return fmt.Errorf("unable to PushUpdateAddTag: %q to Repo[%d:%s/%s]: %w", tagName, repo.ID, repo.OwnerName, repo.Name, err)
}
}
}
@@ -294,11 +296,11 @@ func SyncReleasesWithTags(repo *repo_model.Repository, gitRepo *git.Repository)
func PushUpdateAddTag(repo *repo_model.Repository, gitRepo *git.Repository, tagName string) error {
tag, err := gitRepo.GetTag(tagName)
if err != nil {
return fmt.Errorf("GetTag: %v", err)
return fmt.Errorf("unable to GetTag: %w", err)
}
commit, err := tag.Commit(gitRepo)
if err != nil {
return fmt.Errorf("Commit: %v", err)
return fmt.Errorf("unable to get tag Commit: %w", err)
}
sig := tag.Tagger
@@ -310,22 +312,22 @@ func PushUpdateAddTag(repo *repo_model.Repository, gitRepo *git.Repository, tagN
}
var author *user_model.User
var createdAt = time.Unix(1, 0)
createdAt := time.Unix(1, 0)
if sig != nil {
author, err = user_model.GetUserByEmail(sig.Email)
if err != nil && !user_model.IsErrUserNotExist(err) {
return fmt.Errorf("GetUserByEmail: %v", err)
return fmt.Errorf("unable to GetUserByEmail for %q: %w", sig.Email, err)
}
createdAt = sig.When
}
commitsCount, err := commit.CommitsCount()
if err != nil {
return fmt.Errorf("CommitsCount: %v", err)
return fmt.Errorf("unable to get CommitsCount: %w", err)
}
var rel = models.Release{
rel := models.Release{
RepoID: repo.ID,
TagName: tagName,
LowerTagName: strings.ToLower(tagName),
@@ -359,14 +361,14 @@ func StoreMissingLfsObjectsInRepository(ctx context.Context, repo *repo_model.Re
_, err := models.NewLFSMetaObject(&models.LFSMetaObject{Pointer: p, RepositoryID: repo.ID})
if err != nil {
log.Error("Error creating LFS meta object %v: %v", p, err)
log.Error("Repo[%-v]: Error creating LFS meta object %-v: %v", repo, p, err)
return err
}
if err := contentStore.Put(p, content); err != nil {
log.Error("Error storing content for LFS meta object %v: %v", p, err)
log.Error("Repo[%-v]: Error storing content for LFS meta object %-v: %v", repo, p, err)
if _, err2 := models.RemoveLFSMetaObjectByOid(repo.ID, p.Oid); err2 != nil {
log.Error("Error removing LFS meta object %v: %v", p, err2)
log.Error("Repo[%-v]: Error removing LFS meta object %-v: %v", repo, p, err2)
}
return err
}
@@ -386,32 +388,32 @@ func StoreMissingLfsObjectsInRepository(ctx context.Context, repo *repo_model.Re
for pointerBlob := range pointerChan {
meta, err := models.GetLFSMetaObjectByOid(repo.ID, pointerBlob.Oid)
if err != nil && err != models.ErrLFSObjectNotExist {
log.Error("Error querying LFS meta object %v: %v", pointerBlob.Pointer, err)
log.Error("Repo[%-v]: Error querying LFS meta object %-v: %v", repo, pointerBlob.Pointer, err)
return err
}
if meta != nil {
log.Trace("Skipping unknown LFS meta object %v", pointerBlob.Pointer)
log.Trace("Repo[%-v]: Skipping unknown LFS meta object %-v", repo, pointerBlob.Pointer)
continue
}
log.Trace("LFS object %v not present in repository %s", pointerBlob.Pointer, repo.FullName())
log.Trace("Repo[%-v]: LFS object %-v not present in repository", repo, pointerBlob.Pointer)
exist, err := contentStore.Exists(pointerBlob.Pointer)
if err != nil {
log.Error("Error checking if LFS object %v exists: %v", pointerBlob.Pointer, err)
log.Error("Repo[%-v]: Error checking if LFS object %-v exists: %v", repo, pointerBlob.Pointer, err)
return err
}
if exist {
log.Trace("LFS object %v already present; creating meta object", pointerBlob.Pointer)
log.Trace("Repo[%-v]: LFS object %-v already present; creating meta object", repo, pointerBlob.Pointer)
_, err := models.NewLFSMetaObject(&models.LFSMetaObject{Pointer: pointerBlob.Pointer, RepositoryID: repo.ID})
if err != nil {
log.Error("Error creating LFS meta object %v: %v", pointerBlob.Pointer, err)
log.Error("Repo[%-v]: Error creating LFS meta object %-v: %v", repo, pointerBlob.Pointer, err)
return err
}
} else {
if setting.LFS.MaxFileSize > 0 && pointerBlob.Size > setting.LFS.MaxFileSize {
log.Info("LFS object %v download denied because of LFS_MAX_FILE_SIZE=%d < size %d", pointerBlob.Pointer, setting.LFS.MaxFileSize, pointerBlob.Size)
log.Info("Repo[%-v]: LFS object %-v download denied because of LFS_MAX_FILE_SIZE=%d < size %d", repo, pointerBlob.Pointer, setting.LFS.MaxFileSize, pointerBlob.Size)
continue
}
@@ -432,7 +434,7 @@ func StoreMissingLfsObjectsInRepository(ctx context.Context, repo *repo_model.Re
err, has := <-errChan
if has {
log.Error("Error enumerating LFS objects for repository: %v", err)
log.Error("Repo[%-v]: Error enumerating LFS objects for repository: %v", repo, err)
return err
}

View File

@@ -15,13 +15,17 @@ import (
"code.gitea.io/gitea/modules/json"
"code.gitea.io/gitea/modules/log"
"golang.org/x/text/cases"
"golang.org/x/text/language"
ini "gopkg.in/ini.v1"
)
var filenameSuffix = ""
var descriptionLock = sync.RWMutex{}
var logDescriptions = make(map[string]*LogDescription)
var (
filenameSuffix = ""
descriptionLock = sync.RWMutex{}
logDescriptions = make(map[string]*LogDescription)
)
// GetLogDescriptions returns a race safe set of descriptions
func GetLogDescriptions() map[string]*LogDescription {
@@ -86,7 +90,7 @@ func RemoveSubLogDescription(key, name string) bool {
type defaultLogOptions struct {
levelName string // LogLevel
flags string
filename string //path.Join(LogRootPath, "gitea.log")
filename string // path.Join(LogRootPath, "gitea.log")
bufferLength int64
disableConsole bool
}
@@ -243,7 +247,7 @@ func generateNamedLogger(key string, options defaultLogOptions) *LogDescription
Provider: provider,
Config: config,
})
log.Info("%s Log: %s(%s:%s)", strings.Title(key), strings.Title(name), provider, levelName)
log.Info("%s Log: %s(%s:%s)", cases.Title(language.English).String(key), cases.Title(language.English).String(name), provider, levelName)
}
AddLogDescription(key, &description)
@@ -327,7 +331,7 @@ func newLogService() {
Provider: provider,
Config: config,
})
log.Info("Gitea Log Mode: %s(%s:%s)", strings.Title(name), strings.Title(provider), levelName)
log.Info("Gitea Log Mode: %s(%s:%s)", cases.Title(language.English).String(name), cases.Title(language.English).String(provider), levelName)
}
AddLogDescription(log.DEFAULT, &description)

View File

@@ -30,6 +30,8 @@ import (
"github.com/unknwon/com"
gossh "golang.org/x/crypto/ssh"
"golang.org/x/text/cases"
"golang.org/x/text/language"
ini "gopkg.in/ini.v1"
)
@@ -90,13 +92,15 @@ var (
// AppDataPath is the default path for storing data.
// It maps to ini:"APP_DATA_PATH" and defaults to AppWorkPath + "/data"
AppDataPath string
// LocalURL is the url for locally running applications to contact Gitea. It always has a '/' suffix
// It maps to ini:"LOCAL_ROOT_URL"
LocalURL string
// Server settings
Protocol Scheme
Domain string
HTTPAddr string
HTTPPort string
LocalURL string
RedirectOtherPort bool
PortToRedirect string
OfflineMode bool
@@ -637,7 +641,7 @@ func loadFromConf(allowEmpty bool, extraConfig string) {
}
UnixSocketPermissionRaw := sec.Key("UNIX_SOCKET_PERMISSION").MustString("666")
UnixSocketPermissionParsed, err := strconv.ParseUint(UnixSocketPermissionRaw, 8, 32)
if err != nil || UnixSocketPermissionParsed > 0777 {
if err != nil || UnixSocketPermissionParsed > 0o777 {
log.Fatal("Failed to parse unixSocketPermission: %s", UnixSocketPermissionRaw)
}
@@ -710,6 +714,7 @@ func loadFromConf(allowEmpty bool, extraConfig string) {
}
}
LocalURL = sec.Key("LOCAL_ROOT_URL").MustString(defaultLocalURL)
LocalURL = strings.TrimRight(LocalURL, "/") + "/"
RedirectOtherPort = sec.Key("REDIRECT_OTHER_PORT").MustBool(false)
PortToRedirect = sec.Key("PORT_TO_REDIRECT").MustString("80")
OfflineMode = sec.Key("OFFLINE_MODE").MustBool()
@@ -793,16 +798,16 @@ func loadFromConf(allowEmpty bool, extraConfig string) {
SSH.AuthorizedPrincipalsAllow, SSH.AuthorizedPrincipalsEnabled = parseAuthorizedPrincipalsAllow(sec.Key("SSH_AUTHORIZED_PRINCIPALS_ALLOW").Strings(","))
if !SSH.Disabled && !SSH.StartBuiltinServer {
if err := os.MkdirAll(SSH.RootPath, 0700); err != nil {
if err := os.MkdirAll(SSH.RootPath, 0o700); err != nil {
log.Fatal("Failed to create '%s': %v", SSH.RootPath, err)
} else if err = os.MkdirAll(SSH.KeyTestPath, 0644); err != nil {
} else if err = os.MkdirAll(SSH.KeyTestPath, 0o644); err != nil {
log.Fatal("Failed to create '%s': %v", SSH.KeyTestPath, err)
}
if len(trustedUserCaKeys) > 0 && SSH.AuthorizedPrincipalsEnabled {
fname := sec.Key("SSH_TRUSTED_USER_CA_KEYS_FILENAME").MustString(filepath.Join(SSH.RootPath, "gitea-trusted-user-ca-keys.pem"))
if err := os.WriteFile(fname,
[]byte(strings.Join(trustedUserCaKeys, "\n")), 0600); err != nil {
[]byte(strings.Join(trustedUserCaKeys, "\n")), 0o600); err != nil {
log.Fatal("Failed to create '%s': %v", fname, err)
}
}
@@ -943,8 +948,9 @@ func loadFromConf(allowEmpty bool, extraConfig string) {
// The following is a purposefully undocumented option. Please do not run Gitea as root. It will only cause future headaches.
// Please don't use root as a bandaid to "fix" something that is broken, instead the broken thing should instead be fixed properly.
unsafeAllowRunAsRoot := Cfg.Section("").Key("I_AM_BEING_UNSAFE_RUNNING_AS_ROOT").MustBool(false)
RunMode = Cfg.Section("").Key("RUN_MODE").MustString("prod")
IsProd = strings.EqualFold(RunMode, "prod")
RunMode = Cfg.Section("").Key("RUN_MODE").MustString("Prod")
RunMode = cases.Title(language.English).String(strings.ToLower(RunMode))
IsProd = RunMode == "Prod"
// Does not check run user when the install lock is off.
if InstallLock {
currentUser, match := IsRunUserMatchCurrentUser(RunUser)
@@ -1074,7 +1080,7 @@ func loadInternalToken(sec *ini.Section) string {
}
switch tempURI.Scheme {
case "file":
fp, err := os.OpenFile(tempURI.RequestURI(), os.O_RDWR, 0600)
fp, err := os.OpenFile(tempURI.RequestURI(), os.O_RDWR, 0o600)
if err != nil {
log.Fatal("Failed to open InternalTokenURI (%s): %v", uri, err)
}

View File

@@ -317,64 +317,7 @@ func Listen(host string, port int, ciphers, keyExchanges, macs []string) {
}
}
// Workaround slightly broken behaviour in x/crypto/ssh/handshake.go:458-463
//
// Fundamentally the issue here is that HostKeyAlgos make the incorrect assumption
// that the PublicKey().Type() matches the signature algorithm.
//
// Therefore we need to add duplicates for the RSA with different signing algorithms.
signers := make([]ssh.Signer, 0, len(srv.HostSigners))
for _, signer := range srv.HostSigners {
if signer.PublicKey().Type() == "ssh-rsa" {
signers = append(signers,
&wrapSigner{
Signer: signer,
algorithm: gossh.SigAlgoRSASHA2512,
},
&wrapSigner{
Signer: signer,
algorithm: gossh.SigAlgoRSASHA2256,
},
)
}
signers = append(signers, signer)
}
srv.HostSigners = signers
go listen(&srv)
}
// wrapSigner wraps a signer and overrides its public key type with the provided algorithm
type wrapSigner struct {
ssh.Signer
algorithm string
}
// PublicKey returns an associated PublicKey instance.
func (s *wrapSigner) PublicKey() gossh.PublicKey {
return &wrapPublicKey{
PublicKey: s.Signer.PublicKey(),
algorithm: s.algorithm,
}
}
// Sign returns raw signature for the given data. This method
// will apply the hash specified for the keytype to the data using
// the algorithm assigned for this key
func (s *wrapSigner) Sign(rand io.Reader, data []byte) (*gossh.Signature, error) {
return s.Signer.(gossh.AlgorithmSigner).SignWithAlgorithm(rand, data, s.algorithm)
}
// wrapPublicKey wraps a PublicKey and overrides its type
type wrapPublicKey struct {
gossh.PublicKey
algorithm string
}
// Type returns the algorithm
func (k *wrapPublicKey) Type() string {
return k.algorithm
}
// GenKeyPair make a pair of public and private keys for SSH access.

View File

@@ -9,15 +9,15 @@ import (
"io"
"net/url"
"os"
"path"
"path/filepath"
"strings"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/util"
)
var (
_ ObjectStorage = &LocalStorage{}
)
var _ ObjectStorage = &LocalStorage{}
// LocalStorageType is the type descriptor for local storage
const LocalStorageType Type = "local"
@@ -59,14 +59,18 @@ func NewLocalStorage(ctx context.Context, cfg interface{}) (ObjectStorage, error
}, nil
}
func (l *LocalStorage) buildLocalPath(p string) string {
return filepath.Join(l.dir, path.Clean("/" + strings.ReplaceAll(p, "\\", "/"))[1:])
}
// Open a file
func (l *LocalStorage) Open(path string) (Object, error) {
return os.Open(filepath.Join(l.dir, path))
return os.Open(l.buildLocalPath(path))
}
// Save a file
func (l *LocalStorage) Save(path string, r io.Reader, size int64) (int64, error) {
p := filepath.Join(l.dir, path)
p := l.buildLocalPath(path)
if err := os.MkdirAll(filepath.Dir(p), os.ModePerm); err != nil {
return 0, err
}
@@ -106,13 +110,12 @@ func (l *LocalStorage) Save(path string, r io.Reader, size int64) (int64, error)
// Stat returns the info of the file
func (l *LocalStorage) Stat(path string) (os.FileInfo, error) {
return os.Stat(filepath.Join(l.dir, path))
return os.Stat(l.buildLocalPath(path))
}
// Delete delete a file
func (l *LocalStorage) Delete(path string) error {
p := filepath.Join(l.dir, path)
return util.Remove(p)
return util.Remove(l.buildLocalPath(path))
}
// URL gets the redirect URL to a file

View File

@@ -0,0 +1,53 @@
// Copyright 2022 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 storage
import (
"testing"
"github.com/stretchr/testify/assert"
)
func TestBuildLocalPath(t *testing.T) {
kases := []struct {
localDir string
path string
expected string
}{
{
"a",
"0/a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a14",
"a/0/a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a14",
},
{
"a",
"../0/a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a14",
"a/0/a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a14",
},
{
"a",
"0\\a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a14",
"a/0/a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a14",
},
{
"b",
"a/../0/a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a14",
"b/0/a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a14",
},
{
"b",
"a\\..\\0/a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a14",
"b/0/a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a14",
},
}
for _, k := range kases {
t.Run(k.path, func(t *testing.T) {
l := LocalStorage{dir: k.localDir}
assert.EqualValues(t, k.expected, l.buildLocalPath(k.path))
})
}
}

View File

@@ -117,7 +117,7 @@ func NewMinioStorage(ctx context.Context, cfg interface{}) (ObjectStorage, error
}
func (m *MinioStorage) buildMinioPath(p string) string {
return strings.TrimPrefix(path.Join(m.basePath, p), "/")
return strings.TrimPrefix(path.Join(m.basePath, path.Clean("/" + strings.ReplaceAll(p, "\\", "/"))[1:]), "/")
}
// Open open a file

View File

@@ -38,6 +38,8 @@ import (
"code.gitea.io/gitea/modules/timeutil"
"code.gitea.io/gitea/modules/util"
"code.gitea.io/gitea/services/gitdiff"
"golang.org/x/text/cases"
"golang.org/x/text/language"
"github.com/editorconfig/editorconfig-core-go/v2"
)
@@ -49,7 +51,7 @@ var mailSubjectSplit = regexp.MustCompile(`(?m)^-{3,}[\s]*$`)
func NewFuncMap() []template.FuncMap {
return []template.FuncMap{map[string]interface{}{
"GoVer": func() string {
return strings.Title(runtime.Version())
return cases.Title(language.English).String(runtime.Version())
},
"UseHTTPS": func() bool {
return strings.HasPrefix(setting.AppURL, "https")
@@ -285,7 +287,7 @@ func NewFuncMap() []template.FuncMap {
return util.MergeInto(dict, values...)
},
"percentage": func(n int, values ...int) float32 {
var sum = 0
sum := 0
for i := 0; i < len(values); i++ {
sum += values[i]
}
@@ -378,6 +380,7 @@ func NewFuncMap() []template.FuncMap {
},
"Join": strings.Join,
"QueryEscape": url.QueryEscape,
"DotEscape": DotEscape,
}}
}
@@ -386,7 +389,7 @@ func NewFuncMap() []template.FuncMap {
func NewTextFuncMap() []texttmpl.FuncMap {
return []texttmpl.FuncMap{map[string]interface{}{
"GoVer": func() string {
return strings.Title(runtime.Version())
return cases.Title(language.English).String(runtime.Version())
},
"AppName": func() string {
return setting.AppName
@@ -477,7 +480,7 @@ func NewTextFuncMap() []texttmpl.FuncMap {
return dict, nil
},
"percentage": func(n int, values ...int) float32 {
var sum = 0
sum := 0
for i := 0; i < len(values); i++ {
sum += values[i]
}
@@ -501,8 +504,10 @@ func NewTextFuncMap() []texttmpl.FuncMap {
}}
}
var widthRe = regexp.MustCompile(`width="[0-9]+?"`)
var heightRe = regexp.MustCompile(`height="[0-9]+?"`)
var (
widthRe = regexp.MustCompile(`width="[0-9]+?"`)
heightRe = regexp.MustCompile(`height="[0-9]+?"`)
)
func parseOthers(defaultSize int, defaultClass string, others ...interface{}) (int, string) {
size := defaultSize
@@ -629,6 +634,11 @@ func JSEscape(raw string) string {
return template.JSEscapeString(raw)
}
// DotEscape wraps a dots in names with ZWJ [U+200D] in order to prevent autolinkers from detecting these as urls
func DotEscape(raw string) string {
return strings.ReplaceAll(raw, ".", "\u200d.\u200d")
}
// Sha1 returns sha1 sum of string
func Sha1(str string) string {
return base.EncodeSha1(str)
@@ -736,7 +746,7 @@ func RenderEmoji(text string) template.HTML {
return template.HTML(renderedText)
}
//ReactionToEmoji renders emoji for use in reactions
// ReactionToEmoji renders emoji for use in reactions
func ReactionToEmoji(reaction string) template.HTML {
val := emoji.FromCode(reaction)
if val != nil {

View File

@@ -1,19 +0,0 @@
// 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 util
import (
"net"
)
// IsIPPrivate for net.IP.IsPrivate. TODO: replace with `ip.IsPrivate()` if min go version is bumped to 1.17
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
}

18
modules/util/slice.go Normal file
View File

@@ -0,0 +1,18 @@
// Copyright 2022 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 util
// RemoveIDFromList removes the given ID from the slice, if found.
// It does not preserve order, and assumes the ID is unique.
func RemoveIDFromList(list []int64, id int64) ([]int64, bool) {
n := len(list) - 1
for i, item := range list {
if item == id {
list[i] = list[n]
return list[:n], true
}
}
return list, false
}

View File

@@ -119,6 +119,7 @@ func CreateUser(ctx *context.APIContext) {
user_model.IsErrEmailAlreadyUsed(err) ||
db.IsErrNameReserved(err) ||
db.IsErrNameCharsNotAllowed(err) ||
user_model.IsErrEmailCharIsNotSupported(err) ||
user_model.IsErrEmailInvalid(err) ||
db.IsErrNamePatternNotAllowed(err) {
ctx.Error(http.StatusUnprocessableEntity, "", err)
@@ -265,7 +266,9 @@ func EditUser(ctx *context.APIContext) {
}
if err := user_model.UpdateUser(u, emailChanged); err != nil {
if user_model.IsErrEmailAlreadyUsed(err) || user_model.IsErrEmailInvalid(err) {
if user_model.IsErrEmailAlreadyUsed(err) ||
user_model.IsErrEmailCharIsNotSupported(err) ||
user_model.IsErrEmailInvalid(err) {
ctx.Error(http.StatusUnprocessableEntity, "", err)
} else {
ctx.Error(http.StatusInternalServerError, "UpdateUser", err)

View File

@@ -121,7 +121,7 @@ func ListRepoNotifications(ctx *context.APIContext) {
return
}
err = nl.LoadAttributes()
if err != nil && !models.IsErrCommentNotExist(err) {
if err != nil {
ctx.InternalServerError(err)
return
}

View File

@@ -245,18 +245,23 @@ func SearchIssues(ctx *context.APIContext) {
UpdatedAfterUnix: since,
}
ctxUserID := int64(0)
if ctx.IsSigned {
ctxUserID = ctx.User.ID
}
// Filter for: Created by User, Assigned to User, Mentioning User, Review of User Requested
if ctx.FormBool("created") {
issuesOpt.PosterID = ctx.User.ID
issuesOpt.PosterID = ctxUserID
}
if ctx.FormBool("assigned") {
issuesOpt.AssigneeID = ctx.User.ID
issuesOpt.AssigneeID = ctxUserID
}
if ctx.FormBool("mentioned") {
issuesOpt.MentionedID = ctx.User.ID
issuesOpt.MentionedID = ctxUserID
}
if ctx.FormBool("review_requested") {
issuesOpt.ReviewRequestedID = ctx.User.ID
issuesOpt.ReviewRequestedID = ctxUserID
}
if issues, err = models.Issues(issuesOpt); err != nil {
@@ -599,7 +604,7 @@ func CreateIssue(ctx *context.APIContext) {
DeadlineUnix: deadlineUnix,
}
var assigneeIDs = make([]int64, 0)
assigneeIDs := make([]int64, 0)
var err error
if ctx.Repo.CanWrite(unit.TypeIssues) {
issue.MilestoneID = form.Milestone

View File

@@ -144,7 +144,7 @@ func GetDeployKey(ctx *context.APIContext) {
// "200":
// "$ref": "#/responses/DeployKey"
key, err := asymkey_model.GetDeployKeyByID(db.DefaultContext, ctx.ParamsInt64(":id"))
key, err := asymkey_model.GetDeployKeyByID(ctx, ctx.ParamsInt64(":id"))
if err != nil {
if asymkey_model.IsErrDeployKeyNotExist(err) {
ctx.NotFound()

View File

@@ -80,7 +80,8 @@ func AddEmail(ctx *context.APIContext) {
if err := user_model.AddEmailAddresses(emails); err != nil {
if user_model.IsErrEmailAlreadyUsed(err) {
ctx.Error(http.StatusUnprocessableEntity, "", "Email address has been used: "+err.(user_model.ErrEmailAlreadyUsed).Email)
} else if user_model.IsErrEmailInvalid(err) {
} else if user_model.IsErrEmailCharIsNotSupported(err) ||
user_model.IsErrEmailInvalid(err) {
errMsg := fmt.Sprintf("Email address %s invalid", err.(user_model.ErrEmailInvalid).Email)
ctx.Error(http.StatusUnprocessableEntity, "", errMsg)
} else {

View File

@@ -10,7 +10,6 @@ import (
"reflect"
"runtime"
"strconv"
"strings"
"code.gitea.io/gitea/models"
asymkey_model "code.gitea.io/gitea/models/asymkey"
@@ -47,6 +46,8 @@ import (
"code.gitea.io/gitea/services/repository/archiver"
"code.gitea.io/gitea/services/task"
"code.gitea.io/gitea/services/webhook"
"golang.org/x/text/cases"
"golang.org/x/text/language"
"gitea.com/go-chi/session"
)
@@ -111,7 +112,7 @@ func GlobalInitInstalled(ctx context.Context) {
log.Info("Custom path: %s", setting.CustomPath)
log.Info("Log path: %s", setting.LogRootPath)
log.Info("Configuration file: %s", setting.CustomConf)
log.Info("Run Mode: %s", strings.Title(setting.RunMode))
log.Info("Run Mode: %s", cases.Title(language.English).String(setting.RunMode))
// Setup i18n
translation.InitLocales()

View File

@@ -12,6 +12,8 @@ import (
"strings"
"code.gitea.io/gitea/models"
asymkey_model "code.gitea.io/gitea/models/asymkey"
perm_model "code.gitea.io/gitea/models/perm"
"code.gitea.io/gitea/models/unit"
user_model "code.gitea.io/gitea/models/user"
gitea_context "code.gitea.io/gitea/modules/context"
@@ -24,8 +26,12 @@ import (
type preReceiveContext struct {
*gitea_context.PrivateContext
user *user_model.User
perm models.Permission
// loadedPusher indicates that where the following information are loaded
loadedPusher bool
user *user_model.User // it's the org user if a DeployKey is used
userPerm models.Permission
deployKeyAccessMode perm_model.AccessMode
canCreatePullRequest bool
checkedCanCreatePullRequest bool
@@ -41,62 +47,52 @@ type preReceiveContext struct {
opts *private.HookOptions
}
// User gets or loads User
func (ctx *preReceiveContext) User() *user_model.User {
if ctx.user == nil {
ctx.user, ctx.perm = loadUserAndPermission(ctx.PrivateContext, ctx.opts.UserID)
}
return ctx.user
}
// Perm gets or loads Perm
func (ctx *preReceiveContext) Perm() *models.Permission {
if ctx.user == nil {
ctx.user, ctx.perm = loadUserAndPermission(ctx.PrivateContext, ctx.opts.UserID)
}
return &ctx.perm
}
// CanWriteCode returns true if can write code
// CanWriteCode returns true if pusher can write code
func (ctx *preReceiveContext) CanWriteCode() bool {
if !ctx.checkedCanWriteCode {
ctx.canWriteCode = ctx.Perm().CanWrite(unit.TypeCode)
if !ctx.loadPusherAndPermission() {
return false
}
ctx.canWriteCode = ctx.userPerm.CanWrite(unit.TypeCode) || ctx.deployKeyAccessMode >= perm_model.AccessModeWrite
ctx.checkedCanWriteCode = true
}
return ctx.canWriteCode
}
// AssertCanWriteCode returns true if can write code
// AssertCanWriteCode returns true if pusher can write code
func (ctx *preReceiveContext) AssertCanWriteCode() bool {
if !ctx.CanWriteCode() {
if ctx.Written() {
return false
}
ctx.JSON(http.StatusForbidden, map[string]interface{}{
"err": "User permission denied.",
"err": "User permission denied for writing.",
})
return false
}
return true
}
// CanCreatePullRequest returns true if can create pull requests
// CanCreatePullRequest returns true if pusher can create pull requests
func (ctx *preReceiveContext) CanCreatePullRequest() bool {
if !ctx.checkedCanCreatePullRequest {
ctx.canCreatePullRequest = ctx.Perm().CanRead(unit.TypePullRequests)
if !ctx.loadPusherAndPermission() {
return false
}
ctx.canCreatePullRequest = ctx.userPerm.CanRead(unit.TypePullRequests)
ctx.checkedCanCreatePullRequest = true
}
return ctx.canCreatePullRequest
}
// AssertCanCreatePullRequest returns true if can create pull requests
// AssertCreatePullRequest returns true if can create pull requests
func (ctx *preReceiveContext) AssertCreatePullRequest() bool {
if !ctx.CanCreatePullRequest() {
if ctx.Written() {
return false
}
ctx.JSON(http.StatusForbidden, map[string]interface{}{
"err": "User permission denied.",
"err": "User permission denied for creating pull-request.",
})
return false
}
@@ -246,7 +242,7 @@ func preReceiveBranch(ctx *preReceiveContext, oldCommitID, newCommitID, refFullN
// 5. Check if the doer is allowed to push
canPush := false
if ctx.opts.IsDeployKey {
if ctx.opts.DeployKeyID != 0 {
canPush = !changedProtectedfiles && protectBranch.CanPush && (!protectBranch.EnableWhitelist || protectBranch.WhitelistDeployKeys)
} else {
canPush = !changedProtectedfiles && protectBranch.CanUserPush(ctx.opts.UserID)
@@ -303,9 +299,15 @@ func preReceiveBranch(ctx *preReceiveContext, oldCommitID, newCommitID, refFullN
return
}
// although we should have called `loadPusherAndPermission` before, here we call it explicitly again because we need to access ctx.user below
if !ctx.loadPusherAndPermission() {
// if error occurs, loadPusherAndPermission had written the error response
return
}
// Now check if the user is allowed to merge PRs for this repository
// Note: we can use ctx.perm and ctx.user directly as they will have been loaded above
allowedMerge, err := pull_service.IsUserAllowedToMerge(pr, ctx.perm, ctx.user)
allowedMerge, err := pull_service.IsUserAllowedToMerge(pr, ctx.userPerm, ctx.user)
if err != nil {
log.Error("Error calculating if allowed to merge: %v", err)
ctx.JSON(http.StatusInternalServerError, private.Response{
@@ -323,7 +325,7 @@ func preReceiveBranch(ctx *preReceiveContext, oldCommitID, newCommitID, refFullN
}
// If we're an admin for the repository we can ignore status checks, reviews and override protected files
if ctx.perm.IsAdmin() {
if ctx.userPerm.IsAdmin() {
return
}
@@ -450,24 +452,44 @@ func generateGitEnv(opts *private.HookOptions) (env []string) {
return env
}
func loadUserAndPermission(ctx *gitea_context.PrivateContext, id int64) (user *user_model.User, perm models.Permission) {
user, err := user_model.GetUserByID(id)
if err != nil {
log.Error("Unable to get User id %d Error: %v", id, err)
ctx.JSON(http.StatusInternalServerError, private.Response{
Err: fmt.Sprintf("Unable to get User id %d Error: %v", id, err),
})
return
// loadPusherAndPermission returns false if an error occurs, and it writes the error response
func (ctx *preReceiveContext) loadPusherAndPermission() bool {
if ctx.loadedPusher {
return true
}
perm, err = models.GetUserRepoPermission(ctx.Repo.Repository, user)
user, err := user_model.GetUserByID(ctx.opts.UserID)
if err != nil {
log.Error("Unable to get User id %d Error: %v", ctx.opts.UserID, err)
ctx.JSON(http.StatusInternalServerError, private.Response{
Err: fmt.Sprintf("Unable to get User id %d Error: %v", ctx.opts.UserID, err),
})
return false
}
ctx.user = user
userPerm, err := models.GetUserRepoPermission(ctx.Repo.Repository, user)
if err != nil {
log.Error("Unable to get Repo permission of repo %s/%s of User %s", ctx.Repo.Repository.OwnerName, ctx.Repo.Repository.Name, user.Name, err)
ctx.JSON(http.StatusInternalServerError, private.Response{
Err: fmt.Sprintf("Unable to get Repo permission of repo %s/%s of User %s: %v", ctx.Repo.Repository.OwnerName, ctx.Repo.Repository.Name, user.Name, err),
})
return
return false
}
ctx.userPerm = userPerm
if ctx.opts.DeployKeyID != 0 {
deployKey, err := asymkey_model.GetDeployKeyByID(ctx, ctx.opts.DeployKeyID)
if err != nil {
log.Error("Unable to get DeployKey id %d Error: %v", ctx.opts.DeployKeyID, err)
ctx.JSON(http.StatusInternalServerError, private.Response{
Err: fmt.Sprintf("Unable to get DeployKey id %d Error: %v", ctx.opts.DeployKeyID, err),
})
return false
}
ctx.deployKeyAccessMode = deployKey.Mode
}
return
ctx.loadedPusher = true
return true
}

View File

@@ -60,7 +60,7 @@ func SendEmail(ctx *context.PrivateContext) {
}
} else {
err := user_model.IterateUser(func(user *user_model.User) error {
if len(user.Email) > 0 {
if len(user.Email) > 0 && user.IsActive {
emails = append(emails, user.Email)
}
return nil

View File

@@ -229,8 +229,6 @@ func ServCommand(ctx *context.PrivateContext) {
var deployKey *asymkey_model.DeployKey
var user *user_model.User
if key.Type == asymkey_model.KeyTypeDeploy {
results.IsDeployKey = true
var err error
deployKey, err = asymkey_model.GetDeployKeyByRepo(key.ID, repo.ID)
if err != nil {
@@ -248,6 +246,7 @@ func ServCommand(ctx *context.PrivateContext) {
})
return
}
results.DeployKeyID = deployKey.ID
results.KeyName = deployKey.Name
// FIXME: Deploy keys aren't really the owner of the repo pushing changes
@@ -410,9 +409,9 @@ func ServCommand(ctx *context.PrivateContext) {
return
}
}
log.Debug("Serv Results:\nIsWiki: %t\nIsDeployKey: %t\nKeyID: %d\tKeyName: %s\nUserName: %s\nUserID: %d\nOwnerName: %s\nRepoName: %s\nRepoID: %d",
log.Debug("Serv Results:\nIsWiki: %t\nDeployKeyID: %d\nKeyID: %d\tKeyName: %s\nUserName: %s\nUserID: %d\nOwnerName: %s\nRepoName: %s\nRepoID: %d",
results.IsWiki,
results.IsDeployKey,
results.DeployKeyID,
results.KeyID,
results.KeyName,
results.UserName,

View File

@@ -209,7 +209,7 @@ func shadowPassword(provider, cfgItem string) string {
case "redis":
return shadowPasswordKV(cfgItem, ",")
case "mysql":
//root:@tcp(localhost:3306)/macaron?charset=utf8
// root:@tcp(localhost:3306)/macaron?charset=utf8
atIdx := strings.Index(cfgItem, "@")
if atIdx > 0 {
colonIdx := strings.Index(cfgItem[:atIdx], ":")
@@ -244,7 +244,7 @@ func Config(ctx *context.Context) {
ctx.Data["OfflineMode"] = setting.OfflineMode
ctx.Data["DisableRouterLog"] = setting.DisableRouterLog
ctx.Data["RunUser"] = setting.RunUser
ctx.Data["RunMode"] = strings.Title(setting.RunMode)
ctx.Data["RunMode"] = setting.RunMode
if version, err := git.LocalVersion(); err == nil {
ctx.Data["GitVersion"] = version.Original()
}

View File

@@ -93,7 +93,7 @@ func NewAuthSource(ctx *context.Context) {
ctx.Data["PageIsAdmin"] = true
ctx.Data["PageIsAdminAuthentications"] = true
ctx.Data["type"] = auth.LDAP
ctx.Data["type"] = auth.LDAP.Int()
ctx.Data["CurrentTypeName"] = auth.Names[auth.LDAP]
ctx.Data["CurrentSecurityProtocol"] = ldap.SecurityProtocolNames[ldap.SecurityProtocolUnencrypted]
ctx.Data["smtp_auth"] = "PLAIN"
@@ -112,7 +112,7 @@ func NewAuthSource(ctx *context.Context) {
ctx.Data["SSPIDefaultLanguage"] = ""
// only the first as default
ctx.Data["oauth2_provider"] = oauth2providers[0]
ctx.Data["oauth2_provider"] = oauth2providers[0].Name
ctx.HTML(http.StatusOK, tplAuthNew)
}
@@ -181,6 +181,14 @@ func parseOAuth2Config(form forms.AuthenticationForm) *oauth2.Source {
} else {
customURLMapping = nil
}
var scopes []string
for _, s := range strings.Split(form.Oauth2Scopes, ",") {
s = strings.TrimSpace(s)
if s != "" {
scopes = append(scopes, s)
}
}
return &oauth2.Source{
Provider: form.Oauth2Provider,
ClientID: form.Oauth2Key,
@@ -188,7 +196,7 @@ func parseOAuth2Config(form forms.AuthenticationForm) *oauth2.Source {
OpenIDConnectAutoDiscoveryURL: form.OpenIDConnectAutoDiscoveryURL,
CustomURLMapping: customURLMapping,
IconURL: form.Oauth2IconURL,
Scopes: strings.Split(form.Oauth2Scopes, ","),
Scopes: scopes,
RequiredClaimName: form.Oauth2RequiredClaimName,
RequiredClaimValue: form.Oauth2RequiredClaimValue,
SkipLocalTwoFA: form.SkipLocalTwoFA,
@@ -243,6 +251,9 @@ func NewAuthSourcePost(ctx *context.Context) {
ctx.Data["SSPISeparatorReplacement"] = "_"
ctx.Data["SSPIDefaultLanguage"] = ""
// FIXME: most error path to render tplAuthNew will fail and result in 500
// * template: admin/auth/new:17:68: executing "admin/auth/new" at <.type.Int>: can't evaluate field Int in type interface {}
// * template: admin/auth/source/oauth:5:93: executing "admin/auth/source/oauth" at <.oauth2_provider.Name>: can't evaluate field Name in type interface {}
hasTLS := false
var config convert.Conversion
switch auth.Type(form.Type) {
@@ -393,6 +404,7 @@ func EditAuthSourcePost(ctx *context.Context) {
source.IsActive = form.IsActive
source.IsSyncEnabled = form.IsSyncEnabled
source.Cfg = config
// FIXME: if the name conflicts, it will result in 500: Error 1062: Duplicate entry 'aa' for key 'login_source.UQE_login_source_name'
if err := auth.UpdateSource(source); err != nil {
if oauth2.IsErrOpenIDConnectInitialize(err) {
ctx.Flash.Error(err.Error(), true)

View File

@@ -171,6 +171,9 @@ func NewUserPost(ctx *context.Context) {
case user_model.IsErrEmailAlreadyUsed(err):
ctx.Data["Err_Email"] = true
ctx.RenderWithErr(ctx.Tr("form.email_been_used"), tplUserNew, &form)
case user_model.IsErrEmailCharIsNotSupported(err):
ctx.Data["Err_Email"] = true
ctx.RenderWithErr(ctx.Tr("form.email_invalid"), tplUserNew, &form)
case user_model.IsErrEmailInvalid(err):
ctx.Data["Err_Email"] = true
ctx.RenderWithErr(ctx.Tr("form.email_invalid"), tplUserNew, &form)
@@ -386,7 +389,8 @@ func EditUserPost(ctx *context.Context) {
if user_model.IsErrEmailAlreadyUsed(err) {
ctx.Data["Err_Email"] = true
ctx.RenderWithErr(ctx.Tr("form.email_been_used"), tplUserEdit, &form)
} else if user_model.IsErrEmailInvalid(err) {
} else if user_model.IsErrEmailCharIsNotSupported(err) ||
user_model.IsErrEmailInvalid(err) {
ctx.Data["Err_Email"] = true
ctx.RenderWithErr(ctx.Tr("form.email_invalid"), tplUserEdit, &form)
} else {

View File

@@ -195,7 +195,7 @@ func SignInPost(ctx *context.Context) {
form := web.GetForm(ctx).(*forms.SignInForm)
u, source, err := auth_service.UserSignIn(form.UserName, form.Password)
if err != nil {
if user_model.IsErrUserNotExist(err) {
if user_model.IsErrUserNotExist(err) || user_model.IsErrEmailAddressNotExist(err) {
ctx.RenderWithErr(ctx.Tr("form.username_password_incorrect"), tplSignIn, &form)
log.Info("Failed authentication attempt for %s from %s: %v", form.UserName, ctx.RemoteAddr(), err)
} else if user_model.IsErrEmailAlreadyUsed(err) {
@@ -573,6 +573,9 @@ func createUserInContext(ctx *context.Context, tpl base.TplName, form interface{
case user_model.IsErrEmailAlreadyUsed(err):
ctx.Data["Err_Email"] = true
ctx.RenderWithErr(ctx.Tr("form.email_been_used"), tpl, form)
case user_model.IsErrEmailCharIsNotSupported(err):
ctx.Data["Err_Email"] = true
ctx.RenderWithErr(ctx.Tr("form.email_invalid"), tpl, form)
case user_model.IsErrEmailInvalid(err):
ctx.Data["Err_Email"] = true
ctx.RenderWithErr(ctx.Tr("form.email_invalid"), tpl, form)
@@ -618,6 +621,12 @@ func handleUserCreated(ctx *context.Context, u *user_model.User, gothUser *goth.
// Send confirmation email
if !u.IsActive && u.ID > 1 {
if setting.Service.RegisterManualConfirm {
ctx.Data["ManualActivationOnly"] = true
ctx.HTML(http.StatusOK, TplActivate)
return
}
mailer.SendActivateAccountMail(ctx.Locale, u)
ctx.Data["IsSendRegisterMail"] = true

View File

@@ -11,7 +11,6 @@ import (
"net/http"
"os"
"path"
"path/filepath"
"strings"
"code.gitea.io/gitea/modules/context"
@@ -27,6 +26,8 @@ import (
)
func storageHandler(storageSetting setting.Storage, prefix string, objStore storage.ObjectStorage) func(next http.Handler) http.Handler {
prefix = strings.Trim(prefix, "/")
return func(next http.Handler) http.Handler {
if storageSetting.ServeDirect {
return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
@@ -35,12 +36,14 @@ func storageHandler(storageSetting setting.Storage, prefix string, objStore stor
return
}
if !strings.HasPrefix(req.URL.RequestURI(), "/"+prefix) {
if !strings.HasPrefix(req.URL.Path, "/"+prefix+"/") {
next.ServeHTTP(w, req)
return
}
rPath := strings.TrimPrefix(req.URL.RequestURI(), "/"+prefix)
rPath := strings.TrimPrefix(req.URL.Path, "/"+prefix+"/")
rPath = path.Clean("/" + strings.ReplaceAll(rPath, "\\", "/"))[1:]
u, err := objStore.URL(rPath, path.Base(rPath))
if err != nil {
if os.IsNotExist(err) || errors.Is(err, os.ErrNotExist) {
@@ -52,11 +55,12 @@ func storageHandler(storageSetting setting.Storage, prefix string, objStore stor
http.Error(w, fmt.Sprintf("Error whilst getting URL for %s %s", prefix, rPath), 500)
return
}
http.Redirect(
w,
req,
u.String(),
301,
http.StatusMovedPermanently,
)
})
}
@@ -67,28 +71,24 @@ func storageHandler(storageSetting setting.Storage, prefix string, objStore stor
return
}
prefix := strings.Trim(prefix, "/")
if !strings.HasPrefix(req.URL.EscapedPath(), "/"+prefix+"/") {
if !strings.HasPrefix(req.URL.Path, "/"+prefix+"/") {
next.ServeHTTP(w, req)
return
}
rPath := strings.TrimPrefix(req.URL.EscapedPath(), "/"+prefix+"/")
rPath = strings.TrimPrefix(rPath, "/")
rPath := strings.TrimPrefix(req.URL.Path, "/"+prefix+"/")
rPath = path.Clean("/" + strings.ReplaceAll(rPath, "\\", "/"))[1:]
if rPath == "" {
http.Error(w, "file not found", 404)
return
}
rPath = path.Clean("/" + filepath.ToSlash(rPath))
rPath = rPath[1:]
fi, err := objStore.Stat(rPath)
if err == nil && httpcache.HandleTimeCache(req, w, fi) {
return
}
//If we have matched and access to release or issue
// If we have matched and access to release or issue
fr, err := objStore.Open(rPath)
if err != nil {
if os.IsNotExist(err) || errors.Is(err, os.ErrNotExist) {
@@ -121,7 +121,7 @@ func (d *dataStore) GetData() map[string]interface{} {
// Recovery returns a middleware that recovers from any panics and writes a 500 and a log if so.
// This error will be created with the gitea 500 page.
func Recovery() func(next http.Handler) http.Handler {
var rnd = templates.HTMLRenderer()
rnd := templates.HTMLRenderer()
return func(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
defer func() {
@@ -131,14 +131,14 @@ func Recovery() func(next http.Handler) http.Handler {
sessionStore := session.GetSession(req)
var lc = middleware.Locale(w, req)
var store = dataStore{
lc := middleware.Locale(w, req)
store := dataStore{
"Language": lc.Language(),
"CurrentURL": setting.AppSubURL + req.URL.RequestURI(),
"i18n": lc,
}
var user = context.GetContextUser(req)
user := context.GetContextUser(req)
if user == nil {
// Get user from session if logged in - do not attempt to sign-in
user = auth.SessionUser(sessionStore)

View File

@@ -298,6 +298,13 @@ func ParseCompareInfo(ctx *context.Context) *CompareInfo {
ci.BaseBranch = baseCommit.ID.String()
ctx.Data["BaseBranch"] = ci.BaseBranch
baseIsCommit = true
} else if ci.BaseBranch == git.EmptySHA {
if isSameRepo {
ctx.Redirect(ctx.Repo.RepoLink + "/compare/" + util.PathEscapeSegments(ci.HeadBranch))
} else {
ctx.Redirect(ctx.Repo.RepoLink + "/compare/" + util.PathEscapeSegments(ci.HeadRepo.FullName()) + ":" + util.PathEscapeSegments(ci.HeadBranch))
}
return nil
} else {
ctx.NotFound("IsRefExist", nil)
return nil

View File

@@ -223,7 +223,6 @@ func httpBase(ctx *context.Context) (h *serviceHandler) {
models.EnvRepoName + "=" + reponame,
models.EnvPusherName + "=" + ctx.User.Name,
models.EnvPusherID + fmt.Sprintf("=%d", ctx.User.ID),
models.EnvIsDeployKey + "=false",
models.EnvAppURL + "=" + setting.AppURL,
}

View File

@@ -843,12 +843,19 @@ func NewIssue(ctx *context.Context) {
func NewIssueChooseTemplate(ctx *context.Context) {
ctx.Data["Title"] = ctx.Tr("repo.issues.new")
ctx.Data["PageIsIssueList"] = true
ctx.Data["milestone"] = ctx.FormInt64("milestone")
issueTemplates := ctx.IssueTemplatesFromDefaultBranch()
ctx.Data["NewIssueChooseTemplate"] = len(issueTemplates) > 0
ctx.Data["IssueTemplates"] = issueTemplates
if len(issueTemplates) == 0 {
// The "issues/new" and "issues/new/choose" share the same query parameters "project" and "milestone", if no template here, just redirect to the "issues/new" page with these parameters.
ctx.Redirect(fmt.Sprintf("%s/issues/new?%s", ctx.Repo.Repository.HTMLURL(), ctx.Req.URL.RawQuery), http.StatusSeeOther)
return
}
ctx.Data["milestone"] = ctx.FormInt64("milestone")
ctx.Data["project"] = ctx.FormInt64("project")
ctx.HTML(http.StatusOK, tplIssueChoose)
}

View File

@@ -253,6 +253,13 @@ func LFSFileGet(ctx *context.Context) {
}
ctx.Data["LFSFilesLink"] = ctx.Repo.RepoLink + "/settings/lfs"
oid := ctx.Params("oid")
p := lfs.Pointer{Oid: oid}
if !p.IsValid() {
ctx.NotFound("LFSFileGet", nil)
return
}
ctx.Data["Title"] = oid
ctx.Data["PageIsSettingsLFS"] = true
meta, err := models.GetLFSMetaObjectByOid(ctx.Repo.Repository.ID, oid)
@@ -343,6 +350,12 @@ func LFSDelete(ctx *context.Context) {
return
}
oid := ctx.Params("oid")
p := lfs.Pointer{Oid: oid}
if !p.IsValid() {
ctx.NotFound("LFSDelete", nil)
return
}
count, err := models.RemoveLFSMetaObjectByOid(ctx.Repo.Repository.ID, oid)
if err != nil {
ctx.ServerError("LFSDelete", err)

View File

@@ -197,7 +197,7 @@ func Milestones(ctx *context.Context) {
if issueReposQueryPattern.MatchString(reposQuery) {
// remove "[" and "]" from string
reposQuery = reposQuery[1 : len(reposQuery)-1]
//for each ID (delimiter ",") add to int to repoIDs
// for each ID (delimiter ",") add to int to repoIDs
for _, rID := range strings.Split(reposQuery, ",") {
// Ensure nonempty string entries
@@ -350,7 +350,6 @@ func Issues(ctx *context.Context) {
var issueReposQueryPattern = regexp.MustCompile(`^\[\d+(,\d+)*,?\]$`)
func buildIssueOverview(ctx *context.Context, unitType unit.Type) {
// ----------------------------------------------------
// Determine user; can be either user or organization.
// Return with NotFound or ServerError if unsuccessful.
@@ -364,7 +363,7 @@ func buildIssueOverview(ctx *context.Context, unitType unit.Type) {
var (
viewType string
sortType = ctx.FormString("sort")
filterMode = models.FilterModeAll
filterMode int
)
// --------------------------------------------------------------------------------
@@ -390,8 +389,10 @@ func buildIssueOverview(ctx *context.Context, unitType unit.Type) {
filterMode = models.FilterModeMention
case "review_requested":
filterMode = models.FilterModeReviewRequested
case "your_repositories": // filterMode already set to All
case "your_repositories":
fallthrough
default:
filterMode = models.FilterModeYourRepositories
viewType = "your_repositories"
}
@@ -421,6 +422,30 @@ func buildIssueOverview(ctx *context.Context, unitType unit.Type) {
User: ctx.User,
}
// Search all repositories which
//
// As user:
// - Owns the repository.
// - Have collaborator permissions in repository.
//
// As org:
// - Owns the repository.
//
// As team:
// - Team org's owns the repository.
// - Team has read permission to repository.
repoOpts := &models.SearchRepoOptions{
Actor: ctx.User,
OwnerID: ctx.User.ID,
Private: true,
AllPublic: false,
AllLimited: false,
}
if ctxUser.IsOrganization() && ctx.Org.Team != nil {
repoOpts.TeamID = ctx.Org.Team.ID
}
switch filterMode {
case models.FilterModeAll:
case models.FilterModeAssign:
@@ -431,6 +456,19 @@ func buildIssueOverview(ctx *context.Context, unitType unit.Type) {
opts.MentionedID = ctx.User.ID
case models.FilterModeReviewRequested:
opts.ReviewRequestedID = ctx.User.ID
case models.FilterModeYourRepositories:
if ctxUser.IsOrganization() && ctx.Org.Team != nil {
// Fixes a issue whereby the user's ID would be used
// to check if it's in the team(which possible isn't the case).
opts.User = nil
}
userRepoIDs, _, err := models.SearchRepositoryIDs(repoOpts)
if err != nil {
ctx.ServerError("models.SearchRepositoryIDs: %v", err)
return
}
opts.RepoIDs = userRepoIDs
}
// keyword holds the search term entered into the search field.
@@ -562,8 +600,12 @@ func buildIssueOverview(ctx *context.Context, unitType unit.Type) {
Org: org,
Team: team,
}
if len(repoIDs) > 0 {
statsOpts.RepoIDs = repoIDs
if filterMode == models.FilterModeYourRepositories {
statsOpts.RepoCond = models.SearchRepositoryCondition(repoOpts)
}
// Detect when we only should search by team.
if opts.User == nil {
statsOpts.UserID = 0
}
issueStats, err = models.GetUserIssueStats(statsOpts)
if err != nil {
@@ -586,8 +628,7 @@ func buildIssueOverview(ctx *context.Context, unitType unit.Type) {
ctx.Data["IsShowClosed"] = isShowClosed
ctx.Data["IssueRefEndNames"], ctx.Data["IssueRefURLs"] =
issue_service.GetRefEndNamesAndURLs(issues, ctx.FormString("RepoLink"))
ctx.Data["IssueRefEndNames"], ctx.Data["IssueRefURLs"] = issue_service.GetRefEndNamesAndURLs(issues, ctx.FormString("RepoLink"))
ctx.Data["Issues"] = issues
@@ -661,7 +702,7 @@ func getRepoIDs(reposQuery string) []int64 {
var repoIDs []int64
// remove "[" and "]" from string
reposQuery = reposQuery[1 : len(reposQuery)-1]
//for each ID (delimiter ",") add to int to repoIDs
// for each ID (delimiter ",") add to int to repoIDs
for _, rID := range strings.Split(reposQuery, ",") {
// Ensure nonempty string entries
if rID != "" && rID != "0" {
@@ -693,8 +734,8 @@ func issueIDsFromSearch(ctxUser *user_model.User, keyword string, opts *models.I
}
func loadRepoByIDs(ctxUser *user_model.User, issueCountByRepo map[int64]int64, unitType unit.Type) (map[int64]*repo_model.Repository, error) {
var totalRes = make(map[int64]*repo_model.Repository, len(issueCountByRepo))
var repoIDs = make([]int64, 0, 500)
totalRes := make(map[int64]*repo_model.Repository, len(issueCountByRepo))
repoIDs := make([]int64, 0, 500)
for id := range issueCountByRepo {
if id <= 0 {
continue
@@ -745,7 +786,7 @@ func ShowGPGKeys(ctx *context.Context, uid int64) {
if err != nil {
if asymkey_model.IsErrGPGKeyImportNotExist(err) {
failedEntitiesID = append(failedEntitiesID, k.KeyID)
continue //Skip previous import without backup of imported armored key
continue // Skip previous import without backup of imported armored key
}
ctx.ServerError("ShowGPGKeys", err)
return
@@ -755,12 +796,12 @@ func ShowGPGKeys(ctx *context.Context, uid int64) {
var buf bytes.Buffer
headers := make(map[string]string)
if len(failedEntitiesID) > 0 { //If some key need re-import to be exported
if len(failedEntitiesID) > 0 { // If some key need re-import to be exported
headers["Note"] = fmt.Sprintf("The keys with the following IDs couldn't be exported and need to be reuploaded %s", strings.Join(failedEntitiesID, ", "))
}
writer, _ := armor.Encode(&buf, "PGP PUBLIC KEY BLOCK", headers)
for _, e := range entities {
err = e.Serialize(writer) //TODO find why key are exported with a different cipherTypeByte as original (should not be blocking but strange)
err = e.Serialize(writer) // TODO find why key are exported with a different cipherTypeByte as original (should not be blocking but strange)
if err != nil {
ctx.ServerError("ShowGPGKeys", err)
return

View File

@@ -188,7 +188,8 @@ func EmailPost(ctx *context.Context) {
ctx.RenderWithErr(ctx.Tr("form.email_been_used"), tplSettingsAccount, &form)
return
} else if user_model.IsErrEmailInvalid(err) {
} else if user_model.IsErrEmailCharIsNotSupported(err) ||
user_model.IsErrEmailInvalid(err) {
loadAccountData(ctx)
ctx.RenderWithErr(ctx.Tr("form.email_invalid"), tplSettingsAccount, &form)

View File

@@ -98,6 +98,11 @@ func Routes(sessioner func(http.Handler) http.Handler) *web.Route {
http.Redirect(w, req, path.Join(setting.StaticURLPrefix, "/assets/img/apple-touch-icon.png"), 301)
})
// redirect default favicon to the path of the custom favicon with a default as a fallback
routes.Get("/favicon.ico", func(w http.ResponseWriter, req *http.Request) {
http.Redirect(w, req, path.Join(setting.StaticURLPrefix, "/assets/img/favicon.png"), 301)
})
common := []interface{}{}
if setting.EnableGzip {

View File

@@ -715,7 +715,8 @@ func TestDiffToHTML_14231(t *testing.T) {
diffRecord := diffMatchPatch.DiffMain(highlight.Code("main.v", "", " run()\n"), highlight.Code("main.v", "", " run(db)\n"), true)
diffRecord = diffMatchPatch.DiffCleanupEfficiency(diffRecord)
expected := ` <span class="n">run</span><span class="added-code"><span class="o">(</span><span class="n">db</span></span><span class="o">)</span>`
expected := `<span class="line"><span class="cl"> <span class="n">run</span><span class="added-code"><span class="o">(</span><span class="n">db</span></span><span class="o">)</span>
</span></span>`
output := diffToHTML("main.v", diffRecord, DiffLineAdd)
assertEqual(t, expected, output.Content)

View File

@@ -77,8 +77,9 @@ func sendUserMail(language string, u *user_model.User, tpl base.TplName, code, s
"Code": code,
"Language": locale.Language(),
// helper
"i18n": locale,
"Str2html": templates.Str2html,
"i18n": locale,
"Str2html": templates.Str2html,
"DotEscape": templates.DotEscape,
}
var content bytes.Buffer
@@ -127,8 +128,9 @@ func SendActivateEmailMail(u *user_model.User, email *user_model.EmailAddress) {
"Email": email.Email,
"Language": locale.Language(),
// helper
"i18n": locale,
"Str2html": templates.Str2html,
"i18n": locale,
"Str2html": templates.Str2html,
"DotEscape": templates.DotEscape,
}
var content bytes.Buffer
@@ -146,8 +148,8 @@ func SendActivateEmailMail(u *user_model.User, email *user_model.EmailAddress) {
// SendRegisterNotifyMail triggers a notify e-mail by admin created a account.
func SendRegisterNotifyMail(u *user_model.User) {
if setting.MailService == nil {
// No mail service configured
if setting.MailService == nil || !u.IsActive {
// No mail service configured OR user is inactive
return
}
locale := translation.NewLocale(u.Language)
@@ -157,8 +159,9 @@ func SendRegisterNotifyMail(u *user_model.User) {
"Username": u.Name,
"Language": locale.Language(),
// helper
"i18n": locale,
"Str2html": templates.Str2html,
"i18n": locale,
"Str2html": templates.Str2html,
"DotEscape": templates.DotEscape,
}
var content bytes.Buffer
@@ -176,8 +179,8 @@ func SendRegisterNotifyMail(u *user_model.User) {
// SendCollaboratorMail sends mail notification to new collaborator.
func SendCollaboratorMail(u, doer *user_model.User, repo *repo_model.Repository) {
if setting.MailService == nil {
// No mail service configured
if setting.MailService == nil || !u.IsActive {
// No mail service configured OR the user is inactive
return
}
locale := translation.NewLocale(u.Language)
@@ -190,8 +193,9 @@ func SendCollaboratorMail(u, doer *user_model.User, repo *repo_model.Repository)
"Link": repo.HTMLURL(),
"Language": locale.Language(),
// helper
"i18n": locale,
"Str2html": templates.Str2html,
"i18n": locale,
"Str2html": templates.Str2html,
"DotEscape": templates.DotEscape,
}
var content bytes.Buffer
@@ -273,8 +277,9 @@ func composeIssueCommentMessages(ctx *mailCommentContext, lang string, recipient
"ReviewComments": reviewComments,
"Language": locale.Language(),
// helper
"i18n": locale,
"Str2html": templates.Str2html,
"i18n": locale,
"Str2html": templates.Str2html,
"DotEscape": templates.DotEscape,
}
var mailSubject bytes.Buffer
@@ -404,6 +409,10 @@ func SendIssueAssignedMail(issue *models.Issue, doer *user_model.User, content s
langMap := make(map[string][]*user_model.User)
for _, user := range recipients {
if !user.IsActive {
// don't send emails to inactive users
continue
}
langMap[user.Language] = append(langMap[user.Language], user)
}

View File

@@ -125,6 +125,10 @@ func mailIssueCommentBatch(ctx *mailCommentContext, users []*user_model.User, vi
langMap := make(map[string][]*user_model.User)
for _, user := range users {
if !user.IsActive {
// Exclude deactivated users
continue
}
// At this point we exclude:
// user that don't have all mails enabled or users only get mail on mention and this is one ...
if !(user.EmailNotificationsPreference == user_model.EmailNotificationsEnabled ||

View File

@@ -74,8 +74,9 @@ func mailNewRelease(lang string, tos []string, rel *models.Release) {
"Subject": subject,
"Language": locale.Language(),
// helper
"i18n": locale,
"Str2html": templates.Str2html,
"i18n": locale,
"Str2html": templates.Str2html,
"DotEscape": templates.DotEscape,
}
var mailBody bytes.Buffer

View File

@@ -31,6 +31,10 @@ func SendRepoTransferNotifyMail(doer, newOwner *user_model.User, repo *repo_mode
langMap := make(map[string][]string)
for _, user := range users {
if !user.IsActive {
// don't send emails to inactive users
continue
}
langMap[user.Language] = append(langMap[user.Language], user.Email)
}
@@ -69,8 +73,9 @@ func sendRepoTransferNotifyMailPerLang(lang string, newOwner, doer *user_model.U
"Language": locale.Language(),
"Destination": destination,
// helper
"i18n": locale,
"Str2html": templates.Str2html,
"i18n": locale,
"Str2html": templates.Str2html,
"DotEscape": templates.DotEscape,
}
if err := bodyTemplates.ExecuteTemplate(&content, string(mailRepoTransferNotify), data); err != nil {

View File

@@ -22,14 +22,13 @@ import (
"code.gitea.io/gitea/modules/log"
base "code.gitea.io/gitea/modules/migration"
"code.gitea.io/gitea/modules/repository"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/structs"
"gopkg.in/yaml.v2"
)
var (
_ base.Uploader = &RepositoryDumper{}
)
var _ base.Uploader = &RepositoryDumper{}
// RepositoryDumper implements an Uploader to the local directory
type RepositoryDumper struct {
@@ -151,9 +150,10 @@ func (g *RepositoryDumper) CreateRepo(repo *base.Repository, opts base.MigrateOp
}
err = git.Clone(remoteAddr, repoPath, git.CloneRepoOptions{
Mirror: true,
Quiet: true,
Timeout: migrateTimeout,
Mirror: true,
Quiet: true,
Timeout: migrateTimeout,
SkipTLSVerify: setting.Migrations.SkipTLSVerify,
})
if err != nil {
return fmt.Errorf("Clone: %v", err)
@@ -168,10 +168,11 @@ func (g *RepositoryDumper) CreateRepo(repo *base.Repository, opts base.MigrateOp
}
if err := git.Clone(wikiRemotePath, wikiPath, git.CloneRepoOptions{
Mirror: true,
Quiet: true,
Timeout: migrateTimeout,
Branch: "master",
Mirror: true,
Quiet: true,
Timeout: migrateTimeout,
Branch: "master",
SkipTLSVerify: setting.Migrations.SkipTLSVerify,
}); err != nil {
log.Warn("Clone wiki: %v", err)
if err := os.RemoveAll(wikiPath); err != nil {
@@ -403,7 +404,7 @@ func (g *RepositoryDumper) createItems(dir string, itemFiles map[int64]*os.File,
// CreateComments creates comments of issues
func (g *RepositoryDumper) CreateComments(comments ...*base.Comment) error {
var commentsMap = make(map[int64][]interface{}, len(comments))
commentsMap := make(map[int64][]interface{}, len(comments))
for _, comment := range comments {
commentsMap[comment.IssueIndex] = append(commentsMap[comment.IssueIndex], comment)
}
@@ -532,7 +533,7 @@ func (g *RepositoryDumper) CreatePullRequests(prs ...*base.PullRequest) error {
// CreateReviews create pull request reviews
func (g *RepositoryDumper) CreateReviews(reviews ...*base.Review) error {
var reviewsMap = make(map[int64][]interface{}, len(reviews))
reviewsMap := make(map[int64][]interface{}, len(reviews))
for _, review := range reviews {
reviewsMap[review.IssueIndex] = append(reviewsMap[review.IssueIndex], review)
}
@@ -611,7 +612,7 @@ func RestoreRepository(ctx context.Context, baseDir, ownerName, repoName string,
if err != nil {
return err
}
var uploader = NewGiteaLocalUploader(ctx, doer, ownerName, repoName)
uploader := NewGiteaLocalUploader(ctx, doer, ownerName, repoName)
downloader, err := NewRepositoryRestorer(ctx, baseDir, ownerName, repoName)
if err != nil {
return err
@@ -622,7 +623,7 @@ func RestoreRepository(ctx context.Context, baseDir, ownerName, repoName string,
}
tp, _ := strconv.Atoi(opts["service_type"])
var migrateOpts = base.MigrateOptions{
migrateOpts := base.MigrateOptions{
GitServiceType: structs.GitServiceType(tp),
}
updateOptionsUnits(&migrateOpts, units)

View File

@@ -29,19 +29,23 @@ const (
// SyncRequest for the mirror queue
type SyncRequest struct {
Type SyncType
RepoID int64
Type SyncType
ReferenceID int64 // RepoID for pull mirror, MirrorID fro push mirror
}
// doMirrorSync causes this request to mirror itself
func doMirrorSync(ctx context.Context, req *SyncRequest) {
if req.ReferenceID == 0 {
log.Warn("Skipping mirror sync request, no reference ID was specified")
return
}
switch req.Type {
case PushMirrorType:
_ = SyncPushMirror(ctx, req.RepoID)
_ = SyncPushMirror(ctx, req.ReferenceID)
case PullMirrorType:
_ = SyncPullMirror(ctx, req.RepoID)
_ = SyncPullMirror(ctx, req.ReferenceID)
default:
log.Error("Unknown Request type in queue: %v for RepoID[%d]", req.Type, req.RepoID)
log.Error("Unknown Request type in queue: %v for ReferenceID[%d]", req.Type, req.ReferenceID)
}
}
@@ -67,8 +71,8 @@ func Update(ctx context.Context, pullLimit, pushLimit int) error {
}
repo = m.Repo
item = SyncRequest{
Type: PullMirrorType,
RepoID: m.RepoID,
Type: PullMirrorType,
ReferenceID: m.RepoID,
}
} else if m, ok := bean.(*repo_model.PushMirror); ok {
if m.Repo == nil {
@@ -77,8 +81,8 @@ func Update(ctx context.Context, pullLimit, pushLimit int) error {
}
repo = m.Repo
item = SyncRequest{
Type: PushMirrorType,
RepoID: m.RepoID,
Type: PushMirrorType,
ReferenceID: m.ID,
}
} else {
log.Error("Unknown bean: %v", bean)
@@ -162,8 +166,8 @@ func StartToMirror(repoID int64) {
}
go func() {
err := mirrorQueue.Push(&SyncRequest{
Type: PullMirrorType,
RepoID: repoID,
Type: PullMirrorType,
ReferenceID: repoID,
})
if err != nil {
log.Error("Unable to push sync request for to the queue for push mirror repo[%d]: Error: %v", repoID, err)
@@ -178,8 +182,8 @@ func AddPushMirrorToQueue(mirrorID int64) {
}
go func() {
err := mirrorQueue.Push(&SyncRequest{
Type: PushMirrorType,
RepoID: mirrorID,
Type: PushMirrorType,
ReferenceID: mirrorID,
})
if err != nil {
log.Error("Unable to push sync request to the queue for pull mirror repo[%d]: Error: %v", mirrorID, err)

View File

@@ -196,7 +196,7 @@ func runSync(ctx context.Context, m *repo_model.Mirror) ([]*mirrorSyncResult, bo
remoteAddr, remoteErr := git.GetRemoteAddress(ctx, repoPath, m.GetRemoteName())
if remoteErr != nil {
log.Error("GetRemoteAddress Error %v", remoteErr)
log.Error("SyncMirrors [repo: %-v]: GetRemoteAddress Error %v", m.Repo, remoteErr)
}
stdoutBuilder := strings.Builder{}
@@ -215,7 +215,7 @@ func runSync(ctx context.Context, m *repo_model.Mirror) ([]*mirrorSyncResult, bo
// Now check if the error is a resolve reference due to broken reference
if strings.Contains(stderr, "unable to resolve reference") && strings.Contains(stderr, "reference broken") {
log.Warn("Failed to update mirror repository %-v due to broken references:\nStdout: %s\nStderr: %s\nErr: %v\nAttempting Prune", m.Repo, stdoutMessage, stderrMessage, err)
log.Warn("SyncMirrors [repo: %-v]: failed to update mirror repository due to broken references:\nStdout: %s\nStderr: %s\nErr: %v\nAttempting Prune", m.Repo, stdoutMessage, stderrMessage, err)
err = nil
// Attempt prune
@@ -240,7 +240,7 @@ func runSync(ctx context.Context, m *repo_model.Mirror) ([]*mirrorSyncResult, bo
// If there is still an error (or there always was an error)
if err != nil {
log.Error("Failed to update mirror repository %-v:\nStdout: %s\nStderr: %s\nErr: %v", m.Repo, stdoutMessage, stderrMessage, err)
log.Error("SyncMirrors [repo: %-v]: failed to update mirror repository:\nStdout: %s\nStderr: %s\nErr: %v", m.Repo, stdoutMessage, stderrMessage, err)
desc := fmt.Sprintf("Failed to update mirror repository '%s': %s", repoPath, stderrMessage)
if err = admin_model.CreateRepositoryNotice(desc); err != nil {
log.Error("CreateRepositoryNotice: %v", err)
@@ -252,13 +252,13 @@ func runSync(ctx context.Context, m *repo_model.Mirror) ([]*mirrorSyncResult, bo
gitRepo, err := git.OpenRepository(repoPath)
if err != nil {
log.Error("OpenRepository: %v", err)
log.Error("SyncMirrors [repo: %-v]: failed to OpenRepository: %v", m.Repo, err)
return nil, false
}
log.Trace("SyncMirrors [repo: %-v]: syncing releases with tags...", m.Repo)
if err = repo_module.SyncReleasesWithTags(m.Repo, gitRepo); err != nil {
log.Error("Failed to synchronize tags to releases for repository: %v", err)
log.Error("SyncMirrors [repo: %-v]: failed to synchronize tags to releases: %v", m.Repo, err)
}
if m.LFS && setting.LFS.StartServer {
@@ -266,14 +266,14 @@ func runSync(ctx context.Context, m *repo_model.Mirror) ([]*mirrorSyncResult, bo
endpoint := lfs.DetermineEndpoint(remoteAddr.String(), m.LFSEndpoint)
lfsClient := lfs.NewClient(endpoint, nil)
if err = repo_module.StoreMissingLfsObjectsInRepository(ctx, m.Repo, gitRepo, lfsClient); err != nil {
log.Error("Failed to synchronize LFS objects for repository: %v", err)
log.Error("SyncMirrors [repo: %-v]: failed to synchronize LFS objects for repository: %v", m.Repo, err)
}
}
gitRepo.Close()
log.Trace("SyncMirrors [repo: %-v]: updating size of repository", m.Repo)
if err := models.UpdateRepoSize(db.DefaultContext, m.Repo); err != nil {
log.Error("Failed to update size for mirror repository: %v", err)
log.Error("SyncMirrors [repo: %-v]: failed to update size for mirror repository: %v", m.Repo, err)
}
if m.Repo.HasWiki() {
@@ -291,7 +291,7 @@ func runSync(ctx context.Context, m *repo_model.Mirror) ([]*mirrorSyncResult, bo
remoteAddr, remoteErr := git.GetRemoteAddress(ctx, wikiPath, m.GetRemoteName())
if remoteErr != nil {
log.Error("GetRemoteAddress Error %v", remoteErr)
log.Error("SyncMirrors [repo: %-v Wiki]: unable to get GetRemoteAddress Error %v", m.Repo, remoteErr)
}
// sanitize the output, since it may contain the remote address, which may
@@ -302,7 +302,7 @@ func runSync(ctx context.Context, m *repo_model.Mirror) ([]*mirrorSyncResult, bo
// Now check if the error is a resolve reference due to broken reference
if strings.Contains(stderrMessage, "unable to resolve reference") && strings.Contains(stderrMessage, "reference broken") {
log.Warn("Failed to update mirror wiki repository %-v due to broken references:\nStdout: %s\nStderr: %s\nErr: %v\nAttempting Prune", m.Repo, stdoutMessage, stderrMessage, err)
log.Warn("SyncMirrors [repo: %-v Wiki]: failed to update mirror wiki repository due to broken references:\nStdout: %s\nStderr: %s\nErr: %v\nAttempting Prune", m.Repo, stdoutMessage, stderrMessage, err)
err = nil
// Attempt prune
@@ -325,7 +325,7 @@ func runSync(ctx context.Context, m *repo_model.Mirror) ([]*mirrorSyncResult, bo
// If there is still an error (or there always was an error)
if err != nil {
log.Error("Failed to update mirror repository wiki %-v:\nStdout: %s\nStderr: %s\nErr: %v", m.Repo, stdoutMessage, stderrMessage, err)
log.Error("SyncMirrors [repo: %-v Wiki]: failed to update mirror repository wiki:\nStdout: %s\nStderr: %s\nErr: %v", m.Repo, stdoutMessage, stderrMessage, err)
desc := fmt.Sprintf("Failed to update mirror repository wiki '%s': %s", wikiPath, stderrMessage)
if err = admin_model.CreateRepositoryNotice(desc); err != nil {
log.Error("CreateRepositoryNotice: %v", err)
@@ -339,7 +339,7 @@ func runSync(ctx context.Context, m *repo_model.Mirror) ([]*mirrorSyncResult, bo
log.Trace("SyncMirrors [repo: %-v]: invalidating mirror branch caches...", m.Repo)
branches, _, err := git.GetBranchesByPath(m.Repo.RepoPath(), 0, 0)
if err != nil {
log.Error("GetBranches: %v", err)
log.Error("SyncMirrors [repo: %-v]: failed to GetBranches: %v", m.Repo, err)
return nil, false
}
@@ -360,12 +360,12 @@ func SyncPullMirror(ctx context.Context, repoID int64) bool {
return
}
// There was a panic whilst syncMirrors...
log.Error("PANIC whilst syncMirrors[%d] Panic: %v\nStacktrace: %s", repoID, err, log.Stack(2))
log.Error("PANIC whilst SyncMirrors[repo_id: %d] Panic: %v\nStacktrace: %s", repoID, err, log.Stack(2))
}()
m, err := repo_model.GetMirrorByRepoID(repoID)
if err != nil {
log.Error("GetMirrorByRepoID [%d]: %v", repoID, err)
log.Error("SyncMirrors [repo_id: %v]: unable to GetMirrorByRepoID: %v", repoID, err)
return false
}
@@ -381,7 +381,7 @@ func SyncPullMirror(ctx context.Context, repoID int64) bool {
log.Trace("SyncMirrors [repo: %-v]: Scheduling next update", m.Repo)
m.ScheduleNextUpdate()
if err = repo_model.UpdateMirror(m); err != nil {
log.Error("UpdateMirror [%d]: %v", m.RepoID, err)
log.Error("SyncMirrors [repo: %-v]: failed to UpdateMirror with next update date: %v", m.Repo, err)
return false
}
@@ -392,7 +392,7 @@ func SyncPullMirror(ctx context.Context, repoID int64) bool {
log.Trace("SyncMirrors [repo: %-v]: %d branches updated", m.Repo, len(results))
gitRepo, err = git.OpenRepositoryCtx(ctx, m.Repo.RepoPath())
if err != nil {
log.Error("OpenRepository [%d]: %v", m.RepoID, err)
log.Error("SyncMirrors [repo: %-v]: unable to OpenRepository: %v", m.Repo, err)
return false
}
defer gitRepo.Close()
@@ -419,7 +419,7 @@ func SyncPullMirror(ctx context.Context, repoID int64) bool {
}
commitID, err := gitRepo.GetRefCommitID(result.refName)
if err != nil {
log.Error("gitRepo.GetRefCommitID [repo_id: %d, ref_name: %s]: %v", m.RepoID, result.refName, err)
log.Error("SyncMirrors [repo: %-v]: unable to GetRefCommitID [ref_name: %s]: %v", m.Repo, result.refName, err)
continue
}
notification.NotifySyncPushCommits(m.Repo.MustOwner(), m.Repo, &repo_module.PushUpdateOptions{
@@ -440,17 +440,17 @@ func SyncPullMirror(ctx context.Context, repoID int64) bool {
// Push commits
oldCommitID, err := git.GetFullCommitID(gitRepo.Path, result.oldCommitID)
if err != nil {
log.Error("GetFullCommitID [%d]: %v", m.RepoID, err)
log.Error("SyncMirrors [repo: %-v]: unable to get GetFullCommitID[%s]: %v", m.Repo, result.oldCommitID, err)
continue
}
newCommitID, err := git.GetFullCommitID(gitRepo.Path, result.newCommitID)
if err != nil {
log.Error("GetFullCommitID [%d]: %v", m.RepoID, err)
log.Error("SyncMirrors [repo: %-v]: unable to get GetFullCommitID [%s]: %v", m.Repo, result.newCommitID, err)
continue
}
commits, err := gitRepo.CommitsBetweenIDs(newCommitID, oldCommitID)
if err != nil {
log.Error("CommitsBetweenIDs [repo_id: %d, new_commit_id: %s, old_commit_id: %s]: %v", m.RepoID, newCommitID, oldCommitID, err)
log.Error("SyncMirrors [repo: %-v]: unable to get CommitsBetweenIDs [new_commit_id: %s, old_commit_id: %s]: %v", m.Repo, newCommitID, oldCommitID, err)
continue
}
@@ -472,12 +472,12 @@ func SyncPullMirror(ctx context.Context, repoID int64) bool {
// Get latest commit date and update to current repository updated time
commitDate, err := git.GetLatestCommitTime(m.Repo.RepoPath())
if err != nil {
log.Error("GetLatestCommitDate [%d]: %v", m.RepoID, err)
log.Error("SyncMirrors [repo: %-v]: unable to GetLatestCommitDate: %v", m.Repo, err)
return false
}
if err = repo_model.UpdateRepositoryUpdatedTime(m.RepoID, commitDate); err != nil {
log.Error("Update repository 'updated_unix' [%d]: %v", m.RepoID, err)
log.Error("SyncMirrors [repo: %-v]: unable to update repository 'updated_unix': %v", m.Repo, err)
return false
}

View File

@@ -335,6 +335,13 @@ func ListUnadoptedRepositories(query string, opts *db.ListOptions) ([]string, in
}
repoNamesToCheck = append(repoNamesToCheck, name)
if len(repoNamesToCheck) > setting.Database.IterateBufferSize {
if err = checkUnadoptedRepositories(userName, repoNamesToCheck, unadopted); err != nil {
return err
}
repoNamesToCheck = repoNamesToCheck[:0]
}
return filepath.SkipDir
}); err != nil {
return nil, 0, err

View File

@@ -216,7 +216,34 @@ func pushUpdates(optsList []*repo_module.PushUpdateOptions) error {
if len(commits.Commits) > setting.UI.FeedMaxCommitNum {
commits.Commits = commits.Commits[:setting.UI.FeedMaxCommitNum]
}
commits.CompareURL = repo.ComposeCompareURL(opts.OldCommitID, opts.NewCommitID)
oldCommitID := opts.OldCommitID
if oldCommitID == git.EmptySHA && len(commits.Commits) > 0 {
oldCommit, err := gitRepo.GetCommit(commits.Commits[len(commits.Commits)-1].Sha1)
if err != nil && !git.IsErrNotExist(err) {
log.Error("unable to GetCommit %s from %-v: %v", oldCommitID, repo, err)
}
if oldCommit != nil {
for i := 0; i < oldCommit.ParentCount(); i++ {
commitID, _ := oldCommit.ParentID(i)
if !commitID.IsZero() {
oldCommitID = commitID.String()
break
}
}
}
}
if oldCommitID == git.EmptySHA && repo.DefaultBranch != branch {
oldCommitID = repo.DefaultBranch
}
if oldCommitID != git.EmptySHA {
commits.CompareURL = repo.ComposeCompareURL(oldCommitID, opts.NewCommitID)
} else {
commits.CompareURL = ""
}
notification.NotifyPushCommits(pusher, repo, opts, commits)
if err = models.RemoveDeletedBranchByName(repo.ID, branch); err != nil {

View File

@@ -14,7 +14,7 @@
<div class="inline required field {{if .Err_Type}}error{{end}}">
<label>{{.i18n.Tr "admin.auths.auth_type"}}</label>
<div class="ui selection type dropdown">
<input type="hidden" id="auth_type" name="type" value="{{.type.Int}}">
<input type="hidden" id="auth_type" name="type" value="{{.type}}">
<div class="text">{{.CurrentTypeName}}</div>
{{svg "octicon-triangle-down" 14 "dropdown icon"}}
<div class="menu">

View File

@@ -2,8 +2,8 @@
<div class="inline required field">
<label>{{.i18n.Tr "admin.auths.oauth2_provider"}}</label>
<div class="ui selection type dropdown">
<input type="hidden" id="oauth2_provider" name="oauth2_provider" value="{{.oauth2_provider.Name}}">
<div class="text">{{.oauth2_provider.Name}}</div>
<input type="hidden" id="oauth2_provider" name="oauth2_provider" value="{{.oauth2_provider}}">
<div class="text">{{.oauth2_provider}}</div>
{{svg "octicon-triangle-down" 14 "dropdown icon"}}
<div class="menu">
{{range .OAuth2Providers}}

View File

@@ -5,7 +5,7 @@
{{template "base/alert" .}}
{{if .NeedUpdate}}
<div class="ui negative message flash-error">
<p>{{.i18n.Tr "admin.dashboard.new_version_hint" (.RemoteVersion | Str2html) (AppVer | Str2html)}}</p>
<p>{{(.i18n.Tr "admin.dashboard.new_version_hint" .RemoteVersion AppVer) | Str2html}}</p>
</div>
{{end}}
<h4 class="ui top attached header">

View File

@@ -2,12 +2,13 @@
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>{{.i18n.Tr "mail.activate_account.title" .DisplayName}}</title>
<meta name="format-detection" content="telephone=no,date=no,address=no,email=no,url=no"/>
<title>{{.i18n.Tr "mail.activate_account.title" (.DisplayName|DotEscape)}}</title>
</head>
{{ $activate_url := printf "%suser/activate?code=%s" AppUrl (QueryEscape .Code)}}
<body>
<p>{{.i18n.Tr "mail.activate_account.text_1" .DisplayName AppName | Str2html}}</p><br>
<p>{{.i18n.Tr "mail.activate_account.text_1" (.DisplayName|DotEscape) AppName | Str2html}}</p><br>
<p>{{.i18n.Tr "mail.activate_account.text_2" .ActiveCodeLives | Str2html}}</p><p><a href="{{$activate_url}}">{{$activate_url}}</a></p><br>
<p>{{.i18n.Tr "mail.link_not_working_do_paste"}}</p>

View File

@@ -2,12 +2,13 @@
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>{{.i18n.Tr "mail.activate_email.title" .DisplayName}}</title>
<meta name="format-detection" content="telephone=no,date=no,address=no,email=no,url=no"/>
<title>{{.i18n.Tr "mail.activate_email.title" (.DisplayName|DotEscape)}}</title>
</head>
{{ $activate_url := printf "%suser/activate_email?code=%s&email=%s" AppUrl (QueryEscape .Code) (QueryEscape .Email)}}
<body>
<p>{{.i18n.Tr "mail.hi_user_x" .DisplayName | Str2html}}</p><br>
<p>{{.i18n.Tr "mail.hi_user_x" (.DisplayName|DotEscape) | Str2html}}</p><br>
<p>{{.i18n.Tr "mail.activate_email.text" .ActiveCodeLives | Str2html}}</p><p><a href="{{$activate_url}}">{{$activate_url}}</a></p><br>
<p>{{.i18n.Tr "mail.link_not_working_do_paste"}}</p>

View File

@@ -2,12 +2,13 @@
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>{{.i18n.Tr "mail.register_notify.title" .DisplayName AppName}}</title>
<meta name="format-detection" content="telephone=no,date=no,address=no,email=no,url=no"/>
<title>{{.i18n.Tr "mail.register_notify.title" (.DisplayName|DotEscape) AppName}}</title>
</head>
{{$set_pwd_url := printf "%[1]suser/forgot_password" AppUrl}}
<body>
<p>{{.i18n.Tr "mail.hi_user_x" .DisplayName | Str2html}}</p><br>
<p>{{.i18n.Tr "mail.hi_user_x" (.DisplayName|DotEscape) | Str2html}}</p><br>
<p>{{.i18n.Tr "mail.register_notify.text_1" AppName}}</p><br>
<p>{{.i18n.Tr "mail.register_notify.text_2" .Username}}</p><p><a href="{{AppUrl}}user/login">{{AppUrl}}user/login</a></p><br>
<p>{{.i18n.Tr "mail.register_notify.text_3" ($set_pwd_url | Escape) | Str2html}}</p><br>

View File

@@ -2,12 +2,13 @@
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>{{.i18n.Tr "mail.reset_password.title" .DisplayName}}</title>
<meta name="format-detection" content="telephone=no,date=no,address=no,email=no,url=no"/>
<title>{{.i18n.Tr "mail.reset_password.title" (.DisplayName|DotEscape)}}</title>
</head>
{{ $recover_url := printf "%suser/recover_account?code=%s" AppUrl (QueryEscape .Code)}}
<body>
<p>{{.i18n.Tr "mail.hi_user_x" .DisplayName | Str2html}}</p><br>
<p>{{.i18n.Tr "mail.hi_user_x" (.DisplayName|DotEscape) | Str2html}}</p><br>
<p>{{.i18n.Tr "mail.reset_password.text" .ResetPwdCodeLives | Str2html}}</p><p><a href="{{$recover_url}}">{{$recover_url}}</a></p><br>
<p>{{.i18n.Tr "mail.link_not_working_do_paste"}}</p>

View File

@@ -19,17 +19,24 @@
</button>
{{end}}
{{if not (and $.DisableHTTP $.DisableSSH)}}
<script defer>
const isSSH = localStorage.getItem('repo-clone-protocol') === 'ssh';
const sshButton = document.getElementById('repo-clone-ssh');
const httpsButton = document.getElementById('repo-clone-https');
const input = document.getElementById('repo-clone-url');
if (input) input.value = (isSSH ? sshButton : httpsButton).getAttribute('data-link');
if (sshButton) sshButton.classList[isSSH ? 'add' : 'remove']('primary');
if (httpsButton) httpsButton.classList[isSSH ? 'remove' : 'add']('primary');
setTimeout(() => {
if (sshButton) sshButton.classList.remove('no-transition');
if (httpsButton) httpsButton.classList.remove('no-transition');
}, 100);
<script>
<!-- /* eslint-disable */ -->
window.config.pageData['repoCloneButtons']= {httpsDisabled: {{$.DisableHTTP}}};
</script>
<script>
(() => {
const tmplData = window.config.pageData.repoCloneButtons;
const isSSH = tmplData.httpsDisabled || localStorage.getItem('repo-clone-protocol') === 'ssh';
const sshButton = document.getElementById('repo-clone-ssh');
const httpsButton = document.getElementById('repo-clone-https');
const input = document.getElementById('repo-clone-url');
if (input) input.value = (isSSH ? sshButton : httpsButton).getAttribute('data-link');
if (sshButton) sshButton.classList[isSSH ? 'add' : 'remove']('primary');
if (httpsButton) httpsButton.classList[isSSH ? 'remove' : 'add']('primary');
setTimeout(() => {
if (sshButton) sshButton.classList.remove('no-transition');
if (httpsButton) httpsButton.classList.remove('no-transition');
}, 100);
})();
</script>
{{end}}

View File

@@ -14,7 +14,7 @@
<br/>{{.About | RenderEmojiPlain}}
</div>
<div class="column right aligned">
<a href="{{$.RepoLink}}/issues/new?template={{.FileName}}{{if $.milestone}}&milestone={{$.milestone}}{{end}}" class="ui green button">{{$.i18n.Tr "repo.issues.choose.get_started"}}</a>
<a href="{{$.RepoLink}}/issues/new?template={{.FileName}}{{if $.milestone}}&milestone={{$.milestone}}{{end}}{{if $.project}}&project={{$.project}}{{end}}" class="ui green button">{{$.i18n.Tr "repo.issues.choose.get_started"}}</a>
</div>
</div>
</div>
@@ -26,7 +26,7 @@
<br/>{{.i18n.Tr "repo.issues.choose.blank_about"}}
</div>
<div class="column right aligned">
<a href="{{.RepoLink}}/issues/new{{if .milestone}}?milestone={{.milestone}}{{end}}" class="ui green button">{{$.i18n.Tr "repo.issues.choose.get_started"}}</a>
<a href="{{.RepoLink}}/issues/new?{{if .milestone}}&milestone={{.milestone}}{{end}}{{if $.project}}&project={{$.project}}{{end}}" class="ui green button">{{$.i18n.Tr "repo.issues.choose.get_started"}}</a>
</div>
</div>
</div>

View File

@@ -8,7 +8,7 @@
</div>
<div class="column right aligned">
{{if and .CanWriteProjects (not .Repository.IsArchived)}}
<a class="ui green button show-modal item" href="{{$.RepoLink}}/issues/new?project={{$.Project.ID}}">{{.i18n.Tr "repo.issues.new"}}</a>
<a class="ui green button show-modal item" href="{{$.RepoLink}}/issues/new/choose?project={{$.Project.ID}}">{{.i18n.Tr "repo.issues.new"}}</a>
<a class="ui green button show-modal item" data-modal="#new-board-item">{{.i18n.Tr "new_project_board"}}</a>
{{end}}
<div class="ui small modal new-board-modal" id="new-board-item">

View File

@@ -125,7 +125,7 @@
<div class="column">
{{if $.Permission.CanRead $.UnitTypeIssues}}
<div class="ui link list">
<a class="item ref-in-new-issue" href="{{.RepoLink}}/issues/new?body={{.Repository.HTMLURL}}{{printf "/src/commit/" }}{{PathEscape .CommitID}}/{{PathEscapeSegments .TreePath}}">{{.i18n.Tr "repo.issues.context.reference_issue"}}</a>
<a class="item ref-in-new-issue" href="{{.RepoLink}}/issues/new?body={{.Repository.HTMLURL}}{{printf "/src/commit/" }}{{PathEscape .CommitID}}/{{PathEscapeSegments .TreePath}}" rel="nofollow noindex">{{.i18n.Tr "repo.issues.context.reference_issue"}}</a>
</div>
{{end}}
<div class="ui link list">

View File

@@ -32,6 +32,8 @@
<p>{{.i18n.Tr "auth.confirmation_mail_sent_prompt" (.Email|Escape) .ActiveCodeLives | Str2html}}</p>
{{else if .IsActivateFailed}}
<p>{{.i18n.Tr "auth.invalid_code"}}</p>
{{else if .ManualActivationOnly}}
<p class="center">{{.i18n.Tr "auth.disable_register_mail"}}</p>
{{else}}
<p>{{.i18n.Tr "auth.has_unconfirmed_mail" (.SignedUser.Name|Escape) (.SignedUser.Email|Escape) | Str2html}}</p>
<div class="ui divider"></div>

View File

@@ -461,7 +461,8 @@ export function initRepoPullRequestReview() {
(async () => {
// the editor's height is too large in some cases, and the panel cannot be scrolled with page now because there is `.repository .diff-detail-box.sticky { position: sticky; }`
// the temporary solution is to make the editor's height smaller (about 4 lines). GitHub also only show 4 lines for default. We can improve the UI (including Dropzone area) in future
await createCommentEasyMDE($reviewBox.find('textarea'), {minHeight: '80px', maxHeight: 'calc(100vh - 360px)'});
// EasyMDE's options can not handle minHeight & maxHeight together correctly, we have to set max-height for .CodeMirror-scroll in CSS.
await createCommentEasyMDE($reviewBox.find('textarea'), {minHeight: '80px'});
initCompImagePaste($reviewBox);
})();
}

View File

@@ -197,6 +197,13 @@ a.blob-excerpt:hover {
color: #fff;
}
// See the comment of createCommentEasyMDE() for the review editor
// EasyMDE's options can not handle minHeight & maxHeight together correctly, we have to set minHeight in JS code
#review-box .CodeMirror-scroll {
min-height: 80px;
max-height: calc(100vh - 360px);
}
@media @mediaSm {
#review-box > .menu {
> .ui.segment {