Skip to content

Commit dad92ed

Browse files
committed
fix(relay): accept whitespace-prefixed stored JSON (#161)
Select the stored format from a whitespace-trimmed view while decoding the original JSON value, and align the changelog with Relay device-ID and provisioning terminology. What could go wrong and why this is safe: valid JSON with leading whitespace could otherwise be mistaken for a legacy identifier and block Relay work. The change affects format selection only; every decoded member still passes canonical validation, malformed reads remain fail-closed, and no rewrite, delete, or provisioning path is added.
1 parent cc6b92e commit dad92ed

3 files changed

Lines changed: 15 additions & 2 deletions

File tree

CHANGELOG.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ All notable changes to VaultSync are documented here.
1212

1313
### Fixed
1414

15-
- **Cloud Relay no longer continues from invalid saved server identities** ([#161](https://github.com/psimaker/vaultsync/issues/161)) — if secure storage contains a malformed server identifier, VaultSync reports that registration did not complete and sends no registration request, without rewriting or deleting the stored value. Valid existing JSON and legacy records remain unchanged.
15+
- **Cloud Relay no longer continues from malformed saved Relay device IDs** ([#161](https://github.com/psimaker/vaultsync/issues/161)) — VaultSync reports that Cloud Relay provisioning did not complete and sends no provisioning request, without rewriting or deleting the stored value. Valid existing JSON and legacy records remain unchanged.
1616
- **Push and Cloud Relay registration details now survive failed secure-storage updates** ([#148](https://github.com/psimaker/vaultsync/issues/148)) — VaultSync keeps the last valid value when a replacement cannot be saved and reports the failure instead of continuing as if registration succeeded.
1717
- **Folder access now stays intact when reconnecting or syncing in the background** ([#147](https://github.com/psimaker/vaultsync/issues/147)) — reselecting the same Obsidian folder no longer accumulates access claims. Switching folders takes effect only after the new location is readable, scanned, and its permission is saved; any failure keeps the previous folder connected. Background runs release only their own access on completion, restart, or cancellation.
1818
- **Background sync no longer reports unfinished work as completed** ([#146](https://github.com/psimaker/vaultsync/issues/146)) — continued processing now reports success only after every expected vault is confirmed fully idle. If the sync engine stops, vault status cannot be read, a vault reports an error, the run expires or is cancelled, or the app returns to the foreground, the background run reports failure instead; conflict checks happen only after idle is proven.

ios/VaultSync/Services/SubscriptionManager.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,7 @@ enum RelayDeviceIDStorage {
118118

119119
static func decodeStoredValue(_ stored: String) -> LoadResult {
120120
let ids: [String]
121-
if stored.hasPrefix("[") {
121+
if stored.trimmingCharacters(in: .whitespacesAndNewlines).hasPrefix("[") {
122122
guard let data = stored.data(using: .utf8),
123123
let decoded = try? JSONDecoder().decode([String].self, from: data) else {
124124
return .failed

ios/VaultSyncTests/KeychainServiceTests.swift

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -402,6 +402,19 @@ struct RelayDeviceIDStorageTests {
402402
]))
403403
}
404404

405+
@Test("Valid JSON with leading whitespace loads unchanged (#161)")
406+
func issue161WhitespacePrefixedJSONStorageLoads() throws {
407+
let stored = " \n\t" + (try Self.json([
408+
Self.firstValidDeviceID,
409+
Self.secondValidDeviceID,
410+
]))
411+
412+
#expect(RelayDeviceIDStorage.decodeStoredValue(stored) == .loaded([
413+
Self.firstValidDeviceID,
414+
Self.secondValidDeviceID,
415+
]))
416+
}
417+
405418
@Test("A JSON array containing only an invalid device ID fails closed (#161)")
406419
func issue161InvalidJSONMemberFailsClosed() throws {
407420
let stored = try Self.json([Self.invalidDeviceID])

0 commit comments

Comments
 (0)