Compare commits

...

1064 Commits

Author SHA1 Message Date
bt90
467522d04d lib/connections: Allow IPv6 ULA in discovery announcements (fixes #7456) (#9048)
The allowed IPv4 ranges are the same as before. But we now also accept IPv6 addresses in the ULA range FC00::/7. These addresses don't require an interface identifier and are roughly equivalent to the IPv4 private ranges.

Typical usecases:

VPN interface IPs: Wireguard, OpenVPN, Tailscale, ...
fixed IPv6 LAN addressing while the provider assigns a dynamic prefix. e.g used by pihole
https://cs.opensource.google/go/go/+/refs/tags/go1.21.0:src/net/ip.go;l=146
2023-08-23 12:28:48 +02:00
bt90
3147285c60 lib/beacon: Check FlagRunning (#9051) 2023-08-22 11:27:43 +02:00
Jakob Borg
acd767b30b all: Remove lib/util package (#9049)
Grab-bag packages are nasty, this cleans it up a little by splitting it
into topical packages sempahore, netutil, stringutil, structutil.
2023-08-21 19:44:33 +02:00
Jakob Borg
40b3b9ad15 lib/model: Clean up index handler life cycle (fixes #9021) (#9038)
Co-authored-by: Simon Frei <freisim93@gmail.com>
2023-08-21 18:39:13 +02:00
bt90
c2c6133aa5 lib/osutil, lib/upnp: Check FlagRunning (fixes #8767) (#9047) 2023-08-21 14:49:28 +00:00
Jakob Borg
ccec8a4cdb build: Update dependencies (#9046) 2023-08-21 15:56:02 +02:00
Jakob Borg
cbf0e31f69 all: Use Go 1.21, new QUIC API (#9040) 2023-08-21 15:25:52 +02:00
Syncthing Release Automation
c40dae315b gui, man, authors: Update docs, translations, and contributors 2023-08-21 03:45:38 +00:00
Jakob Borg
ac0ce1c38f script: Remove find-metrics which belongs in docs 2023-08-17 12:27:56 +02:00
Jakob Borg
72c683aaca gui: Fix inadvertently always-false comparison (ref #7726) 2023-08-16 11:51:45 +02:00
Syncthing Release Automation
8042bd1a54 gui, man, authors: Update docs, translations, and contributors 2023-08-14 03:45:48 +00:00
Jakob Borg
462389934b cmd/stupgrades: Serve friendlier URLs for upgrade assets (fixes #9033) 2023-08-09 21:01:15 +02:00
Jakob Borg
b347c14bd1 build: Use correct range specification for Go version
The old `^1.20.7` means `1.x.y, >= 1.20.7` which allows 1.21.0, which
was not intended. The new `~1.20.7` means `1.20.x, >= 1.20.7`, which is
safer.
2023-08-09 16:05:11 +02:00
Jakob Borg
8dfec6983b build: WASM is not a thing we need to try to compile for 2023-08-09 11:02:43 +02:00
Jakob Borg
9ebf2dae7b build: Ability to manually trigger Actions builds 2023-08-09 10:50:07 +02:00
André Colomb
a8cacdca94 lib/versioner: Minor fixes in comments and error message (#9031)
* lib/versioner: Factor out DefaultPath constant.

Replace several instances where .stversions is named literally to all
use the same definition in the versioner package.  Exceptions are the
packages where a cyclic dependency on versioner is impossible, or some
tests which combine the versions base path with other components.

* lib/versioner: Fix comment about trash can in simple versioner.

* lib/versioner: Fix wrong versioning type string in error message.

The error message shows the folder type instead of the versioning
type, although the correct field is used in the comparison.
2023-08-09 07:10:06 +00:00
Jakob Borg
8b87cd5229 lib/model: Reinstate setting folder idle state (#9029) 2023-08-08 07:24:02 +02:00
Syncthing Release Automation
e09146ee03 gui, man, authors: Update docs, translations, and contributors 2023-08-07 03:45:35 +00:00
Jakob Borg
b9c08d3814 all: Add Prometheus-style metrics to expose some internal performance counters (fixes #5175) (#9003) 2023-08-04 19:57:30 +02:00
Jakob Borg
58042b3129 build: Increase Go version to 1.20.7 2023-08-03 08:11:16 +02:00
Keith Harrison
eed12f3ec5 lib/config: Allow sharing already encrypted folder with untrusted devices (fixes #8965) (#9012)
Safety check added in v1.23.6 introduced bug. Bug unshares folders with untrusted devices if folder does not have an encryption password set, regardless of whether the folder is shared with the untrusted device as encrypted or not. Prevents sharing with untrusted devices in some cases where sharing would be encrypted.

Patch preserves safety check but permits sharing folders with untrusted devices if they are shared as encrypted.

Signed-off-by: kewiha <keithh@protonmail.com>
2023-08-02 07:14:53 +00:00
tomasz1986
5323928159 gui: Use case-insensive and backslash-agnostic versions filter (fixes #7973) (#8995)
Currently, the versions filter is case-sensitive regardless of the
underlying OS. With this change, the filter becomes case-insensitive
everywhere, which is more user-friendly and makes it easier to search
for files whose exact case the user may not remember.

In addition, forward and backslashes are no longer distinguished,
whether used as path separators or as part of a file / directory
name (which is unlikely but possible on some platforms).

Signed-off-by: Tomasz Wilczyński <twilczynski@naver.com>
2023-08-01 14:20:01 +02:00
Syncthing Release Automation
97625ccc26 gui, man, authors: Update docs, translations, and contributors 2023-07-31 03:45:37 +00:00
Jakob Borg
4fe746d9aa build: Run govulncheck (fixes #8983) 2023-07-30 14:38:36 +02:00
Jakob Borg
4f8cdd41ee build: Run build & tests on main branch nightly 2023-07-30 14:24:17 +02:00
Jakob Borg
406e3646e5 build: Send test logs to Grafana Loki for statistics 2023-07-30 13:40:26 +02:00
Jakob Borg
9d21b91124 all: Refactor the protocol/model interface a bit (ref #8981) (#9007) 2023-07-29 10:24:44 +02:00
Chih-Hsuan Yen
b806026990 lib/connections: Fix building with -tags noquic (#9009) 2023-07-28 10:08:50 +00:00
tomasz1986
341b79814e gui: Fix tooltips on buttons inside button groups (ref #7984) (#9008)
As per Bootstrap recommendation, buttons with tooltips inside button
groups require to have container: 'body' set. This prevents tooltips
from causing the buttons to jump on hover and also allows the tooltips
to be wider instead of wrapping on every space.

Ref: https://getbootstrap.com/docs/3.3/components/#btn-groups

Signed-off-by: Tomasz Wilczyński <twilczynski@naver.com>
2023-07-27 14:38:48 +02:00
Jakob Borg
319916124b cmd/strelaysrv: Handle accept error with debug set (fixes #9001) (#9004) 2023-07-26 23:55:48 +01:00
Emil Lundberg
b08b99e284 lib/api: Fix data race in TestCSRFRequired (#9006) 2023-07-26 21:33:45 +00:00
Jakob Borg
f565df628c gui: Show full error for failed items (#9005)
Also closes #8992.
2023-07-26 23:20:17 +02:00
Jakob Borg
855c6dc67b lib/api: Allow Bearer authentication style with API key (#9002)
Currently, historically, we look for the `X-API-Key` header to
authenticate with an API key. There's nothing wrong with this, but in
some scenarios it's easier to produce an `Authorization` header with a
`Bearer $token` content, which is nowadays more common. This change adds
support for both, so that we will accept an API key either in our custom
header or as a bearer token.
2023-07-26 13:13:06 +02:00
tomasz1986
dc5e10fa2c gui: Remove Twitter link from footer (#9000) 2023-07-25 00:53:57 +02:00
Syncthing Release Automation
b857e57a35 gui, man, authors: Update docs, translations, and contributors 2023-07-24 03:45:42 +00:00
tomasz1986
f42f041f53 lib/ur: Don't report uptime if start time is in the past (fixes #7698) (#8996)
Currently, because of devices with unset RTC clock, the 100% percentile
for Uptime on [1] is calculated since the Unix epoch which is useless as
far as usage statistics are concerned. Thus, if the Syncthing start time
is set to a past date, assume that the clock is wrong and do not even
try to report the uptime.

[1] https://data.syncthing.net

Signed-off-by: Tomasz Wilczyński <twilczynski@naver.com>
Co-authored-by: Jakob Borg <jakob@kastelo.net>
2023-07-22 21:25:03 +00:00
Christian Kujau
6b6b2c6194 lib/model: use WARN for "Unexpected folder" messages (#8998) 2023-07-22 21:17:32 +00:00
tomasz1986
d70eb569f2 lib/osutil: Skip setLowPriority in Windows if already lower (fixes #6597) (#8993) 2023-07-21 04:38:15 +00:00
deepsource-autofix[bot]
21c074cc2c all: replace empty slice literal with var (#8990)
refactor: replace empty slice literal with `var`

An empty slice can be represented by `nil` or an empty slice literal. They are
functionally equivalent — their `len` and `cap` are both zero — but the `nil`
slice is the preferred style. For more information about empty slices,
see [Declaring Empty Slices](https://github.com/golang/go/wiki/CodeReviewComments#declaring-empty-slices).

Co-authored-by: deepsource-autofix[bot] <62050782+deepsource-autofix[bot]@users.noreply.github.com>
2023-07-18 14:44:37 +00:00
deepsource-autofix[bot]
f23c41221b all: fix unused method receiver (#8988)
refactor: fix unused method receiver

Methods with unused receivers can be a symptom of unfinished refactoring or a bug. To keep 
the same method signature, omit the receiver name or '_' as it is unused.

Co-authored-by: deepsource-autofix[bot] <62050782+deepsource-autofix[bot]@users.noreply.github.com>
2023-07-18 14:34:50 +00:00
deepsource-autofix[bot]
24e230d455 all: unused parameter should be replaced by underscore (#8989)
refactor: unused parameter should be replaced by underscore

Unused parameters in functions or methods should be replaced with `_`
(underscore) or removed.

Co-authored-by: deepsource-autofix[bot] <62050782+deepsource-autofix[bot]@users.noreply.github.com>
2023-07-18 14:33:13 +00:00
Syncthing Release Automation
31daa20367 gui, man, authors: Update docs, translations, and contributors 2023-07-17 03:46:46 +00:00
Jakob Borg
e4d0f9dd6c cmd/syncthing: Mention STVERSIONEXTRA in --help output (ref #8980) 2023-07-16 17:48:24 +02:00
Jakob Borg
df2ac7aaeb gui, lib/api: Add possibility to feed through extra version information (#8980)
This adds an environment variable STVERSIONEXTRA that, when set, gets
added to the version information in the API and GUI.

The purpose of all this is to be able to communicate something about the
bundling or packaging, through the log & GUI and the end user, to the
potential person supporting it -- i.e., us. :) A wrapper can set this
variable to indicate that Syncthing is being run via `SyncTrayzor`,
`Syncthing-macOS`, etc., and thus indicate to the end user that the GUI
they are looking at is perhaps not the only source of truth and
management for this instance.
2023-07-16 17:43:10 +02:00
Jakob Borg
b96b23957b cmd/ursrv: Update map tile URL 2023-07-16 17:36:05 +02:00
bt90
265ce139c5 cmd/strelaypoolsrv: Update map tile URL (#8985) 2023-07-16 17:20:40 +02:00
Jakob Borg
48c95eb41d cmd/stcrashreceiver: Correct parsing of current version string 2023-07-12 09:27:34 +02:00
Jakob Borg
937895be69 build: Update dependencies 2023-07-11 09:14:21 +02:00
Jakob Borg
a3886f778d cmd/ursrv: Remove old, unused user movement code 2023-07-10 09:21:40 +02:00
Jakob Borg
6aecc2622c cmd/ursrv: Merge ursrv and uraggregate as subcommands 2023-07-10 09:00:57 +02:00
Jakob Borg
c55b205a0b cmd/ursrv: Remove useless static TLS cert handling 2023-07-10 08:39:30 +02:00
Jakob Borg
2fcf7006e6 cmd/ursrv: Embed static assets 2023-07-10 08:33:09 +02:00
Jakob Borg
bf61e485a6 cmd/ursrv: Refactor to use CLI options, fewer global vars 2023-07-10 08:27:16 +02:00
Jakob Borg
b2886f11b1 gui: Show xattr filter editor when send xattrs checked (fixes #8958) (#8959) 2023-07-10 08:01:08 +02:00
Syncthing Release Automation
11ece5d89e gui, man, authors: Update docs, translations, and contributors 2023-07-10 03:46:49 +00:00
Jakob Borg
cf68dfac43 build: Build Docker image for plain 32 bit arm (fixes #8973) 2023-07-08 10:55:09 +02:00
Jakob Borg
c44de2cd58 lib/fs: Clarify errors for Windows filenames (fixes #8968) (#8969)
With this change, error messages include the offending characters or
name parts. Examples:

    nul.txt: name is invalid, contains Windows reserved name: "nul"
    foo>bar.txt: name is invalid, contains Windows reserved character: ">"
    foo \bar.txt: name is invalid, must not end in space or period on Windows
2023-07-07 11:00:40 +00:00
Jakob Borg
6ff5ed6d23 gui: Avoid spurious comma in shared-with device list (fixes #8967) (#8970) 2023-07-07 07:25:24 +02:00
Jakob Borg
25ec2b63ab cmd/ursrv: Summarize tiny fraction items into Other 2023-07-05 08:22:10 +02:00
Jakob Borg
c5ab71d7a5 cmd/ursrv: Update distributions list 2023-07-05 08:08:29 +02:00
Jakob Borg
1fc4c9d9c5 build: Only push releases to cloud storage, and also use latest 2023-07-04 10:27:26 +02:00
Jakob Borg
bebf2c259c readme: Remove outdated build badges/links 2023-07-03 13:03:09 +02:00
Jakob Borg
b7d526903e build: Push to correct Docker images 2023-07-03 12:08:53 +02:00
Jakob Borg
92917c9f62 Merge branch 'release'
* release:
  build: Build and publish Docker images for relay and discovery server (fixes #8691, fixes #8960)
2023-07-03 11:52:11 +02:00
Jakob Borg
fdde05cf12 build: Build and publish Docker images for relay and discovery server (fixes #8691, fixes #8960)
This adds builds for the discovery and relay servers in the same manner
as Syncthing, so that Docker images are kept up to date with releases.

Inspired by and closes #8834.

Co-authored-by: Migelo <miha@filetki.si>
2023-07-03 11:51:12 +02:00
Syncthing Release Automation
a7d7325e9b gui, man, authors: Update docs, translations, and contributors 2023-07-03 03:45:49 +00:00
Jakob Borg
465823237f build: Build and publish Docker images for relay and discovery server (fixes #8691, fixes #8960)
This adds builds for the discovery and relay servers in the same manner
as Syncthing, so that Docker images are kept up to date with releases.

Inspired by and closes #8834.

Co-authored-by: Migelo <miha@filetki.si>
2023-07-01 08:48:12 +02:00
Jakob Borg
5a1f996e56 build: Build infrastructure images 2023-07-01 08:23:55 +02:00
Jakob Borg
229b6a292c cmd/stcrashreceiver: Add /ping endpoint 2023-07-01 07:53:50 +02:00
Jakob Borg
c84e47a7b2 build: Update dependencies 2023-06-28 14:00:30 +02:00
otbutz
daf7baaeff etc: Update sysctl configs (#8955) 2023-06-28 07:05:12 +02:00
Jakob Borg
a4a1231e92 gui: Remove tilde auto-expansions (fixes #8890) (#8954)
This removes the tilde expansion we had in the GUI. I'm not sure why we
had it, but there are valid reasons to have a folder path with tilde in
it in the config, and it was previously impossible to enter one of
those.
2023-06-28 07:03:53 +02:00
Jakob Borg
b99dee3ac3 cmd/syncthing: Add environment variables for --home, --conf, and --data (fixes #8957) (#8952)
This allows environment overrides for our directories. This is
advantageous because, apart from the obvious, it means we can set it in
the Docker file and not add command line options there. Having the
command line option as we did meant that it was impossible to use the
Docker image for other commands than `serve` (because that is implied
when we see other options on the command line).
2023-06-28 07:03:36 +02:00
Syncthing Release Automation
89fc69249b gui, man, authors: Update docs, translations, and contributors 2023-06-26 03:47:58 +00:00
Jakob Borg
d421d66a3f build: Docker images should have auto upgrade disabled... 2023-06-22 14:38:34 +02:00
guangwu
27aba3567b all: Minor staticcheck fixes (#8939) 2023-06-19 06:50:53 +00:00
Syncthing Release Automation
5532532db9 gui, man, authors: Update docs, translations, and contributors 2023-06-19 03:46:01 +00:00
Felix
c369f8abb2 gui: Have static link to favicon, for bookmarks etc (fixes #7638) (#8850) 2023-06-14 09:59:56 +02:00
Jakob Borg
9e52f6cf2f build: Update some dependencies 2023-06-14 09:43:45 +02:00
Jakob Borg
d22a38d947 build: Make sure we get the latest matching Go version
Also, disable caching in setup-go when we do manual cache setup with a
better cache key. It became default-true in the latest action version.
2023-06-14 09:37:59 +02:00
Jakob Borg
439fa6c848 build: Multi arch Docker images with GitHub actions (ref #8834)
This builds and publishes our Docker images from GitHub.
2023-06-14 09:28:04 +02:00
Jakob Borg
6b475bdb78 lib/config, gui: Disallow some options in combination with "untrusted" (fixes #8920) (#8921)
This prevents combining untrusted with introducer and auto-accept, and
also verifies that folders shared with untrusted devices have passwords
at config loading time.

Co-authored-by: Simon Frei <freisim93@gmail.com>
2023-06-14 09:24:31 +02:00
Syncthing Release Automation
7d56fba321 gui, man, authors: Update docs, translations, and contributors 2023-06-12 03:45:39 +00:00
Simon Frei
bf6ffbbd67 Don't add empty device to config on init (#8933)
We usually want to ensure that our own device is present. However if the
given device ID is the empty ID, we shouldn't do that. This is a
legimate (though way too non-obvious) use-case when opening the config
without knowing/caring about the device ID.
2023-06-10 20:33:39 +00:00
Jakob Borg
a972811f54 build: Push release files to cloud storage 2023-06-06 17:53:05 +02:00
Jakob Borg
88da67d7c3 build: Generate .asc files for release packages (fixes #8897) 2023-06-06 13:58:44 +02:00
Jakob Borg
1f07e05470 build: Properly build all Debian archs (fixes #8898) 2023-06-06 12:52:30 +02:00
Jakob Borg
5cab08a36a Merge branch 'release'
* release:
  gui: Avoid code generating HTML (#8923)
  gui: Remove HTML support in tooltips
2023-06-06 09:09:30 +02:00
Jakob Borg
73c52eafb6 gui: Avoid code generating HTML (#8923) 2023-06-06 09:06:51 +02:00
Jakob Borg
be5961f59b gui: Remove HTML support in tooltips 2023-06-06 09:06:36 +02:00
Jakob Borg
4e2bb58e2d gui: Avoid code generating HTML (#8923) 2023-06-05 13:16:02 +02:00
Jakob Borg
ae176ea9cd build: Tests should run with Go 1.20 on Windows (#8924)
Tests should run with Go 1.20 on Windows
2023-06-05 10:19:47 +02:00
Syncthing Release Automation
2b17db8aa3 gui, man, authors: Update docs, translations, and contributors 2023-06-05 03:45:37 +00:00
Jakob Borg
81a4b22d43 lib/model: Improve test for unignored parent directories (#8926) 2023-06-04 15:32:03 +02:00
Jakob Borg
f7da96fb82 build: Update dependencies (#8925)
The easy ones, there is also a quic-go update but it requires API
refactoring.
2023-06-04 15:31:20 +02:00
Jakob Borg
f5e5af391a gui: Remove HTML support in tooltips 2023-06-03 09:58:08 +02:00
Jakob Borg
5a3ac86c3f cmd/syncthing: Use correct binary when restarting monitor (#8919) 2023-06-02 07:54:31 +02:00
dependabot[bot]
3d78ff9f68 build(deps): bump github.com/minio/sha256-simd from 1.0.0 to 1.0.1 (#8916)
Bumps [github.com/minio/sha256-simd](https://github.com/minio/sha256-simd) from 1.0.0 to 1.0.1.
- [Release notes](https://github.com/minio/sha256-simd/releases)
- [Commits](https://github.com/minio/sha256-simd/compare/v1.0.0...v1.0.1)

---
updated-dependencies:
- dependency-name: github.com/minio/sha256-simd
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-06-01 12:16:46 +02:00
Jakob Borg
f3127a66ee build: Increase concurrency, add "basic checks" gatekeeper 2023-06-01 12:15:31 +02:00
Syncthing Release Automation
90b4711ad2 gui, man, authors: Update docs, translations, and contributors 2023-05-29 03:45:27 +00:00
Syncthing Release Automation
716b42103a gui, man, authors: Update docs, translations, and contributors 2023-05-22 03:45:33 +00:00
Anthony Goeckner
405cdedcd3 lib/model: Set platform data for new folders w/ ignorePerms (ref #8883) (#8907)
* Platform data (ownership, xattrs, etc.) is now set correctly for newly-received folders, even if the received folder has the NoPermissions flag.

* Call setPlatformData on receivers that have ignorePerms set to true.
2023-05-17 09:06:50 +02:00
Syncthing Release Automation
0b3a101ccd gui, man, authors: Update docs, translations, and contributors 2023-05-15 03:45:55 +00:00
Eng Zer Jun
089320aadc lib: replace Readdir(-1) with os.ReadDir (#8901) 2023-05-11 15:35:52 +00:00
Will Rouesnel
b2fb2ef276 lib/api: Allow BindDN to exclude any username formatting (fixes #8899) (#8900)
This allows a syncthing instance to be locked to exactly 1 user without
needing search capability on the LDAP instance.
2023-05-10 07:52:02 +02:00
Jakob Borg
e136d11dce build: Attempt cross compilation for ~all targets, allow it to fail 2023-05-09 10:01:57 +00:00
Ross Smith II
3adfe2f91f lib/fs: Fix root path handling for Windows (fixes #8778)
Co-authored-by: Jakob Borg <jakob@kastelo.net>
2023-05-09 10:01:57 +00:00
Jakob Borg
1103a27337 all: Grand test refactor (fixes #8779, fixes #8799)
This fixes various test issues with Go 1.20.

- Most tests rewritten to use fakefs where possible
- Some tests that were already skipped, or dubious (invasive,
  unmaintainable, unclear what they even tested) have been removed
- Some actual code rewritten to better support testing in fakefs

Co-authored-by: Eric P <eric@kastelo.net>
2023-05-09 10:01:57 +00:00
Alexander Seiler
ddce692f72 all: Correct various typos (#8870) 2023-05-09 08:54:02 +02:00
Syncthing Release Automation
66faea7712 gui, man, authors: Update docs, translations, and contributors 2023-05-08 03:45:35 +00:00
Anthony Goeckner
7e31ec5417 lib/model: Set platform data, incl. copying ownership, for new folders w/ NoPermissions flag (#8883)
Platform data (ownership, xattrs, etc.) is now set correctly for newly-received folders, even if the received folder has the NoPermissions flag.
2023-05-02 11:11:39 +02:00
André Colomb
a4fa764b7d gui: Add Thai (th) translation template. (#8887) 2023-05-02 06:38:29 +00:00
Jakob Borg
7226b8456b build: Produce nightly release builds 2023-05-01 09:42:44 +02:00
Syncthing Release Automation
dae5eab787 gui, man, authors: Update docs, translations, and contributors 2023-05-01 03:45:35 +00:00
K.B.Dharun Krishna
f38e9628a1 build: Bump actions version; fix Node 12 deprecation warning (#8881) 2023-04-29 15:21:46 +02:00
Jakob Borg
43e3b12e29 build: Build Debian packages 2023-04-28 13:22:25 +02:00
Jakob Borg
aa01ff5d50 build: Sign for upgrades 2023-04-28 13:03:25 +02:00
Jakob Borg
63503e0c98 build: Notarize mac builds 2023-04-28 13:03:25 +02:00
dependabot[bot]
947dd0db09 build(deps): bump github.com/quic-go/quic-go from 0.33.0 to 0.34.0 (#8877)
Bumps [github.com/quic-go/quic-go](https://github.com/quic-go/quic-go) from 0.33.0 to 0.34.0.
- [Release notes](https://github.com/quic-go/quic-go/releases)
- [Changelog](https://github.com/quic-go/quic-go/blob/master/Changelog.md)
- [Commits](https://github.com/quic-go/quic-go/compare/v0.33.0...v0.34.0)

---
updated-dependencies:
- dependency-name: github.com/quic-go/quic-go
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-04-24 19:04:27 +02:00
Syncthing Release Automation
218b6e5193 gui, man, authors: Update docs, translations, and contributors 2023-04-24 03:45:39 +00:00
Eric P
9f131eee6b lib/ignore: Properly handle non-existing included ignore-files (fixes #8764) (#8874)
In the sequence of loading ignores, the error File Does Not Exist is not being considered a fatal  error, since the .stignore file is allowed to not exist. However, included ignore files also tossed that same error in case those do not exist while in those cases it's considered an error and it should lead to the folder stopping. Changing the error when opening an included ignore file to something other than the regular does fix this issue, as in it now works again as described in the Documentation.
2023-04-20 15:00:55 +02:00
Jakob Borg
09efe03e1d lib/connections: Avoid using nil lanChecker
Otherwise it panics when someone calls Priority() on it...
2023-04-19 10:42:25 +02:00
Syncthing Release Automation
0f87607cd5 gui, man, authors: Update docs, translations, and contributors 2023-04-17 03:45:33 +00:00
Jakob Borg
9b660c1959 lib/config, lib/connections: Configurable protocol priority (ref #8626) (#8868)
This makes the various protocol priorities configurable among the other
options. With this, it's possible to prefer QUIC over TCP for WAN
connections, for example. Both sides need to be similarly configured for
this to work properly.

The default priority order remains the same as previously (TCP, QUIC,
Relay, with LAN better than WAN).

To make this happen I made each dialer & listener more priority aware,
and moved the check for whether a connection is LAN or not into the
dialer / listener -- this is the new "lanChecker" type that's passed
around.
2023-04-16 14:54:28 +02:00
Simon Frei
c867a5f5b3 build: Upgrade recli (fixes #8503) (#8871) 2023-04-14 18:46:50 +02:00
Jakob Borg
1886b47031 build: Update dependencies (#8869) 2023-04-11 20:01:42 +02:00
Jakob Borg
f59ffc8ddd lib/model: Improve path generation for auto accepted folders (fixes #8859) (#8860)
- Make sure we don't try to use empty last path components
- Create the directory to "reserve" it once we've decided to use it
2023-04-11 13:07:22 +02:00
Evgeny Kuznetsov
61444960bc docs: fix typo (#8857) 2023-04-10 10:30:11 +00:00
Syncthing Release Automation
30bb8f2116 gui, man, authors: Update docs, translations, and contributors 2023-04-10 03:45:37 +00:00
Jakob Borg
4a8c691aef lib/syncthing: Handle successful global migration (fixes #8851) (#8852)
lib/syncthing: Handle successfull global migration (fixes #8851)
2023-04-05 15:25:55 +02:00
Syncthing Release Automation
e8dafb979c gui, man, authors: Update docs, translations, and contributors 2023-04-03 03:45:47 +00:00
Simon Frei
3a41d4afa5 lib/model: Set enc. trailer size on pull (ref #8563, #8556) (#8839)
In the original fix in #8563 I simply forgot this. Which meant #8556
wasn't actually fixed, as the trialer size would have been 0 (default),
and thus we would have still sent the inflated size to encrypted peers.
2023-03-28 22:47:24 +02:00
Simon Frei
6a66aee489 lib/model: Fix file size inconsistency due to enc. trailer (#8840)
lib/model: Fix file size inconsisency due to enc. trailer

Fixes a regression due to PR #8563, while arguable the bug was actually
introduced in a much older PR #7155, but didn't have any bad effects so
far:
We account for the encryption trailer in the db updater routine,
calculating the file-info size there. However there's no guarantee that
the file-info at this point is still the exact same as when it was
written. It was before, but isn't anymore since introducing the new
EncryptedTrailerSize field.
Fix: Adjust the size in the info at the same place where the trailer is
written, i.e. we definitely have the actual size on disk.
2023-03-28 22:02:59 +02:00
Syncthing Release Automation
51e85d5162 gui, man, authors: Update docs, translations, and contributors 2023-03-27 03:45:37 +00:00
Jakob Borg
b49f535834 cmd/stdiscorv: Fix database test (fixes #8828)
The problem was that a statistics/cleanup run is triggered when the
database started and runs concurrently with the test. That cleanup run
removes old entries without valid addresses, and one of the test objects
matched this. The test object would thus randomly be removed in the
middle of the test, causing a failure. This fixes it so the object looks
recent when the cleaner-upper looks, and also uses a RAM database
(faster).
2023-03-24 09:15:12 +01:00
Jakob Borg
34b312b85b lib/ur: Fix custom releases URL comparison 2023-03-24 09:15:12 +01:00
André Colomb
be3751ab5f gui: Remove untranslated strings from JSON files (#8836)
* gui: Import latest state from Weblate.

Downloaded 2023-03-23 at 20:38:53.

* gui: Remove untranslated strings from JSON files.

The GUI code will fall back to the English string translation anyway,
so keeping it identical inside the other language files does not
help.  It makes the filter handling on Weblate easier though.

Current state retreived with these filter settings:

    state:>=translated OR (state:needs-editing AND NOT check:same)
2023-03-23 21:12:31 +01:00
Dimitri Papadopoulos Orfanos
526e21ae26 all: Fix typos found by codespell (#8833) 2023-03-21 08:07:28 +01:00
Jakob Borg
bc371eacf6 gui: Hide download progress legend when download progress is disabled 2023-03-20 15:34:18 +01:00
Syncthing Release Automation
5caf9bfc18 gui, man, authors: Update docs, translations, and contributors 2023-03-20 03:45:38 +00:00
Jakob Borg
f378e63147 lib/protocol: Handle encrypted requests without encrypted hash (fixes #8277) (#8827)
The layout of the request differs based on whether it comes from an
untrusted device or a trusted device with encrypted enabled. Handle
both.

Closes #8819.
2023-03-18 10:22:18 +01:00
dependabot[bot]
fb89898462 build(deps): bump github.com/hashicorp/golang-lru/v2 from 2.0.1 to 2.0.2 (#8826)
Bumps [github.com/hashicorp/golang-lru/v2](https://github.com/hashicorp/golang-lru) from 2.0.1 to 2.0.2.
- [Release notes](https://github.com/hashicorp/golang-lru/releases)
- [Commits](https://github.com/hashicorp/golang-lru/compare/v2.0.1...v2.0.2)

---
updated-dependencies:
- dependency-name: github.com/hashicorp/golang-lru/v2
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-03-18 10:17:16 +01:00
tomasz1986
358cf25cff lib/config: Allow sub-second watcher delay (fixes #7859) (#7864)
Allow the watcher delay to take fractional values, effectively allowing
for much shorter delays. The minimum value is limited at 0.01, which
effectively translates to 10ms. This is required in order to guarantee
that there is still enough time to aggregate multiple single change
events.

Signed-off-by: Tomasz Wilczyński <twilczynski@naver.com>
2023-03-18 08:50:38 +01:00
Syncthing Release Automation
59de7048bd gui, man, authors: Update docs, translations, and contributors 2023-03-13 03:45:45 +00:00
Jakob Borg
466b56ded1 lib/protocol: Cache expensive key operations (fixes #8599) (#8820)
This adds a cache to the expensive key generation operations. It's fixes
size LRU/MRU stuff to keep memory usage bounded under absurd conditions.

Also closes #8600.
2023-03-12 20:06:59 +01:00
André Colomb
3ffe859fe8 gui: Add Persian (fa) translation template (#8822)
gui: Add Persian (fa) translation template.

Based on user request from Weblate, user @a-kbd.
2023-03-10 16:27:48 +01:00
Simon Frei
da72df6ffc lib: Correctly handle encrypted trailer size (fixes #8556) (#8563) 2023-03-10 14:14:14 +01:00
tomasz1986
b53c1b9a04 gui: Disable Restore Versions filters when no versioned files exist (fixes #5408) (#8539)
Currently, the name and date filters in the Restore Versions modal are
always enabled, even if there are no versioned files present. With this
change, they are enabled only when there are no errors and versioned
files actually exist.

In addition to disabling the filters, also completely skip date picker
generation, as it serves no function while still displaying a non-sense
date range, which starts today and ends in the past.

Signed-off-by: Tomasz Wilczyński <twilczynski@naver.com>
2023-03-10 13:41:15 +01:00
dependabot[bot]
b00976781c build(deps): bump github.com/chmduquesne/rollinghash from 0.0.0-20180912150627-a60f8e7142b5 to 4.0.0+incompatible (#8804)
build(deps): bump github.com/chmduquesne/rollinghash

Bumps [github.com/chmduquesne/rollinghash](https://github.com/chmduquesne/rollinghash) from 0.0.0-20180912150627-a60f8e7142b5 to 4.0.0+incompatible.
- [Release notes](https://github.com/chmduquesne/rollinghash/releases)
- [Commits](https://github.com/chmduquesne/rollinghash/commits/v4.0.0)

---
updated-dependencies:
- dependency-name: github.com/chmduquesne/rollinghash
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-03-10 13:36:25 +01:00
Jakob Borg
58f9dcca31 build: Update dependencies (#8821) 2023-03-10 13:04:13 +01:00
Jakob Borg
ab8e6a82ab lib/api: Expose blocksHash in file info (#8810)
This adds the BlocksHash field from the FileInfo to our API output. It
can be useful for debugging, or for external tools. I'm intentionally
leaving it as an opaque base64 string because no meaning should be
derived from it: it's just a string.
2023-03-06 15:37:15 +01:00
Syncthing Release Automation
3cdcb7dd72 gui, man, authors: Update docs, translations, and contributors 2023-03-06 03:45:45 +00:00
entity0xfe
4558eef446 lib/discover: Don't leak relay-tokens to discovery (#8762)
Use an allowlist to send only the `id` query param to the discovery server.
2023-03-04 12:16:57 +01:00
Syncthing Release Automation
8bbf2ba9ac gui, man, authors: Update docs, translations, and contributors 2023-02-27 03:45:16 +00:00
André Colomb
49c56b8caa gui: Add Croatian (hr) translation template (#8801) 2023-02-24 17:54:30 +01:00
dependabot[bot]
0b8aa7974b build(deps): bump github.com/quic-go/quic-go from 0.32.0 to 0.33.0 (#8800)
Bumps [github.com/quic-go/quic-go](https://github.com/quic-go/quic-go) from 0.32.0 to 0.33.0.
- [Release notes](https://github.com/quic-go/quic-go/releases)
- [Changelog](https://github.com/quic-go/quic-go/blob/master/Changelog.md)
- [Commits](https://github.com/quic-go/quic-go/compare/v0.32.0...v0.33.0)

---
updated-dependencies:
- dependency-name: github.com/quic-go/quic-go
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-02-22 13:01:08 +01:00
Jakob Borg
cbec697e5f cmd/stupgrades: Cache should apply to HEAD as well as GET 2023-02-22 12:22:52 +01:00
Jakob Borg
8991ecf444 build: Add more GitHub Actions 2023-02-22 10:56:55 +01:00
tomasz1986
17887ce0b1 gui: Remove non-existent customicons.css file reference (fixes #8797) (#8798)
The reference comes from fd0a6225aa,
but the file itself was removed in the process of working on the pull
request, yet the reference to it was still left in the index.html.

Signed-off-by: Tomasz Wilczyński <twilczynski@naver.com>
2023-02-21 19:05:15 +01:00
Andreas Sommer
2f88dafa56 Only fail after chmod error if permissions differ (e.g. on config file) (#8771) 2023-02-20 15:41:10 +01:00
Syncthing Release Automation
2321d0db08 gui, man, authors: Update docs, translations, and contributors 2023-02-20 03:45:34 +00:00
Jakob Borg
7047e00d1e build: Use Go 1.19.6 for Windows 2023-02-15 13:20:47 +01:00
Jakob Borg
a8533b269d build: Update dependencies 2023-02-14 19:08:25 +01:00
Syncthing Release Automation
ee30647bf7 gui, man, authors: Update docs, translations, and contributors 2023-02-13 03:48:08 +00:00
André Colomb
750accb25f gui: Remove duplicate Spanish (Spain) translation (fixes #8781) (#8782)
gui: Remove duplicate Spanish (Spain) translation.

Currently not among the set of "valid" (sufficiently complete)
languages and no longer synced with the tranlation platform, Weblate.
2023-02-09 10:10:40 +01:00
Eric P
0530f0edbf gui: Add xattr filter editor (fixes #8660) (#8734) 2023-02-09 09:14:36 +01:00
André Colomb
784129e1cf gui: Switch to Weblate for translations (#8777)
* Normalize EOL before EOF.

* Import current Transifex state, only translated.

Skip duplicated and completely empty languages.

* Re-add untranslated strings to JSON files.

These are now treated correctly as untranslated, but present with the
original (English) translation key.

* Update valid language codes and names.

* Refer to Weblate instead of Transifex for translations.

* lang-es: Copy untranslated strings from es-ES.

* Integrate translation changes from Weblate.

Translated using Weblate (Polish)

Currently translated at 100.0% (512 of 512 strings)

Translation: Syncthing/GUI strings
Translate-URL: https://hosted.weblate.org/projects/syncthing/gui/pl/

Translated using Weblate (Danish)

Currently translated at 98.6% (505 of 512 strings)

Translation: Syncthing/GUI strings
Translate-URL: https://hosted.weblate.org/projects/syncthing/gui/da/

Translated using Weblate (Lithuanian)

Currently translated at 85.4% (441 of 516 strings)

Translation: Syncthing/GUI strings
Translate-URL: https://hosted.weblate.org/projects/syncthing/gui/lt/

Translated using Weblate (French)

Currently translated at 100.0% (516 of 516 strings)

Translation: Syncthing/GUI strings
Translate-URL: https://hosted.weblate.org/projects/syncthing/gui/fr/

Translated using Weblate (Danish)

Currently translated at 98.6% (509 of 516 strings)

Translation: Syncthing/GUI strings
Translate-URL: https://hosted.weblate.org/projects/syncthing/gui/da/

Translated using Weblate (Spanish)

Currently translated at 100.0% (516 of 516 strings)

Translation: Syncthing/GUI strings
Translate-URL: https://hosted.weblate.org/projects/syncthing/gui/es/

* translation update uses weblate

---------

Co-authored-by: Jakob Borg <jakob@kastelo.net>
2023-02-07 12:22:08 +01:00
greatroar
38f2b34d29 all: Use new Go 1.19 atomic types (#8772) 2023-02-07 12:07:34 +01:00
Syncthing Release Automation
882b711958 gui, man, authors: Update docs, translations, and contributors 2023-02-06 03:45:18 +00:00
Jakob Borg
99595ce3d9 build: Update quic-go and pfilter for Go 1.20 (fixes #8768) (#8769) 2023-02-02 22:00:50 +01:00
Jakob Borg
d5e4ef249f Add forgotten copyright notices 2023-02-01 22:59:41 +01:00
Jakob Borg
65cfefaa3c cmd, docker: Updates for infrastructure
These are some changes to the relay pool server, upgrade server, and
crash receiver to run under Kubernetes. It's been in production for a
while.
2023-01-31 11:17:52 +01:00
Jakob Borg
a6c2a5a0ce cmd/ursrv: The driver import is important, though 2023-01-31 09:57:16 +01:00
Jakob Borg
a5b6199507 cmd/ursrv: Remove old, unused migration code 2023-01-31 09:12:48 +01:00
Jakob Borg
966e9f9a68 cmd/ursrv: Harmonize timespan of charts 2023-01-31 09:11:15 +01:00
Jakob Borg
b10e11abb7 cmd/ursrv: Remove broken and unsustainable join/leave chart 2023-01-31 09:10:52 +01:00
Jakob Borg
5a50de1154 cmd/ursrv: Fix broken block transfer chart 2023-01-31 09:09:36 +01:00
Syncthing Release Automation
dc6d695c00 gui, man, authors: Update docs, translations, and contributors 2023-01-30 03:45:28 +00:00
Vik
b120278b3a gui: Fix broken link to Transifex in lang/README.txt (#8761)
Updated URL
2023-01-29 21:52:09 +01:00
Syncthing Release Automation
c25f5b40d9 gui, man, authors: Update docs, translations, and contributors 2023-01-23 03:45:17 +00:00
Jakob Borg
abdac2caa2 Handle relay connect timeout (fixes #8749) (#8755)
This makes sure the service manager doesn't interpret timeout errors, or any other error, as a signal to stop the service instead of restarting it.

I added it directly to our service utility function, as it may help catch other instances of the same problem... We would typically want timeouts etc to be a retryable error, unless it is the top level context that has timed out and we check for that specifically.
2023-01-19 11:15:18 +01:00
Syncthing Release Automation
5f1e27bb7f gui, man, authors: Update docs, translations, and contributors 2023-01-16 03:48:02 +00:00
André Colomb
a85b4ab263 build: Go 1.19.5 2023-01-12 07:30:17 +04:00
Syncthing Release Automation
cf962a4fe8 gui, man, authors: Update docs, translations, and contributors 2023-01-09 03:45:24 +00:00
André Colomb
39c0bfa05a script: Add weblatedl.go for downloading updated translations (#8723)
Based on the transifexdl.go script.  Map Weblate language codes to the
existing ones during import.  Do not delete incomplete languages from
repo.
2023-01-08 15:25:00 +01:00
tomasz1986
458d6cff2a gui: Allow to translate action and type in Recent Changes modal (#8548)
Currently, action and type are both displayed only in English. This
commit makes it possible to translate both of them.

Signed-off-by: Tomasz Wilczyński <twilczynski@naver.com>
2023-01-05 14:33:03 +01:00
Syncthing Release Automation
ded881c372 gui, man, authors: Update docs, translations, and contributors 2023-01-02 03:45:30 +00:00
tomasz1986
fb4209e382 gui: Fix undefined lastSeenDays error in disconnected-inactive status check (ref #8530) (#8730)
The current code assumes that lastSeenDays is always set which is not
the case when device reports its lastSeen as equal to the Unix epoch.
Thus, make sure that lastSeenDays is set before proceeding with the
disconnected-inactive status check to avoid JS errors in the browser.

Signed-off-by: Tomasz Wilczyński <twilczynski@naver.com>
2022-12-26 12:59:04 +01:00
Syncthing Release Automation
473ca68dc4 gui, man, authors: Update docs, translations, and contributors 2022-12-26 03:45:20 +00:00
Jakob Borg
c4e69cd66c gui, api: Indicate running under container (#8728)
This adds a word to the version string when running containerized. The
purpose is mostly to facilitate troubleshooting via screenshot by
"leaking" this rather important aspect of the setup. Additionally, the
version row gets "no-overflow-ellipsis" treatment so that the whole
thing is actually visible in the GUI and the (now useless) tooltip is
removed. In production releases this won't make a difference as the
whole thing will typically fit, but in odd setups it provides more info
up front.
2022-12-25 08:08:41 +01:00
Simon Frei
634a3d0e3b lib/fs: Use io/fs errors as recommended in std lib (#8726) 2022-12-21 23:42:22 +01:00
Jakob Borg
09f4d865ae build: Handle co-authors (ref #3744) (#8708)
The authorship script didn't pick up people who were only ever
"co-authors" of a commit, such as when they wrote stuff which was later
included in a PR by someone else, or added code during code review.

This modified the script to look closer in the commit bodies for
"Co-authored-by:"-lines and adds those found to the set of authors.
2022-12-21 22:02:44 +01:00
Jakob Borg
ad0044fec8 lib/fs: Watching is unsupported on android/amd64 (fixes #8709) (#8710) 2022-12-21 22:01:00 +01:00
Simon Frei
d157d12037 lib/model: Only log at info level if setting change time fails (#8725) 2022-12-21 21:58:35 +01:00
Aleksey Vasenev
f9d68474ac lib/model: Don't lower rescan interval from default on auto accepted enc folder (fixes #8572) (#8573) 2022-12-21 19:52:22 +01:00
Syncthing Release Automation
f0126fe1ab gui, man, authors: Update docs, translations, and contributors 2022-12-19 03:45:31 +00:00
André Colomb
940536a964 gui: Remove unmaintained language variant nl-BE (#8722)
gui: Remove unmaintained language variant nl-BE.

This has long been removed from Transifex and from the valid-langs.js
list, but somehow the translation file stayed in the repo.  There is
already a generic Dutch variant (nl) available as replacement.
2022-12-18 08:30:26 +01:00
André Colomb
f378c4f191 gui, script: Fix indentation in lang-en.json to match others (#8721)
* Indent lang-en.json with four spaces as all other languages.

* Regenerate lang-en.json.

Removes two no longer used strings.
2022-12-18 08:29:59 +01:00
James O'Beirne
358d2143e2 docker: Ensure entrypoint is executable (#8719)
On systems with safe umasks (`umask 077`), the entrypoint as copied from
the host may not be executable by other users. Ensure that it is set to
be within the Dockerfile.
2022-12-16 08:16:22 +01:00
Jakob Borg
622ade40ad Go 1.19.4 2022-12-13 14:03:06 +01:00
Jakob Borg
323405ea07 Update dependencies (#8717) 2022-12-12 17:20:33 +01:00
Syncthing Release Automation
88c226ef87 gui, man, authors: Update docs, translations, and contributors 2022-12-12 03:48:00 +00:00
Jakob Borg
d4b668caac docker: Update healthcheck cmd for buildx (ref #8640) (#8706) 2022-12-06 21:23:49 +01:00
Aleksey Vasenev
05738001ac lib/model: Fixed adding empty items to device list (fixes #8646) (#8647) 2022-12-06 21:22:35 +01:00
Jakob Borg
d40d9d5698 build: Update dependencies (#8704) 2022-12-06 11:39:43 +01:00
Syncthing Release Automation
648c71cbd1 gui, man, authors: Update docs, translations, and contributors 2022-12-05 03:45:25 +00:00
André Colomb
ab0eb909a2 gui, lib/connections: Let the backend decide whether connection is local (fixes #8686) (#8694)
* lib/connections: Cache isLAN decision for later external access.

The check whether a remote device's address is on a local network
currently happens when handling the Hello message, to configure the
limiters.  Save the result to the ConnectionInfo and pass it out as
part of the model's ConnectionInfo struct in ConnectionStats().

* gui: Use provided connection attribute to distinguish LAN / WAN.

Replace the dumb IP address check which didn't catch common cases and
actually could contradict what the backend decided.  That could have
been confusing if the GUI says WAN, but the limiter is not actually
applied because the backend thinks it's a LAN.

Add strings for QUIC and relay connections to also differentiate
between LAN and WAN.

* gui: Redefine reception level icons for all connection types.

Move the mapping to the JS code, as it is much easier to handle
multiple switch cases by fall-through there.

QUIC is regarded no less than TCP anymore.  LAN and WAN make the
difference between levels 4 / 3 and 2 / 1:

{TCP,QUIC} LAN --> {TCP,QUIC} WAN --> Relay LAN --> Relay WAN -->
Disconnected.
2022-11-28 09:28:33 +01:00
Syncthing Release Automation
d16c0652f7 gui, man, authors: Update docs, translations, and contributors 2022-11-28 03:48:37 +00:00
Jakob Borg
0dae06deb3 Set build metadata correctly in Windows build (#8692)
Without this, we tag the build as made by some random user account on some random host name which is not useful.

(And minor bug in the cache key which has no effect on the build itself.)
2022-11-25 13:52:48 +01:00
greatroar
663106ef6e lib/fs: Optimize WindowsInvalidFilename (#8687)
Replaced strings.Split with the new strings.Cut, which doesn't allocate.

name                           old time/op    new time/op    delta
WindowsInvalidFilenameValid-8     154ns ± 2%      89ns ± 0%   -42.09%  (p=0.000 n=10+9)
WindowsInvalidFilenameNUL-8       124ns ± 2%     124ns ± 1%      ~     (p=0.371 n=8+10)

name                           old alloc/op   new alloc/op   delta
WindowsInvalidFilenameValid-8     16.0B ± 0%      0.0B       -100.00%  (p=0.000 n=10+10)
WindowsInvalidFilenameNUL-8       19.0B ± 0%      3.0B ± 0%   -84.21%  (p=0.000 n=10+10)

name                           old allocs/op  new allocs/op  delta
WindowsInvalidFilenameValid-8      1.00 ± 0%      0.00       -100.00%  (p=0.000 n=10+10)
WindowsInvalidFilenameNUL-8        2.00 ± 0%      1.00 ± 0%   -50.00%  (p=0.000 n=10+10)
2022-11-21 12:58:00 +01:00
Syncthing Release Automation
0b2b8baf19 gui, man, authors: Update docs, translations, and contributors 2022-11-21 03:57:01 +00:00
Jakob Borg
24275b4584 cmd/syncthing: Use main logger in generate subcommand (fixes #8682) (#8685)
We had some unholy mix of our own logger and the stdlib logger, probably
because for historical reasons we wanted the device ID to stdout and the
rest to stderr? But that's not the case any more, and the mix of formats
is weird. Ideally I think the generate command should be silent and just
print the device ID and nothing else, but that's tricky to accomplish
since we have other methods do logging on their own. Hence this just
harmonizes it so that we at least use the same logger with the same
format and target...
2022-11-20 13:48:08 +01:00
Jakob Borg
2a8362d7af build: Update all dependencies (fixes #8679) (#8680)
Minor API change for the LRU cache in casefs
2022-11-17 21:26:10 +01:00
Syncthing Release Automation
8cca9dfef5 gui, man, authors: Update docs, translations, and contributors 2022-11-14 04:02:37 +00:00
Jakob Borg
6aa04118a6 lib/model: Correctly set xattrs on temp files (fixes #8667) (#8670) 2022-11-11 11:49:15 +01:00
Boris Rybalkin
1b32e9f858 gui: Automatically dismiss authentication reminder when in LDAP mode (fixes #8661) (#8663) 2022-11-10 08:14:47 +01:00
Jakob Borg
a523fef78e lib/model: Correctly handle xattrs on directories (fixes #8657) (#8658) 2022-11-09 06:54:04 +01:00
Simon Frei
ce2a68622c lib/protocol: Ignore inode time when xattr&ownership is ignored (fixes #8654) (#8655)
lib/protocol: Ignore inode time when both xattr and ownership is ignored (fixes #8654)
2022-11-08 08:36:41 +01:00
Jakob Borg
a29605750d lib/fs: Try to remove read only Windows files (fixes #3744) (#8650)
This happens when folders contain a custom icon.

Co-authored-by: Alexandre Alves <alexandrealvesdb.contact@gmail.com>
2022-11-07 21:33:17 +01:00
tomasz1986
5e384c9185 gui: Add copy to clipboard, share by email, and share by SMS buttons to device IDs (fixes #2771, ref #3868) (#7984)
gui: Add copy to clipboard, share by email, and share by SMS buttons to device IDs (fixes #2771, ref #3868)

Add buttons to allow for simpler sharing device IDs with others. The
first one copies the ID to clipboard (trying to use three different
methods, depending on the browser). The second one triggers a mailto
link with prefilled subject and body. The third one triggers an sms link
with prefilled body. The short description of Syncthing included in the
latter part of the body is a direct copy from the description at the
official website https://syncthing.net.

Issue #3868 is referred here, because the copy to clipboard button
offers an alternative method for IE11 users to actually be able to copy
device IDs without having to select it manually (which doesn't work).

Signed-off-by: Tomasz Wilczyński <twilczynski@naver.com>
2022-11-07 20:11:12 +01:00
Syncthing Release Automation
a1cc293c21 gui, man, authors: Update docs, translations, and contributors 2022-11-07 04:03:05 +00:00
Jakob Borg
452daad14b build: Add GitHub actions build for Windows (#8627)
This is sort of a proof of concept, but since our current Windows
builder is down this might solve the problem. It includes a change for
easier code signing (taking the certificate in a secret/env var rather
than existing already on disk), but otherwise mirrors precisely what we
already do in the build server.
2022-11-05 15:40:53 +01:00
tomasz1986
fbdaa265d3 gui: Fix connection type icon width (fixes #8592) (#8644)
The connection type icon comes from Bootstrap. As such, it does not
follow the same dimensions as the other GUI icons, which come from Fork
Awesome. Thus, add left and right margin to make its width roughly the
same as the other GUI icons, which fixes its alignment in relation to
text.

Signed-off-by: Tomasz Wilczyński <twilczynski@naver.com>
2022-11-04 21:12:18 +01:00
tomasz1986
46b375e8cc gui: Adjust connection type icon size scaling and alignment (#8645) 2022-11-04 19:41:27 +01:00
bt90
1e9bf17512 docker: Use healthcheck endpoint (#8640)
Query healthcheck endpoint
2022-11-03 20:43:32 +01:00
Jakob Borg
413c8cf4ea lib/connections: Use adaptive write size for rate limited connections (fixes #8630) (#8631) 2022-11-03 15:44:46 +01:00
tomasz1986
d8296ce111 gui: Mark devices that haven't connected for a long time (fixes #7703) (#8530)
Currently, a disconnected device is marked as "Disconnected" without any
consideration whether the state is just temporary or rather it has been
like that for a long time, potentially requiring user intervention.

This commit adds a new state called "Disconnected (Inactive)" which is
shown for devices that have been disconnected for longer than a week. It
also changes the "Last seen" information, so that "Never" is used only
when the device hasn't connected at all, and the exact date is displayed
otherwise.

Additionally, when the date is older than 1 week, a note about that is
displayed below the date. Furthermore, when the date becomes older than
1 month, the note text colour changes to orange, and when it exceeds 1
year, the colour changes again to red. This is done to provide the user
with a visual clue that something may potentially be wrong and requires
a manual fix.

Signed-off-by: Tomasz Wilczyński <twilczynski@naver.com>
Co-authored-by: André Colomb <src@andre.colomb.de>
2022-11-03 12:09:28 +01:00
Aleksey Vasenev
06a1635d1d gui: Fix rescan interval when add encrypted folder with watch for changes enabled (fixes #8570) (#8571) 2022-11-03 12:07:36 +01:00
tomasz1986
36221b70ac gui: Always show Out of Sync Items for remote devices (#8632)
Right now, the Out of Sync Items list for a specific remote device is
available only when the device is online and currently synchronising.
However, the list itself is being created by Syncthing all the time, so
there is no need to hide it from the user even when the remote device is
offline or paused. This way they can always easily check which files
exactly have not been synchronised yet.

In addition, the Out of Sync Items entry already includes file size next
to it, so there is no need to display it again next to the Sync Status
entry. Thus, remove out-of-sync file size from Sync Status, leaving only
percentage next to it.

Signed-off-by: Tomasz Wilczyński <twilczynski@naver.com>
2022-11-03 12:06:31 +01:00
Jakob Borg
bf1e418e4a lib/fs: Let xattr test avoid non-test attributes (fixes #8601) (#8628)
SELinux for example adds security.* attributes by default that we are
not allowed to touch, which causes the test to fail.
2022-11-03 11:57:30 +01:00
Jakob Borg
922946683d Merge branch 'release'
* release:
  build: Add GitHub actions build for Windows
2022-11-02 09:00:35 +01:00
Jakob Borg
abb921acbc build: Add GitHub actions build for Windows
This is sort of a proof of concept, but since our current Windows
builder is down this might solve the problem. It includes a change for
easier code signing (taking the certificate in a secret/env var rather
than existing already on disk), but otherwise mirrors precisely what we
already do in the build server.
2022-11-02 07:27:53 +01:00
Syncthing Release Automation
816354e66b gui, man, authors: Update docs, translations, and contributors 2022-10-31 04:04:36 +00:00
tomasz1986
8228020ff0 gui: Display folder and device count number (#8615)
In large setups, it is currently impossible to know the exact number of
folders and remote devices without counting them manually, either in the
GUI or in config.xml. Thus, to provide this information to the user, add
a specific number right next to both Folders and Remote Devices headers
in the Web GUI. The numbers are only displayed when two or more folders
or devices are present.

Signed-off-by: Tomasz Wilczyński <twilczynski@naver.com>
2022-10-21 16:01:41 +02:00
Syncthing Release Automation
c96f76e1fd gui, man, authors: Update docs, translations, and contributors 2022-10-17 04:34:10 +00:00
Jakob Borg
d3f50637d2 lib/model, lib/protocol: Fix file comparisons (fixes #8594) (#8603) 2022-10-16 17:04:28 +02:00
Jakob Borg
ed588ce335 lib/scanner: More sensible debug output (#8596)
Previous debug input didn't really give enough info to show what was
happening, while it also printed full block lists which are enormously
verbose. Now it consistently prints 1. what it sees on disk, 2. what it
got from CurrentFile (without blocks), 3. the action taken on that file.
2022-10-13 19:32:58 +02:00
tomasz1986
34d91b228d gui: Allow automatic device ID selection on WebKit browsers (ref #8544) (#8597)
Some WebKit browsers select more than needed when using double click to
select device IDs, e.g. new lines and white space. This commit adds a
prefixed version of user-select in CSS in order to add support for those
browsers and allow them to select just device IDs automatically.

Signed-off-by: Tomasz Wilczyński <twilczynski@naver.com>
2022-10-10 23:01:37 +02:00
Syncthing Release Automation
fb6a35c98c gui, man, authors: Update docs, translations, and contributors 2022-10-10 04:24:03 +00:00
Jakob Borg
87bf09ea40 lib/protocol: Show inode change time in FileInfo debug string (#8591) 2022-10-08 19:28:10 +02:00
André Colomb
a13bb926b7 gui: Tweak whitespace (#8587) 2022-10-07 08:10:17 +02:00
Eric P
7a402409f1 lib/api: Add /rest/noauth/health health-check (fixes #8430) (#8585) 2022-10-06 21:28:49 +02:00
Eric P
c791dba392 api, gui: Prevent connection issues due to unsupported-upgrade (fixes #8569) (#8586)
There are some situations where an upgrade wouldn't be supported, even though the noUpgrade bool isn't set. So when handling the errors that are caused by this, when attempting an upgrade, it shouldn't lead to some sort of offline-message/restart/warning/etc...

I added some checks on specific errors related to this and return a 501 (Not Implemented) response instead, in case of an "UpgradeUnsupported"-error. Additionally, on the GUI-side, the 501-response is now not to be considered an error to act upon.
2022-10-06 21:27:08 +02:00
Simon Frei
a0c80e030a lib/model: Fix warning log statement (ref #8583) (#8584) 2022-10-05 18:45:37 +02:00
Jakob Borg
b6bb67b142 build: Update dependencies (#8581) 2022-10-04 11:23:41 +02:00
Jakob Borg
1306d86a62 build: Also update Dockerfile.buildx for new package dependency 2022-10-04 08:31:54 +02:00
Jakob Borg
57443804ba Merge branch 'release'
* release:
  docker: Fix handling of PCAP variable (fixes #8567) (#8568)
  lib/fs: Skip xattrs test on EOPNOTSUPP (fixes #8564) (#8565)
2022-10-04 07:57:07 +02:00
Syncthing Release Automation
2839baf0de gui, man, authors: Update docs, translations, and contributors 2022-10-03 04:04:44 +00:00
Jakob Borg
7e848a150b docker: Fix handling of PCAP variable (fixes #8567) (#8568)
This correctly handles the absense of the PCAP environment variable,
which was broken in the previous change.
2022-10-02 08:58:22 +02:00
Simon Frei
81bdde79ea lib/fs: Skip xattrs test on EOPNOTSUPP (fixes #8564) (#8565) 2022-10-02 08:58:19 +02:00
Jakob Borg
a206366d10 docker: Fix handling of PCAP variable (fixes #8567) (#8568)
This correctly handles the absense of the PCAP environment variable,
which was broken in the previous change.
2022-10-02 08:50:27 +02:00
Jakob Borg
1e652de5af cmd/stcrashreceiver: Update to more modern panicparse (#8566) 2022-10-01 21:03:14 +01:00
entity0xfe
ad986f372d cmd/strelaysrv: Add optional auth token (fixes #3987) (#8561)
* implement authentication via token for relaysrv

Make replaysrv check for a token before allowing clients to
join. The token can be set via the replay-uri.

* fix formatting

* key composite literal

* do not error out if auth material is provided but not needed

* remove unused method receiver

* clean up unused parameter in functions

* cleaner token handling, disable joining the pool if token is set.

* Keep backwards compatibility with older clients.

In prior versions of the protocol JoinRelayRequest did not have a
token field. Trying to unmarshal such a request will result in
an error. Return an empty JoinRelayRequest, that is a request
without token, instead.

Co-authored-by: entity0xfe <entity0xfe@my.domain>
2022-10-01 20:41:02 +01:00
Simon Frei
0935886045 lib/fs: Skip xattrs test on EOPNOTSUPP (fixes #8564) (#8565) 2022-10-01 08:48:00 +02:00
Eric P
fd0a6225aa gui: Add connection status icons to Remote Devices (fixes #8244) (#8553) 2022-09-30 18:15:19 +02:00
tomasz1986
b39985483d gui: Filter scope ID out of IPv6 addresses in Remote GUI (fixes #8084) (#8559)
Currently, the link to remote GUI uses device addresses as they are
advertised from the router. Because of this, they may end up having a
scope ID attached to them. The problem is that browsers do not support
such addresses, leaving the user with a non-working URL.

Because of the above, use regex to simply filter out the scope ID from
the address before using it for Remote GUI.

Signed-off-by: Tomasz Wilczyński <twilczynski@naver.com>
2022-09-27 19:57:48 +02:00
Nick Busey
f38df0dadb cmd/syncthing: Fix incorrect cli help text (#8557) 2022-09-26 22:52:33 +01:00
Jakob Borg
361f7ae564 docker: Add env var to control capabilities (#8552)
As it's not simple to run a container under Docker/Kubernetes as
non-root but with additional capabilities, add an internal hack.
2022-09-26 13:39:41 +02:00
Syncthing Release Automation
1cd2f5a91f gui, man, authors: Update docs, translations, and contributors 2022-09-26 04:33:20 +00:00
tomasz1986
dab68cf841 gui: Add size and improve alt text of device QR code image (#8545)
Currently, the QR code image has no size specified in the HTML. This
causes other elements of the modal to jump around when opening it for
the first time and waiting for the QR image to generate. The jumping is
especially noticeable when the GUI is accessed remotely and there is a
delay while loading the elements due to slow connection.

In addition, capitalise "QR" in the alt text. This is necessary for
accessibility reasons, e.g. when using a screen reader, which may read
upper- and lowercase characters differently.

Lastly, allow to translate the alt text itself.

Signed-off-by: Tomasz Wilczyński <twilczynski@naver.com>
2022-09-20 11:46:35 +02:00
dependabot[bot]
d51fe3fb3f build(deps): bump actions/setup-go from 3.2.1 to 3.3.0 (#8518)
Bumps [actions/setup-go](https://github.com/actions/setup-go) from 3.2.1 to 3.3.0.
- [Release notes](https://github.com/actions/setup-go/releases)
- [Commits](84cbf80943...268d8c0ca0)

---
updated-dependencies:
- dependency-name: actions/setup-go
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-09-20 11:46:19 +02:00
tomasz1986
5baf5fedb5 gui: Replace JS select-on-click with CSS user-select (fixes #3868) (#8544)
Currently, a custom JS script is used to select the whole device ID on
click. However, the current script isn't compatible with all browsers
(and in IE in particular), making it impossible to select the ID in them
at all. Additionally, the same functionality is already available in CSS
with no such drawbacks, as the whole selection process is handled by the
Web browser natively, which is lightweight and does not require custom
code.

Thus, remove the currently used JS script completely, replacing it with
a new CSS class that can be added to an element when required. If the
browser does not support the CSS, the user can still select the element
manually, which makes it safer than the current behaviour that can block
the user from being able to select the element at all.

Signed-off-by: Tomasz Wilczyński <twilczynski@naver.com>
2022-09-20 11:37:34 +02:00
Eric P
3f2742a275 lib/versioner: Fix error in Trashcan restore (fixes: #7965) (#8549)
The restore function of Trash Can ran a rename at the end regardless of whether there was anything to rename. In this case, when the file-to-be-restored did not exist in the destination folder, this resulted in an error. I added a simple check, keeping track of whether the file existed prior to restoring it in the destination folder and depending on this value it will now return nil after the restoration to prevent the renaming function to kick off. Added a test for this specific edge-case as well.
2022-09-20 11:34:15 +02:00
tomasz1986
0e23002414 gui: Fix missing word in sendOwnership explanation in GUI (#8547)
For consistency with syncOwnership explanation right above this one, the
sentence should talk about "sending ownership information", and not just
"sending ownership".

Signed-off-by: Tomasz Wilczyński <twilczynski@naver.com>
2022-09-19 21:34:10 +02:00
Syncthing Release Automation
641941562f gui, man, authors: Update docs, translations, and contributors 2022-09-19 04:32:50 +00:00
André Colomb
698346edc3 script: Support single quotes in $translate.instant() parsing (#8542)
Duplicate the regular expression for single and double quotes.
Support additional arguments (string substitution) in both variants.
Simplify the translation string group matching by using a lazy
quantifier instead of excluding the quote itself.
2022-09-16 22:52:33 +02:00
Jakob Borg
39d3424e34 build: Improve update-deps command, update deps (#8540) 2022-09-14 10:29:44 +02:00
Jakob Borg
6cac308bcd all: Support syncing extended attributes (fixes #2698) (#8513)
This adds support for syncing extended attributes on supported
filesystem on Linux, macOS, FreeBSD and NetBSD. Windows is currently
excluded because the APIs seem onerous and annoying and frankly the uses
cases seem few and far between. On Unixes this also covers ACLs as those
are stored as extended attributes.

Similar to ownership syncing this will optional & opt-in, which two
settings controlling the main behavior: one to "sync" xattrs (read &
write) and another one to "scan" xattrs (only read them so other devices
can "sync" them, but not apply any locally).

Co-authored-by: Tomasz Wilczyński <twilczynski@naver.com>
2022-09-14 09:50:55 +02:00
greatroar
8065cf7e97 lib: Factor out getting IP address from net.Addr (#8538)
... and add fast paths for common cases.
2022-09-14 08:44:46 +02:00
Eric P
6e768a8387 lib/versioner: Fix cleaning behaviour (fixes #7988) (#8537)
The cleaning logic in util.go was used by Simple and Trashcan but only
really suited Trashcan since it works based on mtimes which Simple does
not use. The cleaning logic in util.go was moved to trashcan.go.
Staggered and Simple seemed to be able to benefit from the same base so
util.go now has the base for those two with an added parameter which
takes a function so it can still handle versioner-specific logic to
decide which files to clean up. Simple now also correctly cleans files
based on their time-stamp in the title together with a specific maximum
amount to keep. The Archive function in Simple.go was changed to get rid
of duplicated code.

Additionally the trashcan testcase which was used by Trashcan as well as
Simple was moved from versioner_test.go to trashcan_test.go to keep it
clean, there was no need to keep it in a separate test file
2022-09-13 19:21:42 +02:00
tomasz1986
7d3c390c91 gui: Fix text wrapping on tablet-sized screens (fixes #8529) (#8533)
Currently, the code contains a "mobile phone" fix to allow wrapping of
long lines in table heading and cells. However, the fix is applied to
all screen sizes equal or below 768 px wide, which causes the layout to
break on tablet-sized screens.

The commit moves the "mobile" fix to the actual mobile media query,
which is applied to screens up to 419 px wide. It is only really needed
there, where it synergises with the existing fix that changes table cell
display to "block". There is no need to wrap the text on larger screens,
as there is more than enough space to display the lines in full on them.

Signed-off-by: Tomasz Wilczyński <twilczynski@naver.com>
2022-09-13 19:18:57 +02:00
André Colomb
3e99ddfbf0 etc/linux-systemd: Mention AmbientCapabilities for syncOwnership. (#8536)
Add a commented entry to the systemd service file templates to point
the user in the right direction when using syncOwnership and starting
via systemd.  Which is more upgrade-friendly than setting caps on the
executable directly, as mentioned in the docs.
2022-09-13 10:00:47 +02:00
tomasz1986
43f0e5c91d gui: Fix error in Restore Versions when path exists as both directory and file (fixes #7068) (#8532)
The current code checks whether the same-named item exists in the tree,
and when it does, it re-uses it when adding new children to it. However,
the code doesn't check whether the existing item is a folder or a file.
It rather assumes that it is always a folder, which is not necessarily
the case.

This commit adds a new check to the code, so that the existing element
is reused only when it is a folder, and ignored otherwise.

Signed-off-by: Tomasz Wilczyński <twilczynski@naver.com>
2022-09-12 08:19:29 +02:00
Syncthing Release Automation
c3902f9887 gui, man, authors: Update docs, translations, and contributors 2022-09-12 04:32:45 +00:00
tomasz1986
33e3643aed gui: Add tooltip to folder error message (fixes #7603) (#8531)
Currently, the error message is often quite long and thus it appears
truncated with no possibility for the user to view the full string.
Thus, add a tooltip that displays the message in full on hover. This
follows the convention used in other parts of the GUI in similar cases.

Signed-off-by: Tomasz Wilczyński <twilczynski@naver.com>
2022-09-11 22:13:04 +02:00
greatroar
78be7225fb build(deps): Bump github.com/pierrec/lz4 (#8528) 2022-09-11 10:13:27 +02:00
cui fliter
6afaa9f20c cmd/syncthing: Fix two typos (#8493)
Signed-off-by: cui fliter <imcusg@gmail.com>
2022-09-11 00:43:10 +02:00
greatroar
152388b3a3 lib/tlsutil: Use crypto.Signer interface (#8526)
*rsa.PrivateKey and *ecdsa.PrivateKey are both Signers, which have a
method to get the public key. No need for the type switch.
2022-09-09 14:22:38 +02:00
Syncthing Release Automation
053425695a gui, man, authors: Update docs, translations, and contributors 2022-09-05 04:26:01 +00:00
Syncthing Release Automation
5d917e1306 gui, man, authors: Update docs, translations, and contributors 2022-08-29 04:23:19 +00:00
luzpaz
837ffcfab5 all: Fix various user-facing and non-user-facing typos (#8509)
Found via `codespell -q 3 -S lang,./gui/default/vendor -L benchs,bu,inflight,ro`
2022-08-23 15:44:11 +02:00
Syncthing Release Automation
62d4261f62 gui, man, authors: Update docs, translations, and contributors 2022-08-22 04:16:54 +00:00
Simon Frei
6dedffe3f7 cmd/syncthing: Use os.executable in monitor, only fallback to PATH (#8502) 2022-08-17 08:57:33 +02:00
Jakob Borg
b10d106a55 all: Modernize error wrapping (#8491)
This replaces old style errors.Wrap with modern fmt.Errorf and removes
the (direct) dependency on github.com/pkg/errors. A couple of cases are
adjusted by hand as previously errors.Wrap(nil, ...) would return nil,
which is not what fmt.Errorf does.
2022-08-16 10:01:49 +02:00
Syncthing Release Automation
75eeae0ee7 gui, man, authors: Update docs, translations, and contributors 2022-08-15 04:09:30 +00:00
Simon Frei
5fd6278609 cmd/syncthing: Work around binary in current dir restriction (fixes #8499) (#8500) 2022-08-14 21:25:45 +02:00
Jakob Borg
eb81f7400c lib/fs: Cache user lookups (#8496) 2022-08-12 07:48:00 +02:00
Jakob Borg
06273875ae all: Make scanning ownership opt-in (#8497) 2022-08-12 07:47:20 +02:00
André Colomb
4d4bfe8032 lib/model: Skip paused folders in aggregated completion loop (fixes #8219) (#8220)
Locally paused folders will fail on checkFolderRunningLocked() and
therefore abort the loop.  Avoid this by skipping paused folders
directly.

Co-authored-by: Jakob Borg <jakob@kastelo.net>
2022-08-10 08:50:19 +02:00
tomasz1986
28c660e41d gui: Remove unused strings from translations (#8288)
These strings no longer exist in the GUI, hence there is no need to keep
them in the translation json files either.

Signed-off-by: Tomasz Wilczyński <twilczynski@naver.com>
Co-authored-by: Jakob Borg <jakob@kastelo.net>
2022-08-10 08:44:45 +02:00
Jakob Borg
d6a90f0022 Merge branch 'release'
* release:
  lib/ur: Properly initialize map in failure data (fixes #8479)
2022-08-10 08:30:46 +02:00
André Colomb
63de838f27 gui, api: Show internal config and state paths (fixes #8323) (#8324)
* lib/locations: Fix enum values camelCase.

* lib/locations: Remove unused FailuresFile.

* cmd/syncthing: Turn around role of locations storage.

Previously the locations package was used to provide default paths,
possibly with an overridden home directory.  Extra paths supplied on
the command line were handled and passed around in the options object.

To make the changed paths available to any other interested package,
override the location setting from the option if supplied, instead of
vice versa when not supplied.  Adapt code using this to read from the
locations package instead of passing through the options object.

* lib/locations: Refactor showPaths to locations package.

Generate a reusable string in locations.PrettyPrintPaths().
Enumerating all possible locations in different packages is error
prone, so add a new public function to generate the listing as a
string in the locations package.  Adapt cmd/syncthing --paths to use
that instead of its own console output.

* lib/locations: Include CSRF token in pretty printed paths.

* lib/api: New endpoint /rest/system/paths.

The paths should be available for troubleshooting from a running
instance.  Using the --paths CLI option is not easy in some
environments, so expose the locations mapping to a JSON endpoint.

Add utility function ListExpandedPaths() that also filters out any
entries which still contain variable placeholders.

* gui: List runtime paths in separate log viewer tab.

* Wrap paths.

* lib/syncthing: Utilize locations.Get() instead of passing an arg.

* Include base directories, move label to table caption.

* gui: Switch to hard-coded paths instead of iterating over all.

* gui: Break aboutModalView into tabs.

Use tabs to separate authors from included third-party software.

* gui: Move paths from log viewer to about modal.

* lib/locations: Adjust pretty print output order to match GUI.

* gui, authors: Remove additional bot names and fix indent.

The indentation changed because of the tabbed about dialog, fix the
authors script to respect that.

Skip Syncthing*Automation in authors list as well.

* Update AUTHORS list to remove bot names.

* Revert AUTHORS email order change.

* Do not emphasize DB and log file locations.

* Review line wrapping.

* review part 1: strings.Builder, naming

* Rename and extend locations.Set() with error handling.

Remodel the Override() function along the existing SetBaseDir() and
rename it to simply Set().  Make sure to use absolute paths when given
log file or GUI assets override options.  Add proper error reporting
if that goes wrong.

* Remove obsolete comment about empty logfile option.

* Don't filter out unexpanded baseDir placeholders, only ${timestamp}.

* Restore behavior regarding special "-" logfile argument.

If the option is given, but with empty value, assume the no log
file (same as "-").  Don't try to convert the special value to an
absolute path though and document this fact in a comment for the Set()
function.

* Use template to check for location key validity.

* Don't filter out timestamp placeholders.

* lib/api: Remove paths from /rest/system/status.

* lib/ur: Properly initialize map in failure data (fixes #8479)

Co-authored-by: Jakob Borg <jakob@kastelo.net>
2022-08-10 08:25:13 +02:00
dependabot[bot]
20dea04aa2 build(deps): bump github.com/go-ldap/ldap/v3 from 3.4.1 to 3.4.4 (#8475)
Bumps [github.com/go-ldap/ldap/v3](https://github.com/go-ldap/ldap) from 3.4.1 to 3.4.4.
- [Release notes](https://github.com/go-ldap/ldap/releases)
- [Commits](https://github.com/go-ldap/ldap/compare/v3.4.1...v3.4.4)

---
updated-dependencies:
- dependency-name: github.com/go-ldap/ldap/v3
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-08-10 08:15:35 +02:00
Jakob Borg
f5aa604efc Merge branch 'release'
* release:
  lib/ur: Properly initialize map in failure data (fixes #8479)
2022-08-09 18:52:51 +02:00
dependabot[bot]
4eef43c62d build: bump actions/setup-go from 2.2.0 to 3.2.1 (#8492)
Bumps [actions/setup-go](https://github.com/actions/setup-go) from 2.2.0 to 3.2.1.
- [Release notes](https://github.com/actions/setup-go/releases)
- [Commits](bfdd3570ce...84cbf80943)

---
updated-dependencies:
- dependency-name: actions/setup-go
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-08-09 12:37:20 +02:00
Jauder Ho
d2f132f37f build: Let dependabot suggest updates to GitHub actions (#8490)
Configure Dependabot to update GitHub Actions in workflows.
2022-08-09 12:31:08 +02:00
Jauder Ho
ecdb970468 update: Go version in update-docs-translations action (#8489)
Bump Go minimum version to 1.18.4
2022-08-08 21:01:08 +02:00
Syncthing Release Automation
b32e43fbb3 gui, man, authors: Update docs, translations, and contributors 2022-08-08 04:01:50 +00:00
Martchus
373859be83 cmd/syncthing: Refactor CLI code to allow passing CLI arguments via function parameter (#8485)
Currently the `Run()` function of the CLI always uses `os.Args` directly.
This change adds an additional `RunWithArgs()` function that allows passing
arguments as `[]string` instead. This is useful when linking against
Syncthing as a library to be able to also expose the CLI.
2022-08-07 18:15:26 +02:00
Jakob Borg
209e68c1ba build: Update quic-go for Go 1.19 (#8483)
Also adds idle time and keepalive parameters because how this is
configured has changed in the new package version. The values are those
that seems like might already be default, if keep-alives were enabled,
which is not obvious from the doc comments.

Also, Go 1.19 gofmt reformatting of comments.
2022-08-03 15:43:26 +02:00
Jakob Borg
cc54488e55 lib/ur: Properly initialize map in failure data (fixes #8479) (#8480) 2022-08-03 10:41:26 +02:00
Jakob Borg
c7b4fd5784 lib/ur: Properly initialize map in failure data (fixes #8479) 2022-08-02 10:10:29 +02:00
Syncthing Release Automation
5c69761bc8 gui, man, authors: Update docs, translations, and contributors 2022-08-01 04:20:52 +00:00
bt90
de7d62cc1b docs: Clarify docker network mode limitations (#8472) 2022-07-31 20:46:57 +02:00
Jakob Borg
5977868165 lib/config: Use net.JoinHostPort instead of string manipulation (#8470) 2022-07-28 22:06:55 +02:00
Jakob Borg
585fb3f49b lib/api: Fix inverted logic in string comparison 2022-07-28 21:51:14 +02:00
deepsource-autofix[bot]
8e3f1190d1 lib/model: Use bytes.Equal instead of converting to string (#8469)
Co-authored-by: deepsource-autofix[bot] <62050782+deepsource-autofix[bot]@users.noreply.github.com>
2022-07-28 20:00:07 +02:00
Jakob Borg
a3c724f2c3 all: Add build constants for runtime.GOOS comparisons (#8442)
all: Add package runtimeos for runtime.GOOS comparisons

I grew tired of hand written string comparisons. This adds generated
constants for the GOOS values, and predefined Is$OS constants that can
be iffed on. In a couple of places I rewrote trivial switch:es to if:s,
and added Illumos where we checked for Solaris (because they are
effectively the same, and if we're going to target one of them that
would be Illumos...).
2022-07-28 19:36:39 +02:00
deepsource-autofix[bot]
f13d65262a cmd/strelaysrv: Fix superfluous else statements (#8468)
Co-authored-by: deepsource-autofix[bot] <62050782+deepsource-autofix[bot]@users.noreply.github.com>
2022-07-28 19:31:43 +02:00
deepsource-autofix[bot]
f2be9d1166 all: Fix nested if with else if (#8467)
Co-authored-by: deepsource-autofix[bot] <62050782+deepsource-autofix[bot]@users.noreply.github.com>
2022-07-28 19:14:22 +02:00
Jakob Borg
dde275c6cc all: Unused errors 2022-07-28 19:08:51 +02:00
Jakob Borg
212258d213 lib/fs: Consolidate append in test 2022-07-28 19:05:24 +02:00
Jakob Borg
966db0d076 lib/api: Further (final?) unused parameters removal 2022-07-28 19:02:12 +02:00
Jakob Borg
6686810943 cmd/syncthing: Incorrect error handling 2022-07-28 18:51:22 +02:00
Jakob Borg
6baa93e13f lib/api: String comparisons 2022-07-28 18:49:44 +02:00
Jakob Borg
0c8b22c696 lib/api: Remove unused parameters 2022-07-28 18:48:15 +02:00
deepsource-autofix[bot]
81d8fa1cb5 all: Fix unused method receiver (further) (#8466)
Co-authored-by: deepsource-autofix[bot] <62050782+deepsource-autofix[bot]@users.noreply.github.com>
2022-07-28 17:55:29 +02:00
Jakob Borg
79f8bd0f33 all: Minor deprecation updates 2022-07-28 17:54:12 +02:00
Jakob Borg
5958f42294 lib/model: Clarify normal shallow copy 2022-07-28 17:41:07 +02:00
Jakob Borg
8b4bd43306 lib/api: Missing error handling in config handler (#8463) 2022-07-28 17:35:43 +02:00
deepsource-autofix[bot]
755d21953f all: Remove unused method receivers (#8462)
Co-authored-by: deepsource-autofix[bot] <62050782+deepsource-autofix[bot]@users.noreply.github.com>
2022-07-28 17:32:45 +02:00
Jakob Borg
388e4db9cd all: Combine sequential appends (#8461) 2022-07-28 17:28:24 +02:00
Jakob Borg
f3835122bb cmd/ursrv: Silence linter with correct regexps (#8460) 2022-07-28 17:26:07 +02:00
deepsource-autofix[bot]
5130c414da all: Unused parameter should be replaced by underscore (#8464)
Co-authored-by: deepsource-autofix[bot] <62050782+deepsource-autofix[bot]@users.noreply.github.com>
2022-07-28 17:17:29 +02:00
Jakob Borg
7bdb5faa9c all: Remove or convert deprecated API usages (#8459) 2022-07-28 17:14:49 +02:00
deepsource-autofix[bot]
7e26f74f38 lib/config: Remove unnecessary use of fmt.Sprintf (#8458)
Co-authored-by: deepsource-autofix[bot] <62050782+deepsource-autofix[bot]@users.noreply.github.com>
2022-07-28 17:00:41 +02:00
deepsource-autofix[bot]
0bdd0d595b lib/model: Replace for loop with append (#8457)
Co-authored-by: deepsource-autofix[bot] <62050782+deepsource-autofix[bot]@users.noreply.github.com>
2022-07-28 16:57:09 +02:00
deepsource-autofix[bot]
80ec4acb53 all: Fix check for empty string (#8456)
Co-authored-by: deepsource-autofix[bot] <62050782+deepsource-autofix[bot]@users.noreply.github.com>
2022-07-28 16:51:03 +02:00
Jakob Borg
a2c5d901f2 cmd/syncthing, lib/config: Remove restartOnWakeup option & functionality (fixes #8448) (#8449) 2022-07-26 16:53:10 +02:00
LSmithx2
1b575b4461 gui: Remove blank meta tags (#8362) 2022-07-26 10:19:12 +02:00
Evan Spensley
c6a319d98b gui: Add device sync status (fixes #7981) (#8401) 2022-07-26 10:15:19 +02:00
tomasz1986
9f4d23cacf gui: Fix detailed staggered versioning information in folder info (ref #8348) (#8433)
Currently, there are two issues with the detailed staggered versioning
information displayed in the folder info. Firstly, the maxAge value of
365d is displayed despite matching the default. Secondly, there is no
consideration for the special case of maxAge equal to 0, meaning that
versions are kept forever.

This commit fixes both of those issues, so that the default maxAge is
not displayed and its value of 0 is displayed as "forever".

Signed-off-by: Tomasz Wilczyński <twilczynski@naver.com>
2022-07-26 10:12:15 +02:00
Jakob Borg
adce6fa473 all: Support syncing ownership (fixes #1329) (#8434)
This adds support for syncing ownership on Unixes and on Windows. The
scanner always picks up ownership information, but it is not applied
unless the new folder option "Sync Ownership" is set.

Ownership data is stored in a new FileInfo field called "platform data". This
is intended to hold further platform-specific data in the future
(specifically, extended attributes), which is why the whole design is a
bit overkill for just ownership.
2022-07-26 08:24:58 +02:00
Syncthing Release Automation
34a5f087c8 gui, man, authors: Update docs, translations, and contributors 2022-07-25 04:05:44 +00:00
André Colomb
a6dba7c6d6 lib/model, lib/config: Apply sensible defaults for auto-accepted encrypted folder (fixes #8296) (#8427)
* lib/model: Override scan config for auto-accepted encrypted folders.

Encrypted folders should not have the fs watcher enabled and rarely
benefit from a scheduled rescan.  The GUI adjusts the suggested
settings (watcher disabled, one day rescan interval) when accepting a
receive-encrypted folder.  Mirror that behavior to the auto-accept
case where the GUI is not involved.

Versioning also does not work well for encrypted folders, same
treatment.
2022-07-22 11:27:58 +02:00
tomasz1986
2eabc79d4c gui: Move filesystem watcher explanation from tooltip to help block (#8432)
Currently, the filesystem watcher explanation in the Advanced tab in the
Edit Folder modal window is split into two parts. The first is location
in a tooltip that is visible only when hovering the mouse over the small
checkbox, which makes it not easily accessible, e.g. for new or touch
screen users.

No other settings in the Edit Folder window have their explanation
presentend like that. When needed, it is always displayed in their
respective help blocks, which are always visible on the screen. Thus,
move the filesystem watcher explanation from the tooltip to the help
block, merging it with the other part of the explanation in the process.

Signed-off-by: Tomasz Wilczyński <twilczynski@naver.com>
2022-07-22 11:25:14 +02:00
André Colomb
9c2428c2ee gui: Use discovered IDs from cache when adding a new remote device (#8382)
* gui: Use discovered IDs from cache when adding a new remote device.

The GUI already does refreshDiscoveryCache() when it comes online and
on every 10 second refresh cycle.  Querying the same information
freshly in addDevice() seems unnecessary and adds some more round-trip
delay on a possibly slow network link.  Instead use the IDs from the
existing discoveryCache property to populate the suggested ID list.

* Increase maximum suggested device ID count to 100.

For the auto-completion list, which is hidden by default and filtered
by the browser, we can offer more discovered device IDs without
causing much confusion.  The list of suggested "nearby" devices is
still limited to the first five.

* Rename $scope.discoveryUnknown.

The old name "discovery" was pretty ambiguous..
2022-07-22 11:09:26 +02:00
Jakob Borg
9b390f1264 build: Update goleveldb (#8440) 2022-07-21 18:39:14 +02:00
Syncthing Release Automation
c06a169f5f gui, man, authors: Update docs, translations, and contributors 2022-07-18 04:04:58 +00:00
sec65
4335285a64 cmd/syncthing/cli: Add show discovery command (fixes #8007) (#8378) 2022-07-13 23:11:17 +02:00
Syncthing Release Automation
34c05bee6d gui, man, authors: Update docs, translations, and contributors 2022-07-11 04:01:52 +00:00
Aroun
7cb8af9029 lib/osutil: Only announce address of interfaces which are up (fixes #7458) (#8422) 2022-07-07 19:19:29 +02:00
tomasz1986
8facaf5a6a gui: Fix missing span end tag and missing nbsp semicolon in HTML (#8419)
Signed-off-by: Tomasz Wilczyński <twilczynski@naver.com>
2022-07-05 23:04:30 +02:00
Jakob Borg
abea3d7552 cmd/syncthing: Apply file permissions and modtimes when decrypting (#8412)
Directories are not represented in the encrypted storagage so they get
to keep default permissions...
2022-07-04 10:57:45 +02:00
Syncthing Release Automation
13d545c9f2 gui, man, authors: Update docs, translations, and contributors 2022-06-27 04:05:49 +00:00
Simon Frei
3a6ebb8482 lib/config, lib/model: Warn about two-way introducer (fixes #8393) (#8395) 2022-06-20 18:36:45 +01:00
dependabot[bot]
e071f16531 build(deps): bump github.com/prometheus/client_golang from 1.11.0 to 1.12.2 (#8345)
build(deps): bump github.com/prometheus/client_golang

Bumps [github.com/prometheus/client_golang](https://github.com/prometheus/client_golang) from 1.11.0 to 1.12.2.
- [Release notes](https://github.com/prometheus/client_golang/releases)
- [Changelog](https://github.com/prometheus/client_golang/blob/main/CHANGELOG.md)
- [Commits](https://github.com/prometheus/client_golang/compare/v1.11.0...v1.12.2)

---
updated-dependencies:
- dependency-name: github.com/prometheus/client_golang
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-06-20 19:26:22 +02:00
dependabot[bot]
920f2ce1e6 build(deps): bump github.com/alecthomas/kong from 0.3.0 to 0.6.1 (#8398)
Bumps [github.com/alecthomas/kong](https://github.com/alecthomas/kong) from 0.3.0 to 0.6.1.
- [Release notes](https://github.com/alecthomas/kong/releases)
- [Commits](https://github.com/alecthomas/kong/compare/v0.3.0...v0.6.1)

---
updated-dependencies:
- dependency-name: github.com/alecthomas/kong
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-06-20 19:25:14 +02:00
dependabot[bot]
2e135d0c65 build(deps): bump github.com/pierrec/lz4/v4 from 4.1.13 to 4.1.15 (#8397)
Bumps [github.com/pierrec/lz4/v4](https://github.com/pierrec/lz4) from 4.1.13 to 4.1.15.
- [Release notes](https://github.com/pierrec/lz4/releases)
- [Commits](https://github.com/pierrec/lz4/compare/v4.1.13...v4.1.15)

---
updated-dependencies:
- dependency-name: github.com/pierrec/lz4/v4
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-06-20 18:43:05 +02:00
Jakob Borg
0e79b532cf build: Update to patched github.com/gobwas/glob (fixes #8386) (#8387)
The glob package has seen very little activity the last few years so I'm
not holding my breath on getting this merged.
2022-06-15 21:49:15 +02:00
André Colomb
f7e30a9f10 gui: Fix missing folder names in Edit Device > Sharing tab (fixes #8369) (#8388) 2022-06-15 19:31:54 +02:00
Syncthing Release Automation
b140b4a994 gui, man, authors: Update docs, translations, and contributors 2022-06-13 04:02:19 +00:00
Devon G. Redekopp
6fd7cd808c gui: Disable autocomplete for user/password fields in settings (fixes #8376) (#8377)
Disable Chrome autofill username/password in GUI settings modal dialog.
2022-06-07 06:59:11 +02:00
Syncthing Release Automation
02224be83f gui, man, authors: Update docs, translations, and contributors 2022-06-06 03:58:32 +00:00
tomasz1986
ebe45b3965 gui: Display "days" next to "maximum age" in Staggered Versioning (#8374) 2022-06-04 14:24:06 +02:00
落心
486bb2da0e cmd/strelaysrv: Trivial cleanup in test utility (#8373) 2022-06-02 15:15:42 +02:00
André Colomb
68aa00539e gui: Fix use of old, renamed function in edit folder sharing tab (fixes #8369) (#8371)
Fix use of old, renamed function in edit folder sharing tab.
2022-05-31 22:19:44 +02:00
Syncthing Release Automation
52a883d34e gui, man, authors: Update docs, translations, and contributors 2022-05-30 04:01:43 +00:00
Simon Frei
5ac122b85f lib/model: Don't include deleted items in kqueue warning threshold (ref #7855) (#8365) 2022-05-28 20:15:38 +02:00
tomasz1986
de2d7c33a3 gui: Add detailed file versioning information to folder info (ref #963) (#8348) 2022-05-28 13:46:15 +02:00
greatroar
2ca8a5ac61 lib/assets: MIME types, time formats (#8351)
.eot and .woff2 weren't listed, but are present in vendored fontawesome.

.ttf and .woff are font/* according to IANA,
https://www.iana.org/assignments/media-types/media-types.xhtml#font.
This matches what mime.TypeByExtension returns.

.eot is from https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types/Common_types.
mime.TypeByExtension doesn't recognize this extension.

* lib/assets: Use http.ParseTime

This understands the three time formats allowed in HTTP.
2022-05-22 22:10:18 +02:00
Simon Frei
e3078cc531 lib/model: Don't fail on temporary chmod (fixes #8355, ref #8235) (#8356) 2022-05-22 13:52:40 +02:00
tomasz1986
5495d0f8ab gui: Update Fork Awesome from v1.1.2 to v1.2.0 (#8349)
This commit updates Fork Awesome from version 1.1.2 from 2018 to version
1.2.0 from 2021. The changes are few and non-breaking, consisting mainly
of new icon additions.

It is worth to note that the new version includes also a Syncthing icon,
which was not present before.

Signed-off-by: Tomasz Wilczyński <twilczynski@naver.com>
2022-05-18 14:08:45 +02:00
Syncthing Release Automation
388b21d9db gui, man, authors: Update docs, translations, and contributors 2022-05-16 03:52:16 +00:00
Syncthing Release Automation
a162e8d9f9 gui, man, authors: Update docs, translations, and contributors 2022-05-09 03:58:03 +00:00
André Colomb
235422c26d gui, authors: Remove additional bot names (#8333)
Skip Syncthing*Automation in authors list as well.
2022-05-08 22:42:05 +02:00
André Colomb
2bcaa17fc3 gui: Add default ignores to the advanced configuration editor modal (fixes #8264) (#8265) 2022-05-08 21:34:03 +02:00
greatroar
97291c9184 lib/api: Fix and optimize csrfManager (#8329)
An off-by-one error could cause tokens to be forgotten. Suppose

	tokens := []string{"foo", "bar", "baz", "quux"}
	i := 2
	token := tokens[i] // token == "baz"

Then, after

	copy(tokens[1:], tokens[:i+1])
	tokens[0] = token

we have

	tokens == []string{"baz", "foo", "bar", "baz"}

The short test actually relied on this bug.
2022-05-07 12:30:13 +02:00
Jakob Borg
520ca4bcb0 script, gui: Exclude bots from the in-GUI authors list 2022-05-06 08:00:22 +02:00
Simon Frei
f35fb974d0 build: Add concise build instructions to readme (#8327) 2022-05-06 07:56:26 +02:00
Jakob Borg
f8c51d801a lib/discover: Filter locally announced addresses (fixes #7289) (#8302) 2022-05-04 18:43:00 +02:00
Jakob Borg
16c0c2f7a7 Merge branch 'release'
* release:
  lib/connections: Correct race on loop variable (fixes #8320) (#8321)
2022-05-04 18:25:58 +02:00
Jakob Borg
2145b3701d lib/connections: Correct race on loop variable (fixes #8320) (#8321) 2022-05-04 18:17:03 +02:00
Jakob Borg
ce0ded7c78 lib/connections: Correct race on loop variable (fixes #8320) (#8321) 2022-05-04 18:16:36 +02:00
André Colomb
31a78592e8 gui: Mark folders paused on remote device. (#8286)
Similar to the "remote has not accepted sharing" message, add a
footnote number 2 to indicate a folder which will not sync with a
certain device because the remote has paused it.  Applies to the edit
folder / device modals' sharing tab, as well as the "shared with"
listing and tooltips under device and folder details.
2022-05-03 21:51:09 +02:00
Jakob Borg
334a78f185 cmd/strelaysrv, cmd/strelaypoolsrv: Sanitize query strings (fixes #8314) (#8315)
Use the proper encoding function in the relay server when constructing
the URL. In the pool server, parse and re-encode the query values to
sanitize whatever the client sent.
2022-05-02 10:38:49 +02:00
greatroar
233d3e7f7b lib/events: Remove unused method noopLogger.Stop (#8312)
This was needed for the old suture API, abandoned in
9524b51708.
2022-05-02 08:00:55 +02:00
Syncthing Release Automation
41a429b52c gui, man, authors: Update docs, translations, and contributors 2022-05-02 04:07:12 +00:00
greatroar
d00a30069a lib/db: Constant/unused args and return values, double it.Release (#8259) 2022-04-27 20:32:44 +02:00
greatroar
49488c0e71 all: Clean up fmt.Errorf usage (#8309) 2022-04-27 20:30:13 +02:00
Simon Frei
4031568cdf gui: Bandaid for null http errors (fixes #8261) (#8305) 2022-04-25 19:15:14 +02:00
Syncthing Release Automation
fff9bf98eb gui, man, authors: Update docs, translations, and contributors 2022-04-25 03:54:44 +00:00
Simon Frei
6a7fc49c6b lib/discover: Increase global discovery timeout (#8303) 2022-04-23 16:12:25 +02:00
red_led
89f5d0d400 gui: Always show vertical scroll bar (#8301)
This stops interface from jumping left and right when page content no longer fits into screen.
2022-04-22 21:39:30 +02:00
André Colomb
1eda82b95f lib/model: Improve remoteFolderState reporting (fixes #8266) (#8283) 2022-04-22 08:42:20 +02:00
Jakob Borg
623ec03dad lib/model: Correct type of event data (fixes #8294) (#8295)
These things are fragile, every event should use an ${eventType}Data struct or something instead.
2022-04-21 15:45:31 +02:00
Jakob Borg
c0de42e3df gui: Use neutral color for zero out of zero listeners (#8281) 2022-04-20 14:43:11 +02:00
tomasz1986
4893513800 gui: Improve Latest Change translation string for better multilanguage support (#8290)
Currently, the "Latest Change" translation string is hard-coded to use
the English-like word order of V ("deleted") + N ("file"). As such, it
is incompatible with languages that require to use a different word
order, e.g. Korean or Japanese. In other words, a proper translation of
the string to those languages is currently impossible.

This commit changes the translation string, so that it includes the file
variable, and thanks to this, it can be easily adopted to languages with
different word order than English.

Signed-off-by: Tomasz Wilczyński <twilczynski@naver.com>
2022-04-18 06:41:26 +02:00
Syncthing Release Automation
100142067d gui, man, authors: Update docs, translations, and contributors 2022-04-18 03:54:08 +00:00
Simon Frei
3907cb0693 lib/model: Subscribe to correct event for fs watching (ref #8249) (#8287) 2022-04-17 12:41:25 +04:00
Jakob Borg
61dffabf97 cmd/syncthing, lib/logger: Add date to default log format (fixes #8272) (#8273)
This changes the default log format to include the date.
2022-04-15 07:46:14 +04:00
Eng Zer Jun
bc27aa12cd all: use T.TempDir to create temporary test directory (#8280)
This commit replaces `os.MkdirTemp` with `t.TempDir` in tests. The
directory created by `t.TempDir` is automatically removed when the test
and all its subtests complete.

Prior to this commit, temporary directory created using `os.MkdirTemp`
needs to be removed manually by calling `os.RemoveAll`, which is omitted
in some tests. The error handling boilerplate e.g.
	defer func() {
		if err := os.RemoveAll(dir); err != nil {
			t.Fatal(err)
		}
	}
is also tedious, but `t.TempDir` handles this for us nicely.

Reference: https://pkg.go.dev/testing#T.TempDir
Signed-off-by: Eng Zer Jun <engzerjun@gmail.com>
2022-04-15 07:44:06 +04:00
André Colomb
0537b9546f lib/model: Switch the remoteFolderState default value to valid (#8275)
Showing all folders from disconnected or paused remote devices as
unaccepted would be a lot of false positives.  As we cannot know
whether the remote has accepted while it doesn't have an active
connection, let's better report false negatives, as in assuming the
folders are accepted.
2022-04-13 18:15:58 +02:00
Simon Frei
0525c755f4 build: Bump quic-go to 0.26.0 for go1.18 update (#8231)
Merging because I want this in the RC, when we do the RC...
2022-04-12 16:27:29 +04:00
Simon Frei
bcd91f536e lib/connections: Create the forgotten channel (ref #8263) (#8267) 2022-04-11 17:32:22 +04:00
Syncthing Release Automation
f9c6c69fa8 gui, man, authors: Update docs, translations, and contributors 2022-04-11 03:52:11 +00:00
André Colomb
0c46e0a9cc gui, lib/model: Mark folders unaccepted by remote device (fixes #8202) (#8201) 2022-04-10 22:47:57 +02:00
Greg
bca6d31b95 Correct comment typo in build.go (#8234) 2022-04-10 22:24:57 +02:00
Simon Frei
db72579f0e lib: Get rid of buggy filesystem wrapping (#8257) 2022-04-10 20:55:05 +02:00
Jakob Borg
9b09bcc5f1 lib/connections: Always run a simple connection test (#7866) 2022-04-10 20:54:42 +02:00
Simon Frei
22e12904c9 lib/connections: Make request tests sequential (#8263) 2022-04-10 20:54:16 +02:00
Simon Frei
b947056e62 lib: Removal global connection registry (#8254) 2022-04-09 16:04:56 +02:00
Jeffery To
e30898ddb3 build: Update go directive to 1.17 (fixes #8258) (#8260)
This should fix compiling from the source tarball with Go 1.18.
2022-04-09 16:01:24 +02:00
Simon Frei
072fa46bfd lib/connections, lib/model: Improve new conn handling (#8253) 2022-04-07 17:35:33 +02:00
Simon Frei
edc3a77b98 lib/fs, lib/model: Add warning about kqueue resource usage (fixes #7855) (#8249) 2022-04-05 21:32:06 +02:00
Syncthing Release Automation
2b80848341 gui, man, authors: Update docs, translations, and contributors 2022-04-04 03:50:52 +00:00
André Colomb
30fa462e33 all: Comments and cosmetics (#8218)
* lib/api: Note ItemStarted and ItemFinished for default filtering.

The reasoning why LocalChangeDetected and RemoteChangeDetected events
are not included in the event stream by default (without explicit
filter mask requested) also holds for the ItemStarted and ItemFinished
events.  They should be excluded as well when we start to break the
API compatibility for some reason.

* gui: Enumerate unused event types in the eventService.

Define constants for the unused event types as well, for completeness'
sake.  They are intentionally not handled in the GUI currently.

* cmd/syncthing: Harmonize uppercase CLI argument placeholders.

Use ALL-UPPERCASE and connecting dashes to distinguish argument
placeholders from literal argument options (e.g. "cpu" or "heap" for
profiling).  The dash makes it clear which words form a single
argument and where a new argument starts.

This style is already used for the "syncthing cli debug file" command.

* lib/model: Simplify event data structure.

Using map[string]interface{} is not necessary when all values are
known to be strings.
2022-04-02 20:36:19 +02:00
Syncthing Release Automation
11ac945b87 gui, man, authors: Update docs, translations, and contributors 2022-03-28 03:50:34 +00:00
Simon Frei
55c513b827 lib/model: Clear folder error after loading ignores (fixes #8232) (#8238) 2022-03-27 21:29:40 +02:00
greatroar
0eca0ac45a lib/model: Chmod to mode|0700, not 755 (#8235) 2022-03-26 12:07:07 +02:00
greatroar
4be867c560 all: Replace errors.Cause with errors.Is (#8236) 2022-03-26 12:05:57 +02:00
Naveen
44b11ec257 Pin actions to a full length commit SHA (#8224) 2022-03-24 16:46:06 +01:00
Greg
53926a1ae6 lib/fs: Do not follow symlinks in watcher on solaris (fixes #8020) (#8223) 2022-03-24 08:36:43 +01:00
Syncthing Release Automation
5f383923df gui, man, authors: Update docs, translations, and contributors 2022-03-21 03:47:47 +00:00
greatroar
26eaedc491 lib/db, lib/discover: Minor cleanup (#8217) 2022-03-14 22:48:10 +01:00
Syncthing Release Automation
7b63254a35 gui, man, authors: Update docs, translations, and contributors 2022-03-14 03:47:23 +00:00
greatroar
d0fd6c6c82 lib/db: Make err(Closed|NotFound) values (#8215) 2022-03-13 20:53:34 +01:00
tomasz1986
6862dd04ab gui: Allow to translate calendar buttons in Restore Versions modal (#8213) 2022-03-12 22:44:56 +01:00
tomasz1986
e1b1631c65 gui: Allow to translate Twitter footer link (#8212) 2022-03-12 22:44:10 +01:00
Andrew Meyer
1d74b547dd Add port for local discovery broadcasts to Docker documentation (#8197)
* Docs: Add descriptive comments to Docker ports

* Docs: Add Docker port for local discovery broadcasts

See https://docs.syncthing.net/specs/localdisco-v4.html
2022-03-08 08:06:45 +01:00
Jakob Borg
a3a4da6e3e gui: Use versioned link to documentation in bottom bar (#8204) 2022-03-08 07:56:42 +01:00
Syncthing Release Automation
e974c13c7a gui, man, authors: Update docs, translations, and contributors 2022-03-07 03:45:51 +00:00
André Colomb
1999383443 Rename environment variable STCPUPROFILE for consistency. (#8200) 2022-03-03 15:27:17 +01:00
greatroar
bd0acd04b1 lib/protocol: Use one mutex for rawConnect.awaiting and nextID (#8198)
Having a separate mutex for the three or four instructions needed to
fetch and increment nextID means the overhead exceeds the cost of this
operation.  nextID is now handled inside the critical section for
awaiting instead, while the more expensive channel creation has been
moved outside it.

This is mostly a simplification, though it may have minor performance
benefits in some situations. The single-threaded sender benchmark shows
no significant difference:

name               old speed      new speed      delta
RequestsRawTCP-8   55.3MB/s ± 7%  56.6MB/s ± 6%   ~     (p=0.190 n=10+10)
RequestsTLSoTCP-8  20.5MB/s ±20%  20.8MB/s ± 8%   ~     (p=0.604 n=10+9)
2022-02-28 09:13:30 +01:00
Syncthing Release Automation
f25947e5eb gui, man, authors: Update docs, translations, and contributors 2022-02-28 03:46:00 +00:00
Jakob Borg
f890fe6fd3 lib/config: Improve clarity of free space errors (fixes #8180) (#8191) 2022-02-24 17:07:51 +01:00
dependabot[bot]
10f9d95cd2 build(deps): bump github.com/thejerf/suture/v4 from 4.0.1 to 4.0.2 (#8190)
Bumps [github.com/thejerf/suture/v4](https://github.com/thejerf/suture) from 4.0.1 to 4.0.2.
- [Release notes](https://github.com/thejerf/suture/releases)
- [Commits](https://github.com/thejerf/suture/compare/v4.0.1...v4.0.2)

---
updated-dependencies:
- dependency-name: github.com/thejerf/suture/v4
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-02-23 21:07:15 +01:00
Jakob Borg
013c757a84 github: Provide Git history when checking out for actions 2022-02-21 14:57:21 +01:00
Syncthing Release Automation
ffa46c2461 gui, man, authors: Update docs, translations, and contributors 2022-02-21 03:45:27 +00:00
Syncthing Release Automation
48fd9d05b5 gui, man, authors: Update docs, translations, and contributors 2022-02-14 03:45:24 +00:00
tomasz1986
0b1f792290 gui: Add Docs help links to each setting in Advanced Configuration (#7358)
Add a link next to each setting's label to its explanation in the Docs.
This way, it is easy to quickly check what the setting is about without
going to the Docs site separately and searching for it manually.

Signed-off-by: Tomasz Wilczyński <twilczynski@naver.com>
2022-02-09 00:05:26 +01:00
tomasz1986
c25fcf0001 gui: Remove superfluous Trash Can info text from Simple Versioning (#8177)
Right now, the Trash Can versioning info text is displayed for both the
Trash Can and Simple versioning. However, the Simple versioning has its
own info text that is also displayed, which results in two very similar
sentences being shown on the screen.

This commit limits the Trash Can info text to be displayed only when the
Trash Can versioning is selected, and moves the Simple versioning info
text up to the same location as the other one.

Signed-off-by: Tomasz Wilczyński <twilczynski@naver.com>
2022-02-08 20:10:03 +01:00
dependabot[bot]
ba2c79f310 build(deps): bump github.com/pierrec/lz4/v4 from 4.1.12 to 4.1.13 (#8170)
Bumps [github.com/pierrec/lz4/v4](https://github.com/pierrec/lz4) from 4.1.12 to 4.1.13.
- [Release notes](https://github.com/pierrec/lz4/releases)
- [Commits](https://github.com/pierrec/lz4/compare/v4.1.12...v4.1.13)

---
updated-dependencies:
- dependency-name: github.com/pierrec/lz4/v4
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-02-08 07:15:50 +01:00
tomasz1986
c396124bc9 gui: Don't use italic text for CJK languages (#8172)
Even though technically possible, CJK languages normally don't use
italic text at all, as not only does it make the characters/letters look
unnatural, but also, in the case of complex characters, unreadable too.
For these reasons, it is usually recommended not to use the italic font
style at all [1][2].

This commit changes the default font-style of the i element for Chinese,
Japanese, and Korean langauge to "normal" instead of "italic". In order
to do so, the HTML lang attribute is also changed following each change
of the GUI language.

[1] https://bobtung.medium.com/best-practice-in-chinese-layout-f933aff1728f
[2] https://devblogs.microsoft.com/oldnewthing/20060914-02/?p=29743

Signed-off-by: Tomasz Wilczyński <twilczynski@naver.com>
2022-02-08 07:07:22 +01:00
tomasz1986
d35d7d2360 lib, gui: Removed unused cleanInterval from Staggered Versioning (ref #541) (#8161)
Staggered File Versioning used to have its own cleanInterval that
controlled how often file versions were cleaned. Nowadays, there is a
seperate setting called cleanupIntervalS responsible for the cleanup,
which applies to all File Versioning (except External). Thus, remove the
unneeded code and don't set the param up on new folders anymore.

Signed-off-by: Tomasz Wilczyński <twilczynski@naver.com>
2022-02-08 07:06:14 +01:00
tomasz1986
2738735321 gui: Allow to translate and fix incorrect Versions date filter ranges (#8162)
* gui: Allow to translate and fix incorrect Versions date filter ranges

Translate the previously English-only ranges used in Versions date
filter. In the process, fix the currently incorrect range calculation.

For instance, let us say it is 08:05. Selecting "today" should set the
range to start at 00:00 and end at 08:05. However, what really happens
is that both start and end are set to 08:05, and as a result "today" is
never shown to the user. The case is the same for "yesterday", which in
contrary to "today" is shown, but its range is fixed at 08:05 on the
previous day.

This commit fixes the above by always calculating "today" starting at
00:00 up to the current moment, and calculating "yesterday" from 00:00
on the previous to 00:00 on the current day.

When it comes to "last x days", the commit fixes the calculation so that
it actually covers the whole day, which is done by moving the start date
to 00:00 on the first day.

Signed-off-by: Tomasz Wilczyński <twilczynski@naver.com>
2022-02-07 21:41:05 +01:00
André Colomb
1c74944cca lib/api: Fix comments for endpoint parameters (#8163) 2022-02-07 08:51:09 +01:00
Syncthing Release Automation
412616bb96 gui, man, authors: Update docs, translations, and contributors 2022-02-07 03:45:33 +00:00
Simon Frei
518d5174e6 lib/model: Print device when a block request fails (#8159) 2022-02-01 20:20:55 +01:00
Simon Frei
2656c1b8e1 gui: Fix mistake (fixes #8152, ref #8147) (#8157) 2022-01-31 17:54:19 +01:00
Simon Frei
635085d139 lib/db, lib/model: Remove filesystem state from FileSet (fixes #7850) (#8151) 2022-01-31 10:12:52 +01:00
Syncthing Release Automation
d1e81a0acf gui, man, authors: Update docs, translations, and contributors 2022-01-31 03:45:29 +00:00
Simon Frei
6094b95784 gui: Fix and align folder editing states (fixes #8145) (#8147) 2022-01-30 17:43:39 +01:00
Jonathan
d37a5b03f1 lib/fs: Handle permission change events on macos (fixes #7924) (#8150) 2022-01-30 17:21:21 +01:00
tomasz1986
1794d45ff3 gui: Fix ignoreDelete warning formatting (ref #8054) (#8138)
The ignoreDelete warning code originally comprised of two sentences,
which in total were much longer than the current one. Because of that,
some additional fixes were added to make it present itself better, e.g.
white-space was set to normal to allow for text wrap on narrow screens,
and the help link was moved to a new line to make sure both the anchor
and the question mark always stayed together.

However, the code fixes remained despite the final text being much
shorter than the original. Therefore, remove the unnecessary white-space
formatting, and also move the help link right next to the warning. This
makes it clear that the link is related to this particular warning when
both it and the ignore patterns warning are displayed at the same time.

Ref: https://github.com/syncthing/syncthing/pull/8054#issuecomment-978148117

Signed-off-by: Tomasz Wilczyński <twilczynski@naver.com>
2022-01-30 13:03:46 +01:00
Daniel Barczyk
7b0fbb6fef cmd/syncthing/cli: Add showing pending folders for given device (fixes #8130) (#8131)
Add --device flag to filter pending folders.
2022-01-30 08:09:37 +01:00
tomasz1986
80d4bc1cea gui: Translate fancytree messages in Versions modal (#8149)
* gui: Translate fancytree messages in Versions modal

Currently, the default fancytree info/error messages are used. This
means that a) they are English-only, and b) they are very generic. With
this commit, the messages are added to the translatable strings, and
they are also more specifically related to file versioning.

On a side note, the "moreData" string has been left out on purpose, as
it is not used in the current code. It can be added later if needed.

Signed-off-by: Tomasz Wilczyński <twilczynski@naver.com>
2022-01-30 07:56:36 +01:00
Simon Frei
8763fb05ec lib/fs: Improve error messages checking file paths (fixes #7942) (#8148) 2022-01-29 18:47:55 +01:00
tomasz1986
73e2e2a794 gui: Make device ID read-only and hide "nearby devices" when adding a new pending device (fixes #8083) (#8091)
* gui: Make ID read-only and hide nearby devices when adding pending devices (fixes #8083)

Currently, there is no distinction between adding "new" and "pending"
devices. For this reason, the user is always presented with a list of
"nearby devices" to choose from. This commit adds such distinction to
the code, and in the case of "pending" device, both the device ID is
made read-only and the nearby devices list is hidden.

As a by-product of the function rename and clean-up, this commit also
hides the non-functional "remove" button that is shown when editing
device defaults.

Signed-off-by: Tomasz Wilczyński <twilczynski@naver.com>
2022-01-28 09:15:56 +01:00
Jakob Borg
479712cdc5 cmd/stdiscosrv: Don't start replication listener without peers (fixes #8143) (#8144)
The intention was that if no peers are given, we shouldn't start the
listener. We did that anyway, because:

- splitting an empty string on comma returns a slice with one empty
  string in it
- parsing the empty string as a device ID returns the empty device ID

so we end up with a valid replication peer which is the empty device ID.
2022-01-27 09:36:54 +01:00
tomasz1986
9efac0f067 gui: Tweak the Restore Versions modal for better usability (#7972) 2022-01-25 23:08:27 +01:00
greatroar
a0fd619df3 lib/protocol: Require at least 3.125% savings from compression (#8133)
* lib/protocol: Require at least 3.125% savings from compression

The new lz4 library doesn't need its output buffer to be the maximum
size, unlike the old one (which would allocate if it weren't). It can
take a buffer that is of a smaller size and will report if compressed
data can fit inside the buffer (with a small chance of reporting a false
negative). Use that property to our advantage by requiring compressed
data to be at most n-n/32 = .96875*n bytes long for n input bytes.

* lib/protocol: Remove unused receivers

To make DeepSource happy.

* lib/protocol: Micro-optimize lz4Compress

Only write the length if compression was successful. This is a memory
write, so the compiler can't reorder it.

Only check the return value of lz4.CompressBlock.  Length-zero inputs
are always expanded by LZ4 compression (the library documents this),
so the check on len(src) isn't needed.
2022-01-24 19:36:58 +01:00
André Colomb
1af87577e1 gui: Generate version-specific documentation link URLs (#8108)
Replace all HTML references to https://docs.syncthing.net with a
function call to return a version-specific URL.
2022-01-24 19:36:11 +01:00
Syncthing Release Automation
99f96c5cb7 gui, man, authors: Update docs, translations, and contributors 2022-01-24 03:45:54 +00:00
dependabot[bot]
4329ba316f build(deps): bump github.com/shirou/gopsutil/v3 from 3.21.8 to 3.21.12 (#8123)
Bumps [github.com/shirou/gopsutil/v3](https://github.com/shirou/gopsutil) from 3.21.8 to 3.21.12.
- [Release notes](https://github.com/shirou/gopsutil/releases)
- [Commits](https://github.com/shirou/gopsutil/compare/v3.21.8...v3.21.12)

---
updated-dependencies:
- dependency-name: github.com/shirou/gopsutil/v3
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-01-22 08:46:03 +01:00
dependabot[bot]
a78aedec7e build(deps): bump github.com/alecthomas/kong from 0.2.17 to 0.3.0 (#8126)
Bumps [github.com/alecthomas/kong](https://github.com/alecthomas/kong) from 0.2.17 to 0.3.0.
- [Release notes](https://github.com/alecthomas/kong/releases)
- [Commits](https://github.com/alecthomas/kong/compare/v0.2.17...v0.3.0)

---
updated-dependencies:
- dependency-name: github.com/alecthomas/kong
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-01-22 08:32:03 +01:00
Simon Frei
f0d5dc5696 gui: Fix loading default ignores (#8135) 2022-01-21 17:24:11 +01:00
Simon Frei
e40289ce7a build: Bump quic to v0.25.0 for Go1.18 support (#8134) 2022-01-21 14:54:42 +01:00
Jakob Borg
b6d1e16b4e lib/protocol: Switch to a newer lz4 package (#8122) 2022-01-17 18:52:43 +01:00
Syncthing Release Automation
e700ef3208 gui, man, authors: Update docs, translations, and contributors 2022-01-17 03:47:43 +00:00
Simon Frei
45d145a281 gui: Fix bug saving settings (fixes #8116) (#8117) 2022-01-16 19:06:50 +01:00
Simon Frei
b2996eee87 gui: Handle folder missing in model on error event (#8120) 2022-01-16 18:07:33 +01:00
Simon Frei
21d04b895a lib, gui: Default ignores for new folders (fixes #7428) (#7530) 2022-01-13 23:38:21 +01:00
Ryan Qian
40bb52fdd8 build: Add an option to specify output dir for crosscompiling all (#8109)
When GOBIN is set, 'go install' cannot install cross-compilied binaries.
To satisfy cross-compilation, it's necessary to add the '-o' to build
target, otherwise 'go build' will discarding the resulting objects when
compiling multiple packages.

Signed-off-by: bekcpear <i@bitbili.net>
2022-01-13 09:57:23 +01:00
Jakob Borg
1242ac74ab github: Make docs commits as release bot 2022-01-12 21:56:21 +01:00
Syncthing Automation
3bfd41c48b gui, man, authors: Update docs, translations, and contributors 2022-01-10 13:48:17 +00:00
Jakob Borg
4fb7e04686 github: Use specific token to override branch protection 2022-01-10 14:45:47 +01:00
Jakob Borg
dc0dbed96e github: Add docs update workflow (#8105) 2022-01-10 14:28:39 +01:00
André Colomb
0cba3154f0 lib/model: Remove bogus fields from connections API endpoint (fixes #8103) (#8104)
* lib/model: Remove bogus fields from connections API endpoint.

Switch the returned data type for the /rest/system/connections element
"total" to use only the Statistics struct.  The other fields of the
ConnectionInfo struct are not populated and misleading.

* Lowercase JSON field names.

* lib/model: Get rid of ConnectionInfo.MarshalJSON().

It was missing the StartedAt field from the embedded Statistics
struct.  Just lowercasing the JSON attribute names can be done just as
easily with annotations.

* lib/model: Remove bogus startedAt field from totals.

Instead of using the Statistics type with one field empty, just switch
to a free-form map with the three needed fields.
2022-01-10 10:26:45 +01:00
tomasz1986
fec476cc80 gui: Sort language names vertically and don't truncate on small screens (#8101) 2022-01-08 16:51:29 +01:00
Jakob Borg
bc3d306dd7 cmd/syncthing: Error capitalization 2022-01-07 11:50:19 +01:00
André Colomb
5237337626 cmd/syncthing: Add --skip-port-probing (fixes #8090) (#8099)
* cmd/syncthing: Remove unnecessary function arguments.

The openGUI() function does not need a device ID to work, and there is
only one caller anyway which uses EmptyDeviceID.

The loadOrDefaultConfig() function is always called with the same
dummy values.

* cmd/syncthing: Avoid misleading info messages from monitor process.

In order to check whether panic reporting is enabled, the monitor
process utilizes the loadOrDefaultConfig() function.  In case there is
no config file yet, info messages may be logged during creation if the
config Wrapper, which is discarded immediately after.

Stop using the DefaultConfig() utility function from lib/syncthing and
directly generate a minimal config instead to avoid these.

Add comments to loadOrDefaultConfig() explaining its limited purpose.

* cmd/syncthing/generate: Always write updated config file.

Previously, an existing config file was left untouched unless either
of the --gui-user or --gui-password options was given.  Remove that
condition and simplify the checking code.

* lib/config: Factor out ProbeFreePorts().

* cmd/syncthing: Add option --skip-port-probing.

Applies to both the "generate" and "serve" subcommands, as well as the
deprecated --generate option, just as the --no-default-folder flag.
2022-01-07 11:19:17 +01:00
André Colomb
368094e15d cmd/syncthing: Always update config.xml with generate subcommand (ref #8090) (#8098)
* cmd/syncthing: Remove unnecessary function arguments.

The openGUI() function does not need a device ID to work, and there is
only one caller anyway which uses EmptyDeviceID.

The loadOrDefaultConfig() function is always called with the same
dummy values.

* cmd/syncthing: Avoid misleading info messages from monitor process.

In order to check whether panic reporting is enabled, the monitor
process utilizes the loadOrDefaultConfig() function.  In case there is
no config file yet, info messages may be logged during creation if the
config Wrapper, which is discarded immediately after.

Stop using the DefaultConfig() utility function from lib/syncthing and
directly generate a minimal config instead to avoid these.

Add comments to loadOrDefaultConfig() explaining its limited purpose.

* cmd/syncthing/generate: Always write updated config file.

Previously, an existing config file was left untouched unless either
of the --gui-user or --gui-password options was given.  Remove that
condition and simplify the checking code.
2022-01-07 11:02:12 +01:00
tomasz1986
0f93e76e80 gui: Use indexOf instead of startsWith for IE11 compatibility (ref #6940) (#8097)
Use indexOf instead of startsWith to make the now translatable theme
names appear correctly in IE11. This also prevents console log error
spam in the browser. The same problem was previously reported in #6940.

Signed-off-by: Tomasz Wilczyński <twilczynski@naver.com>
2022-01-06 12:46:15 +01:00
Kebin Liu
083fa1803a cmd/stdiscosrv: Support deploying behind Caddyserver (#8092) 2022-01-05 15:17:13 +01:00
Simon Frei
c00c6b3957 build: Bump quic-go to 0.24.0 2021-12-30 13:07:01 +01:00
Gahl Saraf
cc39341eb9 lib: Fix panic due to closed event subscriptions on shutdown (#8079) 2021-12-22 20:16:21 +01:00
ignacy123
bf7f82f7b2 cmd/syncthing/cli: Add command to show pending devices/folders (fixes #8068) (#8069) 2021-12-09 21:18:47 +01:00
greatroar
eb857dbc45 lib/osutil: Use x/sys/windows for SetLowPriority 2021-11-27 15:35:07 +01:00
greatroar
e7620e951d cmd/stdiscosrv: use strconv.Itoa 2021-11-27 15:35:07 +01:00
greatroar
286a25ae49 lib/upgrade: Use strings.Reader instead of bytes.Buffer 2021-11-27 15:35:07 +01:00
greatroar
ae70046b49 lib/protocol: Remove unused sorting boilerplate 2021-11-27 15:35:07 +01:00
greatroar
c366933416 lib/sync: Make the clock a function pointer 2021-11-27 15:35:07 +01:00
greatroar
6a9716e8a1 lib/model: Return index from deviceActivity.leastBusy
This way, we don't need a second loop over the Availabilities to remove
the selected item.
2021-11-26 12:07:43 +01:00
villekalliomaki
b84ee4d240 gui: Notice on folders with ignoreDelete enabled (fixes #8050) (#8054) 2021-11-25 14:04:59 +01:00
greatroar
8a1e54d58a lib/fs: Optimize Canonicalize
When pathSep is a constant, the compiler precomputes pathSep+pathSep and
".."+pathSep instead of emitting function calls to compute "//" and
"../". Benchmark results in lib/osutil:

name                old time/op    new time/op    delta
TraversesSymlink-8    8.86µs ± 3%    8.53µs ± 4%  -3.79%  (p=0.000 n=18+20)

name                old alloc/op   new alloc/op   delta
TraversesSymlink-8    1.06kB ± 0%    1.06kB ± 0%    ~     (all equal)

name                old allocs/op  new allocs/op  delta
TraversesSymlink-8      15.0 ± 0%      15.0 ± 0%    ~     (all equal)
2021-11-23 21:25:29 +01:00
greatroar
3e032c4da6 lib/fs: optimize Windows path checking/sanitizing
name                          old time/op    new time/op    delta
WindowsInvalidFilenameValid-8     875ns ± 1%     150ns ± 1%  -82.84%  (p=0.000 n=9+9)
WindowsInvalidFilenameNUL-8       276ns ± 4%     121ns ± 3%  -56.26%  (p=0.000 n=10+10)

name                          old alloc/op   new alloc/op   delta
WindowsInvalidFilenameValid-8     32.0B ± 0%     16.0B ± 0%  -50.00%  (p=0.000 n=10+10)
WindowsInvalidFilenameNUL-8       32.0B ± 0%     19.0B ± 0%  -40.62%  (p=0.000 n=10+10)

name                          old allocs/op  new allocs/op  delta
WindowsInvalidFilenameValid-8      2.00 ± 0%      1.00 ± 0%  -50.00%  (p=0.000 n=10+10)
WindowsInvalidFilenameNUL-8        2.00 ± 0%      2.00 ± 0%     ~     (all equal)
2021-11-23 21:25:29 +01:00
Jakob Borg
7c3b267645 meta: Add test for deprecated package ioutil (#8053) 2021-11-22 10:11:00 +01:00
tomasz1986
7161a99b04 gui: Allow text wrapping in remove folder/device modals (#7976)
Remove the embedded CSS that prevents the lines from wrapping, resulting
in device and folder names being hidden on small screens.
2021-11-22 09:41:43 +01:00
Jakob Borg
1754c93370 lib/config, lib/ignore: Write Windows line endings (fixes #7115) (#8052) 2021-11-22 09:38:24 +01:00
Jakob Borg
4b750b6dc3 all: Remove usage of deprecated io/ioutil (#7971)
As of Go 1.16 io/ioutil is deprecated. This replaces usage with the
corresponding functions in package os and package io.
2021-11-22 08:59:47 +01:00
greatroar
bf89bffb0b lib/config: Decouple VerifyConfiguration from Committer (#7939)
... and remove 8/10 implementations, which were no-ops. This saves code
and time copying configurations.
2021-11-22 08:45:29 +01:00
Jakob Borg
e2288fe441 lib/relay: Send SNI when the address is a host name (fixes #8014) (#8015) 2021-11-22 08:31:03 +01:00
greatroar
8265dac127 lib/nat: Fix race condition in Mapping (#8042)
The locking protocol in nat.Mapping was racy:

* Mapping.addressMap RLock'd, but then returned a map shared between
  caller and Mapping, so the lock didn't do anything.

* Operations inside Service.{verifyExistingMappings,acquireNewMappings}
  would lock the map for every update, but that means callers to
  Mapping.ExternalAddresses can be looping over the map while the
  Service methods are concurrently modifying it. When the Go runtime
  detects that happening, it panics.

* Mapping.expires was read and updated without locking.

The Service methods now lock the map once and release the lock only when
done.

Also, subscribers no longer get the added and removed addresses, because
none of them were using the information. This was changed for a previous
attempt to retain the fine-grained locking and not reverted because it
simplifies the code.
2021-11-22 08:29:44 +01:00
André Colomb
100870e142 cmd/syncthing: Implement generate as a subcommand with optional API credential setting (fixes #8021) (#8043)
Accept a subcommand as an alternative to the --generate option.  It
accepts a custom config directory through either the --home or
--config options, using the default location if neither is given.

Add the options --gui-user and --gui-password to "generate", but not
the "serve --generate" option form.  If either is given, an existing
config will not abort the command, but rather load, modify and save it
with the new credentials.  The password can be read from standard
input by passing only a single dash as argument.

Config modification is skipped if the value matches what's already in
the config.

* cmd/syncthing: Utilize lib/locations package in generate().
Instead of manually joining paths with "magic" file names, get them
from the centralized locations helper lib.

* cmd/syncthing: Simplify logging for --generate option.
Visible change: No more timestamp prefixes.
2021-11-18 22:57:59 +01:00
Jakob Borg
12fb7f2a0a lib/model: Correct "reverting folder" log entry 2021-11-17 12:52:10 +01:00
Jakob Borg
f1bf4d899a lib/model: Correct handling of fakefs cache
We looked under one cache key, then stored under another...
2021-11-17 12:52:10 +01:00
Simon Frei
591e4d8af1 gui, lib: Fix tracking deleted locally-changed on encrypted (fixes #7715) (#7726) 2021-11-10 09:46:21 +01:00
André Colomb
dec6f80d2b lib/config: Move the bcrypt password hashing to GUIConfiguration (#8028)
What hash is used to store the password should ideally be an
implementation detail, so that every user of the GUIConfiguration
object automatically agrees on how to handle it.  That is currently
distribututed over the confighandler.go and api_auth.go files, plus
tests.

Add the SetHasedPassword() / CompareHashedPassword() API to keep the
hashing method encapsulated.  Add a separate test for it and adjust
other users and tests.  Remove all deprecated imports of the bcrypt
package.
2021-11-08 13:32:04 +01:00
André Colomb
ec8a748514 lib/syncthing: Clean up / refactor LoadOrGenerateCertificate() utility function. (#8025)
LoadOrGenerateCertificate() takes two file path arguments, but then
uses the locations package to determine the actual path.  Fix that
with a minimally invasive change, by using the arguments instead.
Factor out GenerateCertificate().

The only caller of this function is cmd/syncthing, which passes the
same values, so this is technically a no-op.

* lib/tlsutil: Make storing generated certificate optional.  Avoid
  temporary cert and key files in tests, keep cert in memory.
2021-11-07 23:59:48 +01:00
greatroar
db15e52743 lib/api: http.Request.BasicAuth instead of custom code (#8039) 2021-11-06 12:38:08 +01:00
André Colomb
41bfb7a330 Normalize CLI options to always use two dashes. (#8037)
Consistently use double dashes and fix typos -conf, -data-dir and
-verify.

Applies also to tests running the syncthing binary for consistency.

* Fix mismatched option name --conf in cli subcommand.

According to the source code comments, the cli option flags should
mirror those from the serve subcommand where applicable.  That one is
actually called --config though.

* cli: Fix help text option placeholders.

The urfave/cli package uses the Value field of StringFlag to provide a
default value, not to name the placeholder.  That is instead done with
backticks around some part of the Usage field.

* cli: Add missing --data flag in subcommand help text.

The urfave/cli based option parsing uses a fake flags collection to
generate help texts matching the used global options.  But the --data
option was omitted from it, although it is definitely required when
using --config as well.  Note that it cannot just be ignored, as some
debug stuff actually uses the DB:

syncthing cli --data=/bar --config=/foo debug index dump
2021-11-04 08:42:55 +01:00
André Colomb
1c2e96a5ca gui: Display identicons for discovered device IDs. (#8022) 2021-10-29 20:23:41 +02:00
greatroar
28ff033da6 cmd/syncthing/cli: indexDumpSize doesn't need a heap (#8024) 2021-10-29 20:21:50 +02:00
greatroar
807a6b1022 lib/model: Optimize jobQueue performance and memory use (#8023)
By truncating time.Time to an int64 nanosecond count, we lose the
ability to precisely order timestamps before 1678 or after 2262, but we
gain (linux/amd64, Go 1.17.1):

name                      old time/op    new time/op    delta
JobQueuePushPopDone10k-8    2.85ms ± 5%    2.29ms ± 2%  -19.80%  (p=0.000 n=20+18)
JobQueueBump-8              34.0µs ± 1%    29.8µs ± 1%  -12.35%  (p=0.000 n=19+19)

name                      old alloc/op   new alloc/op   delta
JobQueuePushPopDone10k-8    2.56MB ± 0%    1.76MB ± 0%  -31.31%  (p=0.000 n=18+13)

name                      old allocs/op  new allocs/op  delta
JobQueuePushPopDone10k-8      23.0 ± 0%      23.0 ± 0%     ~     (all equal)

Results for BenchmarkJobQueueBump are with the fixed version, which no
longer depends on b.N for the amount of work performed. rand.Rand.Intn
is cheap at ~10ns per iteration.
2021-10-29 20:20:46 +02:00
Tomasz Wilczyński
296cc1bca2 lib/model: Limit the number of default hashers on Android (ref #2220)
Like Windows and Mac, Android is also an interactive operating system.
On top of that, it usually runs on much slower hardware than the other
two. Because of that, it makes sense to limit the number of hashes used
by default there too.

Signed-off-by: Tomasz Wilczyński <twilczynski@naver.com>
2021-10-29 10:06:52 +02:00
Simon Frei
951b058952 lib/model: Set mod. time after writing trailer in shortcut (ref #7992) 2021-10-24 16:50:30 +02:00
greatroar
8f8e8a9285 lib/protocol: Simplify codeToError, errorToCode
Also be explicit about the fact that ErrNoError is nil. That name isn't
used anywhere outside this file.
2021-10-22 18:40:40 +02:00
greatroar
46082f194c lib/protocol: Eliminate nativeModel on Unix 2021-10-22 18:40:40 +02:00
tomasz1986
cb607e8551 gui: Add direct link to Ignore Patterns from folder panel (fixes #4293) (#7993) 2021-10-20 23:06:03 +02:00
André Colomb
3e3954eb38 gui: Translate theme names in settings (#8006)
Add each subdirectory of the guiDir as a translation candidate string.
The key is prefixed with "theme-name-" and the default English
translation corresponds to the directory name turned to title case.
Disable the automatic name mangling in the GUI JS code in favor of
just looking up the translation.
2021-10-20 19:44:38 +02:00
Simon Frei
517667c590 lib/model: Pull when a new connection is established (fixes #8012) (#8013) 2021-10-20 18:55:22 +02:00
Jakob Borg
36c044562c gui, man, authors: Update docs, translations, and contributors 2021-10-20 07:45:29 +02:00
Jakob Borg
f760ef15b0 gui, man, authors: Update docs, translations, and contributors 2021-10-13 07:45:24 +02:00
Max
e557ba82e7 build: Fix error in Debian install scripts preventing restarts for stdiscosrv + strelaysrv (#8001) 2021-10-09 20:33:14 +02:00
greatroar
7c292cc812 lib/connections: Fix and optimize registry (#7996)
Registry.Get used a full sort to get the minimum of a list, and the sort
was broken because util.AddressUnspecifiedLess assumed it could find out
whether an address is IPv4 or IPv6 from its Network method. However,
net.(TCP|UDP)Addr.Network always returns "tcp"/"udp".
2021-10-06 10:52:51 +02:00
Simon Frei
c94b797f00 lib/protocol: Preserve sequence decrypting fileinfos (fixes #7994) (#7995) 2021-10-06 10:26:54 +02:00
Jakob Borg
4e513b8393 gui, man, authors: Update docs, translations, and contributors 2021-10-06 07:45:42 +02:00
Simon Frei
708a5c2070 lib/model: Write trailer when shortcutting on recv-enc (fixes #7991) (#7992) 2021-10-05 11:23:27 +02:00
Jakob Borg
92eaf52c21 lib/protocol: Test to lock down encryption key derivation
So that we don't inadvertently change how these things work.
2021-10-04 14:36:28 +02:00
tomasz1986
b75d083035 gui: Use case insensitive sort with folders on top in Restore Versions (#7980)
Currently, the default sorting of the file list in the Restore Versions
modal in both case sensitive, and it also does not distinguish between
files and folders. With this change, which uses a slightly modified code
from the fancytree itself (with added folder prioritisation), the sort
becomes case insensitive and also always places folders on top. This is
to make it behave more similar to what file managers do in the commonly
used operating systems (including popular Linux desktop environments).

Signed-off-by: Tomasz Wilczyński <twilczynski@naver.com>
2021-09-29 08:05:01 +02:00
Jakob Borg
b0460079c1 gui, man, authors: Update docs, translations, and contributors 2021-09-29 07:45:32 +02:00
tomasz1986
e20d4e192d Revert "gui: Allow to resize command in External Versioning (#7410)" (#7978)
This reverts commit cca17f5306.

Using textarea instead of input makes it possible to enter new lines,
which then are added to config.xml as "&#xA;". This breaks the whole
script, because these characters are passed to the command line as "\n".
Therefore, the script should rather remain a single-lined input field.

Signed-off-by: Tomasz Wilczyński <twilczynski@naver.com>
2021-09-28 08:05:18 +02:00
tomasz1986
8d8f331a4a lib/config: Always set mtime window to 2 on Android unless ext detected (ref #7963) (#7966)
The current detection is flawed, because it looks for a few specific
file systems like "msdos" or "fat" to set the mtime window, while in
reality Android seems to report names like "fuseblk", which can stand
for fat, ext4, or even f2fs.

At the moment, we set the mtime window only for a few known names used
for the fat filesystem. With this change, we take a safer approach of
always setting the time window unless we explicitly detect file systems
like ext2/ext3/ex4, which are known not to experience issues with moving
timestamps on Android.

Signed-off-by: Tomasz Wilczyński <twilczynski@naver.com>
2021-09-27 21:29:51 +02:00
tomasz1986
793035de61 gui: Fix jumping nav tabs in black and dark themes (#7977) 2021-09-27 21:28:14 +02:00
greatroar
198028d627 lib/rand: Optimizations (#7964)
rand.secureSource.Uint64 no longer allocates. rand.String uses a
strings.Builder. Benchmark results on linux/amd64:

name            old time/op    new time/op    delta
SecureSource-8    69.1ns ± 3%    51.7ns ± 3%   -25.21%  (p=0.000 n=20+10)
String-8          2.66µs ± 2%    1.95µs ± 1%   -26.61%  (p=0.000 n=10+10)

name            old alloc/op   new alloc/op   delta
SecureSource-8     8.00B ± 0%     0.00B       -100.00%  (p=0.000 n=20+10)
String-8            288B ± 0%       32B ± 0%   -88.89%  (p=0.000 n=10+10)

name            old allocs/op  new allocs/op  delta
SecureSource-8      1.00 ± 0%      0.00       -100.00%  (p=0.000 n=20+10)
String-8            33.0 ± 0%       1.0 ± 0%   -96.97%  (p=0.000 n=10+10)
2021-09-26 12:15:39 +02:00
Jakob Borg
c5ec6cd7ef build: Fix deepsource test & exclude patterns (#7969) 2021-09-26 12:08:59 +02:00
Jakob Borg
73c5184518 build: Update all dependencies (#7968)
Also add a script step for how to do this, as frankly I forget each time
what the canonical way is.

`go run build.go update-deps`
2021-09-26 12:08:23 +02:00
greatroar
f96c211198 lib/db: Replace SipHash with hash/maphash (#7962) 2021-09-24 21:26:07 +02:00
Jayachithra
6d2489a562 gui: Removed superfluous quotes (fixes #7853) (#7961)
Co-authored-by: Jaya Kumar <jaya.kumar@ict.nl>
2021-09-23 23:38:06 +02:00
Jakob Borg
fa05a1ba8c gui, man, authors: Update docs, translations, and contributors 2021-09-22 07:45:31 +02:00
greatroar
a4489dec30 lib/tlsutil: Allocate UnionedConnection in one go (#7912) 2021-09-21 08:40:34 +02:00
Jakob Borg
30e5243f5e build: Update go-ole for Windows/arm 2021-09-17 17:10:32 +02:00
Ross Smith II
06998b3484 build: Add -arm flag to goversioninfo (#7947) 2021-09-17 17:07:32 +02:00
Jakob Borg
3c66d93aba gui, man, authors: Update docs, translations, and contributors 2021-09-15 07:45:29 +02:00
André Colomb
a5792f3c42 gui: Sort already shared devices in edit folder modal (fixes #7940) (#7945)
The list of unshared devices is built from deviceList(), which sorts
the result.  But the shared devices are listed in undefined order from
the unsorted currentFolder.devices array.  Apply the same sorting
after building the array used in the dialog.
2021-09-13 20:41:15 +02:00
Simon Frei
721cd740d8 lib/model: Don't reset db while folder is running (fixes #7935) (#7936) 2021-09-11 17:14:47 +02:00
greatroar
de719ac409 lib/db: Inline sync.Once in releaser (#7938)
Having a pointer to a Once suggests that it is shared with other
objects, but it never is.
2021-09-10 09:58:17 +02:00
jtagcat
0ffa7f3f57 all: Clarify 'Cleaning data for folder' log message (#7937)
Instead of data (could be read as user data), use metadata.
2021-09-10 09:56:44 +02:00
Jakob Borg
4868d347db gui, man, authors: Update docs, translations, and contributors 2021-09-08 07:45:36 +02:00
greatroar
7fa141ea39 all: Unused args, retvals, assignments (#7926) 2021-09-08 00:11:16 +02:00
greatroar
13196ddd92 lib/relay/protocol: Merge two Sprintf calls 2021-09-06 15:30:56 +02:00
greatroar
eafb40460d lib/discover, lib/protocol: Buffer allocation 2021-09-06 15:30:56 +02:00
Simon Frei
4e2a9bb139 lib/model: Remove encryption pw on folder stop (#7925) 2021-09-03 09:54:47 +02:00
greatroar
3b2239357f lib/model: Add missing error assignment + Remove unused argument (#7922) 2021-09-01 22:03:06 +02:00
tomasz1986
7be1f0a71c gui: Move dismiss button after add/ignore buttons (#7848)
Currently, the dismiss button is displayed as the first of the three
buttons. However, the most common action that the user wants to do when
sharing a new folder is to add it on a different device. Because of
this, the add button should be displayed first as the most prominent of
the three. The ignore button is the opposite of the add button, and also
results in a parmenent action, hence it makes sense to lump the two
together. Thus, the dismiss button should be moved to the last place as
an alternative to the two main actions, when the user is yet unsure what
they want to do with the notification.

Signed-off-by: Tomasz Wilczyński <twilczynski@naver.com>
2021-09-01 21:59:47 +02:00
Jakob Borg
96f5a11fd5 gui, man, authors: Update docs, translations, and contributors 2021-09-01 07:45:32 +02:00
Ross Smith II
7501bee430 lib/model: Typo in folder_recvonly.go (#7919) 2021-09-01 07:41:18 +02:00
jtagcat
445c5f13c3 readme: Add a link to docs source (#7909) 2021-08-29 22:32:46 +02:00
greatroar
ed98039aa5 lib/fs: Optimize TempName + some cosmetic changes (#7911) 2021-08-29 10:47:53 +02:00
Jakob Borg
2816780b52 lib/api: Set "Secure" on session cookies served over HTTPS (ref #7399) (#7907)
So that it does not unnecessarily leak over clear text connections.
2021-08-27 17:56:54 +02:00
Jakob Borg
c76bd7dcc4 gui, man, authors: Update docs, translations, and contributors 2021-08-25 07:45:41 +02:00
xjtdy888
48796a1b60 lib/ur: Fix panic build goroutines for failures (#7903) 2021-08-25 07:16:55 +02:00
Simon Frei
5711bacd83 build: Readd systemd files to deb releases (ref #7564) (#7899) 2021-08-22 20:04:47 +02:00
Simon Frei
70a840d3d5 lib/connections: Remove future go build constraints on quic (#7898) 2021-08-19 21:05:28 +02:00
Benjamin Nater
37df662325 build: Update x/sys to fix new issue in go 1.17 2021-08-19 20:38:14 +02:00
Jakob Borg
ca908270ec gui, man, authors: Update docs, translations, and contributors 2021-08-18 07:45:38 +02:00
Jakob Borg
d47745a86b all: Update build constraints to Go 1.17 style (#7894) 2021-08-17 10:10:41 +02:00
Jakob Borg
8c94ce8d14 build: Simplify gem command in Debian Docker image 2021-08-17 09:38:42 +02:00
Simon Frei
0fe72e6fc5 lib/model: Schedule pull after revert on recv-enc (#7892) 2021-08-17 09:24:10 +02:00
Simon Frei
c025e76f30 lib/model: Do not wait for scan when setting ignores (fixes #7893) (#7891) 2021-08-17 09:23:33 +02:00
Simon Frei
e1bf1e672e lib/ur: Fix panic getting goroutines for failures (ref #7785) (#7890) 2021-08-16 22:47:05 +02:00
tomasz1986
a5bbb500e6 gui: Use large modals for Listeners and Discovery (#7884) 2021-08-13 20:09:10 +02:00
Jakob Borg
a615f868a5 gui, man, authors: Update docs, translations, and contributors 2021-08-11 07:45:33 +02:00
Simon Frei
db302b15ea lib/syncthing: Set system timezone on android (#7878) 2021-08-09 09:27:14 +02:00
Simon Frei
952f3ffb0c lib/db/backend: Prevent panic in errors.As (#7873) 2021-08-05 11:25:20 +01:00
Audrius Butkevicius
fe77fac23f Update quic to 0.22.0 to support RFC9000, enable batch reads (#7862)
* Update quic to 0.22.0 to support RFC9000, enable batch reads
* Remove wrappers that are not needed anymore
2021-08-05 05:44:22 +02:00
Simon Frei
e61091d240 lib/stun: Prevent nil deref when naming service (#7872) 2021-08-05 00:04:22 +01:00
Simon Frei
50aacdf1f0 lib/protocol: Ensure correct blocksize on enc. fileinfo (ref #7861) (#7870) 2021-08-04 23:12:01 +02:00
Simon Frei
e56e8b7aa1 lib/model: Don't consider hashes pulling on recv-enc (#7869) 2021-08-04 11:10:10 +02:00
Jakob Borg
6d0816e85a gui, man, authors: Update docs, translations, and contributors 2021-08-04 07:45:31 +02:00
tomasz1986
abdf024517 gui: Improve revert/override/delete warning modals (#7847)
1. Change each modal title text to match the action that is being
   executed (i.e. "Revert" to "Revert Local Additions", "Override" to
   "Override Changes", "Delete" to "Delete Unexpected Items").
2. Change the icons to match the icons used by each action (i.e. arrow-
   circle-down for Revert, arrow-circle-up for Override). Replace the
   broken lock icon for Delete with minus-circle.
3. Rearrange the order in the modal HTML code to simplify it a little.
2021-08-03 10:46:20 +01:00
tomasz1986
5a1f6cb813 lib/fs: Improve case conflict error message (fixes #7827) (#7829) 2021-08-01 22:44:49 +02:00
greatroar
37d0ba1660 lib/watchaggregator: Replace counter map by two integers (#7856) 2021-08-01 12:30:20 +02:00
Simon Frei
734c2fc870 Merge branch 'release' 2021-07-30 14:46:20 +02:00
Jonathan
490ec4350c lib/model: Fix config deadlock when deleting a paused folder (#7854) 2021-07-30 14:41:57 +02:00
Jonathan
0836439256 lib/model: Fix config deadlock when deleting a paused folder (#7854) 2021-07-30 14:41:00 +02:00
Jakob Borg
b197b698a4 gui, man, authors: Update docs, translations, and contributors 2021-07-28 07:45:33 +02:00
Simon Frei
67b18569cf all: Send deadlocks as failures, crash only as a last resort (#7785) 2021-07-27 21:27:52 +02:00
Simon Frei
dc0dd09e93 lib/model: Don't try to delete deleted item on revert (#7843) 2021-07-23 14:26:20 +02:00
Simon Frei
7ec76095e6 gui, script: Parse JS files for translation values (fixes #7845) (#7846) 2021-07-23 14:24:08 +02:00
Simon Frei
cb26552440 gui, script: Fix various gui string/translation issues (fixes #7839) (#7842) 2021-07-22 11:47:03 +02:00
Simon Frei
1ae5ac7d0b cmd/stcrashreceiver: Sanitize failure report fingerprints (#7840) 2021-07-22 11:16:24 +02:00
Simon Frei
eeb7091180 lib/model: Missing fmut-lock on encryption failures (#7841) 2021-07-22 11:15:25 +02:00
greatroar
dc38e6ae88 lib/relay/client: Stricter typing and remove unused code (#7819) 2021-07-21 09:49:09 +02:00
Jakob Borg
eb6cad7f93 gui, man, authors: Update docs, translations, and contributors 2021-07-21 07:45:25 +02:00
jtagcat
ae30b46bfe gui: advanced: On open collapse all, inc. GUI section. (#7820) 2021-07-16 06:40:30 +02:00
Jakob Borg
eab268f5f8 gui, man, authors: Update docs, translations, and contributors 2021-07-14 07:45:27 +02:00
greatroar
1e21042138 lib/connections: switch statement to get the QUIC network (#7816) 2021-07-10 13:53:51 +02:00
Jakob Borg
a56f70ab94 gui, man, authors: Update docs, translations, and contributors 2021-07-07 07:45:25 +02:00
Chih-Hsuan Yen
11c57b9097 lib/connections: Resolve IPv6 for quic6:// peers (fixes #7809) (#7810)
Before this patch, IPv4-compatible addresses (::ffff:aaa.bbb.ccc.ddd)
may be used if a quic6://some.domain:port is specified and both IPv4 and
IPv6 addresses exist for that domain name.
2021-07-05 13:19:56 +02:00
Simon Frei
1921533c4c lib/connections: Fully dial resumed devices (#7798) 2021-07-03 18:26:55 +02:00
Simon Frei
89e762fd6e lib/model: Prevent folder-type change from/to encrypted (fixes #7704) (#7796) 2021-07-03 13:47:04 +02:00
Simon Frei
a63d3ee625 lib/model: Scan removed dirs when reverting recv-enc (fixes #7706) (#7797) 2021-07-03 13:46:24 +02:00
Jakob Borg
82741ad207 gui, man, authors: Update docs, translations, and contributors 2021-06-30 07:45:30 +02:00
greatroar
bd363fe0b7 lib/protocol: Write uncompressible messages uncompressed (#7790) 2021-06-27 17:59:30 +02:00
Vladimir Rusinov
7a4c6d262f build: Remove no longer used temporaryBuildDir (#7795) 2021-06-27 17:59:02 +02:00
Simon Frei
445a82f120 lib/model: Compare all items with global on scan (fixes #7740) (#7791) 2021-06-27 08:48:54 +02:00
Simon Frei
69ce121267 lib/db: Missing event-logger in write-transaction (#7793) 2021-06-27 08:43:49 +02:00
Simon Frei
08e3cd1cce lib/fs: Set expiry after DirNames in case-fs (#7794) 2021-06-27 08:30:02 +02:00
André Colomb
da0e5edbec gui: Fix typo "recurr", again and for real (#7788) 2021-06-25 12:08:18 +02:00
Simon Frei
c78fa42f31 lib/connections: Dial devices in parallel (#7783) 2021-06-25 11:38:04 +02:00
Jakob Borg
993a3ebe73 lib/api: Always include usage reporting data in support bundle (#7786) 2021-06-24 22:00:14 +04:00
Jakob Borg
8040502599 gui, man, authors: Update docs, translations, and contributors 2021-06-23 07:45:27 +02:00
Simon Frei
c84e8d1e09 gui: Consider size 0 items in remote completion (fixes #7741) (#7781) 2021-06-21 22:53:50 +02:00
Simon Frei
5fb72eed85 gui: Make listener/discovery modal more discoverable (#7780) 2021-06-21 21:44:28 +02:00
Simon Frei
400d62c1e6 lib/connections: Missed map init in nextDialAt (ref #7753) (#7778) 2021-06-17 21:13:57 +04:00
Simon Frei
857caf3637 lib/connections: Trigger dialer when connection gets closed (#7753) 2021-06-17 13:57:44 +02:00
Simon Frei
aeca1fb575 lib/db: Check if sequences change when repairing metadata (#7770) 2021-06-17 13:53:39 +02:00
Simon Frei
ac2988a485 gui, lib: Handle pw adding remote encrypted folder (fixes #7705) (#7772) 2021-06-17 13:53:02 +02:00
Simon Frei
cb5ef250f4 build: Add codecov upload script to repo (#7776) 2021-06-17 13:52:10 +02:00
Simon Frei
23a0e18292 lib/db: Fix accounting bug when dropping indexes (#7774) 2021-06-17 10:15:11 +02:00
Simon Frei
aa6c55dec1 lib/model: Remove bogus failureevent when restarting folder (#7773) 2021-06-17 08:57:24 +02:00
André Colomb
7e0c24ec89 gui: Move the QR code button next to device ID in editDevice modal (#7653) 2021-06-16 21:10:16 +02:00
Simon Frei
2c7d9b59c6 gui: Fix race in online event callback (fixes #7733) (#7771) 2021-06-16 19:32:30 +02:00
Jakob Borg
adb7763f87 gui, man, authors: Update docs, translations, and contributors 2021-06-16 07:45:27 +02:00
André Colomb
89740490ac gui: Fix typo in new tooltip. (#7769) 2021-06-14 23:06:24 +02:00
greatroar
0b290f7206 all: go mod tidy (#7758) 2021-06-10 13:16:44 +02:00
Simon Frei
1e7a3997e3 lib/db, lib/model: Improve error handling on pending items (#7754) 2021-06-09 13:35:17 +02:00
Anur
e7f8538e4d lib/fs: Add bitmasks for Darwin to handle change to empty files (fixes #7731) (#7756) 2021-06-09 12:57:06 +02:00
Jakob Borg
18a608a6ff gui, man, authors: Update docs, translations, and contributors 2021-06-09 07:45:34 +02:00
Simon Frei
1a22689328 lib/db: Add failure reports to failures iterating over hashes (#7755) 2021-06-07 23:10:35 +02:00
Jakob Borg
ce65aea0ab lib/db: Use a more concurrent GC (fixes #7722) (#7750)
This changes the GC mechanism so that the first pass (which reads all
FileInfos to populate bloom filters with block & version hashes) can
happen concurrently with normal database operations.

The big gcMut still exists, and we grab it temporarily to block all
other modifications while we set up the bloom filters. We then release
the lock and let other things happen, with those other things also
updating the bloom filters as required. Once the first phase is done we
again grab the gcMut, knowing that we are the sole modifier of the
database, and do the cleanup.

I also removed the final compaction step.
2021-06-07 10:52:06 +02:00
André Colomb
45edad867c all: Allow dismissing pending devices / folders without ignoring (fixes #7700) (#7712) 2021-06-07 10:29:24 +02:00
André Colomb
ea0a408849 gui: Modal dialog for listeners and discovery status (#7539) 2021-06-07 09:08:44 +02:00
Simon Frei
18592af993 lib/model: Fix wrongly hardcoded arguments in test helper (#7749) 2021-06-05 17:01:23 +02:00
Simon Frei
b1e0e7b923 lib/model: Fix indexhandling for new folders paused on remote (#7747) 2021-06-05 16:27:15 +02:00
Jakob Borg
1e212a8dc6 cmd/syncthing: Wording on error return in "cli debug file" 2021-06-05 11:45:29 +02:00
Jakob Borg
0e9d2a13af cmd/syncthing: Improve "cli debug file" handling
Proper URL encoding, and return a sensible error when it's not found.
2021-06-05 11:19:02 +02:00
Simon Frei
6494a9332d lib/model: Fix test introduced in #7714 failing due to #7689 (#7745) 2021-06-04 15:32:47 +02:00
Simon Frei
41baccb85d lib/model: Fix passwords on receive-enc needing token (ref #7518) (#7739) 2021-06-03 15:39:49 +02:00
Simon Frei
52eb7392c4 lib/api, lib/config: Apply defaults before deserializing json (#7690) 2021-06-03 15:09:35 +02:00
Simon Frei
855c53ad02 lib/model: Fix reverting when version has only our own ID (fixes #7708) (#7714) 2021-06-03 15:08:56 +02:00
Simon Frei
004eded398 lib/model: Don't share with introduced device if encrypted (fixes #7724) (#7734) 2021-06-03 15:02:57 +02:00
Simon Frei
df48276300 lib/model: Ensure indexes are only received after checking IDs (ref #7649) (#7689) 2021-06-03 14:58:50 +02:00
Jakob Borg
accaf23aa3 gui, man, authors: Update docs, translations, and contributors 2021-06-02 07:45:38 +02:00
André Colomb
de6fe4dc6f gui: Show ID under each device section (local / remote), clickable for QR code (#7728) 2021-06-01 18:04:11 +02:00
Ikko Ashimine
08f6a91441 contributing: Fix GitHub format (#7713) 2021-05-31 10:27:35 +02:00
greatroar
95c9561e97 lib/db: Clean up Timer and wait for logging before return in GC (#7720) 2021-05-31 09:50:21 +02:00
Simon Frei
fcb19518c7 build, lib/model: Add flag to run tests without -short and fix failure (#7716) 2021-05-28 22:20:18 +02:00
Jakob Borg
fbaf696821 readme: Remove drama (#7711) 2021-05-26 14:59:49 +02:00
Jakob Borg
abe3483a8f gui, man, authors: Update docs, translations, and contributors 2021-05-26 07:45:29 +02:00
Simon Frei
22e09334ec lib/model: Fix incoming request on receive-enc (fixes #7699) (#7702) 2021-05-22 21:38:49 +02:00
Simon Frei
58592e3ef1 lib/db: Add logging for GC (#7707) 2021-05-22 21:36:43 +02:00
Simon Frei
0126188ba7 lib/config: Set DisableTempIndexes to true on receive-encrypted (#7701) 2021-05-20 22:33:23 +02:00
Simon Frei
5bdb6798a9 all: Regenerate proto (#7696) 2021-05-19 13:30:20 +02:00
Jakob Borg
ab2729ab79 gui, man, authors: Update docs, translations, and contributors 2021-05-19 07:45:35 +02:00
Audrius Butkevicius
58e81fdffb cmd/syncthing/cli: Update recli, fix stdin handling (fixes #7685, fixes #7673) (#7694) 2021-05-18 20:09:48 +01:00
tomasz1986
0619a27872 cmd/strelaypoolsrv: Fix minor grammar, use https in links (#7695)
* cmd/strelaypoolsrv: Fix minor grammar, use https in links

Add a few minor grammatical/stylistic fixes. Use `https` instead of
`http` in the MaxMind link in the footer.

Signed-off-by: Tomasz Wilczyński <twilczynski@naver.com>

* wip

Signed-off-by: Tomasz Wilczyński <twilczynski@naver.com>
2021-05-18 19:07:09 +01:00
greatroar
0e52ce830a lib/fs: Fix UnicodeLowercaseNormalized on lowercase NFD (#7692)
Co-authored-by: greatroar <@>
2021-05-17 20:43:07 +02:00
Jakob Borg
97437cad64 lib/fs: Ignore normalization differences in case insensitive lookup (fixes #7677) (#7678) 2021-05-17 12:35:03 +02:00
Simon Frei
5b90a98650 lib/model: Fix addFakeConn and other test improvements (#7684) 2021-05-16 17:23:27 +02:00
Audrius Butkevicius
96dae7bfec cmd/uraggregate: Optimise queries (#7679)
* cmd/uraggregate: Optimise queries

* Update main.go
2021-05-16 12:34:46 +01:00
Simon Frei
93a02c677e lib/scanner: Do not drop all not-exist-errors and debug logging (#7675) 2021-05-15 11:51:35 +02:00
Simon Frei
0d054f9b64 lib/model: Don't use empty folder cfg for index sender (fixes #7649) (#7671) 2021-05-15 11:13:39 +02:00
Audrius Butkevicius
1107f6eb5f lib/connections: Reduce default quic redial interval (fixes #7471) (#7672)
* lib/connections: Reduce default quic redial interval (fixes #7471)

* Update quic_dial.go
2021-05-14 14:26:02 +01:00
Simon Frei
3650364017 Merge branch 'release' 2021-05-13 11:44:59 +02:00
bt90
086508f51a docker: Remove sysctl from README (#7670) 2021-05-12 22:17:51 +02:00
Audrius Butkevicius
4ace451013 Update main.go (#7667) 2021-05-12 08:01:18 +01:00
Jakob Borg
c9ea773a22 gui, man, authors: Update docs, translations, and contributors 2021-05-12 07:45:34 +02:00
Simon Frei
0f4ae7636d build: Upgrade pfilter (fixes #7664) (#7666) 2021-05-11 20:57:38 +02:00
Simon Frei
87d3a8363b build: Upgrade pfilter (fixes #7664) 2021-05-11 20:45:35 +02:00
Simon Frei
c494ced21f lib/connections: Actually remove listenerSupervisor (ref #7644) (#7663) 2021-05-11 14:35:13 +02:00
Audrius Butkevicius
a8e2fc6f61 cmd/uraggregate: Handle malformed data, dont abort on error (fixes #7639) (#7659) 2021-05-11 08:02:19 +02:00
Audrius Butkevicius
aca1b45e93 lib/connections: Update pfilter to pick up bugfix/oob stuff, support OOB connections (fixes #7636) (#7654) 2021-05-11 07:59:56 +02:00
Simon Frei
5cb2a10138 lib/model: Improve encryption cluster-config errors (#7658) 2021-05-11 07:55:44 +02:00
Audrius Butkevicius
411796606c lib/connections: Correct service termination order (#7657) 2021-05-10 22:29:27 +02:00
Simon Frei
1a9b54c9fa lib/connections: Separate listener supervisors and lower backoff time (#7644) 2021-05-10 22:26:51 +02:00
Simon Frei
c7f4f15272 lib/relay, lib/svcutil: Improve service logging (fixes #7580) (#7647) 2021-05-10 22:26:25 +02:00
Simon Frei
713527facf all: Refactor relay invitations (#7646) 2021-05-10 22:25:43 +02:00
Simon Frei
6e662dc9fc lib/suture: Use ServeBackground to start main supervisor (#7626) 2021-05-10 16:50:45 +02:00
Audrius Butkevicius
eb178caf3a lib/connections: Add connection benchmarks, allow binding to port zero addresses (#7648)
* Add connbench

* Refactor port fixup

* More cleanup

* touch for build

Co-authored-by: Jakob Borg <jakob@kastelo.net>
2021-05-10 15:44:47 +01:00
Audrius Butkevicius
adf3f641ce Ignore GoLand cruft 2021-05-09 23:56:18 +01:00
Simon Frei
6157c766de lib/connections: Correct comments on quic wrapper type (#7652) 2021-05-09 19:15:10 +01:00
Audrius Butkevicius
745cd4744a lib/connections: Revert add more methods to the quic conn wrapper (#7651)
This reverts commit faf15b4567.
2021-05-09 19:43:16 +02:00
Simon Frei
faf15b4567 lib/connections: Add more methods to the quic conn wrapper (#7643) 2021-05-09 12:45:08 +01:00
greatroar
3746c899b7 build: List go:generate tools in tools.go (#7599) 2021-05-08 12:52:06 +02:00
Jakob Borg
7bbca12ff8 Merge branch 'release'
* release:
  build: Ignore error from pkill on apt upgrade (fixes #7628) (#7629)
2021-05-06 13:23:02 +02:00
Simon Frei
3967b39a17 build: Ignore error from pkill on apt upgrade (fixes #7628) (#7629) 2021-05-05 09:37:23 +02:00
Jakob Borg
2b2d24fe20 gui, man, authors: Update docs, translations, and contributors 2021-05-05 07:45:35 +02:00
Simon Frei
f4e112f404 build: Ignore error from pkill on apt upgrade (fixes #7628) (#7629) 2021-05-04 18:33:25 +02:00
Audrius Butkevicius
87a0eecc31 lib/fs, lib/api, lib/model: Expose mtime remappings as part of /db/file (#7624)
* lib/fs, lib/api, lib/model: Expose mtime remappings as part of /db/file

* Fix wrong error returned by CLI

* Gofmt

* Better names

* Review comments

* Review comments
2021-05-03 11:28:25 +01:00
overkill
f09dcb98eb gui: Semicolons (#7597) 2021-05-03 12:14:54 +02:00
dependabot[bot]
f90870b99f build: Bump github.com/shirou/gopsutil/v3 from 3.21.3 to 3.21.4 (#7625)
Bumps [github.com/shirou/gopsutil/v3](https://github.com/shirou/gopsutil) from 3.21.3 to 3.21.4.
- [Release notes](https://github.com/shirou/gopsutil/releases)
- [Commits](https://github.com/shirou/gopsutil/compare/v3.21.3...v3.21.4)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-05-03 12:10:04 +02:00
Simon Frei
75b58eb480 lib/fs: Watch attrib. changes on inotify for mod. time (#7623)
* lib/fs: Watch attrib. changes on inotify for mod. time

* fix bsds (real) and darwin (test only)
2021-05-02 16:45:44 +02:00
Jakob Borg
ed9cb923fb build: Update most dependencies (fixes: all the dependabot PRs) (#7622) 2021-04-30 09:11:11 +02:00
Simon Frei
dd39556759 lib: Revert needing invalid files (fixes #7608, ref #7476) (#7609) 2021-04-29 22:01:46 +02:00
dependabot[bot]
d5141c6d51 build: Bump github.com/prometheus/client_golang from 1.8.0 to 1.10.0 (#7612)
Bumps [github.com/prometheus/client_golang](https://github.com/prometheus/client_golang) from 1.8.0 to 1.10.0.
- [Release notes](https://github.com/prometheus/client_golang/releases)
- [Changelog](https://github.com/prometheus/client_golang/blob/master/CHANGELOG.md)
- [Commits](https://github.com/prometheus/client_golang/compare/v1.8.0...v1.10.0)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-04-29 21:57:22 +02:00
dependabot-preview[bot]
5675644341 build: Upgrade to GitHub-native Dependabot (#7607) 2021-04-29 21:19:06 +02:00
Simon Frei
1f30383866 lib/model: Remove path from enc errors and report only once (#7610) 2021-04-29 19:21:07 +02:00
tomasz1986
40531ef247 gui: Disable versions button when folder is paused (#7611)
Disable the Versions button when the folder is paused, because it does
not work, i.e. the versioned files are not loaded. The folder needs to
be unpaused to actually be able to view the versioned file list.

Signed-off-by: Tomasz Wilczyński <twilczynski@naver.com>
2021-04-29 18:34:08 +02:00
Wulf Weich
366700dc36 gui: Cut off long remote device names (fixes #7592) (#7606) 2021-04-28 18:11:05 +02:00
Jakob Borg
f23fd683a9 gui, man, authors: Update docs, translations, and contributors 2021-04-28 07:45:43 +02:00
Jakob Borg
755ed6f69f Merge branch 'release'
* release:
  lib/model: Handle invalid needed items on send-only (ref #7476) (#7596)
  gui: Handle empty path in validation (ref #7379) (#7595)
  cmd/syncthing: Don't fail early on api setup error (fixes 7558) (#7591)
2021-04-27 07:59:51 +02:00
Gahl Saraf
66662cd678 Trigger connection loop on config device addition (fixes #7600) (#7604)
* Trigger connection loop on config device addition (fixes #7600)

* Also check for device address equality

* Move EqualStrings from api_test to utils, and use in connections/service.go

* Make sure CommitConfiguration cannot block due on the deviceAddressesChanged channel

* Update lib/connections/service.go

Co-authored-by: Jakob Borg <jakob@kastelo.net>
2021-04-26 21:13:59 +01:00
Simon Frei
ec86db176e lib/model: Handle invalid needed items on send-only (ref #7476) (#7596) 2021-04-26 15:38:08 +02:00
Simon Frei
60e8630413 gui: Handle empty path in validation (ref #7379) (#7595) 2021-04-26 15:38:08 +02:00
Simon Frei
9d29dbbe5d cmd/syncthing: Don't fail early on api setup error (fixes 7558) (#7591)
* cmd/syncthing: Don't fail early on api setup error (fixes 7558)

* switch to factory pattern

* refactor config command to show help on nothing

* wip

* wip

* already abort in before
2021-04-26 15:38:08 +02:00
Simon Frei
8734fa65fc lib/model: Handle invalid needed items on send-only (ref #7476) (#7596) 2021-04-26 15:36:51 +02:00
Simon Frei
c53e5c5f17 gui: Handle empty path in validation (ref #7379) (#7595) 2021-04-26 15:35:12 +02:00
Jakob Borg
74823e81e9 all: Deprecate TLS 1.2 on sync connections (fixes #7594) (#7598)
This makes us use TLS 1.3+ on sync connections by default. A new option
`insecureAllowOldTLSVersions` exists to allow communication with TLS
1.2-only clients (roughly Syncthing 1.2.2 and older). Even with that
option set you get a slightly simplified setup, with the cipher suite
order fixed instead of auto detected.
2021-04-26 10:04:35 +02:00
Simon Frei
ef4b8a2cf8 cmd/syncthing: Don't fail early on api setup error (fixes 7558) (#7591)
* cmd/syncthing: Don't fail early on api setup error (fixes 7558)

* switch to factory pattern

* refactor config command to show help on nothing

* wip

* wip

* already abort in before
2021-04-25 20:48:17 +01:00
Simon Frei
54e27f551d cmd/syncthing: Add debug commands to cli (#7503) 2021-04-22 11:14:25 +02:00
Jakob Borg
59bdcdabba gui, man, authors: Update docs, translations, and contributors 2021-04-21 07:45:43 +02:00
Simon Frei
f6375ecbfc gui: Unset current folder on modal close (fixes #7584) (#7586) 2021-04-20 17:29:38 +02:00
Simon Frei
031b91c0ed gui: Fix folder path validation (fixes #7379) (#7585) 2021-04-20 17:29:06 +02:00
Jakob Borg
e4c995a321 lib/model: Don't remove non-empty .stfolder (#7578) 2021-04-15 18:13:35 +02:00
André Colomb
130d14cec9 api: Log API authorization failures. (#7575) 2021-04-15 07:33:02 +02:00
Jakob Borg
e893ca1c9a gui, man, authors: Update docs, translations, and contributors 2021-04-14 07:45:37 +02:00
Simon Frei
156d96e582 gui: Add missing file (fixes #7571, ref #7567) (#7573) 2021-04-13 20:22:55 +02:00
Simon Frei
9ba7611537 build: Bump go-stun to v0.1.3 (fixes #7568) (#7572) 2021-04-13 17:10:52 +01:00
Simon Frei
15d2dc3a4f lib/connections: Add SyscallConn() to quic conn (fixes #7551) (#7570) 2021-04-13 12:59:58 +01:00
André Colomb
f6df1a760d lib/api: Log the remote address on login attempts (#7560)
This enables usage of the audit log to e.g. automatically block remote
addresses from connecting after repeated login failures.
2021-04-13 10:14:44 +02:00
Simon Frei
f71fcd440a all: Remove untrusted feature flag (fixes #109) (#7567)
No longer hide the web UI controls for the new untrusted/encrypted
device feature. Testing hasn't been very widespread, but there has been
some and quite a few bugs have been caught and fixed. I believe its time
to not hide it anymore, and cautiously recommend usage. E.g. mention
that the feature hasn't been widely used yet and anyone using it is an
early adopter, but drop the bit about not using it with production data.
We can maybe stress the need for backups in general and especially
using this.
2021-04-13 10:12:56 +02:00
Simon Frei
c2bb11a794 build: Do not use --deb-systemd with fpm (fixes #7548) (#7564) 2021-04-11 20:04:15 +02:00
Simon Frei
1a00ea7c6e lib: Prevent using protocol method with native path (fixes #7557) (#7563) 2021-04-11 15:29:43 +02:00
Simon Frei
ec0a66c75b lib/db, lib/model: Refactor removing expired pending folders (#7537) 2021-04-11 15:24:08 +02:00
Jakob Borg
1658afc883 gui, man, authors: Update docs, translations, and contributors 2021-04-07 07:45:38 +02:00
Jakob Borg
67aaeef537 Merge branch 'release'
* release:
  cmd/syncthing: Rename --conf back to --config
  lib/db: Fix comparison of pending folder timestamps (fixes #7532) (#7535)
2021-04-06 10:47:00 +02:00
Jakob Borg
13679284ac cmd/syncthing: Rename --conf back to --config
This was inadvertently changed in the flag migration.
2021-04-06 10:42:29 +02:00
Jakob Borg
a514b65d81 cmd/syncthing: Rename --conf back to --config (fixes #7549) (#7550) 2021-04-06 10:40:52 +02:00
André Colomb
7931af1078 lib/db: Fix comparison of pending folder timestamps (fixes #7532) (#7535) 2021-04-06 10:37:11 +02:00
Jakob Borg
4fc3446f24 Merge branch 'release'
* release:
  Merge pull request from GHSA-x462-89pf-6r5h
2021-04-06 08:05:57 +02:00
Jakob Borg
fb4fdaf4c0 Merge pull request from GHSA-x462-89pf-6r5h 2021-04-06 08:03:22 +02:00
Jakob Borg
8e38ecdeb2 Merge pull request from GHSA-x462-89pf-6r5h 2021-04-06 08:00:00 +02:00
tomasz1986
04623718ce gui: Remove download animation from Out of Sync Items modal (fixes #3322) (#7388)
Remove the animation due to its excessive CPU usage, especially when a
large number of files is being downloaded and listed at the same time.
Also, remove the stripes, as they serve no purpose in the now-static
progress bar.

Signed-off-by: Tomasz Wilczyński <twilczynski@naver.com>
2021-04-05 10:28:06 +02:00
Simon Frei
9e857ed2d4 build: Add test coverage info (#7502) 2021-04-05 10:25:39 +02:00
Simon Frei
f30f9c50f8 lib/db: Handle indirection error repairing sequences (fixes #7026) (#7525) 2021-04-05 10:24:16 +02:00
mclang
96ba5c2b23 docker: Add docker-compose example (#7355)
Co-authored-by: bt90 <btom1990@googlemail.com>
2021-04-01 13:04:15 +02:00
Simon Frei
0dcd9794d4 lib/protocol: Deterministic encrypted version (fixes #7533) (#7538) 2021-03-31 08:59:15 +02:00
bt90
34f0feb13a docker: Raise UDP buffer size in example (#7536) 2021-03-31 08:57:46 +02:00
Jakob Borg
7778f50b50 gui, man, authors: Update docs, translations, and contributors 2021-03-31 07:45:27 +02:00
André Colomb
fb2d85b9d5 lib/db: Fix comparison of pending folder timestamps (fixes #7532) (#7535) 2021-03-30 21:24:53 +02:00
Simon Frei
7f0d4f6ba8 lib/db: Don't panic debugging an inexistent file (#7534) 2021-03-30 20:06:01 +02:00
MichaIng
33212716cf etc: Fix start-limit parameters location in systemd units (ref #7439) (#7529) 2021-03-28 14:14:10 +02:00
Simon Frei
707001c403 gui: Add confirmation dialog for revert/override (fixes #7520) (#7522) 2021-03-26 16:56:15 +01:00
Jonta
f93c6fbe4a readme: Larger link for Fitt's law, still semantic (#7523) 2021-03-26 07:24:40 +01:00
Jakob Borg
70b9654671 gui, man, authors: Update docs, translations, and contributors 2021-03-24 07:45:32 +01:00
Simon Frei
0d7a77ba85 lib/model: Reset conn when enc token is missing (fixes #7198) (#7518) 2021-03-23 10:38:40 +01:00
Simon Frei
924b96856f lib: Handle adding enc folders on an existing conn (fixes #7509) (#7510) 2021-03-22 21:50:19 +01:00
Audrius Butkevicius
f7929229c8 cmd/strelaysrv: Increase default strelaysrv network buffer size (fixes #7514) (#7517)
Increases throughput at the cost of more memory per connection
2021-03-22 21:47:51 +01:00
Simon Frei
6b25eb2e79 lib/ur: Prevent panic when blocksResult is nil (ref #7495) (#7515) 2021-03-22 15:07:41 +01:00
Simon Frei
bc08a951f1 lib/model: Encrypted fileinfo trailer needs to be in wire format (#7505) 2021-03-21 10:34:08 +01:00
Lars Lehtonen
a87c5515bd lib/model: Error check in test (#7508) 2021-03-21 10:32:17 +01:00
Jakob Borg
ebcd22b02b lib/osutil: Fix raising max FDs on macOS (#7507)
There was a logic mistake, so the limit in question wasn't used. On my
macOS this doesn't seem to matter, the hard limit returned is 2^63-1 and
setting the soft limit to that works. However I'm assuming that's not
the case for older macOSes since it was so nicely documented, so we
should still have this working. (10240 FDs should be enough for
anybody.)
2021-03-20 16:32:36 +01:00
Audrius Butkevicius
4b02b7e6f1 lib/connections: Silence "connected to myself" messages. (#7500) 2021-03-17 23:53:20 +01:00
Jakob Borg
fdd823d2cb lib/osutil: Remove unused code 2021-03-17 23:18:07 +01:00
Jakob Borg
8ef504f745 all: Simplify some method calls (#7499)
strings.Replace(a, b, c, -1) -> strings.ReplaceAll(a, b, c)

(Go 1.12) and who knows what was up with that dialQueue.Sort() thing.
2021-03-17 23:12:26 +01:00
Jakob Borg
960e850a78 cmd/uraggregate: Ignore errors harder (#7498)
We were already ignoring them, it just didn't look like it.
2021-03-17 22:55:43 +01:00
Jakob Borg
ea701a4e9e cmd/syncthing: Error handling on upgrade (#7497)
dat innocuous little colon
2021-03-17 22:52:43 +01:00
deepsource-autofix[bot]
6c573a5762 Remove unnecessary guard around delete (#7496)
Co-authored-by: deepsource-autofix[bot] <62050782+deepsource-autofix[bot]@users.noreply.github.com>
2021-03-17 22:23:36 +01:00
Jakob Borg
3ac858b150 all: Remove miscellaneous vestigial code (#7495) 2021-03-17 22:23:12 +01:00
Jakob Borg
f4372710bf all: Remove crypto/md5 (#7493)
This is a mostly pointless change to make security scanners and static
analysis tools happy, as they all hate seeing md5. None of our md5 uses
were security relevant, but still. Only visible effect of this change is
that our temp file names for very long file names become slightly longer
than they were previously...
2021-03-17 22:22:49 +01:00
Jakob Borg
f39477bbd5 lib/api: Missing error handling in API delete-device (#7494) 2021-03-17 22:08:44 +01:00
Jakob Borg
6e5514419d lib/db: Fix some omitted error checks, unused variable (#7489) 2021-03-17 21:41:07 +01:00
tomasz1986
f014b7b919 gui: Improve Receive Encrypted folder type requirements text (#7473)
The current text gives an impression that we are currently using a
Receive Encrypted folder, even if we are not. Thus, make the current
text displayed only when the folder is in fact Receive Encrypted, and
add a new string to be displayed when using different folder types.

Signed-off-by: Tomasz Wilczyński <twilczynski@naver.com>
2021-03-17 21:36:11 +01:00
Jakob Borg
81484699db lib/model: Actually break puller loop on context cancel (#7492)
Current break does nothing (breaks the select).
2021-03-17 21:34:52 +01:00
Jakob Borg
6d93d9c488 deepsource: Test patterns 2021-03-17 21:12:51 +01:00
deepsource-autofix[bot]
0930bccf88 cmd/ursrv, lib/scanner: Remove unnecessary slicing of slices (#7491)
Co-authored-by: deepsource-autofix[bot] <62050782+deepsource-autofix[bot]@users.noreply.github.com>
2021-03-17 21:04:36 +01:00
Jakob Borg
e321bd3941 lib/*/auto: Add noassets files (#7490)
This adds a couple of dummy asset files protected by the "noassets"
build tag. The purpose is that it should be possible for, for example,
CI tools and static analysis things to compile and analyze the source
tree without our custom asset generation step. Also makes `go test -tags
noassets ./...` work without building assets first.
2021-03-17 21:03:35 +01:00
Simon Frei
4b02937862 lib/model: Add missing lock on availability func (#7487) 2021-03-17 20:46:13 +01:00
Jakob Borg
21e6849f2d Add DeepSource for static analysis 2021-03-17 20:05:20 +01:00
Simon Frei
39c2d1bc1a cmd/syncthing: Check os.Args length (fixes #7486) 2021-03-17 15:51:14 +01:00
Simon Frei
cd21b8dfa5 cmd/syncthing/cli: Remove db reset and adjust others (#7484) 2021-03-17 09:06:37 +01:00
Simon Frei
40fbdc87ce cmd/syncthing: Refactor cli subcommand to allow flags (#7454) 2021-03-17 09:04:50 +01:00
Jakob Borg
1814f4693d gui, man, authors: Update docs, translations, and contributors 2021-03-17 07:45:40 +01:00
Simon Frei
3f2b584c4e lib/model: Don't use ignore patterns for recv-enc folders (fixes #7469) (#7472) 2021-03-16 15:04:11 +01:00
Jakob Borg
e0dd737822 gui: Fix validation and help texts in versioning editor (fixes #7481) (#7482) 2021-03-16 09:30:07 +01:00
Simon Frei
d2d4fcc1df lib/protocol: Improve messages when an error occurs receiving (ref #7466) (#7470) 2021-03-15 19:14:09 +01:00
Simon Frei
273ee09925 lib/db, lib/model: Allow needing invalid files (fixes #7474) (#7476) 2021-03-15 07:58:01 +01:00
tomasz1986
bb886868d2 gui: Use grey background for disabled options in form-control (#7468)
Disabled options are currently barely distinguishable from enabled
ones. This changes their background to grey, following the Bootstrap
defaults already used for disabled <select>.

Signed-off-by: Tomasz Wilczyński <twilczynski@naver.com>
2021-03-14 08:14:19 +01:00
Simon Frei
f80ee472c2 lib/protocol: Set invalid flag on encrypted file infos (fixes #7466) (#7467) 2021-03-13 16:57:36 +01:00
tomasz1986
a12ede3bbe gui: Fix missing trashcanClean in simple versioning (#7465) 2021-03-13 10:14:26 +01:00
Simon Frei
97a8777d03 lib/fs: Check both old and new path when renaming (fixes #7426) (#7463) 2021-03-12 21:15:50 +01:00
Simon Frei
8a4c00d82e lib/model: Send failure report on CC encryption check error (#7460) 2021-03-12 12:21:54 +01:00
Simon Frei
31f859e909 lib/model: Return correct error in puller-iteration (ref #7424) (#7461) 2021-03-12 12:21:28 +01:00
Jakob Borg
4d979a1ce9 all: Truncate some timestamps (fixes #7457) (#7459)
This truncates times meant for API consumption to second precision,
where fractions won't typically matter or add any value. Exception to
this is timestamps on logs and events, and of course I'm not touching
things like file metadata.

I'm not 100% certain this is an exhaustive change, but it's the things I
found by grepping and following the breadcrumbs from lib/api...

I also considered general-but-ugly solutions, like having the API
serializer itself do reflection magic or even regexps on returned
objects, but decided against it because aurgh...
2021-03-12 10:35:10 +01:00
Simon Frei
4465cdf8bc lib/api: Fix body of renamed config/restart-required endpoint (ref #7402) (#7453) 2021-03-11 15:54:05 +01:00
Simon Frei
3938b61c3f lib/fs: Expose fs option on interface (fixes #7385, ref #7381) (#7389) 2021-03-11 15:23:56 +01:00
Jakob Borg
cdef503db6 all: Make config.Wrapper an actual suture.Service (fixes #7451) (#7452) 2021-03-11 14:51:00 +01:00
Jakob Borg
df08984a58 lib/api: Sanitize names used in certificates (fixes #7434) (#7435) 2021-03-11 13:15:03 +01:00
Simon Frei
cf838c71f7 gui: Check if versioning object exists (fixes #7449) (#7450) 2021-03-11 11:21:35 +01:00
Simon Frei
9a001051d6 cmd/ursrv, lib/ur: Collect and present encryption usage (#7448) 2021-03-10 22:26:56 +00:00
Jakob Borg
5548a8eb7a gui, man, authors: Update docs, translations, and contributors 2021-03-10 07:45:45 +01:00
Simon Frei
727df34aa1 cmd/syncthing: Correct name of HiddenConsole flag (fixes #7446) (#7447) 2021-03-10 07:31:31 +01:00
Simon Frei
9587a523b3 build: Update notify (#7444) 2021-03-08 13:36:03 +01:00
Jakob Borg
22e44642a0 next-gen-gui: Add button to restore default theme (#7433)
This adds a button in the top right that changes the config back to the
default theme.

Code wise, it takes the header that was previously a part of the
dashboard component and moves it to the app component, and then adds the
button there. Possibly the header should be a component of it's own, but
that's more of refactor that can happen separately I think.

The config change uses the new config API to just patch the relevant
setting.

I'm not doing an automatic reload because 1) I don't want to figure out
how to do it correctly and 2) this doesn't work reliably anyway, as
for example the current gen GUI does a reload and ends up with
connection refused as the API service is still reloading...
2021-03-08 12:54:08 +01:00
greatroar
c00520281b lib/protocol: Optimize FileKey (#7440) 2021-03-07 18:44:21 +01:00
Simon Frei
587c89d979 cmd/syncthing, etc: Consistent failure restart backoff (#7439) 2021-03-07 15:25:55 +01:00
Simon Frei
310fba4c12 lib: Return error from db.FileSet.Snapshot (fixes #7419, ref #5907) (#7424) 2021-03-07 13:43:22 +01:00
bt90
c1d06d9501 build: Package sysctl configuration to raise UDP buffer size on Linux (#7417)
* Provide a sysctl config to raise max UDP buffer size

* Add sysctl config to deb

* Check if `deb-systemd-invoke` is available

Co-authored-by: otbutz <tbutz@optitool.de>
2021-03-05 08:08:29 +01:00
Simon Frei
4735575e8d cmd/syncthing: Set flag defaults through kong vars (#7431) 2021-03-05 08:06:54 +01:00
Simon Frei
767e1c6f58 lib/connections: Expose SetReadBuffer on conn passed to quic (ref #7417) (#7432) 2021-03-05 08:06:37 +01:00
Simon Frei
83fcb49894 gui: Apply #7430 to untrusted 2021-03-04 21:09:18 +01:00
André Colomb
5fd88481b6 gui: Fix hidden Ignore Patterns tab for folder editing (fixes #7429) (#7430) 2021-03-04 21:08:15 +01:00
Simon Frei
69c63e94bf scripts: Remove unused import (ref #7375) 2021-03-03 09:00:43 +01:00
Simon Frei
3d91f7c975 lib: Use counterfeiter to mock interfaces in tests (#7375) 2021-03-03 08:53:50 +01:00
Jakob Borg
7945430e64 gui, man, authors: Update docs, translations, and contributors 2021-03-03 07:45:37 +01:00
bt90
e2120c4728 docker: Expose 22000/udp (#7421)
Co-authored-by: otbutz <tbutz@optitool.de>
2021-03-02 20:42:25 +01:00
greatroar
56b5352f64 all: Use crypt/rand through its buffered version, but not in benchmarks (#7420) 2021-03-02 19:17:20 +01:00
Jakob Borg
55d5e03639 lib/db: Remove Badger experiment (#7413) 2021-03-01 09:16:08 +01:00
tomasz1986
cca17f5306 gui: Allow to resize command in External Versioning (#7410) 2021-02-27 09:41:16 +01:00
greatroar
ffcaffa32f lib/protocol: Optimize encrypted filename handling + make it more strict (#7408) 2021-02-27 08:57:12 +01:00
Simon Frei
0ffd80f380 lib/protocol: Alwasy return buffers to the pool (#7409) 2021-02-27 08:55:51 +01:00
wouter bolsterlee
25151b14e7 lib/api: Treat *.localhost as valid localhost addresses (#7412) (ref #4815)
This loosens the ‘is this localhost?’ check to include *.localhost host
names.

This allows for clearer (hence better) names to be used in browsers,
e.g. when accessing a remote syncthing instance ‘foo’ using a ssh port
forward, one can use foo.localhost to remind oneself which one is which.
💡 Without these changes, Syncthing shows a ‘Host check error’ when
pointing a browser at http://foo.localhost/, and with these changes, the
interface loads as usual.

The .localhost top level domain is a reserved top-level domain (RFC 2606):

> The ".localhost" TLD has traditionally been statically defined in
> host DNS implementations as having an A record pointing to the
> loop back IP address and is reserved for such use.  Any other use
> would conflict with widely deployed code which assumes this use.
> – https://tools.ietf.org/html/rfc2606

As Wikipedia puts it:

> This allows the use of these names for either documentation purposes
or in local testing scenarios. – https://en.wikipedia.org/wiki/.localhost

On Linux systems, systemd-resolved resolves *.localhost, on purpose:
https://www.freedesktop.org/software/systemd/man/systemd-resolved.service.html

See also #4815, #4816.
2021-02-27 08:52:49 +01:00
Simon Frei
428c5c02ce Merge branch 'release' 2021-02-26 13:47:03 +01:00
Simon Frei
e2e5643c3c all: Fix versioning path handling (#7407) 2021-02-26 13:21:13 +01:00
Simon Frei
956d212e99 gui: Folder versioning editing cleanup (#7384) 2021-02-26 13:20:53 +01:00
Simon Frei
fff8805ff6 all: Fix versioning path handling (#7407) 2021-02-26 12:04:05 +01:00
Simon Frei
a69afc9eeb gui: Folder versioning editing cleanup (#7384) 2021-02-25 18:24:18 +01:00
Simon Frei
0bf9645f2f lib/api: Rename config insync endpoint to restart-required (#7402) 2021-02-25 09:29:44 +01:00
Steven Eckhoff
6bfad8fce8 build: Make stupgrades build target conditional (fixes #7199) (#7404) 2021-02-25 09:29:14 +01:00
Jakob Borg
6ebab5db07 gui, man, authors: Update docs, translations, and contributors 2021-02-24 07:45:23 +01:00
bt90
34aa89a7d6 Allow QUIC traffic (#7400) 2021-02-23 20:39:03 +00:00
Jakob Borg
44e4f754dd Merge branch 'release'
* release:
  all: Fix Microsoft documentation links in code comments (#7387)
  gui: Handle info labels that are longer than available space (fixes #944) (#7386)
  gui: Show "Last seen" at the top when device is disconnected (ref #7166) (#7373)
  gui: Remove cleanupIntervalS leftovers from External Versioning (ref #7360) (#7378)
  gui: Allow setting custom path for all versioning except external (#7377)
  lib/fs: Consider options in case-fs caching (fixes #7371) (#7381)
  lib/scanner: Pass on errors while hashing (#7380)
  build: Update pfilter (#7376)
  gui: Hide the Rescan All button when no folders exist (#7367)
  lib/connections: Allow QUIC with Go 1.16 (#7372)
  gui: Hide non-functional Versions button when using External Versioning (#7365)
  gui, man, authors: Update docs, translations, and contributors
  gui: Fix setting external versioning command (fixes #7361) (#7362)
  lib/versioner: Improve error messages (fixes #7354) (#7357)
  gui: Disable Cleanup Interval with External File Versioning as unsupported (#7360)
2021-02-23 07:37:07 +01:00
tomasz1986
60c218efdb all: Fix Microsoft documentation links in code comments (#7387) 2021-02-22 18:27:41 +01:00
tomasz1986
8d290eb055 gui: Handle info labels that are longer than available space (fixes #944) (#7386)
Apply to table headers the same code as already used for table data.
This way, the headers will be either pushed to the next line, or cut
with an ellipsis if the single word is too long.

Signed-off-by: Tomasz Wilczyński <twilczynski@naver.com>
2021-02-22 18:27:41 +01:00
tomasz1986
cd17aa2cab gui: Show "Last seen" at the top when device is disconnected (ref #7166) (#7373)
Move the "Last seen" field to the very top in the device information.
This way, if a device has disconnected unexpectly, we can quickly check
the time when it was last available. Right now, due to the very long
address field, it is usually necessary to scroll down in order to view
the "Last seen" field.

Signed-off-by: Tomasz Wilczyński <twilczynski@naver.com>
2021-02-22 18:27:41 +01:00
tomasz1986
edaff81c0a gui: Remove cleanupIntervalS leftovers from External Versioning (ref #7360) (#7378) 2021-02-22 18:27:41 +01:00
tomasz1986
dd7d6188f2 gui: Allow setting custom path for all versioning except external (#7377) 2021-02-22 18:27:41 +01:00
Simon Frei
9be6f1a70e lib/fs: Consider options in case-fs caching (fixes #7371) (#7381) 2021-02-22 18:27:40 +01:00
Simon Frei
b0cce98648 lib/scanner: Pass on errors while hashing (#7380) 2021-02-22 18:27:40 +01:00
Simon Frei
e159f76ced build: Update pfilter (#7376) 2021-02-22 18:27:40 +01:00
tomasz1986
07d3af21c2 gui: Hide the Rescan All button when no folders exist (#7367)
If there are no folders present, show only the "Add Folder" button, and
hide the "Rescan All" button. Only show the latter when at least one
folder exists.

Signed-off-by: Tomasz Wilczyński <twilczynski@naver.com>
2021-02-22 18:27:40 +01:00
tomasz1986
1ed0116147 all: Fix Microsoft documentation links in code comments (#7387) 2021-02-20 14:56:45 +01:00
tomasz1986
c5663689a3 gui: Handle info labels that are longer than available space (fixes #944) (#7386)
Apply to table headers the same code as already used for table data.
This way, the headers will be either pushed to the next line, or cut
with an ellipsis if the single word is too long.

Signed-off-by: Tomasz Wilczyński <twilczynski@naver.com>
2021-02-20 10:28:08 +00:00
tomasz1986
9caaaa49b6 gui: Show "Last seen" at the top when device is disconnected (ref #7166) (#7373)
Move the "Last seen" field to the very top in the device information.
This way, if a device has disconnected unexpectly, we can quickly check
the time when it was last available. Right now, due to the very long
address field, it is usually necessary to scroll down in order to view
the "Last seen" field.

Signed-off-by: Tomasz Wilczyński <twilczynski@naver.com>
2021-02-20 10:26:34 +00:00
otbutz
c18dc6a629 cmd/strelaysrv: Load map tiles over HTTPS (#7382) 2021-02-19 22:07:05 +01:00
tomasz1986
b1fbd87680 gui: Remove cleanupIntervalS leftovers from External Versioning (ref #7360) (#7378) 2021-02-19 17:49:56 +01:00
tomasz1986
be630691b1 gui: Allow setting custom path for all versioning except external (#7377) 2021-02-19 17:48:46 +01:00
Simon Frei
aa1c274231 lib/fs: Consider options in case-fs caching (fixes #7371) (#7381) 2021-02-19 11:06:25 +01:00
Simon Frei
78c2844e3f lib/scanner: Pass on errors while hashing (#7380) 2021-02-19 08:51:39 +01:00
Simon Frei
57a7f4391f build: Update pfilter (#7376) 2021-02-18 15:09:46 +00:00
Simon Frei
0970aed596 cmd/stcrashreceiver: Add tag for report type (crash/failure) (#7374) 2021-02-18 13:16:32 +00:00
tomasz1986
342ade501a gui: Hide the Rescan All button when no folders exist (#7367)
If there are no folders present, show only the "Add Folder" button, and
hide the "Rescan All" button. Only show the latter when at least one
folder exists.

Signed-off-by: Tomasz Wilczyński <twilczynski@naver.com>
2021-02-17 18:02:55 +01:00
Jakob Borg
35316e9142 lib/connections: Allow QUIC with Go 1.16 (#7372) 2021-02-17 11:17:45 +01:00
tomasz1986
2a0775da03 gui: Hide non-functional Versions button when using External Versioning (#7365)
The button does nothing when the External Versioning is being used, so
it should not be displayed at all to avoid confusing the users.

Signed-off-by: Tomasz Wilczyński <twilczynski@naver.com>
2021-02-17 11:17:45 +01:00
Jakob Borg
8bd67f72dd gui, man, authors: Update docs, translations, and contributors 2021-02-17 11:17:45 +01:00
Simon Frei
82f190285a gui: Fix setting external versioning command (fixes #7361) (#7362) 2021-02-17 11:17:44 +01:00
Simon Frei
f5590c3345 lib/versioner: Improve error messages (fixes #7354) (#7357) 2021-02-17 11:17:44 +01:00
tomasz1986
9be07de7c6 gui: Disable Cleanup Interval with External File Versioning as unsupported (#7360)
As for right now, the External File Versioning does not support Cleanup
Interval. Therefore, the option should no be available at all when using
it.

Ref: https://forum.syncthing.net/t/16346

Signed-off-by: Tomasz Wilczyński <twilczynski@naver.com>
2021-02-17 11:17:44 +01:00
Jakob Borg
327604719a lib/connections: Allow QUIC with Go 1.16 (#7372) 2021-02-17 11:09:16 +01:00
tomasz1986
e8ef586cef gui: Hide non-functional Versions button when using External Versioning (#7365)
The button does nothing when the External Versioning is being used, so
it should not be displayed at all to avoid confusing the users.

Signed-off-by: Tomasz Wilczyński <twilczynski@naver.com>
2021-02-17 08:29:25 +01:00
Jakob Borg
c014fc5ec5 gui, man, authors: Update docs, translations, and contributors 2021-02-17 07:45:43 +01:00
Audrius Butkevicius
fb078068b4 cmd/syncthing: Add cli as a subcommand (fixes #6566, fixes #4719) (#7364)
* cmd/syncthing: Add cli as a subcommand (fixes #6566, fixes #4719)

* Hijack help

* Add comment

* Revert go.mod/go.sum
2021-02-15 18:50:53 +01:00
Jakob Borg
b2c9e7b07b build: Add build process for newgui (#7351) 2021-02-15 14:52:28 +01:00
Simon Frei
d117b4b570 gui: Fix setting external versioning command (fixes #7361) (#7362) 2021-02-14 09:54:49 +01:00
Simon Frei
80fc238bec all: Automatic/disabled folder-config when receive-encrypted (#7327) 2021-02-12 22:51:29 +01:00
Simon Frei
7e4e2f3720 lib/versioner: Improve error messages (fixes #7354) (#7357) 2021-02-12 20:30:51 +01:00
tomasz1986
5e9c7bc022 gui: Disable Cleanup Interval with External File Versioning as unsupported (#7360)
As for right now, the External File Versioning does not support Cleanup
Interval. Therefore, the option should no be available at all when using
it.

Ref: https://forum.syncthing.net/t/16346

Signed-off-by: Tomasz Wilczyński <twilczynski@naver.com>
2021-02-12 17:32:25 +00:00
Jakob Borg
55afa625fc cmd/syncthing: Add decrypt subcommand (#7332)
This adds the `syncthing decrypt` subcommand that is used to
(offline-)decrypt or just verify the contents of an encrypted folder.
2021-02-12 08:38:43 +01:00
Simon Frei
f2e9b40ad1 etc: Adjust all the startup scripts to new cmd (ref #7330) (#7353) 2021-02-11 12:18:47 +01:00
Simon Frei
6697b8fde3 cmd/syncthing: Fix hyphenated flag names (ref #7330) (#7352) 2021-02-11 11:37:48 +01:00
Jakob Borg
4f20c900d0 cmd/syncthing: Refactor command line parsing (#7330) 2021-02-10 20:35:37 +01:00
Jakob Borg
0471daf771 newgui: Merge separate repo into syncthing/syncthing
Co-authored-by: Audrius Butkevicius <audrius.butkevicius@gmail.com>
Co-authored-by: Simon Frei <freisim93@gmail.com>
2021-02-10 14:04:28 +01:00
Jakob Borg
5788ad2529 Reassign copyright to the Syncthing Authors 2021-02-10 13:58:51 +01:00
Jakob Borg
472affb6a3 Move all into newgui/ 2021-02-10 13:58:08 +01:00
Jakob Borg
802b933778 gui, man, authors: Update docs, translations, and contributors 2021-02-10 07:45:27 +01:00
Simon Frei
f1ec7fe55b gui: Check that connection exists on event (fixes #7347) (#7348) 2021-02-09 12:37:35 +01:00
Simon Frei
d842197931 lib/model: Disable tests involving scrypt with -short (fixes #7344) (#7346) 2021-02-08 17:13:28 +01:00
tomasz1986
4e7510dea9 build: Fix strings in versioninfo for Windows (fixes #7340) (#7342) 2021-02-08 15:48:05 +01:00
Simon Frei
c0f353c0e8 lib: Do not set ModifiedBy on meta only changes (#7345) 2021-02-08 15:30:39 +01:00
Simon Frei
e95d005c21 gui: Add defaults config to advanced menu (ref #7131) (#7343) 2021-02-08 12:59:02 +01:00
Simon Frei
11e9d575c8 lib/model: Refactor folder.scanSubdirs into smaller parts (#7321) 2021-02-08 08:40:57 +01:00
Simon Frei
46bbc78e82 lib/db: Fix and improve removing entries from global (ref #6501) (#7336) 2021-02-08 08:38:41 +01:00
Simon Frei
50a621bc7b gui: Apply #7339 to untrusted 2021-02-07 10:53:55 +01:00
Christian Prescott
d0c84916c7 gui: fix setDeviceConfig updating devices with undefined key (#7339) 2021-02-07 10:52:36 +01:00
Jakob Borg
6db8dc33f2 lib/model: Correctly verify short read blocks (fixes #7333) (#7334)
An untrusted device will receive padded info for small blocks, and hence
sometimes request a larger block than actually exists on disk.
Previously we let this pass because we didn't have a hash to compare to
in that case and we ignored the EOF error based on that.

Now the untrusted device does pass an encrypted hash that we decrypt and
verify. This means we can't check for len(hash)==0 any more, but on the
other hand we do have a valid hash we can apply to the data we actually
read. If it matches then we don't need to worry about the read
supposedly being a bit short.
2021-02-05 16:07:21 +01:00
Jakob Borg
194501c958 lib/api: Give the config changes some more time? (#7335) 2021-02-05 15:33:37 +01:00
Simon Frei
27a34609a1 all: Failure reporting fixes (#7331) 2021-02-05 11:21:14 +01:00
Simon Frei
ffc14a77c6 all: Add configurable defaults (fixes #4224, fixes #6086) (#7131) 2021-02-04 21:10:41 +01:00
greatroar
31119ed61a lib/ignore: Store cache timestamps as Unix ns counts (#7326) 2021-02-04 18:39:06 +01:00
Simon Frei
070bf3b776 lib/db: Report number of repaired items from checkGlobal (#7329) 2021-02-04 14:42:46 +01:00
Quentin Hibon
ade8d79d42 gui: Do not touch .stignore when not needed (fixes #7284) (#7325) 2021-02-03 20:58:24 +01:00
greatroar
42917d707d lib/scanner: Remove unused field, move WaitGroup.Add out of loop (#7323) 2021-02-03 14:25:24 +01:00
Jakob Borg
1522cf74bc gui, man, authors: Update docs, translations, and contributors 2021-02-03 07:45:28 +01:00
Jakob Borg
3b7a57d108 lib/protocol: Hide repeated data blocks in a given file (#7319) 2021-02-02 20:15:14 +01:00
Audrius Butkevicius
a7d9268e4d lib/model: Make /browse endpoint return sane objects (#7306) 2021-02-01 09:27:34 +01:00
Simon Frei
052dc13487 lib/model: Correct pull progress for small files (fixes #7263) (#7316) 2021-01-31 23:40:15 +01:00
Simon Frei
249bcb3a01 lib/model: Optimize rename detection in scanner (#7315) 2021-01-31 21:02:42 +01:00
greatroar
fbe52faf49 lib/scanner: Allocate structure for final partial block (#7310)
Benchmark results on Linux/amd64, using updated benchmark for old and
new:

name        old time/op    new time/op    delta
HashFile-8    88.6ms ± 1%    88.3ms ± 1%   -0.33%  (p=0.046 n=19+19)

name        old speed      new speed      delta
HashFile-8   201MB/s ± 1%   202MB/s ± 1%   +0.33%  (p=0.044 n=19+19)

name        old alloc/op   new alloc/op   delta
HashFile-8    59.4kB ± 0%    46.1kB ± 0%  -22.47%  (p=0.000 n=14+20)

name        old allocs/op  new allocs/op  delta
HashFile-8      29.0 ± 0%      27.0 ± 0%   -6.90%  (p=0.000 n=20+20)

Co-authored-by: greatroar <@>
2021-01-28 14:23:24 +01:00
greatroar
8b86171642 lib/stun: Inline util.OnDone, comment on its purpose (#7308)
Co-authored-by: greatroar <@>
2021-01-27 19:27:00 +01:00
Simon Frei
e19d6e993d lib/fs: Cache all real-case results (fixes #7270) (#7286) 2021-01-27 19:25:34 +01:00
greatroar
ef0473c091 lib/util, lib/svcutil: Remove unused code (#7309)
Duplicates the definition in lib/svcutil.

Co-authored-by: greatroar <@>
2021-01-27 16:33:01 +01:00
Tomasz Wilczyński
3406a3ba95 gui: Reduce checkboxes size in Advanced Configuration (fixes #6949) (#7296) 2021-01-27 12:23:58 +01:00
Jakob Borg
7c1ed420a9 gui, man, authors: Update docs, translations, and contributors 2021-01-27 07:45:21 +01:00
André Colomb
d7e86af6c6 gui/untrusted: Mirror changes from #7205 and #7192 (#7302) 2021-01-25 20:19:55 +01:00
Tomasz Wilczyński
76cf326290 gui: Make label and input IDs in Advanced Configuration unique (fixes #7287) (#7290) 2021-01-25 19:54:42 +01:00
greatroar
6c3e187d1d lib/svcutil: Simplify doneService (#7303)
OnSupervisorDone no longer allocates.

Co-authored-by: greatroar <@>
2021-01-25 16:27:17 +01:00
André Colomb
e32a516b5f lib/model: Forget pending folders no longer announced in ClusterConfig (fixes #5187) (#7205)
* lib/db: Add ExpirePendingFolders().

Use-case is to drop any no-longer-pending folders for a specific
device when parsing its ClusterConfig message where previously offered
folders are not mentioned any more.

The timestamp in ObservedFolder is stored with only second precision,
so round to seconds here as well.  This allows calling the function
within the same second of adding or updating entries.

* lib/model: Weed out pending folders when receiving ClusterConfig.

Filter the entries by timestamp, which must be newer than or equal to
the reception time of the ClusterConfig.  For just mentioned ones,
this assumption will hold as AddOrUpdatePendingFolder() updates the
timestamp.

* lib/model, gui: Notify when one or more pending folders expired.

Introduce new event type FolderOfferCancelled and use it to trigger a
complete refreshCluster() cycle.  Listing individual entries would be
much more code and probably just as much work to answer the API
request.

* lib/model: Add comment and rename ExpirePendingFolders().

* lib/events: Rename FolderOfferCancelled to ClusterPendingChanged.

* lib/model: Reuse ClusterPendingChanged event for cleanPending()

Changing the config does not necessarily mean that the
/resut/cluster/pending endpoints need to be refreshed, but only if
something was actually removed.  Detect this and indicate it through
the ClusterPendingChanged event, which is already hooked up to requery
respective endpoints within the GUI.

No more need for a separate refreshCluster() in reaction to
ConfigSaved event or calling refreshConfig().

* lib/model: Gofmt.

* lib/db: Warn instead of info log for failed removal.

* gui: Fix pending notifications not loading on GUI start.

* lib/db: Use short device ID in log message.

* lib/db: Return list of expired folder IDs after deleting them.

* lib/model: Refactor Pending...Changed events.

* lib/model: Adjust format of removed pending folders enumeration.

Use an array of objects with device / folder ID properties, matching
the other places where it's used.

* lib/db: Drop invalid entries in RemovePendingFoldersBeforeTime().

* lib/model: Gofmt.

My local gofmt did not complain here, strangely...

* gui: Handle PendingDevicesChanged event.

Even though it currently only holds one device at a time, wrap the
contents in an array under the "added" property name.

* lib/model: Fix null values in PendingFoldersChanged removed member.

* gui: Handle PendingFoldersChanged event.

* lib/model: Simplify construction of expiredPendingList.

* lib/model: Reduce code duplication in cleanPending().

Use goto and a label for the common parts of calling the DB removal
function and building the event data part.

* lib/events, gui: Mark ...Rejected events deprecated.

Extend comments explaining the conditions when the replacement event
types are emitted.

* lib/model: Wrap removed devices in array of objects as well.

* lib/db: Use iter.Value() instead of needless db.Get(iter.Key())

* lib/db: Add comment explaining RemovePendingFoldersBeforeTime().

* lib/model: Rename fields folderID and deviceID in event data.

* lib/db: Only list actually expired IDs as removed.

Skip entries where Delete() failed as well as invalid entries that got
removed automatically.

* lib/model: Gofmt
2021-01-25 10:58:10 +00:00
greatroar
6da83ac9f5 lib/util: Remove duplicate error handling code (#7299)
This is also in lib/svcutil, and never used by clients.

Co-authored-by: greatroar <@>
2021-01-24 20:19:10 +01:00
Jakob Borg
adc07eddf6 gui, man, authors: Update docs, translations, and contributors 2021-01-20 07:45:29 +01:00
greatroar
9c88efd55f lib/util: Don't modify input in UniqueTrimmedStrings (#7288)
Also clarified the comment.
2021-01-16 17:39:15 +01:00
Jakob Borg
ffcb57580f cmd/syncthing: Provide early startup for config service (ref #7188) (#7285) 2021-01-16 12:58:02 +01:00
Quentin Hibon
abfbd13f17 gui: Allow device removal even if possibly reintroduced (fixes #5426) (#7216) 2021-01-15 20:46:04 +01:00
Simon Frei
f63cdbfcfa lib: Apply config changes sequentially (ref #5298) (#7188) 2021-01-15 15:43:34 +01:00
Simon Frei
b2d82da20d lib/model: Pull when folder leaves error state (fixes #7280) (#7281) 2021-01-14 13:29:01 +01:00
Choongkyu
70fddb6523 gui: Disable "Rescan All" when all folders are paused (fixes #7257) (#7278) 2021-01-14 09:15:47 +01:00
Choongkyu
83cfd308b4 gui: Fix log-tailing behavior when scrolled to top (fixes #7267) (#7272) 2021-01-13 20:08:39 +01:00
Jakob Borg
36acaf5e21 lib/fs: Avoid blocking new caseFs creation while waiting to drop cache (fixes #7273) (#7275) 2021-01-13 17:45:29 +01:00
Jakob Borg
572ccfe3e2 gui, man, authors: Update docs, translations, and contributors 2021-01-13 07:45:46 +01:00
Jakob Borg
253049a4cc lib/api, lib/model: Avoid contention on filesystem for DB status call (ref #7270) (#7271)
This splits the ignore getting to two methods, one that loads from disk
(the old one) and one that just returns whatever is already loaded (the
new one). The folder summary service which is just interested in stats
now uses the latter method. This means that it, and API calls that call
it, does not get blocked by folder I/O.
2021-01-12 16:25:21 +01:00
Jakob Borg
8f199e12b3 lib/fs, lib/model: Reduce lock contention on NewCaseFilesystem (fixes #7268) (#7269) 2021-01-12 16:22:21 +01:00
greatroar
f6fac3e949 lib/ur: Plug file descriptor leak in Linux memorySize (#7266) 2021-01-11 15:15:21 +01:00
Jakob Borg
0b193b76c2 lib/config, lib/connections: Add optional connection limits (fixes #7176) (#7223)
This adds two new configuration options:

    // The number of connections at which we stop trying to connect to more
    // devices, zero meaning no limit. Does not affect incoming connections.
    ConnectionLimitEnough int

    // The maximum number of connections which we will allow in total, zero
    // meaning no limit. Affects incoming connections and prevents
    // attempting outgoing connections.
    ConnectionLimitMax int

These can be used to limit the number of concurrent connections in
various ways.
2021-01-11 15:14:44 +01:00
Jakob Borg
e6f0ed65be gui, man, authors: Update docs, translations, and contributors 2021-01-06 07:45:28 +01:00
Jakob Borg
b13b15758d lib/connections, lib/model: Track last connection duration (ref #7223) (#7242)
This adds a statistic to track the last connection duration per device.
It isn't used for much in this PR, but it's available for #7223 to use
in deciding how to order device connection attempts (deprioritizing
devices that just dropped our connection the last time).
2021-01-05 17:45:07 +01:00
Simon Frei
c48eb4241a lib/model: Fix child-check when deleting dirs in pull (#7236) 2021-01-02 21:40:37 +01:00
Simon Frei
0f8290485e lib/model: Handle index sender terminating due to error (fixes #7231) (#7232) 2020-12-30 09:59:11 +01:00
André Colomb
3d1edd2492 lib/fs: Fix TestChmodDir depending on umask (fixes #6551) (#7241)
The test would fail if the umask on UNIX is greater than 0022, because
the OS transparently subtracts it from the mode passed to Mkdir(), as
the Go documentation confirms.

Our goal here is not to test os.Mkdir(), so just make sure the desired
mode is actually set by forcing it afterwards.
2020-12-30 09:56:10 +01:00
Jakob Borg
a73db6fd84 gui, man, authors: Update docs, translations, and contributors 2020-12-30 07:45:26 +01:00
Simon Frei
a05dc6cc47 lib/model: Cleanup redundant filesystem variables in folders (#7237) 2020-12-27 22:26:25 +01:00
Simon Frei
5440d1dc3b gui: Do not replace zero versioning cleanup interval (#7234) 2020-12-27 10:08:15 +01:00
Simon Frei
f13e6ca631 lib/model: Remove obsolete return val from ccHandleFolders (ref #6443) (#7229) 2020-12-23 13:10:08 +01:00
Jakob Borg
81553b4da7 gui, man, authors: Update docs, translations, and contributors 2020-12-23 07:45:28 +01:00
André Colomb
07618f8674 gui: Fix missing sharing device when adding pending folder (#7227) 2020-12-22 22:37:29 +01:00
André Colomb
1555a4da7f cmd/stevents: Add command line argument for event type filtering. (#7226)
Add a -types flag which can be set to a comma-separated list of event
types.  The contents will be included verbatim in the URL parameter
"events".
2020-12-22 22:10:26 +01:00
Simon Frei
a20a5f61f0 lib/ur: Send unreported failures on shutdown (#7164) 2020-12-22 20:17:14 +01:00
André Colomb
4bcc38cf63 gui: Fix nonfunctional ignore button on pending folder notification (#7224)
The merge of #6443 apparently introduced a wrong argument name in
$scope.ignoreFolder().
2020-12-22 07:28:10 +01:00
Jakob Borg
05f25e600e lib/connections: Refactor connection loop (#7177)
This breaks out some methods from the connection loop to make it simpler
to manage and understand.

Some slight simplifications to remove the `seen` variable (we can filter
`nextDial` based on times are in the future or not, so we don't need to
track `seen`) and adding a minimum loop interval (5s) in case some
dialer goes haywire and requests a 0s redial interval or such.

Otherwise no significant behavioral changes.
2020-12-21 16:40:13 +01:00
Simon Frei
a744dee94c lib/fs: Correct wrapping order for meaningful log-caller (#7209) 2020-12-21 13:01:34 +01:00
Simon Frei
78bd0341a8 all: Handle errors opening db/creating file-set (ref #5907) (#7150) 2020-12-21 12:59:22 +01:00
Roberto Santalla
b5de49917c cmd/relaypoolsrv: Allow validation of relay join requests by certificate (fixes #7196) (#7217) 2020-12-21 11:55:16 +01:00
Simon Frei
c845e245a1 lib: Close underlying conn in protocol (fixes #7165) (#7212) 2020-12-21 11:40:51 +01:00
Simon Frei
4a787986cd lib/db: Prevent IndexID creation race (#7211) 2020-12-21 11:32:59 +01:00
Simon Frei
78a41828fc gui: Reflect change in untrusted in sharing tab (#7201) 2020-12-21 11:11:44 +01:00
Simon Frei
bd0c9913cf lib/db: Remove index ids when dropping folder (#7200) 2020-12-21 11:10:59 +01:00
Simon Frei
d904dfa191 lib/model: Fix flaky test and add some scanning debug (#7214) 2020-12-20 18:13:35 +01:00
Simon Frei
fa40ccece1 lib: Consistently set suture logging (#7202) 2020-12-18 19:44:00 +01:00
Simon Frei
7919310dc6 lib/model: Unflake TestIgnoreDeleteUnignore (#7208) 2020-12-18 18:42:09 +01:00
Simon Frei
7669af578a gui: Apply changes to untrusted (ref #6443) (#7206) 2020-12-17 23:13:28 +01:00
Simon Frei
739e99c4d9 lib/config: Remove deprecated pending entries from config (ref #6443) (#7204) 2020-12-17 22:49:29 +01:00
André Colomb
7502997e7e all: Store pending devices and folders in database (fixes #7178) (#6443) 2020-12-17 19:54:31 +01:00
Jakob Borg
4470cd5aaa gui, man, authors: Update docs, translations, and contributors 2020-12-16 07:45:23 +01:00
André Colomb
466e8a5cd0 gui: Sort folders and devices in advanced config modal (#7192) 2020-12-14 16:45:38 +01:00
Jakob Borg
4142a431b5 model: Actually print folder description in "Overriding" log message 2020-12-12 12:32:24 +01:00
Jakob Borg
5565afdd9f gui: version.tags is an array, which is truthy when empty 2020-12-12 10:34:26 +01:00
Simon Frei
0db3b7a530 build: Switch to gopsutil's v3 module (#7191) 2020-12-10 16:43:15 +01:00
Simon Frei
b37ecc3cf4 build: Update notify (fixes #7076) (#7189) 2020-12-10 15:43:05 +01:00
Jakob Borg
ec5a5d5218 lib/api: Returns tags in version as list (#7190) 2020-12-10 12:22:09 +01:00
Jakob Borg
7980c8cea2 gui: Harmonize architecture names 2020-12-10 11:23:47 +01:00
Jakob Borg
e9b68a224c lib/connections: Handle QUIC not being available (#7186)
This does two things:

- Exclude QUIC from go1.16 builds, automatically, for now, since it
  doesn't work and just panics.

- Provide some fake listeners and dialers when QUIC is disabled.

These fake listeners and dialers indicate that they are disabled and
unsupported, which silences "Dialing $address: unknown address scheme:
quic" type of stuff which is not super helpful to the user.
2020-12-09 19:23:50 +01:00
Simon Frei
8fd6b1d428 lib/protocol: Handle slashified paths in IsEncryptedParent (fixes #7184) (#7187) 2020-12-09 18:16:14 +01:00
André Colomb
4198b5061f gui: Split folders into two categories on the sharing tab for devices (#7162) 2020-12-09 14:54:51 +01:00
Jakob Borg
b0a525a504 gui, man, authors: Update docs, translations, and contributors 2020-12-09 07:45:25 +01:00
Eric Lesiuta
25d904dc37 gui: Fix blank device name under "Recent Changes" (#7185)
fixes the device showing up as blank if the friendly name is known
2020-12-07 22:19:28 +01:00
Jakob Borg
777a30e870 Add usage notes and screenshot 2020-04-17 09:34:31 +02:00
Jakob Borg
aea66ff25a v1.0.0 2020-04-17 09:11:01 +02:00
Jesse Lucas
9dd319f4da status-list: update styling, adding selected and hover states 2020-04-14 21:00:48 -04:00
Jesse Lucas
8b4a1f52d0 update folder devices array for the "shared with" section in the folder list #CTR-2 2020-04-14 21:00:48 -04:00
Jesse Lucas
7a9f317ee1 enable expandable rows for devices list 2020-04-14 21:00:48 -04:00
Jesse Lucas
48efea99e5 add trim pipe 2020-04-14 21:00:48 -04:00
Jesse Lucas
fbef856a97 Remove unused columns 2020-04-14 21:00:48 -04:00
Jesse Lucas
3b7c760ffd start of expandable rows for folder list 2020-04-14 21:00:48 -04:00
Jesse Lucas
ae776ff8df Rework device and folder service to have public obseravble
to accomaccommodatemodate many subscribers without re-requesting data
from the API
2020-04-14 21:00:48 -04:00
Jesse Lucas
24a637e9e6 Change device/folder getAll to getEach 2020-04-14 21:00:48 -04:00
Jesse Lucas
f53475a204 use replay subject in place of timer 2020-04-14 21:00:48 -04:00
Jakob Borg
3fbc51cd38 Skip animations on donut charts 2020-04-14 16:29:52 +02:00
Jesse Lucas
5f1aba9a37 adjusting styles 2020-04-09 13:01:06 -04:00
Jesse Lucas
95f7a26bce style dialog component and close button 2020-04-09 13:01:06 -04:00
Jesse Lucas
6e1828ff63 support dark mode and add custom card component 2020-04-09 13:01:06 -04:00
Jesse Lucas
89c53c508b consolidate retry logic in error interceptor
remove retry operator from services
2020-04-09 13:01:06 -04:00
Jesse Lucas
9918cb4ffc Add MatDialog and use messageService to display errors 2020-04-09 13:01:06 -04:00
Jesse Lucas
7b61f800c3 add missing semicolon 2020-04-09 13:01:06 -04:00
Jesse Lucas
33d47063e8 remove unused data binding 2020-04-09 13:01:06 -04:00
Jesse Lucas
e67b91977d remove console logs 2020-04-09 13:01:06 -04:00
Jesse Lucas
ac603e9228 start of message service 2020-04-09 13:01:06 -04:00
Jesse Lucas
632b6f8fbd start of dialog component 2020-04-09 13:01:06 -04:00
Jesse Lucas
b247ef2632 start of error interceptor 2020-04-09 13:01:06 -04:00
Jesse Lucas
5a6d79a66e Recalculate completion for devices and update total properties 2020-04-06 14:30:44 -04:00
Jesse Lucas
1e33cc9720 update progress service with device/folders loaded and add animation 2020-04-05 11:50:05 -04:00
Jesse Lucas
ee465c0890 update progress service with get percentValue and table tests 2020-04-05 11:50:05 -04:00
Jesse Lucas
236816cb93 Add imports and providers to enable basic testing 2020-04-05 11:50:05 -04:00
Jesse Lucas
3ee9bc097f Update tech-ui-blue style to have contrast 2020-04-05 11:50:05 -04:00
Jesse Lucas
f205ce14c1 start of progress indicator and animation 2020-04-05 11:50:05 -04:00
Jesse Lucas
8199e0a7a9 update angular dependencies 2020-04-05 11:50:05 -04:00
Jakob Borg
f18fc40436 Harmonize license with Syncthing proper 2020-04-03 22:28:36 +02:00
Jesse Lucas
f509c65509 increase chart item padding 2020-04-03 10:25:19 -04:00
Jesse Lucas
bf062db83f create chart item state to toggle filter selection 2020-04-03 09:20:27 -05:00
Jesse Lucas
9907523321 switch filter to Subject from BehaviorSubject 2020-04-03 09:20:27 -05:00
Jesse Lucas
915faabe25 Filter lists when donut chart items are clicked 2020-04-03 09:20:27 -05:00
Jesse Lucas
a9b6801b22 Store last filtered value between toggling of lists 2020-04-03 09:20:27 -05:00
Jesse Lucas
d76f1fe356 Style chart item 2020-04-03 09:20:27 -05:00
Jesse Lucas
3bdceb1d6b add filter service and enable chart states to filter lists 2020-04-03 09:20:27 -05:00
Jesse Lucas
cce8b60515 adjust filter style and add filter to device list 2020-03-31 20:40:36 -04:00
Jesse Lucas
06eacb87d8 Add additional columns, styling and data to lists 2020-03-31 20:40:36 -04:00
Jesse Lucas
865f1f2ea6 reduce mock data delay for testing 2020-03-31 20:40:36 -04:00
Jesse Lucas
f59a26cb80 relative path apiURL 2020-03-31 11:41:59 -04:00
Jesse Lucas
d384ac52a1 use relative path for base-href and meta.js 2020-03-31 11:41:59 -04:00
Jesse Lucas
42fa03aa4a start of list filtering 2020-03-31 11:41:59 -04:00
Jesse Lucas
dae1f990a5 Combine types 2020-03-31 11:41:59 -04:00
Jakob Borg
33398b0b6b Also mention STGUIASSETS 2020-03-31 16:14:09 +02:00
Jakob Borg
192e843989 README/LICENSE 2020-03-31 15:55:39 +02:00
Jesse Lucas
8851f4571c Add header and logo 2020-03-30 14:48:53 -04:00
Jesse Lucas
7fed8334b9 Use a smaller font when device or folder counts are above 4 digits 2020-03-30 14:48:53 -04:00
Jesse Lucas
6af2657d7e Combine folder and device chart component into chart component 2020-03-30 14:48:53 -04:00
Jesse Lucas
933a57af7a Add title to donut chart and media queries 2020-03-30 11:54:54 -04:00
Jesse Lucas
e5b85ff1a0 update angular cli, devkit and node 2020-03-30 11:54:24 -04:00
Jesse Lucas
c382aa04e4 right justify chart items 2020-03-29 17:45:08 -04:00
Jesse Lucas
86141c1eef enable chart canvas responsiveness 2020-03-29 16:51:12 -04:00
Jesse Lucas
d67c9b66d3 determine chart color based on state type 2020-03-29 16:51:12 -04:00
Jesse Lucas
6158b20a8c Style donut chart and add total count 2020-03-29 16:51:12 -04:00
Jesse Lucas
485a234263 Use flexbox for dashboard layout 2020-03-29 16:51:12 -04:00
Jesse Lucas
7226a87c6d Create tech ui card css to replace material cards 2020-03-29 16:51:12 -04:00
Jesse Lucas
7aca2bcbc0 add custom chartjs tooltip 2020-03-29 16:51:12 -04:00
Jesse Lucas
3840d57f8d temporarily handle current device in device list 2020-03-29 16:51:12 -04:00
Jesse Lucas
b7f3425f36 add system status service and mock data 2020-03-29 16:51:12 -04:00
Jesse Lucas
9fe0c30299 update mock names 2020-03-29 16:51:12 -04:00
Jesse Lucas
9d126760fa Synchronously get the status of each device 2020-03-29 16:51:12 -04:00
Jesse Lucas
09673ba0c6 create db completion service and mock data 2020-03-29 16:51:12 -04:00
Jesse Lucas
bc7d71ee3d Create system connections service, mocks, and work on updating devices chart 2020-03-29 16:51:12 -04:00
Jesse Lucas
78a31449aa create Device namespace and getStateType function 2020-03-29 16:51:12 -04:00
Jesse Lucas
0361d303f2 organize services into services folder 2020-03-29 16:51:12 -04:00
Jesse Lucas
2fe94736e6 update device chart to use donut chart updateData 2020-03-29 16:51:12 -04:00
Jesse Lucas
9589f25e57 refactor to use caching interceptor 2020-03-29 16:51:12 -04:00
Jesse Lucas
15c2556e06 fix conditional logic 2020-03-29 16:51:12 -04:00
Jesse Lucas
f342a2a54b refactor to use array of objects to map state data to chart update 2020-03-29 16:51:12 -04:00
Jesse Lucas
598dc991e8 complete observers 2020-03-29 16:51:12 -04:00
Jesse Lucas
7d59dc6c18 add updateData and removeAllData methods to donut chart 2020-03-29 16:51:12 -04:00
Jesse Lucas
05f01a5d94 start of caching, csrf interceptor, and device service 2020-03-29 16:51:12 -04:00
Jesse Lucas
03c6fb2f82 Rename folders 2020-03-29 16:51:12 -04:00
Jesse Lucas
7a657bf3c7 Create states map and set chart-items based on map 2020-03-29 16:51:12 -04:00
Jesse Lucas
02d14c7e9b Add chart item component, StateType and getStateType to determine state from Folder 2020-03-29 16:51:12 -04:00
Jesse Lucas
32c849e18c Refactor Folder interface to use Folder namespace 2020-03-29 16:51:12 -04:00
Jesse Lucas
c27fe5694d Update mock data 2020-03-29 16:51:12 -04:00
Jesse Lucas
b0ebf56283 Add new component chart-item 2020-03-29 16:51:12 -04:00
Jesse Lucas
fb33a8ad6b Remove unused tags in index.html 2020-03-29 16:51:12 -04:00
Jesse Lucas
9207562545 refactor status toggle to list toggle 2020-03-29 16:51:12 -04:00
Jesse Lucas
230eb20a34 update font styles 2020-03-29 16:51:12 -04:00
Jesse Lucas
e0d9542bfe update status list template and add flex box 2020-03-29 16:51:12 -04:00
Jesse Lucas
063951cffa Synchronously get the status of each folder 2020-03-29 16:51:12 -04:00
Jesse Lucas
dae0872379 Remove Folder object from array in development only 2020-03-29 16:51:12 -04:00
Jesse Lucas
123f4a6d9d Update mock data 2020-03-29 16:51:12 -04:00
Jesse Lucas
65679892b0 Don't encapsulate data for in memory services for development 2020-03-29 16:51:12 -04:00
Jesse Lucas
c4979cf6d6 update readme to disable syncthing upgrade 2020-03-29 16:51:12 -04:00
Jesse Lucas
09d498bb80 Refactor charts to use @ViewChild instead of @Input 2020-03-29 16:51:12 -04:00
Jesse Lucas
90ed7aa121 add apiRetry to api-utils 2020-03-29 16:51:12 -04:00
Jesse Lucas
206c0d0933 Work on db status service 2020-03-29 16:51:12 -04:00
Jesse Lucas
81c539c516 new folder service 2020-03-29 16:51:12 -04:00
Jesse Lucas
75b3b31d11 create folder status interface 2020-03-29 16:51:12 -04:00
Jesse Lucas
90c39de0cc add system config service retry 2020-03-29 16:51:12 -04:00
Jesse Lucas
241864b43c create mock data 2020-03-29 16:51:12 -04:00
Jesse Lucas
b2d839d4e7 fix race condition with Observables in list components 2020-03-29 16:51:12 -04:00
Jesse Lucas
8bdf409d07 start of db status service 2020-03-29 16:51:12 -04:00
Jesse Lucas
08da982de5 pass and add data to donut chart 2020-03-29 16:51:12 -04:00
Jesse Lucas
f250425ef1 clean up mock data and update device interface 2020-03-29 16:51:12 -04:00
Jesse Lucas
aebcc495f9 create style.ts to set elevation for all dashboard components 2020-03-29 16:51:12 -04:00
Jesse Lucas
eaffbc0f92 refactor chart and list component structure 2020-03-29 16:51:12 -04:00
Jesse Lucas
37f2f2cdf6 add delay to in memory service and update check interval 2020-03-29 16:51:12 -04:00
Jesse Lucas
82f5706350 start of chart component 2020-03-29 16:51:12 -04:00
Jesse Lucas
ad2902b3ee start of dashboard component with flexbox 2020-03-15 17:19:57 -04:00
Jesse Lucas
ce2c6c01da update mock config data and service 2020-03-15 17:19:57 -04:00
Jesse Lucas
fb4c7d288c update system config url and http options 2020-03-15 12:47:24 -04:00
Jesse Lucas
838b2a6a34 add mock in-memory data service 2020-03-15 12:47:24 -04:00
Jesse Lucas
fd0de9eb6c update readme to indicate build and syncthing tech-ui branch 2020-03-14 22:38:41 -04:00
Jesse Lucas
6b89991ba8 create cookie service to find CSRF header data 2020-03-14 20:11:05 -04:00
Jesse Lucas
4727570870 create api-utils to hold convenience convenience data structures 2020-03-14 20:11:05 -04:00
Jesse Lucas
ebf0541385 start of CSRF 2020-03-14 20:11:05 -04:00
Jesse Lucas
af3d380b6a update SystemConfigService to load config and set folders and devices
update getFolders and getDevices to send respective array as soon as it has data
2020-03-14 20:11:05 -04:00
Jesse Lucas
cf3de8cf35 toggle status lists 2020-03-11 21:24:02 -04:00
Jesse Lucas
61b4de581d create folder and device list components
refactor status-list to contain device and folder list
2020-03-11 21:24:02 -04:00
Jesse Lucas
031fd72dfd start of toggle to switch between devices and folders data table 2020-03-11 21:24:02 -04:00
Jesse Lucas
1d249a877e start of StatusList component 2020-03-10 22:51:50 -04:00
Jesse Lucas
3eb6045dee initial commit 2020-03-10 10:57:02 -04:00
793 changed files with 110553 additions and 37235 deletions

View File

@@ -1,5 +1,20 @@
comment: false
coverage:
range: "40...100"
precision: 1
status:
patch:
default:
informational: true
project:
default:
informational: true
github_checks:
annotations: false
ignore:
- "**.pb.go"
- "**_mocked.go"
- "**/mocks/*"

12
.deepsource.toml Normal file
View File

@@ -0,0 +1,12 @@
version = 1
exclude_patterns = ["**/*.pb.go"]
test_patterns = ["**/*_test.go"]
[[analyzers]]
name = "go"
enabled = true
[analyzers.meta]
import_paths = ["github.com/syncthing/syncthing"]
build_tags = ["noassets"]

13
.github/dependabot.yml vendored Normal file
View File

@@ -0,0 +1,13 @@
version: 2
updates:
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: weekly
open-pull-requests-limit: 10
- package-ecosystem: "gomod"
directory: "/"
schedule:
interval: weekly
open-pull-requests-limit: 10

View File

@@ -0,0 +1,54 @@
name: Build Infrastructure Images
on:
push:
branches:
- infrastructure
env:
GO_VERSION: "^1.21.0"
CGO_ENABLED: "0"
BUILD_USER: docker
BUILD_HOST: github.syncthing.net
jobs:
docker-syncthing:
name: Build and push Docker images
runs-on: ubuntu-latest
environment: docker
strategy:
matrix:
pkg:
- stcrashreceiver
- strelaypoolsrv
- stupgrades
steps:
- uses: actions/checkout@v3
with:
fetch-depth: 0
- name: Login to Docker Hub
uses: docker/login-action@v2
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Build binaries
run: |
for arch in arm64 amd64; do
go run build.go -goos linux -goarch "$arch" build ${{ matrix.pkg }}
mv ${{ matrix.pkg }} ${{ matrix.pkg }}-linux-"$arch"
done
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2
- name: Build and push
uses: docker/build-push-action@v4
with:
context: .
file: ./Dockerfile.${{ matrix.pkg }}
platforms: linux/amd64,linux/arm64
push: true
tags: syncthing/${{ matrix.pkg }}:latest,syncthing/${{ matrix.pkg }}:${{ github.sha }}

789
.github/workflows/build-syncthing.yaml vendored Normal file
View File

@@ -0,0 +1,789 @@
name: Build Syncthing
on:
pull_request:
push:
schedule:
# Run nightly build at 05:00 UTC
- cron: '00 05 * * *'
workflow_dispatch:
env:
# The go version to use for builds. We set check-latest to true when
# installing, so we get the latest patch version that matches the
# expression.
GO_VERSION: "~1.21.0"
# Optimize compatibility on the slow archictures.
GO386: softfloat
GOARM: "5"
GOMIPS: softfloat
# Avoid hilarious amounts of obscuring log output when running tests.
LOGGER_DISCARD: "1"
# Our build metadata
BUILD_USER: builder
BUILD_HOST: github.syncthing.net
# A note on actions and third party code... The actions under actions/ (like
# `uses: actions/checkout`) are maintained by GitHub, and we need to trust
# GitHub to maintain their code and infrastructure or we're in deep shit in
# general. The same doesn't necessarily apply to other actions authors, so
# some care needs to be taken when adding steps, especially in the paths
# that lead up to code being packaged and signed.
jobs:
#
# Tests for all platforms. Runs a matrix build on Windows, Linux and Mac,
# with the list of expected supported Go versions (current, previous).
#
build-test:
name: Build and test
strategy:
fail-fast: false
matrix:
runner: ["windows-latest", "ubuntu-latest", "macos-latest"]
# The oldest version in this list should match what we have in our go.mod.
# Variables don't seem to be supported here, or we could have done something nice.
go: ["1.20", "1.21"]
runs-on: ${{ matrix.runner }}
steps:
- name: Set git to use LF
if: matrix.runner == 'windows-latest'
# Without this, the Windows checkout will happen with CRLF line
# endings, which is fine for the source code but messes up tests
# that depend on data on disk being as expected. Ideally, those
# tests should be fixed, but not today.
run: |
git config --global core.autocrlf false
git config --global core.eol lf
- uses: actions/checkout@v3
- uses: actions/setup-go@v4
with:
go-version: ${{ matrix.go }}
cache: true
check-latest: true
- name: Build
run: |
go run build.go
- name: Install go-test-json-to-loki
run: |
go install calmh.dev/go-test-json-to-loki@latest
- name: Test
run: |
go run build.go test | go-test-json-to-loki
env:
GOFLAGS: "-json"
LOKI_URL: ${{ secrets.LOKI_URL }}
LOKI_USER: ${{ secrets.LOKI_USER }}
LOKI_PASSWORD: ${{ secrets.LOKI_PASSWORD }}
LOKI_LABELS: "go=${{ matrix.go }},runner=${{ matrix.runner }},repo=${{ github.repository }},ref=${{ github.ref }}"
#
# Meta checks for formatting, copyright, etc
#
correctness:
name: Check correctness
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-go@v4
with:
go-version: ${{ env.GO_VERSION }}
cache: false
check-latest: true
- name: Check correctness
run: |
go test -v ./meta
#
# The basic checks job is a virtual one that depends on the matrix tests,
# the correctness checks, and various builds that we always do. This makes
# it easy to have the PR process have a single test as a gatekeeper for
# merging, instead of having to add all the matrix tests and update them
# each time the version changes. (The top level test is not available for
# choosing there, only the matrix "children".)
#
basics:
name: Basic checks passed
runs-on: ubuntu-latest
needs:
- build-test
- correctness
- package-linux
- package-cross
- package-source
- package-debian
- govulncheck
steps:
- uses: actions/checkout@v3
#
# Windows
#
package-windows:
name: Package for Windows
if: github.event_name == 'push' && (github.ref == 'refs/heads/release' || startsWith(github.ref, 'refs/heads/release-'))
environment: signing
runs-on: windows-latest
steps:
- name: Set git to use LF
# Without this, the checkout will happen with CRLF line endings,
# which is fine for the source code but messes up tests that depend
# on data on disk being as expected. Ideally, those tests should be
# fixed, but not today.
run: |
git config --global core.autocrlf false
git config --global core.eol lf
- uses: actions/checkout@v3
with:
fetch-depth: 0
- uses: actions/setup-go@v4
with:
go-version: ${{ env.GO_VERSION }}
cache: false
check-latest: true
- uses: actions/cache@v3
with:
path: |
~\AppData\Local\go-build
~\go\pkg\mod
key: ${{ runner.os }}-go-${{ env.GO_VERSION }}-package-${{ hashFiles('**/go.sum') }}
- name: Install dependencies
run: |
go install github.com/josephspurrier/goversioninfo/cmd/goversioninfo@v1.4.0
- name: Create packages
run: |
go run build.go -goarch amd64 zip
go run build.go -goarch arm zip
go run build.go -goarch arm64 zip
go run build.go -goarch 386 zip
env:
CGO_ENABLED: "0"
CODESIGN_SIGNTOOL: ${{ secrets.CODESIGN_SIGNTOOL }}
CODESIGN_CERTIFICATE_BASE64: ${{ secrets.CODESIGN_CERTIFICATE_BASE64 }}
CODESIGN_CERTIFICATE_PASSWORD: ${{ secrets.CODESIGN_CERTIFICATE_PASSWORD }}
CODESIGN_TIMESTAMP_SERVER: ${{ secrets.CODESIGN_TIMESTAMP_SERVER }}
- name: Archive artifacts
uses: actions/upload-artifact@v3
with:
name: packages-windows
path: syncthing-windows-*.zip
#
# Linux
#
package-linux:
name: Package for Linux
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
with:
fetch-depth: 0
- uses: actions/setup-go@v4
with:
go-version: ${{ env.GO_VERSION }}
cache: false
check-latest: true
- uses: actions/cache@v3
with:
path: |
~/.cache/go-build
~/go/pkg/mod
key: ${{ runner.os }}-go-${{ env.GO_VERSION }}-package-${{ hashFiles('**/go.sum') }}
- name: Create packages
run: |
archs=$(go tool dist list | grep linux | sed 's#linux/##')
for goarch in $archs ; do
go run build.go -goarch "$goarch" tar
done
env:
CGO_ENABLED: "0"
- name: Archive artifacts
uses: actions/upload-artifact@v3
with:
name: packages-linux
path: syncthing-linux-*.tar.gz
#
# macOS
#
package-macos:
name: Package for macOS
if: github.event_name == 'push' && (github.ref == 'refs/heads/release' || startsWith(github.ref, 'refs/heads/release-'))
environment: signing
runs-on: macos-latest
steps:
- uses: actions/checkout@v3
with:
fetch-depth: 0
- uses: actions/setup-go@v4
with:
go-version: ${{ env.GO_VERSION }}
cache: false
check-latest: true
- uses: actions/cache@v3
with:
path: |
~/.cache/go-build
~/go/pkg/mod
key: ${{ runner.os }}-go-${{ env.GO_VERSION }}-package-${{ hashFiles('**/go.sum') }}
- name: Import signing certificate
run: |
# Set up a run-specific keychain, making it available for the
# `codesign` tool.
umask 066
KEYCHAIN_PATH=$RUNNER_TEMP/codesign.keychain
KEYCHAIN_PASSWORD=$(uuidgen)
security create-keychain -p "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH"
security default-keychain -s "$KEYCHAIN_PATH"
security unlock-keychain -p "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH"
security set-keychain-settings -lut 21600 "$KEYCHAIN_PATH"
# Import the certificate
CERTIFICATE_PATH=$RUNNER_TEMP/codesign.p12
echo "$DEVELOPER_ID_CERTIFICATE_BASE64" | base64 -d -o "$CERTIFICATE_PATH"
security import "$CERTIFICATE_PATH" -k "$KEYCHAIN_PATH" -P "$DEVELOPER_ID_CERTIFICATE_PASSWORD" -T /usr/bin/codesign -T /usr/bin/productsign
security set-key-partition-list -S apple-tool:,apple: -s -k actions "$KEYCHAIN_PATH"
# Set the codesign identity for following steps
echo "CODESIGN_IDENTITY=$CODESIGN_IDENTITY" >> $GITHUB_ENV
env:
DEVELOPER_ID_CERTIFICATE_BASE64: ${{ secrets.DEVELOPER_ID_CERTIFICATE_BASE64 }}
DEVELOPER_ID_CERTIFICATE_PASSWORD: ${{ secrets.DEVELOPER_ID_CERTIFICATE_PASSWORD }}
CODESIGN_IDENTITY: ${{ secrets.CODESIGN_IDENTITY }}
- name: Create package (amd64)
run: |
go run build.go -goarch amd64 zip
env:
CGO_ENABLED: "1"
- name: Create package (arm64 cross)
run: |
cat <<EOT > xgo.sh
#!/bin/bash
CGO_ENABLED=1 \
CGO_CFLAGS="-target arm64-apple-macos10.15" \
CGO_LDFLAGS="-target arm64-apple-macos10.15" \
go "\$@"
EOT
chmod 755 xgo.sh
go run build.go -gocmd ./xgo.sh -goarch arm64 zip
env:
CGO_ENABLED: "1"
- name: Create package (universal)
run: |
rm -rf _tmp
mkdir _tmp
pushd _tmp
unzip ../syncthing-macos-amd64-*.zip
unzip ../syncthing-macos-arm64-*.zip
lipo -create syncthing-macos-amd64-*/syncthing syncthing-macos-arm64-*/syncthing -o syncthing
amd64=(syncthing-macos-amd64-*)
universal="${amd64/amd64/universal}"
mv "$amd64" "$universal"
mv syncthing "$universal"
zip -r "../$universal.zip" "$universal"
- name: Archive artifacts
uses: actions/upload-artifact@v3
with:
name: packages-macos
path: syncthing-*.zip
notarize-macos:
name: Notarize for macOS
if: github.event_name == 'push' && (github.ref == 'refs/heads/release' || startsWith(github.ref, 'refs/heads/release-'))
environment: signing
needs:
- package-macos
- basics
runs-on: macos-latest
steps:
- name: Download artifacts
uses: actions/download-artifact@v3
with:
name: packages-macos
- name: Notarize binaries
run: |
APPSTORECONNECT_API_KEY_PATH="$RUNNER_TEMP/apikey.p8"
echo "$APPSTORECONNECT_API_KEY" | base64 -d -o "$APPSTORECONNECT_API_KEY_PATH"
for file in syncthing-macos-*.zip ; do
xcrun notarytool submit \
-k "$APPSTORECONNECT_API_KEY_PATH" \
-d "$APPSTORECONNECT_API_KEY_ID" \
-i "$APPSTORECONNECT_API_KEY_ISSUER" \
$file
done
env:
APPSTORECONNECT_API_KEY: ${{ secrets.APPSTORECONNECT_API_KEY }}
APPSTORECONNECT_API_KEY_ID: ${{ secrets.APPSTORECONNECT_API_KEY_ID }}
APPSTORECONNECT_API_KEY_ISSUER: ${{ secrets.APPSTORECONNECT_API_KEY_ISSUER }}
#
# Cross compile other unixes
#
package-cross:
name: Package cross compiled
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
with:
fetch-depth: 0
- uses: actions/setup-go@v4
with:
go-version: ${{ env.GO_VERSION }}
cache: false
check-latest: true
- uses: actions/cache@v3
with:
path: |
~/.cache/go-build
~/go/pkg/mod
key: ${{ runner.os }}-go-${{ env.GO_VERSION }}-cross-${{ hashFiles('**/go.sum') }}
- name: Create packages
run: |
platforms=$(go tool dist list \
| grep -v aix/ppc64 \
| grep -v android/ \
| grep -v darwin/ \
| grep -v ios/ \
| grep -v js/ \
| grep -v linux/ \
| grep -v nacl/ \
| grep -v plan9/ \
| grep -v windows/ \
| grep -v /wasm \
)
for plat in $platforms; do
goos="${plat%/*}"
goarch="${plat#*/}"
if ! go run build.go -goos "$goos" -goarch "$goarch" tar ; then
echo "*** $plat failed ***"
fi
done
env:
CGO_ENABLED: "0"
- name: Archive artifacts
uses: actions/upload-artifact@v3
with:
name: packages-other
path: syncthing-*.tar.gz
#
# Source
#
package-source:
name: Package source code
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
with:
fetch-depth: 0
- uses: actions/setup-go@v4
with:
go-version: ${{ env.GO_VERSION }}
cache: false
check-latest: true
- name: Package source
run: |
version=$(go run build.go version)
echo "$version" > RELEASE
go mod vendor
go run build.go assets
cd ..
tar c -z -f "syncthing-source-$version.tar.gz" \
--exclude .git \
syncthing
mv "syncthing-source-$version.tar.gz" syncthing
- name: Archive artifacts
uses: actions/upload-artifact@v3
with:
name: packages-source
path: syncthing-source-*.tar.gz
#
# Sign binaries for auto upgrade, generate ASC signature files
#
sign-for-upgrade:
name: Sign for upgrade
if: github.event_name == 'push' && (github.ref == 'refs/heads/release' || startsWith(github.ref, 'refs/heads/release-'))
environment: signing
needs:
- basics
- package-windows
- package-linux
- package-macos
- package-cross
- package-source
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
with:
fetch-depth: 0
- uses: actions/checkout@v3
with:
repository: syncthing/release-tools
path: tools
fetch-depth: 0
- name: Download artifacts
uses: actions/download-artifact@v3
- name: Install signing tool
run: |
go install ./cmd/stsigtool
- name: Sign archives
run: |
export PRIVATE_KEY="$RUNNER_TEMP/privkey.pem"
export PATH="$PATH:$(go env GOPATH)/bin"
echo "$STSIGTOOL_PRIVATE_KEY" | base64 -d > "$PRIVATE_KEY"
mkdir packages
mv packages-*/* packages
pushd packages
"$GITHUB_WORKSPACE/tools/sign-only"
rm -f "$PRIVATE_KEY"
env:
STSIGTOOL_PRIVATE_KEY: ${{ secrets.STSIGTOOL_PRIVATE_KEY }}
- name: Create and sign .asc files
run: |
sudo apt update
sudo apt -y install gnupg
export SIGNING_KEY="$RUNNER_TEMP/gpg-secret.asc"
echo "$GNUPG_SIGNING_KEY_BASE64" | base64 -d > "$SIGNING_KEY"
gpg --import < "$SIGNING_KEY"
pushd packages
files=(*.tar.gz *.zip)
sha1sum "${files[@]}" | gpg --clearsign > sha1sum.txt.asc
sha256sum "${files[@]}" | gpg --clearsign > sha256sum.txt.asc
gpg --sign --armour --detach syncthing-source-*.tar.gz
popd
rm -f "$SIGNING_KEY" .gnupg
env:
GNUPG_SIGNING_KEY_BASE64: ${{ secrets.GNUPG_SIGNING_KEY_BASE64 }}
- name: Archive artifacts
uses: actions/upload-artifact@v3
with:
name: packages-signed
path: packages/*
#
# Debian
#
package-debian:
name: Package for Debian
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
with:
fetch-depth: 0
- uses: actions/setup-go@v4
with:
go-version: ${{ env.GO_VERSION }}
cache: false
check-latest: true
- uses: ruby/setup-ruby@v1
with:
ruby-version: '3.0'
- name: Install fpm
run: |
gem install fpm
- uses: actions/cache@v3
with:
path: |
~/.cache/go-build
~/go/pkg/mod
key: ${{ runner.os }}-go-${{ env.GO_VERSION }}-debian-${{ hashFiles('**/go.sum') }}
- name: Package for Debian
run: |
for arch in amd64 i386 armhf armel arm64 ; do
go run build.go -no-upgrade -installsuffix=no-upgrade -goarch "$arch" deb
done
env:
BUILD_USER: debian
- name: Archive artifacts
uses: actions/upload-artifact@v3
with:
name: debian-packages
path: "*.deb"
#
# Nightlies
#
publish-nightly:
name: Publish nightly build
if: github.event_name == 'push' && startsWith(github.ref, 'refs/heads/release-nightly')
environment: signing
needs:
- sign-for-upgrade
- notarize-macos
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
with:
repository: syncthing/release-tools
path: tools
fetch-depth: 0
- name: Download artifacts
uses: actions/download-artifact@v3
with:
name: packages-signed
path: packages
- name: Create release json
run: |
cd packages
"$GITHUB_WORKSPACE/tools/generate-release-json" "$BASE_URL" > nightly.json
env:
BASE_URL: https://syncthing.ams3.digitaloceanspaces.com/nightly/
- name: Push artifacts
uses: docker://docker.io/rclone/rclone:latest
env:
RCLONE_CONFIG_SPACES_TYPE: s3
RCLONE_CONFIG_SPACES_PROVIDER: DigitalOcean
RCLONE_CONFIG_SPACES_ACCESS_KEY_ID: ${{ secrets.SPACES_KEY }}
RCLONE_CONFIG_SPACES_SECRET_ACCESS_KEY: ${{ secrets.SPACES_SECRET }}
RCLONE_CONFIG_SPACES_ENDPOINT: ams3.digitaloceanspaces.com
RCLONE_CONFIG_SPACES_ACL: public-read
with:
args: sync packages spaces:syncthing/nightly
#
# Push release artifacts to Spaces
#
publish-release-files:
name: Publish release files
if: github.event_name == 'push' && github.ref == 'refs/heads/release'
environment: signing
needs:
- sign-for-upgrade
- package-debian
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
with:
fetch-depth: 0
- name: Download signed packages
uses: actions/download-artifact@v3
with:
name: packages-signed
path: packages
- name: Download debian packages
uses: actions/download-artifact@v3
with:
name: debian-packages
path: packages
- name: Set version
run: |
version=$(go run build.go version)
echo "VERSION=$version" >> $GITHUB_ENV
- name: Push to Spaces (${{ env.VERSION }})
uses: docker://docker.io/rclone/rclone:latest
env:
RCLONE_CONFIG_SPACES_TYPE: s3
RCLONE_CONFIG_SPACES_PROVIDER: DigitalOcean
RCLONE_CONFIG_SPACES_ACCESS_KEY_ID: ${{ secrets.SPACES_KEY }}
RCLONE_CONFIG_SPACES_SECRET_ACCESS_KEY: ${{ secrets.SPACES_SECRET }}
RCLONE_CONFIG_SPACES_ENDPOINT: ams3.digitaloceanspaces.com
RCLONE_CONFIG_SPACES_ACL: public-read
with:
args: sync packages spaces:syncthing/release/${{ env.VERSION }}
- name: Push to Spaces (latest)
uses: docker://docker.io/rclone/rclone:latest
env:
RCLONE_CONFIG_SPACES_TYPE: s3
RCLONE_CONFIG_SPACES_PROVIDER: DigitalOcean
RCLONE_CONFIG_SPACES_ACCESS_KEY_ID: ${{ secrets.SPACES_KEY }}
RCLONE_CONFIG_SPACES_SECRET_ACCESS_KEY: ${{ secrets.SPACES_SECRET }}
RCLONE_CONFIG_SPACES_ENDPOINT: ams3.digitaloceanspaces.com
RCLONE_CONFIG_SPACES_ACL: public-read
with:
args: sync spaces:syncthing/release/${{ env.VERSION }} spaces:syncthing/release/latest
#
# Build and push to Docker Hub
#
docker-syncthing:
name: Build and push Docker images
runs-on: ubuntu-latest
if: github.event_name == 'push' && (github.ref == 'refs/heads/release' || github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/heads/release-'))
environment: docker
strategy:
matrix:
pkg:
- syncthing
- strelaysrv
- stdiscosrv
include:
- pkg: syncthing
dockerfile: Dockerfile
image: syncthing/syncthing
- pkg: strelaysrv
dockerfile: Dockerfile.strelaysrv
image: syncthing/relaysrv
- pkg: stdiscosrv
dockerfile: Dockerfile.stdiscosrv
image: syncthing/discosrv
steps:
- uses: actions/checkout@v3
with:
fetch-depth: 0
- uses: actions/setup-go@v4
with:
go-version: ${{ env.GO_VERSION }}
cache: false
check-latest: true
- uses: actions/cache@v3
with:
path: |
~/.cache/go-build
~/go/pkg/mod
key: ${{ runner.os }}-go-${{ env.GO_VERSION }}-docker-${{ matrix.pkg }}-${{ hashFiles('**/go.sum') }}
- name: Build binaries
run: |
for arch in amd64 arm64 arm; do
go run build.go -goos linux -goarch "$arch" -no-upgrade build ${{ matrix.pkg }}
mv ${{ matrix.pkg }} ${{ matrix.pkg }}-linux-"$arch"
done
env:
CGO_ENABLED: "0"
BUILD_USER: docker
- name: Check if we will be able to push images
run: |
if [[ "${{ secrets.DOCKERHUB_TOKEN }}" != "" ]]; then
echo "DOCKER_PUSH=true" >> $GITHUB_ENV;
fi
- name: Login to Docker Hub
uses: docker/login-action@v2
if: env.DOCKER_PUSH == 'true'
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2
- name: Set version tags
run: |
version=$(go run build.go version)
version=${version#v}
if [[ $version == @([0-9]|[0-9][0-9]).@([0-9]|[0-9][0-9]).@([0-9]|[0-9][0-9]) ]] ; then
echo Release version, pushing to :latest and version tags
major=${version%.*.*}
minor=${version%.*}
tags=${{ matrix.image }}:$version,${{ matrix.image }}:$major,${{ matrix.image }}:$minor,${{ matrix.image }}:latest
elif [[ $version == *-rc.@([0-9]|[0-9][0-9]) ]] ; then
echo Release candidate, pushing to :rc
tags=${{ matrix.image }}:rc
else
echo Development version, pushing to :edge
tags=${{ matrix.image }}:edge
fi
echo "DOCKER_TAGS=$tags" >> $GITHUB_ENV
- name: Build and push Docker image
uses: docker/build-push-action@v4
with:
context: .
file: ${{ matrix.dockerfile }}
platforms: linux/amd64,linux/arm64,linux/arm/7
push: ${{ env.DOCKER_PUSH == 'true' }}
tags: ${{ env.DOCKER_TAGS }}
#
# Check for known vulnerabilities in Go dependencies
#
govulncheck:
runs-on: ubuntu-latest
name: Run govulncheck
steps:
- uses: actions/checkout@v3
- uses: actions/setup-go@v4
with:
go-version: ${{ env.GO_VERSION }}
cache: false
check-latest: true
- name: run govulncheck
run: |
go run build.go assets
go install golang.org/x/vuln/cmd/govulncheck@latest
govulncheck ./...

21
.github/workflows/trigger-nightly.yaml vendored Normal file
View File

@@ -0,0 +1,21 @@
name: Trigger nightly build & release
on:
workflow_dispatch:
schedule:
# Run nightly build at 01:00 UTC
- cron: '00 01 * * *'
jobs:
trigger-nightly:
runs-on: ubuntu-latest
name: Push to release-nightly to trigger build
steps:
- uses: actions/checkout@v3
with:
token: ${{ secrets.ACTIONS_GITHUB_TOKEN }}
fetch-depth: 0
- run: |
git push origin main:release-nightly

View File

@@ -0,0 +1,28 @@
name: Update translations and documentation
on:
workflow_dispatch:
schedule:
- cron: '42 3 * * 1'
jobs:
update_transifex_docs:
runs-on: ubuntu-latest
name: Update translations and documentation
steps:
- uses: actions/checkout@v3
with:
fetch-depth: 0
token: ${{ secrets.ACTIONS_GITHUB_TOKEN }}
- uses: actions/setup-go@v4
with:
go-version: ^1.19.6
- run: |
set -euo pipefail
git config --global user.name 'Syncthing Release Automation'
git config --global user.email 'release@syncthing.net'
bash build.sh translate
bash build.sh prerelease
git push
env:
WEBLATE_TOKEN: ${{ secrets.WEBLATE_TOKEN }}

2
.gitignore vendored
View File

@@ -18,3 +18,5 @@ deb
*.bz2
/repos
/proto/scripts/protoc-gen-gosyncthing
/gui/next-gen-gui
.idea

4
.yamlfmt Normal file
View File

@@ -0,0 +1,4 @@
line_ending: lf
formatter:
type: basic
retain_line_breaks: true

73
AUTHORS
View File

@@ -18,24 +18,32 @@ Adam Piggott (ProactiveServices) <aD@simplypeachy.co.uk> <simplypeachy@users.nor
Adel Qalieh (adelq) <aqalieh95@gmail.com> <adelq@users.noreply.github.com>
Alan Pope <alan@popey.com>
Alberto Donato <albertodonato@users.noreply.github.com>
Aleksey Vasenev <margtu-fivt@ya.ru>
Alessandro G. (alessandro.g89) <alessandro.g89@gmail.com>
Alex Lindeman <139387+aelindeman@users.noreply.github.com>
Alex Xu <alex.hello71@gmail.com>
Alexander Graf (alex2108) <register-github@alex-graf.de>
Alexander Seiler <seileralex@gmail.com>
Alexandre Alves <alexandrealvesdb.contact@gmail.com>
Alexandre Viau (aviau) <alexandre@alexandreviau.net> <aviau@debian.org>
Aman Gupta <aman@tmm1.net>
Anderson Mesquita (andersonvom) <andersonvom@gmail.com>
Andreas Sommer <andreas.sommer87@googlemail.com>
andresvia <andres.via@gmail.com>
Andrew Dunham (andrew-d) <andrew@du.nham.ca>
Andrew Meyer <andrewm.bpi@gmail.com>
Andrew Rabert (nvllsvm) <ar@nullsum.net> <6550543+nvllsvm@users.noreply.github.com>
Andrey D (scienmind) <scintertech@cryptolab.net> <scienmind@users.noreply.github.com>
André Colomb (acolomb) <src@andre.colomb.de> <github.com@andre.colomb.de>
andyleap <andyleap@gmail.com>
Anjan Momi <anjan@momi.ca>
Anthony Goeckner <agoeckner@users.noreply.github.com>
Antoine Lamielle (0x010C) <antoine.lamielle@0x010c.fr> <gh@0x010c.fr>
Antony Male (canton7) <antony.male@gmail.com>
Anur <anurnomeru@163.com>
Aranjedeath <Aranjedeath@users.noreply.github.com>
Arkadiusz Tymiński <gevleeog@gmail.com>
Aroun <login@b-vo.fr>
Arthur Axel fREW Schmidt (frioux) <frew@afoolishmanifesto.com> <frioux@gmail.com>
Artur Zubilewicz <AkaZecik@users.noreply.github.com>
Audrius Butkevicius (AudriusButkevicius) <audrius.butkevicius@gmail.com> <github@audrius.rocks>
@@ -48,6 +56,7 @@ Ben Shepherd (benshep) <bjashepherd@gmail.com>
Ben Sidhom (bsidhom) <bsidhom@gmail.com>
Benedikt Heine (bebehei) <bebe@bebehei.de>
Benedikt Morbach <benedikt.morbach@googlemail.com>
Benjamin Nater <17193640+bn4t@users.noreply.github.com>
Benno Fünfstück <benno.fuenfstueck@gmail.com>
Benny Ng (tpng) <benny.tpng@gmail.com>
boomsquared <54829195+boomsquared@users.noreply.github.com>
@@ -56,51 +65,71 @@ Boris Rybalkin <ribalkin@gmail.com>
Brandon Philips (philips) <brandon@ifup.org>
Brendan Long (brendanlong) <self@brendanlong.com>
Brian R. Becker (brbecker) <brbecker@gmail.com>
bt90 <btom1990@googlemail.com>
Caleb Callaway (cqcallaw) <enlightened.despot@gmail.com>
Carsten Hagemann (carstenhag) <moter8@gmail.com> <carsten@chagemann.de>
Cathryne Linenweaver (Cathryne) <cathryne.linenweaver@gmail.com> <Cathryne@users.noreply.github.com> <katrinleinweber@MAC.local>
Cedric Staniewski (xduugu) <cedric@gmx.ca>
chenrui <rui@meetup.com>
Chih-Hsuan Yen <yan12125@gmail.com> <1937689+yan12125@users.noreply.github.com>
Choongkyu <choongkyu.kim+gh@gmail.com> <vapidlyrapid+gh@gmail.com>
Chris Howie (cdhowie) <me@chrishowie.com>
Chris Joel (cdata) <chris@scriptolo.gy>
Chris Tonkinson <chris@masterbran.ch>
Christian Kujau <ckujau@users.noreply.github.com>
Christian Prescott <me@christianprescott.com>
chucic <chucic@seznam.cz>
Colin Kennedy (moshen) <moshen.colin@gmail.com>
Cromefire_ <tim.l@nghorst.net> <26320625+cromefire@users.noreply.github.com>
cui fliter <imcusg@gmail.com>
Cyprien Devillez <cypx@users.noreply.github.com>
Dale Visser <dale.visser@live.com>
Dan <benda.daniel@gmail.com>
Daniel Barczyk <46358936+DanielBarczyk@users.noreply.github.com>
Daniel Bergmann (brgmnn) <dan.arne.bergmann@gmail.com> <brgmnn@users.noreply.github.com>
Daniel Harte (norgeous) <daniel@harte.me> <daniel@danielharte.co.uk> <norgeous@users.noreply.github.com>
Daniel Martí (mvdan) <mvdan@mvdan.cc>
Darshil Chanpura (dtchanpura) <dtchanpura@gmail.com> <dcprime314@gmail.com>
David Rimmer (dinosore) <dinosore@dbrsoftware.co.uk>
deepsource-autofix[bot] <62050782+deepsource-autofix[bot]@users.noreply.github.com>
Denis A. (dva) <denisva@gmail.com>
Dennis Wilson (snnd) <dw@risu.io>
dependabot-preview[bot] <dependabot-preview[bot]@users.noreply.github.com> <27856297+dependabot-preview[bot]@users.noreply.github.com>
dependabot[bot] <dependabot[bot]@users.noreply.github.com>
dependabot[bot] <dependabot[bot]@users.noreply.github.com> <49699333+dependabot[bot]@users.noreply.github.com>
derekriemer <derek.riemer@colorado.edu>
desbma <desbma@users.noreply.github.com>
Devon G. Redekopp <devon@redekopp.com>
Dimitri Papadopoulos Orfanos <3234522+DimitriPapadopoulos@users.noreply.github.com>
Dmitry Saveliev (dsaveliev) <d.e.saveliev@gmail.com>
Domenic Horner <domenic@tgxn.net>
Dominik Heidler (asdil12) <dominik@heidler.eu>
Elias Jarlebring (jarlebring) <jarlebring@gmail.com>
Elliot Huffman <thelich2@gmail.com>
Emil Hessman (ceh) <emil@hessman.se>
Emil Lundberg <emil@emlun.se>
Eng Zer Jun <engzerjun@gmail.com>
entity0xfe <109791748+entity0xfe@users.noreply.github.com> <entity0xfe@my.domain>
Eric Lesiuta <elesiuta@gmail.com>
Eric P <eric@kastelo.net>
Erik Meitner (WSGCSysadmin) <e.meitner@willystreet.coop>
Evan Spensley <94762716+0evan@users.noreply.github.com>
Evgeny Kuznetsov <evgeny@kuznetsov.md>
Federico Castagnini (facastagnini) <federico.castagnini@gmail.com>
Felix <53702818+f-eliks@users.noreply.github.com>
Felix Ableitner (Nutomic) <me@nutomic.com>
Felix Lampe <mail@flampe.de>
Felix Unterpaintner (bigbear2nd) <bigbear2nd@gmail.com>
Francois-Xavier Gsell (zukoo) <fxgsell@gmail.com>
Frank Isemann (fti7) <frank@isemann.name>
Gahl Saraf <saraf.gahl@gmail.com> <gahl@raftt.io>
georgespatton <georgespatton@users.noreply.github.com>
ghjklw <malo@jaffre.info>
Gilli Sigurdsson (gillisig) <gilli@vx.is>
Gleb Sinyavskiy <zhulik.gleb@gmail.com>
Graham Miln (grahammiln) <graham.miln@dssw.co.uk> <graham.miln@miln.eu>
greatroar <61184462+greatroar@users.noreply.github.com>
Greg <gco@jazzhaiku.com>
guangwu <guoguangwu@magic-shield.com>
Han Boetes <han@boetes.org>
HansK-p <42314815+HansK-p@users.noreply.github.com>
Harrison Jones (harrisonhjones) <harrisonhjones@users.noreply.github.com>
@@ -108,6 +137,8 @@ Heiko Zuerker (Smiley73) <heiko@zuerker.org>
Hugo Locurcio <hugo.locurcio@hugo.pro>
Iain Barnett <iainspeed@gmail.com>
Ian Johnson (anonymouse64) <ian.johnson@canonical.com> <person.uwsome@gmail.com>
ignacy123 <ignacy.buczek@onet.pl>
Ikko Ashimine <eltociear@gmail.com>
Ilya Brin <464157+ilyabrin@users.noreply.github.com>
Iskander Sharipov (Alex) <quasilyte@gmail.com>
Jaakko Hannikainen (jgke) <jgke@jgke.fi>
@@ -116,27 +147,37 @@ Jack Croft <jccroft1@users.noreply.github.com>
Jacob <jyundt@gmail.com>
Jake Peterson (acogdev) <jake@acogdev.com>
Jakob Borg (calmh) <jakob@nym.se> <jakob@kastelo.net>
James O'Beirne <wild-github@au92.org>
James Patterson (jpjp) <jamespatterson@operamail.com> <jpjp@users.noreply.github.com>
janost <janost@tuta.io>
Jaroslav Lichtblau <svetlemodry@users.noreply.github.com>
Jaroslav Malec (dzarda) <dzardacz@gmail.com>
jaseg <githubaccount@jaseg.net>
Jauder Ho <jauderho@users.noreply.github.com>
Jaya Chithra (jayachithra) <s.k.jayachithra@gmail.com>
Jaya Kumar <jaya.kumar@ict.nl>
Jeffery To <jeffery.to@gmail.com>
jelle van der Waa <jelle@vdwaa.nl>
Jens Diemer (jedie) <github.com@jensdiemer.de> <git@jensdiemer.de>
Jerry Jacobs (xor-gate) <jerry.jacobs@xor-gate.org> <xor-gate@users.noreply.github.com>
Jesse Lucas <jesse@jesselucas.com>
Jochen Voss (seehuhn) <voss@seehuhn.de>
Johan Andersson <j@i19.se>
Johan Vromans (sciurius) <jvromans@squirrel.nl>
John Rinehart (fuzzybear3965) <johnrichardrinehart@gmail.com>
Jonas Thelemann <e-mail@jonas-thelemann.de>
Jonathan <artback@protonmail.com>
Jonathan <artback@protonmail.com> <jonagn@gmail.com>
Jonathan Cross <jcross@gmail.com>
Jonta <359397+Jonta@users.noreply.github.com>
Jose Manuel Delicado (jmdaweb) <jmdaweb@hotmail.com> <jmdaweb@users.noreply.github.com>
jtagcat <git-514635f7@jtag.cat> <git-12dbd862@jtag.cat>
Jörg Thalheim <Mic92@users.noreply.github.com>
Jędrzej Kula <kula.jedrek@gmail.com>
K.B.Dharun Krishna <kbdharunkrishna@gmail.com>
Kalle Laine <pahakalle@protonmail.com>
Karol Różycki (krozycki) <rozycki.karol@gmail.com>
Kebin Liu <lkebin@gmail.com>
Keith Harrison <keithh@protonmail.com>
Keith Turner <kturner@apache.org>
Kelong Cong (kc1212) <kc04bc@gmx.com> <kc1212@users.noreply.github.com>
Ken'ichi Kamada (kamadak) <kamada@nanohz.org>
@@ -146,13 +187,16 @@ Kevin White, Jr. (kwhite17) <kevinwhite1710@gmail.com>
klemens <ka7@github.com>
Kurt Fitzner (Kudalufi) <kurt@va1der.ca> <kurt.fitzner@gmail.com>
Lars K.W. Gohlke (lkwg82) <lkwg82@gmx.de>
Lars Lehtonen <lars.lehtonen@gmail.com>
Laurent Arnoud <laurent@spkdev.net>
Laurent Etiemble (letiemble) <laurent.etiemble@gmail.com> <laurent.etiemble@monobjc.net>
Leo Arias (elopio) <yo@elopio.net>
Liu Siyuan (liusy182) <liusy182@gmail.com> <liusy182@hotmail.com>
Lode Hoste (Zillode) <zillode@zillode.be>
Lord Landon Agahnim (LordLandon) <lordlandon@gmail.com>
LSmithx2 <42276854+lsmithx2@users.noreply.github.com>
Lukas Lihotzki <lukas@lihotzki.de>
luzpaz <luzpaz@users.noreply.github.com>
Majed Abdulaziz (majedev) <majed.alhajry@gmail.com>
Marc Laporte (marclaporte) <marc@marclaporte.com> <marc@laporte.name>
Marc Pujol (kilburn) <kilburn@la3.org>
@@ -161,6 +205,7 @@ marco-m <marco.molteni@laposte.net>
Marcus Legendre <marcus.legendre@gmail.com>
Mario Majila <mariustshipichik@gmail.com>
Mark Pulford (mpx) <mark@kyne.com.au>
Martchus <martchus@gmx.net>
Mateusz Naściszewski (mateon1) <matin1111@wp.pl>
Mateusz Ż <thedead4fun@live.com>
Matic Potočnik <hairyfotr@gmail.com>
@@ -168,20 +213,26 @@ Matt Burke (burkemw3) <mburke@amplify.com> <burkemw3@gmail.com>
Matt Robenolt <matt@ydekproductions.com>
Matteo Ruina <matteo.ruina@gmail.com>
Maurizio Tomasi <ziotom78@gmail.com>
Max <github@germancoding.com>
Max Schulze (kralo) <max.schulze@online.de> <kralo@users.noreply.github.com>
MaximAL <almaximal@ya.ru>
Maxime Thirouin <m@moox.io>
mclang <1721600+mclang@users.noreply.github.com>
Michael Jephcote (Rewt0r) <rewt0r@gmx.com> <Rewt0r@users.noreply.github.com>
Michael Ploujnikov (plouj) <ploujj@gmail.com>
Michael Rienstra <mrienstra@gmail.com>
Michael Tilli (pyfisch) <pyfisch@gmail.com>
MichaIng <micha@dietpi.com>
Migelo <miha@filetki.si>
Mike Boone <mike@boonedocks.net>
MikeLund <MikeLund@users.noreply.github.com>
MikolajTwarog <43782609+MikolajTwarog@users.noreply.github.com>
Mingxuan Lin <gdlmx@users.noreply.github.com>
mv1005 <49659413+mv1005@users.noreply.github.com>
Nate Morrison (nrm21) <natemorrison@gmail.com>
Naveen <172697+naveensrinivasan@users.noreply.github.com>
Nicholas Rishel (PrototypeNM1) <rishel.nick@gmail.com> <PrototypeNM1@users.noreply.github.com>
Nick Busey <NickBusey@users.noreply.github.com>
Nico Stapelbroek <3368018+nstapelbroek@users.noreply.github.com>
Nicolas Braud-Santoni <nicolas@braud-santoni.eu>
Nicolas Perraut <n.perraut@gmail.com>
@@ -193,6 +244,7 @@ NoLooseEnds <jon.koslung@gmail.com>
Oliver Freyermuth <o.freyermuth@googlemail.com>
otbutz <tbutz@optitool.de>
Otiel <Otiel@users.noreply.github.com>
overkill <22098433+0verk1ll@users.noreply.github.com>
Oyebanji Jacob Mayowa <oyebanji05@gmail.com>
Pablo <pbaeyens31+github@gmail.com>
Pascal Jungblut (pascalj) <github@pascalj.com> <mail@pascal-jungblut.com>
@@ -211,25 +263,33 @@ Phill Luby (pluby) <phill.luby@newredo.com>
Pier Paolo Ramon <ramonpierre@gmail.com>
Piotr Bejda (piobpl) <piotrb10@gmail.com>
Pramodh KP (pramodhkp) <pramodh.p@directi.com> <1507241+pramodhkp@users.noreply.github.com>
Quentin Hibon <qh.public@yahoo.com>
Rahmi Pruitt <rjpruitt16@gmail.com>
red_led <red-led@users.noreply.github.com>
Richard Hartmann <RichiH@users.noreply.github.com>
Robert Carosi (nov1n) <robert@carosi.nl>
Roberto Santalla <roobre@users.noreply.github.com>
Robin Schoonover <robin@cornhooves.org>
Roman Zaynetdinov (zaynetro) <romanznet@gmail.com>
Ross Smith II (rasa) <ross@smithii.com>
rubenbe <github-com-00ff86@vandamme.email>
Ruslan Yevdokymov <38809160+ruslanye@users.noreply.github.com>
Ryan Qian <i@bitbili.net>
Ryan Sullivan (KayoticSully) <kayoticsully@gmail.com>
Sacheendra Talluri (sacheendra) <sacheendra.t@gmail.com>
Scott Klupfel (kluppy) <kluppy@going2blue.com>
sec65 <106604020+sec65@users.noreply.github.com>
Sergey Mishin (ralder) <ralder@yandex.ru>
Shaarad Dalvi <60266155+shaaraddalvi@users.noreply.github.com>
Shaarad Dalvi <60266155+shaaraddalvi@users.noreply.github.com> <shdalv@microsoft.com>
Simon Frei (imsodin) <freisim93@gmail.com>
Simon Mwepu <simonmwepu@gmail.com>
Sly_tom_cat <slytomcat@mail.ru>
Stefan Kuntz (Stefan-Code) <stefan.github@gmail.com> <Stefan.github@gmail.com>
Stefan Tatschner (rumpelsepp) <stefan@sevenbyte.org> <rumpelsepp@sevenbyte.org> <stefan@rumpelsepp.org>
Steven Eckhoff <steven.eckhoff.opensource@gmail.com>
Suhas Gundimeda (snugghash) <suhas.gundimeda@gmail.com> <snugghash@gmail.com>
Syncthing Automation <automation@syncthing.net>
Syncthing Release Automation <release@syncthing.net>
Taylor Khan (nelsonkhan) <nelsonkhan@gmail.com>
Thomas Hipp <thomashipp@gmail.com>
Tim Abell (timabell) <tim@timwise.co.uk>
@@ -246,13 +306,18 @@ Tyler Kropp <kropptyler@gmail.com>
Unrud (Unrud) <unrud@openaliasbox.org> <Unrud@users.noreply.github.com>
Veeti Paananen (veeti) <veeti.paananen@rojekti.fi>
Victor Buinsky (buinsky) <vix_booja@tut.by>
Vik <63919734+ViktorOn@users.noreply.github.com>
Vil Brekin (Vilbrekin) <vilbrekin@gmail.com>
Vladimir Rusinov <vrusinov@google.com>
villekalliomaki <53118179+villekalliomaki@users.noreply.github.com>
Vladimir Rusinov <vrusinov@google.com> <vladimir.rusinov@gmail.com>
wangguoliang <liangcszzu@163.com>
Will Rouesnel <wrouesnel@wrouesnel.com>
William A. Kennington III (wkennington) <william@wkennington.com>
wouter bolsterlee <wouter@bolsterl.ee>
Wulf Weich (wweich) <wweich@users.noreply.github.com> <wweich@gmx.de> <wulf@weich-kr.de>
xarx00 <xarx00@users.noreply.github.com>
Xavier O. (damajor) <damajor@gmail.com>
xjtdy888 (xjtdy888) <xjtdy888@163.com>
Yannic A. (eipiminus1) <eipiminusone+github@gmail.com> <eipiminus1@users.noreply.github.com>
佛跳墙 <daoquan@qq.com>
落心 <luoxin.ttt@gmail.com>

View File

@@ -1,6 +1,6 @@
## Reporting Bugs
Please file bugs in the [Github Issue
Please file bugs in the [GitHub Issue
Tracker](https://github.com/syncthing/syncthing/issues). Include at
least the following:
@@ -24,10 +24,15 @@ too much information will never get you yelled at. :)
## Contributing Translations
All translations are done via
[Transifex](https://www.transifex.com/projects/p/syncthing/). If you
wish to contribute to a translation, just head over there and sign up.
[Weblate](https://hosted.weblate.org/projects/syncthing/). If you wish
to contribute to a translation, just head over there and sign up.
Before every release, the language resources are updated from the
latest info on Transifex.
latest info on Weblate.
Note that the previously used service at
[Transifex](https://www.transifex.com/projects/p/syncthing/) is being
retired and we kindly ask you to sign up on Weblate for continued
involvement.
## Contributing Code

View File

@@ -1,29 +1,49 @@
ARG GOVERSION=latest
#
# Maybe build Syncthing. This is a bit ugly as we can't make an entire
# section of the Dockerfile conditional, so we end up always pulling the
# golang image as builder. Then we check if the executable we need already
# exists (pre-built) otherwise we build it.
#
FROM golang:$GOVERSION AS builder
ARG BUILD_USER
ARG BUILD_HOST
ARG TARGETARCH
WORKDIR /src
COPY . .
ENV CGO_ENABLED=0
ENV BUILD_HOST=syncthing.net
ENV BUILD_USER=docker
RUN rm -f syncthing && go run build.go -no-upgrade build syncthing
RUN if [ ! -f syncthing-linux-$TARGETARCH ] ; then \
go run build.go -no-upgrade build syncthing ; \
mv syncthing syncthing-linux-$TARGETARCH ; \
fi
#
# The rest of the Dockerfile uses the binary from the builder, prebuilt or
# not.
#
FROM alpine
ARG TARGETARCH
EXPOSE 8384 22000 21027/udp
EXPOSE 8384 22000/tcp 22000/udp 21027/udp
VOLUME ["/var/syncthing"]
RUN apk add --no-cache ca-certificates su-exec tzdata
RUN apk add --no-cache ca-certificates curl libcap su-exec tzdata
COPY --from=builder /src/syncthing /bin/syncthing
COPY --from=builder /src/syncthing-linux-$TARGETARCH /bin/syncthing
COPY --from=builder /src/script/docker-entrypoint.sh /bin/entrypoint.sh
ENV PUID=1000 PGID=1000 HOME=/var/syncthing
HEALTHCHECK --interval=1m --timeout=10s \
CMD nc -z 127.0.0.1 8384 || exit 1
CMD curl -fkLsS -m 2 127.0.0.1:8384/rest/noauth/health | grep -o --color=never OK || exit 1
ENV STGUIADDRESS=0.0.0.0:8384
ENTRYPOINT ["/bin/entrypoint.sh", "/bin/syncthing", "-home", "/var/syncthing/config"]
ENV STHOMEDIR=/var/syncthing/config
RUN chmod 755 /bin/entrypoint.sh
ENTRYPOINT ["/bin/entrypoint.sh", "/bin/syncthing"]

View File

@@ -6,4 +6,4 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
locales rubygems ruby-dev build-essential git \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/* \
&& gem install --no-ri --no-rdoc fpm
&& gem install fpm

View File

@@ -1,19 +0,0 @@
FROM alpine
ARG TARGETARCH
EXPOSE 8384 22000 21027/udp
VOLUME ["/var/syncthing"]
RUN apk add --no-cache ca-certificates su-exec tzdata
COPY ./syncthing-linux-$TARGETARCH /bin/syncthing
COPY ./script/docker-entrypoint.sh /bin/entrypoint.sh
ENV PUID=1000 PGID=1000 HOME=/var/syncthing
HEALTHCHECK --interval=1m --timeout=10s \
CMD nc -z 127.0.0.1 8384 || exit 1
ENV STGUIADDRESS=0.0.0.0:8384
ENTRYPOINT ["/bin/entrypoint.sh", "/bin/syncthing", "-home", "/var/syncthing/config"]

View File

@@ -0,0 +1,8 @@
FROM alpine
ARG TARGETARCH
EXPOSE 8080
COPY stcrashreceiver-linux-${TARGETARCH} /bin/stcrashreceiver
ENTRYPOINT [ "/bin/stcrashreceiver" ]

View File

@@ -1,15 +1,20 @@
ARG GOVERSION=latest
FROM golang:$GOVERSION AS builder
ARG BUILD_USER
ARG BUILD_HOST
ARG TARGETARCH
WORKDIR /src
COPY . .
ENV CGO_ENABLED=0
ENV BUILD_HOST=syncthing.net
ENV BUILD_USER=docker
RUN rm -f stdiscosrv && go run build.go -no-upgrade build stdiscosrv
RUN if [ ! -f stdiscosrv-linux-$TARGETARCH ] ; then \
go run build.go -no-upgrade build stdiscosrv ; \
mv stdiscosrv stdiscosrv-linux-$TARGETARCH ; \
fi
FROM alpine
ARG TARGETARCH
EXPOSE 19200 8443
@@ -17,7 +22,7 @@ VOLUME ["/var/stdiscosrv"]
RUN apk add --no-cache ca-certificates su-exec
COPY --from=builder /src/stdiscosrv /bin/stdiscosrv
COPY --from=builder /src/stdiscosrv-linux-$TARGETARCH /bin/stdiscosrv
COPY --from=builder /src/script/docker-entrypoint.sh /bin/entrypoint.sh
ENV PUID=1000 PGID=1000 HOME=/var/stdiscosrv

16
Dockerfile.strelaypoolsrv Normal file
View File

@@ -0,0 +1,16 @@
FROM alpine
ARG TARGETARCH
EXPOSE 8080
RUN apk add --no-cache ca-certificates su-exec curl
ENV PUID=1000 PGID=1000 MAXMIND_KEY=
RUN mkdir /var/strelaypoolsrv && chown 1000 /var/strelaypoolsrv
USER 1000
COPY strelaypoolsrv-linux-${TARGETARCH} /bin/strelaypoolsrv
COPY script/strelaypoolsrv-entrypoint.sh /bin/entrypoint.sh
WORKDIR /var/strelaypoolsrv
ENTRYPOINT ["/bin/entrypoint.sh", "/bin/strelaypoolsrv", "-listen", ":8080"]

View File

@@ -1,15 +1,20 @@
ARG GOVERSION=latest
FROM golang:$GOVERSION AS builder
ARG BUILD_USER
ARG BUILD_HOST
ARG TARGETARCH
WORKDIR /src
COPY . .
ENV CGO_ENABLED=0
ENV BUILD_HOST=syncthing.net
ENV BUILD_USER=docker
RUN rm -f strelaysrv && go run build.go -no-upgrade build strelaysrv
RUN if [ ! -f strelaysrv-linux-$TARGETARCH ] ; then \
go run build.go -no-upgrade build strelaysrv ; \
mv strelaysrv strelaysrv-linux-$TARGETARCH ; \
fi
FROM alpine
ARG TARGETARCH
EXPOSE 22067 22070
@@ -17,7 +22,7 @@ VOLUME ["/var/strelaysrv"]
RUN apk add --no-cache ca-certificates su-exec
COPY --from=builder /src/strelaysrv /bin/strelaysrv
COPY --from=builder /src/strelaysrv-linux-$TARGETARCH /bin/strelaysrv
COPY --from=builder /src/script/docker-entrypoint.sh /bin/entrypoint.sh
ENV PUID=1000 PGID=1000 HOME=/var/strelaysrv

8
Dockerfile.stupgrades Normal file
View File

@@ -0,0 +1,8 @@
FROM alpine
ARG TARGETARCH
EXPOSE 8080
COPY stupgrades-linux-${TARGETARCH} /bin/stupgrades
ENTRYPOINT [ "/bin/stupgrades" ]

View File

@@ -57,7 +57,7 @@ latest technology is not always available to any given individual.
> Computers include desktops, laptops, servers, virtual machines, small
> general purpose computers such as Raspberry Pis and, *where possible*,
> tablets and phones. NAS appliances, toasters, cars, firearms, thermostats
> and so on may include computing capabitilies but it is not our goal for
> and so on may include computing capabilities but it is not our goal for
> Syncthing to run smoothly on these devices.
### 6. For Individuals

View File

@@ -7,25 +7,57 @@ Use the `/var/syncthing` volume to have the synchronized files available on the
host. You can add more folders and map them as you prefer.
Note that Syncthing runs as UID 1000 and GID 1000 by default. These may be
altered with the ``PUID`` and ``PGID`` environment variables.
altered with the `PUID` and `PGID` environment variables. In addition
the name of the Syncthing instance can be optionally defined by using
`--hostname=syncthing` parameter.
To grant Syncthing additional capabilities without running as root, use the
`PCAP` environment variable with the same syntax as that for `setcap(8)`.
For example, `PCAP=cap_chown,cap_fowner+ep`.
## Example Usage
**Docker cli**
```
$ docker pull syncthing/syncthing
$ docker run -p 8384:8384 -p 22000:22000 \
$ 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
```
## Discovery
Note that local device discovery will not work with the above command,
resulting in poor local transfer rates if local device addresses are not
manually configured.
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.
To allow local discovery, the docker host network can be used instead:
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 \
@@ -33,6 +65,24 @@ $ docker run --network=host \
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
network_mode: host
restart: unless-stopped
```
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.

View File

@@ -2,9 +2,6 @@
---
[![Latest Linux & Cross Build](https://img.shields.io/teamcity/https/build.syncthing.net/s/Syncthing_BuildLinuxCross.svg?style=flat-square&label=linux+%26+cross+build)](https://build.syncthing.net/viewType.html?buildTypeId=Syncthing_BuildLinuxCross&guest=1)
[![Latest Windows Build](https://img.shields.io/teamcity/https/build.syncthing.net/s/Syncthing_BuildWindows.svg?style=flat-square&label=windows+build)](https://build.syncthing.net/viewType.html?buildTypeId=Syncthing_BuildWindows&guest=1)
[![Latest Mac Build](https://img.shields.io/teamcity/https/build.syncthing.net/s/Syncthing_BuildMac.svg?style=flat-square&label=mac+build)](https://build.syncthing.net/viewType.html?buildTypeId=Syncthing_BuildMac&guest=1)
[![MPLv2 License](https://img.shields.io/badge/license-MPLv2-blue.svg?style=flat-square)](https://www.mozilla.org/MPL/2.0/)
[![CII Best Practices](https://bestpractices.coreinfrastructure.org/projects/88/badge)](https://bestpractices.coreinfrastructure.org/projects/88)
[![Go Report Card](https://goreportcard.com/badge/github.com/syncthing/syncthing)](https://goreportcard.com/report/github.com/syncthing/syncthing)
@@ -73,15 +70,16 @@ This helps the team understand what are the biggest pain points for our users, a
## Getting in Touch
The first and best point of contact is the [Forum][8]. There is also an IRC
channel, `#syncthing` on [freenode][4] (with a [web client][9]), for talking
directly to developers and users. If you've found something that is clearly a
The first and best point of contact is the [Forum][8].
If you've found something that is clearly a
bug, feel free to report it in the [GitHub issue tracker][10].
## Building
Building Syncthing from source is easy, and there's a [guide][5]
that describes it for both Unix and Windows systems.
Building Syncthing from source is easy. After extracting the source bundle from
a release or checking out git, you just need to run `go run build.go` and the
binaries are created in `./bin`. There's [a guide][5] with more details on the
build process.
## Signed Releases
@@ -95,19 +93,17 @@ binaries are also properly code signed.
## Documentation
Please see the [Syncthing documentation site][6].
Please see the Syncthing [documentation site][6] [[source]][17].
All code is licensed under the [MPLv2 License][7].
[1]: https://docs.syncthing.net/specs/bep-v1.html
[2]: https://docs.syncthing.net/intro/getting-started.html
[3]: https://github.com/syncthing/syncthing/blob/main/etc
[4]: https://www.freenode.net/
[5]: https://docs.syncthing.net/dev/building.html
[6]: https://docs.syncthing.net/
[7]: https://github.com/syncthing/syncthing/blob/main/LICENSE
[8]: https://forum.syncthing.net/
[9]: https://kiwiirc.com/client/irc.freenode.net/#syncthing
[10]: https://github.com/syncthing/syncthing/issues
[11]: https://docs.syncthing.net/users/contrib.html#gui-wrappers
[12]: https://www.bountysource.com/teams/syncthing/issues
@@ -115,4 +111,4 @@ All code is licensed under the [MPLv2 License][7].
[14]: assets/logo-text-128.png
[15]: https://syncthing.net/
[16]: https://github.com/syncthing/syncthing/blob/main/README-Docker.md
[17]: https://github.com/syncthing/docs

371
build.go
View File

@@ -4,6 +4,7 @@
// 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/.
//go:build ignore
// +build ignore
package main
@@ -14,13 +15,12 @@ import (
"bytes"
"compress/flate"
"compress/gzip"
"crypto/sha256"
"encoding/base64"
"encoding/json"
"errors"
"flag"
"fmt"
"io"
"io/ioutil"
"log"
"os"
"os/exec"
@@ -30,27 +30,34 @@ import (
"runtime"
"strconv"
"strings"
"text/template"
"time"
buildpkg "github.com/syncthing/syncthing/lib/build"
)
var (
goarch string
goos string
noupgrade bool
version string
goCmd string
race bool
debug = os.Getenv("BUILDDEBUG") != ""
extraTags string
installSuffix string
pkgdir string
cc string
run string
benchRun string
debugBinary bool
coverage bool
timeout = "120s"
numVersions = 5
goarch string
goos string
noupgrade bool
version string
goCmd string
race bool
debug = os.Getenv("BUILDDEBUG") != ""
extraTags string
installSuffix string
pkgdir string
cc string
run string
benchRun string
buildOut string
debugBinary bool
coverage bool
long bool
timeout = "120s"
longTimeout = "600s"
numVersions = 5
withNextGenGUI = os.Getenv("BUILD_NEXT_GEN_GUI") != ""
)
type target struct {
@@ -58,12 +65,11 @@ type target struct {
debname string
debdeps []string
debpre string
debpost string
description string
buildPkgs []string
binaryName string
archiveFiles []archiveFile
systemdServices []string
systemdService string
installationFiles []archiveFile
tags []string
}
@@ -85,7 +91,6 @@ var targets = map[string]target{
name: "syncthing",
debname: "syncthing",
debdeps: []string{"libc6", "procps"},
debpost: "script/post-upgrade",
description: "Open Source Continuous File Synchronization",
buildPkgs: []string{"github.com/syncthing/syncthing/cmd/syncthing"},
binaryName: "syncthing", // .exe will be added automatically for Windows builds
@@ -96,6 +101,7 @@ var targets = map[string]target{
{src: "AUTHORS", dst: "AUTHORS.txt", perm: 0644},
// All files from etc/ and extra/ added automatically in init().
},
systemdService: "syncthing@*.service",
installationFiles: []archiveFile{
{src: "{{binary}}", dst: "deb/usr/bin/{{binary}}", perm: 0755},
{src: "README.md", dst: "deb/usr/share/doc/syncthing/README.txt", perm: 0644},
@@ -114,6 +120,7 @@ var targets = map[string]target{
{src: "etc/linux-systemd/system/syncthing@.service", dst: "deb/lib/systemd/system/syncthing@.service", perm: 0644},
{src: "etc/linux-systemd/system/syncthing-resume.service", dst: "deb/lib/systemd/system/syncthing-resume.service", perm: 0644},
{src: "etc/linux-systemd/user/syncthing.service", dst: "deb/usr/lib/systemd/user/syncthing.service", perm: 0644},
{src: "etc/linux-sysctl/30-syncthing.conf", dst: "deb/usr/lib/sysctl.d/30-syncthing.conf", perm: 0644},
{src: "etc/firewall-ufw/syncthing", dst: "deb/etc/ufw/applications.d/syncthing", perm: 0644},
{src: "etc/linux-desktop/syncthing-start.desktop", dst: "deb/usr/share/applications/syncthing-start.desktop", perm: 0644},
{src: "etc/linux-desktop/syncthing-ui.desktop", dst: "deb/usr/share/applications/syncthing-ui.desktop", perm: 0644},
@@ -139,15 +146,14 @@ var targets = map[string]target{
{src: "LICENSE", dst: "LICENSE.txt", perm: 0644},
{src: "AUTHORS", dst: "AUTHORS.txt", perm: 0644},
},
systemdServices: []string{
"cmd/stdiscosrv/etc/linux-systemd/stdiscosrv.service",
},
systemdService: "stdiscosrv.service",
installationFiles: []archiveFile{
{src: "{{binary}}", dst: "deb/usr/bin/{{binary}}", perm: 0755},
{src: "cmd/stdiscosrv/README.md", dst: "deb/usr/share/doc/syncthing-discosrv/README.txt", perm: 0644},
{src: "LICENSE", dst: "deb/usr/share/doc/syncthing-discosrv/LICENSE.txt", perm: 0644},
{src: "AUTHORS", dst: "deb/usr/share/doc/syncthing-discosrv/AUTHORS.txt", perm: 0644},
{src: "man/stdiscosrv.1", dst: "deb/usr/share/man/man1/stdiscosrv.1", perm: 0644},
{src: "cmd/stdiscosrv/etc/linux-systemd/stdiscosrv.service", dst: "deb/lib/systemd/system/stdiscosrv.service", perm: 0644},
{src: "cmd/stdiscosrv/etc/linux-systemd/default", dst: "deb/etc/default/syncthing-discosrv", perm: 0644},
{src: "cmd/stdiscosrv/etc/firewall-ufw/stdiscosrv", dst: "deb/etc/ufw/applications.d/stdiscosrv", perm: 0644},
},
@@ -168,9 +174,7 @@ var targets = map[string]target{
{src: "LICENSE", dst: "LICENSE.txt", perm: 0644},
{src: "AUTHORS", dst: "AUTHORS.txt", perm: 0644},
},
systemdServices: []string{
"cmd/strelaysrv/etc/linux-systemd/strelaysrv.service",
},
systemdService: "strelaysrv.service",
installationFiles: []archiveFile{
{src: "{{binary}}", dst: "deb/usr/bin/{{binary}}", perm: 0755},
{src: "cmd/strelaysrv/README.md", dst: "deb/usr/share/doc/syncthing-relaysrv/README.txt", perm: 0644},
@@ -178,6 +182,7 @@ var targets = map[string]target{
{src: "LICENSE", dst: "deb/usr/share/doc/syncthing-relaysrv/LICENSE.txt", perm: 0644},
{src: "AUTHORS", dst: "deb/usr/share/doc/syncthing-relaysrv/AUTHORS.txt", perm: 0644},
{src: "man/strelaysrv.1", dst: "deb/usr/share/man/man1/strelaysrv.1", perm: 0644},
{src: "cmd/strelaysrv/etc/linux-systemd/strelaysrv.service", dst: "deb/lib/systemd/system/strelaysrv.service", perm: 0644},
{src: "cmd/strelaysrv/etc/linux-systemd/default", dst: "deb/etc/default/syncthing-relaysrv", perm: 0644},
{src: "cmd/strelaysrv/etc/firewall-ufw/strelaysrv", dst: "deb/etc/ufw/applications.d/strelaysrv", perm: 0644},
},
@@ -202,21 +207,27 @@ var targets = map[string]target{
{src: "AUTHORS", dst: "deb/usr/share/doc/syncthing-relaypoolsrv/AUTHORS.txt", perm: 0644},
},
},
"stupgrades": {
name: "stupgrades",
description: "Syncthing Upgrade Check Server",
buildPkgs: []string{"github.com/syncthing/syncthing/cmd/stupgrades"},
binaryName: "stupgrades",
},
"stcrashreceiver": {
name: "stcrashreceiver",
description: "Syncthing Crash Server",
buildPkgs: []string{"github.com/syncthing/syncthing/cmd/stcrashreceiver"},
binaryName: "stcrashreceiver",
},
"ursrv": {
name: "ursrv",
description: "Syncthing Usage Reporting Server",
buildPkgs: []string{"github.com/syncthing/syncthing/cmd/ursrv"},
binaryName: "ursrv",
},
}
// These are repos we need to clone to run "go generate"
type dependencyRepo struct {
path string
repo string
commit string
}
var dependencyRepos = []dependencyRepo{
{path: "xdr", repo: "https://github.com/calmh/xdr.git", commit: "08e072f9cb16"},
}
func init() {
func initTargets() {
all := targets["all"]
pkgs, _ := filepath.Glob("cmd/*")
for _, pkg := range pkgs {
@@ -225,6 +236,9 @@ func init() {
// ignore dotfiles
continue
}
if noupgrade && pkg == "stupgrades" {
continue
}
all.buildPkgs = append(all.buildPkgs, fmt.Sprintf("github.com/syncthing/syncthing/cmd/%s", pkg))
}
targets["all"] = all
@@ -256,6 +270,8 @@ func main() {
}()
}
initTargets()
// Invoking build.go with no parameters at all builds everything (incrementally),
// which is what you want for maximum error checking during development.
if flag.NArg() == 0 {
@@ -307,15 +323,24 @@ func runCommand(cmd string, target target) {
case "assets":
rebuildAssets()
case "update-deps":
updateDependencies()
case "proto":
proto()
case "testmocks":
testmocks()
case "translate":
translate()
case "transifex":
transifex()
case "weblate":
weblate()
case "tar":
buildTar(target, tags)
@@ -369,9 +394,12 @@ func parseFlags() {
flag.StringVar(&cc, "cc", os.Getenv("CC"), "Set CC environment variable for `go build`")
flag.BoolVar(&debugBinary, "debug-binary", debugBinary, "Create unoptimized binary to use with delve, set -gcflags='-N -l' and omit -ldflags")
flag.BoolVar(&coverage, "coverage", coverage, "Write coverage profile of tests to coverage.txt")
flag.BoolVar(&long, "long", long, "Run tests without the -short flag")
flag.IntVar(&numVersions, "num-versions", numVersions, "Number of versions for changelog command")
flag.StringVar(&run, "run", "", "Specify which tests to run")
flag.StringVar(&benchRun, "bench", "", "Specify which benchmarks to run")
flag.BoolVar(&withNextGenGUI, "with-next-gen-gui", withNextGenGUI, "Also build 'newgui'")
flag.StringVar(&buildOut, "build-out", "", "Set the '-o' value for 'go build'")
flag.Parse()
}
@@ -379,11 +407,17 @@ func test(tags []string, pkgs ...string) {
lazyRebuildAssets()
tags = append(tags, "purego")
args := []string{"test", "-short", "-timeout", timeout, "-tags", strings.Join(tags, " ")}
args := []string{"test", "-tags", strings.Join(tags, " ")}
if long {
timeout = longTimeout
} else {
args = append(args, "-short")
}
args = append(args, "-timeout", timeout)
if runtime.GOARCH == "amd64" {
switch runtime.GOOS {
case "darwin", "linux", "freebsd": // , "windows": # See https://github.com/golang/go/issues/27089
case buildpkg.Darwin, buildpkg.Linux, buildpkg.FreeBSD: // , "windows": # See https://github.com/golang/go/issues/27089
args = append(args, "-race")
}
}
@@ -438,6 +472,10 @@ func benchArgs() []string {
}
func install(target target, tags []string) {
if (target.name == "syncthing" || target.name == "") && !withNextGenGUI {
log.Println("Notice: Next generation GUI will not be built; see --with-next-gen-gui.")
}
lazyRebuildAssets()
tags = append(target.tags, tags...)
@@ -461,12 +499,16 @@ func install(target target, tags []string) {
defer shouldCleanupSyso(sysoPath)
}
args := []string{"install", "-v", "-trimpath"}
args := []string{"install", "-v"}
args = appendParameters(args, tags, target.buildPkgs...)
runPrint(goCmd, args...)
}
func build(target target, tags []string) {
if (target.name == "syncthing" || target.name == "") && !withNextGenGUI {
log.Println("Notice: Next generation GUI will not be built; see --with-next-gen-gui.")
}
lazyRebuildAssets()
tags = append(target.tags, tags...)
@@ -489,7 +531,10 @@ func build(target target, tags []string) {
defer shouldCleanupSyso(sysoPath)
}
args := []string{"build", "-v", "-trimpath"}
args := []string{"build", "-v"}
if buildOut != "" {
args = append(args, "-o", buildOut)
}
args = appendParameters(args, tags, target.buildPkgs...)
runPrint(goCmd, args...)
}
@@ -523,13 +568,13 @@ func appendParameters(args []string, tags []string, pkgs ...string) []string {
if !debugBinary {
// Regular binaries get version tagged and skip some debug symbols
args = append(args, "-ldflags", ldflags(tags))
args = append(args, "-trimpath", "-ldflags", ldflags(tags))
} else {
// -gcflags to disable optimizations and inlining. Skip -ldflags
// because `Could not launch program: decoding dwarf section info at
// offset 0x0: too short` on 'dlv exec ...' see
// https://github.com/go-delve/delve/issues/79
args = append(args, "-gcflags", "-N -l")
args = append(args, "-gcflags", "all=-N -l")
}
return append(args, pkgs...)
@@ -635,11 +680,13 @@ func buildDeb(target target) {
for _, dep := range target.debdeps {
args = append(args, "-d", dep)
}
for _, service := range target.systemdServices {
args = append(args, "--deb-systemd", service)
}
if target.debpost != "" {
args = append(args, "--after-upgrade", target.debpost)
if target.systemdService != "" {
debpost, err := createPostInstScript(target)
defer os.Remove(debpost)
if err != nil {
log.Fatal(err)
}
args = append(args, "--after-upgrade", debpost)
}
if target.debpre != "" {
args = append(args, "--before-install", target.debpre)
@@ -647,6 +694,28 @@ func buildDeb(target target) {
runPrint("fpm", args...)
}
func createPostInstScript(target target) (string, error) {
scriptname := filepath.Join("script", "deb-post-inst.template")
t, err := template.ParseFiles(scriptname)
if err != nil {
return "", err
}
scriptname = strings.TrimSuffix(scriptname, ".template")
w, err := os.Create(scriptname)
if err != nil {
return "", err
}
defer w.Close()
if err = t.Execute(w, struct {
Service, Command string
}{
target.systemdService, target.binaryName,
}); err != nil {
return "", err
}
return scriptname, nil
}
func shouldBuildSyso(dir string) (string, error) {
type M map[string]interface{}
version := getVersion()
@@ -666,11 +735,14 @@ func shouldBuildSyso(dir string) (string, error) {
},
},
"StringFileInfo": M{
"FileDescription": "Open Source Continuous File Synchronization",
"LegalCopyright": "The Syncthing Authors",
"FileVersion": version,
"ProductVersion": version,
"ProductName": "Syncthing",
"CompanyName": "The Syncthing Authors",
"FileDescription": "Syncthing - Open Source Continuous File Synchronization",
"FileVersion": version,
"InternalName": "syncthing",
"LegalCopyright": "The Syncthing Authors",
"OriginalFilename": "syncthing",
"ProductName": "Syncthing",
"ProductVersion": version,
},
"IconPath": "assets/logo.ico",
})
@@ -679,7 +751,7 @@ func shouldBuildSyso(dir string) (string, error) {
}
jsonPath := filepath.Join(dir, "versioninfo.json")
err = ioutil.WriteFile(jsonPath, bs, 0644)
err = os.WriteFile(jsonPath, bs, 0644)
if err != nil {
return "", errors.New("failed to create " + jsonPath + ": " + err.Error())
}
@@ -692,7 +764,13 @@ func shouldBuildSyso(dir string) (string, error) {
sysoPath := filepath.Join(dir, "cmd", "syncthing", "resource.syso")
if _, err := runError("goversioninfo", "-o", sysoPath); err != nil {
// See https://github.com/josephspurrier/goversioninfo#command-line-flags
armOption := ""
if strings.Contains(goarch, "arm") {
armOption = "-arm=true"
}
if _, err := runError("goversioninfo", "-o", sysoPath, armOption); err != nil {
return "", errors.New("failed to create " + sysoPath + ": " + err.Error())
}
@@ -712,12 +790,12 @@ func shouldCleanupSyso(sysoFilePath string) {
// exists. The permission bits are copied as well. If dst already exists and
// the contents are identical to src the modification time is not updated.
func copyFile(src, dst string, perm os.FileMode) error {
in, err := ioutil.ReadFile(src)
in, err := os.ReadFile(src)
if err != nil {
return err
}
out, err := ioutil.ReadFile(dst)
out, err := os.ReadFile(dst)
if err != nil {
// The destination probably doesn't exist, we should create
// it.
@@ -733,7 +811,7 @@ func copyFile(src, dst string, perm os.FileMode) error {
copy:
os.MkdirAll(filepath.Dir(dst), 0777)
if err := ioutil.WriteFile(dst, in, perm); err != nil {
if err := os.WriteFile(dst, in, perm); err != nil {
return err
}
@@ -761,11 +839,46 @@ func rebuildAssets() {
}
func lazyRebuildAssets() {
if shouldRebuildAssets("lib/api/auto/gui.files.go", "gui") || shouldRebuildAssets("cmd/strelaypoolsrv/auto/gui.files.go", "cmd/strelaypoolsrv/gui") {
shouldRebuild := shouldRebuildAssets("lib/api/auto/gui.files.go", "gui") ||
shouldRebuildAssets("cmd/strelaypoolsrv/auto/gui.files.go", "cmd/strelaypoolsrv/gui")
if withNextGenGUI {
shouldRebuild = buildNextGenGUI() || shouldRebuild
}
if shouldRebuild {
rebuildAssets()
}
}
func buildNextGenGUI() bool {
// Check if we need to run the npm process, and if so also set the flag
// to rebuild Go assets afterwards. The index.html is regenerated every
// time by the build process. This assumes the new GUI ends up in
// next-gen-gui/dist/next-gen-gui.
if !shouldRebuildAssets("gui/next-gen-gui/index.html", "next-gen-gui") {
// The GUI is up to date.
return false
}
runPrintInDir("next-gen-gui", "npm", "install")
runPrintInDir("next-gen-gui", "npm", "run", "build", "--", "--prod", "--subresource-integrity")
rmr("gui/tech-ui")
for _, src := range listFiles("next-gen-gui/dist") {
rel, _ := filepath.Rel("next-gen-gui/dist", src)
dst := filepath.Join("gui", rel)
if err := copyFile(src, dst, 0644); err != nil {
fmt.Println("copy:", err)
os.Exit(1)
}
}
return true
}
func shouldRebuildAssets(target, srcdir string) bool {
info, err := os.Stat(target)
if err != nil {
@@ -792,27 +905,59 @@ func shouldRebuildAssets(target, srcdir string) bool {
return assetsAreNewer
}
func updateDependencies() {
// Figure out desired Go version
bs, err := os.ReadFile("go.mod")
if err != nil {
log.Fatal(err)
}
re := regexp.MustCompile(`(?m)^go\s+([0-9.]+)`)
matches := re.FindSubmatch(bs)
if len(matches) != 2 {
log.Fatal("failed to parse go.mod")
}
goVersion := string(matches[1])
runPrint(goCmd, "get", "-u", "./...")
runPrint(goCmd, "mod", "tidy", "-go="+goVersion, "-compat="+goVersion)
// We might have updated the protobuf package and should regenerate to match.
proto()
}
func proto() {
pv := protobufVersion()
dependencyRepos = append(dependencyRepos,
dependencyRepo{path: "protobuf", repo: "https://github.com/gogo/protobuf.git", commit: pv},
)
repo := "https://github.com/gogo/protobuf.git"
path := filepath.Join("repos", "protobuf")
runPrint(goCmd, "get", fmt.Sprintf("github.com/gogo/protobuf/protoc-gen-gogofast@%v", pv))
runPrint(goCmd, "install", fmt.Sprintf("github.com/gogo/protobuf/protoc-gen-gogofast@%v", pv))
os.MkdirAll("repos", 0755)
for _, dep := range dependencyRepos {
path := filepath.Join("repos", dep.path)
if _, err := os.Stat(path); err != nil {
runPrintInDir("repos", "git", "clone", dep.repo, dep.path)
} else {
runPrintInDir(path, "git", "fetch")
}
runPrintInDir(path, "git", "checkout", dep.commit)
if _, err := os.Stat(path); err != nil {
runPrint("git", "clone", repo, path)
} else {
runPrintInDir(path, "git", "fetch")
}
runPrint(goCmd, "generate", "github.com/syncthing/syncthing/lib/...", "github.com/syncthing/syncthing/cmd/stdiscosrv")
runPrintInDir(path, "git", "checkout", pv)
runPrint(goCmd, "generate", "github.com/syncthing/syncthing/cmd/stdiscosrv")
runPrint(goCmd, "generate", "proto/generate.go")
}
func testmocks() {
args := []string{
"generate",
"github.com/syncthing/syncthing/lib/config",
"github.com/syncthing/syncthing/lib/connections",
"github.com/syncthing/syncthing/lib/discover",
"github.com/syncthing/syncthing/lib/events",
"github.com/syncthing/syncthing/lib/logger",
"github.com/syncthing/syncthing/lib/model",
"github.com/syncthing/syncthing/lib/protocol",
}
runPrint(goCmd, args...)
}
func translate() {
os.Chdir("gui/default/assets/lang")
runPipe("lang-en-new.json", goCmd, "run", "../../../../script/translate.go", "lang-en.json", "../../../")
@@ -829,6 +974,11 @@ func transifex() {
runPrint(goCmd, "run", "../../../../script/transifexdl.go")
}
func weblate() {
os.Chdir("gui/default/assets/lang")
runPrint(goCmd, "run", "../../../../script/weblatedl.go")
}
func ldflags(tags []string) string {
b := new(strings.Builder)
b.WriteString("-w")
@@ -853,7 +1003,7 @@ func rmr(paths ...string) {
}
func getReleaseVersion() (string, error) {
bs, err := ioutil.ReadFile("RELEASE")
bs, err := os.ReadFile("RELEASE")
if err != nil {
return "", err
}
@@ -876,7 +1026,7 @@ func getGitVersion() (string, error) {
v0 := string(bs)
// To be more semantic-versionish and ensure proper ordering in our
// upgrade process, we make sure there's only one hypen in the version.
// upgrade process, we make sure there's only one hyphen in the version.
versionRe := regexp.MustCompile(`-([0-9]{1,3}-g[0-9a-f]{5,10}(-dirty)?)`)
if m := versionRe.FindStringSubmatch(vcur); len(m) > 0 {
@@ -964,10 +1114,14 @@ func getBranchSuffix() string {
branch = parts[len(parts)-1]
switch branch {
case "master", "release", "main":
case "release", "main":
// these are not special
return ""
}
if strings.HasPrefix(branch, "release-") {
// release branches are not special
return ""
}
validBranchRe := regexp.MustCompile(`^[a-zA-Z0-9_.-]+$`)
if !validBranchRe.MatchString(branch) {
@@ -1185,11 +1339,11 @@ func zipFile(out string, files []archiveFile) {
if strings.HasSuffix(f.dst, ".txt") {
// Text file. Read it and convert line endings.
bs, err := ioutil.ReadAll(sf)
bs, err := io.ReadAll(sf)
if err != nil {
log.Fatal(err)
}
bs = bytes.Replace(bs, []byte{'\n'}, []byte{'\n', '\r'}, -1)
bs = bytes.Replace(bs, []byte{'\n'}, []byte{'\r', '\n'}, -1)
fh.UncompressedSize = uint32(len(bs))
fh.UncompressedSize64 = uint64(len(bs))
@@ -1260,6 +1414,33 @@ func windowsCodesign(file string) {
args := []string{"sign", "/fd", algo}
if f := os.Getenv("CODESIGN_CERTIFICATE_FILE"); f != "" {
args = append(args, "/f", f)
} else if b := os.Getenv("CODESIGN_CERTIFICATE_BASE64"); b != "" {
// Decode the PFX certificate from base64.
bs, err := base64.RawStdEncoding.DecodeString(b)
if err != nil {
log.Println("Codesign: signing failed: decoding base64:", err)
return
}
// Write it to a temporary file
f, err := os.CreateTemp("", "codesign-*.pfx")
if err != nil {
log.Println("Codesign: signing failed: creating temp file:", err)
return
}
_ = f.Chmod(0600) // best effort remove other users' access
defer os.Remove(f.Name())
if _, err := f.Write(bs); err != nil {
log.Println("Codesign: signing failed: writing temp file:", err)
return
}
if err := f.Close(); err != nil {
log.Println("Codesign: signing failed: closing temp file:", err)
return
}
// Use that when signing
args = append(args, "/f", f.Name())
}
if p := os.Getenv("CODESIGN_CERTIFICATE_PASSWORD"); p != "" {
args = append(args, "/p", p)
@@ -1279,7 +1460,7 @@ func windowsCodesign(file string) {
bs, err := runError(st, args...)
if err != nil {
log.Println("Codesign: signing failed:", string(bs))
log.Printf("Codesign: signing failed: %v: %s", err, string(bs))
return
}
log.Println("Codesign: successfully signed", file, "using", algo)
@@ -1296,32 +1477,6 @@ func metalintShort() {
runPrint(goCmd, "test", "-short", "-run", "Metalint", "./meta")
}
func temporaryBuildDir() (string, error) {
// The base of our temp dir is "syncthing-xxxxxxxx" where the x:es
// are eight bytes from the sha256 of our working directory. We do
// this because we want a name in the global temp dir that doesn't
// conflict with someone else building syncthing on the same
// machine, yet is persistent between runs from the same source
// directory.
wd, err := os.Getwd()
if err != nil {
return "", err
}
hash := sha256.Sum256([]byte(wd))
base := fmt.Sprintf("syncthing-%x", hash[:4])
// The temp dir is taken from $STTMPDIR if set, otherwise the system
// default (potentially infrluenced by $TMPDIR on unixes).
var tmpDir string
if t := os.Getenv("STTMPDIR"); t != "" {
tmpDir = t
} else {
tmpDir = os.TempDir()
}
return filepath.Join(tmpDir, base), nil
}
func (t target) BinaryName() string {
if goos == "windows" {
return t.binaryName + ".exe"

View File

@@ -23,7 +23,7 @@ case "${1:-default}" in
prerelease)
script authors
build transifex
build weblate
pushd man ; ./refresh.sh ; popd
git add -A gui man AUTHORS
git commit -m 'gui, man, authors: Update docs, translations, and contributors'

View File

@@ -1,96 +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 main
import (
"bytes"
"context"
"crypto/tls"
"errors"
"fmt"
"net"
"net/http"
"strings"
"github.com/syncthing/syncthing/lib/config"
)
type APIClient struct {
http.Client
cfg config.GUIConfiguration
apikey string
}
func getClient(cfg config.GUIConfiguration) *APIClient {
httpClient := http.Client{
Transport: &http.Transport{
TLSClientConfig: &tls.Config{
InsecureSkipVerify: true,
},
DialContext: func(_ context.Context, _, _ string) (net.Conn, error) {
return net.Dial(cfg.Network(), cfg.Address())
},
},
}
return &APIClient{
Client: httpClient,
cfg: cfg,
apikey: cfg.APIKey,
}
}
func (c *APIClient) Endpoint() string {
if c.cfg.Network() == "unix" {
return "http://unix/"
}
url := c.cfg.URL()
if !strings.HasSuffix(url, "/") {
url += "/"
}
return url
}
func (c *APIClient) Do(req *http.Request) (*http.Response, error) {
req.Header.Set("X-API-Key", c.apikey)
resp, err := c.Client.Do(req)
if err != nil {
return nil, err
}
return resp, checkResponse(resp)
}
func (c *APIClient) Get(url string) (*http.Response, error) {
request, err := http.NewRequest("GET", c.Endpoint()+"rest/"+url, nil)
if err != nil {
return nil, err
}
return c.Do(request)
}
func (c *APIClient) Post(url, body string) (*http.Response, error) {
request, err := http.NewRequest("POST", c.Endpoint()+"rest/"+url, bytes.NewBufferString(body))
if err != nil {
return nil, err
}
return c.Do(request)
}
func checkResponse(response *http.Response) error {
if response.StatusCode == 404 {
return errors.New("invalid endpoint or API call")
} else if response.StatusCode == 403 {
return errors.New("invalid API key")
} else if response.StatusCode != 200 {
data, err := responseToBArray(response)
if err != nil {
return err
}
body := strings.TrimSpace(string(data))
return fmt.Errorf("unexpected HTTP status returned: %s\n%s", response.Status, body)
}
return nil
}

View File

@@ -1,192 +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 main
import (
"bufio"
"crypto/tls"
"encoding/json"
"flag"
"log"
"os"
"reflect"
"github.com/AudriusButkevicius/recli"
"github.com/flynn-archive/go-shlex"
"github.com/mattn/go-isatty"
"github.com/pkg/errors"
"github.com/syncthing/syncthing/lib/build"
"github.com/syncthing/syncthing/lib/config"
"github.com/syncthing/syncthing/lib/events"
"github.com/syncthing/syncthing/lib/locations"
"github.com/syncthing/syncthing/lib/protocol"
"github.com/urfave/cli"
)
func main() {
// This is somewhat a hack around a chicken and egg problem.
// We need to set the home directory and potentially other flags to know where the syncthing instance is running
// in order to get it's config ... which we then use to construct the actual CLI ... at which point it's too late
// to add flags there...
homeBaseDir := locations.GetBaseDir(locations.ConfigBaseDir)
guiCfg := config.GUIConfiguration{}
flags := flag.NewFlagSet("", flag.ContinueOnError)
flags.StringVar(&guiCfg.RawAddress, "gui-address", guiCfg.RawAddress, "Override GUI address (e.g. \"http://192.0.2.42:8443\")")
flags.StringVar(&guiCfg.APIKey, "gui-apikey", guiCfg.APIKey, "Override GUI API key")
flags.StringVar(&homeBaseDir, "home", homeBaseDir, "Set configuration directory")
// Implement the same flags at the lower CLI, with the same default values (pre-parse), but do nothing with them.
// This is so that we could reuse os.Args
fakeFlags := []cli.Flag{
cli.StringFlag{
Name: "gui-address",
Value: guiCfg.RawAddress,
Usage: "Override GUI address (e.g. \"http://192.0.2.42:8443\")",
},
cli.StringFlag{
Name: "gui-apikey",
Value: guiCfg.APIKey,
Usage: "Override GUI API key",
},
cli.StringFlag{
Name: "home",
Value: homeBaseDir,
Usage: "Set configuration directory",
},
}
// Do not print usage of these flags, and ignore errors as this can't understand plenty of things
flags.Usage = func() {}
_ = flags.Parse(os.Args[1:])
// Now if the API key and address is not provided (we are not connecting to a remote instance),
// try to rip it out of the config.
if guiCfg.RawAddress == "" && guiCfg.APIKey == "" {
// Update the base directory
err := locations.SetBaseDir(locations.ConfigBaseDir, homeBaseDir)
if err != nil {
log.Fatal(errors.Wrap(err, "setting home"))
}
// Load the certs and get the ID
cert, err := tls.LoadX509KeyPair(
locations.Get(locations.CertFile),
locations.Get(locations.KeyFile),
)
if err != nil {
log.Fatal(errors.Wrap(err, "reading device ID"))
}
myID := protocol.NewDeviceID(cert.Certificate[0])
// Load the config
cfg, _, err := config.Load(locations.Get(locations.ConfigFile), myID, events.NoopLogger)
if err != nil {
log.Fatalln(errors.Wrap(err, "loading config"))
}
guiCfg = cfg.GUI()
} else if guiCfg.Address() == "" || guiCfg.APIKey == "" {
log.Fatalln("Both -gui-address and -gui-apikey should be specified")
}
if guiCfg.Address() == "" {
log.Fatalln("Could not find GUI Address")
}
if guiCfg.APIKey == "" {
log.Fatalln("Could not find GUI API key")
}
client := getClient(guiCfg)
cfg, err := getConfig(client)
original := cfg.Copy()
if err != nil {
log.Fatalln(errors.Wrap(err, "getting config"))
}
// Copy the config and set the default flags
recliCfg := recli.DefaultConfig
recliCfg.IDTag.Name = "xml"
recliCfg.SkipTag.Name = "json"
commands, err := recli.New(recliCfg).Construct(&cfg)
if err != nil {
log.Fatalln(errors.Wrap(err, "config reflect"))
}
// Construct the actual CLI
app := cli.NewApp()
app.Name = "stcli"
app.HelpName = app.Name
app.Author = "The Syncthing Authors"
app.Usage = "Syncthing command line interface"
app.Version = build.Version
app.Flags = fakeFlags
app.Metadata = map[string]interface{}{
"client": client,
}
app.Commands = []cli.Command{
{
Name: "config",
HideHelp: true,
Usage: "Configuration modification command group",
Subcommands: commands,
},
showCommand,
operationCommand,
errorsCommand,
}
tty := isatty.IsTerminal(os.Stdin.Fd()) || isatty.IsCygwinTerminal(os.Stdin.Fd())
if !tty {
// Not a TTY, consume from stdin
scanner := bufio.NewScanner(os.Stdin)
for scanner.Scan() {
input, err := shlex.Split(scanner.Text())
if err != nil {
log.Fatalln(errors.Wrap(err, "parsing input"))
}
if len(input) == 0 {
continue
}
err = app.Run(append(os.Args, input...))
if err != nil {
log.Fatalln(err)
}
}
err = scanner.Err()
if err != nil {
log.Fatalln(err)
}
} else {
err = app.Run(os.Args)
if err != nil {
log.Fatalln(err)
}
}
if !reflect.DeepEqual(cfg, original) {
body, err := json.MarshalIndent(cfg, "", " ")
if err != nil {
log.Fatalln(err)
}
resp, err := client.Post("system/config", string(body))
if err != nil {
log.Fatalln(err)
}
if resp.StatusCode != 200 {
body, err := responseToBArray(resp)
if err != nil {
log.Fatalln(err)
}
log.Fatalln(string(body))
}
}
}

View File

@@ -1,94 +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 main
import (
"encoding/json"
"fmt"
"io/ioutil"
"net/http"
"os"
"github.com/syncthing/syncthing/lib/config"
"github.com/urfave/cli"
)
func responseToBArray(response *http.Response) ([]byte, error) {
bytes, err := ioutil.ReadAll(response.Body)
if err != nil {
return nil, err
}
return bytes, response.Body.Close()
}
func emptyPost(url string) cli.ActionFunc {
return func(c *cli.Context) error {
client := c.App.Metadata["client"].(*APIClient)
_, err := client.Post(url, "")
return err
}
}
func dumpOutput(url string) cli.ActionFunc {
return func(c *cli.Context) error {
client := c.App.Metadata["client"].(*APIClient)
response, err := client.Get(url)
if err != nil {
return err
}
return prettyPrintResponse(c, response)
}
}
func getConfig(c *APIClient) (config.Configuration, error) {
cfg := config.Configuration{}
response, err := c.Get("system/config")
if err != nil {
return cfg, err
}
bytes, err := responseToBArray(response)
if err != nil {
return cfg, err
}
err = json.Unmarshal(bytes, &cfg)
if err == nil {
return cfg, err
}
return cfg, nil
}
func expects(n int, actionFunc cli.ActionFunc) cli.ActionFunc {
return func(ctx *cli.Context) error {
if ctx.NArg() != n {
plural := ""
if n != 1 {
plural = "s"
}
return fmt.Errorf("expected %d argument%s, got %d", n, plural, ctx.NArg())
}
return actionFunc(ctx)
}
}
func prettyPrintJSON(data interface{}) error {
enc := json.NewEncoder(os.Stdout)
enc.SetIndent("", " ")
return enc.Encode(data)
}
func prettyPrintResponse(c *cli.Context, response *http.Response) error {
bytes, err := responseToBArray(response)
if err != nil {
return err
}
var data interface{}
if err := json.Unmarshal(bytes, &data); err != nil {
return err
}
// TODO: Check flag for pretty print format
return prettyPrintJSON(data)
}

View File

@@ -7,7 +7,6 @@
package main
import (
"crypto/md5"
"errors"
"flag"
"fmt"
@@ -15,6 +14,8 @@ import (
"log"
"os"
"path/filepath"
"github.com/syncthing/syncthing/lib/sha256"
)
func main() {
@@ -74,7 +75,7 @@ type fileInfo struct {
name string
mode os.FileMode
mod int64
hash [16]byte
hash [sha256.Size]byte
}
func (f fileInfo) String() string {
@@ -106,11 +107,7 @@ func startWalker(dir string, res chan<- fileInfo, abort <-chan struct{}) chan er
if err != nil {
return err
}
h := md5.New()
h.Write([]byte(tgt))
hash := h.Sum(nil)
copy(f.hash[:], hash)
f.hash = sha256.Sum256([]byte(tgt))
} else if info.IsDir() {
f = fileInfo{
name: rn,
@@ -123,7 +120,7 @@ func startWalker(dir string, res chan<- fileInfo, abort <-chan struct{}) chan er
mode: info.Mode(),
mod: info.ModTime().Unix(),
}
sum, err := md5file(path)
sum, err := sha256file(path)
if err != nil {
return err
}
@@ -150,14 +147,14 @@ func startWalker(dir string, res chan<- fileInfo, abort <-chan struct{}) chan er
return errc
}
func md5file(fname string) (hash [16]byte, err error) {
func sha256file(fname string) (hash [sha256.Size]byte, err error) {
f, err := os.Open(fname)
if err != nil {
return
}
defer f.Close()
h := md5.New()
h := sha256.New()
io.Copy(h, f)
hb := h.Sum(nil)
copy(hash[:], hb)

View File

@@ -0,0 +1,187 @@
// Copyright (C) 2023 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 main
import (
"bytes"
"compress/gzip"
"context"
"io"
"log"
"os"
"path/filepath"
"sort"
"time"
)
type diskStore struct {
dir string
inbox chan diskEntry
maxBytes int64
maxFiles int
currentFiles []currentFile
currentSize int64
}
type diskEntry struct {
path string
data []byte
}
type currentFile struct {
path string
size int64
mtime int64
}
func (d *diskStore) Serve(ctx context.Context) {
if err := os.MkdirAll(d.dir, 0750); err != nil {
log.Println("Creating directory:", err)
return
}
if err := d.inventory(); err != nil {
log.Println("Failed to inventory disk store:", err)
}
d.clean()
cleanTimer := time.NewTicker(time.Minute)
inventoryTimer := time.NewTicker(24 * time.Hour)
buf := new(bytes.Buffer)
gw := gzip.NewWriter(buf)
for {
select {
case entry := <-d.inbox:
path := d.fullPath(entry.path)
if err := os.MkdirAll(filepath.Dir(path), 0755); err != nil {
log.Println("Creating directory:", err)
continue
}
buf.Reset()
gw.Reset(buf)
if _, err := gw.Write(entry.data); err != nil {
log.Println("Failed to compress crash report:", err)
continue
}
if err := gw.Close(); err != nil {
log.Println("Failed to compress crash report:", err)
continue
}
if err := os.WriteFile(path, buf.Bytes(), 0644); err != nil {
log.Printf("Failed to write %s: %v", entry.path, err)
_ = os.Remove(path)
continue
}
d.currentSize += int64(buf.Len())
d.currentFiles = append(d.currentFiles, currentFile{
size: int64(len(entry.data)),
path: path,
})
case <-cleanTimer.C:
d.clean()
case <-inventoryTimer.C:
if err := d.inventory(); err != nil {
log.Println("Failed to inventory disk store:", err)
}
case <-ctx.Done():
return
}
}
}
func (d *diskStore) Put(path string, data []byte) bool {
select {
case d.inbox <- diskEntry{
path: path,
data: data,
}:
return true
default:
return false
}
}
func (d *diskStore) Get(path string) ([]byte, error) {
path = d.fullPath(path)
bs, err := os.ReadFile(path)
if err != nil {
return nil, err
}
gr, err := gzip.NewReader(bytes.NewReader(bs))
if err != nil {
return nil, err
}
defer gr.Close()
return io.ReadAll(gr)
}
func (d *diskStore) Exists(path string) bool {
path = d.fullPath(path)
_, err := os.Lstat(path)
return err == nil
}
func (d *diskStore) clean() {
for len(d.currentFiles) > 0 && (len(d.currentFiles) > d.maxFiles || d.currentSize > d.maxBytes) {
f := d.currentFiles[0]
log.Println("Removing", f.path)
if err := os.Remove(f.path); err != nil {
log.Println("Failed to remove file:", err)
}
d.currentFiles = d.currentFiles[1:]
d.currentSize -= f.size
}
var oldest time.Duration
if len(d.currentFiles) > 0 {
oldest = time.Since(time.Unix(d.currentFiles[0].mtime, 0)).Truncate(time.Minute)
}
log.Printf("Clean complete: %d files, %d MB, oldest is %v ago", len(d.currentFiles), d.currentSize>>20, oldest)
}
func (d *diskStore) inventory() error {
d.currentFiles = nil
d.currentSize = 0
err := filepath.Walk(d.dir, func(path string, info os.FileInfo, err error) error {
if err != nil {
return err
}
if info.IsDir() {
return nil
}
if filepath.Ext(path) != ".gz" {
return nil
}
d.currentSize += info.Size()
d.currentFiles = append(d.currentFiles, currentFile{
path: path,
size: info.Size(),
mtime: info.ModTime().Unix(),
})
return nil
})
sort.Slice(d.currentFiles, func(i, j int) bool {
return d.currentFiles[i].mtime < d.currentFiles[j].mtime
})
var oldest time.Duration
if len(d.currentFiles) > 0 {
oldest = time.Since(time.Unix(d.currentFiles[0].mtime, 0)).Truncate(time.Minute)
}
log.Printf("Inventory complete: %d files, %d MB, oldest is %v ago", len(d.currentFiles), d.currentSize>>20, oldest)
return err
}
func (d *diskStore) fullPath(path string) string {
return filepath.Join(d.dir, path[0:2], path[2:]) + ".gz"
}

View File

@@ -13,17 +13,17 @@
package main
import (
"context"
"encoding/json"
"flag"
"fmt"
"io"
"io/ioutil"
"log"
"net"
"net/http"
"os"
"path/filepath"
"time"
"github.com/alecthomas/kong"
"github.com/syncthing/syncthing/lib/sha256"
"github.com/syncthing/syncthing/lib/ur"
@@ -32,34 +32,61 @@ import (
const maxRequestSize = 1 << 20 // 1 MiB
type cli struct {
Dir string `help:"Parent directory to store crash and failure reports in" env:"REPORTS_DIR" default:"."`
DSN string `help:"Sentry DSN" env:"SENTRY_DSN"`
Listen string `help:"HTTP listen address" default:":8080" env:"LISTEN_ADDRESS"`
MaxDiskFiles int `help:"Maximum number of reports on disk" default:"100000" env:"MAX_DISK_FILES"`
MaxDiskSizeMB int64 `help:"Maximum disk space to use for reports" default:"1024" env:"MAX_DISK_SIZE_MB"`
CleanInterval time.Duration `help:"Interval between cleaning up old reports" default:"12h" env:"CLEAN_INTERVAL"`
SentryQueue int `help:"Maximum number of reports to queue for sending to Sentry" default:"64" env:"SENTRY_QUEUE"`
DiskQueue int `help:"Maximum number of reports to queue for writing to disk" default:"64" env:"DISK_QUEUE"`
}
func main() {
dir := flag.String("dir", ".", "Directory to store reports in")
dsn := flag.String("dsn", "", "Sentry DSN")
listen := flag.String("listen", ":22039", "HTTP listen address")
flag.Parse()
var params cli
kong.Parse(&params)
mux := http.NewServeMux()
cr := &crashReceiver{
dir: *dir,
dsn: *dsn,
ds := &diskStore{
dir: filepath.Join(params.Dir, "crash_reports"),
inbox: make(chan diskEntry, params.DiskQueue),
maxFiles: params.MaxDiskFiles,
maxBytes: params.MaxDiskSizeMB << 20,
}
mux.Handle("/", cr)
go ds.Serve(context.Background())
if *dsn != "" {
mux.HandleFunc("/failure", handleFailureFn(*dsn))
ss := &sentryService{
dsn: params.DSN,
inbox: make(chan sentryRequest, params.SentryQueue),
}
go ss.Serve(context.Background())
cr := &crashReceiver{
store: ds,
sentry: ss,
}
mux.Handle("/", cr)
mux.HandleFunc("/ping", func(w http.ResponseWriter, req *http.Request) {
w.Write([]byte("OK"))
})
if params.DSN != "" {
mux.HandleFunc("/newcrash/failure", handleFailureFn(params.DSN, filepath.Join(params.Dir, "failure_reports")))
}
log.SetOutput(os.Stdout)
if err := http.ListenAndServe(*listen, mux); err != nil {
if err := http.ListenAndServe(params.Listen, mux); err != nil {
log.Fatalln("HTTP serve:", err)
}
}
func handleFailureFn(dsn string) func(w http.ResponseWriter, req *http.Request) {
func handleFailureFn(dsn, failureDir string) func(w http.ResponseWriter, req *http.Request) {
return func(w http.ResponseWriter, req *http.Request) {
lr := io.LimitReader(req.Body, maxRequestSize)
bs, err := ioutil.ReadAll(lr)
bs, err := io.ReadAll(lr)
req.Body.Close()
if err != nil {
http.Error(w, err.Error(), 500)
@@ -84,12 +111,25 @@ func handleFailureFn(dsn string) func(w http.ResponseWriter, req *http.Request)
return
}
for _, r := range reports {
pkt := packet(version)
pkt := packet(version, "failure")
pkt.Message = r.Description
pkt.Extra = raven.Extra{
"count": r.Count,
}
pkt.Fingerprint = []string{r.Description}
for k, v := range r.Extra {
pkt.Extra[k] = v
}
if r.Goroutines != "" {
url, err := saveFailureWithGoroutines(r.FailureData, failureDir)
if err != nil {
log.Println("Saving failure report:", err)
http.Error(w, "Internal server error", http.StatusInternalServerError)
return
}
pkt.Extra["goroutinesURL"] = url
}
message := sanitizeMessageLDB(r.Description)
pkt.Fingerprint = []string{message}
if err := sendReport(dsn, pkt, userIDFor(req)); err != nil {
log.Println("Failed to send failure report:", err)
@@ -100,19 +140,15 @@ func handleFailureFn(dsn string) func(w http.ResponseWriter, req *http.Request)
}
}
// userIDFor returns a string we can use as the user ID for the purpose of
// counting affected users. It's the truncated hash of a salt, the user
// remote IP, and the current month.
func userIDFor(req *http.Request) string {
addr := req.RemoteAddr
if fwd := req.Header.Get("x-forwarded-for"); fwd != "" {
addr = fwd
func saveFailureWithGoroutines(data ur.FailureData, failureDir string) (string, error) {
bs := make([]byte, len(data.Description)+len(data.Goroutines))
copy(bs, data.Description)
copy(bs[len(data.Description):], data.Goroutines)
id := fmt.Sprintf("%x", sha256.Sum256(bs))
path := fullPathCompressed(failureDir, id)
err := compressAndWrite(bs, path)
if err != nil {
return "", err
}
if host, _, err := net.SplitHostPort(addr); err == nil {
addr = host
}
now := time.Now().Format("200601")
salt := "stcrashreporter"
hash := sha256.Sum256([]byte(salt + addr + now))
return fmt.Sprintf("%x", hash[:8])
return reportServer + path, nil
}

View File

@@ -8,14 +8,16 @@ package main
import (
"bytes"
"context"
"errors"
"io/ioutil"
"io"
"log"
"regexp"
"strings"
"sync"
raven "github.com/getsentry/raven-go"
"github.com/maruel/panicparse/stack"
"github.com/maruel/panicparse/v2/stack"
)
const reportServer = "https://crash.syncthing.net/report/"
@@ -31,6 +33,44 @@ var (
clientsMut sync.Mutex
)
type sentryService struct {
dsn string
inbox chan sentryRequest
}
type sentryRequest struct {
reportID string
data []byte
}
func (s *sentryService) Serve(ctx context.Context) {
for {
select {
case req := <-s.inbox:
pkt, err := parseCrashReport(req.reportID, req.data)
if err != nil {
log.Println("Failed to parse crash report:", err)
continue
}
if err := sendReport(s.dsn, pkt, req.reportID); err != nil {
log.Println("Failed to send crash report:", err)
}
case <-ctx.Done():
return
}
}
}
func (s *sentryService) Send(reportID string, data []byte) bool {
select {
case s.inbox <- sentryRequest{reportID, data}:
return true
default:
return false
}
}
func sendReport(dsn string, pkt *raven.Packet, userID string) error {
pkt.Interfaces = append(pkt.Interfaces, &raven.User{ID: userID})
@@ -93,10 +133,13 @@ func parseCrashReport(path string, report []byte) (*raven.Packet, error) {
}
r := bytes.NewReader(report)
ctx, err := stack.ParseDump(r, ioutil.Discard, false)
if err != nil {
ctx, _, err := stack.ScanSnapshot(r, io.Discard, stack.DefaultOpts())
if err != nil && err != io.EOF {
return nil, err
}
if ctx == nil || len(ctx.Goroutines) == 0 {
return nil, errors.New("no goroutines found")
}
// Lock the source code loader to the version we are processing here.
if version.commit != "" {
@@ -116,13 +159,13 @@ func parseCrashReport(path string, report []byte) (*raven.Packet, error) {
if gr.First {
trace.Frames = make([]*raven.StacktraceFrame, len(gr.Stack.Calls))
for i, sc := range gr.Stack.Calls {
trace.Frames[len(trace.Frames)-1-i] = raven.NewStacktraceFrame(0, sc.Func.Name(), sc.SrcPath, sc.Line, 3, nil)
trace.Frames[len(trace.Frames)-1-i] = raven.NewStacktraceFrame(0, sc.Func.Name, sc.RemoteSrcPath, sc.Line, 3, nil)
}
break
}
}
pkt := packet(version)
pkt := packet(version, "crash")
pkt.Message = string(subjectLine)
pkt.Extra = raven.Extra{
"url": reportServer + path,
@@ -143,15 +186,20 @@ var (
ldbPathRe = regexp.MustCompile(`(open|write|read) .+[\\/].+[\\/]index[^\\/]+[\\/][^\\/]+: `)
)
func crashReportFingerprint(message string) []string {
// Do not fingerprint on the stack in case of db corruption or fatal
// db io error - where it occurs doesn't matter.
orig := message
func sanitizeMessageLDB(message string) string {
message = ldbPosRe.ReplaceAllString(message, "${1}x)")
message = ldbFileRe.ReplaceAllString(message, "${1}x${3}")
message = ldbChecksumRe.ReplaceAllString(message, "${1}X${3}X")
message = ldbInternalKeyRe.ReplaceAllString(message, "${1}x${2}x")
message = ldbPathRe.ReplaceAllString(message, "$1 x: ")
return message
}
func crashReportFingerprint(message string) []string {
// Do not fingerprint on the stack in case of db corruption or fatal
// db io error - where it occurs doesn't matter.
orig := message
message = sanitizeMessageLDB(message)
if message != orig {
return []string{message}
}
@@ -167,7 +215,13 @@ func crashReportFingerprint(message string) []string {
}
// syncthing v1.1.4-rc.1+30-g6aaae618-dirty-crashrep "Erbium Earthworm" (go1.12.5 darwin-amd64) jb@kvin.kastelo.net 2019-05-23 16:08:14 UTC [foo, bar]
var longVersionRE = regexp.MustCompile(`syncthing\s+(v[^\s]+)\s+"([^"]+)"\s\(([^\s]+)\s+([^-]+)-([^)]+)\)\s+([^\s]+)[^\[]*(?:\[(.+)\])?$`)
// or, somewhere along the way the "+" in the version tag disappeared:
// syncthing v1.23.7-dev.26.gdf7b56ae.dirty-stversionextra "Fermium Flea" (go1.20.5 darwin-arm64) jb@ok.kastelo.net 2023-07-12 06:55:26 UTC [Some Wrapper, purego, stnoupgrade]
var (
longVersionRE = regexp.MustCompile(`syncthing\s+(v[^\s]+)\s+"([^"]+)"\s\(([^\s]+)\s+([^-]+)-([^)]+)\)\s+([^\s]+)[^\[]*(?:\[(.+)\])?$`)
gitExtraRE = regexp.MustCompile(`\.\d+\.g[0-9a-f]+`) // ".1.g6aaae618"
gitExtraSepRE = regexp.MustCompile(`[.-]`) // dot or dash
)
type version struct {
version string // "v1.1.4-rc.1+30-g6aaae618-dirty-crashrep"
@@ -209,10 +263,21 @@ func parseVersion(line string) (version, error) {
builder: m[6],
}
parts := strings.Split(v.version, "+")
// Split the version tag into tag and commit. This is old style
// v1.2.3-something.4+11-g12345678 or newer with just dots
// v1.2.3-something.4.11.g12345678 or v1.2.3-dev.11.g12345678.
parts := []string{v.version}
if strings.Contains(v.version, "+") {
parts = strings.Split(v.version, "+")
} else {
idxs := gitExtraRE.FindStringIndex(v.version)
if len(idxs) > 0 {
parts = []string{v.version[:idxs[0]], v.version[idxs[0]+1:]}
}
}
v.tag = parts[0]
if len(parts) > 1 {
fields := strings.Split(parts[1], "-")
fields := gitExtraSepRE.Split(parts[1], -1)
if len(fields) >= 2 && strings.HasPrefix(fields[1], "g") {
v.commit = fields[1][1:]
}
@@ -229,7 +294,7 @@ func parseVersion(line string) (version, error) {
return v, nil
}
func packet(version version) *raven.Packet {
func packet(version version, reportType string) *raven.Packet {
pkt := &raven.Packet{
Platform: "go",
Release: version.tag,
@@ -242,6 +307,7 @@ func packet(version version) *raven.Packet {
raven.Tag{Key: "goos", Value: version.goos},
raven.Tag{Key: "goarch", Value: version.goarch},
raven.Tag{Key: "builder", Value: version.builder},
raven.Tag{Key: "report_type", Value: reportType},
},
}
if version.commit != "" {

View File

@@ -8,7 +8,7 @@ package main
import (
"fmt"
"io/ioutil"
"os"
"testing"
)
@@ -44,6 +44,20 @@ func TestParseVersion(t *testing.T) {
extra: []string{"foo", "bar"},
},
},
{
longVersion: `syncthing v1.23.7-dev.26.gdf7b56ae-stversionextra "Fermium Flea" (go1.20.5 darwin-arm64) jb@ok.kastelo.net 2023-07-12 06:55:26 UTC [Some Wrapper, purego, stnoupgrade]`,
parsed: version{
version: "v1.23.7-dev.26.gdf7b56ae-stversionextra",
tag: "v1.23.7-dev",
commit: "df7b56ae",
codename: "Fermium Flea",
runtime: "go1.20.5",
goos: "darwin",
goarch: "arm64",
builder: "jb@ok.kastelo.net",
extra: []string{"Some Wrapper", "purego", "stnoupgrade"},
},
},
}
for _, tc := range cases {
@@ -59,7 +73,7 @@ func TestParseVersion(t *testing.T) {
}
func TestParseReport(t *testing.T) {
bs, err := ioutil.ReadFile("_testdata/panic.log")
bs, err := os.ReadFile("_testdata/panic.log")
if err != nil {
t.Fatal(err)
}

View File

@@ -9,7 +9,7 @@ package main
import (
"bytes"
"fmt"
"io/ioutil"
"io"
"net/http"
"path/filepath"
"strings"
@@ -80,7 +80,7 @@ func (l *githubSourceCodeLoader) Load(filename string, line, context int) ([][]b
fmt.Println("Loading source:", resp.Status)
return nil, 0
}
data, err := ioutil.ReadAll(resp.Body)
data, err := io.ReadAll(resp.Body)
_ = resp.Body.Close()
if err != nil {
fmt.Println("Loading source:", err.Error())

View File

@@ -7,21 +7,16 @@
package main
import (
"bytes"
"compress/gzip"
"io"
"io/ioutil"
"log"
"net/http"
"os"
"path"
"path/filepath"
"strings"
)
type crashReceiver struct {
dir string
dsn string
store *diskStore
sentry *sentryService
}
func (r *crashReceiver) ServeHTTP(w http.ResponseWriter, req *http.Request) {
@@ -44,99 +39,55 @@ func (r *crashReceiver) ServeHTTP(w http.ResponseWriter, req *http.Request) {
return
}
// The location of the report on disk, compressed
fullPath := filepath.Join(r.dir, r.dirFor(reportID), reportID) + ".gz"
switch req.Method {
case http.MethodGet:
r.serveGet(fullPath, w, req)
r.serveGet(reportID, w, req)
case http.MethodHead:
r.serveHead(fullPath, w, req)
r.serveHead(reportID, w, req)
case http.MethodPut:
r.servePut(reportID, fullPath, w, req)
r.servePut(reportID, w, req)
default:
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
}
}
// serveGet responds to GET requests by serving the uncompressed report.
func (r *crashReceiver) serveGet(fullPath string, w http.ResponseWriter, _ *http.Request) {
fd, err := os.Open(fullPath)
func (r *crashReceiver) serveGet(reportID string, w http.ResponseWriter, _ *http.Request) {
bs, err := r.store.Get(reportID)
if err != nil {
http.Error(w, "Not found", http.StatusNotFound)
return
}
defer fd.Close()
gr, err := gzip.NewReader(fd)
if err != nil {
http.Error(w, "Internal server error", http.StatusInternalServerError)
return
}
_, _ = io.Copy(w, gr) // best effort
w.Write(bs)
}
// serveHead responds to HEAD requests by checking if the named report
// already exists in the system.
func (r *crashReceiver) serveHead(fullPath string, w http.ResponseWriter, _ *http.Request) {
if _, err := os.Lstat(fullPath); err != nil {
func (r *crashReceiver) serveHead(reportID string, w http.ResponseWriter, _ *http.Request) {
if !r.store.Exists(reportID) {
http.Error(w, "Not found", http.StatusNotFound)
}
}
// servePut accepts and stores the given report.
func (r *crashReceiver) servePut(reportID, fullPath string, w http.ResponseWriter, req *http.Request) {
// Ensure the destination directory exists
if err := os.MkdirAll(filepath.Dir(fullPath), 0755); err != nil {
log.Println("Creating directory:", err)
http.Error(w, "Internal server error", http.StatusInternalServerError)
return
}
func (r *crashReceiver) servePut(reportID string, w http.ResponseWriter, req *http.Request) {
// Read at most maxRequestSize of report data.
log.Println("Receiving report", reportID)
lr := io.LimitReader(req.Body, maxRequestSize)
bs, err := ioutil.ReadAll(lr)
bs, err := io.ReadAll(lr)
if err != nil {
log.Println("Reading report:", err)
http.Error(w, "Internal server error", http.StatusInternalServerError)
return
}
// Compress the report for storage
buf := new(bytes.Buffer)
gw := gzip.NewWriter(buf)
_, _ = gw.Write(bs) // can't fail
gw.Close()
// Create an output file with the compressed report
err = ioutil.WriteFile(fullPath, buf.Bytes(), 0644)
if err != nil {
log.Println("Saving report:", err)
http.Error(w, "Internal server error", http.StatusInternalServerError)
return
// Store the report
if !r.store.Put(reportID, bs) {
log.Println("Failed to store report (queue full):", reportID)
}
// Send the report to Sentry
if r.dsn != "" {
// Remote ID
user := userIDFor(req)
go func() {
// There's no need for the client to have to wait for this part.
pkt, err := parseCrashReport(reportID, bs)
if err != nil {
log.Println("Failed to parse crash report:", err)
return
}
if err := sendReport(r.dsn, pkt, user); err != nil {
log.Println("Failed to send crash report:", err)
}
}()
if !r.sentry.Send(reportID, bs) {
log.Println("Failed to send report to sentry (queue full):", reportID)
}
}
// 01234567890abcdef... => 01/23
func (r *crashReceiver) dirFor(base string) string {
return filepath.Join(base[0:2], base[2:4])
}

View File

@@ -0,0 +1,57 @@
// Copyright (C) 2021 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 main
import (
"bytes"
"compress/gzip"
"fmt"
"net"
"net/http"
"os"
"path/filepath"
"time"
"github.com/syncthing/syncthing/lib/sha256"
)
// userIDFor returns a string we can use as the user ID for the purpose of
// counting affected users. It's the truncated hash of a salt, the user
// remote IP, and the current month.
func userIDFor(req *http.Request) string {
addr := req.RemoteAddr
if fwd := req.Header.Get("x-forwarded-for"); fwd != "" {
addr = fwd
}
if host, _, err := net.SplitHostPort(addr); err == nil {
addr = host
}
now := time.Now().Format("200601")
salt := "stcrashreporter"
hash := sha256.Sum256([]byte(salt + addr + now))
return fmt.Sprintf("%x", hash[:8])
}
// 01234567890abcdef... => 01/23
func dirFor(base string) string {
return filepath.Join(base[0:2], base[2:4])
}
func fullPathCompressed(root, reportID string) string {
return filepath.Join(root, dirFor(reportID), reportID) + ".gz"
}
func compressAndWrite(bs []byte, fullPath string) error {
// Compress the report for storage
buf := new(bytes.Buffer)
gw := gzip.NewWriter(buf)
_, _ = gw.Write(bs) // can't fail
gw.Close()
// Create an output file with the compressed report
return os.WriteFile(fullPath, buf.Bytes(), 0644)
}

View File

@@ -10,8 +10,10 @@ import (
"bytes"
"context"
"crypto/tls"
"encoding/base64"
"encoding/json"
"encoding/pem"
"errors"
"fmt"
"log"
"math/rand"
@@ -66,7 +68,7 @@ func newAPISrv(addr string, cert tls.Certificate, db database, repl replicator,
}
}
func (s *apiSrv) Serve(ctx context.Context) error {
func (s *apiSrv) Serve(_ context.Context) error {
if s.useHTTP {
listener, err := net.Listen("tcp", s.addr)
if err != nil {
@@ -229,10 +231,10 @@ func (s *apiSrv) handleGET(ctx context.Context, w http.ResponseWriter, req *http
func (s *apiSrv) handlePOST(ctx context.Context, remoteAddr *net.TCPAddr, w http.ResponseWriter, req *http.Request) {
reqID := ctx.Value(idKey).(requestID)
rawCert := certificateBytes(req)
if rawCert == nil {
rawCert, err := certificateBytes(req)
if err != nil {
if debug {
log.Println(reqID, "no certificates")
log.Println(reqID, "no certificates:", err)
}
announceRequestsTotal.WithLabelValues("no_certificate").Inc()
w.Header().Set("Retry-After", errorRetryAfterString())
@@ -300,13 +302,13 @@ func (s *apiSrv) handleAnnounce(deviceID protocol.DeviceID, addresses []string)
return s.db.merge(key, dbAddrs, seen)
}
func handlePing(w http.ResponseWriter, r *http.Request) {
func handlePing(w http.ResponseWriter, _ *http.Request) {
w.WriteHeader(204)
}
func certificateBytes(req *http.Request) []byte {
func certificateBytes(req *http.Request) ([]byte, error) {
if req.TLS != nil && len(req.TLS.PeerCertificates) > 0 {
return req.TLS.PeerCertificates[0].Raw
return req.TLS.PeerCertificates[0].Raw, nil
}
var bs []byte
@@ -319,7 +321,7 @@ func certificateBytes(req *http.Request) []byte {
hdr, err := url.QueryUnescape(hdr)
if err != nil {
// Decoding failed
return nil
return nil, err
}
bs = []byte(hdr)
@@ -338,6 +340,15 @@ func certificateBytes(req *http.Request) []byte {
}
}
}
} else if hdr := req.Header.Get("X-Tls-Client-Cert-Der-Base64"); hdr != "" {
// Caddy {tls_client_certificate_der_base64}
hdr, err := base64.StdEncoding.DecodeString(hdr)
if err != nil {
// Decoding failed
return nil, err
}
bs = pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: hdr})
} else if hdr := req.Header.Get("X-Forwarded-Tls-Client-Cert"); hdr != "" {
// Traefik 2 passtlsclientcert
// The certificate is in PEM format with url encoding but without newlines
@@ -346,7 +357,7 @@ func certificateBytes(req *http.Request) []byte {
hdr, err := url.QueryUnescape(hdr)
if err != nil {
// Decoding failed
return nil
return nil, err
}
for i := 64; i < len(hdr); i += 65 {
@@ -359,16 +370,16 @@ func certificateBytes(req *http.Request) []byte {
}
if bs == nil {
return nil
return nil, errors.New("empty certificate header")
}
block, _ := pem.Decode(bs)
if block == nil {
// Decoding failed
return nil
return nil, errors.New("certificate decode result is empty")
}
return block.Bytes
return block.Bytes, nil
}
// fixupAddresses checks the list of addresses, removing invalid ones and
@@ -419,7 +430,7 @@ func fixupAddresses(remote *net.TCPAddr, addresses []string) []string {
// If zero port was specified, use remote port.
if port == "0" && remote.Port > 0 {
port = fmt.Sprintf("%d", remote.Port)
port = strconv.Itoa(remote.Port)
}
}

View File

@@ -16,6 +16,7 @@ import (
"time"
"github.com/syndtr/goleveldb/leveldb"
"github.com/syndtr/goleveldb/leveldb/storage"
"github.com/syndtr/goleveldb/leveldb/util"
)
@@ -54,6 +55,18 @@ func newLevelDBStore(dir string) (*levelDBStore, error) {
}, nil
}
func newMemoryLevelDBStore() (*levelDBStore, error) {
db, err := leveldb.Open(storage.NewMemStorage(), nil)
if err != nil {
return nil, err
}
return &levelDBStore{
db: db,
inbox: make(chan func(), 16),
clock: defaultClock{},
}, nil
}
func (s *levelDBStore) put(key string, rec DatabaseRecord) error {
t0 := time.Now()
defer func() {

View File

@@ -510,10 +510,7 @@ func (m *DatabaseRecord) Unmarshal(dAtA []byte) error {
if err != nil {
return err
}
if skippy < 0 {
return ErrInvalidLengthDatabase
}
if (iNdEx + skippy) < 0 {
if (skippy < 0) || (iNdEx+skippy) < 0 {
return ErrInvalidLengthDatabase
}
if (iNdEx + skippy) > l {
@@ -648,10 +645,7 @@ func (m *ReplicationRecord) Unmarshal(dAtA []byte) error {
if err != nil {
return err
}
if skippy < 0 {
return ErrInvalidLengthDatabase
}
if (iNdEx + skippy) < 0 {
if (skippy < 0) || (iNdEx+skippy) < 0 {
return ErrInvalidLengthDatabase
}
if (iNdEx + skippy) > l {
@@ -752,10 +746,7 @@ func (m *DatabaseAddress) Unmarshal(dAtA []byte) error {
if err != nil {
return err
}
if skippy < 0 {
return ErrInvalidLengthDatabase
}
if (iNdEx + skippy) < 0 {
if (skippy < 0) || (iNdEx+skippy) < 0 {
return ErrInvalidLengthDatabase
}
if (iNdEx + skippy) > l {

View File

@@ -9,15 +9,12 @@ package main
import (
"context"
"fmt"
"os"
"testing"
"time"
)
func TestDatabaseGetSet(t *testing.T) {
os.RemoveAll("_database")
defer os.RemoveAll("_database")
db, err := newLevelDBStore("_database")
db, err := newMemoryLevelDBStore()
if err != nil {
t.Fatal(err)
}
@@ -119,7 +116,7 @@ func TestDatabaseGetSet(t *testing.T) {
// Put a record with misses
rec = DatabaseRecord{Misses: 42}
rec = DatabaseRecord{Misses: 42, Missed: tc.Now().UnixNano()}
if err := db.put("efgh", rec); err != nil {
t.Fatal(err)
}
@@ -209,5 +206,6 @@ func (t *testClock) wind(d time.Duration) {
}
func (t *testClock) Now() time.Time {
t.now = t.now.Add(time.Nanosecond)
return t.now
}

View File

@@ -116,8 +116,11 @@ func main() {
var replicationDestinations []string
parts := strings.Split(replicationPeers, ",")
for _, part := range parts {
fields := strings.Split(part, "@")
if part == "" {
continue
}
fields := strings.Split(part, "@")
switch len(fields) {
case 2:
// This is an id@address specification. Grab the address for the
@@ -137,6 +140,9 @@ func main() {
if err != nil {
log.Fatalln("Parsing device ID:", err)
}
if id == protocol.EmptyDeviceID {
log.Fatalf("Missing device ID for peer in %q", part)
}
allowedReplicationPeers = append(allowedReplicationPeers, id)
default:

View File

@@ -120,7 +120,7 @@ func (s *replicationSender) Serve(ctx context.Context) error {
if _, err := conn.Write(buf[:4+n]); err != nil {
replicationSendsTotal.WithLabelValues("error").Inc()
log.Println("Replication write:", err)
// Yes, we are loosing the replication event here.
// Yes, we are losing the replication event here.
return err
}
replicationSendsTotal.WithLabelValues("success").Inc()
@@ -135,7 +135,7 @@ func (s *replicationSender) String() string {
return fmt.Sprintf("replicationSender(%q)", s.dst)
}
func (s *replicationSender) send(key string, ps []DatabaseAddress, seen int64) {
func (s *replicationSender) send(key string, ps []DatabaseAddress, _ int64) {
item := ReplicationRecord{
Key: key,
Addresses: ps,

View File

@@ -10,6 +10,7 @@ import (
"os"
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/collectors"
)
var (
@@ -109,7 +110,7 @@ func init() {
databaseKeys, databaseStatisticsSeconds,
databaseOperations, databaseOperationSeconds)
processCollectorOpts := prometheus.ProcessCollectorOpts{
processCollectorOpts := collectors.ProcessCollectorOpts{
Namespace: "syncthing_discovery",
PidFn: func() (int, error) {
return os.Getpid(), nil
@@ -117,7 +118,7 @@ func init() {
}
prometheus.MustRegister(
prometheus.NewProcessCollector(processCollectorOpts),
collectors.NewProcessCollector(processCollectorOpts),
)
}

View File

@@ -28,16 +28,21 @@ func main() {
log.SetFlags(0)
target := flag.String("target", "localhost:8384", "Target Syncthing instance")
types := flag.String("types", "", "Filter for specific event types (comma-separated)")
apikey := flag.String("apikey", "", "Syncthing API key")
flag.Parse()
if *apikey == "" {
log.Fatal("Must give -apikey argument")
}
var eventsArg string
if len(*types) > 0 {
eventsArg = "&events=" + *types
}
since := 0
for {
req, err := http.NewRequest("GET", fmt.Sprintf("http://%s/rest/events?since=%d", *target, since), nil)
req, err := http.NewRequest("GET", fmt.Sprintf("http://%s/rest/events?since=%d%s", *target, since, eventsArg), nil)
if err != nil {
log.Fatal(err)
}

View File

@@ -84,7 +84,7 @@ func checkServers(deviceID protocol.DeviceID, servers ...string) {
}
func checkServer(deviceID protocol.DeviceID, server string) checkResult {
disco, err := discover.NewGlobal(server, tls.Certificate{}, nil, events.NoopLogger)
disco, err := discover.NewGlobal(server, tls.Certificate{}, nil, events.NoopLogger, nil)
if err != nil {
return checkResult{error: err}
}

View File

@@ -4,7 +4,7 @@
// 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/.
// Commmand stfindignored lists ignored files under a given folder root.
// Command stfindignored lists ignored files under a given folder root.
package main
import (

View File

@@ -66,7 +66,7 @@ func generateFiles(dir string, files, maxexp int, srcname string) error {
}
func generateOneFile(fd io.ReadSeeker, p1 string, s int64) error {
src := io.LimitReader(&inifiteReader{fd}, s)
src := io.LimitReader(&infiniteReader{fd}, s)
dst, err := os.Create(p1)
if err != nil {
return err
@@ -105,11 +105,11 @@ func readRand(bs []byte) (int, error) {
return len(bs), nil
}
type inifiteReader struct {
type infiniteReader struct {
rd io.ReadSeeker
}
func (i *inifiteReader) Read(bs []byte) (int, error) {
func (i *infiniteReader) Read(bs []byte) (int, error) {
n, err := i.rd.Read(bs)
if err == io.EOF {
err = nil

View File

@@ -1,63 +0,0 @@
// Copyright (C) 2014 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 main
import (
"flag"
"fmt"
"log"
"os"
"path/filepath"
"github.com/syncthing/syncthing/lib/db/backend"
)
func main() {
var mode string
log.SetFlags(0)
log.SetOutput(os.Stdout)
flag.StringVar(&mode, "mode", "dump", "Mode of operation: dump, dumpsize, idxck")
flag.Parse()
path := flag.Arg(0)
if path == "" {
path = filepath.Join(defaultConfigDir(), "index-v0.14.0.db")
}
var ldb backend.Backend
var err error
if looksLikeBadger(path) {
ldb, err = backend.OpenBadger(path)
} else {
ldb, err = backend.OpenLevelDBRO(path)
}
if err != nil {
log.Fatal(err)
}
switch mode {
case "dump":
dump(ldb)
case "dumpsize":
dumpsize(ldb)
case "idxck":
if !idxck(ldb) {
os.Exit(1)
}
case "account":
account(ldb)
default:
fmt.Println("Unknown mode")
}
}
func looksLikeBadger(path string) bool {
_, err := os.Stat(filepath.Join(path, "KEYREGISTRY"))
return err == nil
}

View File

@@ -1,52 +0,0 @@
// Copyright (C) 2015 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 main
import (
"log"
"os"
"path/filepath"
"runtime"
"github.com/syncthing/syncthing/lib/fs"
)
func nulString(bs []byte) string {
for i := range bs {
if bs[i] == 0 {
return string(bs[:i])
}
}
return string(bs)
}
func defaultConfigDir() string {
switch runtime.GOOS {
case "windows":
if p := os.Getenv("LocalAppData"); p != "" {
return filepath.Join(p, "Syncthing")
}
return filepath.Join(os.Getenv("AppData"), "Syncthing")
case "darwin":
dir, err := fs.ExpandTilde("~/Library/Application Support/Syncthing")
if err != nil {
log.Fatal(err)
}
return dir
default:
if xdgCfg := os.Getenv("XDG_CONFIG_HOME"); xdgCfg != "" {
return filepath.Join(xdgCfg, "syncthing")
}
dir, err := fs.ExpandTilde("~/.config/syncthing")
if err != nil {
log.Fatal(err)
}
return dir
}
}

View File

@@ -0,0 +1,16 @@
// Copyright (C) 2021 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/.
//go:build noassets
// +build noassets
package auto
import "github.com/syncthing/syncthing/lib/assets"
func Assets() map[string]assets.Asset {
return nil
}

View File

@@ -46,18 +46,18 @@
<h1>Relay Pool Data</h1>
<div ng-if="relays === undefined" class="text-center">
<img src="https://cdnjs.cloudflare.com/ajax/libs/galleriffic/2.0.1/css/loader.gif" alt=""/>
<p>Please wait while we gather data</p>
<p>Please wait while we gather data</p>
</div>
<div>
<div ng-show="relays !== undefined" class="ng-hide">
<p>
The relays listed on this page are not managed or vetted by the Syncthing project.
Each relay is the responsibility of the relay operator.
Currently {{ relays.length }} relays online.
Currently {{ relays.length }} relays are online.
</p>
</div>
<div id="map"></div> <!-- Can't hide the map, otherwise it freaks out -->
<p>The circle size represents how much bytes the relay transferred relative to other relays</p>
<p>The circle size represents how much bytes the relay has transferred relatively to other relays.</p>
</div>
<div>
<table class="table table-striped table-condensed table">
@@ -188,7 +188,7 @@
<hr>
<p>
This product includes GeoLite2 data created by MaxMind, available from
<a href="http://www.maxmind.com">http://www.maxmind.com</a>.
<a href="https://www.maxmind.com">https://www.maxmind.com</a>.
</p>
</div>
@@ -237,7 +237,7 @@
uptimeSeconds: 0,
};
$scope.map = L.map('map').setView([40.90296, 1.90925], 2);
L.tileLayer('http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png',
L.tileLayer('https://tile.openstreetmap.org/{z}/{x}/{y}.png',
{
attribution: 'Leaflet',
maxZoom: 17

View File

@@ -3,14 +3,12 @@
package main
import (
"compress/gzip"
"context"
"crypto/tls"
"crypto/x509"
"encoding/json"
"flag"
"fmt"
"io"
"io/ioutil"
"log"
"net"
"net/http"
@@ -19,9 +17,13 @@ import (
"path/filepath"
"strconv"
"strings"
"sync/atomic"
"time"
"github.com/golang/groupcache/lru"
lru "github.com/hashicorp/golang-lru/v2"
"github.com/syncthing/syncthing/lib/httpcache"
"github.com/syncthing/syncthing/lib/protocol"
"github.com/oschwald/geoip2-golang"
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promhttp"
@@ -31,7 +33,6 @@ import (
"github.com/syncthing/syncthing/lib/relay/client"
"github.com/syncthing/syncthing/lib/sync"
"github.com/syncthing/syncthing/lib/tlsutil"
"golang.org/x/time/rate"
)
type location struct {
@@ -97,27 +98,13 @@ var (
dir string
evictionTime = time.Hour
debug bool
getLRUSize = 10 << 10
getLimitBurst = 10
getLimitAvg = 2
postLRUSize = 1 << 10
postLimitBurst = 2
postLimitAvg = 2
getLimit time.Duration
postLimit time.Duration
permRelaysFile string
ipHeader string
geoipPath string
proto string
statsRefresh = time.Minute / 2
requestQueueLen = 10
requestProcessors = 1
getMut = sync.NewMutex()
getLRUCache *lru.Cache
postMut = sync.NewMutex()
postLRUCache *lru.Cache
statsRefresh = time.Minute
requestQueueLen = 64
requestProcessors = 8
requests chan request
@@ -125,6 +112,7 @@ var (
knownRelays = make([]*relay, 0)
permanentRelays = make([]*relay, 0)
evictionTimers = make(map[string]*time.Timer)
globalBlocklist = newErrorTracker(1000)
)
const (
@@ -139,13 +127,8 @@ func main() {
flag.StringVar(&dir, "keys", dir, "Directory where http-cert.pem and http-key.pem is stored for TLS listening")
flag.BoolVar(&debug, "debug", debug, "Enable debug output")
flag.DurationVar(&evictionTime, "eviction", evictionTime, "After how long the relay is evicted")
flag.IntVar(&getLRUSize, "get-limit-cache", getLRUSize, "Get request limiter cache size")
flag.IntVar(&getLimitAvg, "get-limit-avg", getLimitAvg, "Allowed average get request rate, per 10 s")
flag.IntVar(&getLimitBurst, "get-limit-burst", getLimitBurst, "Allowed burst get requests")
flag.IntVar(&postLRUSize, "post-limit-cache", postLRUSize, "Post request limiter cache size")
flag.IntVar(&postLimitAvg, "post-limit-avg", postLimitAvg, "Allowed average post request rate, per minute")
flag.IntVar(&postLimitBurst, "post-limit-burst", postLimitBurst, "Allowed burst post requests")
flag.StringVar(&permRelaysFile, "perm-relays", "", "Path to list of permanent relays")
flag.StringVar(&knownRelaysFile, "known-relays", knownRelaysFile, "Path to list of current relays")
flag.StringVar(&ipHeader, "ip-header", "", "Name of header which holds clients ip:port. Only meaningful when running behind a reverse proxy.")
flag.StringVar(&geoipPath, "geoip", "GeoLite2-City.mmdb", "Path to GeoLite2-City database")
flag.StringVar(&proto, "protocol", "tcp", "Protocol used for listening. 'tcp' for IPv4 and IPv6, 'tcp4' for IPv4, 'tcp6' for IPv6")
@@ -157,12 +140,6 @@ func main() {
requests = make(chan request, requestQueueLen)
getLimit = 10 * time.Second / time.Duration(getLimitAvg)
postLimit = time.Minute / time.Duration(postLimitAvg)
getLRUCache = lru.New(getLRUSize)
postLRUCache = lru.New(postLRUSize)
var listener net.Listener
var err error
@@ -208,6 +185,7 @@ func main() {
tlsCfg := &tls.Config{
Certificates: []tls.Certificate{cert},
MinVersion: tls.VersionTLS10, // No SSLv3
ClientAuth: tls.RequestClientCert,
CipherSuites: []uint16{
// No RC4
tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
@@ -237,7 +215,7 @@ func main() {
handler := http.NewServeMux()
handler.HandleFunc("/", handleAssets)
handler.HandleFunc("/endpoint", handleRequest)
handler.Handle("/endpoint", httpcache.SinglePath(http.HandlerFunc(handleRequest), 15*time.Second))
handler.HandleFunc("/metrics", handleMetrics)
srv := http.Server{
@@ -288,21 +266,17 @@ func handleRequest(w http.ResponseWriter, r *http.Request) {
}()
if ipHeader != "" {
r.RemoteAddr = r.Header.Get(ipHeader)
hdr := r.Header.Get(ipHeader)
fields := strings.Split(hdr, ",")
if len(fields) > 0 {
r.RemoteAddr = strings.TrimSpace(fields[len(fields)-1])
}
}
w.Header().Set("Access-Control-Allow-Origin", "*")
switch r.Method {
case "GET":
if limit(r.RemoteAddr, getLRUCache, getMut, getLimit, getLimitBurst) {
w.WriteHeader(httpStatusEnhanceYourCalm)
return
}
handleGetRequest(w, r)
case "POST":
if limit(r.RemoteAddr, postLRUCache, postMut, postLimit, postLimitBurst) {
w.WriteHeader(httpStatusEnhanceYourCalm)
return
}
handlePostRequest(w, r)
default:
if debug {
@@ -324,20 +298,34 @@ func handleGetRequest(rw http.ResponseWriter, r *http.Request) {
// Shuffle
rand.Shuffle(relays)
w := io.Writer(rw)
if strings.Contains(r.Header.Get("Accept-Encoding"), "gzip") {
rw.Header().Set("Content-Encoding", "gzip")
gw := gzip.NewWriter(rw)
defer gw.Close()
w = gw
}
_ = json.NewEncoder(w).Encode(map[string][]*relay{
_ = json.NewEncoder(rw).Encode(map[string][]*relay{
"relays": relays,
})
}
func handlePostRequest(w http.ResponseWriter, r *http.Request) {
// Get the IP address of the client
rhost := r.RemoteAddr
if host, _, err := net.SplitHostPort(rhost); err == nil {
rhost = host
}
// Check the black list. A client is blacklisted if their last 10
// attempts to join have all failed. The "Unauthorized" status return
// causes strelaysrv to cease attempting to join.
if globalBlocklist.IsBlocked(rhost) {
log.Println("Rejected blocked client", rhost)
http.Error(w, "Too many errors", http.StatusUnauthorized)
globalBlocklist.ClearErrors(rhost)
return
}
var relayCert *x509.Certificate
if r.TLS != nil && len(r.TLS.PeerCertificates) > 0 {
relayCert = r.TLS.PeerCertificates[0]
log.Printf("Got TLS cert from relay server")
}
var newRelay relay
err := json.NewDecoder(r.Body).Decode(&newRelay)
r.Body.Close()
@@ -359,6 +347,21 @@ func handlePostRequest(w http.ResponseWriter, r *http.Request) {
return
}
// Canonicalize the URL. In particular, parse and re-encode the query
// string so that it's guaranteed to be valid.
uri.RawQuery = uri.Query().Encode()
newRelay.URL = uri.String()
if relayCert != nil {
advertisedId := uri.Query().Get("id")
idFromCert := protocol.NewDeviceID(relayCert.Raw).String()
if advertisedId != idFromCert {
log.Println("Warning: Relay server requested to join with an ID different from the join request, rejecting")
http.Error(w, "mismatched advertised id and join request cert", http.StatusBadRequest)
return
}
}
host, port, err := net.SplitHostPort(uri.Host)
if err != nil {
if debug {
@@ -368,18 +371,12 @@ func handlePostRequest(w http.ResponseWriter, r *http.Request) {
return
}
// Get the IP address of the client
rhost := r.RemoteAddr
if host, _, err := net.SplitHostPort(rhost); err == nil {
rhost = host
}
ip := net.ParseIP(host)
// The client did not provide an IP address, use the IP address of the client.
if ip == nil || ip.IsUnspecified() {
uri.Host = net.JoinHostPort(rhost, port)
newRelay.URL = uri.String()
} else if host != rhost {
} else if host != rhost && relayCert == nil {
if debug {
log.Println("IP address advertised does not match client IP address", r.RemoteAddr, uri)
}
@@ -405,10 +402,14 @@ func handlePostRequest(w http.ResponseWriter, r *http.Request) {
case requests <- request{&newRelay, reschan, prometheus.NewTimer(relayTestActionsSeconds.WithLabelValues("queue"))}:
result := <-reschan
if result.err != nil {
log.Println("Join from", r.RemoteAddr, "failed:", result.err)
globalBlocklist.AddError(rhost)
relayTestsTotal.WithLabelValues("failed").Inc()
http.Error(w, result.err.Error(), http.StatusBadRequest)
return
}
log.Println("Join from", r.RemoteAddr, "succeeded")
globalBlocklist.ClearErrors(rhost)
relayTestsTotal.WithLabelValues("success").Inc()
w.Header().Set("Content-Type", "application/json; charset=utf-8")
json.NewEncoder(w).Encode(map[string]time.Duration{
@@ -456,7 +457,7 @@ func handleRelayTest(request request) {
updateMetrics(request.relay.uri.Host, *stats, location)
}
request.relay.Stats = stats
request.relay.StatsRetrieved = time.Now()
request.relay.StatsRetrieved = time.Now().Truncate(time.Second)
request.relay.Location = location
timer, ok := evictionTimers[request.relay.uri.Host]
@@ -522,25 +523,8 @@ func evict(relay *relay) func() {
}
}
func limit(addr string, cache *lru.Cache, lock sync.Mutex, intv time.Duration, burst int) bool {
if host, _, err := net.SplitHostPort(addr); err == nil {
addr = host
}
lock.Lock()
v, _ := cache.Get(addr)
bkt, ok := v.(*rate.Limiter)
if !ok {
bkt = rate.NewLimiter(rate.Every(intv), burst)
cache.Add(addr, bkt)
}
lock.Unlock()
return !bkt.Allow()
}
func loadRelays(file string) []*relay {
content, err := ioutil.ReadFile(file)
content, err := os.ReadFile(file)
if err != nil {
log.Println("Failed to load relays: " + err.Error())
return nil
@@ -548,7 +532,7 @@ func loadRelays(file string) []*relay {
var relays []*relay
for _, line := range strings.Split(string(content), "\n") {
if len(line) == 0 {
if line == "" {
continue
}
@@ -578,11 +562,11 @@ func saveRelays(file string, relays []*relay) error {
for _, relay := range relays {
content += relay.uri.String() + "\n"
}
return ioutil.WriteFile(file, []byte(content), 0777)
return os.WriteFile(file, []byte(content), 0o777)
}
func createTestCertificate() tls.Certificate {
tmpDir, err := ioutil.TempDir("", "relaypoolsrv")
tmpDir, err := os.MkdirTemp("", "relaypoolsrv")
if err != nil {
log.Fatal(err)
}
@@ -637,3 +621,42 @@ func (lrw *loggingResponseWriter) WriteHeader(code int) {
lrw.statusCode = code
lrw.ResponseWriter.WriteHeader(code)
}
type errorTracker struct {
errors *lru.TwoQueueCache[string, *errorCounter]
}
type errorCounter struct {
count atomic.Int32
}
func newErrorTracker(size int) *errorTracker {
cache, err := lru.New2Q[string, *errorCounter](size)
if err != nil {
panic(err)
}
return &errorTracker{
errors: cache,
}
}
func (b *errorTracker) AddError(host string) {
entry, ok := b.errors.Get(host)
if !ok {
entry = &errorCounter{}
b.errors.Add(host, entry)
}
c := entry.count.Add(1)
log.Printf("Error count for %s is now %d", host, c)
}
func (b *errorTracker) ClearErrors(host string) {
b.errors.Remove(host)
}
func (b *errorTracker) IsBlocked(host string) bool {
if be, ok := b.errors.Get(host); ok {
return be.count.Load() > 10
}
return false
}

View File

@@ -11,6 +11,7 @@ import (
"encoding/json"
"fmt"
"net/http/httptest"
"net/url"
"strings"
"sync"
"testing"
@@ -65,3 +66,29 @@ func TestHandleGetRequest(t *testing.T) {
}
}
}
func TestCanonicalizeQueryValues(t *testing.T) {
// This just demonstrates and validates the uri.Parse/String stuff in
// regards to query strings.
in := "http://example.com/?some weird= query^value"
exp := "http://example.com/?some+weird=+query%5Evalue"
uri, err := url.Parse(in)
if err != nil {
t.Fatal(err)
}
str := uri.String()
if str != in {
// Just re-encoding the URL doesn't sanitize the query string.
t.Errorf("expected %q, got %q", in, str)
}
uri.RawQuery = uri.Query().Encode()
str = uri.String()
if str != exp {
// The query string is now in correct format.
t.Errorf("expected %q, got %q", exp, str)
}
}

View File

@@ -10,11 +10,12 @@ import (
"time"
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/collectors"
"github.com/syncthing/syncthing/lib/sync"
)
func init() {
processCollectorOpts := prometheus.ProcessCollectorOpts{
processCollectorOpts := collectors.ProcessCollectorOpts{
Namespace: "syncthing_relaypoolsrv",
PidFn: func() (int, error) {
return os.Getpid(), nil
@@ -22,7 +23,7 @@ func init() {
}
prometheus.MustRegister(
prometheus.NewProcessCollector(processCollectorOpts),
collectors.NewProcessCollector(processCollectorOpts),
)
}

View File

@@ -20,10 +20,10 @@ import (
var (
outboxesMut = sync.RWMutex{}
outboxes = make(map[syncthingprotocol.DeviceID]chan interface{})
numConnections int64
numConnections atomic.Int64
)
func listener(proto, addr string, config *tls.Config) {
func listener(_, addr string, config *tls.Config, token string) {
tcpListener, err := net.Listen("tcp", addr)
if err != nil {
log.Fatalln(err)
@@ -36,8 +36,14 @@ func listener(proto, addr string, config *tls.Config) {
for {
conn, isTLS, err := listener.AcceptNoWrapTLS()
if err != nil {
// Conn may be nil if accept failed, or non-nil if the initial
// read to figure out if it's TLS or not failed. In the latter
// case, close the connection before moving on.
if conn != nil {
conn.Close()
}
if debug {
log.Println("Listener failed to accept connection from", conn.RemoteAddr(), ". Possibly a TCP Ping.")
log.Println("Listener failed to accept:", err)
}
continue
}
@@ -49,7 +55,7 @@ func listener(proto, addr string, config *tls.Config) {
}
if isTLS {
go protocolConnectionHandler(conn, config)
go protocolConnectionHandler(conn, config, token)
} else {
go sessionConnectionHandler(conn)
}
@@ -57,7 +63,7 @@ func listener(proto, addr string, config *tls.Config) {
}
}
func protocolConnectionHandler(tcpConn net.Conn, config *tls.Config) {
func protocolConnectionHandler(tcpConn net.Conn, config *tls.Config, token string) {
conn := tls.Server(tcpConn, config)
if err := conn.SetDeadline(time.Now().Add(messageTimeout)); err != nil {
if debug {
@@ -76,7 +82,7 @@ func protocolConnectionHandler(tcpConn net.Conn, config *tls.Config) {
}
state := conn.ConnectionState()
if (!state.NegotiatedProtocolIsMutual || state.NegotiatedProtocol != protocol.ProtocolName) && debug {
if debug && state.NegotiatedProtocol != protocol.ProtocolName {
log.Println("Protocol negotiation error")
}
@@ -119,7 +125,16 @@ func protocolConnectionHandler(tcpConn net.Conn, config *tls.Config) {
switch msg := message.(type) {
case protocol.JoinRelayRequest:
if atomic.LoadInt32(&overLimit) > 0 {
if token != "" && msg.Token != token {
if debug {
log.Printf("invalid token %s\n", msg.Token)
}
protocol.WriteMessage(conn, protocol.ResponseWrongToken)
conn.Close()
continue
}
if overLimit.Load() {
protocol.WriteMessage(conn, protocol.RelayFull{})
if debug {
log.Println("Refusing join request from", id, "due to being over limits")
@@ -258,7 +273,7 @@ func protocolConnectionHandler(tcpConn net.Conn, config *tls.Config) {
conn.Close()
}
if atomic.LoadInt32(&overLimit) > 0 && !hasSessions(id) {
if overLimit.Load() && !hasSessions(id) {
if debug {
log.Println("Dropping", id, "as it has no sessions and we are over our limits")
}
@@ -351,8 +366,8 @@ func sessionConnectionHandler(conn net.Conn) {
}
func messageReader(conn net.Conn, messages chan<- interface{}, errors chan<- error) {
atomic.AddInt64(&numConnections, 1)
defer atomic.AddInt64(&numConnections, -1)
numConnections.Add(1)
defer numConnections.Add(-1)
for {
msg, err := protocol.ReadMessage(conn)

View File

@@ -14,7 +14,6 @@ import (
"os"
"os/signal"
"path/filepath"
"runtime"
"strings"
"sync/atomic"
"syscall"
@@ -50,13 +49,14 @@ var (
sessionLimitBps int
globalLimitBps int
overLimit int32
overLimit atomic.Bool
descriptorLimit int64
sessionLimiter *rate.Limiter
globalLimiter *rate.Limiter
networkBufferSize int
statusAddr string
token string
poolAddrs string
pools []string
providedBy string
@@ -90,6 +90,7 @@ func main() {
flag.IntVar(&globalLimitBps, "global-rate", globalLimitBps, "Global rate limit, in bytes/s")
flag.BoolVar(&debug, "debug", debug, "Enable debug output")
flag.StringVar(&statusAddr, "status-srv", ":22070", "Listen address for status service (blank to disable)")
flag.StringVar(&token, "token", "", "Token to restrict access to the relay (optional). Disables joining any pools.")
flag.StringVar(&poolAddrs, "pools", defaultPoolAddrs, "Comma separated list of relay pool addresses to join")
flag.StringVar(&providedBy, "provided-by", "", "An optional description about who provides the relay")
flag.StringVar(&extAddress, "ext-address", "", "An optional address to advertise as being available on.\n\tAllows listening on an unprivileged port with port forwarding from e.g. 443, and be connected to on port 443.")
@@ -99,7 +100,7 @@ func main() {
flag.IntVar(&natRenewal, "nat-renewal", 30, "NAT renewal frequency in minutes")
flag.IntVar(&natTimeout, "nat-timeout", 10, "NAT discovery timeout in seconds")
flag.BoolVar(&pprofEnabled, "pprof", false, "Enable the built in profiling on the status server")
flag.IntVar(&networkBufferSize, "network-buffer", 2048, "Network buffer size (two of these per proxied connection)")
flag.IntVar(&networkBufferSize, "network-buffer", 65536, "Network buffer size (two of these per proxied connection)")
showVersion := flag.Bool("version", false, "Show version")
flag.Parse()
@@ -146,7 +147,7 @@ func main() {
log.Println("Connection limit", descriptorLimit)
go monitorLimits()
} else if err != nil && runtime.GOOS != "windows" {
} else if err != nil && !build.IsWindows {
log.Println("Assuming no connection limit, due to error retrieving rlimits:", err)
}
@@ -186,10 +187,11 @@ func main() {
}
wrapper := config.Wrap("config", config.New(id), id, events.NoopLogger)
wrapper.SetOptions(config.OptionsConfiguration{
NATLeaseM: natLease,
NATRenewalM: natRenewal,
NATTimeoutS: natTimeout,
go wrapper.Serve(context.TODO())
wrapper.Modify(func(cfg *config.Configuration) {
cfg.Options.NATLeaseM = natLease
cfg.Options.NATRenewalM = natRenewal
cfg.Options.NATTimeoutS = natTimeout
})
natSvc := nat.NewService(id, wrapper)
mapping := mapping{natSvc.NewMapping(nat.TCP, addr.IP, addr.Port)}
@@ -199,7 +201,7 @@ func main() {
go natSvc.Serve(ctx)
defer cancel()
found := make(chan struct{})
mapping.OnChanged(func(_ *nat.Mapping, _, _ []nat.Address) {
mapping.OnChanged(func() {
select {
case found <- struct{}{}:
default:
@@ -229,13 +231,37 @@ func main() {
go statusService(statusAddr)
}
uri, err := url.Parse(fmt.Sprintf("relay://%s/?id=%s&pingInterval=%s&networkTimeout=%s&sessionLimitBps=%d&globalLimitBps=%d&statusAddr=%s&providedBy=%s", mapping.Address(), id, pingInterval, networkTimeout, sessionLimitBps, globalLimitBps, statusAddr, providedBy))
uri, err := url.Parse(fmt.Sprintf("relay://%s/", mapping.Address()))
if err != nil {
log.Fatalln("Failed to construct URI", err)
return
}
// Add properly encoded query string parameters to URL.
query := make(url.Values)
query.Set("id", id.String())
query.Set("pingInterval", pingInterval.String())
query.Set("networkTimeout", networkTimeout.String())
if sessionLimitBps > 0 {
query.Set("sessionLimitBps", fmt.Sprint(sessionLimitBps))
}
if globalLimitBps > 0 {
query.Set("globalLimitBps", fmt.Sprint(globalLimitBps))
}
if statusAddr != "" {
query.Set("statusAddr", statusAddr)
}
if providedBy != "" {
query.Set("providedBy", providedBy)
}
uri.RawQuery = query.Encode()
log.Println("URI:", uri.String())
if token != "" {
poolAddrs = ""
}
if poolAddrs == defaultPoolAddrs {
log.Println("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!")
log.Println("!! Joining default relay pools, this relay will be available for public use. !!")
@@ -247,11 +273,11 @@ func main() {
for _, pool := range pools {
pool = strings.TrimSpace(pool)
if len(pool) > 0 {
go poolHandler(pool, uri, mapping)
go poolHandler(pool, uri, mapping, cert)
}
}
go listener(proto, listen, tlsCfg)
go listener(proto, listen, tlsCfg, token)
sigs := make(chan os.Signal, 1)
signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM)
@@ -282,10 +308,10 @@ func main() {
func monitorLimits() {
limitCheckTimer = time.NewTimer(time.Minute)
for range limitCheckTimer.C {
if atomic.LoadInt64(&numConnections)+atomic.LoadInt64(&numProxies) > descriptorLimit {
atomic.StoreInt32(&overLimit, 1)
if numConnections.Load()+numProxies.Load() > descriptorLimit {
overLimit.Store(true)
log.Println("Gone past our connection limits. Starting to refuse new/drop idle connections.")
} else if atomic.CompareAndSwapInt32(&overLimit, 1, 0) {
} else if overLimit.CompareAndSwap(true, false) {
log.Println("Dropped below our connection limits. Accepting new connections.")
}
limitCheckTimer.Reset(time.Minute)

View File

@@ -4,8 +4,9 @@ package main
import (
"bytes"
"crypto/tls"
"encoding/json"
"io/ioutil"
"io"
"log"
"net/http"
"net/url"
@@ -16,7 +17,7 @@ const (
httpStatusEnhanceYourCalm = 429
)
func poolHandler(pool string, uri *url.URL, mapping mapping) {
func poolHandler(pool string, uri *url.URL, mapping mapping, ownCert tls.Certificate) {
if debug {
log.Println("Joining", pool)
}
@@ -31,14 +32,31 @@ func poolHandler(pool string, uri *url.URL, mapping mapping) {
uriCopy.String(),
})
resp, err := httpClient.Post(pool, "application/json", &b)
poolUrl, err := url.Parse(pool)
if err != nil {
log.Printf("Could not parse pool url '%s': %v", pool, err)
}
client := http.DefaultClient
if poolUrl.Scheme == "https" {
// Sent our certificate in join request
client = &http.Client{
Transport: &http.Transport{
TLSClientConfig: &tls.Config{
Certificates: []tls.Certificate{ownCert},
},
},
}
}
resp, err := client.Post(pool, "application/json", &b)
if err != nil {
log.Printf("Error joining pool %v: HTTP request: %v", pool, err)
time.Sleep(time.Minute)
continue
}
bs, err := ioutil.ReadAll(resp.Body)
bs, err := io.ReadAll(resp.Body)
resp.Body.Close()
if err != nil {
log.Printf("Error joining pool %v: reading response: %v", pool, err)
@@ -56,9 +74,8 @@ func poolHandler(pool string, uri *url.URL, mapping mapping) {
log.Printf("Joined pool %s, rejoining in %v", pool, rejoin)
time.Sleep(rejoin)
continue
} else {
log.Printf("Joined pool %s, failed to deserialize response: %v", pool, err)
}
log.Printf("Joined pool %s, failed to deserialize response: %v", pool, err)
case http.StatusInternalServerError:
log.Printf("Failed to join %v: server error", pool)

View File

@@ -23,8 +23,8 @@ var (
sessionMut = sync.RWMutex{}
activeSessions = make([]*session, 0)
pendingSessions = make(map[string]*session)
numProxies int64
bytesProxied int64
numProxies atomic.Int64
bytesProxied atomic.Int64
)
func newSession(serverid, clientid syncthingprotocol.DeviceID, sessionRateLimit, globalRateLimit *rate.Limiter) *session {
@@ -251,8 +251,8 @@ func (s *session) proxy(c1, c2 net.Conn) error {
log.Println("Proxy", c1.RemoteAddr(), "->", c2.RemoteAddr())
}
atomic.AddInt64(&numProxies, 1)
defer atomic.AddInt64(&numProxies, -1)
numProxies.Add(1)
defer numProxies.Add(-1)
buf := make([]byte, networkBufferSize)
for {
@@ -262,7 +262,7 @@ func (s *session) proxy(c1, c2 net.Conn) error {
return err
}
atomic.AddInt64(&bytesProxied, int64(n))
bytesProxied.Add(int64(n))
if debug {
log.Printf("%d bytes from %s to %s", n, c1.RemoteAddr(), c2.RemoteAddr())

View File

@@ -36,7 +36,7 @@ func statusService(addr string) {
}
}
func getStatus(w http.ResponseWriter, r *http.Request) {
func getStatus(w http.ResponseWriter, _ *http.Request) {
w.Header().Set("Access-Control-Allow-Origin", "*")
status := make(map[string]interface{})
@@ -51,9 +51,9 @@ func getStatus(w http.ResponseWriter, r *http.Request) {
status["numPendingSessionKeys"] = len(pendingSessions)
status["numActiveSessions"] = len(activeSessions)
sessionMut.Unlock()
status["numConnections"] = atomic.LoadInt64(&numConnections)
status["numProxies"] = atomic.LoadInt64(&numProxies)
status["bytesProxied"] = atomic.LoadInt64(&bytesProxied)
status["numConnections"] = numConnections.Load()
status["numProxies"] = numProxies.Load()
status["bytesProxied"] = bytesProxied.Load()
status["goVersion"] = runtime.Version()
status["goOS"] = runtime.GOOS
status["goArch"] = runtime.GOARCH
@@ -88,13 +88,13 @@ func getStatus(w http.ResponseWriter, r *http.Request) {
}
type rateCalculator struct {
counter *int64 // atomic, must remain 64-bit aligned
counter *atomic.Int64
rates []int64
prev int64
startTime time.Time
}
func newRateCalculator(keepIntervals int, interval time.Duration, counter *int64) *rateCalculator {
func newRateCalculator(keepIntervals int, interval time.Duration, counter *atomic.Int64) *rateCalculator {
r := &rateCalculator{
rates: make([]int64, keepIntervals),
counter: counter,
@@ -112,7 +112,7 @@ func (r *rateCalculator) updateRates(interval time.Duration) {
next := now.Truncate(interval).Add(interval)
time.Sleep(next.Sub(now))
cur := atomic.LoadInt64(r.counter)
cur := r.counter.Load()
rate := int64(float64(cur-r.prev) / interval.Seconds())
copy(r.rates[1:], r.rates)
r.rates[0] = rate

View File

@@ -57,7 +57,7 @@ func main() {
if join {
log.Println("Creating client")
relay, err := client.NewClient(uri, []tls.Certificate{cert}, nil, 10*time.Second)
relay, err := client.NewClient(uri, []tls.Certificate{cert}, 10*time.Second)
if err != nil {
log.Fatal(err)
}
@@ -127,10 +127,6 @@ func stdinReader(c chan<- string) {
}
func connectToStdio(stdin <-chan string, conn net.Conn) {
go func() {
}()
buf := make([]byte, 1024)
for {
conn.SetReadDeadline(time.Now().Add(time.Millisecond))

View File

@@ -9,7 +9,6 @@ package main
import (
"flag"
"io"
"io/ioutil"
"log"
"os"
@@ -69,7 +68,7 @@ func gen() {
}
func sign(keyname, dataname string) {
privkey, err := ioutil.ReadFile(keyname)
privkey, err := os.ReadFile(keyname)
if err != nil {
log.Fatal(err)
}
@@ -95,7 +94,7 @@ func sign(keyname, dataname string) {
}
func verifyWithFile(signame, dataname, keyname string) {
pubkey, err := ioutil.ReadFile(keyname)
pubkey, err := os.ReadFile(keyname)
if err != nil {
log.Fatal(err)
}
@@ -103,7 +102,7 @@ func verifyWithFile(signame, dataname, keyname string) {
}
func verifyWithKey(signame, dataname string, pubkey []byte) {
sig, err := ioutil.ReadFile(signame)
sig, err := os.ReadFile(signame)
if err != nil {
log.Fatal(err)
}

View File

@@ -7,31 +7,122 @@
package main
import (
"bytes"
"encoding/json"
"flag"
"fmt"
"io"
"log"
"net/http"
"os"
"sort"
"strings"
"time"
"github.com/alecthomas/kong"
"github.com/syncthing/syncthing/lib/httpcache"
"github.com/syncthing/syncthing/lib/upgrade"
)
const defaultURL = "https://api.github.com/repos/syncthing/syncthing/releases?per_page=25"
type cli struct {
Listen string `default:":8080" help:"Listen address"`
URL string `short:"u" default:"https://api.github.com/repos/syncthing/syncthing/releases?per_page=25" help:"GitHub releases url"`
Forward []string `short:"f" help:"Forwarded pages, format: /path->https://example/com/url"`
CacheTime time.Duration `default:"15m" help:"Cache time"`
}
func main() {
url := flag.String("u", defaultURL, "GitHub releases url")
flag.Parse()
rels := upgrade.FetchLatestReleases(*url, "")
if rels == nil {
// An error was already logged
var params cli
kong.Parse(&params)
if err := server(&params); err != nil {
fmt.Printf("Error: %v\n", err)
os.Exit(1)
}
}
func server(params *cli) error {
http.Handle("/meta.json", httpcache.SinglePath(&githubReleases{url: params.URL}, params.CacheTime))
for _, fwd := range params.Forward {
path, url, ok := strings.Cut(fwd, "->")
if !ok {
return fmt.Errorf("invalid forward: %q", fwd)
}
http.Handle(path, httpcache.SinglePath(&proxy{url: url}, params.CacheTime))
}
return http.ListenAndServe(params.Listen, nil)
}
type githubReleases struct {
url string
}
func (p *githubReleases) ServeHTTP(w http.ResponseWriter, _ *http.Request) {
log.Println("Fetching", p.url)
rels := upgrade.FetchLatestReleases(p.url, "")
if rels == nil {
http.Error(w, "no releases", http.StatusInternalServerError)
return
}
sort.Sort(upgrade.SortByRelease(rels))
rels = filterForLatest(rels)
if err := json.NewEncoder(os.Stdout).Encode(rels); err != nil {
os.Exit(1)
// Move the URL used for browser downloads to the URL field, and remove
// the browser URL field. This avoids going via the GitHub API for
// downloads, since Syncthing uses the URL field.
for _, rel := range rels {
for j, asset := range rel.Assets {
rel.Assets[j].URL = asset.BrowserURL
rel.Assets[j].BrowserURL = ""
}
}
buf := new(bytes.Buffer)
_ = json.NewEncoder(buf).Encode(rels)
w.Header().Set("Content-Type", "application/json; charset=utf-8")
w.Header().Set("Access-Control-Allow-Origin", "*")
w.Header().Set("Access-Control-Allow-Methods", "GET")
w.Write(buf.Bytes())
}
type proxy struct {
url string
}
func (p *proxy) ServeHTTP(w http.ResponseWriter, req *http.Request) {
log.Println("Fetching", p.url)
req, err := http.NewRequestWithContext(req.Context(), http.MethodGet, p.url, nil)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
resp, err := http.DefaultClient.Do(req)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
defer resp.Body.Close()
ct := resp.Header.Get("Content-Type")
w.Header().Set("Content-Type", ct)
if resp.StatusCode == http.StatusOK {
w.Header().Set("Cache-Control", "public, max-age=900")
w.Header().Set("Access-Control-Allow-Origin", "*")
w.Header().Set("Access-Control-Allow-Methods", "GET")
}
w.WriteHeader(resp.StatusCode)
if strings.HasPrefix(ct, "application/json") {
// Special JSON handling; clean it up a bit.
var v interface{}
if err := json.NewDecoder(resp.Body).Decode(&v); err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
_ = json.NewEncoder(w).Encode(v)
} else {
_, _ = io.Copy(w, resp.Body)
}
}

View File

@@ -37,14 +37,14 @@ type result struct {
func main() {
flag.Parse()
prefix := strings.ToUpper(strings.Replace(flag.Arg(0), "-", "", -1))
prefix := strings.ToUpper(strings.ReplaceAll(flag.Arg(0), "-", ""))
if len(prefix) > 7 {
prefix = prefix[:7] + "-" + prefix[7:]
}
found := make(chan result)
stop := make(chan struct{})
var count int64
var count atomic.Int64
// Print periodic progress reports.
go printProgress(prefix, &count)
@@ -72,7 +72,7 @@ func main() {
// Try certificates until one is found that has the prefix at the start of
// the resulting device ID. Increments count atomically, sends the result to
// found, returns when stop is closed.
func generatePrefixed(prefix string, count *int64, found chan<- result, stop <-chan struct{}) {
func generatePrefixed(prefix string, count *atomic.Int64, found chan<- result, stop <-chan struct{}) {
notBefore := time.Now()
notAfter := time.Date(2049, 12, 31, 23, 59, 59, 0, time.UTC)
@@ -109,7 +109,7 @@ func generatePrefixed(prefix string, count *int64, found chan<- result, stop <-c
}
id := protocol.NewDeviceID(derBytes)
atomic.AddInt64(count, 1)
count.Add(1)
if strings.HasPrefix(id.String(), prefix) {
select {
@@ -121,7 +121,7 @@ func generatePrefixed(prefix string, count *int64, found chan<- result, stop <-c
}
}
func printProgress(prefix string, count *int64) {
func printProgress(prefix string, count *atomic.Int64) {
started := time.Now()
wantBits := 5 * len(prefix)
if wantBits > 63 {
@@ -132,7 +132,7 @@ func printProgress(prefix string, count *int64) {
fmt.Printf("Want %d bits for prefix %q, about %.2g certs to test (statistically speaking)\n", wantBits, prefix, expectedIterations)
for range time.NewTicker(15 * time.Second).C {
tried := atomic.LoadInt64(count)
tried := count.Load()
elapsed := time.Since(started)
rate := float64(tried) / elapsed.Seconds()
expected := timeStr(expectedIterations / rate)

View File

@@ -7,31 +7,15 @@
package main
import (
"bytes"
"crypto/md5"
"flag"
"fmt"
"io"
"os"
"time"
"github.com/syncthing/syncthing/lib/sha256"
)
func getmd5(filePath string) ([]byte, error) {
var result []byte
file, err := os.Open(filePath)
if err != nil {
return result, err
}
defer file.Close()
hash := md5.New()
if _, err := io.Copy(hash, file); err != nil {
return result, err
}
return hash.Sum(result), nil
}
func main() {
period := flag.Duration("period", 200*time.Millisecond, "Sleep period between checks")
flag.Parse()
@@ -46,7 +30,7 @@ func main() {
exists := true
size := int64(0)
mtime := time.Time{}
hash := []byte{}
var hash [sha256.Size]byte
for {
time.Sleep(*period)
@@ -72,7 +56,7 @@ func main() {
if !exists {
size = 0
mtime = time.Time{}
hash = []byte{}
hash = [sha256.Size]byte{}
continue
}
@@ -83,12 +67,12 @@ func main() {
newSize := fi.Size()
newMtime := fi.ModTime()
newHash, err := getmd5(file)
newHash, err := sha256file(file)
if err != nil {
fmt.Println("getmd5:", err)
fmt.Println("sha256file:", err)
}
if newSize != size || newMtime != mtime || !bytes.Equal(newHash, hash) {
if newSize != size || newMtime != mtime || newHash != hash {
fmt.Println(file, "Size:", newSize, "Mtime:", newMtime, "Hash:", fmt.Sprintf("%x", newHash))
hash = newHash
size = newSize
@@ -96,3 +80,18 @@ func main() {
}
}
}
func sha256file(fname string) (hash [sha256.Size]byte, err error) {
f, err := os.Open(fname)
if err != nil {
return
}
defer f.Close()
h := sha256.New()
io.Copy(h, f)
hb := h.Sum(nil)
copy(hash[:], hb)
return
}

View File

@@ -15,19 +15,17 @@ import (
"time"
)
func init() {
if innerProcess && os.Getenv("STBLOCKPROFILE") != "" {
profiler := pprof.Lookup("block")
if profiler == nil {
panic("Couldn't find block profiler")
}
l.Debugln("Starting block profiling")
go func() {
err := saveBlockingProfiles(profiler) // Only returns on error
l.Warnln("Block profiler failed:", err)
panic("Block profiler failed")
}()
func startBlockProfiler() {
profiler := pprof.Lookup("block")
if profiler == nil {
panic("Couldn't find block profiler")
}
l.Debugln("Starting block profiling")
go func() {
err := saveBlockingProfiles(profiler) // Only returns on error
l.Warnln("Block profiler failed:", err)
panic("Block profiler failed")
}()
}
func saveBlockingProfiles(profiler *pprof.Profile) error {

172
cmd/syncthing/cli/client.go Normal file
View File

@@ -0,0 +1,172 @@
// 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 cli
import (
"bytes"
"context"
"crypto/tls"
"encoding/json"
"errors"
"fmt"
"io"
"net"
"net/http"
"strings"
"github.com/syncthing/syncthing/lib/config"
"github.com/syncthing/syncthing/lib/events"
"github.com/syncthing/syncthing/lib/locations"
"github.com/syncthing/syncthing/lib/protocol"
)
type APIClient interface {
Get(url string) (*http.Response, error)
Post(url, body string) (*http.Response, error)
PutJSON(url string, o interface{}) (*http.Response, error)
}
type apiClient struct {
http.Client
cfg config.GUIConfiguration
apikey string
}
type apiClientFactory struct {
cfg config.GUIConfiguration
}
func (f *apiClientFactory) getClient() (APIClient, error) {
// Now if the API key and address is not provided (we are not connecting to a remote instance),
// try to rip it out of the config.
if f.cfg.RawAddress == "" && f.cfg.APIKey == "" {
var err error
f.cfg, err = loadGUIConfig()
if err != nil {
return nil, err
}
} else if f.cfg.Address() == "" || f.cfg.APIKey == "" {
return nil, errors.New("Both --gui-address and --gui-apikey should be specified")
}
httpClient := http.Client{
Transport: &http.Transport{
TLSClientConfig: &tls.Config{
InsecureSkipVerify: true,
},
DialContext: func(_ context.Context, _, _ string) (net.Conn, error) {
return net.Dial(f.cfg.Network(), f.cfg.Address())
},
},
}
return &apiClient{
Client: httpClient,
cfg: f.cfg,
apikey: f.cfg.APIKey,
}, nil
}
func loadGUIConfig() (config.GUIConfiguration, error) {
// Load the certs and get the ID
cert, err := tls.LoadX509KeyPair(
locations.Get(locations.CertFile),
locations.Get(locations.KeyFile),
)
if err != nil {
return config.GUIConfiguration{}, fmt.Errorf("reading device ID: %w", err)
}
myID := protocol.NewDeviceID(cert.Certificate[0])
// Load the config
cfg, _, err := config.Load(locations.Get(locations.ConfigFile), myID, events.NoopLogger)
if err != nil {
return config.GUIConfiguration{}, fmt.Errorf("loading config: %w", err)
}
guiCfg := cfg.GUI()
if guiCfg.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 guiCfg, nil
}
func (c *apiClient) Endpoint() string {
if c.cfg.Network() == "unix" {
return "http://unix/"
}
url := c.cfg.URL()
if !strings.HasSuffix(url, "/") {
url += "/"
}
return url
}
func (c *apiClient) Do(req *http.Request) (*http.Response, error) {
req.Header.Set("X-API-Key", c.apikey)
resp, err := c.Client.Do(req)
if err != nil {
return nil, err
}
return resp, checkResponse(resp)
}
func (c *apiClient) Request(url, method string, r io.Reader) (*http.Response, error) {
request, err := http.NewRequest(method, c.Endpoint()+"rest/"+url, r)
if err != nil {
return nil, err
}
return c.Do(request)
}
func (c *apiClient) RequestString(url, method, data string) (*http.Response, error) {
return c.Request(url, method, bytes.NewBufferString(data))
}
func (c *apiClient) RequestJSON(url, method string, o interface{}) (*http.Response, error) {
data, err := json.Marshal(o)
if err != nil {
return nil, err
}
return c.Request(url, method, bytes.NewBuffer(data))
}
func (c *apiClient) Get(url string) (*http.Response, error) {
return c.RequestString(url, "GET", "")
}
func (c *apiClient) Post(url, body string) (*http.Response, error) {
return c.RequestString(url, "POST", body)
}
func (c *apiClient) PutJSON(url string, o interface{}) (*http.Response, error) {
return c.RequestJSON(url, "PUT", o)
}
var errNotFound = errors.New("invalid endpoint or API call")
func checkResponse(response *http.Response) error {
if response.StatusCode == http.StatusNotFound {
return errNotFound
} else if response.StatusCode == http.StatusUnauthorized {
return errors.New("invalid API key")
} else if response.StatusCode != http.StatusOK {
data, err := responseToBArray(response)
if err != nil {
return err
}
body := strings.TrimSpace(string(data))
return fmt.Errorf("unexpected HTTP status returned: %s\n%s", response.Status, body)
}
return nil
}

View File

@@ -0,0 +1,87 @@
// Copyright (C) 2021 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 cli
import (
"encoding/json"
"errors"
"fmt"
"reflect"
"github.com/AudriusButkevicius/recli"
"github.com/syncthing/syncthing/lib/config"
"github.com/urfave/cli"
)
type configHandler struct {
original, cfg config.Configuration
client APIClient
err error
}
func getConfigCommand(f *apiClientFactory) (cli.Command, error) {
h := new(configHandler)
h.client, h.err = f.getClient()
if h.err == nil {
h.cfg, h.err = getConfig(h.client)
}
h.original = h.cfg.Copy()
// Copy the config and set the default flags
recliCfg := recli.DefaultConfig
recliCfg.IDTag.Name = "xml"
recliCfg.SkipTag.Name = "json"
commands, err := recli.New(recliCfg).Construct(&h.cfg)
if err != nil {
return cli.Command{}, fmt.Errorf("config reflect: %w", err)
}
return cli.Command{
Name: "config",
HideHelp: true,
Usage: "Configuration modification command group",
Subcommands: commands,
Before: h.configBefore,
After: h.configAfter,
}, nil
}
func (h *configHandler) configBefore(c *cli.Context) error {
for _, arg := range c.Args() {
if arg == "--help" || arg == "-h" {
return nil
}
}
return h.err
}
func (h *configHandler) configAfter(_ *cli.Context) error {
if h.err != nil {
// Error was already returned in configBefore
return nil
}
if reflect.DeepEqual(h.cfg, h.original) {
return nil
}
body, err := json.MarshalIndent(h.cfg, "", " ")
if err != nil {
return err
}
resp, err := h.client.Post("system/config", string(body))
if err != nil {
return err
}
if resp.StatusCode != 200 {
body, err := responseToBArray(resp)
if err != nil {
return err
}
return errors.New(string(body))
}
return nil
}

View File

@@ -0,0 +1,55 @@
// Copyright (C) 2021 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 cli
import (
"fmt"
"net/url"
"github.com/urfave/cli"
)
var debugCommand = cli.Command{
Name: "debug",
HideHelp: true,
Usage: "Debug command group",
Subcommands: []cli.Command{
{
Name: "file",
Usage: "Show information about a file (or directory/symlink)",
ArgsUsage: "FOLDER-ID PATH",
Action: expects(2, debugFile()),
},
indexCommand,
{
Name: "profile",
Usage: "Save a profile to help figuring out what Syncthing does.",
ArgsUsage: "cpu | heap",
Action: expects(1, profile()),
},
},
}
func debugFile() cli.ActionFunc {
return func(c *cli.Context) error {
query := make(url.Values)
query.Set("folder", c.Args()[0])
query.Set("file", normalizePath(c.Args()[1]))
return indexDumpOutput("debug/file?" + query.Encode())(c)
}
}
func profile() cli.ActionFunc {
return func(c *cli.Context) error {
switch t := c.Args()[0]; t {
case "cpu", "heap":
return saveToFile(fmt.Sprintf("debug/%vprof", c.Args()[0]))(c)
default:
return fmt.Errorf("expected cpu or heap as argument, got %v", t)
}
}
}

View File

@@ -4,7 +4,7 @@
// 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 main
package cli
import (
"errors"
@@ -22,12 +22,12 @@ var errorsCommand = cli.Command{
{
Name: "show",
Usage: "Show pending errors",
Action: expects(0, dumpOutput("system/error")),
Action: expects(0, indexDumpOutput("system/error")),
},
{
Name: "push",
Usage: "Push an error to active clients",
ArgsUsage: "[error message]",
ArgsUsage: "ERROR-MESSAGE",
Action: expects(1, errorsPush),
},
{
@@ -39,7 +39,7 @@ var errorsCommand = cli.Command{
}
func errorsPush(c *cli.Context) error {
client := c.App.Metadata["client"].(*APIClient)
client := c.App.Metadata["client"].(APIClient)
errStr := strings.Join(c.Args(), " ")
response, err := client.Post("system/error", strings.TrimSpace(errStr))
if err != nil {

View File

@@ -0,0 +1,38 @@
// Copyright (C) 2014 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 cli
import (
"github.com/urfave/cli"
)
var indexCommand = cli.Command{
Name: "index",
Usage: "Show information about the index (database)",
Subcommands: []cli.Command{
{
Name: "dump",
Usage: "Print the entire db",
Action: expects(0, indexDump),
},
{
Name: "dump-size",
Usage: "Print the db size of different categories of information",
Action: expects(0, indexDumpSize),
},
{
Name: "check",
Usage: "Check the database for inconsistencies",
Action: expects(0, indexCheck),
},
{
Name: "account",
Usage: "Print key and value size statistics per key type",
Action: expects(0, indexAccount),
},
},
}

View File

@@ -4,22 +4,26 @@
// 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 main
package cli
import (
"fmt"
"log"
"os"
"text/tabwriter"
"github.com/syncthing/syncthing/lib/db/backend"
"github.com/urfave/cli"
)
// account prints key and data size statistics per class
func account(ldb backend.Backend) {
// indexAccount prints key and data size statistics per class
func indexAccount(*cli.Context) error {
ldb, err := getDB()
if err != nil {
return err
}
it, err := ldb.NewPrefixIterator(nil)
if err != nil {
log.Fatal(err)
return err
}
var ksizes [256]int
@@ -55,4 +59,6 @@ func account(ldb backend.Backend) {
}
fmt.Fprintf(tw, "Total\t%d items,\t%d KB keys +\t%d KB data.\t\n", toti, totks/1000, totds/1000)
tw.Flush()
return nil
}

View File

@@ -4,23 +4,27 @@
// 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 main
package cli
import (
"encoding/binary"
"fmt"
"log"
"time"
"github.com/urfave/cli"
"github.com/syncthing/syncthing/lib/db"
"github.com/syncthing/syncthing/lib/db/backend"
"github.com/syncthing/syncthing/lib/protocol"
)
func dump(ldb backend.Backend) {
func indexDump(*cli.Context) error {
ldb, err := getDB()
if err != nil {
return err
}
it, err := ldb.NewPrefixIterator(nil)
if err != nil {
log.Fatal(err)
return err
}
for it.Next() {
key := it.Key()
@@ -34,7 +38,7 @@ func dump(ldb backend.Backend) {
var f protocol.FileInfo
err := f.Unmarshal(it.Value())
if err != nil {
log.Fatal(err)
return err
}
fmt.Printf(" V:%v\n", f)
@@ -61,10 +65,10 @@ func dump(ldb backend.Backend) {
folder := binary.BigEndian.Uint32(key[1:])
name := nulString(key[1+4:])
val := it.Value()
var real, virt time.Time
real.UnmarshalBinary(val[:len(val)/2])
virt.UnmarshalBinary(val[len(val)/2:])
fmt.Printf("[mtime] F:%d N:%q R:%v V:%v\n", folder, name, real, virt)
var realTime, virtualTime time.Time
realTime.UnmarshalBinary(val[:len(val)/2])
virtualTime.UnmarshalBinary(val[len(val)/2:])
fmt.Printf("[mtime] F:%d N:%q R:%v V:%v\n", folder, name, realTime, virtualTime)
case db.KeyTypeFolderIdx:
key := binary.BigEndian.Uint32(key[1:])
@@ -131,8 +135,26 @@ func dump(ldb backend.Backend) {
fmt.Printf(" V:%v\n", v)
}
case db.KeyTypePendingFolder:
device := binary.BigEndian.Uint32(key[1:])
folder := string(key[5:])
var of db.ObservedFolder
of.Unmarshal(it.Value())
fmt.Printf("[pendingFolder] D:%d F:%s V:%v\n", device, folder, of)
case db.KeyTypePendingDevice:
device := "<invalid>"
dev, err := protocol.DeviceIDFromBytes(key[1:])
if err == nil {
device = dev.String()
}
var od db.ObservedDevice
od.Unmarshal(it.Value())
fmt.Printf("[pendingDevice] D:%v V:%v\n", device, od)
default:
fmt.Printf("[??? %d]\n %x\n %x\n", key[0], key, it.Value())
}
}
return nil
}

View File

@@ -4,51 +4,38 @@
// 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 main
package cli
import (
"container/heap"
"encoding/binary"
"fmt"
"log"
"sort"
"github.com/urfave/cli"
"github.com/syncthing/syncthing/lib/db"
"github.com/syncthing/syncthing/lib/db/backend"
)
type SizedElement struct {
key string
size int
}
func indexDumpSize(*cli.Context) error {
type sizedElement struct {
key string
size int
}
type ElementHeap []SizedElement
func (h ElementHeap) Len() int { return len(h) }
func (h ElementHeap) Less(i, j int) bool { return h[i].size > h[j].size }
func (h ElementHeap) Swap(i, j int) { h[i], h[j] = h[j], h[i] }
func (h *ElementHeap) Push(x interface{}) {
*h = append(*h, x.(SizedElement))
}
func (h *ElementHeap) Pop() interface{} {
old := *h
n := len(old)
x := old[n-1]
*h = old[0 : n-1]
return x
}
func dumpsize(ldb backend.Backend) {
h := &ElementHeap{}
heap.Init(h)
ldb, err := getDB()
if err != nil {
return err
}
it, err := ldb.NewPrefixIterator(nil)
if err != nil {
log.Fatal(err)
return err
}
var ele SizedElement
var elems []sizedElement
for it.Next() {
var ele sizedElement
key := it.Key()
switch key[0] {
case db.KeyTypeDevice:
@@ -89,11 +76,15 @@ func dumpsize(ldb backend.Backend) {
ele.key = fmt.Sprintf("UNKNOWN:%x", key)
}
ele.size = len(it.Value())
heap.Push(h, ele)
elems = append(elems, ele)
}
for h.Len() > 0 {
ele = heap.Pop(h).(SizedElement)
sort.Slice(elems, func(i, j int) bool {
return elems[i].size > elems[j].size
})
for _, ele := range elems {
fmt.Println(ele.key, ele.size)
}
return nil
}

View File

@@ -4,17 +4,18 @@
// 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 main
package cli
import (
"bytes"
"encoding/binary"
"errors"
"fmt"
"log"
"sort"
"github.com/urfave/cli"
"github.com/syncthing/syncthing/lib/db"
"github.com/syncthing/syncthing/lib/db/backend"
"github.com/syncthing/syncthing/lib/protocol"
)
@@ -34,7 +35,12 @@ type sequenceKey struct {
sequence uint64
}
func idxck(ldb backend.Backend) (success bool) {
func indexCheck(*cli.Context) (err error) {
ldb, err := getDB()
if err != nil {
return err
}
folders := make(map[uint32]string)
devices := make(map[uint32]string)
deviceToIDs := make(map[string]uint32)
@@ -47,11 +53,20 @@ func idxck(ldb backend.Backend) (success bool) {
usedBlocklists := make(map[string]struct{})
usedVersions := make(map[string]struct{})
var localDeviceKey uint32
success = true
success := true
defer func() {
if err == nil {
if success {
fmt.Println("Index check completed successfully.")
} else {
err = errors.New("Inconsistencies found in the index")
}
}
}()
it, err := ldb.NewPrefixIterator(nil)
if err != nil {
log.Fatal(err)
return err
}
for it.Next() {
key := it.Key()
@@ -329,12 +344,12 @@ func idxck(ldb backend.Backend) (success bool) {
fmt.Printf("%d version entries out of %d needs GC\n", d, len(versions))
}
return
return nil
}
func needsLocally(vl db.VersionList) bool {
gfv, gok := vl.GetGlobal()
if !gok { // That's weird, but we hardly need something non-existant
if !gok { // That's weird, but we hardly need something non-existent
return false
}
fv, ok := vl.Get(protocol.LocalDeviceID[:])

172
cmd/syncthing/cli/main.go Normal file
View File

@@ -0,0 +1,172 @@
// 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 cli
import (
"bufio"
"errors"
"fmt"
"io"
"os"
"strings"
"github.com/alecthomas/kong"
"github.com/flynn-archive/go-shlex"
"github.com/urfave/cli"
"github.com/syncthing/syncthing/cmd/syncthing/cmdutil"
"github.com/syncthing/syncthing/lib/config"
)
type preCli struct {
GUIAddress string `name:"gui-address"`
GUIAPIKey string `name:"gui-apikey"`
HomeDir string `name:"home"`
ConfDir string `name:"config"`
DataDir string `name:"data"`
}
func Run() error {
// This is somewhat a hack around a chicken and egg problem. We need to set
// the home directory and potentially other flags to know where the
// syncthing instance is running in order to get it's config ... which we
// then use to construct the actual CLI ... at which point it's too late to
// add flags there...
c := preCli{}
parseFlags(&c)
return runInternal(c, os.Args)
}
func RunWithArgs(cliArgs []string) error {
c := preCli{}
parseFlagsWithArgs(cliArgs, &c)
return runInternal(c, cliArgs)
}
func runInternal(c preCli, cliArgs []string) error {
// Not set as default above because the strings can be really long.
err := cmdutil.SetConfigDataLocationsFromFlags(c.HomeDir, c.ConfDir, c.DataDir)
if err != nil {
return fmt.Errorf("Command line options: %w", err)
}
clientFactory := &apiClientFactory{
cfg: config.GUIConfiguration{
RawAddress: c.GUIAddress,
APIKey: c.GUIAPIKey,
},
}
configCommand, err := getConfigCommand(clientFactory)
if err != nil {
return err
}
// Implement the same flags at the upper CLI, but do nothing with them.
// This is so that the usage text is the same
fakeFlags := []cli.Flag{
cli.StringFlag{
Name: "gui-address",
Usage: "Override GUI address to `URL` (e.g. \"192.0.2.42:8443\")",
},
cli.StringFlag{
Name: "gui-apikey",
Usage: "Override GUI API key to `API-KEY`",
},
cli.StringFlag{
Name: "home",
Usage: "Set configuration and data directory to `PATH`",
},
cli.StringFlag{
Name: "config",
Usage: "Set configuration directory (config and keys) to `PATH`",
},
cli.StringFlag{
Name: "data",
Usage: "Set data directory (database and logs) to `PATH`",
},
}
// Construct the actual CLI
app := cli.NewApp()
app.Author = "The Syncthing Authors"
app.Metadata = map[string]interface{}{
"clientFactory": clientFactory,
}
app.Commands = []cli.Command{{
Name: "cli",
Usage: "Syncthing command line interface",
Flags: fakeFlags,
Subcommands: []cli.Command{
configCommand,
showCommand,
operationCommand,
errorsCommand,
debugCommand,
{
Name: "-",
HideHelp: true,
Usage: "Read commands from stdin",
Action: func(ctx *cli.Context) error {
if ctx.NArg() > 0 {
return errors.New("command does not expect any arguments")
}
// Drop the `-` not to recurse into self.
args := make([]string, len(cliArgs)-1)
copy(args, cliArgs)
fmt.Println("Reading commands from stdin...", args)
scanner := bufio.NewScanner(os.Stdin)
for scanner.Scan() {
input, err := shlex.Split(scanner.Text())
if err != nil {
return fmt.Errorf("parsing input: %w", err)
}
if len(input) == 0 {
continue
}
err = app.Run(append(args, input...))
if err != nil {
return err
}
}
return scanner.Err()
},
},
},
}}
return app.Run(cliArgs)
}
func parseFlags(c *preCli) error {
// kong only needs to parse the global arguments after "cli" and before the
// subcommand (if any).
if len(os.Args) <= 2 {
return nil
}
return parseFlagsWithArgs(os.Args[2:], c)
}
func parseFlagsWithArgs(args []string, c *preCli) error {
for i := 0; i < len(args); i++ {
if !strings.HasPrefix(args[i], "--") {
args = args[:i]
break
}
if !strings.Contains(args[i], "=") {
i++
}
}
// We don't want kong to print anything nor os.Exit (e.g. on -h)
parser, err := kong.New(c, kong.Writers(io.Discard, io.Discard), kong.Exit(func(int) {}))
if err != nil {
return err
}
_, err = parser.Parse(args)
return err
}

View File

@@ -4,11 +4,16 @@
// 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 main
package cli
import (
"bufio"
"errors"
"fmt"
"path/filepath"
"github.com/syncthing/syncthing/lib/config"
"github.com/syncthing/syncthing/lib/fs"
"github.com/urfave/cli"
)
@@ -27,11 +32,6 @@ var operationCommand = cli.Command{
Usage: "Shutdown syncthing",
Action: expects(0, emptyPost("system/shutdown")),
},
{
Name: "reset",
Usage: "Reset syncthing deleting all folders and devices",
Action: expects(0, emptyPost("system/reset")),
},
{
Name: "upgrade",
Usage: "Upgrade syncthing (if a newer version is available)",
@@ -39,15 +39,24 @@ var operationCommand = cli.Command{
},
{
Name: "folder-override",
Usage: "Override changes on folder (remote for sendonly, local for receiveonly)",
ArgsUsage: "[folder id]",
Usage: "Override changes on folder (remote for sendonly, local for receiveonly). WARNING: Destructive - deletes/changes your data.",
ArgsUsage: "FOLDER-ID",
Action: expects(1, foldersOverride),
},
{
Name: "default-ignores",
Usage: "Set the default ignores (config) from a file",
ArgsUsage: "PATH",
Action: expects(1, setDefaultIgnores),
},
},
}
func foldersOverride(c *cli.Context) error {
client := c.App.Metadata["client"].(*APIClient)
client, err := getClientFactory(c).getClient()
if err != nil {
return err
}
cfg, err := getConfig(client)
if err != nil {
return err
@@ -69,10 +78,36 @@ func foldersOverride(c *cli.Context) error {
if body != "" {
errStr += "\nBody: " + body
}
return fmt.Errorf(errStr)
return errors.New(errStr)
}
return nil
}
}
return fmt.Errorf("Folder " + rid + " not found")
return fmt.Errorf("Folder %q not found", rid)
}
func setDefaultIgnores(c *cli.Context) error {
client, err := getClientFactory(c).getClient()
if err != nil {
return err
}
dir, file := filepath.Split(c.Args()[0])
filesystem := fs.NewFilesystem(fs.FilesystemTypeBasic, dir)
fd, err := filesystem.Open(file)
if err != nil {
return err
}
scanner := bufio.NewScanner(fd)
var lines []string
for scanner.Scan() {
lines = append(lines, scanner.Text())
}
fd.Close()
if err := scanner.Err(); err != nil {
return err
}
_, err = client.PutJSON("config/defaults/ignores", config.Ignores{Lines: lines})
return err
}

View File

@@ -0,0 +1,45 @@
// Copyright (C) 2021 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 cli
import (
"net/url"
"github.com/urfave/cli"
)
var pendingCommand = cli.Command{
Name: "pending",
HideHelp: true,
Usage: "Pending subcommand group",
Subcommands: []cli.Command{
{
Name: "devices",
Usage: "Show pending devices",
Action: expects(0, indexDumpOutput("cluster/pending/devices")),
},
{
Name: "folders",
Usage: "Show pending folders",
Flags: []cli.Flag{
cli.StringFlag{Name: "device", Usage: "Show pending folders offered by given device"},
},
Action: expects(0, folders()),
},
},
}
func folders() cli.ActionFunc {
return func(c *cli.Context) error {
if c.String("device") != "" {
query := make(url.Values)
query.Set("device", c.String("device"))
return indexDumpOutput("cluster/pending/folders?" + query.Encode())(c)
}
return indexDumpOutput("cluster/pending/folders")(c)
}
}

View File

@@ -4,7 +4,7 @@
// 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 main
package cli
import (
"github.com/urfave/cli"
@@ -18,27 +18,33 @@ var showCommand = cli.Command{
{
Name: "version",
Usage: "Show syncthing client version",
Action: expects(0, dumpOutput("system/version")),
Action: expects(0, indexDumpOutput("system/version")),
},
{
Name: "config-status",
Usage: "Show configuration status, whether or not a restart is required for changes to take effect",
Action: expects(0, dumpOutput("system/config/insync")),
Action: expects(0, indexDumpOutput("config/restart-required")),
},
{
Name: "system",
Usage: "Show system status",
Action: expects(0, dumpOutput("system/status")),
Action: expects(0, indexDumpOutput("system/status")),
},
{
Name: "connections",
Usage: "Report about connections to other devices",
Action: expects(0, dumpOutput("system/connections")),
Action: expects(0, indexDumpOutput("system/connections")),
},
{
Name: "discovery",
Usage: "Show the discovered addresses of remote devices (from cache of the running syncthing instance)",
Action: expects(0, indexDumpOutput("system/discovery")),
},
pendingCommand,
{
Name: "usage",
Usage: "Show usage report",
Action: expects(0, dumpOutput("svc/report")),
Action: expects(0, indexDumpOutput("svc/report")),
},
},
}

165
cmd/syncthing/cli/utils.go Normal file
View File

@@ -0,0 +1,165 @@
// 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 cli
import (
"encoding/json"
"errors"
"fmt"
"io"
"mime"
"net/http"
"os"
"path/filepath"
"github.com/syncthing/syncthing/lib/config"
"github.com/syncthing/syncthing/lib/db/backend"
"github.com/syncthing/syncthing/lib/locations"
"github.com/urfave/cli"
)
func responseToBArray(response *http.Response) ([]byte, error) {
bytes, err := io.ReadAll(response.Body)
if err != nil {
return nil, err
}
return bytes, response.Body.Close()
}
func emptyPost(url string) cli.ActionFunc {
return func(c *cli.Context) error {
client, err := getClientFactory(c).getClient()
if err != nil {
return err
}
_, err = client.Post(url, "")
return err
}
}
func indexDumpOutput(url string) cli.ActionFunc {
return func(c *cli.Context) error {
client, err := getClientFactory(c).getClient()
if err != nil {
return err
}
response, err := client.Get(url)
if errors.Is(err, errNotFound) {
return errors.New("not found (folder/file not in database)")
}
if err != nil {
return err
}
return prettyPrintResponse(response)
}
}
func saveToFile(url string) cli.ActionFunc {
return func(c *cli.Context) error {
client, err := getClientFactory(c).getClient()
if err != nil {
return err
}
response, err := client.Get(url)
if err != nil {
return err
}
_, params, err := mime.ParseMediaType(response.Header.Get("Content-Disposition"))
if err != nil {
return err
}
filename := params["filename"]
if filename == "" {
return errors.New("Missing filename in response")
}
bs, err := responseToBArray(response)
if err != nil {
return err
}
f, err := os.Create(filename)
if err != nil {
return err
}
defer f.Close()
_, err = f.Write(bs)
if err != nil {
return err
}
fmt.Println("Wrote results to", filename)
return err
}
}
func getConfig(c APIClient) (config.Configuration, error) {
cfg := config.Configuration{}
response, err := c.Get("system/config")
if err != nil {
return cfg, err
}
bytes, err := responseToBArray(response)
if err != nil {
return cfg, err
}
err = json.Unmarshal(bytes, &cfg)
if err != nil {
return config.Configuration{}, err
}
return cfg, nil
}
func expects(n int, actionFunc cli.ActionFunc) cli.ActionFunc {
return func(ctx *cli.Context) error {
if ctx.NArg() != n {
plural := ""
if n != 1 {
plural = "s"
}
return fmt.Errorf("expected %d argument%s, got %d", n, plural, ctx.NArg())
}
return actionFunc(ctx)
}
}
func prettyPrintJSON(data interface{}) error {
enc := json.NewEncoder(os.Stdout)
enc.SetIndent("", " ")
return enc.Encode(data)
}
func prettyPrintResponse(response *http.Response) error {
bytes, err := responseToBArray(response)
if err != nil {
return err
}
var data interface{}
if err := json.Unmarshal(bytes, &data); err != nil {
return err
}
// TODO: Check flag for pretty print format
return prettyPrintJSON(data)
}
func getDB() (backend.Backend, error) {
return backend.OpenLevelDBRO(locations.Get(locations.Database))
}
func nulString(bs []byte) string {
for i := range bs {
if bs[i] == 0 {
return string(bs[:i])
}
}
return string(bs)
}
func normalizePath(path string) string {
return filepath.ToSlash(filepath.Clean(path))
}
func getClientFactory(c *cli.Context) *apiClientFactory {
return c.App.Metadata["clientFactory"].(*apiClientFactory)
}

View File

@@ -0,0 +1,16 @@
// Copyright (C) 2021 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 cmdutil
// CommonOptions are reused among several subcommands
type CommonOptions struct {
buildCommonOptions
ConfDir string `name:"config" placeholder:"PATH" env:"STCONFDIR" help:"Set configuration directory (config and keys)"`
HomeDir string `name:"home" placeholder:"PATH" env:"STHOMEDIR" help:"Set configuration and data directory"`
NoDefaultFolder bool `env:"STNODEFAULTFOLDER" help:"Don't create the \"default\" folder on first startup"`
SkipPortProbing bool `help:"Don't try to find free ports for GUI and listen addresses on first startup"`
}

View File

@@ -1,10 +1,14 @@
// Copyright (C) 2016 The Syncthing Authors.
// Copyright (C) 2021 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/.
// The existence of this file means we get 0% test coverage rather than no
// test coverage at all. Remove when implementing an actual test.
//go:build !windows
// +build !windows
package stats
package cmdutil
type buildCommonOptions struct {
HideConsole bool `hidden:""`
}

View File

@@ -0,0 +1,11 @@
// Copyright (C) 2021 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 cmdutil
type buildCommonOptions struct {
HideConsole bool `name:"no-console" help:"Hide console window"`
}

View File

@@ -0,0 +1,35 @@
// Copyright (C) 2014 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 cmdutil
import (
"errors"
"github.com/syncthing/syncthing/lib/locations"
)
func SetConfigDataLocationsFromFlags(homeDir, confDir, dataDir string) error {
homeSet := homeDir != ""
confSet := confDir != ""
dataSet := dataDir != ""
switch {
case dataSet != confSet:
return errors.New("either both or none of --config and --data must be given, use --home to set both at once")
case homeSet && dataSet:
return errors.New("--home must not be used together with --config and --data")
case homeSet:
confDir = homeDir
dataDir = homeDir
fallthrough
case dataSet:
if err := locations.SetBaseDir(locations.ConfigBaseDir, confDir); err != nil {
return err
}
return locations.SetBaseDir(locations.DataBaseDir, dataDir)
}
return nil
}

View File

@@ -10,7 +10,6 @@ import (
"bytes"
"context"
"fmt"
"io/ioutil"
"net/http"
"os"
"path/filepath"
@@ -62,7 +61,7 @@ func uploadPanicLogs(ctx context.Context, urlBase, dir string) {
// the log contents. A HEAD request is made to see if the log has already
// been reported. If not, a PUT is made with the log contents.
func uploadPanicLog(ctx context.Context, urlBase, file string) error {
data, err := ioutil.ReadFile(file)
data, err := os.ReadFile(file)
if err != nil {
return err
}

View File

@@ -0,0 +1,289 @@
// Copyright (C) 2021 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 decrypt implements the `syncthing decrypt` subcommand.
package decrypt
import (
"encoding/binary"
"encoding/json"
"errors"
"fmt"
"io"
"log"
"os"
"path/filepath"
"github.com/syncthing/syncthing/lib/config"
"github.com/syncthing/syncthing/lib/fs"
"github.com/syncthing/syncthing/lib/osutil"
"github.com/syncthing/syncthing/lib/protocol"
"github.com/syncthing/syncthing/lib/scanner"
)
type CLI struct {
Path string `arg:"" required:"1" help:"Path to encrypted folder"`
To string `xor:"mode" placeholder:"PATH" help:"Destination directory, when decrypting"`
VerifyOnly bool `xor:"mode" help:"Don't write decrypted files to disk (but verify plaintext hashes)"`
Password string `help:"Folder password for decryption / verification" env:"FOLDER_PASSWORD"`
FolderID string `help:"Folder ID of the encrypted folder, if it cannot be determined automatically"`
Continue bool `help:"Continue processing next file in case of error, instead of aborting"`
Verbose bool `help:"Show verbose progress information"`
TokenPath string `placeholder:"PATH" help:"Path to the token file within the folder (used to determine folder ID)"`
folderKey *[32]byte
keyGen *protocol.KeyGenerator
}
type storedEncryptionToken struct {
FolderID string
Token []byte
}
func (c *CLI) Run() error {
log.SetFlags(0)
if c.To == "" && !c.VerifyOnly {
return errors.New("must set --to or --verify-only")
}
if c.TokenPath == "" {
// This is a bit long to show as default in --help
c.TokenPath = filepath.Join(config.DefaultMarkerName, config.EncryptionTokenName)
}
if c.FolderID == "" {
// We should try to figure out the folder ID
folderID, err := c.getFolderID()
if err != nil {
log.Println("No --folder-id given and couldn't read folder token")
return fmt.Errorf("getting folder ID: %w", err)
}
c.FolderID = folderID
if c.Verbose {
log.Println("Found folder ID:", c.FolderID)
}
}
c.keyGen = protocol.NewKeyGenerator()
c.folderKey = c.keyGen.KeyFromPassword(c.FolderID, c.Password)
return c.walk()
}
// walk finds and processes every file in the encrypted folder
func (c *CLI) walk() error {
srcFs := fs.NewFilesystem(fs.FilesystemTypeBasic, c.Path)
var dstFs fs.Filesystem
if c.To != "" {
dstFs = fs.NewFilesystem(fs.FilesystemTypeBasic, c.To)
}
return srcFs.Walk(".", func(path string, info fs.FileInfo, err error) error {
if err != nil {
return err
}
if !info.IsRegular() {
return nil
}
if fs.IsInternal(path) {
return nil
}
return c.withContinue(c.process(srcFs, dstFs, path))
})
}
// If --continue was set we just mention the error and return nil to
// continue processing.
func (c *CLI) withContinue(err error) error {
if err == nil {
return nil
}
if c.Continue {
log.Println("Warning:", err)
return nil
}
return err
}
// getFolderID returns the folder ID found in the encrypted token, or an
// error.
func (c *CLI) getFolderID() (string, error) {
tokenPath := filepath.Join(c.Path, c.TokenPath)
bs, err := os.ReadFile(tokenPath)
if err != nil {
return "", fmt.Errorf("reading folder token: %w", err)
}
var tok storedEncryptionToken
if err := json.Unmarshal(bs, &tok); err != nil {
return "", fmt.Errorf("parsing folder token: %w", err)
}
return tok.FolderID, nil
}
// process handles the file named path in srcFs, decrypting it into dstFs
// unless dstFs is nil.
func (c *CLI) process(srcFs fs.Filesystem, dstFs fs.Filesystem, path string) error {
// Which filemode bits to preserve
const retainBits = fs.ModePerm | fs.ModeSetgid | fs.ModeSetuid | fs.ModeSticky
if c.Verbose {
log.Printf("Processing %q", path)
}
encFd, err := srcFs.Open(path)
if err != nil {
return err
}
defer encFd.Close()
encFi, err := loadEncryptedFileInfo(encFd)
if err != nil {
return fmt.Errorf("%s: loading metadata trailer: %w", path, err)
}
// Workaround for a bug in <= v1.15.0-rc.5 where we stored names
// in native format, while protocol expects wire format (slashes).
encFi.Name = osutil.NormalizedFilename(encFi.Name)
plainFi, err := protocol.DecryptFileInfo(c.keyGen, *encFi, c.folderKey)
if err != nil {
return fmt.Errorf("%s: decrypting metadata: %w", path, err)
}
if c.Verbose {
log.Printf("Plaintext filename is %q", plainFi.Name)
}
var plainFd fs.File
if dstFs != nil {
if err := dstFs.MkdirAll(filepath.Dir(plainFi.Name), 0o700); err != nil {
return fmt.Errorf("%s: %w", plainFi.Name, err)
}
plainFd, err = dstFs.Create(plainFi.Name)
if err != nil {
return fmt.Errorf("%s: %w", plainFi.Name, err)
}
defer plainFd.Close() // also closed explicitly in the return
if err := dstFs.Chmod(plainFi.Name, fs.FileMode(plainFi.Permissions&uint32(retainBits))); err != nil {
return fmt.Errorf("%s: %w", plainFi.Name, err)
}
}
if err := c.decryptFile(encFi, &plainFi, encFd, plainFd); err != nil {
// Decrypting the file failed, leaving it in an inconsistent state.
// Delete it. Even --continue currently doesn't mean "leave broken
// stuff in place", it just means "try the next file instead of
// aborting".
if plainFd != nil {
_ = dstFs.Remove(plainFd.Name())
}
return fmt.Errorf("%s: %s: %w", path, plainFi.Name, err)
} else if c.Verbose {
log.Printf("Data verified for %q", plainFi.Name)
}
if plainFd != nil {
if err := plainFd.Close(); err != nil {
return fmt.Errorf("%s: %w", plainFi.Name, err)
}
if err := dstFs.Chtimes(plainFi.Name, plainFi.ModTime(), plainFi.ModTime()); err != nil {
return fmt.Errorf("%s: %w", plainFi.Name, err)
}
}
return nil
}
// decryptFile reads, decrypts and verifies all the blocks in src, writing
// it to dst if dst is non-nil. (If dst is nil it just becomes a
// read-and-verify operation.)
func (c *CLI) decryptFile(encFi *protocol.FileInfo, plainFi *protocol.FileInfo, src io.ReaderAt, dst io.WriterAt) error {
// The encrypted and plaintext files must consist of an equal number of blocks
if len(encFi.Blocks) != len(plainFi.Blocks) {
return fmt.Errorf("block count mismatch: encrypted %d != plaintext %d", len(encFi.Blocks), len(plainFi.Blocks))
}
fileKey := c.keyGen.FileKey(plainFi.Name, c.folderKey)
for i, encBlock := range encFi.Blocks {
// Read the encrypted block
buf := make([]byte, encBlock.Size)
if _, err := src.ReadAt(buf, encBlock.Offset); err != nil {
return fmt.Errorf("encrypted block %d (%d bytes): %w", i, encBlock.Size, err)
}
// Decrypt it
dec, err := protocol.DecryptBytes(buf, fileKey)
if err != nil {
return fmt.Errorf("encrypted block %d (%d bytes): %w", i, encBlock.Size, err)
}
// Verify the block size against the expected plaintext
plainBlock := plainFi.Blocks[i]
if i == len(plainFi.Blocks)-1 && len(dec) > plainBlock.Size {
// The last block might be padded, which is fine (we skip the padding)
dec = dec[:plainBlock.Size]
} else if len(dec) != plainBlock.Size {
return fmt.Errorf("plaintext block %d size mismatch, actual %d != expected %d", i, len(dec), plainBlock.Size)
}
// Verify the hash against the plaintext block info
if !scanner.Validate(dec, plainBlock.Hash, 0) {
// The block decrypted correctly but fails the hash check. This
// is odd and unexpected, but it it's still a valid block from
// the source. The file might have changed while we pulled it?
err := fmt.Errorf("plaintext block %d (%d bytes) failed validation after decryption", i, plainBlock.Size)
if c.Continue {
log.Printf("Warning: %s: %s: %v", encFi.Name, plainFi.Name, err)
} else {
return err
}
}
// Write it to the destination, unless we're just verifying.
if dst != nil {
if _, err := dst.WriteAt(dec, plainBlock.Offset); err != nil {
return err
}
}
}
return nil
}
// loadEncryptedFileInfo loads the encrypted FileInfo trailer from a file on
// disk.
func loadEncryptedFileInfo(fd fs.File) (*protocol.FileInfo, error) {
// Seek to the size of the trailer block
if _, err := fd.Seek(-4, io.SeekEnd); err != nil {
return nil, err
}
var bs [4]byte
if _, err := io.ReadFull(fd, bs[:]); err != nil {
return nil, err
}
size := int64(binary.BigEndian.Uint32(bs[:]))
// Seek to the start of the trailer
if _, err := fd.Seek(-(4 + size), io.SeekEnd); err != nil {
return nil, err
}
trailer := make([]byte, size)
if _, err := io.ReadFull(fd, trailer); err != nil {
return nil, err
}
var encFi protocol.FileInfo
if err := encFi.Unmarshal(trailer); err != nil {
return nil, err
}
return &encFi, nil
}

View File

@@ -0,0 +1,136 @@
// Copyright (C) 2021 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 generate implements the `syncthing generate` subcommand.
package generate
import (
"bufio"
"context"
"crypto/tls"
"errors"
"fmt"
"os"
"github.com/syncthing/syncthing/cmd/syncthing/cmdutil"
"github.com/syncthing/syncthing/lib/config"
"github.com/syncthing/syncthing/lib/events"
"github.com/syncthing/syncthing/lib/fs"
"github.com/syncthing/syncthing/lib/locations"
"github.com/syncthing/syncthing/lib/logger"
"github.com/syncthing/syncthing/lib/osutil"
"github.com/syncthing/syncthing/lib/protocol"
"github.com/syncthing/syncthing/lib/syncthing"
)
type CLI struct {
cmdutil.CommonOptions
GUIUser string `placeholder:"STRING" help:"Specify new GUI authentication user name"`
GUIPassword string `placeholder:"STRING" help:"Specify new GUI authentication password (use - to read from standard input)"`
}
func (c *CLI) Run(l logger.Logger) error {
if c.HideConsole {
osutil.HideConsole()
}
if c.HomeDir != "" {
if c.ConfDir != "" {
return errors.New("--home must not be used together with --config")
}
c.ConfDir = c.HomeDir
}
if c.ConfDir == "" {
c.ConfDir = locations.GetBaseDir(locations.ConfigBaseDir)
}
// Support reading the password from a pipe or similar
if c.GUIPassword == "-" {
reader := bufio.NewReader(os.Stdin)
password, _, err := reader.ReadLine()
if err != nil {
return fmt.Errorf("failed reading GUI password: %w", err)
}
c.GUIPassword = string(password)
}
if err := Generate(l, c.ConfDir, c.GUIUser, c.GUIPassword, c.NoDefaultFolder, c.SkipPortProbing); err != nil {
return fmt.Errorf("failed to generate config and keys: %w", err)
}
return nil
}
func Generate(l logger.Logger, confDir, guiUser, guiPassword string, noDefaultFolder, skipPortProbing bool) error {
dir, err := fs.ExpandTilde(confDir)
if err != nil {
return err
}
if err := syncthing.EnsureDir(dir, 0700); err != nil {
return err
}
locations.SetBaseDir(locations.ConfigBaseDir, dir)
var myID protocol.DeviceID
certFile, keyFile := locations.Get(locations.CertFile), locations.Get(locations.KeyFile)
cert, err := tls.LoadX509KeyPair(certFile, keyFile)
if err == nil {
l.Warnln("Key exists; will not overwrite.")
} else {
cert, err = syncthing.GenerateCertificate(certFile, keyFile)
if err != nil {
return fmt.Errorf("create certificate: %w", err)
}
}
myID = protocol.NewDeviceID(cert.Certificate[0])
l.Infoln("Device ID:", myID)
cfgFile := locations.Get(locations.ConfigFile)
cfg, _, err := config.Load(cfgFile, myID, events.NoopLogger)
if fs.IsNotExist(err) {
if cfg, err = syncthing.DefaultConfig(cfgFile, myID, events.NoopLogger, noDefaultFolder, skipPortProbing); err != nil {
return fmt.Errorf("create config: %w", err)
}
} else if err != nil {
return fmt.Errorf("load config: %w", err)
}
ctx, cancel := context.WithCancel(context.Background())
go cfg.Serve(ctx)
defer cancel()
var updateErr error
waiter, err := cfg.Modify(func(cfg *config.Configuration) {
updateErr = updateGUIAuthentication(l, &cfg.GUI, guiUser, guiPassword)
})
if err != nil {
return fmt.Errorf("modify config: %w", err)
}
waiter.Wait()
if updateErr != nil {
return updateErr
}
if err := cfg.Save(); err != nil {
return fmt.Errorf("save config: %w", err)
}
return nil
}
func updateGUIAuthentication(l logger.Logger, guiCfg *config.GUIConfiguration, guiUser, guiPassword string) error {
if guiUser != "" && guiCfg.User != guiUser {
guiCfg.User = guiUser
l.Infoln("Updated GUI authentication user name:", guiUser)
}
if guiPassword != "" && guiCfg.Password != guiPassword {
if err := guiCfg.HashAndSetPassword(guiPassword); err != nil {
return fmt.Errorf("failed to set GUI authentication password: %w", err)
}
l.Infoln("Updated GUI authentication password.")
}
return nil
}

View File

@@ -11,24 +11,17 @@ import (
"os"
"runtime"
"runtime/pprof"
"strconv"
"syscall"
"time"
)
func init() {
if innerProcess && os.Getenv("STHEAPPROFILE") != "" {
rate := 1
if i, err := strconv.Atoi(os.Getenv("STHEAPPROFILE")); err == nil {
rate = i
}
l.Debugln("Starting heap profiling")
go func() {
err := saveHeapProfiles(rate) // Only returns on error
l.Warnln("Heap profiler failed:", err)
panic("Heap profiler failed")
}()
}
func startHeapProfiler() {
l.Debugln("Starting heap profiling")
go func() {
err := saveHeapProfiles(1) // Only returns on error
l.Warnln("Heap profiler failed:", err)
panic("Heap profiler failed")
}()
}
func saveHeapProfiles(rate int) error {

View File

File diff suppressed because it is too large Load Diff

View File

@@ -15,18 +15,16 @@ import (
"os/exec"
"os/signal"
"path/filepath"
"runtime"
"strings"
"syscall"
"time"
"github.com/syncthing/syncthing/lib/events"
"github.com/syncthing/syncthing/lib/build"
"github.com/syncthing/syncthing/lib/fs"
"github.com/syncthing/syncthing/lib/locations"
"github.com/syncthing/syncthing/lib/osutil"
"github.com/syncthing/syncthing/lib/protocol"
"github.com/syncthing/syncthing/lib/svcutil"
"github.com/syncthing/syncthing/lib/sync"
"github.com/syncthing/syncthing/lib/util"
)
var (
@@ -36,20 +34,21 @@ var (
)
const (
countRestarts = 4
loopThreshold = 60 * time.Second
restartCounts = 4
restartPause = 1 * time.Second
restartLoopThreshold = 60 * time.Second
logFileAutoCloseDelay = 5 * time.Second
logFileMaxOpenTime = time.Minute
panicUploadMaxWait = 30 * time.Second
panicUploadNoticeWait = 10 * time.Second
)
func monitorMain(runtimeOptions RuntimeOptions) {
func monitorMain(options serveOptions) {
l.SetPrefix("[monitor] ")
var dst io.Writer = os.Stdout
logFile := runtimeOptions.logFile
logFile := locations.Get(locations.LogFile)
if logFile != "-" {
if expanded, err := fs.ExpandTilde(logFile); err == nil {
logFile = expanded
@@ -59,15 +58,15 @@ func monitorMain(runtimeOptions RuntimeOptions) {
open := func(name string) (io.WriteCloser, error) {
return newAutoclosedFile(name, logFileAutoCloseDelay, logFileMaxOpenTime)
}
if runtimeOptions.logMaxSize > 0 {
fileDst, err = newRotatedFile(logFile, open, int64(runtimeOptions.logMaxSize), runtimeOptions.logMaxFiles)
if options.LogMaxSize > 0 {
fileDst, err = newRotatedFile(logFile, open, int64(options.LogMaxSize), options.LogMaxFiles)
} else {
fileDst, err = open(logFile)
}
if err != nil {
l.Warnln("Failed to setup logging to file, proceeding with logging to stdout only:", err)
} else {
if runtime.GOOS == "windows" {
if build.IsWindows {
// Translate line breaks to Windows standard
fileDst = osutil.ReplacingWriter{
Writer: fileDst,
@@ -84,7 +83,12 @@ func monitorMain(runtimeOptions RuntimeOptions) {
}
args := os.Args
var restarts [countRestarts]time.Time
binary, err := getBinary(args[0])
if err != nil {
l.Warnln("Error starting the main Syncthing process:", err)
panic("Error starting the main Syncthing process")
}
var restarts [restartCounts]time.Time
stopSign := make(chan os.Signal, 1)
signal.Notify(stopSign, os.Interrupt, sigTerm)
@@ -97,15 +101,15 @@ func monitorMain(runtimeOptions RuntimeOptions) {
for {
maybeReportPanics()
if t := time.Since(restarts[0]); t < loopThreshold {
l.Warnf("%d restarts in %v; not retrying further", countRestarts, t)
os.Exit(util.ExitError.AsInt())
if t := time.Since(restarts[0]); t < restartLoopThreshold {
l.Warnf("%d restarts in %v; not retrying further", restartCounts, t)
os.Exit(svcutil.ExitError.AsInt())
}
copy(restarts[0:], restarts[1:])
restarts[len(restarts)-1] = time.Now()
cmd := exec.Command(args[0], args[1:]...)
cmd := exec.Command(binary, args[1:]...)
cmd.Env = childEnv
stderr, err := cmd.StderrPipe()
@@ -169,31 +173,31 @@ func monitorMain(runtimeOptions RuntimeOptions) {
if err == nil {
// Successful exit indicates an intentional shutdown
os.Exit(util.ExitSuccess.AsInt())
os.Exit(svcutil.ExitSuccess.AsInt())
}
if exiterr, ok := err.(*exec.ExitError); ok {
exitCode := exiterr.ExitCode()
if stopped || runtimeOptions.noRestart {
if stopped || options.NoRestart {
os.Exit(exitCode)
}
if exitCode == util.ExitUpgrade.AsInt() {
if exitCode == svcutil.ExitUpgrade.AsInt() {
// Restart the monitor process to release the .old
// binary as part of the upgrade process.
l.Infoln("Restarting monitor...")
if err = restartMonitor(args); err != nil {
if err = restartMonitor(binary, args); err != nil {
l.Warnln("Restart:", err)
}
os.Exit(exitCode)
}
}
if runtimeOptions.noRestart {
os.Exit(util.ExitError.AsInt())
if options.NoRestart {
os.Exit(svcutil.ExitError.AsInt())
}
l.Infoln("Syncthing exited:", err)
time.Sleep(1 * time.Second)
time.Sleep(restartPause)
if first {
// Let the next child process know that this is not the first time
@@ -204,6 +208,19 @@ func monitorMain(runtimeOptions RuntimeOptions) {
}
}
func getBinary(args0 string) (string, error) {
e, err := os.Executable()
if err == nil {
return e, nil
}
// Check if args0 cuts it
e, lerr := exec.LookPath(args0)
if lerr == nil {
return e, nil
}
return "", err
}
func copyStderr(stderr io.Reader, dst io.Writer) {
br := bufio.NewReader(stderr)
@@ -256,7 +273,7 @@ func copyStderr(stderr io.Reader, dst io.Writer) {
* This crash usually occurs due to one of the following reasons: *
* - Syncthing being stopped abruptly (killed/loss of power) *
* - Bad hardware (memory/disk issues) *
* - Software that affects disk writes (SSD caching software and simillar) *
* - Software that affects disk writes (SSD caching software and similar) *
* *
* Please see the following URL for instructions on how to recover: *
* https://docs.syncthing.net/users/faq.html#my-syncthing-database-is-corrupt *
@@ -310,40 +327,30 @@ func copyStdout(stdout io.Reader, dst io.Writer) {
}
}
func restartMonitor(args []string) error {
func restartMonitor(binary string, args []string) error {
// Set the STRESTART environment variable to indicate to the next
// process that this is a restart and not initial start. This prevents
// opening the browser on startup.
os.Setenv("STRESTART", "yes")
if runtime.GOOS != "windows" {
if !build.IsWindows {
// syscall.Exec is the cleanest way to restart on Unixes as it
// replaces the current process with the new one, keeping the pid and
// controlling terminal and so on
return restartMonitorUnix(args)
return restartMonitorUnix(binary, args)
}
// but it isn't supported on Windows, so there we start a normal
// exec.Command and return.
return restartMonitorWindows(args)
return restartMonitorWindows(binary, args)
}
func restartMonitorUnix(args []string) error {
if !strings.ContainsRune(args[0], os.PathSeparator) {
// The path to the binary doesn't contain a slash, so it should be
// found in $PATH.
binary, err := exec.LookPath(args[0])
if err != nil {
return err
}
args[0] = binary
}
return syscall.Exec(args[0], args, os.Environ())
func restartMonitorUnix(binary string, args []string) error {
return syscall.Exec(binary, args, os.Environ())
}
func restartMonitorWindows(args []string) error {
cmd := exec.Command(args[0], args[1:]...)
func restartMonitorWindows(binary string, args []string) error {
cmd := exec.Command(binary, args[1:]...)
// Retain the standard streams
cmd.Stderr = os.Stderr
cmd.Stdout = os.Stdout
@@ -514,7 +521,7 @@ func (f *autoclosedFile) ensureOpenLocked() error {
// We open the file for write only, and create it if it doesn't exist.
flags := os.O_WRONLY | os.O_CREATE | os.O_APPEND
fd, err := os.OpenFile(f.name, flags, 0644)
fd, err := os.OpenFile(f.name, flags, 0o644)
if err != nil {
return err
}
@@ -563,7 +570,7 @@ func childEnv() []string {
// panicUploadMaxWait uploading panics...
func maybeReportPanics() {
// Try to get a config to see if/where panics should be reported.
cfg, err := loadOrDefaultConfig(protocol.EmptyDeviceID, events.NoopLogger)
cfg, err := loadOrDefaultConfig()
if err != nil {
l.Warnln("Couldn't load config; not reporting crash")
return

View File

@@ -8,7 +8,6 @@ package main
import (
"io"
"io/ioutil"
"os"
"path/filepath"
"testing"
@@ -18,14 +17,17 @@ import (
func TestRotatedFile(t *testing.T) {
// Verify that log rotation happens.
dir, err := ioutil.TempDir("", "syncthing")
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(dir)
dir := t.TempDir()
open := func(name string) (io.WriteCloser, error) {
return os.Create(name)
f, err := os.Create(name)
t.Cleanup(func() {
if f != nil {
_ = f.Close()
}
})
return f, err
}
logName := filepath.Join(dir, "log.txt")
@@ -179,7 +181,7 @@ func TestAutoClosedFile(t *testing.T) {
}
// The file should have both writes in it.
bs, err := ioutil.ReadFile(file)
bs, err := os.ReadFile(file)
if err != nil {
t.Fatal(err)
}
@@ -199,7 +201,7 @@ func TestAutoClosedFile(t *testing.T) {
}
// It should now contain three writes, as the file is always opened for appending
bs, err = ioutil.ReadFile(file)
bs, err = os.ReadFile(file)
if err != nil {
t.Fatal(err)
}

View File

@@ -4,26 +4,25 @@
// 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/.
//go:build !windows
// +build !windows
package main
import (
"os/exec"
"runtime"
"syscall"
"github.com/syncthing/syncthing/lib/build"
)
func openURL(url string) error {
switch runtime.GOOS {
case "darwin":
if build.IsDarwin {
return exec.Command("open", url).Run()
default:
cmd := exec.Command("xdg-open", url)
cmd.SysProcAttr = &syscall.SysProcAttr{
Setpgid: true,
}
return cmd.Run()
}
cmd := exec.Command("xdg-open", url)
cmd.SysProcAttr = &syscall.SysProcAttr{
Setpgid: true,
}
return cmd.Run()
}

View File

@@ -4,6 +4,7 @@
// 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/.
//go:build windows
// +build windows
package main

View File

@@ -4,6 +4,7 @@
// 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/.
//go:build !solaris && !windows
// +build !solaris,!windows
package main
@@ -18,10 +19,8 @@ import (
"github.com/syncthing/syncthing/lib/protocol"
)
func init() {
if innerProcess && os.Getenv("STPERFSTATS") != "" {
go savePerfStats(fmt.Sprintf("perfstats-%d.csv", syscall.Getpid()))
}
func startPerfStats() {
go savePerfStats(fmt.Sprintf("perfstats-%d.csv", syscall.Getpid()))
}
func savePerfStats(file string) {

View File

@@ -0,0 +1,13 @@
// Copyright (C) 2021 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/.
//go:build solaris || windows
// +build solaris windows
package main
func startPerfStats() {
}

View File

@@ -4,7 +4,8 @@
// 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/.
//+build go1.7
//go:build go1.7
// +build go1.7
package main

View File

@@ -1,57 +0,0 @@
// Copyright (C) 2014 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 main
import (
"bytes"
"flag"
"fmt"
"io"
"text/tabwriter"
)
func optionTable(w io.Writer, rows [][]string) {
tw := tabwriter.NewWriter(w, 2, 4, 2, ' ', 0)
for _, row := range rows {
for i, cell := range row {
if i > 0 {
tw.Write([]byte("\t"))
}
tw.Write([]byte(cell))
}
tw.Write([]byte("\n"))
}
tw.Flush()
}
func usageFor(fs *flag.FlagSet, usage string, extra string) func() {
return func() {
var b bytes.Buffer
b.WriteString("Usage:\n " + usage + "\n")
var options [][]string
fs.VisitAll(func(f *flag.Flag) {
var opt = " -" + f.Name
if f.DefValue != "false" {
opt += "=" + fmt.Sprintf(`"%s"`, f.DefValue)
}
options = append(options, []string{opt, f.Usage})
})
if len(options) > 0 {
b.WriteString("\nOptions:\n")
optionTable(&b, options)
}
fmt.Println(b.String())
if len(extra) > 0 {
fmt.Println(extra)
}
}
}

View File

@@ -1,330 +0,0 @@
// Copyright (C) 2018 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 main
import (
"database/sql"
"log"
"os"
"time"
_ "github.com/lib/pq"
)
var dbConn = getEnvDefault("UR_DB_URL", "postgres://user:password@localhost/ur?sslmode=disable")
func getEnvDefault(key, def string) string {
if val := os.Getenv(key); val != "" {
return val
}
return def
}
func main() {
log.SetFlags(log.Ltime | log.Ldate)
log.SetOutput(os.Stdout)
db, err := sql.Open("postgres", dbConn)
if err != nil {
log.Fatalln("database:", err)
}
err = setupDB(db)
if err != nil {
log.Fatalln("database:", err)
}
for {
runAggregation(db)
// Sleep until one minute past next midnight
sleepUntilNext(24*time.Hour, 1*time.Minute)
}
}
func runAggregation(db *sql.DB) {
since := maxIndexedDay(db, "VersionSummary")
log.Println("Aggregating VersionSummary data since", since)
rows, err := aggregateVersionSummary(db, since)
if err != nil {
log.Fatalln("aggregate:", err)
}
log.Println("Inserted", rows, "rows")
log.Println("Aggregating UserMovement data")
rows, err = aggregateUserMovement(db)
if err != nil {
log.Fatalln("aggregate:", err)
}
log.Println("Inserted", rows, "rows")
log.Println("Aggregating Performance data")
since = maxIndexedDay(db, "Performance")
rows, err = aggregatePerformance(db, since)
if err != nil {
log.Fatalln("aggregate:", err)
}
log.Println("Inserted", rows, "rows")
log.Println("Aggregating BlockStats data")
since = maxIndexedDay(db, "BlockStats")
rows, err = aggregateBlockStats(db, since)
if err != nil {
log.Fatalln("aggregate:", err)
}
log.Println("Inserted", rows, "rows")
}
func sleepUntilNext(intv, margin time.Duration) {
now := time.Now().UTC()
next := now.Truncate(intv).Add(intv).Add(margin)
log.Println("Sleeping until", next)
time.Sleep(next.Sub(now))
}
func setupDB(db *sql.DB) error {
_, err := db.Exec(`CREATE TABLE IF NOT EXISTS VersionSummary (
Day TIMESTAMP NOT NULL,
Version VARCHAR(8) NOT NULL,
Count INTEGER NOT NULL
)`)
if err != nil {
return err
}
_, err = db.Exec(`CREATE TABLE IF NOT EXISTS UserMovement (
Day TIMESTAMP NOT NULL,
Added INTEGER NOT NULL,
Bounced INTEGER NOT NULL,
Removed INTEGER NOT NULL
)`)
if err != nil {
return err
}
_, err = db.Exec(`CREATE TABLE IF NOT EXISTS Performance (
Day TIMESTAMP NOT NULL,
TotFiles INTEGER NOT NULL,
TotMiB INTEGER NOT NULL,
SHA256Perf DOUBLE PRECISION NOT NULL,
MemorySize INTEGER NOT NULL,
MemoryUsageMiB INTEGER NOT NULL
)`)
if err != nil {
return err
}
_, err = db.Exec(`CREATE TABLE IF NOT EXISTS BlockStats (
Day TIMESTAMP NOT NULL,
Reports INTEGER NOT NULL,
Total INTEGER NOT NULL,
Renamed INTEGER NOT NULL,
Reused INTEGER NOT NULL,
Pulled INTEGER NOT NULL,
CopyOrigin INTEGER NOT NULL,
CopyOriginShifted INTEGER NOT NULL,
CopyElsewhere INTEGER NOT NULL
)`)
if err != nil {
return err
}
var t string
row := db.QueryRow(`SELECT 'UniqueDayVersionIndex'::regclass`)
if err := row.Scan(&t); err != nil {
_, err = db.Exec(`CREATE UNIQUE INDEX UniqueDayVersionIndex ON VersionSummary (Day, Version)`)
}
row = db.QueryRow(`SELECT 'VersionDayIndex'::regclass`)
if err := row.Scan(&t); err != nil {
_, err = db.Exec(`CREATE INDEX VersionDayIndex ON VersionSummary (Day)`)
}
row = db.QueryRow(`SELECT 'MovementDayIndex'::regclass`)
if err := row.Scan(&t); err != nil {
_, err = db.Exec(`CREATE INDEX MovementDayIndex ON UserMovement (Day)`)
}
row = db.QueryRow(`SELECT 'PerformanceDayIndex'::regclass`)
if err := row.Scan(&t); err != nil {
_, err = db.Exec(`CREATE INDEX PerformanceDayIndex ON Performance (Day)`)
}
row = db.QueryRow(`SELECT 'BlockStatsDayIndex'::regclass`)
if err := row.Scan(&t); err != nil {
_, err = db.Exec(`CREATE INDEX BlockStatsDayIndex ON BlockStats (Day)`)
}
return err
}
func maxIndexedDay(db *sql.DB, table string) time.Time {
var t time.Time
row := db.QueryRow("SELECT MAX(Day) FROM " + table)
err := row.Scan(&t)
if err != nil {
return time.Time{}
}
return t
}
func aggregateVersionSummary(db *sql.DB, since time.Time) (int64, error) {
res, err := db.Exec(`INSERT INTO VersionSummary (
SELECT
DATE_TRUNC('day', Received) AS Day,
SUBSTRING(Report->>'version' FROM '^v\d.\d+') AS Ver,
COUNT(*) AS Count
FROM ReportsJson
WHERE
DATE_TRUNC('day', Received) > $1
AND DATE_TRUNC('day', Received) < DATE_TRUNC('day', NOW())
AND Report->>'version' like 'v_.%'
GROUP BY Day, Ver
);
`, since)
if err != nil {
return 0, err
}
return res.RowsAffected()
}
func aggregateUserMovement(db *sql.DB) (int64, error) {
rows, err := db.Query(`SELECT
DATE_TRUNC('day', Received) AS Day,
Report->>'uniqueID'
FROM ReportsJson
WHERE
DATE_TRUNC('day', Received) < DATE_TRUNC('day', NOW())
AND Report->>'version' like 'v_.%'
ORDER BY Day
`)
if err != nil {
return 0, err
}
defer rows.Close()
firstSeen := make(map[string]time.Time)
lastSeen := make(map[string]time.Time)
var minTs time.Time
minTs = minTs.In(time.UTC)
for rows.Next() {
var ts time.Time
var id string
if err := rows.Scan(&ts, &id); err != nil {
return 0, err
}
if minTs.IsZero() {
minTs = ts
}
if _, ok := firstSeen[id]; !ok {
firstSeen[id] = ts
}
lastSeen[id] = ts
}
type sumRow struct {
day time.Time
added int
removed int
bounced int
}
var sumRows []sumRow
for t := minTs; t.Before(time.Now().Truncate(24 * time.Hour)); t = t.AddDate(0, 0, 1) {
var added, removed, bounced int
old := t.Before(time.Now().AddDate(0, 0, -30))
for id, first := range firstSeen {
last := lastSeen[id]
if first.Equal(t) && last.Equal(t) && old {
bounced++
continue
}
if first.Equal(t) {
added++
}
if last == t && old {
removed++
}
}
sumRows = append(sumRows, sumRow{t, added, removed, bounced})
}
tx, err := db.Begin()
if err != nil {
return 0, err
}
if _, err := tx.Exec("DELETE FROM UserMovement"); err != nil {
tx.Rollback()
return 0, err
}
for _, r := range sumRows {
if _, err := tx.Exec("INSERT INTO UserMovement (Day, Added, Removed, Bounced) VALUES ($1, $2, $3, $4)", r.day, r.added, r.removed, r.bounced); err != nil {
tx.Rollback()
return 0, err
}
}
return int64(len(sumRows)), tx.Commit()
}
func aggregatePerformance(db *sql.DB, since time.Time) (int64, error) {
res, err := db.Exec(`INSERT INTO Performance (
SELECT
DATE_TRUNC('day', Received) AS Day,
AVG((Report->>'totFiles')::numeric) As TotFiles,
AVG((Report->>'totMiB')::numeric) As TotMiB,
AVG((Report->>'sha256Perf')::numeric) As SHA256Perf,
AVG((Report->>'memorySize')::numeric) As MemorySize,
AVG((Report->>'memoryUsageMiB')::numeric) As MemoryUsageMiB
FROM ReportsJson
WHERE
DATE_TRUNC('day', Received) > $1
AND DATE_TRUNC('day', Received) < DATE_TRUNC('day', NOW())
AND Report->>'version' like 'v_.%'
GROUP BY Day
);
`, since)
if err != nil {
return 0, err
}
return res.RowsAffected()
}
func aggregateBlockStats(db *sql.DB, since time.Time) (int64, error) {
// Filter out anything prior 0.14.41 as that has sum aggregations which
// made no sense.
res, err := db.Exec(`INSERT INTO BlockStats (
SELECT
DATE_TRUNC('day', Received) AS Day,
COUNT(1) As Reports,
SUM((Report->'blockStats'->>'total')::numeric) AS Total,
SUM((Report->'blockStats'->>'renamed')::numeric) AS Renamed,
SUM((Report->'blockStats'->>'reused')::numeric) AS Reused,
SUM((Report->'blockStats'->>'pulled')::numeric) AS Pulled,
SUM((Report->'blockStats'->>'copyOrigin')::numeric) AS CopyOrigin,
SUM((Report->'blockStats'->>'copyOriginShifted')::numeric) AS CopyOriginShifted,
SUM((Report->'blockStats'->>'copyElsewhere')::numeric) AS CopyElsewhere
FROM ReportsJson
WHERE
DATE_TRUNC('day', Received) > $1
AND DATE_TRUNC('day', Received) < DATE_TRUNC('day', NOW())
AND (Report->>'urVersion')::numeric >= 3
AND Report->>'version' like 'v_.%'
AND Report->>'version' NOT LIKE 'v0.14.40%'
AND Report->>'version' NOT LIKE 'v0.14.39%'
AND Report->>'version' NOT LIKE 'v0.14.38%'
GROUP BY Day
);
`, since)
if err != nil {
return 0, err
}
return res.RowsAffected()
}

View File

@@ -0,0 +1,226 @@
// Copyright (C) 2018 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 aggregate
import (
"database/sql"
"fmt"
"log"
"os"
"time"
_ "github.com/lib/pq"
)
type CLI struct {
DBConn string `env:"UR_DB_URL" default:"postgres://user:password@localhost/ur?sslmode=disable"`
}
func (cli *CLI) Run() error {
log.SetFlags(log.Ltime | log.Ldate)
log.SetOutput(os.Stdout)
db, err := sql.Open("postgres", cli.DBConn)
if err != nil {
return fmt.Errorf("database: %w", err)
}
err = setupDB(db)
if err != nil {
return fmt.Errorf("database: %w", err)
}
for {
runAggregation(db)
// Sleep until one minute past next midnight
sleepUntilNext(24*time.Hour, 1*time.Minute)
}
}
func runAggregation(db *sql.DB) {
since := maxIndexedDay(db, "VersionSummary")
log.Println("Aggregating VersionSummary data since", since)
rows, err := aggregateVersionSummary(db, since.Add(24*time.Hour))
if err != nil {
log.Println("aggregate:", err)
}
log.Println("Inserted", rows, "rows")
since = maxIndexedDay(db, "Performance")
log.Println("Aggregating Performance data since", since)
rows, err = aggregatePerformance(db, since.Add(24*time.Hour))
if err != nil {
log.Println("aggregate:", err)
}
log.Println("Inserted", rows, "rows")
since = maxIndexedDay(db, "BlockStats")
log.Println("Aggregating BlockStats data since", since)
rows, err = aggregateBlockStats(db, since.Add(24*time.Hour))
if err != nil {
log.Println("aggregate:", err)
}
log.Println("Inserted", rows, "rows")
}
func sleepUntilNext(intv, margin time.Duration) {
now := time.Now().UTC()
next := now.Truncate(intv).Add(intv).Add(margin)
log.Println("Sleeping until", next)
time.Sleep(next.Sub(now))
}
func setupDB(db *sql.DB) error {
_, err := db.Exec(`CREATE TABLE IF NOT EXISTS VersionSummary (
Day TIMESTAMP NOT NULL,
Version VARCHAR(8) NOT NULL,
Count INTEGER NOT NULL
)`)
if err != nil {
return err
}
_, err = db.Exec(`CREATE TABLE IF NOT EXISTS Performance (
Day TIMESTAMP NOT NULL,
TotFiles INTEGER NOT NULL,
TotMiB INTEGER NOT NULL,
SHA256Perf DOUBLE PRECISION NOT NULL,
MemorySize INTEGER NOT NULL,
MemoryUsageMiB INTEGER NOT NULL
)`)
if err != nil {
return err
}
_, err = db.Exec(`CREATE TABLE IF NOT EXISTS BlockStats (
Day TIMESTAMP NOT NULL,
Reports INTEGER NOT NULL,
Total BIGINT NOT NULL,
Renamed BIGINT NOT NULL,
Reused BIGINT NOT NULL,
Pulled BIGINT NOT NULL,
CopyOrigin BIGINT NOT NULL,
CopyOriginShifted BIGINT NOT NULL,
CopyElsewhere BIGINT NOT NULL
)`)
if err != nil {
return err
}
var t string
row := db.QueryRow(`SELECT 'UniqueDayVersionIndex'::regclass`)
if err := row.Scan(&t); err != nil {
_, _ = db.Exec(`CREATE UNIQUE INDEX UniqueDayVersionIndex ON VersionSummary (Day, Version)`)
}
row = db.QueryRow(`SELECT 'VersionDayIndex'::regclass`)
if err := row.Scan(&t); err != nil {
_, _ = db.Exec(`CREATE INDEX VersionDayIndex ON VersionSummary (Day)`)
}
row = db.QueryRow(`SELECT 'PerformanceDayIndex'::regclass`)
if err := row.Scan(&t); err != nil {
_, _ = db.Exec(`CREATE INDEX PerformanceDayIndex ON Performance (Day)`)
}
row = db.QueryRow(`SELECT 'BlockStatsDayIndex'::regclass`)
if err := row.Scan(&t); err != nil {
_, _ = db.Exec(`CREATE INDEX BlockStatsDayIndex ON BlockStats (Day)`)
}
return nil
}
func maxIndexedDay(db *sql.DB, table string) time.Time {
var t time.Time
row := db.QueryRow("SELECT MAX(DATE_TRUNC('day', Day)) FROM " + table)
err := row.Scan(&t)
if err != nil {
return time.Time{}
}
return t
}
func aggregateVersionSummary(db *sql.DB, since time.Time) (int64, error) {
res, err := db.Exec(`INSERT INTO VersionSummary (
SELECT
DATE_TRUNC('day', Received) AS Day,
SUBSTRING(Report->>'version' FROM '^v\d.\d+') AS Ver,
COUNT(*) AS Count
FROM ReportsJson
WHERE
Received > $1
AND Received < DATE_TRUNC('day', NOW())
AND Report->>'version' like 'v_.%'
GROUP BY Day, Ver
);
`, since)
if err != nil {
return 0, err
}
return res.RowsAffected()
}
func aggregatePerformance(db *sql.DB, since time.Time) (int64, error) {
res, err := db.Exec(`INSERT INTO Performance (
SELECT
DATE_TRUNC('day', Received) AS Day,
AVG((Report->>'totFiles')::numeric) As TotFiles,
AVG((Report->>'totMiB')::numeric) As TotMiB,
AVG((Report->>'sha256Perf')::numeric) As SHA256Perf,
AVG((Report->>'memorySize')::numeric) As MemorySize,
AVG((Report->>'memoryUsageMiB')::numeric) As MemoryUsageMiB
FROM ReportsJson
WHERE
Received > $1
AND Received < DATE_TRUNC('day', NOW())
AND Report->>'version' like 'v_.%'
/* Some custom implementation reported bytes when we expect megabytes, cap at petabyte */
AND (Report->>'memorySize')::numeric < 1073741824
GROUP BY Day
);
`, since)
if err != nil {
return 0, err
}
return res.RowsAffected()
}
func aggregateBlockStats(db *sql.DB, since time.Time) (int64, error) {
// Filter out anything prior 0.14.41 as that has sum aggregations which
// made no sense.
res, err := db.Exec(`INSERT INTO BlockStats (
SELECT
DATE_TRUNC('day', Received) AS Day,
COUNT(1) As Reports,
SUM((Report->'blockStats'->>'total')::numeric)::bigint AS Total,
SUM((Report->'blockStats'->>'renamed')::numeric)::bigint AS Renamed,
SUM((Report->'blockStats'->>'reused')::numeric)::bigint AS Reused,
SUM((Report->'blockStats'->>'pulled')::numeric)::bigint AS Pulled,
SUM((Report->'blockStats'->>'copyOrigin')::numeric)::bigint AS CopyOrigin,
SUM((Report->'blockStats'->>'copyOriginShifted')::numeric)::bigint AS CopyOriginShifted,
SUM((Report->'blockStats'->>'copyElsewhere')::numeric)::bigint AS CopyElsewhere
FROM ReportsJson
WHERE
Received > $1
AND Received < DATE_TRUNC('day', NOW())
AND (Report->>'urVersion')::numeric >= 3
AND Report->>'version' like 'v_.%'
AND Report->>'version' NOT LIKE 'v0.14.40%'
AND Report->>'version' NOT LIKE 'v0.14.39%'
AND Report->>'version' NOT LIKE 'v0.14.38%'
GROUP BY Day
);
`, since)
if err != nil {
return 0, err
}
return res.RowsAffected()
}

View File

File diff suppressed because it is too large Load Diff

View File

@@ -1,143 +0,0 @@
// Copyright (C) 2020 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 main
import (
"database/sql"
"database/sql/driver"
"encoding/json"
"errors"
"log"
"strings"
"github.com/lib/pq"
"github.com/syncthing/syncthing/lib/ur/contract"
)
func migrate(db *sql.DB) error {
var count uint64
log.Println("Checking old table row count, this might take a while...")
if err := db.QueryRow(`SELECT COUNT(1) FROM Reports`).Scan(&count); err != nil || count == 0 {
// err != nil most likely means table does not exist.
return nil
}
log.Printf("Found %d records, will perform migration.", count)
tx, err := db.Begin()
if err != nil {
log.Println("sql:", err)
return err
}
defer tx.Rollback()
// These must be lower case, because we don't quote them when creating, so postgres creates them lower case.
// Yet pg.CopyIn quotes them, which makes them case sensitive.
stmt, err := tx.Prepare(pq.CopyIn("reportsjson", "received", "report"))
if err != nil {
log.Println("sql:", err)
return err
}
// Custom types used in the old struct.
var rep contract.Report
var rescanIntvs pq.Int64Array
var fsWatcherDelay pq.Int64Array
pullOrder := make(IntMap)
fileSystemType := make(IntMap)
themes := make(IntMap)
transportStats := make(IntMap)
rows, err := db.Query(`SELECT ` + strings.Join(rep.FieldNames(), ", ") + `, FolderFsWatcherDelays, RescanIntvs, FolderPullOrder, FolderFilesystemType, GUITheme, Transport FROM Reports`)
if err != nil {
log.Println("sql:", err)
return err
}
defer rows.Close()
var done uint64
pct := count / 100
for rows.Next() {
err := rows.Scan(append(rep.FieldPointers(), &fsWatcherDelay, &rescanIntvs, &pullOrder, &fileSystemType, &themes, &transportStats)...)
if err != nil {
log.Println("sql scan:", err)
return err
}
// Patch up parts that used to use custom types
rep.RescanIntvs = make([]int, len(rescanIntvs))
for i := range rescanIntvs {
rep.RescanIntvs[i] = int(rescanIntvs[i])
}
rep.FolderUsesV3.FsWatcherDelays = make([]int, len(fsWatcherDelay))
for i := range fsWatcherDelay {
rep.FolderUsesV3.FsWatcherDelays[i] = int(fsWatcherDelay[i])
}
rep.FolderUsesV3.PullOrder = pullOrder
rep.FolderUsesV3.FilesystemType = fileSystemType
rep.GUIStats.Theme = themes
rep.TransportStats = transportStats
_, err = stmt.Exec(rep.Received, rep)
if err != nil {
log.Println("sql insert:", err)
return err
}
done++
if done%pct == 0 {
log.Printf("Migration progress %d/%d (%d%%)", done, count, (100*done)/count)
}
}
// Tell the driver bulk copy is finished
_, err = stmt.Exec()
if err != nil {
log.Println("sql stmt exec:", err)
return err
}
err = stmt.Close()
if err != nil {
log.Println("sql stmt close:", err)
return err
}
_, err = tx.Exec("DROP TABLE Reports")
if err != nil {
log.Println("sql drop:", err)
return err
}
err = tx.Commit()
if err != nil {
log.Println("sql commit:", err)
return err
}
return nil
}
type IntMap map[string]int
func (p IntMap) Value() (driver.Value, error) {
return json.Marshal(p)
}
func (p *IntMap) Scan(src interface{}) error {
source, ok := src.([]byte)
if !ok {
return errors.New("Type assertion .([]byte) failed.")
}
var i map[string]int
err := json.Unmarshal(source, &i)
if err != nil {
return err
}
*p = i
return nil
}

View File

@@ -4,7 +4,7 @@
// 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 main
package serve
import (
"regexp"
@@ -145,7 +145,7 @@ func statsForFloats(data []float64) [4]float64 {
return res
}
func group(by func(string) string, as []analytic, perGroup int) []analytic {
func group(by func(string) string, as []analytic, perGroup int, otherPct float64) []analytic {
var res []analytic
next:
@@ -170,6 +170,25 @@ next:
}
sort.Sort(analyticList(res))
if otherPct > 0 {
// Groups with less than otherPCt go into "Other"
other := analytic{
Key: "Other",
}
for i := 0; i < len(res); i++ {
if res[i].Percentage < otherPct || res[i].Key == "Other" {
other.Count += res[i].Count
other.Percentage += res[i].Percentage
res = append(res[:i], res[i+1:]...)
i--
}
}
if other.Count > 0 {
res = append(res, other)
}
}
return res
}

Some files were not shown because too many files have changed in this diff Show More