feat: add snjs package
This commit is contained in:
34
packages/snjs/lib/Migrations/StorageReaders/Functions.ts
Normal file
34
packages/snjs/lib/Migrations/StorageReaders/Functions.ts
Normal file
@@ -0,0 +1,34 @@
|
||||
import { ApplicationIdentifier } from '@standardnotes/common'
|
||||
import { compareSemVersions, isRightVersionGreaterThanLeft } from '@Lib/Version'
|
||||
import { DeviceInterface, Environment } from '@standardnotes/services'
|
||||
import { StorageReader } from './Reader'
|
||||
import * as ReaderClasses from './Versions'
|
||||
|
||||
function ReaderClassForVersion(
|
||||
version: string,
|
||||
): typeof ReaderClasses.StorageReader2_0_0 | typeof ReaderClasses.StorageReader1_0_0 {
|
||||
/** Sort readers by newest first */
|
||||
const allReaders = Object.values(ReaderClasses).sort((a, b) => {
|
||||
return compareSemVersions(a.version(), b.version()) * -1
|
||||
})
|
||||
for (const reader of allReaders) {
|
||||
if (reader.version() === version) {
|
||||
return reader
|
||||
}
|
||||
if (isRightVersionGreaterThanLeft(reader.version(), version)) {
|
||||
return reader
|
||||
}
|
||||
}
|
||||
|
||||
throw Error(`Cannot find reader for version ${version}`)
|
||||
}
|
||||
|
||||
export function CreateReader(
|
||||
version: string,
|
||||
deviceInterface: DeviceInterface,
|
||||
identifier: ApplicationIdentifier,
|
||||
environment: Environment,
|
||||
): StorageReader {
|
||||
const readerClass = ReaderClassForVersion(version)
|
||||
return new readerClass(deviceInterface, identifier, environment)
|
||||
}
|
||||
31
packages/snjs/lib/Migrations/StorageReaders/Reader.ts
Normal file
31
packages/snjs/lib/Migrations/StorageReaders/Reader.ts
Normal file
@@ -0,0 +1,31 @@
|
||||
import { ApplicationIdentifier } from '@standardnotes/common'
|
||||
import { DeviceInterface, Environment } from '@standardnotes/services'
|
||||
|
||||
/**
|
||||
* A storage reader reads storage via a device interface
|
||||
* given a specific version of SNJS
|
||||
*/
|
||||
export abstract class StorageReader {
|
||||
constructor(
|
||||
protected deviceInterface: DeviceInterface,
|
||||
protected identifier: ApplicationIdentifier,
|
||||
protected environment: Environment,
|
||||
) {}
|
||||
|
||||
public static version(): string {
|
||||
throw Error('Must override')
|
||||
}
|
||||
|
||||
public abstract getAccountKeyParams(): Promise<unknown | undefined>
|
||||
|
||||
/**
|
||||
* Returns true if the state of storage has account keys present
|
||||
* in version-specific storage (either keychain or raw storage)
|
||||
*/
|
||||
public abstract hasNonWrappedAccountKeys(): Promise<boolean>
|
||||
|
||||
public abstract hasPasscode(): Promise<boolean>
|
||||
|
||||
/** Whether this version used the keychain to store keys */
|
||||
public abstract usesKeychain(): boolean
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
import { isNullOrUndefined } from '@standardnotes/utils'
|
||||
import { isEnvironmentMobile } from '@Lib/Application/Platforms'
|
||||
import { PreviousSnjsVersion1_0_0 } from '../../../Version'
|
||||
import { isMobileDevice, LegacyKeys1_0_0 } from '@standardnotes/services'
|
||||
import { StorageReader } from '../Reader'
|
||||
|
||||
export class StorageReader1_0_0 extends StorageReader {
|
||||
static override version() {
|
||||
return PreviousSnjsVersion1_0_0
|
||||
}
|
||||
|
||||
public async getAccountKeyParams() {
|
||||
return this.deviceInterface.getJsonParsedRawStorageValue(LegacyKeys1_0_0.AllAccountKeyParamsKey)
|
||||
}
|
||||
|
||||
/**
|
||||
* In 1.0.0, web uses raw storage for unwrapped account key, and mobile uses
|
||||
* the keychain
|
||||
*/
|
||||
public async hasNonWrappedAccountKeys() {
|
||||
if (isMobileDevice(this.deviceInterface)) {
|
||||
const value = await this.deviceInterface.getRawKeychainValue()
|
||||
return !isNullOrUndefined(value)
|
||||
} else {
|
||||
const value = await this.deviceInterface.getRawStorageValue('mk')
|
||||
return !isNullOrUndefined(value)
|
||||
}
|
||||
}
|
||||
|
||||
public async hasPasscode() {
|
||||
if (isEnvironmentMobile(this.environment)) {
|
||||
const rawPasscodeParams = await this.deviceInterface.getJsonParsedRawStorageValue(
|
||||
LegacyKeys1_0_0.MobilePasscodeParamsKey,
|
||||
)
|
||||
return !isNullOrUndefined(rawPasscodeParams)
|
||||
} else {
|
||||
const encryptedStorage = await this.deviceInterface.getJsonParsedRawStorageValue(
|
||||
LegacyKeys1_0_0.WebEncryptedStorageKey,
|
||||
)
|
||||
return !isNullOrUndefined(encryptedStorage)
|
||||
}
|
||||
}
|
||||
|
||||
/** Keychain was not used on desktop/web in 1.0.0 */
|
||||
public usesKeychain() {
|
||||
return isEnvironmentMobile(this.environment) ? true : false
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
import { isNullOrUndefined } from '@standardnotes/utils'
|
||||
import { RawStorageKey, StorageKey, namespacedKey, ValueModesKeys } from '@standardnotes/services'
|
||||
import { StorageReader } from '../Reader'
|
||||
import { PreviousSnjsVersion2_0_0 } from '@Lib/Version'
|
||||
|
||||
export class StorageReader2_0_0 extends StorageReader {
|
||||
static override version() {
|
||||
return PreviousSnjsVersion2_0_0
|
||||
}
|
||||
|
||||
private async getStorage() {
|
||||
const storageKey = namespacedKey(this.identifier, RawStorageKey.StorageObject)
|
||||
const storage = await this.deviceInterface.getRawStorageValue(storageKey)
|
||||
const values = storage ? JSON.parse(storage) : undefined
|
||||
return values
|
||||
}
|
||||
|
||||
private async getNonWrappedValue(key: string) {
|
||||
const values = await this.getStorage()
|
||||
if (!values) {
|
||||
return undefined
|
||||
}
|
||||
return values[ValueModesKeys.Nonwrapped]?.[key]
|
||||
}
|
||||
|
||||
/**
|
||||
* In 2.0.0+, account key params are stored in NonWrapped storage
|
||||
*/
|
||||
public async getAccountKeyParams() {
|
||||
return this.getNonWrappedValue(StorageKey.RootKeyParams)
|
||||
}
|
||||
|
||||
public async hasNonWrappedAccountKeys() {
|
||||
const value = await this.deviceInterface.getNamespacedKeychainValue(this.identifier)
|
||||
return !isNullOrUndefined(value)
|
||||
}
|
||||
|
||||
public async hasPasscode() {
|
||||
const wrappedRootKey = await this.getNonWrappedValue(StorageKey.WrappedRootKey)
|
||||
return !isNullOrUndefined(wrappedRootKey)
|
||||
}
|
||||
|
||||
public usesKeychain() {
|
||||
return true
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
export { StorageReader2_0_0 } from './Reader2_0_0'
|
||||
export { StorageReader1_0_0 } from './Reader1_0_0'
|
||||
Reference in New Issue
Block a user