Compare commits

..

41 Commits

Author SHA1 Message Date
Jakob Borg
1b6e4645b1 Update docs & translations 2015-12-06 13:09:22 +01:00
Jakob Borg
a6a573f5dc Fix STTRACE=http (it should use the http debug logger) 2015-12-05 15:59:35 +01:00
Jakob Borg
415415b5b2 Response with Bad Request to bad config posts, not Internal Server Errors
The error is the clients fault, or so we think, so we should not accept
the blame.
2015-12-05 15:56:10 +01:00
Audrius Butkevicius
38e9b92c42 Merge pull request #2550 from canton7/feature/deadline
staticClient.connect(): don't handshake twice (fixes #2547, #2548)
2015-12-04 12:05:28 +00:00
Antony Male
345d727936 staticClient.connect(): don't handshake twice (fixes #2547, #2548)
The first handshake occurred before setting the Deadline, which could
cause an unintended hang.
2015-12-04 12:01:01 +00:00
Nate Morrison
86e8e5199e Filenames added to audit log in the LocalIndexUpdated event (fixes #2549) 2015-12-04 08:42:00 +01:00
Jakob Borg
739979a116 Add nrm21 2015-12-04 08:38:45 +01:00
Jakob Borg
7cbc81adca Merge pull request #2545 from rumpelsepp/master
Add syncthing-relay(7)
2015-12-01 15:54:10 +01:00
Stefan Tatschner
737d0fa23c Add syncthing-relay(7) 2015-12-01 15:34:58 +01:00
Jakob Borg
ab1962934d Docs & translations update 2015-12-01 11:24:30 +01:00
Jakob Borg
192455702d Repair AUTHORS 2015-12-01 11:23:35 +01:00
Jakob Borg
cb0d739daf New key for discovery-*-3 2015-12-01 11:20:16 +01:00
Jakob Borg
a937fcc477 Lol shadowing :( 2015-12-01 11:20:16 +01:00
Audrius Butkevicius
9503e60444 Merge pull request #2544 from calmh/negcache2
Accept Retry-After header on discovery lookup failures
2015-12-01 10:14:32 +00:00
Jakob Borg
9f2dc4554d Accept Retry-After header on discovery lookup failures 2015-12-01 11:10:03 +01:00
Jakob Borg
3008dc76d3 Add buinsky 2015-11-30 18:30:36 +01:00
Audrius Butkevicius
596c4b77e8 Merge pull request #2539 from buinsky/master
Fix deleting folders on WinXP (fixes #2522)
2015-11-30 16:21:46 +00:00
buinsky
05a31c2686 Fix deleting folders on WinXP (fixes #2522) 2015-11-30 19:09:36 +03:00
Audrius Butkevicius
45535c0f5a Merge pull request #2538 from canton7/feature/issue-2537
Allow #urPreview to scroll in the browser (fixes #2537)
2015-11-30 13:36:28 +00:00
Antony Male
4bd0dd2123 Allow #urPreview to scroll in the browser (fixes #2537)
This is the same issue as #2014/#2062. Bootstrap doesn't like having two dialogs
open at once: it marks the body has having no dialogs open when the first dialog
is closed, regardless of whether the second dialog is still open.

This means that scrolling doesn't happen properly, and the user cannot
scroll to the dialog's 'close' button.

Work around this by making sure the first dialog (the settings page) is fully closed
before the second dialog (usage preview) is opened.
2015-11-30 13:27:07 +00:00
Jakob Borg
9b2a643626 Update docs and translations 2015-11-29 08:55:38 +01:00
Jakob Borg
1ebc9a9a88 Merge pull request #2525 from kluppy/master
Don't chmod in Atomic on android (fixes  #2472)
2015-11-28 22:57:00 +01:00
Jakob Borg
f0c8b7ce40 Add kluppy 2015-11-28 22:17:05 +01:00
Jakob Borg
ec54550f21 Merge pull request #2529 from AudriusButkevicius/fixlinks
Fix symlinks (fixes #2524)
2015-11-28 21:29:33 +01:00
Audrius Butkevicius
4474d200b0 Fix symlinks (fixes #2524) 2015-11-28 20:23:08 +00:00
kluppy
f062e35641 Don't chmod in Atomic on android (fixes #2472) 2015-11-28 02:46:06 +10:00
Jakob Borg
321ef9816c Merge pull request #2521 from AudriusButkevicius/dialtimeout
Add dialer.DialTimeout, use that when connecting to relays
2015-11-27 10:01:21 +01:00
Audrius Butkevicius
be01e925c7 Merge pull request #2523 from calmh/ecdsa
Generate ECDSA keys instead of RSA
2015-11-27 08:28:51 +00:00
Jakob Borg
6d11006b54 Generate ECDSA keys instead of RSA
This replaces the current 3072 bit RSA certificates with 384 bit ECDSA
certificates. The advantage is these certificates are smaller and
essentially instantaneous to generate. According to RFC4492 (ECC Cipher
Suites for TLS), Table 1: Comparable Key Sizes, ECC has comparable
strength to 3072 bit RSA at 283 bits - so we exceed that.

There is no compatibility issue with existing Syncthing code - this is
verified by the integration test ("h2" instance has the new
certificate).

There are browsers out there that don't understand ECC certificates yet,
although I think they're dying out. In the meantime, I've retained the
RSA code for the HTTPS certificate, but pulled it down to 2048 bits. I
don't think a higher security level there is motivated, is this matches
current industry standard for HTTPS certificates.
2015-11-27 09:15:12 +01:00
Audrius Butkevicius
ed792b97c0 Take timeout into account when dialing 2015-11-26 23:41:11 +00:00
Audrius Butkevicius
a4b8c2298a Add dialer.DialTimeout support 2015-11-26 23:31:37 +00:00
Jakob Borg
e5b33ce9f6 Regenerate XDR for empty struct types 2015-11-24 20:54:49 +01:00
Jakob Borg
30374d46c9 Merge pull request #2510 from plouj/master
Log problems fetching releases
2015-11-24 20:39:29 +01:00
Michael Ploujnikov
9edf8233f7 Improve upgrade error messages 2015-11-24 08:29:42 -05:00
Michael Ploujnikov
bd4a14519c FetchLatestReleases: just log the error here
Since the return value is being ignored by the caller.
2015-11-24 08:29:42 -05:00
Michael Ploujnikov
f12bf8c09a Rename LatestGithubReleases -> FetchLatestReleases 2015-11-24 08:29:42 -05:00
Audrius Butkevicius
53cc45a0d5 Merge pull request #2512 from calmh/compact
Compact database on startup (ref #2400)
2015-11-24 12:43:38 +00:00
Jakob Borg
fa4b4dece1 Compact database on startup (ref #2400) 2015-11-24 13:17:30 +01:00
Jakob Borg
02f044a2a1 Add plouj 2015-11-24 08:35:25 +01:00
Audrius Butkevicius
431d51f5c4 Add timeouts to relay methods 2015-11-23 21:14:46 +00:00
Jakob Borg
45c1357bab Update osext dependency (fixes #1272) 2015-11-23 13:09:42 +01:00
68 changed files with 962 additions and 553 deletions

View File

@@ -52,13 +52,16 @@ Marcin Dziadus <dziadus.marcin@gmail.com>
Mateusz Naściszewski <matin1111@wp.pl>
Matt Burke <mburke@amplify.com> <burkemw3@gmail.com>
Michael Jephcote <rewt0r@gmx.com> <Rewt0r@users.noreply.github.com>
Michael Ploujnikov <ploujj@gmail.com>
Michael Tilli <pyfisch@gmail.com>
Nate Morrison <natemorrison@gmail.com>
Pascal Jungblut <github@pascalj.com> <mail@pascal-jungblut.com>
Peter Hoeg <peter@speartail.com>
Philippe Schommers <philippe@schommers.be>
Phill Luby <phill.luby@newredo.com>
Piotr Bejda <piotrb10@gmail.com>
Ryan Sullivan <kayoticsully@gmail.com>
Scott Klupfel <kluppy@going2blue.com>
Sergey Mishin <ralder@yandex.ru>
Stefan Tatschner <stefan@sevenbyte.org> <rumpelsepp@sevenbyte.org>
Stefan Kuntz <stefan.github@gmail.com> <Stefan.github@gmail.com>
@@ -69,4 +72,5 @@ Tully Robinson <tully@tojr.org>
Tyler Brazier <tyler@tylerbrazier.com>
Veeti Paananen <veeti.paananen@rojekti.fi>
Vil Brekin <vilbrekin@gmail.com>
Victor Buinsky <vix_booja@tut.by>
Yannic A. <eipiminusone+github@gmail.com> <eipiminus1@users.noreply.github.com>

4
Godeps/Godeps.json generated
View File

@@ -19,7 +19,7 @@
},
{
"ImportPath": "github.com/calmh/xdr",
"Rev": "47c0042d09a827b81ee62497f99e5e0c7f0bd31c"
"Rev": "9eb3e1a622d9364deb39c831f7e5f164393d7e37"
},
{
"ImportPath": "github.com/golang/snappy",
@@ -31,7 +31,7 @@
},
{
"ImportPath": "github.com/kardianos/osext",
"Rev": "6e7f843663477789fac7c02def0d0909e969b4e5"
"Rev": "345163ffe35aa66560a4cd7dddf00f3ae21c9fda"
},
{
"ImportPath": "github.com/rcrowley/go-metrics",

View File

@@ -171,6 +171,39 @@ func (o *{{.TypeName}}) DecodeXDRFrom(xr *xdr.Reader) error {
return xr.Error()
}`))
var emptyTypeTpl = template.Must(template.New("encoder").Parse(`
func (o {{.TypeName}}) EncodeXDR(w io.Writer) (int, error) {
return 0, nil
}//+n
func (o {{.TypeName}}) MarshalXDR() ([]byte, error) {
return nil, nil
}//+n
func (o {{.TypeName}}) MustMarshalXDR() []byte {
return nil
}//+n
func (o {{.TypeName}}) AppendXDR(bs []byte) ([]byte, error) {
return bs, nil
}//+n
func (o {{.TypeName}}) EncodeXDRInto(xw *xdr.Writer) (int, error) {
return xw.Tot(), xw.Error()
}//+n
func (o *{{.TypeName}}) DecodeXDR(r io.Reader) error {
return nil
}//+n
func (o *{{.TypeName}}) UnmarshalXDR(bs []byte) error {
return nil
}//+n
func (o *{{.TypeName}}) DecodeXDRFrom(xr *xdr.Reader) error {
return xr.Error()
}`))
var maxRe = regexp.MustCompile(`(?:\Wmax:)(\d+)(?:\s*,\s*(\d+))?`)
type typeSet struct {
@@ -300,7 +333,14 @@ func generateCode(output io.Writer, s structInfo) {
fs := s.Fields
var buf bytes.Buffer
err := encodeTpl.Execute(&buf, map[string]interface{}{"TypeName": name, "Fields": fs})
var err error
if len(fs) == 0 {
// This is an empty type. We can create a quite simple codec for it.
err = emptyTypeTpl.Execute(&buf, map[string]interface{}{"TypeName": name})
} else {
// Generate with the default template.
err = encodeTpl.Execute(&buf, map[string]interface{}{"TypeName": name, "Fields": fs})
}
if err != nil {
panic(err)
}
@@ -326,6 +366,14 @@ func generateDiagram(output io.Writer, s structInfo) {
fs := s.Fields
fmt.Fprintln(output, sn+" Structure:")
if len(fs) == 0 {
fmt.Fprintln(output, "(contains no fields)")
fmt.Fprintln(output)
fmt.Fprintln(output)
return
}
fmt.Fprintln(output)
fmt.Fprintln(output, " 0 1 2 3")
fmt.Fprintln(output, " 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1")

View File

@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build linux netbsd openbsd solaris dragonfly
// +build linux netbsd solaris dragonfly
package osext
@@ -27,7 +27,7 @@ func executable() (string, error) {
return execpath, nil
case "netbsd":
return os.Readlink("/proc/curproc/exe")
case "openbsd", "dragonfly":
case "dragonfly":
return os.Readlink("/proc/curproc/file")
case "solaris":
return os.Readlink(fmt.Sprintf("/proc/%d/path/a.out", os.Getpid()))

View File

@@ -2,12 +2,13 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build darwin freebsd
// +build darwin freebsd openbsd
package osext
import (
"os"
"os/exec"
"path/filepath"
"runtime"
"syscall"
@@ -23,6 +24,8 @@ func executable() (string, error) {
mib = [4]int32{1 /* CTL_KERN */, 14 /* KERN_PROC */, 12 /* KERN_PROC_PATHNAME */, -1}
case "darwin":
mib = [4]int32{1 /* CTL_KERN */, 38 /* KERN_PROCARGS */, int32(os.Getpid()), -1}
case "openbsd":
mib = [4]int32{1 /* CTL_KERN */, 55 /* KERN_PROC_ARGS */, int32(os.Getpid()), 1 /* KERN_PROC_ARGV */}
}
n := uintptr(0)
@@ -42,14 +45,58 @@ func executable() (string, error) {
if n == 0 { // This shouldn't happen.
return "", nil
}
for i, v := range buf {
if v == 0 {
buf = buf[:i]
break
var execPath string
switch runtime.GOOS {
case "openbsd":
// buf now contains **argv, with pointers to each of the C-style
// NULL terminated arguments.
var args []string
argv := uintptr(unsafe.Pointer(&buf[0]))
Loop:
for {
argp := *(**[1<<20]byte)(unsafe.Pointer(argv))
if argp == nil {
break
}
for i := 0; uintptr(i) < n; i++ {
// we don't want the full arguments list
if string(argp[i]) == " " {
break Loop
}
if argp[i] != 0 {
continue
}
args = append(args, string(argp[:i]))
n -= uintptr(i)
break
}
if n < unsafe.Sizeof(argv) {
break
}
argv += unsafe.Sizeof(argv)
n -= unsafe.Sizeof(argv)
}
execPath = args[0]
// There is no canonical way to get an executable path on
// OpenBSD, so check PATH in case we are called directly
if execPath[0] != '/' && execPath[0] != '.' {
execIsInPath, err := exec.LookPath(execPath)
if err == nil {
execPath = execIsInPath
}
}
default:
for i, v := range buf {
if v == 0 {
buf = buf[:i]
break
}
}
execPath = string(buf)
}
var err error
execPath := string(buf)
// execPath will not be empty due to above checks.
// Try to get the absolute path if the execPath is not rooted.
if execPath[0] != '/' {

4
NICKS
View File

@@ -20,6 +20,7 @@ brbecker <brbecker@gmail.com>
brendanlong <self@brendanlong.com>
brgmnn <dan.arne.bergmann@gmail.com> <brgmnn@users.noreply.github.com>
bsidhom <bsidhom@gmail.com>
buinsky <vix_booja@tut.by>
burkemw3 <mburke@amplify.com> <burkemw3@gmail.com>
calmh <jakob@nym.se>
canton7 <antony.male@gmail.com>
@@ -41,6 +42,7 @@ jedie <github.com@jensdiemer.de> <git@jensdiemer.de>
jpjp <jamespatterson@operamail.com> <jpjp@users.noreply.github.com>
kamadak <kamada@nanohz.org>
kilburn <kilburn@la3.org>
kluppy <kluppy@going2blue.com>
kozec <kozec@kozec.com>
krozycki <rozycki.karol@gmail.com>
marcindziadus <dziadus.marcin@gmail.com>
@@ -49,10 +51,12 @@ mateon1 <matin1111@wp.pl>
mogwa1 <devriesb@gmail.com>
moshen <moshen.colin@gmail.com>
mvdan <mvdan@mvdan.cc>
nrm21 <natemorrison@gmail.com>
pascalj <github@pascalj.com> <mail@pascal-jungblut.com>
peterhoeg <peter@speartail.com>
philips <brandon@ifup.org>
piobpl <piotrb10@gmail.com>
plouj <ploujj@gmail.com>
pluby <phill.luby@newredo.com>
pyfisch <pyfisch@gmail.com>
qbit <qbit@deftly.net>

View File

@@ -405,7 +405,7 @@ func assets() {
}
func xdr() {
runPrint("go", "generate", "./lib/discover", "./lib/db", "./lib/protocol")
runPrint("go", "generate", "./lib/discover", "./lib/db", "./lib/protocol", "./lib/relay/protocol")
}
func translate() {

View File

@@ -98,7 +98,7 @@ func (s *apiSvc) getListener(guiCfg config.GUIConfiguration) (net.Listener, erro
name = tlsDefaultCommonName
}
cert, err = tlsutil.NewCertificate(locations[locHTTPSCertFile], locations[locHTTPSKeyFile], name, tlsRSABits)
cert, err = tlsutil.NewCertificate(locations[locHTTPSCertFile], locations[locHTTPSKeyFile], name, httpsRSABits)
}
if err != nil {
return nil, err
@@ -317,7 +317,7 @@ func debugMiddleware(h http.Handler) http.Handler {
written = rf.Int()
}
}
l.Debugf("http: %s %q: status %d, %d bytes in %.02f ms", r.Method, r.URL.String(), status, written, ms)
httpl.Debugf("http: %s %q: status %d, %d bytes in %.02f ms", r.Method, r.URL.String(), status, written, ms)
}
})
}
@@ -578,7 +578,7 @@ func (s *apiSvc) postSystemConfig(w http.ResponseWriter, r *http.Request) {
to, err := config.ReadJSON(r.Body, myID)
if err != nil {
l.Warnln("decoding posted config:", err)
http.Error(w, err.Error(), 500)
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
@@ -587,7 +587,7 @@ func (s *apiSvc) postSystemConfig(w http.ResponseWriter, r *http.Request) {
hash, err := bcrypt.GenerateFromPassword([]byte(to.GUI.Password), 0)
if err != nil {
l.Warnln("bcrypting password:", err)
http.Error(w, err.Error(), 500)
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}

View File

@@ -70,7 +70,8 @@ const (
const (
bepProtocolName = "bep/1.0"
tlsDefaultCommonName = "syncthing"
tlsRSABits = 3072
httpsRSABits = 2048
bepRSABits = 0 // 384 bit ECDSA used instead
pingEventInterval = time.Minute
maxSystemErrors = 5
initialSystemLog = 10
@@ -378,7 +379,7 @@ func generate(generateDir string) {
l.Warnln("Key exists; will not overwrite.")
l.Infoln("Device ID:", protocol.NewDeviceID(cert.Certificate[0]))
} else {
cert, err = tlsutil.NewCertificate(certFile, keyFile, tlsDefaultCommonName, tlsRSABits)
cert, err = tlsutil.NewCertificate(certFile, keyFile, tlsDefaultCommonName, bepRSABits)
if err != nil {
l.Fatalln("Create certificate:", err)
}
@@ -501,8 +502,8 @@ func syncthingMain() {
// Ensure that that we have a certificate and key.
cert, err := tls.LoadX509KeyPair(locations[locCertFile], locations[locKeyFile])
if err != nil {
l.Infof("Generating RSA key and certificate for %s...", tlsDefaultCommonName)
cert, err = tlsutil.NewCertificate(locations[locCertFile], locations[locKeyFile], tlsDefaultCommonName, tlsRSABits)
l.Infof("Generating ECDSA key and certificate for %s...", tlsDefaultCommonName)
cert, err = tlsutil.NewCertificate(locations[locCertFile], locations[locKeyFile], tlsDefaultCommonName, bepRSABits)
if err != nil {
l.Fatalln(err)
}
@@ -639,6 +640,13 @@ func syncthingMain() {
}
}
// Pack and optimize the database
if err := ldb.Compact(); err != nil {
// I don't think this is fatal, but who knows. If it is, we'll surely
// get an error when trying to write to the db later.
l.Infoln("Compacting database:", err)
}
m := model.NewModel(cfg, myID, myName, "syncthing", Version, ldb, protectedFiles)
cfg.Subscribe(m)

View File

@@ -0,0 +1,225 @@
{
"A negative number of days doesn't make sense.": "Et negativt antal dage giver ikke mening.",
"A new major version may not be compatible with previous versions.": "En ny versionsudgivelse er måske ikke kompatibel med tidligere versioner.",
"API Key": "API-nøgle",
"About": "Om",
"Actions": "Handlinger.",
"Add": "Tilføj",
"Add Device": "Tilføj enhed",
"Add Folder": "Tilføj mappe",
"Add new folder?": "Tilføj ny mappe",
"Address": "Adresse",
"Addresses": "Adresser",
"Advanced": "Avanceret",
"Advanced Configuration": "Avanceret konfiguration",
"All Data": "Alt data",
"Allow Anonymous Usage Reporting?": "Tillad anonym brugerstatistik?",
"Alphabetic": "Alfabetisk",
"An external command handles the versioning. It has to remove the file from the synced folder.": " ",
"Anonymous Usage Reporting": "Anonym brugerstatistik",
"Any devices configured on an introducer device will be added to this device as well.": "Alle enheder som er konfigueret som en introducerende enhed, vil også blive tilføjet til denne enhed.",
"Automatic upgrades": "Automatisk opdatering",
"Be careful!": "Vær forsigtig!",
"Bugs": "Fejl",
"CPU Utilization": "CPU-forbrug",
"Changelog": "Udgivelsesnoter",
"Clean out after": "Rens efter",
"Close": "Luk",
"Command": "Kommando",
"Comment, when used at the start of a line": "Kommentering som bruges i starten af en linje",
"Compression": "Anvend komprimering",
"Connection Error": "Tilslutnings fejl",
"Copied from elsewhere": "Kopieret fra et andet sted",
"Copied from original": "Kopieret fra originalen",
"Copyright © 2015 the following Contributors:": "Copyright © 2015 alle bidragsydere:",
"Danger!": "Fare!",
"Delete": "Slet",
"Deleted": "Slettet",
"Device ID": "Enheds-ID",
"Device Identification": "Enhedsidentifikation",
"Device Name": "Enhedsnavn",
"Device {%device%} ({%address%}) wants to connect. Add new device?": "Enheden {{device}} ({{address}}) ønsker at forbinde. Tilføj denne enhed?",
"Devices": "Enheder",
"Disconnected": "Ikke tilsluttet",
"Discovery": "Opslag",
"Documentation": "Dokumentation",
"Download Rate": "Downloadhastighed",
"Downloaded": "Downloadet",
"Downloading": "Downloader",
"Edit": "Rediger",
"Edit Device": "Rediger enhed",
"Edit Folder": "Rediger mappe",
"Editing": "Redigerer",
"Enable UPnP": "Anvend UPnP",
"Enter comma separated (\"tcp://ip:port\", \"tcp://host:port\") addresses or \"dynamic\" to perform automatic discovery of the address.": "Angiv kommaseparerede adresser (\"tcp://ip:port\", \"tcp://host:port\") eller \"dynamic\" for at benytte automatisk opdagelse af adressen.",
"Enter ignore patterns, one per line.": "Vælg ignorer maske, én per linje.",
"Error": "Fejl",
"External File Versioning": "Ekstern fil-versionskontrol",
"Failed Items": "Mislykkede filer",
"File Pull Order": "Filhentnings rækkefølge",
"File Versioning": "Filversionering",
"File permission bits are ignored when looking for changes. Use on FAT file systems.": "Filtilladelses bits ignoreres når der søges efter ændringer. Bruges på FAT filsystemer. ",
"Files are moved to .stversions folder when replaced or deleted by Syncthing.": "Filer flyttes til .stversions mappen når de erstattes eller slettes af Syncthing.",
"Files are moved to date stamped versions in a .stversions folder when replaced or deleted by Syncthing.": "Filer flyttes til data-stemplede versioner i en .stversions mappe når de erstattes eller slettes af Syncthing.",
"Files are protected from changes made on other devices, but changes made on this device will be sent to the rest of the cluster.": "Filer er beskyttet fra ændringer foretaget på andre enheder, men ændringerne på denne enhed vil blive sendt til alle andre tilknyttede enheder.",
"Folder": "Mappe",
"Folder ID": "Mappe-ID",
"Folder Master": "Mastermappe",
"Folder Path": "Mappesti",
"Folders": "Mapper",
"GUI": "GUI",
"GUI Authentication Password": "GUI-kodeord",
"GUI Authentication User": "GUI-brugernavn",
"GUI Listen Addresses": "GUI-lytteadresse",
"Generate": "Opret",
"Global Discovery": "Globalt opslag",
"Global Discovery Server": "Global opslagsserver",
"Global State": "Global tilstand",
"Help": "Hjælp",
"Home page": "Hjem",
"Ignore": "Ignorer",
"Ignore Patterns": "Ignoreringsmaske",
"Ignore Permissions": "Ignorér filrettigheder",
"Incoming Rate Limit (KiB/s)": "Indgående hastighedsbegrænsning (KiB/s)",
"Incorrect configuration may damage your folder contents and render Syncthing inoperable.": "Ukorrekt opsætning kan skade dine data og gøre Syncthing ude af stand til at fungere.",
"Introducer": "Introducerende enhed",
"Inversion of the given condition (i.e. do not exclude)": "Det omvendte (dvs. undlad ikke)",
"Keep Versions": "Behold versioner",
"Largest First": "Største først",
"Last File Received": "Sidste modtaget fil",
"Last seen": "Sidst set",
"Later": "Senere",
"Local Discovery": "Lokal opslag",
"Local State": "Lokal tilstand",
"Local State (Total)": "Lokal tilstand (total)",
"Major Upgrade": "Ny version",
"Maximum Age": "Maks alder",
"Metadata Only": "Kun metadata",
"Minimum Free Disk Space": "Mindst ledig diskplads",
"Move to top of queue": "Flyt til toppen af køen",
"Multi level wildcard (matches multiple directory levels)": "Flerniveau wildcard (matcher flere biblioteksniveauer)",
"Never": "Aldrig",
"New Device": "Ny enhed",
"New Folder": "Ny mappe",
"Newest First": "Nyeste først",
"No": "Nej",
"No File Versioning": "Ingen filversion",
"Notice": "OBS",
"OK": "OK",
"Off": "Slå fra",
"Oldest First": "Ældste først",
"Options": "Indstillinger",
"Out of Sync": "Ikke synkroniseret",
"Out of Sync Items": "Endnu ikke synkroniserede filer",
"Outgoing Rate Limit (KiB/s)": "Udgående hastighedsbegrænsning (KiB/s)",
"Override Changes": "Overskriv ændringer",
"Path to the folder on the local computer. Will be created if it does not exist. The tilde character (~) can be used as a shortcut for": "Sti til den lokale mappe. Vil blive oprettet hvis den ikke findes. Tilde tegnet (~) kan bruges som en forkortelse for",
"Path where versions should be stored (leave empty for the default .stversions folder in the folder).": "Sti hvor versioner skal gemmes (efterlad tom for default .stversions mappe)",
"Pause": "Pause",
"Paused": "Pauset",
"Please consult the release notes before performing a major upgrade.": "Tjek venligst udgivelsesnoterne før opgradering til en ny version.",
"Please set a GUI Authentication User and Password in the Settings dialog.": "Sæt vensligt en GUI bruger og kodeord i opsætningsdialogen.",
"Please wait": "Vent venligst",
"Preview": "Forhåndsvisning",
"Preview Usage Report": "Forhåndsvisning af forbrugsrapport",
"Quick guide to supported patterns": "Hurtig guide til supporteret mønstre",
"RAM Utilization": "RAM-forbrug",
"Random": "Tilfældig",
"Relayed via": "Passeret gennem",
"Relays": "Passager",
"Release Notes": "Udgivelsesnoter",
"Remove": "Fjern",
"Rescan": "Skan igen",
"Rescan All": "Skan alt igen",
"Rescan Interval": "Genskannings interval",
"Restart": "Genstart",
"Restart Needed": "Programmet kræver genstart",
"Restarting": "Genstarter",
"Resume": "Genoptag",
"Reused": "Genbrugt",
"Save": "Gem",
"Scan Time Remaining": "Tid tilbage af skanningen",
"Scanning": "Opdaterer",
"Select the devices to share this folder with.": "Vælg hvilke enheder du vil dele denne mappe med",
"Select the folders to share with this device.": "Vælg hvilke mapper du vil dele med denne enhed.",
"Settings": "Indstillinger",
"Share": "Del",
"Share Folder": "Delt mappe",
"Share Folders With Device": "Del mappe med enhed",
"Share With Devices": "Del med enhed",
"Share this folder?": "Del denne mappe",
"Shared With": "Delt med",
"Short identifier for the folder. Must be the same on all cluster devices.": "Kort navn for mappen. Skal være det samme på alle tilknyttede enheder.",
"Show ID": "Vis ID",
"Shown instead of Device ID in the cluster status. Will be advertised to other devices as an optional default name.": "Vist istedet for Enheds ID i klynge status. Vil blive vist på andre enheder som valgfrit standard navn.",
"Shown instead of Device ID in the cluster status. Will be updated to the name the device advertises if left empty.": "Vist istedet for Enheds ID i klynge status. Vil blive opdateret til det navn som enheden viser, hvis det ikke er udfyldt.",
"Shutdown": "Luk ned",
"Shutdown Complete": "Nedlukning fuldført",
"Simple File Versioning": "Simpel fil versioner",
"Single level wildcard (matches within a directory only)": "Enkeltnivau wildcard (matcher kun inden for en mapp)",
"Smallest First": "Mindste først",
"Source Code": "Kildekode",
"Staggered File Versioning": "Forskudte filversioner",
"Start Browser": "Start browser",
"Statistics": "Statistikker",
"Stopped": "Stoppet",
"Support": "Support",
"Sync Protocol Listen Addresses": "Lytteadresser for indgående forbindelser",
"Syncing": "Synkroniserer",
"Syncthing has been shut down.": "Syncthing er blevet lukket ned.",
"Syncthing includes the following software or portions thereof:": "Syncthing indeholder følgende software eller dele heraf:",
"Syncthing is restarting.": "Syncthing genstarter",
"Syncthing is upgrading.": "Syncthing opgraderer",
"Syncthing seems to be down, or there is a problem with your Internet connection. Retrying…": "Syncthing ser ud til at være stoppet eller oplever problemer med din internetforbindels. Prøver igen...",
"Syncthing seems to be experiencing a problem processing your request. Please refresh the page or restart Syncthing if the problem persists.": "Det ser ud til at Syncthiing har problemer med at udføre opgaven. Prøv at genopfriske siden eller genstarte Synching hvis problemet vedbliver.",
"The Syncthing admin interface is configured to allow remote access without a password.": "Syncthing administationsdelen er konfigureret til at blive fjernstyret uden kodeord.",
"The aggregated statistics are publicly available at {%url%}.": "Samlet statistik er offentligt tilgængelig på {{url}}.",
"The configuration has been saved but not activated. Syncthing must restart to activate the new configuration.": "Konfigurationen er gemt, men ikke aktiveret. Syncthing skal genstarte for at aktivere den nye konfiguration.",
"The device ID cannot be blank.": "Enhedens ID må ikke være tom.",
"The device ID to enter here can be found in the \"Edit > Show ID\" dialog on the other device. Spaces and dashes are optional (ignored).": "Enheds ID som som skal bruges her, kan du finde i \"Rediger > Vis ID\"-dialogen på den anden enhed. Mellemrum og bindestreg er valgfri (ignoreres).",
"The encrypted usage report is sent daily. It is used to track common platforms, folder sizes and app versions. If the reported data set is changed you will be prompted with this dialog again.": "Den krypterede forbrugsrapport sendes dagligt. Den benyttes til at spore anvendte platforme, mappestørrelser og versioner. Hvis det typen af opsamlet data ændres på et senere tidspunkt, vil du blive spurgt om tilladelse igen.",
"The entered device ID does not look valid. It should be a 52 or 56 character string consisting of letters and numbers, with spaces and dashes being optional.": "Det indtastede node ID ser ikke gyldigt ud. Det skal være en 52 eller 56 tegn streng, bestående af tal og bogstaver, eventuelt med mellemrum og bindestreger.",
"The first command line parameter is the folder path and the second parameter is the relative path in the folder.": "Den første kommandolinjeparameter er mappestien og den anden parameter er den relative sti til mappen.",
"The folder ID cannot be blank.": "Mappe-ID må ikke være tom",
"The folder ID must be a short identifier (64 characters or less) consisting of letters, numbers and the dot (.), dash (-) and underscode (_) characters only.": "Mappe-ID skal være en kort identificierende streng (64 karakterer eller mindre) bestående af bogstav-, tal-, punktum- (.), bindestreg- (-) og understregskarakteren (_).",
"The folder ID must be unique.": "Mappe-ID skal være unik",
"The folder path cannot be blank.": "Mappestien må ikke være tom",
"The following intervals are used: for the first hour a version is kept every 30 seconds, for the first day a version is kept every hour, for the first 30 days a version is kept every day, until the maximum age a version is kept every week.": "De følgende intervaller er brugt: i den første time, er en version gemt hvert 30. sekund, for første da er en version gemt hver time, for de første 30 dage er en version gemt hver dag og indtil den maksimale periode er en version hver uge gemt.",
"The following items could not be synchronized.": "Følgende filer kunne ikke synkroniseres.",
"The maximum age must be a number and cannot be blank.": "Maks alder skal være et nummer og må ikke være tom",
"The maximum time to keep a version (in days, set to 0 to keep versions forever).": "Maks tid gamle udgaver skal gemmes (i dage, sæt lig med 0 for at beholde gamle versioner for altid)",
"The minimum free disk space percentage must be a non-negative number between 0 and 100 (inclusive).": "Procentsatsen på den mindste ledige diskplads må ikke være negative og skal være mellem 0 og 100 (inklusiv).",
"The number of days must be a number and cannot be blank.": "Antallet af dage skal være et nummer og feltet må ikke være tomt",
"The number of days to keep files in the trash can. Zero means forever.": "Antal dage filer gemmes i skraldespanden. Nul betyder for evigt.",
"The number of old versions to keep, per file.": "Antallet af gamle versioner som gemmes, per fil.",
"The number of versions must be a number and cannot be blank.": "Antallet af versioner skal være et tal, og kan ikke være blankt.",
"The path cannot be blank.": "Stien må ikke være tom",
"The rate limit must be a non-negative number (0: no limit)": "Ratebegrænsningen må ikke være negative tal (0: ingen begrænsning)",
"The rescan interval must be a non-negative number of seconds.": "Genskanningsintervallet skal være et ikke-negativt antal sekunder",
"They are retried automatically and will be synced when the error is resolved.": "De prøves igen automatisk og vil blive synkroniseret når fejlen er løst.",
"This can easily give hackers access to read and change any files on your computer.": "Dette gør det nemt for hackere at få adgang til at læse og ændre filer på din computer.",
"This is a major version upgrade.": "Dette er en ny version",
"Trash Can File Versioning": "Skraldespand fil versioner",
"Unknown": "Ukendt",
"Unshared": "Ikke delt",
"Unused": "Ubrugt",
"Up to Date": "Fuldt opdateret",
"Updated": "Opdateret",
"Upgrade": "Upgradér",
"Upgrade To {%version%}": "Opgradér til {{version}}",
"Upgrading": "Opgradere",
"Upload Rate": "Uploadhastighed",
"Uptime": "Oppetid",
"Use HTTPS for GUI": "Anvend HTTPS til GUI adgang",
"Version": "Version",
"Versions Path": "Versions-sti",
"Versions are automatically deleted if they are older than the maximum age or exceed the number of files allowed in an interval.": "Versioner slettes automatisk, hvis de er ældre end den satte maksimum alder eller overstiger det tilladte antal filer i et interval.",
"When adding a new device, keep in mind that this device must be added on the other side too.": "Når der tilføjes en ny enhed, vær da opmærksom på, at denne enhed også skal tilføjes på den anden side.",
"When adding a new folder, keep in mind that the Folder ID is used to tie folders together between devices. They are case sensitive and must match exactly between all devices.": "Når der tilføjes en ny enhed, vær da opmærksom på at samme ID bruges til at forbinde mapperne på de forskellige enheder. Der er forskel på store og små bogstaver, og ID skal være fuldstændig identisk på alle enheder.",
"Yes": "Ja",
"You must keep at least one version.": "Du skal beholde mindst én version.",
"days": "dage",
"full documentation": "Fuld dokumentation",
"items": "poster",
"{%device%} wants to share folder \"{%folder%}\".": "{{device}} ønsker at dele mappen \"{{folder}}\". "
}

View File

@@ -138,7 +138,7 @@
"Resume": "Fortfahren",
"Reused": "Erneut benutzt",
"Save": "Speichern",
"Scan Time Remaining": "Scan Time Remaining",
"Scan Time Remaining": "Zeit für Scan verbleibend",
"Scanning": "Scannen",
"Select the devices to share this folder with.": "Wähle die Geräte aus, mit denen Du dieses Verzeichnis teilen willst.",
"Select the folders to share with this device.": "Wähle die Verzeichnisse aus, die du mit diesem Gerät teilen möchtest",
@@ -172,7 +172,7 @@
"Syncthing is upgrading.": "Syncthing wird aktualisiert",
"Syncthing seems to be down, or there is a problem with your Internet connection. Retrying…": "Syncthing scheint nicht erreichbar zu sein oder es gibt ein Problem mit Deiner Internetverbindung. Versuche erneut...",
"Syncthing seems to be experiencing a problem processing your request. Please refresh the page or restart Syncthing if the problem persists.": "Syncthing scheint ein Problem mit der Verarbeitung Deiner Eingabe zu haben. Bitte lade die Seite neu oder führe einen Neustart durch, falls das Problem weiterhin besteht.",
"The Syncthing admin interface is configured to allow remote access without a password.": "Das Syncthing Administrationsoberfläche erlaubt mit den jetzigen Einstellungen einen Fernzugriff ohne ein Passwort.",
"The Syncthing admin interface is configured to allow remote access without a password.": "Die Syncthing-Administrationsoberfläche erlaubt mit den jetzigen Einstellungen einen Fernzugriff ohne Passwort.",
"The aggregated statistics are publicly available at {%url%}.": "Die gesammelten Statistiken sind öffentlich verfügbar unter {{url}}.",
"The configuration has been saved but not activated. Syncthing must restart to activate the new configuration.": "Die Konfiguration wurde gespeichert, aber noch nicht aktiviert. Syncthing muss neugestartet werden, um die neue Konfiguration zu übernehmen.",
"The device ID cannot be blank.": "Die Geräte ID darf nicht leer sein.",

View File

@@ -32,7 +32,7 @@
"Copied from elsewhere": "Copié d'ailleurs",
"Copied from original": "Copié depuis l'original",
"Copyright © 2015 the following Contributors:": "Copyright © 2015 Les contributeurs suivants:",
"Danger!": "Danger!",
"Danger!": "Attention !",
"Delete": "Supprimer",
"Deleted": "Supprimé",
"Device ID": "ID du périphérique",
@@ -118,7 +118,7 @@
"Pause": "Pause",
"Paused": "En pause",
"Please consult the release notes before performing a major upgrade.": "Veuillez consulter les notes de version avant de réaliser une mise à jour majeure.",
"Please set a GUI Authentication User and Password in the Settings dialog.": "Please set a GUI Authentication User and Password in the Settings dialog.",
"Please set a GUI Authentication User and Password in the Settings dialog.": "SVP, mettez un nom d'utilisateur et un mot de passe dans la fenêtre de paramétrage.",
"Please wait": "Merci de patienter",
"Preview": "Aperçu",
"Preview Usage Report": "Aperçu du rapport de statistiques d'utilisation",
@@ -129,17 +129,17 @@
"Relays": "Relais",
"Release Notes": "Notes de version",
"Remove": "Enlever",
"Rescan": "Rescanner",
"Rescan": "Réanalyse",
"Rescan All": "Réanalyser tout",
"Rescan Interval": "Intervalle de scan",
"Rescan Interval": "Intervalle d'analyse",
"Restart": "Redémarrer",
"Restart Needed": "Redémarrage nécessaire",
"Restarting": "Redémarrage",
"Resume": "Résumer",
"Reused": "Réutilisé",
"Save": "Sauver",
"Scan Time Remaining": "Scan Time Remaining",
"Scanning": "En cours de scan",
"Scan Time Remaining": "Intervalle entre chaque analyse",
"Scanning": "En cours d'analyse",
"Select the devices to share this folder with.": "Sélectionner les appareils avec qui partager ce dossier.",
"Select the folders to share with this device.": "Sélectionner les dossiers à partager avec cet appareil.",
"Settings": "Configuration",
@@ -172,7 +172,7 @@
"Syncthing is upgrading.": "Syncthing est cours de mise à jour.",
"Syncthing seems to be down, or there is a problem with your Internet connection. Retrying…": "Syncthing semble être éteint, ou il y a un problème avec votre connexion Internet. Nouvelle tentative ...",
"Syncthing seems to be experiencing a problem processing your request. Please refresh the page or restart Syncthing if the problem persists.": "Syncthing semble avoir un problème pour traiter votre demande. S'il vous plait, rafraichissez la page ou redémarrer Syncthing si le problème persiste.",
"The Syncthing admin interface is configured to allow remote access without a password.": "The Syncthing admin interface is configured to allow remote access without a password.",
"The Syncthing admin interface is configured to allow remote access without a password.": "L'interface d'administration de Syncthing est paramétrée pour autoriser les accès à distance sans mot de passe.",
"The aggregated statistics are publicly available at {%url%}.": "Les statistiques agrégées sont disponibles publiquement à l'adresse {{url}}.",
"The configuration has been saved but not activated. Syncthing must restart to activate the new configuration.": "La configuration a été enregistrée mais pas activée. Syncthing doit redémarrer afin d'activer la nouvelle configuration.",
"The device ID cannot be blank.": "L'ID de l'appareil ne peut être vide.",
@@ -197,7 +197,7 @@
"The rate limit must be a non-negative number (0: no limit)": "La limite de débit ne doit pas être négative (0: Aucune limite)",
"The rescan interval must be a non-negative number of seconds.": "L'intervalle d'analyse ne doit pas être un nombre négatif de secondes.",
"They are retried automatically and will be synced when the error is resolved.": "Ils seront réessayés automatiquement et synchronisés quand l'erreur sera résolue.",
"This can easily give hackers access to read and change any files on your computer.": "This can easily give hackers access to read and change any files on your computer.",
"This can easily give hackers access to read and change any files on your computer.": "Cela permet facilement aux pirates de lire et modifier n'importe quel fichier de votre machine.",
"This is a major version upgrade.": "Ceci est une mise à jour majeure.",
"Trash Can File Versioning": "Gestion des versions de fichier style poubelle.",
"Unknown": "Inconnu",

View File

@@ -4,10 +4,10 @@
"API Key": "API-kaai",
"About": "Oer",
"Actions": "Aksjes",
"Add": "Tafoegje",
"Add Device": "Apparaat tafoegje",
"Add Folder": "Map tafoegje",
"Add new folder?": "Nije map tafoegje?",
"Add": "Taheakje",
"Add Device": "Apparaat taheakje",
"Add Folder": "Map taheakje",
"Add new folder?": "Nije map taheakje?",
"Address": "Adres",
"Addresses": "Adressen",
"Advanced": "Avansearre",
@@ -17,7 +17,7 @@
"Alphabetic": "Alfabetysk",
"An external command handles the versioning. It has to remove the file from the synced folder.": "In ekstern kommando soarget foar it ferzjebehear. It moat de triem út de syngronisearre map fuortsmite.",
"Anonymous Usage Reporting": "Anonym brûkensrapportaazje",
"Any devices configured on an introducer device will be added to this device as well.": "Alle apparaten die op in 'yntrodusearjend apparaat' ynstelt binne, wurde ek oan dit apparaat tafoeget.",
"Any devices configured on an introducer device will be added to this device as well.": "Alle apparaten die op in 'yntrodusearjend apparaat' ynstelt binne, wurde ek op dit apparaat taheakke.",
"Automatic upgrades": "Automatyske fernijings",
"Be careful!": "Tink derom!",
"Bugs": "Brekkings",
@@ -36,23 +36,23 @@
"Delete": "Fuortsmite",
"Deleted": "Fuortsmiten",
"Device ID": "Apparaat-ID",
"Device Identification": "Apparaat-identifikaasje",
"Device Name": "Apparaat-namme",
"Device {%device%} ({%address%}) wants to connect. Add new device?": "Apparaat {{device}} ({{address}}) wol ferbining meitsje. Nij apparaat tafoege?",
"Device Identification": "Apparaatidentifikaasje",
"Device Name": "Apparaatnamme",
"Device {%device%} ({%address%}) wants to connect. Add new device?": "Apparaat {{device}} ({{address}}) wol ferbining meitsje. Nij apparaat taheakje?",
"Devices": "Apparaten",
"Disconnected": "Ferbining ferbrutsen",
"Discovery": "Untdekking",
"Documentation": "Dokumintaasje",
"Download Rate": "Download-fluggens",
"Downloaded": "Downloaden",
"Downloading": "Oan it downloaden",
"Download Rate": "Ynlaadfluggens",
"Downloaded": "Ynladen",
"Downloading": "Oan it ynladen",
"Edit": "Bewurkje",
"Edit Device": "Apparaat bewurkje",
"Edit Folder": "Map bewurkje",
"Editing": "Bewurkjen",
"Enable UPnP": "UPnP oansette",
"Enter comma separated (\"tcp://ip:port\", \"tcp://host:port\") addresses or \"dynamic\" to perform automatic discovery of the address.": "Fier troch komma's skieden (\"tcp://ip:port\", \"tcp://host:port\") adressen yn of \"dynamysk\" om automatyske ûntdekking fan it adres út te fieren.",
"Enter ignore patterns, one per line.": "Fier negear-patroanen yn, ien per rigel.",
"Enter comma separated (\"tcp://ip:port\", \"tcp://host:port\") addresses or \"dynamic\" to perform automatic discovery of the address.": "Fier troch komma's skieden (\"tcp://ip:port\", \"tcp://host:port\") adressen yn of \"dynamic\" om automatyske ûntdekking fan it adres út te fieren.",
"Enter ignore patterns, one per line.": "Fier negearpatroanen yn, ien per rigel.",
"Error": "Flater",
"External File Versioning": "Ekstern ferzjebehear foar triemen",
"Failed Items": "Mislearre items",
@@ -68,9 +68,9 @@
"Folder Path": "Map-paad",
"Folders": "Mappen",
"GUI": "GUI",
"GUI Authentication Password": "GUI-wachtwurd foar ferifikaasje",
"GUI Authentication User": "GUI-brûkerferifikaasje",
"GUI Listen Addresses": "GUI-harkadres",
"GUI Authentication Password": "Wachtwurd foar ferifikaasje yn GUI",
"GUI Authentication User": "Brûkers-ID foar ferifikaasje yn GUI",
"GUI Listen Addresses": "Harkadres foar GUI",
"Generate": "Generearje",
"Global Discovery": "Wrâldwide ûntdekking",
"Global Discovery Server": "Wrâldwide ûntdekkingstsjinner",
@@ -84,9 +84,9 @@
"Incorrect configuration may damage your folder contents and render Syncthing inoperable.": "Ferkearde konfiguraasje kin de ynhâld fan jo mappen skeine en Syncthing unbrûkber meitsje.",
"Introducer": "Yntrodusearrer",
"Inversion of the given condition (i.e. do not exclude)": "Dizze betingst omkeare (d.w.z. net útslute) ",
"Keep Versions": "Ferzjes hâlde",
"Keep Versions": "Ferzjes bewarje",
"Largest First": "Grutste earst",
"Last File Received": "Leste triem ûntfangen",
"Last File Received": "Leste triem ûntfongen",
"Last seen": "Lêst sjoen",
"Later": "Letter",
"Local Discovery": "Lokale ûntdekking",
@@ -95,7 +95,7 @@
"Major Upgrade": "Wichtige fernijing",
"Maximum Age": "Maksimale âldens",
"Metadata Only": "Allinnich metadata",
"Minimum Free Disk Space": "Maksimale frije skiifromte",
"Minimum Free Disk Space": "Minimale frije skiifromte",
"Move to top of queue": "Fersette nei boppe oan de rige",
"Multi level wildcard (matches multiple directory levels)": "Multi-nivo jokerteken (wildcard) (fergelykt mei meardere map-nivo's)",
"Never": "Nea",
@@ -112,33 +112,33 @@
"Out of Sync": "Net syngronisearre",
"Out of Sync Items": "Net syngronisearre items",
"Outgoing Rate Limit (KiB/s)": "Uploadfluggenslimyt (KiB/s)",
"Override Changes": "Feroarings oerfleane",
"Path to the folder on the local computer. Will be created if it does not exist. The tilde character (~) can be used as a shortcut for": "Paad nei de map op de lokale kompjûter. Wurd oanmakke at dizze net bestiet. It tilde teken (~) kin brûkt wurde as fluchkeppeling foar",
"Path where versions should be stored (leave empty for the default .stversions folder in the folder).": "Paad wêr de ferzjes bewarre wurde moatte (lit leech foar de standert .stversions-map yn de map).",
"Pause": "Skoft",
"Override Changes": "Feroarings oerskriuwe",
"Path to the folder on the local computer. Will be created if it does not exist. The tilde character (~) can be used as a shortcut for": "Paad nei de map op de lokale kompjûter. Wurd oanmakke as dizze net bestiet. It tilde teken (~) kin brûkt wurde as fluchkeppeling foar",
"Path where versions should be stored (leave empty for the default .stversions folder in the folder).": "Paad dêr't de ferzjes bewarre wurde moatte (leech litte foar de standert .stversions-map yn de map).",
"Pause": "Skoftsje",
"Paused": "Skoftet",
"Please consult the release notes before performing a major upgrade.": "Lês graach de fernijingsnotysjes foardat in wichtige fernijing ynstallearre wurd.",
"Please set a GUI Authentication User and Password in the Settings dialog.": "Graach foar GUI-ferifikaasje in brûkers-ID en wachtwurd ynfiere in it ynstellingsdialooch",
"Please wait": "In amerijke graach",
"Please consult the release notes before performing a major upgrade.": "Foardat jo in wichtige fernijing ynstallearre, graach earst de fernijingsoantekenings lêze.",
"Please set a GUI Authentication User and Password in the Settings dialog.": "Graach foar GUI-ferifikaasje in brûkers-ID en wachtwurd ynstelle yn it ynstellingsdialooch.",
"Please wait": "In amerijke",
"Preview": "Foarbyld",
"Preview Usage Report": "Foarbyld fan brûksrapport ",
"Preview Usage Report": "Foarbyld fan brûkensrapport ",
"Quick guide to supported patterns": "Fluch-paadwizer foar stipe patroanen",
"RAM Utilization": "Rambrûken",
"RAM Utilization": "RAM-brûken",
"Random": "Willekeurich",
"Relayed via": "Trochjûn fia",
"Relays": "Trochjouers",
"Release Notes": "Utjeftenotysjes",
"Remove": "Fuortsmite",
"Rescan": "Opnij skenne",
"Rescan All": "Alles opnij skenne",
"Rescan Interval": "Ynterval foar opnij skenne",
"Restart": "Werstart",
"Rescan": "Sken opnij",
"Rescan All": "Sken alles opnij",
"Rescan Interval": "Wersken ynterval",
"Restart": "Werstarte",
"Restart Needed": "Werstart nedich",
"Restarting": "Oan it werstarten",
"Resume": "Trochgean",
"Reused": "Opnij brûkt",
"Save": "Bewarje",
"Scan Time Remaining": "Scan Time Remaining",
"Scan Time Remaining": "Oerbleaune skentiid",
"Scanning": "Oan it skennen",
"Select the devices to share this folder with.": "Sykje de apparaten út om dizze map mei te dielen.",
"Select the folders to share with this device.": "Sykje de mappen út om mei dit apparaat te dielen.",
@@ -151,16 +151,16 @@
"Shared With": "Dielt mei",
"Short identifier for the folder. Must be the same on all cluster devices.": "Koart opskrift foar de map. Moat op alle apparaten itselde wêze.",
"Show ID": "ID sjen litte",
"Shown instead of Device ID in the cluster status. Will be advertised to other devices as an optional default name.": "Wurd yn de bondeltastân sjen litten ynstee fan apparaat-ID. Wurd nei oare apparaten advertearre as opsjonele standertnamme.",
"Shown instead of Device ID in the cluster status. Will be updated to the name the device advertises if left empty.": "Wurd yn de bondeltastân sjen litten ynstee fan apparaat-ID. Wannear it leech litten wurd, wurd it fernijt nei de namme die it apparaat advertearret.",
"Shown instead of Device ID in the cluster status. Will be advertised to other devices as an optional default name.": "Wurd ynstee fan apparaat-ID sjen litten by de bondeltastân. Wurd nei oare apparaten advertearre as in mooglike standertnamme.",
"Shown instead of Device ID in the cluster status. Will be updated to the name the device advertises if left empty.": "Wurd yn de bondel-tastân sjen litten ynstee fan apparaat-ID. Wannear't leech litten wurd, wurd it fernijt nei de namme die it apparaat útstjoert.",
"Shutdown": "Ofslute",
"Shutdown Complete": "Ofsluten klear",
"Simple File Versioning": "Ienfâldige triemferzjebehear",
"Single level wildcard (matches within a directory only)": "Inkel-nivo jokerteken (wildcard) (fergeliket allinich binnen in map)",
"Simple File Versioning": "Ienfâldich triemferzjebehear",
"Single level wildcard (matches within a directory only)": "Inkel-nivo jokerteken (wildcard) (fergeliket allinnich binnen in map)",
"Smallest First": "Lytste earst",
"Source Code": "Boarnekoade",
"Staggered File Versioning": "Sprieden triemferzjebehear",
"Start Browser": "Browser starte",
"Start Browser": "Browser iepenje wannear't Syncthing start",
"Statistics": "Statistiken",
"Stopped": "Stoppe",
"Support": "Understeuning",
@@ -170,25 +170,25 @@
"Syncthing includes the following software or portions thereof:": "Syncthing befettet de folgende sêftguod of parten dêrfan:",
"Syncthing is restarting.": "Syncthing oan it werstarten.",
"Syncthing is upgrading.": "Syncthing is oan it fernijen.",
"Syncthing seems to be down, or there is a problem with your Internet connection. Retrying…": "It liket dêrop dat Syncthing op dit stuit net rint, of der is in probleem mei jo ynternetferbining. ",
"Syncthing seems to be down, or there is a problem with your Internet connection. Retrying…": "It liket dêrop dat Syncthing op dit stuit net rint, of der is in swierrichheid mei jo ynternetferbining. Wurd no opnij besocht...",
"Syncthing seems to be experiencing a problem processing your request. Please refresh the page or restart Syncthing if the problem persists.": "It liket dêrop dat Syncthing swierrichheden ûnderfynt mei it ferwurkjen fan jo fersyk. Graach de stee ferfarskje of Syncthing werstarte as it probleem der bliuwt.",
"The Syncthing admin interface is configured to allow remote access without a password.": "De Syncthing haadbrûker-ynterfaasje is sa ynstelt dat tagong fan ôfstân sûnder wachtwurd tastean is.",
"The aggregated statistics are publicly available at {%url%}.": "De fersammele statistiken binnen yn it publyk beskikber op {{url}}.",
"The configuration has been saved but not activated. Syncthing must restart to activate the new configuration.": "De konfiguraasje is bewarre mar noch net aktivearre. Syncthing moat werstarte om de nije konfiguraasje te aktivearren.",
"The device ID cannot be blank.": "De apparaat-ID kin net leech wêze.",
"The device ID to enter here can be found in the \"Edit > Show ID\" dialog on the other device. Spaces and dashes are optional (ignored).": "It apparaat-ID dat hjir ynfierd wurde kin, kin fûn wurde yn in it \"Bewurkje > ID sjen litte\" dialooch op de oare apparaten. Spaasjes en streepkes binne opsjoneel (negeard).",
"The encrypted usage report is sent daily. It is used to track common platforms, folder sizes and app versions. If the reported data set is changed you will be prompted with this dialog again.": "It ferkaaide brûkensrapport wurd eltse dei ferstjoerd. It wurd brûkt om folle brûkte platfoarmen, mapgruttens en appferzjes by te hâlden. At de rapportearre dataset feroare wurd, krije jo dit dialooch wer te sjen.",
"The entered device ID does not look valid. It should be a 52 or 56 character string consisting of letters and numbers, with spaces and dashes being optional.": "Dit yntypte apparaat-ID liket net falide. It moat in tekenrige (string) mei in lingte fan 52 of 56 karakters wêze, besteande út letters en nûmers, mei spaasjes en streepkes opsjoneel.",
"The first command line parameter is the folder path and the second parameter is the relative path in the folder.": "De earste kommando-rigel-parameter is it paad fan de map, de twadde parameter is it relative paad yn de map.",
"The device ID cannot be blank.": "It apparaat-ID kin net leech wêze.",
"The device ID to enter here can be found in the \"Edit > Show ID\" dialog on the other device. Spaces and dashes are optional (ignored).": "It apparaat-ID dat hjir ynfierd wurde kin, kin fûn wurde yn in it \"Bewurkje > ID sjen litte\" dialooch op de oare apparaten. Spaasjes en streepkes binne mooglik (wurde negeard).",
"The encrypted usage report is sent daily. It is used to track common platforms, folder sizes and app versions. If the reported data set is changed you will be prompted with this dialog again.": "It ferkaaide brûkensrapport wurd eltse dei ferstjoerd. It wurd brûkt om algemiene platfoarmen, mapgruttens en app-ferzjes by te hâlden. As de rapportearre dataset feroaret, krije jo dit dialooch wer te sjen.",
"The entered device ID does not look valid. It should be a 52 or 56 character string consisting of letters and numbers, with spaces and dashes being optional.": "Dit ynfierde apparaat-ID liket ûnjildich. It moat in tekenrige (string) wêze mei in lingte fan 52 of 56 karakters besteande út letters en nûmers, mei spaasjes en streepkes mooglik.",
"The first command line parameter is the folder path and the second parameter is the relative path in the folder.": "De earste parameter yn de kommando-rigel is it paad fan de map, de twadde parameter is it relative paad yn de map.",
"The folder ID cannot be blank.": "It map-ID mei net leech wêze.",
"The folder ID must be a short identifier (64 characters or less) consisting of letters, numbers and the dot (.), dash (-) and underscode (_) characters only.": "It map-ID moat in koart opskrift wêze (64 karakters of minder) allinnich besteande út letters, nûmers en punt- (.), streep- (-) en lizzend-streepkekarakters (_) .",
"The folder ID must be unique.": "It map-ID moat unyk wêze.",
"The folder path cannot be blank.": "It map-paad mei net leech wêze.",
"The following intervals are used: for the first hour a version is kept every 30 seconds, for the first day a version is kept every hour, for the first 30 days a version is kept every day, until the maximum age a version is kept every week.": "De folgende yntervals wurd brûkt: foar it earste oere wurd eltse 30 sekonden in ferzje bewarre, foar de earste dei wurd eltse oere in ferzje bewarre, foar de earste 30 dagen wurd eltse dei in ferzje bewarre, oant de maksimale âldens wurd eltse wike in ferzje bewarre.",
"The following intervals are used: for the first hour a version is kept every 30 seconds, for the first day a version is kept every hour, for the first 30 days a version is kept every day, until the maximum age a version is kept every week.": "De folgende yntervals wurd brûkt: foar it earste oere wurd eltse 30 sekonden in ferzje bewarre, foar de earste dei wurd eltse oere in ferzje bewarre, foar de earste 30 dagen wurd eltse dei in ferzje bewarre, oant ta de maksimale âldens wurd eltse wike in ferzje bewarre.",
"The following items could not be synchronized.": "De folgende items koene net syngronisearre wurde.",
"The maximum age must be a number and cannot be blank.": "De maksimale âldens moat in nûmer wêze en mei net leech wêze.",
"The maximum age must be a number and cannot be blank.": "De maksimale âldens moat in nûmer en net leech wêze.",
"The maximum time to keep a version (in days, set to 0 to keep versions forever).": "De maksimale tiid dat in ferzje bewarre wurde moat (yn dagen, stel yn op 0 om ferzjes foar immer te bewarjen).",
"The minimum free disk space percentage must be a non-negative number between 0 and 100 (inclusive).": "It persintaazje maksimale frije skiifromte moat in posityf nûmer wêze tusken 0 en 100 (ynklusyf).",
"The minimum free disk space percentage must be a non-negative number between 0 and 100 (inclusive).": "It maksimale persintaazje frije skiifromte moat in posityf nûmer wêze tusken 0 en 100 (ynklusyf).",
"The number of days must be a number and cannot be blank.": "It tal fan dagen moat in nûmer wêze en mei net leech wêze.",
"The number of days to keep files in the trash can. Zero means forever.": "It tal fan dagen om triemen in it jiskefet te bewarjen. Nul (0) betsjuttet foar immer.",
"The number of old versions to keep, per file.": "It tal fan âlde ferzjes om te bewarjen, de triem.",
@@ -196,8 +196,8 @@
"The path cannot be blank.": "It paad mei net leech wêze.",
"The rate limit must be a non-negative number (0: no limit)": "It fluggenslimyt moat in posityf nûmer wêze (0: gjin limyt)",
"The rescan interval must be a non-negative number of seconds.": "It wersken-ynterfal moat in posityf tal fan sekonden wêze.",
"They are retried automatically and will be synced when the error is resolved.": "Dizze wurde automatysk opnij probearre en sille syngronisearre wurde wannear at de flater oplost is.",
"This can easily give hackers access to read and change any files on your computer.": "Dit kin samar hackers tagong jaan om samar wat triemen op jo kompjûter besjen en te feroarjen.",
"They are retried automatically and will be synced when the error is resolved.": "Sy wurde automatysk opnij probearre en sille syngronisearre wurde wannear at de flater oplost is.",
"This can easily give hackers access to read and change any files on your computer.": "Dit kin samar ynkringers (hackers) tagong jaan om elke triem op jo kompjûter te besjen en te feroarjen.",
"This is a major version upgrade.": "Dit is in wichtige ferzjefernijing.",
"Trash Can File Versioning": "Jiskefet-triemferzjebehear",
"Unknown": "Unbekend",
@@ -208,16 +208,16 @@
"Upgrade": "Fernije",
"Upgrade To {%version%}": "Fernije nei {{version}}",
"Upgrading": "Oan it fernijen",
"Upload Rate": "Upload-fluggens",
"Uptime": "Yn-it-wurk-tiid",
"Upload Rate": "Oplaadfluggens",
"Uptime": "Rintiid",
"Use HTTPS for GUI": "Brûk HTTPS foar GUI",
"Version": "Ferzje",
"Versions Path": "Ferzjes-paad",
"Versions are automatically deleted if they are older than the maximum age or exceed the number of files allowed in an interval.": "Ferzjes wurde automatysk fuortsmiten wannear't se âlder binne dan de maksimale âldens of wannear it tal fan triemen yn in ynterval grutter is dan tastean.",
"When adding a new device, keep in mind that this device must be added on the other side too.": "Hâld by it tafoegjen fan nij apparaat yn de holle dat it apparaat oan de oare kant ek tafoege wurde moat. ",
"When adding a new folder, keep in mind that the Folder ID is used to tie folders together between devices. They are case sensitive and must match exactly between all devices.": "Hâld by it tafoegjen fan nije map yn de holle dat de map-ID brûkt wurd om de mappen tusken apparaten mei-inoar te ferbinen. Se binne haadlettergefoelich en moatte oer alle apparaten krekt oerienkomme.",
"When adding a new device, keep in mind that this device must be added on the other side too.": "Hâld by it taheakjen fan in nij apparaat yn de holle dat it apparaat oan de oare kant ek taheakke wurde moat. ",
"When adding a new folder, keep in mind that the Folder ID is used to tie folders together between devices. They are case sensitive and must match exactly between all devices.": "Hâld by it taheakjen fan in nije map yn de holle dat de map-ID brûkt wurd om de mappen tusken apparaten mei-inoar te ferbinen. Se binne haadlettergefoelich en moatte oer alle apparaten eksakt oerienkomme.",
"Yes": "Ja",
"You must keep at least one version.": "Jo moatte op syn minst ien ferzje bewarje.",
"You must keep at least one version.": "Jo moatte minstens ien ferzje bewarje.",
"days": "dagen",
"full documentation": "komplete dokumintaasje",
"items": "items",

View File

@@ -15,7 +15,7 @@
"All Data": "Minden adat",
"Allow Anonymous Usage Reporting?": "Engedélyezed a névtelen felhasználási adatok küldését?",
"Alphabetic": "ABC rendben",
"An external command handles the versioning. It has to remove the file from the synced folder.": "Egy külső program kezeli a fájl verziózást. El kell távolítsa a fájlt a szinkronizált mappából.",
"An external command handles the versioning. It has to remove the file from the synced folder.": "Külső program kezeli a fájl verziókövetést. A fájlt el kell távolítania a szinkronizált mappából.",
"Anonymous Usage Reporting": "Névtelen felhasználási adatok küldése",
"Any devices configured on an introducer device will be added to this device as well.": "Minden eszköz ami a bevezető eszközön lett beállítva hozzá lesz adva ehhez az eszközhöz is.",
"Automatic upgrades": "Automatikus frissítés",
@@ -32,7 +32,7 @@
"Copied from elsewhere": "Másolva máshonnan",
"Copied from original": "Másolva az eredetiről",
"Copyright © 2015 the following Contributors:": "Copyright © 2015 az alábbi Közreműködők:",
"Danger!": "Danger!",
"Danger!": "Veszély!",
"Delete": "Törlés",
"Deleted": "Törölve",
"Device ID": "Eszköz azonosító",
@@ -54,13 +54,13 @@
"Enter comma separated (\"tcp://ip:port\", \"tcp://host:port\") addresses or \"dynamic\" to perform automatic discovery of the address.": "Vesszővel elválasztva több cím is bevihető (\"tcp://ip:port\", \"tcp://host:port\"), az automatikus felderítéshez a 'dynamic' kulcsszó használatos. ",
"Enter ignore patterns, one per line.": "Figyelmen kívül hagyáshoz ide írhatod a mintákat, soronként egyet",
"Error": "Hiba",
"External File Versioning": "Külső fájl verziós",
"External File Versioning": "Külső fájl verziókövetés",
"Failed Items": "Hibás elemek",
"File Pull Order": "Fájl küldési sorrend",
"File Versioning": "Fájl verziós",
"File Versioning": "Fájl verziókövetés",
"File permission bits are ignored when looking for changes. Use on FAT file systems.": "Fájl jogosultságok figyelmen kívül hagyása változások keresésekor. FAT fájlrendszerek használatakor.",
"Files are moved to .stversions folder when replaced or deleted by Syncthing.": "Ha a Syncthing áthelyezi vagy törli a fájlokat, akkor azok a .stversions mappába lesznek áthelyezve.",
"Files are moved to date stamped versions in a .stversions folder when replaced or deleted by Syncthing.": "Ha a Syncthing áthelyezi vagy törli a fájlokat, akkor azok a .stversions mappába lesznek áthelyezve, időbélyegzővel ellátva.",
"Files are moved to date stamped versions in a .stversions folder when replaced or deleted by Syncthing.": "Ha a Syncthing felülírja vagy törli a fájlokat, akkor azok a .stversions mappába lesznek áthelyezve, időbélyegzővel ellátva.",
"Files are protected from changes made on other devices, but changes made on this device will be sent to the rest of the cluster.": "A fájlok védve vannak a más eszközökön történt változásokkal szemben, de az ezen az eszközön történt változások érvényesek lesznek a többire.",
"Folder": "Mappa",
"Folder ID": "Mappa azonosító",
@@ -103,7 +103,7 @@
"New Folder": "Új mappa",
"Newest First": "Újabb először",
"No": "Nem",
"No File Versioning": "Nincs fájl verziós",
"No File Versioning": "Nincs fájl verziókövetés",
"Notice": "Megjegyzés",
"OK": "Rendben",
"Off": "Kikapcsolva",
@@ -118,7 +118,7 @@
"Pause": "Szünet",
"Paused": "Szünetel",
"Please consult the release notes before performing a major upgrade.": "Nagyobb frissítés előtt ellenőrizni kell a kiadási megjegyzéseket.",
"Please set a GUI Authentication User and Password in the Settings dialog.": "Please set a GUI Authentication User and Password in the Settings dialog.",
"Please set a GUI Authentication User and Password in the Settings dialog.": "Kérlek állítsd be a grafikus felület felhasználónevét és jelszavát a Beállítások ablakban",
"Please wait": "Kérlek, várj",
"Preview": "Előnézet",
"Preview Usage Report": "Felhasználási adatok átnézése",
@@ -138,7 +138,7 @@
"Resume": "Folytatás",
"Reused": "Újrafelhasználva",
"Save": "Mentés",
"Scan Time Remaining": "Scan Time Remaining",
"Scan Time Remaining": "Fennmaradó átnézési idő",
"Scanning": "Átnézés",
"Select the devices to share this folder with.": "Válaszd ki az eszközöket amelyekkel meg szeretnéd osztani a mappát",
"Select the folders to share with this device.": "Válaszd ki a mappákat amiket meg szeretnél osztani ezzel az eszközzel",
@@ -172,7 +172,7 @@
"Syncthing is upgrading.": "Syncthing frissül",
"Syncthing seems to be down, or there is a problem with your Internet connection. Retrying…": "Úgy tűnik, hogy a Syncthing nem működik, vagy valami probléma van az hálózati kapcsolattal. Újra próbálom...",
"Syncthing seems to be experiencing a problem processing your request. Please refresh the page or restart Syncthing if the problem persists.": "Úgy tűnik, hogy a Syncthing problémába ütközött a kérés feldolgozása során. Ha a probléma továbbra is fennáll, akkor frissíteni kell az oldalt, vagy újra kell indítani a Syncthinget.",
"The Syncthing admin interface is configured to allow remote access without a password.": "The Syncthing admin interface is configured to allow remote access without a password.",
"The Syncthing admin interface is configured to allow remote access without a password.": "A Syncthing adminisztrációs felületének távoli elérése be van kapcsolva jelszó nélkül.",
"The aggregated statistics are publicly available at {%url%}.": "Az összevont statisztikák nyilvánosan elérhetők a {{url}} címen.",
"The configuration has been saved but not activated. Syncthing must restart to activate the new configuration.": "A beállítások elmentésre kerültek, de nem lettek aktiválva. Indítsd újra a Syncthing-et, hogy aktiváld őket.",
"The device ID cannot be blank.": "Az eszköz azonosító nem lehet üres.",
@@ -197,9 +197,9 @@
"The rate limit must be a non-negative number (0: no limit)": "Az arány limitnek pozitív számnak kell lennie (0: nincs limit)",
"The rescan interval must be a non-negative number of seconds.": "Az átnézési intervallum nullánál nagyobb másodperc érték kell legyen",
"They are retried automatically and will be synced when the error is resolved.": "A hiba javítása után automatikusan újra megpróbálja a szinkronizálást.",
"This can easily give hackers access to read and change any files on your computer.": "This can easily give hackers access to read and change any files on your computer.",
"This can easily give hackers access to read and change any files on your computer.": "Így a hekkerek könnyedén hozzáférhetnek a számítógépen található fájlokhoz. ",
"This is a major version upgrade.": "Ez egy főverzió frissítés.",
"Trash Can File Versioning": "Szemetes fájl verziós",
"Trash Can File Versioning": "Szemetes fájl verziókövetés",
"Unknown": "Ismeretlen",
"Unshared": "Nincs megosztva",
"Unused": "Nincs használatban",

View File

@@ -118,7 +118,7 @@
"Pause": "Pauze",
"Paused": "Gepauseerd",
"Please consult the release notes before performing a major upgrade.": "Lees eerst de release notes voordat u een grote update uitvoert.",
"Please set a GUI Authentication User and Password in the Settings dialog.": "Stel een GUI Authentication User en wachtwoord in. Dit kan in het dialoogvenster met instellingen.",
"Please set a GUI Authentication User and Password in the Settings dialog.": "Stel een gebruikersnaam en wachtwoord in bij 'Instellingen'.",
"Please wait": "Even geduld",
"Preview": "Preview",
"Preview Usage Report": "Preview gebruiksstatistieken",
@@ -138,7 +138,7 @@
"Resume": "Hervatten",
"Reused": "Hergebruikt",
"Save": "Bewaar",
"Scan Time Remaining": "Scan Time Remaining",
"Scan Time Remaining": "Resterende scantijd",
"Scanning": "Aan het zoeken",
"Select the devices to share this folder with.": "Selecteer de apparaten om deze map mee te delen.",
"Select the folders to share with this device.": "Selecteer de mappen om met dit apparaat te delen.",
@@ -172,7 +172,7 @@
"Syncthing is upgrading.": "Syncthing is aan het upgraden.",
"Syncthing seems to be down, or there is a problem with your Internet connection. Retrying…": "Syncthing lijkt afgesloten te zijn, of er is een verbindingsprobleem met het internet. Nieuwe poging....",
"Syncthing seems to be experiencing a problem processing your request. Please refresh the page or restart Syncthing if the problem persists.": "Syncthing lijkt een probleem te ondervinden met het verwerken van je verzoek. Refresh de pagina of herstart Syncthing als de problemen zich blijven voordoen. ",
"The Syncthing admin interface is configured to allow remote access without a password.": "De Syncthing admin interface is geconfigureerd om op afstand toegang zonder een wachtwoord toe te staan.",
"The Syncthing admin interface is configured to allow remote access without a password.": "Syncthing's beheerdersinterface is ingesteld om externe toegang zonder wachtwoord toe te staan.",
"The aggregated statistics are publicly available at {%url%}.": "The verzamelde statistieken zijn publiek beschikbaar op {{url}}",
"The configuration has been saved but not activated. Syncthing must restart to activate the new configuration.": "De configuratie is opslagen maar nog niet actief. Syncthing moet opnieuw opgestart worden om de nieuwe configuratie te activeren.",
"The device ID cannot be blank.": "Het apparaat-ID mag niet leeg zijn.",
@@ -197,7 +197,7 @@
"The rate limit must be a non-negative number (0: no limit)": "De snelheidslimiet moet een positief nummer zijn (0: geen limiet)",
"The rescan interval must be a non-negative number of seconds.": "De scanfrequentie moet een positief getal in seconden zijn.",
"They are retried automatically and will be synced when the error is resolved.": "Het wordt automatisch opnieuw geprobeerd. Bestanden worden gesynchroniseerd als de fout is hersteld.",
"This can easily give hackers access to read and change any files on your computer.": "Dit kan hackers eenvoudig toegang geven tot het lezen en wijzigen van bestanden op jouw computer.",
"This can easily give hackers access to read and change any files on your computer.": "Dit kan kwaadwilligen eenvoudig toegang geven tot het lezen en wijzigen van bestanden op jouw computer.",
"This is a major version upgrade.": "Dit is een grote update.",
"Trash Can File Versioning": "Versiebeheer bestanden prullenbak",
"Unknown": "Onbekend",
@@ -208,7 +208,7 @@
"Upgrade": "Upgrade",
"Upgrade To {%version%}": "Upgrade naar {{version}}",
"Upgrading": "Bezig met upgrade",
"Upload Rate": "Upload snelheid",
"Upload Rate": "Uploadsnelheid",
"Uptime": "Uptime",
"Use HTTPS for GUI": "Gebruik HTTPS voor de GUI",
"Version": "Versie",

View File

@@ -138,7 +138,7 @@
"Resume": "Resumir",
"Reused": "Reutilizado",
"Save": "Salvar",
"Scan Time Remaining": "Scan Time Remaining",
"Scan Time Remaining": "Tempo de verificação restante",
"Scanning": "Verificando",
"Select the devices to share this folder with.": "Selecione os dispositivos com os quais esta pasta será compartilhada.",
"Select the folders to share with this device.": "Selecione as pastas a serem compartilhadas com este dispositivo.",

View File

@@ -1,5 +1,5 @@
{
"A negative number of days doesn't make sense.": "Від'ємна кількість днів не має сенсу.",
"A negative number of days doesn't make sense.": "Від'ємна кількість днів немає сенсу.",
"A new major version may not be compatible with previous versions.": "Нова мажорна версія може бути несумісною із попередніми версіями.",
"API Key": "API ключ",
"About": "Про програму",
@@ -32,7 +32,7 @@
"Copied from elsewhere": "Скопійовано з іншого місця",
"Copied from original": "Скопійовано з оригіналу",
"Copyright © 2015 the following Contributors:": "Copyright © 2015 наступних контриб’юторів:",
"Danger!": "Danger!",
"Danger!": "Небезпечно!",
"Delete": "Видалити",
"Deleted": "Видалене",
"Device ID": "ID пристрою",
@@ -41,7 +41,7 @@
"Device {%device%} ({%address%}) wants to connect. Add new device?": "Пристрій {{device}} ({{address}}) намагається під’єднатися. Додати новий пристрій?",
"Devices": "Пристрої",
"Disconnected": "З’єднання відсутнє",
"Discovery": "Discovery",
"Discovery": "Виявлення",
"Documentation": "Документація",
"Download Rate": "Швидкість завантаження",
"Downloaded": "Завантажено",
@@ -118,7 +118,7 @@
"Pause": "Пауза",
"Paused": "Призупинено",
"Please consult the release notes before performing a major upgrade.": "Будь ласка перегляньте примітки до випуску перед мажорним оновленням. ",
"Please set a GUI Authentication User and Password in the Settings dialog.": "Please set a GUI Authentication User and Password in the Settings dialog.",
"Please set a GUI Authentication User and Password in the Settings dialog.": "Будь ласка, встановіть у налаштуваннях ім'я користувача та пароль до графічного інтерфейсу.",
"Please wait": "Будь ласка, зачекайте",
"Preview": "Попередній перегляд",
"Preview Usage Report": "Попередній перегляд статистичного звіту",
@@ -138,7 +138,7 @@
"Resume": "Продовжити",
"Reused": "Використано вдруге",
"Save": "Зберегти",
"Scan Time Remaining": "Scan Time Remaining",
"Scan Time Remaining": "Час до кінця сканування",
"Scanning": "Сканування",
"Select the devices to share this folder with.": "Оберіть пристрої, які матимуть доступ до цієї директорії.",
"Select the folders to share with this device.": "Оберіть директорії до яких матиме доступ цей пристрій.",
@@ -172,7 +172,7 @@
"Syncthing is upgrading.": "Syncthing оновлюється.",
"Syncthing seems to be down, or there is a problem with your Internet connection. Retrying…": "Схоже на те, що Syncthing закритий, або виникла проблема із Інтернет-з’єднанням. Проводиться повторна спроба з’єднання…",
"Syncthing seems to be experiencing a problem processing your request. Please refresh the page or restart Syncthing if the problem persists.": "Схоже на те, що Syncthing стикнувся з проблемою оброблюючи ваш запит. Будь ласка перезавантажте сторінку в браузері або перезапустіть Syncthing.",
"The Syncthing admin interface is configured to allow remote access without a password.": "The Syncthing admin interface is configured to allow remote access without a password.",
"The Syncthing admin interface is configured to allow remote access without a password.": "Інтерфейс адміністрування Syncthing налаштовано на дозвіл віддаленого доступу без пароля.",
"The aggregated statistics are publicly available at {%url%}.": "Зібрана статистика публічно доступна за посиланням {{url}}.",
"The configuration has been saved but not activated. Syncthing must restart to activate the new configuration.": "Конфігурацію збережено, але не активовано. Необхідно перезапустити Syncthing для того, щоби активувати нову конфігурацію.",
"The device ID cannot be blank.": "ID пристрою не може бути порожнім.",
@@ -197,7 +197,7 @@
"The rate limit must be a non-negative number (0: no limit)": "Швидкість має бути додатнім числом.",
"The rescan interval must be a non-negative number of seconds.": "Інтервал повторного сканування повинен бути неід’ємною величиною.",
"They are retried automatically and will be synced when the error is resolved.": "Вони будуть автоматично повторно синхронізовані, коли помилку буде усунено. ",
"This can easily give hackers access to read and change any files on your computer.": "This can easily give hackers access to read and change any files on your computer.",
"This can easily give hackers access to read and change any files on your computer.": "Це легко може дати хакерам доступ до читання та зміни будь-яких файлів на вашому комп'ютері.",
"This is a major version upgrade.": "Це оновлення мажорної версії",
"Trash Can File Versioning": "Версіонування файлів у кошику ",
"Unknown": "Невідомо",

View File

@@ -1 +1 @@
var langPrettyprint = {"bg":"Bulgarian","ca":"Catalan","ca@valencia":"Catalan (Valencian)","cs":"Czech","de":"German","el":"Greek","en":"English","en-GB":"English (United Kingdom)","es":"Spanish","es-ES":"Spanish (Spain)","fi":"Finnish","fr":"French","fr-CA":"French (Canada)","fy":"Western Frisian","hu":"Hungarian","it":"Italian","ja":"Japanese","ko-KR":"Korean (Korea)","lt":"Lithuanian","nb":"Norwegian Bokmål","nl":"Dutch","nn":"Norwegian Nynorsk","pl":"Polish","pt-BR":"Portuguese (Brazil)","pt-PT":"Portuguese (Portugal)","ro-RO":"Romanian (Romania)","ru":"Russian","sv":"Swedish","uk":"Ukrainian","zh-CN":"Chinese (China)","zh-TW":"Chinese (Taiwan)"}
var langPrettyprint = {"bg":"Bulgarian","ca":"Catalan","ca@valencia":"Catalan (Valencian)","cs":"Czech","da":"Danish","de":"German","el":"Greek","en":"English","en-GB":"English (United Kingdom)","es":"Spanish","es-ES":"Spanish (Spain)","fi":"Finnish","fr":"French","fr-CA":"French (Canada)","fy":"Western Frisian","hu":"Hungarian","it":"Italian","ja":"Japanese","ko-KR":"Korean (Korea)","lt":"Lithuanian","nb":"Norwegian Bokmål","nl":"Dutch","nn":"Norwegian Nynorsk","pl":"Polish","pt-BR":"Portuguese (Brazil)","pt-PT":"Portuguese (Portugal)","ro-RO":"Romanian (Romania)","ru":"Russian","sv":"Swedish","uk":"Ukrainian","zh-CN":"Chinese (China)","zh-TW":"Chinese (Taiwan)"}

View File

@@ -1 +1 @@
var validLangs = ["bg","ca","ca@valencia","cs","de","el","en","en-GB","es","es-ES","fi","fr","fr-CA","fy","hu","it","ja","ko-KR","lt","nb","nl","nn","pl","pt-BR","pt-PT","ro-RO","ru","sv","uk","zh-CN","zh-TW"]
var validLangs = ["bg","ca","ca@valencia","cs","da","de","el","en","en-GB","es","es-ES","fi","fr","fr-CA","fy","hu","it","ja","ko-KR","lt","nb","nl","nn","pl","pt-BR","pt-PT","ro-RO","ru","sv","uk","zh-CN","zh-TW"]

View File

@@ -64,13 +64,16 @@
<li class="auto-generated">Mateusz Naściszewski</li>
<li class="auto-generated">Matt Burke</li>
<li class="auto-generated">Michael Jephcote</li>
<li class="auto-generated">Michael Ploujnikov</li>
<li class="auto-generated">Michael Tilli</li>
<li class="auto-generated">Nate Morrison</li>
<li class="auto-generated">Pascal Jungblut</li>
<li class="auto-generated">Peter Hoeg</li>
<li class="auto-generated">Philippe Schommers</li>
<li class="auto-generated">Phill Luby</li>
<li class="auto-generated">Piotr Bejda</li>
<li class="auto-generated">Ryan Sullivan</li>
<li class="auto-generated">Scott Klupfel</li>
<li class="auto-generated">Sergey Mishin</li>
<li class="auto-generated">Stefan Kuntz</li>
<li class="auto-generated">Stefan Tatschner</li>
@@ -80,6 +83,7 @@
<li class="auto-generated">Tully Robinson</li>
<li class="auto-generated">Tyler Brazier</li>
<li class="auto-generated">Veeti Paananen</li>
<li class="auto-generated">Victor Buinsky</li>
<li class="auto-generated">Vil Brekin</li>
<li class="auto-generated">Yannic A.</li>
</ul>

View File

@@ -1414,10 +1414,13 @@ angular.module('syncthing.core')
};
$scope.showURPreview = function () {
$('#settings').modal('hide');
$('#urPreview').modal().on('hidden.bs.modal', function () {
$('#settings').modal();
});
$('#settings').modal('hide')
.one('hidden.bs.modal', function() {
$('#urPreview').modal()
.one('hidden.bs.modal', function () {
$('#settings').modal();
});
});
};
$scope.acceptUR = function () {

View File

File diff suppressed because one or more lines are too long

View File

@@ -36,14 +36,14 @@ var (
DefaultDiscoveryServersV4 = []string{
"https://discovery-v4-1.syncthing.net/?id=SR7AARM-TCBUZ5O-VFAXY4D-CECGSDE-3Q6IZ4G-XG7AH75-OBIXJQV-QJ6NLQA", // 194.126.249.5, Sweden
"https://discovery-v4-2.syncthing.net/?id=DVU36WY-H3LVZHW-E6LLFRE-YAFN5EL-HILWRYP-OC2M47J-Z4PE62Y-ADIBDQC", // 45.55.230.38, USA
"https://discovery-v4-3.syncthing.net/?id=7WT2BVR-FX62ZOW-TNVVW25-6AHFJGD-XEXQSBW-VO3MPL2-JBTLL4T-P4572Q4", // 128.199.95.124, Singapore
"https://discovery-v4-3.syncthing.net/?id=VK6HNJ3-VVMM66S-HRVWSCR-IXEHL2H-U4AQ4MW-UCPQBWX-J2L2UBK-NVZRDQZ", // 128.199.95.124, Singapore
}
// DefaultDiscoveryServersV6 should be substituted when the configuration
// contains <globalAnnounceServer>default-v6</globalAnnounceServer>.
DefaultDiscoveryServersV6 = []string{
"https://discovery-v6-1.syncthing.net/?id=SR7AARM-TCBUZ5O-VFAXY4D-CECGSDE-3Q6IZ4G-XG7AH75-OBIXJQV-QJ6NLQA", // 2001:470:28:4d6::5, Sweden
"https://discovery-v6-2.syncthing.net/?id=DVU36WY-H3LVZHW-E6LLFRE-YAFN5EL-HILWRYP-OC2M47J-Z4PE62Y-ADIBDQC", // 2604:a880:800:10::182:a001, USA
"https://discovery-v6-3.syncthing.net/?id=7WT2BVR-FX62ZOW-TNVVW25-6AHFJGD-XEXQSBW-VO3MPL2-JBTLL4T-P4572Q4", // 2400:6180:0:d0::d9:d001, Singapore
"https://discovery-v6-3.syncthing.net/?id=VK6HNJ3-VVMM66S-HRVWSCR-IXEHL2H-U4AQ4MW-UCPQBWX-J2L2UBK-NVZRDQZ", // 2400:6180:0:d0::d9:d001, Singapore
}
// DefaultDiscoveryServers should be substituted when the configuration
// contains <globalAnnounceServer>default</globalAnnounceServer>.
@@ -54,10 +54,10 @@ var (
DefaultDiscoveryServersIP = []string{
"https://194.126.249.5/?id=SR7AARM-TCBUZ5O-VFAXY4D-CECGSDE-3Q6IZ4G-XG7AH75-OBIXJQV-QJ6NLQA",
"https://45.55.230.38/?id=AQEHEO2-XOS7QRA-X2COH5K-PO6OPVA-EWOSEGO-KZFMD32-XJ4ZV46-CUUVKAS",
"https://128.199.95.124/?id=7WT2BVR-FX62ZOW-TNVVW25-6AHFJGD-XEXQSBW-VO3MPL2-JBTLL4T-P4572Q4",
"https://128.199.95.124/?id=VK6HNJ3-VVMM66S-HRVWSCR-IXEHL2H-U4AQ4MW-UCPQBWX-J2L2UBK-NVZRDQZ",
"https://[2001:470:28:4d6::5]/?id=SR7AARM-TCBUZ5O-VFAXY4D-CECGSDE-3Q6IZ4G-XG7AH75-OBIXJQV-QJ6NLQA",
"https://[2604:a880:800:10::182:a001]/?id=AQEHEO2-XOS7QRA-X2COH5K-PO6OPVA-EWOSEGO-KZFMD32-XJ4ZV46-CUUVKAS",
"https://[2400:6180:0:d0::d9:d001]/?id=7WT2BVR-FX62ZOW-TNVVW25-6AHFJGD-XEXQSBW-VO3MPL2-JBTLL4T-P4572Q4",
"https://[2400:6180:0:d0::d9:d001]/?id=VK6HNJ3-VVMM66S-HRVWSCR-IXEHL2H-U4AQ4MW-UCPQBWX-J2L2UBK-NVZRDQZ",
}
)

View File

@@ -377,7 +377,7 @@ func (s *connectionSvc) connectViaRelay(deviceID protocol.DeviceID, addr discove
return nil
}
inv, err := client.GetInvitationFromRelay(uri, deviceID, s.tlsCfg.Certificates)
inv, err := client.GetInvitationFromRelay(uri, deviceID, s.tlsCfg.Certificates, 10*time.Second)
if err != nil {
l.Debugf("Failed to get invitation for %s from %s: %v", deviceID, uri, err)
return nil

View File

@@ -65,6 +65,10 @@ func newDBInstance(db *leveldb.DB) *Instance {
}
}
func (db *Instance) Compact() error {
return db.CompactRange(util.Range{})
}
func (db *Instance) genericReplace(folder, device []byte, fs []protocol.FileInfo, localSize, globalSize *sizeTracker, deleteFn deletionHandler) int64 {
sort.Sort(fileList(fs)) // sort list on name, same as in the database

View File

@@ -1,102 +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 http://mozilla.org/MPL/2.0/.
package dialer
import (
"net"
"net/http"
"os"
"strings"
"time"
"golang.org/x/net/proxy"
"github.com/syncthing/syncthing/lib/logger"
"github.com/syncthing/syncthing/lib/osutil"
)
var (
l = logger.DefaultLogger.NewFacility("dialer", "Dialing connections")
dialer = proxy.FromEnvironment()
usingProxy = dialer != proxy.Direct
)
func init() {
l.SetDebug("dialer", strings.Contains(os.Getenv("STTRACE"), "dialer") || os.Getenv("STTRACE") == "all")
if usingProxy {
http.DefaultTransport = &http.Transport{
Dial: Dial,
Proxy: http.ProxyFromEnvironment,
TLSHandshakeTimeout: 10 * time.Second,
}
// Defer this, so that logging gets setup.
go func() {
time.Sleep(500 * time.Millisecond)
l.Infoln("Proxy settings detected")
}()
}
}
// Dial tries dialing via proxy if a proxy is configured, and falls back to
// a direct connection if no proxy is defined, or connecting via proxy fails.
func Dial(network, addr string) (net.Conn, error) {
if usingProxy {
conn, err := dialer.Dial(network, addr)
if err == nil {
l.Debugf("Dialing %s address %s via proxy - success, %s -> %s", network, addr, conn.LocalAddr(), conn.RemoteAddr())
if tcpconn, ok := conn.(*net.TCPConn); ok {
osutil.SetTCPOptions(tcpconn)
}
return dialerConn{
conn, newDialerAddr(network, addr),
}, nil
}
l.Debugf("Dialing %s address %s via proxy - error %s", network, addr, err)
}
conn, err := proxy.Direct.Dial(network, addr)
if err == nil {
l.Debugf("Dialing %s address %s directly - success, %s -> %s", network, addr, conn.LocalAddr(), conn.RemoteAddr())
if tcpconn, ok := conn.(*net.TCPConn); ok {
osutil.SetTCPOptions(tcpconn)
}
} else {
l.Debugf("Dialing %s address %s directly - error %s", network, addr, err)
}
return conn, err
}
type dialerConn struct {
net.Conn
addr net.Addr
}
func (c dialerConn) RemoteAddr() net.Addr {
return c.addr
}
func newDialerAddr(network, addr string) net.Addr {
netaddr, err := net.ResolveIPAddr(network, addr)
if err == nil {
return netaddr
}
return fallbackAddr{network, addr}
}
type fallbackAddr struct {
network string
addr string
}
func (a fallbackAddr) Network() string {
return a.network
}
func (a fallbackAddr) String() string {
return a.addr
}

140
lib/dialer/internal.go Normal file
View File

@@ -0,0 +1,140 @@
// 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 http://mozilla.org/MPL/2.0/.
package dialer
import (
"net"
"net/http"
"net/url"
"os"
"strings"
"time"
"golang.org/x/net/proxy"
"github.com/syncthing/syncthing/lib/logger"
"github.com/syncthing/syncthing/lib/osutil"
)
var (
l = logger.DefaultLogger.NewFacility("dialer", "Dialing connections")
proxyDialer = getDialer(proxy.Direct)
usingProxy = proxyDialer != proxy.Direct
)
type dialFunc func(network, addr string) (net.Conn, error)
func init() {
l.SetDebug("dialer", strings.Contains(os.Getenv("STTRACE"), "dialer") || os.Getenv("STTRACE") == "all")
if usingProxy {
http.DefaultTransport = &http.Transport{
Dial: Dial,
Proxy: http.ProxyFromEnvironment,
TLSHandshakeTimeout: 10 * time.Second,
}
// Defer this, so that logging gets setup.
go func() {
time.Sleep(500 * time.Millisecond)
l.Infoln("Proxy settings detected")
}()
} else {
go func() {
time.Sleep(500 * time.Millisecond)
l.Debugln("Dialer logging disabled, as no proxy was detected")
}()
}
}
func dialWithFallback(proxyDialFunc dialFunc, fallbackDialFunc dialFunc, network, addr string) (net.Conn, error) {
conn, err := proxyDialFunc(network, addr)
if err == nil {
l.Debugf("Dialing %s address %s via proxy - success, %s -> %s", network, addr, conn.LocalAddr(), conn.RemoteAddr())
if tcpconn, ok := conn.(*net.TCPConn); ok {
osutil.SetTCPOptions(tcpconn)
}
return dialerConn{
conn, newDialerAddr(network, addr),
}, nil
}
l.Debugf("Dialing %s address %s via proxy - error %s", network, addr, err)
conn, err = fallbackDialFunc(network, addr)
if err == nil {
l.Debugf("Dialing %s address %s via fallback - success, %s -> %s", network, addr, conn.LocalAddr(), conn.RemoteAddr())
if tcpconn, ok := conn.(*net.TCPConn); ok {
osutil.SetTCPOptions(tcpconn)
}
} else {
l.Debugf("Dialing %s address %s via fallback - error %s", network, addr, err)
}
return conn, err
}
// This is a rip off of proxy.FromEnvironment with a custom forward dialer
func getDialer(forward proxy.Dialer) proxy.Dialer {
allProxy := os.Getenv("all_proxy")
if len(allProxy) == 0 {
return forward
}
proxyURL, err := url.Parse(allProxy)
if err != nil {
return forward
}
prxy, err := proxy.FromURL(proxyURL, forward)
if err != nil {
return forward
}
noProxy := os.Getenv("no_proxy")
if len(noProxy) == 0 {
return prxy
}
perHost := proxy.NewPerHost(prxy, forward)
perHost.AddFromString(noProxy)
return perHost
}
type timeoutDirectDialer struct {
timeout time.Duration
}
func (d *timeoutDirectDialer) Dial(network, addr string) (net.Conn, error) {
return net.DialTimeout(network, addr, d.timeout)
}
type dialerConn struct {
net.Conn
addr net.Addr
}
func (c dialerConn) RemoteAddr() net.Addr {
return c.addr
}
func newDialerAddr(network, addr string) net.Addr {
netaddr, err := net.ResolveIPAddr(network, addr)
if err == nil {
return netaddr
}
return fallbackAddr{network, addr}
}
type fallbackAddr struct {
network string
addr string
}
func (a fallbackAddr) Network() string {
return a.network
}
func (a fallbackAddr) String() string {
return a.addr
}

48
lib/dialer/public.go Normal file
View File

@@ -0,0 +1,48 @@
// 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 http://mozilla.org/MPL/2.0/.
package dialer
import (
"net"
"time"
)
// Dial tries dialing via proxy if a proxy is configured, and falls back to
// a direct connection if no proxy is defined, or connecting via proxy fails.
func Dial(network, addr string) (net.Conn, error) {
if usingProxy {
return dialWithFallback(proxyDialer.Dial, net.Dial, network, addr)
}
return net.Dial(network, addr)
}
// DialTimeout tries dialing via proxy with a timeout if a proxy is configured,
// and falls back to a direct connection if no proxy is defined, or connecting
// via proxy fails. The timeout can potentially be applied twice, once trying
// to connect via the proxy connection, and second time trying to connect
// directly.
func DialTimeout(network, addr string, timeout time.Duration) (net.Conn, error) {
if usingProxy {
// Because the proxy package is poorly structured, we have to
// construct a struct that matches proxy.Dialer but has a timeout
// and reconstrcut the proxy dialer using that, in order to be able to
// set a timeout.
dd := &timeoutDirectDialer{
timeout: timeout,
}
// Check if the dialer we are getting is not timeoutDirectDialer we just
// created. It could happen that usingProxy is true, but getDialer
// returns timeoutDirectDialer due to env vars changing.
if timeoutProxyDialer := getDialer(dd); timeoutProxyDialer != dd {
directDialFunc := func(inetwork, iaddr string) (net.Conn, error) {
return net.DialTimeout(inetwork, iaddr, timeout)
}
return dialWithFallback(timeoutProxyDialer.Dial, directDialFunc, network, addr)
}
}
return net.DialTimeout(network, addr, timeout)
}

View File

@@ -44,6 +44,13 @@ type prioritizedAddress struct {
addr string
}
// An error may implement cachedError, in which case it will be interrogated
// to see how long we should cache the error. This overrides the default
// negative cache time.
type cachedError interface {
CacheFor() time.Duration
}
func NewCachingMux() *CachingMux {
return &CachingMux{
Supervisor: suture.NewSimple("discover.cachingMux"),
@@ -84,10 +91,11 @@ func (m *CachingMux) Lookup(deviceID protocol.DeviceID) (direct []string, relays
continue
}
if !cacheEntry.found && time.Since(cacheEntry.when) < finder.negCacheTime {
valid := time.Now().Before(cacheEntry.validUntil) || time.Since(cacheEntry.when) < finder.negCacheTime
if !cacheEntry.found && valid {
// It's a negative, valid entry. We should not make another
// attempt right now.
l.Debugln("negative cache entry for", deviceID, "at", finder)
l.Debugln("negative cache entry for", deviceID, "at", finder, "valid until", cacheEntry.when.Add(finder.negCacheTime), "or", cacheEntry.validUntil)
continue
}
@@ -111,10 +119,14 @@ func (m *CachingMux) Lookup(deviceID protocol.DeviceID) (direct []string, relays
})
} else {
// Lookup returned error, add a negative cache entry.
m.caches[i].Set(deviceID, CacheEntry{
entry := CacheEntry{
when: time.Now(),
found: false,
})
}
if err, ok := err.(cachedError); ok {
entry.validUntil = time.Now().Add(err.CacheFor())
}
m.caches[i].Set(deviceID, entry)
}
}
m.mut.Unlock()

View File

@@ -22,10 +22,11 @@ type Finder interface {
}
type CacheEntry struct {
Direct []string `json:"direct"`
Relays []Relay `json:"relays"`
when time.Time // When did we get the result
found bool // Is it a success (cacheTime applies) or a failure (negCacheTime applies)?
Direct []string `json:"direct"`
Relays []Relay `json:"relays"`
when time.Time // When did we get the result
found bool // Is it a success (cacheTime applies) or a failure (negCacheTime applies)?
validUntil time.Time // Validity time, overrides normal calculation
}
// A FinderService is a Finder that has background activity and must be run as

View File

@@ -56,6 +56,16 @@ type serverOptions struct {
id string // expected server device ID
}
// A lookupError is any other error but with a cache validity time attached.
type lookupError struct {
error
cacheFor time.Duration
}
func (e lookupError) CacheFor() time.Duration {
return e.cacheFor
}
func NewGlobal(server string, cert tls.Certificate, addrList AddressLister, relayStat RelayStatusProvider) (FinderService, error) {
server, opts, err := parseOptions(server)
if err != nil {
@@ -138,11 +148,16 @@ func (c *globalClient) Lookup(device protocol.DeviceID) (direct []string, relays
if resp.StatusCode != 200 {
resp.Body.Close()
l.Debugln("globalClient.Lookup", qURL, resp.Status)
return nil, nil, errors.New(resp.Status)
err := errors.New(resp.Status)
if secs, atoiErr := strconv.Atoi(resp.Header.Get("Retry-After")); atoiErr == nil && secs > 0 {
err = lookupError{
error: err,
cacheFor: time.Duration(secs) * time.Second,
}
}
return nil, nil, err
}
// TODO: Handle 429 and Retry-After?
var ann announcement
err = json.NewDecoder(resp.Body).Decode(&ann)
resp.Body.Close()

View File

@@ -1128,10 +1128,16 @@ func (m *Model) updateLocals(folder string, fs []protocol.FileInfo) {
m.fmut.RUnlock()
files.Update(protocol.LocalDeviceID, fs)
filenames := make([]string, len(fs))
for i, file := range fs {
filenames[i] = file.Name
}
events.Default.Log(events.LocalIndexUpdated, map[string]interface{}{
"folder": folder,
"items": len(fs),
"version": files.LocalVersion(protocol.LocalDeviceID),
"folder": folder,
"items": len(fs),
"filenames": filenames,
"version": files.LocalVersion(protocol.LocalDeviceID),
})
}

View File

@@ -716,6 +716,7 @@ func (p *rwFolder) deleteDir(file protocol.FileInfo) {
osutil.InWritableDir(osutil.Remove, filepath.Join(realName, file))
}
}
dir.Close()
}
err = osutil.InWritableDir(osutil.Remove, realName)

View File

@@ -139,7 +139,9 @@ func (s *sharedPullerState) tempFile() (io.WriterAt, error) {
return nil, err
}
if s.sparse {
// Don't truncate symlink files, as that will mean that the path will
// contain a bunch of nulls.
if s.sparse && !s.file.IsSymlink() {
// Truncate sets the size of the file. This creates a sparse file or a
// space reservation, depending on the underlying filesystem.
if err := fd.Truncate(s.file.Size()); err != nil {

View File

@@ -37,10 +37,13 @@ func CreateAtomic(path string, mode os.FileMode) (*AtomicWriter, error) {
return nil, err
}
if err := os.Chmod(fd.Name(), mode); err != nil {
fd.Close()
os.Remove(fd.Name())
return nil, err
// chmod fails on Android so don't even try
if runtime.GOOS != "android" {
if err := os.Chmod(fd.Name(), mode); err != nil {
fd.Close()
os.Remove(fd.Name())
return nil, err
}
}
w := &AtomicWriter{

View File

@@ -1152,10 +1152,7 @@ func (o *CloseMessage) DecodeXDRFrom(xr *xdr.Reader) error {
/*
EmptyMessage Structure:
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
(contains no fields)
struct EmptyMessage {
@@ -1164,27 +1161,19 @@ struct EmptyMessage {
*/
func (o EmptyMessage) EncodeXDR(w io.Writer) (int, error) {
var xw = xdr.NewWriter(w)
return o.EncodeXDRInto(xw)
return 0, nil
}
func (o EmptyMessage) MarshalXDR() ([]byte, error) {
return o.AppendXDR(make([]byte, 0, 128))
return nil, nil
}
func (o EmptyMessage) MustMarshalXDR() []byte {
bs, err := o.MarshalXDR()
if err != nil {
panic(err)
}
return bs
return nil
}
func (o EmptyMessage) AppendXDR(bs []byte) ([]byte, error) {
var aw = xdr.AppendWriter(bs)
var xw = xdr.NewWriter(&aw)
_, err := o.EncodeXDRInto(xw)
return []byte(aw), err
return bs, nil
}
func (o EmptyMessage) EncodeXDRInto(xw *xdr.Writer) (int, error) {
@@ -1192,14 +1181,11 @@ func (o EmptyMessage) EncodeXDRInto(xw *xdr.Writer) (int, error) {
}
func (o *EmptyMessage) DecodeXDR(r io.Reader) error {
xr := xdr.NewReader(r)
return o.DecodeXDRFrom(xr)
return nil
}
func (o *EmptyMessage) UnmarshalXDR(bs []byte) error {
var br = bytes.NewReader(bs)
var xr = xdr.NewReader(br)
return o.DecodeXDRFrom(xr)
return nil
}
func (o *EmptyMessage) DecodeXDRFrom(xr *xdr.Reader) error {

View File

@@ -11,7 +11,7 @@ import (
"github.com/syncthing/syncthing/lib/relay/protocol"
)
type relayClientFactory func(uri *url.URL, certs []tls.Certificate, invitations chan protocol.SessionInvitation) RelayClient
type relayClientFactory func(uri *url.URL, certs []tls.Certificate, invitations chan protocol.SessionInvitation, timeout time.Duration) RelayClient
var (
supportedSchemes = map[string]relayClientFactory{
@@ -31,11 +31,11 @@ type RelayClient interface {
URI() *url.URL
}
func NewClient(uri *url.URL, certs []tls.Certificate, invitations chan protocol.SessionInvitation) (RelayClient, error) {
func NewClient(uri *url.URL, certs []tls.Certificate, invitations chan protocol.SessionInvitation, timeout time.Duration) (RelayClient, error) {
factory, ok := supportedSchemes[uri.Scheme]
if !ok {
return nil, fmt.Errorf("Unsupported scheme: %s", uri.Scheme)
}
return factory(uri, certs, invitations), nil
return factory(uri, certs, invitations, timeout), nil
}

View File

@@ -22,13 +22,14 @@ type dynamicClient struct {
certs []tls.Certificate
invitations chan protocol.SessionInvitation
closeInvitationsOnFinish bool
timeout time.Duration
mut sync.RWMutex
client RelayClient
stop chan struct{}
}
func newDynamicClient(uri *url.URL, certs []tls.Certificate, invitations chan protocol.SessionInvitation) RelayClient {
func newDynamicClient(uri *url.URL, certs []tls.Certificate, invitations chan protocol.SessionInvitation, timeout time.Duration) RelayClient {
closeInvitationsOnFinish := false
if invitations == nil {
closeInvitationsOnFinish = true
@@ -39,6 +40,7 @@ func newDynamicClient(uri *url.URL, certs []tls.Certificate, invitations chan pr
certs: certs,
invitations: invitations,
closeInvitationsOnFinish: closeInvitationsOnFinish,
timeout: timeout,
mut: sync.NewRWMutex(),
}
@@ -94,7 +96,7 @@ func (c *dynamicClient) Serve() {
l.Debugln(c, "skipping relay", addr, err)
continue
}
client, err := NewClient(ruri, c.certs, c.invitations)
client, err := NewClient(ruri, c.certs, c.invitations, c.timeout)
if err != nil {
continue
}

View File

@@ -16,18 +16,18 @@ import (
"github.com/syncthing/syncthing/lib/relay/protocol"
)
func GetInvitationFromRelay(uri *url.URL, id syncthingprotocol.DeviceID, certs []tls.Certificate) (protocol.SessionInvitation, error) {
func GetInvitationFromRelay(uri *url.URL, id syncthingprotocol.DeviceID, certs []tls.Certificate, timeout time.Duration) (protocol.SessionInvitation, error) {
if uri.Scheme != "relay" {
return protocol.SessionInvitation{}, fmt.Errorf("Unsupported relay scheme: %v", uri.Scheme)
}
rconn, err := dialer.Dial("tcp", uri.Host)
rconn, err := dialer.DialTimeout("tcp", uri.Host, timeout)
if err != nil {
return protocol.SessionInvitation{}, err
}
conn := tls.Client(rconn, configForCerts(certs))
conn.SetDeadline(time.Now().Add(10 * time.Second))
conn.SetDeadline(time.Now().Add(timeout))
if err := performHandshakeAndValidation(conn, uri); err != nil {
return protocol.SessionInvitation{}, err
@@ -99,10 +99,10 @@ func JoinSession(invitation protocol.SessionInvitation) (net.Conn, error) {
}
}
func TestRelay(uri *url.URL, certs []tls.Certificate, sleep time.Duration, times int) bool {
func TestRelay(uri *url.URL, certs []tls.Certificate, sleep, timeout time.Duration, times int) bool {
id := syncthingprotocol.NewDeviceID(certs[0].Certificate[0])
invs := make(chan protocol.SessionInvitation, 1)
c, err := NewClient(uri, certs, invs)
c, err := NewClient(uri, certs, invs, timeout)
if err != nil {
close(invs)
return false
@@ -114,7 +114,7 @@ func TestRelay(uri *url.URL, certs []tls.Certificate, sleep time.Duration, times
}()
for i := 0; i < times; i++ {
_, err := GetInvitationFromRelay(uri, id, certs)
_, err := GetInvitationFromRelay(uri, id, certs, timeout)
if err == nil {
return true
}

View File

@@ -9,6 +9,7 @@ import (
"net/url"
"time"
"github.com/syncthing/syncthing/lib/dialer"
syncthingprotocol "github.com/syncthing/syncthing/lib/protocol"
"github.com/syncthing/syncthing/lib/relay/protocol"
"github.com/syncthing/syncthing/lib/sync"
@@ -22,7 +23,8 @@ type staticClient struct {
config *tls.Config
timeout time.Duration
messageTimeout time.Duration
connectTimeout time.Duration
stop chan struct{}
stopped chan struct{}
@@ -34,7 +36,7 @@ type staticClient struct {
latency time.Duration
}
func newStaticClient(uri *url.URL, certs []tls.Certificate, invitations chan protocol.SessionInvitation) RelayClient {
func newStaticClient(uri *url.URL, certs []tls.Certificate, invitations chan protocol.SessionInvitation, timeout time.Duration) RelayClient {
closeInvitationsOnFinish := false
if invitations == nil {
closeInvitationsOnFinish = true
@@ -49,7 +51,8 @@ func newStaticClient(uri *url.URL, certs []tls.Certificate, invitations chan pro
config: configForCerts(certs),
timeout: time.Minute * 2,
messageTimeout: time.Minute * 2,
connectTimeout: timeout,
stop: make(chan struct{}),
stopped: make(chan struct{}),
@@ -95,12 +98,12 @@ func (c *staticClient) Serve() {
go messageReader(c.conn, messages, errors)
timeout := time.NewTimer(c.timeout)
timeout := time.NewTimer(c.messageTimeout)
for {
select {
case message := <-messages:
timeout.Reset(c.timeout)
timeout.Reset(c.messageTimeout)
l.Debugf("%s received message %T", c, message)
switch msg := message.(type) {
@@ -187,7 +190,7 @@ func (c *staticClient) connect() error {
}
t0 := time.Now()
tcpConn, err := net.Dial("tcp", c.uri.Host)
tcpConn, err := dialer.DialTimeout("tcp", c.uri.Host, c.connectTimeout)
if err != nil {
return err
}
@@ -197,11 +200,8 @@ func (c *staticClient) connect() error {
c.mut.Unlock()
conn := tls.Client(tcpConn, c.config)
if err = conn.Handshake(); err != nil {
return err
}
if err := conn.SetDeadline(time.Now().Add(10 * time.Second)); err != nil {
if err := conn.SetDeadline(time.Now().Add(c.connectTimeout)); err != nil {
conn.Close()
return err
}

View File

@@ -86,10 +86,7 @@ func (o *header) DecodeXDRFrom(xr *xdr.Reader) error {
/*
Ping Structure:
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
(contains no fields)
struct Ping {
@@ -98,27 +95,19 @@ struct Ping {
*/
func (o Ping) EncodeXDR(w io.Writer) (int, error) {
var xw = xdr.NewWriter(w)
return o.EncodeXDRInto(xw)
return 0, nil
}
func (o Ping) MarshalXDR() ([]byte, error) {
return o.AppendXDR(make([]byte, 0, 128))
return nil, nil
}
func (o Ping) MustMarshalXDR() []byte {
bs, err := o.MarshalXDR()
if err != nil {
panic(err)
}
return bs
return nil
}
func (o Ping) AppendXDR(bs []byte) ([]byte, error) {
var aw = xdr.AppendWriter(bs)
var xw = xdr.NewWriter(&aw)
_, err := o.EncodeXDRInto(xw)
return []byte(aw), err
return bs, nil
}
func (o Ping) EncodeXDRInto(xw *xdr.Writer) (int, error) {
@@ -126,14 +115,11 @@ func (o Ping) EncodeXDRInto(xw *xdr.Writer) (int, error) {
}
func (o *Ping) DecodeXDR(r io.Reader) error {
xr := xdr.NewReader(r)
return o.DecodeXDRFrom(xr)
return nil
}
func (o *Ping) UnmarshalXDR(bs []byte) error {
var br = bytes.NewReader(bs)
var xr = xdr.NewReader(br)
return o.DecodeXDRFrom(xr)
return nil
}
func (o *Ping) DecodeXDRFrom(xr *xdr.Reader) error {
@@ -143,10 +129,7 @@ func (o *Ping) DecodeXDRFrom(xr *xdr.Reader) error {
/*
Pong Structure:
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
(contains no fields)
struct Pong {
@@ -155,27 +138,19 @@ struct Pong {
*/
func (o Pong) EncodeXDR(w io.Writer) (int, error) {
var xw = xdr.NewWriter(w)
return o.EncodeXDRInto(xw)
return 0, nil
}
func (o Pong) MarshalXDR() ([]byte, error) {
return o.AppendXDR(make([]byte, 0, 128))
return nil, nil
}
func (o Pong) MustMarshalXDR() []byte {
bs, err := o.MarshalXDR()
if err != nil {
panic(err)
}
return bs
return nil
}
func (o Pong) AppendXDR(bs []byte) ([]byte, error) {
var aw = xdr.AppendWriter(bs)
var xw = xdr.NewWriter(&aw)
_, err := o.EncodeXDRInto(xw)
return []byte(aw), err
return bs, nil
}
func (o Pong) EncodeXDRInto(xw *xdr.Writer) (int, error) {
@@ -183,14 +158,11 @@ func (o Pong) EncodeXDRInto(xw *xdr.Writer) (int, error) {
}
func (o *Pong) DecodeXDR(r io.Reader) error {
xr := xdr.NewReader(r)
return o.DecodeXDRFrom(xr)
return nil
}
func (o *Pong) UnmarshalXDR(bs []byte) error {
var br = bytes.NewReader(bs)
var xr = xdr.NewReader(br)
return o.DecodeXDRFrom(xr)
return nil
}
func (o *Pong) DecodeXDRFrom(xr *xdr.Reader) error {
@@ -200,10 +172,7 @@ func (o *Pong) DecodeXDRFrom(xr *xdr.Reader) error {
/*
JoinRelayRequest Structure:
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
(contains no fields)
struct JoinRelayRequest {
@@ -212,27 +181,19 @@ struct JoinRelayRequest {
*/
func (o JoinRelayRequest) EncodeXDR(w io.Writer) (int, error) {
var xw = xdr.NewWriter(w)
return o.EncodeXDRInto(xw)
return 0, nil
}
func (o JoinRelayRequest) MarshalXDR() ([]byte, error) {
return o.AppendXDR(make([]byte, 0, 128))
return nil, nil
}
func (o JoinRelayRequest) MustMarshalXDR() []byte {
bs, err := o.MarshalXDR()
if err != nil {
panic(err)
}
return bs
return nil
}
func (o JoinRelayRequest) AppendXDR(bs []byte) ([]byte, error) {
var aw = xdr.AppendWriter(bs)
var xw = xdr.NewWriter(&aw)
_, err := o.EncodeXDRInto(xw)
return []byte(aw), err
return bs, nil
}
func (o JoinRelayRequest) EncodeXDRInto(xw *xdr.Writer) (int, error) {
@@ -240,14 +201,11 @@ func (o JoinRelayRequest) EncodeXDRInto(xw *xdr.Writer) (int, error) {
}
func (o *JoinRelayRequest) DecodeXDR(r io.Reader) error {
xr := xdr.NewReader(r)
return o.DecodeXDRFrom(xr)
return nil
}
func (o *JoinRelayRequest) UnmarshalXDR(bs []byte) error {
var br = bytes.NewReader(bs)
var xr = xdr.NewReader(br)
return o.DecodeXDRFrom(xr)
return nil
}
func (o *JoinRelayRequest) DecodeXDRFrom(xr *xdr.Reader) error {
@@ -257,10 +215,7 @@ func (o *JoinRelayRequest) DecodeXDRFrom(xr *xdr.Reader) error {
/*
RelayFull Structure:
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
(contains no fields)
struct RelayFull {
@@ -269,27 +224,19 @@ struct RelayFull {
*/
func (o RelayFull) EncodeXDR(w io.Writer) (int, error) {
var xw = xdr.NewWriter(w)
return o.EncodeXDRInto(xw)
return 0, nil
}
func (o RelayFull) MarshalXDR() ([]byte, error) {
return o.AppendXDR(make([]byte, 0, 128))
return nil, nil
}
func (o RelayFull) MustMarshalXDR() []byte {
bs, err := o.MarshalXDR()
if err != nil {
panic(err)
}
return bs
return nil
}
func (o RelayFull) AppendXDR(bs []byte) ([]byte, error) {
var aw = xdr.AppendWriter(bs)
var xw = xdr.NewWriter(&aw)
_, err := o.EncodeXDRInto(xw)
return []byte(aw), err
return bs, nil
}
func (o RelayFull) EncodeXDRInto(xw *xdr.Writer) (int, error) {
@@ -297,14 +244,11 @@ func (o RelayFull) EncodeXDRInto(xw *xdr.Writer) (int, error) {
}
func (o *RelayFull) DecodeXDR(r io.Reader) error {
xr := xdr.NewReader(r)
return o.DecodeXDRFrom(xr)
return nil
}
func (o *RelayFull) UnmarshalXDR(bs []byte) error {
var br = bytes.NewReader(bs)
var xr = xdr.NewReader(br)
return o.DecodeXDRFrom(xr)
return nil
}
func (o *RelayFull) DecodeXDRFrom(xr *xdr.Reader) error {

View File

@@ -110,7 +110,7 @@ func (s *Svc) CommitConfiguration(from, to config.Configuration) bool {
_, ok := s.tokens[key]
if !ok {
l.Debugln("Connecting to relay", uri)
c, err := client.NewClient(uri, s.tlsCfg.Certificates, s.invitations)
c, err := client.NewClient(uri, s.tlsCfg.Certificates, s.invitations, 10*time.Second)
if err != nil {
l.Debugln("Failed to connect to relay", uri, err)
continue

View File

@@ -8,6 +8,8 @@ package tlsutil
import (
"bufio"
"crypto/ecdsa"
"crypto/elliptic"
"crypto/rand"
"crypto/rsa"
"crypto/tls"
@@ -27,8 +29,17 @@ var (
ErrIdentificationFailed = fmt.Errorf("failed to identify socket type")
)
// NewCertificate generates and returns a new TLS certificate. If tlsRSABits
// is greater than zero we generate an RSA certificate with the specified
// number of bits. Otherwise we create a 384 bit ECDSA certificate.
func NewCertificate(certFile, keyFile, tlsDefaultCommonName string, tlsRSABits int) (tls.Certificate, error) {
priv, err := rsa.GenerateKey(rand.Reader, tlsRSABits)
var priv interface{}
var err error
if tlsRSABits > 0 {
priv, err = rsa.GenerateKey(rand.Reader, tlsRSABits)
} else {
priv, err = ecdsa.GenerateKey(elliptic.P384(), rand.Reader)
}
if err != nil {
return tls.Certificate{}, fmt.Errorf("generate key: %s", err)
}
@@ -47,10 +58,9 @@ func NewCertificate(certFile, keyFile, tlsDefaultCommonName string, tlsRSABits i
KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature,
ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth, x509.ExtKeyUsageClientAuth},
BasicConstraintsValid: true,
SignatureAlgorithm: x509.SHA256WithRSA,
}
derBytes, err := x509.CreateCertificate(rand.Reader, &template, &template, &priv.PublicKey, priv)
derBytes, err := x509.CreateCertificate(rand.Reader, &template, &template, publicKey(priv), priv)
if err != nil {
return tls.Certificate{}, fmt.Errorf("create cert: %s", err)
}
@@ -72,7 +82,13 @@ func NewCertificate(certFile, keyFile, tlsDefaultCommonName string, tlsRSABits i
if err != nil {
return tls.Certificate{}, fmt.Errorf("save key: %s", err)
}
err = pem.Encode(keyOut, &pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(priv)})
block, err := pemBlockForKey(priv)
if err != nil {
return tls.Certificate{}, fmt.Errorf("save key: %s", err)
}
err = pem.Encode(keyOut, block)
if err != nil {
return tls.Certificate{}, fmt.Errorf("save key: %s", err)
}
@@ -136,3 +152,29 @@ type UnionedConnection struct {
func (c *UnionedConnection) Read(b []byte) (n int, err error) {
return c.Reader.Read(b)
}
func publicKey(priv interface{}) interface{} {
switch k := priv.(type) {
case *rsa.PrivateKey:
return &k.PublicKey
case *ecdsa.PrivateKey:
return &k.PublicKey
default:
return nil
}
}
func pemBlockForKey(priv interface{}) (*pem.Block, error) {
switch k := priv.(type) {
case *rsa.PrivateKey:
return &pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(k)}, nil
case *ecdsa.PrivateKey:
b, err := x509.MarshalECPrivateKey(k)
if err != nil {
return nil, err
}
return &pem.Block{Type: "EC PRIVATE KEY", Bytes: b}, nil
default:
return nil, fmt.Errorf("unknown key type")
}
}

View File

@@ -30,7 +30,8 @@ type Asset struct {
var (
ErrVersionUpToDate = errors.New("current version is up to date")
ErrVersionUnknown = errors.New("couldn't fetch release information")
ErrNoReleaseDownload = errors.New("couldn't find a release to download")
ErrNoVersionToSelect = errors.New("no version to select")
ErrUpgradeUnsupported = errors.New("upgrade unsupported")
ErrUpgradeInProgress = errors.New("upgrade already in progress")
upgradeUnlocked = make(chan bool, 1)

View File

@@ -47,22 +47,24 @@ var insecureHTTP = &http.Client{
},
}
// LatestGithubReleases returns the latest releases, including prereleases or
// FetchLatestReleases returns the latest releases, including prereleases or
// not depending on the argument
func LatestGithubReleases(releasesURL, version string) ([]Release, error) {
func FetchLatestReleases(releasesURL, version string) []Release {
resp, err := insecureHTTP.Get(releasesURL)
if err != nil {
return nil, err
l.Infoln("Couldn't fetch release information:", err)
return nil
}
if resp.StatusCode > 299 {
return nil, fmt.Errorf("API call returned HTTP error: %s", resp.Status)
l.Infoln("API call returned HTTP error: %s", resp.Status)
return nil
}
var rels []Release
json.NewDecoder(resp.Body).Decode(&rels)
resp.Body.Close()
return rels, nil
return rels
}
type SortByRelease []Release
@@ -78,13 +80,13 @@ func (s SortByRelease) Less(i, j int) bool {
}
func LatestRelease(releasesURL, version string) (Release, error) {
rels, _ := LatestGithubReleases(releasesURL, version)
rels := FetchLatestReleases(releasesURL, version)
return SelectLatestRelease(version, rels)
}
func SelectLatestRelease(version string, rels []Release) (Release, error) {
if len(rels) == 0 {
return Release{}, ErrVersionUnknown
return Release{}, ErrNoVersionToSelect
}
sort.Sort(SortByRelease(rels))
@@ -106,7 +108,7 @@ func SelectLatestRelease(version string, rels []Release) (Release, error) {
}
}
}
return Release{}, ErrVersionUnknown
return Release{}, ErrNoReleaseDownload
}
// Upgrade to the given release, saving the previous binary with a ".old" extension.
@@ -122,7 +124,7 @@ func upgradeTo(binary string, rel Release) error {
}
}
return ErrVersionUnknown
return ErrNoReleaseDownload
}
// Upgrade to the given release, saving the previous binary with a ".old" extension.

View File

@@ -15,6 +15,7 @@ pages=(
syncthing-bep.7
syncthing-localdisco.7
syncthing-globaldisco.7
syncthing-relay.7
)
for page in "${pages[@]}" ; do

View File

@@ -1,6 +1,6 @@
.\" Man page generated from reStructuredText.
.
.TH "SYNCTHING-BEP" "7" "November 21, 2015" "v0.12" "Syncthing"
.TH "SYNCTHING-BEP" "7" "December 01, 2015" "v0.12" "Syncthing"
.SH NAME
syncthing-bep \- Block Exchange Protocol v1
.

View File

@@ -1,6 +1,6 @@
.\" Man page generated from reStructuredText.
.
.TH "SYNCTHING-CONFIG" "5" "November 21, 2015" "v0.12" "Syncthing"
.TH "SYNCTHING-CONFIG" "5" "December 01, 2015" "v0.12" "Syncthing"
.SH NAME
syncthing-config \- Syncthing Configuration
.

View File

@@ -1,6 +1,6 @@
.\" Man page generated from reStructuredText.
.
.TH "SYNCTHING-DEVICE-IDS" "7" "November 21, 2015" "v0.12" "Syncthing"
.TH "SYNCTHING-DEVICE-IDS" "7" "December 01, 2015" "v0.12" "Syncthing"
.SH NAME
syncthing-device-ids \- Understanding Device IDs
.

View File

@@ -1,6 +1,6 @@
.\" Man page generated from reStructuredText.
.
.TH "SYNCTHING-EVENT-API" "7" "November 21, 2015" "v0.12" "Syncthing"
.TH "SYNCTHING-EVENT-API" "7" "December 01, 2015" "v0.12" "Syncthing"
.SH NAME
syncthing-event-api \- Event API
.

View File

@@ -1,6 +1,6 @@
.\" Man page generated from reStructuredText.
.
.TH "SYNCTHING-FAQ" "7" "November 21, 2015" "v0.12" "Syncthing"
.TH "SYNCTHING-FAQ" "7" "December 01, 2015" "v0.12" "Syncthing"
.SH NAME
syncthing-faq \- Frequently Asked Questions
.

View File

@@ -1,6 +1,6 @@
.\" Man page generated from reStructuredText.
.
.TH "SYNCTHING-GLOBALDISCO" "7" "November 21, 2015" "v0.12" "Syncthing"
.TH "SYNCTHING-GLOBALDISCO" "7" "December 01, 2015" "v0.12" "Syncthing"
.SH NAME
syncthing-globaldisco \- Global Discovery Protocol v3
.

View File

@@ -1,6 +1,6 @@
.\" Man page generated from reStructuredText.
.
.TH "SYNCTHING-LOCALDISCO" "7" "November 21, 2015" "v0.12" "Syncthing"
.TH "SYNCTHING-LOCALDISCO" "7" "December 01, 2015" "v0.12" "Syncthing"
.SH NAME
syncthing-localdisco \- Local Discovery Protocol v3
.

View File

@@ -1,6 +1,6 @@
.\" Man page generated from reStructuredText.
.
.TH "SYNCTHING-NETWORKING" "7" "November 21, 2015" "v0.12" "Syncthing"
.TH "SYNCTHING-NETWORKING" "7" "December 01, 2015" "v0.12" "Syncthing"
.SH NAME
syncthing-networking \- Firewall Setup
.

7
man/syncthing-relay.7 Normal file
View File

@@ -0,0 +1,7 @@
<html>
<head><title>404 Not Found</title></head>
<body bgcolor="white">
<center><h1>404 Not Found</h1></center>
<hr><center>nginx/1.7.4</center>
</body>
</html>

View File

@@ -1,6 +1,6 @@
.\" Man page generated from reStructuredText.
.
.TH "SYNCTHING-REST-API" "7" "November 21, 2015" "v0.12" "Syncthing"
.TH "SYNCTHING-REST-API" "7" "December 01, 2015" "v0.12" "Syncthing"
.SH NAME
syncthing-rest-api \- REST API
.
@@ -199,7 +199,7 @@ for config and db:
.sp
.nf
.ft C
$ curl \-H X\-API\-Key:abc123 \-X POST \(aqhttp://localhost:8385/rest/system/debug?disable=beacon,discovery&enable=config,db\(aq
$ curl \-H X\-API\-Key:abc123 \-X POST \(aqhttp://localhost:8384/rest/system/debug?disable=beacon,discovery&enable=config,db\(aq
.ft P
.fi
.UNINDENT

View File

@@ -1,6 +1,6 @@
.\" Man page generated from reStructuredText.
.
.TH "SYNCTHING-SECURITY" "7" "November 21, 2015" "v0.12" "Syncthing"
.TH "SYNCTHING-SECURITY" "7" "December 01, 2015" "v0.12" "Syncthing"
.SH NAME
syncthing-security \- Security Principles
.
@@ -132,6 +132,22 @@ NSA or someone else) will be able to see that you use Syncthing, and your device
ID\(aqs \fI\%are OK to share anyway\fP <\fBhttp://docs.syncthing.net/users/faq.html#should-i-keep-my-device-ids-secret\fP>,
but the actual transmitted data is protected as well as we can. Knowing your
device ID can expose your IP address, using global discovery.
.SH PROTECTING YOUR SYNCTHING KEYS AND IDENTITY
.sp
Anyone who can access the Syncthing TLS keys and config file on your device can
impersonate your device, connect to your peers, and then have access to your
synced files. Here are some general principles to protect your files:
.INDENT 0.0
.IP 1. 3
If a device of yours is lost, make sure to revoke its access from your other
devices.
.UNINDENT
.INDENT 0.0
.IP 2. 3
If you\(aqre syncing confidential data on an encrypted disk to guard against
device theft, put the Syncthing config folder on the same encrypted disk to
avoid leaking keys and metadata. Or, use whole disk encryption.
.UNINDENT
.SH AUTHOR
The Syncthing Authors
.SH COPYRIGHT

View File

@@ -1,6 +1,6 @@
.\" Man page generated from reStructuredText.
.
.TH "SYNCTHING-STIGNORE" "5" "November 21, 2015" "v0.12" "Syncthing"
.TH "SYNCTHING-STIGNORE" "5" "December 01, 2015" "v0.12" "Syncthing"
.SH NAME
syncthing-stignore \- Prevent files from being synchronized to other nodes
.
@@ -93,7 +93,8 @@ matching. \fB(?i)test\fP matches \fBtest\fP, \fBTEST\fP and \fBtEsT\fP\&. The
\fB(?i)\fP prefix can be combined with other patterns, for example the
pattern \fB(?i)!picture*.png\fP indicates that \fBPicture1.PNG\fP should
be synchronized. Note that case\-insensitive patterns must start with
\fB(?i)\fP when combined with other flags. On Mac OS and Windows, patterns are always case\-insensitive.
\fB(?i)\fP when combined with other flags. On Mac OS and Windows,
patterns are always case\-insensitive.
.IP \(bu 2
A line beginning with \fB//\fP is a comment and has no effect.
.UNINDENT
@@ -180,17 +181,16 @@ Assume two nodes, Alice and Bob, where Alice has 100 files to share, but
Bob ignores 25 of these. From Alice\(aqs point of view Bob will become
about 75% in sync (the actual number depends on the sizes of the
individual files) and remain in "Syncing" state even though it is in
fact not syncing anything (\fI\%issue #623\fP <\fBhttps://github.com/syncthing/syncthing/issues/623\fP>). From
Bob\(aqs point of view it\(aqs 100% up to date but will show fewer files in
both the local and global view.
fact not syncing anything (\fI\%issue #623\fP <\fBhttps://github.com/syncthing/syncthing/issues/623\fP>). From Bob\(aqs point of view, it\(aqs
100% up to date but will show fewer files in both the local and global
view.
.sp
If Bob adds files that have already been synced to the ignore list, they
will remain in the "global" view but disappear from the "local" view.
The end result is more files in the global repository than in the local,
but still 100% in sync (\fI\%issue #624\fP <\fBhttps://github.com/syncthing/syncthing/issues/624\fP>). From
Alice\(aqs point of view, Bob will remain 100% in sync until the next
reconnect, because Bob has already announce that he has the files that
are now suddenly ignored.
but still 100% in sync (\fI\%issue #624\fP <\fBhttps://github.com/syncthing/syncthing/issues/624\fP>). From Alice\(aqs point of view, Bob
will remain 100% in sync until the next reconnect, because Bob has
already announced that he has the files that are now suddenly ignored.
.SH AUTHOR
The Syncthing Authors
.SH COPYRIGHT

View File

@@ -1,6 +1,6 @@
.\" Man page generated from reStructuredText.
.
.TH "TODO" "7" "November 21, 2015" "v0.12" "Syncthing"
.TH "TODO" "7" "December 01, 2015" "v0.12" "Syncthing"
.SH NAME
Todo \- Keep automatic backups of deleted files by other nodes
.

View File

@@ -1,6 +1,6 @@
.\" Man page generated from reStructuredText.
.
.TH "SYNCTHING" "1" "November 21, 2015" "v0.12" "Syncthing"
.TH "SYNCTHING" "1" "December 01, 2015" "v0.12" "Syncthing"
.SH NAME
syncthing \- Syncthing
.
@@ -36,8 +36,7 @@ level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
.sp
.nf
.ft C
syncthing [\-audit] [\-generate=<dir>] [\-gui\-address=<address>]
[\-gui\-apikey=<key>] [\-gui\-authentication=<username:password>]
syncthing [\-audit] [\-generate=<dir>] [\-gui\-address=<address>] [\-gui\-apikey=<key>]
[\-home=<dir>] [\-logfile=<filename>] [\-logflags=<flags>] [\-no\-browser]
[\-no\-console] [\-no\-restart] [\-reset] [\-upgrade] [\-upgrade\-check]
[\-upgrade\-to=<url>] [\-verbose] [\-version]
@@ -76,11 +75,6 @@ Override GUI API key.
.UNINDENT
.INDENT 0.0
.TP
.B \-gui\-authentication=<username:password>
Override GUI authentication; username:password.
.UNINDENT
.INDENT 0.0
.TP
.B \-home=<dir>
Set configuration directory. The default configuration directory is:
\fB$HOME/.config/syncthing\fP\&.

View File

@@ -1,7 +1,7 @@
<configuration version="12">
<folder id="default" path="s1/" ro="false" rescanIntervalS="10" ignorePerms="false" autoNormalize="true">
<device id="I6KAH76-66SLLLB-5PFXSOA-UFJCDZC-YAOMLEK-CP2GB32-BV5RQST-3PSROAU"></device>
<device id="JMFJCXB-GZDE4BN-OCJE3VF-65GYZNU-AIVJRET-3J6HMRQ-AUQIGJO-FKNHMQU"></device>
<device id="MRIW7OK-NETT3M4-N6SBWME-N25O76W-YJKVXPH-FUMQJ3S-P57B74J-GBITBAC"></device>
<device id="373HSRP-QLPNLIE-JYKZVQF-P4PKZ63-R2ZE6K3-YD442U2-JHBGBQG-WWXAHAU"></device>
<device id="7PBCTLL-JJRYBSA-MOWZRKL-MSDMN4N-4US4OMX-SYEXUS4-HSBGNRY-CZXRXAT"></device>
<minDiskFreePct>1</minDiskFreePct>
@@ -18,7 +18,7 @@
</folder>
<folder id="¯\_(ツ)_/¯ Räksmörgås 动作 Адрес" path="s12-1/" ro="false" rescanIntervalS="10" ignorePerms="false" autoNormalize="true">
<device id="I6KAH76-66SLLLB-5PFXSOA-UFJCDZC-YAOMLEK-CP2GB32-BV5RQST-3PSROAU"></device>
<device id="JMFJCXB-GZDE4BN-OCJE3VF-65GYZNU-AIVJRET-3J6HMRQ-AUQIGJO-FKNHMQU"></device>
<device id="MRIW7OK-NETT3M4-N6SBWME-N25O76W-YJKVXPH-FUMQJ3S-P57B74J-GBITBAC"></device>
<minDiskFreePct>1</minDiskFreePct>
<versioning></versioning>
<copiers>1</copiers>
@@ -37,7 +37,7 @@
<device id="I6KAH76-66SLLLB-5PFXSOA-UFJCDZC-YAOMLEK-CP2GB32-BV5RQST-3PSROAU" name="s1" compression="metadata" introducer="false">
<address>tcp://127.0.0.1:22001</address>
</device>
<device id="JMFJCXB-GZDE4BN-OCJE3VF-65GYZNU-AIVJRET-3J6HMRQ-AUQIGJO-FKNHMQU" name="s2" compression="metadata" introducer="false">
<device id="MRIW7OK-NETT3M4-N6SBWME-N25O76W-YJKVXPH-FUMQJ3S-P57B74J-GBITBAC" name="s2" compression="metadata" introducer="false">
<address>tcp://127.0.0.1:22002</address>
</device>
<device id="373HSRP-QLPNLIE-JYKZVQF-P4PKZ63-R2ZE6K3-YD442U2-JHBGBQG-WWXAHAU" name="s3" compression="metadata" introducer="false">

View File

@@ -1,23 +1,11 @@
-----BEGIN CERTIFICATE-----
MIID3jCCAkigAwIBAgIBADALBgkqhkiG9w0BAQUwFDESMBAGA1UEAxMJc3luY3Ro
aW5nMB4XDTE0MDMxNDA3MDEwNFoXDTQ5MTIzMTIzNTk1OVowFDESMBAGA1UEAxMJ
c3luY3RoaW5nMIIBojANBgkqhkiG9w0BAQEFAAOCAY8AMIIBigKCAYEAsIV0syyR
O56BvIOro4bIqB6iFJsNc4zX8MiM4QPTWgqGlYwsKSVmNppTdlACZCJIqyzoscrF
qJPto8/e2Fc3oaTdEREGIs7cmc7LSXfot/mAgPpy71SVWtb7xNmXro2JJPZjRBCS
pl1ulPug+/8w7fSKQdLMjh4Hp2YlwVBfVu0bYEEW+7Vl9PZVTv+NbTqXYvYVc9R6
QFIbN/njWAuo2wpjJlY7vqNnSYZyskAaaAC17fFJkVQKKblTeTk1C9PxTmVTB1j9
yOoD3+V/6IrTYKXdTHGJ1MqdieTHj1jHXe5TOeSB+Hjgq4tr25mPfQ4ixXqDqIcx
5390DAjInuSKNUJ5pqiFrVe9eIDmySZCg5/JIL3c8phy6g1bxiJN14+Dn0om/0+9
UrHK8LVzWMmtFRVycWVUYmARWFY3EE10k0RXU2HtzmjfnBkRrl13b0ExizlA1qJ3
3ngxF5rNEDSMpwf4og5uYOjRUPYuvCL9XtQKr254NFO/sg/qqPV4hFWTAgMBAAGj
PzA9MA4GA1UdDwEB/wQEAwIAoDAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUH
AwIwDAYDVR0TAQH/BAIwADALBgkqhkiG9w0BAQUDggGBAAZSU08zAzyuGqKqqU/c
Pr+xML8oKiJqko5pb3ETDQC+uVw+qUHwiGYsvHI1cih4ix+tKvf+Yaiizp/35VkP
qwls3a4ljq1Ww0Sf7J87QX0DumYpBGOfoCpmV4MacyjLhpLRKRGZHwIbOeFsmEu9
oO38co+GvDy4CiAt3tuOdjBNs0gNOAdTTxqgm97raB9oXeg2i4Fb4MCT4UBUdXLM
ZNLCifza+PWkBxmfBORvlKGeJBruLpXHBWnWEigZSLXIFjn3JJUy4fKd+/JMp063
8Pjo6zUOckBCH8Lv90vzfrmdlQK555jWpcebN0l9neESEXw19l0OlqkJGVTr6JKq
w5kjiL4eP7kpKKwCezhDSX3jf4P36wdF8MpOUBxVqfM+Oh5tHIcZctnurhYV7rXs
jR70FMqWjHBmwemsXGrObNVt8c75yB+19U6DAulr2RhRw5GD74U1znP00eGZ8TJf
RN1FYilUPCawMYeQoB8WIn9So7zIm0MfOl4KXNWDX02+Kw==
MIIBmzCCASCgAwIBAgIIawvqtXNSqBQwCgYIKoZIzj0EAwMwFDESMBAGA1UEAxMJ
c3luY3RoaW5nMB4XDTE1MTEyNzA4MDA1N1oXDTQ5MTIzMTIzNTk1OVowFDESMBAG
A1UEAxMJc3luY3RoaW5nMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAE7iI2E5etAs53
6s+SUV3HKZeK55iHUY6X4PHePjyvNxOCZ6GvbErOXWqumU4+vzVREW1wvNtGXAtv
z/hsHIPJ7EdKIX0QPATms2NplCbaFlUxHBpUzhlNulhsoV5ajn7yoz8wPTAOBgNV
HQ8BAf8EBAMCBaAwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMAwGA1Ud
EwEB/wQCMAAwCgYIKoZIzj0EAwMDaQAwZgIxAPe+pj6NrQiK720v/9IMDPWIRxqt
hxgy03YGzbQskXRDJVvLU49HCHV+8JNL6WwgKgIxALA+RdYb0qDxhcdtt57Zu3A1
eQZEvsJg9FGJOjYDnxZYqEpNZSgTwgcRvGH1Srt37w==
-----END CERTIFICATE-----

View File

@@ -1,7 +1,7 @@
<configuration version="12">
<folder id="default" path="s2/" ro="false" rescanIntervalS="15" ignorePerms="false" autoNormalize="true">
<device id="I6KAH76-66SLLLB-5PFXSOA-UFJCDZC-YAOMLEK-CP2GB32-BV5RQST-3PSROAU"></device>
<device id="JMFJCXB-GZDE4BN-OCJE3VF-65GYZNU-AIVJRET-3J6HMRQ-AUQIGJO-FKNHMQU"></device>
<device id="MRIW7OK-NETT3M4-N6SBWME-N25O76W-YJKVXPH-FUMQJ3S-P57B74J-GBITBAC"></device>
<device id="373HSRP-QLPNLIE-JYKZVQF-P4PKZ63-R2ZE6K3-YD442U2-JHBGBQG-WWXAHAU"></device>
<minDiskFreePct>1</minDiskFreePct>
<versioning type="trashcan">
@@ -16,10 +16,11 @@
<pullerSleepS>0</pullerSleepS>
<pullerPauseS>0</pullerPauseS>
<maxConflicts>-1</maxConflicts>
<disableSparseFiles>false</disableSparseFiles>
</folder>
<folder id="¯\_(ツ)_/¯ Räksmörgås 动作 Адрес" path="s12-2/" ro="false" rescanIntervalS="15" ignorePerms="false" autoNormalize="true">
<device id="I6KAH76-66SLLLB-5PFXSOA-UFJCDZC-YAOMLEK-CP2GB32-BV5RQST-3PSROAU"></device>
<device id="JMFJCXB-GZDE4BN-OCJE3VF-65GYZNU-AIVJRET-3J6HMRQ-AUQIGJO-FKNHMQU"></device>
<device id="MRIW7OK-NETT3M4-N6SBWME-N25O76W-YJKVXPH-FUMQJ3S-P57B74J-GBITBAC"></device>
<minDiskFreePct>1</minDiskFreePct>
<versioning></versioning>
<copiers>1</copiers>
@@ -31,9 +32,10 @@
<pullerSleepS>0</pullerSleepS>
<pullerPauseS>0</pullerPauseS>
<maxConflicts>-1</maxConflicts>
<disableSparseFiles>false</disableSparseFiles>
</folder>
<folder id="s23" path="s23-2/" ro="false" rescanIntervalS="15" ignorePerms="false" autoNormalize="true">
<device id="JMFJCXB-GZDE4BN-OCJE3VF-65GYZNU-AIVJRET-3J6HMRQ-AUQIGJO-FKNHMQU"></device>
<device id="MRIW7OK-NETT3M4-N6SBWME-N25O76W-YJKVXPH-FUMQJ3S-P57B74J-GBITBAC"></device>
<device id="373HSRP-QLPNLIE-JYKZVQF-P4PKZ63-R2ZE6K3-YD442U2-JHBGBQG-WWXAHAU"></device>
<minDiskFreePct>1</minDiskFreePct>
<versioning></versioning>
@@ -46,11 +48,12 @@
<pullerSleepS>0</pullerSleepS>
<pullerPauseS>0</pullerPauseS>
<maxConflicts>-1</maxConflicts>
<disableSparseFiles>false</disableSparseFiles>
</folder>
<device id="I6KAH76-66SLLLB-5PFXSOA-UFJCDZC-YAOMLEK-CP2GB32-BV5RQST-3PSROAU" name="s1" compression="metadata" introducer="false">
<address>tcp://127.0.0.1:22001</address>
</device>
<device id="JMFJCXB-GZDE4BN-OCJE3VF-65GYZNU-AIVJRET-3J6HMRQ-AUQIGJO-FKNHMQU" name="s2" compression="metadata" introducer="false">
<device id="MRIW7OK-NETT3M4-N6SBWME-N25O76W-YJKVXPH-FUMQJ3S-P57B74J-GBITBAC" name="s2" compression="metadata" introducer="false">
<address>tcp://127.0.0.1:22002</address>
</device>
<device id="373HSRP-QLPNLIE-JYKZVQF-P4PKZ63-R2ZE6K3-YD442U2-JHBGBQG-WWXAHAU" name="s3" compression="metadata" introducer="false">
@@ -91,7 +94,6 @@
<progressUpdateIntervalS>5</progressUpdateIntervalS>
<symlinksEnabled>true</symlinksEnabled>
<limitBandwidthInLan>false</limitBandwidthInLan>
<databaseBlockCacheMiB>0</databaseBlockCacheMiB>
<minHomeDiskFreePct>1</minHomeDiskFreePct>
<releasesURL>https://api.github.com/repos/syncthing/syncthing/releases?per_page=30</releasesURL>
</options>

View File

@@ -1,23 +1,18 @@
-----BEGIN CERTIFICATE-----
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
vqe+Ym0B+xIRsfn0FApfVUqZkA==
-----END CERTIFICATE-----

View File

@@ -1,39 +1,27 @@
-----BEGIN RSA PRIVATE KEY-----
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
-----END RSA PRIVATE KEY-----

View File

@@ -1,39 +1,6 @@
-----BEGIN RSA PRIVATE KEY-----
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
-----END RSA PRIVATE KEY-----
-----BEGIN EC PRIVATE KEY-----
MIGkAgEBBDBz4/RQhZfObYcjS4t5bZthw0Pj6YliqI357mdB6hfiQgMdTB8v7jnO
Scbil+Rri0+gBwYFK4EEACKhZANiAATuIjYTl60Cznfqz5JRXccpl4rnmIdRjpfg
8d4+PK83E4Jnoa9sSs5daq6ZTj6/NVERbXC820ZcC2/P+Gwcg8nsR0ohfRA8BOaz
Y2mUJtoWVTEcGlTOGU26WGyhXlqOfvI=
-----END EC PRIVATE KEY-----

View File

@@ -1,6 +1,6 @@
<configuration version="12">
<folder id="s23" path="s23-3/" ro="false" rescanIntervalS="20" ignorePerms="false" autoNormalize="true">
<device id="JMFJCXB-GZDE4BN-OCJE3VF-65GYZNU-AIVJRET-3J6HMRQ-AUQIGJO-FKNHMQU"></device>
<device id="MRIW7OK-NETT3M4-N6SBWME-N25O76W-YJKVXPH-FUMQJ3S-P57B74J-GBITBAC"></device>
<device id="373HSRP-QLPNLIE-JYKZVQF-P4PKZ63-R2ZE6K3-YD442U2-JHBGBQG-WWXAHAU"></device>
<minDiskFreePct>1</minDiskFreePct>
<versioning></versioning>
@@ -16,7 +16,7 @@
</folder>
<folder id="default" path="s3/" ro="false" rescanIntervalS="20" ignorePerms="false" autoNormalize="true">
<device id="I6KAH76-66SLLLB-5PFXSOA-UFJCDZC-YAOMLEK-CP2GB32-BV5RQST-3PSROAU"></device>
<device id="JMFJCXB-GZDE4BN-OCJE3VF-65GYZNU-AIVJRET-3J6HMRQ-AUQIGJO-FKNHMQU"></device>
<device id="MRIW7OK-NETT3M4-N6SBWME-N25O76W-YJKVXPH-FUMQJ3S-P57B74J-GBITBAC"></device>
<device id="373HSRP-QLPNLIE-JYKZVQF-P4PKZ63-R2ZE6K3-YD442U2-JHBGBQG-WWXAHAU"></device>
<minDiskFreePct>1</minDiskFreePct>
<versioning type="simple">
@@ -35,7 +35,7 @@
<device id="I6KAH76-66SLLLB-5PFXSOA-UFJCDZC-YAOMLEK-CP2GB32-BV5RQST-3PSROAU" name="s1" compression="metadata" introducer="false">
<address>tcp://127.0.0.1:22001</address>
</device>
<device id="JMFJCXB-GZDE4BN-OCJE3VF-65GYZNU-AIVJRET-3J6HMRQ-AUQIGJO-FKNHMQU" name="s2" compression="metadata" introducer="false">
<device id="MRIW7OK-NETT3M4-N6SBWME-N25O76W-YJKVXPH-FUMQJ3S-P57B74J-GBITBAC" name="s2" compression="metadata" introducer="false">
<address>tcp://127.0.0.1:22002</address>
</device>
<device id="373HSRP-QLPNLIE-JYKZVQF-P4PKZ63-R2ZE6K3-YD442U2-JHBGBQG-WWXAHAU" name="s3" compression="metadata" introducer="false">

View File

@@ -37,7 +37,7 @@ func init() {
const (
id1 = "I6KAH76-66SLLLB-5PFXSOA-UFJCDZC-YAOMLEK-CP2GB32-BV5RQST-3PSROAU"
id2 = "JMFJCXB-GZDE4BN-OCJE3VF-65GYZNU-AIVJRET-3J6HMRQ-AUQIGJO-FKNHMQU"
id2 = "MRIW7OK-NETT3M4-N6SBWME-N25O76W-YJKVXPH-FUMQJ3S-P57B74J-GBITBAC"
id3 = "373HSRP-QLPNLIE-JYKZVQF-P4PKZ63-R2ZE6K3-YD442U2-JHBGBQG-WWXAHAU"
apiKey = "abc123"
)