Compare commits

...
Author SHA1 Message Date
StandardNotes CI a3cf2b9565 chore(release): publish
- @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
2023-07-31 15:56:25 +00:00
Karol Sójko f18c86da54 chore: fix deleting account specs (#2378)
* chore: fix deleting account specs

* fix: specs
2023-07-31 17:23:20 +02:00
Aman Harwara 661fddf433 refactor: fix potential issues when converting to string [no ci] 2023-07-31 16:29:46 +05:30
Aman Harwara f24e0b0e50 refactor: component props [no ci] 2023-07-30 12:43:43 +05:30
StandardNotes CI 50452ff6ca chore(release): publish
- @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
2023-07-29 17:42:06 +00:00
Aman Harwara c42afa45b4 fix: Fixed issue where autocapitalization wouldn't work on iOS for newly created Super notes 2023-07-29 22:37:12 +05:30
StandardNotes CI d3dfa73fa0 chore(release): publish
- @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
2023-07-29 15:08:28 +00:00
Aman Harwara 64855315e8 fix: Fixed issue where links in Super would not open 2023-07-29 20:06:23 +05:30
StandardNotes CI edccea8499 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-28 12:37:36 +00:00
Mo c7fb0d2aca refactor: component viewer (#2377) 2023-07-28 07:08:52 -05:00
StandardNotes CI 3de6af445b chore(release): publish
- @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
2023-07-28 07:40:53 +00:00
Aman Harwara 4b002fa501 chore: misc 2023-07-28 12:38:49 +05:30
Aman Harwara fee9dcaa34 chore: fix issue with custom note title format 2023-07-28 12:36:17 +05:30
49 changed files with 579 additions and 257 deletions
+32 -25
View File
@@ -1,3 +1,5 @@
// Recommended: https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/eslint-plugin/src/configs/recommended-type-checked.ts
module.exports = {
root: true,
parser: '@typescript-eslint/parser',
@@ -9,15 +11,25 @@ module.exports = {
plugins: ['@typescript-eslint', 'prettier'],
ignorePatterns: ['**/*.spec.ts'],
rules: {
'@typescript-eslint/restrict-template-expressions': 'error',
'standard/no-callback-literal': 0, // Disable this as we have too many callbacks relying on literals
'no-throw-literal': 0,
camelcase: 'off',
'sort-imports': 'off',
'eol-last': 'error',
'no-multiple-empty-lines': ['error', { max: 1, maxEOF: 0 }],
'no-trailing-spaces': 'error',
'prettier/prettier': [
'error',
{
singleQuote: true,
trailingComma: 'all',
printWidth: 120,
semi: false,
},
{
usePrettierrc: false,
},
],
'@typescript-eslint/no-explicit-any': 'warn',
'@typescript-eslint/no-for-in-array': 'error',
'@typescript-eslint/no-var-requires': 'error',
'@typescript-eslint/prefer-as-const': 'error',
'@typescript-eslint/no-array-constructor': 'error',
'@typescript-eslint/no-duplicate-enum-values': 'error',
'@typescript-eslint/restrict-template-expressions': 'error',
'@typescript-eslint/no-unused-vars': [
'error',
{
@@ -31,31 +43,26 @@ module.exports = {
'@typescript-eslint/no-floating-promises': ['error'],
'block-scoped-var': 'error',
'comma-dangle': ['error', 'always-multiline'],
curly: ['error', 'all'],
'eol-last': 'error',
'no-confusing-arrow': 'error',
'no-inline-comments': 'warn',
'no-invalid-this': 'error',
'no-return-assign': 'warn',
'no-console': ['warn', { allow: ['warn', 'error'] }],
'no-constructor-return': 'error',
'no-duplicate-imports': 'error',
'no-inline-comments': 'warn',
'no-invalid-this': 'error',
'no-multiple-empty-lines': ['error', { max: 1, maxEOF: 0 }],
'no-return-assign': 'warn',
'no-self-compare': 'error',
'no-console': ['warn', { allow: ['warn', 'error'] }],
'no-throw-literal': 0,
'no-trailing-spaces': 'error',
'no-unmodified-loop-condition': 'error',
'no-unused-private-class-members': 'error',
'object-curly-spacing': ['error', 'always'],
'sort-imports': 'off',
'standard/no-callback-literal': 0, // Disable this as we have too many callbacks relying on literals
camelcase: 'off',
curly: ['error', 'all'],
quotes: ['error', 'single', { avoidEscape: true }],
semi: ['error', 'never'],
'prettier/prettier': [
'error',
{
singleQuote: true,
trailingComma: 'all',
printWidth: 120,
semi: false,
},
{
usePrettierrc: false,
},
],
},
}
+4
View File
@@ -3,6 +3,10 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.26.36](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-07-28)
**Note:** Version bump only for package @standardnotes/api
## [1.26.35](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-07-28)
**Note:** Version bump only for package @standardnotes/api
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@standardnotes/api",
"version": "1.26.35",
"version": "1.26.36",
"engines": {
"node": ">=16.0.0 <17.0.0"
},
+20
View File
@@ -3,6 +3,26 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.1.125](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-07-31)
**Note:** Version bump only for package @standardnotes/clipper
## [1.1.124](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-07-29)
**Note:** Version bump only for package @standardnotes/clipper
## [1.1.123](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-07-29)
**Note:** Version bump only for package @standardnotes/clipper
## [1.1.122](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-07-28)
**Note:** Version bump only for package @standardnotes/clipper
## [1.1.121](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-07-28)
**Note:** Version bump only for package @standardnotes/clipper
## [1.1.120](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-07-28)
**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.120",
"version": "1.1.125",
"private": true,
"scripts": {
"build-mv2": "yarn clean && webpack --config ./webpack.config.prod.js",
+20
View File
@@ -3,6 +3,26 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [3.108.56](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-07-31)
**Note:** Version bump only for package @standardnotes/desktop
## [3.108.55](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-07-29)
**Note:** Version bump only for package @standardnotes/desktop
## [3.108.54](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-07-29)
**Note:** Version bump only for package @standardnotes/desktop
## [3.108.53](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-07-28)
**Note:** Version bump only for package @standardnotes/desktop
## [3.108.52](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-07-28)
**Note:** Version bump only for package @standardnotes/desktop
## [3.108.51](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-07-28)
**Note:** Version bump only for package @standardnotes/desktop
+1 -1
View File
@@ -1,7 +1,7 @@
{
"name": "@standardnotes/desktop",
"main": "./app/dist/index.js",
"version": "3.108.51",
"version": "3.108.56",
"license": "AGPL-3.0-or-later",
"author": "Standard Notes.",
"private": true,
+4
View File
@@ -3,6 +3,10 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.21.59](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-07-28)
**Note:** Version bump only for package @standardnotes/encryption
## [1.21.58](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-07-28)
**Note:** Version bump only for package @standardnotes/encryption
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@standardnotes/encryption",
"version": "1.21.58",
"version": "1.21.59",
"engines": {
"node": ">=16.0.0 <17.0.0"
},
+4
View File
@@ -3,6 +3,10 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.28.69](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-07-28)
**Note:** Version bump only for package @standardnotes/filepicker
## [1.28.68](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-07-28)
**Note:** Version bump only for package @standardnotes/filepicker
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@standardnotes/filepicker",
"version": "1.28.68",
"version": "1.28.69",
"engines": {
"node": ">=16.0.0 <17.0.0"
},
+4
View File
@@ -3,6 +3,10 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.16.15](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-07-28)
**Note:** Version bump only for package @standardnotes/files
## [1.16.14](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-07-28)
**Note:** Version bump only for package @standardnotes/files
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@standardnotes/files",
"version": "1.16.14",
"version": "1.16.15",
"engines": {
"node": ">=16.0.0 <17.0.0"
},
+22
View File
@@ -3,6 +3,28 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [3.56.36](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-07-31)
**Note:** Version bump only for package @standardnotes/mobile
## [3.56.35](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-07-29)
**Note:** Version bump only for package @standardnotes/mobile
## [3.56.34](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-07-29)
### Bug Fixes
* Fixed issue where links in Super would not open ([6485531](https://github.com/standardnotes/app/commit/64855315e8ec66f8d9397838b62f1a4d15a66937))
## [3.56.33](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-07-28)
**Note:** Version bump only for package @standardnotes/mobile
## [3.56.32](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-07-28)
**Note:** Version bump only for package @standardnotes/mobile
## [3.56.31](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-07-28)
**Note:** Version bump only for package @standardnotes/mobile
+6 -6
View File
@@ -380,7 +380,7 @@ PODS:
- glog
- react-native-fingerprint-scanner (5.0.0):
- React-Core
- react-native-mmkv (2.7.0):
- react-native-mmkv (2.10.1):
- MMKV (>= 1.2.13)
- React-Core
- react-native-version-info (1.1.1):
@@ -503,13 +503,13 @@ PODS:
- React-Core
- RNFS (2.20.0):
- React-Core
- RNIap (12.7.4):
- RNIap (12.10.5):
- React-Core
- RNKeychain (8.0.0):
- React-Core
- RNPrivacySnapshot (1.0.0):
- React-Core
- RNShare (8.2.0):
- RNShare (8.2.2):
- React-Core
- SNReactNative (1.0.1):
- React-Core
@@ -759,7 +759,7 @@ SPEC CHECKSUMS:
React-jsinspector: b511447170f561157547bc0bef3f169663860be7
React-logger: c5b527272d5f22eaa09bb3c3a690fee8f237ae95
react-native-fingerprint-scanner: be63e626b31fb951780a5fac5328b065a61a3d6e
react-native-mmkv: a2a40a0458bdbc9d43c4e7752ecfc5e3a87b66dd
react-native-mmkv: dea675cf9697ad35940f1687e98e133e1358ef9f
react-native-version-info: a106f23009ac0db4ee00de39574eb546682579b9
react-native-webview: 9f111dfbcfc826084d6c507f569e5e03342ee1c1
React-NativeModulesApple: c57f3efe0df288a6532b726ad2d0322a9bf38472
@@ -782,10 +782,10 @@ SPEC CHECKSUMS:
RNCAsyncStorage: 4b98ac3c64efa4e35c1197cb0c5ca5e9f5d4c666
RNFileViewer: ce7ca3ac370e18554d35d6355cffd7c30437c592
RNFS: 4ac0f0ea233904cb798630b3c077808c06931688
RNIap: 1a0b01a82ce45e61e72f8ef38f85922c5534510d
RNIap: c397f49db45af3b10dca64b2325f21bb8078ad21
RNKeychain: 4f63aada75ebafd26f4bc2c670199461eab85d94
RNPrivacySnapshot: 8eaf571478a353f2e5184f5c803164f22428b023
RNShare: b089c33619bbfb0a32bc4069c858b9274e694187
RNShare: d82e10f6b7677f4b0048c23709bd04098d5aee6c
SNReactNative: b5e9e529c175c13f3a618e27c76cf3071213d5e1
SocketRocket: f32cd54efbe0f095c4d7594881e52619cfe80b17
TrustKit: 073855e3adecd317417bda4ac9e9ac54a2e3b9f2
@@ -15,7 +15,7 @@
07CAB7702A618385008FE1EF /* ReceiveSharingIntent.m in Sources */ = {isa = PBXBuildFile; fileRef = 07CAB76F2A618385008FE1EF /* ReceiveSharingIntent.m */; };
13B07FBF1A68108700A75B9A /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 13B07FB51A68108700A75B9A /* Images.xcassets */; };
13B07FC11A68108700A75B9A /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB71A68108700A75B9A /* main.m */; };
1C2EEB3B45F4EB07AC795C77 /* (null) in Frameworks */ = {isa = PBXBuildFile; };
1C2EEB3B45F4EB07AC795C77 /* BuildFile in Frameworks */ = {isa = PBXBuildFile; };
33BB1B14071EBE5978EBF3A8 /* libPods-StandardNotes-StandardNotesTests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 04FCB5A3A3387CA3CFC82AA3 /* libPods-StandardNotes-StandardNotesTests.a */; };
BC8DEA834BF198E8511F04FF /* libPods-StandardNotesDev.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 51F2D747BE02C2A1BCFEEFD1 /* libPods-StandardNotesDev.a */; };
CD6592A9291EEFCC00C09DC6 /* StoreKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CD6592A8291EEFCC00C09DC6 /* StoreKit.framework */; };
@@ -123,7 +123,7 @@
buildActionMask = 2147483647;
files = (
CD6592A9291EEFCC00C09DC6 /* StoreKit.framework in Frameworks */,
1C2EEB3B45F4EB07AC795C77 /* (null) in Frameworks */,
1C2EEB3B45F4EB07AC795C77 /* BuildFile in Frameworks */,
DD3D1CE428EC1C8BA0C49211 /* libPods-StandardNotes.a in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@standardnotes/mobile",
"version": "3.56.31",
"version": "3.56.36",
"author": "Standard Notes.",
"private": true,
"license": "AGPL-3.0-or-later",
+4
View File
@@ -3,6 +3,10 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.46.18](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-07-28)
**Note:** Version bump only for package @standardnotes/models
## [1.46.17](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-07-28)
**Note:** Version bump only for package @standardnotes/models
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@standardnotes/models",
"version": "1.46.17",
"version": "1.46.18",
"engines": {
"node": ">=16.0.0 <17.0.0"
},
@@ -2,6 +2,7 @@ import {
ComponentArea,
ComponentPermission,
EditorFeatureDescription,
FindNativeFeature,
NativeFeatureIdentifier,
NoteType,
ThemeDockIcon,
@@ -47,6 +48,10 @@ export class UIFeature<F extends UIFeatureDescriptionTypes> implements UIFeature
throw new Error('Cannot cast item to feature description')
}
get isNativeFeature(): boolean {
return FindNativeFeature(this.featureIdentifier) !== undefined
}
get uniqueIdentifier(): NativeFeatureIdentifier | Uuid {
if (isNativeFeature(this.item)) {
const nativeFeature = NativeFeatureIdentifier.create(this.item.identifier)
@@ -17,6 +17,7 @@ export interface UIFeatureInterface<F extends UIFeatureDescriptionTypes> {
get isThemeComponent(): boolean
get asComponent(): ComponentInterface
get asFeatureDescription(): F
get isNativeFeature(): boolean
get uniqueIdentifier(): NativeFeatureIdentifier | Uuid
get featureIdentifier(): string
get noteType(): NoteType
+20
View File
@@ -3,6 +3,26 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.4.408](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-07-31)
**Note:** Version bump only for package @standardnotes/releases
## [1.4.407](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-07-29)
**Note:** Version bump only for package @standardnotes/releases
## [1.4.406](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-07-29)
**Note:** Version bump only for package @standardnotes/releases
## [1.4.405](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-07-28)
**Note:** Version bump only for package @standardnotes/releases
## [1.4.404](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-07-28)
**Note:** Version bump only for package @standardnotes/releases
## [1.4.403](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-07-28)
**Note:** Version bump only for package @standardnotes/releases
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@standardnotes/releases",
"version": "1.4.403",
"version": "1.4.408",
"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.63.18](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-07-31)
**Note:** Version bump only for package @standardnotes/services
## [1.63.17](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-07-28)
**Note:** Version bump only for package @standardnotes/services
## [1.63.16](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-07-28)
**Note:** Version bump only for package @standardnotes/services
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@standardnotes/services",
"version": "1.63.16",
"version": "1.63.18",
"engines": {
"node": ">=16.0.0 <17.0.0"
},
@@ -244,7 +244,9 @@ export class UserService
await this.signOut(true)
void this.alerts.alert(InfoStrings.AccountDeleted)
if (this.alerts) {
void this.alerts.alert(InfoStrings.AccountDeleted)
}
return {
error: false,
+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.
## [2.202.22](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-07-31)
**Note:** Version bump only for package @standardnotes/snjs
## [2.202.21](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-07-28)
**Note:** Version bump only for package @standardnotes/snjs
## [2.202.20](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-07-28)
**Note:** Version bump only for package @standardnotes/snjs
@@ -458,8 +458,7 @@ export class ComponentViewer implements ComponentViewerInterface {
}
this.log('Send message to component', this.componentOrFeature, 'message: ', message)
let origin = this.options.url
if (!origin || !this.window) {
if (!this.window) {
if (essential) {
void this.services.alerts.alert(
`Standard Notes is trying to communicate with ${this.componentOrFeature.displayName}, ` +
@@ -469,13 +468,11 @@ export class ComponentViewer implements ComponentViewerInterface {
return
}
if (!origin.startsWith('http') && !origin.startsWith('file')) {
/* Native extension running in web, prefix current host */
origin = window.location.href + origin
}
/** Because iframes do not allow-same-origin, their origin is `null`, and so we can't target their explicit origin */
const nullOrigin = '*'
/* Mobile messaging requires json */
this.window.postMessage(this.isMobile ? JSON.stringify(message) : message, origin)
this.window.postMessage(this.isMobile ? JSON.stringify(message) : message, nullOrigin)
}
private responseItemsByRemovingPrivateProperties<T extends OutgoingItemMessagePayload | IncomingComponentItemPayload>(
+180 -168
View File
@@ -13,25 +13,27 @@ describe('basic auth', function () {
awaitAll: true,
}
beforeEach(async function () {
localStorage.clear()
this.expectedItemCount = BaseItemCounts.DefaultItemsWithAccount
this.context = await Factory.createAppContext()
await this.context.launch()
this.application = this.context.application
this.email = UuidGenerator.GenerateUuid()
this.password = UuidGenerator.GenerateUuid()
})
let context
afterEach(async function () {
await Factory.safeDeinit(this.application)
await context.deinit()
localStorage.clear()
})
beforeEach(async function () {
localStorage.clear()
context = await Factory.createAppContextWithRealCrypto()
await context.launch()
this.expectedItemCount = BaseItemCounts.DefaultItemsWithAccount
})
it('successfully register new account', async function () {
const response = await this.application.register(this.email, this.password)
const response = await context.register()
expect(response).to.be.ok
expect(await this.application.encryption.getRootKey()).to.be.ok
expect(await context.application.encryption.getRootKey()).to.be.ok
})
it('fails register new account with short password', async function () {
@@ -39,7 +41,7 @@ describe('basic auth', function () {
let error = null
try {
await this.application.register(this.email, password)
await context.application.register(context.email, password)
} catch (caughtError) {
error = caughtError
}
@@ -49,41 +51,44 @@ describe('basic auth', function () {
'For your security, please choose a longer password or, ideally, a passphrase, and try again.',
)
expect(await this.application.encryption.getRootKey()).to.not.be.ok
expect(await context.application.encryption.getRootKey()).to.not.be.ok
})
it('successfully signs out of account', async function () {
await this.application.register(this.email, this.password)
await context.register()
expect(await this.application.encryption.getRootKey()).to.be.ok
expect(await context.application.encryption.getRootKey()).to.be.ok
this.application = await Factory.signOutApplicationAndReturnNew(this.application)
context.application = await Factory.signOutApplicationAndReturnNew(context.application)
expect(await this.application.encryption.getRootKey()).to.not.be.ok
expect(this.application.encryption.rootKeyManager.getKeyMode()).to.equal(KeyMode.RootKeyNone)
expect(await context.application.encryption.getRootKey()).to.not.be.ok
expect(context.application.encryption.rootKeyManager.getKeyMode()).to.equal(KeyMode.RootKeyNone)
})
it('successfully signs in to registered account', async function () {
await this.application.register(this.email, this.password)
this.application = await Factory.signOutApplicationAndReturnNew(this.application)
const response = await this.application.signIn(this.email, this.password, undefined, undefined, undefined, true)
await context.register()
await context.signout()
const response = await context.application.signIn(context.email, context.password, undefined, undefined, undefined, true)
expect(response).to.be.ok
expect(response.data.error).to.not.be.ok
expect(await this.application.encryption.getRootKey()).to.be.ok
expect(await context.application.encryption.getRootKey()).to.be.ok
}).timeout(20000)
it('cannot sign while already signed in', async function () {
await this.application.register(this.email, this.password)
await Factory.createSyncedNote(this.application)
this.application = await Factory.signOutApplicationAndReturnNew(this.application)
const response = await this.application.signIn(this.email, this.password, undefined, undefined, undefined, true)
await context.register()
await Factory.createSyncedNote(context.application)
await context.signout()
const response = await context.application.signIn(context.email, context.password, undefined, undefined, undefined, true)
expect(response).to.be.ok
expect(response.data.error).to.not.be.ok
expect(await this.application.encryption.getRootKey()).to.be.ok
expect(await context.application.encryption.getRootKey()).to.be.ok
let error
try {
await this.application.signIn(this.email, this.password, undefined, undefined, undefined, true)
await context.application.signIn(context.email, context.password, undefined, undefined, undefined, true)
} catch (e) {
error = e
}
@@ -91,27 +96,27 @@ describe('basic auth', function () {
}).timeout(20000)
it('cannot register while already signed in', async function () {
await this.application.register(this.email, this.password)
await context.register()
let error
try {
await this.application.register(this.email, this.password)
await context.register()
} catch (e) {
error = e
}
expect(error).to.be.ok
expect(await this.application.encryption.getRootKey()).to.be.ok
expect(await context.application.encryption.getRootKey()).to.be.ok
}).timeout(20000)
it('cannot perform two sign-ins at the same time', async function () {
await this.application.register(this.email, this.password)
this.application = await Factory.signOutApplicationAndReturnNew(this.application)
await context.register()
await context.signout()
await Promise.all([
(async () => {
const response = await this.application.signIn(this.email, this.password, undefined, undefined, undefined, true)
const response = await context.application.signIn(context.email, context.password, undefined, undefined, undefined, true)
expect(response).to.be.ok
expect(response.data.error).to.not.be.ok
expect(await this.application.encryption.getRootKey()).to.be.ok
expect(await context.application.encryption.getRootKey()).to.be.ok
})(),
(async () => {
/** Make sure the first function runs first */
@@ -119,7 +124,7 @@ describe('basic auth', function () {
/** Try to sign in while the first request is going */
let error
try {
await this.application.signIn(this.email, this.password, undefined, undefined, undefined, true)
await context.application.signIn(context.email, context.password, undefined, undefined, undefined, true)
} catch (e) {
error = e
}
@@ -131,10 +136,10 @@ describe('basic auth', function () {
it('cannot perform two register operations at the same time', async function () {
await Promise.all([
(async () => {
const response = await this.application.register(this.email, this.password)
const response = await context.register()
expect(response).to.be.ok
expect(response.error).to.not.be.ok
expect(await this.application.encryption.getRootKey()).to.be.ok
expect(await context.application.encryption.getRootKey()).to.be.ok
})(),
(async () => {
/** Make sure the first function runs first */
@@ -142,7 +147,7 @@ describe('basic auth', function () {
/** Try to register in while the first request is going */
let error
try {
await this.application.register(this.email, this.password)
await context.register()
} catch (e) {
error = e
}
@@ -152,14 +157,14 @@ describe('basic auth', function () {
}).timeout(20000)
it('successfuly signs in after failing once', async function () {
await this.application.register(this.email, this.password)
this.application = await Factory.signOutApplicationAndReturnNew(this.application)
await context.register()
await context.signout()
let response = await this.application.signIn(this.email, 'wrong password', undefined, undefined, undefined, true)
let response = await context.application.signIn(context.email, 'wrong password', undefined, undefined, undefined, true)
expect(response).to.have.property('status', 401)
expect(response.data.error).to.be.ok
response = await this.application.signIn(this.email, this.password, undefined, undefined, undefined, true)
response = await context.application.signIn(context.email, context.password, undefined, undefined, undefined, true)
expect(response.status).to.equal(200)
expect(response.data).to.not.haveOwnProperty('error')
@@ -183,9 +188,9 @@ describe('basic auth', function () {
* Registering with an uppercase email should still allow us to sign in
* with lowercase email
*/
await this.application.register(uppercase, this.password)
await context.application.register(uppercase, context.password)
const response = await this.application.sessions.retrieveKeyParams(lowercase)
const response = await context.application.sessions.retrieveKeyParams(lowercase)
const keyParams = response.keyParams
expect(keyParams.identifier).to.equal(lowercase)
expect(keyParams.identifier).to.not.equal(uppercase)
@@ -195,16 +200,23 @@ describe('basic auth', function () {
const rand = `${Math.random()}`
const uppercase = `[email protected]${rand}`
const lowercase = `[email protected]${rand}`
/**
* Registering with a lowercase email should allow us to sign in
* with an uppercase email
*/
await this.application.register(lowercase, this.password)
this.application = await Factory.signOutApplicationAndReturnNew(this.application)
const response = await this.application.signIn(uppercase, this.password, undefined, undefined, undefined, true)
const password = UuidGenerator.GenerateUuid()
let specContext = await Factory.createAppContextWithFakeCrypto(Math.random(), lowercase, password)
await specContext.launch()
await specContext.register()
await specContext.signout()
await specContext.deinit()
specContext = await Factory.createAppContextWithFakeCrypto(Math.random(), uppercase, password)
await specContext.launch()
const response = await specContext.signIn()
expect(response).to.be.ok
expect(response.data.error).to.not.be.ok
expect(await this.application.encryption.getRootKey()).to.be.ok
expect(await specContext.application.encryption.getRootKey()).to.be.ok
}).timeout(20000)
it('can sign into account regardless of whitespace', async function () {
@@ -215,47 +227,55 @@ describe('basic auth', function () {
* Registering with a lowercase email should allow us to sign in
* with an uppercase email
*/
await this.application.register(nospace, this.password)
this.application = await Factory.signOutApplicationAndReturnNew(this.application)
const response = await this.application.signIn(withspace, this.password, undefined, undefined, undefined, true)
const password = UuidGenerator.GenerateUuid()
let specContext = await Factory.createAppContextWithFakeCrypto(Math.random(), nospace, password)
await specContext.launch()
await specContext.register()
await specContext.signout()
await specContext.deinit()
specContext = await Factory.createAppContextWithFakeCrypto(Math.random(), withspace, password)
await specContext.launch()
const response = await specContext.signIn()
expect(response).to.be.ok
expect(response.data.error).to.not.be.ok
expect(await this.application.encryption.getRootKey()).to.be.ok
expect(await specContext.application.encryption.getRootKey()).to.be.ok
}).timeout(20000)
it('fails login with wrong password', async function () {
await this.application.register(this.email, this.password)
this.application = await Factory.signOutApplicationAndReturnNew(this.application)
const response = await this.application.signIn(this.email, 'wrongpassword', undefined, undefined, undefined, true)
await context.register()
context.application = await Factory.signOutApplicationAndReturnNew(context.application)
const response = await context.application.signIn(context.email, 'wrongpassword', undefined, undefined, undefined, true)
expect(response).to.be.ok
expect(response.data.error).to.be.ok
expect(await this.application.encryption.getRootKey()).to.not.be.ok
expect(await context.application.encryption.getRootKey()).to.not.be.ok
}).timeout(20000)
it('fails to change to short password', async function () {
await this.application.register(this.email, this.password)
await context.register()
const newPassword = '123456'
const response = await this.application.changePassword(this.password, newPassword)
const response = await context.application.changePassword(context.password, newPassword)
expect(response.error).to.be.ok
}).timeout(20000)
it('fails to change password when current password is incorrect', async function () {
await this.application.register(this.email, this.password)
const response = await this.application.changePassword('Invalid password', 'New password')
await context.register()
const response = await context.application.changePassword('Invalid password', 'New password')
expect(response.error).to.be.ok
/** Ensure we can still log in */
this.application = await Factory.signOutAndBackIn(this.application, this.email, this.password)
context.application = await Factory.signOutAndBackIn(context.application, context.email, context.password)
}).timeout(20000)
it('registering for new account and completing first after download sync should not put us out of sync', async function () {
this.email = UuidGenerator.GenerateUuid()
this.password = UuidGenerator.GenerateUuid()
context.email = UuidGenerator.GenerateUuid()
context.password = UuidGenerator.GenerateUuid()
let outOfSync = true
let didCompletePostDownloadFirstSync = false
let didCompleteDownloadFirstSync = false
this.application.sync.addEventObserver((eventName) => {
context.application.sync.addEventObserver((eventName) => {
if (eventName === SyncEvent.DownloadFirstSyncCompleted) {
didCompleteDownloadFirstSync = true
}
@@ -265,14 +285,14 @@ describe('basic auth', function () {
if (!didCompletePostDownloadFirstSync && eventName === SyncEvent.PaginatedSyncRequestCompleted) {
didCompletePostDownloadFirstSync = true
/** Should be in sync */
outOfSync = this.application.sync.isOutOfSync()
outOfSync = context.application.sync.isOutOfSync()
}
})
await Factory.registerUserToApplication({
application: this.application,
email: this.email,
password: this.password,
application: context.application,
email: context.email,
password: context.password,
})
expect(didCompleteDownloadFirstSync).to.equal(true)
@@ -281,47 +301,47 @@ describe('basic auth', function () {
})
async function changePassword() {
await this.application.register(this.email, this.password)
await context.register()
const noteCount = 10
await Factory.createManyMappedNotes(this.application, noteCount)
await Factory.createManyMappedNotes(context.application, noteCount)
this.expectedItemCount += noteCount
await this.application.sync.sync(syncOptions)
await context.application.sync.sync(syncOptions)
expect(this.application.items.items.length).to.equal(this.expectedItemCount)
expect(context.application.items.items.length).to.equal(this.expectedItemCount)
const newPassword = 'newpassword'
const response = await this.application.changePassword(this.password, newPassword)
const response = await context.application.changePassword(context.password, newPassword)
/** New items key */
this.expectedItemCount++
expect(this.application.items.items.length).to.equal(this.expectedItemCount)
expect(context.application.items.items.length).to.equal(this.expectedItemCount)
expect(response.error).to.not.be.ok
expect(this.application.items.items.length).to.equal(this.expectedItemCount)
expect(this.application.payloads.invalidPayloads.length).to.equal(0)
expect(context.application.items.items.length).to.equal(this.expectedItemCount)
expect(context.application.payloads.invalidPayloads.length).to.equal(0)
await this.application.sync.markAllItemsAsNeedingSyncAndPersist()
await this.application.sync.sync(syncOptions)
await context.application.sync.markAllItemsAsNeedingSyncAndPersist()
await context.application.sync.sync(syncOptions)
expect(this.application.items.items.length).to.equal(this.expectedItemCount)
expect(context.application.items.items.length).to.equal(this.expectedItemCount)
const note = this.application.items.getDisplayableNotes()[0]
const note = context.application.items.getDisplayableNotes()[0]
/**
* Create conflict for a note. First modify the item without saving so that
* our local contents digress from the server's
*/
await this.application.mutator.changeItem(note, (mutator) => {
await context.application.mutator.changeItem(note, (mutator) => {
mutator.title = `${Math.random()}`
})
await Factory.changePayloadTimeStampAndSync(
this.application,
context.application,
note.payload,
Factory.dateToMicroseconds(Factory.yesterday()),
{
@@ -331,18 +351,18 @@ describe('basic auth', function () {
)
this.expectedItemCount++
this.application = await Factory.signOutApplicationAndReturnNew(this.application)
await context.signout()
/** Should login with new password */
const signinResponse = await this.application.signIn(this.email, newPassword, undefined, undefined, undefined, true)
const signinResponse = await context.application.signIn(context.email, newPassword, undefined, undefined, undefined, true)
expect(signinResponse).to.be.ok
expect(signinResponse.data.error).to.not.be.ok
expect(await this.application.encryption.getRootKey()).to.be.ok
expect(await context.application.encryption.getRootKey()).to.be.ok
expect(this.application.items.items.length).to.equal(this.expectedItemCount)
expect(this.application.payloads.invalidPayloads.length).to.equal(0)
expect(context.application.items.items.length).to.equal(this.expectedItemCount)
expect(context.application.payloads.invalidPayloads.length).to.equal(0)
}
it('successfully changes password', changePassword).timeout(40000)
@@ -355,42 +375,42 @@ describe('basic auth', function () {
if (prompt.validation === ChallengeValidation.LocalPasscode) {
values.push(CreateChallengeValue(prompt, passcode))
} else {
values.push(CreateChallengeValue(prompt, this.password))
values.push(CreateChallengeValue(prompt, context.password))
}
}
return values
}
this.application.setLaunchCallback({
context.application.setLaunchCallback({
receiveChallenge: (challenge) => {
this.application.addChallengeObserver(challenge, {
context.application.addChallengeObserver(challenge, {
onInvalidValue: (value) => {
const values = promptValueReply([value.prompt])
this.application.submitValuesForChallenge(challenge, values)
context.application.submitValuesForChallenge(challenge, values)
numPasscodeAttempts++
},
})
const initialValues = promptValueReply(challenge.prompts)
this.application.submitValuesForChallenge(challenge, initialValues)
context.application.submitValuesForChallenge(challenge, initialValues)
},
})
await this.application.setPasscode(passcode)
await context.application.setPasscode(passcode)
await changePassword.bind(this)()
}).timeout(20000)
it('changes password many times', async function () {
await this.application.register(this.email, this.password)
await context.register()
const noteCount = 10
await Factory.createManyMappedNotes(this.application, noteCount)
await Factory.createManyMappedNotes(context.application, noteCount)
this.expectedItemCount += noteCount
await this.application.sync.sync(syncOptions)
await context.application.sync.sync(syncOptions)
const numTimesToChangePw = 3
let newPassword = Factory.randomString()
let currentPassword = this.password
let currentPassword = context.password
for (let i = 0; i < numTimesToChangePw; i++) {
await this.application.changePassword(currentPassword, newPassword)
await context.application.changePassword(currentPassword, newPassword)
/** New items key */
this.expectedItemCount++
@@ -398,20 +418,20 @@ describe('basic auth', function () {
currentPassword = newPassword
newPassword = Factory.randomString()
expect(this.application.items.items.length).to.equal(this.expectedItemCount)
expect(this.application.payloads.invalidPayloads.length).to.equal(0)
expect(context.application.items.items.length).to.equal(this.expectedItemCount)
expect(context.application.payloads.invalidPayloads.length).to.equal(0)
await this.application.sync.markAllItemsAsNeedingSyncAndPersist()
await this.application.sync.sync(syncOptions)
await context.application.sync.markAllItemsAsNeedingSyncAndPersist()
await context.application.sync.sync(syncOptions)
this.application = await this.context.signout()
await context.signout()
expect(this.application.items.items.length).to.equal(BaseItemCounts.DefaultItems)
expect(this.application.payloads.invalidPayloads.length).to.equal(0)
expect(context.application.items.items.length).to.equal(BaseItemCounts.DefaultItems)
expect(context.application.payloads.invalidPayloads.length).to.equal(0)
/** Should login with new password */
const signinResponse = await this.application.signIn(
this.email,
const signinResponse = await context.application.signIn(
context.email,
currentPassword,
undefined,
undefined,
@@ -421,40 +441,40 @@ describe('basic auth', function () {
expect(signinResponse).to.be.ok
expect(signinResponse.data.error).to.not.be.ok
expect(await this.application.encryption.getRootKey()).to.be.ok
expect(await context.application.encryption.getRootKey()).to.be.ok
}
}).timeout(80000)
it('signing in with a clean email string should only try once', async function () {
await Factory.registerUserToApplication({
application: this.application,
email: this.email,
password: this.password,
application: context.application,
email: context.email,
password: context.password,
})
this.application = await Factory.signOutApplicationAndReturnNew(this.application)
const performSignIn = sinon.spy(this.application.sessions, 'performSignIn')
await this.application.signIn(this.email, 'wrong password', undefined, undefined, undefined, true)
context.application = await Factory.signOutApplicationAndReturnNew(context.application)
const performSignIn = sinon.spy(context.application.sessions, 'performSignIn')
await context.application.signIn(context.email, 'wrong password', undefined, undefined, undefined, true)
expect(performSignIn.callCount).to.equal(1)
})
it('should rollback password change if fails to sync new items key', async function () {
/** Should delete the new items key locally without marking it as deleted so that it doesn't sync */
await this.context.register()
await context.register()
const originalImpl = this.application.encryption.getSureDefaultItemsKey
this.application.encryption.getSureDefaultItemsKey = () => {
const originalImpl = context.application.encryption.getSureDefaultItemsKey
context.application.encryption.getSureDefaultItemsKey = () => {
return {
neverSynced: true,
}
}
const mutatorSpy = sinon.spy(this.application.mutator, 'setItemToBeDeleted')
const removeItemsSpy = sinon.spy(this.application.items, 'removeItemsFromMemory')
const deletePayloadsSpy = sinon.spy(this.application.storage, 'deletePayloadsWithUuids')
const mutatorSpy = sinon.spy(context.application.mutator, 'setItemToBeDeleted')
const removeItemsSpy = sinon.spy(context.application.items, 'removeItemsFromMemory')
const deletePayloadsSpy = sinon.spy(context.application.storage, 'deletePayloadsWithUuids')
await this.context.changePassword('new-password')
await context.changePassword('new-password')
this.application.encryption.getSureDefaultItemsKey = originalImpl
context.application.encryption.getSureDefaultItemsKey = originalImpl
expect(mutatorSpy.callCount).to.equal(0)
expect(removeItemsSpy.callCount).to.equal(1)
@@ -464,13 +484,13 @@ describe('basic auth', function () {
describe('add passcode', function () {
it('should set passcode successfully', async function () {
const passcode = 'passcode'
const result = await this.application.addPasscode(passcode)
const result = await context.application.addPasscode(passcode)
expect(result).to.be.true
})
it('should fail when attempting to set 0 character passcode', async function () {
const passcode = ''
const result = await this.application.addPasscode(passcode)
const result = await context.application.addPasscode(passcode)
expect(result).to.be.false
})
})
@@ -479,65 +499,57 @@ describe('basic auth', function () {
it('should change passcode successfully', async function () {
const passcode = 'passcode'
const newPasscode = 'newPasscode'
await this.application.addPasscode(passcode)
Factory.handlePasswordChallenges(this.application, passcode)
const result = await this.application.changePasscode(newPasscode)
await context.application.addPasscode(passcode)
Factory.handlePasswordChallenges(context.application, passcode)
const result = await context.application.changePasscode(newPasscode)
expect(result).to.be.true
}).timeout(Factory.TenSecondTimeout)
it('should fail when attempting to change to a 0 character passcode', async function () {
const passcode = 'passcode'
const newPasscode = ''
await this.application.addPasscode(passcode)
Factory.handlePasswordChallenges(this.application, passcode)
const result = await this.application.changePasscode(newPasscode)
await context.application.addPasscode(passcode)
Factory.handlePasswordChallenges(context.application, passcode)
const result = await context.application.changePasscode(newPasscode)
expect(result).to.be.false
}).timeout(Factory.TenSecondTimeout)
})
describe.skip('account deletion', function () {
it('should delete account', async function () {
await Factory.registerUserToApplication({
application: this.application,
email: this.email,
password: this.password,
})
Factory.handlePasswordChallenges(this.application, this.password)
const _response = await this.application.user.deleteAccount()
}).timeout(Factory.TenSecondTimeout)
describe('account deletion', function () {
beforeEach(async () => {
await context.register()
})
it('should prompt for account password when deleting account', async function () {
await Factory.registerUserToApplication({
application: this.application,
email: this.email,
password: this.password,
})
Factory.handlePasswordChallenges(context.application, context.password)
Factory.handlePasswordChallenges(this.application, this.password)
const sendChallengeSpy = sinon.spy(context.application.challenges, 'sendChallenge')
const _response = await this.application.deleteAccount()
await context.application.user.deleteAccount()
sinon.spy(snApp.challenges, 'sendChallenge')
const spyCall = snApp.challenges.sendChallenge.getCall(0)
const challenge = spyCall.firstArg
expect(challenge.prompts).to.have.lengthOf(2)
expect(challenge.prompts[0].validation).to.equal(ChallengeValidation.AccountPassword)
// ...
expect(sendChallengeSpy.callCount).to.equal(1)
}).timeout(Factory.TenSecondTimeout)
it('deleting account should sign out current user', async function () {
await Factory.registerUserToApplication({
application: this.application,
email: this.email,
password: this.password,
})
Factory.handlePasswordChallenges(context.application, context.password)
Factory.handlePasswordChallenges(this.application, this.password)
const signOutSpy = sinon.spy(context.application.user.sessions, 'signOut')
const _response = await this.application.deleteAccount()
await context.application.user.deleteAccount()
expect(application.hasAccount()).to.be.false
expect(context.application.dealloced).to.be.true
expect(signOutSpy.callCount).to.equal(1)
}).timeout(Factory.TenSecondTimeout)
it('should not allow to delete someone else\'s account', async function () {
const secondContext = await Factory.createAppContextWithRealCrypto()
await secondContext.launch()
const registerResponse = await secondContext.register()
const response = await context.application.dependencies.get(TYPES.UserApiService).deleteAccount(registerResponse.user.uuid)
expect(response.status).to.equal(401)
expect(response.data.error.message).to.equal('Operation not allowed.')
})
})
})
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@standardnotes/snjs",
"version": "2.202.20",
"version": "2.202.22",
"engines": {
"node": ">=16.0.0 <17.0.0"
},
+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.28.20](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-07-31)
**Note:** Version bump only for package @standardnotes/ui-services
## [1.28.19](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-07-28)
**Note:** Version bump only for package @standardnotes/ui-services
## [1.28.18](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-07-28)
**Note:** Version bump only for package @standardnotes/ui-services
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@standardnotes/ui-services",
"version": "1.28.18",
"version": "1.28.20",
"engines": {
"node": ">=16.0.0 <17.0.0"
},
+24
View File
@@ -3,6 +3,30 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [3.167.23](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-07-31)
**Note:** Version bump only for package @standardnotes/web
## [3.167.22](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-07-29)
### Bug Fixes
* Fixed issue where autocapitalization wouldn't work on iOS for newly created Super notes ([c42afa4](https://github.com/standardnotes/app/commit/c42afa45b42f6d4afcc120cd053ceff14fe2089e))
## [3.167.21](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-07-29)
### Bug Fixes
* Fixed issue where links in Super would not open ([6485531](https://github.com/standardnotes/app/commit/64855315e8ec66f8d9397838b62f1a4d15a66937))
## [3.167.20](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-07-28)
**Note:** Version bump only for package @standardnotes/web
## [3.167.19](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-07-28)
**Note:** Version bump only for package @standardnotes/web
## [3.167.18](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-07-28)
**Note:** Version bump only for package @standardnotes/web
+61
View File
@@ -1,5 +1,66 @@
{
"versions": [
{
"version": "3.167.23",
"title": "[3.167.23](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-07-31)",
"date": null,
"body": "**Note:** Version bump only for package @standardnotes/web",
"parsed": {
"_": [
"Note: Version bump only for package @standardnotes/web"
]
}
},
{
"version": "3.167.22",
"title": "[3.167.22](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-07-29)",
"date": null,
"body": "### Bug Fixes\n\n* Fixed issue where autocapitalization wouldn't work on iOS for newly created Super notes ([c42afa4](https://github.com/standardnotes/app/commit/c42afa45b42f6d4afcc120cd053ceff14fe2089e))",
"parsed": {
"_": [
"Fixed issue where autocapitalization wouldn't work on iOS for newly created Super notes (c42afa4)"
],
"Bug Fixes": [
"Fixed issue where autocapitalization wouldn't work on iOS for newly created Super notes (c42afa4)"
]
}
},
{
"version": "3.167.21",
"title": "[3.167.21](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-07-29)",
"date": null,
"body": "### Bug Fixes\n\n* Fixed issue where links in Super would not open ([6485531](https://github.com/standardnotes/app/commit/64855315e8ec66f8d9397838b62f1a4d15a66937))",
"parsed": {
"_": [
"Fixed issue where links in Super would not open (6485531)"
],
"Bug Fixes": [
"Fixed issue where links in Super would not open (6485531)"
]
}
},
{
"version": "3.167.20",
"title": "[3.167.20](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-07-28)",
"date": null,
"body": "**Note:** Version bump only for package @standardnotes/web",
"parsed": {
"_": [
"Note: Version bump only for package @standardnotes/web"
]
}
},
{
"version": "3.167.19",
"title": "[3.167.19](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-07-28)",
"date": null,
"body": "**Note:** Version bump only for package @standardnotes/web",
"parsed": {
"_": [
"Note: Version bump only for package @standardnotes/web"
]
}
},
{
"version": "3.167.18",
"title": "[3.167.18](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2023-07-28)",
+2 -2
View File
@@ -1,6 +1,6 @@
{
"name": "@standardnotes/web",
"version": "3.167.18",
"version": "3.167.23",
"license": "AGPL-3.0-or-later",
"main": "dist/app.js",
"author": "Standard Notes",
@@ -66,7 +66,7 @@
"circular-dependency-plugin": "^5.2.2",
"copy-webpack-plugin": "^11.0.0",
"css-loader": "*",
"dayjs": "^1.11.7",
"dayjs": "^1.11.9",
"dotenv": "^16.0.3",
"eslint": "*",
"eslint-config-prettier": "^8.9.0",
@@ -7,7 +7,7 @@ import {
ComponentInterface,
SubscriptionManagerEvent,
} from '@standardnotes/snjs'
import { FunctionComponent, useCallback, useEffect, useRef, useState } from 'react'
import { FunctionComponent, useCallback, useEffect, useMemo, useRef, useState } from 'react'
import { observer } from 'mobx-react-lite'
import OfflineRestricted from '@/Components/ComponentView/OfflineRestricted'
import UrlMissing from '@/Components/ComponentView/UrlMissing'
@@ -178,6 +178,37 @@ const IframeFeatureView: FunctionComponent<Props> = ({ onLoad, componentViewer,
}
}, [application, requestReload, componentViewer, uiFeature])
const sandboxAttributes = useMemo(() => {
const attributes = [
'allow-scripts',
'allow-top-navigation-by-user-activation',
'allow-popups',
'allow-modals',
'allow-forms',
'allow-downloads',
]
if (uiFeature.isNativeFeature) {
attributes.push('allow-popups-to-escape-sandbox')
}
if (application.isNativeMobileWeb()) {
/**
* Native mobile web serves native components through the file:// protocol.
* Native mobile web also does not use localStorage, unlike the web app.
* So, components served through the file:// (precompiled editors) will be treated
* as same origin as the parent app, but will not have meaningful access.
*
* Third party components will have a non-file:// origin, and thus don't need this attribute.
*/
if (uiFeature.isNativeFeature) {
attributes.push('allow-same-origin')
}
}
return attributes
}, [application, uiFeature])
return (
<>
{hasIssueLoading && (
@@ -208,7 +239,7 @@ const IframeFeatureView: FunctionComponent<Props> = ({ onLoad, componentViewer,
data-component-viewer-id={componentViewer.identifier}
frameBorder={0}
src={componentViewer.url || ''}
sandbox="allow-scripts allow-top-navigation-by-user-activation allow-popups allow-popups-to-escape-sandbox allow-same-origin allow-modals allow-forms allow-downloads"
sandbox={sandboxAttributes.join(' ')}
>
Loading
</iframe>
@@ -21,14 +21,8 @@ import { EditorOption, getDropdownItemsForAllEditors } from '@/Utils/DropdownIte
import { classNames } from '@standardnotes/utils'
import { NoteTitleFormatOptions } from './NoteTitleFormatOptions'
import { usePremiumModal } from '@/Hooks/usePremiumModal'
import dayjs from 'dayjs'
import dayjsAdvancedFormat from 'dayjs/plugin/advancedFormat'
import dayjsUTC from 'dayjs/plugin/utc'
import dayjsTimezone from 'dayjs/plugin/timezone'
dayjs.extend(dayjsAdvancedFormat)
dayjs.extend(dayjsUTC)
dayjs.extend(dayjsTimezone)
import { getDayjsFormattedString } from '@/Utils/GetDayjsFormattedString'
import { ErrorBoundary } from '@/Utils/ErrorBoundary'
const PrefChangeDebounceTimeInMs = 25
@@ -42,6 +36,10 @@ type Props = {
disabled?: boolean
}
function CustomNoteTitleFormatPreview({ format }: { format: string }) {
return <em>{getDayjsFormattedString(undefined, format)}</em>
}
const NewNotePreferences: FunctionComponent<Props> = ({
application,
selectedTag,
@@ -209,7 +207,9 @@ const NewNotePreferences: FunctionComponent<Props> = ({
</div>
<div className="mt-3 text-neutral">
<span className="font-bold">Preview: </span>
<em>{dayjs().format(customNoteTitleFormat)}</em>
<ErrorBoundary>
<CustomNoteTitleFormatPreview format={customNoteTitleFormat} />
</ErrorBoundary>
</div>
<div className="mt-2 text-neutral">
<a
@@ -209,7 +209,7 @@ const Modal = ({
<Button
primary={action.type === 'primary'}
colorStyle={action.type === 'destructive' ? 'danger' : undefined}
key={action.label.toString()}
key={index}
onClick={action.onClick}
className={classNames(
action.mobileSlot ? 'hidden md:block' : '',
@@ -130,12 +130,6 @@ export const PlainEditor = forwardRef<PlainEditorInterface, Props>(
}
}, [])
useEffect(() => {
if (controller.isTemplateNote && controller.templateNoteOptions?.autofocusBehavior === 'editor') {
focusEditor()
}
}, [controller, focusEditor])
useEffect(() => {
const shouldFocus = controller.isTemplateNote && controller.templateNoteOptions?.autofocusBehavior === 'editor'
@@ -75,7 +75,7 @@ const CompoundPredicateBuilder = ({ controller }: Props) => {
{predicate.keypath && (
<PredicateValue
keypath={predicate.keypath as PredicateKeypath}
value={predicate.value.toString()}
value={typeof predicate.value !== 'string' ? JSON.stringify(predicate.value) : predicate.value}
setValue={(value: string) => {
setPredicate(index, { value })
}}
@@ -0,0 +1,33 @@
import { useApplication } from '@/Components/ApplicationProvider'
import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext'
import { Platform } from '@standardnotes/snjs'
import { useEffect, useState } from 'react'
export default function AutoFocusPlugin({ isEnabled }: { isEnabled: boolean }) {
const application = useApplication()
const [editor] = useLexicalComposerContext()
const [didInitialFocus, setDidInitialFocus] = useState(false)
useEffect(() => {
if (!isEnabled) {
return
}
if (application.platform !== Platform.Ios) {
editor.focus()
return
}
return editor.registerUpdateListener(() => {
if (didInitialFocus) {
return
}
const rootElement = editor.getRootElement()
if (!rootElement) {
return
}
rootElement.focus()
setDidInitialFocus(true)
})
}, [application.platform, didInitialFocus, editor, isEnabled])
return null
}
@@ -43,6 +43,7 @@ import { useApplication } from '@/Components/ApplicationProvider'
import { GetRemoteImageBlock } from '../Blocks/RemoteImage'
import { InsertRemoteImageDialog } from '../RemoteImagePlugin/RemoteImagePlugin'
import LinkEditor from '../FloatingLinkEditorPlugin/LinkEditor'
import { FOCUSABLE_BUT_NOT_TABBABLE } from '@/Constants/Constants'
const MobileToolbarPlugin = () => {
const application = useApplication()
@@ -222,7 +223,8 @@ const MobileToolbarPlugin = () => {
const elementToBeFocused = event.relatedTarget as Node
const toolbarContainsElementToFocus = toolbarRef.current && toolbarRef.current.contains(elementToBeFocused)
const linkEditorContainsElementToFocus =
linkEditorRef.current && linkEditorRef.current.contains(elementToBeFocused)
linkEditorRef.current &&
(linkEditorRef.current.contains(elementToBeFocused) || elementToBeFocused === linkEditorRef.current)
const willFocusBackspaceButton = backspaceButtonRef.current && elementToBeFocused === backspaceButtonRef.current
if (toolbarContainsElementToFocus || linkEditorContainsElementToFocus || willFocusBackspaceButton) {
return
@@ -359,7 +361,11 @@ const MobileToolbarPlugin = () => {
{modal}
<div className="bg-contrast" id="super-mobile-toolbar">
{isSelectionLink && (
<div className="border-t border-border px-2" ref={linkEditorRef}>
<div
className="border-t border-border px-2 focus:outline-none focus:shadow-none"
ref={linkEditorRef}
tabIndex={FOCUSABLE_BUT_NOT_TABBABLE}
>
<LinkEditor
linkUrl={linkUrl}
isEditMode={isLinkEditMode}
@@ -39,7 +39,6 @@ import { SUPER_SHOW_MARKDOWN_PREVIEW } from '@standardnotes/ui-services'
import { SuperNoteMarkdownPreview } from './SuperNoteMarkdownPreview'
import { ExportPlugin } from './Plugins/ExportPlugin/ExportPlugin'
import GetMarkdownPlugin, { GetMarkdownPluginInterface } from './Plugins/GetMarkdownPlugin/GetMarkdownPlugin'
import { AutoFocusPlugin } from '@lexical/react/LexicalAutoFocusPlugin'
import { getPlaintextFontSize } from '@/Utils/getPlaintextFontSize'
import ReadonlyPlugin from './Plugins/ReadonlyPlugin/ReadonlyPlugin'
import { SuperSearchContextProvider } from './Plugins/SearchPlugin/Context'
@@ -49,6 +48,7 @@ import MobileToolbarPlugin from './Plugins/MobileToolbarPlugin/MobileToolbarPlug
import CodeOptionsPlugin from './Plugins/CodeOptionsPlugin/CodeOptions'
import RemoteImagePlugin from './Plugins/RemoteImagePlugin/RemoteImagePlugin'
import NotEntitledBanner from '../ComponentView/NotEntitledBanner'
import AutoFocusPlugin from './Plugins/AutoFocusPlugin'
export const SuperNotePreviewCharLimit = 160
@@ -242,7 +242,7 @@ export const SuperEditor: FunctionComponent<Props> = ({
<NodeObserverPlugin nodeType={FileNode} onRemove={handleBubbleRemove} />
<ExportPlugin />
<ReadonlyPlugin note={note.current} />
{controller.isTemplateNote ? <AutoFocusPlugin /> : null}
<AutoFocusPlugin isEnabled={controller.isTemplateNote} />
<SuperSearchContextProvider>
<SearchPlugin />
</SuperSearchContextProvider>
@@ -89,8 +89,8 @@ const U2FAuthIframe = () => {
if (!error) {
return
}
setError(error.toString())
console.error(error.toString())
setError(JSON.stringify(error))
console.error(error)
}
}, [source, username, apiHost])
@@ -34,10 +34,6 @@ import { SelectedItemsController } from '../SelectedItemsController'
import { NotesController } from '../NotesController/NotesController'
import { formatDateAndTimeForNote } from '@/Utils/DateUtils'
import dayjs from 'dayjs'
import dayjsAdvancedFormat from 'dayjs/plugin/advancedFormat'
dayjs.extend(dayjsAdvancedFormat)
import { AbstractViewController } from '../Abstract/AbstractViewController'
import { log, LoggingDomain } from '@/Logging'
import { NoteViewController } from '@/Components/NoteView/Controller/NoteViewController'
@@ -45,6 +41,7 @@ import { FileViewController } from '@/Components/NoteView/Controller/FileViewCon
import { TemplateNoteViewAutofocusBehavior } from '@/Components/NoteView/Controller/TemplateNoteViewControllerOptions'
import { ItemsReloadSource } from './ItemsReloadSource'
import { VaultDisplayServiceEvent } from '@standardnotes/ui-services'
import { getDayjsFormattedString } from '@/Utils/GetDayjsFormattedString'
const MinNoteCellHeight = 51.0
const DefaultListNumNotes = 20
@@ -671,7 +668,12 @@ export class ItemListController extends AbstractViewController implements Intern
this.navigationController.selected?.preferences?.customNoteTitleFormat ||
this.application.getPreference(PrefKey.CustomNoteTitleFormat, PrefDefaults[PrefKey.CustomNoteTitleFormat])
return dayjs(createdAt).format(customFormat)
try {
return getDayjsFormattedString(createdAt, customFormat)
} catch (error) {
console.error(error)
return formatDateAndTimeForNote(createdAt || new Date())
}
}
if (titleFormat === NewNoteTitleFormat.Empty) {
@@ -0,0 +1,18 @@
import dayjs from 'dayjs'
import AdvancedFormat from 'dayjs/plugin/advancedFormat'
import IsoWeek from 'dayjs/plugin/isoWeek'
import UTC from 'dayjs/plugin/utc'
import Timezone from 'dayjs/plugin/timezone'
import WeekYear from 'dayjs/plugin/weekYear'
import WeekOfYear from 'dayjs/plugin/weekOfYear'
dayjs.extend(AdvancedFormat)
dayjs.extend(IsoWeek)
dayjs.extend(UTC)
dayjs.extend(Timezone)
dayjs.extend(WeekYear)
dayjs.extend(WeekOfYear)
export function getDayjsFormattedString(date: Parameters<typeof dayjs>[0], format: string): string {
return dayjs(date).format(format)
}
+2 -2
View File
@@ -221,8 +221,8 @@ export const getBase64FromBlob = (blob: Blob) => {
return new Promise<string>((resolve, reject) => {
const reader = new FileReader()
reader.onloadend = () => {
if (reader.result) {
resolve(reader.result.toString())
if (reader.result && typeof reader.result === 'string') {
resolve(reader.result)
} else {
reject()
}
+3
View File
@@ -17,6 +17,9 @@ module.exports = (env, argv) => {
},
plugins: [new ReactRefreshWebpackPlugin()],
devServer: {
headers: {
'Access-Control-Allow-Origin': '*',
},
hot: true,
static: './dist',
port,
+2 -2
View File
@@ -5030,7 +5030,7 @@ __metadata:
circular-dependency-plugin: ^5.2.2
copy-webpack-plugin: ^11.0.0
css-loader: "*"
dayjs: ^1.11.7
dayjs: ^1.11.9
dotenv: ^16.0.3
eslint: "*"
eslint-config-prettier: ^8.9.0
@@ -9635,7 +9635,7 @@ __metadata:
languageName: node
linkType: hard
"dayjs@npm:^1.11.7, dayjs@npm:^1.8.15":
"dayjs@npm:^1.11.9, dayjs@npm:^1.8.15":
version: 1.11.9
resolution: "dayjs@npm:1.11.9"
checksum: a4844d83dc87f921348bb9b1b93af851c51e6f71fa259604809cfe1b49d1230e6b0212dab44d1cb01994c096ad3a77ea1cf18fa55154da6efcc9d3610526ac38