Compare commits

...

850 Commits

Author SHA1 Message Date
Syncthing Release Automation
6069cf39e5 gui, man, authors: Update docs, translations, and contributors 2023-11-27 03:45:21 +00:00
Emil Lundberg
1f7d236742 gui: Specialize a special-purpose checkbox style (#9236)
### Purpose

Discovered while working on the WebAuthn credentials table in #9175:
there's a style on `td input[type="checkbox"]` that modifies margins for
all checkboxes in `<table>`s. It looks like this style is specially
tailored to the particular table that added it (PR #8734), so it should
have a correspondingly special-purpose class to not accidentally apply
it to other tables.

As best as I could tell there are only 2 instances of `<input
type="checkbox">` in `<td>`s, shown in the screenshots below.

### Testing

- Open "Actions > Logging > Debugging Facilities" and observe the
vertical spacing of the checkboxes.
- Open "Edit Folder > Advanced", check "Sync Extended Attributes" or
"Send Extended Attributes", click "Add filter entry" and observe the
vertical spacing of the checkbox that appears.

### Screenshots

#### Before

![Logs > Debugging
Facilities](https://github.com/syncthing/syncthing/assets/1367758/998fc66d-a0ad-41d9-a476-7a2b3da622d1)
![Add filter
entry](https://github.com/syncthing/syncthing/assets/1367758/647cb565-fcd0-4a81-a6ca-1f75137039b0)

#### After

Logs > Debugging Facilities now more compact:
![Logs > Debugging Facilities now
](https://github.com/syncthing/syncthing/assets/1367758/7cf8fc77-610e-4b4a-be21-c50d30be7bb9)

Add filter entry unchanged:
![Add filter
entry](https://github.com/syncthing/syncthing/assets/1367758/0ba710d6-cee1-49b4-92bc-acfc0c22c2bd)
2023-11-21 10:00:18 +01:00
Syncthing Release Automation
8e9ee3fbe8 gui, man, authors: Update docs, translations, and contributors 2023-11-20 08:49:38 +00:00
Jakob Borg
35b0afc131 build: Support new nested namespaces in Weblate downloads 2023-11-20 09:47:08 +01:00
Simon Frei
958ff67ccc lib/model: Acquire fmut lock in ensureIndexHandler (fixes #9234) (#9235)
Towards the end of the function f.folderCfgs and f.folderRunners are
read without the lock.
2023-11-20 08:12:25 +01:00
tomasz1986
13d9317a38 gui: Allow to translate "unknown device" (#9229)
The string is currently hard-coded in English, so allow to translate it
into other languages. It appears mainly in the browser title bar before
logging in into the GUI or when the GUI is still loading.

Signed-off-by: Tomasz Wilczyński <twilczynski@naver.com>
2023-11-16 22:07:15 +01:00
Anatoli Babenia
b184d46d8a cmd/ursrv: Add link to source code (#9224)
To see that https://data.syncthing.net is open source, study the code
and change it.
2023-11-15 08:51:23 +00:00
Jakob Borg
3f32c5cb4b cmd/ursrv: Anchor distribution expressions to avoid mismatches (ref #9141) 2023-11-15 09:32:46 +01:00
Jakob Borg
5c65a1bc83 build: Ursrv image for infrastructure 2023-11-15 08:48:00 +01:00
Jakob Borg
d0a6dc5b13 cmd/ursv: Report on copy range method 2023-11-15 08:48:00 +01:00
Jakob Borg
439c6c5b7c lib/api: Add cache busting for basic auth (ref #9208) (#9215)
This adds our short device ID to the basic auth realm. This has at least
two consequences:

- It is different from what's presented by another device on the same
address (e.g., if I use SSH forwards to different dives on the same
local address), preventing credentials for one from being sent to
another.

- It is different from what we did previously, meaning we avoid cached
credentials from old versions interfering with the new login flow.

I don't *think* there should be things that depend on our precise realm
string, so this shouldn't break any existing setups...

Sneakily this also changes the session cookie and CSRF name, because I
think `id.Short().String()` is nicer than `id.String()[:5]` and the
short ID is two characters longer. That's also not a problem...
2023-11-14 11:57:39 +01:00
Jakob Borg
aaee0c126b cmd/stdiscorv: Expose build info in metrics 2023-11-14 09:31:53 +01:00
André Colomb
f3bd4d71de gui: Fix Weblate merge conflict (#9222)
The manual translation updates in the recently merged PR #9220 caused
conflicts with the existing (test) entries on Weblate. This will fix it.
2023-11-14 08:21:40 +01:00
Jakob Borg
876d056705 build: Fixup Docker changes from previous (#9223) 2023-11-14 08:17:34 +01:00
DerRockWolf
e988978fa1 Add org.opencontainers.image.source to Dockerfiles (#9211)
### Purpose

The OCI image spec specifies well-defined
[annotations](https://github.com/opencontainers/image-spec/blob/main/annotations.md)
that can be added to images.
Theses annotations can then be used by other tools to gather more
information of an image.

This PR adds the `org.opencontainers.image.source` to allow tools such
as [renovate](https://github.com/renovatebot/renovate) to find the
release notes of a give version.

~~I've only done this change for `Dockerfile`. Should I also add the
label to the other dockerfiles?~~
I've now added the source annotations to all `Dockerfile`s & action
workflows.

### Testing

None, change was done by following the [renovate
documentation](https://docs.renovatebot.com/modules/datasource/docker/).
2023-11-14 07:46:14 +01:00
Jakob Borg
d5deede7a1 build: Update dependencies 2023-11-14 07:41:53 +01:00
André Colomb
4f70f5c280 gui: Use nested namespace for theme name translation keys (#9220)
Following up on #9192, this makes use of the new mechanism for the theme
names.

The dummy string added for testing is removed again here. All
translations are updated to the new nested syntax, except Chinese
(zh-HK) where the string weren't actually translated.
2023-11-14 07:22:52 +01:00
Emil Lundberg
a1ad020b63 Support explicit translation ID and dotted namespaces in translation extraction (#9192)
Some translations, especially single words or other short
labels for buttons and the like, may not be transferable between
contexts even if they happen to be equal in English. In these cases,
setting an explicit translation ID is important for context separation.
Angular Translate also supports nested JSON in translation tables,
addressed using `.` as namespace separator; this enhancement makes use
of this when extracting translation with an explicit translation ID.
2023-11-13 21:04:24 +01:00
Jakob Borg
8f1b0df74b lib/api: Improve cookie handling (fixes #9208) (#9214) 2023-11-13 20:37:29 +01:00
Jakob Borg
0f8dc6c1d3 test: Update testing configs
Somewhere along the way I snuck in a change to the test configs that is
quite annoying. This reverts that back to the more usual setup it was
before.
2023-11-13 13:51:17 +01:00
Jakob Borg
8ae9db3b2d build: Use actual Go version as cache key (#9216)
We use `env.GO_VERSION` as cache key for the build cache, but this is
nowadays typically something like `~1.21.1` which doesn't change when
1.21.2, 1.21.3 etc are released, making the cache fairly useless as
everything gets rebuilt. This re-sets the `GO_VERSION` variable after
installing Go so that it contains the actual installed version.
2023-11-13 12:20:40 +01:00
Jakob Borg
e477777f49 build: Version constraint to avoid Go 1.21.4 on Windows (ref #9207) (#9213) 2023-11-13 09:52:59 +00:00
Syncthing Release Automation
7a132bdf24 gui, man, authors: Update docs, translations, and contributors 2023-11-13 03:45:25 +00:00
Jakob Borg
5e2b7825dc cmd/stdiscosrv: Metric for returned retry-after 2023-11-08 12:18:59 +01:00
Jakob Borg
6d30c109e4 build: Push to Docker :edge tag for infrastructure builds 2023-11-08 12:18:59 +01:00
Jakob Borg
58bd931d90 cmd/stdiscosrv: Account IPv4 & IPv6 2023-11-08 12:18:59 +01:00
vapatel2
854499382e cmd/stdiscosrv: Prevent nil IPs from X-Forwarded-For (fixes #9189) (#9190)
### Purpose

Treat X-Forwarded-For as a comma-separated string to prevent nil IP being returned by the Discovery Server

### Testing

Unit Tests implemented

Testing with a Discovery Client can be done as follows:
```
A simple example to replicate this entails running Discovery with HTTP, use Nginx as a reverse proxy and hardcode (as an example) a list of IPs in the X-Forwarded-For header.
1. Send an Announcement with tcp://0.0.0.0:<some-port>
2. Query the DeviceID
3. Observe the returned IP Address is no longer nil; i.e.  `tcp://<nil>:<some-port>`
```
2023-11-08 11:10:23 +00:00
Jakob Borg
cb4c1f9ad2 build: Update dependencies (#9202) 2023-11-06 16:43:11 -08:00
Catfriend1
b452fb3ad2 gui: Add id attribute to login button, allows form filling tools to be used (fixes #9200) (#9201)
Add an id attribute to the submit button shown on the login form. This
allows my password manager's form filling function to interact with the
button after filling in username and password (which already have the id
attribute in place).
2023-11-06 16:30:19 -08:00
Syncthing Release Automation
c17a1fea77 gui, man, authors: Update docs, translations, and contributors 2023-11-06 03:45:25 +00:00
Syncthing Release Automation
d50511c5c6 gui, man, authors: Update docs, translations, and contributors 2023-10-30 03:45:44 +00:00
Jakob Borg
bae6d5f375 lib/location: Fix regression of timestamp handling (ref #9180) (#9185) 2023-10-26 07:41:02 +02:00
Jakob Borg
b5082f6af8 lib/locations: Change default config/data location to new XDG recommendation (fixes #9178, fixes #9179) (#9180)
This makes the new default $XDG_STATE_HOME/syncthing or
~/.local/state/syncthing, while still looking in legacy locations first
for existing installs.

Note that this does not *move* existing installs, and nor should we.
Existing paths will continue to be used as-is, but the user can move the
dir into the new place if they want to use it (as they could prior to
this change as well, for that matter).

### Documentation

Needs update to the config docs about our default locations.
2023-10-25 11:16:24 +02:00
dependabot[bot]
9666e9701b build(deps): bump github.com/quic-go/quic-go from 0.39.0 to 0.39.1 (#9181) 2023-10-24 07:23:38 +02:00
Syncthing Release Automation
86e1c5ff18 gui, man, authors: Update docs, translations, and contributors 2023-10-23 03:45:41 +00:00
tomasz1986
16ae1fbe5e lib/fs: Ignore inode change time on Android (#9177)
lib/fs: Fix conflicts on Android due to fluctuating inode change time

[1] added inode change time to file info in order to support syncing
extended attributes. However, in the case of Android, this inode change
time fluctuates, leading to unexpected conflicts even when the user has
not even touched the files on the Android device itself. Thus, in order
to prevent those conflicts from happening, do not write inode change
time on Android.

[1] 6cac308bcd

Signed-off-by: Tomasz Wilczyński <twilczynski@naver.com>
2023-10-21 08:24:29 +02:00
Jakob Borg
11f508d9be build: Post build logs to Syncthing Loki 2023-10-16 11:07:40 +02:00
Jakob Borg
9ce6a73f42 Revert "cmd/stcrashreceiver: Aggregate slice out of bounds errors"
This reverts commit dc6a10dff4.
2023-10-16 08:08:23 +02:00
Syncthing Release Automation
c5a991cf0a gui, man, authors: Update docs, translations, and contributors 2023-10-16 03:45:30 +00:00
Emil Lundberg
14569f12d3 Hide log out button when auth is not enabled (#9158)
This was an oversight in #8757: the new "Log out" button is always shown
in the "Actions" menu, even when authentication is not enabled.
2023-10-15 14:10:41 +02:00
Jakob Borg
a405c21ebb cmd/stdiscosrv: Only attempt unescaping when there are %-encodings in the header (fixes #9143) 2023-10-14 12:30:29 +02:00
Jakob Borg
dc6a10dff4 cmd/stcrashreceiver: Aggregate slice out of bounds errors 2023-10-14 12:19:55 +02:00
Jakob Borg
d4c2acf6f6 cmd/stcrashreceiver: Propagate synthetic user ID for crashes 2023-10-14 12:19:55 +02:00
Jakob Borg
483ecada80 build: Update dependencies 2023-10-14 12:18:36 +02:00
Eric P
9553365d31 lib/fs: Properly handle Windows deduplicated files (fixes #9120) (#9168)
### Purpose

Deduplicated files are apparently considered 'irregular' under the hood,
this causes them to simply be ignored by Syncthing. This change is more
of a workaround than a proper fix, as the fix should probably happen in
the underlying libraries? - which may take some time. In the meanwhile,
this change should make deduplicated files be treated as regular files
and be indexed and synced as they should.

### Testing

Create some volume where deduplication is turned on (see the relevant
issue for details, including a proper description of how to reproduce
it). Prior to this change, the deduplicated files were simply ignored
(even by the indexer). After this change, the deduplicated files are
being index and synced properly.
2023-10-11 14:40:55 +02:00
orangekame3
5eb20580b1 cmd/ursrv: Replace "2006-01-02" with time.DateOnly (#9157)
This commit replaces "2006-01-02" to time.DateOnly. time.DateOnly is
introduced since Go1.20
2023-10-11 10:32:19 +00:00
Emil Lundberg
ea1ea366d2 lib/api: Check basic auth (and set session cookie) before noauth exceptions (#9159)
This is motivated by the Android app:
https://github.com/syncthing/syncthing-android/pull/1982#issuecomment-1752042554

The planned fix in response to basic auth behaviour changing in #8757
was to add the `Authorization` header when opening the WebView, but it
turns out the function used only applies the header to the initial page
load, not any subsequent script loads or AJAX calls. The
`basicAuthAndSessionMiddleware` checks for no-auth exceptions before
checking the `Authorization` header, so the header has no effect on the
initial page load since the `/` path is a no-auth exception. Thus the
Android app fails to log in when opening the WebView.

This changes the order of checks in `basicAuthAndSessionMiddleware` so
that the `Authorization` header is always checked if present, and a
session cookie is set if it is valid. Only after that does the
middleware fall back to checking for no-auth exceptions.

`api_test.go` has been expanded with additional checks:
- Check that a session cookie is set whenever correct basic auth is
provided.
- Check that a session cookie is not set when basic auth is incorrect.
- Check that a session cookie is not set when authenticating with an API
token (either via `X-Api-Key` or `Authorization: Bearer`).

And an additional test case:
- Check that requests to `/` always succeed, but receive a session
cookie when correct basic auth is provided.

I have manually verified that
- The new assertions fail if the `createSession` call is removed in
`basicAuthAndSessionMiddleware`.
- The new test cases in e6e4df4d70 fail
before the change in 0e47d37e73 is
applied.
2023-10-10 07:48:55 +02:00
Syncthing Release Automation
6e4574a9f7 gui, man, authors: Update docs, translations, and contributors 2023-10-09 03:45:35 +00:00
Jakob Borg
3d0da5ac60 lib/api: Better handle %s templates in LDAP strings (fixes #9072) (#9155)
Also add some escaping for good measure.
2023-10-07 02:29:53 +00:00
Jakob Borg
9f8e6966d8 docker: Allow start even if chown fails (fixes #9133) (#9152) 2023-10-07 02:12:07 +00:00
Jakob Borg
a64ae36bcc lib/model: Verify versioning on configuration reload (fixes #9106) (#9154) 2023-10-07 04:09:51 +02:00
Jakob Borg
690b55360f cmd/stdiscosrv: Handle unescaped cert header from Traefik (fixes #9143) (#9153) 2023-10-07 04:09:07 +02:00
DeflateAwning
2f6187dc0e Add oxford comma (#9137)
Co-authored-by: André Colomb <src@andre.colomb.de>
2023-10-06 17:25:28 +02:00
Emil Lundberg
8294870ffc Add HTML login form (fixes #4137) (#8757) 2023-10-06 13:00:58 +02:00
bt90
ac2e444a97 gui: Fix favicon status (fixes #9149) (#9150) 2023-10-06 12:27:13 +02:00
Jakob Borg
4f6b86a1c0 cmd/stdiscosrv: Slightly tweak replication settings 2023-10-04 14:15:00 +02:00
Jakob Borg
516c057d43 build: Update deps 2023-10-03 10:00:16 +02:00
Jakob Borg
d644dce4e7 build: Run release steps for workflow_dispatch as well 2023-10-03 09:33:52 +02:00
bt90
7c579880eb cmd/ursrv: Add linuxserver.io detection (#9145)
Detect linuxserver
2023-10-02 12:48:04 +02:00
Jakob Borg
296db314f5 lib/config: Improve parsing of gui-address overrides (#9144)
improve parsing of gui-address overrides

make checks for whether the gui-address is overridden consistent by
checking whether the environment variable is set and not an empty
string. the `Network()` function however checked for the inclusion of
a slash instead of the presence of any characters. If the config file's
gui address was set to a unix socket and the gui override to a tcp
address, then the function would have wrongly returned "unix".

the `URL()` function always returned the config file's gui address if a
unix socket was configured, even if an override was specified.

the `URL()` function wrongly formatted unix addresses. the http(s)
protocol was used as the sheme and the path was percent escaped. because
of the previous bug, this could only be triggered if the config file's
gui address was tcp and an unix socket override was given.

simplify the `useTLS()` function's codepath for overrides.

Co-authored-by: digital <didev@dinid.net>
2023-10-02 08:40:03 +02:00
Syncthing Release Automation
a8486b0468 gui, man, authors: Update docs, translations, and contributors 2023-10-02 03:45:41 +00:00
bt90
f8a7a034a7 cmd/ursrv: Fix f-droid detection (#9142)
Fix f-droid detection
2023-09-29 17:42:44 +02:00
bt90
ceae56a860 cmd/ursrv: Support new android build user (#9141)
Support new android build user
2023-09-29 16:34:28 +02:00
DeflateAwning
dcafd6ec72 readme: Style fixes, add security note (#9136) 2023-09-28 11:55:48 +02:00
Jakob Borg
8619a03f01 build: Update Actions 2023-09-25 21:50:17 +02:00
Jakob Borg
b91d7711aa Update dependencies (#9129)
And some QUIC API changes, of course.
2023-09-25 21:45:57 +02:00
d-volution
9940c91ebf gui: Scroll to bottom by clicking message in log viewer (#9128) 2023-09-25 19:42:27 +00:00
tomasz1986
80a577b025 gui: Show if device is untrusted in the main GUI (#9116)
Add a new entry to the unfolded device info to inform the user that the
device has been marked as "untrusted" and all folders shared with it
have to be password-protected or already Receive Encrypted.

Signed-off-by: Tomasz Wilczyński <twilczynski@naver.com>
2023-09-25 21:34:19 +02:00
tomasz1986
d672175ce4 gui: Show if device has Auto Accept enabled in the main GUI (#9118)
Add a new entry to the unfolded device info to inform the user that the
device has Auto Accept enabled.

Signed-off-by: Tomasz Wilczyński <twilczynski@naver.com>
2023-09-25 21:33:16 +02:00
tomasz1986
a44b31d173 gui: Fix body padding infinitely increasing due to overlapping modals (ref #9063) (#9078)
Opening and hiding multiple modals at the same time as well as opening a
modal before fully hiding the previous one can lead to the body padding
infinitely increasing by the scrollbar width each time, with the only
way to fix it being refreshing the GUI.

Therefore, always try to ensure to open and hide multiple modals one by
one, and also that the previous modal has fully been hidden before
proceeding to open the next one. The most common case when this problem
happens is when saving config changes which displays a GUI blocking
modal that overlaps, e.g. with folder or device modals that have not
been hidden yet.

Ref: https://github.com/twbs/bootstrap/issues/3902#issuecomment-1547187799

Signed-off-by: Tomasz Wilczyński <twilczynski@naver.com>
2023-09-25 21:17:57 +02:00
Martin Polehla
70065e6b13 gitignore: All exe files, no editor configs (#9126) 2023-09-25 14:17:01 +00:00
Syncthing Release Automation
adbb3ed2e9 gui, man, authors: Update docs, translations, and contributors 2023-09-25 03:45:38 +00:00
Jakob Borg
6ed9c0c34c lib/config: Accept pre-hashed password (fixes #9123) (#9124) 2023-09-24 19:23:49 +02:00
tomasz1986
19bbf4f6bf gui: Add missing $scope in editDeviceUntrustedChanged function (#9117)
Because $scope is missing, there are JavaScript errors when ticking and
unticking the "Untrusted" checkbox in the Advanced tab of the Edit
Device modal.

Signed-off-by: Tomasz Wilczyński <twilczynski@naver.com>
2023-09-22 07:39:16 +02:00
bt90
cf46bf0297 lib/connections: Fix transport type detection for QUIC (fixes #8274) (#9114)
Check remote address
2023-09-20 11:23:48 +02:00
Jakob Borg
051cbdc713 lib/fs, lib/model: Be careful about potentially negative durations (fixes #9112) (#9113)
I don't really understand under what circumstances, but sometimes these
calls panic with a "panic: counter cannot decrease in value" because the
value passed to Add() was negative.
2023-09-20 09:04:47 +02:00
Syncthing Release Automation
58d1f3a471 gui, man, authors: Update docs, translations, and contributors 2023-09-18 03:45:31 +00:00
tomasz1986
c9dfd75d8e gui: Block GUI when saving changes only if necessary (ref #9063) (#9079)
Currently, the UI is always blocked from modifications when changes are
being saved, even if the save process takes very little time. This leads
to a situation where showing and closing the blocking modal can take
more time than is actually required to perform the whole operation. The
modal opening and closing very quickly can also cause the screen to
flash for a brief moment, leading to visual discomfort.

Because of this, wait for at least 200 ms and only show the blocking
modal if the changes have not been saved until then yet. The value of
200 ms is loosely based on [1] which states that 'a delay of 0.2–1.0
seconds does mean that users notice the delay and thus feel the computer
is "working" on the command, as opposed to having the command be a
direct effect of the users' actions.' Additionally, the delay must not
be too long, because the main purpose of the blocking modal is to
prevent the user from making further changes, and a longer delay would
possibly allow to do so in that brief amount of time as long as the user
is quick enough with their input.

[1] https://nngroup.com/articles/response-times-3-important-limits

Signed-off-by: Tomasz Wilczyński <twilczynski@naver.com>
2023-09-12 15:02:37 +02:00
Jakob Borg
f47de83914 lib/protocol: Ensure starting & closing a connection are exclusive (fixes #9102) (#9103)
In principle a connection can close while it's in progress with
starting, and then it's undefined if we wait for goroutines to exit etc.
With this change, we will wait for start to complete before starting to
stop everything.
2023-09-12 14:48:15 +02:00
tomasz1986
caedb19307 gui: Remove unused hard-coded styles from Recent Changes modal (#9101)
gui: Remove unused hard-coded styles from globalChangesModalView modal

Currently, the globalChangesModalView modal has hardcoded th and td
styles. However, they are not even used in the modal itself, because
Bootstrap overrides them with its own styles for these elements in the
same modal. Yet, when hard-coded like that, these styles can conflict
with other table elements in the GUI. Thus, remove them completely.

Signed-off-by: Tomasz Wilczyński <twilczynski@naver.com>
2023-09-12 14:47:31 +02:00
bt90
e860d3b974 lib/connections: Make assumptions about isLAN when interface address listing fails (#9093) 2023-09-12 12:34:30 +00:00
bt90
ed66fba42b lib/beacon, lib/discover: Send IPv4 limited broadcast when address listing fails (fixes #1628) (#9087) 2023-09-12 14:28:17 +02:00
Jakob Borg
415f320005 build: Update dependencies 2023-09-12 14:08:59 +02:00
Jakob Borg
4812600098 lib/versioner: Don't complain when folder is stopping (#9097) 2023-09-11 23:10:18 +02:00
Jakob Borg
5ff11ce142 gui: Add help link for numConnections (#9082) 2023-09-11 14:59:48 +02:00
tomasz1986
541572781b gui: Add missing translation related to Number of Connections (ref #8918) (#9095)
Signed-off-by: Tomasz Wilczyński <twilczynski@naver.com>
2023-09-11 05:50:23 +02:00
Syncthing Release Automation
e38679d9bf gui, man, authors: Update docs, translations, and contributors 2023-09-11 03:45:45 +00:00
Jakob Borg
f25a169c4c build: Go 1.21.1 or higher 2023-09-06 21:11:19 +02:00
bt90
06ac10ee37 cmd/stdiscosrv: Deduplicate addresses (fixes #8482) (#9080) 2023-09-06 14:36:00 +02:00
Jakob Borg
7c0223bd06 lib/build: Next version is the Gold Grasshopper 2023-09-06 13:13:39 +02:00
Jakob Borg
c6334e61aa all: Support multiple device connections (fixes #141) (#8918)
This adds the ability to have multiple concurrent connections to a single device. This is primarily useful when the network has multiple physical links for aggregated bandwidth. A single connection will never see a higher rate than a single link can give, but multiple connections are load-balanced over multiple links.

It is also incidentally useful for older multi-core CPUs, where bandwidth could be limited by the TLS performance of a single CPU core -- using multiple connections achieves concurrency in the required crypto calculations...

Co-authored-by: Simon Frei <freisim93@gmail.com>
Co-authored-by: tomasz1986 <twilczynski@naver.com>
Co-authored-by: bt90 <btom1990@googlemail.com>
2023-09-06 12:52:01 +02:00
Jakob Borg
38bbdebffa build: Use actions/checkout@v4 2023-09-05 09:52:19 +02:00
Jakob Borg
e80d04845e build: Minor dependency update 2023-09-05 09:47:51 +02:00
Syncthing Release Automation
4138e22898 gui, man, authors: Update docs, translations, and contributors 2023-09-04 03:45:39 +00:00
Maximilian
c42c0e7ceb lib/connections: Fix WANAddresses returning only unspecified IPs (ref #9010) (#9073)
Avoids taking the address of the same variable twice.
2023-09-03 15:03:27 +00:00
Jakob Borg
5118538179 lib/model: Refactor folderRunners to use a serviceMap (#9071)
Instead of separately tracking the token.

Also changes serviceMap to have a channel version of RemoveAndWait, so
that it's possible to do the removal under a lock but wait outside of
the lock. And changed where we do that in connection close, reversing
the change that happened when I added the serviceMap in 40b3b9ad1.
2023-09-02 16:42:46 +02:00
tomasz1986
4d93648f75 gui: Don't hide default values for folders and devices (#8987)
Currently, some of the information for folders and devices displayed in
the GUI relies on arbitrary values that come pre-set as defaults on a
fresh Syncthing installation, i.e. if the value matches the default, it
is hidden, and if does not, then it is displayed.

With this change, the GUI always displays all information regardless
of their value, making the overall experience more consistent and
predictable.

Signed-off-by: Tomasz Wilczyński <twilczynski@naver.com>
2023-09-02 12:19:18 +02:00
tomasz1986
29f100c162 gui: Fix File Versioning icon to match in all places (#9070)
Currently, different icons are used for File Versioning when displayed
in the unfolded folder info in the main part of the GUI, and the icon
used in the Edit Folder modal. This changes the main GUI icon to match
the icon used in the modal.

Signed-off-by: Tomasz Wilczyński <twilczynski@naver.com>
2023-09-01 11:15:20 +02:00
tomasz1986
cd98a43b80 gui: Fix Logs modal icon to match header icon (ref #9067) (#9069)
The Logs icon was changed in [1] in the header, however the icon used in
the modal was left out. This changes it, so that the header and the
modal icons match.

[1] 2abba1dfb0

Signed-off-by: Tomasz Wilczyński <twilczynski@naver.com>
2023-09-01 11:14:28 +02:00
Jakob Borg
4bf982376e build: Be more subtle about cross compilation errors
Summarize platforms that fail to build, without overloading the build
log with errors that we anyway ignore. (Currently freebsd/riscv64 fails
to build.)
2023-09-01 09:16:14 +02:00
Jakob Borg
29056d5873 build: Update dependencies (#9068) 2023-09-01 08:39:15 +02:00
tomasz1986
2abba1dfb0 gui: Remove footer and move links to header (fixes #5607) (#9067)
* gui: Remove footer and move links to header (fixes #5607)

Currently, the footer is always present and takes space at the bottom of
the GUI. However, the links listed there are not part of everyday user
interaction, and as such, they unnecessarily clutter the page, reducing
the usable screen space. Thus, transform the current Help link in the
header into a Help dropdown menu, and move the links from the footer
into it.

Also apply the following tweaks:

1. Move the About dialog from Actions to Help.
2. Add an Introduction (to the GUI) link to Help.
3. Change the Support icon from a question mark to a group of people.
4. Change the Changelog and About icons to a filled version to match the
   other icons better.
5. Use a source code icon for Source Code instead of a wrench icon, and
   move the wrench icon to Logs. This is done to prevent Changelog and
   Logs from using the same icon.
6. Update all dropdown icons' Fork Awesome styles to "fa fa-fw <icon>".

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

* a few more Fork Awesome style updates

---------

Signed-off-by: Tomasz Wilczyński <twilczynski@naver.com>
2023-09-01 08:18:30 +02:00
tomasz1986
325b3b114f gui: Fix lastSeenDays error due to undefined deviceStats when adding new devices (ref #8730) (#9066) 2023-09-01 07:22:04 +02:00
tomasz1986
03590e5ac7 gui: Automatically select device ID on click (ref #8544) (#9065)
The CSS method to select device IDs on click was added in [1]. However,
it was later mistakenly overwritten by [2]. This commit fixes the
regression and also applies the same behaviour to the Edit Device modal
which was omitted in the original commit.

[1] 5baf5fedb5
[2] 5e384c9185

Signed-off-by: Tomasz Wilczyński <twilczynski@naver.com>
2023-08-31 22:16:59 +02:00
tomasz1986
95b3c26da7 gui: Prevent modifications when saving changes (fixes #9019) (#9063) 2023-08-31 17:11:03 +02:00
tomasz1986
3e5f0b1d0e gui: Show in GUI if limitBandwidthInLan is enabled (#9062) 2023-08-31 07:22:24 +02:00
Jakob Borg
3130af3773 lib/upgrade: Enable HTTP/2 for upgrade checks (#9060) 2023-08-30 21:58:34 +02:00
Jakob Borg
abd89f15f7 lib/discover: Enable HTTP/2 for global discovery requests (#9059)
By creating the http.Transport and tls.Configuration ourselves we
override some default behavior and end up with a client that speaks only
HTTP/1.1.

This adds a call to http.ConfigureTransport to do the relevant magic to
enable HTTP/2.

Also tweaks the keepalive settings to be a little kinder to the
server(s).
2023-08-30 21:58:05 +02:00
Jakob Borg
a80e6be353 cmd/stdiscosrv: Streamline context handling 2023-08-30 09:36:27 +02:00
Jakob Borg
acc532fc60 cmd/stdiscosrv: Explicitly enable HTTP/2
The server supports it, but it's not negotiated unless explicitly
allowed in the TLS config NextProtos.
2023-08-30 09:09:52 +02:00
Syncthing Release Automation
3cc3fb7504 gui, man, authors: Update docs, translations, and contributors 2023-08-28 03:45:57 +00:00
Jakob Borg
a04cc95005 cmd/stdiscosrv: Separate HTTPS and replication certificates 2023-08-23 13:43:54 +02:00
Jakob Borg
480fa4b915 cmd/stdiscosrv: Use larger database settings 2023-08-23 13:43:14 +02:00
Jakob Borg
92a4931850 cmd/stdiscosrv: Modernise TLS settings, remove excessive HTTP logging 2023-08-23 13:39:52 +02:00
Jakob Borg
bdfef9010f cmd/stdiscosrv: Serve compressed responses 2023-08-23 13:39:14 +02:00
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
a514b65d81 cmd/syncthing: Rename --conf back to --config (fixes #7549) (#7550) 2021-04-06 10:40:52 +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
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
640 changed files with 54325 additions and 33989 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/*"

View File

@@ -1,7 +1,7 @@
version = 1
exclude_patterns = ["*.pb.go"]
test_patterns = ["*_test.go"]
exclude_patterns = ["**/*.pb.go"]
test_patterns = ["**/*_test.go"]
[[analyzers]]
name = "go"

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,56 @@
name: Build Infrastructure Images
on:
push:
branches:
- infrastructure
env:
GO_VERSION: "~1.21.1"
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
- ursrv
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Login to Docker Hub
uses: docker/login-action@v3
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@v3
- name: Build and push
uses: docker/build-push-action@v5
with:
context: .
file: ./Dockerfile.${{ matrix.pkg }}
platforms: linux/amd64,linux/arm64
push: true
tags: syncthing/${{ matrix.pkg }}:latest,syncthing/${{ matrix.pkg }}:${{ github.sha }}
labels: |
org.opencontainers.image.revision=${{ github.sha }}

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

@@ -0,0 +1,845 @@
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.1"
# 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"]
# Don't run the Windows tests with Go 1.21.4 or 1.20.11; this can be
# removed when 1.21.5 and 1.20.12 is released.
exclude:
- runner: windows-latest
go: "1.20"
- runner: windows-latest
go: "1.21"
include:
- runner: windows-latest
go: "~1.20.12 || ~1.20.0 <1.20.11"
- runner: windows-latest
go: "~1.21.5 || ~1.21.1 <1.21.4"
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@v4
- 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 version
go run build.go test | go-test-json-to-loki
env:
GOFLAGS: "-json"
LOKI_URL: ${{ vars.LOKI_URL }}
LOKI_USER: ${{ vars.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@v4
- 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@v4
#
# Windows
#
package-windows:
name: Package for Windows
if: (github.event_name == 'push' || github.event_name == 'workflow_dispatch') && (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@v4
with:
fetch-depth: 0
- uses: actions/setup-go@v4
with:
# Temporary version constraint to avoid 1.21.4 which has a bug in
# path handling. This can be removed when 1.21.5 is released.
go-version: "~1.21.5 || ~1.21.1 <1.21.4"
cache: false
check-latest: true
- name: Get actual Go version
run: |
go version
echo "GO_VERSION=$(go version | sed 's#^.*go##;s# .*##')" >> $GITHUB_ENV
- 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@v4
with:
fetch-depth: 0
- uses: actions/setup-go@v4
with:
go-version: ${{ env.GO_VERSION }}
cache: false
check-latest: true
- name: Get actual Go version
run: |
go version
echo "GO_VERSION=$(go version | sed 's#^.*go##;s# .*##')" >> $GITHUB_ENV
- 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.event_name == 'workflow_dispatch') && (github.ref == 'refs/heads/release' || startsWith(github.ref, 'refs/heads/release-'))
environment: signing
runs-on: macos-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- uses: actions/setup-go@v4
with:
go-version: ${{ env.GO_VERSION }}
cache: false
check-latest: true
- name: Get actual Go version
run: |
go version
echo "GO_VERSION=$(go version | sed 's#^.*go##;s# .*##')" >> $GITHUB_ENV
- 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.event_name == 'workflow_dispatch') && (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@v4
with:
fetch-depth: 0
- uses: actions/setup-go@v4
with:
go-version: ${{ env.GO_VERSION }}
cache: false
check-latest: true
- name: Get actual Go version
run: |
go version
echo "GO_VERSION=$(go version | sed 's#^.*go##;s# .*##')" >> $GITHUB_ENV
- 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 \
)
# Build for each platform with errors silenced, because we expect
# some oddball platforms to fail. This avoids a bunch of errors in
# the GitHub Actions output, instead summarizing each build
# failure as a warning.
for plat in $platforms; do
goos="${plat%/*}"
goarch="${plat#*/}"
echo "::group ::$plat"
if ! go run build.go -goos "$goos" -goarch "$goarch" tar 2>/dev/null; then
echo "::warning ::Failed to build for $plat"
fi
echo "::endgroup::"
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@v4
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.event_name == 'workflow_dispatch') && (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@v4
with:
fetch-depth: 0
- uses: actions/checkout@v4
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@v4
with:
fetch-depth: 0
- uses: actions/setup-go@v4
with:
go-version: ${{ env.GO_VERSION }}
cache: false
check-latest: true
- name: Get actual Go version
run: |
go version
echo "GO_VERSION=$(go version | sed 's#^.*go##;s# .*##')" >> $GITHUB_ENV
- 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' || github.event_name == 'workflow_dispatch') && startsWith(github.ref, 'refs/heads/release-nightly')
environment: signing
needs:
- sign-for-upgrade
- notarize-macos
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
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.event_name == 'workflow_dispatch') && github.ref == 'refs/heads/release'
environment: signing
needs:
- sign-for-upgrade
- package-debian
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
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.event_name == 'workflow_dispatch') && (github.ref == 'refs/heads/release' || github.ref == 'refs/heads/main' || github.ref == 'refs/heads/infrastructure' || 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@v4
with:
fetch-depth: 0
- uses: actions/setup-go@v4
with:
go-version: ${{ env.GO_VERSION }}
cache: false
check-latest: true
- name: Get actual Go version
run: |
go version
echo "GO_VERSION=$(go version | sed 's#^.*go##;s# .*##')" >> $GITHUB_ENV
- 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@v3
if: env.DOCKER_PUSH == 'true'
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- 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
echo "VERSION=$version" >> $GITHUB_ENV
- name: Build and push Docker image
uses: docker/build-push-action@v5
with:
context: .
file: ${{ matrix.dockerfile }}
platforms: linux/amd64,linux/arm64,linux/arm/7
push: ${{ env.DOCKER_PUSH == 'true' }}
tags: ${{ env.DOCKER_TAGS }}
labels: |
org.opencontainers.image.version=${{ env.VERSION }}
org.opencontainers.image.revision=${{ github.sha }}
#
# Check for known vulnerabilities in Go dependencies
#
govulncheck:
runs-on: ubuntu-latest
name: Run govulncheck
steps:
- uses: actions/checkout@v4
- 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@v4
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@v4
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 }}

3
.gitignore vendored
View File

@@ -1,11 +1,10 @@
/syncthing
/stdiscosrv
syncthing.exe
stdiscosrv.exe
*.tar.gz
*.zip
*.asc
*.deb
*.exe
.jshintrc
coverage.out
files/pidx

4
.yamlfmt Normal file
View File

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

74
AUTHORS
View File

@@ -18,24 +18,33 @@ 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>
Anatoli Babenia <anatoli@rainforce.org>
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 +57,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>
@@ -59,52 +69,73 @@ 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>
Catfriend1 <16361913+Catfriend1@users.noreply.github.com>
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>
d-volution <49024624+d-volution@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>
DeflateAwning <11021263+DeflateAwning@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>
DerRockWolf <50499906+DerRockWolf@users.noreply.github.com>
desbma <desbma@users.noreply.github.com>
Devon G. Redekopp <devon@redekopp.com>
digital <didev@dinid.net>
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>
@@ -112,6 +143,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>
@@ -120,12 +153,16 @@ 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>
@@ -135,13 +172,18 @@ 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>
@@ -151,13 +193,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>
@@ -166,6 +211,8 @@ 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>
Martin Polehla <p0l0us@users.noreply.github.com>
Mateusz Naściszewski (mateon1) <matin1111@wp.pl>
Mateusz Ż <thedead4fun@live.com>
Matic Potočnik <hairyfotr@gmail.com>
@@ -173,20 +220,27 @@ 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>
Maximilian <maxi.rostock@outlook.de>
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>
@@ -196,8 +250,10 @@ NinoM4ster <ninom4ster@gmail.com>
Nitroretro <43112364+Nitroretro@users.noreply.github.com>
NoLooseEnds <jon.koslung@gmail.com>
Oliver Freyermuth <o.freyermuth@googlemail.com>
orangekame3 <miya.org.0309@gmail.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>
@@ -218,6 +274,7 @@ 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>
@@ -226,11 +283,13 @@ 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>
@@ -238,6 +297,8 @@ 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>
@@ -252,11 +313,15 @@ Tully Robinson (tojrobinson) <tully@tojr.org>
Tyler Brazier (tylerbrazier) <tyler@tylerbrazier.com>
Tyler Kropp <kropptyler@gmail.com>
Unrud (Unrud) <unrud@openaliasbox.org> <Unrud@users.noreply.github.com>
vapatel2 <149737089+vapatel2@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>
@@ -265,3 +330,4 @@ 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,57 @@
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
LABEL org.opencontainers.image.authors="The Syncthing Project" \
org.opencontainers.image.url="https://syncthing.net" \
org.opencontainers.image.documentation="https://docs.syncthing.net" \
org.opencontainers.image.source="https://github.com/syncthing/syncthing" \
org.opencontainers.image.vendor="The Syncthing Project" \
org.opencontainers.image.licenses="MPL-2.0" \
org.opencontainers.image.title="Syncthing"
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

@@ -1,9 +1,17 @@
ARG GOVERSION=latest
FROM golang:$GOVERSION
LABEL org.opencontainers.image.authors="The Syncthing Project" \
org.opencontainers.image.url="https://syncthing.net" \
org.opencontainers.image.documentation="https://docs.syncthing.net" \
org.opencontainers.image.source="https://github.com/syncthing/syncthing" \
org.opencontainers.image.vendor="The Syncthing Project" \
org.opencontainers.image.licenses="MPL-2.0" \
org.opencontainers.image.title="Syncthing Builder"
# FPM to build Debian packages
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/tcp 22000/udp 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,16 @@
FROM alpine
ARG TARGETARCH
LABEL org.opencontainers.image.authors="The Syncthing Project" \
org.opencontainers.image.url="https://syncthing.net" \
org.opencontainers.image.documentation="https://docs.syncthing.net" \
org.opencontainers.image.source="https://github.com/syncthing/syncthing" \
org.opencontainers.image.vendor="The Syncthing Project" \
org.opencontainers.image.licenses="MPL-2.0" \
org.opencontainers.image.title="Syncthing Crash Receiver"
EXPOSE 8080
COPY stcrashreceiver-linux-${TARGETARCH} /bin/stcrashreceiver
ENTRYPOINT [ "/bin/stcrashreceiver" ]

View File

@@ -1,15 +1,28 @@
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
LABEL org.opencontainers.image.authors="The Syncthing Project" \
org.opencontainers.image.url="https://syncthing.net" \
org.opencontainers.image.documentation="https://docs.syncthing.net" \
org.opencontainers.image.source="https://github.com/syncthing/syncthing" \
org.opencontainers.image.vendor="The Syncthing Project" \
org.opencontainers.image.licenses="MPL-2.0" \
org.opencontainers.image.title="Syncthing Discovery Server"
EXPOSE 19200 8443
@@ -17,7 +30,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

24
Dockerfile.strelaypoolsrv Normal file
View File

@@ -0,0 +1,24 @@
FROM alpine
ARG TARGETARCH
LABEL org.opencontainers.image.authors="The Syncthing Project" \
org.opencontainers.image.url="https://syncthing.net" \
org.opencontainers.image.documentation="https://docs.syncthing.net" \
org.opencontainers.image.source="https://github.com/syncthing/syncthing" \
org.opencontainers.image.vendor="The Syncthing Project" \
org.opencontainers.image.licenses="MPL-2.0" \
org.opencontainers.image.title="Syncthing Relay Pool Server"
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,28 @@
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
LABEL org.opencontainers.image.authors="The Syncthing Project" \
org.opencontainers.image.url="https://syncthing.net" \
org.opencontainers.image.documentation="https://docs.syncthing.net" \
org.opencontainers.image.source="https://github.com/syncthing/syncthing" \
org.opencontainers.image.vendor="The Syncthing Project" \
org.opencontainers.image.licenses="MPL-2.0" \
org.opencontainers.image.title="Syncthing Relay Server"
EXPOSE 22067 22070
@@ -17,7 +30,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

16
Dockerfile.stupgrades Normal file
View File

@@ -0,0 +1,16 @@
FROM alpine
ARG TARGETARCH
LABEL org.opencontainers.image.authors="The Syncthing Project" \
org.opencontainers.image.url="https://syncthing.net" \
org.opencontainers.image.documentation="https://docs.syncthing.net" \
org.opencontainers.image.source="https://github.com/syncthing/syncthing" \
org.opencontainers.image.vendor="The Syncthing Project" \
org.opencontainers.image.licenses="MPL-2.0" \
org.opencontainers.image.title="Syncthing Upgrades"
EXPOSE 8080
COPY stupgrades-linux-${TARGETARCH} /bin/stupgrades
ENTRYPOINT [ "/bin/stupgrades" ]

16
Dockerfile.ursrv Normal file
View File

@@ -0,0 +1,16 @@
FROM alpine
ARG TARGETARCH
LABEL org.opencontainers.image.authors="The Syncthing Project" \
org.opencontainers.image.url="https://syncthing.net" \
org.opencontainers.image.documentation="https://docs.syncthing.net" \
org.opencontainers.image.source="https://github.com/syncthing/syncthing" \
org.opencontainers.image.vendor="The Syncthing Project" \
org.opencontainers.image.licenses="MPL-2.0" \
org.opencontainers.image.title="Syncthing Usage Reporting Server"
EXPOSE 8080
COPY ursrv-linux-${TARGETARCH} /bin/ursrv
ENTRYPOINT [ "/bin/ursrv" ]

View File

@@ -24,17 +24,17 @@ to avoid corrupting the user's files.
### 2. Secure Against Attackers
Again, protecting the user's data is paramount. Regardless of our other
goals we must never allow the user's data to be susceptible to eavesdropping
goals, we must never allow the user's data to be susceptible to eavesdropping
or modification by unauthorized parties.
> This should be understood in context. It is not necessarily reasonable to
> expect Syncthing to be resistant against well equipped state level
> attackers. We will however do our best. Note also that this is different
> attackers. We will, however, do our best. Note also that this is different
> from anonymity which is not, currently, a goal.
### 3. Easy to Use
Syncthing should be approachable, understandable and inclusive.
Syncthing should be approachable, understandable, and inclusive.
> Complex concepts and maths form the base of Syncthing's functionality.
> This should nonetheless be abstracted or hidden to a degree where
@@ -52,18 +52,18 @@ User interaction should be required only when absolutely necessary.
### 5. Universally Available
Syncthing should run on every common computer. We are mindful that the
latest technology is not always available to any given individual.
latest technology is not always available to every 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
> tablets and phones. NAS appliances, toasters, cars, firearms, thermostats,
> and so on may include computing capabilities but it is not our goal for
> Syncthing to run smoothly on these devices.
### 6. For Individuals
Syncthing is primarily about empowering the individual user with safe,
secure and easy to use file synchronization.
secure, and easy to use file synchronization.
> We acknowledge that it's also useful in an enterprise setting and include
> functionality to support that. If this is in conflict with the

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/tcp -p 22000:22000/udp \
$ 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)
@@ -13,8 +10,8 @@
Syncthing is a **continuous file synchronization program**. It synchronizes
files between two or more computers. We strive to fulfill the goals below.
The goals are listed in order of importance, the most important one being
the first. This is the summary version of the goal list - for more
The goals are listed in order of importance, the most important ones first.
This is the summary version of the goal list - for more
commentary, see the full [Goals document][13].
Syncthing should be:
@@ -27,12 +24,12 @@ Syncthing should be:
2. **Secure Against Attackers**
Again, protecting the user's data is paramount. Regardless of our other
goals we must never allow the user's data to be susceptible to
goals, we must never allow the user's data to be susceptible to
eavesdropping or modification by unauthorized parties.
3. **Easy to Use**
Syncthing should be approachable, understandable and inclusive.
Syncthing should be approachable, understandable, and inclusive.
4. **Automatic**
@@ -41,12 +38,12 @@ Syncthing should be:
5. **Universally Available**
Syncthing should run on every common computer. We are mindful that the
latest technology is not always available to any given individual.
latest technology is not always available to every individual.
6. **For Individuals**
Syncthing is primarily about empowering the individual user with safe,
secure and easy to use file synchronization.
secure, and easy to use file synchronization.
7. **Everything Else**
@@ -60,7 +57,7 @@ Take a look at the [getting started guide][2].
There are a few examples for keeping Syncthing running in the background
on your system in [the etc directory][3]. There are also several [GUI
implementations][11] for Windows, Mac and Linux.
implementations][11] for Windows, Mac, and Linux.
## Docker
@@ -69,45 +66,49 @@ To run Syncthing in Docker, see [the Docker README][16].
## Vote on features/bugs
We'd like to encourage you to [vote][12] on issues that matter to you.
This helps the team understand what are the biggest pain points for our users, and could potentially influence what is being worked on next.
This helps the team understand what are the biggest pain points for our
users, and could potentially influence what is being worked on next.
## 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].
If you believe that youve found a Syncthing-related security vulnerability,
please report it by emailing security@syncthing.net. Do not report it in the
Forum or issue tracker.
## 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
As of v0.10.15 and onwards release binaries are GPG signed with the key
As of v0.10.15 and onwards, release binaries are GPG signed with the key
D26E6ED000654A3E, available from https://syncthing.net/security.html and
most key servers.
There is also a built in automatic upgrade mechanism (disabled in some
There is also a built-in automatic upgrade mechanism (disabled in some
distribution channels) which uses a compiled in ECDSA signature. macOS
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 +116,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

252
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,7 +30,10 @@ import (
"runtime"
"strconv"
"strings"
"text/template"
"time"
buildpkg "github.com/syncthing/syncthing/lib/build"
)
var (
@@ -47,9 +50,12 @@ var (
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") != ""
)
@@ -59,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
}
@@ -86,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
@@ -97,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},
@@ -141,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},
},
@@ -170,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},
@@ -180,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},
},
@@ -204,18 +207,24 @@ var targets = map[string]target{
{src: "AUTHORS", dst: "deb/usr/share/doc/syncthing-relaypoolsrv/AUTHORS.txt", perm: 0644},
},
},
}
// 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"},
"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",
},
}
func initTargets() {
@@ -314,6 +323,9 @@ func runCommand(cmd string, target target) {
case "assets":
rebuildAssets()
case "update-deps":
updateDependencies()
case "proto":
proto()
@@ -326,6 +338,9 @@ func runCommand(cmd string, target target) {
case "transifex":
transifex()
case "weblate":
weblate()
case "tar":
buildTar(target, tags)
@@ -379,10 +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()
}
@@ -390,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")
}
}
@@ -476,7 +499,7 @@ 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...)
}
@@ -508,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...)
}
@@ -542,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...)
@@ -654,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)
@@ -666,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()
@@ -701,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())
}
@@ -714,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())
}
@@ -734,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.
@@ -755,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
}
@@ -849,30 +905,46 @@ 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")
}
runPrintInDir(path, "git", "checkout", pv)
runPrint(goCmd, "generate", "github.com/syncthing/syncthing/cmd/stdiscosrv")
runPrint(goCmd, "generate", "proto/generate.go")
}
func testmocks() {
runPrint(goCmd, "get", "golang.org/x/tools/cmd/goimports")
runPrint(goCmd, "get", "github.com/maxbrunsfeld/counterfeiter/v6")
args := []string{
"generate",
"github.com/syncthing/syncthing/lib/config",
@@ -902,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")
@@ -926,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
}
@@ -949,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 {
@@ -1037,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) {
@@ -1258,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))
@@ -1333,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)
@@ -1352,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)
@@ -1369,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

@@ -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("/newcrash/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)
@@ -89,7 +116,20 @@ func handleFailureFn(dsn string) func(w http.ResponseWriter, req *http.Request)
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,45 @@ var (
clientsMut sync.Mutex
)
type sentryService struct {
dsn string
inbox chan sentryRequest
}
type sentryRequest struct {
reportID string
userID 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.userID); err != nil {
log.Println("Failed to send crash report:", err)
}
case <-ctx.Done():
return
}
}
}
func (s *sentryService) Send(reportID, userID string, data []byte) bool {
select {
case s.inbox <- sentryRequest{reportID, userID, 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 +134,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,7 +160,7 @@ 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
}
@@ -143,15 +187,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 +216,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 +264,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:]
}

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, userIDFor(req), 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

@@ -8,11 +8,15 @@ package main
import (
"bytes"
"compress/gzip"
"context"
"crypto/tls"
"encoding/base64"
"encoding/json"
"encoding/pem"
"errors"
"fmt"
io "io"
"log"
"math/rand"
"net"
@@ -25,6 +29,7 @@ import (
"time"
"github.com/syncthing/syncthing/lib/protocol"
"github.com/syncthing/syncthing/lib/stringutil"
)
// announcement is the format received from and sent to clients
@@ -66,7 +71,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 {
@@ -76,18 +81,10 @@ func (s *apiSrv) Serve(ctx context.Context) error {
s.listener = listener
} else {
tlsCfg := &tls.Config{
Certificates: []tls.Certificate{s.cert},
ClientAuth: tls.RequestClientCert,
SessionTicketsDisabled: true,
MinVersion: tls.VersionTLS12,
CipherSuites: []uint16{
tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
tls.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
tls.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,
},
Certificates: []tls.Certificate{s.cert},
ClientAuth: tls.RequestClientCert,
MinVersion: tls.VersionTLS12,
NextProtos: []string{"h2", "http/1.1"},
}
tlsListener, err := tls.Listen("tcp", s.addr, tlsCfg)
@@ -105,6 +102,7 @@ func (s *apiSrv) Serve(ctx context.Context) error {
ReadTimeout: httpReadTimeout,
WriteTimeout: httpWriteTimeout,
MaxHeaderBytes: httpMaxHeaderBytes,
ErrorLog: log.New(io.Discard, "", 0),
}
err := srv.Serve(s.listener)
@@ -114,8 +112,6 @@ func (s *apiSrv) Serve(ctx context.Context) error {
return err
}
var topCtx = context.Background()
func (s *apiSrv) handler(w http.ResponseWriter, req *http.Request) {
t0 := time.Now()
@@ -128,10 +124,10 @@ func (s *apiSrv) handler(w http.ResponseWriter, req *http.Request) {
}()
reqID := requestID(rand.Int63())
ctx := context.WithValue(topCtx, idKey, reqID)
req = req.WithContext(context.WithValue(req.Context(), idKey, reqID))
if debug {
log.Println(reqID, req.Method, req.URL)
log.Println(reqID, req.Method, req.URL, req.Proto)
}
remoteAddr := &net.TCPAddr{
@@ -140,7 +136,12 @@ func (s *apiSrv) handler(w http.ResponseWriter, req *http.Request) {
}
if s.useHTTP {
remoteAddr.IP = net.ParseIP(req.Header.Get("X-Forwarded-For"))
// X-Forwarded-For can have multiple client IPs; split using the comma separator
forwardIP, _, _ := strings.Cut(req.Header.Get("X-Forwarded-For"), ",")
// net.ParseIP will return nil if leading/trailing whitespace exists; use strings.TrimSpace()
remoteAddr.IP = net.ParseIP(strings.TrimSpace(forwardIP))
if parsedPort, err := strconv.ParseInt(req.Header.Get("X-Client-Port"), 10, 0); err == nil {
remoteAddr.Port = int(parsedPort)
}
@@ -157,17 +158,17 @@ func (s *apiSrv) handler(w http.ResponseWriter, req *http.Request) {
}
switch req.Method {
case "GET":
s.handleGET(ctx, lw, req)
case "POST":
s.handlePOST(ctx, remoteAddr, lw, req)
case http.MethodGet:
s.handleGET(lw, req)
case http.MethodPost:
s.handlePOST(remoteAddr, lw, req)
default:
http.Error(lw, "Method Not Allowed", http.StatusMethodNotAllowed)
}
}
func (s *apiSrv) handleGET(ctx context.Context, w http.ResponseWriter, req *http.Request) {
reqID := ctx.Value(idKey).(requestID)
func (s *apiSrv) handleGET(w http.ResponseWriter, req *http.Request) {
reqID := req.Context().Value(idKey).(requestID)
deviceID, err := protocol.DeviceIDFromString(req.URL.Query().Get("device"))
if err != nil {
@@ -211,28 +212,39 @@ func (s *apiSrv) handleGET(ctx context.Context, w http.ResponseWriter, req *http
s.db.put(key, rec)
}
w.Header().Set("Retry-After", notFoundRetryAfterString(int(misses)))
afterS := notFoundRetryAfterSeconds(int(misses))
retryAfterHistogram.Observe(float64(afterS))
w.Header().Set("Retry-After", strconv.Itoa(afterS))
http.Error(w, "Not Found", http.StatusNotFound)
return
}
lookupRequestsTotal.WithLabelValues("success").Inc()
bs, _ := json.Marshal(announcement{
Seen: time.Unix(0, rec.Seen),
w.Header().Set("Content-Type", "application/json")
var bw io.Writer = w
// Use compression if the client asks for it
if strings.Contains(req.Header.Get("Accept-Encoding"), "gzip") {
w.Header().Set("Content-Encoding", "gzip")
gw := gzip.NewWriter(bw)
defer gw.Close()
bw = gw
}
json.NewEncoder(bw).Encode(announcement{
Seen: time.Unix(0, rec.Seen).Truncate(time.Second),
Addresses: addressStrs(rec.Addresses),
})
w.Header().Set("Content-Type", "application/json")
w.Write(bs)
}
func (s *apiSrv) handlePOST(ctx context.Context, remoteAddr *net.TCPAddr, w http.ResponseWriter, req *http.Request) {
reqID := ctx.Value(idKey).(requestID)
func (s *apiSrv) handlePOST(remoteAddr *net.TCPAddr, w http.ResponseWriter, req *http.Request) {
reqID := req.Context().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 +312,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 +331,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,15 +350,27 @@ func certificateBytes(req *http.Request) []byte {
}
}
}
} 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
// and start/end statements. We need to decode, reinstate the newlines every 64
// character and add statements for the PEM decoder
hdr, err := url.QueryUnescape(hdr)
} 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
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, maybe with URL encoding
// (depends on Traefik version) but without newlines and start/end
// statements. We need to decode, reinstate the newlines every 64
// character and add statements for the PEM decoder
if strings.Contains(hdr, "%") {
if unesc, err := url.QueryUnescape(hdr); err == nil {
hdr = unesc
}
}
for i := 64; i < len(hdr); i += 65 {
@@ -354,21 +378,21 @@ func certificateBytes(req *http.Request) []byte {
}
hdr = "-----BEGIN CERTIFICATE-----\n" + hdr
hdr = hdr + "\n-----END CERTIFICATE-----\n"
hdr += "\n-----END CERTIFICATE-----\n"
bs = []byte(hdr)
}
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
@@ -393,13 +417,13 @@ func fixupAddresses(remote *net.TCPAddr, addresses []string) []string {
continue
}
if remote != nil {
if host == "" || ip.IsUnspecified() {
if host == "" || ip.IsUnspecified() {
if remote != nil {
// Replace the unspecified IP with the request source.
// ... unless the request source is the loopback address or
// multicast/unspecified (can't happen, really).
if remote.IP.IsLoopback() || remote.IP.IsMulticast() || remote.IP.IsUnspecified() {
if remote.IP == nil || remote.IP.IsLoopback() || remote.IP.IsMulticast() || remote.IP.IsUnspecified() {
continue
}
@@ -415,11 +439,22 @@ func fixupAddresses(remote *net.TCPAddr, addresses []string) []string {
}
host = remote.IP.String()
} else {
// remote is nil, unable to determine host IP
continue
}
// If zero port was specified, use remote port.
if port == "0" && remote.Port > 0 {
port = fmt.Sprintf("%d", remote.Port)
}
// If zero port was specified, use remote port.
if port == "0" {
if remote != nil && remote.Port > 0 {
// use remote port
port = strconv.Itoa(remote.Port)
} else {
// unable to determine remote port
continue
}
}
@@ -427,6 +462,9 @@ func fixupAddresses(remote *net.TCPAddr, addresses []string) []string {
fixed = append(fixed, uri.String())
}
// Remove duplicate addresses
fixed = stringutil.UniqueTrimmedStrings(fixed)
return fixed
}
@@ -456,13 +494,13 @@ func errorRetryAfterString() string {
return strconv.Itoa(errorRetryAfterSeconds + rand.Intn(errorRetryFuzzSeconds))
}
func notFoundRetryAfterString(misses int) string {
func notFoundRetryAfterSeconds(misses int) int {
retryAfterS := notFoundRetryMinSeconds + notFoundRetryIncSeconds*misses
if retryAfterS > notFoundRetryMaxSeconds {
retryAfterS = notFoundRetryMaxSeconds
}
retryAfterS += rand.Intn(notFoundRetryFuzzSeconds)
return strconv.Itoa(retryAfterS)
return retryAfterS
}
func reannounceAfterString() string {

View File

@@ -69,6 +69,14 @@ func TestFixupAddresses(t *testing.T) {
remote: addr("123.123.123.123", 9000),
in: []string{"tcp://44.44.44.44:0"},
out: []string{"tcp://44.44.44.44:9000"},
}, { // remote ip nil
remote: addr("", 9000),
in: []string{"tcp://:22000", "tcp://44.44.44.44:9000"},
out: []string{"tcp://44.44.44.44:9000"},
}, { // remote port 0
remote: addr("123.123.123.123", 0),
in: []string{"tcp://:22000", "tcp://44.44.44.44"},
out: []string{"tcp://123.123.123.123:22000"},
},
}

View File

@@ -12,10 +12,14 @@ package main
import (
"context"
"log"
"net"
"net/url"
"sort"
"time"
"github.com/syncthing/syncthing/lib/sliceutil"
"github.com/syndtr/goleveldb/leveldb"
"github.com/syndtr/goleveldb/leveldb/storage"
"github.com/syndtr/goleveldb/leveldb/util"
)
@@ -54,6 +58,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() {
@@ -204,7 +220,7 @@ func (s *levelDBStore) statisticsServe(trigger <-chan struct{}, done chan<- stru
cutoff24h := t0.Add(-24 * time.Hour).UnixNano()
cutoff1w := t0.Add(-7 * 24 * time.Hour).UnixNano()
cutoff2Mon := t0.Add(-60 * 24 * time.Hour).UnixNano()
current, last24h, last1w, inactive, errors := 0, 0, 0, 0, 0
current, currentIPv4, currentIPv6, last24h, last1w, inactive, errors := 0, 0, 0, 0, 0, 0, 0
iter := s.db.NewIterator(&util.Range{}, nil)
for iter.Next() {
@@ -219,9 +235,35 @@ func (s *levelDBStore) statisticsServe(trigger <-chan struct{}, done chan<- stru
// If there are addresses that have not expired it's a current
// record, otherwise account it based on when it was last seen
// (last 24 hours or last week) or finally as inactice.
addrs := expire(rec.Addresses, nowNanos)
switch {
case len(expire(rec.Addresses, nowNanos)) > 0:
case len(addrs) > 0:
current++
seenIPv4, seenIPv6 := false, false
for _, addr := range addrs {
uri, err := url.Parse(addr.Address)
if err != nil {
continue
}
host, _, err := net.SplitHostPort(uri.Host)
if err != nil {
continue
}
if ip := net.ParseIP(host); ip != nil && ip.To4() != nil {
seenIPv4 = true
} else if ip != nil {
seenIPv6 = true
}
if seenIPv4 && seenIPv6 {
break
}
}
if seenIPv4 {
currentIPv4++
}
if seenIPv6 {
currentIPv6++
}
case rec.Seen > cutoff24h:
last24h++
case rec.Seen > cutoff1w:
@@ -245,6 +287,8 @@ func (s *levelDBStore) statisticsServe(trigger <-chan struct{}, done chan<- stru
iter.Release()
databaseKeys.WithLabelValues("current").Set(float64(current))
databaseKeys.WithLabelValues("currentIPv4").Set(float64(currentIPv4))
databaseKeys.WithLabelValues("currentIPv6").Set(float64(currentIPv6))
databaseKeys.WithLabelValues("last24h").Set(float64(last24h))
databaseKeys.WithLabelValues("last1w").Set(float64(last1w))
databaseKeys.WithLabelValues("inactive").Set(float64(inactive))
@@ -339,14 +383,7 @@ func expire(addrs []DatabaseAddress, now int64) []DatabaseAddress {
i := 0
for i < len(addrs) {
if addrs[i].Expires < now {
// This item is expired. Replace it with the last in the list
// (noop if we are at the last item).
addrs[i] = addrs[len(addrs)-1]
// Wipe the last item of the list to release references to
// strings and stuff.
addrs[len(addrs)-1] = DatabaseAddress{}
// Shorten the slice.
addrs = addrs[:len(addrs)-1]
addrs = sliceutil.RemoveAndZero(addrs, i)
continue
}
i++

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)
}
@@ -188,7 +185,7 @@ func TestFilter(t *testing.T) {
},
{
a: []DatabaseAddress{{Address: "a", Expires: 5}, {Address: "b", Expires: 15}, {Address: "c", Expires: 5}, {Address: "d", Expires: 15}, {Address: "e", Expires: 5}},
b: []DatabaseAddress{{Address: "d", Expires: 15}, {Address: "b", Expires: 15}}, // gets reordered
b: []DatabaseAddress{{Address: "b", Expires: 15}, {Address: "d", Expires: 15}},
},
}
@@ -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

@@ -14,6 +14,7 @@ import (
"net"
"net/http"
"os"
"runtime"
"strings"
"time"
@@ -64,9 +65,7 @@ var levelDBOptions = &opt.Options{
WriteBuffer: 32 << 20, // default 4<<20
}
var (
debug = false
)
var debug = false
func main() {
var listen string
@@ -76,20 +75,26 @@ func main() {
var replicationPeers string
var certFile string
var keyFile string
var replCertFile string
var replKeyFile string
var useHTTP bool
var largeDB bool
log.SetOutput(os.Stdout)
log.SetFlags(0)
flag.StringVar(&certFile, "cert", "./cert.pem", "Certificate file")
flag.StringVar(&keyFile, "key", "./key.pem", "Key file")
flag.StringVar(&dir, "db-dir", "./discovery.db", "Database directory")
flag.BoolVar(&debug, "debug", false, "Print debug output")
flag.BoolVar(&useHTTP, "http", false, "Listen on HTTP (behind an HTTPS proxy)")
flag.StringVar(&listen, "listen", ":8443", "Listen address")
flag.StringVar(&keyFile, "key", "./key.pem", "Key file")
flag.StringVar(&metricsListen, "metrics-listen", "", "Metrics listen address")
flag.StringVar(&replicationPeers, "replicate", "", "Replication peers, id@address, comma separated")
flag.StringVar(&replicationListen, "replication-listen", ":19200", "Replication listen address")
flag.StringVar(&replCertFile, "replication-cert", "", "Certificate file for replication")
flag.StringVar(&replKeyFile, "replication-key", "", "Key file for replication")
flag.BoolVar(&largeDB, "large-db", false, "Use larger database settings")
showVersion := flag.Bool("version", false, "Show version")
flag.Parse()
@@ -98,6 +103,17 @@ func main() {
return
}
buildInfo.WithLabelValues(build.Version, runtime.Version(), build.User, build.Date.UTC().Format("2006-01-02T15:04:05Z")).Set(1)
if largeDB {
levelDBOptions.BlockCacheCapacity = 64 << 20
levelDBOptions.BlockSize = 64 << 10
levelDBOptions.CompactionTableSize = 16 << 20
levelDBOptions.CompactionTableSizeMultiplier = 2.0
levelDBOptions.WriteBuffer = 64 << 20
levelDBOptions.CompactionL0Trigger = 8
}
cert, err := tls.LoadX509KeyPair(certFile, keyFile)
if os.IsNotExist(err) {
log.Println("Failed to load keypair. Generating one, this might take a while...")
@@ -111,13 +127,26 @@ func main() {
devID := protocol.NewDeviceID(cert.Certificate[0])
log.Println("Server device ID is", devID)
replCert := cert
if replCertFile != "" && replKeyFile != "" {
replCert, err = tls.LoadX509KeyPair(replCertFile, replKeyFile)
if err != nil {
log.Fatalln("Failed to load replication keypair:", err)
}
}
replDevID := protocol.NewDeviceID(replCert.Certificate[0])
log.Println("Replication device ID is", replDevID)
// Parse the replication specs, if any.
var allowedReplicationPeers []protocol.DeviceID
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 +166,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:
@@ -159,14 +191,14 @@ func main() {
// Start any replication senders.
var repl replicationMultiplexer
for _, dst := range replicationDestinations {
rs := newReplicationSender(dst, cert, allowedReplicationPeers)
rs := newReplicationSender(dst, replCert, allowedReplicationPeers)
main.Add(rs)
repl = append(repl, rs)
}
// If we have replication configured, start the replication listener.
if len(allowedReplicationPeers) > 0 {
rl := newReplicationListener(replicationListen, cert, allowedReplicationPeers, db)
rl := newReplicationListener(replicationListen, replCert, allowedReplicationPeers, db)
main.Add(rl)
}

View File

@@ -19,8 +19,11 @@ import (
"github.com/syncthing/syncthing/lib/protocol"
)
const replicationReadTimeout = time.Minute
const replicationHeartbeatInterval = time.Second * 30
const (
replicationReadTimeout = time.Minute
replicationWriteTimeout = 30 * time.Second
replicationHeartbeatInterval = time.Second * 30
)
type replicator interface {
send(key string, addrs []DatabaseAddress, seen int64)
@@ -68,6 +71,12 @@ func (s *replicationSender) Serve(ctx context.Context) error {
conn.Close()
}()
// The replication stream is not especially latency sensitive, but it is
// quite a lot of data in small writes. Make it more efficient.
if tcpc, ok := conn.NetConn().(*net.TCPConn); ok {
_ = tcpc.SetNoDelay(false)
}
// Get the other side device ID.
remoteID, err := deviceID(conn)
if err != nil {
@@ -116,11 +125,11 @@ func (s *replicationSender) Serve(ctx context.Context) error {
binary.BigEndian.PutUint32(buf, uint32(n))
// Send
conn.SetWriteDeadline(time.Now().Add(5 * time.Second))
conn.SetWriteDeadline(time.Now().Add(replicationWriteTimeout))
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 +144,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,9 +10,18 @@ import (
"os"
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/collectors"
)
var (
buildInfo = prometheus.NewGaugeVec(
prometheus.GaugeOpts{
Namespace: "syncthing",
Subsystem: "discovery",
Name: "build_info",
Help: "A metric with a constant '1' value labeled by version, goversion, builduser and builddate from which stdiscosrv was built.",
}, []string{"version", "goversion", "builduser", "builddate"})
apiRequestsTotal = prometheus.NewCounterVec(
prometheus.CounterOpts{
Namespace: "syncthing",
@@ -89,6 +98,14 @@ var (
Help: "Latency of database operations.",
Objectives: map[float64]float64{0.5: 0.05, 0.9: 0.01, 0.99: 0.001},
}, []string{"operation"})
retryAfterHistogram = prometheus.NewHistogram(prometheus.HistogramOpts{
Namespace: "syncthing",
Subsystem: "discovery",
Name: "retry_after_seconds",
Help: "Retry-After header value in seconds.",
Buckets: prometheus.ExponentialBuckets(60, 2, 7), // 60, 120, 240, 480, 960, 1920, 3840
})
)
const (
@@ -103,13 +120,15 @@ const (
)
func init() {
prometheus.MustRegister(apiRequestsTotal, apiRequestsSeconds,
prometheus.MustRegister(buildInfo,
apiRequestsTotal, apiRequestsSeconds,
lookupRequestsTotal, announceRequestsTotal,
replicationSendsTotal, replicationRecvsTotal,
databaseKeys, databaseStatisticsSeconds,
databaseOperations, databaseOperationSeconds)
databaseOperations, databaseOperationSeconds,
retryAfterHistogram)
processCollectorOpts := prometheus.ProcessCollectorOpts{
processCollectorOpts := collectors.ProcessCollectorOpts{
Namespace: "syncthing_discovery",
PidFn: func() (int, error) {
return os.Getpid(), nil
@@ -117,7 +136,6 @@ func init() {
}
prometheus.MustRegister(
prometheus.NewProcessCollector(processCollectorOpts),
collectors.NewProcessCollector(processCollectorOpts),
)
}

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,52 +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")
}
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")
}
}

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

@@ -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 noassets
//go:build noassets
// +build noassets
package auto

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('https://{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,15 +3,12 @@
package main
import (
"compress/gzip"
"context"
"crypto/tls"
"crypto/x509"
"encoding/json"
"flag"
"fmt"
"io"
"io/ioutil"
"log"
"net"
"net/http"
@@ -20,11 +17,13 @@ import (
"path/filepath"
"strconv"
"strings"
"sync/atomic"
"time"
lru "github.com/hashicorp/golang-lru/v2"
"github.com/syncthing/syncthing/lib/httpcache"
"github.com/syncthing/syncthing/lib/protocol"
"github.com/golang/groupcache/lru"
"github.com/oschwald/geoip2-golang"
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promhttp"
@@ -34,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 {
@@ -100,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
@@ -128,6 +112,7 @@ var (
knownRelays = make([]*relay, 0)
permanentRelays = make([]*relay, 0)
evictionTimers = make(map[string]*time.Timer)
globalBlocklist = newErrorTracker(1000)
)
const (
@@ -142,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")
@@ -160,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
@@ -241,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{
@@ -292,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 {
@@ -328,20 +298,28 @@ 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]
@@ -369,6 +347,11 @@ 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()
@@ -388,12 +371,6 @@ 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() {
@@ -425,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{
@@ -542,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
@@ -568,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
}
@@ -598,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)
}
@@ -657,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.")
@@ -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)
}
@@ -200,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:
@@ -230,14 +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. !!")
@@ -253,7 +277,7 @@ func main() {
}
}
go listener(proto, listen, tlsCfg)
go listener(proto, listen, tlsCfg, token)
sigs := make(chan os.Signal, 1)
signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM)
@@ -284,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

@@ -6,7 +6,7 @@ import (
"bytes"
"crypto/tls"
"encoding/json"
"io/ioutil"
"io"
"log"
"net/http"
"net/url"
@@ -56,7 +56,7 @@ func poolHandler(pool string, uri *url.URL, mapping mapping, ownCert tls.Certifi
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)
@@ -74,9 +74,8 @@ func poolHandler(pool string, uri *url.URL, mapping mapping, ownCert tls.Certifi
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

@@ -44,7 +44,7 @@ func main() {
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

@@ -10,40 +10,98 @@ 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 struct {
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
}
func getClient(cfg config.GUIConfiguration) *APIClient {
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(cfg.Network(), cfg.Address())
return net.Dial(f.cfg.Network(), f.cfg.Address())
},
},
}
return &APIClient{
return &apiClient{
Client: httpClient,
cfg: cfg,
apikey: cfg.APIKey,
}
cfg: f.cfg,
apikey: f.cfg.APIKey,
}, nil
}
func (c *APIClient) Endpoint() string {
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/"
}
@@ -54,7 +112,7 @@ func (c *APIClient) Endpoint() string {
return url
}
func (c *APIClient) Do(req *http.Request) (*http.Response, error) {
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 {
@@ -63,28 +121,46 @@ func (c *APIClient) Do(req *http.Request) (*http.Response, error) {
return resp, checkResponse(resp)
}
func (c *APIClient) Get(url string) (*http.Response, error) {
request, err := http.NewRequest("GET", c.Endpoint()+"rest/"+url, nil)
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) Post(url, body string) (*http.Response, error) {
request, err := http.NewRequest("POST", c.Endpoint()+"rest/"+url, bytes.NewBufferString(body))
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.Do(request)
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 == 404 {
return errors.New("invalid endpoint or API call")
} else if response.StatusCode == 403 {
if response.StatusCode == http.StatusNotFound {
return errNotFound
} else if response.StatusCode == http.StatusUnauthorized {
return errors.New("invalid API key")
} else if response.StatusCode != 200 {
} else if response.StatusCode != http.StatusOK {
data, err := responseToBArray(response)
if err != nil {
return err

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

@@ -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:])
@@ -152,4 +156,5 @@ func dump(ldb backend.Backend) {
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[:])

View File

@@ -8,30 +8,26 @@ package cli
import (
"bufio"
"crypto/tls"
"encoding/json"
"io/ioutil"
"errors"
"fmt"
"io"
"os"
"reflect"
"strings"
"github.com/AudriusButkevicius/recli"
"github.com/alecthomas/kong"
"github.com/flynn-archive/go-shlex"
"github.com/mattn/go-isatty"
"github.com/pkg/errors"
"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"
"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:"conf"`
ConfDir string `name:"config"`
DataDir string `name:"data"`
}
func Run() error {
@@ -42,76 +38,31 @@ func Run() error {
// 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.
var err error
homeSet := c.HomeDir != ""
confSet := c.ConfDir != ""
switch {
case homeSet && confSet:
err = errors.New("-home must not be used together with -conf")
case homeSet:
err = locations.SetBaseDir(locations.ConfigBaseDir, c.HomeDir)
case confSet:
err = locations.SetBaseDir(locations.ConfigBaseDir, c.ConfDir)
}
err := cmdutil.SetConfigDataLocationsFromFlags(c.HomeDir, c.ConfDir, c.DataDir)
if err != nil {
return errors.Wrap(err, "Command line options:")
return fmt.Errorf("Command line options: %w", err)
}
guiCfg := config.GUIConfiguration{
RawAddress: c.GUIAddress,
APIKey: c.GUIAPIKey,
clientFactory := &apiClientFactory{
cfg: config.GUIConfiguration{
RawAddress: c.GUIAddress,
APIKey: c.GUIAPIKey,
},
}
// 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 == "" {
// Load the certs and get the ID
cert, err := tls.LoadX509KeyPair(
locations.Get(locations.CertFile),
locations.Get(locations.KeyFile),
)
if err != nil {
return 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 {
return errors.Wrap(err, "loading config")
}
guiCfg = cfg.GUI()
} else if guiCfg.Address() == "" || guiCfg.APIKey == "" {
return errors.New("Both --gui-address and --gui-apikey should be specified")
}
if guiCfg.Address() == "" {
return errors.New("Could not find GUI Address")
}
if guiCfg.APIKey == "" {
return errors.New("Could not find GUI API key")
}
client := getClient(guiCfg)
cfg, err := getConfig(client)
original := cfg.Copy()
configCommand, err := getConfigCommand(clientFactory)
if err != nil {
return 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 {
return errors.Wrap(err, "config reflect")
return err
}
// Implement the same flags at the upper CLI, but do nothing with them.
@@ -119,23 +70,23 @@ func Run() error {
fakeFlags := []cli.Flag{
cli.StringFlag{
Name: "gui-address",
Value: "URL",
Usage: "Override GUI address (e.g. \"http://192.0.2.42:8443\")",
Usage: "Override GUI address to `URL` (e.g. \"192.0.2.42:8443\")",
},
cli.StringFlag{
Name: "gui-apikey",
Value: "API-KEY",
Usage: "Override GUI API key",
Usage: "Override GUI API key to `API-KEY`",
},
cli.StringFlag{
Name: "home",
Value: "PATH",
Usage: "Set configuration and data directory",
Usage: "Set configuration and data directory to `PATH`",
},
cli.StringFlag{
Name: "conf",
Value: "PATH",
Usage: "Set configuration directory (config and keys)",
Name: "config",
Usage: "Set configuration directory (config and keys) to `PATH`",
},
cli.StringFlag{
Name: "data",
Usage: "Set data directory (database and logs) to `PATH`",
},
}
@@ -143,71 +94,53 @@ func Run() error {
app := cli.NewApp()
app.Author = "The Syncthing Authors"
app.Metadata = map[string]interface{}{
"client": client,
"clientFactory": clientFactory,
}
app.Commands = []cli.Command{{
Name: "cli",
Usage: "Syncthing command line interface",
Flags: fakeFlags,
Subcommands: []cli.Command{
{
Name: "config",
HideHelp: true,
Usage: "Configuration modification command group",
Subcommands: commands,
},
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()
},
},
},
}}
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 {
return errors.Wrap(err, "parsing input")
}
if len(input) == 0 {
continue
}
err = app.Run(append(os.Args, input...))
if err != nil {
return err
}
}
err = scanner.Err()
if err != nil {
return err
}
} else {
err = app.Run(os.Args)
if err != nil {
return err
}
}
if !reflect.DeepEqual(cfg, original) {
body, err := json.MarshalIndent(cfg, "", " ")
if err != nil {
return err
}
resp, err := 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
return app.Run(cliArgs)
}
func parseFlags(c *preCli) error {
@@ -216,7 +149,10 @@ func parseFlags(c *preCli) error {
if len(os.Args) <= 2 {
return nil
}
args := os.Args[2:]
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]
@@ -227,7 +163,7 @@ func parseFlags(c *preCli) error {
}
}
// We don't want kong to print anything nor os.Exit (e.g. on -h)
parser, err := kong.New(c, kong.Writers(ioutil.Discard, ioutil.Discard), kong.Exit(func(int) {}))
parser, err := kong.New(c, kong.Writers(io.Discard, io.Discard), kong.Exit(func(int) {}))
if err != nil {
return err
}

View File

@@ -7,8 +7,13 @@
package cli
import (
"bufio"
"errors"
"fmt"
"path/filepath"
"github.com/syncthing/syncthing/lib/config"
"github.com/syncthing/syncthing/lib/fs"
"github.com/urfave/cli"
)
@@ -35,14 +40,23 @@ var operationCommand = cli.Command{
{
Name: "folder-override",
Usage: "Override changes on folder (remote for sendonly, local for receiveonly). WARNING: Destructive - deletes/changes your data.",
ArgsUsage: "[folder id]",
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
@@ -64,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

@@ -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("config/restart-required")),
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")),
},
},
}

View File

@@ -8,17 +8,22 @@ package cli
import (
"encoding/json"
"errors"
"fmt"
"io/ioutil"
"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 := ioutil.ReadAll(response.Body)
bytes, err := io.ReadAll(response.Body)
if err != nil {
return nil, err
}
@@ -27,24 +32,69 @@ func responseToBArray(response *http.Response) ([]byte, error) {
func emptyPost(url string) cli.ActionFunc {
return func(c *cli.Context) error {
client := c.App.Metadata["client"].(*APIClient)
_, err := client.Post(url, "")
client, err := getClientFactory(c).getClient()
if err != nil {
return err
}
_, err = client.Post(url, "")
return err
}
}
func dumpOutput(url string) cli.ActionFunc {
func indexDumpOutput(url string) cli.ActionFunc {
return func(c *cli.Context) error {
client := c.App.Metadata["client"].(*APIClient)
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
}
return prettyPrintResponse(c, response)
_, 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) {
func getConfig(c APIClient) (config.Configuration, error) {
cfg := config.Configuration{}
response, err := c.Get("system/config")
if err != nil {
@@ -55,8 +105,8 @@ func getConfig(c *APIClient) (config.Configuration, error) {
return cfg, err
}
err = json.Unmarshal(bytes, &cfg)
if err == nil {
return cfg, err
if err != nil {
return config.Configuration{}, err
}
return cfg, nil
}
@@ -80,7 +130,7 @@ func prettyPrintJSON(data interface{}) error {
return enc.Encode(data)
}
func prettyPrintResponse(c *cli.Context, response *http.Response) error {
func prettyPrintResponse(response *http.Response) error {
bytes, err := responseToBArray(response)
if err != nil {
return err
@@ -92,3 +142,24 @@ func prettyPrintResponse(c *cli.Context, response *http.Response) error {
// 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

@@ -4,10 +4,11 @@
// 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
package cmdutil
type buildServeOptions struct {
type buildCommonOptions struct {
HideConsole bool `hidden:""`
}

View File

@@ -4,8 +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/.
package main
package cmdutil
type buildServeOptions struct {
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

@@ -10,10 +10,11 @@ package decrypt
import (
"encoding/binary"
"encoding/json"
"errors"
"fmt"
"io"
"io/ioutil"
"log"
"os"
"path/filepath"
"github.com/syncthing/syncthing/lib/config"
@@ -34,6 +35,7 @@ type CLI struct {
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 {
@@ -45,7 +47,7 @@ func (c *CLI) Run() error {
log.SetFlags(0)
if c.To == "" && !c.VerifyOnly {
return fmt.Errorf("must set --to or --verify")
return errors.New("must set --to or --verify-only")
}
if c.TokenPath == "" {
@@ -67,7 +69,8 @@ func (c *CLI) Run() error {
}
}
c.folderKey = protocol.KeyFromPassword(c.FolderID, c.Password)
c.keyGen = protocol.NewKeyGenerator()
c.folderKey = c.keyGen.KeyFromPassword(c.FolderID, c.Password)
return c.walk()
}
@@ -112,7 +115,7 @@ func (c *CLI) withContinue(err error) error {
// error.
func (c *CLI) getFolderID() (string, error) {
tokenPath := filepath.Join(c.Path, c.TokenPath)
bs, err := ioutil.ReadFile(tokenPath)
bs, err := os.ReadFile(tokenPath)
if err != nil {
return "", fmt.Errorf("reading folder token: %w", err)
}
@@ -128,6 +131,9 @@ func (c *CLI) getFolderID() (string, error) {
// 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)
}
@@ -138,7 +144,7 @@ func (c *CLI) process(srcFs fs.Filesystem, dstFs fs.Filesystem, path string) err
}
defer encFd.Close()
encFi, err := c.loadEncryptedFileInfo(encFd)
encFi, err := loadEncryptedFileInfo(encFd)
if err != nil {
return fmt.Errorf("%s: loading metadata trailer: %w", path, err)
}
@@ -147,7 +153,7 @@ func (c *CLI) process(srcFs fs.Filesystem, dstFs fs.Filesystem, path string) err
// in native format, while protocol expects wire format (slashes).
encFi.Name = osutil.NormalizedFilename(encFi.Name)
plainFi, err := protocol.DecryptFileInfo(*encFi, c.folderKey)
plainFi, err := protocol.DecryptFileInfo(c.keyGen, *encFi, c.folderKey)
if err != nil {
return fmt.Errorf("%s: decrypting metadata: %w", path, err)
}
@@ -158,7 +164,7 @@ func (c *CLI) process(srcFs fs.Filesystem, dstFs fs.Filesystem, path string) err
var plainFd fs.File
if dstFs != nil {
if err := dstFs.MkdirAll(filepath.Dir(plainFi.Name), 0700); err != nil {
if err := dstFs.MkdirAll(filepath.Dir(plainFi.Name), 0o700); err != nil {
return fmt.Errorf("%s: %w", plainFi.Name, err)
}
@@ -167,6 +173,9 @@ func (c *CLI) process(srcFs fs.Filesystem, dstFs fs.Filesystem, path string) err
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 {
@@ -183,7 +192,12 @@ func (c *CLI) process(srcFs fs.Filesystem, dstFs fs.Filesystem, path string) err
}
if plainFd != nil {
return plainFd.Close()
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
}
@@ -197,7 +211,7 @@ func (c *CLI) decryptFile(encFi *protocol.FileInfo, plainFi *protocol.FileInfo,
return fmt.Errorf("block count mismatch: encrypted %d != plaintext %d", len(encFi.Blocks), len(plainFi.Blocks))
}
fileKey := protocol.FileKey(plainFi.Name, c.folderKey)
fileKey := c.keyGen.FileKey(plainFi.Name, c.folderKey)
for i, encBlock := range encFi.Blocks {
// Read the encrypted block
buf := make([]byte, encBlock.Size)
@@ -246,7 +260,7 @@ func (c *CLI) decryptFile(encFi *protocol.FileInfo, plainFi *protocol.FileInfo,
// loadEncryptedFileInfo loads the encrypted FileInfo trailer from a file on
// disk.
func (c *CLI) loadEncryptedFileInfo(fd fs.File) (*protocol.FileInfo, error) {
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

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, 0o700); 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.SetPassword(guiPassword); err != nil {
return fmt.Errorf("failed to set GUI authentication password: %w", err)
}
l.Infoln("Updated GUI authentication password.")
}
return nil
}

View File

@@ -10,9 +10,9 @@ import (
"bytes"
"context"
"crypto/tls"
"errors"
"fmt"
"io"
"io/ioutil"
"log"
"net/http"
_ "net/http/pprof" // Need to import this to support STPROFILER.
@@ -34,7 +34,9 @@ import (
"github.com/thejerf/suture/v4"
"github.com/syncthing/syncthing/cmd/syncthing/cli"
"github.com/syncthing/syncthing/cmd/syncthing/cmdutil"
"github.com/syncthing/syncthing/cmd/syncthing/decrypt"
"github.com/syncthing/syncthing/cmd/syncthing/generate"
"github.com/syncthing/syncthing/lib/build"
"github.com/syncthing/syncthing/lib/config"
"github.com/syncthing/syncthing/lib/db"
@@ -48,16 +50,11 @@ import (
"github.com/syncthing/syncthing/lib/protocol"
"github.com/syncthing/syncthing/lib/svcutil"
"github.com/syncthing/syncthing/lib/syncthing"
"github.com/syncthing/syncthing/lib/tlsutil"
"github.com/syncthing/syncthing/lib/upgrade"
"github.com/pkg/errors"
)
const (
tlsDefaultCommonName = "syncthing"
deviceCertLifetimeDays = 20 * 365
sigTerm = syscall.Signal(15)
sigTerm = syscall.Signal(15)
)
const (
@@ -70,14 +67,14 @@ The --logflags value is a sum of the following:
8 Long filename
16 Short filename
I.e. to prefix each log line with date and time, set --logflags=3 (1 + 2 from
above). The value 0 is used to disable all of the above. The default is to
show time only (2).
I.e. to prefix each log line with time and filename, set --logflags=18 (2 + 16
from above). The value 0 is used to disable all of the above. The default is
to show date and time (3).
Logging always happens to the command line (stdout) and optionally to the
file at the path specified by -logfile=path. In addition to an path, the special
file at the path specified by --logfile=path. In addition to an path, the special
values "default" and "-" may be used. The former logs to DATADIR/syncthing.log
(see -data-dir), which is the default on Windows, and the latter only to stdout,
(see --data), which is the default on Windows, and the latter only to stdout,
no file, which is the default anywhere else.
@@ -102,6 +99,11 @@ above.
"minio" for the github.com/minio/sha256-simd implementation,
and blank (the default) for auto detection.
STVERSIONEXTRA Add extra information to the version string in logs and the
version line in the GUI. Can be set to the name of a wrapper
or tool controlling syncthing to communicate this to the end
user.
GOMAXPROCS Set the maximum number of CPU cores to use. Defaults to all
available CPU cores.
@@ -134,32 +136,30 @@ var (
// commands and options here are top level commands to syncthing.
// Cli is just a placeholder for the help text (see main).
var entrypoint struct {
Serve serveOptions `cmd:"" help:"Run Syncthing"`
Decrypt decrypt.CLI `cmd:"" help:"Decrypt or verify an encrypted folder"`
Cli struct{} `cmd:"" help:"Command line interface for Syncthing"`
Serve serveOptions `cmd:"" help:"Run Syncthing"`
Generate generate.CLI `cmd:"" help:"Generate key and config, then exit"`
Decrypt decrypt.CLI `cmd:"" help:"Decrypt or verify an encrypted folder"`
Cli struct{} `cmd:"" help:"Command line interface for Syncthing"`
}
// serveOptions are the options for the `syncthing serve` command.
type serveOptions struct {
buildServeOptions
cmdutil.CommonOptions
AllowNewerConfig bool `help:"Allow loading newer than current config version"`
Audit bool `help:"Write events to audit file"`
AuditFile string `name:"auditfile" placeholder:"PATH" help:"Specify audit file (use \"-\" for stdout, \"--\" for stderr)"`
BrowserOnly bool `help:"Open GUI in browser"`
ConfDir string `name:"config" placeholder:"PATH" help:"Set configuration directory (config and keys)"`
DataDir string `name:"data" placeholder:"PATH" help:"Set data directory (database and logs)"`
DataDir string `name:"data" placeholder:"PATH" env:"STDATADIR" help:"Set data directory (database and logs)"`
DeviceID bool `help:"Show the device ID"`
GenerateDir string `name:"generate" placeholder:"PATH" help:"Generate key and config in specified dir, then exit"`
GenerateDir string `name:"generate" placeholder:"PATH" help:"Generate key and config in specified dir, then exit"` // DEPRECATED: replaced by subcommand!
GUIAddress string `name:"gui-address" placeholder:"URL" help:"Override GUI address (e.g. \"http://192.0.2.42:8443\")"`
GUIAPIKey string `name:"gui-apikey" placeholder:"API-KEY" help:"Override GUI API key"`
HomeDir string `name:"home" placeholder:"PATH" help:"Set configuration and data directory"`
LogFile string `name:"logfile" default:"${logFile}" placeholder:"PATH" help:"Log file name (see below)"`
LogFlags int `name:"logflags" default:"${logFlags}" placeholder:"BITS" help:"Select information in log line prefix (see below)"`
LogMaxFiles int `placeholder:"N" default:"${logMaxFiles}" name:"log-max-old-files" help:"Number of old files to keep (zero to keep only current)"`
LogMaxSize int `placeholder:"BYTES" default:"${logMaxSize}" help:"Maximum size of any file (zero to disable log rotation)"`
NoBrowser bool `help:"Do not start browser"`
NoRestart bool `env:"STNORESTART" help:"Do not restart Syncthing when exiting due to API/GUI command, upgrade, or crash"`
NoDefaultFolder bool `env:"STNODEFAULTFOLDER" help:"Don't create the \"default\" folder on first startup"`
NoUpgrade bool `env:"STNOUPGRADE" help:"Disable automatic upgrades"`
Paths bool `help:"Show configuration paths"`
Paused bool `help:"Start with all devices and folders paused"`
@@ -177,7 +177,7 @@ type serveOptions struct {
DebugGUIAssetsDir string `placeholder:"PATH" help:"Directory to load GUI assets from" env:"STGUIASSETS"`
DebugPerfStats bool `env:"STPERFSTATS" help:"Write running performance statistics to perf-$pid.csv (Unix only)"`
DebugProfileBlock bool `env:"STBLOCKPROFILE" help:"Write block profiles to block-$pid-$timestamp.pprof every 20 seconds"`
DebugProfileCPU bool `help:"Write a CPU profile to cpu-$pid.pprof on exit" env:"CPUPROFILE"`
DebugProfileCPU bool `help:"Write a CPU profile to cpu-$pid.pprof on exit" env:"STCPUPROFILE"`
DebugProfileHeap bool `env:"STHEAPPROFILE" help:"Write heap profiles to heap-$pid-$timestamp.pprof each time heap usage increases"`
DebugProfilerListen string `placeholder:"ADDR" env:"STPROFILER" help:"Network profiler listen address"`
DebugResetDatabase bool `name:"reset-database" help:"Reset the database, forcing a full rescan and resync"`
@@ -191,7 +191,7 @@ type serveOptions struct {
func defaultVars() kong.Vars {
vars := kong.Vars{}
vars["logFlags"] = strconv.Itoa(log.Ltime)
vars["logFlags"] = strconv.Itoa(logger.DefaultFlags)
vars["logMaxSize"] = strconv.Itoa(10 << 20) // 10 MiB
vars["logMaxFiles"] = "3" // plus the current one
@@ -203,7 +203,7 @@ func defaultVars() kong.Vars {
// Windows, the "default" options.logFile will later be replaced with the
// default path, unless the user has manually specified "-" or
// something else.
if runtime.GOOS == "windows" {
if build.IsWindows {
vars["logFile"] = "default"
} else {
vars["logFile"] = "-"
@@ -256,6 +256,7 @@ func main() {
ctx, err := parser.Parse(args)
parser.FatalIfErrorf(err)
ctx.BindTo(l, (*logger.Logger)(nil)) // main logger available to subcommands
err = ctx.Run()
parser.FatalIfErrorf(err)
}
@@ -290,39 +291,31 @@ func (options serveOptions) Run() error {
}
// Not set as default above because the strings can be really long.
var err error
homeSet := options.HomeDir != ""
confSet := options.ConfDir != ""
dataSet := options.DataDir != ""
switch {
case dataSet != confSet:
err = errors.New("either both or none of -conf and -data must be given, use -home to set both at once")
case homeSet && dataSet:
err = errors.New("-home must not be used together with -conf and -data")
case homeSet:
if err = locations.SetBaseDir(locations.ConfigBaseDir, options.HomeDir); err == nil {
err = locations.SetBaseDir(locations.DataBaseDir, options.HomeDir)
}
case dataSet:
if err = locations.SetBaseDir(locations.ConfigBaseDir, options.ConfDir); err == nil {
err = locations.SetBaseDir(locations.DataBaseDir, options.DataDir)
}
}
err := cmdutil.SetConfigDataLocationsFromFlags(options.HomeDir, options.ConfDir, options.DataDir)
if err != nil {
l.Warnln("Command line options:", err)
os.Exit(svcutil.ExitError.AsInt())
}
if options.LogFile == "default" || options.LogFile == "" {
// Treat an explicitly empty log file name as no log file
if options.LogFile == "" {
options.LogFile = "-"
}
if options.LogFile != "default" {
// We must set this *after* expandLocations above.
// Handling an empty value is for backwards compatibility (<1.4.1).
options.LogFile = locations.Get(locations.LogFile)
if err := locations.Set(locations.LogFile, options.LogFile); err != nil {
l.Warnln("Setting log file path:", err)
os.Exit(svcutil.ExitError.AsInt())
}
}
if options.DebugGUIAssetsDir == "" {
if options.DebugGUIAssetsDir != "" {
// The asset dir is blank if STGUIASSETS wasn't set, in which case we
// should look for extra assets in the default place.
options.DebugGUIAssetsDir = locations.Get(locations.GUIAssets)
if err := locations.Set(locations.GUIAssets, options.DebugGUIAssetsDir); err != nil {
l.Warnln("Setting GUI assets path:", err)
os.Exit(svcutil.ExitError.AsInt())
}
}
if options.Version {
@@ -331,7 +324,7 @@ func (options serveOptions) Run() error {
}
if options.Paths {
showPaths(options)
fmt.Print(locations.PrettyPaths())
return nil
}
@@ -350,7 +343,7 @@ func (options serveOptions) Run() error {
}
if options.BrowserOnly {
if err := openGUI(protocol.EmptyDeviceID); err != nil {
if err := openGUI(); err != nil {
l.Warnln("Failed to open web UI:", err)
os.Exit(svcutil.ExitError.AsInt())
}
@@ -358,7 +351,7 @@ func (options serveOptions) Run() error {
}
if options.GenerateDir != "" {
if err := generate(options.GenerateDir, options.NoDefaultFolder); err != nil {
if err := generate.Generate(l, options.GenerateDir, "", "", options.NoDefaultFolder, options.SkipPortProbing); err != nil {
l.Warnln("Failed to generate config and keys:", err)
os.Exit(svcutil.ExitError.AsInt())
}
@@ -366,7 +359,7 @@ func (options serveOptions) Run() error {
}
// Ensure that our home directory exists.
if err := ensureDir(locations.GetBaseDir(locations.ConfigBaseDir), 0700); err != nil {
if err := syncthing.EnsureDir(locations.GetBaseDir(locations.ConfigBaseDir), 0o700); err != nil {
l.Warnln("Failure on home directory:", err)
os.Exit(svcutil.ExitError.AsInt())
}
@@ -427,13 +420,13 @@ func (options serveOptions) Run() error {
return nil
}
func openGUI(myID protocol.DeviceID) error {
cfg, err := loadOrDefaultConfig(myID, events.NoopLogger, true)
func openGUI() error {
cfg, err := loadOrDefaultConfig()
if err != nil {
return err
}
if cfg.GUI().Enabled {
if err := openURL(cfg.GUI().URL()); err != nil {
if guiCfg := cfg.GUI(); guiCfg.Enabled {
if err := openURL(guiCfg.URL()); err != nil {
return err
}
} else {
@@ -442,46 +435,6 @@ func openGUI(myID protocol.DeviceID) error {
return nil
}
func generate(generateDir string, noDefaultFolder bool) error {
dir, err := fs.ExpandTilde(generateDir)
if err != nil {
return err
}
if err := ensureDir(dir, 0700); err != nil {
return err
}
var myID protocol.DeviceID
certFile, keyFile := filepath.Join(dir, "cert.pem"), filepath.Join(dir, "key.pem")
cert, err := tls.LoadX509KeyPair(certFile, keyFile)
if err == nil {
l.Warnln("Key exists; will not overwrite.")
} else {
cert, err = tlsutil.NewCertificate(certFile, keyFile, tlsDefaultCommonName, deviceCertLifetimeDays)
if err != nil {
return errors.Wrap(err, "create certificate")
}
}
myID = protocol.NewDeviceID(cert.Certificate[0])
l.Infoln("Device ID:", myID)
cfgFile := filepath.Join(dir, "config.xml")
if _, err := os.Stat(cfgFile); err == nil {
l.Warnln("Config exists; will not overwrite.")
return nil
}
cfg, err := syncthing.DefaultConfig(cfgFile, myID, events.NoopLogger, noDefaultFolder)
if err != nil {
return err
}
err = cfg.Save()
if err != nil {
return errors.Wrap(err, "save config")
}
return nil
}
func debugFacilities() string {
facilities := l.Facilities()
@@ -513,7 +466,7 @@ func (e *errNoUpgrade) Error() string {
}
func checkUpgrade() (upgrade.Release, error) {
cfg, err := loadOrDefaultConfig(protocol.EmptyDeviceID, events.NoopLogger, true)
cfg, err := loadOrDefaultConfig()
if err != nil {
return upgrade.Release{}, err
}
@@ -532,7 +485,11 @@ func checkUpgrade() (upgrade.Release, error) {
}
func upgradeViaRest() error {
cfg, _ := loadOrDefaultConfig(protocol.EmptyDeviceID, events.NoopLogger, true)
cfg, err := loadOrDefaultConfig()
if err != nil {
return err
}
u, err := url.Parse(cfg.GUI().URL())
if err != nil {
return err
@@ -556,7 +513,7 @@ func upgradeViaRest() error {
return err
}
if resp.StatusCode != 200 {
bs, err := ioutil.ReadAll(resp.Body)
bs, err := io.ReadAll(resp.Body)
defer resp.Body.Close()
if err != nil {
return err
@@ -608,7 +565,7 @@ func syncthingMain(options serveOptions) {
evLogger := events.NewLogger()
earlyService.Add(evLogger)
cfgWrapper, err := syncthing.LoadConfigAtStartup(locations.Get(locations.ConfigFile), cert, evLogger, options.AllowNewerConfig, options.NoDefaultFolder)
cfgWrapper, err := syncthing.LoadConfigAtStartup(locations.Get(locations.ConfigFile), cert, evLogger, options.AllowNewerConfig, options.NoDefaultFolder, options.SkipPortProbing)
if err != nil {
l.Warnln("Failed to initialize config:", err)
os.Exit(svcutil.ExitError.AsInt())
@@ -640,7 +597,7 @@ func syncthingMain(options serveOptions) {
}
// Check if auto-upgrades is possible, and if yes, and it's enabled do an initial
// upgrade immedately. The auto-upgrade routine can only be started
// upgrade immediately. The auto-upgrade routine can only be started
// later after App is initialised.
autoUpgradePossible := autoUpgradePossible(options)
@@ -669,7 +626,6 @@ func syncthingMain(options serveOptions) {
}
appOpts := syncthing.Options{
AssetDir: options.DebugGUIAssetsDir,
DeadlockTimeoutS: options.DebugDeadlockTimeout,
NoUpgrade: options.NoUpgrade,
ProfilerAddr: options.DebugProfilerListen,
@@ -704,7 +660,7 @@ func syncthingMain(options serveOptions) {
setupSignalHandling(app)
if len(os.Getenv("GOMAXPROCS")) == 0 {
if os.Getenv("GOMAXPROCS") == "" {
runtime.GOMAXPROCS(runtime.NumCPU())
}
@@ -720,8 +676,6 @@ func syncthingMain(options serveOptions) {
}
}
go standbyMonitor(app, cfgWrapper)
if err := app.Start(); err != nil {
os.Exit(svcutil.ExitError.AsInt())
}
@@ -768,12 +722,14 @@ func setupSignalHandling(app *syncthing.App) {
}()
}
func loadOrDefaultConfig(myID protocol.DeviceID, evLogger events.Logger, noDefaultFolder bool) (config.Wrapper, error) {
// loadOrDefaultConfig creates a temporary, minimal configuration wrapper if no file
// exists. As it disregards some command-line options, that should never be persisted.
func loadOrDefaultConfig() (config.Wrapper, error) {
cfgFile := locations.Get(locations.ConfigFile)
cfg, _, err := config.Load(cfgFile, myID, evLogger)
cfg, _, err := config.Load(cfgFile, protocol.EmptyDeviceID, events.NoopLogger)
if err != nil {
cfg, err = syncthing.DefaultConfig(cfgFile, myID, evLogger, noDefaultFolder)
newCfg := config.New(protocol.EmptyDeviceID)
return config.Wrap(cfgFile, newCfg, protocol.EmptyDeviceID, events.NoopLogger), nil
}
return cfg, err
@@ -798,7 +754,7 @@ func auditWriter(auditFile string) io.Writer {
} else {
auditFlags = os.O_WRONLY | os.O_CREATE | os.O_APPEND
}
fd, err = os.OpenFile(auditFile, auditFlags, 0600)
fd, err = os.OpenFile(auditFile, auditFlags, 0o600)
if err != nil {
l.Warnln("Audit:", err)
os.Exit(svcutil.ExitError.AsInt())
@@ -815,49 +771,6 @@ func resetDB() error {
return os.RemoveAll(locations.Get(locations.Database))
}
func ensureDir(dir string, mode fs.FileMode) error {
fs := fs.NewFilesystem(fs.FilesystemTypeBasic, dir)
err := fs.MkdirAll(".", mode)
if err != nil {
return err
}
if fi, err := fs.Stat("."); err == nil {
// Apprently the stat may fail even though the mkdirall passed. If it
// does, we'll just assume things are in order and let other things
// fail (like loading or creating the config...).
currentMode := fi.Mode() & 0777
if currentMode != mode {
err := fs.Chmod(".", mode)
// This can fail on crappy filesystems, nothing we can do about it.
if err != nil {
l.Warnln(err)
}
}
}
return nil
}
func standbyMonitor(app *syncthing.App, cfg config.Wrapper) {
restartDelay := 60 * time.Second
now := time.Now()
for {
time.Sleep(10 * time.Second)
if time.Since(now) > 2*time.Minute && cfg.Options().RestartOnWakeup {
l.Infof("Paused state detected, possibly woke up from standby. Restarting in %v.", restartDelay)
// We most likely just woke from standby. If we restart
// immediately chances are we won't have networking ready. Give
// things a moment to stabilize.
time.Sleep(restartDelay)
app.Stop(svcutil.ExitRestart)
return
}
now = time.Now()
}
}
func autoUpgradePossible(options serveOptions) bool {
if upgrade.DisabledByCompilation {
return false
@@ -989,16 +902,6 @@ func cleanConfigDirectory() {
}
}
func showPaths(options serveOptions) {
fmt.Printf("Configuration file:\n\t%s\n\n", locations.Get(locations.ConfigFile))
fmt.Printf("Database directory:\n\t%s\n\n", locations.Get(locations.Database))
fmt.Printf("Device private key & certificate files:\n\t%s\n\t%s\n\n", locations.Get(locations.KeyFile), locations.Get(locations.CertFile))
fmt.Printf("HTTPS private key & certificate files:\n\t%s\n\t%s\n\n", locations.Get(locations.HTTPSKeyFile), locations.Get(locations.HTTPSCertFile))
fmt.Printf("Log file:\n\t%s\n\n", options.LogFile)
fmt.Printf("GUI override directory:\n\t%s\n\n", options.DebugGUIAssetsDir)
fmt.Printf("Default sync folder directory:\n\t%s\n\n", locations.Get(locations.DefFolder))
}
func setPauseState(cfgWrapper config.Wrapper, paused bool) {
_, err := cfgWrapper.Modify(func(cfg *config.Configuration) {
for i := range cfg.Devices {

View File

@@ -15,16 +15,14 @@ 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"
)
@@ -50,7 +48,7 @@ func monitorMain(options serveOptions) {
var dst io.Writer = os.Stdout
logFile := options.LogFile
logFile := locations.Get(locations.LogFile)
if logFile != "-" {
if expanded, err := fs.ExpandTilde(logFile); err == nil {
logFile = expanded
@@ -68,7 +66,7 @@ func monitorMain(options serveOptions) {
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,
@@ -85,6 +83,11 @@ func monitorMain(options serveOptions) {
}
args := os.Args
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)
@@ -106,7 +109,7 @@ func monitorMain(options serveOptions) {
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()
@@ -182,7 +185,7 @@ func monitorMain(options serveOptions) {
// 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)
@@ -205,6 +208,19 @@ func monitorMain(options serveOptions) {
}
}
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)
@@ -257,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 *
@@ -311,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
@@ -515,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
}
@@ -564,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, true)
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

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

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

@@ -4,10 +4,11 @@
// 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 aggregate
import (
"database/sql"
"fmt"
"log"
"os"
"time"
@@ -15,26 +16,21 @@ import (
_ "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
type CLI struct {
DBConn string `env:"UR_DB_URL" default:"postgres://user:password@localhost/ur?sslmode=disable"`
}
func main() {
func (cli *CLI) Run() error {
log.SetFlags(log.Ltime | log.Ldate)
log.SetOutput(os.Stdout)
db, err := sql.Open("postgres", dbConn)
db, err := sql.Open("postgres", cli.DBConn)
if err != nil {
log.Fatalln("database:", err)
return fmt.Errorf("database: %w", err)
}
err = setupDB(db)
if err != nil {
log.Fatalln("database:", err)
return fmt.Errorf("database: %w", err)
}
for {
@@ -47,32 +43,25 @@ func main() {
func runAggregation(db *sql.DB) {
since := maxIndexedDay(db, "VersionSummary")
log.Println("Aggregating VersionSummary data since", since)
rows, err := aggregateVersionSummary(db, since)
rows, err := aggregateVersionSummary(db, since.Add(24*time.Hour))
if err != nil {
log.Fatalln("aggregate:", err)
log.Println("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)
log.Println("Aggregating Performance data since", since)
rows, err = aggregatePerformance(db, since.Add(24*time.Hour))
if err != nil {
log.Fatalln("aggregate:", err)
log.Println("aggregate:", err)
}
log.Println("Inserted", rows, "rows")
log.Println("Aggregating BlockStats data")
since = maxIndexedDay(db, "BlockStats")
rows, err = aggregateBlockStats(db, since)
log.Println("Aggregating BlockStats data since", since)
rows, err = aggregateBlockStats(db, since.Add(24*time.Hour))
if err != nil {
log.Fatalln("aggregate:", err)
log.Println("aggregate:", err)
}
log.Println("Inserted", rows, "rows")
}
@@ -94,16 +83,6 @@ func setupDB(db *sql.DB) error {
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,
@@ -119,13 +98,13 @@ func setupDB(db *sql.DB) error {
_, 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
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
@@ -143,11 +122,6 @@ func setupDB(db *sql.DB) error {
_, _ = db.Exec(`CREATE INDEX VersionDayIndex ON VersionSummary (Day)`)
}
row = db.QueryRow(`SELECT 'MovementDayIndex'::regclass`)
if err := row.Scan(&t); err != nil {
_, _ = db.Exec(`CREATE INDEX MovementDayIndex ON UserMovement (Day)`)
}
row = db.QueryRow(`SELECT 'PerformanceDayIndex'::regclass`)
if err := row.Scan(&t); err != nil {
_, _ = db.Exec(`CREATE INDEX PerformanceDayIndex ON Performance (Day)`)
@@ -163,7 +137,7 @@ func setupDB(db *sql.DB) error {
func maxIndexedDay(db *sql.DB, table string) time.Time {
var t time.Time
row := db.QueryRow("SELECT MAX(Day) FROM " + table)
row := db.QueryRow("SELECT MAX(DATE_TRUNC('day', Day)) FROM " + table)
err := row.Scan(&t)
if err != nil {
return time.Time{}
@@ -179,8 +153,8 @@ func aggregateVersionSummary(db *sql.DB, since time.Time) (int64, error) {
COUNT(*) AS Count
FROM ReportsJson
WHERE
DATE_TRUNC('day', Received) > $1
AND DATE_TRUNC('day', Received) < DATE_TRUNC('day', NOW())
Received > $1
AND Received < DATE_TRUNC('day', NOW())
AND Report->>'version' like 'v_.%'
GROUP BY Day, Ver
);
@@ -192,86 +166,6 @@ func aggregateVersionSummary(db *sql.DB, since time.Time) (int64, error) {
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
@@ -283,9 +177,11 @@ func aggregatePerformance(db *sql.DB, since time.Time) (int64, error) {
AVG((Report->>'memoryUsageMiB')::numeric) As MemoryUsageMiB
FROM ReportsJson
WHERE
DATE_TRUNC('day', Received) > $1
AND DATE_TRUNC('day', Received) < DATE_TRUNC('day', NOW())
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)
@@ -303,17 +199,17 @@ func aggregateBlockStats(db *sql.DB, since time.Time) (int64, error) {
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
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
DATE_TRUNC('day', Received) > $1
AND DATE_TRUNC('day', Received) < DATE_TRUNC('day', NOW())
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%'

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
}

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 "testing"

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 (
"bytes"

1121
cmd/ursrv/serve/serve.go Normal file
View File

File diff suppressed because it is too large Load Diff

View File

Before

Width:  |  Height:  |  Size: 4.8 KiB

After

Width:  |  Height:  |  Size: 4.8 KiB

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