diff --git a/packages/desktop/app/javascripts/Main/FileBackups/FileBackupsManager.ts b/packages/desktop/app/javascripts/Main/FileBackups/FileBackupsManager.ts index 988827040..25108f095 100644 --- a/packages/desktop/app/javascripts/Main/FileBackups/FileBackupsManager.ts +++ b/packages/desktop/app/javascripts/Main/FileBackups/FileBackupsManager.ts @@ -62,6 +62,10 @@ export class FilesBackupManager implements FileBackupsDevice { return uuid } + async joinPaths(...paths: string[]): Promise { + return path.join(...paths) + } + public async migrateLegacyFileBackupsToNewStructure(newLocation: string): Promise { const legacyLocation = await this.getLegacyFilesBackupsLocation() if (!legacyLocation) { diff --git a/packages/desktop/app/javascripts/Main/Remote/RemoteBridge.ts b/packages/desktop/app/javascripts/Main/Remote/RemoteBridge.ts index 2e120e8a6..a60af3fcf 100644 --- a/packages/desktop/app/javascripts/Main/Remote/RemoteBridge.ts +++ b/packages/desktop/app/javascripts/Main/Remote/RemoteBridge.ts @@ -76,6 +76,7 @@ export class RemoteBridge implements CrossProcessBridge { migrateLegacyFileBackupsToNewStructure: this.migrateLegacyFileBackupsToNewStructure.bind(this), getUserDocumentsDirectory: this.getUserDocumentsDirectory.bind(this), monitorPlaintextBackupsLocationForChanges: this.monitorPlaintextBackupsLocationForChanges.bind(this), + joinPaths: this.joinPaths.bind(this), } } @@ -235,6 +236,10 @@ export class RemoteBridge implements CrossProcessBridge { return this.fileBackups.monitorPlaintextBackupsLocationForChanges(backupsDirectory) } + joinPaths(...paths: string[]): Promise { + return this.fileBackups.joinPaths(...paths) + } + askForMediaAccess(type: 'camera' | 'microphone'): Promise { return this.media.askForMediaAccess(type) } diff --git a/packages/desktop/app/javascripts/Renderer/DesktopDevice.ts b/packages/desktop/app/javascripts/Renderer/DesktopDevice.ts index 9c04b6491..4408535b5 100644 --- a/packages/desktop/app/javascripts/Renderer/DesktopDevice.ts +++ b/packages/desktop/app/javascripts/Renderer/DesktopDevice.ts @@ -153,6 +153,10 @@ export class DesktopDevice extends WebOrDesktopDevice implements DesktopDeviceIn return this.remoteBridge.monitorPlaintextBackupsLocationForChanges(backupsDirectory) } + joinPaths(...paths: string[]): Promise { + return this.remoteBridge.joinPaths(...paths) + } + async performHardReset(): Promise { console.error('performHardReset is not yet implemented') } diff --git a/packages/files/src/Domain/Device/FileBackupsDevice.ts b/packages/files/src/Domain/Device/FileBackupsDevice.ts index 72fafdbaf..70b4eaf80 100644 --- a/packages/files/src/Domain/Device/FileBackupsDevice.ts +++ b/packages/files/src/Domain/Device/FileBackupsDevice.ts @@ -19,6 +19,8 @@ export interface FileBackupsDevice TextBackupsMethods { openLocation(path: string): Promise + joinPaths(...paths: string[]): Promise + /** * The reason we combine presenting a directory picker and transfering old files to the new location * in one function is so we don't have to expose a general `transferDirectories` function to the web app, diff --git a/packages/files/src/Domain/Service/BackupServiceInterface.ts b/packages/files/src/Domain/Service/BackupServiceInterface.ts index 9453bcfd6..18663ebdd 100644 --- a/packages/files/src/Domain/Service/BackupServiceInterface.ts +++ b/packages/files/src/Domain/Service/BackupServiceInterface.ts @@ -5,7 +5,7 @@ import { SuperConverterServiceInterface } from './SuperConverterServiceInterface export interface BackupServiceInterface { openAllDirectoriesContainingBackupFiles(): void - prependWorkspacePathForPath(path: string): string + prependWorkspacePathForPath(path: string): Promise importWatchedDirectoryChanges(changes: DesktopWatchedDirectoriesChanges): Promise setSuperConverter(converter: SuperConverterServiceInterface): void diff --git a/packages/services/src/Domain/Backups/BackupService.ts b/packages/services/src/Domain/Backups/BackupService.ts index e5f7ce28c..ccf5d1c81 100644 --- a/packages/services/src/Domain/Backups/BackupService.ts +++ b/packages/services/src/Domain/Backups/BackupService.ts @@ -184,17 +184,17 @@ export class FilesBackupService extends AbstractService implements BackupService return this.storage.getValue(StorageKey.TextBackupsEnabled, undefined, true) } - prependWorkspacePathForPath(path: string): string { + async prependWorkspacePathForPath(path: string): Promise { const workspacePath = this.session.getWorkspaceDisplayIdentifier() - return `${workspacePath}/${path}` + return this.device.joinPaths(workspacePath, path) } async enableTextBackups(): Promise { let location = this.getTextBackupsLocation() if (!location) { location = await this.device.presentDirectoryPickerForLocationChangeAndTransferOld( - this.prependWorkspacePathForPath(TextBackupsDirectoryName), + await this.prependWorkspacePathForPath(TextBackupsDirectoryName), ) if (!location) { return @@ -223,7 +223,7 @@ export class FilesBackupService extends AbstractService implements BackupService async changeTextBackupsLocation(): Promise { const oldLocation = this.getTextBackupsLocation() const newLocation = await this.device.presentDirectoryPickerForLocationChangeAndTransferOld( - this.prependWorkspacePathForPath(TextBackupsDirectoryName), + await this.prependWorkspacePathForPath(TextBackupsDirectoryName), oldLocation, ) @@ -253,7 +253,7 @@ export class FilesBackupService extends AbstractService implements BackupService let location = this.getPlaintextBackupsLocation() if (!location) { location = await this.device.presentDirectoryPickerForLocationChangeAndTransferOld( - this.prependWorkspacePathForPath(PlaintextBackupsDirectoryName), + await this.prependWorkspacePathForPath(PlaintextBackupsDirectoryName), ) if (!location) { return @@ -285,7 +285,7 @@ export class FilesBackupService extends AbstractService implements BackupService async changePlaintextBackupsLocation(): Promise { const oldLocation = this.getPlaintextBackupsLocation() const newLocation = await this.device.presentDirectoryPickerForLocationChangeAndTransferOld( - this.prependWorkspacePathForPath(PlaintextBackupsDirectoryName), + await this.prependWorkspacePathForPath(PlaintextBackupsDirectoryName), oldLocation, ) @@ -302,7 +302,7 @@ export class FilesBackupService extends AbstractService implements BackupService let location = this.getFilesBackupsLocation() if (!location) { location = await this.device.presentDirectoryPickerForLocationChangeAndTransferOld( - this.prependWorkspacePathForPath(FileBackupsDirectoryName), + await this.prependWorkspacePathForPath(FileBackupsDirectoryName), ) if (!location) { return @@ -328,7 +328,7 @@ export class FilesBackupService extends AbstractService implements BackupService public async changeFilesBackupsLocation(): Promise { const oldLocation = this.getFilesBackupsLocation() const newLocation = await this.device.presentDirectoryPickerForLocationChangeAndTransferOld( - this.prependWorkspacePathForPath(FileBackupsDirectoryName), + await this.prependWorkspacePathForPath(FileBackupsDirectoryName), oldLocation, ) if (!newLocation) { diff --git a/packages/snjs/lib/Application/Application.ts b/packages/snjs/lib/Application/Application.ts index b57f2c4e2..2a945b3d3 100644 --- a/packages/snjs/lib/Application/Application.ts +++ b/packages/snjs/lib/Application/Application.ts @@ -1369,6 +1369,7 @@ export class SNApplication implements ApplicationInterface, AppGroupManagedAppli singletonManager: this.singletonManager, featuresService: this.featuresService, environment: this.environment, + platform: this.platform, identifier: this.identifier, internalEventBus: this.internalEventBus, legacySessionStorageMapper: this.legacySessionStorageMapper, diff --git a/packages/snjs/lib/Migrations/MigrationServices.ts b/packages/snjs/lib/Migrations/MigrationServices.ts index d6c46feb6..d99fe9a91 100644 --- a/packages/snjs/lib/Migrations/MigrationServices.ts +++ b/packages/snjs/lib/Migrations/MigrationServices.ts @@ -1,5 +1,5 @@ import { BackupServiceInterface } from '@standardnotes/files' -import { Environment } from '@standardnotes/models' +import { Environment, Platform } from '@standardnotes/models' import { DeviceInterface, InternalEventBusInterface, EncryptionService } from '@standardnotes/services' import { SNSessionManager } from '../Services/Session/SessionManager' import { ApplicationIdentifier } from '@standardnotes/common' @@ -18,6 +18,7 @@ export type MigrationServices = { singletonManager: SNSingletonManager featuresService: SNFeaturesService environment: Environment + platform: Platform identifier: ApplicationIdentifier legacySessionStorageMapper: MapperInterface> internalEventBus: InternalEventBusInterface diff --git a/packages/snjs/lib/Migrations/Versions/2_167_6.ts b/packages/snjs/lib/Migrations/Versions/2_167_6.ts index fab93a362..6cbfbcf69 100644 --- a/packages/snjs/lib/Migrations/Versions/2_167_6.ts +++ b/packages/snjs/lib/Migrations/Versions/2_167_6.ts @@ -30,9 +30,11 @@ export class Migration2_167_6 extends Migration { if (fileBackupsEnabled) { const legacyLocation = await device.getLegacyFilesBackupsLocation() - const newLocation = `${legacyLocation}/${this.services.backups.prependWorkspacePathForPath( - FileBackupsDirectoryName, - )}` + const newLocation = await device.joinPaths( + legacyLocation as string, + await this.services.backups.prependWorkspacePathForPath(FileBackupsDirectoryName), + ) + await device.migrateLegacyFileBackupsToNewStructure(newLocation) this.services.storageService.setValue(StorageKey.FileBackupsLocation, newLocation) } @@ -41,9 +43,10 @@ export class Migration2_167_6 extends Migration { if (wasLegacyDisabled) { this.services.storageService.setValue(StorageKey.TextBackupsEnabled, false) } else { - const newTextBackupsLocation = `${await device.getLegacyTextBackupsLocation()}/${this.services.backups.prependWorkspacePathForPath( - TextBackupsDirectoryName, - )}` + const newTextBackupsLocation = await device.joinPaths( + (await device.getLegacyTextBackupsLocation()) as string, + await this.services.backups.prependWorkspacePathForPath(TextBackupsDirectoryName), + ) this.services.storageService.setValue(StorageKey.TextBackupsLocation, newTextBackupsLocation) this.services.storageService.setValue(StorageKey.TextBackupsEnabled, true) } diff --git a/packages/snjs/lib/Migrations/Versions/2_168_6.ts b/packages/snjs/lib/Migrations/Versions/2_168_6.ts new file mode 100644 index 000000000..29fa68c1b --- /dev/null +++ b/packages/snjs/lib/Migrations/Versions/2_168_6.ts @@ -0,0 +1,54 @@ +import { Platform } from '@standardnotes/models' +import { ApplicationStage, StorageKey, isDesktopDevice } from '@standardnotes/services' +import { Migration } from '@Lib/Migrations/Migration' + +export class Migration2_168_6 extends Migration { + static override version(): string { + return '2.168.6' + } + + protected registerStageHandlers(): void { + this.registerStageHandler(ApplicationStage.Launched_10, async () => { + await this.migrateErroneousWindowsPathFromPreviousMigration() + this.markDone() + }) + } + + private async migrateErroneousWindowsPathFromPreviousMigration(): Promise { + const device = this.services.deviceInterface + if (!isDesktopDevice(device) || !this.services.backups) { + return + } + + if (this.services.platform !== Platform.WindowsDesktop) { + return + } + + const textBackupsLocation = this.services.backups.getTextBackupsLocation() + if (textBackupsLocation) { + const parts = textBackupsLocation.split('/') + if (parts.length > 1) { + const newLocation = await device.joinPaths(...parts) + this.services.storageService.setValue(StorageKey.TextBackupsLocation, newLocation) + } + } + + const fileBackupsLocation = this.services.backups.getFilesBackupsLocation() + if (fileBackupsLocation) { + const parts = fileBackupsLocation.split('/') + if (parts.length > 1) { + const newLocation = await device.joinPaths(...parts) + this.services.storageService.setValue(StorageKey.FileBackupsLocation, newLocation) + } + } + + const plaintextBackupsLocation = this.services.backups.getPlaintextBackupsLocation() + if (plaintextBackupsLocation) { + const parts = plaintextBackupsLocation.split('/') + if (parts.length > 1) { + const newLocation = await device.joinPaths(...parts) + this.services.storageService.setValue(StorageKey.PlaintextBackupsLocation, newLocation) + } + } + } +} diff --git a/packages/snjs/lib/Migrations/Versions/index.ts b/packages/snjs/lib/Migrations/Versions/index.ts index 8c4f99d89..bd65de105 100644 --- a/packages/snjs/lib/Migrations/Versions/index.ts +++ b/packages/snjs/lib/Migrations/Versions/index.ts @@ -4,6 +4,7 @@ import { Migration2_20_0 } from './2_20_0' import { Migration2_36_0 } from './2_36_0' import { Migration2_42_0 } from './2_42_0' import { Migration2_167_6 } from './2_167_6' +import { Migration2_168_6 } from './2_168_6' export const MigrationClasses = [ Migration2_0_15, @@ -12,6 +13,15 @@ export const MigrationClasses = [ Migration2_36_0, Migration2_42_0, Migration2_167_6, + Migration2_168_6, ] -export { Migration2_0_15, Migration2_7_0, Migration2_20_0, Migration2_36_0, Migration2_42_0, Migration2_167_6 } +export { + Migration2_0_15, + Migration2_7_0, + Migration2_20_0, + Migration2_36_0, + Migration2_42_0, + Migration2_167_6, + Migration2_168_6, +}