mirror of
https://github.com/standardnotes/app
synced 2026-09-13 09:46:02 -04:00
Compare commits
16
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bfd2b14264 | ||
|
|
eb062220d6 | ||
|
|
0eb552ddc7 | ||
|
|
14bae5e895 | ||
|
|
1fef36d601 | ||
|
|
d268c02ab3 | ||
|
|
86fc4c684d | ||
|
|
ef2d1b9228 | ||
|
|
868a84f587 | ||
|
|
7c463b36af | ||
|
|
908cbaf895 | ||
|
|
51cb14c010 | ||
|
|
47a36c4cbd | ||
|
|
7222ca7fd0 | ||
|
|
6ad5d028af | ||
|
|
596e041c42 |
BIN
Binary file not shown.
@@ -3,6 +3,22 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.26.34](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-07-27)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/api
|
||||
|
||||
## [1.26.33](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-07-27)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/api
|
||||
|
||||
## [1.26.32](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-07-26)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/api
|
||||
|
||||
## [1.26.31](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-07-26)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/api
|
||||
|
||||
## [1.26.30](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-07-23)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/api
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/api",
|
||||
"version": "1.26.30",
|
||||
"version": "1.26.34",
|
||||
"engines": {
|
||||
"node": ">=16.0.0 <17.0.0"
|
||||
},
|
||||
@@ -36,7 +36,7 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@standardnotes/common": "^1.50.0",
|
||||
"@standardnotes/domain-core": "^1.22.0",
|
||||
"@standardnotes/domain-core": "^1.24.0",
|
||||
"@standardnotes/models": "workspace:*",
|
||||
"@standardnotes/responses": "workspace:*",
|
||||
"@standardnotes/utils": "workspace:*",
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { SharedVaultPermission } from '@standardnotes/responses'
|
||||
import { SharedVaultUserPermission } from '@standardnotes/domain-core'
|
||||
|
||||
export type CreateSharedVaultInviteParams = {
|
||||
sharedVaultUuid: string
|
||||
recipientUuid: string
|
||||
encryptedMessage: string
|
||||
permissions: SharedVaultPermission
|
||||
permission: SharedVaultUserPermission
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { SharedVaultPermission } from '@standardnotes/responses'
|
||||
import { SharedVaultUserPermission } from '@standardnotes/domain-core'
|
||||
|
||||
export type UpdateSharedVaultInviteParams = {
|
||||
sharedVaultUuid: string
|
||||
inviteUuid: string
|
||||
encryptedMessage: string
|
||||
permissions?: SharedVaultPermission
|
||||
permission?: SharedVaultUserPermission
|
||||
}
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
export const AsymmetricMessagesPaths = {
|
||||
createMessage: '/v1/asymmetric-messages',
|
||||
getMessages: '/v1/asymmetric-messages',
|
||||
updateMessage: (messageUuid: string) => `/v1/asymmetric-messages/${messageUuid}`,
|
||||
getInboundUserMessages: () => '/v1/asymmetric-messages',
|
||||
getOutboundUserMessages: () => '/v1/asymmetric-messages/outbound',
|
||||
deleteMessage: (messageUuid: string) => `/v1/asymmetric-messages/${messageUuid}`,
|
||||
deleteAllInboundMessages: '/v1/asymmetric-messages/inbound',
|
||||
createMessage: '/v1/messages',
|
||||
getMessages: '/v1/messages',
|
||||
updateMessage: (messageUuid: string) => `/v1/messages/${messageUuid}`,
|
||||
getInboundUserMessages: () => '/v1/messages',
|
||||
getOutboundUserMessages: () => '/v1/messages/outbound',
|
||||
deleteMessage: (messageUuid: string) => `/v1/messages/${messageUuid}`,
|
||||
deleteAllInboundMessages: '/v1/messages/inbound',
|
||||
}
|
||||
|
||||
@@ -26,14 +26,14 @@ export class SharedVaultInvitesServer implements SharedVaultInvitesServerInterfa
|
||||
return this.httpService.post(SharedVaultInvitesPaths.createInvite(params.sharedVaultUuid), {
|
||||
recipient_uuid: params.recipientUuid,
|
||||
encrypted_message: params.encryptedMessage,
|
||||
permissions: params.permissions,
|
||||
permission: params.permission.value,
|
||||
})
|
||||
}
|
||||
|
||||
updateInvite(params: UpdateSharedVaultInviteParams): Promise<HttpResponse<UpdateSharedVaultInviteResponse>> {
|
||||
return this.httpService.patch(SharedVaultInvitesPaths.updateInvite(params.sharedVaultUuid, params.inviteUuid), {
|
||||
encrypted_message: params.encryptedMessage,
|
||||
permissions: params.permissions,
|
||||
permission: params.permission?.value,
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -3,6 +3,30 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.1.118](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-07-27)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/clipper
|
||||
|
||||
## [1.1.117](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-07-27)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/clipper
|
||||
|
||||
## [1.1.116](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-07-26)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/clipper
|
||||
|
||||
## [1.1.115](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-07-26)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/clipper
|
||||
|
||||
## [1.1.114](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-07-26)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/clipper
|
||||
|
||||
## [1.1.113](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-07-25)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/clipper
|
||||
|
||||
## [1.1.112](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-07-25)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/clipper
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@standardnotes/clipper",
|
||||
"description": "Web clipper browser extension for Standard Notes",
|
||||
"version": "1.1.112",
|
||||
"version": "1.1.118",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"build-mv2": "yarn clean && webpack --config ./webpack.config.prod.js",
|
||||
|
||||
@@ -3,6 +3,32 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [3.108.49](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-07-27)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/desktop
|
||||
|
||||
## [3.108.48](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-07-27)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/desktop
|
||||
|
||||
## [3.108.47](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-07-26)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/desktop
|
||||
|
||||
## [3.108.46](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-07-26)
|
||||
|
||||
### Reverts
|
||||
|
||||
* Revert "chore: upgrade desktop deps" ([ef2d1b9](https://github.com/standardnotes/app/commit/ef2d1b9228c90a9cb9cf88535526a312bb28fca4))
|
||||
|
||||
## [3.108.45](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-07-26)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/desktop
|
||||
|
||||
## [3.108.44](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-07-25)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/desktop
|
||||
|
||||
## [3.108.43](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-07-25)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/desktop
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@standardnotes/desktop",
|
||||
"main": "./app/dist/index.js",
|
||||
"version": "3.108.43",
|
||||
"version": "3.108.49",
|
||||
"license": "AGPL-3.0-or-later",
|
||||
"author": "Standard Notes.",
|
||||
"private": true,
|
||||
@@ -35,7 +35,7 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@electron/remote": "^2.0.9",
|
||||
"@standardnotes/domain-core": "^1.22.0",
|
||||
"@standardnotes/domain-core": "^1.24.0",
|
||||
"@standardnotes/electron-clear-data": "1.1.1",
|
||||
"@standardnotes/web": "workspace:*",
|
||||
"axios": "^1.1.3",
|
||||
|
||||
@@ -3,6 +3,22 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.21.57](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-07-27)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/encryption
|
||||
|
||||
## [1.21.56](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-07-27)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/encryption
|
||||
|
||||
## [1.21.55](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-07-26)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/encryption
|
||||
|
||||
## [1.21.54](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-07-26)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/encryption
|
||||
|
||||
## [1.21.53](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-07-23)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/encryption
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/encryption",
|
||||
"version": "1.21.53",
|
||||
"version": "1.21.57",
|
||||
"engines": {
|
||||
"node": ">=16.0.0 <17.0.0"
|
||||
},
|
||||
@@ -29,7 +29,7 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@standardnotes/common": "^1.50.0",
|
||||
"@standardnotes/domain-core": "^1.22.0",
|
||||
"@standardnotes/domain-core": "^1.24.0",
|
||||
"@standardnotes/models": "workspace:*",
|
||||
"@standardnotes/responses": "workspace:*",
|
||||
"@standardnotes/sncrypto-common": "workspace:*",
|
||||
|
||||
+2
-2
@@ -3,7 +3,7 @@ import { V004Algorithm } from '../../../../Algorithm'
|
||||
import {
|
||||
KeySystemRootKeyInterface,
|
||||
KeySystemRootKeyParamsInterface,
|
||||
KeySystemRootKeyPasswordType,
|
||||
KeySystemPasswordType,
|
||||
} from '@standardnotes/models'
|
||||
import { ProtocolVersion } from '@standardnotes/common'
|
||||
import { DeriveKeySystemRootKeyUseCase } from './DeriveKeySystemRootKey'
|
||||
@@ -20,7 +20,7 @@ export class CreateRandomKeySystemRootKey {
|
||||
|
||||
const keyParams: KeySystemRootKeyParamsInterface = {
|
||||
systemIdentifier: dto.systemIdentifier,
|
||||
passwordType: KeySystemRootKeyPasswordType.Randomized,
|
||||
passwordType: KeySystemPasswordType.Randomized,
|
||||
creationTimestamp: new Date().getTime(),
|
||||
seed,
|
||||
version,
|
||||
|
||||
+2
-2
@@ -4,7 +4,7 @@ import {
|
||||
KeySystemIdentifier,
|
||||
KeySystemRootKeyInterface,
|
||||
KeySystemRootKeyParamsInterface,
|
||||
KeySystemRootKeyPasswordType,
|
||||
KeySystemPasswordType,
|
||||
} from '@standardnotes/models'
|
||||
import { ProtocolVersion } from '@standardnotes/common'
|
||||
import { DeriveKeySystemRootKeyUseCase } from './DeriveKeySystemRootKey'
|
||||
@@ -19,7 +19,7 @@ export class CreateUserInputKeySystemRootKey {
|
||||
|
||||
const keyParams: KeySystemRootKeyParamsInterface = {
|
||||
systemIdentifier: dto.systemIdentifier,
|
||||
passwordType: KeySystemRootKeyPasswordType.UserInputted,
|
||||
passwordType: KeySystemPasswordType.UserInputted,
|
||||
creationTimestamp: new Date().getTime(),
|
||||
seed,
|
||||
version,
|
||||
|
||||
+2
-2
@@ -14,9 +14,9 @@ export class GetPayloadAuthenticatedDataDetachedUseCase {
|
||||
execute(
|
||||
encrypted: EncryptedOutputParameters,
|
||||
): RootKeyEncryptedAuthenticatedData | ItemAuthenticatedData | LegacyAttachedData | undefined {
|
||||
const itemKeyComponents = deconstructEncryptedPayloadString(encrypted.enc_item_key)
|
||||
const contentKeyComponents = deconstructEncryptedPayloadString(encrypted.enc_item_key)
|
||||
|
||||
const authenticatedDataString = itemKeyComponents.authenticatedData
|
||||
const authenticatedDataString = contentKeyComponents.authenticatedData
|
||||
|
||||
const result = this.parseStringUseCase.execute<
|
||||
RootKeyEncryptedAuthenticatedData | ItemAuthenticatedData | LegacyAttachedData
|
||||
|
||||
@@ -3,6 +3,16 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.59.12](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-07-27)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/features
|
||||
|
||||
## [1.59.11](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-07-26)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* Fixes issue where lock screen would not use previously active theme ([#2372](https://github.com/standardnotes/app/issues/2372)) ([d268c02](https://github.com/standardnotes/app/commit/d268c02ab31beb5e2fd9e6547610f9a4dd61bed4))
|
||||
|
||||
## [1.59.10](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-07-17)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/features
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/features",
|
||||
"version": "1.59.10",
|
||||
"version": "1.59.12",
|
||||
"engines": {
|
||||
"node": ">=16.0.0 <17.0.0"
|
||||
},
|
||||
@@ -26,7 +26,7 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@standardnotes/common": "^1.50.0",
|
||||
"@standardnotes/domain-core": "^1.22.0",
|
||||
"@standardnotes/domain-core": "^1.24.0",
|
||||
"reflect-metadata": "^0.1.13"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
import { FeatureIdentifier } from './../Feature/FeatureIdentifier'
|
||||
|
||||
type ThirdPartyIdentifier = string
|
||||
|
||||
export type EditorIdentifier = FeatureIdentifier | ThirdPartyIdentifier
|
||||
@@ -1,16 +1,16 @@
|
||||
import { FeatureIdentifier } from '@standardnotes/features'
|
||||
import { NativeFeatureIdentifier } from '@standardnotes/features'
|
||||
import { noteTypeForEditorIdentifier, NoteType } from './NoteType'
|
||||
|
||||
describe('note type', () => {
|
||||
it('should return the correct note type for editor identifier', () => {
|
||||
expect(noteTypeForEditorIdentifier(FeatureIdentifier.PlainEditor)).toEqual(NoteType.Plain)
|
||||
expect(noteTypeForEditorIdentifier(FeatureIdentifier.SuperEditor)).toEqual(NoteType.Super)
|
||||
expect(noteTypeForEditorIdentifier(FeatureIdentifier.MarkdownProEditor)).toEqual(NoteType.Markdown)
|
||||
expect(noteTypeForEditorIdentifier(FeatureIdentifier.PlusEditor)).toEqual(NoteType.RichText)
|
||||
expect(noteTypeForEditorIdentifier(FeatureIdentifier.CodeEditor)).toEqual(NoteType.Code)
|
||||
expect(noteTypeForEditorIdentifier(FeatureIdentifier.SheetsEditor)).toEqual(NoteType.Spreadsheet)
|
||||
expect(noteTypeForEditorIdentifier(FeatureIdentifier.TaskEditor)).toEqual(NoteType.Task)
|
||||
expect(noteTypeForEditorIdentifier(FeatureIdentifier.TokenVaultEditor)).toEqual(NoteType.Authentication)
|
||||
expect(noteTypeForEditorIdentifier(NativeFeatureIdentifier.TYPES.PlainEditor)).toEqual(NoteType.Plain)
|
||||
expect(noteTypeForEditorIdentifier(NativeFeatureIdentifier.TYPES.SuperEditor)).toEqual(NoteType.Super)
|
||||
expect(noteTypeForEditorIdentifier(NativeFeatureIdentifier.TYPES.MarkdownProEditor)).toEqual(NoteType.Markdown)
|
||||
expect(noteTypeForEditorIdentifier(NativeFeatureIdentifier.TYPES.PlusEditor)).toEqual(NoteType.RichText)
|
||||
expect(noteTypeForEditorIdentifier(NativeFeatureIdentifier.TYPES.CodeEditor)).toEqual(NoteType.Code)
|
||||
expect(noteTypeForEditorIdentifier(NativeFeatureIdentifier.TYPES.SheetsEditor)).toEqual(NoteType.Spreadsheet)
|
||||
expect(noteTypeForEditorIdentifier(NativeFeatureIdentifier.TYPES.TaskEditor)).toEqual(NoteType.Task)
|
||||
expect(noteTypeForEditorIdentifier(NativeFeatureIdentifier.TYPES.TokenVaultEditor)).toEqual(NoteType.Authentication)
|
||||
expect(noteTypeForEditorIdentifier('org.third.party')).toEqual(NoteType.Unknown)
|
||||
})
|
||||
})
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
import { EditorFeatureDescription } from '../Feature/EditorFeatureDescription'
|
||||
import { FindNativeFeature } from '../Feature/Features'
|
||||
import { IframeComponentFeatureDescription } from '../Feature/IframeComponentFeatureDescription'
|
||||
import { FeatureIdentifier } from './../Feature/FeatureIdentifier'
|
||||
import { EditorIdentifier } from './EditorIdentifier'
|
||||
|
||||
export enum NoteType {
|
||||
Authentication = 'authentication',
|
||||
@@ -16,10 +14,8 @@ export enum NoteType {
|
||||
Unknown = 'unknown',
|
||||
}
|
||||
|
||||
export function noteTypeForEditorIdentifier(identifier: EditorIdentifier): NoteType {
|
||||
const feature = FindNativeFeature<EditorFeatureDescription | IframeComponentFeatureDescription>(
|
||||
identifier as FeatureIdentifier,
|
||||
)
|
||||
export function noteTypeForEditorIdentifier(identifier: string): NoteType {
|
||||
const feature = FindNativeFeature<EditorFeatureDescription | IframeComponentFeatureDescription>(identifier)
|
||||
if (feature && feature.note_type) {
|
||||
return feature.note_type
|
||||
}
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import { PermissionName } from '../Permission/PermissionName'
|
||||
import { FeatureIdentifier } from './FeatureIdentifier'
|
||||
import { ComponentFlag } from '../Component/ComponentFlag'
|
||||
import { RoleFields } from './RoleFields'
|
||||
|
||||
@@ -14,7 +13,7 @@ export type BaseFeatureDescription = RoleFields & {
|
||||
clientControlled?: boolean
|
||||
|
||||
flags?: ComponentFlag[]
|
||||
identifier: FeatureIdentifier
|
||||
identifier: string
|
||||
marketing_url?: string
|
||||
name: string
|
||||
no_expire?: boolean
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
import { PermissionName } from '../Permission/PermissionName'
|
||||
import { FeatureIdentifier } from './FeatureIdentifier'
|
||||
import { RoleFields } from './RoleFields'
|
||||
|
||||
export type ClientFeatureDescription = RoleFields & {
|
||||
identifier: FeatureIdentifier
|
||||
identifier: string
|
||||
permission_name: PermissionName
|
||||
description: string
|
||||
name: string
|
||||
|
||||
@@ -1,51 +0,0 @@
|
||||
export enum FeatureIdentifier {
|
||||
DailyEmailBackup = 'org.standardnotes.daily-email-backup',
|
||||
Files = 'org.standardnotes.files',
|
||||
FilesLowStorageTier = 'org.standardnotes.files-low-storage-tier',
|
||||
FilesMaximumStorageTier = 'org.standardnotes.files-max-storage-tier',
|
||||
ListedCustomDomain = 'org.standardnotes.listed-custom-domain',
|
||||
NoteHistory30Days = 'org.standardnotes.note-history-30',
|
||||
NoteHistory365Days = 'org.standardnotes.note-history-365',
|
||||
NoteHistoryUnlimited = 'org.standardnotes.note-history-unlimited',
|
||||
SignInAlerts = 'com.standardnotes.sign-in-alerts',
|
||||
SmartFilters = 'org.standardnotes.smart-filters',
|
||||
TagNesting = 'org.standardnotes.tag-nesting',
|
||||
TwoFactorAuth = 'org.standardnotes.two-factor-auth',
|
||||
UniversalSecondFactor = 'org.standardnotes.universal-second-factor',
|
||||
SubscriptionSharing = 'org.standardnotes.subscription-sharing',
|
||||
|
||||
AutobiographyTheme = 'org.standardnotes.theme-autobiography',
|
||||
DynamicTheme = 'org.standardnotes.theme-dynamic',
|
||||
DarkTheme = 'org.standardnotes.theme-focus',
|
||||
FuturaTheme = 'org.standardnotes.theme-futura',
|
||||
MidnightTheme = 'org.standardnotes.theme-midnight',
|
||||
SolarizedDarkTheme = 'org.standardnotes.theme-solarized-dark',
|
||||
TitaniumTheme = 'org.standardnotes.theme-titanium',
|
||||
|
||||
PlainEditor = 'com.standardnotes.plain-text',
|
||||
SuperEditor = 'com.standardnotes.super-editor',
|
||||
|
||||
CodeEditor = 'org.standardnotes.code-editor',
|
||||
MarkdownProEditor = 'org.standardnotes.advanced-markdown-editor',
|
||||
PlusEditor = 'org.standardnotes.plus-editor',
|
||||
SheetsEditor = 'org.standardnotes.standard-sheets',
|
||||
TaskEditor = 'org.standardnotes.simple-task-editor',
|
||||
TokenVaultEditor = 'org.standardnotes.token-vault',
|
||||
|
||||
Extension = 'org.standardnotes.extension',
|
||||
|
||||
DeprecatedMarkdownVisualEditor = 'org.standardnotes.markdown-visual-editor',
|
||||
DeprecatedBoldEditor = 'org.standardnotes.bold-editor',
|
||||
DeprecatedMarkdownBasicEditor = 'org.standardnotes.simple-markdown-editor',
|
||||
DeprecatedMarkdownMathEditor = 'org.standardnotes.fancy-markdown-editor',
|
||||
DeprecatedMarkdownMinimistEditor = 'org.standardnotes.minimal-markdown-editor',
|
||||
DeprecatedFoldersComponent = 'org.standardnotes.folders',
|
||||
DeprecatedFileSafe = 'org.standardnotes.file-safe',
|
||||
}
|
||||
|
||||
/**
|
||||
* Identifier for standalone filesafe instance offered as legacy installable via extensions-server
|
||||
*/
|
||||
export const LegacyFileSafeIdentifier = 'org.standardnotes.legacy.file-safe'
|
||||
|
||||
export const ExperimentalFeatures = []
|
||||
@@ -1,7 +1,7 @@
|
||||
import { AnyFeatureDescription } from './AnyFeatureDescription'
|
||||
import { ThemeFeatureDescription } from './ThemeFeatureDescription'
|
||||
import { EditorFeatureDescription } from './EditorFeatureDescription'
|
||||
import { FeatureIdentifier } from './FeatureIdentifier'
|
||||
import { NativeFeatureIdentifier } from './NativeFeatureIdentifier'
|
||||
import { serverFeatures } from '../Lists/ServerFeatures'
|
||||
import { clientFeatures } from '../Lists/ClientFeatures'
|
||||
import { GetDeprecatedFeatures } from '../Lists/DeprecatedFeatures'
|
||||
@@ -23,11 +23,11 @@ export function GetFeatures(): AnyFeatureDescription[] {
|
||||
]
|
||||
}
|
||||
|
||||
export function FindNativeFeature<T extends AnyFeatureDescription>(identifier: FeatureIdentifier): T | undefined {
|
||||
export function FindNativeFeature<T extends AnyFeatureDescription>(identifier: string): T | undefined {
|
||||
return GetFeatures().find((f) => f.identifier === identifier) as T
|
||||
}
|
||||
|
||||
export function FindNativeTheme(identifier: FeatureIdentifier): ThemeFeatureDescription | undefined {
|
||||
export function FindNativeTheme(identifier: string): ThemeFeatureDescription | undefined {
|
||||
return themes().find((t) => t.identifier === identifier)
|
||||
}
|
||||
|
||||
@@ -40,11 +40,11 @@ export function GetIframeEditors(): IframeComponentFeatureDescription[] {
|
||||
}
|
||||
|
||||
export function GetSuperNoteFeature(): EditorFeatureDescription {
|
||||
return FindNativeFeature(FeatureIdentifier.SuperEditor) as EditorFeatureDescription
|
||||
return FindNativeFeature(NativeFeatureIdentifier.TYPES.SuperEditor) as EditorFeatureDescription
|
||||
}
|
||||
|
||||
export function GetPlainNoteFeature(): EditorFeatureDescription {
|
||||
return FindNativeFeature(FeatureIdentifier.PlainEditor) as EditorFeatureDescription
|
||||
return FindNativeFeature(NativeFeatureIdentifier.TYPES.PlainEditor) as EditorFeatureDescription
|
||||
}
|
||||
|
||||
export function GetNativeThemes(): ThemeFeatureDescription[] {
|
||||
@@ -52,5 +52,5 @@ export function GetNativeThemes(): ThemeFeatureDescription[] {
|
||||
}
|
||||
|
||||
export function GetDarkThemeFeature(): ThemeFeatureDescription {
|
||||
return themes().find((t) => t.identifier === FeatureIdentifier.DarkTheme) as ThemeFeatureDescription
|
||||
return themes().find((t) => t.identifier === NativeFeatureIdentifier.TYPES.DarkTheme) as ThemeFeatureDescription
|
||||
}
|
||||
|
||||
@@ -0,0 +1,75 @@
|
||||
import { Result, ValueObject } from '@standardnotes/domain-core'
|
||||
|
||||
export interface NativeFeatureIdentifierProps {
|
||||
value: string
|
||||
}
|
||||
|
||||
export class NativeFeatureIdentifier extends ValueObject<NativeFeatureIdentifierProps> {
|
||||
static readonly TYPES = {
|
||||
DailyEmailBackup: 'org.standardnotes.daily-email-backup',
|
||||
Files: 'org.standardnotes.files',
|
||||
FilesLowStorageTier: 'org.standardnotes.files-low-storage-tier',
|
||||
FilesMaximumStorageTier: 'org.standardnotes.files-max-storage-tier',
|
||||
ListedCustomDomain: 'org.standardnotes.listed-custom-domain',
|
||||
NoteHistory30Days: 'org.standardnotes.note-history-30',
|
||||
NoteHistory365Days: 'org.standardnotes.note-history-365',
|
||||
NoteHistoryUnlimited: 'org.standardnotes.note-history-unlimited',
|
||||
SignInAlerts: 'com.standardnotes.sign-in-alerts',
|
||||
SmartFilters: 'org.standardnotes.smart-filters',
|
||||
TagNesting: 'org.standardnotes.tag-nesting',
|
||||
TwoFactorAuth: 'org.standardnotes.two-factor-auth',
|
||||
UniversalSecondFactor: 'org.standardnotes.universal-second-factor',
|
||||
SubscriptionSharing: 'org.standardnotes.subscription-sharing',
|
||||
|
||||
AutobiographyTheme: 'org.standardnotes.theme-autobiography',
|
||||
DynamicTheme: 'org.standardnotes.theme-dynamic',
|
||||
DarkTheme: 'org.standardnotes.theme-focus',
|
||||
FuturaTheme: 'org.standardnotes.theme-futura',
|
||||
MidnightTheme: 'org.standardnotes.theme-midnight',
|
||||
SolarizedDarkTheme: 'org.standardnotes.theme-solarized-dark',
|
||||
TitaniumTheme: 'org.standardnotes.theme-titanium',
|
||||
|
||||
PlainEditor: 'com.standardnotes.plain-text',
|
||||
SuperEditor: 'com.standardnotes.super-editor',
|
||||
|
||||
CodeEditor: 'org.standardnotes.code-editor',
|
||||
MarkdownProEditor: 'org.standardnotes.advanced-markdown-editor',
|
||||
PlusEditor: 'org.standardnotes.plus-editor',
|
||||
SheetsEditor: 'org.standardnotes.standard-sheets',
|
||||
TaskEditor: 'org.standardnotes.simple-task-editor',
|
||||
TokenVaultEditor: 'org.standardnotes.token-vault',
|
||||
|
||||
Clipper: 'org.standardnotes.clipper',
|
||||
|
||||
DeprecatedMarkdownVisualEditor: 'org.standardnotes.markdown-visual-editor',
|
||||
DeprecatedBoldEditor: 'org.standardnotes.bold-editor',
|
||||
DeprecatedMarkdownBasicEditor: 'org.standardnotes.simple-markdown-editor',
|
||||
DeprecatedMarkdownMathEditor: 'org.standardnotes.fancy-markdown-editor',
|
||||
DeprecatedMarkdownMinimistEditor: 'org.standardnotes.minimal-markdown-editor',
|
||||
DeprecatedFoldersComponent: 'org.standardnotes.folders',
|
||||
DeprecatedFileSafe: 'org.standardnotes.file-safe',
|
||||
LegacyFileSafeIdentifier: 'org.standardnotes.legacy.file-safe',
|
||||
}
|
||||
|
||||
get value(): string {
|
||||
return this.props.value
|
||||
}
|
||||
|
||||
private constructor(props: NativeFeatureIdentifierProps) {
|
||||
super(props)
|
||||
}
|
||||
|
||||
static create(type: string): Result<NativeFeatureIdentifier> {
|
||||
const isValidType = Object.values(this.TYPES).includes(type)
|
||||
if (!isValidType) {
|
||||
return Result.fail<NativeFeatureIdentifier>(`Invalid feature identifier: ${type}`)
|
||||
} else {
|
||||
return Result.ok<NativeFeatureIdentifier>(new NativeFeatureIdentifier({ value: type }))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Identifier for standalone filesafe instance offered as legacy installable via extensions-server
|
||||
*/
|
||||
export const ExperimentalFeatures = []
|
||||
@@ -1,11 +1,10 @@
|
||||
import { PermissionName } from '../Permission/PermissionName'
|
||||
import { FeatureIdentifier } from './FeatureIdentifier'
|
||||
import { RoleFields } from './RoleFields'
|
||||
|
||||
export type ServerFeatureDescription = RoleFields & {
|
||||
name: string
|
||||
description?: string
|
||||
identifier: FeatureIdentifier
|
||||
identifier: string
|
||||
permission_name: PermissionName
|
||||
deprecated?: boolean
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { PermissionName } from '../Permission/PermissionName'
|
||||
import { FeatureIdentifier } from '../Feature/FeatureIdentifier'
|
||||
import { NativeFeatureIdentifier } from '../Feature/NativeFeatureIdentifier'
|
||||
import { RoleName } from '@standardnotes/domain-core'
|
||||
import { ClientFeatureDescription } from '../Feature/ClientFeatureDescription'
|
||||
|
||||
@@ -8,7 +8,7 @@ export function clientFeatures(): ClientFeatureDescription[] {
|
||||
{
|
||||
name: 'Tag Nesting',
|
||||
availableInRoles: [RoleName.NAMES.PlusUser, RoleName.NAMES.ProUser],
|
||||
identifier: FeatureIdentifier.TagNesting,
|
||||
identifier: NativeFeatureIdentifier.TYPES.TagNesting,
|
||||
permission_name: PermissionName.TagNesting,
|
||||
description: 'Organize your tags into folders.',
|
||||
},
|
||||
@@ -16,22 +16,22 @@ export function clientFeatures(): ClientFeatureDescription[] {
|
||||
{
|
||||
name: 'Smart Filters',
|
||||
availableInRoles: [RoleName.NAMES.PlusUser, RoleName.NAMES.ProUser],
|
||||
identifier: FeatureIdentifier.SmartFilters,
|
||||
identifier: NativeFeatureIdentifier.TYPES.SmartFilters,
|
||||
permission_name: PermissionName.SmartFilters,
|
||||
description: 'Create smart filters for viewing notes matching specific criteria.',
|
||||
},
|
||||
{
|
||||
name: 'Encrypted files',
|
||||
availableInRoles: [RoleName.NAMES.PlusUser, RoleName.NAMES.ProUser],
|
||||
identifier: FeatureIdentifier.Files,
|
||||
identifier: NativeFeatureIdentifier.TYPES.Files,
|
||||
permission_name: PermissionName.Files,
|
||||
description: '',
|
||||
},
|
||||
{
|
||||
name: 'Extension',
|
||||
name: 'Clipper',
|
||||
availableInRoles: [RoleName.NAMES.PlusUser, RoleName.NAMES.ProUser],
|
||||
identifier: FeatureIdentifier.Extension,
|
||||
permission_name: PermissionName.Extension,
|
||||
identifier: NativeFeatureIdentifier.TYPES.Clipper,
|
||||
permission_name: PermissionName.Clipper,
|
||||
description: '',
|
||||
},
|
||||
]
|
||||
|
||||
@@ -3,7 +3,7 @@ import { EditorFeatureDescription } from '../Feature/EditorFeatureDescription'
|
||||
import { IframeComponentFeatureDescription } from '../Feature/IframeComponentFeatureDescription'
|
||||
import { ContentType, RoleName } from '@standardnotes/domain-core'
|
||||
import { PermissionName } from '../Permission/PermissionName'
|
||||
import { FeatureIdentifier } from '../Feature/FeatureIdentifier'
|
||||
import { NativeFeatureIdentifier } from '../Feature/NativeFeatureIdentifier'
|
||||
import { NoteType } from '../Component/NoteType'
|
||||
import { FillIframeEditorDefaults } from './Utilities/FillEditorComponentDefaults'
|
||||
import { ComponentAction } from '../Component/ComponentAction'
|
||||
@@ -12,7 +12,7 @@ import { ComponentArea } from '../Component/ComponentArea'
|
||||
export function GetDeprecatedFeatures(): AnyFeatureDescription[] {
|
||||
const bold: EditorFeatureDescription = FillIframeEditorDefaults({
|
||||
name: 'Alternative Rich Text',
|
||||
identifier: FeatureIdentifier.DeprecatedBoldEditor,
|
||||
identifier: NativeFeatureIdentifier.TYPES.DeprecatedBoldEditor,
|
||||
note_type: NoteType.RichText,
|
||||
file_type: 'html',
|
||||
component_permissions: [
|
||||
@@ -39,7 +39,7 @@ export function GetDeprecatedFeatures(): AnyFeatureDescription[] {
|
||||
|
||||
const markdownBasic: EditorFeatureDescription = FillIframeEditorDefaults({
|
||||
name: 'Basic Markdown',
|
||||
identifier: FeatureIdentifier.DeprecatedMarkdownBasicEditor,
|
||||
identifier: NativeFeatureIdentifier.TYPES.DeprecatedMarkdownBasicEditor,
|
||||
note_type: NoteType.Markdown,
|
||||
spellcheckControl: true,
|
||||
file_type: 'md',
|
||||
@@ -52,7 +52,7 @@ export function GetDeprecatedFeatures(): AnyFeatureDescription[] {
|
||||
|
||||
const markdownAlt: EditorFeatureDescription = FillIframeEditorDefaults({
|
||||
name: 'Markdown Alternative',
|
||||
identifier: FeatureIdentifier.DeprecatedMarkdownVisualEditor,
|
||||
identifier: NativeFeatureIdentifier.TYPES.DeprecatedMarkdownVisualEditor,
|
||||
note_type: NoteType.Markdown,
|
||||
file_type: 'md',
|
||||
deprecated: true,
|
||||
@@ -66,7 +66,7 @@ export function GetDeprecatedFeatures(): AnyFeatureDescription[] {
|
||||
|
||||
const markdownMinimist: EditorFeatureDescription = FillIframeEditorDefaults({
|
||||
name: 'Minimal Markdown',
|
||||
identifier: FeatureIdentifier.DeprecatedMarkdownMinimistEditor,
|
||||
identifier: NativeFeatureIdentifier.TYPES.DeprecatedMarkdownMinimistEditor,
|
||||
note_type: NoteType.Markdown,
|
||||
file_type: 'md',
|
||||
index_path: 'index.html',
|
||||
@@ -80,7 +80,7 @@ export function GetDeprecatedFeatures(): AnyFeatureDescription[] {
|
||||
|
||||
const markdownMath: EditorFeatureDescription = FillIframeEditorDefaults({
|
||||
name: 'Markdown with Math',
|
||||
identifier: FeatureIdentifier.DeprecatedMarkdownMathEditor,
|
||||
identifier: NativeFeatureIdentifier.TYPES.DeprecatedMarkdownMathEditor,
|
||||
spellcheckControl: true,
|
||||
permission_name: PermissionName.MarkdownMathEditor,
|
||||
note_type: NoteType.Markdown,
|
||||
@@ -94,7 +94,7 @@ export function GetDeprecatedFeatures(): AnyFeatureDescription[] {
|
||||
|
||||
const filesafe: IframeComponentFeatureDescription = FillIframeEditorDefaults({
|
||||
name: 'FileSafe',
|
||||
identifier: FeatureIdentifier.DeprecatedFileSafe,
|
||||
identifier: NativeFeatureIdentifier.TYPES.DeprecatedFileSafe,
|
||||
component_permissions: [
|
||||
{
|
||||
name: ComponentAction.StreamContextItem,
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { PermissionName } from '../Permission/PermissionName'
|
||||
import { FeatureIdentifier } from '../Feature/FeatureIdentifier'
|
||||
import { NativeFeatureIdentifier } from '../Feature/NativeFeatureIdentifier'
|
||||
import { NoteType } from '../Component/NoteType'
|
||||
import { FillIframeEditorDefaults } from './Utilities/FillEditorComponentDefaults'
|
||||
import { RoleName } from '@standardnotes/domain-core'
|
||||
@@ -9,7 +9,7 @@ export function IframeEditors(): IframeComponentFeatureDescription[] {
|
||||
const code = FillIframeEditorDefaults({
|
||||
name: 'Code',
|
||||
spellcheckControl: true,
|
||||
identifier: FeatureIdentifier.CodeEditor,
|
||||
identifier: NativeFeatureIdentifier.TYPES.CodeEditor,
|
||||
permission_name: PermissionName.CodeEditor,
|
||||
note_type: NoteType.Code,
|
||||
file_type: 'txt',
|
||||
@@ -26,7 +26,7 @@ export function IframeEditors(): IframeComponentFeatureDescription[] {
|
||||
name: 'Rich Text',
|
||||
note_type: NoteType.RichText,
|
||||
file_type: 'html',
|
||||
identifier: FeatureIdentifier.PlusEditor,
|
||||
identifier: NativeFeatureIdentifier.TYPES.PlusEditor,
|
||||
permission_name: PermissionName.PlusEditor,
|
||||
spellcheckControl: true,
|
||||
description:
|
||||
@@ -37,7 +37,7 @@ export function IframeEditors(): IframeComponentFeatureDescription[] {
|
||||
|
||||
const markdown = FillIframeEditorDefaults({
|
||||
name: 'Markdown',
|
||||
identifier: FeatureIdentifier.MarkdownProEditor,
|
||||
identifier: NativeFeatureIdentifier.TYPES.MarkdownProEditor,
|
||||
note_type: NoteType.Markdown,
|
||||
file_type: 'md',
|
||||
permission_name: PermissionName.MarkdownProEditor,
|
||||
@@ -50,7 +50,7 @@ export function IframeEditors(): IframeComponentFeatureDescription[] {
|
||||
|
||||
const task = FillIframeEditorDefaults({
|
||||
name: 'Checklist',
|
||||
identifier: FeatureIdentifier.TaskEditor,
|
||||
identifier: NativeFeatureIdentifier.TYPES.TaskEditor,
|
||||
note_type: NoteType.Task,
|
||||
spellcheckControl: true,
|
||||
file_type: 'md',
|
||||
@@ -67,7 +67,7 @@ export function IframeEditors(): IframeComponentFeatureDescription[] {
|
||||
note_type: NoteType.Authentication,
|
||||
file_type: 'json',
|
||||
interchangeable: false,
|
||||
identifier: FeatureIdentifier.TokenVaultEditor,
|
||||
identifier: NativeFeatureIdentifier.TYPES.TokenVaultEditor,
|
||||
permission_name: PermissionName.TokenVaultEditor,
|
||||
description:
|
||||
'Encrypt and protect your 2FA secrets for all your internet accounts. Authenticator handles your 2FA secrets so that you never lose them again, or have to start over when you get a new device.',
|
||||
@@ -77,7 +77,7 @@ export function IframeEditors(): IframeComponentFeatureDescription[] {
|
||||
|
||||
const spreadsheets = FillIframeEditorDefaults({
|
||||
name: 'Spreadsheet',
|
||||
identifier: FeatureIdentifier.SheetsEditor,
|
||||
identifier: NativeFeatureIdentifier.TYPES.SheetsEditor,
|
||||
note_type: NoteType.Spreadsheet,
|
||||
file_type: 'json',
|
||||
interchangeable: false,
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { RoleName } from '@standardnotes/domain-core'
|
||||
import { NoteType } from '../Component/NoteType'
|
||||
import { EditorFeatureDescription } from '../Feature/EditorFeatureDescription'
|
||||
import { FeatureIdentifier } from '../Feature/FeatureIdentifier'
|
||||
import { NativeFeatureIdentifier } from '../Feature/NativeFeatureIdentifier'
|
||||
import { PermissionName } from '../Permission/PermissionName'
|
||||
|
||||
export function nativeEditors(): EditorFeatureDescription[] {
|
||||
@@ -9,7 +9,7 @@ export function nativeEditors(): EditorFeatureDescription[] {
|
||||
{
|
||||
name: 'Super',
|
||||
note_type: NoteType.Super,
|
||||
identifier: FeatureIdentifier.SuperEditor,
|
||||
identifier: NativeFeatureIdentifier.TYPES.SuperEditor,
|
||||
spellcheckControl: true,
|
||||
file_type: 'json',
|
||||
interchangeable: false,
|
||||
@@ -24,7 +24,7 @@ export function nativeEditors(): EditorFeatureDescription[] {
|
||||
spellcheckControl: true,
|
||||
file_type: 'txt',
|
||||
interchangeable: true,
|
||||
identifier: FeatureIdentifier.PlainEditor,
|
||||
identifier: NativeFeatureIdentifier.TYPES.PlainEditor,
|
||||
availableInRoles: [RoleName.NAMES.CoreUser, RoleName.NAMES.PlusUser, RoleName.NAMES.ProUser],
|
||||
permission_name: PermissionName.PlainEditor,
|
||||
},
|
||||
|
||||
@@ -1,67 +1,67 @@
|
||||
import { ServerFeatureDescription } from '../Feature/ServerFeatureDescription'
|
||||
import { PermissionName } from '../Permission/PermissionName'
|
||||
import { FeatureIdentifier } from '../Feature/FeatureIdentifier'
|
||||
import { NativeFeatureIdentifier } from '../Feature/NativeFeatureIdentifier'
|
||||
import { RoleName } from '@standardnotes/domain-core'
|
||||
|
||||
export function serverFeatures(): ServerFeatureDescription[] {
|
||||
return [
|
||||
{
|
||||
name: 'Two factor authentication',
|
||||
identifier: FeatureIdentifier.TwoFactorAuth,
|
||||
identifier: NativeFeatureIdentifier.TYPES.TwoFactorAuth,
|
||||
permission_name: PermissionName.TwoFactorAuth,
|
||||
availableInRoles: [RoleName.NAMES.PlusUser, RoleName.NAMES.ProUser],
|
||||
},
|
||||
{
|
||||
name: 'U2F authentication',
|
||||
identifier: FeatureIdentifier.UniversalSecondFactor,
|
||||
identifier: NativeFeatureIdentifier.TYPES.UniversalSecondFactor,
|
||||
permission_name: PermissionName.UniversalSecondFactor,
|
||||
availableInRoles: [RoleName.NAMES.ProUser],
|
||||
},
|
||||
{
|
||||
name: 'Unlimited note history',
|
||||
identifier: FeatureIdentifier.NoteHistoryUnlimited,
|
||||
identifier: NativeFeatureIdentifier.TYPES.NoteHistoryUnlimited,
|
||||
permission_name: PermissionName.NoteHistoryUnlimited,
|
||||
availableInRoles: [RoleName.NAMES.ProUser],
|
||||
},
|
||||
{
|
||||
name: '365 days note history',
|
||||
identifier: FeatureIdentifier.NoteHistory365Days,
|
||||
identifier: NativeFeatureIdentifier.TYPES.NoteHistory365Days,
|
||||
permission_name: PermissionName.NoteHistory365Days,
|
||||
availableInRoles: [RoleName.NAMES.PlusUser],
|
||||
},
|
||||
{
|
||||
name: 'Email backups',
|
||||
identifier: FeatureIdentifier.DailyEmailBackup,
|
||||
identifier: NativeFeatureIdentifier.TYPES.DailyEmailBackup,
|
||||
permission_name: PermissionName.DailyEmailBackup,
|
||||
availableInRoles: [RoleName.NAMES.PlusUser, RoleName.NAMES.ProUser],
|
||||
},
|
||||
{
|
||||
name: 'Sign-in email alerts',
|
||||
identifier: FeatureIdentifier.SignInAlerts,
|
||||
identifier: NativeFeatureIdentifier.TYPES.SignInAlerts,
|
||||
permission_name: PermissionName.SignInAlerts,
|
||||
availableInRoles: [RoleName.NAMES.PlusUser, RoleName.NAMES.ProUser],
|
||||
},
|
||||
{
|
||||
name: 'Files maximum storage tier',
|
||||
identifier: FeatureIdentifier.FilesMaximumStorageTier,
|
||||
identifier: NativeFeatureIdentifier.TYPES.FilesMaximumStorageTier,
|
||||
permission_name: PermissionName.FilesMaximumStorageTier,
|
||||
availableInRoles: [RoleName.NAMES.ProUser],
|
||||
},
|
||||
{
|
||||
name: 'Files low storage tier',
|
||||
identifier: FeatureIdentifier.FilesLowStorageTier,
|
||||
identifier: NativeFeatureIdentifier.TYPES.FilesLowStorageTier,
|
||||
permission_name: PermissionName.FilesLowStorageTier,
|
||||
availableInRoles: [RoleName.NAMES.PlusUser],
|
||||
},
|
||||
{
|
||||
name: 'Files medium storage tier',
|
||||
identifier: FeatureIdentifier.SubscriptionSharing,
|
||||
identifier: NativeFeatureIdentifier.TYPES.SubscriptionSharing,
|
||||
permission_name: PermissionName.SubscriptionSharing,
|
||||
availableInRoles: [RoleName.NAMES.ProUser],
|
||||
},
|
||||
{
|
||||
name: 'Listed Custom Domain',
|
||||
identifier: FeatureIdentifier.ListedCustomDomain,
|
||||
identifier: NativeFeatureIdentifier.TYPES.ListedCustomDomain,
|
||||
permission_name: PermissionName.ListedCustomDomain,
|
||||
availableInRoles: [RoleName.NAMES.PlusUser, RoleName.NAMES.ProUser],
|
||||
},
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
import { ThemeFeatureDescription } from '../Feature/ThemeFeatureDescription'
|
||||
import { PermissionName } from '../Permission/PermissionName'
|
||||
import { FeatureIdentifier } from '../Feature/FeatureIdentifier'
|
||||
import { NativeFeatureIdentifier } from '../Feature/NativeFeatureIdentifier'
|
||||
import { FillThemeComponentDefaults } from './Utilities/FillThemeComponentDefaults'
|
||||
import { RoleName } from '@standardnotes/domain-core'
|
||||
|
||||
export function themes(): ThemeFeatureDescription[] {
|
||||
const midnight: ThemeFeatureDescription = FillThemeComponentDefaults({
|
||||
name: 'Midnight',
|
||||
identifier: FeatureIdentifier.MidnightTheme,
|
||||
identifier: NativeFeatureIdentifier.TYPES.MidnightTheme,
|
||||
permission_name: PermissionName.MidnightTheme,
|
||||
isDark: true,
|
||||
dock_icon: {
|
||||
@@ -22,7 +22,7 @@ export function themes(): ThemeFeatureDescription[] {
|
||||
const futura: ThemeFeatureDescription = FillThemeComponentDefaults({
|
||||
availableInRoles: [RoleName.NAMES.PlusUser, RoleName.NAMES.ProUser],
|
||||
name: 'Futura',
|
||||
identifier: FeatureIdentifier.FuturaTheme,
|
||||
identifier: NativeFeatureIdentifier.TYPES.FuturaTheme,
|
||||
permission_name: PermissionName.FuturaTheme,
|
||||
isDark: true,
|
||||
dock_icon: {
|
||||
@@ -36,7 +36,7 @@ export function themes(): ThemeFeatureDescription[] {
|
||||
const solarizedDark: ThemeFeatureDescription = FillThemeComponentDefaults({
|
||||
availableInRoles: [RoleName.NAMES.PlusUser, RoleName.NAMES.ProUser],
|
||||
name: 'Solarized Dark',
|
||||
identifier: FeatureIdentifier.SolarizedDarkTheme,
|
||||
identifier: NativeFeatureIdentifier.TYPES.SolarizedDarkTheme,
|
||||
permission_name: PermissionName.SolarizedDarkTheme,
|
||||
isDark: true,
|
||||
dock_icon: {
|
||||
@@ -50,7 +50,7 @@ export function themes(): ThemeFeatureDescription[] {
|
||||
const autobiography: ThemeFeatureDescription = FillThemeComponentDefaults({
|
||||
availableInRoles: [RoleName.NAMES.PlusUser, RoleName.NAMES.ProUser],
|
||||
name: 'Autobiography',
|
||||
identifier: FeatureIdentifier.AutobiographyTheme,
|
||||
identifier: NativeFeatureIdentifier.TYPES.AutobiographyTheme,
|
||||
permission_name: PermissionName.AutobiographyTheme,
|
||||
dock_icon: {
|
||||
type: 'circle',
|
||||
@@ -63,7 +63,7 @@ export function themes(): ThemeFeatureDescription[] {
|
||||
const dark: ThemeFeatureDescription = FillThemeComponentDefaults({
|
||||
availableInRoles: [RoleName.NAMES.CoreUser, RoleName.NAMES.PlusUser, RoleName.NAMES.ProUser],
|
||||
name: 'Dark',
|
||||
identifier: FeatureIdentifier.DarkTheme,
|
||||
identifier: NativeFeatureIdentifier.TYPES.DarkTheme,
|
||||
permission_name: PermissionName.FocusedTheme,
|
||||
clientControlled: true,
|
||||
isDark: true,
|
||||
@@ -78,7 +78,7 @@ export function themes(): ThemeFeatureDescription[] {
|
||||
const titanium: ThemeFeatureDescription = FillThemeComponentDefaults({
|
||||
availableInRoles: [RoleName.NAMES.PlusUser, RoleName.NAMES.ProUser],
|
||||
name: 'Titanium',
|
||||
identifier: FeatureIdentifier.TitaniumTheme,
|
||||
identifier: NativeFeatureIdentifier.TYPES.TitaniumTheme,
|
||||
permission_name: PermissionName.TitaniumTheme,
|
||||
dock_icon: {
|
||||
type: 'circle',
|
||||
@@ -91,7 +91,7 @@ export function themes(): ThemeFeatureDescription[] {
|
||||
const dynamic: ThemeFeatureDescription = FillThemeComponentDefaults({
|
||||
availableInRoles: [RoleName.NAMES.PlusUser, RoleName.NAMES.ProUser],
|
||||
name: 'Dynamic Panels',
|
||||
identifier: FeatureIdentifier.DynamicTheme,
|
||||
identifier: NativeFeatureIdentifier.TYPES.DynamicTheme,
|
||||
permission_name: PermissionName.ThemeDynamic,
|
||||
layerable: true,
|
||||
no_mobile: true,
|
||||
|
||||
@@ -37,5 +37,5 @@ export enum PermissionName {
|
||||
UniversalSecondFactor = 'server:universal-second-factor',
|
||||
SubscriptionSharing = 'server:subscription-sharing',
|
||||
SuperEditor = 'editor:super-editor',
|
||||
Extension = 'app:extension',
|
||||
Clipper = 'app:clipper',
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
export * from './Feature/AnyFeatureDescription'
|
||||
export * from './Feature/FeatureIdentifier'
|
||||
export * from './Feature/NativeFeatureIdentifier'
|
||||
export * from './Feature/Features'
|
||||
export * from './Feature/TypeGuards'
|
||||
|
||||
@@ -22,4 +22,3 @@ export * from './Component/ComponentFlag'
|
||||
export * from './Component/ComponentPermission'
|
||||
export * from './Component/NoteType'
|
||||
export * from './Component/ThemeDockIcon'
|
||||
export * from './Component/EditorIdentifier'
|
||||
|
||||
@@ -3,6 +3,22 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.28.66](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-07-27)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/filepicker
|
||||
|
||||
## [1.28.65](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-07-27)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/filepicker
|
||||
|
||||
## [1.28.64](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-07-26)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/filepicker
|
||||
|
||||
## [1.28.63](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-07-26)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/filepicker
|
||||
|
||||
## [1.28.62](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-07-23)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/filepicker
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/filepicker",
|
||||
"version": "1.28.62",
|
||||
"version": "1.28.66",
|
||||
"engines": {
|
||||
"node": ">=16.0.0 <17.0.0"
|
||||
},
|
||||
|
||||
@@ -3,6 +3,22 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.16.12](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-07-27)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/files
|
||||
|
||||
## [1.16.11](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-07-27)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/files
|
||||
|
||||
## [1.16.10](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-07-26)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/files
|
||||
|
||||
## [1.16.9](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-07-26)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/files
|
||||
|
||||
## [1.16.8](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-07-23)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/files
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/files",
|
||||
"version": "1.16.8",
|
||||
"version": "1.16.12",
|
||||
"engines": {
|
||||
"node": ">=16.0.0 <17.0.0"
|
||||
},
|
||||
|
||||
@@ -3,6 +3,30 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [3.56.29](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-07-27)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/mobile
|
||||
|
||||
## [3.56.28](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-07-27)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/mobile
|
||||
|
||||
## [3.56.27](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-07-26)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/mobile
|
||||
|
||||
## [3.56.26](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-07-26)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/mobile
|
||||
|
||||
## [3.56.25](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-07-26)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/mobile
|
||||
|
||||
## [3.56.24](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-07-25)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/mobile
|
||||
|
||||
## [3.56.23](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-07-25)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/mobile
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/mobile",
|
||||
"version": "3.56.23",
|
||||
"version": "3.56.29",
|
||||
"author": "Standard Notes.",
|
||||
"private": true,
|
||||
"license": "AGPL-3.0-or-later",
|
||||
|
||||
@@ -3,6 +3,24 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.46.16](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-07-27)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/models
|
||||
|
||||
## [1.46.15](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-07-27)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/models
|
||||
|
||||
## [1.46.14](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-07-26)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* Fixes issue where lock screen would not use previously active theme ([#2372](https://github.com/standardnotes/app/issues/2372)) ([d268c02](https://github.com/standardnotes/app/commit/d268c02ab31beb5e2fd9e6547610f9a4dd61bed4))
|
||||
|
||||
## [1.46.13](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-07-26)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/models
|
||||
|
||||
## [1.46.12](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-07-23)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/models
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/models",
|
||||
"version": "1.46.12",
|
||||
"version": "1.46.16",
|
||||
"engines": {
|
||||
"node": ">=16.0.0 <17.0.0"
|
||||
},
|
||||
@@ -23,7 +23,7 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@standardnotes/common": "^1.50.0",
|
||||
"@standardnotes/domain-core": "^1.22.0",
|
||||
"@standardnotes/domain-core": "^1.24.0",
|
||||
"@standardnotes/features": "workspace:*",
|
||||
"@standardnotes/responses": "workspace:*",
|
||||
"@standardnotes/sncrypto-common": "workspace:^",
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
export enum KeySystemRootKeyPasswordType {
|
||||
export enum KeySystemPasswordType {
|
||||
UserInputted = 'user_inputted',
|
||||
Randomized = 'randomized',
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
import { ProtocolVersion } from '@standardnotes/common'
|
||||
import { KeySystemIdentifier } from '../../Syncable/KeySystemRootKey/KeySystemIdentifier'
|
||||
import { KeySystemRootKeyPasswordType } from './KeySystemRootKeyPasswordType'
|
||||
import { KeySystemPasswordType } from './KeySystemPasswordType'
|
||||
|
||||
/**
|
||||
* Key params are public data that contain information about how a root key was created.
|
||||
@@ -11,6 +11,6 @@ export interface KeySystemRootKeyParamsInterface {
|
||||
systemIdentifier: KeySystemIdentifier
|
||||
seed: string
|
||||
version: ProtocolVersion
|
||||
passwordType: KeySystemRootKeyPasswordType
|
||||
passwordType: KeySystemPasswordType
|
||||
creationTimestamp: number
|
||||
}
|
||||
|
||||
@@ -0,0 +1,127 @@
|
||||
import {
|
||||
Collection,
|
||||
DecryptedCollectionElement,
|
||||
DeletedCollectionElement,
|
||||
EncryptedCollectionElement,
|
||||
} from './Collection'
|
||||
import { FullyFormedPayloadInterface } from '../../Abstract/Payload'
|
||||
|
||||
class TestCollection<P extends FullyFormedPayloadInterface = FullyFormedPayloadInterface> extends Collection<
|
||||
P,
|
||||
DecryptedCollectionElement,
|
||||
EncryptedCollectionElement,
|
||||
DeletedCollectionElement
|
||||
> {}
|
||||
|
||||
describe('Collection', () => {
|
||||
let collection: TestCollection
|
||||
|
||||
beforeEach(() => {
|
||||
collection = new TestCollection()
|
||||
})
|
||||
|
||||
it('should initialize correctly', () => {
|
||||
expect(collection.map).toEqual({})
|
||||
expect(collection.typedMap).toEqual({})
|
||||
expect(collection.referenceMap).toBeDefined()
|
||||
expect(collection.conflictMap).toBeDefined()
|
||||
})
|
||||
|
||||
it('should set and get element correctly', () => {
|
||||
const testElement = {
|
||||
uuid: 'test-uuid',
|
||||
content_type: 'test-type',
|
||||
content: {},
|
||||
references: [],
|
||||
} as unknown as FullyFormedPayloadInterface
|
||||
|
||||
collection.set(testElement)
|
||||
const element = collection.find('test-uuid')
|
||||
|
||||
expect(element).toBe(testElement)
|
||||
})
|
||||
|
||||
it('should check existence of an element correctly', () => {
|
||||
const testElement = {
|
||||
uuid: 'test-uuid',
|
||||
content_type: 'test-type',
|
||||
content: {},
|
||||
references: [],
|
||||
} as unknown as FullyFormedPayloadInterface
|
||||
|
||||
collection.set(testElement)
|
||||
const hasElement = collection.has('test-uuid')
|
||||
|
||||
expect(hasElement).toBe(true)
|
||||
})
|
||||
|
||||
it('should return all elements', () => {
|
||||
const testElement1 = {
|
||||
uuid: 'test-uuid-1',
|
||||
content_type: 'test-type',
|
||||
content: {},
|
||||
references: [],
|
||||
} as unknown as FullyFormedPayloadInterface
|
||||
|
||||
const testElement2 = {
|
||||
uuid: 'test-uuid-2',
|
||||
content_type: 'test-type',
|
||||
content: {},
|
||||
references: [],
|
||||
} as unknown as FullyFormedPayloadInterface
|
||||
|
||||
collection.set(testElement1)
|
||||
collection.set(testElement2)
|
||||
|
||||
const allElements = collection.all()
|
||||
|
||||
expect(allElements).toEqual([testElement1, testElement2])
|
||||
})
|
||||
|
||||
it('should add uuid to invalidsIndex if element is error decrypting', () => {
|
||||
const testElement = {
|
||||
uuid: 'test-uuid',
|
||||
content_type: 'test-type',
|
||||
content: 'encrypted content',
|
||||
errorDecrypting: true,
|
||||
} as unknown as FullyFormedPayloadInterface
|
||||
|
||||
collection.set(testElement)
|
||||
|
||||
expect(collection.invalidsIndex.has(testElement.uuid)).toBe(true)
|
||||
})
|
||||
|
||||
it('should add uuid to invalidsIndex if element is encrypted', () => {
|
||||
const testElement = {
|
||||
uuid: 'test-uuid',
|
||||
content_type: 'test-type',
|
||||
content: 'encrypted content',
|
||||
} as unknown as FullyFormedPayloadInterface
|
||||
|
||||
collection.set(testElement)
|
||||
|
||||
expect(collection.invalidsIndex.has(testElement.uuid)).toBe(true)
|
||||
})
|
||||
|
||||
it('should remove uuid from invalidsIndex if element is not encrypted', () => {
|
||||
const testElement1 = {
|
||||
uuid: 'test-uuid-1',
|
||||
content_type: 'test-type',
|
||||
content: 'encrypted content',
|
||||
errorDecrypting: true,
|
||||
} as unknown as FullyFormedPayloadInterface
|
||||
|
||||
const testElement2 = {
|
||||
uuid: 'test-uuid-1',
|
||||
content_type: 'test-type',
|
||||
content: {},
|
||||
references: [],
|
||||
} as unknown as FullyFormedPayloadInterface
|
||||
|
||||
collection.set(testElement1)
|
||||
expect(collection.invalidsIndex.has(testElement1.uuid)).toBe(true)
|
||||
|
||||
collection.set(testElement2)
|
||||
expect(collection.invalidsIndex.has(testElement2.uuid)).toBe(false)
|
||||
})
|
||||
})
|
||||
@@ -59,7 +59,7 @@ export abstract class Collection<
|
||||
}
|
||||
|
||||
isErrorDecryptingElement = (e: Decrypted | Encrypted | Deleted): e is Encrypted => {
|
||||
return this.isEncryptedElement(e) && e.errorDecrypting === true
|
||||
return this.isEncryptedElement(e)
|
||||
}
|
||||
|
||||
isDeletedElement = (e: Decrypted | Encrypted | Deleted): e is Deleted => {
|
||||
@@ -78,10 +78,10 @@ export abstract class Collection<
|
||||
conflictMapCopy?: UuidMap,
|
||||
) {
|
||||
if (copy) {
|
||||
this.map = mapCopy!
|
||||
this.typedMap = typedMapCopy!
|
||||
this.referenceMap = referenceMapCopy!
|
||||
this.conflictMap = conflictMapCopy!
|
||||
this.map = mapCopy as Record<string, Element>
|
||||
this.typedMap = typedMapCopy as Record<string, Element[]>
|
||||
this.referenceMap = referenceMapCopy as UuidMap
|
||||
this.conflictMap = conflictMapCopy as UuidMap
|
||||
} else {
|
||||
this.referenceMap = new UuidMap()
|
||||
this.conflictMap = new UuidMap()
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import { ImmutablePayloadCollection } from '../Collection/Payload/ImmutablePayloadCollection'
|
||||
import { ConflictDelta } from './Conflict'
|
||||
import { DecryptedPayloadInterface } from '../../Abstract/Payload/Interfaces/DecryptedPayload'
|
||||
import { DeletedPayloadInterface, isDecryptedPayload, PayloadEmitSource } from '../../Abstract/Payload'
|
||||
import { FullyFormedPayloadInterface, isDecryptedPayload, PayloadEmitSource } from '../../Abstract/Payload'
|
||||
import { HistoryMap } from '../History'
|
||||
import { extendSyncDelta, SourcelessSyncDeltaEmit, SyncDeltaEmit } from './Abstract/DeltaEmit'
|
||||
import { DeltaInterface } from './Abstract/DeltaInterface'
|
||||
@@ -11,7 +10,7 @@ import { getIncrementedDirtyIndex } from '../DirtyCounter/DirtyCounter'
|
||||
export class DeltaFileImport implements DeltaInterface {
|
||||
constructor(
|
||||
readonly baseCollection: ImmutablePayloadCollection,
|
||||
private readonly applyPayloads: DecryptedPayloadInterface[],
|
||||
private readonly applyPayloads: FullyFormedPayloadInterface[],
|
||||
protected readonly historyMap: HistoryMap,
|
||||
) {}
|
||||
|
||||
@@ -31,10 +30,7 @@ export class DeltaFileImport implements DeltaInterface {
|
||||
return result
|
||||
}
|
||||
|
||||
private resolvePayload(
|
||||
payload: DecryptedPayloadInterface | DeletedPayloadInterface,
|
||||
currentResults: SyncDeltaEmit,
|
||||
): SourcelessSyncDeltaEmit {
|
||||
private resolvePayload(payload: FullyFormedPayloadInterface, currentResults: SyncDeltaEmit): SourcelessSyncDeltaEmit {
|
||||
/**
|
||||
* Check to see if we've already processed a payload for this id.
|
||||
* If so, that would be the latest value, and not what's in the base collection.
|
||||
|
||||
@@ -6,11 +6,7 @@ import {
|
||||
NoteType,
|
||||
UIFeatureDescriptionTypes,
|
||||
} from '@standardnotes/features'
|
||||
import {
|
||||
isUIFeatureAnIframeFeature,
|
||||
isComponentOrFeatureDescriptionAComponent,
|
||||
isComponentOrFeatureDescriptionAFeatureDescription,
|
||||
} from './TypeGuards'
|
||||
import { isUIFeatureAnIframeFeature, isItemBasedFeature, isNativeFeature } from './TypeGuards'
|
||||
import { UIFeature } from './UIFeature'
|
||||
import { ComponentInterface } from '../../Syncable/Component'
|
||||
import { ContentType } from '@standardnotes/domain-core'
|
||||
@@ -45,7 +41,7 @@ describe('TypeGuards', () => {
|
||||
uuid: 'abc-123',
|
||||
} as ComponentInterface
|
||||
|
||||
expect(isComponentOrFeatureDescriptionAComponent(x)).toBe(true)
|
||||
expect(isItemBasedFeature(x)).toBe(true)
|
||||
})
|
||||
|
||||
it('should return false if feature description is not a component', () => {
|
||||
@@ -53,17 +49,17 @@ describe('TypeGuards', () => {
|
||||
note_type: NoteType.Super,
|
||||
} as jest.Mocked<EditorFeatureDescription>
|
||||
|
||||
expect(isComponentOrFeatureDescriptionAComponent(x)).toBe(false)
|
||||
expect(isItemBasedFeature(x)).toBe(false)
|
||||
})
|
||||
})
|
||||
|
||||
describe('isComponentOrFeatureDescriptionAFeatureDescription', () => {
|
||||
describe('isNativeFeature', () => {
|
||||
it('should return true if x is a feature description', () => {
|
||||
const x: AnyFeatureDescription = {
|
||||
content_type: 'TestContentType',
|
||||
} as AnyFeatureDescription
|
||||
|
||||
expect(isComponentOrFeatureDescriptionAFeatureDescription(x)).toBe(true)
|
||||
expect(isNativeFeature(x)).toBe(true)
|
||||
})
|
||||
|
||||
it('should return false if x is a component', () => {
|
||||
@@ -71,7 +67,7 @@ describe('TypeGuards', () => {
|
||||
uuid: 'abc-123',
|
||||
} as ComponentInterface
|
||||
|
||||
expect(isComponentOrFeatureDescriptionAFeatureDescription(x)).toBe(false)
|
||||
expect(isNativeFeature(x)).toBe(false)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@@ -14,14 +14,10 @@ export function isUIFeatureAnIframeFeature(
|
||||
return isIframeComponentFeatureDescription(x.featureDescription)
|
||||
}
|
||||
|
||||
export function isComponentOrFeatureDescriptionAComponent(
|
||||
x: ComponentInterface | UIFeatureDescriptionTypes,
|
||||
): x is ComponentInterface {
|
||||
export function isItemBasedFeature(x: ComponentInterface | UIFeatureDescriptionTypes): x is ComponentInterface {
|
||||
return 'uuid' in x
|
||||
}
|
||||
|
||||
export function isComponentOrFeatureDescriptionAFeatureDescription(
|
||||
x: ComponentInterface | AnyFeatureDescription,
|
||||
): x is AnyFeatureDescription {
|
||||
export function isNativeFeature(x: ComponentInterface | AnyFeatureDescription): x is AnyFeatureDescription {
|
||||
return !('uuid' in x)
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@ import {
|
||||
ComponentArea,
|
||||
ComponentPermission,
|
||||
EditorFeatureDescription,
|
||||
FeatureIdentifier,
|
||||
NativeFeatureIdentifier,
|
||||
NoteType,
|
||||
ThemeDockIcon,
|
||||
UIFeatureDescriptionTypes,
|
||||
@@ -12,29 +12,27 @@ import {
|
||||
} from '@standardnotes/features'
|
||||
import { ComponentInterface } from '../../Syncable/Component/ComponentInterface'
|
||||
import { isTheme } from '../../Syncable/Theme'
|
||||
import {
|
||||
isComponentOrFeatureDescriptionAComponent,
|
||||
isComponentOrFeatureDescriptionAFeatureDescription,
|
||||
} from './TypeGuards'
|
||||
import { isItemBasedFeature, isNativeFeature } from './TypeGuards'
|
||||
import { UIFeatureInterface } from './UIFeatureInterface'
|
||||
import { Uuid } from '@standardnotes/domain-core'
|
||||
|
||||
export class UIFeature<F extends UIFeatureDescriptionTypes> implements UIFeatureInterface<F> {
|
||||
constructor(public readonly item: ComponentInterface | F) {}
|
||||
|
||||
get isComponent(): boolean {
|
||||
return isComponentOrFeatureDescriptionAComponent(this.item)
|
||||
return isItemBasedFeature(this.item)
|
||||
}
|
||||
|
||||
get isFeatureDescription(): boolean {
|
||||
return isComponentOrFeatureDescriptionAFeatureDescription(this.item)
|
||||
return isNativeFeature(this.item)
|
||||
}
|
||||
|
||||
get isThemeComponent(): boolean {
|
||||
return isComponentOrFeatureDescriptionAComponent(this.item) && isTheme(this.item)
|
||||
return isItemBasedFeature(this.item) && isTheme(this.item)
|
||||
}
|
||||
|
||||
get asComponent(): ComponentInterface {
|
||||
if (isComponentOrFeatureDescriptionAComponent(this.item)) {
|
||||
if (isItemBasedFeature(this.item)) {
|
||||
return this.item
|
||||
}
|
||||
|
||||
@@ -42,29 +40,30 @@ export class UIFeature<F extends UIFeatureDescriptionTypes> implements UIFeature
|
||||
}
|
||||
|
||||
get asFeatureDescription(): F {
|
||||
if (isComponentOrFeatureDescriptionAFeatureDescription(this.item)) {
|
||||
if (isNativeFeature(this.item)) {
|
||||
return this.item
|
||||
}
|
||||
|
||||
throw new Error('Cannot cast item to feature description')
|
||||
}
|
||||
|
||||
get uniqueIdentifier(): string {
|
||||
if (isComponentOrFeatureDescriptionAFeatureDescription(this.item)) {
|
||||
return this.item.identifier
|
||||
get uniqueIdentifier(): NativeFeatureIdentifier | Uuid {
|
||||
if (isNativeFeature(this.item)) {
|
||||
const nativeFeature = NativeFeatureIdentifier.create(this.item.identifier)
|
||||
return nativeFeature.getValue()
|
||||
} else {
|
||||
return this.item.uuid
|
||||
return Uuid.create(this.item.uuid).getValue()
|
||||
}
|
||||
}
|
||||
|
||||
get featureIdentifier(): FeatureIdentifier {
|
||||
get featureIdentifier(): string {
|
||||
return this.item.identifier
|
||||
}
|
||||
|
||||
get noteType(): NoteType {
|
||||
if (isComponentOrFeatureDescriptionAFeatureDescription(this.item) && isEditorFeatureDescription(this.item)) {
|
||||
if (isNativeFeature(this.item) && isEditorFeatureDescription(this.item)) {
|
||||
return this.item.note_type ?? NoteType.Unknown
|
||||
} else if (isComponentOrFeatureDescriptionAComponent(this.item)) {
|
||||
} else if (isItemBasedFeature(this.item)) {
|
||||
return this.item.noteType
|
||||
}
|
||||
|
||||
@@ -72,12 +71,9 @@ export class UIFeature<F extends UIFeatureDescriptionTypes> implements UIFeature
|
||||
}
|
||||
|
||||
get fileType(): EditorFeatureDescription['file_type'] {
|
||||
if (isComponentOrFeatureDescriptionAFeatureDescription(this.item) && isEditorFeatureDescription(this.item)) {
|
||||
if (isNativeFeature(this.item) && isEditorFeatureDescription(this.item)) {
|
||||
return this.item.file_type
|
||||
} else if (
|
||||
isComponentOrFeatureDescriptionAComponent(this.item) &&
|
||||
isEditorFeatureDescription(this.item.package_info)
|
||||
) {
|
||||
} else if (isItemBasedFeature(this.item) && isEditorFeatureDescription(this.item.package_info)) {
|
||||
return this.item.package_info?.file_type ?? 'txt'
|
||||
}
|
||||
|
||||
@@ -85,7 +81,7 @@ export class UIFeature<F extends UIFeatureDescriptionTypes> implements UIFeature
|
||||
}
|
||||
|
||||
get displayName(): string {
|
||||
if (isComponentOrFeatureDescriptionAFeatureDescription(this.item)) {
|
||||
if (isNativeFeature(this.item)) {
|
||||
return this.item.name ?? ''
|
||||
} else {
|
||||
return this.item.displayName
|
||||
@@ -93,7 +89,7 @@ export class UIFeature<F extends UIFeatureDescriptionTypes> implements UIFeature
|
||||
}
|
||||
|
||||
get description(): string {
|
||||
if (isComponentOrFeatureDescriptionAFeatureDescription(this.item)) {
|
||||
if (isNativeFeature(this.item)) {
|
||||
return this.item.description ?? ''
|
||||
} else {
|
||||
return this.item.package_info.description ?? ''
|
||||
@@ -101,7 +97,7 @@ export class UIFeature<F extends UIFeatureDescriptionTypes> implements UIFeature
|
||||
}
|
||||
|
||||
get deprecationMessage(): string | undefined {
|
||||
if (isComponentOrFeatureDescriptionAFeatureDescription(this.item)) {
|
||||
if (isNativeFeature(this.item)) {
|
||||
return this.item.deprecation_message
|
||||
} else {
|
||||
return this.item.deprecationMessage
|
||||
@@ -109,7 +105,7 @@ export class UIFeature<F extends UIFeatureDescriptionTypes> implements UIFeature
|
||||
}
|
||||
|
||||
get expirationDate(): Date | undefined {
|
||||
if (isComponentOrFeatureDescriptionAFeatureDescription(this.item)) {
|
||||
if (isNativeFeature(this.item)) {
|
||||
return this.item.expires_at ? new Date(this.item.expires_at) : undefined
|
||||
} else {
|
||||
return this.item.valid_until
|
||||
@@ -117,7 +113,7 @@ export class UIFeature<F extends UIFeatureDescriptionTypes> implements UIFeature
|
||||
}
|
||||
|
||||
get featureDescription(): F {
|
||||
if (isComponentOrFeatureDescriptionAFeatureDescription(this.item)) {
|
||||
if (isNativeFeature(this.item)) {
|
||||
return this.item
|
||||
} else {
|
||||
return this.item.package_info as F
|
||||
@@ -125,12 +121,9 @@ export class UIFeature<F extends UIFeatureDescriptionTypes> implements UIFeature
|
||||
}
|
||||
|
||||
get acquiredPermissions(): ComponentPermission[] {
|
||||
if (
|
||||
isComponentOrFeatureDescriptionAFeatureDescription(this.item) &&
|
||||
isIframeComponentFeatureDescription(this.item)
|
||||
) {
|
||||
if (isNativeFeature(this.item) && isIframeComponentFeatureDescription(this.item)) {
|
||||
return this.item.component_permissions ?? []
|
||||
} else if (isComponentOrFeatureDescriptionAComponent(this.item)) {
|
||||
} else if (isItemBasedFeature(this.item)) {
|
||||
return this.item.permissions
|
||||
}
|
||||
|
||||
@@ -146,7 +139,7 @@ export class UIFeature<F extends UIFeatureDescriptionTypes> implements UIFeature
|
||||
}
|
||||
|
||||
get layerable(): boolean {
|
||||
if (isComponentOrFeatureDescriptionAComponent(this.item) && isTheme(this.item)) {
|
||||
if (isItemBasedFeature(this.item) && isTheme(this.item)) {
|
||||
return this.item.layerable
|
||||
} else if (isThemeFeatureDescription(this.asFeatureDescription)) {
|
||||
return this.asFeatureDescription.layerable ?? false
|
||||
@@ -156,7 +149,7 @@ export class UIFeature<F extends UIFeatureDescriptionTypes> implements UIFeature
|
||||
}
|
||||
|
||||
get dockIcon(): ThemeDockIcon | undefined {
|
||||
if (isComponentOrFeatureDescriptionAComponent(this.item) && isTheme(this.item)) {
|
||||
if (isItemBasedFeature(this.item) && isTheme(this.item)) {
|
||||
return this.item.package_info.dock_icon
|
||||
} else if (isThemeFeatureDescription(this.asFeatureDescription)) {
|
||||
return this.asFeatureDescription.dock_icon
|
||||
|
||||
@@ -2,12 +2,13 @@ import {
|
||||
ComponentArea,
|
||||
ComponentPermission,
|
||||
EditorFeatureDescription,
|
||||
FeatureIdentifier,
|
||||
NativeFeatureIdentifier,
|
||||
NoteType,
|
||||
ThemeDockIcon,
|
||||
UIFeatureDescriptionTypes,
|
||||
} from '@standardnotes/features'
|
||||
import { ComponentInterface } from '../../Syncable/Component'
|
||||
import { Uuid } from '@standardnotes/domain-core'
|
||||
|
||||
export interface UIFeatureInterface<F extends UIFeatureDescriptionTypes> {
|
||||
item: ComponentInterface | F
|
||||
@@ -16,8 +17,8 @@ export interface UIFeatureInterface<F extends UIFeatureDescriptionTypes> {
|
||||
get isThemeComponent(): boolean
|
||||
get asComponent(): ComponentInterface
|
||||
get asFeatureDescription(): F
|
||||
get uniqueIdentifier(): string
|
||||
get featureIdentifier(): FeatureIdentifier
|
||||
get uniqueIdentifier(): NativeFeatureIdentifier | Uuid
|
||||
get featureIdentifier(): string
|
||||
get noteType(): NoteType
|
||||
get fileType(): EditorFeatureDescription['file_type']
|
||||
get displayName(): string
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import { isValidUrl } from '@standardnotes/utils'
|
||||
import {
|
||||
FeatureIdentifier,
|
||||
ThirdPartyFeatureDescription,
|
||||
ComponentArea,
|
||||
ComponentFlag,
|
||||
@@ -175,7 +174,7 @@ export class SNComponent extends DecryptedItem<ComponentContent> implements Comp
|
||||
return this.valid_until.getTime() > 0 && this.valid_until <= new Date()
|
||||
}
|
||||
|
||||
public get identifier(): FeatureIdentifier {
|
||||
public get identifier(): string {
|
||||
return this.package_info.identifier
|
||||
}
|
||||
|
||||
|
||||
@@ -1,10 +1,4 @@
|
||||
import {
|
||||
ComponentArea,
|
||||
ComponentPermission,
|
||||
FeatureIdentifier,
|
||||
NoteType,
|
||||
ThirdPartyFeatureDescription,
|
||||
} from '@standardnotes/features'
|
||||
import { ComponentArea, ComponentPermission, NoteType, ThirdPartyFeatureDescription } from '@standardnotes/features'
|
||||
import { ComponentPackageInfo } from './PackageInfo'
|
||||
import { DecryptedItemInterface } from '../../Abstract/Item'
|
||||
import { ComponentContent } from './ComponentContent'
|
||||
@@ -35,7 +29,7 @@ export interface ComponentInterface extends DecryptedItemInterface<ComponentCont
|
||||
isExplicitlyDisabledForItem(uuid: string): boolean
|
||||
legacyIsDefaultEditor(): boolean
|
||||
|
||||
get identifier(): FeatureIdentifier
|
||||
get identifier(): string
|
||||
get noteType(): NoteType
|
||||
get displayName(): string
|
||||
get deprecationMessage(): string | undefined
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { AppDataField } from './../../Abstract/Item/Types/AppDataField'
|
||||
import { FeatureIdentifier, NoteType } from '@standardnotes/features'
|
||||
import { NoteType } from '@standardnotes/features'
|
||||
import { DecryptedItem } from '../../Abstract/Item/Implementations/DecryptedItem'
|
||||
import { ItemInterface } from '../../Abstract/Item/Interfaces/ItemInterface'
|
||||
import { DecryptedPayloadInterface } from '../../Abstract/Payload/Interfaces/DecryptedPayload'
|
||||
@@ -21,7 +21,7 @@ export class SNNote extends DecryptedItem<NoteContent> implements NoteContentSpe
|
||||
public readonly authorizedForListed: boolean
|
||||
|
||||
/** The package_info.identifier of the editor (not its uuid), such as org.standardnotes.advanced-markdown */
|
||||
public readonly editorIdentifier?: FeatureIdentifier | string
|
||||
public readonly editorIdentifier?: string
|
||||
|
||||
constructor(payload: DecryptedPayloadInterface<NoteContent>) {
|
||||
super(payload)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { FeatureIdentifier, NoteType } from '@standardnotes/features'
|
||||
import { NoteType } from '@standardnotes/features'
|
||||
import { ItemContent } from '../../Abstract/Content/ItemContent'
|
||||
import { EditorLineWidth } from '../UserPrefs'
|
||||
|
||||
@@ -11,7 +11,7 @@ export interface NoteContentSpecialized {
|
||||
spellcheck?: boolean
|
||||
editorWidth?: EditorLineWidth
|
||||
noteType?: NoteType
|
||||
editorIdentifier?: FeatureIdentifier | string
|
||||
editorIdentifier?: string
|
||||
authorizedForListed?: boolean
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { NoteMutator } from './NoteMutator'
|
||||
import { createNote } from './../../Utilities/Test/SpecUtils'
|
||||
import { MutationType } from '../../Abstract/Item'
|
||||
import { FeatureIdentifier, NoteType } from '@standardnotes/features'
|
||||
import { NativeFeatureIdentifier, NoteType } from '@standardnotes/features'
|
||||
|
||||
describe('note mutator', () => {
|
||||
it('sets noteType', () => {
|
||||
@@ -16,9 +16,9 @@ describe('note mutator', () => {
|
||||
it('sets componentIdentifier', () => {
|
||||
const note = createNote({})
|
||||
const mutator = new NoteMutator(note, MutationType.NoUpdateUserTimestamps)
|
||||
mutator.editorIdentifier = FeatureIdentifier.MarkdownProEditor
|
||||
mutator.editorIdentifier = NativeFeatureIdentifier.TYPES.MarkdownProEditor
|
||||
const result = mutator.getResult()
|
||||
|
||||
expect(result.content.editorIdentifier).toEqual(FeatureIdentifier.MarkdownProEditor)
|
||||
expect(result.content.editorIdentifier).toEqual(NativeFeatureIdentifier.TYPES.MarkdownProEditor)
|
||||
})
|
||||
})
|
||||
|
||||
@@ -3,7 +3,7 @@ import { DecryptedItemMutator } from '../../Abstract/Item/Mutator/DecryptedItemM
|
||||
import { SNNote } from './Note'
|
||||
import { NoteToNoteReference } from '../../Abstract/Reference/NoteToNoteReference'
|
||||
import { ContentReferenceType } from '../../Abstract/Item'
|
||||
import { FeatureIdentifier, NoteType } from '@standardnotes/features'
|
||||
import { NoteType } from '@standardnotes/features'
|
||||
import { EditorLineWidth } from '../UserPrefs'
|
||||
import { ContentType } from '@standardnotes/domain-core'
|
||||
|
||||
@@ -40,7 +40,7 @@ export class NoteMutator extends DecryptedItemMutator<NoteContent> {
|
||||
this.mutableContent.noteType = noteType
|
||||
}
|
||||
|
||||
set editorIdentifier(identifier: FeatureIdentifier | string | undefined) {
|
||||
set editorIdentifier(identifier: string | undefined) {
|
||||
this.mutableContent.editorIdentifier = identifier
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import { EditorIdentifier } from '@standardnotes/features'
|
||||
import { NewNoteTitleFormat } from '../UserPrefs'
|
||||
import { CollectionSortProperty } from './../../Runtime/Collection/CollectionSort'
|
||||
|
||||
@@ -15,7 +14,7 @@ export interface TagPreferences {
|
||||
hideEditorIcon?: boolean
|
||||
newNoteTitleFormat?: NewNoteTitleFormat
|
||||
customNoteTitleFormat?: string
|
||||
editorIdentifier?: EditorIdentifier
|
||||
editorIdentifier?: string
|
||||
entryMode?: 'normal' | 'daily'
|
||||
panelWidth?: number
|
||||
useTableView?: boolean
|
||||
|
||||
@@ -1,7 +1,3 @@
|
||||
import { FeatureIdentifier } from '@standardnotes/features'
|
||||
|
||||
type UuidString = string
|
||||
|
||||
export type AllComponentPreferences = Record<FeatureIdentifier | UuidString, ComponentPreferencesEntry>
|
||||
export type AllComponentPreferences = Record<string, ComponentPreferencesEntry>
|
||||
|
||||
export type ComponentPreferencesEntry = Record<string, unknown>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { FeatureIdentifier } from '@standardnotes/features'
|
||||
import { NativeFeatureIdentifier } from '@standardnotes/features'
|
||||
import { CollectionSort } from '../../Runtime/Collection/CollectionSort'
|
||||
import { EditorFontSize } from './EditorFontSize'
|
||||
import { EditorLineHeight } from './EditorLineHeight'
|
||||
@@ -29,7 +29,7 @@ export const PrefDefaults = {
|
||||
[PrefKey.NotesHideEditorIcon]: false,
|
||||
[PrefKey.UseSystemColorScheme]: false,
|
||||
[PrefKey.AutoLightThemeIdentifier]: 'Default',
|
||||
[PrefKey.AutoDarkThemeIdentifier]: FeatureIdentifier.DarkTheme,
|
||||
[PrefKey.AutoDarkThemeIdentifier]: NativeFeatureIdentifier.TYPES.DarkTheme,
|
||||
[PrefKey.NoteAddToParentFolders]: true,
|
||||
[PrefKey.NewNoteTitleFormat]: NewNoteTitleFormat.CurrentDateAndTime,
|
||||
[PrefKey.CustomNoteTitleFormat]: 'YYYY-MM-DD [at] hh:mm A',
|
||||
@@ -37,7 +37,7 @@ export const PrefDefaults = {
|
||||
[PrefKey.PaneGesturesEnabled]: true,
|
||||
[PrefKey.MomentsDefaultTagUuid]: undefined,
|
||||
[PrefKey.ClipperDefaultTagUuid]: undefined,
|
||||
[PrefKey.DefaultEditorIdentifier]: FeatureIdentifier.PlainEditor,
|
||||
[PrefKey.DefaultEditorIdentifier]: NativeFeatureIdentifier.TYPES.PlainEditor,
|
||||
[PrefKey.SuperNoteExportFormat]: 'json',
|
||||
[PrefKey.SystemViewPreferences]: {},
|
||||
[PrefKey.AuthenticatorNames]: '',
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import { CollectionSortProperty } from '../../Runtime/Collection/CollectionSort'
|
||||
import { EditorIdentifier, FeatureIdentifier } from '@standardnotes/features'
|
||||
import { SystemViewId } from '../SmartView'
|
||||
import { TagPreferences } from '../Tag'
|
||||
import { NewNoteTitleFormat } from './NewNoteTitleFormat'
|
||||
@@ -67,8 +66,8 @@ export type PrefValue = {
|
||||
[PrefKey.NotesHideTags]: boolean
|
||||
[PrefKey.NotesHideEditorIcon]: boolean
|
||||
[PrefKey.UseSystemColorScheme]: boolean
|
||||
[PrefKey.AutoLightThemeIdentifier]: FeatureIdentifier | 'Default' | 'Dark'
|
||||
[PrefKey.AutoDarkThemeIdentifier]: FeatureIdentifier | 'Default' | 'Dark'
|
||||
[PrefKey.AutoLightThemeIdentifier]: string
|
||||
[PrefKey.AutoDarkThemeIdentifier]: string
|
||||
[PrefKey.NoteAddToParentFolders]: boolean
|
||||
[PrefKey.NewNoteTitleFormat]: NewNoteTitleFormat
|
||||
[PrefKey.CustomNoteTitleFormat]: string
|
||||
@@ -76,7 +75,7 @@ export type PrefValue = {
|
||||
[PrefKey.EditorLineWidth]: EditorLineWidth
|
||||
[PrefKey.EditorFontSize]: EditorFontSize
|
||||
[PrefKey.UpdateSavingStatusIndicator]: boolean
|
||||
[PrefKey.DefaultEditorIdentifier]: EditorIdentifier
|
||||
[PrefKey.DefaultEditorIdentifier]: string
|
||||
[PrefKey.MomentsDefaultTagUuid]: string | undefined
|
||||
[PrefKey.ClipperDefaultTagUuid]: string | undefined
|
||||
[PrefKey.SystemViewPreferences]: Partial<Record<SystemViewId, TagPreferences>>
|
||||
|
||||
@@ -2,7 +2,7 @@ import { ConflictStrategy, DecryptedItem } from '../../Abstract/Item'
|
||||
import { DecryptedPayloadInterface } from '../../Abstract/Payload'
|
||||
import { HistoryEntryInterface } from '../../Runtime/History'
|
||||
import { KeySystemRootKeyParamsInterface } from '../../Local/KeyParams/KeySystemRootKeyParamsInterface'
|
||||
import { KeySystemRootKeyPasswordType } from '../../Local/KeyParams/KeySystemRootKeyPasswordType'
|
||||
import { KeySystemPasswordType } from '../../Local/KeyParams/KeySystemPasswordType'
|
||||
import { SharedVaultListingInterface, VaultListingInterface } from './VaultListingInterface'
|
||||
import { VaultListingContent } from './VaultListingContent'
|
||||
import { KeySystemRootKeyStorageMode } from '../KeySystemRootKey/KeySystemRootKeyStorageMode'
|
||||
@@ -44,7 +44,7 @@ export class VaultListing extends DecryptedItem<VaultListingContent> implements
|
||||
return incomingKeyTimestamp > baseKeyTimestamp ? ConflictStrategy.KeepApply : ConflictStrategy.KeepBase
|
||||
}
|
||||
|
||||
get keyPasswordType(): KeySystemRootKeyPasswordType {
|
||||
get keyPasswordType(): KeySystemPasswordType {
|
||||
return this.rootKeyParams.passwordType
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { KeySystemIdentifier } from '../KeySystemRootKey/KeySystemIdentifier'
|
||||
import { KeySystemRootKeyParamsInterface } from '../../Local/KeyParams/KeySystemRootKeyParamsInterface'
|
||||
import { KeySystemRootKeyPasswordType } from '../../Local/KeyParams/KeySystemRootKeyPasswordType'
|
||||
import { KeySystemPasswordType } from '../../Local/KeyParams/KeySystemPasswordType'
|
||||
import { KeySystemRootKeyStorageMode } from '../KeySystemRootKey/KeySystemRootKeyStorageMode'
|
||||
import { VaultListingSharingInfo } from './VaultListingSharingInfo'
|
||||
import { VaultListingContent } from './VaultListingContent'
|
||||
@@ -17,7 +17,7 @@ export interface VaultListingInterface extends DecryptedItemInterface<VaultListi
|
||||
|
||||
sharing?: VaultListingSharingInfo
|
||||
|
||||
get keyPasswordType(): KeySystemRootKeyPasswordType
|
||||
get keyPasswordType(): KeySystemPasswordType
|
||||
isSharedVaultListing(): this is SharedVaultListingInterface
|
||||
|
||||
get key_system_identifier(): undefined
|
||||
|
||||
@@ -37,7 +37,7 @@ export * from './Device/Platform'
|
||||
|
||||
export * from './Local/KeyParams/RootKeyParamsInterface'
|
||||
export * from './Local/KeyParams/KeySystemRootKeyParamsInterface'
|
||||
export * from './Local/KeyParams/KeySystemRootKeyPasswordType'
|
||||
export * from './Local/KeyParams/KeySystemPasswordType'
|
||||
export * from './Local/RootKey/KeychainTypes'
|
||||
export * from './Local/RootKey/RootKeyContent'
|
||||
export * from './Local/RootKey/RootKeyInterface'
|
||||
|
||||
@@ -3,6 +3,30 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.4.401](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-07-27)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/releases
|
||||
|
||||
## [1.4.400](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-07-27)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/releases
|
||||
|
||||
## [1.4.399](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-07-26)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/releases
|
||||
|
||||
## [1.4.398](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-07-26)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/releases
|
||||
|
||||
## [1.4.397](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-07-26)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/releases
|
||||
|
||||
## [1.4.396](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-07-25)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/releases
|
||||
|
||||
## [1.4.395](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-07-25)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/releases
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/releases",
|
||||
"version": "1.4.395",
|
||||
"version": "1.4.401",
|
||||
"license": "AGPL-3.0-or-later",
|
||||
"main": "dist/releases.json",
|
||||
"types": "dist/index.d.ts",
|
||||
|
||||
@@ -3,6 +3,14 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.13.33](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-07-27)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/responses
|
||||
|
||||
## [1.13.32](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-07-26)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/responses
|
||||
|
||||
## [1.13.31](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-07-23)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/responses
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/responses",
|
||||
"version": "1.13.31",
|
||||
"version": "1.13.33",
|
||||
"engines": {
|
||||
"node": ">=16.0.0 <17.0.0"
|
||||
},
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
export interface AsymmetricMessageServerHash {
|
||||
uuid: string
|
||||
user_uuid: string
|
||||
recipient_uuid: string
|
||||
sender_uuid: string
|
||||
replaceabilityIdentifier?: string
|
||||
encrypted_message: string
|
||||
|
||||
@@ -16,7 +16,7 @@ export type RawSyncData = {
|
||||
unsaved?: ConflictParams[]
|
||||
shared_vaults?: SharedVaultServerHash[]
|
||||
shared_vault_invites?: SharedVaultInviteServerHash[]
|
||||
user_events?: UserEventServerHash[]
|
||||
asymmetric_messages?: AsymmetricMessageServerHash[]
|
||||
notifications?: UserEventServerHash[]
|
||||
messages?: AsymmetricMessageServerHash[]
|
||||
status?: number
|
||||
}
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import { AsymmetricMessageServerHash } from '../AsymmetricMessage/AsymmetricMessageServerHash'
|
||||
import { SharedVaultPermission } from './SharedVaultPermission'
|
||||
|
||||
export interface SharedVaultInviteServerHash extends AsymmetricMessageServerHash {
|
||||
uuid: string
|
||||
@@ -7,7 +6,7 @@ export interface SharedVaultInviteServerHash extends AsymmetricMessageServerHash
|
||||
user_uuid: string
|
||||
sender_uuid: string
|
||||
encrypted_message: string
|
||||
permissions: SharedVaultPermission
|
||||
permission: string
|
||||
created_at_timestamp: number
|
||||
updated_at_timestamp: number
|
||||
}
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
export enum SharedVaultPermission {
|
||||
Read = 'read',
|
||||
Write = 'write',
|
||||
Admin = 'admin',
|
||||
}
|
||||
@@ -1,9 +1,7 @@
|
||||
import { SharedVaultPermission } from './SharedVaultPermission'
|
||||
|
||||
export interface SharedVaultUserServerHash {
|
||||
uuid: string
|
||||
shared_vault_uuid: string
|
||||
user_uuid: string
|
||||
permissions: SharedVaultPermission
|
||||
permission: string
|
||||
updated_at_timestamp: number
|
||||
}
|
||||
|
||||
@@ -1,14 +0,0 @@
|
||||
import { UserEventType } from './UserEventType'
|
||||
|
||||
export type UserEventPayload =
|
||||
| {
|
||||
eventType: UserEventType.SharedVaultItemRemoved
|
||||
itemUuid: string
|
||||
sharedVaultUuid: string
|
||||
version: string
|
||||
}
|
||||
| {
|
||||
eventType: UserEventType.RemovedFromSharedVault
|
||||
sharedVaultUuid: string
|
||||
version: string
|
||||
}
|
||||
@@ -1,10 +1,8 @@
|
||||
import { UserEventType } from './UserEventType'
|
||||
|
||||
export type UserEventServerHash = {
|
||||
uuid: string
|
||||
user_uuid: string
|
||||
event_type: UserEventType
|
||||
event_payload: string
|
||||
type: string
|
||||
payload: string
|
||||
created_at_timestamp?: number
|
||||
updated_at_timestamp?: number
|
||||
}
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
export enum UserEventType {
|
||||
SharedVaultItemRemoved = 'shared_vault_item_removed',
|
||||
RemovedFromSharedVault = 'removed_from_shared_vault',
|
||||
}
|
||||
@@ -36,7 +36,6 @@ export * from './Http'
|
||||
export * from './SharedVaults/SharedVaultInviteServerHash'
|
||||
export * from './SharedVaults/SharedVaultUserServerHash'
|
||||
export * from './SharedVaults/SharedVaultServerHash'
|
||||
export * from './SharedVaults/SharedVaultPermission'
|
||||
|
||||
export * from './AsymmetricMessage/AsymmetricMessageServerHash'
|
||||
|
||||
@@ -68,5 +67,3 @@ export * from './User/SettingData'
|
||||
export * from './User/UpdateSettingResponse'
|
||||
|
||||
export * from './UserEvent/UserEventServerHash'
|
||||
export * from './UserEvent/UserEventType'
|
||||
export * from './UserEvent/UserEventPayload'
|
||||
|
||||
@@ -3,6 +3,32 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.63.14](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-07-27)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/services
|
||||
|
||||
## [1.63.13](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-07-27)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/services
|
||||
|
||||
## [1.63.12](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-07-26)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* Fixes issue where lock screen would not use previously active theme ([#2372](https://github.com/standardnotes/app/issues/2372)) ([d268c02](https://github.com/standardnotes/app/commit/d268c02ab31beb5e2fd9e6547610f9a4dd61bed4))
|
||||
|
||||
## [1.63.11](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-07-26)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/services
|
||||
|
||||
## [1.63.10](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-07-26)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/services
|
||||
|
||||
## [1.63.9](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-07-25)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/services
|
||||
|
||||
## [1.63.8](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-07-24)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/services
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/services",
|
||||
"version": "1.63.8",
|
||||
"version": "1.63.14",
|
||||
"engines": {
|
||||
"node": ">=16.0.0 <17.0.0"
|
||||
},
|
||||
@@ -18,7 +18,7 @@
|
||||
"dependencies": {
|
||||
"@standardnotes/api": "workspace:^",
|
||||
"@standardnotes/common": "^1.50.0",
|
||||
"@standardnotes/domain-core": "^1.22.0",
|
||||
"@standardnotes/domain-core": "^1.24.0",
|
||||
"@standardnotes/encryption": "workspace:^",
|
||||
"@standardnotes/features": "workspace:^",
|
||||
"@standardnotes/files": "workspace:^",
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import { VaultUserServiceInterface, VaultInviteServiceInterface } from '@standardnotes/services'
|
||||
import { VaultLockServiceInterface } from './../VaultLock/VaultLockServiceInterface'
|
||||
import { HistoryServiceInterface } from './../History/HistoryServiceInterface'
|
||||
import { InternalEventBusInterface } from './../Internal/InternalEventBusInterface'
|
||||
import { PreferenceServiceInterface } from './../Preferences/PreferenceServiceInterface'
|
||||
@@ -5,7 +7,7 @@ import { AsymmetricMessageServiceInterface } from './../AsymmetricMessage/Asymme
|
||||
import { SyncOptions } from './../Sync/SyncOptions'
|
||||
import { ImportDataReturnType } from './../Mutator/ImportDataUseCase'
|
||||
import { ChallengeServiceInterface } from './../Challenge/ChallengeServiceInterface'
|
||||
import { VaultServiceInterface } from './../Vaults/VaultServiceInterface'
|
||||
import { VaultServiceInterface } from '../Vault/VaultServiceInterface'
|
||||
import { ApplicationIdentifier } from '@standardnotes/common'
|
||||
import {
|
||||
BackupFile,
|
||||
@@ -95,24 +97,27 @@ export interface ApplicationInterface {
|
||||
syncOptions?: SyncOptions,
|
||||
): Promise<void>
|
||||
|
||||
get features(): FeaturesClientInterface
|
||||
get componentManager(): ComponentManagerInterface
|
||||
get items(): ItemManagerInterface
|
||||
get mutator(): MutatorClientInterface
|
||||
get user(): UserClientInterface
|
||||
get files(): FilesClientInterface
|
||||
get subscriptions(): SubscriptionManagerInterface
|
||||
get fileBackups(): BackupServiceInterface | undefined
|
||||
get sessions(): SessionsClientInterface
|
||||
get homeServer(): HomeServerServiceInterface | undefined
|
||||
get vaults(): VaultServiceInterface
|
||||
get challenges(): ChallengeServiceInterface
|
||||
get alerts(): AlertService
|
||||
get asymmetric(): AsymmetricMessageServiceInterface
|
||||
get preferences(): PreferenceServiceInterface
|
||||
get events(): InternalEventBusInterface
|
||||
get history(): HistoryServiceInterface
|
||||
get challenges(): ChallengeServiceInterface
|
||||
get componentManager(): ComponentManagerInterface
|
||||
get encryption(): EncryptionProviderInterface
|
||||
get events(): InternalEventBusInterface
|
||||
get features(): FeaturesClientInterface
|
||||
get fileBackups(): BackupServiceInterface | undefined
|
||||
get files(): FilesClientInterface
|
||||
get history(): HistoryServiceInterface
|
||||
get homeServer(): HomeServerServiceInterface | undefined
|
||||
get items(): ItemManagerInterface
|
||||
get mutator(): MutatorClientInterface
|
||||
get preferences(): PreferenceServiceInterface
|
||||
get sessions(): SessionsClientInterface
|
||||
get subscriptions(): SubscriptionManagerInterface
|
||||
get user(): UserClientInterface
|
||||
get vaults(): VaultServiceInterface
|
||||
get vaultLocks(): VaultLockServiceInterface
|
||||
get vaultUsers(): VaultUserServiceInterface
|
||||
get vaultInvites(): VaultInviteServiceInterface
|
||||
|
||||
readonly identifier: ApplicationIdentifier
|
||||
readonly platform: Platform
|
||||
|
||||
@@ -1,14 +1,12 @@
|
||||
import { GetVault } from './../Vault/UseCase/GetVault'
|
||||
import { SessionsClientInterface } from './../Session/SessionsClientInterface'
|
||||
import { EncryptionProviderInterface } from './../Encryption/EncryptionProviderInterface'
|
||||
import { GetUntrustedPayload } from './UseCase/GetUntrustedPayload'
|
||||
import { GetInboundMessages } from './UseCase/GetInboundMessages'
|
||||
import { GetOutboundMessages } from './UseCase/GetOutboundMessages'
|
||||
import { SendOwnContactChangeMessage } from './UseCase/SendOwnContactChangeMessage'
|
||||
import { HandleRootKeyChangedMessage } from './UseCase/HandleRootKeyChangedMessage'
|
||||
import { GetVault } from './../Vaults/UseCase/GetVault'
|
||||
import { GetTrustedPayload } from './UseCase/GetTrustedPayload'
|
||||
import { ReplaceContactData } from './../Contacts/UseCase/ReplaceContactData'
|
||||
import { GetAllContacts } from './../Contacts/UseCase/GetAllContacts'
|
||||
import { FindContact } from './../Contacts/UseCase/FindContact'
|
||||
import { CreateOrEditContact } from './../Contacts/UseCase/CreateOrEditContact'
|
||||
import { MutatorClientInterface } from './../Mutator/MutatorClientInterface'
|
||||
@@ -42,12 +40,10 @@ describe('AsymmetricMessageService', () => {
|
||||
encryption = {} as jest.Mocked<EncryptionProviderInterface>
|
||||
const createOrEditContact = {} as jest.Mocked<CreateOrEditContact>
|
||||
const findContact = {} as jest.Mocked<FindContact>
|
||||
const getAllContacts = {} as jest.Mocked<GetAllContacts>
|
||||
const replaceContactData = {} as jest.Mocked<ReplaceContactData>
|
||||
const getTrustedPayload = {} as jest.Mocked<GetTrustedPayload>
|
||||
const getVault = {} as jest.Mocked<GetVault>
|
||||
const handleRootKeyChangedMessage = {} as jest.Mocked<HandleRootKeyChangedMessage>
|
||||
const sendOwnContactChangedMessage = {} as jest.Mocked<SendOwnContactChangeMessage>
|
||||
const getOutboundMessagesUseCase = {} as jest.Mocked<GetOutboundMessages>
|
||||
const getInboundMessagesUseCase = {} as jest.Mocked<GetInboundMessages>
|
||||
const getUntrustedPayload = {} as jest.Mocked<GetUntrustedPayload>
|
||||
@@ -68,12 +64,10 @@ describe('AsymmetricMessageService', () => {
|
||||
messageServer,
|
||||
createOrEditContact,
|
||||
findContact,
|
||||
getAllContacts,
|
||||
replaceContactData,
|
||||
getTrustedPayload,
|
||||
getVault,
|
||||
handleRootKeyChangedMessage,
|
||||
sendOwnContactChangedMessage,
|
||||
getOutboundMessagesUseCase,
|
||||
getInboundMessagesUseCase,
|
||||
getUntrustedPayload,
|
||||
@@ -86,7 +80,7 @@ describe('AsymmetricMessageService', () => {
|
||||
const messages: AsymmetricMessageServerHash[] = [
|
||||
{
|
||||
uuid: 'keypair-changed-message',
|
||||
user_uuid: '1',
|
||||
recipient_uuid: '1',
|
||||
sender_uuid: '2',
|
||||
encrypted_message: 'encrypted_message',
|
||||
created_at_timestamp: 2,
|
||||
@@ -94,7 +88,7 @@ describe('AsymmetricMessageService', () => {
|
||||
},
|
||||
{
|
||||
uuid: 'misc-message',
|
||||
user_uuid: '1',
|
||||
recipient_uuid: '1',
|
||||
sender_uuid: '2',
|
||||
encrypted_message: 'encrypted_message',
|
||||
created_at_timestamp: 1,
|
||||
@@ -125,7 +119,7 @@ describe('AsymmetricMessageService', () => {
|
||||
const messages: AsymmetricMessageServerHash[] = [
|
||||
{
|
||||
uuid: 'newer-message',
|
||||
user_uuid: '1',
|
||||
recipient_uuid: '1',
|
||||
sender_uuid: '2',
|
||||
encrypted_message: 'encrypted_message',
|
||||
created_at_timestamp: 2,
|
||||
@@ -133,7 +127,7 @@ describe('AsymmetricMessageService', () => {
|
||||
},
|
||||
{
|
||||
uuid: 'older-message',
|
||||
user_uuid: '1',
|
||||
recipient_uuid: '1',
|
||||
sender_uuid: '2',
|
||||
encrypted_message: 'encrypted_message',
|
||||
created_at_timestamp: 1,
|
||||
@@ -159,7 +153,7 @@ describe('AsymmetricMessageService', () => {
|
||||
it('should handle ContactShare message', async () => {
|
||||
const message: AsymmetricMessageServerHash = {
|
||||
uuid: 'message',
|
||||
user_uuid: '1',
|
||||
recipient_uuid: '1',
|
||||
sender_uuid: '2',
|
||||
encrypted_message: 'encrypted_message',
|
||||
created_at_timestamp: 2,
|
||||
@@ -187,7 +181,7 @@ describe('AsymmetricMessageService', () => {
|
||||
it('should handle SenderKeypairChanged message', async () => {
|
||||
const message: AsymmetricMessageServerHash = {
|
||||
uuid: 'message',
|
||||
user_uuid: '1',
|
||||
recipient_uuid: '1',
|
||||
sender_uuid: '2',
|
||||
encrypted_message: 'encrypted_message',
|
||||
created_at_timestamp: 2,
|
||||
@@ -216,7 +210,7 @@ describe('AsymmetricMessageService', () => {
|
||||
it('should handle SharedVaultRootKeyChanged message', async () => {
|
||||
const message: AsymmetricMessageServerHash = {
|
||||
uuid: 'message',
|
||||
user_uuid: '1',
|
||||
recipient_uuid: '1',
|
||||
sender_uuid: '2',
|
||||
encrypted_message: 'encrypted_message',
|
||||
created_at_timestamp: 2,
|
||||
@@ -244,7 +238,7 @@ describe('AsymmetricMessageService', () => {
|
||||
it('should handle SharedVaultMetadataChanged message', async () => {
|
||||
const message: AsymmetricMessageServerHash = {
|
||||
uuid: 'message',
|
||||
user_uuid: '1',
|
||||
recipient_uuid: '1',
|
||||
sender_uuid: '2',
|
||||
encrypted_message: 'encrypted_message',
|
||||
created_at_timestamp: 2,
|
||||
@@ -274,7 +268,7 @@ describe('AsymmetricMessageService', () => {
|
||||
it('should throw if message type is SharedVaultInvite', async () => {
|
||||
const message: AsymmetricMessageServerHash = {
|
||||
uuid: 'message',
|
||||
user_uuid: '1',
|
||||
recipient_uuid: '1',
|
||||
sender_uuid: '2',
|
||||
encrypted_message: 'encrypted_message',
|
||||
created_at_timestamp: 2,
|
||||
@@ -300,7 +294,7 @@ describe('AsymmetricMessageService', () => {
|
||||
it('should delete message from server after processing', async () => {
|
||||
const message: AsymmetricMessageServerHash = {
|
||||
uuid: 'message',
|
||||
user_uuid: '1',
|
||||
recipient_uuid: '1',
|
||||
sender_uuid: '2',
|
||||
encrypted_message: 'encrypted_message',
|
||||
created_at_timestamp: 2,
|
||||
|
||||
@@ -22,17 +22,14 @@ import {
|
||||
import { HandleRootKeyChangedMessage } from './UseCase/HandleRootKeyChangedMessage'
|
||||
import { SessionEvent } from '../Session/SessionEvent'
|
||||
import { AsymmetricMessageServer } from '@standardnotes/api'
|
||||
import { UserKeyPairChangedEventData } from '../Session/UserKeyPairChangedEventData'
|
||||
import { SendOwnContactChangeMessage } from './UseCase/SendOwnContactChangeMessage'
|
||||
import { GetOutboundMessages } from './UseCase/GetOutboundMessages'
|
||||
import { GetInboundMessages } from './UseCase/GetInboundMessages'
|
||||
import { GetVault } from '../Vaults/UseCase/GetVault'
|
||||
import { GetVault } from '../Vault/UseCase/GetVault'
|
||||
import { AsymmetricMessageServiceInterface } from './AsymmetricMessageServiceInterface'
|
||||
import { GetUntrustedPayload } from './UseCase/GetUntrustedPayload'
|
||||
import { FindContact } from '../Contacts/UseCase/FindContact'
|
||||
import { CreateOrEditContact } from '../Contacts/UseCase/CreateOrEditContact'
|
||||
import { ReplaceContactData } from '../Contacts/UseCase/ReplaceContactData'
|
||||
import { GetAllContacts } from '../Contacts/UseCase/GetAllContacts'
|
||||
import { EncryptionProviderInterface } from '../Encryption/EncryptionProviderInterface'
|
||||
|
||||
export class AsymmetricMessageService
|
||||
@@ -46,12 +43,10 @@ export class AsymmetricMessageService
|
||||
private messageServer: AsymmetricMessageServer,
|
||||
private _createOrEditContact: CreateOrEditContact,
|
||||
private _findContact: FindContact,
|
||||
private _getAllContacts: GetAllContacts,
|
||||
private _replaceContactData: ReplaceContactData,
|
||||
private _getTrustedPayload: GetTrustedPayload,
|
||||
private _getVault: GetVault,
|
||||
private _handleRootKeyChangedMessage: HandleRootKeyChangedMessage,
|
||||
private _sendOwnContactChangedMessage: SendOwnContactChangeMessage,
|
||||
private _getOutboundMessagesUseCase: GetOutboundMessages,
|
||||
private _getInboundMessagesUseCase: GetInboundMessages,
|
||||
private _getUntrustedPayload: GetUntrustedPayload,
|
||||
@@ -60,11 +55,26 @@ export class AsymmetricMessageService
|
||||
super(eventBus)
|
||||
}
|
||||
|
||||
public override deinit(): void {
|
||||
super.deinit()
|
||||
;(this.messageServer as unknown) = undefined
|
||||
;(this.encryption as unknown) = undefined
|
||||
;(this.mutator as unknown) = undefined
|
||||
;(this._createOrEditContact as unknown) = undefined
|
||||
;(this._findContact as unknown) = undefined
|
||||
;(this._replaceContactData as unknown) = undefined
|
||||
;(this._getTrustedPayload as unknown) = undefined
|
||||
;(this._getVault as unknown) = undefined
|
||||
;(this._handleRootKeyChangedMessage as unknown) = undefined
|
||||
;(this._getOutboundMessagesUseCase as unknown) = undefined
|
||||
;(this._getInboundMessagesUseCase as unknown) = undefined
|
||||
;(this._getUntrustedPayload as unknown) = undefined
|
||||
}
|
||||
|
||||
async handleEvent(event: InternalEventInterface): Promise<void> {
|
||||
switch (event.type) {
|
||||
case SessionEvent.UserKeyPairChanged:
|
||||
void this.messageServer.deleteAllInboundMessages()
|
||||
void this.sendOwnContactChangeEventToAllContacts(event.payload as UserKeyPairChangedEventData)
|
||||
break
|
||||
case SyncEvent.ReceivedAsymmetricMessages:
|
||||
void this.handleRemoteReceivedAsymmetricMessages(event.payload as SyncEventReceivedAsymmetricMessagesData)
|
||||
@@ -89,31 +99,6 @@ export class AsymmetricMessageService
|
||||
await this.handleRemoteReceivedAsymmetricMessages(messages)
|
||||
}
|
||||
|
||||
private async sendOwnContactChangeEventToAllContacts(data: UserKeyPairChangedEventData): Promise<void> {
|
||||
if (!data.previous) {
|
||||
return
|
||||
}
|
||||
|
||||
const contacts = this._getAllContacts.execute()
|
||||
if (contacts.isFailed()) {
|
||||
return
|
||||
}
|
||||
|
||||
for (const contact of contacts.getValue()) {
|
||||
if (contact.isMe) {
|
||||
continue
|
||||
}
|
||||
|
||||
await this._sendOwnContactChangedMessage.execute({
|
||||
senderOldKeyPair: data.previous.encryption,
|
||||
senderOldSigningKeyPair: data.previous.signing,
|
||||
senderNewKeyPair: data.current.encryption,
|
||||
senderNewSigningKeyPair: data.current.signing,
|
||||
contact,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
sortServerMessages(messages: AsymmetricMessageServerHash[]): AsymmetricMessageServerHash[] {
|
||||
const SortedPriorityTypes = [AsymmetricMessagePayloadType.SenderKeypairChanged]
|
||||
|
||||
@@ -288,22 +273,4 @@ export class AsymmetricMessageService
|
||||
): Promise<void> {
|
||||
await this._handleRootKeyChangedMessage.execute(trustedPayload)
|
||||
}
|
||||
|
||||
public override deinit(): void {
|
||||
super.deinit()
|
||||
;(this.messageServer as unknown) = undefined
|
||||
;(this.encryption as unknown) = undefined
|
||||
;(this.mutator as unknown) = undefined
|
||||
;(this._createOrEditContact as unknown) = undefined
|
||||
;(this._findContact as unknown) = undefined
|
||||
;(this._getAllContacts as unknown) = undefined
|
||||
;(this._replaceContactData as unknown) = undefined
|
||||
;(this._getTrustedPayload as unknown) = undefined
|
||||
;(this._getVault as unknown) = undefined
|
||||
;(this._handleRootKeyChangedMessage as unknown) = undefined
|
||||
;(this._sendOwnContactChangedMessage as unknown) = undefined
|
||||
;(this._getOutboundMessagesUseCase as unknown) = undefined
|
||||
;(this._getInboundMessagesUseCase as unknown) = undefined
|
||||
;(this._getUntrustedPayload as unknown) = undefined
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -10,7 +10,7 @@ import {
|
||||
} from '@standardnotes/models'
|
||||
|
||||
import { ContentType } from '@standardnotes/domain-core'
|
||||
import { GetVault } from '../../Vaults/UseCase/GetVault'
|
||||
import { GetVault } from '../../Vault/UseCase/GetVault'
|
||||
import { EncryptionProviderInterface } from '../../Encryption/EncryptionProviderInterface'
|
||||
|
||||
export class HandleRootKeyChangedMessage {
|
||||
|
||||
@@ -31,9 +31,9 @@ export class ResendAllMessages implements UseCaseInterface<void> {
|
||||
const errors: string[] = []
|
||||
|
||||
for (const message of messages.data.messages) {
|
||||
const recipient = this.findContact.execute({ userUuid: message.user_uuid })
|
||||
if (recipient) {
|
||||
errors.push(`Contact not found for invite ${message.user_uuid}`)
|
||||
const recipient = this.findContact.execute({ userUuid: message.recipient_uuid })
|
||||
if (recipient.isFailed()) {
|
||||
errors.push(`Contact not found for invite ${message.recipient_uuid}`)
|
||||
continue
|
||||
}
|
||||
|
||||
@@ -41,7 +41,7 @@ export class ResendAllMessages implements UseCaseInterface<void> {
|
||||
keys: params.keys,
|
||||
previousKeys: params.previousKeys,
|
||||
message: message,
|
||||
recipient,
|
||||
recipient: recipient.getValue(),
|
||||
})
|
||||
|
||||
await this.messageServer.deleteMessage({
|
||||
|
||||
@@ -3,13 +3,14 @@ import {
|
||||
ComponentArea,
|
||||
ComponentFeatureDescription,
|
||||
EditorFeatureDescription,
|
||||
EditorIdentifier,
|
||||
IframeComponentFeatureDescription,
|
||||
NativeFeatureIdentifier,
|
||||
ThemeFeatureDescription,
|
||||
} from '@standardnotes/features'
|
||||
import { ActionObserver, ComponentInterface, UIFeature, PermissionDialog, SNNote, SNTag } from '@standardnotes/models'
|
||||
import { DesktopManagerInterface } from '../Device/DesktopManagerInterface'
|
||||
import { ComponentViewerInterface } from './ComponentViewerInterface'
|
||||
import { Uuid } from '@standardnotes/domain-core'
|
||||
|
||||
export interface ComponentManagerInterface {
|
||||
urlForFeature(uiFeature: UIFeature<ComponentFeatureDescription>): string | undefined
|
||||
@@ -31,12 +32,12 @@ export interface ComponentManagerInterface {
|
||||
setPermissionDialogUIHandler(handler: (dialog: PermissionDialog) => void): void
|
||||
|
||||
editorForNote(note: SNNote): UIFeature<EditorFeatureDescription | IframeComponentFeatureDescription>
|
||||
getDefaultEditorIdentifier(currentTag?: SNTag): EditorIdentifier
|
||||
getDefaultEditorIdentifier(currentTag?: SNTag): string
|
||||
|
||||
isThemeActive(theme: UIFeature<ThemeFeatureDescription>): boolean
|
||||
toggleTheme(theme: UIFeature<ThemeFeatureDescription>): Promise<void>
|
||||
getActiveThemes(): UIFeature<ThemeFeatureDescription>[]
|
||||
getActiveThemesIdentifiers(): string[]
|
||||
getActiveThemesIdentifiers(): { features: NativeFeatureIdentifier[]; uuids: Uuid[] }
|
||||
|
||||
isComponentActive(component: ComponentInterface): boolean
|
||||
toggleComponent(component: ComponentInterface): Promise<void>
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
import { ActionObserver, ComponentEventObserver, ComponentMessage, UIFeature } from '@standardnotes/models'
|
||||
import { FeatureStatus } from '../Feature/FeatureStatus'
|
||||
import { ComponentViewerError } from './ComponentViewerError'
|
||||
import { IframeComponentFeatureDescription } from '@standardnotes/features'
|
||||
import { IframeComponentFeatureDescription, NativeFeatureIdentifier } from '@standardnotes/features'
|
||||
import { Uuid } from '@standardnotes/domain-core'
|
||||
|
||||
export interface ComponentViewerInterface {
|
||||
readonly identifier: string
|
||||
@@ -9,7 +10,7 @@ export interface ComponentViewerInterface {
|
||||
readonly sessionKey?: string
|
||||
|
||||
get url(): string
|
||||
get componentUniqueIdentifier(): string
|
||||
get componentUniqueIdentifier(): NativeFeatureIdentifier | Uuid
|
||||
|
||||
getComponentOrFeatureItem(): UIFeature<IframeComponentFeatureDescription>
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { SendOwnContactChangeMessage } from './UseCase/SendOwnContactChangeMessage'
|
||||
import { DeleteContact } from './UseCase/DeleteContact'
|
||||
import { MutatorClientInterface } from './../Mutator/MutatorClientInterface'
|
||||
import { UserKeyPairChangedEventData } from './../Session/UserKeyPairChangedEventData'
|
||||
@@ -42,6 +43,7 @@ export class ContactService
|
||||
private _createOrEditContact: CreateOrEditContact,
|
||||
private _editContact: EditContact,
|
||||
private _validateItemSigner: ValidateItemSigner,
|
||||
private _sendOwnContactChangedMessage: SendOwnContactChangeMessage,
|
||||
eventBus: InternalEventBusInterface,
|
||||
) {
|
||||
super(eventBus)
|
||||
@@ -52,11 +54,36 @@ export class ContactService
|
||||
async handleEvent(event: InternalEventInterface): Promise<void> {
|
||||
if (event.type === SessionEvent.UserKeyPairChanged) {
|
||||
const data = event.payload as UserKeyPairChangedEventData
|
||||
|
||||
await this.selfContactManager.updateWithNewPublicKeySet({
|
||||
encryption: data.current.encryption.publicKey,
|
||||
signing: data.current.signing.publicKey,
|
||||
})
|
||||
void this.sendOwnContactChangeEventToAllContacts(event.payload as UserKeyPairChangedEventData)
|
||||
}
|
||||
}
|
||||
|
||||
private async sendOwnContactChangeEventToAllContacts(data: UserKeyPairChangedEventData): Promise<void> {
|
||||
if (!data.previous) {
|
||||
return
|
||||
}
|
||||
|
||||
const contacts = this._getAllContacts.execute()
|
||||
if (contacts.isFailed()) {
|
||||
return
|
||||
}
|
||||
|
||||
for (const contact of contacts.getValue()) {
|
||||
if (contact.isMe) {
|
||||
continue
|
||||
}
|
||||
|
||||
await this._sendOwnContactChangedMessage.execute({
|
||||
senderOldKeyPair: data.previous.encryption,
|
||||
senderOldSigningKeyPair: data.previous.signing,
|
||||
senderNewKeyPair: data.current.encryption,
|
||||
senderNewSigningKeyPair: data.current.signing,
|
||||
contact,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -5,7 +5,7 @@ import {
|
||||
AsymmetricMessageSenderKeypairChanged,
|
||||
} from '@standardnotes/models'
|
||||
import { PkcKeyPair } from '@standardnotes/sncrypto-common'
|
||||
import { SendMessage } from './SendMessage'
|
||||
import { SendMessage } from '../../AsymmetricMessage/UseCase/SendMessage'
|
||||
import { EncryptMessage } from '../../Encryption/UseCase/Asymmetric/EncryptMessage'
|
||||
import { Result, UseCaseInterface } from '@standardnotes/domain-core'
|
||||
|
||||
@@ -112,7 +112,6 @@ export class ValidateItemSigner {
|
||||
const signerPublicKey = signatureResult.publicKey
|
||||
|
||||
const trustedContact = this.findContact.execute({ signingPublicKey: signerPublicKey })
|
||||
|
||||
if (trustedContact.isFailed()) {
|
||||
return ItemSignatureValidationResult.NotTrusted
|
||||
}
|
||||
|
||||
@@ -89,7 +89,6 @@ export interface EncryptionProviderInterface {
|
||||
setNewRootKeyWrapper(wrappingKey: RootKeyInterface): Promise<void>
|
||||
|
||||
createNewItemsKeyWithRollback(): Promise<() => Promise<void>>
|
||||
reencryptApplicableItemsAfterUserRootKeyChange(): Promise<void>
|
||||
getSureDefaultItemsKey(): ItemsKeyInterface
|
||||
|
||||
createRandomizedKeySystemRootKey(dto: { systemIdentifier: KeySystemIdentifier }): KeySystemRootKeyInterface
|
||||
|
||||
@@ -240,10 +240,6 @@ export class EncryptionService
|
||||
return this.itemsEncryption.repersistAllItems()
|
||||
}
|
||||
|
||||
public async reencryptApplicableItemsAfterUserRootKeyChange(): Promise<void> {
|
||||
await this.rootKeyManager.reencryptApplicableItemsAfterUserRootKeyChange()
|
||||
}
|
||||
|
||||
public async createNewItemsKeyWithRollback(): Promise<() => Promise<void>> {
|
||||
return this._createNewItemsKeyWithRollback.execute()
|
||||
}
|
||||
|
||||
+7
-7
@@ -2,24 +2,24 @@ import { ItemsKeyMutator } from '@standardnotes/encryption'
|
||||
import { MutatorClientInterface } from '../../../Mutator/MutatorClientInterface'
|
||||
import { ItemManagerInterface } from '../../../Item/ItemManagerInterface'
|
||||
import { CreateNewDefaultItemsKey } from './CreateNewDefaultItemsKey'
|
||||
import { RemoveItemsLocally } from '../../../UseCase/RemoveItemsLocally'
|
||||
import { DiscardItemsLocally } from '../../../UseCase/DiscardItemsLocally'
|
||||
import { FindDefaultItemsKey } from './FindDefaultItemsKey'
|
||||
|
||||
export class CreateNewItemsKeyWithRollback {
|
||||
constructor(
|
||||
private mutator: MutatorClientInterface,
|
||||
private items: ItemManagerInterface,
|
||||
private createDefaultItemsKey: CreateNewDefaultItemsKey,
|
||||
private removeItemsLocally: RemoveItemsLocally,
|
||||
private findDefaultItemsKey: FindDefaultItemsKey,
|
||||
private _createDefaultItemsKey: CreateNewDefaultItemsKey,
|
||||
private _discardItemsLocally: DiscardItemsLocally,
|
||||
private _findDefaultItemsKey: FindDefaultItemsKey,
|
||||
) {}
|
||||
|
||||
async execute(): Promise<() => Promise<void>> {
|
||||
const currentDefaultItemsKey = this.findDefaultItemsKey.execute(this.items.getDisplayableItemsKeys()).getValue()
|
||||
const newDefaultItemsKey = await this.createDefaultItemsKey.execute()
|
||||
const currentDefaultItemsKey = this._findDefaultItemsKey.execute(this.items.getDisplayableItemsKeys()).getValue()
|
||||
const newDefaultItemsKey = await this._createDefaultItemsKey.execute()
|
||||
|
||||
const rollback = async () => {
|
||||
await this.removeItemsLocally.execute([newDefaultItemsKey])
|
||||
await this._discardItemsLocally.execute([newDefaultItemsKey])
|
||||
|
||||
if (currentDefaultItemsKey) {
|
||||
await this.mutator.changeItem<ItemsKeyMutator>(currentDefaultItemsKey, (mutator) => {
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
import { MutatorClientInterface } from './../../../Mutator/MutatorClientInterface'
|
||||
import { ItemManagerInterface } from './../../../Item/ItemManagerInterface'
|
||||
import { Result, UseCaseInterface } from '@standardnotes/domain-core'
|
||||
import { ContentTypesUsingRootKeyEncryption } from '@standardnotes/models'
|
||||
|
||||
/**
|
||||
* When the user root key changes, we must re-encrypt all relevant items with this new root key (by simply re-syncing).
|
||||
*/
|
||||
export class ReencryptTypeAItems implements UseCaseInterface<void> {
|
||||
constructor(private items: ItemManagerInterface, private mutator: MutatorClientInterface) {}
|
||||
|
||||
public async execute(): Promise<Result<void>> {
|
||||
const items = this.items.getItems(ContentTypesUsingRootKeyEncryption())
|
||||
if (items.length > 0) {
|
||||
/**
|
||||
* Do not call sync after marking dirty.
|
||||
* Re-encrypting items keys is called by consumers who have specific flows who
|
||||
* will sync on their own timing
|
||||
*/
|
||||
await this.mutator.setItemsDirty(items)
|
||||
}
|
||||
|
||||
return Result.ok()
|
||||
}
|
||||
}
|
||||
@@ -1,12 +1,15 @@
|
||||
import { FeatureIdentifier } from '@standardnotes/features'
|
||||
import { ComponentInterface, DecryptedItemInterface } from '@standardnotes/models'
|
||||
|
||||
import { FeatureStatus } from './FeatureStatus'
|
||||
import { SetOfflineFeaturesFunctionResponse } from './SetOfflineFeaturesFunctionResponse'
|
||||
import { NativeFeatureIdentifier } from '@standardnotes/features'
|
||||
import { Uuid } from '@standardnotes/domain-core'
|
||||
|
||||
export interface FeaturesClientInterface {
|
||||
initializeFromDisk(): void
|
||||
getFeatureStatus(featureId: FeatureIdentifier, options?: { inContextOfItem?: DecryptedItemInterface }): FeatureStatus
|
||||
getFeatureStatus(
|
||||
featureId: NativeFeatureIdentifier | Uuid,
|
||||
options?: { inContextOfItem?: DecryptedItemInterface },
|
||||
): FeatureStatus
|
||||
hasMinimumRole(role: string): boolean
|
||||
|
||||
hasFirstPartyOfflineSubscription(): boolean
|
||||
@@ -16,13 +19,13 @@ export interface FeaturesClientInterface {
|
||||
|
||||
isThirdPartyFeature(identifier: string): boolean
|
||||
|
||||
toggleExperimentalFeature(identifier: FeatureIdentifier): void
|
||||
getExperimentalFeatures(): FeatureIdentifier[]
|
||||
getEnabledExperimentalFeatures(): FeatureIdentifier[]
|
||||
enableExperimentalFeature(identifier: FeatureIdentifier): void
|
||||
disableExperimentalFeature(identifier: FeatureIdentifier): void
|
||||
isExperimentalFeatureEnabled(identifier: FeatureIdentifier): boolean
|
||||
isExperimentalFeature(identifier: FeatureIdentifier): boolean
|
||||
toggleExperimentalFeature(identifier: string): void
|
||||
getExperimentalFeatures(): string[]
|
||||
getEnabledExperimentalFeatures(): string[]
|
||||
enableExperimentalFeature(identifier: string): void
|
||||
disableExperimentalFeature(identifier: string): void
|
||||
isExperimentalFeatureEnabled(identifier: string): boolean
|
||||
isExperimentalFeature(identifier: string): boolean
|
||||
|
||||
downloadRemoteThirdPartyFeature(urlOrCode: string): Promise<ComponentInterface | undefined>
|
||||
}
|
||||
|
||||
@@ -80,7 +80,7 @@ export interface ItemManagerInterface extends AbstractService {
|
||||
): T[]
|
||||
subItemsMatchingPredicates<T extends DecryptedItemInterface>(items: T[], predicates: PredicateInterface<T>[]): T[]
|
||||
removeAllItemsFromMemory(): Promise<void>
|
||||
removeItemsLocally(items: AnyItemInterface[]): void
|
||||
removeItemsFromMemory(items: AnyItemInterface[]): void
|
||||
getDirtyItems(): (DecryptedItemInterface | DeletedItemInterface)[]
|
||||
getTagLongTitle(tag: SNTag): string
|
||||
getSortedTagsForItem(item: DecryptedItemInterface<ItemContent>): SNTag[]
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { RemoveItemsFromMemory } from './../Storage/UseCase/RemoveItemsFromMemory'
|
||||
import { InternalEventHandlerInterface } from './../Internal/InternalEventHandlerInterface'
|
||||
import { MutatorClientInterface } from './../Mutator/MutatorClientInterface'
|
||||
import { ApplicationStage } from './../Application/ApplicationStage'
|
||||
@@ -36,11 +37,20 @@ export class KeySystemKeyManager
|
||||
private readonly items: ItemManagerInterface,
|
||||
private readonly mutator: MutatorClientInterface,
|
||||
private readonly storage: StorageServiceInterface,
|
||||
private readonly _removeItemsFromMemory: RemoveItemsFromMemory,
|
||||
eventBus: InternalEventBusInterface,
|
||||
) {
|
||||
super(eventBus)
|
||||
}
|
||||
|
||||
public override deinit(): void {
|
||||
;(this.items as unknown) = undefined
|
||||
;(this.mutator as unknown) = undefined
|
||||
;(this.storage as unknown) = undefined
|
||||
;(this._removeItemsFromMemory as unknown) = undefined
|
||||
super.deinit()
|
||||
}
|
||||
|
||||
async handleEvent(event: InternalEventInterface): Promise<void> {
|
||||
if (event.type === ApplicationEvent.ApplicationStageChanged) {
|
||||
const stage = (event.payload as ApplicationStageChangedEventPayload).stage
|
||||
@@ -60,9 +70,30 @@ export class KeySystemKeyManager
|
||||
const keyPayloads = keyRawPayloads.map((rawPayload) => new DecryptedPayload<KeySystemRootKeyContent>(rawPayload))
|
||||
|
||||
const keys = keyPayloads.map((payload) => new KeySystemRootKey(payload))
|
||||
keys.forEach((key) => {
|
||||
|
||||
for (const key of keys) {
|
||||
this.rootKeyMemoryCache[key.systemIdentifier] = key
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
getRootKeyFromStorageForVault(keySystemIdentifier: KeySystemIdentifier): KeySystemRootKeyInterface | undefined {
|
||||
const payload = this.storage.getValue<DecryptedTransferPayload<KeySystemRootKeyContent>>(
|
||||
this.storageKeyForRootKey(keySystemIdentifier),
|
||||
)
|
||||
|
||||
if (!payload) {
|
||||
return undefined
|
||||
}
|
||||
|
||||
const keyPayload = new DecryptedPayload<KeySystemRootKeyContent>(payload)
|
||||
|
||||
const key = new KeySystemRootKey(keyPayload)
|
||||
|
||||
return key
|
||||
}
|
||||
|
||||
getMemCachedRootKey(systemIdentifier: KeySystemIdentifier): KeySystemRootKeyInterface {
|
||||
return this.rootKeyMemoryCache[systemIdentifier]
|
||||
}
|
||||
|
||||
private storageKeyForRootKey(systemIdentifier: KeySystemIdentifier): string {
|
||||
@@ -73,17 +104,14 @@ export class KeySystemKeyManager
|
||||
* When the key system root key changes, we must re-encrypt all vault items keys
|
||||
* with this new key system root key (by simply re-syncing).
|
||||
*/
|
||||
public async reencryptKeySystemItemsKeysForVault(keySystemIdentifier: KeySystemIdentifier): Promise<void> {
|
||||
public async queueVaultItemsKeysForReencryption(keySystemIdentifier: KeySystemIdentifier): Promise<void> {
|
||||
const keySystemItemsKeys = this.getKeySystemItemsKeys(keySystemIdentifier)
|
||||
if (keySystemItemsKeys.length > 0) {
|
||||
await this.mutator.setItemsDirty(keySystemItemsKeys)
|
||||
}
|
||||
}
|
||||
|
||||
public intakeNonPersistentKeySystemRootKey(
|
||||
key: KeySystemRootKeyInterface,
|
||||
storage: KeySystemRootKeyStorageMode,
|
||||
): void {
|
||||
public cacheKey(key: KeySystemRootKeyInterface, storage: KeySystemRootKeyStorageMode): void {
|
||||
this.rootKeyMemoryCache[key.systemIdentifier] = key
|
||||
|
||||
if (storage === KeySystemRootKeyStorageMode.Local) {
|
||||
@@ -91,7 +119,7 @@ export class KeySystemKeyManager
|
||||
}
|
||||
}
|
||||
|
||||
public undoIntakeNonPersistentKeySystemRootKey(systemIdentifier: KeySystemIdentifier): void {
|
||||
public removeKeyFromCache(systemIdentifier: KeySystemIdentifier): void {
|
||||
delete this.rootKeyMemoryCache[systemIdentifier]
|
||||
void this.storage.removeValue(this.storageKeyForRootKey(systemIdentifier))
|
||||
}
|
||||
@@ -100,11 +128,11 @@ export class KeySystemKeyManager
|
||||
return this.items.getItems(ContentType.TYPES.KeySystemRootKey)
|
||||
}
|
||||
|
||||
public clearMemoryOfKeysRelatedToVault(vault: VaultListingInterface): void {
|
||||
public async wipeVaultKeysFromMemory(vault: VaultListingInterface): Promise<void> {
|
||||
delete this.rootKeyMemoryCache[vault.systemIdentifier]
|
||||
|
||||
const itemsKeys = this.getKeySystemItemsKeys(vault.systemIdentifier)
|
||||
this.items.removeItemsLocally(itemsKeys)
|
||||
await this._removeItemsFromMemory.execute(itemsKeys)
|
||||
}
|
||||
|
||||
public getSyncedKeySystemRootKeysForVault(systemIdentifier: KeySystemIdentifier): KeySystemRootKeyInterface[] {
|
||||
@@ -131,19 +159,6 @@ export class KeySystemKeyManager
|
||||
await this.mutator.setItemsToBeDeleted(keys)
|
||||
}
|
||||
|
||||
public getKeySystemRootKeyWithToken(
|
||||
systemIdentifier: KeySystemIdentifier,
|
||||
rootKeyToken: string,
|
||||
): KeySystemRootKeyInterface | undefined {
|
||||
const keys = this.getAllKeySystemRootKeysForVault(systemIdentifier).filter((key) => key.token === rootKeyToken)
|
||||
|
||||
if (keys.length > 1) {
|
||||
throw new Error('Multiple synced key system root keys found for token')
|
||||
}
|
||||
|
||||
return keys[0]
|
||||
}
|
||||
|
||||
public getPrimaryKeySystemRootKey(systemIdentifier: KeySystemIdentifier): KeySystemRootKeyInterface | undefined {
|
||||
const keys = this.getAllKeySystemRootKeysForVault(systemIdentifier)
|
||||
|
||||
|
||||
@@ -16,17 +16,13 @@ export interface KeySystemKeyManagerInterface {
|
||||
getAllKeySystemRootKeysForVault(systemIdentifier: KeySystemIdentifier): KeySystemRootKeyInterface[]
|
||||
getSyncedKeySystemRootKeysForVault(systemIdentifier: KeySystemIdentifier): KeySystemRootKeyInterface[]
|
||||
getAllSyncedKeySystemRootKeys(): KeySystemRootKeyInterface[]
|
||||
getKeySystemRootKeyWithToken(
|
||||
systemIdentifier: KeySystemIdentifier,
|
||||
keyIdentifier: string,
|
||||
): KeySystemRootKeyInterface | undefined
|
||||
getPrimaryKeySystemRootKey(systemIdentifier: KeySystemIdentifier): KeySystemRootKeyInterface | undefined
|
||||
reencryptKeySystemItemsKeysForVault(keySystemIdentifier: KeySystemIdentifier): Promise<void>
|
||||
queueVaultItemsKeysForReencryption(keySystemIdentifier: KeySystemIdentifier): Promise<void>
|
||||
|
||||
intakeNonPersistentKeySystemRootKey(key: KeySystemRootKeyInterface, storage: KeySystemRootKeyStorageMode): void
|
||||
undoIntakeNonPersistentKeySystemRootKey(systemIdentifier: KeySystemIdentifier): void
|
||||
cacheKey(key: KeySystemRootKeyInterface, storage: KeySystemRootKeyStorageMode): void
|
||||
removeKeyFromCache(systemIdentifier: KeySystemIdentifier): void
|
||||
|
||||
clearMemoryOfKeysRelatedToVault(vault: VaultListingInterface): void
|
||||
wipeVaultKeysFromMemory(vault: VaultListingInterface): Promise<void>
|
||||
deleteNonPersistentSystemRootKeysForVault(systemIdentifier: KeySystemIdentifier): Promise<void>
|
||||
deleteAllSyncedKeySystemRootKeys(systemIdentifier: KeySystemIdentifier): Promise<void>
|
||||
}
|
||||
|
||||
@@ -9,18 +9,16 @@ import { ProtocolVersion, compareVersions } from '@standardnotes/common'
|
||||
import {
|
||||
BackupFile,
|
||||
BackupFileDecryptedContextualPayload,
|
||||
ComponentContent,
|
||||
CopyPayloadWithContentOverride,
|
||||
CreateDecryptedBackupFileContextPayload,
|
||||
CreateEncryptedBackupFileContextPayload,
|
||||
DecryptedItemInterface,
|
||||
DecryptedPayloadInterface,
|
||||
isDecryptedPayload,
|
||||
isEncryptedPayload,
|
||||
isEncryptedTransferPayload,
|
||||
} from '@standardnotes/models'
|
||||
import { ClientDisplayableError } from '@standardnotes/responses'
|
||||
import { Challenge, ChallengePrompt, ChallengeReason, ChallengeValidation } from '../Challenge'
|
||||
import { ContentType } from '@standardnotes/domain-core'
|
||||
import { Result } from '@standardnotes/domain-core'
|
||||
import { EncryptionProviderInterface } from '../Encryption/EncryptionProviderInterface'
|
||||
|
||||
const Strings = {
|
||||
@@ -57,44 +55,22 @@ export class ImportDataUseCase {
|
||||
* .affectedItems: Items that were either created or dirtied by this import
|
||||
* .errorCount: The number of items that were not imported due to failure to decrypt.
|
||||
*/
|
||||
|
||||
async execute(data: BackupFile, awaitSync = false): Promise<ImportDataReturnType> {
|
||||
if (data.version) {
|
||||
/**
|
||||
* Prior to 003 backup files did not have a version field so we cannot
|
||||
* stop importing if there is no backup file version, only if there is
|
||||
* an unsupported version.
|
||||
*/
|
||||
const version = data.version as ProtocolVersion
|
||||
|
||||
const supportedVersions = this.encryption.supportedVersions()
|
||||
if (!supportedVersions.includes(version)) {
|
||||
return { error: new ClientDisplayableError(Strings.UnsupportedBackupFileVersion) }
|
||||
}
|
||||
|
||||
const userVersion = this.encryption.getUserVersion()
|
||||
if (userVersion && compareVersions(version, userVersion) === 1) {
|
||||
/** File was made with a greater version than the user's account */
|
||||
return { error: new ClientDisplayableError(Strings.BackupFileMoreRecentThanAccount) }
|
||||
const result = this.validateVersion(data.version)
|
||||
if (result.isFailed()) {
|
||||
return { error: new ClientDisplayableError(result.getError()) }
|
||||
}
|
||||
}
|
||||
|
||||
let password: string | undefined
|
||||
|
||||
if (data.auth_params || data.keyParams) {
|
||||
/** Get import file password. */
|
||||
const challenge = new Challenge(
|
||||
[new ChallengePrompt(ChallengeValidation.None, Strings.FileAccountPassword, undefined, true)],
|
||||
ChallengeReason.DecryptEncryptedFile,
|
||||
true,
|
||||
)
|
||||
const passwordResponse = await this.challengeService.promptForChallengeResponse(challenge)
|
||||
if (passwordResponse == undefined) {
|
||||
/** Challenge was canceled */
|
||||
return { error: new ClientDisplayableError('Import aborted') }
|
||||
const passwordResult = await this.getFilePassword()
|
||||
if (passwordResult.isFailed()) {
|
||||
return { error: new ClientDisplayableError(passwordResult.getError()) }
|
||||
}
|
||||
this.challengeService.completeChallenge(challenge)
|
||||
password = passwordResponse?.values[0].value as string
|
||||
password = passwordResult.getValue()
|
||||
}
|
||||
|
||||
if (!(await this.protectionService.authorizeFileImport())) {
|
||||
@@ -110,31 +86,23 @@ export class ImportDataUseCase {
|
||||
})
|
||||
|
||||
const decryptedPayloadsOrError = await this._decryptBackFile.execute(data, password)
|
||||
|
||||
if (decryptedPayloadsOrError instanceof ClientDisplayableError) {
|
||||
return { error: decryptedPayloadsOrError }
|
||||
}
|
||||
|
||||
const validPayloads = decryptedPayloadsOrError.filter(isDecryptedPayload).map((payload) => {
|
||||
/* Don't want to activate any components during import process in
|
||||
* case of exceptions breaking up the import proccess */
|
||||
if (payload.content_type === ContentType.TYPES.Component && (payload.content as ComponentContent).active) {
|
||||
const typedContent = payload as DecryptedPayloadInterface<ComponentContent>
|
||||
return CopyPayloadWithContentOverride(typedContent, {
|
||||
active: false,
|
||||
})
|
||||
} else {
|
||||
return payload
|
||||
}
|
||||
const decryptedPayloads = decryptedPayloadsOrError.filter(isDecryptedPayload)
|
||||
const encryptedPayloads = decryptedPayloadsOrError.filter(isEncryptedPayload)
|
||||
const acceptableEncryptedPayloads = encryptedPayloads.filter((payload) => {
|
||||
return payload.key_system_identifier !== undefined
|
||||
})
|
||||
const importablePayloads = [...decryptedPayloads, ...acceptableEncryptedPayloads]
|
||||
|
||||
const affectedUuids = await this.payloadManager.importPayloads(
|
||||
validPayloads,
|
||||
importablePayloads,
|
||||
this.historyService.getHistoryMapCopy(),
|
||||
)
|
||||
|
||||
const promise = this.sync.sync()
|
||||
|
||||
if (awaitSync) {
|
||||
await promise
|
||||
}
|
||||
@@ -143,7 +111,42 @@ export class ImportDataUseCase {
|
||||
|
||||
return {
|
||||
affectedItems: affectedItems,
|
||||
errorCount: decryptedPayloadsOrError.length - validPayloads.length,
|
||||
errorCount: decryptedPayloadsOrError.length - importablePayloads.length,
|
||||
}
|
||||
}
|
||||
|
||||
private async getFilePassword(): Promise<Result<string>> {
|
||||
const challenge = new Challenge(
|
||||
[new ChallengePrompt(ChallengeValidation.None, Strings.FileAccountPassword, undefined, true)],
|
||||
ChallengeReason.DecryptEncryptedFile,
|
||||
true,
|
||||
)
|
||||
const passwordResponse = await this.challengeService.promptForChallengeResponse(challenge)
|
||||
if (passwordResponse == undefined) {
|
||||
/** Challenge was canceled */
|
||||
return Result.fail('Import aborted')
|
||||
}
|
||||
this.challengeService.completeChallenge(challenge)
|
||||
return Result.ok(passwordResponse?.values[0].value as string)
|
||||
}
|
||||
|
||||
/**
|
||||
* Prior to 003 backup files did not have a version field so we cannot
|
||||
* stop importing if there is no backup file version, only if there is
|
||||
* an unsupported version.
|
||||
*/
|
||||
private validateVersion(version: ProtocolVersion): Result<void> {
|
||||
const supportedVersions = this.encryption.supportedVersions()
|
||||
if (!supportedVersions.includes(version)) {
|
||||
return Result.fail(Strings.UnsupportedBackupFileVersion)
|
||||
}
|
||||
|
||||
const userVersion = this.encryption.getUserVersion()
|
||||
if (userVersion && compareVersions(version, userVersion) === 1) {
|
||||
/** File was made with a greater version than the user's account */
|
||||
return Result.fail(Strings.BackupFileMoreRecentThanAccount)
|
||||
}
|
||||
|
||||
return Result.ok()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,6 @@ import {
|
||||
EncryptedPayloadInterface,
|
||||
FullyFormedPayloadInterface,
|
||||
PayloadEmitSource,
|
||||
DecryptedPayloadInterface,
|
||||
HistoryMap,
|
||||
} from '@standardnotes/models'
|
||||
import { IntegrityPayload } from '@standardnotes/responses'
|
||||
@@ -24,7 +23,7 @@ export interface PayloadManagerInterface {
|
||||
*/
|
||||
get nonDeletedItems(): FullyFormedPayloadInterface[]
|
||||
|
||||
importPayloads(payloads: DecryptedPayloadInterface[], historyMap: HistoryMap): Promise<string[]>
|
||||
importPayloads(payloads: FullyFormedPayloadInterface[], historyMap: HistoryMap): Promise<string[]>
|
||||
|
||||
removePayloadLocally(payload: FullyFormedPayloadInterface | FullyFormedPayloadInterface[]): void
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user