Compare commits

..

1 Commits

Author SHA1 Message Date
vorotamoroz
a6be20695a feat: use new p2p-rpc wrapper 2026-05-11 03:49:35 +01:00
6 changed files with 35 additions and 105 deletions

Submodule src/lib updated: 16ed161ffa...6a2dc6777f

View File

@@ -6,7 +6,6 @@ import {
SuffixDatabaseName,
} from "../../../lib/src/common/types.ts";
import { Logger } from "../../../lib/src/common/logger.ts";
import { generateUserHashSalt } from "../../../lib/src/common/utils.ts";
import { LiveSyncSetting as Setting } from "./LiveSyncSetting.ts";
import type { ObsidianLiveSyncSettingTab } from "./ObsidianLiveSyncSettingTab.ts";
import type { PageFunctions } from "./SettingPane.ts";
@@ -157,42 +156,6 @@ export function panePatches(this: ObsidianLiveSyncSettingTab, paneEl: HTMLElemen
await this.core.localDatabase._prepareHashFunctions();
});
});
void addPanel(paneEl, "Chunk ID Namespace").then((paneEl) => {
paneEl.createDiv({
text: "Manage the Chunk ID Namespace Salt (userHashSalt). This value is used as a seed for generating chunk IDs. If you change this value, chunk IDs will be regenerated and you must rebuild the database.",
cls: "op-warn-info",
});
new Setting(paneEl)
.autoWireText("userHashSalt", { holdValue: true })
.setClass("wizardHidden")
.addApplyButton(["userHashSalt"]);
new Setting(paneEl)
.setName("Generate New Salt")
.setDesc(
"Generate a new random salt for the Chunk ID namespace. After generating, a database rebuild is strongly recommended."
)
.addButton((button) => {
button
.setButtonText("Generate New Salt")
.setCta()
.onClick(async () => {
const confirmed = await this.core.confirm.askYesNo(
"Generating a new salt will invalidate existing chunk IDs. Until you rebuild the database, deduplication will be inefficient. Are you sure to generate a new salt now?"
);
if (confirmed) {
const newSalt = generateUserHashSalt();
this.editingSettings.userHashSalt = newSalt;
await this.saveSettings(["userHashSalt"]);
Logger(`New Chunk ID Namespace Salt generated.`, LOG_LEVEL_NOTICE);
this.requestUpdate();
}
});
});
});
void addPanel(paneEl, "Edge case addressing (Behaviour)").then((paneEl) => {
new Setting(paneEl).autoWireToggle("doNotSuspendOnFetching");
new Setting(paneEl).setClass("wizardHidden").autoWireToggle("doNotDeleteFolder");

View File

@@ -7,7 +7,7 @@ import {
REMOTE_MINIO,
REMOTE_P2P,
} from "../../lib/src/common/types.ts";
import { generatePatchObj, isObjectDifferent, generateUserHashSalt } from "../../lib/src/common/utils.ts";
import { generatePatchObj, isObjectDifferent } from "../../lib/src/common/utils.ts";
import Intro from "./SetupWizard/dialogs/Intro.svelte";
import SelectMethodNewUser from "./SetupWizard/dialogs/SelectMethodNewUser.svelte";
import SelectMethodExisting from "./SetupWizard/dialogs/SelectMethodExisting.svelte";
@@ -328,9 +328,6 @@ export class SetupManager extends AbstractModule {
}
if (confirm) {
extra();
if (userMode === UserMode.NewUser && !newConf.userHashSalt) {
newConf.userHashSalt = generateUserHashSalt();
}
await this.applySetting(newConf, userMode);
if (userMode === UserMode.NewUser) {
// For new users, schedule a rebuild everything.

View File

@@ -154,47 +154,4 @@ describe("SetupManager", () => {
);
expect(setting.currentSettings().activeConfigurationId).toBe("legacy-couchdb");
});
it("onConfirmApplySettingsFromWizard should generate userHashSalt for NewUser when absent", async () => {
const { manager, setting, dialogManager, core } = createSetupManager();
const randomSpy = vi.spyOn(globalThis.crypto, "getRandomValues").mockImplementation((array) => {
const target = array as Uint8Array;
for (let i = 0; i < target.length; i++) {
target[i] = 0xab;
}
return array;
});
dialogManager.openWithExplicitCancel.mockResolvedValueOnce(true);
await manager.onConfirmApplySettingsFromWizard(
{
...setting.currentSettings(),
userHashSalt: "",
},
UserMode.NewUser
);
expect(setting.currentSettings().userHashSalt).toBe("abababababababababababababababab");
expect(core.rebuilder.scheduleRebuild).toHaveBeenCalledTimes(1);
randomSpy.mockRestore();
});
it("onConfirmApplySettingsFromWizard should keep existing userHashSalt for NewUser", async () => {
const { manager, setting, dialogManager, core } = createSetupManager();
const randomSpy = vi.spyOn(globalThis.crypto, "getRandomValues");
dialogManager.openWithExplicitCancel.mockResolvedValueOnce(true);
await manager.onConfirmApplySettingsFromWizard(
{
...setting.currentSettings(),
userHashSalt: "00112233445566778899aabbccddeeff",
},
UserMode.NewUser
);
expect(setting.currentSettings().userHashSalt).toBe("00112233445566778899aabbccddeeff");
expect(randomSpy).not.toHaveBeenCalled();
expect(core.rebuilder.scheduleRebuild).toHaveBeenCalledTimes(1);
randomSpy.mockRestore();
});
});

View File

@@ -5,27 +5,10 @@ The head note of 0.25 is now in [updates_old.md](https://github.com/vrtmrz/obsid
## Unreleased
### Improved
### P2P Synchronisation
- Chunk ID namespace is now separated from the E2EE passphrase by introducing `userHashSalt`.
- Chunk ID hashing now prefers `userHashSalt` when present, and falls back to the legacy passphrase-derived seed for compatibility.
- New setup now generates `userHashSalt` automatically if it is missing.
- `rebuildEverything` now generates `userHashSalt` only when it is missing, as a migration path for existing vaults.
- Setup URI / QR settings round-trip now preserves `userHashSalt`.
### Behaviour and safety
- `userHashSalt` has been added to tweak-value mismatch detection so devices can notice and resolve mismatched chunk-ID namespace settings.
- `userHashSalt` mismatch is treated as compatible but potentially lossy (inefficient), not hard-incompatible.
- Mismatch dialogues now mask `userHashSalt` values to avoid exposing the raw value in UI.
### Tests
- Added and updated unit tests for:
- `HashManager` (`userHashSalt` priority and differing-salt behaviour).
- `SetupManager` (generation only when missing, preserving existing value).
- `Rebuilder` (generation only when missing, no regeneration when present).
- `processSetting` setup URI round-trip and secure-field handling.
Now the foundation for P2P synchronisation has been rewritten, and the unit tests have been added. The foundation has been separated into the transport layer, signalling-and-connection layer, and, an RPC layers. And each layer has been unit-tested. As the result, the P2P synchronisation now uses the robust shim that uses RPC-ed PouchDB synchronisation in contrast to previous implementation.
This P2P synchronisation is not compatible with previous versions in terms of connectivity. All devices must be updated.
## 0.25.60

30
vitest.config.rpc-unit.ts Normal file
View File

@@ -0,0 +1,30 @@
import { defineConfig, mergeConfig } from "vitest/config";
import viteConfig from "./vitest.config.common";
export default mergeConfig(
viteConfig,
defineConfig({
resolve: {
alias: {
obsidian: "",
},
},
test: {
name: "rpc-unit-tests",
include: ["src/lib/src/rpc/**/*.unit.spec.ts"],
exclude: ["test/**"],
coverage: {
include: ["src/lib/src/rpc/**/*.ts"],
exclude: ["**/*.unit.spec.ts", "**/index.ts"],
provider: "v8",
reporter: ["text", "json", "html", ["text", { file: "coverage-rpc-text.txt" }]],
thresholds: {
lines: 90,
functions: 90,
branches: 75,
statements: 90,
},
},
},
})
);