Add sync reset key bridge

This commit is contained in:
2026-06-27 18:46:05 +08:00
parent a2791c494f
commit 35012025b6
7 changed files with 113 additions and 1 deletions
+36
View File
@@ -1550,6 +1550,8 @@ func (a *App) syncStatus() (*SyncStatusDTO, error) {
dto.StatusLabel = "connected"
case dto.Configured:
dto.StatusLabel = "disconnected"
case dto.ServerURL != "":
dto.StatusLabel = "disconnected"
default:
dto.StatusLabel = "disabled"
}
@@ -1699,6 +1701,40 @@ func (a *App) PluginSyncSetInterval(pluginID string, minutes int) string {
return ""
}
func (a *App) syncResetKey() error {
if err := a.requireVault(); err != nil {
return err
}
vaultPath := a.vaultPath()
if err := syncsvc.RemoveDeviceToken(vaultPath); err != nil && !os.IsNotExist(err) {
return err
}
cfg := a.appSettings.Get()
cfg.Sync.Enabled = false
cfg.Sync.DeviceID = ""
cfg.Sync.DeviceName = ""
cfg.Sync.LastStatus = "disconnected"
cfg.Sync.LastError = ""
if a.syncSvc != nil {
if err := a.syncSvc.SetState(cfg.Sync.ServerURL, ""); err != nil {
return err
}
}
return a.appSettings.UpdateSync(cfg.Sync)
}
// PluginSyncResetKey clears the stored sync device token for a plugin with sync permission.
func (a *App) PluginSyncResetKey(pluginID string) string {
if err := a.requirePluginSyncAccess(pluginID, false); err != nil {
return err.Error()
}
if err := a.syncResetKey(); err != nil {
return err.Error()
}
return ""
}
func (a *App) syncNow() (map[string]interface{}, error) {
if err := a.requireVault(); err != nil {
return nil, err
+42
View File
@@ -1270,6 +1270,48 @@ func TestPluginSyncBridgeRequiresDeclaredPermissions(t *testing.T) {
if _, errStr := app.PluginSyncNow("sync.local"); !strings.Contains(errStr, "network.remote") {
t.Fatalf("PluginSyncNow err = %q, want network.remote permission error", errStr)
}
app.syncSvc = syncsvc.NewService(app.vaultPath(), "local-device")
app.appSettings = appsettings.NewManager(filepath.Join(t.TempDir(), "config.json"))
if err := app.appSettings.Load(); err != nil {
t.Fatalf("settings Load: %v", err)
}
cfg := app.appSettings.Get()
cfg.Sync.Enabled = true
cfg.Sync.ServerURL = "https://sync.example.test"
cfg.Sync.DeviceID = "device-1"
cfg.Sync.DeviceName = "test-device"
cfg.Sync.LastStatus = "connected"
if err := app.appSettings.UpdateSync(cfg.Sync); err != nil {
t.Fatalf("settings UpdateSync: %v", err)
}
if err := syncsvc.SaveDeviceToken(app.vaultPath(), "secret-token"); err != nil {
t.Fatalf("SaveDeviceToken: %v", err)
}
if errStr := app.PluginSyncResetKey("sync.local"); errStr != "" {
t.Fatalf("PluginSyncResetKey: %s", errStr)
}
if token := syncsvc.LoadDeviceToken(app.vaultPath()); token != "" {
t.Fatalf("device token = %q, want cleared", token)
}
cfg = app.appSettings.Get()
if cfg.Sync.DeviceID != "" || cfg.Sync.DeviceName != "" || cfg.Sync.LastStatus != "disconnected" {
t.Fatalf("sync settings after reset = %#v, want cleared device and disconnected status", cfg.Sync)
}
if cfg.Sync.ServerURL != "https://sync.example.test" {
t.Fatalf("server URL = %q, want preserved", cfg.Sync.ServerURL)
}
status, errStr = app.PluginSyncStatus("sync.local")
if errStr != "" {
t.Fatalf("PluginSyncStatus after reset: %s", errStr)
}
if status.Configured || status.ServerURL != "https://sync.example.test" || status.StatusLabel != "disconnected" {
t.Fatalf("status after reset = %#v, want server preserved, not configured, disconnected", status)
}
if errStr := app.PluginSyncResetKey("no.storage"); !strings.Contains(errStr, "sync.participate") {
t.Fatalf("PluginSyncResetKey err = %q, want sync.participate permission error", errStr)
}
}
func TestPluginBridgeCapabilitiesCommandsAndEventsAreChecked(t *testing.T) {