Skip to content

Commit d576e32

Browse files
authored
Merge branch 'main' into wip-dumprestore-test
2 parents c8b4f3d + e034d3a commit d576e32

File tree

81 files changed

+1633
-253
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

81 files changed

+1633
-253
lines changed

cmd/web.go

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -222,18 +222,19 @@ func listen(m http.Handler, handleRedirector bool) error {
222222
}
223223
err = runHTTP("tcp", listenAddr, "Web", m)
224224
case setting.HTTPS:
225-
if setting.EnableLetsEncrypt {
226-
err = runLetsEncrypt(listenAddr, setting.Domain, setting.LetsEncryptDirectory, setting.LetsEncryptEmail, m)
225+
if setting.EnableAcme {
226+
err = runACME(listenAddr, m)
227227
break
228-
}
229-
if handleRedirector {
230-
if setting.RedirectOtherPort {
231-
go runHTTPRedirector()
232-
} else {
233-
NoHTTPRedirector()
228+
} else {
229+
if handleRedirector {
230+
if setting.RedirectOtherPort {
231+
go runHTTPRedirector()
232+
} else {
233+
NoHTTPRedirector()
234+
}
234235
}
236+
err = runHTTPS("tcp", listenAddr, "Web", setting.CertFile, setting.KeyFile, m)
235237
}
236-
err = runHTTPS("tcp", listenAddr, "Web", setting.CertFile, setting.KeyFile, m)
237238
case setting.FCGI:
238239
if handleRedirector {
239240
NoHTTPRedirector()

cmd/web_letsencrypt.go renamed to cmd/web_acme.go

Lines changed: 38 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,11 @@
55
package cmd
66

77
import (
8+
"crypto/x509"
9+
"encoding/pem"
10+
"fmt"
811
"net/http"
12+
"os"
913
"strconv"
1014
"strings"
1115

@@ -16,7 +20,25 @@ import (
1620
"github.com/caddyserver/certmagic"
1721
)
1822

19-
func runLetsEncrypt(listenAddr, domain, directory, email string, m http.Handler) error {
23+
func getCARoot(path string) (*x509.CertPool, error) {
24+
r, err := os.ReadFile(path)
25+
if err != nil {
26+
return nil, err
27+
}
28+
block, _ := pem.Decode(r)
29+
if block == nil {
30+
return nil, fmt.Errorf("no PEM found in the file %s", path)
31+
}
32+
caRoot, err := x509.ParseCertificate(block.Bytes)
33+
if err != nil {
34+
return nil, err
35+
}
36+
certPool := x509.NewCertPool()
37+
certPool.AddCert(caRoot)
38+
return certPool, nil
39+
}
40+
41+
func runACME(listenAddr string, m http.Handler) error {
2042
// If HTTP Challenge enabled, needs to be serving on port 80. For TLSALPN needs 443.
2143
// Due to docker port mapping this can't be checked programmatically
2244
// TODO: these are placeholders until we add options for each in settings with appropriate warning
@@ -33,10 +55,21 @@ func runLetsEncrypt(listenAddr, domain, directory, email string, m http.Handler)
3355
}
3456

3557
magic := certmagic.NewDefault()
36-
magic.Storage = &certmagic.FileStorage{Path: directory}
58+
magic.Storage = &certmagic.FileStorage{Path: setting.AcmeLiveDirectory}
59+
// Try to use private CA root if provided, otherwise defaults to system's trust
60+
var certPool *x509.CertPool
61+
if setting.AcmeCARoot != "" {
62+
var err error
63+
certPool, err = getCARoot(setting.AcmeCARoot)
64+
if err != nil {
65+
log.Warn("Failed to parse CA Root certificate, using default CA trust: %v", err)
66+
}
67+
}
3768
myACME := certmagic.NewACMEManager(magic, certmagic.ACMEManager{
38-
Email: email,
39-
Agreed: setting.LetsEncryptTOS,
69+
CA: setting.AcmeURL,
70+
TrustedRoots: certPool,
71+
Email: setting.AcmeEmail,
72+
Agreed: setting.AcmeTOS,
4073
DisableHTTPChallenge: !enableHTTPChallenge,
4174
DisableTLSALPNChallenge: !enableTLSALPNChallenge,
4275
ListenHost: setting.HTTPAddr,
@@ -47,7 +80,7 @@ func runLetsEncrypt(listenAddr, domain, directory, email string, m http.Handler)
4780
magic.Issuers = []certmagic.Issuer{myACME}
4881

4982
// this obtains certificates or renews them if necessary
50-
err := magic.ManageSync(graceful.GetManager().HammerContext(), []string{domain})
83+
err := magic.ManageSync(graceful.GetManager().HammerContext(), []string{setting.Domain})
5184
if err != nil {
5285
return err
5386
}

custom/conf/app.example.ini

Lines changed: 35 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -82,12 +82,15 @@ RUN_MODE = ; prod
8282
;; Whether to use the builtin SSH server or not.
8383
;START_SSH_SERVER = false
8484
;;
85-
;; Username to use for the builtin SSH server. If blank, then it is the value of RUN_USER.
86-
;BUILTIN_SSH_SERVER_USER =
85+
;; Username to use for the builtin SSH server.
86+
;BUILTIN_SSH_SERVER_USER = %(RUN_USER)s
8787
;;
8888
;; Domain name to be exposed in clone URL
8989
;SSH_DOMAIN = %(DOMAIN)s
9090
;;
91+
;; SSH username displayed in clone URLs.
92+
;SSH_USER = %(BUILTIN_SSH_SERVER_USER)s
93+
;;
9194
;; The network interface the builtin SSH server should listen on
9295
;SSH_LISTEN_HOST =
9396
;;
@@ -175,6 +178,36 @@ RUN_MODE = ; prod
175178
;OFFLINE_MODE = false
176179
;DISABLE_ROUTER_LOG = false
177180
;;
181+
;; TLS Settings: Either ACME or manual
182+
;; (Other common TLS configuration are found before)
183+
;ENABLE_ACME = false
184+
;;
185+
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
186+
;;
187+
;; ACME automatic TLS settings
188+
;;
189+
;; ACME directory URL (e.g. LetsEncrypt's staging/testing URL: https://acme-staging-v02.api.letsencrypt.org/directory)
190+
;; Leave empty to default to LetsEncrypt's (production) URL
191+
;ACME_URL =
192+
;;
193+
;; Explicitly accept the ACME's TOS. The specific TOS cannot be retrieved at the moment.
194+
;ACME_ACCEPTTOS = false
195+
;;
196+
;; If the ACME CA is not in your system's CA trust chain, it can be manually added here
197+
;ACME_CA_ROOT =
198+
;;
199+
;; Email used for the ACME registration service
200+
;; Can be left blank to initialize at first run and use the cached value
201+
;ACME_EMAIL =
202+
;;
203+
;; ACME live directory (not to be confused with ACME directory URL: ACME_URL)
204+
;; (Refer to caddy's ACME manager https://github.com/caddyserver/certmagic)
205+
;ACME_DIRECTORY = https
206+
;;
207+
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
208+
;;
209+
;; Manual TLS settings: (Only applicable if ENABLE_ACME=false)
210+
;;
178211
;; Generate steps:
179212
;; $ ./gitea cert -ca=true -duration=8760h0m0s -host=myhost.example.com
180213
;;

docs/content/doc/advanced/config-cheat-sheet.en-us.md

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -265,6 +265,7 @@ The following configuration set `Content-Type: application/vnd.android.package-a
265265
- `DISABLE_SSH`: **false**: Disable SSH feature when it's not available.
266266
- `START_SSH_SERVER`: **false**: When enabled, use the built-in SSH server.
267267
- `BUILTIN_SSH_SERVER_USER`: **%(RUN_USER)s**: Username to use for the built-in SSH Server.
268+
- `SSH_USER`: **%(BUILTIN_SSH_SERVER_USER)**: SSH username displayed in clone URLs. This is only for people who configure the SSH server themselves; in most cases, you want to leave this blank and modify the `BUILTIN_SSH_SERVER_USER`.
268269
- `SSH_DOMAIN`: **%(DOMAIN)s**: Domain name of this server, used for displayed clone URL.
269270
- `SSH_PORT`: **22**: SSH port displayed in clone URL.
270271
- `SSH_LISTEN_HOST`: **0.0.0.0**: Listen address for the built-in SSH server.
@@ -291,8 +292,8 @@ The following configuration set `Content-Type: application/vnd.android.package-a
291292
- `MINIMUM_KEY_SIZE_CHECK`: **true**: Indicate whether to check minimum key size with corresponding type.
292293

293294
- `OFFLINE_MODE`: **false**: Disables use of CDN for static files and Gravatar for profile pictures.
294-
- `CERT_FILE`: **https/cert.pem**: Cert file path used for HTTPS. When chaining, the server certificate must come first, then intermediate CA certificates (if any). From 1.11 paths are relative to `CUSTOM_PATH`.
295-
- `KEY_FILE`: **https/key.pem**: Key file path used for HTTPS. From 1.11 paths are relative to `CUSTOM_PATH`.
295+
- `CERT_FILE`: **https/cert.pem**: Cert file path used for HTTPS. When chaining, the server certificate must come first, then intermediate CA certificates (if any). This is ignored if `ENABLE_ACME=true`. From 1.11 paths are relative to `CUSTOM_PATH`.
296+
- `KEY_FILE`: **https/key.pem**: Key file path used for HTTPS. This is ignored if `ENABLE_ACME=true`. From 1.11 paths are relative to `CUSTOM_PATH`.
296297
- `STATIC_ROOT_PATH`: **./**: Upper level of template and static files path.
297298
- `APP_DATA_PATH`: **data** (**/data/gitea** on docker): Default path for application data.
298299
- `STATIC_CACHE_TIME`: **6h**: Web browser cache time for static resources on `custom/`, `public/` and all uploaded avatars. Note that this cache is disabled when `RUN_MODE` is "dev".
@@ -346,11 +347,12 @@ The following configuration set `Content-Type: application/vnd.android.package-a
346347
- Aliased names
347348
- "ecdhe_rsa_with_chacha20_poly1305" is an alias for "ecdhe_rsa_with_chacha20_poly1305_sha256"
348349
- "ecdhe_ecdsa_with_chacha20_poly1305" is alias for "ecdhe_ecdsa_with_chacha20_poly1305_sha256"
349-
- `ENABLE_LETSENCRYPT`: **false**: If enabled you must set `DOMAIN` to valid internet facing domain (ensure DNS is set and port 80 is accessible by letsencrypt validation server).
350-
By using Lets Encrypt **you must consent** to their [terms of service](https://letsencrypt.org/documents/LE-SA-v1.2-November-15-2017.pdf).
351-
- `LETSENCRYPT_ACCEPTTOS`: **false**: This is an explicit check that you accept the terms of service for Let's Encrypt.
352-
- `LETSENCRYPT_DIRECTORY`: **https**: Directory that Letsencrypt will use to cache information such as certs and private keys.
353-
- `LETSENCRYPT_EMAIL`: **[email protected]**: Email used by Letsencrypt to notify about problems with issued certificates. (No default)
350+
- `ENABLE_ACME`: **false**: Flag to enable automatic certificate management via an ACME capable Certificate Authority (CA) server (default: Lets Encrypt). If enabled, `CERT_FILE` and `KEY_FILE` are ignored, and the CA must resolve `DOMAIN` to this gitea server. Ensure that DNS records are set and either port `80` or port `443` are accessible by the CA server (the public internet by default), and redirected to the appropriate ports `PORT_TO_REDIRECT` or `HTTP_PORT` respectively.
351+
- `ACME_URL`: **\<empty\>**: The CA's ACME directory URL, e.g. for a self-hosted [smallstep CA server](https://github.com/smallstep/certificates), it can look like `https://ca.example.com/acme/acme/directory`. If left empty, it defaults to using Let's Encerypt's production CA (check `LETSENCRYPT_ACCEPTTOS` as well).
352+
- `ACME_ACCEPTTOS`: **false**: This is an explicit check that you accept the terms of service of the ACME provider. The default is Lets Encrypt [terms of service](https://letsencrypt.org/documents/LE-SA-v1.2-November-15-2017.pdf).
353+
- `ACME_DIRECTORY`: **https**: Directory that the certificate manager will use to cache information such as certs and private keys.
354+
- `ACME_EMAIL`: **\<empty\>**: Email used for the ACME registration. Usually it is to notify about problems with issued certificates.
355+
- `ACME_CA_ROOT`: **\<empty\>**: The CA's root certificate. If left empty, it defaults to using the system's trust chain.
354356
- `ALLOW_GRACEFUL_RESTARTS`: **true**: Perform a graceful restart on SIGHUP
355357
- `GRACEFUL_HAMMER_TIME`: **60s**: After a restart the parent process will stop accepting new connections and will allow requests to finish before stopping. Shutdown will be forced if it takes longer than this time.
356358
- `STARTUP_TIMEOUT`: **0**: Shutsdown the server if startup takes longer than the provided time. On Windows setting this sends a waithint to the SVC host to tell the SVC host startup may take some time. Please note startup is determined by the opening of the listeners - HTTP/HTTPS/SSH. Indexers may take longer to startup and can have their own timeouts.

docs/content/doc/features/comparison.en-us.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ _Symbols used in table:_
5050
| Repository Tokens with write rights ||||||||
5151
| Built-in Container Registry | [](https://github.com/go-gitea/gitea/issues/2316) |||||||
5252
| External git mirroring ||||||||
53-
| FIDO U2F (2FA) ||||||| |
53+
| WebAuthn (2FA) ||||||| ? |
5454
| Built-in CI/CD ||||||||
5555
| Subgroups: groups within groups ||||||||
5656

@@ -66,6 +66,7 @@ _Symbols used in table:_
6666
| Granular user roles (Code, Issues, Wiki etc) ||||||||
6767
| Verified Committer ||| ? |||||
6868
| GPG Signed Commits ||||||||
69+
| SSH Signed Commits |||||| ? | ? |
6970
| Reject unsigned commits | [](https://github.com/go-gitea/gitea/pull/9708) |||||||
7071
| Repository Activity page ||||||||
7172
| Branch manager ||||||||

docs/content/doc/features/comparison.zh-cn.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ _表格中的符号含义:_
4848
| 仓库写权限令牌 ||||||||
4949
| 内置容器 Registry ||||||||
5050
| 外部 Git 镜像 ||||||||
51-
| FIDO U2F (2FA) ||||||| |
51+
| WebAuthn (2FA) | ||||| | ? |
5252
| 内置 CI/CD ||||||||
5353
| 子组织:组织内的组织 ||||||||
5454

@@ -64,6 +64,7 @@ _表格中的符号含义:_
6464
| 细粒度用户角色 (例如 Code, Issues, Wiki) ||||||||
6565
| 提交人的身份验证 ||| ? |||||
6666
| GPG 签名的提交 ||||||||
67+
| SSH 签名的提交 |||||| ? | ? |
6768
| 拒绝未用通过验证的提交 ||||||||
6869
| 仓库活跃度页面 ||||||||
6970
| 分支管理 ||||||||

docs/content/doc/usage/https-support.md

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -55,20 +55,34 @@ PORT_TO_REDIRECT = 3080
5555

5656
If you are using Docker, make sure that this port is configured in your `docker-compose.yml` file.
5757

58-
## Using Let's Encrypt
58+
## Using ACME (Default: Let's Encrypt)
5959

60-
[Let's Encrypt](https://letsencrypt.org/) is a Certificate Authority that allows you to automatically request and renew SSL/TLS certificates. In addition to starting Gitea on your configured port, to request HTTPS certificates, Gitea will also need to listed on port 80, and will set up an autoredirect to HTTPS for you. Let's Encrypt will need to be able to access Gitea via the Internet to verify your ownership of the domain.
60+
[ACME](https://tools.ietf.org/html/rfc8555) is a Certificate Authority standard protocol that allows you to automatically request and renew SSL/TLS certificates. [Let's Encrypt](https://letsencrypt.org/) is a free publicly trusted Certificate Authority server using this standard. Only `HTTP-01` and `TLS-ALPN-01` challenges are implemented. In order for ACME challenges to pass and verify your domain ownership, external traffic to the gitea domain on port `80` (`HTTP-01`) or port `443` (`TLS-ALPN-01`) has to be served by the gitea instance. Setting up [HTTP redirection](#setting-up-http-redirection) and port-forwards might be needed for external traffic to route correctly. Normal traffic to port `80` will otherwise be automatically redirected to HTTPS. **You must consent** to the ACME provider's terms of service (default Let's Encrypt's [terms of service](https://letsencrypt.org/documents/LE-SA-v1.2-November-15-2017.pdf)).
6161

62-
By using Let's Encrypt **you must consent** to their [terms of service](https://letsencrypt.org/documents/LE-SA-v1.2-November-15-2017.pdf).
62+
Minimum setup using the default Let's Encrypt:
63+
```ini
64+
[server]
65+
PROTOCOL=https
66+
DOMAIN=git.example.com
67+
ENABLE_ACME=true
68+
ACME_ACCEPTTOS=true
69+
ACME_DIRECTORY=https
70+
;; Email can be omitted here and provided manually at first run, after which it is cached
71+
72+
```
6373

74+
Minimumg setup using a [smallstep CA](https://github.com/smallstep/certificates), refer to [their tutorial](https://smallstep.com/docs/tutorials/acme-challenge) for more information.
6475
```ini
6576
[server]
6677
PROTOCOL=https
6778
DOMAIN=git.example.com
68-
ENABLE_LETSENCRYPT=true
69-
LETSENCRYPT_ACCEPTTOS=true
70-
LETSENCRYPT_DIRECTORY=https
71-
LETSENCRYPT_EMAIL[email protected]
79+
ENABLE_ACME=true
80+
ACME_ACCEPTTOS=true
81+
ACME_URL=https://ca.example.com/acme/acme/directory
82+
;; Can be omitted if using the system's trust is preferred
83+
;ACME_CA_ROOT=/path/to/root_ca.crt
84+
ACME_DIRECTORY=https
85+
7286
```
7387

7488
To learn more about the config values, please checkout the [Config Cheat Sheet](../config-cheat-sheet#server-server).

integrations/repo_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,7 @@ func TestViewRepo1CloneLinkAuthorized(t *testing.T) {
135135
assert.Equal(t, setting.AppURL+"user2/repo1.git", link)
136136
link, exists = htmlDoc.doc.Find("#repo-clone-ssh").Attr("data-link")
137137
assert.True(t, exists, "The template has changed")
138-
sshURL := fmt.Sprintf("ssh://%s@%s:%d/user2/repo1.git", setting.SSH.BuiltinServerUser, setting.SSH.Domain, setting.SSH.Port)
138+
sshURL := fmt.Sprintf("ssh://%s@%s:%d/user2/repo1.git", setting.SSH.User, setting.SSH.Domain, setting.SSH.Port)
139139
assert.Equal(t, sshURL, link)
140140
}
141141

models/issue_label.go

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ import (
2222
)
2323

2424
// LabelColorPattern is a regexp witch can validate LabelColor
25-
var LabelColorPattern = regexp.MustCompile("^#[0-9a-fA-F]{6}$")
25+
var LabelColorPattern = regexp.MustCompile("^#?(?:[0-9a-fA-F]{6}|[0-9a-fA-F]{3})$")
2626

2727
// Label represents a label of repository for issues.
2828
type Label struct {
@@ -258,6 +258,23 @@ func NewLabel(label *Label) error {
258258
if !LabelColorPattern.MatchString(label.Color) {
259259
return fmt.Errorf("bad color code: %s", label.Color)
260260
}
261+
262+
// normalize case
263+
label.Color = strings.ToLower(label.Color)
264+
265+
// add leading hash
266+
if label.Color[0] != '#' {
267+
label.Color = "#" + label.Color
268+
}
269+
270+
// convert 3-character shorthand into 6-character version
271+
if len(label.Color) == 4 {
272+
r := label.Color[1]
273+
g := label.Color[2]
274+
b := label.Color[3]
275+
label.Color = fmt.Sprintf("#%c%c%c%c%c%c", r, r, g, g, b, b)
276+
}
277+
261278
return newLabel(db.GetEngine(db.DefaultContext), label)
262279
}
263280

models/issue_label_test.go

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,11 +38,15 @@ func TestNewLabels(t *testing.T) {
3838
assert.NoError(t, unittest.PrepareTestDatabase())
3939
labels := []*Label{
4040
{RepoID: 2, Name: "labelName2", Color: "#123456"},
41-
{RepoID: 3, Name: "labelName3", Color: "#23456F"},
41+
{RepoID: 3, Name: "labelName3", Color: "#123"},
42+
{RepoID: 4, Name: "labelName4", Color: "ABCDEF"},
43+
{RepoID: 5, Name: "labelName5", Color: "DEF"},
4244
}
4345
assert.Error(t, NewLabel(&Label{RepoID: 3, Name: "invalid Color", Color: ""}))
44-
assert.Error(t, NewLabel(&Label{RepoID: 3, Name: "invalid Color", Color: "123456"}))
46+
assert.Error(t, NewLabel(&Label{RepoID: 3, Name: "invalid Color", Color: "#45G"}))
4547
assert.Error(t, NewLabel(&Label{RepoID: 3, Name: "invalid Color", Color: "#12345G"}))
48+
assert.Error(t, NewLabel(&Label{RepoID: 3, Name: "invalid Color", Color: "45G"}))
49+
assert.Error(t, NewLabel(&Label{RepoID: 3, Name: "invalid Color", Color: "12345G"}))
4650
for _, label := range labels {
4751
unittest.AssertNotExistsBean(t, label)
4852
}

0 commit comments

Comments
 (0)