Compare commits

...
Author SHA1 Message Date
StandardNotes CI f6d0aa0f0a chore(release): publish
- @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].6
 - @standardnotes/[email protected].6
 - @standardnotes/[email protected].6
 - @standardnotes/[email protected].3
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].1
 - @standardnotes/[email protected].0
 - @standardnotes/[email protected].0
 - @standardnotes/[email protected].1
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].3
2022-09-28 15:16:53 +00:00
Aman Harwara eafa65e934 fix: grey flash on textarea focus on safari/webkit (#1661) 2022-09-28 20:11:03 +05:30
Mo a83003ee69 feat(crypto): pkc algos for key generation, encrypt, and decrypt (#1663) 2022-09-28 09:15:34 -05:00
StandardNotes CI 554f59a3fe chore(release): publish
- @standardnotes/[email protected]
 - @standardnotes/[email protected].2
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].2
2022-09-28 13:42:14 +00:00
Aman Harwara c0af596f2d fix: sticky header behavior on iOS (#1662) 2022-09-28 18:36:42 +05:30
StandardNotes CI 6e10911d02 chore(release): publish
- @standardnotes/[email protected]
 - @standardnotes/[email protected].1
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].1
2022-09-28 09:41:43 +00:00
Aman Harwara 9502a7fa32 fix: challenge modal 2022-09-28 14:30:31 +05:30
Aman Harwara 727d78cfe2 fix: webapp blanking because of mobileDevice check 2022-09-28 14:24:05 +05:30
StandardNotes CI 44bb4b7ca3 chore(release): publish
- @standardnotes/[email protected]
 - @standardnotes/[email protected].0
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].0
 - @standardnotes/[email protected].0
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].0
2022-09-28 07:19:59 +00:00
Aman Harwara 981d8a7497 feat: handle android back button on android (#1656) 2022-09-28 12:12:55 +05:30
StandardNotes CI 04245dfeeb chore(release): publish
- @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].0
2022-09-27 14:51:15 +00:00
Vardan HakobyanandMo 5db47e83e8 feat: delete account (#1653)
* feat: delete account

* fix: copy adjustments

Co-authored-by: Mo
2022-09-27 18:13:54 +04:00
StandardNotes CI c08602b7b8 chore(release): publish
- @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].0
2022-09-27 13:28:41 +00:00
Aman Harwara ec52e5684d feat: upgrade cta (#1655) 2022-09-27 18:29:50 +05:30
StandardNotes CI f3f7f9d362 chore(release): publish
- @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].3
2022-09-27 12:52:54 +00:00
Mo b9a07d8b5a fix(web): incorrect native access 2022-09-27 07:23:21 -05:00
StandardNotes CI 31213bf268 chore(release): publish
- @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].2
2022-09-27 11:20:27 +00:00
Aman Harwara 70e57e32b3 fix: don't hide note tags container on desktop 2022-09-27 16:19:06 +05:30
StandardNotes CI 720215eea7 chore(release): publish
- @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].5
 - @standardnotes/[email protected].6
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].1
2022-09-27 07:23:11 +00:00
Aman Harwara 6d5ebdeaa1 fix: export/sharing notes on mobile webview (#1644) 2022-09-27 12:24:44 +05:30
StandardNotes CI c99693876f chore(release): publish
- @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].0
2022-09-26 16:21:50 +00:00
Aman Harwara f8f6a5212b feat: sticky header on mobile if plaintext note is scrolled (#1645) 2022-09-26 21:15:11 +05:30
StandardNotes CI 58cd919267 chore(release): publish
- @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].1
2022-09-26 12:42:43 +00:00
Karol Sójko 507823dc4f fix(web): check for proper feature in the subscription sharing section 2022-09-26 14:12:01 +02:00
StandardNotes CI 6ea1def0cf chore(release): publish
- @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].0
2022-09-25 22:06:15 +00:00
Aman Harwara fe2ce9f1e8 feat: note tags button for mobile (#1641) 2022-09-26 02:58:55 +05:30
StandardNotes CI 4985787c5d chore(release): publish
- @standardnotes/[email protected]
 - @standardnotes/[email protected]
2022-09-25 16:08:44 +00:00
Aman Harwara 8614a638a4 fix(mobile): hide drawer on new mobile experience (#1642) 2022-09-25 21:04:04 +05:30
StandardNotes CI 15957c71cb chore(release): publish
- @standardnotes/[email protected]
 - @standardnotes/[email protected].9
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].3
2022-09-24 21:45:51 +00:00
Aman Harwara 59e814bcec fix: improve new note title format (#1640) 2022-09-24 16:18:06 -05:00
StandardNotes CI 4cf9ebf52a chore(release): publish
- @standardnotes/[email protected]
 - @standardnotes/[email protected].8
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].2
2022-09-24 19:32:22 +00:00
Aman Harwara a3611c802f fix: move prefs button next to account menu button in footer (#1639) 2022-09-25 00:33:30 +05:30
StandardNotes CI 9be315730d chore(release): publish
- @standardnotes/[email protected].7
 - @standardnotes/[email protected]
2022-09-24 17:28:41 +00:00
Mo 789a78bda3 fix(mobile): accurate version number 2022-09-24 11:58:29 -05:00
StandardNotes CI 73e170dedd chore(release): publish
- @standardnotes/[email protected]
 - @standardnotes/[email protected].6
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].1
2022-09-24 16:32:37 +00:00
Aman Harwara e4b1b64119 fix: responsiveness when resizing window on web/desktop (#1637) 2022-09-24 21:24:10 +05:30
StandardNotes CI c2a1918843 chore(release): publish
- @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].5
 - @standardnotes/[email protected].5
 - @standardnotes/[email protected].5
 - @standardnotes/[email protected].5
 - @standardnotes/[email protected].0
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].4
 - @standardnotes/[email protected].5
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].0
2022-09-24 11:03:09 +00:00
Aman Harwara d3621d70b1 feat: new note title format w/ prefs (#1629) 2022-09-24 16:04:31 +05:30
StandardNotes CI bf286f4854 chore(release): publish
- @standardnotes/[email protected]
 - @standardnotes/[email protected].4
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].0
2022-09-24 09:32:43 +00:00
Aman Harwara 97835e64ac feat: flatten quick settings menu and add separate prefs button (#1631) 2022-09-24 14:26:55 +05:30
StandardNotes CI 285df04a59 chore(release): publish
- @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].4
 - @standardnotes/[email protected].1
 - @standardnotes/[email protected].4
 - @standardnotes/[email protected].4
 - @standardnotes/[email protected].3
 - @standardnotes/[email protected].4
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].3
 - @standardnotes/[email protected].3
 - @standardnotes/[email protected].4
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].2
2022-09-23 19:29:51 +00:00
Mo 4d5429cc89 fix(mobile): adjust status bar color to match current theme (#1624)
* feat: sync page theme color metadata with active theme bg

* fix: lint

* refactor: extract to method

* feat: recieve theme scheme change on mobile

* fix: handle issue where status bar color changes when keyboard appears on iOS

* fix: disable bouncing on web view
2022-09-23 13:48:51 -05:00
StandardNotes CI da6622dc95 chore(release): publish
- @standardnotes/[email protected]
 - @standardnotes/[email protected].2
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].1
2022-09-23 18:23:20 +00:00
Aman Harwara a548883863 fix: prefs view on desktop (#1628) 2022-09-23 23:22:01 +05:30
StandardNotes CI 1330201d2e chore(release): publish
- @standardnotes/[email protected]
 - @standardnotes/[email protected].1
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].0
2022-09-23 17:16:32 +00:00
Aman Harwara 0af720146c feat: add prefs button to navigation panel on mobile (#1625) 2022-09-23 22:17:50 +05:30
StandardNotes CI 4d6992cf83 chore(release): publish
- @standardnotes/[email protected]
 - @standardnotes/[email protected].0
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].3
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].6
2022-09-23 15:54:05 +00:00
Aman Harwara 5de6f459c1 feat: sync page theme color metadata with active theme bg (#1623) 2022-09-23 20:53:00 +05:30
Mo 3c0d4fac76 fix: biometrics timing loading (#1622) 2022-09-23 09:59:16 -05:00
StandardNotes CI 4cdfcbfd95 chore(release): publish
- @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].5
2022-09-23 11:16:50 +00:00
Aman Harwara 51e50433d3 fix: protected overlay on mobile (#1621) 2022-09-23 16:16:04 +05:30
StandardNotes CI 696327ff03 chore(release): publish
- @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].4
2022-09-23 08:47:03 +00:00
Karol Sójko de64f1bfce fix(web): move email notification preferences to account pane (#1620) 2022-09-23 10:17:21 +02:00
StandardNotes CI 48d484675b chore(release): publish
- @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].3
2022-09-22 20:08:00 +00:00
Aman Harwara 86251b49d3 fix: better safe area padding on iOS (#1618) 2022-09-23 01:03:36 +05:30
StandardNotes CI 5961bc491d chore(release): publish
- @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].2
 - @standardnotes/[email protected].2
2022-09-22 18:54:43 +00:00
Karol Sójko e50f4eb92e Revert "Revert "feat(web): move emails notifications to one pane and enable opening settings via url (#1614)" (#1617)" (#1619)
This reverts commit 6824dd2d5f.
2022-09-22 20:18:19 +02:00
StandardNotes CI 4f8e75f36a chore(release): publish
- @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].1
 - @standardnotes/[email protected].1
2022-09-22 17:21:08 +00:00
Karol Sójko 6824dd2d5f Revert "feat(web): move emails notifications to one pane and enable opening settings via url (#1614)" (#1617)
This reverts commit 1fe833bc24.
2022-09-22 18:50:41 +02:00
Mo 76ec8b0f90 refactor: new mobile experience opt in flow (#1616)
* refactor: new mobile experience opt in flow

* chore: lint
2022-09-22 11:20:26 -05:00
StandardNotes CI 3eebdbb77d chore(release): publish
- @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].0
2022-09-22 15:22:42 +00:00
Aman Harwara ce252def33 feat: show selected editor icon in change editor button (#1615) 2022-09-22 20:22:49 +05:30
StandardNotes CI cb7af03ce8 chore(release): publish
- @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].0
 - @standardnotes/[email protected].0
2022-09-22 11:16:54 +00:00
Karol Sójko 1fe833bc24 feat(web): move emails notifications to one pane and enable opening settings via url (#1614)
* feat(web): move emails notifications to one pane and enable opening settings via url

* fix(web): rename notifications to email

* fix(snjs): add mute marketing emails to settings list options

* fix(web): linter issues
2022-09-22 12:40:08 +02:00
StandardNotes CI ac1f59cde7 chore(release): publish
- @standardnotes/[email protected]
 - @standardnotes/[email protected].9
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].1
2022-09-22 08:08:31 +00:00
Aman Harwara db4ceca10e fix: manage subscription button on mobile webview (#1613) 2022-09-22 13:10:15 +05:30
StandardNotes CI 0176f47fe7 chore(release): publish
- @standardnotes/[email protected]
 - @standardnotes/[email protected].8
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].0
2022-09-22 03:20:23 +00:00
Aman Harwara f281041221 feat: on mobile goto content tab after selecting revision (#1611) 2022-09-22 08:15:08 +05:30
StandardNotes CI ebd56cd5aa chore(release): publish
- @standardnotes/[email protected]
 - @standardnotes/[email protected].7
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].0
2022-09-21 19:32:23 +00:00
Aman Harwara 8fa566336c fix: iOS safe area using CSS (#1610) 2022-09-22 00:22:11 +05:30
Aman Harwara 9dfeac7489 fix: disable focus mode and dynamic panel switches on mobile (#1607) 2022-09-21 22:09:02 +05:30
Aman Harwara d1b71861ec feat: add lock button to navigation panel on mobile (#1609) 2022-09-21 21:40:32 +05:30
StandardNotes CI 766548f12d chore(release): publish
- @standardnotes/[email protected]
 - @standardnotes/[email protected].6
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].6
2022-09-21 15:42:20 +00:00
Aman Harwara 581a08cd09 fix: tag input auto-submitting when pressing space (#1608) 2022-09-21 20:39:29 +05:30
Aman Harwara ee0d44405d fix: revert webview alert changes (#1606) 2022-09-21 20:18:56 +05:30
Aman Harwara 1ae64dcac4 fix: iOS webview window size and padding (#1605) 2022-09-21 19:58:46 +05:30
StandardNotes CI 2be4fb4f83 chore(release): publish
- @standardnotes/[email protected]
 - @standardnotes/[email protected].5
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].0
 - @standardnotes/[email protected].5
2022-09-21 13:19:58 +00:00
Mo 271a8d1d70 fix(web): subscription sharing copy 2022-09-21 07:50:17 -05:00
Karol Sójko e809328fa8 feat(snjs): add retrieving web sockets token for establishing connection (#1602)
* feat(snjs): add retrieving web sockets token for establishing connection

* fix(snjs): imports

* fix(snjs): use only web sockets connection token

* fix(snjs): linter issue
2022-09-21 14:39:43 +02:00
StandardNotes CI 784cefa26f chore(release): publish
- @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].3
 - @standardnotes/[email protected].3
 - @standardnotes/[email protected].3
 - @standardnotes/[email protected].4
 - @standardnotes/[email protected].3
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].2
 - @standardnotes/[email protected].2
 - @standardnotes/[email protected].2
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].4
2022-09-20 17:45:27 +00:00
Mo c5e225d335 fix: move wrapped storage to unwrapped if not encrypted (#1603) 2022-09-20 12:18:00 -05:00
StandardNotes CI cb4c0f1b5c chore(release): publish
- @standardnotes/[email protected]
 - @standardnotes/[email protected].3
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].3
2022-09-20 14:32:24 +00:00
Aman Harwara 91d9364e95 fix: close menu & toggle notes list when note action occurs (#1601) 2022-09-20 19:33:14 +05:30
StandardNotes CI 023d1665b6 chore(release): publish
- @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].2
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].1
 - @standardnotes/[email protected].1
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].2
2022-09-20 11:59:06 +00:00
Karol Sójko 4a773fa537 feat(api): add websocket api definitions 2022-09-20 13:21:02 +02:00
Aman Harwara dd5ca0c28c fix: window size on mobile (#1600) 2022-09-20 16:48:03 +05:30
StandardNotes CI 9aa7bc018e chore(release): publish
- @standardnotes/[email protected]
 - @standardnotes/[email protected].1
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].1
2022-09-20 10:37:17 +00:00
Aman Harwara 571919c969 fix: default to notes list on launch on mobile (#1599) 2022-09-20 15:28:45 +05:30
StandardNotes CI 66a25c7556 chore(release): publish
- @standardnotes/[email protected]
 - @standardnotes/[email protected].0
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].0
 - @standardnotes/[email protected].0
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].0
2022-09-19 20:47:02 +00:00
Aman Harwara e3be17c7f8 fix: show warning on mobile webview before app quits (#1598) 2022-09-20 01:48:40 +05:30
Mo c4d7761496 feat: mobile web bridge (#1597) 2022-09-19 14:47:15 -05:00
StandardNotes CI f80cc5b822 chore(release): publish
- @standardnotes/[email protected]
 - @standardnotes/[email protected].3
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].3
2022-09-19 15:02:19 +00:00
Aman Harwara ecaa2a629f fix: preferences dropdown contrast and color (#1591) 2022-09-19 20:03:23 +05:30
StandardNotes CI 46f3e873a5 chore(release): publish
- @standardnotes/[email protected]
 - @standardnotes/[email protected].2
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].2
 - @standardnotes/[email protected].2
2022-09-19 13:17:25 +00:00
Karol Sójko 038320b2fd fix(snjs): pass unencrypted file size to comply with file service interface (#1595) 2022-09-19 14:36:53 +02:00
StandardNotes CI ee4a1acb9c chore(release): publish
- @standardnotes/[email protected]
 - @standardnotes/[email protected].1
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].1
2022-09-18 12:37:48 +00:00
Aman Harwara efe0c38462 fix: move save status next to note actions on mobile (#1590) 2022-09-18 17:37:30 +05:30
StandardNotes CI 4336c9ed66 chore(release): publish
- @standardnotes/[email protected]
 - @standardnotes/[email protected].0
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].0
2022-09-16 21:52:59 +00:00
Aman Harwara 85c90e07fc feat: add settings to fully switch between native/webview (#1587) 2022-09-17 02:52:38 +05:30
StandardNotes CI 146b3329e0 chore(release): publish
- @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].7
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].3
2022-09-16 18:15:47 +00:00
Mo 0c3c98d7af refactor(mobile): default to web frame if isDev (#1586)
* refactor(mobile): default to web frame if isDev

* fix: ignore native challenges

* fix: use contentInset for padding
2022-09-16 12:44:06 -05:00
StandardNotes CI 5a8752b95a chore(release): publish
- @standardnotes/[email protected]
 - @standardnotes/[email protected].6
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].2
2022-09-16 13:35:11 +00:00
Aman Harwara 7807fa34f3 fix: long titles on non-mobile view (#1575) 2022-09-16 18:35:43 +05:30
StandardNotes CI ddf4c97477 chore(release): publish
- @standardnotes/[email protected]
 - @standardnotes/[email protected].5
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].2
 - @standardnotes/[email protected].1
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].1
2022-09-15 18:43:48 +00:00
Aman Harwara 3a15142940 fix: biometrics input on mobile webview challenge modal (#1572) 2022-09-15 23:41:03 +05:30
StandardNotes CI 79518b6a5d chore(release): publish
- @standardnotes/[email protected]
 - @standardnotes/[email protected].4
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].0
 - @standardnotes/[email protected].0
