Selaa lähdekoodia

Merge branch 'main' into v2

* main:
  fix(strelaysrv): make the session limiter session-dependent (fixes #10072) (#10073)
  build: artifact uploads destination OCI
  chore(gui, man, authors): update docs, translations, and contributors
  chore(gui): use go list --deps for dependency list (#10071)
Jakob Borg 6 kuukautta sitten
vanhempi
sitoutus
2159dfd27d

+ 35 - 19
.github/workflows/build-syncthing.yaml

@@ -734,10 +734,13 @@ jobs:
       - name: Push artifacts
         uses: docker://docker.io/rclone/rclone:latest
         env:
-          RCLONE_CONFIG_OBJSTORE_TYPE: ${{ secrets.AZUREBLOB_TYPE }}
-          RCLONE_CONFIG_OBJSTORE_ACCOUNT: ${{ secrets.AZUREBLOB_ACCOUNT }}
-          RCLONE_CONFIG_OBJSTORE_KEY: ${{ secrets.AZUREBLOB_KEY }}
-          RCLONE_AZUREBLOB_ACCESS_TIER: hot
+          RCLONE_CONFIG_OBJSTORE_TYPE: s3
+          RCLONE_CONFIG_OBJSTORE_PROVIDER: ${{ secrets.S3_PROVIDER }}
+          RCLONE_CONFIG_OBJSTORE_ACCESS_KEY_ID: ${{ secrets.S3_ACCESS_KEY_ID }}
+          RCLONE_CONFIG_OBJSTORE_SECRET_ACCESS_KEY: ${{ secrets.S3_SECRET_ACCESS_KEY }}
+          RCLONE_CONFIG_OBJSTORE_ENDPOINT: ${{ secrets.S3_ENDPOINT }}
+          RCLONE_CONFIG_OBJSTORE_REGION: ${{ secrets.S3_REGION }}
+          RCLONE_CONFIG_OBJSTORE_ACL: public-read
         with:
           args: sync -v packages objstore:nightly
 
@@ -785,20 +788,26 @@ jobs:
       - name: Push to object store (${{ env.VERSION }})
         uses: docker://docker.io/rclone/rclone:latest
         env:
-          RCLONE_CONFIG_OBJSTORE_TYPE: ${{ secrets.AZUREBLOB_TYPE }}
-          RCLONE_CONFIG_OBJSTORE_ACCOUNT: ${{ secrets.AZUREBLOB_ACCOUNT }}
-          RCLONE_CONFIG_OBJSTORE_KEY: ${{ secrets.AZUREBLOB_KEY }}
-          RCLONE_AZUREBLOB_ACCESS_TIER: cool
+          RCLONE_CONFIG_OBJSTORE_TYPE: s3
+          RCLONE_CONFIG_OBJSTORE_PROVIDER: ${{ secrets.S3_PROVIDER }}
+          RCLONE_CONFIG_OBJSTORE_ACCESS_KEY_ID: ${{ secrets.S3_ACCESS_KEY_ID }}
+          RCLONE_CONFIG_OBJSTORE_SECRET_ACCESS_KEY: ${{ secrets.S3_SECRET_ACCESS_KEY }}
+          RCLONE_CONFIG_OBJSTORE_ENDPOINT: ${{ secrets.S3_ENDPOINT }}
+          RCLONE_CONFIG_OBJSTORE_REGION: ${{ secrets.S3_REGION }}
+          RCLONE_CONFIG_OBJSTORE_ACL: public-read
         with:
           args: sync -v packages objstore:release/${{ env.VERSION }}
 
       - name: Push to object store (latest)
         uses: docker://docker.io/rclone/rclone:latest
         env:
-          RCLONE_CONFIG_OBJSTORE_TYPE: ${{ secrets.AZUREBLOB_TYPE }}
-          RCLONE_CONFIG_OBJSTORE_ACCOUNT: ${{ secrets.AZUREBLOB_ACCOUNT }}
-          RCLONE_CONFIG_OBJSTORE_KEY: ${{ secrets.AZUREBLOB_KEY }}
-          RCLONE_AZUREBLOB_ACCESS_TIER: hot
+          RCLONE_CONFIG_OBJSTORE_TYPE: s3
+          RCLONE_CONFIG_OBJSTORE_PROVIDER: ${{ secrets.S3_PROVIDER }}
+          RCLONE_CONFIG_OBJSTORE_ACCESS_KEY_ID: ${{ secrets.S3_ACCESS_KEY_ID }}
+          RCLONE_CONFIG_OBJSTORE_SECRET_ACCESS_KEY: ${{ secrets.S3_SECRET_ACCESS_KEY }}
+          RCLONE_CONFIG_OBJSTORE_ENDPOINT: ${{ secrets.S3_ENDPOINT }}
+          RCLONE_CONFIG_OBJSTORE_REGION: ${{ secrets.S3_REGION }}
+          RCLONE_CONFIG_OBJSTORE_ACL: public-read
         with:
           args: sync -v objstore:release/${{ env.VERSION }} objstore:release/latest
 
@@ -849,9 +858,13 @@ jobs:
       - name: Pull archive
         uses: docker://docker.io/rclone/rclone:latest
         env:
-          RCLONE_CONFIG_OBJSTORE_TYPE: ${{ secrets.AZUREBLOB_TYPE }}
-          RCLONE_CONFIG_OBJSTORE_ACCOUNT: ${{ secrets.AZUREBLOB_ACCOUNT }}
-          RCLONE_CONFIG_OBJSTORE_KEY: ${{ secrets.AZUREBLOB_KEY }}
+          RCLONE_CONFIG_OBJSTORE_TYPE: s3
+          RCLONE_CONFIG_OBJSTORE_PROVIDER: ${{ secrets.S3_PROVIDER }}
+          RCLONE_CONFIG_OBJSTORE_ACCESS_KEY_ID: ${{ secrets.S3_ACCESS_KEY_ID }}
+          RCLONE_CONFIG_OBJSTORE_SECRET_ACCESS_KEY: ${{ secrets.S3_SECRET_ACCESS_KEY }}
+          RCLONE_CONFIG_OBJSTORE_ENDPOINT: ${{ secrets.S3_ENDPOINT }}
+          RCLONE_CONFIG_OBJSTORE_REGION: ${{ secrets.S3_REGION }}
+          RCLONE_CONFIG_OBJSTORE_ACL: public-read
         with:
           args: sync objstore:apt/dists dists
 
@@ -868,10 +881,13 @@ jobs:
       - name: Push archive
         uses: docker://docker.io/rclone/rclone:latest
         env:
-          RCLONE_CONFIG_OBJSTORE_TYPE: ${{ secrets.AZUREBLOB_TYPE }}
-          RCLONE_CONFIG_OBJSTORE_ACCOUNT: ${{ secrets.AZUREBLOB_ACCOUNT }}
-          RCLONE_CONFIG_OBJSTORE_KEY: ${{ secrets.AZUREBLOB_KEY }}
-          RCLONE_AZUREBLOB_ACCESS_TIER: hot
+          RCLONE_CONFIG_OBJSTORE_TYPE: s3
+          RCLONE_CONFIG_OBJSTORE_PROVIDER: ${{ secrets.S3_PROVIDER }}
+          RCLONE_CONFIG_OBJSTORE_ACCESS_KEY_ID: ${{ secrets.S3_ACCESS_KEY_ID }}
+          RCLONE_CONFIG_OBJSTORE_SECRET_ACCESS_KEY: ${{ secrets.S3_SECRET_ACCESS_KEY }}
+          RCLONE_CONFIG_OBJSTORE_ENDPOINT: ${{ secrets.S3_ENDPOINT }}
+          RCLONE_CONFIG_OBJSTORE_REGION: ${{ secrets.S3_REGION }}
+          RCLONE_CONFIG_OBJSTORE_ACL: public-read
         with:
           args: sync -v dists objstore:apt/dists
 

+ 1 - 1
AUTHORS

@@ -223,7 +223,7 @@ Marc Laporte (marclaporte) <[email protected]> <[email protected]>
 Marc Pujol (kilburn) <[email protected]>
 Marcin Dziadus (marcindziadus) <[email protected]>
 marco-m <[email protected]>
-Marcus B Spencer <[email protected]>
+Marcus B Spencer <[email protected]> <[email protected]>
 Marcus Legendre <[email protected]>
 Mario Majila <[email protected]>
 Mark Pulford (mpx) <[email protected]>

+ 1 - 1
cmd/strelaysrv/listener.go

@@ -184,7 +184,7 @@ func protocolConnectionHandler(tcpConn net.Conn, config *tls.Config, token strin
 					continue
 				}
 				// requestedPeer is the server, id is the client
-				ses := newSession(requestedPeer, id, sessionLimiter, globalLimiter)
+				ses := newSession(requestedPeer, id, sessionLimitBps, globalLimiter)
 
 				go ses.Serve()
 

+ 0 - 4
cmd/strelaysrv/main.go

@@ -51,7 +51,6 @@ var (
 	globalLimitBps    int
 	overLimit         atomic.Bool
 	descriptorLimit   int64
-	sessionLimiter    *rate.Limiter
 	globalLimiter     *rate.Limiter
 	networkBufferSize int
 
@@ -228,9 +227,6 @@ func main() {
 		}
 	}
 
-	if sessionLimitBps > 0 {
-		sessionLimiter = rate.NewLimiter(rate.Limit(sessionLimitBps), 2*sessionLimitBps)
-	}
 	if globalLimitBps > 0 {
 		globalLimiter = rate.NewLimiter(rate.Limit(globalLimitBps), 2*globalLimitBps)
 	}

+ 7 - 1
cmd/strelaysrv/session.go

@@ -27,7 +27,7 @@ var (
 	bytesProxied    atomic.Int64
 )
 
-func newSession(serverid, clientid syncthingprotocol.DeviceID, sessionRateLimit, globalRateLimit *rate.Limiter) *session {
+func newSession(serverid, clientid syncthingprotocol.DeviceID, sessionLimitBps int, globalRateLimit *rate.Limiter) *session {
 	serverkey := make([]byte, 32)
 	_, err := rand.Read(serverkey)
 	if err != nil {
@@ -40,12 +40,17 @@ func newSession(serverid, clientid syncthingprotocol.DeviceID, sessionRateLimit,
 		return nil
 	}
 
+	var sessionRateLimit *rate.Limiter
+	if sessionLimitBps > 0 {
+		sessionRateLimit = rate.NewLimiter(rate.Limit(sessionLimitBps), 2*sessionLimitBps)
+	}
 	ses := &session{
 		serverkey: serverkey,
 		serverid:  serverid,
 		clientkey: clientkey,
 		clientid:  clientid,
 		rateLimit: makeRateLimitFunc(sessionRateLimit, globalRateLimit),
+		limiter:   sessionRateLimit,
 		connsChan: make(chan net.Conn),
 		conns:     make([]net.Conn, 0, 2),
 	}
@@ -109,6 +114,7 @@ type session struct {
 	clientid  syncthingprotocol.DeviceID
 
 	rateLimit func(bytes int)
+	limiter   *rate.Limiter
 
 	connsChan chan net.Conn
 	conns     []net.Conn

+ 2 - 0
gui/default/assets/lang/lang-en-GB.json

@@ -27,6 +27,7 @@
     "Allowed Networks": "Allowed Networks",
     "Alphabetic": "Alphabetic",
     "Altered by ignoring deletes.": "Altered by ignoring deletes.",
+    "Always turned on when the folder type is \"{%foldertype%}\".": "Always turned on when the folder type is \"{{foldertype}}\".",
     "An external command handles the versioning. It has to remove the file from the shared folder. If the path to the application contains spaces, it should be quoted.": "An external command handles the versioning. It has to remove the file from the shared folder. If the path to the application contains spaces, it should be quoted.",
     "Anonymous Usage Reporting": "Anonymous Usage Reporting",
     "Anonymous usage report format has changed. Would you like to move to the new format?": "Anonymous usage report format has changed. Would you like to move to the new format?",
@@ -52,6 +53,7 @@
     "Body:": "Body:",
     "Bugs": "Bugs",
     "Cancel": "Cancel",
+    "Cannot be enabled when the folder type is \"{%foldertype%}\".": "Cannot be enabled when the folder type is \"{{foldertype}}\".",
     "Changelog": "Changelog",
     "Clean out after": "Clean out after",
     "Cleaning Versions": "Cleaning Versions",

+ 2 - 0
gui/default/assets/lang/lang-sv.json

@@ -27,6 +27,7 @@
     "Allowed Networks": "Tillåtna nätverk",
     "Alphabetic": "Alfabetisk",
     "Altered by ignoring deletes.": "Ändrad genom att ignorera borttagningar.",
+    "Always turned on when the folder type is \"{%foldertype%}\".": "Alltid på när mapptypen är \"{{foldertype}}\".",
     "An external command handles the versioning. It has to remove the file from the shared folder. If the path to the application contains spaces, it should be quoted.": "Ett externt kommando hanterar versionen. Det måste ta bort filen från den delade mappen. Om sökvägen till applikationen innehåller mellanslag bör den citeras.",
     "Anonymous Usage Reporting": "Anonym användarstatistiksrapportering",
     "Anonymous usage report format has changed. Would you like to move to the new format?": "Anonymt användningsrapportformat har ändrats. Vill du flytta till det nya formatet?",
@@ -52,6 +53,7 @@
     "Body:": "Meddelande:",
     "Bugs": "Felrapporter",
     "Cancel": "Avbryt",
+    "Cannot be enabled when the folder type is \"{%foldertype%}\".": "Kan inte aktiveras när mapptypen är \"{{foldertype}}\".",
     "Changelog": "Ändringslogg",
     "Clean out after": "Rensa efteråt",
     "Cleaning Versions": "Rensningsversioner",

+ 9 - 32
gui/default/syncthing/core/aboutModalView.html

@@ -51,73 +51,51 @@ Jakob Borg, Audrius Butkevicius, Jesse Lucas, Simon Frei, Tomasz Wilczyński, Al
           <li><a href="https://golang.org/">The Go Programming Language</a>, Copyright &copy; 2009 The Go Authors.</li>
           <li><a href="https://prometheus.io/">Prometheus</a>, Copyright &copy; 2012-2015 The Prometheus Authors.</li>
           <li><a href="https://github.com/AudriusButkevicius/recli">AudriusButkevicius/recli</a>, Copyright &copy; 2019 Audrius Butkevicius.</li>
-          <li><a href="https://github.com/Azure/azure-sdk-for-go">Azure/azure-sdk-for-go</a>, Copyright &copy; Microsoft Corporation.</li>
           <li><a href="https://github.com/Azure/go-ntlmssp">Azure/go-ntlmssp</a>, Copyright &copy; 2016 Microsoft.</li>
           <li><a href="https://github.com/alecthomas/kong">alecthomas/kong</a>, Copyright &copy; 2018 Alec Thomas.</li>
-          <li><a href="https://github.com/aws/aws-sdk-go">aws/aws-sdk-go</a>, Copyright &copy; 2015 Amazon.com, Inc. or its affiliates, Copyright 2014-2015 Stripe, Inc.</li>
           <li><a href="https://github.com/beorn7/perks">beorn7/perks</a>, Copyright &copy; 2013 Blake Mizerany.</li>
           <li><a href="https://github.com/calmh/incontainer">calmh/incontainer</a>, Copyright &copy; 2022 calmh.</li>
           <li><a href="https://github.com/calmh/xdr">calmh/xdr</a>, Copyright &copy; 2014 Jakob Borg.</li>
           <li><a href="https://github.com/ccding/go-stun">ccding/go-stun</a>, Copyright &copy; 2016 Cong Ding.</li>
-          <li><a href="https://github.com/cenkalti/backoff">cenkalti/backoff</a>, Copyright &copy; 2014 Cenk Altı.</li>
-          <li><a href="https://github.com/certifi/gocertifi">certifi/gocertifi</a>, Copyright &copy; 2025, the certifi/gocertifi authors.</li>
-          <li><a href="https://github.com/cespare/xxhash">cespare/xxhash</a>, Copyright &copy; 2016 Caleb Spare.</li>
+          <li><a href="https://github.com/cespare/xxhash/v2">cespare/xxhash/v2</a>, Copyright &copy; 2016 Caleb Spare.</li>
           <li><a href="https://github.com/chmduquesne/rollinghash">chmduquesne/rollinghash</a>, Copyright &copy; 2015 Christophe-Marie Duquesne.</li>
-          <li><a href="https://github.com/cpuguy83/go-md2man">cpuguy83/go-md2man</a>, Copyright &copy; 2014 Brian Goff.</li>
-          <li><a href="https://github.com/d4l3k/messagediff">d4l3k/messagediff</a>, Copyright &copy; 2015 Tristan Rice.</li>
-          <li><a href="https://github.com/davecgh/go-spew">davecgh/go-spew</a>, Copyright &copy; 2012-2016 Dave Collins <[email protected]>.</li>
-          <li><a href="https://github.com/ebitengine/purego">ebitengine/purego</a>, Copyright &copy; 2022 The Ebitengine Authors.</li>
-          <li><a href="https://github.com/fsnotify/fsnotify">fsnotify/fsnotify</a>, Copyright &copy; 2012 The Go Authors.</li>
-          <li><a href="https://github.com/getsentry/raven-go">getsentry/raven-go</a>, Copyright &copy; 2013 Apollic Software, LLC.</li>
+          <li><a href="https://github.com/cpuguy83/go-md2man/v2">cpuguy83/go-md2man/v2</a>, Copyright &copy; 2014 Brian Goff.</li>
+          <li><a href="https://github.com/davecgh/go-spew">davecgh/go-spew</a>, Copyright &copy; 2012-2016 Dave Collins.</li>
           <li><a href="https://github.com/go-asn1-ber/asn1-ber">go-asn1-ber/asn1-ber</a>, Copyright &copy; 2011-2015 Michael Mitton ([email protected]).</li>
           <li><a href="https://github.com/go-ldap/ldap">go-ldap/ldap</a>, Copyright &copy; 2011-2015 Michael Mitton ([email protected]).</li>
-          <li><a href="https://github.com/go-ole/go-ole">go-ole/go-ole</a>, Copyright &copy; 2013-2017 Yasuhiro Matsumoto, <[email protected]>.</li>
-          <li><a href="https://github.com/go-task/slim-sprig">go-task/slim-sprig</a>, Copyright &copy; 2013-2020 Masterminds.</li>
           <li><a href="https://github.com/uber-go/automaxprocs">go.uber.org/automaxprocs</a>, Copyright &copy; 2017 Uber Technologies, Inc.</li>
-          <li><a href="https://github.com/uber-go/mock">go.uber.org/mock</a>, Copyright &copy; 2010-2022 Google LLC.</li>
           <li><a href="https://github.com/gobwas/glob">gobwas/glob</a>, Copyright &copy; 2016 Sergey Kamardin.</li>
           <li><a href="https://github.com/gofrs/flock">gofrs/flock</a>, Copyright &copy; 2018-2025, The Gofrs.</li>
           <li><a href="https://github.com/golang/snappy">golang/snappy</a>, Copyright &copy; 2011 The Snappy-Go Authors.</li>
           <li><a href="https://github.com/protocolbuffers/protobuf-go">google.golang.org/protobuf</a>, Copyright &copy; 2018 The Go Authors.</li>
-          <li><a href="https://github.com/google/pprof">google/pprof</a>, Copyright &copy; 2016 Google Inc.</li>
           <li><a href="https://github.com/google/uuid">google/uuid</a>, Copyright &copy; 2009,2014 Google Inc.</li>
-          <li><a href="https://github.com/go-yaml/yaml">gopkg.in/yaml.v3</a>, Copyright &copy; 2006-2010 Kirill Simonov.</li>
+          <li><a href="https://gopkg.in/yaml.v3">gopkg.in/yaml.v3</a>, Copyright &copy; 2025, the gopkg.in/yaml.v3 authors.</li>
           <li><a href="https://github.com/greatroar/blobloom">greatroar/blobloom</a>, Copyright &copy; 2020-2024 the Blobloom authors.</li>
           <li><a href="https://github.com/hashicorp/errwrap">hashicorp/errwrap</a>, Copyright &copy; 2014 HashiCorp, Inc.</li>
           <li><a href="https://github.com/hashicorp/go-multierror">hashicorp/go-multierror</a>, Copyright &copy; 2014 HashiCorp, Inc.</li>
           <li><a href="https://github.com/hashicorp/golang-lru">hashicorp/golang-lru</a>, Copyright &copy; 2014 HashiCorp, Inc.</li>
           <li><a href="https://github.com/jackpal/gateway">jackpal/gateway</a>, Copyright &copy; 2010 Jack Palevich.</li>
           <li><a href="https://github.com/jackpal/go-nat-pmp">jackpal/go-nat-pmp</a>, Copyright 2013 John Howard Palevich.</li>
-          <li><a href="https://github.com/jmespath/go-jmespath">jmespath/go-jmespath</a>, Copyright &copy; 2015 James Saryerwinnie.</li>
           <li><a href="https://github.com/julienschmidt/httprouter">julienschmidt/httprouter</a>, Copyright &copy; 2013, Julien Schmidt.</li>
           <li><a href="https://github.com/kballard/go-shellquote">kballard/go-shellquote</a>, Copyright &copy; 2014 Kevin Ballard.</li>
           <li><a href="https://github.com/klauspost/compress">klauspost/compress</a>, Copyright &copy; 2012 The Go Authors.</li>
-          <li><a href="https://github.com/lufia/plan9stats">lufia/plan9stats</a>, Copyright &copy; 2019, KADOTA, Kyohei.</li>
-          <li><a href="https://github.com/maruel/panicparse">maruel/panicparse</a>, Copyright 2015 Marc-Antoine Ruel.</li>
-          <li><a href="https://github.com/maxbrunsfeld/counterfeiter">maxbrunsfeld/counterfeiter</a>, Copyright &copy; 2014 maxbrunsfeld.</li>
-          <li><a href="https://github.com/maxmind/geoipupdate">maxmind/geoipupdate</a>, Copyright &copy; 2018-2024 by MaxMind, Inc.</li>
           <li><a href="https://github.com/miscreant/miscreant.go">miscreant/miscreant.go</a>, Copyright &copy; 2017-2019 The Miscreant Developers.</li>
           <li><a href="https://github.com/munnerz/goautoneg">munnerz/goautoneg</a>, Copyright &copy; 2011, Open Knowledge Foundation Ltd.</li>
-          <li><a href="https://github.com/nxadm/tail">nxadm/tail</a>, Copyright &copy; 2014 ActiveState.</li>
-          <li><a href="https://github.com/onsi/ginkgo">onsi/ginkgo</a>, Copyright &copy; 2013-2014 Onsi Fakhouri.</li>
-          <li><a href="https://github.com/oschwald/geoip2-golang">oschwald/geoip2-golang</a>, Copyright &copy; 2015, Gregory J. Oschwald.</li>
-          <li><a href="https://github.com/oschwald/maxminddb-golang">oschwald/maxminddb-golang</a>, Copyright &copy; 2015, Gregory J. Oschwald.</li>
           <li><a href="https://github.com/pierrec/lz4">pierrec/lz4</a>, Copyright &copy; 2015 Pierre Curto.</li>
           <li><a href="https://github.com/pkg/errors">pkg/errors</a>, Copyright &copy; 2015, Dave Cheney.</li>
           <li><a href="https://github.com/pmezard/go-difflib">pmezard/go-difflib</a>, Copyright &copy; 2013, Patrick Mezard.</li>
           <li><a href="https://github.com/posener/complete">posener/complete</a>, Copyright &copy; 2017 Eyal Posener.</li>
-          <li><a href="https://github.com/power-devops/perfstat">power-devops/perfstat</a>, Copyright &copy; 2020 Power DevOps.</li>
-          <li><a href="https://github.com/puzpuzpuz/xsync">puzpuzpuz/xsync</a>, Copyright &copy; 2025, the puzpuzpuz/xsync authors.</li>
+          <li><a href="https://github.com/prometheus/client_golang">prometheus/client_golang</a>, Copyright 2012-2015 The Prometheus Authors.</li>
+          <li><a href="https://github.com/prometheus/client_model">prometheus/client_model</a>, Copyright &copy; 2025, the prometheus/client_model authors.</li>
+          <li><a href="https://github.com/prometheus/common">prometheus/common</a>, Copyright &copy; 2025, the prometheus/common authors.</li>
+          <li><a href="https://github.com/prometheus/procfs">prometheus/procfs</a>, Copyright &copy; 2025, the prometheus/procfs authors.</li>
           <li><a href="https://github.com/quic-go/quic-go">quic-go/quic-go</a>, Copyright &copy; 2016 the quic-go authors & Google, Inc.</li>
-          <li><a href="https://github.com/rabbitmq/amqp091-go">rabbitmq/amqp091-go</a>, Copyright &copy; 2021 VMware, Inc. or its affiliates.</li>
           <li><a href="https://github.com/rcrowley/go-metrics">rcrowley/go-metrics</a>, Copyright &copy; 2012 Richard Crowley.</li>
           <li><a href="https://github.com/riywo/loginshell">riywo/loginshell</a>, Copyright &copy; 2019 Ryosuke IWANAGA.</li>
-          <li><a href="https://github.com/russross/blackfriday">russross/blackfriday</a>, Copyright &copy; 2011 Russ Ross.</li>
+          <li><a href="https://github.com/russross/blackfriday/v2">russross/blackfriday/v2</a>, Copyright &copy; 2011 Russ Ross.</li>
           <li><a href="https://github.com/shirou/gopsutil">shirou/gopsutil</a>, Copyright &copy; 2014, WAKAYAMA Shirou.</li>
-          <li><a href="https://github.com/kubernetes-sigs/yaml">sigs.k8s.io/yaml</a>, Copyright &copy; 2014 Sam Ghods.</li>
           <li><a href="https://github.com/stretchr/objx">stretchr/objx</a>, Copyright &copy; 2014 Stretchr, Inc.</li>
           <li><a href="https://github.com/stretchr/testify">stretchr/testify</a>, Copyright &copy; 2012-2020 Mat Ryer, Tyler Bunnell and contributors.</li>
-          <li><a href="https://github.com/syncthing/notify">syncthing/notify</a>, Copyright &copy; 2014-2015 The Notify Authors.</li>
           <li><a href="https://github.com/syndtr/goleveldb">syndtr/goleveldb</a>, Copyright &copy; 2012 Suryandaru Triandana.</li>
           <li><a href="https://github.com/thejerf/suture">thejerf/suture</a>, Copyright &copy; 2014-2015 Barracuda Networks, Inc.</li>
           <li><a href="https://github.com/tklauser/go-sysconf">tklauser/go-sysconf</a>, Copyright &copy; 2018-2022, Tobias Klauser.</li>
@@ -125,7 +103,6 @@ Jakob Borg, Audrius Butkevicius, Jesse Lucas, Simon Frei, Tomasz Wilczyński, Al
           <li><a href="https://github.com/urfave/cli">urfave/cli</a>, Copyright &copy; 2016 Jeremy Saenz & Contributors.</li>
           <li><a href="https://github.com/vitrun/qart">vitrun/qart</a>, Copyright &copy; 2010-2011 The Go Authors.</li>
           <li><a href="https://github.com/willabides/kongplete">willabides/kongplete</a>, Copyright &copy; 2020 WillAbides.</li>
-          <li><a href="https://github.com/yusufpapurcu/wmi">yusufpapurcu/wmi</a>, Copyright &copy; 2013 Stack Exchange.</li>
         </ul>
       </div>
 

+ 1 - 1
man/stdiscosrv.1

@@ -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" "Apr 21, 2025" "v1.29.3" "Syncthing"
+.TH "STDISCOSRV" "1" "Apr 26, 2025" "v1.29.3" "Syncthing"
 .SH NAME
 stdiscosrv \- Syncthing Discovery Server
 .SH SYNOPSIS

+ 1 - 1
man/strelaysrv.1

@@ -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 "STRELAYSRV" "1" "Apr 21, 2025" "v1.29.3" "Syncthing"
+.TH "STRELAYSRV" "1" "Apr 26, 2025" "v1.29.3" "Syncthing"
 .SH NAME
 strelaysrv \- Syncthing Relay Server
 .SH SYNOPSIS

+ 1 - 1
man/syncthing-bep.7

@@ -28,7 +28,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 "SYNCTHING-BEP" "7" "Apr 21, 2025" "v1.29.3" "Syncthing"
+.TH "SYNCTHING-BEP" "7" "Apr 26, 2025" "v1.29.3" "Syncthing"
 .SH NAME
 syncthing-bep \- Block Exchange Protocol v1
 .SH INTRODUCTION AND DEFINITIONS

+ 1 - 1
man/syncthing-config.5

@@ -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 "SYNCTHING-CONFIG" "5" "Apr 21, 2025" "v1.29.3" "Syncthing"
+.TH "SYNCTHING-CONFIG" "5" "Apr 26, 2025" "v1.29.3" "Syncthing"
 .SH NAME
 syncthing-config \- Syncthing Configuration
 .SH SYNOPSIS

+ 1 - 1
man/syncthing-device-ids.7

@@ -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 "SYNCTHING-DEVICE-IDS" "7" "Apr 21, 2025" "v1.29.3" "Syncthing"
+.TH "SYNCTHING-DEVICE-IDS" "7" "Apr 26, 2025" "v1.29.3" "Syncthing"
 .SH NAME
 syncthing-device-ids \- Understanding Device IDs
 .sp

+ 1 - 1
man/syncthing-event-api.7

@@ -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 "SYNCTHING-EVENT-API" "7" "Apr 21, 2025" "v1.29.3" "Syncthing"
+.TH "SYNCTHING-EVENT-API" "7" "Apr 26, 2025" "v1.29.3" "Syncthing"
 .SH NAME
 syncthing-event-api \- Event API
 .SH DESCRIPTION

+ 12 - 3
man/syncthing-faq.7

@@ -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 "SYNCTHING-FAQ" "7" "Apr 21, 2025" "v1.29.3" "Syncthing"
+.TH "SYNCTHING-FAQ" "7" "Apr 26, 2025" "v1.29.3" "Syncthing"
 .SH NAME
 syncthing-faq \- Frequently Asked Questions
 .INDENT 0.0
@@ -74,6 +74,8 @@ syncthing-faq \- Frequently Asked Questions
 \fI\%Why does Syncthing connect to this unknown/suspicious address?\fP
 .IP \(bu 2
 \fI\%I am seeing the error message “folder marker missing”. What do I do?\fP
+.IP \(bu 2
+\fI\%Why do my Windows computers always connect through a relay?\fP
 .UNINDENT
 .IP \(bu 2
 \fI\%Usage\fP
@@ -254,8 +256,7 @@ Syncthing logs to stdout by default. On Windows Syncthing by default also
 creates \fBsyncthing.log\fP in Syncthing’s home directory (run \fBsyncthing
 \-\-paths\fP to see where that is). The command line option \fB\-\-logfile\fP can be
 used to specify a user\-defined logfile.  If you only have access to a running
-instance’s GUI, check under the \fIActions\fP \- \fIAbout\fP menu item to see the used
-paths.
+instance’s GUI, click the \fIHelp\fP \-> \fIAbout\fP menu item, then the \fIPaths\fP tab.
 .sp
 If you’re running a process manager like systemd, check there. If you’re
 using a GUI wrapper integration, it may keep the logs for you.
@@ -424,6 +425,14 @@ it will also reset the database state of this folder. It will be considered a 
 will be merged with files from remote devices.
 .sp
 Also see the \fI\%marker FAQ\fP for more information about the folder marker.
+.SS Why do my Windows computers always connect through a relay?
+.sp
+When connecting to a new network, Windows by default sets its profile to
+“Public”. While being more secure, this setting commonly prevents applications
+like Syncthing from being able to establish direct connections with the device
+in question, forcing it to connect through a relay. If you would rather connect
+your devices directly, please follow \X'tty: link https://support.microsoft.com/windows/essential-network-settings-and-tasks-in-windows-f21a9bbc-c582-55cd-35e0-73431160a1b9#bkmk_network_profile'\fI\%the official Microsoft instructions on how
+to change the network profile to “Private”\fP <\fBhttps://support.microsoft.com/windows/essential-network-settings-and-tasks-in-windows-f21a9bbc-c582-55cd-35e0-73431160a1b9#bkmk_network_profile\fP>\X'tty: link'\&.
 .SH USAGE
 .SS What if there is a conflict?
 .sp

+ 1 - 1
man/syncthing-globaldisco.7

@@ -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 "SYNCTHING-GLOBALDISCO" "7" "Apr 21, 2025" "v1.29.3" "Syncthing"
+.TH "SYNCTHING-GLOBALDISCO" "7" "Apr 26, 2025" "v1.29.3" "Syncthing"
 .SH NAME
 syncthing-globaldisco \- Global Discovery Protocol v3
 .SH ANNOUNCEMENTS

+ 1 - 1
man/syncthing-localdisco.7

@@ -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 "SYNCTHING-LOCALDISCO" "7" "Apr 21, 2025" "v1.29.3" "Syncthing"
+.TH "SYNCTHING-LOCALDISCO" "7" "Apr 26, 2025" "v1.29.3" "Syncthing"
 .SH NAME
 syncthing-localdisco \- Local Discovery Protocol v4
 .SH MODE OF OPERATION

+ 1 - 1
man/syncthing-networking.7

@@ -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 "SYNCTHING-NETWORKING" "7" "Apr 21, 2025" "v1.29.3" "Syncthing"
+.TH "SYNCTHING-NETWORKING" "7" "Apr 26, 2025" "v1.29.3" "Syncthing"
 .SH NAME
 syncthing-networking \- Firewall Setup
 .SH ROUTER SETUP

+ 23 - 4
man/syncthing-relay.7

@@ -28,7 +28,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 "SYNCTHING-RELAY" "7" "Apr 21, 2025" "v1.29.3" "Syncthing"
+.TH "SYNCTHING-RELAY" "7" "Apr 26, 2025" "v1.29.3" "Syncthing"
 .SH NAME
 syncthing-relay \- Relay Protocol v1
 .SH WHAT IS A RELAY?
@@ -105,8 +105,9 @@ If the client fails to send a message (even if it’s a ping message) every minu
 .SS Temporary protocol submode
 .sp
 A temporary protocol submode begins with ConnectRequest message, to which the
-relay responds with either ResponseNotFound if the device the client it is after
-is not available, or with a SessionInvitation, which contains the unique session
+relay responds with ResponseNotFound if the device the client it is after
+is not available, with a RelayFull if the relay has reached its limits,
+or with a SessionInvitation, which contains the unique session
 key which then can be used to establish a connection in session mode.
 .sp
 The connection is terminated immediately after that.
@@ -228,7 +229,7 @@ T}
 The first and only message the client sends in the session mode is the
 JoinSessionRequest message which contains the session key identifying which
 session you are trying to join. The relay responds with one of the following
-Response messages:
+messages:
 .INDENT 0.0
 .IP 1. 3
 ResponseNotFound \- Session key is invalid
@@ -238,6 +239,9 @@ ResponseAlreadyConnected \- Session is full (both sides already connected)
 ResponseSuccess \- You have successfully joined the session
 .UNINDENT
 .sp
+4. RelayFull \- Relay limits are too strict for you to be able to join the session.
+The relay immediately terminates the connection after sending this.
+.sp
 After the successful response, all the bytes written and received will be
 relayed between the two devices in the session directly.
 .SS Example Exchange
@@ -570,6 +574,21 @@ connection this client should assume it’s getting. The value is inverted in
 the invitation which is sent to the other device, so that there is always
 one client socket, and one server socket.
 .UNINDENT
+.SS RelayFull message (Type = 7)
+.INDENT 0.0
+.INDENT 3.5
+.sp
+.EX
+ 0                   1                   2                   3
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
++\-+\-+\-+\-+\-+\-+\-+\-+\-+\-+\-+\-+\-+\-+\-+\-+\-+\-+\-+\-+\-+\-+\-+\-+\-+\-+\-+\-+\-+\-+\-+\-+
+
+
+struct RelayFull {
+}
+.EE
+.UNINDENT
+.UNINDENT
 .SH HOW SYNCTHING USES RELAYS, AND GENERAL SECURITY
 .sp
 In the case of Syncthing and BEP, when two devices connect via relay, they

+ 1 - 1
man/syncthing-rest-api.7

@@ -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 "SYNCTHING-REST-API" "7" "Apr 21, 2025" "v1.29.3" "Syncthing"
+.TH "SYNCTHING-REST-API" "7" "Apr 26, 2025" "v1.29.3" "Syncthing"
 .SH NAME
 syncthing-rest-api \- REST API
 .sp

+ 1 - 1
man/syncthing-security.7

@@ -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 "SYNCTHING-SECURITY" "7" "Apr 21, 2025" "v1.29.3" "Syncthing"
+.TH "SYNCTHING-SECURITY" "7" "Apr 26, 2025" "v1.29.3" "Syncthing"
 .SH NAME
 syncthing-security \- Security Principles
 .sp

+ 1 - 1
man/syncthing-stignore.5

@@ -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 "SYNCTHING-STIGNORE" "5" "Apr 21, 2025" "v1.29.3" "Syncthing"
+.TH "SYNCTHING-STIGNORE" "5" "Apr 26, 2025" "v1.29.3" "Syncthing"
 .SH NAME
 syncthing-stignore \- Prevent files from being synchronized to other nodes
 .SH SYNOPSIS

+ 1 - 1
man/syncthing-versioning.7

@@ -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 "SYNCTHING-VERSIONING" "7" "Apr 21, 2025" "v1.29.3" "Syncthing"
+.TH "SYNCTHING-VERSIONING" "7" "Apr 26, 2025" "v1.29.3" "Syncthing"
 .SH NAME
 syncthing-versioning \- Keep automatic backups of deleted files by other nodes
 .sp

+ 1 - 1
man/syncthing.1

@@ -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 "SYNCTHING" "1" "Apr 21, 2025" "v1.29.3" "Syncthing"
+.TH "SYNCTHING" "1" "Apr 26, 2025" "v1.29.3" "Syncthing"
 .SH NAME
 syncthing \- Syncthing
 .SH SYNOPSIS

+ 41 - 39
script/copyrights.go

@@ -13,8 +13,6 @@
 package main
 
 import (
-	"bufio"
-	"bytes"
 	"encoding/base64"
 	"encoding/json"
 	"fmt"
@@ -50,6 +48,8 @@ var copyrightMap = map[string]string{
 	"jmespath/go-jmespath": "Copyright &copy; 2015 James Saryerwinnie",
 	// https://github.com/maxmind/geoipupdate/blob/main/README.md?plain=1#L140
 	"maxmind/geoipupdate": "Copyright &copy; 2018-2024 by MaxMind, Inc",
+	// https://github.com/search?q=repo%3Aprometheus%2Fclient_golang%20copyright&type=code
+	"prometheus/client_golang": "Copyright 2012-2015 The Prometheus Authors",
 	// https://github.com/search?q=repo%3Apuzpuzpuz%2Fxsync%20copyright&type=code
 	// "puzpuzpuz/xsync": "No copyrights found",
 	// https://github.com/search?q=repo%3Atklauser%2Fnumcpus%20copyright&type=code
@@ -59,13 +59,13 @@ var copyrightMap = map[string]string{
 }
 
 var urlMap = map[string]string{
-	"fontawesome.io":             "https://github.com/FortAwesome/Font-Awesome",
-	"go.uber.org/automaxprocs":   "https://github.com/uber-go/automaxprocs",
-	"go.uber.org/mock":           "https://github.com/uber-go/mock",
+	"fontawesome.io":           "https://github.com/FortAwesome/Font-Awesome",
+	"go.uber.org/automaxprocs": "https://github.com/uber-go/automaxprocs",
+	// "go.uber.org/mock":           "https://github.com/uber-go/mock",
 	"google.golang.org/protobuf": "https://github.com/protocolbuffers/protobuf-go",
-	"gopkg.in/yaml.v2":           "", // ignore, as gopkg.in/yaml.v3 supersedes
-	"gopkg.in/yaml.v3":           "https://github.com/go-yaml/yaml",
-	"sigs.k8s.io/yaml":           "https://github.com/kubernetes-sigs/yaml",
+	// "gopkg.in/yaml.v2":           "", // ignore, as gopkg.in/yaml.v3 supersedes
+	// "gopkg.in/yaml.v3":           "https://github.com/go-yaml/yaml",
+	"sigs.k8s.io/yaml": "https://github.com/kubernetes-sigs/yaml",
 }
 
 const htmlFile = "gui/default/syncthing/core/aboutModalView.html"
@@ -174,6 +174,7 @@ func main() {
 		if n.Type != TypeNew {
 			continue
 		}
+
 		copyright, ok := copyrightMap[n.Name]
 		if ok {
 			notices[i].Copyright = copyright
@@ -272,44 +273,43 @@ func writeFile(path string, data string) {
 }
 
 func getModules() []string {
-	cmd := exec.Command("go", "mod", "graph")
-	output, err := cmd.Output()
+	ignoreRe := regexp.MustCompile(`golang\.org/x/|github\.com/syncthing|^[^.]+(/|$)`)
+
+	// List all modules (used for mapping packages to modules)
+	data, err := exec.Command("go", "list", "-m", "all").Output()
 	if err != nil {
-		log.Fatal(err)
+		log.Fatalf("go list -m all: %v", err)
 	}
+	modules := strings.Split(string(data), "\n")
+	for i := range modules {
+		modules[i], _, _ = strings.Cut(modules[i], " ")
+	}
+	modules = slices.DeleteFunc(modules, func(s string) bool { return s == "" })
 
-	seen := make(map[string]struct{})
-	scanner := bufio.NewScanner(bytes.NewReader(output))
-
-	for scanner.Scan() {
-		line := scanner.Text()
-		fields := strings.Fields(line)
-		if len(fields) == 0 {
-			continue
-		}
-
-		if !strings.HasPrefix(fields[0], "github.com/syncthing/syncthing") {
-			continue
-		}
-
-		// Get left-hand side of dependency pair (before '@')
-		mod := strings.SplitN(fields[1], "@", 2)[0]
+	// List all packages in use by the syncthing binary, map them to modules
+	data, err = exec.Command("go", "list", "-deps", "./cmd/syncthing").Output()
+	if err != nil {
+		log.Fatalf("go list -deps ./cmd/syncthing: %v", err)
+	}
+	packages := strings.Split(string(data), "\n")
+	packages = slices.DeleteFunc(packages, func(s string) bool { return s == "" })
 
-		// Keep only first 3 path components
-		parts := strings.Split(mod, "/")
-		if len(parts) == 1 {
+	seen := make(map[string]struct{})
+	for _, pkg := range packages {
+		if ignoreRe.MatchString(pkg) {
 			continue
 		}
-		short := strings.Join(parts[:min(len(parts), 3)], "/")
-
-		if strings.HasPrefix(short, "golang.org/x") ||
-			strings.HasPrefix(short, "github.com/prometheus") ||
-			short == "go" {
 
+		// Find module for package
+		modIdx := slices.IndexFunc(modules, func(mod string) bool {
+			return strings.HasPrefix(pkg, mod)
+		})
+		if modIdx < 0 {
+			log.Println("no module for", pkg)
 			continue
 		}
-
-		seen[short] = struct{}{}
+		module := modules[modIdx]
+		seen[module] = struct{}{}
 	}
 
 	adds := make([]string, 0)
@@ -404,7 +404,9 @@ func getLicenseText(owner, repo string) string {
 		log.Fatal(err)
 	}
 	defer resp.Body.Close()
-
+	if resp.StatusCode == 404 {
+		return ""
+	}
 	var result struct {
 		Content  string `json:"content"`
 		Encoding string `json:"encoding"`
@@ -416,7 +418,7 @@ func getLicenseText(owner, repo string) string {
 	}
 
 	if result.Encoding != "base64" {
-		log.Fatal(fmt.Sprintf("unexpected encoding: %s", result.Encoding))
+		log.Fatal(fmt.Sprintf("unexpected encoding: %q", result.Encoding))
 	}
 
 	decoded, err := base64.StdEncoding.DecodeString(result.Content)