mirror of
https://github.com/vrtmrz/obsidian-livesync.git
synced 2026-05-11 18:21:50 +00:00
Compare commits
1 Commits
feat-userh
...
p2p-rpc
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a6be20695a |
2
src/lib
2
src/lib
Submodule src/lib updated: 16ed161ffa...6a2dc6777f
@@ -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");
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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();
|
||||
});
|
||||
});
|
||||
|
||||
23
updates.md
23
updates.md
@@ -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
30
vitest.config.rpc-unit.ts
Normal 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,
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
);
|
||||
Reference in New Issue
Block a user