2022-09-15 10:28:11 +00:00
Karol SójkoandAman Harwara 2d0ee10226 feat: sharing subscriptions UI (#1567)
* feat(web): add ui for subscription sharing

* fix(web): add missing triggers

* fix(snjs): setting authorization token on http service

* fix(web): add alert upon invite failure

* fix(web): display invitations list

* fix(web): canceling subscription invitations

* fix(web): fonts

* fix(web): linter issues

* fix: click event handler

* fix: styles

* feat: update styles

* feat: don't show bottom separator if all invites used

* fix(web): references to alert service

* fix(web): remove usebeforeunload

Co-authored-by: Aman Harwara <[email protected]>
2022-09-15 12:00:29 +02:00
213 changed files with 4908 additions and 1130 deletions
+18 -1
View File
@@ -1,2 +1,19 @@
node_modules
scripts
scripts
actions
.yarn
.vscode
.sass-cache
.husky
.github
.git
**/dist
**/coverage
**/node_modules
packages/components
packages/docs
packages/mobile/android
packages/mobile/ios
packages/mobile/html
packages/snjs/mocha
*.d.ts
+1 -1
View File
@@ -1,4 +1,4 @@
{
"extends": ["./node_modules/@standardnotes/config/src/.eslintrc"],
"ignorePatterns": [".eslintrc.js", "*.webpack.*.js", "webpack-defaults.js", "jest.config.js", "__mocks__"]
"ignorePatterns": [".eslintrc.js", "*.webpack.*.js", "webpack-defaults.js", "jest.config.js", "__mocks__", "**/**/coverage"]
}
+1
View File
@@ -1,2 +1,3 @@
node_modules
dist
coverage
+24
View File
@@ -3,6 +3,30 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.8.4](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-28)
**Note:** Version bump only for package @standardnotes/api
## [1.8.3](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-24)
**Note:** Version bump only for package @standardnotes/api
## [1.8.2](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-23)
**Note:** Version bump only for package @standardnotes/api
## [1.8.1](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-20)
### Bug Fixes
* move wrapped storage to unwrapped if not encrypted ([#1603](https://github.com/standardnotes/app/issues/1603)) ([c5e225d](https://github.com/standardnotes/app/commit/c5e225d335537257f44168b8ad05222afccb508a))
# [1.8.0](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-20)
### Features
* **api:** add websocket api definitions ([4a773fa](https://github.com/standardnotes/app/commit/4a773fa53796e17ce5df325ed7d40ba2cb686476))
## [1.7.2](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-15)
**Note:** Version bump only for package @standardnotes/api
+4 -4
View File
@@ -10,10 +10,10 @@ module.exports = {
},
coverageThreshold: {
global: {
branches: 17,
functions: 43,
lines: 46,
statements: 46
branches: 20,
functions: 66,
lines: 63,
statements: 63
}
}
};
+3 -2
View File
@@ -1,6 +1,6 @@
{
"name": "@standardnotes/api",
"version": "1.7.2",
"version": "1.8.4",
"engines": {
"node": ">=16.0.0 <17.0.0"
},
@@ -32,7 +32,8 @@
"eslint": "^8.23.0",
"eslint-plugin-prettier": "*",
"jest": "^28.1.2",
"ts-jest": "^28.0.5"
"ts-jest": "^28.0.5",
"typescript": "*"
},
"dependencies": {
"@standardnotes/common": "^1.32.0",
@@ -0,0 +1,3 @@
export enum WebSocketApiOperations {
CreatingConnectionToken,
}
@@ -0,0 +1,61 @@
import { WebSocketConnectionTokenResponse } from '../../Response'
import { WebSocketServerInterface } from '../../Server/WebSocket/WebSocketServerInterface'
import { WebSocketApiOperations } from './WebSocketApiOperations'
import { WebSocketApiService } from './WebSocketApiService'
describe('WebSocketApiService', () => {
let webSocketServer: WebSocketServerInterface
const createService = () => new WebSocketApiService(webSocketServer)
beforeEach(() => {
webSocketServer = {} as jest.Mocked<WebSocketServerInterface>
webSocketServer.createConnectionToken = jest.fn().mockReturnValue({
data: { token: 'foobar' },
} as jest.Mocked<WebSocketConnectionTokenResponse>)
})
it('should create a websocket connection token', async () => {
const response = await createService().createConnectionToken()
expect(response).toEqual({
data: {
token: 'foobar',
},
})
expect(webSocketServer.createConnectionToken).toHaveBeenCalledWith({})
})
it('should not create a token if it is already creating', async () => {
const service = createService()
Object.defineProperty(service, 'operationsInProgress', {
get: () => new Map([[WebSocketApiOperations.CreatingConnectionToken, true]]),
})
let error = null
try {
await service.createConnectionToken()
} catch (caughtError) {
error = caughtError
}
expect(error).not.toBeNull()
})
it('should not create a token if the server fails', async () => {
webSocketServer.createConnectionToken = jest.fn().mockImplementation(() => {
throw new Error('Oops')
})
let error = null
try {
await createService().createConnectionToken()
} catch (caughtError) {
error = caughtError
}
expect(error).not.toBeNull()
})
})
@@ -0,0 +1,33 @@
import { ErrorMessage } from '../../Error/ErrorMessage'
import { ApiCallError } from '../../Error/ApiCallError'
import { WebSocketApiServiceInterface } from './WebSocketApiServiceInterface'
import { WebSocketApiOperations } from './WebSocketApiOperations'
import { WebSocketServerInterface } from '../../Server'
import { WebSocketConnectionTokenResponse } from '../../Response'
export class WebSocketApiService implements WebSocketApiServiceInterface {
private operationsInProgress: Map<WebSocketApiOperations, boolean>
constructor(private webSocketServer: WebSocketServerInterface) {
this.operationsInProgress = new Map()
}
async createConnectionToken(): Promise<WebSocketConnectionTokenResponse> {
if (this.operationsInProgress.get(WebSocketApiOperations.CreatingConnectionToken)) {
throw new ApiCallError(ErrorMessage.GenericInProgress)
}
this.operationsInProgress.set(WebSocketApiOperations.CreatingConnectionToken, true)
try {
const response = await this.webSocketServer.createConnectionToken({})
this.operationsInProgress.set(WebSocketApiOperations.CreatingConnectionToken, false)
return response
} catch (error) {
throw new ApiCallError(ErrorMessage.GenericFail)
}
}
}
@@ -0,0 +1,5 @@
import { WebSocketConnectionTokenResponse } from '../../Response'
export interface WebSocketApiServiceInterface {
createConnectionToken(): Promise<WebSocketConnectionTokenResponse>
}
+2
View File
@@ -3,3 +3,5 @@ export * from './Subscription/SubscriptionApiService'
export * from './Subscription/SubscriptionApiServiceInterface'
export * from './User/UserApiService'
export * from './User/UserApiServiceInterface'
export * from './WebSocket/WebSocketApiService'
export * from './WebSocket/WebSocketApiServiceInterface'
@@ -0,0 +1,3 @@
export type WebSocketConnectionTokenRequestParams = {
[additionalParam: string]: unknown
}
+1
View File
@@ -5,3 +5,4 @@ export * from './Subscription/SubscriptionInviteDeclineRequestParams'
export * from './Subscription/SubscriptionInviteListRequestParams'
export * from './Subscription/SubscriptionInviteRequestParams'
export * from './User/UserRegistrationRequestParams'
export * from './WebSocket/WebSocketConnectionTokenRequestParams'
@@ -0,0 +1,9 @@
import { Either } from '@standardnotes/common'
import { HttpErrorResponseBody } from '../../Http/HttpErrorResponseBody'
import { HttpResponse } from '../../Http/HttpResponse'
import { WebSocketConnectionTokenResponseBody } from './WebSocketConnectionTokenResponseBody'
export interface WebSocketConnectionTokenResponse extends HttpResponse {
data: Either<WebSocketConnectionTokenResponseBody, HttpErrorResponseBody>
}
@@ -0,0 +1,3 @@
export type WebSocketConnectionTokenResponseBody = {
token: string
}
@@ -10,3 +10,5 @@ export * from './Subscription/SubscriptionInviteResponse'
export * from './Subscription/SubscriptionInviteResponseBody'
export * from './User/UserRegistrationResponse'
export * from './User/UserRegistrationResponseBody'
export * from './WebSocket/WebSocketConnectionTokenResponse'
export * from './WebSocket/WebSocketConnectionTokenResponseBody'
@@ -0,0 +1,9 @@
const TokenPaths = {
createConnectionToken: '/v1/sockets/tokens',
}
export const Paths = {
v1: {
...TokenPaths,
},
}
@@ -0,0 +1,27 @@
import { HttpServiceInterface } from '../../Http'
import { WebSocketConnectionTokenResponse } from '../../Response'
import { WebSocketServer } from './WebSocketServer'
describe('WebSocketServer', () => {
let httpService: HttpServiceInterface
const createServer = () => new WebSocketServer(httpService)
beforeEach(() => {
httpService = {} as jest.Mocked<HttpServiceInterface>
httpService.post = jest.fn().mockReturnValue({
data: { token: 'foobar' },
} as jest.Mocked<WebSocketConnectionTokenResponse>)
})
it('should create a websocket connection token', async () => {
const response = await createServer().createConnectionToken({})
expect(response).toEqual({
data: {
token: 'foobar',
},
})
})
})
@@ -0,0 +1,17 @@
import { HttpServiceInterface } from '../../Http/HttpServiceInterface'
import { WebSocketConnectionTokenRequestParams } from '../../Request/WebSocket/WebSocketConnectionTokenRequestParams'
import { WebSocketConnectionTokenResponse } from '../../Response/WebSocket/WebSocketConnectionTokenResponse'
import { Paths } from './Paths'
import { WebSocketServerInterface } from './WebSocketServerInterface'
export class WebSocketServer implements WebSocketServerInterface {
constructor(private httpService: HttpServiceInterface) {}
async createConnectionToken(
params: WebSocketConnectionTokenRequestParams,
): Promise<WebSocketConnectionTokenResponse> {
const response = await this.httpService.post(Paths.v1.createConnectionToken, params)
return response as WebSocketConnectionTokenResponse
}
}
@@ -0,0 +1,6 @@
import { WebSocketConnectionTokenRequestParams } from '../../Request/WebSocket/WebSocketConnectionTokenRequestParams'
import { WebSocketConnectionTokenResponse } from '../../Response/WebSocket/WebSocketConnectionTokenResponse'
export interface WebSocketServerInterface {
createConnectionToken(params: WebSocketConnectionTokenRequestParams): Promise<WebSocketConnectionTokenResponse>
}
+2
View File
@@ -2,3 +2,5 @@ export * from './Subscription/SubscriptionServer'
export * from './Subscription/SubscriptionServerInterface'
export * from './User/UserServer'
export * from './User/UserServerInterface'
export * from './WebSocket/WebSocketServer'
export * from './WebSocket/WebSocketServerInterface'
+1
View File
@@ -0,0 +1 @@
dist
+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.7.14](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-23)
**Note:** Version bump only for package @standardnotes/components-meta
## [2.7.13](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-16)
**Note:** Version bump only for package @standardnotes/components-meta
## [2.7.12](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-13)
**Note:** Version bump only for package @standardnotes/components-meta
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@standardnotes/components-meta",
"version": "2.7.12",
"version": "2.7.14",
"private": true,
"author": "Standard Notes.",
"main": "dist",
+3
View File
@@ -0,0 +1,3 @@
node_modules
dist
jsign
+186
View File
@@ -3,6 +3,192 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [3.23.169](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-28)
**Note:** Version bump only for package @standardnotes/desktop
## [3.23.168](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-28)
**Note:** Version bump only for package @standardnotes/desktop
## [3.23.167](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-28)
**Note:** Version bump only for package @standardnotes/desktop
## [3.23.166](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-28)
**Note:** Version bump only for package @standardnotes/desktop
## [3.23.165](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-27)
**Note:** Version bump only for package @standardnotes/desktop
## [3.23.164](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-27)
**Note:** Version bump only for package @standardnotes/desktop
## [3.23.163](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-27)
**Note:** Version bump only for package @standardnotes/desktop
## [3.23.162](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-27)
**Note:** Version bump only for package @standardnotes/desktop
## [3.23.161](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-27)
**Note:** Version bump only for package @standardnotes/desktop
## [3.23.160](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-26)
**Note:** Version bump only for package @standardnotes/desktop
## [3.23.159](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-26)
**Note:** Version bump only for package @standardnotes/desktop
## [3.23.158](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-25)
**Note:** Version bump only for package @standardnotes/desktop
## [3.23.157](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-24)
**Note:** Version bump only for package @standardnotes/desktop
## [3.23.156](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-24)
**Note:** Version bump only for package @standardnotes/desktop
## [3.23.155](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-24)
**Note:** Version bump only for package @standardnotes/desktop
## [3.23.154](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-24)
**Note:** Version bump only for package @standardnotes/desktop
## [3.23.153](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-24)
**Note:** Version bump only for package @standardnotes/desktop
## [3.23.152](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-23)
**Note:** Version bump only for package @standardnotes/desktop
## [3.23.151](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-23)
**Note:** Version bump only for package @standardnotes/desktop
## [3.23.150](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-23)
**Note:** Version bump only for package @standardnotes/desktop
## [3.23.149](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-23)
**Note:** Version bump only for package @standardnotes/desktop
## [3.23.148](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-23)
**Note:** Version bump only for package @standardnotes/desktop
## [3.23.147](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-23)
**Note:** Version bump only for package @standardnotes/desktop
## [3.23.146](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-22)
**Note:** Version bump only for package @standardnotes/desktop
## [3.23.145](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-22)
**Note:** Version bump only for package @standardnotes/desktop
## [3.23.144](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-22)
**Note:** Version bump only for package @standardnotes/desktop
## [3.23.143](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-22)
**Note:** Version bump only for package @standardnotes/desktop
## [3.23.142](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-22)
**Note:** Version bump only for package @standardnotes/desktop
## [3.23.141](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-22)
**Note:** Version bump only for package @standardnotes/desktop
## [3.23.140](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-22)
**Note:** Version bump only for package @standardnotes/desktop
## [3.23.139](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-21)
**Note:** Version bump only for package @standardnotes/desktop
## [3.23.138](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-21)
**Note:** Version bump only for package @standardnotes/desktop
## [3.23.137](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-21)
**Note:** Version bump only for package @standardnotes/desktop
## [3.23.136](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-20)
### Bug Fixes
* move wrapped storage to unwrapped if not encrypted ([#1603](https://github.com/standardnotes/app/issues/1603)) ([c5e225d](https://github.com/standardnotes/app/commit/c5e225d335537257f44168b8ad05222afccb508a))
## [3.23.135](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-20)
**Note:** Version bump only for package @standardnotes/desktop
## [3.23.134](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-20)
**Note:** Version bump only for package @standardnotes/desktop
## [3.23.133](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-20)
**Note:** Version bump only for package @standardnotes/desktop
## [3.23.132](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-19)
**Note:** Version bump only for package @standardnotes/desktop
## [3.23.131](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-19)
**Note:** Version bump only for package @standardnotes/desktop
## [3.23.130](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-19)
**Note:** Version bump only for package @standardnotes/desktop
## [3.23.129](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-18)
**Note:** Version bump only for package @standardnotes/desktop
## [3.23.128](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-16)
**Note:** Version bump only for package @standardnotes/desktop
## [3.23.127](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-16)
**Note:** Version bump only for package @standardnotes/desktop
## [3.23.126](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-16)
**Note:** Version bump only for package @standardnotes/desktop
## [3.23.125](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-15)
**Note:** Version bump only for package @standardnotes/desktop
## [3.23.124](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-15)
**Note:** Version bump only for package @standardnotes/desktop
## [3.23.123](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-15)
**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.23.123",
"version": "3.23.169",
"license": "AGPL-3.0-or-later",
"author": "Standard Notes.",
"private": true,
+16
View File
@@ -3,6 +3,22 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.15.6](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-28)
**Note:** Version bump only for package @standardnotes/encryption
## [1.15.5](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-24)
**Note:** Version bump only for package @standardnotes/encryption
## [1.15.4](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-23)
**Note:** Version bump only for package @standardnotes/encryption
## [1.15.3](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-20)
**Note:** Version bump only for package @standardnotes/encryption
## [1.15.2](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-15)
**Note:** Version bump only for package @standardnotes/encryption
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@standardnotes/encryption",
"version": "1.15.2",
"version": "1.15.6",
"engines": {
"node": ">=16.0.0 <17.0.0"
},
+6
View File
@@ -3,6 +3,12 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.52.1](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-23)
### Bug Fixes
* **mobile:** adjust status bar color to match current theme ([#1624](https://github.com/standardnotes/app/issues/1624)) ([4d5429c](https://github.com/standardnotes/app/commit/4d5429cc89c15f870825f20e97844825102c6aec))
# [1.52.0](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-13)
### Features
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@standardnotes/features",
"version": "1.52.0",
"version": "1.52.1",
"engines": {
"node": ">=16.0.0 <17.0.0"
},
@@ -72,6 +72,7 @@ export type ThemeFeatureDescription = ComponentFeatureDescription & {
/** Some themes can be layered on top of other themes */
layerable?: boolean
dock_icon?: ThemeDockIcon
isDark?: boolean
}
export type FeatureDescription = BaseFeatureDescription &
@@ -12,6 +12,7 @@ export function themes(): ThemeFeatureDescription[] {
permission_name: PermissionName.MidnightTheme,
description: 'Elegant utilitarianism.',
thumbnail_url: 'https://s3.amazonaws.com/standard-notes/screenshots/models/themes/midnight-with-mobile.jpg',
isDark: true,
dock_icon: {
type: 'circle',
background_color: '#086DD6',
@@ -27,6 +28,7 @@ export function themes(): ThemeFeatureDescription[] {
permission_name: PermissionName.FuturaTheme,
description: 'Calm and relaxed. Take some time off.',
thumbnail_url: 'https://s3.amazonaws.com/standard-notes/screenshots/models/themes/futura-with-mobile.jpg',
isDark: true,
dock_icon: {
type: 'circle',
background_color: '#fca429',
@@ -42,6 +44,7 @@ export function themes(): ThemeFeatureDescription[] {
permission_name: PermissionName.SolarizedDarkTheme,
description: 'The perfect theme for any time.',
thumbnail_url: 'https://s3.amazonaws.com/standard-notes/screenshots/models/themes/solarized-dark.jpg',
isDark: true,
dock_icon: {
type: 'circle',
background_color: '#2AA198',
@@ -72,6 +75,7 @@ export function themes(): ThemeFeatureDescription[] {
permission_name: PermissionName.FocusedTheme,
description: 'For when you need to go in.',
thumbnail_url: 'https://s3.amazonaws.com/standard-notes/screenshots/models/themes/focus-with-mobile.jpg',
isDark: true,
dock_icon: {
type: 'circle',
background_color: '#a464c2',
+16
View File
@@ -3,6 +3,22 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.23.6](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-28)
**Note:** Version bump only for package @standardnotes/filepicker
## [1.23.5](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-24)
**Note:** Version bump only for package @standardnotes/filepicker
## [1.23.4](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-23)
**Note:** Version bump only for package @standardnotes/filepicker
## [1.23.3](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-20)
**Note:** Version bump only for package @standardnotes/filepicker
## [1.23.2](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-15)
**Note:** Version bump only for package @standardnotes/filepicker
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@standardnotes/filepicker",
"version": "1.23.2",
"version": "1.23.6",
"engines": {
"node": ">=16.0.0 <17.0.0"
},
+16
View File
@@ -3,6 +3,22 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.10.6](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-28)
**Note:** Version bump only for package @standardnotes/files
## [1.10.5](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-24)
**Note:** Version bump only for package @standardnotes/files
## [1.10.4](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-23)
**Note:** Version bump only for package @standardnotes/files
## [1.10.3](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-20)
**Note:** Version bump only for package @standardnotes/files
## [1.10.2](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-15)
**Note:** Version bump only for package @standardnotes/files
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@standardnotes/files",
"version": "1.10.2",
"version": "1.10.6",
"engines": {
"node": ">=16.0.0 <17.0.0"
},
+8 -2
View File
@@ -1,3 +1,9 @@
metro.config.js
packages/mobile/html/Web.bundle/src/components
packages/mobile/html/Web.bundle/src/web-src
html/**/*
node_modules
ios
e2e
android
fastlane
WebFrame
__tests__
+216
View File
@@ -3,6 +3,222 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [3.37.3](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-28)
**Note:** Version bump only for package @standardnotes/mobile
## [3.37.2](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-28)
**Note:** Version bump only for package @standardnotes/mobile
## [3.37.1](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-28)
**Note:** Version bump only for package @standardnotes/mobile
# [3.37.0](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-28)
### Features
* handle android back button on android ([#1656](https://github.com/standardnotes/app/issues/1656)) ([981d8a7](https://github.com/standardnotes/app/commit/981d8a7497ea2600e1535ad9170cb5559550ca4d))
## [3.36.18](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-27)
**Note:** Version bump only for package @standardnotes/mobile
## [3.36.17](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-27)
**Note:** Version bump only for package @standardnotes/mobile
## [3.36.16](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-27)
**Note:** Version bump only for package @standardnotes/mobile
## [3.36.15](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-27)
**Note:** Version bump only for package @standardnotes/mobile
## [3.36.14](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-27)
### Bug Fixes
* export/sharing notes on mobile webview ([#1644](https://github.com/standardnotes/app/issues/1644)) ([6d5ebde](https://github.com/standardnotes/app/commit/6d5ebdeaa1777f31878b6e7d4dfc33fe83abc9fc))
## [3.36.13](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-26)
**Note:** Version bump only for package @standardnotes/mobile
## [3.36.12](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-26)
**Note:** Version bump only for package @standardnotes/mobile
## [3.36.11](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-25)
**Note:** Version bump only for package @standardnotes/mobile
## [3.36.10](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-25)
### Bug Fixes
* **mobile:** hide drawer on new mobile experience ([#1642](https://github.com/standardnotes/app/issues/1642)) ([8614a63](https://github.com/standardnotes/app/commit/8614a638a4bfc8fdf97020bf1fc147c62998cf3b))
## [3.36.9](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-24)
**Note:** Version bump only for package @standardnotes/mobile
## [3.36.8](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-24)
**Note:** Version bump only for package @standardnotes/mobile
## [3.36.7](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-24)
### Bug Fixes
* **mobile:** accurate version number ([789a78b](https://github.com/standardnotes/app/commit/789a78bda33f12d214c12a63ae27d2ba0f39feab))
## [3.36.6](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-24)
**Note:** Version bump only for package @standardnotes/mobile
## [3.36.5](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-24)
**Note:** Version bump only for package @standardnotes/mobile
## [3.36.4](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-24)
**Note:** Version bump only for package @standardnotes/mobile
## [3.36.3](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-23)
### Bug Fixes
* **mobile:** adjust status bar color to match current theme ([#1624](https://github.com/standardnotes/app/issues/1624)) ([4d5429c](https://github.com/standardnotes/app/commit/4d5429cc89c15f870825f20e97844825102c6aec))
## [3.36.2](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-23)
**Note:** Version bump only for package @standardnotes/mobile
## [3.36.1](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-23)
**Note:** Version bump only for package @standardnotes/mobile
# [3.36.0](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-23)
### Features
* sync page theme color metadata with active theme bg ([#1623](https://github.com/standardnotes/app/issues/1623)) ([5de6f45](https://github.com/standardnotes/app/commit/5de6f459c106127f294693389f62fa1c3ed57798))
## [3.35.16](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-23)
**Note:** Version bump only for package @standardnotes/mobile
## [3.35.15](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-23)
**Note:** Version bump only for package @standardnotes/mobile
## [3.35.14](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-22)
**Note:** Version bump only for package @standardnotes/mobile
## [3.35.13](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-22)
**Note:** Version bump only for package @standardnotes/mobile
## [3.35.12](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-22)
**Note:** Version bump only for package @standardnotes/mobile
## [3.35.11](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-22)
**Note:** Version bump only for package @standardnotes/mobile
## [3.35.10](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-22)
**Note:** Version bump only for package @standardnotes/mobile
## [3.35.9](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-22)
**Note:** Version bump only for package @standardnotes/mobile
## [3.35.8](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-22)
**Note:** Version bump only for package @standardnotes/mobile
## [3.35.7](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-21)
### Bug Fixes
* iOS safe area using CSS ([#1610](https://github.com/standardnotes/app/issues/1610)) ([8fa5663](https://github.com/standardnotes/app/commit/8fa566336ceef8a3d7b559b1aaf342f7c51f21cd))
## [3.35.6](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-21)
### Bug Fixes
* iOS webview window size and padding ([#1605](https://github.com/standardnotes/app/issues/1605)) ([1ae64dc](https://github.com/standardnotes/app/commit/1ae64dcac4cc714f8931b2301fce1cb802570862))
## [3.35.5](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-21)
**Note:** Version bump only for package @standardnotes/mobile
## [3.35.4](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-20)
### Bug Fixes
* move wrapped storage to unwrapped if not encrypted ([#1603](https://github.com/standardnotes/app/issues/1603)) ([c5e225d](https://github.com/standardnotes/app/commit/c5e225d335537257f44168b8ad05222afccb508a))
## [3.35.3](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-20)
**Note:** Version bump only for package @standardnotes/mobile
## [3.35.2](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-20)
**Note:** Version bump only for package @standardnotes/mobile
## [3.35.1](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-20)
**Note:** Version bump only for package @standardnotes/mobile
# [3.35.0](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-19)
### Features
* mobile web bridge ([#1597](https://github.com/standardnotes/app/issues/1597)) ([c4d7761](https://github.com/standardnotes/app/commit/c4d776149677269bc766f24da6adc5ec816dbcfb))
## [3.34.3](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-19)
**Note:** Version bump only for package @standardnotes/mobile
## [3.34.2](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-19)
**Note:** Version bump only for package @standardnotes/mobile
## [3.34.1](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-18)
**Note:** Version bump only for package @standardnotes/mobile
# [3.34.0](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-16)
### Features
* add settings to fully switch between native/webview ([#1587](https://github.com/standardnotes/app/issues/1587)) ([85c90e0](https://github.com/standardnotes/app/commit/85c90e07fc8b1ce66eaa88df09f2728ac0fecf1c))
## [3.33.7](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-16)
**Note:** Version bump only for package @standardnotes/mobile
## [3.33.6](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-16)
**Note:** Version bump only for package @standardnotes/mobile
## [3.33.5](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-15)
### Bug Fixes
* biometrics input on mobile webview challenge modal ([#1572](https://github.com/standardnotes/app/issues/1572)) ([3a15142](https://github.com/standardnotes/app/commit/3a15142940ef9391868442e1997c3d9d5eec33be))
## [3.33.4](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-15)
**Note:** Version bump only for package @standardnotes/mobile
## [3.33.3](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-15)
**Note:** Version bump only for package @standardnotes/mobile
@@ -4,7 +4,8 @@
<head>
<meta charset="utf-8" />
<meta content="IE=edge" http-equiv="X-UA-Compatible" />
<meta content="width=device-width, initial-scale=1" name="viewport" />
<meta content="viewport-fit=cover, width=device-width, initial-scale=1" name="viewport" />
<meta content="#ffffff" name="theme-color" />
<link rel="stylesheet" href="web-src/app.css" />
<script>
window.defaultSyncServer = "https://api.standardnotes.com";
@@ -22,4 +23,4 @@
<body>
</body>
</html>
</html>
+5 -3
View File
@@ -1,10 +1,12 @@
import { IsMobileWeb } from '@Lib/Utils'
import { MobileWebApp } from '@Root/MobileWebApp'
import { SNLog } from '@standardnotes/snjs'
import { AppRegistry } from 'react-native'
import 'react-native-gesture-handler'
import { enableScreens } from 'react-native-screens'
import 'react-native-url-polyfill/auto'
import { name as appName } from './app.json'
import { App } from './src/App'
import { NativeApp } from './src/NativeApp'
import { enableAndroidFontFix } from './src/Style/android_text_fix'
enableScreens()
@@ -28,11 +30,11 @@ console.warn = function filterWarnings(msg) {
"[react-native-gesture-handler] Seems like you're using an old API with gesture components",
]
if (!supressedWarnings.some(entry => msg.includes(entry))) {
if (!supressedWarnings.some((entry) => msg.includes(entry))) {
originalWarn.apply(console, arguments)
}
}
enableAndroidFontFix()
AppRegistry.registerComponent(appName, () => App)
AppRegistry.registerComponent(appName, () => (IsMobileWeb ? MobileWebApp : NativeApp))
+2 -2
View File
@@ -1,6 +1,6 @@
{
"name": "@standardnotes/mobile",
"version": "3.33.3",
"version": "3.37.3",
"author": "Standard Notes.",
"private": true,
"license": "AGPL-3.0-or-later",
@@ -69,7 +69,7 @@
"react-native-screens": "3.13.1",
"react-native-search-bar": "standardnotes/react-native-search-bar#7d2139daf9b7663b570403f21f520deceba9bb09",
"react-native-search-box": "standardnotes/react-native-search-box#8c46369912cba78dca718588aca9c16926953ff7",
"react-native-share": "^7.3.7",
"react-native-share": "^7.9.0",
"react-native-sodium-jsi": "1.2.0",
"react-native-static-server": "standardnotes/react-native-static-server#28ef0175dbee3db9aadfab57498497067556a836",
"react-native-store-review": "^0.2.0",
@@ -0,0 +1,21 @@
import { AbstractService, InternalEventBus, ReactNativeToWebEvent } from '@standardnotes/snjs'
import { BackHandler, NativeEventSubscription } from 'react-native'
export class AndroidBackHandlerService extends AbstractService<ReactNativeToWebEvent> {
private removeListener: NativeEventSubscription
constructor() {
const internalEventBus = new InternalEventBus()
super(internalEventBus)
this.removeListener = BackHandler.addEventListener('hardwareBackPress', () => {
void this.notifyEvent(ReactNativeToWebEvent.AndroidBackButtonPressed)
return true
})
}
deinit() {
this.removeListener.remove()
}
}
+20 -29
View File
@@ -2,18 +2,18 @@ import { AppStateEventType, AppStateType, TabletModeChangeData } from '@Lib/Appl
import { AlwaysOpenWebAppOnLaunchKey } from '@Lib/constants'
import { useHasEditor, useIsLocked } from '@Lib/SnjsHelperHooks'
import { ScreenStatus } from '@Lib/StatusManager'
import { IsDev } from '@Lib/Utils'
import { CompositeNavigationProp, RouteProp, useNavigation } from '@react-navigation/native'
import { IsMobileWeb } from '@Lib/Utils'
import { CompositeNavigationProp, RouteProp } from '@react-navigation/native'
import { createStackNavigator, StackNavigationProp } from '@react-navigation/stack'
import { HeaderTitleView } from '@Root/Components/HeaderTitleView'
import { IoniconsHeaderButton } from '@Root/Components/IoniconsHeaderButton'
import { Compose } from '@Root/Screens/Compose/Compose'
import { SCREEN_COMPOSE, SCREEN_NOTES, SCREEN_VIEW_PROTECTED_NOTE, SCREEN_WEB_APP } from '@Root/Screens/screens'
import { SCREEN_COMPOSE, SCREEN_NOTES, SCREEN_VIEW_PROTECTED_NOTE } from '@Root/Screens/screens'
import { MainSideMenu } from '@Root/Screens/SideMenu/MainSideMenu'
import { NoteSideMenu } from '@Root/Screens/SideMenu/NoteSideMenu'
import { ViewProtectedNote } from '@Root/Screens/ViewProtectedNote/ViewProtectedNote'
import { Root } from '@Screens/Root'
import { ApplicationEvent, StorageValueModes, UuidString } from '@standardnotes/snjs'
import { StorageValueModes, UuidString } from '@standardnotes/snjs'
import { ICON_MENU } from '@Style/Icons'
import { ThemeService } from '@Style/ThemeService'
import { getDefaultDrawerWidth } from '@Style/Utils'
@@ -22,13 +22,10 @@ import { Dimensions, Keyboard, ScaledSize } from 'react-native'
import DrawerLayout, { DrawerState } from 'react-native-gesture-handler/DrawerLayout'
import { HeaderButtons, Item } from 'react-navigation-header-buttons'
import { ThemeContext } from 'styled-components'
import { HeaderTitleParams } from './App'
import { ApplicationContext } from './ApplicationContext'
import { MobileWebAppContainer } from './MobileWebAppContainer'
import { ModalStackNavigationProp } from './ModalStack'
const IS_DEBUGGING_WEB_APP = false
const DEFAULT_TO_WEB_APP = IsDev && IS_DEBUGGING_WEB_APP
import { HeaderTitleParams } from './NativeApp'
export type AppStackNavigatorParamList = {
[SCREEN_NOTES]: HeaderTitleParams
@@ -124,27 +121,20 @@ export const AppStackComponent = (props: ModalStackNavigationProp<'AppStack'>) =
[application],
)
const navigation = useNavigation<ModalStackNavigationProp<'AppStack'>['navigation']>()
const shouldOpenWebApp = application?.getValue(AlwaysOpenWebAppOnLaunchKey, StorageValueModes.Nonwrapped) as boolean
useEffect(() => {
if (!application) {
return
}
const removeObserver = application.addEventObserver(async (event) => {
if (event === ApplicationEvent.Launched) {
const value = (await application.getValue(AlwaysOpenWebAppOnLaunchKey, StorageValueModes.Nonwrapped)) as
| boolean
| undefined
const shouldAlwaysOpenWebAppOnLaunch = value ?? false
if (shouldAlwaysOpenWebAppOnLaunch) {
navigation.push(SCREEN_WEB_APP)
}
}
})
return removeObserver
}, [application, navigation])
if (IsMobileWeb || shouldOpenWebApp) {
return (
<AppStack.Navigator
screenOptions={() => ({
headerShown: false,
})}
initialRouteName={SCREEN_NOTES}
>
<AppStack.Screen name={SCREEN_NOTES} component={MobileWebAppContainer} />
</AppStack.Navigator>
)
}
return (
<DrawerLayout
@@ -185,6 +175,7 @@ export const AppStackComponent = (props: ModalStackNavigationProp<'AppStack'>) =
name={SCREEN_NOTES}
options={({ route }) => ({
title: 'All notes',
headerShown: !shouldOpenWebApp,
headerTitle: ({ children }) => {
const screenStatus = isInTabletMode ? composeStatus || notesStatus : notesStatus
@@ -224,7 +215,7 @@ export const AppStackComponent = (props: ModalStackNavigationProp<'AppStack'>) =
</HeaderButtons>
),
})}
component={DEFAULT_TO_WEB_APP ? MobileWebAppContainer : Root}
component={shouldOpenWebApp ? MobileWebAppContainer : Root}
/>
<AppStack.Screen
name={SCREEN_COMPOSE}
@@ -0,0 +1,62 @@
import { AbstractService, InternalEventBus, ReactNativeToWebEvent } from '@standardnotes/snjs'
import { AppState, AppStateStatus, NativeEventSubscription } from 'react-native'
export class AppStateObserverService extends AbstractService<ReactNativeToWebEvent> {
private mostRecentState?: ReactNativeToWebEvent
private removeListener: NativeEventSubscription
private ignoringStateChanges = false
constructor() {
const bus = new InternalEventBus()
super(bus)
this.removeListener = AppState.addEventListener('change', async (nextAppState: AppStateStatus) => {
if (this.ignoringStateChanges) {
return
}
// if the most recent state is not 'background' ('inactive'), then we're going
// from inactive to active, which doesn't really happen unless you, say, swipe
// notification center in iOS down then back up. We don't want to lock on this state change.
const isResuming = nextAppState === 'active'
const isResumingFromBackground = isResuming && this.mostRecentState === ReactNativeToWebEvent.EnteringBackground
const isEnteringBackground = nextAppState === 'background'
const isLosingFocus = nextAppState === 'inactive'
if (isEnteringBackground) {
this.notifyStateChange(ReactNativeToWebEvent.EnteringBackground)
}
if (isResumingFromBackground || isResuming) {
if (isResumingFromBackground) {
this.notifyStateChange(ReactNativeToWebEvent.ResumingFromBackground)
}
// Notify of GainingFocus even if resuming from background
this.notifyStateChange(ReactNativeToWebEvent.GainingFocus)
return
}
if (isLosingFocus) {
this.notifyStateChange(ReactNativeToWebEvent.LosingFocus)
}
})
}
beginIgnoringStateChanges() {
this.ignoringStateChanges = true
}
stopIgnoringStateChanges() {
this.ignoringStateChanges = false
}
deinit() {
this.removeListener.remove()
}
private notifyStateChange(state: ReactNativeToWebEvent): void {
this.mostRecentState = state
void this.notifyEvent(state)
}
}
+1 -1
View File
@@ -12,7 +12,7 @@ import React, { useContext } from 'react'
import { Platform } from 'react-native'
import { HeaderButtons, Item } from 'react-navigation-header-buttons'
import { ThemeContext } from 'styled-components'
import { HeaderTitleParams } from './App'
import { HeaderTitleParams } from './NativeApp'
type HistoryStackNavigatorParamList = {
[SCREEN_NOTE_HISTORY]: (HeaderTitleParams & { noteUuid: string }) | (undefined & { noteUuid: string })
+10 -3
View File
@@ -13,6 +13,7 @@ import {
platformFromString,
SNApplication,
SNComponentManager,
StorageValueModes,
} from '@standardnotes/snjs'
import { Platform } from 'react-native'
@@ -21,15 +22,16 @@ import { MobileAlertService } from './AlertService'
import { ApplicationState } from './ApplicationState'
import { BackupsService } from './BackupsService'
import { ComponentManager } from './ComponentManager'
import { AlwaysOpenWebAppOnLaunchKey } from './constants'
import { FilesService } from './FilesService'
import { InstallationService } from './InstallationService'
import { MobileDeviceInterface } from './Interface'
import { MobileDevice } from './Interface'
import { push } from './NavigationService'
import { PreferencesManager } from './PreferencesManager'
import { SNReactNativeCrypto } from './ReactNativeCrypto'
import { ReviewService } from './ReviewService'
import { StatusManager } from './StatusManager'
import { IsDev } from './Utils'
import { IsDev, IsMobileWeb } from './Utils'
type MobileServices = {
applicationState: ApplicationState
@@ -52,7 +54,7 @@ export class MobileApplication extends SNApplication {
static previouslyLaunched = false
constructor(deviceInterface: MobileDeviceInterface, identifier: string) {
constructor(deviceInterface: MobileDevice, identifier: string) {
super({
environment: Environment.Mobile,
platform: platformFromString(Platform.OS),
@@ -135,6 +137,11 @@ export class MobileApplication extends SNApplication {
}
promptForChallenge(challenge: Challenge) {
const optedIntoWebPreview = this.getValue(AlwaysOpenWebAppOnLaunchKey, StorageValueModes.Nonwrapped) as boolean
if (IsMobileWeb || optedIntoWebPreview) {
return
}
push(SCREEN_AUTHENTICATE, { challenge, title: challenge.modalTitle })
}
+3 -3
View File
@@ -4,14 +4,14 @@ import { ApplicationState } from './ApplicationState'
import { BackupsService } from './BackupsService'
import { FilesService } from './FilesService'
import { InstallationService } from './InstallationService'
import { MobileDeviceInterface } from './Interface'
import { MobileDevice } from './Interface'
import { PreferencesManager } from './PreferencesManager'
import { ReviewService } from './ReviewService'
import { StatusManager } from './StatusManager'
export class ApplicationGroup extends SNApplicationGroup {
constructor() {
super(new MobileDeviceInterface())
super(new MobileDevice())
}
override async initialize(_callback?: any): Promise<void> {
@@ -21,7 +21,7 @@ export class ApplicationGroup extends SNApplicationGroup {
}
private createApplication = async (descriptor: ApplicationDescriptor, deviceInterface: DeviceInterface) => {
const application = new MobileApplication(deviceInterface as MobileDeviceInterface, descriptor.identifier)
const application = new MobileApplication(deviceInterface as MobileDevice, descriptor.identifier)
const internalEventBus = new InternalEventBus()
const applicationState = new ApplicationState(application)
const reviewService = new ReviewService(application, internalEventBus)
+37 -36
View File
@@ -1,4 +1,4 @@
import { MobileDeviceInterface } from '@Lib/Interface'
import { MobileDevice } from '@Lib/Interface'
import {
ApplicationEvent,
ApplicationService,
@@ -169,9 +169,7 @@ export class ApplicationState extends ApplicationService {
override async onAppLaunch() {
MobileApplication.setPreviouslyLaunched()
this.screenshotPrivacyEnabled = (await this.getScreenshotPrivacyEnabled()) ?? true
await (this.application.deviceInterface as MobileDeviceInterface).setAndroidScreenshotPrivacy(
this.screenshotPrivacyEnabled,
)
await (this.application.deviceInterface as MobileDevice).setAndroidScreenshotPrivacy(this.screenshotPrivacyEnabled)
}
/**
@@ -480,28 +478,35 @@ export class ApplicationState extends ApplicationService {
private async checkAndLockApplication() {
const isLocked = await this.application.isLocked()
if (!isLocked) {
const hasBiometrics = await this.application.hasBiometrics()
const hasPasscode = this.application.hasPasscode()
if (hasPasscode && this.passcodeTiming === MobileUnlockTiming.Immediately) {
await this.application.lock()
} else if (hasBiometrics && this.biometricsTiming === MobileUnlockTiming.Immediately && !this.locked) {
const challenge = new Challenge(
[new ChallengePrompt(ChallengeValidation.Biometric)],
ChallengeReason.ApplicationUnlock,
false,
)
void this.application.promptForCustomChallenge(challenge)
this.locked = true
this.notifyLockStateObservers(LockStateType.Locked)
this.application.addChallengeObserver(challenge, {
onComplete: () => {
this.locked = false
this.notifyLockStateObservers(LockStateType.Unlocked)
},
})
}
if (isLocked) {
return
}
const hasBiometrics = this.application.hasBiometrics()
const hasPasscode = this.application.hasPasscode()
const passcodeLockImmediately = hasPasscode && this.passcodeTiming === MobileUnlockTiming.Immediately
const biometricsLockImmediately =
hasBiometrics && this.biometricsTiming === MobileUnlockTiming.Immediately && !this.locked
if (passcodeLockImmediately) {
await this.application.lock()
} else if (biometricsLockImmediately) {
const challenge = new Challenge(
[new ChallengePrompt(ChallengeValidation.Biometric)],
ChallengeReason.ApplicationUnlock,
false,
)
void this.application.promptForCustomChallenge(challenge)
this.locked = true
this.notifyLockStateObservers(LockStateType.Locked)
this.application.addChallengeObserver(challenge, {
onComplete: () => {
this.locked = false
this.notifyLockStateObservers(LockStateType.Unlocked)
},
})
}
}
@@ -565,35 +570,31 @@ export class ApplicationState extends ApplicationService {
).includes(state)
}
private async getScreenshotPrivacyEnabled(): Promise<boolean | undefined> {
private async getScreenshotPrivacyEnabled(): Promise<boolean> {
return this.application.getMobileScreenshotPrivacyEnabled()
}
private async getPasscodeTiming(): Promise<MobileUnlockTiming | undefined> {
return this.application.getValue(StorageKey.MobilePasscodeTiming, StorageValueModes.Nonwrapped) as Promise<
MobileUnlockTiming | undefined
>
return this.application.getMobilePasscodeTiming()
}
private async getBiometricsTiming(): Promise<MobileUnlockTiming | undefined> {
return this.application.getValue(StorageKey.MobileBiometricsTiming, StorageValueModes.Nonwrapped) as Promise<
MobileUnlockTiming | undefined
>
return this.application.getMobileBiometricsTiming()
}
public async setScreenshotPrivacyEnabled(enabled: boolean) {
await this.application.setMobileScreenshotPrivacyEnabled(enabled)
this.screenshotPrivacyEnabled = enabled
await (this.application.deviceInterface as MobileDeviceInterface).setAndroidScreenshotPrivacy(enabled)
await (this.application.deviceInterface as MobileDevice).setAndroidScreenshotPrivacy(enabled)
}
public async setPasscodeTiming(timing: MobileUnlockTiming) {
await this.application.setValue(StorageKey.MobilePasscodeTiming, timing, StorageValueModes.Nonwrapped)
this.application.setValue(StorageKey.MobilePasscodeTiming, timing, StorageValueModes.Nonwrapped)
this.passcodeTiming = timing
}
public async setBiometricsTiming(timing: MobileUnlockTiming) {
await this.application.setValue(StorageKey.MobileBiometricsTiming, timing, StorageValueModes.Nonwrapped)
this.application.setValue(StorageKey.MobileBiometricsTiming, timing, StorageValueModes.Nonwrapped)
this.biometricsTiming = timing
}
@@ -605,7 +606,7 @@ export class ApplicationState extends ApplicationService {
}
public async setPasscodeKeyboardType(type: PasscodeKeyboardType) {
await this.application.setValue(MobileStorageKey.PasscodeKeyboardTypeKey, type, StorageValueModes.Nonwrapped)
this.application.setValue(MobileStorageKey.PasscodeKeyboardTypeKey, type, StorageValueModes.Nonwrapped)
}
public onDrawerOpen() {
@@ -1,6 +1,6 @@
import SNReactNative from '@standardnotes/react-native-utils'
import { ApplicationService, ButtonType, StorageValueModes } from '@standardnotes/snjs'
import { MobileDeviceInterface } from './Interface'
import { MobileDevice } from './Interface'
const FIRST_RUN_KEY = 'first_run'
@@ -23,7 +23,7 @@ export class InstallationService extends ApplicationService {
*/
async needsWipe() {
const hasAccountOrPasscode = this.application.hasAccount() || this.application?.hasPasscode()
const deviceInterface = this.application.deviceInterface as MobileDeviceInterface
const deviceInterface = this.application.deviceInterface as MobileDevice
const keychainKey = await deviceInterface.getNamespacedKeychainValue(this.application.identifier)
const hasKeychainValue = keychainKey != undefined
+245 -9
View File
@@ -1,22 +1,44 @@
import AsyncStorage from '@react-native-community/async-storage'
import { AndroidBackHandlerService } from '@Root/AndroidBackHandlerService'
import SNReactNative from '@standardnotes/react-native-utils'
import {
ApplicationIdentifier,
DeviceInterface,
Environment,
LegacyMobileKeychainStructure,
LegacyRawKeychainValue,
MobileDeviceInterface,
NamespacedRootKeyInKeychain,
Platform as SNPlatform,
RawKeychainValue,
removeFromArray,
TransferPayload,
} from '@standardnotes/snjs'
import { Alert, Linking, Platform } from 'react-native'
import { Alert, Linking, PermissionsAndroid, Platform, StatusBar } from 'react-native'
import FingerprintScanner from 'react-native-fingerprint-scanner'
import FlagSecure from 'react-native-flag-secure-android'
import {
CachesDirectoryPath,
DocumentDirectoryPath,
DownloadDirectoryPath,
exists,
unlink,
writeFile,
} from 'react-native-fs'
import { hide, show } from 'react-native-privacy-snapshot'
import Share from 'react-native-share'
import { AppStateObserverService } from './../AppStateObserverService'
import Keychain from './Keychain'
import { SNReactNativeCrypto } from './ReactNativeCrypto'
import { IsMobileWeb } from './Utils'
export type BiometricsType = 'Fingerprint' | 'Face ID' | 'Biometrics' | 'Touch ID'
export enum MobileDeviceEvent {
RequestsWebViewReload = 0,
}
type MobileDeviceEventHandler = (event: MobileDeviceEvent) => void
/**
* This identifier was the database name used in Standard Notes web/desktop.
*/
@@ -52,11 +74,31 @@ const showLoadFailForItemIds = (failedItemIds: string[]) => {
Alert.alert('Unable to load item(s)', text)
}
export class MobileDeviceInterface implements DeviceInterface {
export class MobileDevice implements MobileDeviceInterface {
environment: Environment.Mobile = Environment.Mobile
platform: SNPlatform.Ios | SNPlatform.Android = Platform.OS === 'ios' ? SNPlatform.Ios : SNPlatform.Android
private eventObservers: MobileDeviceEventHandler[] = []
public isDarkMode = false
private crypto: SNReactNativeCrypto
// eslint-disable-next-line @typescript-eslint/no-empty-function
deinit() {}
constructor(
private stateObserverService?: AppStateObserverService,
private androidBackHandlerService?: AndroidBackHandlerService,
) {
this.crypto = new SNReactNativeCrypto()
}
deinit() {
this.stateObserverService?.deinit()
;(this.stateObserverService as unknown) = undefined
this.androidBackHandlerService?.deinit()
;(this.androidBackHandlerService as unknown) = undefined
}
consoleLog(...args: any[]): void {
// eslint-disable-next-line no-console
console.log(args)
}
async setLegacyRawKeychainValue(value: LegacyRawKeychainValue): Promise<void> {
await Keychain.setKeys(value)
@@ -177,6 +219,14 @@ export class MobileDeviceInterface implements DeviceInterface {
}
}
hideMobileInterfaceFromScreenshots(): void {
hide()
}
stopHidingMobileInterfaceFromScreenshots(): void {
show()
}
async getAllRawStorageKeyValues() {
const keys = await AsyncStorage.getAllKeys()
return this.getRawStorageKeyValues(keys)
@@ -288,15 +338,74 @@ export class MobileDeviceInterface implements DeviceInterface {
}
}
getRawKeychainValue(): Promise<RawKeychainValue | null | undefined> {
return Keychain.getKeys()
async authenticateWithBiometrics() {
this.stateObserverService?.beginIgnoringStateChanges()
const result = await new Promise<boolean>((resolve) => {
if (Platform.OS === 'android') {
FingerprintScanner.authenticate({
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore ts type does not exist for deviceCredentialAllowed
deviceCredentialAllowed: true,
description: 'Biometrics are required to access your notes.',
})
.then(() => {
FingerprintScanner.release()
resolve(true)
})
.catch((error) => {
FingerprintScanner.release()
if (error.name === 'DeviceLocked') {
Alert.alert('Unsuccessful', 'Authentication failed. Wait 30 seconds to try again.')
} else {
Alert.alert('Unsuccessful', 'Authentication failed. Tap to try again.')
}
resolve(false)
})
} else {
// iOS
FingerprintScanner.authenticate({
fallbackEnabled: true,
description: 'This is required to access your notes.',
})
.then(() => {
FingerprintScanner.release()
resolve(true)
})
.catch((error_1) => {
FingerprintScanner.release()
if (error_1.name !== 'SystemCancel') {
if (error_1.name !== 'UserCancel') {
Alert.alert('Unsuccessful')
} else {
Alert.alert('Unsuccessful', 'Authentication failed. Tap to try again.')
}
}
resolve(false)
})
}
})
this.stateObserverService?.stopIgnoringStateChanges()
return result
}
async getRawKeychainValue(): Promise<RawKeychainValue | undefined> {
const result = await Keychain.getKeys()
if (result === null) {
return undefined
}
return result
}
async clearRawKeychainValue(): Promise<void> {
await Keychain.clearKeys()
}
async setAndroidScreenshotPrivacy(enable: boolean): Promise<void> {
setAndroidScreenshotPrivacy(enable: boolean): void {
if (Platform.OS === 'android') {
enable ? FlagSecure.activate() : FlagSecure.deactivate()
}
@@ -328,7 +437,37 @@ export class MobileDeviceInterface implements DeviceInterface {
}
performSoftReset() {
SNReactNative.exitApp()
if (IsMobileWeb) {
this.notifyEvent(MobileDeviceEvent.RequestsWebViewReload)
} else {
SNReactNative.exitApp()
}
}
addMobileWebEventReceiver(handler: MobileDeviceEventHandler): () => void {
this.eventObservers.push(handler)
const thislessObservers = this.eventObservers
return () => {
removeFromArray(thislessObservers, handler)
}
}
handleThemeSchemeChange(isDark: boolean): void {
this.isDarkMode = isDark
this.reloadStatusBarStyle()
}
reloadStatusBarStyle(animated = true) {
StatusBar.setBarStyle(this.isDarkMode ? 'light-content' : 'dark-content', animated)
}
private notifyEvent(event: MobileDeviceEvent): void {
for (const handler of this.eventObservers) {
handler(event)
}
}
// eslint-disable-next-line @typescript-eslint/no-empty-function
@@ -337,4 +476,101 @@ export class MobileDeviceInterface implements DeviceInterface {
isDeviceDestroyed() {
return false
}
async deleteFileAtPathIfExists(path: string) {
if (await exists(path)) {
await unlink(path)
}
}
async shareBase64AsFile(base64: string, filename: string) {
let downloadedTempFilePath: string | undefined
try {
downloadedTempFilePath = await this.downloadBase64AsFile(base64, filename, true)
if (!downloadedTempFilePath) {
return
}
await Share.open({
url: `file://${downloadedTempFilePath}`,
failOnCancel: false,
})
} catch (error) {
this.consoleLog(`${error}`)
} finally {
if (downloadedTempFilePath) {
void this.deleteFileAtPathIfExists(downloadedTempFilePath)
}
}
}
getFileDestinationPath(filename: string, saveInTempLocation: boolean): string {
let directory = DocumentDirectoryPath
if (Platform.OS === 'android') {
directory = saveInTempLocation ? CachesDirectoryPath : DownloadDirectoryPath
}
return `${directory}/${filename}`
}
async hasStoragePermissionOnAndroid(): Promise<boolean> {
if (Platform.OS !== 'android') {
return true
}
const grantedStatus = await PermissionsAndroid.request(PermissionsAndroid.PERMISSIONS.WRITE_EXTERNAL_STORAGE)
if (grantedStatus === PermissionsAndroid.RESULTS.GRANTED) {
return true
}
Alert.alert(
'Storage permissions are required in order to download files. Please accept the permissions prompt and try again.',
)
return false
}
async downloadBase64AsFile(
base64: string,
filename: string,
saveInTempLocation = false,
): Promise<string | undefined> {
const isGrantedStoragePermissionOnAndroid = await this.hasStoragePermissionOnAndroid()
if (!isGrantedStoragePermissionOnAndroid) {
return
}
try {
const path = this.getFileDestinationPath(filename, saveInTempLocation)
void this.deleteFileAtPathIfExists(path)
const decodedContents = this.crypto.base64Decode(base64.replace(/data.*base64,/, ''))
await writeFile(path, decodedContents)
return path
} catch (error) {
this.consoleLog(`${error}`)
}
}
confirmAndExit() {
Alert.alert(
'Close app',
'Do you want to close the app?',
[
{
text: 'Cancel',
style: 'cancel',
// eslint-disable-next-line @typescript-eslint/no-empty-function
onPress: async () => {},
},
{
text: 'Close',
style: 'destructive',
onPress: async () => {
SNReactNative.exitApp()
},
},
],
{
cancelable: true,
},
)
}
}
+2 -1
View File
@@ -1,7 +1,8 @@
import { TEnvironment } from '@Root/App'
import { TEnvironment } from '@Root/NativeApp'
import VersionInfo from 'react-native-version-info'
export const IsDev = VersionInfo.bundleIdentifier?.includes('dev')
export const IsMobileWeb = IsDev
export function isNullOrUndefined(value: unknown) {
return value === null || value === undefined
+16
View File
@@ -0,0 +1,16 @@
import { navigationRef } from '@Lib/NavigationService'
import { NavigationContainer } from '@react-navigation/native'
import React from 'react'
import { MobileWebMainStackComponent } from './ModalStack'
const AppComponent: React.FC = () => {
return (
<NavigationContainer ref={navigationRef}>
<MobileWebMainStackComponent />
</NavigationContainer>
)
}
export const MobileWebApp = () => {
return <AppComponent />
}
+105 -26
View File
@@ -1,13 +1,75 @@
import { MobileDeviceInterface } from '@Lib/Interface'
import React, { useMemo, useRef } from 'react'
import { Platform } from 'react-native'
import { MobileDevice, MobileDeviceEvent } from '@Lib/Interface'
import { IsDev } from '@Lib/Utils'
import { ReactNativeToWebEvent } from '@standardnotes/snjs'
import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react'
import { Keyboard, Platform } from 'react-native'
import VersionInfo from 'react-native-version-info'
import { WebView, WebViewMessageEvent } from 'react-native-webview'
import pjson from '../package.json'
import { AndroidBackHandlerService } from './AndroidBackHandlerService'
import { AppStateObserverService } from './AppStateObserverService'
const LoggingEnabled = IsDev
export const MobileWebAppContainer = () => {
const [identifier, setIdentifier] = useState(Math.random())
const destroyAndReload = useCallback(() => {
setIdentifier(Math.random())
}, [])
return <MobileWebAppContents key={`${identifier}`} destroyAndReload={destroyAndReload} />
}
const MobileWebAppContents = ({ destroyAndReload }: { destroyAndReload: () => void }) => {
const webViewRef = useRef<WebView>(null)
const sourceUri = (Platform.OS === 'android' ? 'file:///android_asset/' : '') + 'Web.bundle/src/index.html'
const webViewRef = useRef<WebView>(null)
const stateService = useMemo(() => new AppStateObserverService(), [])
const androidBackHandlerService = useMemo(() => new AndroidBackHandlerService(), [])
const device = useMemo(
() => new MobileDevice(stateService, androidBackHandlerService),
[androidBackHandlerService, stateService],
)
useEffect(() => {
const removeStateServiceListener = stateService.addEventObserver((event: ReactNativeToWebEvent) => {
webViewRef.current?.postMessage(JSON.stringify({ reactNativeEvent: event, messageType: 'event' }))
})
const removeBackHandlerServiceListener = androidBackHandlerService.addEventObserver(
(event: ReactNativeToWebEvent) => {
webViewRef.current?.postMessage(JSON.stringify({ reactNativeEvent: event, messageType: 'event' }))
},
)
const keyboardShowListener = Keyboard.addListener('keyboardWillShow', () => {
device.reloadStatusBarStyle(false)
})
const keyboardHideListener = Keyboard.addListener('keyboardDidHide', () => {
device.reloadStatusBarStyle(false)
})
return () => {
removeStateServiceListener()
removeBackHandlerServiceListener()
keyboardShowListener.remove()
keyboardHideListener.remove()
}
}, [webViewRef, stateService, device, androidBackHandlerService])
useEffect(() => {
const observer = device.addMobileWebEventReceiver((event) => {
if (event === MobileDeviceEvent.RequestsWebViewReload) {
destroyAndReload()
}
})
return () => {
observer()
}
}, [device, destroyAndReload])
const device = useMemo(() => new MobileDeviceInterface(), [])
const functions = Object.getOwnPropertyNames(Object.getPrototypeOf(device))
const baselineFunctions: Record<string, any> = {
@@ -28,7 +90,7 @@ export const MobileWebAppContainer = () => {
stringFunctions += `
${functionName}(...args) {
return this.sendMessage('${functionName}', args);
return this.askReactNativeToInvokeInterfaceMethod('${functionName}', args);
}
`
}
@@ -36,16 +98,17 @@ export const MobileWebAppContainer = () => {
const WebProcessDeviceInterface = `
class WebProcessDeviceInterface {
constructor(messageSender) {
this.appVersion = '1.2.3'
this.appVersion = '${pjson.version} (${VersionInfo.buildVersion})'
this.environment = 4
this.platform = ${device.platform}
this.databases = []
this.messageSender = messageSender
}
setApplication() {}
sendMessage(functionName, args) {
return this.messageSender.sendMessage(functionName, args)
askReactNativeToInvokeInterfaceMethod(functionName, args) {
return this.messageSender.askReactNativeToInvokeInterfaceMethod(functionName, args)
}
${stringFunctions}
@@ -56,26 +119,18 @@ export const MobileWebAppContainer = () => {
class WebProcessMessageSender {
constructor() {
this.pendingMessages = []
window.addEventListener('message', this.handleMessageFromReactNative.bind(this))
document.addEventListener('message', this.handleMessageFromReactNative.bind(this))
}
handleMessageFromReactNative(event) {
const message = event.data
try {
const parsed = JSON.parse(message)
const { messageId, returnValue } = parsed
const pendingMessage = this.pendingMessages.find((m) => m.messageId === messageId)
pendingMessage.resolve(returnValue)
this.pendingMessages.splice(this.pendingMessages.indexOf(pendingMessage), 1)
} catch (error) {
console.log('Error parsing message from React Native', message, error)
}
handleReplyFromReactNative( messageId, returnValue) {
const pendingMessage = this.pendingMessages.find((m) => m.messageId === messageId)
pendingMessage.resolve(returnValue)
this.pendingMessages.splice(this.pendingMessages.indexOf(pendingMessage), 1)
}
sendMessage(functionName, args) {
askReactNativeToInvokeInterfaceMethod(functionName, args) {
const messageId = Math.random()
window.ReactNativeWebView.postMessage(JSON.stringify({ functionName: functionName, args: args, messageId }))
return new Promise((resolve) => {
this.pendingMessages.push({
messageId,
@@ -98,6 +153,25 @@ export const MobileWebAppContainer = () => {
const messageSender = new WebProcessMessageSender();
window.reactNativeDevice = new WebProcessDeviceInterface(messageSender);
const handleMessageFromReactNative = (event) => {
const message = event.data
try {
const parsed = JSON.parse(message)
const { messageId, returnValue, messageType } = parsed
if (messageType === 'reply') {
messageSender.handleReplyFromReactNative(messageId, returnValue)
}
} catch (error) {
console.log('Error parsing message from React Native', message, error)
}
}
window.addEventListener('message', handleMessageFromReactNative)
document.addEventListener('message', handleMessageFromReactNative)
true;
`
@@ -107,14 +181,18 @@ export const MobileWebAppContainer = () => {
const functionData = JSON.parse(message)
void onFunctionMessage(functionData.functionName, functionData.messageId, functionData.args)
} catch (error) {
console.log('onGeneralMessage', JSON.stringify(message))
if (LoggingEnabled) {
console.log('onGeneralMessage', JSON.stringify(message))
}
}
}
const onFunctionMessage = async (functionName: string, messageId: string, args: any) => {
const returnValue = await (device as any)[functionName](...args)
console.log(`Native device function ${functionName} called`)
webViewRef.current?.postMessage(JSON.stringify({ messageId, returnValue }))
if (LoggingEnabled) {
console.log(`Native device function ${functionName} called`)
}
webViewRef.current?.postMessage(JSON.stringify({ messageId, returnValue, messageType: 'reply' }))
}
/* eslint-disable @typescript-eslint/no-empty-function */
@@ -130,6 +208,7 @@ export const MobileWebAppContainer = () => {
allowFileAccess={true}
allowUniversalAccessFromFileURLs={true}
injectedJavaScriptBeforeContentLoaded={injectedJS}
bounces={false}
/>
)
/* eslint-enable @typescript-eslint/no-empty-function */
+26 -2
View File
@@ -30,11 +30,11 @@ import React, { memo, useContext } from 'react'
import { Platform } from 'react-native'
import { HeaderButtons, Item } from 'react-navigation-header-buttons'
import { ThemeContext } from 'styled-components'
import { HeaderTitleParams, TEnvironment } from './App'
import { ApplicationContext } from './ApplicationContext'
import { AppStackComponent } from './AppStack'
import { HistoryStack } from './HistoryStack'
import { MobileWebAppContainer } from './MobileWebAppContainer'
import { HeaderTitleParams, TEnvironment } from './NativeApp'
export type ModalStackNavigatorParamList = {
AppStack: undefined
@@ -75,7 +75,31 @@ export type ModalStackNavigationProp<T extends keyof ModalStackNavigatorParamLis
const MainStack = createStackNavigator<ModalStackNavigatorParamList>()
export const MainStackComponent = ({ env }: { env: TEnvironment }) => {
export const MobileWebMainStackComponent = () => {
const MemoizedAppStackComponent = memo((props: ModalStackNavigationProp<'AppStack'>) => (
<AppStackComponent {...props} />
))
return (
<MainStack.Navigator
screenOptions={{
gestureEnabled: false,
presentation: 'modal',
}}
initialRouteName="AppStack"
>
<MainStack.Screen
name={'AppStack'}
options={{
headerShown: false,
}}
component={MemoizedAppStackComponent}
/>
</MainStack.Navigator>
)
}
export const NativeMainStackComponent = ({ env }: { env: TEnvironment }) => {
const application = useContext(ApplicationContext)
const theme = useContext(ThemeContext)
@@ -9,10 +9,9 @@ import { MobileThemeVariables } from '@Root/Style/Themes/styled-components'
import { ApplicationGroupEvent, DeinitMode, DeinitSource } from '@standardnotes/snjs'
import { ThemeService, ThemeServiceContext } from '@Style/ThemeService'
import React, { useCallback, useEffect, useRef, useState } from 'react'
import { StatusBar } from 'react-native'
import { ThemeProvider } from 'styled-components/native'
import { ApplicationContext } from './ApplicationContext'
import { MainStackComponent } from './ModalStack'
import { NativeMainStackComponent } from './ModalStack'
export type HeaderTitleParams = {
title?: string
@@ -107,13 +106,12 @@ const AppComponent: React.FC<{
}}
ref={navigationRef}
>
<StatusBar translucent />
{themeService.current && (
<>
<ThemeProvider theme={activeTheme}>
<ActionSheetProvider>
<ThemeServiceContext.Provider value={themeService.current}>
<MainStackComponent env={env} />
<NativeMainStackComponent env={env} />
</ThemeServiceContext.Provider>
</ActionSheetProvider>
<ToastWrapper />
@@ -124,7 +122,7 @@ const AppComponent: React.FC<{
)
}
export const App = (props: { env: TEnvironment }) => {
export const NativeApp = (props: { env: TEnvironment }) => {
const [application, setApplication] = useState<MobileApplication | undefined>()
const createNewAppGroup = useCallback(() => {
@@ -1,5 +1,5 @@
import { AppStateType, PasscodeKeyboardType } from '@Lib/ApplicationState'
import { MobileDeviceInterface } from '@Lib/Interface'
import { MobileDevice } from '@Lib/Interface'
import { HeaderHeightContext } from '@react-navigation/elements'
import { useFocusEffect } from '@react-navigation/native'
import { ApplicationContext } from '@Root/ApplicationContext'
@@ -164,7 +164,7 @@ export const Authenticate = ({
}, [])
const checkForBiometrics = useCallback(
async () => (application?.deviceInterface as MobileDeviceInterface).getDeviceBiometricsAvailability(),
async () => (application?.deviceInterface as MobileDevice).getDeviceBiometricsAvailability(),
[application],
)
@@ -0,0 +1,69 @@
import { AlwaysOpenWebAppOnLaunchKey } from '@Lib/constants'
import { ApplicationContext } from '@Root/ApplicationContext'
import { ButtonCell } from '@Root/Components/ButtonCell'
import { SectionHeader } from '@Root/Components/SectionHeader'
import { TableSection } from '@Root/Components/TableSection'
import { ButtonType, StorageValueModes } from '@standardnotes/snjs'
import React, { useContext } from 'react'
import styled from 'styled-components/native'
import { Label } from './CompanySection.styled'
import { BaseView, StyledSectionedTableCell } from './EncryptionSection.styled'
const Title = styled.Text`
color: ${({ theme }) => theme.stylekitForegroundColor};
font-size: 16px;
font-weight: bold;
`
export const NewMobileSection = () => {
const application = useContext(ApplicationContext)
if (!application) {
return <></>
}
const optIn = async () => {
const confirmationText =
'This will close the app and switch to the new mobile experience next time you open it. You will be able to switch back to the soon-to-be removed classic experience from the settings.'
if (
await application.alertService.confirm(
confirmationText,
'Switch To New Mobile Experience?',
'Switch',
ButtonType.Info,
)
) {
application.setValue(AlwaysOpenWebAppOnLaunchKey, true, StorageValueModes.Nonwrapped)
setTimeout(() => application.deviceInterface.performSoftReset(), 1000)
}
}
return (
<TableSection>
<SectionHeader title={'New Mobile Experience'} />
<StyledSectionedTableCell last={true} first={true}>
<BaseView>
<Title>🎉 New Mobile Experience Preview</Title>
<Label>
The new mobile experience (MX) brings the desktop experience you've come to love right here on your mobile
device. This mode will replace the existing classic mobile experience soon. You can opt in below to begin
using the new MX now.
</Label>
</BaseView>
</StyledSectionedTableCell>
<ButtonCell leftAligned={true} title="Opt In to New Mobile Experience" onPress={optIn}></ButtonCell>
<ButtonCell
leftAligned={true}
title="Read Blog Post"
onPress={() => {
application?.deviceInterface!.openUrl(
'https://blog.standardnotes.com/38384/our-new-mobile-experience-is-launching-soon',
)
}}
></ButtonCell>
</TableSection>
)
}
@@ -1,4 +1,3 @@
import { AlwaysOpenWebAppOnLaunchKey } from '@Lib/constants'
import { useSignedIn } from '@Lib/SnjsHelperHooks'
import { useNavigation } from '@react-navigation/native'
import { ButtonCell } from '@Root/Components/ButtonCell'
@@ -8,10 +7,10 @@ import { SectionHeader } from '@Root/Components/SectionHeader'
import { TableSection } from '@Root/Components/TableSection'
import { useSafeApplicationContext } from '@Root/Hooks/useSafeApplicationContext'
import { ModalStackNavigationProp } from '@Root/ModalStack'
import { SCREEN_MANAGE_SESSIONS, SCREEN_SETTINGS, SCREEN_WEB_APP } from '@Root/Screens/screens'
import { ButtonType, PrefKey, StorageValueModes } from '@standardnotes/snjs'
import { SCREEN_MANAGE_SESSIONS, SCREEN_SETTINGS } from '@Root/Screens/screens'
import { ButtonType, PrefKey } from '@standardnotes/snjs'
import moment from 'moment'
import React, { useCallback, useEffect, useMemo, useState } from 'react'
import React, { useCallback, useMemo, useState } from 'react'
import { Platform } from 'react-native'
import DocumentPicker from 'react-native-document-picker'
import RNFS from 'react-native-fs'
@@ -183,22 +182,6 @@ export const OptionsSection = ({ title, encryptionAvailable }: Props) => {
)
}, [application.alertService])
const [shouldAlwaysOpenWebAppOnLaunch, setShouldAlwaysOpenWebAppOnLaunch] = useState(false)
useEffect(() => {
const getSetting = async () => {
const value = (await application.getValue(AlwaysOpenWebAppOnLaunchKey, StorageValueModes.Nonwrapped)) as
| boolean
| undefined
setShouldAlwaysOpenWebAppOnLaunch(value ?? false)
}
void getSetting()
}, [application])
const openWebApp = useCallback(() => {
navigation.push(SCREEN_WEB_APP)
}, [navigation])
return (
<TableSection>
<SectionHeader title={title} />
@@ -238,17 +221,6 @@ export const OptionsSection = ({ title, encryptionAvailable }: Props) => {
onPress={onExportPress}
/>
<ButtonCell testID="openWebApp" leftAligned title="Open Web App" onPress={() => openWebApp()} />
<SectionedAccessoryTableCell
onPress={() => {
const newValue = !shouldAlwaysOpenWebAppOnLaunch
setShouldAlwaysOpenWebAppOnLaunch(newValue)
void application.setValue(AlwaysOpenWebAppOnLaunchKey, newValue, StorageValueModes.Nonwrapped)
}}
text="Always Open Web App On Launch"
selected={() => shouldAlwaysOpenWebAppOnLaunch}
/>
{!signedIn && (
<SectionedAccessoryTableCell
testID="lastExportDate"
@@ -1,4 +1,4 @@
import { MobileDeviceInterface } from '@Lib/Interface'
import { MobileDevice } from '@Lib/Interface'
import { useFocusEffect, useNavigation } from '@react-navigation/native'
import { ApplicationContext } from '@Root/ApplicationContext'
import { ButtonCell } from '@Root/Components/ButtonCell'
@@ -38,14 +38,14 @@ export const SecuritySection = (props: Props) => {
useEffect(() => {
let mounted = true
const getHasScreenshotPrivacy = async () => {
const hasScreenshotPrivacyEnabled = (await application?.getMobileScreenshotPrivacyEnabled()) ?? true
const hasScreenshotPrivacyEnabled = application?.getMobileScreenshotPrivacyEnabled()
if (mounted) {
setHasScreenshotPrivacy(hasScreenshotPrivacyEnabled)
}
}
void getHasScreenshotPrivacy()
const getHasBiometrics = async () => {
const appHasBiometrics = await application!.hasBiometrics()
const appHasBiometrics = application!.hasBiometrics()
if (mounted) {
setHasBiometrics(appHasBiometrics)
}
@@ -53,7 +53,7 @@ export const SecuritySection = (props: Props) => {
void getHasBiometrics()
const hasBiometricsSupport = async () => {
const hasBiometricsAvailable = await (
application?.deviceInterface as MobileDeviceInterface
application?.deviceInterface as MobileDevice
).getDeviceBiometricsAvailability()
if (mounted) {
setSupportsBiometrics(hasBiometricsAvailable)
@@ -9,6 +9,7 @@ import React, { useCallback, useEffect, useState } from 'react'
import { AuthSection } from './Sections/AuthSection'
import { CompanySection } from './Sections/CompanySection'
import { EncryptionSection } from './Sections/EncryptionSection'
import { NewMobileSection } from './Sections/NewMobilePreview'
import { OptionsSection } from './Sections/OptionsSection'
import { PreferencesSection } from './Sections/PreferencesSection'
import { ProtectionsSection } from './Sections/ProtectionsSection'
@@ -54,6 +55,7 @@ export const Settings = (props: Props) => {
<Container keyboardShouldPersistTaps={'always'} keyboardDismissMode={'interactive'}>
<AuthSection title="Account" signedIn={signedIn} />
<OptionsSection encryptionAvailable={!!encryptionAvailable} title="Options" />
<NewMobileSection />
<WorkspacesSection />
<PreferencesSection />
{application.hasAccount() && isEntitledToFiles && <FilesSection />}
+16
View File
@@ -3,6 +3,22 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
# [1.19.0](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-24)
### Features
* new note title format w/ prefs ([#1629](https://github.com/standardnotes/app/issues/1629)) ([d3621d7](https://github.com/standardnotes/app/commit/d3621d70b1a34537417b06830275467055b753cb))
## [1.18.4](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-23)
### Bug Fixes
* **mobile:** adjust status bar color to match current theme ([#1624](https://github.com/standardnotes/app/issues/1624)) ([4d5429c](https://github.com/standardnotes/app/commit/4d5429cc89c15f870825f20e97844825102c6aec))
## [1.18.3](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-20)
**Note:** Version bump only for package @standardnotes/models
## [1.18.2](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-15)
### Bug Fixes
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@standardnotes/models",
"version": "1.18.2",
"version": "1.19.0",
"engines": {
"node": ">=16.0.0 <17.0.0"
},
@@ -1,4 +1,4 @@
import { FeatureDescription } from '@standardnotes/features'
import { FeatureDescription, ThemeFeatureDescription } from '@standardnotes/features'
type ThirdPartyPackageInfo = {
version: string
@@ -6,3 +6,4 @@ type ThirdPartyPackageInfo = {
}
export type ComponentPackageInfo = FeatureDescription & Partial<ThirdPartyPackageInfo>
export type ThemePackageInfo = FeatureDescription & Partial<ThirdPartyPackageInfo> & ThemeFeatureDescription
@@ -6,11 +6,13 @@ import { HistoryEntryInterface } from '../../Runtime/History'
import { DecryptedItemInterface, ItemInterface } from '../../Abstract/Item'
import { ContentType } from '@standardnotes/common'
import { useBoolean } from '@standardnotes/utils'
import { ThemePackageInfo } from '../Component/PackageInfo'
export const isTheme = (x: ItemInterface): x is SNTheme => x.content_type === ContentType.Theme
export class SNTheme extends SNComponent {
public override area: ComponentArea = ComponentArea.Themes
public override readonly package_info!: ThemePackageInfo
isLayerable(): boolean {
return useBoolean(this.package_info && this.package_info.layerable, false)
@@ -32,6 +32,13 @@ export enum PrefKey {
MobileDoNotShowAgainUnsupportedEditors = 'mobileDoNotShowAgainUnsupportedEditors',
MobileSelectedTagUuid = 'mobileSelectedTagUuid',
MobileNotesHideEditorIcon = 'mobileHideEditorIcon',
NewNoteTitleFormat = 'newNoteTitleFormat',
}
export enum NewNoteTitleFormat {
CurrentDateAndTime = 'CurrentDateAndTime',
CurrentNoteCount = 'CurrentNoteCount',
Empty = 'Empty',
}
export type PrefValue = {
@@ -65,4 +72,5 @@ export type PrefValue = {
[PrefKey.MobileDoNotShowAgainUnsupportedEditors]: boolean
[PrefKey.MobileSelectedTagUuid]: string | undefined
[PrefKey.MobileNotesHideEditorIcon]: boolean
[PrefKey.NewNoteTitleFormat]: NewNoteTitleFormat
}
+192
View File
@@ -3,6 +3,198 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.3.94](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-28)
**Note:** Version bump only for package @standardnotes/releases
## [1.3.93](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-28)
**Note:** Version bump only for package @standardnotes/releases
## [1.3.92](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-28)
**Note:** Version bump only for package @standardnotes/releases
## [1.3.91](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-28)
**Note:** Version bump only for package @standardnotes/releases
## [1.3.90](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-27)
**Note:** Version bump only for package @standardnotes/releases
## [1.3.89](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-27)
**Note:** Version bump only for package @standardnotes/releases
## [1.3.88](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-27)
**Note:** Version bump only for package @standardnotes/releases
## [1.3.87](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-27)
**Note:** Version bump only for package @standardnotes/releases
## [1.3.86](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-27)
**Note:** Version bump only for package @standardnotes/releases
## [1.3.85](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-26)
**Note:** Version bump only for package @standardnotes/releases
## [1.3.84](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-26)
**Note:** Version bump only for package @standardnotes/releases
## [1.3.83](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-25)
**Note:** Version bump only for package @standardnotes/releases
## [1.3.82](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-25)
**Note:** Version bump only for package @standardnotes/releases
## [1.3.81](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-24)
**Note:** Version bump only for package @standardnotes/releases
## [1.3.80](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-24)
**Note:** Version bump only for package @standardnotes/releases
## [1.3.79](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-24)
**Note:** Version bump only for package @standardnotes/releases
## [1.3.78](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-24)
**Note:** Version bump only for package @standardnotes/releases
## [1.3.77](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-24)
**Note:** Version bump only for package @standardnotes/releases
## [1.3.76](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-24)
**Note:** Version bump only for package @standardnotes/releases
## [1.3.75](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-23)
**Note:** Version bump only for package @standardnotes/releases
## [1.3.74](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-23)
**Note:** Version bump only for package @standardnotes/releases
## [1.3.73](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-23)
**Note:** Version bump only for package @standardnotes/releases
## [1.3.72](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-23)
**Note:** Version bump only for package @standardnotes/releases
## [1.3.71](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-23)
**Note:** Version bump only for package @standardnotes/releases
## [1.3.70](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-23)
**Note:** Version bump only for package @standardnotes/releases
## [1.3.69](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-22)
**Note:** Version bump only for package @standardnotes/releases
## [1.3.68](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-22)
**Note:** Version bump only for package @standardnotes/releases
## [1.3.67](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-22)
**Note:** Version bump only for package @standardnotes/releases
## [1.3.66](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-22)
**Note:** Version bump only for package @standardnotes/releases
## [1.3.65](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-22)
**Note:** Version bump only for package @standardnotes/releases
## [1.3.64](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-22)
**Note:** Version bump only for package @standardnotes/releases
## [1.3.63](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-22)
**Note:** Version bump only for package @standardnotes/releases
## [1.3.62](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-21)
**Note:** Version bump only for package @standardnotes/releases
## [1.3.61](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-21)
**Note:** Version bump only for package @standardnotes/releases
## [1.3.60](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-21)
**Note:** Version bump only for package @standardnotes/releases
## [1.3.59](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-20)
**Note:** Version bump only for package @standardnotes/releases
## [1.3.58](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-20)
**Note:** Version bump only for package @standardnotes/releases
## [1.3.57](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-20)
**Note:** Version bump only for package @standardnotes/releases
## [1.3.56](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-20)
**Note:** Version bump only for package @standardnotes/releases
## [1.3.55](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-19)
**Note:** Version bump only for package @standardnotes/releases
## [1.3.54](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-19)
**Note:** Version bump only for package @standardnotes/releases
## [1.3.53](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-19)
**Note:** Version bump only for package @standardnotes/releases
## [1.3.52](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-18)
**Note:** Version bump only for package @standardnotes/releases
## [1.3.51](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-16)
**Note:** Version bump only for package @standardnotes/releases
## [1.3.50](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-16)
**Note:** Version bump only for package @standardnotes/releases
## [1.3.49](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-16)
**Note:** Version bump only for package @standardnotes/releases
## [1.3.48](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-15)
**Note:** Version bump only for package @standardnotes/releases
## [1.3.47](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-15)
**Note:** Version bump only for package @standardnotes/releases
## [1.3.46](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-15)
**Note:** Version bump only for package @standardnotes/releases
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@standardnotes/releases",
"version": "1.3.46",
"version": "1.3.94",
"license": "AGPL-3.0-or-later",
"main": "dist/releases.json",
"types": "dist/index.d.ts",
+1
View File
@@ -1,2 +1,3 @@
node_modules
dist
coverage
+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.10.3](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-23)
**Note:** Version bump only for package @standardnotes/responses
## [1.10.2](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-20)
### Bug Fixes
* move wrapped storage to unwrapped if not encrypted ([#1603](https://github.com/standardnotes/app/issues/1603)) ([c5e225d](https://github.com/standardnotes/app/commit/c5e225d335537257f44168b8ad05222afccb508a))
## [1.10.1](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-13)
**Note:** Version bump only for package @standardnotes/responses
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@standardnotes/responses",
"version": "1.10.1",
"version": "1.10.3",
"engines": {
"node": ">=16.0.0 <17.0.0"
},
+48
View File
@@ -3,6 +3,54 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.22.1](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-28)
**Note:** Version bump only for package @standardnotes/services
# [1.22.0](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-28)
### Features
* handle android back button on android ([#1656](https://github.com/standardnotes/app/issues/1656)) ([981d8a7](https://github.com/standardnotes/app/commit/981d8a7497ea2600e1535ad9170cb5559550ca4d))
## [1.21.5](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-27)
### Bug Fixes
* export/sharing notes on mobile webview ([#1644](https://github.com/standardnotes/app/issues/1644)) ([6d5ebde](https://github.com/standardnotes/app/commit/6d5ebdeaa1777f31878b6e7d4dfc33fe83abc9fc))
## [1.21.4](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-24)
**Note:** Version bump only for package @standardnotes/services
## [1.21.3](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-23)
### Bug Fixes
* **mobile:** adjust status bar color to match current theme ([#1624](https://github.com/standardnotes/app/issues/1624)) ([4d5429c](https://github.com/standardnotes/app/commit/4d5429cc89c15f870825f20e97844825102c6aec))
## [1.21.2](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-20)
### Bug Fixes
* move wrapped storage to unwrapped if not encrypted ([#1603](https://github.com/standardnotes/app/issues/1603)) ([c5e225d](https://github.com/standardnotes/app/commit/c5e225d335537257f44168b8ad05222afccb508a))
## [1.21.1](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-20)
**Note:** Version bump only for package @standardnotes/services
# [1.21.0](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-19)
### Features
* mobile web bridge ([#1597](https://github.com/standardnotes/app/issues/1597)) ([c4d7761](https://github.com/standardnotes/app/commit/c4d776149677269bc766f24da6adc5ec816dbcfb))
## [1.20.2](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-15)
### Bug Fixes
* biometrics input on mobile webview challenge modal ([#1572](https://github.com/standardnotes/app/issues/1572)) ([3a15142](https://github.com/standardnotes/app/commit/3a15142940ef9391868442e1997c3d9d5eec33be))
## [1.20.1](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-15)
**Note:** Version bump only for package @standardnotes/services
+3 -2
View File
@@ -1,6 +1,6 @@
{
"name": "@standardnotes/services",
"version": "1.20.1",
"version": "1.22.1",
"engines": {
"node": ">=16.0.0 <17.0.0"
},
@@ -42,6 +42,7 @@
"eslint": "^8.23.1",
"eslint-plugin-prettier": "*",
"jest": "^28.1.2",
"ts-jest": "^28.0.5"
"ts-jest": "^28.0.5",
"typescript": "*"
}
}
@@ -1,3 +1,4 @@
import { MobileDeviceInterface } from './../Device/MobileDeviceInterface'
import { DesktopManagerInterface } from '../Device/DesktopManagerInterface'
import { WebAppEvent } from '../Event/WebAppEvent'
import { ApplicationInterface } from './ApplicationInterface'
@@ -5,4 +6,12 @@ import { ApplicationInterface } from './ApplicationInterface'
export interface WebApplicationInterface extends ApplicationInterface {
notifyWebEvent(event: WebAppEvent, data?: unknown): void
getDesktopService(): DesktopManagerInterface | undefined
handleMobileEnteringBackgroundEvent(): Promise<void>
handleMobileGainingFocusEvent(): Promise<void>
handleMobileLosingFocusEvent(): Promise<void>
handleMobileResumingFromBackgroundEvent(): Promise<void>
isNativeMobileWeb(): boolean
get mobileDevice(): MobileDeviceInterface
handleAndroidBackButtonPressed(): void
addAndroidBackHandlerEventListener(listener: () => boolean): (() => void) | undefined
}
@@ -1,12 +1,19 @@
import { DeviceInterface } from './DeviceInterface'
import { Environment, RawKeychainValue } from '@standardnotes/models'
import { Environment, Platform, RawKeychainValue } from '@standardnotes/models'
export interface MobileDeviceInterface extends DeviceInterface {
environment: Environment.Mobile
platform: Platform.Ios | Platform.Android
getRawKeychainValue(): Promise<RawKeychainValue | undefined>
getDeviceBiometricsAvailability(): Promise<boolean>
setAndroidScreenshotPrivacy(enable: boolean): Promise<void>
getMobileScreenshotPrivacyEnabled(): Promise<boolean | undefined>
setMobileScreenshotPrivacyEnabled(isEnabled: boolean): Promise<void>
setAndroidScreenshotPrivacy(enable: boolean): void
authenticateWithBiometrics(): Promise<boolean>
hideMobileInterfaceFromScreenshots(): void
stopHidingMobileInterfaceFromScreenshots(): void
consoleLog(...args: any[]): void
handleThemeSchemeChange(isDark: boolean): void
shareBase64AsFile(base64: string, filename: string): Promise<void>
downloadBase64AsFile(base64: string, filename: string, saveInTempLocation?: boolean): Promise<string | undefined>
confirmAndExit(): void
}
+6
View File
@@ -3,6 +3,12 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
# [1.12.0](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-28)
### Features
* **crypto:** pkc algos for key generation, encrypt, and decrypt ([#1663](https://github.com/standardnotes/app/issues/1663)) ([a83003e](https://github.com/standardnotes/app/commit/a83003ee69d144c8e80eaee20bc7be2533d92c63))
## [1.11.1](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-08-23)
**Note:** Version bump only for package @standardnotes/sncrypto-common
+3 -2
View File
@@ -1,6 +1,6 @@
{
"name": "@standardnotes/sncrypto-common",
"version": "1.11.1",
"version": "1.12.0",
"engines": {
"node": ">=16.0.0 <17.0.0"
},
@@ -26,7 +26,8 @@
"devDependencies": {
"@typescript-eslint/eslint-plugin": "^5.30.0",
"@typescript-eslint/parser": "^5.12.1",
"eslint-plugin-prettier": "^4.2.1"
"eslint-plugin-prettier": "^4.2.1",
"typescript": "*"
},
"dependencies": {
"reflect-metadata": "^0.1.13"
@@ -0,0 +1,7 @@
import { HexString } from './HexString'
export type PkcKeyPair = {
keyType: 'curve25519' | 'ed25519' | 'x25519'
privateKey: HexString
publicKey: HexString
}
@@ -8,3 +8,4 @@ export * from './StreamDecryptorResult'
export * from './StreamEncryptor'
export * from './Unencrypted'
export * from './Utf8String'
export * from './PkcKeyPair'
+6
View File
@@ -3,6 +3,12 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
# [1.13.0](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-28)
### Features
* **crypto:** pkc algos for key generation, encrypt, and decrypt ([#1663](https://github.com/standardnotes/app/issues/1663)) ([a83003e](https://github.com/standardnotes/app/commit/a83003ee69d144c8e80eaee20bc7be2533d92c63))
## [1.12.3](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-08-23)
**Note:** Version bump only for package @standardnotes/sncrypto-web
+3 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@standardnotes/sncrypto-web",
"version": "1.12.3",
"version": "1.13.0",
"engines": {
"node": ">=16.0.0 <17.0.0"
},
@@ -39,11 +39,13 @@
"babel-loader": "^8.2.3",
"chai": "^4.3.6",
"connect": "^3.7.0",
"eslint": "*",
"eslint-plugin-prettier": "*",
"regenerator-runtime": "^0.13.9",
"serve-static": "^1.14.2",
"ts-loader": "^9.2.6",
"typedarray-to-buffer": "^4.0.0",
"typescript": "*",
"uuid": "^8.3.2",
"webpack": "*",
"webpack-cli": "*"
+62 -17
View File
@@ -9,6 +9,7 @@ import {
PureCryptoInterface,
Utf8String,
timingSafeEqual,
PkcKeyPair,
} from '@standardnotes/sncrypto-common'
import * as Utils from './utils'
import * as sodium from './libsodium'
@@ -83,7 +84,7 @@ export class SNWebCrypto implements PureCryptoInterface {
iterations: number,
length: number,
): Promise<HexString | null> {
const keyData = await Utils.stringToArrayBuffer(password)
const keyData = Utils.stringToArrayBuffer(password)
const key = await this.webCryptoImportKey(keyData, WebCryptoAlgs.Pbkdf2, [WebCryptoActions.DeriveBits])
if (!key) {
console.error('Key is null, unable to continue')
@@ -99,21 +100,21 @@ export class SNWebCrypto implements PureCryptoInterface {
}
public async aes256CbcEncrypt(plaintext: Utf8String, iv: HexString, key: HexString): Promise<Base64String> {
const keyData = await Utils.hexStringToArrayBuffer(key)
const ivData = await Utils.hexStringToArrayBuffer(iv)
const keyData = Utils.hexStringToArrayBuffer(key)
const ivData = Utils.hexStringToArrayBuffer(iv)
const alg = { name: WebCryptoAlgs.AesCbc, iv: ivData }
const importedKeyData = await this.webCryptoImportKey(keyData, alg.name, [WebCryptoActions.Encrypt])
const textData = await Utils.stringToArrayBuffer(plaintext)
const textData = Utils.stringToArrayBuffer(plaintext)
const result = await crypto.subtle.encrypt(alg, importedKeyData, textData)
return Utils.arrayBufferToBase64(result)
}
public async aes256CbcDecrypt(ciphertext: Base64String, iv: HexString, key: HexString): Promise<Utf8String | null> {
const keyData = await Utils.hexStringToArrayBuffer(key)
const ivData = await Utils.hexStringToArrayBuffer(iv)
const keyData = Utils.hexStringToArrayBuffer(key)
const ivData = Utils.hexStringToArrayBuffer(iv)
const alg = { name: WebCryptoAlgs.AesCbc, iv: ivData }
const importedKeyData = await this.webCryptoImportKey(keyData, alg.name, [WebCryptoActions.Decrypt])
const textData = await Utils.base64ToArrayBuffer(ciphertext)
const textData = Utils.base64ToArrayBuffer(ciphertext)
try {
const result = await crypto.subtle.decrypt(alg, importedKeyData, textData)
@@ -150,11 +151,11 @@ export class SNWebCrypto implements PureCryptoInterface {
}
public async hmac1(message: Utf8String, key: HexString): Promise<HexString | null> {
const keyHexData = await Utils.hexStringToArrayBuffer(key)
const keyHexData = Utils.hexStringToArrayBuffer(key)
const keyData = await this.webCryptoImportKey(keyHexData, WebCryptoAlgs.Hmac, [WebCryptoActions.Sign], {
name: WebCryptoAlgs.Sha1,
})
const messageData = await Utils.stringToArrayBuffer(message)
const messageData = Utils.stringToArrayBuffer(message)
const funcParams = { name: WebCryptoAlgs.Hmac }
try {
@@ -169,15 +170,14 @@ export class SNWebCrypto implements PureCryptoInterface {
}
public async unsafeSha1(text: string): Promise<string> {
const textData = await Utils.stringToArrayBuffer(text)
const textData = Utils.stringToArrayBuffer(text)
const digest = await crypto.subtle.digest(WebCryptoAlgs.Sha1, textData)
return Utils.arrayBufferToHexString(digest)
}
/**
* Converts a raw string key to a WebCrypto CryptoKey object.
* @param rawKey
* A plain utf8 string or an array buffer
* @param keyData
* @param alg
* The name of the algorithm this key will be used for (i.e 'AES-CBC' or 'HMAC')
* @param actions
@@ -220,7 +220,7 @@ export class SNWebCrypto implements PureCryptoInterface {
): Promise<HexString> {
const params = {
name: WebCryptoAlgs.Pbkdf2,
salt: await Utils.stringToArrayBuffer(salt),
salt: Utils.stringToArrayBuffer(salt),
iterations: iterations,
hash: { name: WebCryptoAlgs.Sha512 },
}
@@ -298,13 +298,13 @@ export class SNWebCrypto implements PureCryptoInterface {
public xchacha20StreamEncryptorPush(
encryptor: StreamEncryptor,
plainBuffer: Uint8Array,
assocData: Utf8String,
assocData?: Utf8String,
tag: SodiumConstant = SodiumConstant.CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_TAG_PUSH,
): Uint8Array {
const encryptedBuffer = sodium.crypto_secretstream_xchacha20poly1305_push(
encryptor.state as sodium.StateAddress,
plainBuffer,
assocData.length > 0 ? Utils.stringToArrayBuffer(assocData) : null,
assocData && assocData.length > 0 ? Utils.stringToArrayBuffer(assocData) : null,
tag,
)
return encryptedBuffer
@@ -325,7 +325,7 @@ export class SNWebCrypto implements PureCryptoInterface {
public xchacha20StreamDecryptorPush(
decryptor: StreamDecryptor,
encryptedBuffer: Uint8Array,
assocData: Utf8String,
assocData?: Utf8String,
): StreamDecryptorResult | false {
if (encryptedBuffer.length < SodiumConstant.CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_ABYTES) {
throw new Error('Invalid ciphertext size')
@@ -334,7 +334,7 @@ export class SNWebCrypto implements PureCryptoInterface {
const result = sodium.crypto_secretstream_xchacha20poly1305_pull(
decryptor.state as sodium.StateAddress,
encryptedBuffer,
assocData.length > 0 ? Utils.stringToArrayBuffer(assocData) : null,
assocData && assocData.length > 0 ? Utils.stringToArrayBuffer(assocData) : null,
)
if ((result as unknown) === false) {
@@ -344,6 +344,51 @@ export class SNWebCrypto implements PureCryptoInterface {
return result
}
/**
* https://doc.libsodium.org/public-key_cryptography/authenticated_encryption
*/
public sodiumCryptoBoxEasyEncrypt(
message: Utf8String,
nonce: HexString,
senderSecretKey: HexString,
recipientPublicKey: HexString,
): Base64String {
const result = sodium.crypto_box_easy(
message,
Utils.hexStringToArrayBuffer(nonce),
Utils.hexStringToArrayBuffer(recipientPublicKey),
Utils.hexStringToArrayBuffer(senderSecretKey),
)
return Utils.arrayBufferToBase64(result)
}
public sodiumCryptoBoxEasyDecrypt(
ciphertext: Base64String,
nonce: HexString,
senderPublicKey: HexString,
recipientSecretKey: HexString,
): Base64String {
const result = sodium.crypto_box_open_easy(
Utils.base64ToArrayBuffer(ciphertext),
Utils.hexStringToArrayBuffer(nonce),
Utils.hexStringToArrayBuffer(senderPublicKey),
Utils.hexStringToArrayBuffer(recipientSecretKey),
'text',
)
return result
}
public sodiumCryptoBoxGenerateKeypair(): PkcKeyPair {
const result = sodium.crypto_box_keypair()
const publicKey = Utils.arrayBufferToHexString(result.publicKey)
const privateKey = Utils.arrayBufferToHexString(result.privateKey)
return { publicKey, privateKey, keyType: result.keyType }
}
/**
* Generates a random secret for TOTP authentication
*
+3 -16
View File
@@ -1,16 +1,3 @@
export { SNWebCrypto } from './crypto'
export {
arrayBufferToBase64,
arrayBufferToHexString,
arrayBufferToString,
base64Decode,
base64Encode,
base64ToArrayBuffer,
base64ToHex,
hexStringToArrayBuffer,
hexToBase64,
isWebCryptoAvailable,
stringToArrayBuffer,
base32Decode,
base32Encode,
} from './utils'
export * from './crypto'
export * from './utils'
export { SodiumConstant } from '@standardnotes/sncrypto-common'
+7 -4
View File
@@ -3,12 +3,15 @@ export {
base64_variants,
crypto_aead_xchacha20poly1305_ietf_decrypt,
crypto_aead_xchacha20poly1305_ietf_encrypt,
crypto_secretstream_xchacha20poly1305_push,
crypto_secretstream_xchacha20poly1305_pull,
crypto_secretstream_xchacha20poly1305_init_push,
crypto_secretstream_xchacha20poly1305_init_pull,
crypto_box_easy,
crypto_box_keypair,
crypto_box_open_easy,
crypto_pwhash_ALG_DEFAULT,
crypto_pwhash,
crypto_secretstream_xchacha20poly1305_init_pull,
crypto_secretstream_xchacha20poly1305_init_push,
crypto_secretstream_xchacha20poly1305_pull,
crypto_secretstream_xchacha20poly1305_push,
from_base64,
from_hex,
from_string,
+72 -143
View File
@@ -50,31 +50,18 @@ describe('crypto operations', async function () {
it('compares strings with timing safe comparison', async function () {
const crypto = new SNWebCrypto()
expect(crypto.timingSafeEqual('hello world 🌍', 'hello world 🌍')).to.equal(
true,
)
expect(crypto.timingSafeEqual('helo world 🌍', 'hello world 🌍')).to.equal(
false,
)
expect(crypto.timingSafeEqual('hello world 🌍', 'hello world 🌍')).to.equal(true)
expect(crypto.timingSafeEqual('helo world 🌍', 'hello world 🌍')).to.equal(false)
expect(crypto.timingSafeEqual('', 'a')).to.equal(false)
expect(crypto.timingSafeEqual('', '')).to.equal(true)
expect(
crypto.timingSafeEqual(
'2e1ee7920bb188a88f94bb912153befd83cc55cd',
'2e1ee7920bb188a88f94bb912153befd83cc55cd',
),
crypto.timingSafeEqual('2e1ee7920bb188a88f94bb912153befd83cc55cd', '2e1ee7920bb188a88f94bb912153befd83cc55cd'),
).to.equal(true)
expect(
crypto.timingSafeEqual(
'1e1ee7920bb188a88f94bb912153befd83cc55cd',
'2e1ee7920bb188a88f94bb912153befd83cc55cd',
),
crypto.timingSafeEqual('1e1ee7920bb188a88f94bb912153befd83cc55cd', '2e1ee7920bb188a88f94bb912153befd83cc55cd'),
).to.equal(false)
expect(
crypto.timingSafeEqual(
'2e1ee7920bb188a88f94bb912153befd83cc55cc',
'2e1ee7920bb188a88f94bb912153befd83cc55cd',
),
crypto.timingSafeEqual('2e1ee7920bb188a88f94bb912153befd83cc55cc', '2e1ee7920bb188a88f94bb912153befd83cc55cd'),
).to.equal(false)
})
@@ -85,22 +72,16 @@ describe('crypto operations', async function () {
it('pbkdf2 1', async function () {
const password = 'very_secure🔒'
const salt =
'c3feb78823adce65c4ab024dab9c5cdcda5a04cdbd98f65eac0311dfa432d67b'
const expected =
'bbb3d3af19dd1cbb901c958003faa55f193aad6a57fff30e51a62591bdc054d8'
const salt = 'c3feb78823adce65c4ab024dab9c5cdcda5a04cdbd98f65eac0311dfa432d67b'
const expected = 'bbb3d3af19dd1cbb901c958003faa55f193aad6a57fff30e51a62591bdc054d8'
const result = await webCrypto.pbkdf2(password, salt, 100000, 256)
expect(result).to.equal(expected)
})
it('pbkdf2 2', async function () {
const password = 'correct horse battery staple ✅'
const salt = Buffer.from(
'808182838485868788898a8b8c8d8e8f',
'hex',
).toString('utf8')
const expected =
'795d83b18e55d860d3799f85a20f66ee17eb9dcf041df1d7a13fac30af7103d9'
const salt = Buffer.from('808182838485868788898a8b8c8d8e8f', 'hex').toString('utf8')
const expected = '795d83b18e55d860d3799f85a20f66ee17eb9dcf041df1d7a13fac30af7103d9'
const result = await webCrypto.pbkdf2(password, salt, 100000, 256)
expect(result).to.equal(expected)
})
@@ -116,19 +97,16 @@ describe('crypto operations', async function () {
it('hmac 256', async function () {
const text = 'hello world 🌍'
const key =
'e802dc953f3f1f7b5db62409b74ac848559d4711c4e0047ecc5e312ad8ab8397'
const key = 'e802dc953f3f1f7b5db62409b74ac848559d4711c4e0047ecc5e312ad8ab8397'
const hash = await webCrypto.hmac256(text, key)
const expected =
'b63f94ee33a067ffac3ee97c7987dd3171dcdc747a322bb3f3ab890201c8e6f9'
const expected = 'b63f94ee33a067ffac3ee97c7987dd3171dcdc747a322bb3f3ab890201c8e6f9'
expect(hash).to.equal(expected)
})
it('sha256', async function () {
const text = 'hello world 🌍'
const hash = await webCrypto.sha256(text)
const expected =
'1e71fe32476da1ff115b44dfd74aed5c90d68a1d80a2033065e30cff4335211a'
const expected = '1e71fe32476da1ff115b44dfd74aed5c90d68a1d80a2033065e30cff4335211a'
expect(hash).to.equal(expected)
})
@@ -154,13 +132,7 @@ describe('crypto operations', async function () {
const bytes = 67108864
const length = 16
const iterations = 2
const result = await webCrypto.argon2(
password,
salt,
iterations,
bytes,
length,
)
const result = await webCrypto.argon2(password, salt, iterations, bytes, length)
const expectedResult = '18dfbc268f251701652c8e38b5273f73'
expect(result).to.equal(expectedResult)
})
@@ -172,15 +144,8 @@ describe('crypto operations', async function () {
const bytes = 67108864
const length = 32
const iterations = 5
const result = await webCrypto.argon2(
password,
truncatedSalt,
iterations,
bytes,
length,
)
const expected =
'bb6ec440708c271ce34decd7f997e2444d309b1105992779ccdb47f78a5fda6f'
const result = await webCrypto.argon2(password, truncatedSalt, iterations, bytes, length)
const expected = 'bb6ec440708c271ce34decd7f997e2444d309b1105992779ccdb47f78a5fda6f'
expect(result).to.equal(expected)
})
@@ -189,69 +154,38 @@ describe('crypto operations', async function () {
const nonce = await webCrypto.generateRandomKey(192)
const plaintext = 'hello world 🌍'
const aad = JSON.stringify({ uuid: '123🎤' })
const ciphertext = await webCrypto.xchacha20Encrypt(
plaintext,
nonce,
key,
aad,
)
const decrypted = await webCrypto.xchacha20Decrypt(
ciphertext,
nonce,
key,
aad,
)
const ciphertext = await webCrypto.xchacha20Encrypt(plaintext, nonce, key, aad)
const decrypted = await webCrypto.xchacha20Decrypt(ciphertext, nonce, key, aad)
expect(decrypted).to.equal(plaintext)
})
it('xchacha20 streaming encrypt/decrypt', async function () {
const key = await webCrypto.generateRandomKey(256)
const bigFile = await fetch(
'http://localhost:9003/test/resources/big_file.md',
)
const bigFile = await fetch('http://localhost:9003/test/resources/big_file.md')
const bigText = await bigFile.text()
const plaintext = bigText
const plainBuffer = stringToArrayBuffer(plaintext)
const encryptor = webCrypto.xchacha20StreamEncryptInitEncryptor(key)
const header = base64StringToArrayBuffer(encryptor.header)
const encryptor = webCrypto.xchacha20StreamInitEncryptor(key)
let encryptedBuffer = Buffer.concat([header])
const headerBase64 = encryptor.header
const headerBuffer = base64ToArrayBuffer(encryptor.header)
let encryptedBuffer = Buffer.concat([headerBuffer])
const pushChunkSize = plainBuffer.length / 200
const pullChunkSize =
pushChunkSize +
SodiumConstant.CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_ABYTES
const pullChunkSize = pushChunkSize + SodiumConstant.CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_ABYTES
for (let i = 0; i < plainBuffer.length; i += pushChunkSize) {
const readUntil =
i + pushChunkSize > plainBuffer.length
? plainBuffer.length
: i + pushChunkSize
const chunk = webCrypto.xchacha20StreamEncryptorPush(
encryptor,
plainBuffer.slice(i, readUntil),
)
const readUntil = i + pushChunkSize > plainBuffer.length ? plainBuffer.length : i + pushChunkSize
const chunk = webCrypto.xchacha20StreamEncryptorPush(encryptor, plainBuffer.slice(i, readUntil))
encryptedBuffer = Buffer.concat([encryptedBuffer, chunk])
}
const decryptor = webCrypto.xchacha20StreamEncryptInitDecryptor(
header,
key,
)
const decryptor = webCrypto.xchacha20StreamInitDecryptor(headerBase64, key)
let decryptedBuffer = Buffer.alloc(0)
for (
let i = header.length;
i < encryptedBuffer.length;
i += pullChunkSize
) {
const readUntil =
i + pullChunkSize > encryptedBuffer.length
? encryptedBuffer.length
: i + pullChunkSize
const chunk = webCrypto.xchacha20StreamDecryptorPush(
decryptor,
encryptedBuffer.slice(i, readUntil),
)
for (let i = headerBuffer.length; i < encryptedBuffer.length; i += pullChunkSize) {
const readUntil = i + pullChunkSize > encryptedBuffer.length ? encryptedBuffer.length : i + pullChunkSize
const chunk = webCrypto.xchacha20StreamDecryptorPush(decryptor, encryptedBuffer.slice(i, readUntil))
decryptedBuffer = Buffer.concat([decryptedBuffer, chunk.message])
}
@@ -263,18 +197,8 @@ describe('crypto operations', async function () {
const key = await webCrypto.generateRandomKey(256)
const nonce = await webCrypto.generateRandomKey(192)
const plaintext = 'hello world 🌍'
const ciphertext = await webCrypto.xchacha20Encrypt(
plaintext,
nonce,
key,
JSON.stringify({ uuid: 'foo🎲' }),
)
const result = await webCrypto.xchacha20Decrypt(
ciphertext,
nonce,
key,
JSON.stringify({ uuid: 'bar🎲' }),
)
const ciphertext = await webCrypto.xchacha20Encrypt(plaintext, nonce, key, JSON.stringify({ uuid: 'foo🎲' }))
const result = await webCrypto.xchacha20Decrypt(ciphertext, nonce, key, JSON.stringify({ uuid: 'bar🎲' }))
expect(result).to.not.be.ok
})
@@ -284,23 +208,12 @@ describe('crypto operations', async function () {
"Ladies and Gentlemen of the class of '99: If I could offer you only one tip for the future, sunscreen would be it.🌞"
const assocData = await hexStringToArrayBuffer('50515253c0c1c2c3c4c5c6c7')
const nonce = '404142434445464748494a4b4c4d4e4f5051525354555657'
const key =
'808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9f'
const ciphertext = await webCrypto.xchacha20Encrypt(
plaintext,
nonce,
key,
assocData,
)
const key = '808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9f'
const ciphertext = await webCrypto.xchacha20Encrypt(plaintext, nonce, key, assocData)
const expected =
'vW0XnT6D1DuVdleUk8DpOVcqFwAlK/rMvtKQLCE5bLtzHH8bC0qmRAvzqC9O2n45rmTGcIxUwhbLlrcuEhO0Ui+Mm6QNtdlFsRtpuYLBu54/P6wrw2lIj3ayODVl0//5IflmTJdjfal2iBL2FcaLE7UuOqw6kdl7HV6PKzn0pIOeHH3rkwQ='
expect(ciphertext).to.equal(expected)
const decrypted = await webCrypto.xchacha20Decrypt(
ciphertext,
nonce,
key,
assocData,
)
const decrypted = await webCrypto.xchacha20Decrypt(ciphertext, nonce, key, assocData)
expect(decrypted).to.equal(plaintext)
})
@@ -315,16 +228,10 @@ describe('crypto operations', async function () {
).toString('utf8')
const assocData = Buffer.from('50515253c0c1c2c3c4c5c6c7', 'hex')
const nonce = '404142434445464748494a4b4c4d4e4f5051525354555657'
const key =
'808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9f'
const key = '808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9f'
/** Encrypt */
const ciphertextBase64 = await webCrypto.xchacha20Encrypt(
plaintext,
nonce,
key,
assocData,
)
const ciphertextBase64 = await webCrypto.xchacha20Encrypt(plaintext, nonce, key, assocData)
const ciphertextHex = await base64ToHex(ciphertextBase64)
const expected =
'bd6d179d3e83d43b9576579493c0e939572a1700252bfaccbed2902c21396cbb' +
@@ -335,12 +242,7 @@ describe('crypto operations', async function () {
expect(ciphertextHex).to.equal(expected)
/** Decrypt */
const decrypted = await webCrypto.xchacha20Decrypt(
ciphertextBase64,
nonce,
key,
assocData,
)
const decrypted = await webCrypto.xchacha20Decrypt(ciphertextBase64, nonce, key, assocData)
expect(decrypted).to.equal(plaintext)
})
@@ -351,17 +253,44 @@ describe('crypto operations', async function () {
const bytes = 67108864
const length = 16
const iterations = 2
const result = await webCrypto.argon2(
password,
salt,
iterations,
bytes,
length,
)
const result = await webCrypto.argon2(password, salt, iterations, bytes, length)
const expectedResult = '720f95400220748a811bca9b8cff5d6e'
expect(result).to.equal(expectedResult)
})
it('pkc crypto_box_easy keypair generation', async function () {
const keypair = await webCrypto.sodiumCryptoBoxGenerateKeypair()
expect(keypair.keyType).to.equal('x25519')
expect(keypair.publicKey.length).to.equal(64)
expect(keypair.privateKey.length).to.equal(64)
})
it('pkc crypto_box_easy encrypt/decrypt', async function () {
const senderKeypair = await webCrypto.sodiumCryptoBoxGenerateKeypair()
const recipientKeypair = await webCrypto.sodiumCryptoBoxGenerateKeypair()
const nonce = await webCrypto.generateRandomKey(192)
const plaintext = 'hello world 🌍'
const ciphertext = await webCrypto.sodiumCryptoBoxEasyEncrypt(
plaintext,
nonce,
senderKeypair.privateKey,
recipientKeypair.publicKey,
)
expect(ciphertext.length).to.equal(44)
const decrypted = await webCrypto.sodiumCryptoBoxEasyDecrypt(
ciphertext,
nonce,
senderKeypair.publicKey,
recipientKeypair.privateKey,
)
expect(decrypted).to.equal(plaintext)
})
it('generates random OTP secret 160 bits long', async function () {
const secret = await webCrypto.generateOtpSecret()
expect(secret).to.have.length(32)
+1 -1
View File
@@ -6,7 +6,7 @@
<link rel="stylesheet" href="https://unpkg.com/mocha/mocha.css" />
<script src="https://unpkg.com/chai/chai.js"></script>
<script src="https://unpkg.com/mocha/mocha.js"></script>
<script src="../../../node_modules/regenerator-runtime/runtime.js"></script>
<script src="https://unpkg.com/regenerator-runtime@0.13.9/runtime.js"></script>
<script src="../dist/sncrypto-web.js"></script>
<script>
Object.assign(window, SNCrypto);
+1 -1
View File
@@ -42,7 +42,7 @@ describe('utils', async function () {
it('base64URLEncode', async function () {
const str = 'hello world'
const b64 = await base64Encode(str)
const b64 = await base64URLEncode(str)
expect(b64).to.equal('aGVsbG8gd29ybGQ')
})
+5 -1
View File
@@ -2,4 +2,8 @@ node_modules
dist
test
*.config.js
mocha/**/*
mocha/**/*
coverage
e2e-server.js
jest-global.ts
webpack.*.js
+84
View File
@@ -3,6 +3,90 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [2.133.1](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-28)
**Note:** Version bump only for package @standardnotes/snjs
# [2.133.0](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-28)
### Features
* handle android back button on android ([#1656](https://github.com/standardnotes/app/issues/1656)) ([981d8a7](https://github.com/standardnotes/app/commit/981d8a7497ea2600e1535ad9170cb5559550ca4d))
## [2.132.6](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-27)
**Note:** Version bump only for package @standardnotes/snjs
## [2.132.5](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-24)
**Note:** Version bump only for package @standardnotes/snjs
## [2.132.4](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-23)
**Note:** Version bump only for package @standardnotes/snjs
## [2.132.3](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-23)
### Bug Fixes
* biometrics timing loading ([#1622](https://github.com/standardnotes/app/issues/1622)) ([3c0d4fa](https://github.com/standardnotes/app/commit/3c0d4fac766c3a31bdbebe4f7e88f83ba1ea58da))
## [2.132.2](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-22)
### Reverts
* Revert "Revert "feat(web): move emails notifications to one pane and enable opening settings via url (#1614)" (#1617)" (#1619) ([e50f4eb](https://github.com/standardnotes/app/commit/e50f4eb92efd65b0b8fa3a5001b8dfb611f60180)), closes [#1614](https://github.com/standardnotes/app/issues/1614) [#1617](https://github.com/standardnotes/app/issues/1617) [#1619](https://github.com/standardnotes/app/issues/1619)
## [2.132.1](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-22)
### Reverts
* Revert "feat(web): move emails notifications to one pane and enable opening settings via url (#1614)" (#1617) ([6824dd2](https://github.com/standardnotes/app/commit/6824dd2d5fe4a6d427ff5465540f3b7865933e98)), closes [#1614](https://github.com/standardnotes/app/issues/1614) [#1617](https://github.com/standardnotes/app/issues/1617)
# [2.132.0](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-22)
### Features
* **web:** move emails notifications to one pane and enable opening settings via url ([#1614](https://github.com/standardnotes/app/issues/1614)) ([1fe833b](https://github.com/standardnotes/app/commit/1fe833bc24a3a426a7230381704d418624cc2b82))
# [2.131.0](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-21)
### Features
* **snjs:** add retrieving web sockets token for establishing connection ([#1602](https://github.com/standardnotes/app/issues/1602)) ([e809328](https://github.com/standardnotes/app/commit/e809328fa86d49f76d24bc0d95db010e483c1853))
## [2.130.2](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-20)
### Bug Fixes
* move wrapped storage to unwrapped if not encrypted ([#1603](https://github.com/standardnotes/app/issues/1603)) ([c5e225d](https://github.com/standardnotes/app/commit/c5e225d335537257f44168b8ad05222afccb508a))
## [2.130.1](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-20)
**Note:** Version bump only for package @standardnotes/snjs
# [2.130.0](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-19)
### Features
* mobile web bridge ([#1597](https://github.com/standardnotes/app/issues/1597)) ([c4d7761](https://github.com/standardnotes/app/commit/c4d776149677269bc766f24da6adc5ec816dbcfb))
## [2.129.2](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-19)
### Bug Fixes
* **snjs:** pass unencrypted file size to comply with file service interface ([#1595](https://github.com/standardnotes/app/issues/1595)) ([038320b](https://github.com/standardnotes/app/commit/038320b2fda8348810db586c70b0998647519fd6))
## [2.129.1](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-15)
**Note:** Version bump only for package @standardnotes/snjs
# [2.129.0](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-15)
### Features
* sharing subscriptions UI ([#1567](https://github.com/standardnotes/app/issues/1567)) ([2d0ee10](https://github.com/standardnotes/app/commit/2d0ee10226687df1d24926b9408ce270557a5b57))
## [2.128.1](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-09-15)
**Note:** Version bump only for package @standardnotes/snjs
+36 -6
View File
@@ -10,6 +10,10 @@ import {
UserRegistrationResponseBody,
UserServer,
UserServerInterface,
WebSocketApiService,
WebSocketApiServiceInterface,
WebSocketServer,
WebSocketServerInterface,
} from '@standardnotes/api'
import * as Common from '@standardnotes/common'
import * as ExternalServices from '@standardnotes/services'
@@ -41,6 +45,7 @@ import {
FileService,
SubscriptionClientInterface,
SubscriptionManager,
StorageValueModes,
} from '@standardnotes/services'
import { FilesClientInterface } from '@standardnotes/files'
import { ComputePrivateWorkspaceIdentifier } from '@standardnotes/encryption'
@@ -60,6 +65,7 @@ import { SNLog } from '../Log'
import { Challenge, ChallengeResponse } from '../Services'
import { ApplicationConstructorOptions, FullyResolvedApplicationOptions } from './Options/ApplicationOptions'
import { ApplicationOptionsDefaults } from './Options/Defaults'
import { MobileUnlockTiming } from '@Lib/Services/Protection/MobileUnlockTiming'
/** How often to automatically sync, in milliseconds */
const DEFAULT_AUTO_SYNC_INTERVAL = 30_000
@@ -106,6 +112,8 @@ export class SNApplication
private declare subscriptionApiService: SubscriptionApiServiceInterface
private declare subscriptionServer: SubscriptionServerInterface
private declare subscriptionManager: SubscriptionClientInterface
private declare webSocketApiService: WebSocketApiServiceInterface
private declare webSocketServer: WebSocketServerInterface
private sessionManager!: InternalServices.SNSessionManager
private syncService!: InternalServices.SNSyncService
private challengeService!: InternalServices.ChallengeService
@@ -322,11 +330,12 @@ export class SNApplication
)
}
}
await this.handleStage(ExternalServices.ApplicationStage.StorageDecrypted_09)
this.apiService.loadHost()
this.webSocketsService.loadWebSocketUrl()
this.sessionManager.initializeFromDisk()
await this.sessionManager.initializeFromDisk()
this.settingsService.initializeFromDisk()
@@ -927,20 +936,28 @@ export class SNApplication
return this.deinit(this.getDeinitMode(), DeinitSource.Lock)
}
async setBiometricsTiming(timing: InternalServices.MobileUnlockTiming) {
setBiometricsTiming(timing: MobileUnlockTiming) {
return this.protectionService.setBiometricsTiming(timing)
}
async getMobileScreenshotPrivacyEnabled(): Promise<boolean | undefined> {
getMobileScreenshotPrivacyEnabled(): boolean {
return this.protectionService.getMobileScreenshotPrivacyEnabled()
}
async setMobileScreenshotPrivacyEnabled(isEnabled: boolean) {
setMobileScreenshotPrivacyEnabled(isEnabled: boolean) {
return this.protectionService.setMobileScreenshotPrivacyEnabled(isEnabled)
}
async loadMobileUnlockTiming() {
return this.protectionService.loadMobileUnlockTiming()
getMobilePasscodeTiming(): MobileUnlockTiming | undefined {
return this.getValue(StorageKey.MobilePasscodeTiming, StorageValueModes.Nonwrapped) as
| MobileUnlockTiming
| undefined
}
getMobileBiometricsTiming(): MobileUnlockTiming | undefined {
return this.getValue(StorageKey.MobileBiometricsTiming, StorageValueModes.Nonwrapped) as
| MobileUnlockTiming
| undefined
}
getBiometricsTimingOptions() {
@@ -1079,6 +1096,8 @@ export class SNApplication
this.createUserApiService()
this.createSubscriptionServer()
this.createSubscriptionApiService()
this.createWebSocketServer()
this.createWebSocketApiService()
this.createSubscriptionManager()
this.createWebSocketsService()
this.createSessionManager()
@@ -1120,6 +1139,8 @@ export class SNApplication
;(this.userServer as unknown) = undefined
;(this.subscriptionApiService as unknown) = undefined
;(this.subscriptionServer as unknown) = undefined
;(this.webSocketApiService as unknown) = undefined
;(this.webSocketServer as unknown) = undefined
;(this.subscriptionManager as unknown) = undefined
;(this.sessionManager as unknown) = undefined
;(this.syncService as unknown) = undefined
@@ -1237,6 +1258,7 @@ export class SNApplication
this.webSocketsService = new InternalServices.SNWebSocketsService(
this.diskStorageService,
this.options.webSocketUrl,
this.webSocketApiService,
this.internalEventBus,
)
this.services.push(this.webSocketsService)
@@ -1322,6 +1344,14 @@ export class SNApplication
this.subscriptionServer = new SubscriptionServer(this.httpService)
}
private createWebSocketApiService() {
this.webSocketApiService = new WebSocketApiService(this.webSocketServer)
}
private createWebSocketServer() {
this.webSocketServer = new WebSocketServer(this.httpService)
}
private createSubscriptionManager() {
this.subscriptionManager = new SubscriptionManager(this.subscriptionApiService, this.internalEventBus)
}
@@ -0,0 +1,7 @@
export enum ReactNativeToWebEvent {
EnteringBackground = 'EnteringBackground',
ResumingFromBackground = 'ResumingFromBackground',
GainingFocus = 'GainingFocus',
LosingFocus = 'LosingFocus',
AndroidBackButtonPressed = 'AndroidBackButtonPressed',
}
+1
View File
@@ -2,3 +2,4 @@ export * from './IconsController'
export * from './NoteViewController'
export * from './FileViewController'
export * from './ItemGroupController'
export * from './ReactNativeToWebEvent'
@@ -1,4 +1,6 @@
import { InternalEventBusInterface } from '@standardnotes/services'
import { WebSocketApiServiceInterface } from '@standardnotes/api'
import { StorageKey, DiskStorageService } from '@Lib/index'
import { SNWebSocketsService } from './WebsocketsService'
@@ -6,10 +8,11 @@ describe('webSocketsService', () => {
const webSocketUrl = ''
let storageService: DiskStorageService
let webSocketApiService: WebSocketApiServiceInterface
let internalEventBus: InternalEventBusInterface
const createService = () => {
return new SNWebSocketsService(storageService, webSocketUrl, internalEventBus)
return new SNWebSocketsService(storageService, webSocketUrl, webSocketApiService, internalEventBus)
}
beforeEach(() => {
@@ -18,6 +21,9 @@ describe('webSocketsService', () => {
internalEventBus = {} as jest.Mocked<InternalEventBusInterface>
internalEventBus.publish = jest.fn()
webSocketApiService = {} as jest.Mocked<WebSocketApiServiceInterface>
webSocketApiService.createConnectionToken = jest.fn().mockReturnValue({ token: 'foobar' })
})
describe('setWebSocketUrl()', () => {
@@ -1,6 +1,8 @@
import { UserRolesChangedEvent } from '@standardnotes/domain-events'
import { DiskStorageService } from '../Storage/DiskStorageService'
import { AbstractService, InternalEventBusInterface, StorageKey } from '@standardnotes/services'
import { WebSocketApiServiceInterface } from '@standardnotes/api'
import { DiskStorageService } from '../Storage/DiskStorageService'
export enum WebSocketsServiceEvent {
UserRoleMessageReceived = 'WebSocketMessageReceived',
@@ -12,6 +14,7 @@ export class SNWebSocketsService extends AbstractService<WebSocketsServiceEvent,
constructor(
private storageService: DiskStorageService,
private webSocketUrl: string | undefined,
private webSocketApiService: WebSocketApiServiceInterface,
protected override internalEventBus: InternalEventBusInterface,
) {
super(internalEventBus)
@@ -34,10 +37,15 @@ export class SNWebSocketsService extends AbstractService<WebSocketsServiceEvent,
)._websocket_url
}
public startWebSocketConnection(authToken: string): void {
async startWebSocketConnection(): Promise<void> {
const webSocketConectionToken = await this.createWebSocketConnectionToken()
if (webSocketConectionToken === undefined) {
return
}
if (this.webSocketUrl) {
try {
this.webSocket = new WebSocket(`${this.webSocketUrl}?authToken=Bearer+${authToken}`)
this.webSocket = new WebSocket(`${this.webSocketUrl}?authToken=${webSocketConectionToken}`)
this.webSocket.onmessage = this.onWebSocketMessage.bind(this)
this.webSocket.onclose = this.onWebSocketClose.bind(this)
} catch (e) {
@@ -59,9 +67,22 @@ export class SNWebSocketsService extends AbstractService<WebSocketsServiceEvent,
this.webSocket = undefined
}
private async createWebSocketConnectionToken(): Promise<string | undefined> {
try {
const response = await this.webSocketApiService.createConnectionToken()
return response.data.token
} catch (error) {
console.error((error as Error).message)
return undefined
}
}
override deinit(): void {
super.deinit()
;(this.storageService as unknown) = undefined
;(this.webSocketApiService as unknown) = undefined
this.closeWebSocketConnection()
}
}
@@ -0,0 +1,4 @@
export enum MobileUnlockTiming {
Immediately = 'immediately',
OnQuit = 'on-quit',
}
@@ -18,17 +18,13 @@ import {
} from '@standardnotes/services'
import { ProtectionsClientInterface } from './ClientInterface'
import { ContentType } from '@standardnotes/common'
import { MobileUnlockTiming } from './MobileUnlockTiming'
export enum ProtectionEvent {
UnprotectedSessionBegan = 'UnprotectedSessionBegan',
UnprotectedSessionExpired = 'UnprotectedSessionExpired',
}
export enum MobileUnlockTiming {
Immediately = 'immediately',
OnQuit = 'on-quit',
}
export const ProposedSecondsToDeferUILevelSessionExpirationDuringActiveInteraction = 30
export enum UnprotectedAccessSecondsDuration {
@@ -91,6 +87,8 @@ export class SNProtectionService extends AbstractService<ProtectionEvent> implem
override handleApplicationStage(stage: ApplicationStage): Promise<void> {
if (stage === ApplicationStage.LoadedDatabase_12) {
this.updateSessionExpiryTimer(this.getSessionExpiryDate())
this.mobilePasscodeTiming = this.getPasscodeTiming()
this.mobileBiometricsTiming = this.getBiometricsTiming()
}
return Promise.resolve()
}
@@ -261,36 +259,31 @@ export class SNProtectionService extends AbstractService<ProtectionEvent> implem
]
}
private async getBiometricsTiming(): Promise<MobileUnlockTiming | undefined> {
return this.storageService.getValue<Promise<MobileUnlockTiming | undefined>>(
private getBiometricsTiming(): MobileUnlockTiming | undefined {
return this.storageService.getValue<MobileUnlockTiming | undefined>(
StorageKey.MobileBiometricsTiming,
StorageValueModes.Nonwrapped,
)
}
private async getPasscodeTiming(): Promise<MobileUnlockTiming | undefined> {
return this.storageService.getValue<Promise<MobileUnlockTiming | undefined>>(
private getPasscodeTiming(): MobileUnlockTiming | undefined {
return this.storageService.getValue<MobileUnlockTiming | undefined>(
StorageKey.MobilePasscodeTiming,
StorageValueModes.Nonwrapped,
)
}
async setBiometricsTiming(timing: MobileUnlockTiming) {
await this.storageService.setValue(StorageKey.MobileBiometricsTiming, timing, StorageValueModes.Nonwrapped)
this.storageService.setValue(StorageKey.MobileBiometricsTiming, timing, StorageValueModes.Nonwrapped)
this.mobileBiometricsTiming = timing
}
async setMobileScreenshotPrivacyEnabled(isEnabled: boolean) {
setMobileScreenshotPrivacyEnabled(isEnabled: boolean) {
return this.storageService.setValue(StorageKey.MobileScreenshotPrivacyEnabled, isEnabled, StorageValueModes.Default)
}
async getMobileScreenshotPrivacyEnabled(): Promise<boolean | undefined> {
return this.storageService.getValue(StorageKey.MobileScreenshotPrivacyEnabled, StorageValueModes.Default)
}
async loadMobileUnlockTiming() {
this.mobilePasscodeTiming = await this.getPasscodeTiming()
this.mobileBiometricsTiming = await this.getBiometricsTiming()
getMobileScreenshotPrivacyEnabled(): boolean {
return this.storageService.getValue(StorageKey.MobileScreenshotPrivacyEnabled, StorageValueModes.Default, false)
}
private async validateOrRenewSession(
@@ -1,2 +1,3 @@
export * from './ClientInterface'
export * from './ProtectionService'
export * from './MobileUnlockTiming'
@@ -107,7 +107,7 @@ export class SNSessionManager extends AbstractService<SessionEvent> implements S
this.apiService.setUser(user)
}
public initializeFromDisk() {
async initializeFromDisk() {
this.setUser(this.diskStorageService.getValue(StorageKey.User))
if (!this.user) {
@@ -121,11 +121,13 @@ export class SNSessionManager extends AbstractService<SessionEvent> implements S
if (rawSession) {
const session = SessionFromRawStorageValue(rawSession)
this.setSession(session, false)
this.webSocketsService.startWebSocketConnection(session.authorizationValue)
await this.webSocketsService.startWebSocketConnection()
}
}
private setSession(session: Session, persist = true): void {
this.httpService.setAuthorizationToken(session.authorizationValue)
this.apiService.setSession(session, persist)
}
@@ -621,11 +623,9 @@ export class SNSessionManager extends AbstractService<SessionEvent> implements S
this.httpService.setHost(host)
this.httpService.setAuthorizationToken(session.authorizationValue)
this.setSession(session)
await this.setSession(session)
this.webSocketsService.startWebSocketConnection(session.authorizationValue)
await this.webSocketsService.startWebSocketConnection()
}
private async handleAuthResponse(body: UserRegistrationResponseBody, rootKey: SNRootKey, wrappingKey?: SNRootKey) {
@@ -11,6 +11,7 @@ import {
ListedAuthorSecretsData,
LogSessionUserAgentOption,
SettingName,
MuteMarketingEmailsOption,
} from '@standardnotes/settings'
type SettingType =
@@ -23,6 +24,7 @@ type SettingType =
| MuteFailedBackupsEmailsOption
| MuteFailedCloudBackupsEmailsOption
| MuteSignInEmailsOption
| MuteMarketingEmailsOption
| OneDriveBackupFrequency
export class SettingsList {

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