Compare commits

...
Author SHA1 Message Date
StandardNotes CI bfd2b14264 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]
2023-07-27 14:11:52 +00:00
Karol Sójko eb062220d6 chore: fix endpoints and properties used in shared vaults to match the server (#2370)
* chore: upgrade @standardnotes/domain-core

* chore: enable vault tests by default

* chore: fix asymmetric messages paths

* chore: fix message property from user_uuid to recipient_uuid

* chore: fix server response properties for messages and notifications

* chore: fix user_uuid to recipient_uuid in resend all message use case

* chore: use notification payload and type from domain-core

* chore: fix non existent uuid in conflicts tests

* chore: use shared vault user permission from domain-core

* chore: enable all e2e tests

* chore: upgrade domain-core

* chore: mark failing tests as skipped

* chore: skip test

* chore: fix recipient_uuid in specs

* chore: skip test

* chore: skip test

* chore: skip test

* chore: skip test

* chore: fix remove unused var and unskip test

* Revert "chore: skip test"

This reverts commit 26bb876cf55e2c4fa9eeea56f73b3c2917a26f5c.

* chore: unskip passing tests

* chore: skip test

* chore: skip test

* fix: handle invite creation error

* chore: skip tests

* fix: disable vault tests to merge the PR

* chore: unskip asymmetric messages tests
2023-07-27 15:43:45 +02:00
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
182 changed files with 1859 additions and 1173 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.34](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-07-27)
**Note:** Version bump only for package @standardnotes/api
## [1.26.33](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-07-27)
**Note:** Version bump only for package @standardnotes/api
## [1.26.32](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-07-26)
**Note:** Version bump only for package @standardnotes/api
## [1.26.31](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-07-26)
**Note:** Version bump only for package @standardnotes/api
+2 -2
View File
@@ -1,6 +1,6 @@
{
"name": "@standardnotes/api",
"version": "1.26.31",
"version": "1.26.34",
"engines": {
"node": ">=16.0.0 <17.0.0"
},
@@ -36,7 +36,7 @@
},
"dependencies": {
"@standardnotes/common": "^1.50.0",
"@standardnotes/domain-core": "^1.22.0",
"@standardnotes/domain-core": "^1.24.0",
"@standardnotes/models": "workspace:*",
"@standardnotes/responses": "workspace:*",
"@standardnotes/utils": "workspace:*",
@@ -1,8 +1,8 @@
import { SharedVaultPermission } from '@standardnotes/responses'
import { SharedVaultUserPermission } from '@standardnotes/domain-core'
export type CreateSharedVaultInviteParams = {
sharedVaultUuid: string
recipientUuid: string
encryptedMessage: string
permissions: SharedVaultPermission
permission: SharedVaultUserPermission
}
@@ -1,8 +1,8 @@
import { SharedVaultPermission } from '@standardnotes/responses'
import { SharedVaultUserPermission } from '@standardnotes/domain-core'
export type UpdateSharedVaultInviteParams = {
sharedVaultUuid: string
inviteUuid: string
encryptedMessage: string
permissions?: SharedVaultPermission
permission?: SharedVaultUserPermission
}
@@ -1,9 +1,9 @@
export const AsymmetricMessagesPaths = {
createMessage: '/v1/asymmetric-messages',
getMessages: '/v1/asymmetric-messages',
updateMessage: (messageUuid: string) => `/v1/asymmetric-messages/${messageUuid}`,
getInboundUserMessages: () => '/v1/asymmetric-messages',
getOutboundUserMessages: () => '/v1/asymmetric-messages/outbound',
deleteMessage: (messageUuid: string) => `/v1/asymmetric-messages/${messageUuid}`,
deleteAllInboundMessages: '/v1/asymmetric-messages/inbound',
createMessage: '/v1/messages',
getMessages: '/v1/messages',
updateMessage: (messageUuid: string) => `/v1/messages/${messageUuid}`,
getInboundUserMessages: () => '/v1/messages',
getOutboundUserMessages: () => '/v1/messages/outbound',
deleteMessage: (messageUuid: string) => `/v1/messages/${messageUuid}`,
deleteAllInboundMessages: '/v1/messages/inbound',
}
@@ -26,14 +26,14 @@ export class SharedVaultInvitesServer implements SharedVaultInvitesServerInterfa
return this.httpService.post(SharedVaultInvitesPaths.createInvite(params.sharedVaultUuid), {
recipient_uuid: params.recipientUuid,
encrypted_message: params.encryptedMessage,
permissions: params.permissions,
permission: params.permission.value,
})
}
updateInvite(params: UpdateSharedVaultInviteParams): Promise<HttpResponse<UpdateSharedVaultInviteResponse>> {
return this.httpService.patch(SharedVaultInvitesPaths.updateInvite(params.sharedVaultUuid, params.inviteUuid), {
encrypted_message: params.encryptedMessage,
permissions: params.permissions,
permission: params.permission?.value,
})
}
+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.1.118](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-07-27)
**Note:** Version bump only for package @standardnotes/clipper
## [1.1.117](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-07-27)
**Note:** Version bump only for package @standardnotes/clipper
## [1.1.116](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-07-26)
**Note:** Version bump only for package @standardnotes/clipper
## [1.1.115](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-07-26)
**Note:** Version bump only for package @standardnotes/clipper
+1 -1
View File
@@ -1,7 +1,7 @@
{
"name": "@standardnotes/clipper",
"description": "Web clipper browser extension for Standard Notes",
"version": "1.1.115",
"version": "1.1.118",
"private": true,
"scripts": {
"build-mv2": "yarn clean && webpack --config ./webpack.config.prod.js",
+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.
## [3.108.49](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-07-27)
**Note:** Version bump only for package @standardnotes/desktop
## [3.108.48](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-07-27)
**Note:** Version bump only for package @standardnotes/desktop
## [3.108.47](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-07-26)
**Note:** Version bump only for package @standardnotes/desktop
## [3.108.46](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-07-26)
### Reverts
+2 -2
View File
@@ -1,7 +1,7 @@
{
"name": "@standardnotes/desktop",
"main": "./app/dist/index.js",
"version": "3.108.46",
"version": "3.108.49",
"license": "AGPL-3.0-or-later",
"author": "Standard Notes.",
"private": true,
@@ -35,7 +35,7 @@
},
"dependencies": {
"@electron/remote": "^2.0.9",
"@standardnotes/domain-core": "^1.22.0",
"@standardnotes/domain-core": "^1.24.0",
"@standardnotes/electron-clear-data": "1.1.1",
"@standardnotes/web": "workspace:*",
"axios": "^1.1.3",
+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.57](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-07-27)
**Note:** Version bump only for package @standardnotes/encryption
## [1.21.56](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-07-27)
**Note:** Version bump only for package @standardnotes/encryption
## [1.21.55](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-07-26)
**Note:** Version bump only for package @standardnotes/encryption
## [1.21.54](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-07-26)
**Note:** Version bump only for package @standardnotes/encryption
+2 -2
View File
@@ -1,6 +1,6 @@
{
"name": "@standardnotes/encryption",
"version": "1.21.54",
"version": "1.21.57",
"engines": {
"node": ">=16.0.0 <17.0.0"
},
@@ -29,7 +29,7 @@
},
"dependencies": {
"@standardnotes/common": "^1.50.0",
"@standardnotes/domain-core": "^1.22.0",
"@standardnotes/domain-core": "^1.24.0",
"@standardnotes/models": "workspace:*",
"@standardnotes/responses": "workspace:*",
"@standardnotes/sncrypto-common": "workspace:*",
@@ -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
+10
View File
@@ -3,6 +3,16 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.59.12](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-07-27)
**Note:** Version bump only for package @standardnotes/features
## [1.59.11](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-07-26)
### Bug Fixes
* Fixes issue where lock screen would not use previously active theme ([#2372](https://github.com/standardnotes/app/issues/2372)) ([d268c02](https://github.com/standardnotes/app/commit/d268c02ab31beb5e2fd9e6547610f9a4dd61bed4))
## [1.59.10](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-07-17)
**Note:** Version bump only for package @standardnotes/features
+2 -2
View File
@@ -1,6 +1,6 @@
{
"name": "@standardnotes/features",
"version": "1.59.10",
"version": "1.59.12",
"engines": {
"node": ">=16.0.0 <17.0.0"
},
@@ -26,7 +26,7 @@
},
"dependencies": {
"@standardnotes/common": "^1.50.0",
"@standardnotes/domain-core": "^1.22.0",
"@standardnotes/domain-core": "^1.24.0",
"reflect-metadata": "^0.1.13"
},
"devDependencies": {
@@ -1,5 +0,0 @@
import { FeatureIdentifier } from './../Feature/FeatureIdentifier'
type ThirdPartyIdentifier = string
export type EditorIdentifier = FeatureIdentifier | ThirdPartyIdentifier
@@ -1,16 +1,16 @@
import { FeatureIdentifier } from '@standardnotes/features'
import { NativeFeatureIdentifier } from '@standardnotes/features'
import { noteTypeForEditorIdentifier, NoteType } from './NoteType'
describe('note type', () => {
it('should return the correct note type for editor identifier', () => {
expect(noteTypeForEditorIdentifier(FeatureIdentifier.PlainEditor)).toEqual(NoteType.Plain)
expect(noteTypeForEditorIdentifier(FeatureIdentifier.SuperEditor)).toEqual(NoteType.Super)
expect(noteTypeForEditorIdentifier(FeatureIdentifier.MarkdownProEditor)).toEqual(NoteType.Markdown)
expect(noteTypeForEditorIdentifier(FeatureIdentifier.PlusEditor)).toEqual(NoteType.RichText)
expect(noteTypeForEditorIdentifier(FeatureIdentifier.CodeEditor)).toEqual(NoteType.Code)
expect(noteTypeForEditorIdentifier(FeatureIdentifier.SheetsEditor)).toEqual(NoteType.Spreadsheet)
expect(noteTypeForEditorIdentifier(FeatureIdentifier.TaskEditor)).toEqual(NoteType.Task)
expect(noteTypeForEditorIdentifier(FeatureIdentifier.TokenVaultEditor)).toEqual(NoteType.Authentication)
expect(noteTypeForEditorIdentifier(NativeFeatureIdentifier.TYPES.PlainEditor)).toEqual(NoteType.Plain)
expect(noteTypeForEditorIdentifier(NativeFeatureIdentifier.TYPES.SuperEditor)).toEqual(NoteType.Super)
expect(noteTypeForEditorIdentifier(NativeFeatureIdentifier.TYPES.MarkdownProEditor)).toEqual(NoteType.Markdown)
expect(noteTypeForEditorIdentifier(NativeFeatureIdentifier.TYPES.PlusEditor)).toEqual(NoteType.RichText)
expect(noteTypeForEditorIdentifier(NativeFeatureIdentifier.TYPES.CodeEditor)).toEqual(NoteType.Code)
expect(noteTypeForEditorIdentifier(NativeFeatureIdentifier.TYPES.SheetsEditor)).toEqual(NoteType.Spreadsheet)
expect(noteTypeForEditorIdentifier(NativeFeatureIdentifier.TYPES.TaskEditor)).toEqual(NoteType.Task)
expect(noteTypeForEditorIdentifier(NativeFeatureIdentifier.TYPES.TokenVaultEditor)).toEqual(NoteType.Authentication)
expect(noteTypeForEditorIdentifier('org.third.party')).toEqual(NoteType.Unknown)
})
})
@@ -1,8 +1,6 @@
import { EditorFeatureDescription } from '../Feature/EditorFeatureDescription'
import { FindNativeFeature } from '../Feature/Features'
import { IframeComponentFeatureDescription } from '../Feature/IframeComponentFeatureDescription'
import { FeatureIdentifier } from './../Feature/FeatureIdentifier'
import { EditorIdentifier } from './EditorIdentifier'
export enum NoteType {
Authentication = 'authentication',
@@ -16,10 +14,8 @@ export enum NoteType {
Unknown = 'unknown',
}
export function noteTypeForEditorIdentifier(identifier: EditorIdentifier): NoteType {
const feature = FindNativeFeature<EditorFeatureDescription | IframeComponentFeatureDescription>(
identifier as FeatureIdentifier,
)
export function noteTypeForEditorIdentifier(identifier: string): NoteType {
const feature = FindNativeFeature<EditorFeatureDescription | IframeComponentFeatureDescription>(identifier)
if (feature && feature.note_type) {
return feature.note_type
}
@@ -1,5 +1,4 @@
import { PermissionName } from '../Permission/PermissionName'
import { FeatureIdentifier } from './FeatureIdentifier'
import { ComponentFlag } from '../Component/ComponentFlag'
import { RoleFields } from './RoleFields'
@@ -14,7 +13,7 @@ export type BaseFeatureDescription = RoleFields & {
clientControlled?: boolean
flags?: ComponentFlag[]
identifier: FeatureIdentifier
identifier: string
marketing_url?: string
name: string
no_expire?: boolean
@@ -1,9 +1,8 @@
import { PermissionName } from '../Permission/PermissionName'
import { FeatureIdentifier } from './FeatureIdentifier'
import { RoleFields } from './RoleFields'
export type ClientFeatureDescription = RoleFields & {
identifier: FeatureIdentifier
identifier: string
permission_name: PermissionName
description: string
name: string
@@ -1,51 +0,0 @@
export enum FeatureIdentifier {
DailyEmailBackup = 'org.standardnotes.daily-email-backup',
Files = 'org.standardnotes.files',
FilesLowStorageTier = 'org.standardnotes.files-low-storage-tier',
FilesMaximumStorageTier = 'org.standardnotes.files-max-storage-tier',
ListedCustomDomain = 'org.standardnotes.listed-custom-domain',
NoteHistory30Days = 'org.standardnotes.note-history-30',
NoteHistory365Days = 'org.standardnotes.note-history-365',
NoteHistoryUnlimited = 'org.standardnotes.note-history-unlimited',
SignInAlerts = 'com.standardnotes.sign-in-alerts',
SmartFilters = 'org.standardnotes.smart-filters',
TagNesting = 'org.standardnotes.tag-nesting',
TwoFactorAuth = 'org.standardnotes.two-factor-auth',
UniversalSecondFactor = 'org.standardnotes.universal-second-factor',
SubscriptionSharing = 'org.standardnotes.subscription-sharing',
AutobiographyTheme = 'org.standardnotes.theme-autobiography',
DynamicTheme = 'org.standardnotes.theme-dynamic',
DarkTheme = 'org.standardnotes.theme-focus',
FuturaTheme = 'org.standardnotes.theme-futura',
MidnightTheme = 'org.standardnotes.theme-midnight',
SolarizedDarkTheme = 'org.standardnotes.theme-solarized-dark',
TitaniumTheme = 'org.standardnotes.theme-titanium',
PlainEditor = 'com.standardnotes.plain-text',
SuperEditor = 'com.standardnotes.super-editor',
CodeEditor = 'org.standardnotes.code-editor',
MarkdownProEditor = 'org.standardnotes.advanced-markdown-editor',
PlusEditor = 'org.standardnotes.plus-editor',
SheetsEditor = 'org.standardnotes.standard-sheets',
TaskEditor = 'org.standardnotes.simple-task-editor',
TokenVaultEditor = 'org.standardnotes.token-vault',
Extension = 'org.standardnotes.extension',
DeprecatedMarkdownVisualEditor = 'org.standardnotes.markdown-visual-editor',
DeprecatedBoldEditor = 'org.standardnotes.bold-editor',
DeprecatedMarkdownBasicEditor = 'org.standardnotes.simple-markdown-editor',
DeprecatedMarkdownMathEditor = 'org.standardnotes.fancy-markdown-editor',
DeprecatedMarkdownMinimistEditor = 'org.standardnotes.minimal-markdown-editor',
DeprecatedFoldersComponent = 'org.standardnotes.folders',
DeprecatedFileSafe = 'org.standardnotes.file-safe',
}
/**
* Identifier for standalone filesafe instance offered as legacy installable via extensions-server
*/
export const LegacyFileSafeIdentifier = 'org.standardnotes.legacy.file-safe'
export const ExperimentalFeatures = []
@@ -1,7 +1,7 @@
import { AnyFeatureDescription } from './AnyFeatureDescription'
import { ThemeFeatureDescription } from './ThemeFeatureDescription'
import { EditorFeatureDescription } from './EditorFeatureDescription'
import { FeatureIdentifier } from './FeatureIdentifier'
import { NativeFeatureIdentifier } from './NativeFeatureIdentifier'
import { serverFeatures } from '../Lists/ServerFeatures'
import { clientFeatures } from '../Lists/ClientFeatures'
import { GetDeprecatedFeatures } from '../Lists/DeprecatedFeatures'
@@ -23,11 +23,11 @@ export function GetFeatures(): AnyFeatureDescription[] {
]
}
export function FindNativeFeature<T extends AnyFeatureDescription>(identifier: FeatureIdentifier): T | undefined {
export function FindNativeFeature<T extends AnyFeatureDescription>(identifier: string): T | undefined {
return GetFeatures().find((f) => f.identifier === identifier) as T
}
export function FindNativeTheme(identifier: FeatureIdentifier): ThemeFeatureDescription | undefined {
export function FindNativeTheme(identifier: string): ThemeFeatureDescription | undefined {
return themes().find((t) => t.identifier === identifier)
}
@@ -40,11 +40,11 @@ export function GetIframeEditors(): IframeComponentFeatureDescription[] {
}
export function GetSuperNoteFeature(): EditorFeatureDescription {
return FindNativeFeature(FeatureIdentifier.SuperEditor) as EditorFeatureDescription
return FindNativeFeature(NativeFeatureIdentifier.TYPES.SuperEditor) as EditorFeatureDescription
}
export function GetPlainNoteFeature(): EditorFeatureDescription {
return FindNativeFeature(FeatureIdentifier.PlainEditor) as EditorFeatureDescription
return FindNativeFeature(NativeFeatureIdentifier.TYPES.PlainEditor) as EditorFeatureDescription
}
export function GetNativeThemes(): ThemeFeatureDescription[] {
@@ -52,5 +52,5 @@ export function GetNativeThemes(): ThemeFeatureDescription[] {
}
export function GetDarkThemeFeature(): ThemeFeatureDescription {
return themes().find((t) => t.identifier === FeatureIdentifier.DarkTheme) as ThemeFeatureDescription
return themes().find((t) => t.identifier === NativeFeatureIdentifier.TYPES.DarkTheme) as ThemeFeatureDescription
}
@@ -0,0 +1,75 @@
import { Result, ValueObject } from '@standardnotes/domain-core'
export interface NativeFeatureIdentifierProps {
value: string
}
export class NativeFeatureIdentifier extends ValueObject<NativeFeatureIdentifierProps> {
static readonly TYPES = {
DailyEmailBackup: 'org.standardnotes.daily-email-backup',
Files: 'org.standardnotes.files',
FilesLowStorageTier: 'org.standardnotes.files-low-storage-tier',
FilesMaximumStorageTier: 'org.standardnotes.files-max-storage-tier',
ListedCustomDomain: 'org.standardnotes.listed-custom-domain',
NoteHistory30Days: 'org.standardnotes.note-history-30',
NoteHistory365Days: 'org.standardnotes.note-history-365',
NoteHistoryUnlimited: 'org.standardnotes.note-history-unlimited',
SignInAlerts: 'com.standardnotes.sign-in-alerts',
SmartFilters: 'org.standardnotes.smart-filters',
TagNesting: 'org.standardnotes.tag-nesting',
TwoFactorAuth: 'org.standardnotes.two-factor-auth',
UniversalSecondFactor: 'org.standardnotes.universal-second-factor',
SubscriptionSharing: 'org.standardnotes.subscription-sharing',
AutobiographyTheme: 'org.standardnotes.theme-autobiography',
DynamicTheme: 'org.standardnotes.theme-dynamic',
DarkTheme: 'org.standardnotes.theme-focus',
FuturaTheme: 'org.standardnotes.theme-futura',
MidnightTheme: 'org.standardnotes.theme-midnight',
SolarizedDarkTheme: 'org.standardnotes.theme-solarized-dark',
TitaniumTheme: 'org.standardnotes.theme-titanium',
PlainEditor: 'com.standardnotes.plain-text',
SuperEditor: 'com.standardnotes.super-editor',
CodeEditor: 'org.standardnotes.code-editor',
MarkdownProEditor: 'org.standardnotes.advanced-markdown-editor',
PlusEditor: 'org.standardnotes.plus-editor',
SheetsEditor: 'org.standardnotes.standard-sheets',
TaskEditor: 'org.standardnotes.simple-task-editor',
TokenVaultEditor: 'org.standardnotes.token-vault',
Clipper: 'org.standardnotes.clipper',
DeprecatedMarkdownVisualEditor: 'org.standardnotes.markdown-visual-editor',
DeprecatedBoldEditor: 'org.standardnotes.bold-editor',
DeprecatedMarkdownBasicEditor: 'org.standardnotes.simple-markdown-editor',
DeprecatedMarkdownMathEditor: 'org.standardnotes.fancy-markdown-editor',
DeprecatedMarkdownMinimistEditor: 'org.standardnotes.minimal-markdown-editor',
DeprecatedFoldersComponent: 'org.standardnotes.folders',
DeprecatedFileSafe: 'org.standardnotes.file-safe',
LegacyFileSafeIdentifier: 'org.standardnotes.legacy.file-safe',
}
get value(): string {
return this.props.value
}
private constructor(props: NativeFeatureIdentifierProps) {
super(props)
}
static create(type: string): Result<NativeFeatureIdentifier> {
const isValidType = Object.values(this.TYPES).includes(type)
if (!isValidType) {
return Result.fail<NativeFeatureIdentifier>(`Invalid feature identifier: ${type}`)
} else {
return Result.ok<NativeFeatureIdentifier>(new NativeFeatureIdentifier({ value: type }))
}
}
}
/**
* Identifier for standalone filesafe instance offered as legacy installable via extensions-server
*/
export const ExperimentalFeatures = []
@@ -1,11 +1,10 @@
import { PermissionName } from '../Permission/PermissionName'
import { FeatureIdentifier } from './FeatureIdentifier'
import { RoleFields } from './RoleFields'
export type ServerFeatureDescription = RoleFields & {
name: string
description?: string
identifier: FeatureIdentifier
identifier: string
permission_name: PermissionName
deprecated?: boolean
}
@@ -1,5 +1,5 @@
import { PermissionName } from '../Permission/PermissionName'
import { FeatureIdentifier } from '../Feature/FeatureIdentifier'
import { NativeFeatureIdentifier } from '../Feature/NativeFeatureIdentifier'
import { RoleName } from '@standardnotes/domain-core'
import { ClientFeatureDescription } from '../Feature/ClientFeatureDescription'
@@ -8,7 +8,7 @@ export function clientFeatures(): ClientFeatureDescription[] {
{
name: 'Tag Nesting',
availableInRoles: [RoleName.NAMES.PlusUser, RoleName.NAMES.ProUser],
identifier: FeatureIdentifier.TagNesting,
identifier: NativeFeatureIdentifier.TYPES.TagNesting,
permission_name: PermissionName.TagNesting,
description: 'Organize your tags into folders.',
},
@@ -16,22 +16,22 @@ export function clientFeatures(): ClientFeatureDescription[] {
{
name: 'Smart Filters',
availableInRoles: [RoleName.NAMES.PlusUser, RoleName.NAMES.ProUser],
identifier: FeatureIdentifier.SmartFilters,
identifier: NativeFeatureIdentifier.TYPES.SmartFilters,
permission_name: PermissionName.SmartFilters,
description: 'Create smart filters for viewing notes matching specific criteria.',
},
{
name: 'Encrypted files',
availableInRoles: [RoleName.NAMES.PlusUser, RoleName.NAMES.ProUser],
identifier: FeatureIdentifier.Files,
identifier: NativeFeatureIdentifier.TYPES.Files,
permission_name: PermissionName.Files,
description: '',
},
{
name: 'Extension',
name: 'Clipper',
availableInRoles: [RoleName.NAMES.PlusUser, RoleName.NAMES.ProUser],
identifier: FeatureIdentifier.Extension,
permission_name: PermissionName.Extension,
identifier: NativeFeatureIdentifier.TYPES.Clipper,
permission_name: PermissionName.Clipper,
description: '',
},
]
@@ -3,7 +3,7 @@ import { EditorFeatureDescription } from '../Feature/EditorFeatureDescription'
import { IframeComponentFeatureDescription } from '../Feature/IframeComponentFeatureDescription'
import { ContentType, RoleName } from '@standardnotes/domain-core'
import { PermissionName } from '../Permission/PermissionName'
import { FeatureIdentifier } from '../Feature/FeatureIdentifier'
import { NativeFeatureIdentifier } from '../Feature/NativeFeatureIdentifier'
import { NoteType } from '../Component/NoteType'
import { FillIframeEditorDefaults } from './Utilities/FillEditorComponentDefaults'
import { ComponentAction } from '../Component/ComponentAction'
@@ -12,7 +12,7 @@ import { ComponentArea } from '../Component/ComponentArea'
export function GetDeprecatedFeatures(): AnyFeatureDescription[] {
const bold: EditorFeatureDescription = FillIframeEditorDefaults({
name: 'Alternative Rich Text',
identifier: FeatureIdentifier.DeprecatedBoldEditor,
identifier: NativeFeatureIdentifier.TYPES.DeprecatedBoldEditor,
note_type: NoteType.RichText,
file_type: 'html',
component_permissions: [
@@ -39,7 +39,7 @@ export function GetDeprecatedFeatures(): AnyFeatureDescription[] {
const markdownBasic: EditorFeatureDescription = FillIframeEditorDefaults({
name: 'Basic Markdown',
identifier: FeatureIdentifier.DeprecatedMarkdownBasicEditor,
identifier: NativeFeatureIdentifier.TYPES.DeprecatedMarkdownBasicEditor,
note_type: NoteType.Markdown,
spellcheckControl: true,
file_type: 'md',
@@ -52,7 +52,7 @@ export function GetDeprecatedFeatures(): AnyFeatureDescription[] {
const markdownAlt: EditorFeatureDescription = FillIframeEditorDefaults({
name: 'Markdown Alternative',
identifier: FeatureIdentifier.DeprecatedMarkdownVisualEditor,
identifier: NativeFeatureIdentifier.TYPES.DeprecatedMarkdownVisualEditor,
note_type: NoteType.Markdown,
file_type: 'md',
deprecated: true,
@@ -66,7 +66,7 @@ export function GetDeprecatedFeatures(): AnyFeatureDescription[] {
const markdownMinimist: EditorFeatureDescription = FillIframeEditorDefaults({
name: 'Minimal Markdown',
identifier: FeatureIdentifier.DeprecatedMarkdownMinimistEditor,
identifier: NativeFeatureIdentifier.TYPES.DeprecatedMarkdownMinimistEditor,
note_type: NoteType.Markdown,
file_type: 'md',
index_path: 'index.html',
@@ -80,7 +80,7 @@ export function GetDeprecatedFeatures(): AnyFeatureDescription[] {
const markdownMath: EditorFeatureDescription = FillIframeEditorDefaults({
name: 'Markdown with Math',
identifier: FeatureIdentifier.DeprecatedMarkdownMathEditor,
identifier: NativeFeatureIdentifier.TYPES.DeprecatedMarkdownMathEditor,
spellcheckControl: true,
permission_name: PermissionName.MarkdownMathEditor,
note_type: NoteType.Markdown,
@@ -94,7 +94,7 @@ export function GetDeprecatedFeatures(): AnyFeatureDescription[] {
const filesafe: IframeComponentFeatureDescription = FillIframeEditorDefaults({
name: 'FileSafe',
identifier: FeatureIdentifier.DeprecatedFileSafe,
identifier: NativeFeatureIdentifier.TYPES.DeprecatedFileSafe,
component_permissions: [
{
name: ComponentAction.StreamContextItem,
@@ -1,5 +1,5 @@
import { PermissionName } from '../Permission/PermissionName'
import { FeatureIdentifier } from '../Feature/FeatureIdentifier'
import { NativeFeatureIdentifier } from '../Feature/NativeFeatureIdentifier'
import { NoteType } from '../Component/NoteType'
import { FillIframeEditorDefaults } from './Utilities/FillEditorComponentDefaults'
import { RoleName } from '@standardnotes/domain-core'
@@ -9,7 +9,7 @@ export function IframeEditors(): IframeComponentFeatureDescription[] {
const code = FillIframeEditorDefaults({
name: 'Code',
spellcheckControl: true,
identifier: FeatureIdentifier.CodeEditor,
identifier: NativeFeatureIdentifier.TYPES.CodeEditor,
permission_name: PermissionName.CodeEditor,
note_type: NoteType.Code,
file_type: 'txt',
@@ -26,7 +26,7 @@ export function IframeEditors(): IframeComponentFeatureDescription[] {
name: 'Rich Text',
note_type: NoteType.RichText,
file_type: 'html',
identifier: FeatureIdentifier.PlusEditor,
identifier: NativeFeatureIdentifier.TYPES.PlusEditor,
permission_name: PermissionName.PlusEditor,
spellcheckControl: true,
description:
@@ -37,7 +37,7 @@ export function IframeEditors(): IframeComponentFeatureDescription[] {
const markdown = FillIframeEditorDefaults({
name: 'Markdown',
identifier: FeatureIdentifier.MarkdownProEditor,
identifier: NativeFeatureIdentifier.TYPES.MarkdownProEditor,
note_type: NoteType.Markdown,
file_type: 'md',
permission_name: PermissionName.MarkdownProEditor,
@@ -50,7 +50,7 @@ export function IframeEditors(): IframeComponentFeatureDescription[] {
const task = FillIframeEditorDefaults({
name: 'Checklist',
identifier: FeatureIdentifier.TaskEditor,
identifier: NativeFeatureIdentifier.TYPES.TaskEditor,
note_type: NoteType.Task,
spellcheckControl: true,
file_type: 'md',
@@ -67,7 +67,7 @@ export function IframeEditors(): IframeComponentFeatureDescription[] {
note_type: NoteType.Authentication,
file_type: 'json',
interchangeable: false,
identifier: FeatureIdentifier.TokenVaultEditor,
identifier: NativeFeatureIdentifier.TYPES.TokenVaultEditor,
permission_name: PermissionName.TokenVaultEditor,
description:
'Encrypt and protect your 2FA secrets for all your internet accounts. Authenticator handles your 2FA secrets so that you never lose them again, or have to start over when you get a new device.',
@@ -77,7 +77,7 @@ export function IframeEditors(): IframeComponentFeatureDescription[] {
const spreadsheets = FillIframeEditorDefaults({
name: 'Spreadsheet',
identifier: FeatureIdentifier.SheetsEditor,
identifier: NativeFeatureIdentifier.TYPES.SheetsEditor,
note_type: NoteType.Spreadsheet,
file_type: 'json',
interchangeable: false,
@@ -1,7 +1,7 @@
import { RoleName } from '@standardnotes/domain-core'
import { NoteType } from '../Component/NoteType'
import { EditorFeatureDescription } from '../Feature/EditorFeatureDescription'
import { FeatureIdentifier } from '../Feature/FeatureIdentifier'
import { NativeFeatureIdentifier } from '../Feature/NativeFeatureIdentifier'
import { PermissionName } from '../Permission/PermissionName'
export function nativeEditors(): EditorFeatureDescription[] {
@@ -9,7 +9,7 @@ export function nativeEditors(): EditorFeatureDescription[] {
{
name: 'Super',
note_type: NoteType.Super,
identifier: FeatureIdentifier.SuperEditor,
identifier: NativeFeatureIdentifier.TYPES.SuperEditor,
spellcheckControl: true,
file_type: 'json',
interchangeable: false,
@@ -24,7 +24,7 @@ export function nativeEditors(): EditorFeatureDescription[] {
spellcheckControl: true,
file_type: 'txt',
interchangeable: true,
identifier: FeatureIdentifier.PlainEditor,
identifier: NativeFeatureIdentifier.TYPES.PlainEditor,
availableInRoles: [RoleName.NAMES.CoreUser, RoleName.NAMES.PlusUser, RoleName.NAMES.ProUser],
permission_name: PermissionName.PlainEditor,
},
@@ -1,67 +1,67 @@
import { ServerFeatureDescription } from '../Feature/ServerFeatureDescription'
import { PermissionName } from '../Permission/PermissionName'
import { FeatureIdentifier } from '../Feature/FeatureIdentifier'
import { NativeFeatureIdentifier } from '../Feature/NativeFeatureIdentifier'
import { RoleName } from '@standardnotes/domain-core'
export function serverFeatures(): ServerFeatureDescription[] {
return [
{
name: 'Two factor authentication',
identifier: FeatureIdentifier.TwoFactorAuth,
identifier: NativeFeatureIdentifier.TYPES.TwoFactorAuth,
permission_name: PermissionName.TwoFactorAuth,
availableInRoles: [RoleName.NAMES.PlusUser, RoleName.NAMES.ProUser],
},
{
name: 'U2F authentication',
identifier: FeatureIdentifier.UniversalSecondFactor,
identifier: NativeFeatureIdentifier.TYPES.UniversalSecondFactor,
permission_name: PermissionName.UniversalSecondFactor,
availableInRoles: [RoleName.NAMES.ProUser],
},
{
name: 'Unlimited note history',
identifier: FeatureIdentifier.NoteHistoryUnlimited,
identifier: NativeFeatureIdentifier.TYPES.NoteHistoryUnlimited,
permission_name: PermissionName.NoteHistoryUnlimited,
availableInRoles: [RoleName.NAMES.ProUser],
},
{
name: '365 days note history',
identifier: FeatureIdentifier.NoteHistory365Days,
identifier: NativeFeatureIdentifier.TYPES.NoteHistory365Days,
permission_name: PermissionName.NoteHistory365Days,
availableInRoles: [RoleName.NAMES.PlusUser],
},
{
name: 'Email backups',
identifier: FeatureIdentifier.DailyEmailBackup,
identifier: NativeFeatureIdentifier.TYPES.DailyEmailBackup,
permission_name: PermissionName.DailyEmailBackup,
availableInRoles: [RoleName.NAMES.PlusUser, RoleName.NAMES.ProUser],
},
{
name: 'Sign-in email alerts',
identifier: FeatureIdentifier.SignInAlerts,
identifier: NativeFeatureIdentifier.TYPES.SignInAlerts,
permission_name: PermissionName.SignInAlerts,
availableInRoles: [RoleName.NAMES.PlusUser, RoleName.NAMES.ProUser],
},
{
name: 'Files maximum storage tier',
identifier: FeatureIdentifier.FilesMaximumStorageTier,
identifier: NativeFeatureIdentifier.TYPES.FilesMaximumStorageTier,
permission_name: PermissionName.FilesMaximumStorageTier,
availableInRoles: [RoleName.NAMES.ProUser],
},
{
name: 'Files low storage tier',
identifier: FeatureIdentifier.FilesLowStorageTier,
identifier: NativeFeatureIdentifier.TYPES.FilesLowStorageTier,
permission_name: PermissionName.FilesLowStorageTier,
availableInRoles: [RoleName.NAMES.PlusUser],
},
{
name: 'Files medium storage tier',
identifier: FeatureIdentifier.SubscriptionSharing,
identifier: NativeFeatureIdentifier.TYPES.SubscriptionSharing,
permission_name: PermissionName.SubscriptionSharing,
availableInRoles: [RoleName.NAMES.ProUser],
},
{
name: 'Listed Custom Domain',
identifier: FeatureIdentifier.ListedCustomDomain,
identifier: NativeFeatureIdentifier.TYPES.ListedCustomDomain,
permission_name: PermissionName.ListedCustomDomain,
availableInRoles: [RoleName.NAMES.PlusUser, RoleName.NAMES.ProUser],
},
+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.66](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-07-27)
**Note:** Version bump only for package @standardnotes/filepicker
## [1.28.65](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-07-27)
**Note:** Version bump only for package @standardnotes/filepicker
## [1.28.64](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-07-26)
**Note:** Version bump only for package @standardnotes/filepicker
## [1.28.63](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-07-26)
**Note:** Version bump only for package @standardnotes/filepicker
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@standardnotes/filepicker",
"version": "1.28.63",
"version": "1.28.66",
"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.12](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-07-27)
**Note:** Version bump only for package @standardnotes/files
## [1.16.11](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-07-27)
**Note:** Version bump only for package @standardnotes/files
## [1.16.10](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-07-26)
**Note:** Version bump only for package @standardnotes/files
## [1.16.9](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-07-26)
**Note:** Version bump only for package @standardnotes/files
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@standardnotes/files",
"version": "1.16.9",
"version": "1.16.12",
"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.
## [3.56.29](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-07-27)
**Note:** Version bump only for package @standardnotes/mobile
## [3.56.28](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-07-27)
**Note:** Version bump only for package @standardnotes/mobile
## [3.56.27](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-07-26)
**Note:** Version bump only for package @standardnotes/mobile
## [3.56.26](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-07-26)
**Note:** Version bump only for package @standardnotes/mobile
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@standardnotes/mobile",
"version": "3.56.26",
"version": "3.56.29",
"author": "Standard Notes.",
"private": true,
"license": "AGPL-3.0-or-later",
+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.16](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-07-27)
**Note:** Version bump only for package @standardnotes/models
## [1.46.15](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-07-27)
**Note:** Version bump only for package @standardnotes/models
## [1.46.14](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-07-26)
### Bug Fixes
* Fixes issue where lock screen would not use previously active theme ([#2372](https://github.com/standardnotes/app/issues/2372)) ([d268c02](https://github.com/standardnotes/app/commit/d268c02ab31beb5e2fd9e6547610f9a4dd61bed4))
## [1.46.13](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-07-26)
**Note:** Version bump only for package @standardnotes/models
+2 -2
View File
@@ -1,6 +1,6 @@
{
"name": "@standardnotes/models",
"version": "1.46.13",
"version": "1.46.16",
"engines": {
"node": ">=16.0.0 <17.0.0"
},
@@ -23,7 +23,7 @@
},
"dependencies": {
"@standardnotes/common": "^1.50.0",
"@standardnotes/domain-core": "^1.22.0",
"@standardnotes/domain-core": "^1.24.0",
"@standardnotes/features": "workspace:*",
"@standardnotes/responses": "workspace:*",
"@standardnotes/sncrypto-common": "workspace:^",
@@ -1,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>>
+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.4.401](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-07-27)
**Note:** Version bump only for package @standardnotes/releases
## [1.4.400](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-07-27)
**Note:** Version bump only for package @standardnotes/releases
## [1.4.399](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-07-26)
**Note:** Version bump only for package @standardnotes/releases
## [1.4.398](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-07-26)
**Note:** Version bump only for package @standardnotes/releases
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@standardnotes/releases",
"version": "1.4.398",
"version": "1.4.401",
"license": "AGPL-3.0-or-later",
"main": "dist/releases.json",
"types": "dist/index.d.ts",
+8
View File
@@ -3,6 +3,14 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.13.33](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-07-27)
**Note:** Version bump only for package @standardnotes/responses
## [1.13.32](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-07-26)
**Note:** Version bump only for package @standardnotes/responses
## [1.13.31](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-07-23)
**Note:** Version bump only for package @standardnotes/responses
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@standardnotes/responses",
"version": "1.13.31",
"version": "1.13.33",
"engines": {
"node": ">=16.0.0 <17.0.0"
},
@@ -1,6 +1,6 @@
export interface AsymmetricMessageServerHash {
uuid: string
user_uuid: string
recipient_uuid: string
sender_uuid: string
replaceabilityIdentifier?: string
encrypted_message: string
@@ -16,7 +16,7 @@ export type RawSyncData = {
unsaved?: ConflictParams[]
shared_vaults?: SharedVaultServerHash[]
shared_vault_invites?: SharedVaultInviteServerHash[]
user_events?: UserEventServerHash[]
asymmetric_messages?: AsymmetricMessageServerHash[]
notifications?: UserEventServerHash[]
messages?: AsymmetricMessageServerHash[]
status?: number
}
@@ -1,5 +1,4 @@
import { AsymmetricMessageServerHash } from '../AsymmetricMessage/AsymmetricMessageServerHash'
import { SharedVaultPermission } from './SharedVaultPermission'
export interface SharedVaultInviteServerHash extends AsymmetricMessageServerHash {
uuid: string
@@ -7,7 +6,7 @@ export interface SharedVaultInviteServerHash extends AsymmetricMessageServerHash
user_uuid: string
sender_uuid: string
encrypted_message: string
permissions: SharedVaultPermission
permission: string
created_at_timestamp: number
updated_at_timestamp: number
}
@@ -1,5 +0,0 @@
export enum SharedVaultPermission {
Read = 'read',
Write = 'write',
Admin = 'admin',
}
@@ -1,9 +1,7 @@
import { SharedVaultPermission } from './SharedVaultPermission'
export interface SharedVaultUserServerHash {
uuid: string
shared_vault_uuid: string
user_uuid: string
permissions: SharedVaultPermission
permission: string
updated_at_timestamp: number
}
@@ -1,14 +0,0 @@
import { UserEventType } from './UserEventType'
export type UserEventPayload =
| {
eventType: UserEventType.SharedVaultItemRemoved
itemUuid: string
sharedVaultUuid: string
version: string
}
| {
eventType: UserEventType.RemovedFromSharedVault
sharedVaultUuid: string
version: string
}
@@ -1,10 +1,8 @@
import { UserEventType } from './UserEventType'
export type UserEventServerHash = {
uuid: string
user_uuid: string
event_type: UserEventType
event_payload: string
type: string
payload: string
created_at_timestamp?: number
updated_at_timestamp?: number
}
@@ -1,4 +0,0 @@
export enum UserEventType {
SharedVaultItemRemoved = 'shared_vault_item_removed',
RemovedFromSharedVault = 'removed_from_shared_vault',
}
-3
View File
@@ -36,7 +36,6 @@ export * from './Http'
export * from './SharedVaults/SharedVaultInviteServerHash'
export * from './SharedVaults/SharedVaultUserServerHash'
export * from './SharedVaults/SharedVaultServerHash'
export * from './SharedVaults/SharedVaultPermission'
export * from './AsymmetricMessage/AsymmetricMessageServerHash'
@@ -68,5 +67,3 @@ export * from './User/SettingData'
export * from './User/UpdateSettingResponse'
export * from './UserEvent/UserEventServerHash'
export * from './UserEvent/UserEventType'
export * from './UserEvent/UserEventPayload'
+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.63.14](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-07-27)
**Note:** Version bump only for package @standardnotes/services
## [1.63.13](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-07-27)
**Note:** Version bump only for package @standardnotes/services
## [1.63.12](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-07-26)
### Bug Fixes
* Fixes issue where lock screen would not use previously active theme ([#2372](https://github.com/standardnotes/app/issues/2372)) ([d268c02](https://github.com/standardnotes/app/commit/d268c02ab31beb5e2fd9e6547610f9a4dd61bed4))
## [1.63.11](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-07-26)
**Note:** Version bump only for package @standardnotes/services
+2 -2
View File
@@ -1,6 +1,6 @@
{
"name": "@standardnotes/services",
"version": "1.63.11",
"version": "1.63.14",
"engines": {
"node": ">=16.0.0 <17.0.0"
},
@@ -18,7 +18,7 @@
"dependencies": {
"@standardnotes/api": "workspace:^",
"@standardnotes/common": "^1.50.0",
"@standardnotes/domain-core": "^1.22.0",
"@standardnotes/domain-core": "^1.24.0",
"@standardnotes/encryption": "workspace:^",
"@standardnotes/features": "workspace:^",
"@standardnotes/files": "workspace:^",
@@ -80,7 +80,7 @@ describe('AsymmetricMessageService', () => {
const messages: AsymmetricMessageServerHash[] = [
{
uuid: 'keypair-changed-message',
user_uuid: '1',
recipient_uuid: '1',
sender_uuid: '2',
encrypted_message: 'encrypted_message',
created_at_timestamp: 2,
@@ -88,7 +88,7 @@ describe('AsymmetricMessageService', () => {
},
{
uuid: 'misc-message',
user_uuid: '1',
recipient_uuid: '1',
sender_uuid: '2',
encrypted_message: 'encrypted_message',
created_at_timestamp: 1,
@@ -119,7 +119,7 @@ describe('AsymmetricMessageService', () => {
const messages: AsymmetricMessageServerHash[] = [
{
uuid: 'newer-message',
user_uuid: '1',
recipient_uuid: '1',
sender_uuid: '2',
encrypted_message: 'encrypted_message',
created_at_timestamp: 2,
@@ -127,7 +127,7 @@ describe('AsymmetricMessageService', () => {
},
{
uuid: 'older-message',
user_uuid: '1',
recipient_uuid: '1',
sender_uuid: '2',
encrypted_message: 'encrypted_message',
created_at_timestamp: 1,
@@ -153,7 +153,7 @@ describe('AsymmetricMessageService', () => {
it('should handle ContactShare message', async () => {
const message: AsymmetricMessageServerHash = {
uuid: 'message',
user_uuid: '1',
recipient_uuid: '1',
sender_uuid: '2',
encrypted_message: 'encrypted_message',
created_at_timestamp: 2,
@@ -181,7 +181,7 @@ describe('AsymmetricMessageService', () => {
it('should handle SenderKeypairChanged message', async () => {
const message: AsymmetricMessageServerHash = {
uuid: 'message',
user_uuid: '1',
recipient_uuid: '1',
sender_uuid: '2',
encrypted_message: 'encrypted_message',
created_at_timestamp: 2,
@@ -210,7 +210,7 @@ describe('AsymmetricMessageService', () => {
it('should handle SharedVaultRootKeyChanged message', async () => {
const message: AsymmetricMessageServerHash = {
uuid: 'message',
user_uuid: '1',
recipient_uuid: '1',
sender_uuid: '2',
encrypted_message: 'encrypted_message',
created_at_timestamp: 2,
@@ -238,7 +238,7 @@ describe('AsymmetricMessageService', () => {
it('should handle SharedVaultMetadataChanged message', async () => {
const message: AsymmetricMessageServerHash = {
uuid: 'message',
user_uuid: '1',
recipient_uuid: '1',
sender_uuid: '2',
encrypted_message: 'encrypted_message',
created_at_timestamp: 2,
@@ -268,7 +268,7 @@ describe('AsymmetricMessageService', () => {
it('should throw if message type is SharedVaultInvite', async () => {
const message: AsymmetricMessageServerHash = {
uuid: 'message',
user_uuid: '1',
recipient_uuid: '1',
sender_uuid: '2',
encrypted_message: 'encrypted_message',
created_at_timestamp: 2,
@@ -294,7 +294,7 @@ describe('AsymmetricMessageService', () => {
it('should delete message from server after processing', async () => {
const message: AsymmetricMessageServerHash = {
uuid: 'message',
user_uuid: '1',
recipient_uuid: '1',
sender_uuid: '2',
encrypted_message: 'encrypted_message',
created_at_timestamp: 2,
@@ -31,9 +31,9 @@ export class ResendAllMessages implements UseCaseInterface<void> {
const errors: string[] = []
for (const message of messages.data.messages) {
const recipient = this.findContact.execute({ userUuid: message.user_uuid })
const recipient = this.findContact.execute({ userUuid: message.recipient_uuid })
if (recipient.isFailed()) {
errors.push(`Contact not found for invite ${message.user_uuid}`)
errors.push(`Contact not found for invite ${message.recipient_uuid}`)
continue
}
@@ -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>
@@ -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()
}
@@ -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>
}
@@ -76,9 +76,7 @@ export class KeySystemKeyManager
}
}
public getRootKeyFromStorageForVault(
keySystemIdentifier: KeySystemIdentifier,
): KeySystemRootKeyInterface | undefined {
getRootKeyFromStorageForVault(keySystemIdentifier: KeySystemIdentifier): KeySystemRootKeyInterface | undefined {
const payload = this.storage.getValue<DecryptedTransferPayload<KeySystemRootKeyContent>>(
this.storageKeyForRootKey(keySystemIdentifier),
)
@@ -94,6 +92,10 @@ export class KeySystemKeyManager
return key
}
getMemCachedRootKey(systemIdentifier: KeySystemIdentifier): KeySystemRootKeyInterface {
return this.rootKeyMemoryCache[systemIdentifier]
}
private storageKeyForRootKey(systemIdentifier: KeySystemIdentifier): string {
return `${RootKeyStorageKeyPrefix}${systemIdentifier}`
}
@@ -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,6 +1,6 @@
import { DiscardItemsLocally } from './../UseCase/DiscardItemsLocally'
import { UserKeyPairChangedEventData } from './../Session/UserKeyPairChangedEventData'
import { ClientDisplayableError, UserEventType } from '@standardnotes/responses'
import { ClientDisplayableError } from '@standardnotes/responses'
import {
DecryptedItemInterface,
PayloadEmitSource,
@@ -29,7 +29,7 @@ import { CreateSharedVault } from './UseCase/CreateSharedVault'
import { SendVaultDataChangedMessage } from './UseCase/SendVaultDataChangedMessage'
import { ConvertToSharedVault } from './UseCase/ConvertToSharedVault'
import { GetVault } from '../Vault/UseCase/GetVault'
import { ContentType } from '@standardnotes/domain-core'
import { ContentType, NotificationType, Uuid } from '@standardnotes/domain-core'
import { HandleKeyPairChange } from '../Contacts/UseCase/HandleKeyPairChange'
import { FindContact } from '../Contacts/UseCase/FindContact'
import { EncryptionProviderInterface } from '../Encryption/EncryptionProviderInterface'
@@ -121,18 +121,18 @@ export class SharedVaultService
}
private async handleUserEvent(event: UserEventServiceEventPayload): Promise<void> {
switch (event.eventPayload.eventType) {
case UserEventType.RemovedFromSharedVault: {
switch (event.eventPayload.props.type.value) {
case NotificationType.TYPES.RemovedFromSharedVault: {
const vault = this._getVault.execute<SharedVaultListingInterface>({
sharedVaultUuid: event.eventPayload.sharedVaultUuid,
sharedVaultUuid: event.eventPayload.props.sharedVaultUuid.value,
})
if (!vault.isFailed()) {
await this._deleteThirdPartyVault.execute(vault.getValue())
}
break
}
case UserEventType.SharedVaultItemRemoved: {
const item = this.items.findItem(event.eventPayload.itemUuid)
case NotificationType.TYPES.SharedVaultItemRemoved: {
const item = this.items.findItem((event.eventPayload.props.itemUuid as Uuid).value)
if (item) {
void this._discardItemsLocally.execute([item])
}
@@ -70,7 +70,7 @@ export class NotifyVaultUsersOfKeyRotation implements UseCaseInterface<void> {
sharedVault: params.sharedVault,
sharedVaultContacts: !contacts.isFailed() ? contacts.getValue() : [],
recipient: recipient.getValue(),
permissions: invite.permissions,
permission: invite.permission,
senderUuid: params.senderUuid,
})
}
@@ -1,3 +1,6 @@
import { ApplicationStage } from './../Application/ApplicationStage'
import { SessionEvent } from './../Session/SessionEvent'
import { ApplicationEvent } from './../Event/ApplicationEvent'
import { StorageServiceInterface } from './../Storage/StorageServiceInterface'
import { SessionsClientInterface } from './../Session/SessionsClientInterface'
import { SubscriptionApiServiceInterface } from '@standardnotes/api'
@@ -21,11 +24,66 @@ describe('SubscriptionManager', () => {
subscriptionApiService.listInvites = jest.fn()
sessions = {} as jest.Mocked<SessionsClientInterface>
sessions.isSignedIn = jest.fn().mockReturnValue(true)
storage = {} as jest.Mocked<StorageServiceInterface>
internalEventBus = {} as jest.Mocked<InternalEventBusInterface>
internalEventBus.addEventHandler = jest.fn()
internalEventBus.publish = jest.fn()
})
describe('event handling', () => {
it('should fetch subscriptions when the application has launched', async () => {
const manager = createManager()
jest.spyOn(manager, 'fetchOnlineSubscription')
jest.spyOn(manager, 'fetchAvailableSubscriptions')
await manager.handleEvent({ type: ApplicationEvent.Launched, payload: {} })
expect(manager.fetchOnlineSubscription).toHaveBeenCalledTimes(1)
expect(manager.fetchAvailableSubscriptions).toHaveBeenCalledTimes(1)
})
it('should fetch online subscription when user roles have changed', async () => {
const manager = createManager()
jest.spyOn(manager, 'fetchOnlineSubscription')
await manager.handleEvent({ type: ApplicationEvent.UserRolesChanged, payload: {} })
expect(manager.fetchOnlineSubscription).toHaveBeenCalledTimes(1)
})
it('should fetch online subscription when session is restored', async () => {
const manager = createManager()
jest.spyOn(manager, 'fetchOnlineSubscription')
await manager.handleEvent({ type: SessionEvent.Restored, payload: {} })
expect(manager.fetchOnlineSubscription).toHaveBeenCalledTimes(1)
})
it('should fetch online subscription when user has signed in', async () => {
const manager = createManager()
jest.spyOn(manager, 'fetchOnlineSubscription')
await manager.handleEvent({ type: ApplicationEvent.SignedIn, payload: {} })
expect(manager.fetchOnlineSubscription).toHaveBeenCalledTimes(1)
})
it('should handle stage change and notify event', async () => {
const manager = createManager()
jest.spyOn(manager, 'loadSubscriptionFromStorage')
storage.getValue = jest.fn().mockReturnValue({})
await manager.handleEvent({
type: ApplicationEvent.ApplicationStageChanged,
payload: { stage: ApplicationStage.StorageDecrypted_09 },
})
expect(manager.loadSubscriptionFromStorage).toHaveBeenCalled()
})
})
it('should invite user by email to a shared subscription', async () => {
@@ -1,3 +1,4 @@
import { SessionEvent } from './../Session/SessionEvent'
import { StorageKey } from './../Storage/StorageKeys'
import { ApplicationStage } from './../Application/ApplicationStage'
import { StorageServiceInterface } from './../Storage/StorageServiceInterface'
@@ -51,6 +52,7 @@ export class SubscriptionManager
}
case ApplicationEvent.UserRolesChanged:
case SessionEvent.Restored:
case ApplicationEvent.SignedIn:
void this.fetchOnlineSubscription()
break
@@ -58,13 +60,17 @@ export class SubscriptionManager
case ApplicationEvent.ApplicationStageChanged: {
const stage = (event.payload as ApplicationStageChangedEventPayload).stage
if (stage === ApplicationStage.StorageDecrypted_09) {
this.onlineSubscription = this.storage.getValue(StorageKey.Subscription)
void this.notifyEvent(SubscriptionManagerEvent.DidFetchSubscription)
this.loadSubscriptionFromStorage()
}
}
}
}
loadSubscriptionFromStorage(): void {
this.onlineSubscription = this.storage.getValue(StorageKey.Subscription)
void this.notifyEvent(SubscriptionManagerEvent.DidFetchSubscription)
}
hasOnlineSubscription(): boolean {
return this.onlineSubscription != undefined
}
@@ -204,7 +210,7 @@ export class SubscriptionManager
void this.notifyEvent(SubscriptionManagerEvent.DidFetchSubscription)
}
private async fetchAvailableSubscriptions(): Promise<void> {
async fetchAvailableSubscriptions(): Promise<void> {
try {
const response = await this.subscriptionApiService.getAvailableSubscriptions()
@@ -1,3 +1,4 @@
import { ReencryptTypeAItems } from './../Encryption/UseCase/TypeA/ReencryptTypeAItems'
import { EncryptionProviderInterface } from './../Encryption/EncryptionProviderInterface'
import { UserApiServiceInterface } from '@standardnotes/api'
import { UserRequestType } from '@standardnotes/common'
@@ -25,6 +26,7 @@ describe('UserService', () => {
let challengeService: ChallengeServiceInterface
let protectionService: ProtectionsClientInterface
let userApiService: UserApiServiceInterface
let reencryptTypeAItems: ReencryptTypeAItems
let internalEventBus: InternalEventBusInterface
const createService = () =>
@@ -38,6 +40,7 @@ describe('UserService', () => {
challengeService,
protectionService,
userApiService,
reencryptTypeAItems,
internalEventBus,
)
@@ -37,6 +37,7 @@ import { AccountEvent } from './AccountEvent'
import { SignedInOrRegisteredEventPayload } from './SignedInOrRegisteredEventPayload'
import { CredentialsChangeFunctionResponse } from './CredentialsChangeFunctionResponse'
import { EncryptionProviderInterface } from '../Encryption/EncryptionProviderInterface'
import { ReencryptTypeAItems } from '../Encryption/UseCase/TypeA/ReencryptTypeAItems'
export class UserService
extends AbstractService<AccountEvent, AccountEventData>
@@ -49,33 +50,48 @@ export class UserService
private readonly MINIMUM_PASSWORD_LENGTH = 8
constructor(
private sessionManager: SessionsClientInterface,
private sessions: SessionsClientInterface,
private sync: SyncServiceInterface,
private storageService: StorageServiceInterface,
private itemManager: ItemManagerInterface,
private encryptionService: EncryptionProviderInterface,
private alertService: AlertService,
private challengeService: ChallengeServiceInterface,
private protectionService: ProtectionsClientInterface,
private userApiService: UserApiServiceInterface,
private storage: StorageServiceInterface,
private items: ItemManagerInterface,
private encryption: EncryptionProviderInterface,
private alerts: AlertService,
private challenges: ChallengeServiceInterface,
private protections: ProtectionsClientInterface,
private userApi: UserApiServiceInterface,
private _reencryptTypeAItems: ReencryptTypeAItems,
protected override internalEventBus: InternalEventBusInterface,
) {
super(internalEventBus)
}
public override deinit(): void {
super.deinit()
;(this.sessions as unknown) = undefined
;(this.sync as unknown) = undefined
;(this.storage as unknown) = undefined
;(this.items as unknown) = undefined
;(this.encryption as unknown) = undefined
;(this.alerts as unknown) = undefined
;(this.challenges as unknown) = undefined
;(this.protections as unknown) = undefined
;(this.userApi as unknown) = undefined
;(this._reencryptTypeAItems as unknown) = undefined
}
async handleEvent(event: InternalEventInterface): Promise<void> {
if (event.type === AccountEvent.SignedInOrRegistered) {
const payload = (event.payload as AccountEventData).payload as SignedInOrRegisteredEventPayload
this.sync.resetSyncState()
await this.storageService.setPersistencePolicy(
await this.storage.setPersistencePolicy(
payload.ephemeral ? StoragePersistencePolicies.Ephemeral : StoragePersistencePolicies.Default,
)
if (payload.mergeLocal) {
await this.sync.markAllItemsAsNeedingSyncAndPersist()
} else {
void this.itemManager.removeAllItemsFromMemory()
void this.items.removeAllItemsFromMemory()
await this.clearDatabase()
}
@@ -88,37 +104,24 @@ export class UserService
})
.then(() => {
if (!payload.awaitSync) {
void this.encryptionService.decryptErroredPayloads()
void this.encryption.decryptErroredPayloads()
}
})
if (payload.awaitSync) {
await syncPromise
await this.encryptionService.decryptErroredPayloads()
await this.encryption.decryptErroredPayloads()
}
}
}
public override deinit(): void {
super.deinit()
;(this.sessionManager as unknown) = undefined
;(this.sync as unknown) = undefined
;(this.storageService as unknown) = undefined
;(this.itemManager as unknown) = undefined
;(this.encryptionService as unknown) = undefined
;(this.alertService as unknown) = undefined
;(this.challengeService as unknown) = undefined
;(this.protectionService as unknown) = undefined
;(this.userApiService as unknown) = undefined
}
getUserUuid(): string {
return this.sessionManager.userUuid
return this.sessions.userUuid
}
isSignedIn(): boolean {
return this.sessionManager.isSignedIn()
return this.sessions.isSignedIn()
}
/**
@@ -131,7 +134,7 @@ export class UserService
ephemeral = false,
mergeLocal = true,
): Promise<UserRegistrationResponseBody> {
if (this.encryptionService.hasAccount()) {
if (this.encryption.hasAccount()) {
throw Error('Tried to register when an account already exists.')
}
@@ -143,7 +146,7 @@ export class UserService
try {
this.lockSyncing()
const response = await this.sessionManager.register(email, password, ephemeral)
const response = await this.sessions.register(email, password, ephemeral)
await this.notifyEventSync(AccountEvent.SignedInOrRegistered, {
payload: {
@@ -177,7 +180,7 @@ export class UserService
mergeLocal = true,
awaitSync = false,
): Promise<HttpResponse<SignInResponse>> {
if (this.encryptionService.hasAccount()) {
if (this.encryption.hasAccount()) {
throw Error('Tried to sign in when an account already exists.')
}
@@ -191,7 +194,7 @@ export class UserService
/** Prevent a timed sync from occuring while signing in. */
this.lockSyncing()
const { response } = await this.sessionManager.signIn(email, password, strict, ephemeral)
const { response } = await this.sessions.signIn(email, password, strict, ephemeral)
if (!isErrorResponse(response)) {
const notifyingFunction = awaitSync ? this.notifyEventSync.bind(this) : this.notifyEvent.bind(this)
@@ -218,7 +221,7 @@ export class UserService
message?: string
}> {
if (
!(await this.protectionService.authorizeAction(ChallengeReason.DeleteAccount, {
!(await this.protections.authorizeAction(ChallengeReason.DeleteAccount, {
fallBackToAccountPassword: true,
requireAccountPassword: true,
forcePrompt: false,
@@ -230,8 +233,8 @@ export class UserService
}
}
const uuid = this.sessionManager.getSureUser().uuid
const response = await this.userApiService.deleteAccount(uuid)
const uuid = this.sessions.getSureUser().uuid
const response = await this.userApi.deleteAccount(uuid)
if (isErrorResponse(response)) {
return {
error: true,
@@ -241,7 +244,7 @@ export class UserService
await this.signOut(true)
void this.alertService.alert(InfoStrings.AccountDeleted)
void this.alerts.alert(InfoStrings.AccountDeleted)
return {
error: false,
@@ -249,9 +252,9 @@ export class UserService
}
async submitUserRequest(requestType: UserRequestType): Promise<boolean> {
const userUuid = this.sessionManager.getSureUser().uuid
const userUuid = this.sessions.getSureUser().uuid
try {
const result = await this.userApiService.submitUserRequest({
const result = await this.userApi.submitUserRequest({
userUuid,
requestType,
})
@@ -274,11 +277,7 @@ export class UserService
public async correctiveSignIn(rootKey: SNRootKey): Promise<HttpResponse<SignInResponse>> {
this.lockSyncing()
const response = await this.sessionManager.bypassChecksAndSignInWithRootKey(
rootKey.keyParams.identifier,
rootKey,
false,
)
const response = await this.sessions.bypassChecksAndSignInWithRootKey(rootKey.keyParams.identifier, rootKey, false)
if (!isErrorResponse(response)) {
await this.notifyEvent(AccountEvent.SignedInOrRegistered, {
@@ -313,16 +312,16 @@ export class UserService
}): Promise<CredentialsChangeFunctionResponse> {
const result = await this.performCredentialsChange(parameters)
if (result.error) {
void this.alertService.alert(result.error.message)
void this.alerts.alert(result.error.message)
}
return result
}
public async signOut(force = false, source = DeinitSource.SignOut): Promise<void> {
const performSignOut = async () => {
await this.sessionManager.signOut()
await this.encryptionService.deleteWorkspaceSpecificKeyStateFromDevice()
await this.storageService.clearAllData()
await this.sessions.signOut()
await this.encryption.deleteWorkspaceSpecificKeyStateFromDevice()
await this.storage.clearAllData()
await this.notifyEvent(AccountEvent.SignedOut, { payload: { source } })
}
@@ -332,10 +331,10 @@ export class UserService
return
}
const dirtyItems = this.itemManager.getDirtyItems()
const dirtyItems = this.items.getDirtyItems()
if (dirtyItems.length > 0) {
const singular = dirtyItems.length === 1
const didConfirm = await this.alertService.confirm(
const didConfirm = await this.alerts.confirm(
`There ${singular ? 'is' : 'are'} ${dirtyItems.length} ${
singular ? 'item' : 'items'
} with unsynced changes. If you sign out, these changes will be lost forever. Are you sure you want to sign out?`,
@@ -353,7 +352,7 @@ export class UserService
canceled?: true
error?: { message: string }
}> {
if (!this.sessionManager.isUserMissingKeyPair()) {
if (!this.sessions.isUserMissingKeyPair()) {
throw Error('Cannot update account with first time keypair if user already has a keypair')
}
@@ -367,8 +366,8 @@ export class UserService
canceled?: true
error?: { message: string }
}> {
const hasPasscode = this.encryptionService.hasPasscode()
const hasAccount = this.encryptionService.hasAccount()
const hasPasscode = this.encryption.hasPasscode()
const hasAccount = this.encryption.hasAccount()
const prompts = []
if (hasPasscode) {
prompts.push(
@@ -389,11 +388,11 @@ export class UserService
)
}
const challenge = new Challenge(prompts, ChallengeReason.ProtocolUpgrade, true)
const response = await this.challengeService.promptForChallengeResponse(challenge)
const response = await this.challenges.promptForChallengeResponse(challenge)
if (!response) {
return { canceled: true }
}
const dismissBlockingDialog = await this.alertService.blockingDialog(
const dismissBlockingDialog = await this.alerts.blockingDialog(
Messages.DO_NOT_CLOSE_APPLICATION,
Messages.UPGRADING_ENCRYPTION,
)
@@ -436,11 +435,11 @@ export class UserService
if (passcode.length < this.MINIMUM_PASSCODE_LENGTH) {
return false
}
if (!(await this.protectionService.authorizeAddingPasscode())) {
if (!(await this.protections.authorizeAddingPasscode())) {
return false
}
const dismissBlockingDialog = await this.alertService.blockingDialog(
const dismissBlockingDialog = await this.alerts.blockingDialog(
Messages.DO_NOT_CLOSE_APPLICATION,
Messages.SETTING_PASSCODE,
)
@@ -453,11 +452,11 @@ export class UserService
}
public async removePasscode(): Promise<boolean> {
if (!(await this.protectionService.authorizeRemovingPasscode())) {
if (!(await this.protections.authorizeRemovingPasscode())) {
return false
}
const dismissBlockingDialog = await this.alertService.blockingDialog(
const dismissBlockingDialog = await this.alerts.blockingDialog(
Messages.DO_NOT_CLOSE_APPLICATION,
Messages.REMOVING_PASSCODE,
)
@@ -479,11 +478,11 @@ export class UserService
if (newPasscode.length < this.MINIMUM_PASSCODE_LENGTH) {
return false
}
if (!(await this.protectionService.authorizeChangingPasscode())) {
if (!(await this.protections.authorizeChangingPasscode())) {
return false
}
const dismissBlockingDialog = await this.alertService.blockingDialog(
const dismissBlockingDialog = await this.alerts.blockingDialog(
Messages.DO_NOT_CLOSE_APPLICATION,
origination === KeyParamsOrigination.ProtocolUpgrade
? Messages.ProtocolUpgradeStrings.UpgradingPasscode
@@ -499,7 +498,7 @@ export class UserService
}
public async populateSessionFromDemoShareToken(token: Base64String): Promise<void> {
await this.sessionManager.populateSessionFromDemoShareToken(token)
await this.sessions.populateSessionFromDemoShareToken(token)
await this.notifyEvent(AccountEvent.SignedInOrRegistered, {
payload: {
ephemeral: false,
@@ -512,14 +511,14 @@ export class UserService
private async setPasscodeWithoutWarning(passcode: string, origination: KeyParamsOrigination) {
const identifier = UuidGenerator.GenerateUuid()
const key = await this.encryptionService.createRootKey(identifier, passcode, origination)
await this.encryptionService.setNewRootKeyWrapper(key)
const key = await this.encryption.createRootKey(identifier, passcode, origination)
await this.encryption.setNewRootKeyWrapper(key)
await this.rewriteItemsKeys()
await this.sync.sync()
}
private async removePasscodeWithoutWarning() {
await this.encryptionService.removePasscode()
await this.encryption.removePasscode()
await this.rewriteItemsKeys()
}
@@ -532,9 +531,9 @@ export class UserService
* https://github.com/standardnotes/desktop/issues/131
*/
private async rewriteItemsKeys(): Promise<void> {
const itemsKeys = this.itemManager.getDisplayableItemsKeys()
const itemsKeys = this.items.getDisplayableItemsKeys()
const payloads = itemsKeys.map((key) => key.payloadRepresentation())
await this.storageService.deletePayloads(payloads)
await this.storage.deletePayloads(payloads)
await this.sync.persistPayloads(payloads)
}
@@ -547,7 +546,7 @@ export class UserService
}
private clearDatabase(): Promise<void> {
return this.storageService.clearAllPayloads()
return this.storage.clearAllPayloads()
}
private async performCredentialsChange(parameters: {
@@ -558,7 +557,7 @@ export class UserService
newPassword?: string
passcode?: string
}): Promise<CredentialsChangeFunctionResponse> {
const { wrappingKey, canceled } = await this.challengeService.getWrappingKeyIfApplicable(parameters.passcode)
const { wrappingKey, canceled } = await this.challenges.getWrappingKeyIfApplicable(parameters.passcode)
if (canceled) {
return { error: Error(Messages.CredentialsChangeStrings.PasscodeRequired) }
@@ -572,14 +571,14 @@ export class UserService
}
}
const accountPasswordValidation = await this.encryptionService.validateAccountPassword(parameters.currentPassword)
const accountPasswordValidation = await this.encryption.validateAccountPassword(parameters.currentPassword)
if (!accountPasswordValidation.valid) {
return {
error: Error(Messages.INVALID_PASSWORD),
}
}
const user = this.sessionManager.getUser() as User
const user = this.sessions.getUser() as User
const currentEmail = user.email
const { currentRootKey, newRootKey } = await this.recomputeRootKeysForCredentialChange({
currentPassword: parameters.currentPassword,
@@ -591,7 +590,7 @@ export class UserService
this.lockSyncing()
const { response } = await this.sessionManager.changeCredentials({
const { response } = await this.sessions.changeCredentials({
currentServerPassword: currentRootKey.serverPassword as string,
newRootKey: newRootKey,
wrappingKey,
@@ -604,20 +603,20 @@ export class UserService
return { error: Error(response.data.error?.message) }
}
const rollback = await this.encryptionService.createNewItemsKeyWithRollback()
await this.encryptionService.reencryptApplicableItemsAfterUserRootKeyChange()
const rollback = await this.encryption.createNewItemsKeyWithRollback()
await this._reencryptTypeAItems.execute()
await this.sync.sync({ awaitAll: true })
const defaultItemsKey = this.encryptionService.getSureDefaultItemsKey()
const defaultItemsKey = this.encryption.getSureDefaultItemsKey()
const itemsKeyWasSynced = !defaultItemsKey.neverSynced
if (!itemsKeyWasSynced) {
await this.sessionManager.changeCredentials({
await this.sessions.changeCredentials({
currentServerPassword: newRootKey.serverPassword as string,
newRootKey: currentRootKey,
wrappingKey,
})
await this.encryptionService.reencryptApplicableItemsAfterUserRootKeyChange()
await this._reencryptTypeAItems.execute()
await rollback()
await this.sync.sync({ awaitAll: true })
@@ -634,11 +633,11 @@ export class UserService
newEmail?: string
newPassword?: string
}): Promise<{ currentRootKey: SNRootKey; newRootKey: SNRootKey }> {
const currentRootKey = await this.encryptionService.computeRootKey(
const currentRootKey = await this.encryption.computeRootKey(
parameters.currentPassword,
(await this.encryptionService.getRootKeyParams()) as SNRootKeyParams,
this.encryption.getRootKeyParams() as SNRootKeyParams,
)
const newRootKey = await this.encryptionService.createRootKey(
const newRootKey = await this.encryption.createRootKey(
parameters.newEmail ?? parameters.currentEmail,
parameters.newPassword ?? parameters.currentPassword,
parameters.origination,
@@ -5,6 +5,7 @@ import { InternalEventHandlerInterface } from '../Internal/InternalEventHandlerI
import { InternalEventInterface } from '../Internal/InternalEventInterface'
import { AbstractService } from '../Service/AbstractService'
import { UserEventServiceEventPayload, UserEventServiceEvent } from './UserEventServiceEvent'
import { NotificationPayload } from '@standardnotes/domain-core'
export class UserEventService
extends AbstractService<UserEventServiceEvent, UserEventServiceEventPayload>
@@ -28,9 +29,13 @@ export class UserEventService
}
for (const serverEvent of userEvents) {
const serviceEvent: UserEventServiceEventPayload = {
eventPayload: JSON.parse(serverEvent.event_payload),
const eventPayloadOrError = NotificationPayload.createFromString(serverEvent.payload)
if (eventPayloadOrError.isFailed()) {
continue
}
const eventPayload = eventPayloadOrError.getValue()
const serviceEvent: UserEventServiceEventPayload = { eventPayload }
await this.notifyEventSync(UserEventServiceEvent.UserEventReceived, serviceEvent)
}
@@ -1,9 +1,9 @@
import { UserEventPayload } from '@standardnotes/responses'
import { NotificationPayload } from '@standardnotes/domain-core'
export enum UserEventServiceEvent {
UserEventReceived = 'UserEventReceived',
}
export type UserEventServiceEventPayload = {
eventPayload: UserEventPayload
eventPayload: NotificationPayload
}
@@ -1,4 +1,4 @@
import { SharedVaultInviteServerHash, SharedVaultPermission } from '@standardnotes/responses'
import { SharedVaultInviteServerHash } from '@standardnotes/responses'
import {
TrustedContactInterface,
SharedVaultListingInterface,
@@ -8,7 +8,7 @@ import {
import { SendVaultInvite } from './SendVaultInvite'
import { PkcKeyPair } from '@standardnotes/sncrypto-common'
import { EncryptMessage } from '../../Encryption/UseCase/Asymmetric/EncryptMessage'
import { Result, UseCaseInterface } from '@standardnotes/domain-core'
import { Result, SharedVaultUserPermission, UseCaseInterface } from '@standardnotes/domain-core'
import { ShareContactWithVault } from '../../SharedVaults/UseCase/ShareContactWithVault'
import { KeySystemKeyManagerInterface } from '../../KeySystem/KeySystemKeyManagerInterface'
@@ -29,7 +29,7 @@ export class InviteToVault implements UseCaseInterface<SharedVaultInviteServerHa
sharedVault: SharedVaultListingInterface
sharedVaultContacts: TrustedContactInterface[]
recipient: TrustedContactInterface
permissions: SharedVaultPermission
permission: string
}): Promise<Result<SharedVaultInviteServerHash>> {
const createInviteResult = await this.inviteContact(params)
@@ -74,8 +74,14 @@ export class InviteToVault implements UseCaseInterface<SharedVaultInviteServerHa
sharedVault: SharedVaultListingInterface
sharedVaultContacts: TrustedContactInterface[]
recipient: TrustedContactInterface
permissions: SharedVaultPermission
permission: string
}): Promise<Result<SharedVaultInviteServerHash>> {
const permissionOrError = SharedVaultUserPermission.create(params.permission)
if (permissionOrError.isFailed()) {
return Result.fail(permissionOrError.getError())
}
const permission = permissionOrError.getValue()
const keySystemRootKey = this.keyManager.getPrimaryKeySystemRootKey(params.sharedVault.systemIdentifier)
if (!keySystemRootKey) {
return Result.fail('Cannot invite contact; key system root key not found')
@@ -127,7 +133,7 @@ export class InviteToVault implements UseCaseInterface<SharedVaultInviteServerHa
sharedVaultUuid: params.sharedVault.sharing.sharedVaultUuid,
recipientUuid: params.recipient.contactUuid,
encryptedMessage: encryptedMessage.getValue(),
permissions: params.permissions,
permission: permission.value,
})
return createInviteResult
@@ -49,7 +49,7 @@ export class ReuploadInvite implements UseCaseInterface<void> {
sharedVaultUuid: params.previousInvite.shared_vault_uuid,
recipientUuid: params.recipient.contactUuid,
encryptedMessage: encryptedMessage.getValue(),
permissions: params.previousInvite.permissions,
permission: params.previousInvite.permission,
})
return createInviteResult
@@ -1,11 +1,6 @@
import {
SharedVaultInviteServerHash,
isErrorResponse,
SharedVaultPermission,
getErrorFromErrorResponse,
} from '@standardnotes/responses'
import { SharedVaultInviteServerHash, isErrorResponse, getErrorFromErrorResponse } from '@standardnotes/responses'
import { SharedVaultInvitesServerInterface } from '@standardnotes/api'
import { Result, UseCaseInterface } from '@standardnotes/domain-core'
import { Result, SharedVaultUserPermission, UseCaseInterface } from '@standardnotes/domain-core'
export class SendVaultInvite implements UseCaseInterface<SharedVaultInviteServerHash> {
constructor(private vaultInvitesServer: SharedVaultInvitesServerInterface) {}
@@ -14,13 +9,19 @@ export class SendVaultInvite implements UseCaseInterface<SharedVaultInviteServer
sharedVaultUuid: string
recipientUuid: string
encryptedMessage: string
permissions: SharedVaultPermission
permission: string
}): Promise<Result<SharedVaultInviteServerHash>> {
const permissionOrError = SharedVaultUserPermission.create(params.permission)
if (permissionOrError.isFailed()) {
return Result.fail(permissionOrError.getError())
}
const permission = permissionOrError.getValue()
const response = await this.vaultInvitesServer.createInvite({
sharedVaultUuid: params.sharedVaultUuid,
recipientUuid: params.recipientUuid,
encryptedMessage: params.encryptedMessage,
permissions: params.permissions,
permission: permission,
})
if (isErrorResponse(response)) {
@@ -27,7 +27,6 @@ import { VaultInviteServiceInterface } from './VaultInviteServiceInterface'
import {
ClientDisplayableError,
SharedVaultInviteServerHash,
SharedVaultPermission,
SharedVaultUserServerHash,
isErrorResponse,
} from '@standardnotes/responses'
@@ -173,7 +172,7 @@ export class VaultInviteService
public async inviteContactToSharedVault(
sharedVault: SharedVaultListingInterface,
contact: TrustedContactInterface,
permissions: SharedVaultPermission,
permission: string,
): Promise<Result<SharedVaultInviteServerHash>> {
const contactsResult = await this._getVaultContacts.execute({
sharedVaultUuid: sharedVault.sharing.sharedVaultUuid,
@@ -194,7 +193,7 @@ export class VaultInviteService
sharedVault,
recipient: contact,
sharedVaultContacts: contacts,
permissions,
permission,
})
void this.notifyEvent(VaultInviteServiceEvent.InviteSent)
@@ -1,7 +1,7 @@
import { InviteRecord } from './InviteRecord'
import { ApplicationServiceInterface } from '../Service/ApplicationServiceInterface'
import { SharedVaultListingInterface, TrustedContactInterface } from '@standardnotes/models'
import { ClientDisplayableError, SharedVaultInviteServerHash, SharedVaultPermission } from '@standardnotes/responses'
import { ClientDisplayableError, SharedVaultInviteServerHash } from '@standardnotes/responses'
import { VaultInviteServiceEvent } from './VaultInviteServiceEvent'
import { Result } from '@standardnotes/domain-core'
@@ -10,7 +10,7 @@ export interface VaultInviteServiceInterface extends ApplicationServiceInterface
inviteContactToSharedVault(
sharedVault: SharedVaultListingInterface,
contact: TrustedContactInterface,
permissions: SharedVaultPermission,
permission: string,
): Promise<Result<SharedVaultInviteServerHash>>
getCachedPendingInviteRecords(): InviteRecord[]
deleteInvite(invite: SharedVaultInviteServerHash): Promise<ClientDisplayableError | void>
+1
View File
@@ -75,6 +75,7 @@ export * from './Encryption/UseCase/TypeA/DecryptPayload'
export * from './Encryption/UseCase/TypeA/DecryptPayloadWithKeyLookup'
export * from './Encryption/UseCase/TypeA/EncryptPayload'
export * from './Encryption/UseCase/TypeA/EncryptPayloadWithKeyLookup'
export * from './Encryption/UseCase/TypeA/ReencryptTypeAItems'
export * from './Event/ApplicationEvent'
export * from './Event/ApplicationEventCallback'
export * from './Event/ApplicationStageChangedEventPayload'
+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.
## [2.202.18](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-07-27)
**Note:** Version bump only for package @standardnotes/snjs
## [2.202.17](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-07-27)
**Note:** Version bump only for package @standardnotes/snjs
## [2.202.16](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))
## [2.202.15](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-07-26)
**Note:** Version bump only for package @standardnotes/snjs

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