mirror of
https://github.com/vrtmrz/obsidian-livesync.git
synced 2026-10-21 16:52:32 +00:00
Preserve adopted encryption settings when prerequisites change
This commit is contained in:
@@ -69,8 +69,10 @@ Central replication can assess an effective value which differs from a saved
|
|||||||
preference, such as internal Metadata encryption whose prerequisites are inactive.
|
preference, such as internal Metadata encryption whose prerequisites are inactive.
|
||||||
Recovery accepts the current saved or effective snapshot without treating that
|
Recovery accepts the current saved or effective snapshot without treating that
|
||||||
representation difference as a settings change. Applying assessed changes retains
|
representation difference as a settings change. Applying assessed changes retains
|
||||||
saved preferences for settings whose effective values already agree. The full
|
saved preferences only when they leave the adopted effective values unchanged.
|
||||||
settings signature still detects a preference changed while awaiting a decision.
|
If adoption activates encryption prerequisites, the adopted encryption value
|
||||||
|
takes precedence. The full settings signature still detects a preference changed
|
||||||
|
while awaiting a decision.
|
||||||
|
|
||||||
The active publication reservation is not held while waiting for the dialogue.
|
The active publication reservation is not held while waiting for the dialogue.
|
||||||
Remote writes use the failed attempt's publication guard. Fetch and Rebuild use
|
Remote writes use the failed attempt's publication guard. Fetch and Rebuild use
|
||||||
|
|||||||
@@ -215,8 +215,17 @@ export class ModuleResolvingMismatchedTweaks extends AbstractModule {
|
|||||||
): Promise<[TweakValues | boolean, boolean]> {
|
): Promise<[TweakValues | boolean, boolean]> {
|
||||||
if (assessment.alignment === "matched") return [false, false];
|
if (assessment.alignment === "matched") return [false, false];
|
||||||
if (this.requiresIdConfigurationReview(assessment)) return [false, false];
|
if (this.requiresIdConfigurationReview(assessment)) return [false, false];
|
||||||
// Retain saved preferences when only their effective representation differs from the assessment.
|
// Retain saved preferences only when they leave the adopted effective values unchanged.
|
||||||
|
const assessedSettings = settingsAfterAdoption(assessment, "adoptPreferred");
|
||||||
const acceptedSettings = settingsAfterAdoption(assessment, "adoptPreferred", this.settings);
|
const acceptedSettings = settingsAfterAdoption(assessment, "adoptPreferred", this.settings);
|
||||||
|
if (
|
||||||
|
this.settings.remoteType === REMOTE_COUCHDB &&
|
||||||
|
usesEncryptedInternalMetadata({ ...this.settings, ...acceptedSettings }) !==
|
||||||
|
usesEncryptedInternalMetadata({ ...this.settings, ...assessedSettings })
|
||||||
|
) {
|
||||||
|
// Adopting encryption prerequisites can activate a previously inactive preference.
|
||||||
|
acceptedSettings.encryptInternalMetadata = assessedSettings.encryptInternalMetadata;
|
||||||
|
}
|
||||||
const autoAcceptSide = await this._shouldAutoAcceptCompatibleLossy(assessment);
|
const autoAcceptSide = await this._shouldAutoAcceptCompatibleLossy(assessment);
|
||||||
if (autoAcceptSide === "REMOTE") return [acceptedSettings, false];
|
if (autoAcceptSide === "REMOTE") return [acceptedSettings, false];
|
||||||
if (autoAcceptSide === "CURRENT") return [true, false];
|
if (autoAcceptSide === "CURRENT") return [true, false];
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ import {
|
|||||||
CENTRAL_COMPATIBILITY_REJECTION_REASONS,
|
CENTRAL_COMPATIBILITY_REJECTION_REASONS,
|
||||||
REMOTE_RESOURCE_KINDS,
|
REMOTE_RESOURCE_KINDS,
|
||||||
USER_INITIATED_REPLICATION_AUTHORITY,
|
USER_INITIATED_REPLICATION_AUTHORITY,
|
||||||
|
usesEncryptedInternalMetadata,
|
||||||
type ReplicationAttemptFailure,
|
type ReplicationAttemptFailure,
|
||||||
} from "@vrtmrz/livesync-commonlib/replication";
|
} from "@vrtmrz/livesync-commonlib/replication";
|
||||||
|
|
||||||
@@ -74,6 +75,46 @@ function createModule(settingsOverride: Partial<typeof DEFAULT_SETTINGS> = {}) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
describe("ModuleResolvingMismatchedTweaks", () => {
|
describe("ModuleResolvingMismatchedTweaks", () => {
|
||||||
|
it.each([
|
||||||
|
{ label: "E2EE", encrypt: false, usePathObfuscation: true },
|
||||||
|
{ label: "Property Encryption", encrypt: true, usePathObfuscation: false },
|
||||||
|
])(
|
||||||
|
"uses the remote Metadata encryption preference when adoption enables $label",
|
||||||
|
async ({ encrypt, usePathObfuscation }) => {
|
||||||
|
const { module, core, askSelectStringDialogue } = createModule({
|
||||||
|
autoAcceptCompatibleTweak: false,
|
||||||
|
encrypt,
|
||||||
|
usePathObfuscation,
|
||||||
|
E2EEAlgorithm: "v2",
|
||||||
|
encryptInternalMetadata: true,
|
||||||
|
idDerivationVersion: 0,
|
||||||
|
});
|
||||||
|
const current = {
|
||||||
|
...extractObject(TweakValuesTemplate, core.settings),
|
||||||
|
encryptInternalMetadata: usesEncryptedInternalMetadata(core.settings),
|
||||||
|
};
|
||||||
|
const preferred = { ...current, encrypt: true, usePathObfuscation: true, encryptInternalMetadata: false };
|
||||||
|
const assessment = assessTweakCompatibility(current, preferred);
|
||||||
|
core._services.tweakValue = {
|
||||||
|
checkAndAskResolvingMismatched: module._checkAndAskResolvingMismatchedTweaks.bind(module),
|
||||||
|
};
|
||||||
|
core.rebuilder = { $fetchLocal: vi.fn(async () => undefined) };
|
||||||
|
askSelectStringDialogue.mockResolvedValueOnce("Apply settings to this device, and fetch again");
|
||||||
|
const updateRemote = vi.fn(async () => true);
|
||||||
|
|
||||||
|
await expect(module._askResolvingMismatchedTweaks(preferred, updateRemote, assessment)).resolves.toBe(
|
||||||
|
"CHECKAGAIN"
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(core.rebuilder.$fetchLocal).toHaveBeenCalledOnce();
|
||||||
|
expect(core.settings).toMatchObject({ encrypt: true, usePathObfuscation: true });
|
||||||
|
expect(usesEncryptedInternalMetadata(core.settings)).toBe(false);
|
||||||
|
expect(updateRemote).toHaveBeenCalledWith(
|
||||||
|
expect.objectContaining({ encrypt: true, usePathObfuscation: true, encryptInternalMetadata: false })
|
||||||
|
);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
it.each([
|
it.each([
|
||||||
{ label: "automatic alignment with E2EE disabled", autoAcceptCompatibleTweak: true, encrypt: false },
|
{ label: "automatic alignment with E2EE disabled", autoAcceptCompatibleTweak: true, encrypt: false },
|
||||||
{ label: "manual review with E2EE disabled", autoAcceptCompatibleTweak: false, encrypt: false },
|
{ label: "manual review with E2EE disabled", autoAcceptCompatibleTweak: false, encrypt: false },
|
||||||
|
|||||||
Reference in New Issue
Block a user