mirror of
https://github.com/gogs/gogs.git
synced 2026-02-28 09:10:57 +01:00
Compare commits
21 Commits
v0.12.4-rc
...
v0.12.7-rc
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d06ba7e527 | ||
|
|
b0a902dcca | ||
|
|
bc77440b30 | ||
|
|
2a8f561c64 | ||
|
|
8a046c22a8 | ||
|
|
26395294bd | ||
|
|
c91365774b | ||
|
|
dff067ac28 | ||
|
|
45fdfecf64 | ||
|
|
1bf5d89386 | ||
|
|
670cbccf98 | ||
|
|
4e10265568 | ||
|
|
640e2f62e0 | ||
|
|
eddae31ada | ||
|
|
0fef3c9082 | ||
|
|
5aca56d2dd | ||
|
|
e309bc8324 | ||
|
|
64102be2c9 | ||
|
|
91f2cde5e9 | ||
|
|
b3541030c3 | ||
|
|
bc8b8c3767 |
20
.github/workflows/go.yml
vendored
20
.github/workflows/go.yml
vendored
@@ -30,12 +30,30 @@ jobs:
|
||||
with:
|
||||
version: latest
|
||||
args: --timeout=30m
|
||||
- name: Install Task
|
||||
uses: arduino/setup-task@v1
|
||||
- name: Install go-bindata
|
||||
shell: bash
|
||||
run: |
|
||||
curl --silent --location --output /usr/local/bin/go-bindata https://github.com/kevinburke/go-bindata/releases/download/v3.23.0/go-bindata-linux-amd64
|
||||
chmod +x /usr/local/bin/go-bindata
|
||||
- name: Check Go module tidiness
|
||||
shell: bash
|
||||
run: |
|
||||
go mod tidy
|
||||
STATUS=$(git status --porcelain)
|
||||
if [ ! -z "$STATUS" ]; then
|
||||
echo "Unstaged files:"
|
||||
echo $STATUS
|
||||
echo "Run 'go mod tidy' and commit them"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
test:
|
||||
name: Test
|
||||
strategy:
|
||||
matrix:
|
||||
go-version: [ 1.14.x, 1.15.x, 1.16.x, 1.17.x ]
|
||||
go-version: [ 1.14.x, 1.15.x, 1.16.x, 1.17.x, 1.18.x ]
|
||||
platform: [ ubuntu-latest, macos-latest, windows-latest ]
|
||||
runs-on: ${{ matrix.platform }}
|
||||
steps:
|
||||
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -16,3 +16,4 @@ output*
|
||||
*.sublime-project
|
||||
*.sublime-workspace
|
||||
/release
|
||||
.task
|
||||
|
||||
@@ -1,4 +1,9 @@
|
||||
linters-settings:
|
||||
staticcheck:
|
||||
checks: [
|
||||
"all",
|
||||
"-SA1019" # There are valid use cases of strings.Title
|
||||
]
|
||||
nakedret:
|
||||
max-func-lines: 0 # Disallow any unnamed return statement
|
||||
|
||||
|
||||
91
Taskfile.yml
Normal file
91
Taskfile.yml
Normal file
@@ -0,0 +1,91 @@
|
||||
version: '3'
|
||||
|
||||
vars:
|
||||
BINARY_EXT:
|
||||
sh: echo '{{if eq OS "windows"}}.exe{{end}}'
|
||||
|
||||
tasks:
|
||||
web:
|
||||
desc: Build the binary and start the web server.
|
||||
deps: [build]
|
||||
cmds:
|
||||
- ./gogs web
|
||||
|
||||
build:
|
||||
desc: Build the binary.
|
||||
cmds:
|
||||
- go build -v
|
||||
-ldflags '
|
||||
-X "{{.PKG_PATH}}.BuildTime={{.BUILD_TIME}}"
|
||||
-X "{{.PKG_PATH}}.BuildCommit={{.BUILD_COMMIT}}"
|
||||
'
|
||||
-tags '{{.TAGS}}'
|
||||
-trimpath -o gogs{{.BINARY_EXT}}
|
||||
vars:
|
||||
PKG_PATH: gogs.io/gogs/internal/conf
|
||||
BUILD_TIME:
|
||||
sh: date -u '+%Y-%m-%d %I:%M:%S %Z'
|
||||
BUILD_COMMIT:
|
||||
sh: git rev-parse HEAD
|
||||
sources:
|
||||
- gogs.go
|
||||
- internal/**/*.go
|
||||
|
||||
generate-bindata:
|
||||
desc: Generate bindata for all assets.
|
||||
deps: [clean]
|
||||
cmds:
|
||||
- go generate internal/assets/conf/conf.go
|
||||
- go generate internal/assets/templates/templates.go
|
||||
- go generate internal/assets/public/public.go
|
||||
|
||||
generate-schemadoc:
|
||||
desc: Generate database schema documentation.
|
||||
cmds:
|
||||
- go generate ./internal/db/schemadoc
|
||||
|
||||
generate:
|
||||
desc: Run all go:generate commands.
|
||||
deps: [generate-bindata, generate-schemadoc]
|
||||
|
||||
test:
|
||||
desc: Run all tests.
|
||||
cmds:
|
||||
- go test -cover -race ./...
|
||||
|
||||
clean:
|
||||
desc: Cleans up system meta files for code generation.
|
||||
cmds:
|
||||
- find . -name "*.DS_Store" -type f -delete
|
||||
|
||||
release:
|
||||
desc: Build the binary and pack resources to a ZIP file.
|
||||
deps: [build]
|
||||
cmds:
|
||||
- rm -rf {{.RELEASE_GOGS}}
|
||||
- mkdir -p {{.RELEASE_GOGS}}
|
||||
- cp -r gogs{{.BINARY_EXT}} LICENSE README.md README_ZH.md scripts {{.RELEASE_GOGS}}
|
||||
- cd {{.RELEASE_ROOT}} && zip -r gogs.$(NOW).zip "gogs"
|
||||
vars:
|
||||
RELEASE_ROOT: release
|
||||
RELEASE_GOGS: release/gogs
|
||||
|
||||
less:
|
||||
desc: Generate CSS from LESS files.
|
||||
cmds:
|
||||
- lessc --clean-css --source-map "public/less/gogs.less" public/css/gogs.min.css
|
||||
|
||||
fixme:
|
||||
desc: Show all occurrences of "FIXME".
|
||||
cmds:
|
||||
- grep -rnw "FIXME" internal
|
||||
|
||||
todo:
|
||||
desc: Show all occurrences of "TODO".
|
||||
cmds:
|
||||
- grep -rnw "TODO" internal
|
||||
|
||||
legacy:
|
||||
desc: Identify legacy and deprecated lines.
|
||||
cmds:
|
||||
- grep -rnw "\(LEGACY\|Deprecated\)" internal
|
||||
@@ -169,6 +169,8 @@ COOKIE_SECURE = false
|
||||
ENABLE_LOGIN_STATUS_COOKIE = false
|
||||
; The cookie name to store user login status.
|
||||
LOGIN_STATUS_COOKIE_NAME = login_status
|
||||
; A comma separated list of hostnames that are explicitly allowed to be accessed within the local network.
|
||||
LOCAL_NETWORK_ALLOWLIST =
|
||||
|
||||
[email]
|
||||
; Whether to enable the email service.
|
||||
|
||||
@@ -1242,6 +1242,7 @@ config.security.cookie_secure = Enable secure cookie
|
||||
config.security.reverse_proxy_auth_user = Reverse proxy authentication header
|
||||
config.security.enable_login_status_cookie = Enable login status cookie
|
||||
config.security.login_status_cookie_name = Login status cookie
|
||||
config.security.local_network_allowlist = Local network allowlist
|
||||
|
||||
config.email_config = Email configuration
|
||||
config.email.enabled = Enabled
|
||||
|
||||
@@ -31,8 +31,12 @@ cleanup() {
|
||||
}
|
||||
|
||||
create_volume_subfolder() {
|
||||
# Modify the owner of /data dir, make $USER(git) user have permission to create sub-dir in /data.
|
||||
chown -R "$USER:$USER" /data
|
||||
# only change ownership if needed, if using an nfs mount this could be expensive
|
||||
if [ "$USER:$USER" != "$(stat /data -c '%U:%G')" ]
|
||||
then
|
||||
# Modify the owner of /data dir, make $USER(git) user have permission to create sub-dir in /data.
|
||||
chown -R "$USER:$USER" /data
|
||||
fi
|
||||
|
||||
# Create VOLUME subfolder
|
||||
for f in /data/gogs/data /data/gogs/conf /data/gogs/log /data/git /data/ssh; do
|
||||
|
||||
@@ -153,6 +153,8 @@ You would have to re-run this command after changing Go files, or any file under
|
||||
When you are actively working on HTML templates and static files during development, you may want to enable the following configuration to avoid recompiling and restarting Gogs every time you make a change to files under `template/` and `public/` directories:
|
||||
|
||||
```ini
|
||||
RUN_MODE = dev
|
||||
|
||||
[server]
|
||||
LOAD_ASSETS_FROM_DISK = true
|
||||
```
|
||||
|
||||
8
go.mod
8
go.mod
@@ -28,7 +28,7 @@ require (
|
||||
github.com/issue9/identicon v1.0.1
|
||||
github.com/jaytaylor/html2text v0.0.0-20190408195923-01ec452cbe43
|
||||
github.com/jinzhu/gorm v1.9.12
|
||||
github.com/json-iterator/go v1.1.10
|
||||
github.com/json-iterator/go v1.1.12
|
||||
github.com/klauspost/compress v1.8.6 // indirect
|
||||
github.com/klauspost/cpuid v1.2.1 // indirect
|
||||
github.com/lib/pq v1.3.0 // indirect
|
||||
@@ -56,10 +56,10 @@ require (
|
||||
github.com/unknwon/i18n v0.0.0-20190805065654-5c6446a380b6
|
||||
github.com/unknwon/paginater v0.0.0-20170405233947-45e5d631308e
|
||||
github.com/urfave/cli v1.22.4
|
||||
golang.org/x/crypto v0.0.0-20200220183623-bac4c82f6975
|
||||
golang.org/x/net v0.0.0-20191014212845-da9a3fd4c582
|
||||
golang.org/x/crypto v0.0.0-20220331220935-ae2d96664a29
|
||||
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2
|
||||
golang.org/x/sys v0.0.0-20220114195835-da31bd327af9 // indirect
|
||||
golang.org/x/text v0.3.3
|
||||
golang.org/x/text v0.3.6
|
||||
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect
|
||||
gopkg.in/asn1-ber.v1 v1.0.0-20181015200546-f715ec2f112d // indirect
|
||||
gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df
|
||||
|
||||
24
go.sum
24
go.sum
@@ -151,8 +151,8 @@ github.com/jinzhu/now v1.0.1 h1:HjfetcXq097iXP0uoPCdnM4Efp5/9MsM0/M+XOTeR3M=
|
||||
github.com/jinzhu/now v1.0.1/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
|
||||
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
|
||||
github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||
github.com/json-iterator/go v1.1.10 h1:Kz6Cvnvv2wGdaG/V8yMvfkmNiXq9Ya2KUv4rouJJr68=
|
||||
github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
|
||||
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
|
||||
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
|
||||
github.com/jtolds/gls v4.2.1+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
|
||||
github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo=
|
||||
@@ -202,8 +202,9 @@ github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJ
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||
github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI=
|
||||
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
|
||||
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
|
||||
github.com/msteinert/pam v0.0.0-20190215180659-f29b9f28d6f9 h1:ZivaaKmjs9q90zi6I4gTLW6tbVGtlBjellr3hMYaly0=
|
||||
github.com/msteinert/pam v0.0.0-20190215180659-f29b9f28d6f9/go.mod h1:np1wUFZ6tyoke22qDJZY40URn9Ae51gX7ljIWXN5TJs=
|
||||
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
|
||||
@@ -309,8 +310,8 @@ golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8U
|
||||
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20191205180655-e7c4368fe9dd/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20200220183623-bac4c82f6975 h1:/Tl7pH94bvbAAHBdZJT947M/+gp0+CqQXDtMRC0fseo=
|
||||
golang.org/x/crypto v0.0.0-20200220183623-bac4c82f6975/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20220331220935-ae2d96664a29 h1:tkVvjkPTB7pnW3jnid7kNyAMPVWllTNOf/qKDze4p9o=
|
||||
golang.org/x/crypto v0.0.0-20220331220935-ae2d96664a29/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
|
||||
@@ -331,8 +332,8 @@ golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR
|
||||
golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20191014212845-da9a3fd4c582 h1:p9xBe/w/OzkeYVKm234g55gMdD1nSIooTir5kV11kfA=
|
||||
golang.org/x/net v0.0.0-20191014212845-da9a3fd4c582/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2 h1:CIJ76btIcR3eFI5EgSo6k1qKw9KJexJuRLI9G7Hp5wE=
|
||||
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
@@ -358,13 +359,18 @@ golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7w
|
||||
golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200420163511-1957bb5e6d1f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220114195835-da31bd327af9 h1:XfKQ4OlFl8okEOr5UvAqFRVj8pY/4yfcXrddB8qAbU0=
|
||||
golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1 h1:v+OssWQX+hTHEmOBgwxdZxK4zHq3yOs8F9J7mk0PY8E=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||
golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M=
|
||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
|
||||
2
gogs.go
2
gogs.go
@@ -19,7 +19,7 @@ import (
|
||||
)
|
||||
|
||||
func init() {
|
||||
conf.App.Version = "0.12.4"
|
||||
conf.App.Version = "0.12.7"
|
||||
}
|
||||
|
||||
func main() {
|
||||
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
@@ -27,9 +27,9 @@ func PAMAuth(serviceName, userName, passwd string) error {
|
||||
return err
|
||||
}
|
||||
|
||||
if err = t.Authenticate(0); err != nil {
|
||||
err = t.Authenticate(0)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
return t.AcctMgmt(0)
|
||||
}
|
||||
|
||||
@@ -314,6 +314,7 @@ func runWeb(c *cli.Context) error {
|
||||
}
|
||||
defer fr.Close()
|
||||
|
||||
c.Header().Set("Content-Security-Policy", "default-src 'none'; style-src 'unsafe-inline'; sandbox")
|
||||
c.Header().Set("Cache-Control", "public,max-age=86400")
|
||||
c.Header().Set("Content-Disposition", fmt.Sprintf(`inline; filename="%s"`, attach.Name))
|
||||
|
||||
|
||||
@@ -103,6 +103,7 @@ var (
|
||||
CookieSecure bool
|
||||
EnableLoginStatusCookie bool
|
||||
LoginStatusCookieName string
|
||||
LocalNetworkAllowlist []string `delim:","`
|
||||
|
||||
// Deprecated: Use Auth.ReverseProxyAuthenticationHeader instead, will be removed in 0.13.
|
||||
ReverseProxyAuthenticationUser string
|
||||
|
||||
1
internal/conf/testdata/TestInit.golden.ini
vendored
1
internal/conf/testdata/TestInit.golden.ini
vendored
@@ -80,6 +80,7 @@ COOKIE_USERNAME=gogs_awesome
|
||||
COOKIE_SECURE=false
|
||||
ENABLE_LOGIN_STATUS_COOKIE=false
|
||||
LOGIN_STATUS_COOKIE_NAME=login_status
|
||||
LOCAL_NETWORK_ALLOWLIST=
|
||||
REVERSE_PROXY_AUTHENTICATION_USER=
|
||||
|
||||
[email]
|
||||
|
||||
@@ -249,7 +249,7 @@ func Contexter() macaron.Handler {
|
||||
|
||||
if len(conf.HTTP.AccessControlAllowOrigin) > 0 {
|
||||
c.Header().Set("Access-Control-Allow-Origin", conf.HTTP.AccessControlAllowOrigin)
|
||||
c.Header().Set("'Access-Control-Allow-Credentials' ", "true")
|
||||
c.Header().Set("Access-Control-Allow-Credentials", "true")
|
||||
c.Header().Set("Access-Control-Max-Age", "3600")
|
||||
c.Header().Set("Access-Control-Allow-Headers", "Content-Type, Access-Control-Allow-Headers, Authorization, X-Requested-With")
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
gouuid "github.com/satori/go.uuid"
|
||||
"github.com/unknwon/com"
|
||||
|
||||
@@ -23,9 +24,10 @@ import (
|
||||
|
||||
"gogs.io/gogs/internal/conf"
|
||||
"gogs.io/gogs/internal/cryptoutil"
|
||||
"gogs.io/gogs/internal/db/errors"
|
||||
dberrors "gogs.io/gogs/internal/db/errors"
|
||||
"gogs.io/gogs/internal/gitutil"
|
||||
"gogs.io/gogs/internal/osutil"
|
||||
"gogs.io/gogs/internal/pathutil"
|
||||
"gogs.io/gogs/internal/process"
|
||||
"gogs.io/gogs/internal/tool"
|
||||
)
|
||||
@@ -134,7 +136,7 @@ func (repo *Repository) UpdateRepoFile(doer *User, opts UpdateRepoFileOptions) (
|
||||
if opts.OldBranch != opts.NewBranch {
|
||||
// Directly return error if new branch already exists in the server
|
||||
if git.RepoHasBranch(repoPath, opts.NewBranch) {
|
||||
return errors.BranchAlreadyExists{Name: opts.NewBranch}
|
||||
return dberrors.BranchAlreadyExists{Name: opts.NewBranch}
|
||||
}
|
||||
|
||||
// Otherwise, delete branch from local copy in case out of sync
|
||||
@@ -449,11 +451,16 @@ func isRepositoryGitPath(path string) bool {
|
||||
return strings.HasSuffix(path, ".git") || strings.Contains(path, ".git"+string(os.PathSeparator))
|
||||
}
|
||||
|
||||
func (repo *Repository) UploadRepoFiles(doer *User, opts UploadRepoFileOptions) (err error) {
|
||||
func (repo *Repository) UploadRepoFiles(doer *User, opts UploadRepoFileOptions) error {
|
||||
if len(opts.Files) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Prevent uploading files into the ".git" directory
|
||||
if isRepositoryGitPath(opts.TreePath) {
|
||||
return errors.Errorf("bad tree path %q", opts.TreePath)
|
||||
}
|
||||
|
||||
uploads, err := GetUploadsByUUIDs(opts.Files)
|
||||
if err != nil {
|
||||
return fmt.Errorf("get uploads by UUIDs[%v]: %v", opts.Files, err)
|
||||
@@ -487,7 +494,9 @@ func (repo *Repository) UploadRepoFiles(doer *User, opts UploadRepoFileOptions)
|
||||
continue
|
||||
}
|
||||
|
||||
// Prevent copying files into .git directory, see https://gogs.io/gogs/issues/5558.
|
||||
upload.Name = pathutil.Clean(upload.Name)
|
||||
|
||||
// Prevent uploading files into the ".git" directory
|
||||
if isRepositoryGitPath(upload.Name) {
|
||||
continue
|
||||
}
|
||||
|
||||
@@ -12,7 +12,9 @@ import (
|
||||
"github.com/unknwon/com"
|
||||
"gopkg.in/macaron.v1"
|
||||
|
||||
"gogs.io/gogs/internal/conf"
|
||||
"gogs.io/gogs/internal/db"
|
||||
"gogs.io/gogs/internal/netutil"
|
||||
)
|
||||
|
||||
// _______________________________________ _________.______________________ _______________.___.
|
||||
@@ -67,6 +69,11 @@ func (f MigrateRepo) ParseRemoteAddr(user *db.User) (string, error) {
|
||||
if err != nil {
|
||||
return "", db.ErrInvalidCloneAddr{IsURLError: true}
|
||||
}
|
||||
|
||||
if netutil.IsLocalHostname(u.Hostname(), conf.Security.LocalNetworkAllowlist) {
|
||||
return "", db.ErrInvalidCloneAddr{IsURLError: true}
|
||||
}
|
||||
|
||||
if len(f.AuthUsername)+len(f.AuthPassword) > 0 {
|
||||
u.User = url.UserPassword(f.AuthUsername, f.AuthPassword)
|
||||
}
|
||||
|
||||
71
internal/netutil/netutil.go
Normal file
71
internal/netutil/netutil.go
Normal file
@@ -0,0 +1,71 @@
|
||||
// Copyright 2022 The Gogs 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 netutil
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
)
|
||||
|
||||
var localCIDRs []*net.IPNet
|
||||
|
||||
func init() {
|
||||
// Parsing hardcoded CIDR strings should never fail, if in case it does, let's
|
||||
// fail it at start.
|
||||
rawCIDRs := []string{
|
||||
// https://datatracker.ietf.org/doc/html/rfc5735:
|
||||
"127.0.0.0/8", // Loopback
|
||||
"0.0.0.0/8", // "This" network
|
||||
"100.64.0.0/10", // Shared address space
|
||||
"169.254.0.0/16", // Link local
|
||||
"172.16.0.0/12", // Private-use networks
|
||||
"192.0.0.0/24", // IETF Protocol assignments
|
||||
"192.0.2.0/24", // TEST-NET-1
|
||||
"192.88.99.0/24", // 6to4 Relay anycast
|
||||
"192.168.0.0/16", // Private-use networks
|
||||
"198.18.0.0/15", // Network interconnect
|
||||
"198.51.100.0/24", // TEST-NET-2
|
||||
"203.0.113.0/24", // TEST-NET-3
|
||||
"255.255.255.255/32", // Limited broadcast
|
||||
|
||||
// https://datatracker.ietf.org/doc/html/rfc1918:
|
||||
"10.0.0.0/8", // Private-use networks
|
||||
|
||||
// https://datatracker.ietf.org/doc/html/rfc6890:
|
||||
"::1/128", // Loopback
|
||||
"FC00::/7", // Unique local address
|
||||
"FE80::/10", // Multicast address
|
||||
}
|
||||
for _, raw := range rawCIDRs {
|
||||
_, cidr, err := net.ParseCIDR(raw)
|
||||
if err != nil {
|
||||
panic(fmt.Sprintf("parse CIDR %q: %v", raw, err))
|
||||
}
|
||||
localCIDRs = append(localCIDRs, cidr)
|
||||
}
|
||||
}
|
||||
|
||||
// IsLocalHostname returns true if given hostname is resolved to local network
|
||||
// address, except exempted from the allowlist.
|
||||
func IsLocalHostname(hostname string, allowlist []string) bool {
|
||||
for _, allow := range allowlist {
|
||||
if hostname == allow {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
ips, err := net.LookupIP(hostname)
|
||||
if err != nil {
|
||||
return true
|
||||
}
|
||||
for _, ip := range ips {
|
||||
for _, cidr := range localCIDRs {
|
||||
if cidr.Contains(ip) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
40
internal/netutil/netutil_test.go
Normal file
40
internal/netutil/netutil_test.go
Normal file
@@ -0,0 +1,40 @@
|
||||
// Copyright 2022 The Gogs 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 netutil
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestIsLocalHostname(t *testing.T) {
|
||||
tests := []struct {
|
||||
hostname string
|
||||
allowlist []string
|
||||
want bool
|
||||
}{
|
||||
{hostname: "localhost", want: true},
|
||||
{hostname: "127.0.0.1", want: true},
|
||||
{hostname: "::1", want: true},
|
||||
{hostname: "0:0:0:0:0:0:0:1", want: true},
|
||||
{hostname: "fuf.me", want: true},
|
||||
{hostname: "127.0.0.95", want: true},
|
||||
{hostname: "0.0.0.0", want: true},
|
||||
{hostname: "192.168.123.45", want: true},
|
||||
|
||||
{hostname: "gogs.io", want: false},
|
||||
{hostname: "google.com", want: false},
|
||||
{hostname: "165.232.140.255", want: false},
|
||||
|
||||
{hostname: "192.168.123.45", allowlist: []string{"10.0.0.17"}, want: true},
|
||||
{hostname: "gogs.local", allowlist: []string{"gogs.local"}, want: false},
|
||||
}
|
||||
for _, test := range tests {
|
||||
t.Run("", func(t *testing.T) {
|
||||
assert.Equal(t, test.want, IsLocalHostname(test.hostname, test.allowlist))
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -20,6 +20,7 @@ import (
|
||||
"gogs.io/gogs/internal/db"
|
||||
"gogs.io/gogs/internal/db/errors"
|
||||
"gogs.io/gogs/internal/form"
|
||||
"gogs.io/gogs/internal/netutil"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -118,24 +119,7 @@ func WebhooksNew(c *context.Context, orCtx *orgRepoContext) {
|
||||
c.Success(orCtx.TmplNew)
|
||||
}
|
||||
|
||||
var localHostnames = []string{
|
||||
"localhost",
|
||||
"127.0.0.1",
|
||||
"::1",
|
||||
"0:0:0:0:0:0:0:1",
|
||||
}
|
||||
|
||||
// isLocalHostname returns true if given hostname is a known local address.
|
||||
func isLocalHostname(hostname string) bool {
|
||||
for _, local := range localHostnames {
|
||||
if hostname == local {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func validateWebhook(actor *db.User, l macaron.Locale, w *db.Webhook) (field string, msg string, ok bool) {
|
||||
func validateWebhook(actor *db.User, l macaron.Locale, w *db.Webhook) (field, msg string, ok bool) {
|
||||
if !actor.IsAdmin {
|
||||
// 🚨 SECURITY: Local addresses must not be allowed by non-admins to prevent SSRF,
|
||||
// see https://github.com/gogs/gogs/issues/5366 for details.
|
||||
@@ -144,7 +128,7 @@ func validateWebhook(actor *db.User, l macaron.Locale, w *db.Webhook) (field str
|
||||
return "PayloadURL", l.Tr("repo.settings.webhook.err_cannot_parse_payload_url", err), false
|
||||
}
|
||||
|
||||
if isLocalHostname(payloadURL.Hostname()) {
|
||||
if netutil.IsLocalHostname(payloadURL.Hostname(), conf.Security.LocalNetworkAllowlist) {
|
||||
return "PayloadURL", l.Tr("repo.settings.webhook.err_cannot_use_local_addresses"), false
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,25 +13,6 @@ import (
|
||||
"gogs.io/gogs/internal/mocks"
|
||||
)
|
||||
|
||||
func Test_isLocalHostname(t *testing.T) {
|
||||
tests := []struct {
|
||||
hostname string
|
||||
want bool
|
||||
}{
|
||||
{hostname: "localhost", want: true},
|
||||
{hostname: "127.0.0.1", want: true},
|
||||
{hostname: "::1", want: true},
|
||||
{hostname: "0:0:0:0:0:0:0:1", want: true},
|
||||
|
||||
{hostname: "gogs.io", want: false},
|
||||
}
|
||||
for _, test := range tests {
|
||||
t.Run("", func(t *testing.T) {
|
||||
assert.Equal(t, test.want, isLocalHostname(test.hostname))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_validateWebhook(t *testing.T) {
|
||||
l := &mocks.Locale{
|
||||
MockLang: "en",
|
||||
|
||||
@@ -206,6 +206,8 @@
|
||||
<dd><i class="fa fa{{if .Security.EnableLoginStatusCookie}}-check{{end}}-square-o"></i></dd>
|
||||
<dt>{{.i18n.Tr "admin.config.security.login_status_cookie_name"}}</dt>
|
||||
<dd>{{.Security.LoginStatusCookieName}}</dd>
|
||||
<dt>{{.i18n.Tr "admin.config.security.local_network_allowlist"}}</dt>
|
||||
<dd><code>{{.Security.LocalNetworkAllowlist}}</code></dd>
|
||||
</dl>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
{{range .Members}}
|
||||
<div class="item ui grid">
|
||||
<div class="ui one wide column">
|
||||
<img class="ui avatar" src="{{.RelAvatarLink}}?s=48">
|
||||
<img class="ui avatar" src="{{AppendAvatarSize .RelAvatarLink 48}}">
|
||||
</div>
|
||||
<div class="ui three wide column">
|
||||
<div class="meta"><a href="{{.HomeLink}}">{{.Name}}</a></div>
|
||||
|
||||
Reference in New Issue
Block a user