Compare commits

...
Author SHA1 Message Date
StandardNotes CI 0eb552ddc7 chore(release): publish
- @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
2023-07-27 13:12:27 +00:00
Mo 14bae5e895 tests: vault tests 3 (#2373) 2023-07-27 07:35:38 -05:00
StandardNotes CI 1fef36d601 chore(release): publish
- @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].7
 - @standardnotes/[email protected]
2023-07-26 21:20:45 +00:00
Mo d268c02ab3 fix: Fixes issue where lock screen would not use previously active theme (#2372) 2023-07-26 15:50:08 -05:00
StandardNotes CI 86fc4c684d chore(release): publish
- @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
2023-07-26 13:11:46 +00:00
Mo ef2d1b9228 Revert "chore: upgrade desktop deps"
This reverts commit 47a36c4cbd.
2023-07-26 07:36:39 -05:00
Mo 868a84f587 chore: lint [no ci] 2023-07-26 06:45:29 -05:00
Mo 7c463b36af tests: vault tests [no ci] 2023-07-26 06:43:52 -05:00
StandardNotes CI 908cbaf895 chore(release): publish
- @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].9
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
2023-07-26 10:55:05 +00:00
Aman Harwara 51cb14c010 chore: fix super session history 2023-07-26 15:50:19 +05:30
Mo 47a36c4cbd chore: upgrade desktop deps 2023-07-26 05:09:41 -05:00
Mo 7222ca7fd0 tests: vaults-2 (#2368) 2023-07-26 04:55:58 -05:00
StandardNotes CI 6ad5d028af chore(release): publish
- @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].9
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
2023-07-25 13:13:37 +00:00
Mo 596e041c42 tests: vault tests (#2366) 2023-07-25 07:40:28 -05:00
StandardNotes CI 80436cd0b9 chore(release): publish
- @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
2023-07-25 07:34:13 +00:00
Aman Harwara 40c0a08e74 chore: build 2023-07-25 12:33:11 +05:30
StandardNotes CI 560e91bce9 chore(release): publish
- @standardnotes/[email protected]
 - @standardnotes/[email protected]
2023-07-24 21:53:18 +00:00
Aman Harwara 2a3db43df5 chore: fix issue with sharing files with spaces in filename on ios 2023-07-25 02:53:19 +05:30
222 changed files with 3420 additions and 1712 deletions
+12
View File
@@ -3,6 +3,18 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [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 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@standardnotes/api",
"version": "1.26.30",
"version": "1.26.33",
"engines": {
"node": ">=16.0.0 <17.0.0"
},
+24
View File
@@ -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.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.1.111](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-07-24)
**Note:** Version bump only for package @standardnotes/clipper
+1 -1
View File
@@ -1,7 +1,7 @@
{
"name": "@standardnotes/clipper",
"description": "Web clipper browser extension for Standard Notes",
"version": "1.1.111",
"version": "1.1.117",
"private": true,
"scripts": {
"build-mv2": "yarn clean && webpack --config ./webpack.config.prod.js",
+26
View File
@@ -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.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
## [3.108.42](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-07-24)
**Note:** Version bump only for package @standardnotes/desktop
+1 -1
View File
@@ -1,7 +1,7 @@
{
"name": "@standardnotes/desktop",
"main": "./app/dist/index.js",
"version": "3.108.42",
"version": "3.108.48",
"license": "AGPL-3.0-or-later",
"author": "Standard Notes.",
"private": true,
+12
View File
@@ -3,6 +3,18 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [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 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@standardnotes/encryption",
"version": "1.21.53",
"version": "1.21.56",
"engines": {
"node": ">=16.0.0 <17.0.0"
},
@@ -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,
@@ -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,
@@ -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
+6
View File
@@ -3,6 +3,12 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [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 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@standardnotes/features",
"version": "1.59.10",
"version": "1.59.11",
"engines": {
"node": ">=16.0.0 <17.0.0"
},
@@ -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],
},
+8 -8
View File
@@ -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 -2
View File
@@ -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'
+12
View File
@@ -3,6 +3,18 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [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 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@standardnotes/filepicker",
"version": "1.28.62",
"version": "1.28.65",
"engines": {
"node": ">=16.0.0 <17.0.0"
},
+12
View File
@@ -3,6 +3,18 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [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 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@standardnotes/files",
"version": "1.16.8",
"version": "1.16.11",
"engines": {
"node": ">=16.0.0 <17.0.0"
},
+28
View File
@@ -3,6 +3,34 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [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
## [3.56.22](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-07-24)
**Note:** Version bump only for package @standardnotes/mobile
## [3.56.21](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-07-24)
**Note:** Version bump only for package @standardnotes/mobile
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@standardnotes/mobile",
"version": "3.56.21",
"version": "3.56.28",
"author": "Standard Notes.",
"private": true,
"license": "AGPL-3.0-or-later",
@@ -144,7 +144,7 @@ export class ReceivedSharedItemsHandler {
sendFileToWebView = async (item: ReceivedAndroidFile | ReceivedIosFile) => {
const path = isReceivedAndroidFile(item) ? item.contentUri : item.path
const data = await readFile(path, 'base64')
const data = await readFile(decodeURIComponent(path), 'base64')
const file = {
name: item.fileName || item.path,
data,
+14
View File
@@ -3,6 +3,20 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [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 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@standardnotes/models",
"version": "1.46.12",
"version": "1.46.15",
"engines": {
"node": ">=16.0.0 <17.0.0"
},
@@ -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
+1 -1
View File
@@ -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'
+28
View File
@@ -3,6 +3,34 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [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.4.394](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-07-24)
**Note:** Version bump only for package @standardnotes/releases
## [1.4.393](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-07-24)
**Note:** Version bump only for package @standardnotes/releases
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@standardnotes/releases",
"version": "1.4.393",
"version": "1.4.400",
"license": "AGPL-3.0-or-later",
"main": "dist/releases.json",
"types": "dist/index.d.ts",
+4
View File
@@ -3,6 +3,10 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [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 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@standardnotes/responses",
"version": "1.13.31",
"version": "1.13.32",
"engines": {
"node": ">=16.0.0 <17.0.0"
},
+22
View File
@@ -3,6 +3,28 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [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 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@standardnotes/services",
"version": "1.63.8",
"version": "1.63.13",
"engines": {
"node": ">=16.0.0 <17.0.0"
},
@@ -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,
@@ -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
}
}
@@ -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 {
@@ -32,7 +32,7 @@ export class ResendAllMessages implements UseCaseInterface<void> {
for (const message of messages.data.messages) {
const recipient = this.findContact.execute({ userUuid: message.user_uuid })
if (recipient) {
if (recipient.isFailed()) {
errors.push(`Contact not found for invite ${message.user_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,
})
}
}
@@ -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()
}
@@ -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
}
@@ -13,7 +13,6 @@ import {
EncryptionOperatorsInterface,
} from '@standardnotes/encryption'
import {
ContentTypesUsingRootKeyEncryption,
DecryptedPayload,
DecryptedTransferPayload,
EncryptedPayload,
@@ -32,12 +31,11 @@ import { StorageValueModes } from '../Storage/StorageTypes'
import { EncryptTypeAPayload } from '../Encryption/UseCase/TypeA/EncryptPayload'
import { DecryptTypeAPayload } from '../Encryption/UseCase/TypeA/DecryptPayload'
import { AbstractService } from '../Service/AbstractService'
import { ItemManagerInterface } from '../Item/ItemManagerInterface'
import { MutatorClientInterface } from '../Mutator/MutatorClientInterface'
import { RootKeyManagerEvent } from './RootKeyManagerEvent'
import { ValidatePasscodeResult } from './ValidatePasscodeResult'
import { ValidateAccountPasswordResult } from './ValidateAccountPasswordResult'
import { KeyMode } from './KeyMode'
import { ReencryptTypeAItems } from '../Encryption/UseCase/TypeA/ReencryptTypeAItems'
export class RootKeyManager extends AbstractService<RootKeyManagerEvent> {
private rootKey?: RootKeyInterface
@@ -47,10 +45,9 @@ export class RootKeyManager extends AbstractService<RootKeyManagerEvent> {
constructor(
private device: DeviceInterface,
private storage: StorageServiceInterface,
private items: ItemManagerInterface,
private mutator: MutatorClientInterface,
private operators: EncryptionOperatorsInterface,
private identifier: ApplicationIdentifier,
private _reencryptTypeAItems: ReencryptTypeAItems,
eventBus: InternalEventBusInterface,
) {
super(eventBus)
@@ -58,6 +55,12 @@ export class RootKeyManager extends AbstractService<RootKeyManagerEvent> {
override deinit() {
super.deinit()
;(this.device as unknown) = undefined
;(this.storage as unknown) = undefined
;(this.operators as unknown) = undefined
;(this.identifier as unknown) = undefined
;(this._reencryptTypeAItems as unknown) = undefined
this.rootKey = undefined
this.memoizedRootKeyParams = undefined
}
@@ -307,7 +310,7 @@ export class RootKeyManager extends AbstractService<RootKeyManagerEvent> {
if (this.keyMode === KeyMode.WrapperOnly || this.keyMode === KeyMode.RootKeyPlusWrapper) {
if (this.keyMode === KeyMode.WrapperOnly) {
this.setRootKeyInstance(wrappingKey)
await this.reencryptApplicableItemsAfterUserRootKeyChange()
await this._reencryptTypeAItems.execute()
} else {
await this.wrapAndPersistRootKey(wrappingKey)
}
@@ -473,19 +476,4 @@ export class RootKeyManager extends AbstractService<RootKeyManagerEvent> {
keyParams: keyParams.getPortableValue(),
})
}
/**
* When the root key changes, we must re-encrypt all relevant items with this new root key (by simply re-syncing).
*/
public async reencryptApplicableItemsAfterUserRootKeyChange(): Promise<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)
}
}
}
@@ -1,5 +1,5 @@
export enum SessionEvent {
Restored = 'SessionRestored',
Revoked = 'SessionRevoked',
UserKeyPairChanged = 'UserKeyPairChanged',
Restored = 'SessionEvent:SessionRestored',
Revoked = 'SessionEvent:SessionRevoked',
UserKeyPairChanged = 'SessionEvent:UserKeyPairChanged',
}
@@ -18,8 +18,6 @@ export interface SessionsClientInterface {
getWorkspaceDisplayIdentifier(): string
populateSessionFromDemoShareToken(token: Base64String): Promise<void>
initializeFromDisk(): Promise<void>
getUser(): User | undefined
isSignedIn(): boolean
get userUuid(): string
@@ -1,3 +1,4 @@
import { DiscardItemsLocally } from './../UseCase/DiscardItemsLocally'
import { InternalEventBusInterface } from './../Internal/InternalEventBusInterface'
import { GetOwnedSharedVaults } from './UseCase/GetOwnedSharedVaults'
import { IsVaultOwner } from './../VaultUser/UseCase/IsVaultOwner'
@@ -11,7 +12,7 @@ import { SendVaultDataChangedMessage } from './UseCase/SendVaultDataChangedMessa
import { NotifyVaultUsersOfKeyRotation } from './UseCase/NotifyVaultUsersOfKeyRotation'
import { HandleKeyPairChange } from './../Contacts/UseCase/HandleKeyPairChange'
import { CreateSharedVault } from './UseCase/CreateSharedVault'
import { GetVault } from './../Vaults/UseCase/GetVault'
import { GetVault } from './../Vault/UseCase/GetVault'
import { SharedVaultService } from './SharedVaultService'
import { SyncServiceInterface } from '../Sync/SyncServiceInterface'
import { ItemManagerInterface } from '../Item/ItemManagerInterface'
@@ -42,6 +43,7 @@ describe('SharedVaultService', () => {
const convertToSharedVault = {} as jest.Mocked<ConvertToSharedVault>
const deleteSharedVaultUseCase = {} as jest.Mocked<DeleteSharedVault>
const isVaultAdmin = {} as jest.Mocked<IsVaultOwner>
const discardItemsLocally = {} as jest.Mocked<DiscardItemsLocally>
const eventBus = {} as jest.Mocked<InternalEventBusInterface>
eventBus.addEventHandler = jest.fn()
@@ -62,6 +64,7 @@ describe('SharedVaultService', () => {
convertToSharedVault,
deleteSharedVaultUseCase,
isVaultAdmin,
discardItemsLocally,
eventBus,
)
})
@@ -1,3 +1,4 @@
import { DiscardItemsLocally } from './../UseCase/DiscardItemsLocally'
import { UserKeyPairChangedEventData } from './../Session/UserKeyPairChangedEventData'
import { ClientDisplayableError, UserEventType } from '@standardnotes/responses'
import {
@@ -21,13 +22,13 @@ import { InternalEventInterface } from '../Internal/InternalEventInterface'
import { UserEventServiceEvent, UserEventServiceEventPayload } from '../UserEvent/UserEventServiceEvent'
import { DeleteThirdPartyVault } from './UseCase/DeleteExternalSharedVault'
import { DeleteSharedVault } from './UseCase/DeleteSharedVault'
import { VaultServiceEvent, VaultServiceEventPayload } from '../Vaults/VaultServiceEvent'
import { VaultServiceEvent, VaultServiceEventPayload } from '../Vault/VaultServiceEvent'
import { ShareContactWithVault } from './UseCase/ShareContactWithVault'
import { NotifyVaultUsersOfKeyRotation } from './UseCase/NotifyVaultUsersOfKeyRotation'
import { CreateSharedVault } from './UseCase/CreateSharedVault'
import { SendVaultDataChangedMessage } from './UseCase/SendVaultDataChangedMessage'
import { ConvertToSharedVault } from './UseCase/ConvertToSharedVault'
import { GetVault } from '../Vaults/UseCase/GetVault'
import { GetVault } from '../Vault/UseCase/GetVault'
import { ContentType } from '@standardnotes/domain-core'
import { HandleKeyPairChange } from '../Contacts/UseCase/HandleKeyPairChange'
import { FindContact } from '../Contacts/UseCase/FindContact'
@@ -55,6 +56,7 @@ export class SharedVaultService
private _convertToSharedVault: ConvertToSharedVault,
private _deleteSharedVault: DeleteSharedVault,
private _isVaultAdmin: IsVaultOwner,
private _discardItemsLocally: DiscardItemsLocally,
eventBus: InternalEventBusInterface,
) {
super(eventBus)
@@ -132,7 +134,7 @@ export class SharedVaultService
case UserEventType.SharedVaultItemRemoved: {
const item = this.items.findItem(event.eventPayload.itemUuid)
if (item) {
this.items.removeItemsLocally([item])
void this._discardItemsLocally.execute([item])
}
break
}
@@ -2,7 +2,7 @@ import { SharedVaultListingInterface, VaultListingInterface, VaultListingMutator
import { ClientDisplayableError, isErrorResponse } from '@standardnotes/responses'
import { SharedVaultServerInterface } from '@standardnotes/api'
import { ItemManagerInterface } from '../../Item/ItemManagerInterface'
import { MoveItemsToVault } from '../../Vaults/UseCase/MoveItemsToVault'
import { MoveItemsToVault } from '../../Vault/UseCase/MoveItemsToVault'
import { MutatorClientInterface } from '../../Mutator/MutatorClientInterface'
export class ConvertToSharedVault {
@@ -7,8 +7,8 @@ import {
import { ClientDisplayableError, isErrorResponse } from '@standardnotes/responses'
import { SharedVaultServerInterface } from '@standardnotes/api'
import { ItemManagerInterface } from '../../Item/ItemManagerInterface'
import { CreateVault } from '../../Vaults/UseCase/CreateVault'
import { MoveItemsToVault } from '../../Vaults/UseCase/MoveItemsToVault'
import { CreateVault } from '../../Vault/UseCase/CreateVault'
import { MoveItemsToVault } from '../../Vault/UseCase/MoveItemsToVault'
import { MutatorClientInterface } from '../../Mutator/MutatorClientInterface'
export class CreateSharedVault {
@@ -2,7 +2,7 @@ import { SyncServiceInterface } from './../../Sync/SyncServiceInterface'
import { ItemManagerInterface } from '../../Item/ItemManagerInterface'
import { AnyItemInterface, VaultListingInterface } from '@standardnotes/models'
import { MutatorClientInterface } from '../../Mutator/MutatorClientInterface'
import { RemoveItemsLocally } from '../../UseCase/RemoveItemsLocally'
import { DiscardItemsLocally } from '../../UseCase/DiscardItemsLocally'
import { KeySystemKeyManagerInterface } from '../../KeySystem/KeySystemKeyManagerInterface'
export class DeleteThirdPartyVault {
@@ -11,7 +11,7 @@ export class DeleteThirdPartyVault {
private mutator: MutatorClientInterface,
private keys: KeySystemKeyManagerInterface,
private sync: SyncServiceInterface,
private removeItemsLocally: RemoveItemsLocally,
private _discardItemsLocally: DiscardItemsLocally,
) {}
async execute(vault: VaultListingInterface): Promise<void> {
@@ -33,7 +33,7 @@ export class DeleteThirdPartyVault {
const itemsKeys = this.keys.getKeySystemItemsKeys(vault.systemIdentifier)
await this.removeItemsLocally.execute([...vaultItems, ...itemsKeys])
await this._discardItemsLocally.execute([...vaultItems, ...itemsKeys])
}
private async deleteDataOwnedByThisUser(vault: VaultListingInterface): Promise<void> {
@@ -2,7 +2,7 @@ import { ClientDisplayableError, isErrorResponse } from '@standardnotes/response
import { SharedVaultServerInterface } from '@standardnotes/api'
import { SharedVaultListingInterface } from '@standardnotes/models'
import { SyncServiceInterface } from '../../Sync/SyncServiceInterface'
import { DeleteVault } from '../../Vaults/UseCase/DeleteVault'
import { DeleteVault } from '../../Vault/UseCase/DeleteVault'
export class DeleteSharedVault {
constructor(
@@ -1,4 +1,4 @@
import { GetVaults } from './../../Vaults/UseCase/GetVaults'
import { GetVaults } from '../../Vault/UseCase/GetVaults'
import { Result, SyncUseCaseInterface } from '@standardnotes/domain-core'
import { SharedVaultListingInterface } from '@standardnotes/models'
@@ -14,14 +14,17 @@ export interface StorageServiceInterface {
getAllKeys(mode?: StorageValueModes): string[]
getValue<T>(key: string, mode?: StorageValueModes, defaultValue?: T): T
canDecryptWithKey(key: RootKeyInterface): Promise<boolean>
savePayload(payload: PayloadInterface): Promise<void>
savePayloads(decryptedPayloads: PayloadInterface[]): Promise<void>
setValue<T>(key: string, value: T, mode?: StorageValueModes): void
removeValue(key: string, mode?: StorageValueModes): Promise<void>
setPersistencePolicy(persistencePolicy: StoragePersistencePolicies): Promise<void>
clearAllData(): Promise<void>
getRawPayloads(uuids: string[]): Promise<FullyFormedTransferPayload[]>
savePayload(payload: PayloadInterface): Promise<void>
savePayloads(decryptedPayloads: PayloadInterface[]): Promise<void>
deletePayloads(payloads: FullyFormedPayloadInterface[]): Promise<void>
deletePayloadsWithUuids(uuids: string[]): Promise<void>
clearAllPayloads(): Promise<void>
isEphemeralSession(): boolean
}
@@ -0,0 +1,48 @@
import { RemoveItemsFromMemory } from './RemoveItemsFromMemory'
import { ItemManagerInterface } from '../../Item/ItemManagerInterface'
import { StorageServiceInterface } from '../StorageServiceInterface'
import { PayloadManagerInterface } from '../../Payloads/PayloadManagerInterface'
import { PayloadEmitSource, DecryptedItemInterface } from '@standardnotes/models'
import { Uuids } from '@standardnotes/utils'
describe('RemoveItemsFromMemory', () => {
let storage: StorageServiceInterface
let items: ItemManagerInterface
let payloads: PayloadManagerInterface
let removeItemsFromMemory: RemoveItemsFromMemory
beforeEach(() => {
storage = {
getRawPayloads: jest.fn().mockImplementation(() => Promise.resolve([])),
} as unknown as StorageServiceInterface
items = {
removeItemsFromMemory: jest.fn(),
} as unknown as ItemManagerInterface
payloads = {
emitPayloads: jest.fn().mockImplementation(() => Promise.resolve()),
} as unknown as PayloadManagerInterface
removeItemsFromMemory = new RemoveItemsFromMemory(storage, items, payloads)
})
it('should execute removeItemsFromMemory use case correctly', async () => {
const testItems: DecryptedItemInterface[] = [
<DecryptedItemInterface>{
uuid: 'uuid1',
content_type: 'type1',
},
<DecryptedItemInterface>{
uuid: 'uuid2',
content_type: 'type2',
},
]
await removeItemsFromMemory.execute(testItems)
expect(items.removeItemsFromMemory).toHaveBeenCalledWith(testItems)
expect(storage.getRawPayloads).toHaveBeenCalledWith(Uuids(testItems))
expect(payloads.emitPayloads).toHaveBeenCalledWith([], PayloadEmitSource.LocalDatabaseLoaded)
})
})
@@ -0,0 +1,26 @@
import { ItemManagerInterface } from '../../Item/ItemManagerInterface'
import { Result, UseCaseInterface } from '@standardnotes/domain-core'
import { StorageServiceInterface } from '../StorageServiceInterface'
import { CreatePayload, DecryptedItemInterface, PayloadEmitSource, PayloadSource } from '@standardnotes/models'
import { Uuids } from '@standardnotes/utils'
import { PayloadManagerInterface } from '../../Payloads/PayloadManagerInterface'
export class RemoveItemsFromMemory implements UseCaseInterface<void> {
constructor(
private storage: StorageServiceInterface,
private items: ItemManagerInterface,
private payloads: PayloadManagerInterface,
) {}
async execute(items: DecryptedItemInterface[]): Promise<Result<void>> {
this.items.removeItemsFromMemory(items)
const rawPayloads = await this.storage.getRawPayloads(Uuids(items))
const encryptedPayloads = rawPayloads.map((payload) => CreatePayload(payload, PayloadSource.LocalDatabaseLoaded))
await this.payloads.emitPayloads(encryptedPayloads, PayloadEmitSource.LocalDatabaseLoaded)
return Result.ok()
}
}

Some files were not shown because too many files have changed in this diff Show More