feat: Automatic plaintext backup option in Preferences > Backups will backup your notes and tags into plaintext, unencrypted folders on your computer. In addition, automatic encrypted text backups preference management has moved from the top-level menu in the desktop app to Preferences > Backups. (#2322)
This commit is contained in:
@@ -188,7 +188,7 @@ export class SNApplication implements ApplicationInterface, AppGroupManagedAppli
|
||||
private declare _getRevision: GetRevision
|
||||
private declare _deleteRevision: DeleteRevision
|
||||
|
||||
private internalEventBus!: ExternalServices.InternalEventBusInterface
|
||||
public internalEventBus!: ExternalServices.InternalEventBusInterface
|
||||
|
||||
private eventHandlers: ApplicationObserver[] = []
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
@@ -1184,13 +1184,13 @@ export class SNApplication implements ApplicationInterface, AppGroupManagedAppli
|
||||
this.createSettingsService()
|
||||
this.createFeaturesService()
|
||||
this.createComponentManager()
|
||||
this.createMigrationService()
|
||||
this.createMfaService()
|
||||
|
||||
this.createStatusService()
|
||||
if (isDesktopDevice(this.deviceInterface)) {
|
||||
this.createFilesBackupService(this.deviceInterface)
|
||||
}
|
||||
this.createMigrationService()
|
||||
this.createFileService()
|
||||
|
||||
this.createIntegrityService()
|
||||
@@ -1381,6 +1381,7 @@ export class SNApplication implements ApplicationInterface, AppGroupManagedAppli
|
||||
identifier: this.identifier,
|
||||
internalEventBus: this.internalEventBus,
|
||||
legacySessionStorageMapper: this.legacySessionStorageMapper,
|
||||
backups: this.fileBackups,
|
||||
})
|
||||
this.services.push(this.migrationService)
|
||||
}
|
||||
@@ -1584,6 +1585,7 @@ export class SNApplication implements ApplicationInterface, AppGroupManagedAppli
|
||||
this.httpService,
|
||||
this.sessionStorageMapper,
|
||||
this.legacySessionStorageMapper,
|
||||
this.identifier,
|
||||
this.internalEventBus,
|
||||
)
|
||||
this.serviceObservers.push(
|
||||
@@ -1761,6 +1763,10 @@ export class SNApplication implements ApplicationInterface, AppGroupManagedAppli
|
||||
device,
|
||||
this.statusService,
|
||||
this.options.crypto,
|
||||
this.storage,
|
||||
this.sessions,
|
||||
this.payloadManager,
|
||||
this.historyManager,
|
||||
this.internalEventBus,
|
||||
)
|
||||
this.services.push(this.filesBackupService)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { BackupServiceInterface } from '@standardnotes/files'
|
||||
import { Environment } from '@standardnotes/models'
|
||||
import { DeviceInterface, InternalEventBusInterface, EncryptionService } from '@standardnotes/services'
|
||||
|
||||
import { SNSessionManager } from '../Services/Session/SessionManager'
|
||||
import { ApplicationIdentifier } from '@standardnotes/common'
|
||||
import { ItemManager } from '@Lib/Services/Items/ItemManager'
|
||||
@@ -13,6 +13,7 @@ export type MigrationServices = {
|
||||
storageService: DiskStorageService
|
||||
challengeService: ChallengeService
|
||||
sessionManager: SNSessionManager
|
||||
backups?: BackupServiceInterface
|
||||
itemManager: ItemManager
|
||||
singletonManager: SNSingletonManager
|
||||
featuresService: SNFeaturesService
|
||||
|
||||
51
packages/snjs/lib/Migrations/Versions/2_167_6.ts
Normal file
51
packages/snjs/lib/Migrations/Versions/2_167_6.ts
Normal file
@@ -0,0 +1,51 @@
|
||||
import {
|
||||
ApplicationStage,
|
||||
FileBackupsDirectoryName,
|
||||
StorageKey,
|
||||
TextBackupsDirectoryName,
|
||||
isDesktopDevice,
|
||||
} from '@standardnotes/services'
|
||||
import { Migration } from '@Lib/Migrations/Migration'
|
||||
|
||||
export class Migration2_167_6 extends Migration {
|
||||
static override version(): string {
|
||||
return '2.167.6'
|
||||
}
|
||||
|
||||
protected registerStageHandlers(): void {
|
||||
this.registerStageHandler(ApplicationStage.Launched_10, async () => {
|
||||
await this.migrateStorageKeysForDesktopBackups()
|
||||
this.markDone()
|
||||
})
|
||||
}
|
||||
|
||||
private async migrateStorageKeysForDesktopBackups(): Promise<void> {
|
||||
const device = this.services.deviceInterface
|
||||
if (!isDesktopDevice(device) || !this.services.backups) {
|
||||
return
|
||||
}
|
||||
|
||||
const fileBackupsEnabled = await device.isLegacyFilesBackupsEnabled()
|
||||
this.services.storageService.setValue(StorageKey.FileBackupsEnabled, fileBackupsEnabled)
|
||||
|
||||
if (fileBackupsEnabled) {
|
||||
const legacyLocation = await device.getLegacyFilesBackupsLocation()
|
||||
const newLocation = `${legacyLocation}/${this.services.backups.prependWorkspacePathForPath(
|
||||
FileBackupsDirectoryName,
|
||||
)}`
|
||||
await device.migrateLegacyFileBackupsToNewStructure(newLocation)
|
||||
this.services.storageService.setValue(StorageKey.FileBackupsLocation, newLocation)
|
||||
}
|
||||
|
||||
const wasLegacyDisabled = await device.wasLegacyTextBackupsExplicitlyDisabled()
|
||||
if (wasLegacyDisabled) {
|
||||
this.services.storageService.setValue(StorageKey.TextBackupsEnabled, false)
|
||||
} else {
|
||||
const newTextBackupsLocation = `${await device.getLegacyTextBackupsLocation()}/${this.services.backups.prependWorkspacePathForPath(
|
||||
TextBackupsDirectoryName,
|
||||
)}`
|
||||
this.services.storageService.setValue(StorageKey.TextBackupsLocation, newTextBackupsLocation)
|
||||
this.services.storageService.setValue(StorageKey.TextBackupsEnabled, true)
|
||||
}
|
||||
}
|
||||
}
|
||||
5
packages/snjs/lib/Migrations/Versions/README.md
Normal file
5
packages/snjs/lib/Migrations/Versions/README.md
Normal file
@@ -0,0 +1,5 @@
|
||||
## To create a migration:
|
||||
|
||||
1. Create a new file inside versions specifiying the would-be version of SNJS that would result when publishing your migration. For example, if the current SNJS version is 1.0.0 in package.json, your migration version should be 1.0.1 to target users below this version.
|
||||
|
||||
2. **Important** Export your migration inside the index.ts file.
|
||||
@@ -3,7 +3,15 @@ import { Migration2_7_0 } from './2_7_0'
|
||||
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'
|
||||
|
||||
export const MigrationClasses = [Migration2_0_15, Migration2_7_0, Migration2_20_0, Migration2_36_0, Migration2_42_0]
|
||||
export const MigrationClasses = [
|
||||
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 }
|
||||
export { Migration2_0_15, Migration2_7_0, Migration2_20_0, Migration2_36_0, Migration2_42_0, Migration2_167_6 }
|
||||
|
||||
@@ -5,7 +5,12 @@ import { DiskStorageService } from '@Lib/Services/Storage/DiskStorageService'
|
||||
import { UuidString } from '../../Types/UuidString'
|
||||
import * as Models from '@standardnotes/models'
|
||||
import { SNNote } from '@standardnotes/models'
|
||||
import { AbstractService, DeviceInterface, InternalEventBusInterface } from '@standardnotes/services'
|
||||
import {
|
||||
AbstractService,
|
||||
DeviceInterface,
|
||||
HistoryServiceInterface,
|
||||
InternalEventBusInterface,
|
||||
} from '@standardnotes/services'
|
||||
|
||||
/** The amount of revisions per item above which should call for an optimization. */
|
||||
const DefaultItemRevisionsThreshold = 20
|
||||
@@ -25,7 +30,7 @@ const LargeEntryDeltaThreshold = 25
|
||||
* 2. Remote server history. Entries are automatically added by the server and must be
|
||||
* retrieved per item via an API call.
|
||||
*/
|
||||
export class SNHistoryManager extends AbstractService {
|
||||
export class SNHistoryManager extends AbstractService implements HistoryServiceInterface {
|
||||
private removeChangeObserver: () => void
|
||||
|
||||
/**
|
||||
|
||||
@@ -343,13 +343,13 @@ export class ItemManager
|
||||
/**
|
||||
* Returns all items that an item directly references
|
||||
*/
|
||||
public referencesForItem(
|
||||
public referencesForItem<I extends Models.DecryptedItemInterface = Models.DecryptedItemInterface>(
|
||||
itemToLookupUuidFor: Models.DecryptedItemInterface,
|
||||
contentType?: ContentType,
|
||||
): Models.DecryptedItemInterface[] {
|
||||
const item = this.findSureItem(itemToLookupUuidFor.uuid)
|
||||
): I[] {
|
||||
const item = this.findSureItem<I>(itemToLookupUuidFor.uuid)
|
||||
const uuids = item.references.map((ref) => ref.uuid)
|
||||
let references = this.findItems(uuids)
|
||||
let references = this.findItems<I>(uuids)
|
||||
if (contentType) {
|
||||
references = references.filter((ref) => {
|
||||
return ref?.content_type === contentType
|
||||
|
||||
@@ -54,10 +54,7 @@ export class SNMigrationService extends AbstractService {
|
||||
await this.markMigrationsAsDone()
|
||||
})
|
||||
} else {
|
||||
await this.services.deviceInterface.setRawStorageValue(
|
||||
namespacedKey(this.services.identifier, RawStorageKey.SnjsVersion),
|
||||
SnjsVersion,
|
||||
)
|
||||
await this.markMigrationsAsDone()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -101,6 +101,7 @@ export class SNSessionManager
|
||||
private httpService: HttpServiceInterface,
|
||||
private sessionStorageMapper: MapperInterface<Session, Record<string, unknown>>,
|
||||
private legacySessionStorageMapper: MapperInterface<LegacySession, Record<string, unknown>>,
|
||||
private workspaceIdentifier: string,
|
||||
protected override internalEventBus: InternalEventBusInterface,
|
||||
) {
|
||||
super(internalEventBus)
|
||||
@@ -130,6 +131,14 @@ export class SNSessionManager
|
||||
super.deinit()
|
||||
}
|
||||
|
||||
public getWorkspaceDisplayIdentifier(): string {
|
||||
if (this.user) {
|
||||
return this.user.email
|
||||
} else {
|
||||
return this.workspaceIdentifier
|
||||
}
|
||||
}
|
||||
|
||||
private setUser(user?: User) {
|
||||
this.user = user
|
||||
this.apiService.setUser(user)
|
||||
|
||||
@@ -3,7 +3,7 @@ chai.use(chaiAsPromised)
|
||||
const expect = chai.expect
|
||||
|
||||
describe('migrations', () => {
|
||||
const allMigrations = ['2.0.15', '2.7.0', '2.20.0', '2.36.0', '2.42.0']
|
||||
const allMigrations = ['2.0.15', '2.7.0', '2.20.0', '2.36.0', '2.42.0', '2.167.6']
|
||||
|
||||
beforeEach(async () => {
|
||||
localStorage.clear()
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/snjs",
|
||||
"version": "2.167.5",
|
||||
"version": "2.167.6",
|
||||
"engines": {
|
||||
"node": ">=16.0.0 <17.0.0"
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user