Compare commits

...

5 Commits

Author SHA1 Message Date
Joe Chen
e309bc8324 release: update version to 0.12.5 2022-03-11 14:58:57 +08:00
ysf
64102be2c9 security: fix improper PAM authorization handling (#6819)
Co-authored-by: Joe Chen <jc@unknwon.io>
# Conflicts:
#	CHANGELOG.md
#	internal/auth/pam/pam.go
2022-03-11 14:52:11 +08:00
Michael Rowley
91f2cde5e9 security: fix SSRF in repository migration (#6812)
Co-authored-by: Joe Chen <jc@unknwon.io>
# Conflicts:
#	CHANGELOG.md
#	internal/route/repo/webhook.go
2022-03-11 14:51:32 +08:00
Joe Chen
b3541030c3 Update Taskfile for Windows 2022-01-18 00:23:27 +08:00
Joe Chen
bc8b8c3767 Add Taskfile 2022-01-17 21:38:13 +08:00
9 changed files with 205 additions and 42 deletions

1
.gitignore vendored
View File

@@ -16,3 +16,4 @@ output*
*.sublime-project
*.sublime-workspace
/release
.task

91
Taskfile.yml Normal file
View 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

View File

@@ -19,7 +19,7 @@ import (
)
func init() {
conf.App.Version = "0.12.4"
conf.App.Version = "0.12.5"
}
func main() {

View File

@@ -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)
}

View File

@@ -13,6 +13,7 @@ import (
"gopkg.in/macaron.v1"
"gogs.io/gogs/internal/db"
"gogs.io/gogs/internal/netutil"
)
// _______________________________________ _________.______________________ _______________.___.
@@ -67,6 +68,11 @@ func (f MigrateRepo) ParseRemoteAddr(user *db.User) (string, error) {
if err != nil {
return "", db.ErrInvalidCloneAddr{IsURLError: true}
}
if netutil.IsLocalHostname(u.Hostname()) {
return "", db.ErrInvalidCloneAddr{IsURLError: true}
}
if len(f.AuthUsername)+len(f.AuthPassword) > 0 {
u.User = url.UserPassword(f.AuthUsername, f.AuthPassword)
}

View File

@@ -0,0 +1,64 @@
// 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 a known local address.
func IsLocalHostname(hostname string) bool {
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
}

View File

@@ -0,0 +1,36 @@
// 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
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},
}
for _, test := range tests {
t.Run("", func(t *testing.T) {
assert.Equal(t, test.want, IsLocalHostname(test.hostname))
})
}
}

View File

@@ -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()) {
return "PayloadURL", l.Tr("repo.settings.webhook.err_cannot_use_local_addresses"), false
}
}

View File

@@ -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",