Repository: syncthing/syncthing
File: lib/model/model.go (Go)

Code before:
		}

		m.fmut.RLock()
		fs, ok := m.folderFiles[folder.ID]
		m.fmut.RUnlock()
		if !ok {
			// Shouldn't happen because !cfg.Paused, but might happen
			// if the folder is about to be unpaused, but not yet.
			l.Debugln("ccH: no fset", folder.ID)
			indexSenders.addPending(cfg, ccDeviceInfos[folder.ID])
			continue
		}

		indexSenders.add(cfg, fs, ccDeviceInfos[folder.ID])

		// We might already have files that we need to pull so let the
		// folder runner know that it should recheck the index data.
		m.fmut.RLock()
		if runner := m.folderRunners[folder.ID]; runner != nil {
			defer runner.SchedulePull()
		}
		m.fmut.RUnlock()
	}

	indexSenders.removeAllExcept(seenFolders)
	if expired, err := m.db.ExpirePendingFolders(deviceID, handleTime); err != nil {
		l.Infof("Could not clean up pending folder entries: %v", err)
	} else if expired > 0 {
		m.evLogger.Log(events.FolderOfferCancelled, map[string]interface{}{
			"device": deviceID.String(),
			"count":  expired,
		})
	}

	return changed, tempIndexFolders, paused, nil
}

func (m *model) ccCheckEncryption(fcfg config.FolderConfiguration, folderDevice config.FolderDeviceConfiguration, ccDeviceInfos *indexSenderStartInfo, deviceUntrusted bool) error {
	hasTokenRemote := len(ccDeviceInfos.remote.EncryptionPasswordToken) > 0
	hasTokenLocal := len(ccDeviceInfos.local.EncryptionPasswordToken) > 0
	isEncryptedRemote := folderDevice.EncryptionPassword != ""
	isEncryptedLocal := fcfg.Type == config.FolderTypeReceiveEncrypted

	if !isEncryptedRemote && !isEncryptedLocal && deviceUntrusted {
		return errEncryptionNotEncryptedUntrusted
	}

	if !(hasTokenRemote || hasTokenLocal || isEncryptedRemote || isEncryptedLocal) {
		// Noone cares about encryption here
		return nil
	}

Review comment (bug):
I don't like this mechanism, as it's not obvious from this what gets added or removed.
I think you should explicitly, check what's in the CC, check what's in the database, get a list of what needs to be removed, remove it, potentially debug log it.

Now it's some sort of magical "now" value that goes in, and magic happens underneath, with no clarify what effect that has.

Code after:

		if folder.Paused {
			indexSenders.remove(folder.ID)
			paused[cfg.ID] = struct{}{}
			continue
		}

		if cfg.Paused {
			indexSenders.addPending(cfg, ccDeviceInfos[folder.ID])
			continue
		}

		if err := m.ccCheckEncryption(cfg, folderDevice, ccDeviceInfos[folder.ID], deviceCfg.Untrusted); err != nil {
			sameError := false
			if devs, ok := m.folderEncryptionFailures[folder.ID]; ok {
				sameError = devs[deviceID] == err
			} else {
				m.folderEncryptionFailures[folder.ID] = make(map[protocol.DeviceID]error)
			}
			m.folderEncryptionFailures[folder.ID][deviceID] = err
			msg := fmt.Sprintf("Failure checking encryption consistency with device %v for folder %v: %v", deviceID, cfg.Description(), err)
			if sameError || err == errEncryptionReceivedToken {
				l.Debugln(msg)
			} else {
				l.Warnln(msg)
			}

			return tempIndexFolders, paused, err
		}
		if devErrs, ok := m.folderEncryptionFailures[folder.ID]; ok {
			if len(devErrs) == 1 {
				delete(m.folderEncryptionFailures, folder.ID)
			} else {
				delete(m.folderEncryptionFailures[folder.ID], deviceID)
			}
		}

		// Handle indexes

		if !folder.DisableTempIndexes {
			tempIndexFolders = append(tempIndexFolders, folder.ID)
		}

		m.fmut.RLock()
		fs, ok := m.folderFiles[folder.ID]
		m.fmut.RUnlock()
		if !ok {
			// Shouldn't happen because !cfg.Paused, but might happen
			// if the folder is about to be unpaused, but not yet.
			l.Debugln("ccH: no fset", folder.ID)
			indexSenders.addPending(cfg, ccDeviceInfos[folder.ID])