mirror of
https://github.com/syncthing/syncthing.git
synced 2025-12-23 22:18:14 -05:00
Compare commits
19 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
81c99e07db | ||
|
|
5279330c1d | ||
|
|
194b59b3ed | ||
|
|
8e796ddb94 | ||
|
|
7c9d06b4d2 | ||
|
|
df8d8c276e | ||
|
|
98cf5872e9 | ||
|
|
c883f49a24 | ||
|
|
d84280107c | ||
|
|
d97fd638bc | ||
|
|
a1069a0d70 | ||
|
|
465804161b | ||
|
|
d08f483811 | ||
|
|
655b4568c1 | ||
|
|
c6a887865f | ||
|
|
b4565c87ee | ||
|
|
20d2406a0e | ||
|
|
d3d3fc2d0e | ||
|
|
f8c44923c7 |
20
.github/workflows/org-members.yaml
vendored
Normal file
20
.github/workflows/org-members.yaml
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
name: Org membership recommendations
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
schedule:
|
||||
- cron: '0 0 1 * *'
|
||||
|
||||
jobs:
|
||||
|
||||
run-recommendation:
|
||||
runs-on: ubuntu-latest
|
||||
name: Check for a recommendation
|
||||
steps:
|
||||
|
||||
- uses: docker://ghcr.io/calmh/github-org-members:latest
|
||||
env:
|
||||
GITHUB_ORGANISATION: syncthing
|
||||
GITHUB_TOKEN: ${{ secrets.GOM_GITHUB_TOKEN }}
|
||||
GOM_IGNORE_USERS: ${{ secrets.GOM_IGNORE_USERS }}
|
||||
GOM_ALSO_REPOS: ${{ secrets.GOM_ALSO_REPOS }}
|
||||
@@ -70,6 +70,12 @@ linters:
|
||||
# Rollback errors can be ignored
|
||||
- linters: [errcheck]
|
||||
source: Rollback
|
||||
# Embedded fields named in selectors may add clarity
|
||||
- linters: [staticcheck]
|
||||
text: QF1008
|
||||
# Don't necessarily rewrite !(foo || bar) to !foo && !bar
|
||||
- linters: [staticcheck]
|
||||
text: QF1001
|
||||
settings:
|
||||
sloglint:
|
||||
context: "scope"
|
||||
|
||||
@@ -52,7 +52,7 @@ approval_rules:
|
||||
- syncthing/maintainers
|
||||
options:
|
||||
ignore_update_merges: true
|
||||
allow_contributor: true
|
||||
allow_non_author_contributor: true
|
||||
|
||||
# Regular pull requests require approval by an active contributor
|
||||
- name: is approved by a syncthing contributor
|
||||
@@ -62,7 +62,7 @@ approval_rules:
|
||||
- syncthing/contributors
|
||||
options:
|
||||
ignore_update_merges: true
|
||||
allow_contributor: true
|
||||
allow_non_author_contributor: true
|
||||
|
||||
# Changes to some files (translations, dependencies, compatibility) do not
|
||||
# require approval if they were proposed by a contributor and have a
|
||||
|
||||
2
AUTHORS
2
AUTHORS
@@ -32,6 +32,7 @@ Evgeny Kuznetsov <evgeny@kuznetsov.md>
|
||||
greatroar <61184462+greatroar@users.noreply.github.com>
|
||||
Lars K.W. Gohlke (lkwg82) <lkwg82@gmx.de>
|
||||
Lode Hoste (Zillode) <zillode@zillode.be>
|
||||
Marcus B Spencer <marcus@marcusspencer.xyz> <marcus@marcusspencer.us>
|
||||
Michael Ploujnikov (plouj) <ploujj@gmail.com>
|
||||
Ross Smith II (rasa) <ross@smithii.com>
|
||||
Stefan Tatschner (rumpelsepp) <stefan@sevenbyte.org> <rumpelsepp@sevenbyte.org> <stefan@rumpelsepp.org>
|
||||
@@ -198,7 +199,6 @@ Majed Abdulaziz (majedev) <majed.alhajry@gmail.com>
|
||||
Marc Laporte (marclaporte) <marc@marclaporte.com> <marc@laporte.name>
|
||||
Marcel Meyer <mm.marcelmeyer@gmail.com>
|
||||
Marcin Dziadus (marcindziadus) <dziadus.marcin@gmail.com>
|
||||
Marcus B Spencer <marcus@marcusspencer.xyz> <marcus@marcusspencer.us>
|
||||
Marcus Legendre <marcus.legendre@gmail.com>
|
||||
Mario Majila <mariustshipichik@gmail.com>
|
||||
Mark Pulford (mpx) <mark@kyne.com.au>
|
||||
|
||||
@@ -23,52 +23,7 @@ example `UMASK=002`.
|
||||
**Docker cli**
|
||||
```
|
||||
$ docker pull syncthing/syncthing
|
||||
$ docker run -p 8384:8384 -p 22000:22000/tcp -p 22000:22000/udp -p 21027:21027/udp \
|
||||
-v /wherever/st-sync:/var/syncthing \
|
||||
--hostname=my-syncthing \
|
||||
syncthing/syncthing:latest
|
||||
```
|
||||
|
||||
**Docker compose**
|
||||
```yml
|
||||
---
|
||||
version: "3"
|
||||
services:
|
||||
syncthing:
|
||||
image: syncthing/syncthing
|
||||
container_name: syncthing
|
||||
hostname: my-syncthing
|
||||
environment:
|
||||
- PUID=1000
|
||||
- PGID=1000
|
||||
volumes:
|
||||
- /wherever/st-sync:/var/syncthing
|
||||
ports:
|
||||
- 8384:8384 # Web UI
|
||||
- 22000:22000/tcp # TCP file transfers
|
||||
- 22000:22000/udp # QUIC file transfers
|
||||
- 21027:21027/udp # Receive local discovery broadcasts
|
||||
restart: unless-stopped
|
||||
healthcheck:
|
||||
test: curl -fkLsS -m 2 127.0.0.1:8384/rest/noauth/health | grep -o --color=never OK || exit 1
|
||||
interval: 1m
|
||||
timeout: 10s
|
||||
retries: 3
|
||||
```
|
||||
|
||||
## Discovery
|
||||
|
||||
Note that Docker's default network mode prevents local IP addresses from
|
||||
being discovered, as Syncthing is only able to see the internal IP of the
|
||||
container on the `172.17.0.0/16` subnet. This will result in poor transfer rates
|
||||
if local device addresses are not manually configured.
|
||||
|
||||
It is therefore advisable to use the [host network mode](https://docs.docker.com/network/host/) instead:
|
||||
|
||||
**Docker cli**
|
||||
```
|
||||
$ docker pull syncthing/syncthing
|
||||
$ docker run --network=host \
|
||||
$ docker run --network=host -e STGUIADDRESS= \
|
||||
-v /wherever/st-sync:/var/syncthing \
|
||||
syncthing/syncthing:latest
|
||||
```
|
||||
@@ -85,6 +40,7 @@ services:
|
||||
environment:
|
||||
- PUID=1000
|
||||
- PGID=1000
|
||||
- STGUIADDRESS=
|
||||
volumes:
|
||||
- /wherever/st-sync:/var/syncthing
|
||||
network_mode: host
|
||||
@@ -96,27 +52,27 @@ services:
|
||||
retries: 3
|
||||
```
|
||||
|
||||
## Discovery
|
||||
|
||||
Please note that Docker's default network mode prevents local IP addresses
|
||||
from being discovered, as Syncthing can only see the internal IP address of
|
||||
the container on the `172.17.0.0/16` subnet. This would likely break the ability
|
||||
for nodes to establish LAN connections properly, resulting in poor transfer
|
||||
rates unless local device addresses are configured manually.
|
||||
|
||||
It is therefore strongly recommended to stick to the [host network mode](https://docs.docker.com/network/host/),
|
||||
as shown above.
|
||||
|
||||
Be aware that syncthing alone is now in control of what interfaces and ports it
|
||||
listens on. You can edit the syncthing configuration to change the defaults if
|
||||
there are conflicts.
|
||||
|
||||
## GUI Security
|
||||
|
||||
By default Syncthing inside the Docker image listens on 0.0.0.0:8384 to
|
||||
allow GUI connections via the Docker proxy. This is set by the
|
||||
`STGUIADDRESS` environment variable in the Dockerfile, as it differs from
|
||||
what Syncthing would otherwise use by default. This means you should set up
|
||||
authentication in the GUI, like for any other externally reachable Syncthing
|
||||
instance. If you do not require the GUI, or you use host networking, you can
|
||||
unset the `STGUIADDRESS` variable to have Syncthing fall back to listening
|
||||
on 127.0.0.1:
|
||||
|
||||
```
|
||||
$ docker pull syncthing/syncthing
|
||||
$ docker run -e STGUIADDRESS= \
|
||||
-v /wherever/st-sync:/var/syncthing \
|
||||
syncthing/syncthing:latest
|
||||
```
|
||||
|
||||
With the environment variable unset Syncthing will follow what is set in the
|
||||
configuration file / GUI settings dialog.
|
||||
By default Syncthing inside the Docker image listens on `0.0.0.0:8384`. This
|
||||
allows GUI connections when running without host network mode. The example
|
||||
above unsets the `STGUIADDRESS` environment variable to have Syncthing fall
|
||||
back to listening on what has been configured in the configuration file or the
|
||||
GUI settings dialog. By default this is the localhost IP address `127.0.0.1`.
|
||||
If you configure your GUI to be externally reachable, make sure you set up
|
||||
authentication and enable TLS.
|
||||
|
||||
@@ -118,7 +118,7 @@ func handleFailureFn(dsn, failureDir string, ignore *ignorePatterns) func(w http
|
||||
bs, err := io.ReadAll(lr)
|
||||
req.Body.Close()
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), 500)
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -130,7 +130,7 @@ func handleFailureFn(dsn, failureDir string, ignore *ignorePatterns) func(w http
|
||||
var reports []ur.FailureReport
|
||||
err = json.Unmarshal(bs, &reports)
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), 400)
|
||||
http.Error(w, err.Error(), http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
if len(reports) == 0 {
|
||||
@@ -141,7 +141,7 @@ func handleFailureFn(dsn, failureDir string, ignore *ignorePatterns) func(w http
|
||||
|
||||
version, err := build.ParseVersion(reports[0].Version)
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), 400)
|
||||
http.Error(w, err.Error(), http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
for _, r := range reports {
|
||||
|
||||
@@ -90,7 +90,7 @@ func sendReport(dsn string, pkt *raven.Packet, userID string) error {
|
||||
}
|
||||
|
||||
// The client sets release and such on the packet before sending, in the
|
||||
// misguided idea that it knows this better than than the packet we give
|
||||
// misguided idea that it knows this better than the packet we give
|
||||
// it. So we copy the values from the packet to the client first...
|
||||
cli.SetRelease(pkt.Release)
|
||||
cli.SetEnvironment(pkt.Environment)
|
||||
@@ -136,7 +136,7 @@ func parseCrashReport(path string, report []byte) (*raven.Packet, error) {
|
||||
|
||||
r := bytes.NewReader(report)
|
||||
ctx, _, err := stack.ScanSnapshot(r, io.Discard, stack.DefaultOpts())
|
||||
if err != nil && err != io.EOF {
|
||||
if err != nil && !errors.Is(err, io.EOF) {
|
||||
return nil, err
|
||||
}
|
||||
if ctx == nil || len(ctx.Goroutines) == 0 {
|
||||
|
||||
@@ -10,7 +10,7 @@ import (
|
||||
"bytes"
|
||||
"compress/gzip"
|
||||
"crypto/sha256"
|
||||
"fmt"
|
||||
"encoding/hex"
|
||||
"net"
|
||||
"net/http"
|
||||
"os"
|
||||
@@ -23,7 +23,7 @@ import (
|
||||
// remote IP, and the current month.
|
||||
func userIDFor(req *http.Request) string {
|
||||
addr := req.RemoteAddr
|
||||
if fwd := req.Header.Get("x-forwarded-for"); fwd != "" {
|
||||
if fwd := req.Header.Get("X-Forwarded-For"); fwd != "" {
|
||||
addr = fwd
|
||||
}
|
||||
if host, _, err := net.SplitHostPort(addr); err == nil {
|
||||
@@ -32,7 +32,7 @@ func userIDFor(req *http.Request) string {
|
||||
now := time.Now().Format("200601")
|
||||
salt := "stcrashreporter"
|
||||
hash := sha256.Sum256([]byte(salt + addr + now))
|
||||
return fmt.Sprintf("%x", hash[:8])
|
||||
return hex.EncodeToString(hash[:8])
|
||||
}
|
||||
|
||||
// 01234567890abcdef... => 01/23
|
||||
|
||||
@@ -162,7 +162,7 @@ func main() {
|
||||
|
||||
testCert = createTestCertificate()
|
||||
|
||||
for i := 0; i < requestProcessors; i++ {
|
||||
for range requestProcessors {
|
||||
go requestProcessor(geoip)
|
||||
}
|
||||
|
||||
@@ -180,7 +180,7 @@ func main() {
|
||||
relayTestsTotal.WithLabelValues("success").Inc()
|
||||
}
|
||||
}
|
||||
// Run the the stats refresher once the relays are loaded.
|
||||
// Run the stats refresher once the relays are loaded.
|
||||
statsRefresher(statsRefresh)
|
||||
}()
|
||||
|
||||
@@ -653,6 +653,7 @@ func getLocation(host string, geoip *geoip.Provider) location {
|
||||
|
||||
type loggingResponseWriter struct {
|
||||
http.ResponseWriter
|
||||
|
||||
statusCode int
|
||||
}
|
||||
|
||||
|
||||
@@ -47,7 +47,7 @@ func newMetricsSet(srv *server) *metricsSet {
|
||||
|
||||
var initForType func(reflect.Type)
|
||||
initForType = func(t reflect.Type) {
|
||||
for i := 0; i < t.NumField(); i++ {
|
||||
for i := range t.NumField() {
|
||||
field := t.Field(i)
|
||||
if field.Type.Kind() == reflect.Struct {
|
||||
initForType(field.Type)
|
||||
@@ -175,7 +175,7 @@ func (s *metricsSet) addReport(r *contract.Report) {
|
||||
|
||||
func (s *metricsSet) addReportStruct(v reflect.Value, gaugeVecs map[string][]string) {
|
||||
t := v.Type()
|
||||
for i := 0; i < v.NumField(); i++ {
|
||||
for i := range v.NumField() {
|
||||
field := v.Field(i)
|
||||
if field.Kind() == reflect.Struct {
|
||||
s.addReportStruct(field, gaugeVecs)
|
||||
|
||||
@@ -23,6 +23,7 @@ import (
|
||||
|
||||
type amqpReplicator struct {
|
||||
suture.Service
|
||||
|
||||
broker string
|
||||
sender *amqpSender
|
||||
receiver *amqpReceiver
|
||||
|
||||
@@ -350,7 +350,7 @@ func certificateBytes(req *http.Request) ([]byte, error) {
|
||||
|
||||
var bs []byte
|
||||
|
||||
if hdr := req.Header.Get("X-SSL-Cert"); hdr != "" {
|
||||
if hdr := req.Header.Get("X-Ssl-Cert"); hdr != "" {
|
||||
if strings.Contains(hdr, "%") {
|
||||
// Nginx using $ssl_client_escaped_cert
|
||||
// The certificate is in PEM format with url encoding.
|
||||
@@ -513,6 +513,7 @@ func fixupAddresses(remote *net.TCPAddr, addresses []string) []string {
|
||||
|
||||
type loggingResponseWriter struct {
|
||||
http.ResponseWriter
|
||||
|
||||
statusCode int
|
||||
}
|
||||
|
||||
|
||||
@@ -14,6 +14,7 @@ import (
|
||||
"os"
|
||||
"os/signal"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync/atomic"
|
||||
"syscall"
|
||||
@@ -247,10 +248,10 @@ func main() {
|
||||
query.Set("pingInterval", pingInterval.String())
|
||||
query.Set("networkTimeout", networkTimeout.String())
|
||||
if sessionLimitBps > 0 {
|
||||
query.Set("sessionLimitBps", fmt.Sprint(sessionLimitBps))
|
||||
query.Set("sessionLimitBps", strconv.Itoa(sessionLimitBps))
|
||||
}
|
||||
if globalLimitBps > 0 {
|
||||
query.Set("globalLimitBps", fmt.Sprint(globalLimitBps))
|
||||
query.Set("globalLimitBps", strconv.Itoa(globalLimitBps))
|
||||
}
|
||||
if statusAddr != "" {
|
||||
query.Set("statusAddr", statusAddr)
|
||||
|
||||
@@ -122,7 +122,7 @@ func (r *rateCalculator) updateRates(interval time.Duration) {
|
||||
|
||||
func (r *rateCalculator) rate(periods int) int64 {
|
||||
var tot int64
|
||||
for i := 0; i < periods; i++ {
|
||||
for i := range periods {
|
||||
tot += r.rates[i]
|
||||
}
|
||||
return tot / int64(periods)
|
||||
|
||||
@@ -6,6 +6,7 @@ import (
|
||||
"bufio"
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"errors"
|
||||
"flag"
|
||||
"log"
|
||||
"net"
|
||||
@@ -133,7 +134,8 @@ func connectToStdio(stdin <-chan string, conn net.Conn) {
|
||||
conn.SetReadDeadline(time.Now().Add(time.Millisecond))
|
||||
n, err := conn.Read(buf[0:])
|
||||
if err != nil {
|
||||
nerr, ok := err.(net.Error)
|
||||
var nerr net.Error
|
||||
ok := errors.As(err, &nerr)
|
||||
if !ok || !nerr.Timeout() {
|
||||
log.Println(err)
|
||||
return
|
||||
|
||||
@@ -10,7 +10,7 @@ import (
|
||||
func setTCPOptions(conn net.Conn) error {
|
||||
tcpConn, ok := conn.(*net.TCPConn)
|
||||
if !ok {
|
||||
return errors.New("Not a TCP connection")
|
||||
return errors.New("not a TCP connection")
|
||||
}
|
||||
if err := tcpConn.SetLinger(0); err != nil {
|
||||
return err
|
||||
|
||||
@@ -32,6 +32,7 @@ type APIClient interface {
|
||||
|
||||
type apiClient struct {
|
||||
http.Client
|
||||
|
||||
cfg config.GUIConfiguration
|
||||
apikey string
|
||||
}
|
||||
@@ -91,11 +92,11 @@ func loadGUIConfig() (config.GUIConfiguration, error) {
|
||||
guiCfg := cfg.GUI()
|
||||
|
||||
if guiCfg.Address() == "" {
|
||||
return config.GUIConfiguration{}, errors.New("Could not find GUI Address")
|
||||
return config.GUIConfiguration{}, errors.New("could not find GUI Address")
|
||||
}
|
||||
|
||||
if guiCfg.APIKey == "" {
|
||||
return config.GUIConfiguration{}, errors.New("Could not find GUI API key")
|
||||
return config.GUIConfiguration{}, errors.New("could not find GUI API key")
|
||||
}
|
||||
|
||||
return guiCfg, nil
|
||||
@@ -113,7 +114,7 @@ func (c *apiClient) Endpoint() string {
|
||||
}
|
||||
|
||||
func (c *apiClient) Do(req *http.Request) (*http.Response, error) {
|
||||
req.Header.Set("X-API-Key", c.apikey)
|
||||
req.Header.Set("X-Api-Key", c.apikey)
|
||||
resp, err := c.Client.Do(req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
||||
@@ -10,6 +10,7 @@ import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"reflect"
|
||||
|
||||
"github.com/AudriusButkevicius/recli"
|
||||
@@ -86,7 +87,7 @@ func (h *configHandler) configAfter(_ *cli.Context) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if resp.StatusCode != 200 {
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
body, err := responseToBArray(resp)
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
@@ -9,6 +9,7 @@ package cli
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"github.com/alecthomas/kong"
|
||||
@@ -34,7 +35,7 @@ func (e *errorsPushCommand) Run(ctx Context) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if response.StatusCode != 200 {
|
||||
if response.StatusCode != http.StatusOK {
|
||||
errStr = fmt.Sprint("Failed to push error\nStatus code: ", response.StatusCode)
|
||||
bytes, err := responseToBArray(response)
|
||||
if err != nil {
|
||||
|
||||
@@ -10,6 +10,7 @@ import (
|
||||
"bufio"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/alecthomas/kong"
|
||||
@@ -63,7 +64,7 @@ func (f *folderOverrideCommand) Run(ctx Context) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if response.StatusCode != 200 {
|
||||
if response.StatusCode != http.StatusOK {
|
||||
errStr := fmt.Sprint("Failed to override changes\nStatus code: ", response.StatusCode)
|
||||
bytes, err := responseToBArray(response)
|
||||
if err != nil {
|
||||
|
||||
@@ -31,7 +31,7 @@ const (
|
||||
// directory to the crash reporting server as urlBase. Uploads are attempted
|
||||
// with the newest log first.
|
||||
//
|
||||
// This can can block for a long time. The context can set a final deadline
|
||||
// This can block for a long time. The context can set a final deadline
|
||||
// for this.
|
||||
func uploadPanicLogs(ctx context.Context, urlBase, dir string) {
|
||||
files, err := filepath.Glob(filepath.Join(dir, "panic-*.log"))
|
||||
|
||||
@@ -388,8 +388,8 @@ func upgradeViaRest() error {
|
||||
}
|
||||
u.Path = path.Join(u.Path, "rest/system/upgrade")
|
||||
target := u.String()
|
||||
r, _ := http.NewRequest("POST", target, nil)
|
||||
r.Header.Set("X-API-Key", cfg.GUI().APIKey)
|
||||
r, _ := http.NewRequest(http.MethodPost, target, nil)
|
||||
r.Header.Set("X-Api-Key", cfg.GUI().APIKey)
|
||||
|
||||
tr := &http.Transport{
|
||||
DialContext: dialer.DialContext,
|
||||
@@ -407,7 +407,7 @@ func upgradeViaRest() error {
|
||||
|
||||
defer resp.Body.Close()
|
||||
|
||||
if resp.StatusCode != 200 {
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
bs, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -529,7 +529,8 @@ func (c *serveCmd) syncthingMain() {
|
||||
err = upgrade.To(release)
|
||||
}
|
||||
if err != nil {
|
||||
if _, ok := err.(*errNoUpgrade); ok || err == errTooEarlyUpgradeCheck || err == errTooEarlyUpgrade {
|
||||
var noUpgradeErr *errNoUpgrade
|
||||
if errors.As(err, &noUpgradeErr) || errors.Is(err, errTooEarlyUpgradeCheck) || errors.Is(err, errTooEarlyUpgrade) {
|
||||
slog.Debug("Initial automatic upgrade", slogutil.Error(err))
|
||||
} else {
|
||||
slog.Info("Initial automatic upgrade", slogutil.Error(err))
|
||||
@@ -659,13 +660,14 @@ func auditWriter(auditFile string) io.Writer {
|
||||
var auditDest string
|
||||
var auditFlags int
|
||||
|
||||
if auditFile == "-" {
|
||||
switch auditFile {
|
||||
case "-":
|
||||
fd = os.Stdout
|
||||
auditDest = "stdout"
|
||||
} else if auditFile == "--" {
|
||||
case "--":
|
||||
fd = os.Stderr
|
||||
auditDest = "stderr"
|
||||
} else {
|
||||
default:
|
||||
if auditFile == "" {
|
||||
auditFile = locations.GetTimestamped(locations.AuditLog)
|
||||
auditFlags = os.O_WRONLY | os.O_CREATE | os.O_EXCL
|
||||
@@ -720,7 +722,7 @@ func autoUpgrade(cfg config.Wrapper, app *syncthing.App, evLogger events.Logger)
|
||||
|
||||
checkInterval := time.Duration(opts.AutoUpgradeIntervalH) * time.Hour
|
||||
rel, err := upgrade.LatestRelease(opts.ReleasesURL, build.Version, opts.UpgradeToPreReleases)
|
||||
if err == upgrade.ErrUpgradeUnsupported {
|
||||
if errors.Is(err, upgrade.ErrUpgradeUnsupported) {
|
||||
sub.Unsubscribe()
|
||||
return
|
||||
}
|
||||
@@ -836,7 +838,8 @@ func setPauseState(cfgWrapper config.Wrapper, paused bool) {
|
||||
}
|
||||
|
||||
func exitCodeForUpgrade(err error) int {
|
||||
if _, ok := err.(*errNoUpgrade); ok {
|
||||
var noUpgradeErr *errNoUpgrade
|
||||
if errors.As(err, &noUpgradeErr) {
|
||||
return svcutil.ExitNoUpgradeAvailable.AsInt()
|
||||
}
|
||||
return svcutil.ExitError.AsInt()
|
||||
|
||||
@@ -9,6 +9,7 @@ package main
|
||||
import (
|
||||
"bufio"
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"log/slog"
|
||||
@@ -176,7 +177,8 @@ func (c *serveCmd) monitorMain() {
|
||||
os.Exit(svcutil.ExitSuccess.AsInt())
|
||||
}
|
||||
|
||||
if exiterr, ok := err.(*exec.ExitError); ok {
|
||||
exiterr := &exec.ExitError{}
|
||||
if errors.As(err, &exiterr) {
|
||||
exitCode := exiterr.ExitCode()
|
||||
if stopped || c.NoRestart {
|
||||
os.Exit(exitCode)
|
||||
|
||||
2
gui/default/assets/lang/lang-az.json
Normal file
2
gui/default/assets/lang/lang-az.json
Normal file
@@ -0,0 +1,2 @@
|
||||
{
|
||||
}
|
||||
2
gui/default/assets/lang/lang-ckb.json
Normal file
2
gui/default/assets/lang/lang-ckb.json
Normal file
@@ -0,0 +1,2 @@
|
||||
{
|
||||
}
|
||||
@@ -82,6 +82,7 @@
|
||||
"Custom Range": "Custom Range",
|
||||
"Danger!": "Danger!",
|
||||
"Database Location": "Database Location",
|
||||
"Debug": "Debug",
|
||||
"Debugging Facilities": "Debugging Facilities",
|
||||
"Default": "Default",
|
||||
"Default Configuration": "Default Configuration",
|
||||
@@ -210,6 +211,7 @@
|
||||
"Incoming Rate Limit (KiB/s)": "Incoming Rate Limit (KiB/s)",
|
||||
"Incorrect configuration may damage your folder contents and render Syncthing inoperable.": "Incorrect configuration may damage your folder contents and render Syncthing inoperable.",
|
||||
"Incorrect user name or password.": "Incorrect username or password.",
|
||||
"Info": "Info",
|
||||
"Internally used paths:": "Internally used paths:",
|
||||
"Introduced By": "Introduced By",
|
||||
"Introducer": "Introducer",
|
||||
|
||||
@@ -82,6 +82,7 @@
|
||||
"Custom Range": "Intervallo personalizzato",
|
||||
"Danger!": "Pericolo!",
|
||||
"Database Location": "Posizione del database",
|
||||
"Debug": "Debug",
|
||||
"Debugging Facilities": "Servizi di Debug",
|
||||
"Default": "Default",
|
||||
"Default Configuration": "Configurazione predefinita",
|
||||
@@ -210,6 +211,7 @@
|
||||
"Incoming Rate Limit (KiB/s)": "Limite Velocità in Ingresso (KiB/s)",
|
||||
"Incorrect configuration may damage your folder contents and render Syncthing inoperable.": "Una configurazione non corretta potrebbe danneggiare il contenuto delle cartelle e rendere Syncthing inoperativo.",
|
||||
"Incorrect user name or password.": "Nome utente o password errati.",
|
||||
"Info": "Info",
|
||||
"Internally used paths:": "Percorsi interni utilizzati:",
|
||||
"Introduced By": "Introdotto da",
|
||||
"Introducer": "Introduttore",
|
||||
@@ -227,6 +229,7 @@
|
||||
"Learn more": "Per saperne di più",
|
||||
"Learn more at {%url%}": "Scopri di più su {{url}}",
|
||||
"Limit": "Limite",
|
||||
"Limit Bandwidth in LAN": "Limitare la larghezza di banda nella LAN",
|
||||
"Listener Failures": "Fallimenti dell'Ascoltatore",
|
||||
"Listener Status": "Stato dell'Ascoltatore",
|
||||
"Listeners": "In Ascolto",
|
||||
|
||||
@@ -30,7 +30,7 @@
|
||||
<h4 class="text-center" translate>The Syncthing Authors</h4>
|
||||
<div class="row">
|
||||
<div class="col-md-12" id="contributor-list">
|
||||
Jakob Borg, Audrius Butkevicius, Simon Frei, Tomasz Wilczyński, Alexander Graf, Alexandre Viau, Anderson Mesquita, André Colomb, Antony Male, Ben Schulz, bt90, Caleb Callaway, Daniel Harte, Emil Lundberg, Eric P, Evgeny Kuznetsov, greatroar, Lars K.W. Gohlke, Lode Hoste, Michael Ploujnikov, Ross Smith II, Stefan Tatschner, Tommy van der Vorst, Wulf Weich, Adam Piggott, Adel Qalieh, Aleksey Vasenev, Alessandro G., Alex Ionescu, Alex Lindeman, Alex Xu, Alexander Seiler, Alexandre Alves, Aman Gupta, Andreas Sommer, andresvia, Andrew Rabert, Andrey D, andyleap, Anjan Momi, Anthony Goeckner, Antoine Lamielle, Anur, Aranjedeath, ardevd, Arkadiusz Tymiński, Aroun, Arthur Axel fREW Schmidt, Artur Zubilewicz, Ashish Bhate, Aurélien Rainone, BAHADIR YILMAZ, Bart De Vries, Beat Reichenbach, Ben Shepherd, Ben Sidhom, Benedikt Heine, Benno Fünfstück, Benny Ng, boomsquared, Boqin Qin, Boris Rybalkin, Brendan Long, Catfriend1, Cathryne Linenweaver, Cedric Staniewski, Chih-Hsuan Yen, Choongkyu, Chris Howie, Chris Joel, Christian Kujau, Christian Prescott, chucic, cjc7373, Colin Kennedy, Cromefire_, Cyprien Devillez, d-volution, Dan, Daniel Barczyk, Daniel Bergmann, Daniel Martí, Daniel Padrta, Daniil Gentili, Darshil Chanpura, dashangcun, David Rimmer, DeflateAwning, Denis A., Dennis Wilson, derekriemer, DerRockWolf, desbma, Devon G. Redekopp, digital, Dimitri Papadopoulos Orfanos, Dmitry Saveliev, domain, Domenic Horner, Dominik Heidler, Elias Jarlebring, Elliot Huffman, Emil Hessman, Eng Zer Jun, entity0xfe, Eric Lesiuta, Erik Meitner, Evan Spensley, Federico Castagnini, Felix, Felix Ableitner, Felix Lampe, Felix Unterpaintner, Francois-Xavier Gsell, Frank Isemann, Gahl Saraf, georgespatton, ghjklw, Gilli Sigurdsson, Gleb Sinyavskiy, Graham Miln, Greg, guangwu, gudvinr, Gusted, Han Boetes, HansK-p, Harrison Jones, Hazem Krimi, Heiko Zuerker, Hireworks, Hugo Locurcio, Iain Barnett, Ian Johnson, ignacy123, Iskander Sharipov, Jaakko Hannikainen, Jack Croft, Jacob, Jake Peterson, James O'Beirne, James Patterson, Jaroslav Lichtblau, Jaroslav Malec, Jaspitta, Jaya Chithra, Jaya Kumar, Jeffery To, jelle van der Waa, Jens Diemer, Jochen Voss, Johan Vromans, John Rinehart, Jonas Thelemann, Jonathan, Jose Manuel Delicado, jtagcat, Julian Lehrhuber, Jörg Thalheim, Jędrzej Kula, Kapil Sareen, Karol Różycki, Kebin Liu, Keith Harrison, Kelong Cong, Ken'ichi Kamada, Kevin Allen, Kevin Bushiri, Kevin White, Jr., klemens, Kurt Fitzner, kylosus, Lars Lehtonen, Laurent Etiemble, Leo Arias, Liu Siyuan, Lord Landon Agahnim, LSmithx2, Lukas Lihotzki, Luke Hamburg, luzpaz, Majed Abdulaziz, Marc Laporte, Marcel Meyer, Marcin Dziadus, Marcus B Spencer, Marcus Legendre, Mario Majila, Mark Pulford, Martchus, Mateusz Naściszewski, Mateusz Ż, mathias4833, Matic Potočnik, Matt Burke, Matt Robenolt, Matteo Ruina, Maurizio Tomasi, Max, Max Schulze, MaximAL, Maximilian, Michael Jephcote, Michael Rienstra, MichaIng, Migelo, Mike Boone, MikeLund, MikolajTwarog, Mingxuan Lin, mv1005, Nate Morrison, nf, Nicholas Rishel, Nick Busey, Nico Stapelbroek, Nicolas Braud-Santoni, Nicolas Perraut, Niels Peter Roest, Nils Jakobi, NinoM4ster, Nitroretro, NoLooseEnds, Oliver Freyermuth, orangekame3, otbutz, overkill, Oyebanji Jacob Mayowa, Pablo, Pascal Jungblut, Paul Brit, Paul Donald, Pawel Palenica, perewa, Peter Badida, Peter Dave Hello, Peter Hoeg, Peter Marquardt, Phani Rithvij, Phil Davis, Philippe Schommers, Phill Luby, Piotr Bejda, polyfloyd, pullmerge, Quentin Hibon, Rahmi Pruitt, red_led, Robert Carosi, Roberto Santalla, Robin Schoonover, Roman Zaynetdinov, rubenbe, Ruslan Yevdokymov, Ryan Qian, Ryan Sullivan, Sacheendra Talluri, Scott Klupfel, sec65, Sergey Mishin, Sertonix, Severin von Wnuck-Lipinski, Shaarad Dalvi, Simon Mwepu, Simon Pickup, Sly_tom_cat, Sonu Kumar Saw, Stefan Kuntz, Steven Eckhoff, Suhas Gundimeda, Sven Bachmann, Sébastien WENSKE, Taylor Khan, Terrance, TheCreeper, Thomas, Thomas Hipp, Tim Abell, Tim Howes, Tobias Frölich, Tobias Klauser, Tobias Nygren, Tobias Tom, Tom Jakubowski, Tully Robinson, Tyler Brazier, Tyler Kropp, Unrud, vapatel2, Veeti Paananen, Victor Buinsky, Vik, Vil Brekin, villekalliomaki, Vladimir Rusinov, wangguoliang, WangXi, Will Rouesnel, William A. Kennington III, wouter bolsterlee, xarx00, Xavier O., xjtdy888, Yannic A., yparitcher, 佛跳墙, 落心
|
||||
Jakob Borg, Audrius Butkevicius, Simon Frei, Tomasz Wilczyński, Alexander Graf, Alexandre Viau, Anderson Mesquita, André Colomb, Antony Male, Ben Schulz, bt90, Caleb Callaway, Daniel Harte, Emil Lundberg, Eric P, Evgeny Kuznetsov, greatroar, Lars K.W. Gohlke, Lode Hoste, Marcus B Spencer, Michael Ploujnikov, Ross Smith II, Stefan Tatschner, Tommy van der Vorst, Wulf Weich, Adam Piggott, Adel Qalieh, Aleksey Vasenev, Alessandro G., Alex Ionescu, Alex Lindeman, Alex Xu, Alexander Seiler, Alexandre Alves, Aman Gupta, Andreas Sommer, andresvia, Andrew Rabert, Andrey D, andyleap, Anjan Momi, Anthony Goeckner, Antoine Lamielle, Anur, Aranjedeath, ardevd, Arkadiusz Tymiński, Aroun, Arthur Axel fREW Schmidt, Artur Zubilewicz, Ashish Bhate, Aurélien Rainone, BAHADIR YILMAZ, Bart De Vries, Beat Reichenbach, Ben Shepherd, Ben Sidhom, Benedikt Heine, Benno Fünfstück, Benny Ng, boomsquared, Boqin Qin, Boris Rybalkin, Brendan Long, Catfriend1, Cathryne Linenweaver, Cedric Staniewski, Chih-Hsuan Yen, Choongkyu, Chris Howie, Chris Joel, Christian Kujau, Christian Prescott, chucic, cjc7373, Colin Kennedy, Cromefire_, Cyprien Devillez, d-volution, Dan, Daniel Barczyk, Daniel Bergmann, Daniel Martí, Daniel Padrta, Daniil Gentili, Darshil Chanpura, dashangcun, David Rimmer, DeflateAwning, Denis A., Dennis Wilson, derekriemer, DerRockWolf, desbma, Devon G. Redekopp, digital, Dimitri Papadopoulos Orfanos, Dmitry Saveliev, domain, Domenic Horner, Dominik Heidler, Elias Jarlebring, Elliot Huffman, Emil Hessman, Eng Zer Jun, entity0xfe, Eric Lesiuta, Erik Meitner, Evan Spensley, Federico Castagnini, Felix, Felix Ableitner, Felix Lampe, Felix Unterpaintner, Francois-Xavier Gsell, Frank Isemann, Gahl Saraf, georgespatton, ghjklw, Gilli Sigurdsson, Gleb Sinyavskiy, Graham Miln, Greg, guangwu, gudvinr, Gusted, Han Boetes, HansK-p, Harrison Jones, Hazem Krimi, Heiko Zuerker, Hireworks, Hugo Locurcio, Iain Barnett, Ian Johnson, ignacy123, Iskander Sharipov, Jaakko Hannikainen, Jack Croft, Jacob, Jake Peterson, James O'Beirne, James Patterson, Jaroslav Lichtblau, Jaroslav Malec, Jaspitta, Jaya Chithra, Jaya Kumar, Jeffery To, jelle van der Waa, Jens Diemer, Jochen Voss, Johan Vromans, John Rinehart, Jonas Thelemann, Jonathan, Jose Manuel Delicado, jtagcat, Julian Lehrhuber, Jörg Thalheim, Jędrzej Kula, Kapil Sareen, Karol Różycki, Kebin Liu, Keith Harrison, Kelong Cong, Ken'ichi Kamada, Kevin Allen, Kevin Bushiri, Kevin White, Jr., klemens, Kurt Fitzner, kylosus, Lars Lehtonen, Laurent Etiemble, Leo Arias, Liu Siyuan, Lord Landon Agahnim, LSmithx2, Lukas Lihotzki, Luke Hamburg, luzpaz, Majed Abdulaziz, Marc Laporte, Marcel Meyer, Marcin Dziadus, Marcus Legendre, Mario Majila, Mark Pulford, Martchus, Mateusz Naściszewski, Mateusz Ż, mathias4833, Matic Potočnik, Matt Burke, Matt Robenolt, Matteo Ruina, Maurizio Tomasi, Max, Max Schulze, MaximAL, Maximilian, Michael Jephcote, Michael Rienstra, MichaIng, Migelo, Mike Boone, MikeLund, MikolajTwarog, Mingxuan Lin, mv1005, Nate Morrison, nf, Nicholas Rishel, Nick Busey, Nico Stapelbroek, Nicolas Braud-Santoni, Nicolas Perraut, Niels Peter Roest, Nils Jakobi, NinoM4ster, Nitroretro, NoLooseEnds, Oliver Freyermuth, orangekame3, otbutz, overkill, Oyebanji Jacob Mayowa, Pablo, Pascal Jungblut, Paul Brit, Paul Donald, Pawel Palenica, perewa, Peter Badida, Peter Dave Hello, Peter Hoeg, Peter Marquardt, Phani Rithvij, Phil Davis, Philippe Schommers, Phill Luby, Piotr Bejda, polyfloyd, pullmerge, Quentin Hibon, Rahmi Pruitt, red_led, Robert Carosi, Roberto Santalla, Robin Schoonover, Roman Zaynetdinov, rubenbe, Ruslan Yevdokymov, Ryan Qian, Ryan Sullivan, Sacheendra Talluri, Scott Klupfel, sec65, Sergey Mishin, Sertonix, Severin von Wnuck-Lipinski, Shaarad Dalvi, Simon Mwepu, Simon Pickup, Sly_tom_cat, Sonu Kumar Saw, Stefan Kuntz, Steven Eckhoff, Suhas Gundimeda, Sven Bachmann, Sébastien WENSKE, Taylor Khan, Terrance, TheCreeper, Thomas, Thomas Hipp, Tim Abell, Tim Howes, Tobias Frölich, Tobias Klauser, Tobias Nygren, Tobias Tom, Tom Jakubowski, Tully Robinson, Tyler Brazier, Tyler Kropp, Unrud, vapatel2, Veeti Paananen, Victor Buinsky, Vik, Vil Brekin, villekalliomaki, Vladimir Rusinov, wangguoliang, WangXi, Will Rouesnel, William A. Kennington III, wouter bolsterlee, xarx00, Xavier O., xjtdy888, Yannic A., yparitcher, 佛跳墙, 落心
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -10,6 +10,7 @@ import "github.com/jmoiron/sqlx"
|
||||
|
||||
type txPreparedStmts struct {
|
||||
*sqlx.Tx
|
||||
|
||||
stmts map[string]*sqlx.Stmt
|
||||
}
|
||||
|
||||
|
||||
@@ -14,9 +14,10 @@ import (
|
||||
)
|
||||
|
||||
type folderDB struct {
|
||||
folderID string
|
||||
*baseDB
|
||||
|
||||
folderID string
|
||||
|
||||
localDeviceIdx int64
|
||||
deleteRetention time.Duration
|
||||
}
|
||||
|
||||
@@ -455,7 +455,7 @@ func (s *service) Serve(ctx context.Context) error {
|
||||
// due to a config change through the API, let that finish successfully.
|
||||
timeout, cancel := context.WithTimeout(context.Background(), s.shutdownTimeout)
|
||||
defer cancel()
|
||||
if err := srv.Shutdown(timeout); err == timeout.Err() {
|
||||
if err := srv.Shutdown(timeout); errors.Is(err, timeout.Err()) {
|
||||
srv.Close()
|
||||
}
|
||||
|
||||
@@ -546,7 +546,7 @@ func corsMiddleware(next http.Handler, allowFrameLoading bool) http.Handler {
|
||||
// See https://www.w3.org/TR/cors/ for details.
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
// Process OPTIONS requests
|
||||
if r.Method == "OPTIONS" {
|
||||
if r.Method == http.MethodOptions {
|
||||
// Add a generous access-control-allow-origin header for CORS requests
|
||||
w.Header().Add("Access-Control-Allow-Origin", "*")
|
||||
// Only GET/POST/OPTIONS Methods are supported
|
||||
@@ -557,7 +557,7 @@ func corsMiddleware(next http.Handler, allowFrameLoading bool) http.Handler {
|
||||
w.Header().Set("Access-Control-Max-Age", "600")
|
||||
|
||||
// Indicate that no content will be returned
|
||||
w.WriteHeader(204)
|
||||
w.WriteHeader(http.StatusNoContent)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
@@ -337,7 +337,7 @@ func formatOptionalPercentS(template string, username string) string {
|
||||
if nReps < 0 {
|
||||
nReps = 0
|
||||
}
|
||||
for i := 0; i < nReps; i++ {
|
||||
for range nReps {
|
||||
replacements = append(replacements, username)
|
||||
}
|
||||
return fmt.Sprintf(template, replacements...)
|
||||
|
||||
@@ -22,6 +22,7 @@ import (
|
||||
|
||||
type configMuxBuilder struct {
|
||||
*httprouter.Router
|
||||
|
||||
id protocol.DeviceID
|
||||
cfg config.Wrapper
|
||||
}
|
||||
|
||||
@@ -168,8 +168,8 @@ func (m *tokenCookieManager) createSession(username string, persistent bool, w h
|
||||
// either directly to us, or as used by the client towards a reverse
|
||||
// proxy who sends us headers.
|
||||
connectionIsHTTPS := r.TLS != nil ||
|
||||
strings.ToLower(r.Header.Get("x-forwarded-proto")) == "https" ||
|
||||
strings.Contains(strings.ToLower(r.Header.Get("forwarded")), "proto=https")
|
||||
strings.ToLower(r.Header.Get("X-Forwarded-Proto")) == "https" ||
|
||||
strings.Contains(strings.ToLower(r.Header.Get("Forwarded")), "proto=https")
|
||||
// If the connection is HTTPS, or *should* be HTTPS, set the Secure
|
||||
// bit in cookies.
|
||||
useSecureCookie := connectionIsHTTPS || m.guiCfg.UseTLS()
|
||||
|
||||
@@ -32,6 +32,7 @@ type Interface interface {
|
||||
|
||||
type cast struct {
|
||||
*suture.Supervisor
|
||||
|
||||
name string
|
||||
reader svcutil.ServiceWithError
|
||||
writer svcutil.ServiceWithError
|
||||
|
||||
@@ -8,6 +8,7 @@ package beacon
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"log/slog"
|
||||
"net"
|
||||
"time"
|
||||
@@ -93,7 +94,8 @@ func writeBroadcasts(ctx context.Context, inbox <-chan []byte, port int) error {
|
||||
_, err = conn.WriteTo(bs, dst)
|
||||
conn.SetWriteDeadline(time.Time{})
|
||||
|
||||
if nerr, ok := err.(net.Error); ok && nerr.Timeout() {
|
||||
var nerr net.Error
|
||||
if errors.As(err, &nerr) && nerr.Timeout() {
|
||||
// Write timeouts should not happen. We treat it as a fatal
|
||||
// error on the socket.
|
||||
l.Debugln(err)
|
||||
|
||||
@@ -165,6 +165,7 @@ func (cfg *Configuration) ProbeFreePorts() error {
|
||||
|
||||
type xmlConfiguration struct {
|
||||
Configuration
|
||||
|
||||
XMLName xml.Name `xml:"configuration"`
|
||||
}
|
||||
|
||||
@@ -684,7 +685,7 @@ func copyMatchingTag(from interface{}, to interface{}, tag string, shouldCopy fu
|
||||
panic(fmt.Sprintf("non equal types: %s != %s", fromType, toType))
|
||||
}
|
||||
|
||||
for i := 0; i < toStruct.NumField(); i++ {
|
||||
for i := range toStruct.NumField() {
|
||||
fromField := fromStruct.Field(i)
|
||||
toField := toStruct.Field(i)
|
||||
|
||||
|
||||
@@ -153,7 +153,7 @@ func (f FolderConfiguration) ModTimeWindow() time.Duration {
|
||||
}
|
||||
|
||||
func (f *FolderConfiguration) CreateMarker() error {
|
||||
if err := f.CheckPath(); err != ErrMarkerMissing {
|
||||
if err := f.CheckPath(); !errors.Is(err, ErrMarkerMissing) {
|
||||
return err
|
||||
}
|
||||
if f.MarkerName != DefaultMarkerName {
|
||||
|
||||
@@ -428,11 +428,12 @@ func migrateToConfigV12(cfg *Configuration) {
|
||||
var newDiscoServers []string
|
||||
var useDefault bool
|
||||
for _, addr := range cfg.Options.RawGlobalAnnServers {
|
||||
if addr == "udp4://announce.syncthing.net:22026" {
|
||||
switch addr {
|
||||
case "udp4://announce.syncthing.net:22026":
|
||||
useDefault = true
|
||||
} else if addr == "udp6://announce-v6.syncthing.net:22026" {
|
||||
case "udp6://announce-v6.syncthing.net:22026":
|
||||
useDefault = true
|
||||
} else {
|
||||
default:
|
||||
newDiscoServers = append(newDiscoServers, addr)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@ import "github.com/syncthing/syncthing/lib/config"
|
||||
// invalidListener is never valid
|
||||
type invalidListener struct {
|
||||
listenerFactory
|
||||
|
||||
err error
|
||||
}
|
||||
|
||||
@@ -25,6 +26,7 @@ func (i invalidListener) Valid(_ config.Configuration) error {
|
||||
// invalidDialer is never valid
|
||||
type invalidDialer struct {
|
||||
dialerFactory
|
||||
|
||||
err error
|
||||
}
|
||||
|
||||
|
||||
@@ -225,8 +225,9 @@ func getRateLimiter(m map[protocol.DeviceID]*rate.Limiter, deviceID protocol.Dev
|
||||
|
||||
// limitedReader is a rate limited io.Reader
|
||||
type limitedReader struct {
|
||||
reader io.Reader
|
||||
waiterHolder
|
||||
|
||||
reader io.Reader
|
||||
}
|
||||
|
||||
func (r *limitedReader) Read(buf []byte) (int, error) {
|
||||
@@ -239,8 +240,9 @@ func (r *limitedReader) Read(buf []byte) (int, error) {
|
||||
|
||||
// limitedWriter is a rate limited io.Writer
|
||||
type limitedWriter struct {
|
||||
writer io.Writer
|
||||
waiterHolder
|
||||
|
||||
writer io.Writer
|
||||
}
|
||||
|
||||
func (w *limitedWriter) Write(buf []byte) (int, error) {
|
||||
|
||||
@@ -39,6 +39,7 @@ func init() {
|
||||
|
||||
type quicDialer struct {
|
||||
commonDialer
|
||||
|
||||
registry *registry.Registry
|
||||
}
|
||||
|
||||
|
||||
@@ -39,10 +39,10 @@ func init() {
|
||||
|
||||
type quicListener struct {
|
||||
svcutil.ServiceWithError
|
||||
nat atomic.Uint64 // Holds a stun.NATType.
|
||||
|
||||
onAddressesChangedNotifier
|
||||
|
||||
nat atomic.Uint64 // Holds a stun.NATType.
|
||||
|
||||
uri *url.URL
|
||||
cfg config.Wrapper
|
||||
tlsCfg *tls.Config
|
||||
|
||||
@@ -42,6 +42,7 @@ func quicNetwork(uri *url.URL) string {
|
||||
type quicTlsConn struct {
|
||||
quic.Connection
|
||||
quic.Stream
|
||||
|
||||
// If we created this connection, we should be the ones closing it.
|
||||
createdConn net.PacketConn
|
||||
}
|
||||
|
||||
@@ -1340,7 +1340,7 @@ func (c *deviceConnectionTracker) accountAddedConnection(conn protocol.Connectio
|
||||
// how many total connections they want
|
||||
d := conn.DeviceID()
|
||||
c.connections[d] = append(c.connections[d], conn)
|
||||
c.wantConnections[d] = int(h.NumConnections)
|
||||
c.wantConnections[d] = h.NumConnections
|
||||
l.Debugf("Added connection for %s (now %d), they want %d connections", d.Short(), len(c.connections[d]), h.NumConnections)
|
||||
|
||||
// Update active connections metric
|
||||
|
||||
@@ -39,6 +39,7 @@ type tlsConn interface {
|
||||
// came from (type, priority).
|
||||
type internalConn struct {
|
||||
tlsConn
|
||||
|
||||
connType connType
|
||||
isLocal bool
|
||||
priority int
|
||||
|
||||
@@ -27,6 +27,7 @@ func init() {
|
||||
|
||||
type tcpDialer struct {
|
||||
commonDialer
|
||||
|
||||
registry *registry.Registry
|
||||
}
|
||||
|
||||
|
||||
@@ -81,11 +81,12 @@ func (t *tcpListener) serve(ctx context.Context) error {
|
||||
defer slog.InfoContext(ctx, "TCP listener shutting down", slogutil.Address(tcaddr))
|
||||
|
||||
var ipVersion nat.IPVersion
|
||||
if t.uri.Scheme == "tcp4" {
|
||||
switch t.uri.Scheme {
|
||||
case "tcp4":
|
||||
ipVersion = nat.IPv4Only
|
||||
} else if t.uri.Scheme == "tcp6" {
|
||||
case "tcp6":
|
||||
ipVersion = nat.IPv6Only
|
||||
} else {
|
||||
default:
|
||||
ipVersion = nat.IPvAny
|
||||
}
|
||||
mapping := t.natService.NewMapping(nat.TCP, ipVersion, tcaddr.IP, tcaddr.Port)
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
package connections
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"net"
|
||||
"net/url"
|
||||
"strconv"
|
||||
@@ -20,7 +21,8 @@ func fixupPort(uri *url.URL, defaultPort int) *url.URL {
|
||||
copyURI := *uri
|
||||
|
||||
host, port, err := net.SplitHostPort(uri.Host)
|
||||
if e, ok := err.(*net.AddrError); ok && strings.Contains(e.Err, "missing port") {
|
||||
e := &net.AddrError{}
|
||||
if errors.As(err, &e) && strings.Contains(e.Err, "missing port") {
|
||||
// addr is of the form "1.2.3.4" or "[fe80::1]"
|
||||
host = uri.Host
|
||||
if strings.HasPrefix(host, "[") && strings.HasSuffix(host, "]") {
|
||||
|
||||
@@ -64,6 +64,7 @@ func socksDialerFunction(u *url.URL, forward proxy.Dialer) (proxy.Dialer, error)
|
||||
// existing connection" shenanigans.
|
||||
type dialerConn struct {
|
||||
net.Conn
|
||||
|
||||
addr net.Addr
|
||||
}
|
||||
|
||||
|
||||
@@ -17,6 +17,7 @@ import (
|
||||
// A cachedFinder is a Finder with associated cache timeouts.
|
||||
type cachedFinder struct {
|
||||
Finder
|
||||
|
||||
cacheTime time.Duration
|
||||
negCacheTime time.Duration
|
||||
cache *cache
|
||||
|
||||
@@ -32,6 +32,8 @@ import (
|
||||
)
|
||||
|
||||
type globalClient struct {
|
||||
errorHolder
|
||||
|
||||
server string
|
||||
addrList AddressLister
|
||||
announceClient httpClient
|
||||
@@ -39,7 +41,6 @@ type globalClient struct {
|
||||
noAnnounce bool
|
||||
noLookup bool
|
||||
evLogger events.Logger
|
||||
errorHolder
|
||||
}
|
||||
|
||||
type httpClient interface {
|
||||
@@ -373,6 +374,7 @@ func queryBool(q url.Values, key string) bool {
|
||||
|
||||
type idCheckingHTTPClient struct {
|
||||
httpClient
|
||||
|
||||
id protocol.DeviceID
|
||||
}
|
||||
|
||||
@@ -472,7 +474,7 @@ func ipv4Identity(port int) string {
|
||||
}
|
||||
|
||||
func ipv6Identity(addr string) string {
|
||||
return fmt.Sprintf("IPv6 local multicast discovery on address %s", addr)
|
||||
return "IPv6 local multicast discovery on address " + addr
|
||||
}
|
||||
|
||||
func http2EnabledTransport(t *http.Transport) *http.Transport {
|
||||
|
||||
@@ -34,6 +34,8 @@ import (
|
||||
|
||||
type localClient struct {
|
||||
*suture.Supervisor
|
||||
*cache
|
||||
|
||||
myID protocol.DeviceID
|
||||
addrList AddressLister
|
||||
name string
|
||||
@@ -43,8 +45,6 @@ type localClient struct {
|
||||
localBcastStart time.Time
|
||||
localBcastTick <-chan time.Time
|
||||
forcedBcastTick chan time.Time
|
||||
|
||||
*cache
|
||||
}
|
||||
|
||||
const (
|
||||
|
||||
@@ -41,6 +41,7 @@ type Manager interface {
|
||||
|
||||
type manager struct {
|
||||
*suture.Supervisor
|
||||
|
||||
myID protocol.DeviceID
|
||||
cfg config.Wrapper
|
||||
cert tls.Certificate
|
||||
|
||||
@@ -524,7 +524,7 @@ func (s *bufferedSubscription) Since(id int, into []Event, timeout time.Duration
|
||||
into = append(into, s.buf[i])
|
||||
}
|
||||
}
|
||||
for i := 0; i < s.next; i++ {
|
||||
for i := range s.next {
|
||||
if s.buf[i].SubscriptionID > id {
|
||||
into = append(into, s.buf[i])
|
||||
}
|
||||
|
||||
@@ -340,6 +340,7 @@ func (*BasicFilesystem) underlying() (Filesystem, bool) {
|
||||
// basicFile implements the fs.File interface on top of an os.File
|
||||
type basicFile struct {
|
||||
*os.File
|
||||
|
||||
name string
|
||||
}
|
||||
|
||||
|
||||
@@ -397,10 +397,13 @@ func (f *caseFilesystem) checkCaseExisting(name string) error {
|
||||
type defaultRealCaser struct {
|
||||
cache *caseCache
|
||||
fs Filesystem
|
||||
mut sync.Mutex
|
||||
}
|
||||
|
||||
type caseCache = lru.TwoQueueCache[string, *caseNode]
|
||||
type caseCache struct {
|
||||
*lru.TwoQueueCache[string, *caseNode]
|
||||
|
||||
mut sync.Mutex
|
||||
}
|
||||
|
||||
func newCaseCache() *caseCache {
|
||||
cache, err := lru.New2Q[string, *caseNode](caseCacheItemLimit)
|
||||
@@ -408,7 +411,9 @@ func newCaseCache() *caseCache {
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return cache
|
||||
return &caseCache{
|
||||
TwoQueueCache: cache,
|
||||
}
|
||||
}
|
||||
|
||||
func (r *defaultRealCaser) realCase(name string) (string, error) {
|
||||
@@ -418,7 +423,7 @@ func (r *defaultRealCaser) realCase(name string) (string, error) {
|
||||
}
|
||||
|
||||
for _, comp := range PathComponents(name) {
|
||||
node := r.getExpireAdd(realName)
|
||||
node := r.cache.getExpireAdd(realName, r.fs)
|
||||
|
||||
if node.err != nil {
|
||||
return "", node.err
|
||||
@@ -444,18 +449,18 @@ func (r *defaultRealCaser) dropCache() {
|
||||
|
||||
// getExpireAdd gets an entry for the given key. If no entry exists, or it is
|
||||
// expired a new one is created and added to the cache.
|
||||
func (r *defaultRealCaser) getExpireAdd(key string) *caseNode {
|
||||
r.mut.Lock()
|
||||
defer r.mut.Unlock()
|
||||
node, ok := r.cache.Get(key)
|
||||
func (c *caseCache) getExpireAdd(key string, fs Filesystem) *caseNode {
|
||||
c.mut.Lock()
|
||||
defer c.mut.Unlock()
|
||||
node, ok := c.Get(key)
|
||||
if !ok {
|
||||
node := newCaseNode(key, r.fs)
|
||||
r.cache.Add(key, node)
|
||||
node := newCaseNode(key, fs)
|
||||
c.Add(key, node)
|
||||
return node
|
||||
}
|
||||
if node.expires.Before(time.Now()) {
|
||||
node = newCaseNode(key, r.fs)
|
||||
r.cache.Add(key, node)
|
||||
node = newCaseNode(key, fs)
|
||||
c.Add(key, node)
|
||||
}
|
||||
return node
|
||||
}
|
||||
|
||||
@@ -156,7 +156,7 @@ func testCaseFSStat(t *testing.T, fsys Filesystem) {
|
||||
|
||||
func BenchmarkWalkCaseFakeFS100k(b *testing.B) {
|
||||
const entries = 100_000
|
||||
fsys, paths, err := fakefsForBenchmark(entries, 0)
|
||||
fsys, paths, err := fakefsForTest(entries, 0)
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
@@ -260,7 +260,7 @@ func TestStressCaseFS(t *testing.T) {
|
||||
t.Skip("long test")
|
||||
}
|
||||
|
||||
fsys, paths, err := fakefsForBenchmark(10_000, 0)
|
||||
fsys, paths, err := fakefsForTest(10_000, 0, &OptionDetectCaseConflicts{})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -326,8 +326,8 @@ func doubleWalkFSWithOtherOps(fsys Filesystem, paths []string, otherOpEvery int,
|
||||
return nil
|
||||
}
|
||||
|
||||
func fakefsForBenchmark(nfiles int, latency time.Duration) (Filesystem, []string, error) {
|
||||
fsys := NewFilesystem(FilesystemTypeFake, fmt.Sprintf("fakefsForBenchmark?files=%d&insens=true&latency=%s", nfiles, latency))
|
||||
func fakefsForTest(nfiles int, latency time.Duration, opts ...Option) (Filesystem, []string, error) {
|
||||
fsys := NewFilesystem(FilesystemTypeFake, fmt.Sprintf("fakefsForBenchmark?files=%d&insens=true&latency=%s", nfiles, latency), opts...)
|
||||
|
||||
var paths []string
|
||||
if err := fsys.Walk("/", func(path string, info FileInfo, err error) error {
|
||||
|
||||
@@ -749,6 +749,7 @@ func (fs *fakeFS) reportMetricsPer(b *testing.B, divisor float64, unit string) {
|
||||
// opened for reading or writing, it's all good.
|
||||
type fakeFile struct {
|
||||
*fakeEntry
|
||||
|
||||
mut *sync.Mutex
|
||||
rng io.Reader
|
||||
seed int64
|
||||
|
||||
@@ -140,12 +140,12 @@ func (evType EventType) Merge(other EventType) EventType {
|
||||
}
|
||||
|
||||
func (evType EventType) String() string {
|
||||
switch {
|
||||
case evType == NonRemove:
|
||||
switch evType {
|
||||
case NonRemove:
|
||||
return "non-remove"
|
||||
case evType == Remove:
|
||||
case Remove:
|
||||
return "remove"
|
||||
case evType == Mixed:
|
||||
case Mixed:
|
||||
return "mixed"
|
||||
default:
|
||||
panic("bug: Unknown event type")
|
||||
|
||||
@@ -16,6 +16,7 @@ import (
|
||||
|
||||
type logFilesystem struct {
|
||||
Filesystem
|
||||
|
||||
// Number of filesystem layers on top of logFilesystem to skip when looking
|
||||
// for the true caller of the filesystem
|
||||
layers int
|
||||
|
||||
@@ -19,6 +19,7 @@ type database interface {
|
||||
|
||||
type mtimeFS struct {
|
||||
Filesystem
|
||||
|
||||
chtimes func(string, time.Time, time.Time) error
|
||||
db database
|
||||
folderID string
|
||||
@@ -170,6 +171,7 @@ func (f *mtimeFS) load(name string) (ondisk, virtual time.Time) {
|
||||
|
||||
type mtimeFileInfo struct {
|
||||
FileInfo
|
||||
|
||||
mtime time.Time
|
||||
}
|
||||
|
||||
@@ -179,6 +181,7 @@ func (m mtimeFileInfo) ModTime() time.Time {
|
||||
|
||||
type mtimeFile struct {
|
||||
File
|
||||
|
||||
fs *mtimeFS
|
||||
}
|
||||
|
||||
|
||||
@@ -63,6 +63,7 @@ type WalkFunc func(path string, info FileInfo, err error) error
|
||||
|
||||
type walkFilesystem struct {
|
||||
Filesystem
|
||||
|
||||
checkInfiniteRecursion bool
|
||||
}
|
||||
|
||||
|
||||
@@ -12,6 +12,7 @@ import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
@@ -50,13 +51,13 @@ func (resp *recordedResponse) ServeHTTP(w http.ResponseWriter, r *http.Request)
|
||||
|
||||
if strings.Contains(r.Header.Get("Accept-Encoding"), "gzip") {
|
||||
w.Header().Set("Content-Encoding", "gzip")
|
||||
w.Header().Set("Content-Length", fmt.Sprint(len(resp.gzip)))
|
||||
w.Header().Set("Content-Length", strconv.Itoa(len(resp.gzip)))
|
||||
w.WriteHeader(resp.status)
|
||||
_, _ = w.Write(resp.gzip)
|
||||
return
|
||||
}
|
||||
|
||||
w.Header().Set("Content-Length", fmt.Sprint(len(resp.data)))
|
||||
w.Header().Set("Content-Length", strconv.Itoa(len(resp.data)))
|
||||
w.WriteHeader(resp.status)
|
||||
_, _ = w.Write(resp.data)
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"crypto/sha256"
|
||||
"encoding/hex"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
@@ -353,7 +354,7 @@ func hashPatterns(patterns []Pattern) string {
|
||||
h.Write([]byte(pat.String()))
|
||||
h.Write([]byte("\n"))
|
||||
}
|
||||
return fmt.Sprintf("%x", h.Sum(nil))
|
||||
return hex.EncodeToString(h.Sum(nil))
|
||||
}
|
||||
|
||||
func loadIgnoreFile(fs fs.Filesystem, file string) (fs.File, fs.FileInfo, error) {
|
||||
|
||||
@@ -44,6 +44,7 @@ type folder struct {
|
||||
stateTracker
|
||||
config.FolderConfiguration
|
||||
*stats.FolderStatisticsReference
|
||||
|
||||
ioLimiter *semaphore.Semaphore
|
||||
|
||||
localFlags protocol.FlagLocal
|
||||
|
||||
@@ -48,6 +48,7 @@ func init() {
|
||||
// to be fetched.
|
||||
type pullBlockState struct {
|
||||
*sharedPullerState
|
||||
|
||||
block protocol.BlockInfo
|
||||
}
|
||||
|
||||
@@ -55,6 +56,7 @@ type pullBlockState struct {
|
||||
// copied.
|
||||
type copyBlocksState struct {
|
||||
*sharedPullerState
|
||||
|
||||
blocks []protocol.BlockInfo
|
||||
have int
|
||||
}
|
||||
|
||||
@@ -690,6 +690,7 @@ type ConnectionStats struct {
|
||||
|
||||
type ConnectionInfo struct {
|
||||
protocol.Statistics
|
||||
|
||||
Address string `json:"address"`
|
||||
Type string `json:"type"`
|
||||
IsLocal bool `json:"isLocal"`
|
||||
@@ -3484,6 +3485,7 @@ func redactPathError(err error) (error, bool) {
|
||||
|
||||
type redactedError struct {
|
||||
error
|
||||
|
||||
redacted error
|
||||
}
|
||||
|
||||
|
||||
@@ -356,7 +356,7 @@ func (s *Service) tryNATDevice(ctx context.Context, natd Device, intAddr Address
|
||||
l.Debugf("Error extending lease on %v (external port %d -> internal port %d): %v", natd.ID(), extPort, intAddr.Port, err)
|
||||
}
|
||||
|
||||
for i := 0; i < 10; i++ {
|
||||
for range 10 {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return []Address{}, ctx.Err()
|
||||
|
||||
@@ -44,7 +44,7 @@ func CreateAtomic(path string) (*AtomicWriter, error) {
|
||||
func CreateAtomicFilesystem(filesystem fs.Filesystem, path string) (*AtomicWriter, error) {
|
||||
// The security of this depends on the tempfile having secure
|
||||
// permissions, 0600, from the beginning. This is what os.CreateTemp
|
||||
// does. We have a test that verifies that that is the case, should this
|
||||
// does. We have a test that verifies that this is the case, should this
|
||||
// ever change in the standard library in the future.
|
||||
fd, err := TempFile(filesystem, filepath.Dir(path), TempPrefix)
|
||||
if err != nil {
|
||||
|
||||
@@ -48,7 +48,7 @@ func nextSuffix() string {
|
||||
// to remove the file when no longer needed.
|
||||
func TempFile(filesystem fs.Filesystem, dir, prefix string) (f fs.File, err error) {
|
||||
nconflict := 0
|
||||
for i := 0; i < 10000; i++ {
|
||||
for range 10000 {
|
||||
name := filepath.Join(dir, prefix+nextSuffix())
|
||||
f, err = filesystem.OpenFile(name, fs.OptReadWrite|fs.OptCreate|fs.OptExclusive, 0o600)
|
||||
if fs.IsExist(err) {
|
||||
|
||||
@@ -7,7 +7,6 @@
|
||||
package osutil
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/syncthing/syncthing/lib/fs"
|
||||
@@ -19,7 +18,7 @@ type TraversesSymlinkError struct {
|
||||
}
|
||||
|
||||
func (e *TraversesSymlinkError) Error() string {
|
||||
return fmt.Sprintf("traverses symlink: %s", e.path)
|
||||
return "traverses symlink: " + e.path
|
||||
}
|
||||
|
||||
// NotADirectoryError is an error indicating an expected path is not a directory
|
||||
@@ -28,7 +27,7 @@ type NotADirectoryError struct {
|
||||
}
|
||||
|
||||
func (e *NotADirectoryError) Error() string {
|
||||
return fmt.Sprintf("not a directory: %s", e.path)
|
||||
return "not a directory: " + e.path
|
||||
}
|
||||
|
||||
// TraversesSymlink returns an error if any path component of name (including name
|
||||
|
||||
@@ -9,7 +9,6 @@ package pmp
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"net"
|
||||
"strings"
|
||||
@@ -90,7 +89,7 @@ type wrapper struct {
|
||||
}
|
||||
|
||||
func (w *wrapper) ID() string {
|
||||
return fmt.Sprintf("NAT-PMP@%s", w.gatewayIP.String())
|
||||
return "NAT-PMP@" + w.gatewayIP.String()
|
||||
}
|
||||
|
||||
func (w *wrapper) GetLocalIPv4Address() net.IP {
|
||||
|
||||
@@ -14,6 +14,7 @@ import (
|
||||
|
||||
type countingReader struct {
|
||||
io.Reader
|
||||
|
||||
idString string
|
||||
tot atomic.Int64 // bytes
|
||||
last atomic.Int64 // unix nanos
|
||||
@@ -41,6 +42,7 @@ func (c *countingReader) Last() time.Time {
|
||||
|
||||
type countingWriter struct {
|
||||
io.Writer
|
||||
|
||||
idString string
|
||||
tot atomic.Int64 // bytes
|
||||
last atomic.Int64 // unix nanos
|
||||
|
||||
@@ -181,7 +181,7 @@ func luhnify(s string) (string, error) {
|
||||
}
|
||||
|
||||
res := make([]byte, 4*(13+1))
|
||||
for i := 0; i < 4; i++ {
|
||||
for i := range 4 {
|
||||
p := s[i*13 : (i+1)*13]
|
||||
copy(res[i*(13+1):], p)
|
||||
l, err := luhn32(p)
|
||||
@@ -199,7 +199,7 @@ func unluhnify(s string) (string, error) {
|
||||
}
|
||||
|
||||
res := make([]byte, 52)
|
||||
for i := 0; i < 4; i++ {
|
||||
for i := range 4 {
|
||||
p := s[i*(13+1) : (i+1)*(13+1)-1]
|
||||
copy(res[i*13:], p)
|
||||
l, err := luhn32(p)
|
||||
@@ -216,7 +216,7 @@ func unluhnify(s string) (string, error) {
|
||||
func chunkify(s string) string {
|
||||
chunks := len(s) / 7
|
||||
res := make([]byte, chunks*(7+1)-1)
|
||||
for i := 0; i < chunks; i++ {
|
||||
for i := range chunks {
|
||||
if i > 0 {
|
||||
res[i*(7+1)-1] = '-'
|
||||
}
|
||||
|
||||
@@ -171,6 +171,7 @@ func (e encryptedModel) Closed(err error) {
|
||||
// encrypts outgoing metadata and decrypts incoming responses.
|
||||
type encryptedConnection struct {
|
||||
ConnectionInfo
|
||||
|
||||
conn *rawConnection
|
||||
folderKeys *folderKeyRegistry
|
||||
keyGen *KeyGenerator
|
||||
|
||||
@@ -406,7 +406,7 @@ func (c *rawConnection) readerLoop() {
|
||||
for {
|
||||
msg, err := c.readMessage(fourByteBuf)
|
||||
if err != nil {
|
||||
if err == errUnknownMessage {
|
||||
if errors.Is(err, errUnknownMessage) {
|
||||
// Unknown message types are skipped, for future extensibility.
|
||||
continue
|
||||
}
|
||||
|
||||
@@ -41,7 +41,7 @@ func String(l int) string {
|
||||
var sb strings.Builder
|
||||
sb.Grow(l)
|
||||
|
||||
for i := 0; i < l; i++ {
|
||||
for range l {
|
||||
sb.WriteByte(randomCharset[defaultSecureRand.Intn(len(randomCharset))])
|
||||
}
|
||||
return sb.String()
|
||||
|
||||
12
lib/rc/rc.go
12
lib/rc/rc.go
@@ -144,7 +144,7 @@ func (p *Process) Stop() (*os.ProcessState, error) {
|
||||
default:
|
||||
}
|
||||
|
||||
if _, err := p.Post("/rest/system/shutdown", nil); err != nil && err != io.ErrUnexpectedEOF {
|
||||
if _, err := p.Post("/rest/system/shutdown", nil); err != nil && !errors.Is(err, io.ErrUnexpectedEOF) {
|
||||
// Unexpected EOF is somewhat expected here, as we may exit before
|
||||
// returning something sensible.
|
||||
return nil, err
|
||||
@@ -173,12 +173,12 @@ func (p *Process) Get(path string) ([]byte, error) {
|
||||
}
|
||||
|
||||
url := fmt.Sprintf("http://%s%s", p.addr, path)
|
||||
req, err := http.NewRequest("GET", url, nil)
|
||||
req, err := http.NewRequest(http.MethodGet, url, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
req.Header.Add("X-API-Key", APIKey)
|
||||
req.Header.Add("X-Api-Key", APIKey)
|
||||
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
@@ -198,12 +198,12 @@ func (p *Process) Post(path string, data io.Reader) ([]byte, error) {
|
||||
},
|
||||
}
|
||||
url := fmt.Sprintf("http://%s%s", p.addr, path)
|
||||
req, err := http.NewRequest("POST", url, data)
|
||||
req, err := http.NewRequest(http.MethodPost, url, data)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
req.Header.Add("X-API-Key", APIKey)
|
||||
req.Header.Add("X-Api-Key", APIKey)
|
||||
req.Header.Add("Content-Type", "application/json")
|
||||
|
||||
resp, err := client.Do(req)
|
||||
@@ -397,7 +397,7 @@ func (*Process) readResponse(resp *http.Response) ([]byte, error) {
|
||||
if err != nil {
|
||||
return bs, err
|
||||
}
|
||||
if resp.StatusCode != 200 {
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
return bs, errors.New(resp.Status)
|
||||
}
|
||||
return bs, nil
|
||||
|
||||
@@ -38,6 +38,7 @@ func NewClient(uri *url.URL, certs []tls.Certificate, timeout time.Duration) (Re
|
||||
|
||||
type commonClient struct {
|
||||
svcutil.ServiceWithError
|
||||
|
||||
invitations chan protocol.SessionInvitation
|
||||
}
|
||||
|
||||
|
||||
@@ -48,7 +48,7 @@ func (c *dynamicClient) serve(ctx context.Context) error {
|
||||
|
||||
l.Debugln(c, "looking up dynamic relays")
|
||||
|
||||
req, err := http.NewRequestWithContext(ctx, "GET", uri.String(), nil)
|
||||
req, err := http.NewRequestWithContext(ctx, http.MethodGet, uri.String(), nil)
|
||||
if err != nil {
|
||||
l.Debugln(c, "failed to lookup dynamic relays", err)
|
||||
return err
|
||||
|
||||
@@ -5,6 +5,7 @@ package client
|
||||
import (
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net"
|
||||
"net/url"
|
||||
@@ -132,12 +133,13 @@ func TestRelay(ctx context.Context, uri *url.URL, certs []tls.Certificate, sleep
|
||||
}()
|
||||
defer cancel()
|
||||
|
||||
for i := 0; i < times; i++ {
|
||||
for range times {
|
||||
_, err = GetInvitationFromRelay(ctx, uri, id, certs, timeout)
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
if _, ok := err.(*incorrectResponseCodeErr); !ok {
|
||||
incorrectResponseCodeErr := &incorrectResponseCodeErr{}
|
||||
if errors.As(err, &incorrectResponseCodeErr) {
|
||||
return fmt.Errorf("getting invitation: %w", err)
|
||||
}
|
||||
time.Sleep(sleep)
|
||||
|
||||
@@ -84,7 +84,7 @@ func newParallelHasher(ctx context.Context, folderID string, fs fs.Filesystem, w
|
||||
}
|
||||
|
||||
ph.wg.Add(workers)
|
||||
for i := 0; i < workers; i++ {
|
||||
for range workers {
|
||||
go ph.hashFiles(ctx)
|
||||
}
|
||||
|
||||
|
||||
@@ -681,9 +681,10 @@ func (w *walker) String() string {
|
||||
// A byteCounter gets bytes added to it via Update() and then provides the
|
||||
// Total() and one minute moving average Rate() in bytes per second.
|
||||
type byteCounter struct {
|
||||
total atomic.Int64
|
||||
metrics.EWMA
|
||||
stop chan struct{}
|
||||
|
||||
total atomic.Int64
|
||||
stop chan struct{}
|
||||
}
|
||||
|
||||
func newByteCounter() *byteCounter {
|
||||
|
||||
@@ -14,9 +14,9 @@ import (
|
||||
"crypto/sha256"
|
||||
"crypto/x509"
|
||||
"encoding/asn1"
|
||||
"encoding/hex"
|
||||
"encoding/pem"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"math/big"
|
||||
|
||||
@@ -135,7 +135,7 @@ func hashReader(r io.Reader) ([]byte, error) {
|
||||
if _, err := io.Copy(h, r); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
hash := []byte(fmt.Sprintf("%x", h.Sum(nil)))
|
||||
hash := []byte(hex.EncodeToString(h.Sum(nil)))
|
||||
return hash, nil
|
||||
}
|
||||
|
||||
|
||||
@@ -93,7 +93,7 @@ func FillNil(data any) {
|
||||
func fillNil(data any, skipDeprecated bool) {
|
||||
s := reflect.ValueOf(data).Elem()
|
||||
t := s.Type()
|
||||
for i := 0; i < s.NumField(); i++ {
|
||||
for i := range s.NumField() {
|
||||
if skipDeprecated && strings.HasPrefix(t.Field(i).Name, "Deprecated") {
|
||||
continue
|
||||
}
|
||||
@@ -123,7 +123,7 @@ func fillNil(data any, skipDeprecated bool) {
|
||||
if f.Type().Elem().Kind() != reflect.Struct {
|
||||
continue
|
||||
}
|
||||
for i := 0; i < f.Len(); i++ {
|
||||
for i := range f.Len() {
|
||||
fillNil(f.Index(i).Addr().Interface(), skipDeprecated)
|
||||
}
|
||||
case reflect.Struct:
|
||||
@@ -142,7 +142,7 @@ func FillNilSlices(data any) error {
|
||||
s := reflect.ValueOf(data).Elem()
|
||||
t := s.Type()
|
||||
|
||||
for i := 0; i < s.NumField(); i++ {
|
||||
for i := range s.NumField() {
|
||||
f := s.Field(i)
|
||||
tag := t.Field(i).Tag
|
||||
|
||||
|
||||
@@ -1,64 +0,0 @@
|
||||
// Copyright (C) 2019 The Syncthing Authors.
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public
|
||||
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
// You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
|
||||
package stun
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"net"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
stunFilterPriority = 10
|
||||
otherDataPriority = 100
|
||||
)
|
||||
|
||||
type stunFilter struct {
|
||||
ids map[string]time.Time
|
||||
mut sync.Mutex
|
||||
}
|
||||
|
||||
func (f *stunFilter) Outgoing(out []byte, _ net.Addr) {
|
||||
if !f.isStunPayload(out) {
|
||||
panic("not a stun payload")
|
||||
}
|
||||
f.mut.Lock()
|
||||
f.ids[string(out[8:20])] = time.Now().Add(time.Minute)
|
||||
f.reap()
|
||||
f.mut.Unlock()
|
||||
}
|
||||
|
||||
func (f *stunFilter) ClaimIncoming(in []byte, _ net.Addr) bool {
|
||||
if f.isStunPayload(in) {
|
||||
f.mut.Lock()
|
||||
_, ok := f.ids[string(in[8:20])]
|
||||
f.reap()
|
||||
f.mut.Unlock()
|
||||
return ok
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (*stunFilter) isStunPayload(data []byte) bool {
|
||||
// Need at least 20 bytes
|
||||
if len(data) < 20 {
|
||||
return false
|
||||
}
|
||||
|
||||
// First two bits always unset, and should always send magic cookie.
|
||||
return data[0]&0xc0 == 0 && bytes.Equal(data[4:8], []byte{0x21, 0x12, 0xA4, 0x42})
|
||||
}
|
||||
|
||||
func (f *stunFilter) reap() {
|
||||
now := time.Now()
|
||||
for id, timeout := range f.ids {
|
||||
if timeout.Before(now) {
|
||||
delete(f.ids, id)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -45,7 +45,7 @@ func (m *Internals) SetIgnores(folderID string, content []string) error {
|
||||
}
|
||||
|
||||
func (m *Internals) DownloadBlock(ctx context.Context, deviceID protocol.DeviceID, folderID string, path string, blockNumber int, blockInfo protocol.BlockInfo, allowFromTemporary bool) ([]byte, error) {
|
||||
return m.model.RequestGlobal(ctx, deviceID, folderID, path, int(blockNumber), blockInfo.Offset, blockInfo.Size, blockInfo.Hash, allowFromTemporary)
|
||||
return m.model.RequestGlobal(ctx, deviceID, folderID, path, blockNumber, blockInfo.Offset, blockInfo.Size, blockInfo.Hash, allowFromTemporary)
|
||||
}
|
||||
|
||||
func (m *Internals) BlockAvailability(folderID string, file protocol.FileInfo, block protocol.BlockInfo) ([]model.Availability, error) {
|
||||
|
||||
@@ -200,6 +200,7 @@ func NewCertificateInMemory(commonName string, lifetimeDays int) (tls.Certificat
|
||||
|
||||
type DowngradingListener struct {
|
||||
net.Listener
|
||||
|
||||
TLSConfig *tls.Config
|
||||
}
|
||||
|
||||
@@ -208,7 +209,7 @@ func (l *DowngradingListener) Accept() (net.Conn, error) {
|
||||
|
||||
// We failed to identify the socket type, pretend that everything is fine,
|
||||
// and pass it to the underlying handler, and let them deal with it.
|
||||
if err == ErrIdentificationFailed {
|
||||
if errors.Is(err, ErrIdentificationFailed) {
|
||||
return conn, nil
|
||||
}
|
||||
|
||||
@@ -244,9 +245,10 @@ func (l *DowngradingListener) AcceptNoWrapTLS() (net.Conn, bool, error) {
|
||||
}
|
||||
|
||||
type UnionedConnection struct {
|
||||
net.Conn
|
||||
|
||||
first [1]byte
|
||||
firstDone bool
|
||||
net.Conn
|
||||
}
|
||||
|
||||
func (c *UnionedConnection) Read(b []byte) (n int, err error) {
|
||||
|
||||
@@ -119,7 +119,7 @@ func CompareVersions(a, b string) Relation {
|
||||
}
|
||||
|
||||
// First compare major-minor-patch versions
|
||||
for i := 0; i < minlen; i++ {
|
||||
for i := range minlen {
|
||||
if arel[i] < brel[i] {
|
||||
if i == 0 {
|
||||
// major version difference
|
||||
@@ -168,7 +168,7 @@ func CompareVersions(a, b string) Relation {
|
||||
}
|
||||
|
||||
// Compare prerelease strings
|
||||
for i := 0; i < minlen; i++ {
|
||||
for i := range minlen {
|
||||
switch av := apre[i].(type) {
|
||||
case int:
|
||||
switch bv := bpre[i].(type) {
|
||||
|
||||
@@ -222,7 +222,7 @@ func upgradeToURL(archiveName, binary string, url string) error {
|
||||
func readRelease(archiveName, dir, url string) (string, error) {
|
||||
l.Debugf("loading %q", url)
|
||||
|
||||
req, err := http.NewRequest("GET", url, nil)
|
||||
req, err := http.NewRequest(http.MethodGet, url, nil)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
@@ -254,15 +254,9 @@ func readTarGz(archiveName, dir string, r io.Reader) (string, error) {
|
||||
var sig []byte
|
||||
|
||||
// Iterate through the files in the archive.
|
||||
i := 0
|
||||
for {
|
||||
if i >= maxArchiveMembers {
|
||||
break
|
||||
}
|
||||
i++
|
||||
|
||||
for range maxArchiveMembers {
|
||||
hdr, err := tr.Next()
|
||||
if err == io.EOF {
|
||||
if errors.Is(err, io.EOF) {
|
||||
// end of tar archive
|
||||
break
|
||||
}
|
||||
|
||||
@@ -56,8 +56,6 @@ type IGDService struct {
|
||||
URN string
|
||||
LocalIPv4 net.IP
|
||||
Interface *net.Interface
|
||||
|
||||
nat.Service
|
||||
}
|
||||
|
||||
// AddPinhole adds an IPv6 pinhole in accordance to http://upnp.org/specs/gw/UPnP-gw-WANIPv6FirewallControl-v1-Service.pdf
|
||||
@@ -134,11 +132,12 @@ func (s *IGDService) AddPinhole(ctx context.Context, protocol nat.Protocol, intA
|
||||
|
||||
func (s *IGDService) tryAddPinholeForIP6(ctx context.Context, protocol nat.Protocol, port int, duration time.Duration, ip net.IP) error {
|
||||
var protoNumber int
|
||||
if protocol == nat.TCP {
|
||||
switch protocol {
|
||||
case nat.TCP:
|
||||
protoNumber = 6
|
||||
} else if protocol == nat.UDP {
|
||||
case nat.UDP:
|
||||
protoNumber = 17
|
||||
} else {
|
||||
default:
|
||||
return errors.New("protocol not supported")
|
||||
}
|
||||
|
||||
@@ -260,11 +259,12 @@ func (s *IGDService) GetLocalIPv4Address() net.IP {
|
||||
// SupportsIPVersion checks whether this is a WANIPv6FirewallControl device,
|
||||
// in which case pinholing instead of port mapping should be done
|
||||
func (s *IGDService) SupportsIPVersion(version nat.IPVersion) bool {
|
||||
if version == nat.IPvAny {
|
||||
switch version {
|
||||
case nat.IPvAny:
|
||||
return true
|
||||
} else if version == nat.IPv6Only {
|
||||
case nat.IPv6Only:
|
||||
return s.URN == urnWANIPv6FirewallControlV1
|
||||
} else if version == nat.IPv4Only {
|
||||
case nat.IPv4Only:
|
||||
return s.URN != urnWANIPv6FirewallControlV1
|
||||
}
|
||||
|
||||
|
||||
@@ -86,7 +86,7 @@ type UnsupportedDeviceTypeError struct {
|
||||
}
|
||||
|
||||
func (e *UnsupportedDeviceTypeError) Error() string {
|
||||
return fmt.Sprintf("Unsupported UPnP device of type %s", e.deviceType)
|
||||
return "unsupported UPnP device of type " + e.deviceType
|
||||
}
|
||||
|
||||
const (
|
||||
@@ -229,7 +229,8 @@ USER-AGENT: syncthing/%s
|
||||
|
||||
_, err = socket.WriteTo(search, &ssdp)
|
||||
if err != nil {
|
||||
if e, ok := err.(net.Error); !ok || !e.Timeout() {
|
||||
var e net.Error
|
||||
if !errors.As(err, &e) || !e.Timeout() {
|
||||
l.Debugln("UPnP discovery: sending search request:", err)
|
||||
}
|
||||
return
|
||||
@@ -578,7 +579,7 @@ func soapRequestWithIP(ctx context.Context, url, service, function, message stri
|
||||
|
||||
body := fmt.Sprintf(template, message)
|
||||
|
||||
req, err := http.NewRequestWithContext(ctx, "POST", url, strings.NewReader(body))
|
||||
req, err := http.NewRequestWithContext(ctx, http.MethodPost, url, strings.NewReader(body))
|
||||
if err != nil {
|
||||
return resp, err
|
||||
}
|
||||
|
||||
@@ -249,7 +249,7 @@ func clear(v interface{}, since int) error {
|
||||
s := reflect.ValueOf(v).Elem()
|
||||
t := s.Type()
|
||||
|
||||
for i := 0; i < s.NumField(); i++ {
|
||||
for i := range s.NumField() {
|
||||
f := s.Field(i)
|
||||
tag := t.Field(i).Tag
|
||||
|
||||
|
||||
@@ -41,6 +41,7 @@ var (
|
||||
|
||||
type FailureReport struct {
|
||||
FailureData
|
||||
|
||||
Count int
|
||||
Version string
|
||||
}
|
||||
|
||||
@@ -89,10 +89,10 @@ func (s *Service) reportData(ctx context.Context, urVersion int, preview bool) (
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
totFiles += int(global.Files)
|
||||
totFiles += global.Files
|
||||
totBytes += global.Bytes
|
||||
if int(global.Files) > maxFiles {
|
||||
maxFiles = int(global.Files)
|
||||
if global.Files > maxFiles {
|
||||
maxFiles = global.Files
|
||||
}
|
||||
if global.Bytes > maxBytes {
|
||||
maxBytes = global.Bytes
|
||||
@@ -366,7 +366,7 @@ func (s *Service) sendUsageReport(ctx context.Context) error {
|
||||
},
|
||||
},
|
||||
}
|
||||
req, err := http.NewRequestWithContext(ctx, "POST", s.cfg.Options().URURL, &b)
|
||||
req, err := http.NewRequestWithContext(ctx, http.MethodPost, s.cfg.Options().URURL, &b)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -436,7 +436,7 @@ func CpuBench(ctx context.Context, iterations int, duration time.Duration) float
|
||||
r.Read(bs)
|
||||
|
||||
var perf float64
|
||||
for i := 0; i < iterations; i++ {
|
||||
for range iterations {
|
||||
if v := cpuBenchOnce(ctx, duration, bs); v > perf {
|
||||
perf = v
|
||||
}
|
||||
|
||||
@@ -101,8 +101,9 @@ func (v external) Archive(filePath string) error {
|
||||
combinedOutput, err := cmd.CombinedOutput()
|
||||
l.Debugln("external command output:", string(combinedOutput))
|
||||
if err != nil {
|
||||
if eerr, ok := err.(*exec.ExitError); ok && len(eerr.Stderr) > 0 {
|
||||
return fmt.Errorf("%v: %v", err, string(eerr.Stderr))
|
||||
eerr := &exec.ExitError{}
|
||||
if errors.As(err, &eerr) && len(eerr.Stderr) > 0 {
|
||||
return fmt.Errorf("%w: %v", err, string(eerr.Stderr))
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -55,6 +55,7 @@ func New(cfg config.FolderConfiguration) (Versioner, error) {
|
||||
|
||||
type versionerWithErrorContext struct {
|
||||
Versioner
|
||||
|
||||
vtype string
|
||||
}
|
||||
|
||||
|
||||
@@ -449,10 +449,11 @@ func (a *aggregator) updateConfig(folderCfg config.FolderConfiguration) {
|
||||
}
|
||||
|
||||
func updateInProgressSet(event events.Event, inProgress map[string]struct{}) {
|
||||
if event.Type == events.ItemStarted {
|
||||
switch event.Type {
|
||||
case events.ItemStarted:
|
||||
path := event.Data.(map[string]string)["item"]
|
||||
inProgress[path] = struct{}{}
|
||||
} else if event.Type == events.ItemFinished {
|
||||
case events.ItemFinished:
|
||||
path := event.Data.(map[string]interface{})["item"].(string)
|
||||
delete(inProgress, path)
|
||||
}
|
||||
|
||||
@@ -27,7 +27,7 @@ level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
|
||||
.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
|
||||
.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
|
||||
..
|
||||
.TH "STDISCOSRV" "1" "Sep 14, 2025" "v2.0.0" "Syncthing"
|
||||
.TH "STDISCOSRV" "1" "Oct 23, 2025" "v2.0.0" "Syncthing"
|
||||
.SH NAME
|
||||
stdiscosrv \- Syncthing Discovery Server
|
||||
.SH SYNOPSIS
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user