From 932b4ce9bd800da26e63111c99f877bef92d9504 Mon Sep 17 00:00:00 2001 From: Jakob Borg Date: Tue, 23 Sep 2025 14:16:58 +0300 Subject: [PATCH] fix(model): don't announce untrusted devices to other devices (fixes #10393) (#10408) fix(model): don't announce untrusted devices to other devices Signed-off-by: Jakob Borg --- lib/model/model.go | 11 +++++- lib/model/model_test.go | 78 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 88 insertions(+), 1 deletion(-) diff --git a/lib/model/model.go b/lib/model/model.go index 0bc0a12c1..46c188841 100644 --- a/lib/model/model.go +++ b/lib/model/model.go @@ -2615,6 +2615,7 @@ func (m *model) generateClusterConfigRLocked(device protocol.DeviceID) (*protoco protocolFolder.StopReason = protocol.FolderStopReasonPaused } + nextDevice: for _, folderDevice := range folderCfg.Devices { deviceCfg, _ := m.cfg.Device(folderDevice.DeviceID) @@ -2630,9 +2631,17 @@ func (m *model) generateClusterConfigRLocked(device protocol.DeviceID) (*protoco if deviceCfg.DeviceID == m.id && hasEncryptionToken { protocolDevice.EncryptionPasswordToken = encryptionToken } else if folderDevice.EncryptionPassword != "" { - protocolDevice.EncryptionPasswordToken = protocol.PasswordToken(m.keyGen, folderCfg.ID, folderDevice.EncryptionPassword) + // For encrypted/untrusted devices we send the encryption + // token and prepare the password. We do not send any + // information about untrusted devices to _other_ devices, + // as they are not normal peers sharing the folder and we + // don't want things like the introducer features to kick in + // for them. if folderDevice.DeviceID == device { + protocolDevice.EncryptionPasswordToken = protocol.PasswordToken(m.keyGen, folderCfg.ID, folderDevice.EncryptionPassword) passwords[folderCfg.ID] = folderDevice.EncryptionPassword + } else { + continue nextDevice } } diff --git a/lib/model/model_test.go b/lib/model/model_test.go index c4e6df377..fa152902d 100644 --- a/lib/model/model_test.go +++ b/lib/model/model_test.go @@ -474,6 +474,84 @@ func TestClusterConfig(t *testing.T) { } } +func TestClusterConfigEncrypted(t *testing.T) { + t.Parallel() + + cfg := config.New(device1) + cfg.Options.MinHomeDiskFree.Value = 0 // avoids unnecessary free space checks + cfg.Devices = []config.DeviceConfiguration{ + { + DeviceID: device1, + }, + { + DeviceID: device2, + }, + } + cfg.Folders = []config.FolderConfiguration{ + { + FilesystemType: config.FilesystemTypeFake, + ID: "folder1", + Path: "testdata1", + Devices: []config.FolderDeviceConfiguration{ + {DeviceID: device1, EncryptionPassword: "trololol"}, // not included, untrusted + {DeviceID: device2}, + }, + }, + { + FilesystemType: config.FilesystemTypeFake, + ID: "folder2", + Path: "testdata2", + Devices: []config.FolderDeviceConfiguration{ + {DeviceID: device1, EncryptionPassword: "trololol"}, // not included, untrusted + {DeviceID: device2, EncryptionPassword: "trololol"}, // included, is destinationd device + }, + }, + { + FilesystemType: config.FilesystemTypeFake, + ID: "folder3", + Path: "testdata3", + Devices: []config.FolderDeviceConfiguration{ + {DeviceID: device1}, + // should not be included, does not include device2 + }, + }, + } + + wrapper, cancel := newConfigWrapper(cfg) + defer cancel() + m := newModel(t, wrapper, myID, nil) + m.ServeBackground() + defer cleanupModel(m) + + cm, _ := m.generateClusterConfig(device2) + + if l := len(cm.Folders); l != 2 { + t.Fatalf("Incorrect number of folders %d != 2", l) + } + + r := cm.Folders[0] + if r.ID != "folder1" { + t.Errorf("Incorrect folder %q != folder1", r.ID) + } + if l := len(r.Devices); l != 1 { + t.Errorf("Incorrect number of devices %d != 1", l) + } + if id := r.Devices[0].ID; id != device2 { + t.Errorf("Incorrect device ID %s != %s", id, device2) + } + + r = cm.Folders[1] + if r.ID != "folder2" { + t.Errorf("Incorrect folder %q != folder2", r.ID) + } + if l := len(r.Devices); l != 1 { + t.Errorf("Incorrect number of devices %d != 1", l) + } + if id := r.Devices[0].ID; id != device2 { + t.Errorf("Incorrect device ID %s != %s", id, device2) + } +} + func TestIntroducer(t *testing.T) { var introducedByAnyone protocol.DeviceID