[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 0baefb546a
)
This commit is contained in:
parent
58d43867ca
commit
e8ee41880b
5 changed files with 76 additions and 10 deletions
|
@ -2203,6 +2203,7 @@ ROUTER = console
|
|||
;ENABLE_SUCCESS_NOTICE = false
|
||||
;SCHEDULE = @every 168h
|
||||
;HTTP_ENDPOINT = https://dl.gitea.io/gitea/version.json
|
||||
;DOMAIN_ENDPOINT = release.forgejo.org
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
|
|
@ -1046,6 +1046,7 @@ Default templates for project boards:
|
|||
- `ENABLE_SUCCESS_NOTICE`: **true**: Set to false to switch off success notices.
|
||||
- `SCHEDULE`: **@every 168h**: Cron syntax for scheduling a work, e.g. `@every 168h`.
|
||||
- `HTTP_ENDPOINT`: **https://dl.gitea.io/gitea/version.json**: the endpoint that Gitea will check for newer versions
|
||||
- `DOMAIN_ENDPOINT`: **release.forgejo.org**: the domain that, if specified, Gitea will check for newer versions. This is preferred over `HTTP_ENDPOINT`.
|
||||
|
||||
#### Cron - Delete all old system notices from database ('cron.delete_old_system_notices')
|
||||
|
||||
|
|
|
@ -4,8 +4,11 @@
|
|||
package updatechecker
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"io"
|
||||
"net"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"code.gitea.io/gitea/modules/json"
|
||||
"code.gitea.io/gitea/modules/proxy"
|
||||
|
@ -26,7 +29,51 @@ func (r *CheckerState) Name() string {
|
|||
}
|
||||
|
||||
// GiteaUpdateChecker returns error when new version of Gitea is available
|
||||
func GiteaUpdateChecker(httpEndpoint string) error {
|
||||
func GiteaUpdateChecker(httpEndpoint, domainEndpoint string) error {
|
||||
var version string
|
||||
var err error
|
||||
if domainEndpoint != "" {
|
||||
version, err = getVersionDNS(domainEndpoint)
|
||||
} else {
|
||||
version, err = getVersionHTTP(httpEndpoint)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return UpdateRemoteVersion(version)
|
||||
}
|
||||
|
||||
// getVersionDNS will request the TXT records for the domain. If a record starts
|
||||
// with "forgejo_versions=" everything after that will be used as the latest
|
||||
// version available.
|
||||
func getVersionDNS(domainEndpoint string) (version string, err error) {
|
||||
records, err := net.LookupTXT(domainEndpoint)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
if len(records) == 0 {
|
||||
return "", errors.New("no TXT records were found")
|
||||
}
|
||||
|
||||
for _, record := range records {
|
||||
if strings.HasPrefix(record, "forgejo_versions=") {
|
||||
// Get all supported versions, separated by a comma.
|
||||
supportedVersions := strings.Split(strings.TrimPrefix(record, "forgejo_versions="), ",")
|
||||
// For now always return the latest supported version.
|
||||
return supportedVersions[len(supportedVersions)-1], nil
|
||||
}
|
||||
}
|
||||
|
||||
return "", errors.New("there is no TXT record with a valid value")
|
||||
}
|
||||
|
||||
// getVersionHTTP will make an HTTP request to the endpoint, and the returned
|
||||
// content is JSON. The "latest.version" path's value will be used as the latest
|
||||
// version available.
|
||||
func getVersionHTTP(httpEndpoint string) (version string, err error) {
|
||||
httpClient := &http.Client{
|
||||
Transport: &http.Transport{
|
||||
Proxy: proxy.Proxy(),
|
||||
|
@ -35,16 +82,16 @@ func GiteaUpdateChecker(httpEndpoint string) error {
|
|||
|
||||
req, err := http.NewRequest("GET", httpEndpoint, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
return "", err
|
||||
}
|
||||
resp, err := httpClient.Do(req)
|
||||
if err != nil {
|
||||
return err
|
||||
return "", err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
body, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return err
|
||||
return "", err
|
||||
}
|
||||
|
||||
type respType struct {
|
||||
|
@ -55,10 +102,9 @@ func GiteaUpdateChecker(httpEndpoint string) error {
|
|||
respData := respType{}
|
||||
err = json.Unmarshal(body, &respData)
|
||||
if err != nil {
|
||||
return err
|
||||
return "", err
|
||||
}
|
||||
|
||||
return UpdateRemoteVersion(respData.Latest.Version)
|
||||
return respData.Latest.Version, nil
|
||||
}
|
||||
|
||||
// UpdateRemoteVersion updates the latest available version of Gitea
|
||||
|
|
16
modules/updatechecker/update_checker_test.go
Normal file
16
modules/updatechecker/update_checker_test.go
Normal file
|
@ -0,0 +1,16 @@
|
|||
// Copyright 2023 The Forgejo Authors. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package updatechecker
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestDNSUpdate(t *testing.T) {
|
||||
version, err := getVersionDNS("release.forgejo.org")
|
||||
assert.NoError(t, err)
|
||||
assert.NotEmpty(t, version)
|
||||
}
|
|
@ -142,7 +142,8 @@ func registerDeleteOldActions() {
|
|||
func registerUpdateGiteaChecker() {
|
||||
type UpdateCheckerConfig struct {
|
||||
BaseConfig
|
||||
HTTPEndpoint string
|
||||
HTTPEndpoint string
|
||||
DomainEndpoint string
|
||||
}
|
||||
RegisterTaskFatal("update_checker", &UpdateCheckerConfig{
|
||||
BaseConfig: BaseConfig{
|
||||
|
@ -150,10 +151,11 @@ func registerUpdateGiteaChecker() {
|
|||
RunAtStart: false,
|
||||
Schedule: "@every 168h",
|
||||
},
|
||||
HTTPEndpoint: "https://dl.gitea.io/gitea/version.json",
|
||||
HTTPEndpoint: "https://dl.gitea.io/gitea/version.json",
|
||||
DomainEndpoint: "release.forgejo.org",
|
||||
}, func(ctx context.Context, _ *user_model.User, config Config) error {
|
||||
updateCheckerConfig := config.(*UpdateCheckerConfig)
|
||||
return updatechecker.GiteaUpdateChecker(updateCheckerConfig.HTTPEndpoint)
|
||||
return updatechecker.GiteaUpdateChecker(updateCheckerConfig.HTTPEndpoint, updateCheckerConfig.DomainEndpoint)
|
||||
})
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue