Skip to content

Commit 70cf3e7

Browse files
GustedLoïc Dachary
authored andcommitted
[PRIVACY] Add a DNS method to fetch new updates
- Use TXT records in order to determine the latest available version. - This addresses a valid privacy issue, as with HTTP requests the server can keep track(estimated) of how many instances are using Forgejo, with DNS that's basically not possible as the server will never receive any data, as the only ones receiving data are DNS resolvers. (cherry picked from commit e68aaa0c16362b0f2ea53b791e841f7b8dcbe959)
1 parent e4061e1 commit 70cf3e7

File tree

5 files changed

+76
-10
lines changed

5 files changed

+76
-10
lines changed

custom/conf/app.example.ini

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2112,6 +2112,7 @@ ROUTER = console
21122112
;ENABLE_SUCCESS_NOTICE = false
21132113
;SCHEDULE = @every 168h
21142114
;HTTP_ENDPOINT = https://dl.gitea.io/gitea/version.json
2115+
;DOMAIN_ENDPOINT = release.forgejo.org
21152116

21162117
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
21172118
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -983,6 +983,7 @@ Default templates for project boards:
983983
- `ENABLE_SUCCESS_NOTICE`: **true**: Set to false to switch off success notices.
984984
- `SCHEDULE`: **@every 168h**: Cron syntax for scheduling a work, e.g. `@every 168h`.
985985
- `HTTP_ENDPOINT`: **https://dl.gitea.io/gitea/version.json**: the endpoint that Gitea will check for newer versions
986+
- `DOMAIN_ENDPOINT`: **release.forgejo.org**: the domain that, if specified, Gitea will check for newer versions. This is preferred over `HTTP_ENDPOINT`.
986987

987988
#### Cron - Delete all old system notices from database ('cron.delete_old_system_notices')
988989

modules/updatechecker/update_checker.go

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

77
import (
8+
"errors"
89
"io"
10+
"net"
911
"net/http"
12+
"strings"
1013

1114
"code.gitea.io/gitea/modules/json"
1215
"code.gitea.io/gitea/modules/proxy"
@@ -27,7 +30,51 @@ func (r *CheckerState) Name() string {
2730
}
2831

2932
// GiteaUpdateChecker returns error when new version of Gitea is available
30-
func GiteaUpdateChecker(httpEndpoint string) error {
33+
func GiteaUpdateChecker(httpEndpoint, domainEndpoint string) error {
34+
var version string
35+
var err error
36+
if domainEndpoint != "" {
37+
version, err = getVersionDNS(domainEndpoint)
38+
} else {
39+
version, err = getVersionHTTP(httpEndpoint)
40+
}
41+
42+
if err != nil {
43+
return err
44+
}
45+
46+
return UpdateRemoteVersion(version)
47+
}
48+
49+
// getVersionDNS will request the TXT records for the domain. If a record starts
50+
// with "forgejo_versions=" everything after that will be used as the latest
51+
// version available.
52+
func getVersionDNS(domainEndpoint string) (version string, err error) {
53+
records, err := net.LookupTXT(domainEndpoint)
54+
if err != nil {
55+
return "", err
56+
}
57+
58+
if len(records) == 0 {
59+
return "", errors.New("no TXT records were found")
60+
}
61+
62+
for _, record := range records {
63+
if strings.HasPrefix(record, "forgejo_versions=") {
64+
// Get all supported versions, separated by a comma.
65+
supportedVersions := strings.Split(strings.TrimPrefix(record, "forgejo_versions="), ",")
66+
// For now always return the latest supported version.
67+
return supportedVersions[len(supportedVersions)-1], nil
68+
}
69+
}
70+
71+
return "", errors.New("there is no TXT record with a valid value")
72+
}
73+
74+
// getVersionHTTP will make an HTTP request to the endpoint, and the returned
75+
// content is JSON. The "latest.version" path's value will be used as the latest
76+
// version available.
77+
func getVersionHTTP(httpEndpoint string) (version string, err error) {
3178
httpClient := &http.Client{
3279
Transport: &http.Transport{
3380
Proxy: proxy.Proxy(),
@@ -36,16 +83,16 @@ func GiteaUpdateChecker(httpEndpoint string) error {
3683

3784
req, err := http.NewRequest("GET", httpEndpoint, nil)
3885
if err != nil {
39-
return err
86+
return "", err
4087
}
4188
resp, err := httpClient.Do(req)
4289
if err != nil {
43-
return err
90+
return "", err
4491
}
4592
defer resp.Body.Close()
4693
body, err := io.ReadAll(resp.Body)
4794
if err != nil {
48-
return err
95+
return "", err
4996
}
5097

5198
type respType struct {
@@ -56,10 +103,9 @@ func GiteaUpdateChecker(httpEndpoint string) error {
56103
respData := respType{}
57104
err = json.Unmarshal(body, &respData)
58105
if err != nil {
59-
return err
106+
return "", err
60107
}
61-
62-
return UpdateRemoteVersion(respData.Latest.Version)
108+
return respData.Latest.Version, nil
63109
}
64110

65111
// UpdateRemoteVersion updates the latest available version of Gitea
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
// Copyright 2023 The Forgejo Authors. All rights reserved.
2+
// SPDX-License-Identifier: MIT
3+
4+
package updatechecker
5+
6+
import (
7+
"testing"
8+
9+
"github.com/stretchr/testify/assert"
10+
)
11+
12+
func TestDNSUpdate(t *testing.T) {
13+
version, err := getVersionDNS("release.forgejo.org")
14+
assert.NoError(t, err)
15+
assert.NotEmpty(t, version)
16+
}

services/cron/tasks_extended.go

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -147,18 +147,20 @@ func registerDeleteOldActions() {
147147
func registerUpdateGiteaChecker() {
148148
type UpdateCheckerConfig struct {
149149
BaseConfig
150-
HTTPEndpoint string
150+
HTTPEndpoint string
151+
DomainEndpoint string
151152
}
152153
RegisterTaskFatal("update_checker", &UpdateCheckerConfig{
153154
BaseConfig: BaseConfig{
154155
Enabled: false,
155156
RunAtStart: false,
156157
Schedule: "@every 168h",
157158
},
158-
HTTPEndpoint: "https://dl.gitea.io/gitea/version.json",
159+
HTTPEndpoint: "https://dl.gitea.io/gitea/version.json",
160+
DomainEndpoint: "release.forgejo.org",
159161
}, func(ctx context.Context, _ *user_model.User, config Config) error {
160162
updateCheckerConfig := config.(*UpdateCheckerConfig)
161-
return updatechecker.GiteaUpdateChecker(updateCheckerConfig.HTTPEndpoint)
163+
return updatechecker.GiteaUpdateChecker(updateCheckerConfig.HTTPEndpoint, updateCheckerConfig.DomainEndpoint)
162164
})
163165
}
164166

0 commit comments

Comments
 (0)