Compare commits

...

170 Commits

Author SHA1 Message Date
standardci
22b00479b4 chore(release): publish new version
- @standardnotes/analytics@2.25.9
 - @standardnotes/api-gateway@1.70.1
 - @standardnotes/auth-server@1.131.0
 - @standardnotes/domain-events-infra@1.12.11
 - @standardnotes/domain-events@2.115.0
 - @standardnotes/event-store@1.11.16
 - @standardnotes/files-server@1.20.0
 - @standardnotes/home-server@1.13.34
 - @standardnotes/revisions-server@1.26.3
 - @standardnotes/scheduler-server@1.20.18
 - @standardnotes/security@1.9.0
 - @standardnotes/syncing-server@1.77.0
 - @standardnotes/websockets-server@1.10.13
2023-08-08 12:06:10 +00:00
Karol Sójko
5311e74266 feat: update storage quota used for user based on shared vault files (#689)
* feat: update storage quota used for user based on shared vault files

* fix: use case binding

* fix: increase file upload bytes limit for shared vaults
2023-08-08 13:36:35 +02:00
standardci
5be7db7788 chore(release): publish new version
- @standardnotes/home-server@1.13.33
 - @standardnotes/syncing-server@1.76.1
2023-08-08 09:29:54 +00:00
Karol Sójko
3bd1547ce3 fix(syncing-server): race condition when adding admin user to newly created shared vault (#688) 2023-08-08 11:02:10 +02:00
standardci
a1fe15f7a9 chore(release): publish new version
- @standardnotes/api-gateway@1.70.0
 - @standardnotes/home-server@1.13.32
 - @standardnotes/syncing-server@1.76.0
2023-08-07 16:09:21 +00:00
Karol Sójko
19b8921f28 feat(syncing-server): limit shared vaults creation based on role (#687)
* feat(syncing-server): limit shared vaults creation based on role

* fix: add role names emptyness validation

* fix: roles passing to response locals
2023-08-07 17:35:47 +02:00
standardci
6b7879ba15 chore(release): publish new version
- @standardnotes/auth-server@1.130.1
 - @standardnotes/home-server@1.13.31
2023-08-07 11:50:26 +00:00
Karol Sójko
bd5f492a73 fix(auth): update user agent upon refreshing session token (#685) 2023-08-07 13:21:21 +02:00
standardci
67311cc002 chore(release): publish new version
- @standardnotes/auth-server@1.130.0
 - @standardnotes/home-server@1.13.30
2023-08-07 08:32:08 +00:00
Karol Sójko
f39d3aca5b feat(auth): invalidate other sessions for user if the email or password are changed (#684)
* feat(auth): invalidate other sessions for user if the email or password are changed

* fix(auth): handling credentials change in a legacy protocol scenario

* fix(auth): leave only the newly created session when changing credentials
2023-08-07 10:02:47 +02:00
standardci
8e47491e3c chore(release): publish new version
- @standardnotes/home-server@1.13.29
 - @standardnotes/syncing-server@1.75.4
2023-08-03 13:38:37 +00:00
Karol Sójko
0036d527bd fix(syncing-server): skip retrieval of items with invalid uuids (#683) 2023-08-03 15:05:59 +02:00
standardci
f565f1d950 chore(release): publish new version
- @standardnotes/analytics@2.25.8
 - @standardnotes/api-gateway@1.69.3
 - @standardnotes/auth-server@1.129.0
 - @standardnotes/domain-events-infra@1.12.10
 - @standardnotes/domain-events@2.114.0
 - @standardnotes/event-store@1.11.15
 - @standardnotes/files-server@1.19.18
 - @standardnotes/home-server@1.13.28
 - @standardnotes/revisions-server@1.26.2
 - @standardnotes/scheduler-server@1.20.17
 - @standardnotes/syncing-server@1.75.3
 - @standardnotes/websockets-server@1.10.12
2023-08-03 10:34:26 +00:00
Karol Sójko
8e35dfa4b7 feat(auth): add handling payments account deleted events STA-1769 (#682)
* feat(auth): add handling payments account deleted events

* fix(auth): result type for accounts already deleted

---------

Co-authored-by: Karol Sójko <karolsojko@proton.me>
2023-08-03 12:01:42 +02:00
standardci
f911473be9 chore(release): publish new version
- @standardnotes/analytics@2.25.7
 - @standardnotes/api-gateway@1.69.2
 - @standardnotes/auth-server@1.128.1
 - @standardnotes/domain-core@1.24.2
 - @standardnotes/event-store@1.11.14
 - @standardnotes/files-server@1.19.17
 - @standardnotes/home-server@1.13.27
 - @standardnotes/revisions-server@1.26.1
 - @standardnotes/scheduler-server@1.20.16
 - @standardnotes/settings@1.21.21
 - @standardnotes/syncing-server@1.75.2
 - @standardnotes/websockets-server@1.10.11
2023-08-02 15:51:56 +00:00
Karol Sójko
71624f1897 fix(domain-core): remove unused content types 2023-08-02 17:34:40 +02:00
standardci
17de6ea7e1 chore(release): publish new version
- @standardnotes/home-server@1.13.26
 - @standardnotes/syncing-server@1.75.1
2023-08-02 11:41:20 +00:00
Karol Sójko
6aad7cd207 fix(syncing-server): update unknown content type on items migration 2023-08-02 13:24:14 +02:00
standardci
63af335877 chore(release): publish new version
- @standardnotes/auth-server@1.128.0
 - @standardnotes/home-server@1.13.25
 - @standardnotes/revisions-server@1.26.0
 - @standardnotes/syncing-server@1.75.0
2023-08-02 08:09:24 +00:00
Karol Sójko
8cd7a138ab feat: enable Write Ahead Log mode for SQLite (#681)
Co-authored-by: Karol Sójko <karolsojko@proton.me>
2023-08-02 09:47:37 +02:00
standardci
f69cdc7b03 chore(release): publish new version
- @standardnotes/home-server@1.13.24
 - @standardnotes/syncing-server@1.74.1
 - @standardnotes/websockets-server@1.10.10
2023-08-02 07:35:12 +00:00
Karol Sójko
2ca649cf31 fix(syncing-server): encapsulate delete queries into transactions 2023-08-02 08:35:19 +02:00
Mo
f2ada08201 chore: remove unused package (#680) 2023-08-02 07:46:10 +02:00
Mo
54ba1f69e5 chore: bump mocha timeout 2023-08-01 16:46:19 -05:00
standardci
f13a99f5fd chore(release): publish new version
- @standardnotes/home-server@1.13.23
 - @standardnotes/syncing-server@1.74.0
2023-08-01 16:32:29 +00:00
Karol Sójko
e9bba6fd3a feat(syncing-server): remove legacy privileges items (#679)
Co-authored-by: Karol Sójko <karolsojko@proton.me>
2023-08-01 18:15:16 +02:00
standardci
f0d1a70c87 chore(release): publish new version
- @standardnotes/auth-server@1.127.2
 - @standardnotes/files-server@1.19.16
 - @standardnotes/home-server@1.13.22
 - @standardnotes/revisions-server@1.25.7
 - @standardnotes/syncing-server@1.73.1
 - @standardnotes/websockets-server@1.10.9
2023-08-01 07:53:07 +00:00
Karol Sójko
56f0aef21d fix: controller naming (#678)
* fix: rename home server controllers to base controllers

* fix: rename inversify express controllers to annotated controllers
2023-08-01 09:34:52 +02:00
standardci
75e266cb9e chore(release): publish new version
- @standardnotes/home-server@1.13.21
 - @standardnotes/syncing-server@1.73.0
2023-08-01 05:16:33 +00:00
Karol Sójko
b9bb83c0ce feat(syncing-server): add shared vault snjs filter (#677)
Co-authored-by: Mo <mo@standardnotes.com>
2023-08-01 07:00:14 +02:00
standardci
da645c5ab3 chore(release): publish new version
- @standardnotes/auth-server@1.127.1
 - @standardnotes/home-server@1.13.20
2023-07-31 13:33:09 +00:00
Karol Sójko
318af5757d fix(auth): auth middleware on delete account 2023-07-31 15:09:52 +02:00
standardci
b1cc156a25 chore(release): publish new version
- @standardnotes/api-gateway@1.69.1
 - @standardnotes/home-server@1.13.19
2023-07-31 12:35:22 +00:00
Karol Sójko
79d71ca161 fix(api-gateway): remove duplicating req/res objects on return raw response from payments 2023-07-31 14:19:01 +02:00
standardci
cedd50b366 chore(release): publish new version
- @standardnotes/api-gateway@1.69.0
 - @standardnotes/auth-server@1.127.0
 - @standardnotes/home-server@1.13.18
2023-07-31 11:41:55 +00:00
Karol Sójko
0d5dcdd8ec feat: refactor deleting account (#676)
* fix(api-gateway): TYPES aliases

* feat: refactor account deleting
2023-07-31 13:23:39 +02:00
standardci
d2b0fb144b chore(release): publish new version
- @standardnotes/home-server@1.13.17
 - @standardnotes/syncing-server@1.72.2
2023-07-30 13:24:19 +00:00
Mo
053852b46c fix: missing var reference and brackets (#675) 2023-07-30 08:09:23 -05:00
Karol Sójko
6ad349d379 fix: db name encapsulation 2023-07-28 13:32:13 +02:00
Karol Sójko
f7d33c7164 fix: separate databases and redis instances 2023-07-28 12:00:17 +02:00
Karol Sójko
b53b67328f fix: displaying logs on docker failure 2023-07-28 11:23:16 +02:00
Karol Sójko
573ffbfcf3 fix: add showing logs on docker error 2023-07-28 10:19:32 +02:00
Karol Sójko
501ac0e99f fix: env vars for database runs 2023-07-27 14:32:55 +02:00
Karol Sójko
959a11293a fix: separate database for different configuration 2023-07-27 14:19:21 +02:00
standardci
fee1f1a3a7 chore(release): publish new version
- @standardnotes/analytics@2.25.6
 - @standardnotes/api-gateway@1.68.1
 - @standardnotes/auth-server@1.126.5
 - @standardnotes/domain-core@1.24.1
 - @standardnotes/event-store@1.11.13
 - @standardnotes/files-server@1.19.15
 - @standardnotes/home-server@1.13.16
 - @standardnotes/revisions-server@1.25.6
 - @standardnotes/scheduler-server@1.20.15
 - @standardnotes/settings@1.21.20
 - @standardnotes/syncing-server@1.72.1
 - @standardnotes/websockets-server@1.10.8
2023-07-27 11:10:28 +00:00
Karol Sójko
b0fbe0bb58 fix: extended access token refresh ttl during home server e2e 2023-07-27 12:54:50 +02:00
Karol Sójko
0087c70007 fix: missing env var on e2e 2023-07-27 12:25:31 +02:00
Karol Sójko
36e496dd7c fix: remove dns aliases on accessing mysql and redis in home server e2e 2023-07-27 12:19:01 +02:00
Karol Sójko
f2e2030e85 fix: disable fail-fast on common e2e suite 2023-07-27 12:11:38 +02:00
Karol Sójko
0c3737dc19 fix: redirect STDERR for e2e to common output 2023-07-27 12:07:32 +02:00
Karol Sójko
f7471119e1 fix: add logging error stack on home server failure 2023-07-27 12:00:40 +02:00
Karol Sójko
9bd97b95e9 fix: unset the custom dbsqlite path for e2e 2023-07-27 11:46:48 +02:00
Karol Sójko
b7400c198f fix: setting env vars on common-e2e test suite 2023-07-27 11:30:49 +02:00
Karol Sójko
f87036e3a8 fix: setting env vars on home server in e2e environment 2023-07-27 11:26:05 +02:00
Karol Sójko
a43e5ef724 fix: outputing logs on e2e - already existing logs directory 2023-07-27 10:32:43 +02:00
Karol Sójko
913ced70b0 fix: outputing logs on e2e 2023-07-27 08:33:49 +02:00
standardci
6ffce30a36 chore(release): publish new version
- @standardnotes/api-gateway@1.68.0
 - @standardnotes/home-server@1.13.15
 - @standardnotes/syncing-server@1.72.0
2023-07-27 06:28:46 +00:00
Karol Sójko
f5a57d886c fix: show logs on failing suite 2023-07-27 08:13:49 +02:00
Karol Sójko
e8ba49ecca feat(syncing-server): add deleting outbound messages
Co-authored-by: Mo <mo@standardnotes.com>
2023-07-27 08:06:56 +02:00
Karol Sójko
c79a5dc94b fix: add e2e yarn command for convenience 2023-07-26 15:23:08 +02:00
standardci
4db83ae678 chore(release): publish new version
- @standardnotes/analytics@2.25.5
 - @standardnotes/api-gateway@1.67.4
 - @standardnotes/auth-server@1.126.4
 - @standardnotes/domain-core@1.24.0
 - @standardnotes/event-store@1.11.12
 - @standardnotes/files-server@1.19.14
 - @standardnotes/home-server@1.13.14
 - @standardnotes/revisions-server@1.25.5
 - @standardnotes/scheduler-server@1.20.14
 - @standardnotes/settings@1.21.19
 - @standardnotes/syncing-server@1.71.0
 - @standardnotes/websockets-server@1.10.7
2023-07-26 12:07:57 +00:00
basiljelly
84ceb7ffd2 Update docker-compose.example.yml (#673)
added restart policy for container server_self_hosted so it restarts after rebooting system
2023-07-26 13:52:40 +02:00
Karol Sójko
e215ac4343 feat: extract shared vault user permission to domain-core 2023-07-26 13:45:53 +02:00
standardci
bc8048790f chore(release): publish new version
- @standardnotes/home-server@1.13.13
 - @standardnotes/syncing-server@1.70.5
2023-07-26 11:19:11 +00:00
Karol Sójko
886ccf84c1 fix(syncing-server): uuid comparison when removing user 2023-07-26 13:02:03 +02:00
standardci
c067cb9fe4 chore(release): publish new version
- @standardnotes/home-server@1.13.12
 - @standardnotes/syncing-server@1.70.4
2023-07-26 10:54:46 +00:00
Karol Sójko
6b2389cdc3 fix(syncing-serve): removing other users from shared vault 2023-07-26 12:39:24 +02:00
standardci
d93916b159 chore(release): publish new version
- @standardnotes/analytics@2.25.4
 - @standardnotes/api-gateway@1.67.3
 - @standardnotes/auth-server@1.126.3
 - @standardnotes/domain-core@1.23.4
 - @standardnotes/event-store@1.11.11
 - @standardnotes/files-server@1.19.13
 - @standardnotes/home-server@1.13.11
 - @standardnotes/revisions-server@1.25.4
 - @standardnotes/scheduler-server@1.20.13
 - @standardnotes/settings@1.21.18
 - @standardnotes/syncing-server@1.70.3
 - @standardnotes/websockets-server@1.10.6
2023-07-26 10:38:44 +00:00
Karol Sójko
c34f548e45 fix(syncing-server): persisting aggregate changes from root (#674) 2023-07-26 12:23:10 +02:00
standardci
6fcd56cc86 chore(release): publish new version
- @standardnotes/home-server@1.13.10
 - @standardnotes/syncing-server@1.70.2
2023-07-25 14:07:10 +00:00
Karol Sójko
8f88a87c93 fix(syncing-server): remove notifications after adding item to vault (#672) 2023-07-25 15:51:42 +02:00
standardci
f8c2f84322 chore(release): publish new version
- @standardnotes/home-server@1.13.9
 - @standardnotes/syncing-server@1.70.1
2023-07-25 11:25:55 +00:00
Karol Sójko
46c4947871 fix(syncing-server): allow sender to decline the invite (#671) 2023-07-25 13:05:10 +02:00
standardci
64759ec2da chore(release): publish new version
- @standardnotes/home-server@1.13.8
 - @standardnotes/syncing-server@1.70.0
2023-07-25 11:03:19 +00:00
Karol Sójko
5f7e768e64 feat(syncing-server): filtering items by shared vault permissions (#670)
Co-authored-by: Mo <mo@standardnotes.com>
2023-07-25 12:45:49 +02:00
standardci
4bc189f1c5 chore(release): publish new version
- @standardnotes/home-server@1.13.7
 - @standardnotes/syncing-server@1.69.0
2023-07-24 14:29:21 +00:00
Karol Sójko
71721ab198 feat(syncing-server): determin shared vault operation type (#669)
Co-authored-by: Mo <mo@standardnotes.com>
2023-07-24 15:29:56 +02:00
standardci
5536a48966 chore(release): publish new version
- @standardnotes/home-server@1.13.6
 - @standardnotes/syncing-server@1.68.4
2023-07-24 09:15:15 +00:00
Karol Sójko
f77e29d3c9 fix(syncing-server): force remove shared vault owner when removing shared vault 2023-07-24 10:59:03 +02:00
standardci
4b1fc718a2 chore(release): publish new version
- @standardnotes/analytics@2.25.3
 - @standardnotes/api-gateway@1.67.2
 - @standardnotes/auth-server@1.126.2
 - @standardnotes/domain-core@1.23.3
 - @standardnotes/event-store@1.11.10
 - @standardnotes/files-server@1.19.12
 - @standardnotes/home-server@1.13.5
 - @standardnotes/revisions-server@1.25.3
 - @standardnotes/scheduler-server@1.20.12
 - @standardnotes/settings@1.21.17
 - @standardnotes/syncing-server@1.68.3
 - @standardnotes/websockets-server@1.10.5
2023-07-21 12:03:05 +00:00
Karol Sójko
1708c3f8a0 fix(domain-core): notification payload creation from string 2023-07-21 13:44:44 +02:00
standardci
352e02028d chore(release): publish new version
- @standardnotes/analytics@2.25.2
 - @standardnotes/api-gateway@1.67.1
 - @standardnotes/auth-server@1.126.1
 - @standardnotes/domain-core@1.23.2
 - @standardnotes/event-store@1.11.9
 - @standardnotes/files-server@1.19.11
 - @standardnotes/home-server@1.13.4
 - @standardnotes/revisions-server@1.25.2
 - @standardnotes/scheduler-server@1.20.11
 - @standardnotes/settings@1.21.16
 - @standardnotes/syncing-server@1.68.2
 - @standardnotes/websockets-server@1.10.4
2023-07-21 10:53:53 +00:00
Karol Sójko
1bbb639c83 fix: user notifications structure (#667) 2023-07-21 12:39:19 +02:00
standardci
c14265f103 chore(release): publish new version
- @standardnotes/home-server@1.13.3
 - @standardnotes/syncing-server@1.68.1
2023-07-21 07:37:04 +00:00
Karol Sójko
c030a6b3d8 fix(syncing-server): fetching items associated with shared vaults (#666) 2023-07-20 14:29:31 +02:00
standardci
af997ea658 chore(release): publish new version
- @standardnotes/api-gateway@1.67.0
 - @standardnotes/auth-server@1.126.0
 - @standardnotes/home-server@1.13.2
 - @standardnotes/syncing-server@1.68.0
2023-07-20 10:07:30 +00:00
Karol Sójko
efa4d7fc60 feat(syncing-server): add shared vaults, invites, messages and notifications to sync response (#665)
* feat(syncing-server): add shared vaults, invites, messages and notifications to sync response

* fix(syncing-server): migration timestamps

* fix: issue with migrations for notifications
2023-07-20 11:52:45 +02:00
standardci
f714aaa0e9 chore(release): publish new version
- @standardnotes/api-gateway@1.66.1
 - @standardnotes/home-server@1.13.1
 - @standardnotes/syncing-server@1.67.1
2023-07-19 07:42:57 +00:00
Karol Sójko
aee6e60583 fix: add missing imports and exports for controllers (#664) 2023-07-19 09:28:09 +02:00
standardci
4e602687d5 chore(release): publish new version
- @standardnotes/analytics@2.25.1
 - @standardnotes/api-gateway@1.66.0
 - @standardnotes/auth-server@1.125.1
 - @standardnotes/domain-core@1.23.1
 - @standardnotes/event-store@1.11.8
 - @standardnotes/files-server@1.19.10
 - @standardnotes/home-server@1.13.0
 - @standardnotes/revisions-server@1.25.1
 - @standardnotes/scheduler-server@1.20.10
 - @standardnotes/settings@1.21.15
 - @standardnotes/syncing-server@1.67.0
 - @standardnotes/websockets-server@1.10.3
2023-07-19 06:47:26 +00:00
Karol Sójko
d026152ac8 fix(syncing-server): add missing messages and key system identifier sql representations (#663) 2023-07-19 08:31:23 +02:00
Karol Sójko
3f21a358d2 feat(syncing-server): add persistence of shared vaults with users and invites + controllers (#662)
* feat(syncing-server): associating existing items with key systems and shared vaults

* fix(syncing-server): find item query

* feat(syncing-server): add persistence of shared vaults with users and invites

* feat: shared vault controllers
2023-07-19 07:28:03 +02:00
standardci
dc55e47c98 chore(release): publish new version
- @standardnotes/home-server@1.12.6
 - @standardnotes/syncing-server@1.66.0
2023-07-18 11:39:37 +00:00
Karol Sójko
3b804e2321 feat(syncing-server): associating existing items with key systems and shared vaults (#661)
* feat(syncing-server): associating existing items with key systems and shared vaults

* fix(syncing-server): find item query

* feat(syncing-server): add persistence of shared vaults with users and invites
2023-07-18 13:21:30 +02:00
standardci
b32f851a90 chore(release): publish new version
- @standardnotes/home-server@1.12.5
 - @standardnotes/syncing-server@1.65.0
2023-07-18 09:55:28 +00:00
Karol Sójko
479d20e76f feat(syncing-server): persisting shared vault and key system associations (#660) 2023-07-18 11:39:02 +02:00
standardci
fae4553fc8 chore(release): publish new version
- @standardnotes/analytics@2.25.0
 - @standardnotes/api-gateway@1.65.7
 - @standardnotes/auth-server@1.125.0
 - @standardnotes/domain-core@1.23.0
 - @standardnotes/event-store@1.11.7
 - @standardnotes/files-server@1.19.9
 - @standardnotes/home-server@1.12.4
 - @standardnotes/revisions-server@1.25.0
 - @standardnotes/scheduler-server@1.20.9
 - @standardnotes/settings@1.21.14
 - @standardnotes/syncing-server@1.64.0
 - @standardnotes/websockets-server@1.10.2
2023-07-17 11:46:13 +00:00
Karol Sójko
cb74b23e45 feat(syncing-server): refactor syncing to decouple getting and saving items (#659)
* feat(syncing-server): refactor syncing to decouple getting and saving items

* fix(syncing-server): item hash http representation mapping

* fix(syncing-server): remove redundant specs for inversify express controller
2023-07-17 13:28:50 +02:00
Karol Sójko
af8f12c33a fix: remove skip_paid_features flag from home server e2e testing 2023-07-14 10:30:22 +02:00
standardci
a148c4d1f6 chore(release): publish new version
- @standardnotes/auth-server@1.124.2
 - @standardnotes/home-server@1.12.3
2023-07-14 08:14:31 +00:00
Karol Sójko
f7190c0c9c fix(home-server): allow custom atributtes for activating premium features 2023-07-14 09:59:20 +02:00
Karol Sójko
c00d7765a9 fix: add missing files server url env var to e2e test suite 2023-07-14 09:34:31 +02:00
standardci
2b651d86e2 chore(release): publish new version
- @standardnotes/auth-server@1.124.1
 - @standardnotes/files-server@1.19.8
 - @standardnotes/home-server@1.12.2
2023-07-13 12:30:31 +00:00
Karol Sójko
9be3517093 fix(files): handling unlimited storage quota on home server 2023-07-13 14:16:05 +02:00
standardci
fcfedaf7e7 chore(release): publish new version
- @standardnotes/auth-server@1.124.0
 - @standardnotes/home-server@1.12.1
2023-07-13 12:08:15 +00:00
Karol Sójko
0b82794e9c feat(auth): add overriding subscription settings on home server (#656) 2023-07-13 13:53:33 +02:00
standardci
2a52e398cb chore(release): publish new version
- @standardnotes/home-server@1.12.0
2023-07-13 09:22:59 +00:00
Karol Sójko
c31e882ad2 chore: fix workflow to run e2e test suite mode in home server 2023-07-13 11:05:37 +02:00
Karol Sójko
2f0903e0eb feat(home-server): add activating premium features during an e2e test suite run 2023-07-13 10:58:35 +02:00
standardci
2396053bc1 chore(release): publish new version
- @standardnotes/auth-server@1.123.2
 - @standardnotes/files-server@1.19.7
 - @standardnotes/home-server@1.11.41
 - @standardnotes/revisions-server@1.24.1
 - @standardnotes/sncrypto-node@1.15.3
 - @standardnotes/syncing-server@1.63.1
 - @standardnotes/websockets-server@1.10.1
2023-07-12 12:42:08 +00:00
Karol Sójko
17fd12305e chore(deps): upgrade @standardnotes deps 2023-07-12 14:25:23 +02:00
standardci
425ea4374d chore(release): publish new version
- @standardnotes/auth-server@1.123.1
 - @standardnotes/home-server@1.11.40
2023-07-12 09:20:55 +00:00
Karol Sójko
c076c3c74a chore(deps): upgrade @standardnotes/features 2023-07-12 11:05:44 +02:00
standardci
547cdfd8ec chore(release): publish new version
- @standardnotes/analytics@2.24.9
 - @standardnotes/api-gateway@1.65.6
 - @standardnotes/auth-server@1.123.0
 - @standardnotes/common@1.50.0
 - @standardnotes/domain-core@1.22.0
 - @standardnotes/event-store@1.11.6
 - @standardnotes/files-server@1.19.6
 - @standardnotes/home-server@1.11.39
 - @standardnotes/revisions-server@1.24.0
 - @standardnotes/scheduler-server@1.20.8
 - @standardnotes/settings@1.21.13
 - @standardnotes/syncing-server@1.63.0
 - @standardnotes/websockets-server@1.10.0
2023-07-12 08:34:32 +00:00
Karol Sójko
a0af8f0025 feat: domain items (#655)
* feat: content type as a value object

* feat: turn items into domain entities

* fix: update @standardnotes/api

* fix(syncing-server): bindings order
2023-07-12 10:19:22 +02:00
standardci
c970b1ea68 chore(release): publish new version
- @standardnotes/home-server@1.11.38
 - @standardnotes/syncing-server@1.62.1
2023-07-11 15:22:11 +00:00
Karol Sójko
4d1e2dec26 fix: unify use case usage (#654) 2023-07-11 17:05:45 +02:00
standardci
108408a944 chore(release): publish new version
- @standardnotes/home-server@1.11.37
 - @standardnotes/syncing-server@1.62.0
2023-07-10 12:37:48 +00:00
Karol Sójko
18d07d431f feat: messages controller. (#653)
Co-authored-by: Mo <mo@standardnotes.com>
2023-07-10 14:21:59 +02:00
standardci
cbc024f67a chore(release): publish new version
- @standardnotes/home-server@1.11.36
 - @standardnotes/syncing-server@1.61.0
2023-07-10 11:54:54 +00:00
Karol Sójko
55ec5970da feat: message operations use cases. (#652)
Co-authored-by: Mo <mo@standardnotes.com>
2023-07-10 13:38:07 +02:00
standardci
58bdca6659 chore(release): publish new version
- @standardnotes/home-server@1.11.35
 - @standardnotes/syncing-server@1.60.0
2023-07-10 11:25:21 +00:00
Karol Sójko
ef49b0d3f8 feat: sending messages. (#651)
* feat: sending messages.

Co-authored-by: Mo <mo@standardnotes.com>

* fix: messages repository.

Co-authored-by: Mo <mo@standardnotes.com>

---------

Co-authored-by: Mo <mo@standardnotes.com>
2023-07-10 13:10:31 +02:00
standardci
9cb691e5ad chore(release): publish new version
- @standardnotes/home-server@1.11.34
 - @standardnotes/syncing-server@1.59.1
2023-07-10 10:58:38 +00:00
Karol Sójko
04d09582d4 fix: restructure use cases (#650) 2023-07-10 12:43:20 +02:00
standardci
8f90dc172b chore(release): publish new version
- @standardnotes/home-server@1.11.33
 - @standardnotes/syncing-server@1.59.0
2023-07-10 10:27:47 +00:00
Karol Sójko
f759261919 feat: user to user message model. (#649)
Co-authored-by: Mo <mo@standardnotes.com>
2023-07-10 12:10:25 +02:00
standardci
2606f6d929 chore(release): publish new version
- @standardnotes/analytics@2.24.8
 - @standardnotes/api-gateway@1.65.5
 - @standardnotes/auth-server@1.122.2
 - @standardnotes/domain-core@1.21.1
 - @standardnotes/domain-events-infra@1.12.9
 - @standardnotes/domain-events@2.113.1
 - @standardnotes/event-store@1.11.5
 - @standardnotes/files-server@1.19.5
 - @standardnotes/home-server@1.11.32
 - @standardnotes/revisions-server@1.23.9
 - @standardnotes/scheduler-server@1.20.7
 - @standardnotes/settings@1.21.12
 - @standardnotes/syncing-server@1.58.1
 - @standardnotes/websockets-server@1.9.8
2023-07-07 13:30:56 +00:00
Karol Sójko
c288e5d8dc fix: transfer notifications from auth to syncing-server. (#648)
* fix: transfer notifications from auth to syncing-server.

Co-authored-by: Mo <mo@standardnotes.com>

* fix: add notification to data source init

---------

Co-authored-by: Mo <mo@standardnotes.com>
2023-07-07 15:12:27 +02:00
standardci
4b76d4b71e chore(release): publish new version
- @standardnotes/home-server@1.11.31
 - @standardnotes/syncing-server@1.58.0
2023-07-07 11:53:44 +00:00
Karol Sójko
72310130d2 feat: shared vault invites controller and use cases (#647)
* feat: get shared vault invites sent by user.

Co-authored-by: Mo <mo@standardnotes.com>

* feat: shared vault invites controller.

Co-authored-by: Mo <mo@standardnotes.com>

---------

Co-authored-by: Mo <mo@standardnotes.com>
2023-07-07 13:39:43 +02:00
standardci
f9e51ef06e chore(release): publish new version
- @standardnotes/home-server@1.11.30
 - @standardnotes/syncing-server@1.57.0
2023-07-06 12:09:05 +00:00
Karol Sójko
92a5eb0d98 feat: remove inbound shared vault invites. (#646)
Co-authored-by: Mo <mo@standardnotes.com>
2023-07-06 13:53:52 +02:00
standardci
77d2ea1a1f chore(release): publish new version
- @standardnotes/home-server@1.11.29
 - @standardnotes/syncing-server@1.56.0
2023-07-06 11:06:03 +00:00
Karol Sójko
92f96ddb84 feat: accept and decline shared vault invites (#645)
* feat: accept shared vault invite.

Co-authored-by: Mo <mo@standardnotes.com>

* feat: decline shared vault invite.

Co-authored-by: Mo <mo@standardnotes.com>

---------

Co-authored-by: Mo <mo@standardnotes.com>
2023-07-06 12:47:48 +02:00
standardci
15a914e25e chore(release): publish new version
- @standardnotes/home-server@1.11.28
 - @standardnotes/syncing-server@1.55.0
2023-07-06 10:12:49 +00:00
Karol Sójko
912a29d091 feat: update shared vault invite. (#644)
Co-authored-by: Mo <mo@standardnotes.com>
2023-07-06 11:58:45 +02:00
Karol Sójko
b2c32ce70e feat: shared vault users controller. (#643)
Co-authored-by: Mo <mo@standardnotes.com>
2023-07-06 11:41:36 +02:00
standardci
ed1a708c40 chore(release): publish new version
- @standardnotes/analytics@2.24.7
 - @standardnotes/api-gateway@1.65.4
 - @standardnotes/auth-server@1.122.1
 - @standardnotes/domain-core@1.21.0
 - @standardnotes/event-store@1.11.4
 - @standardnotes/files-server@1.19.4
 - @standardnotes/home-server@1.11.27
 - @standardnotes/revisions-server@1.23.8
 - @standardnotes/scheduler-server@1.20.6
 - @standardnotes/settings@1.21.11
 - @standardnotes/syncing-server@1.54.0
 - @standardnotes/websockets-server@1.9.7
2023-07-06 09:34:50 +00:00
Karol Sójko
e905128d45 feat: getting shared vault users and removing shared vault user (#642)
* feat: getting shared vault users.

Co-authored-by: Mo <mo@standardnotes.com>

* feat: removing shared vault user.

Co-authored-by: Mo <mo@standardnotes.com>

---------

Co-authored-by: Mo <mo@standardnotes.com>
2023-07-06 11:18:06 +02:00
standardci
fd598f372a chore(release): publish new version
- @standardnotes/home-server@1.11.26
 - @standardnotes/syncing-server@1.53.0
2023-07-05 13:33:44 +00:00
Karol Sójko
7a3946a9e2 feat: http controllers for shared vaults. (#641)
Co-authored-by: Mo <mo@standardnotes.com>
2023-07-05 15:17:43 +02:00
standardci
cbdd2584d0 chore(release): publish new version
- @standardnotes/analytics@2.24.6
 - @standardnotes/api-gateway@1.65.3
 - @standardnotes/auth-server@1.122.0
 - @standardnotes/domain-core@1.20.0
 - @standardnotes/domain-events-infra@1.12.8
 - @standardnotes/domain-events@2.113.0
 - @standardnotes/event-store@1.11.3
 - @standardnotes/files-server@1.19.3
 - @standardnotes/home-server@1.11.25
 - @standardnotes/revisions-server@1.23.7
 - @standardnotes/scheduler-server@1.20.5
 - @standardnotes/settings@1.21.10
 - @standardnotes/syncing-server@1.52.0
 - @standardnotes/websockets-server@1.9.6
2023-07-05 11:59:55 +00:00
Karol Sójko
f3161c2712 feat: deleting shared vaults. (#640)
Co-authored-by: Mo <mo@standardnotes.com>
2023-07-05 13:45:49 +02:00
standardci
148542dd5a chore(release): publish new version
- @standardnotes/home-server@1.11.24
 - @standardnotes/syncing-server@1.51.0
2023-07-05 09:17:53 +00:00
Karol Sójko
d2b2c339f2 feat: add getting shared vaults for a user (#639) 2023-07-05 11:01:21 +02:00
standardci
d2578c48f0 chore(release): publish new version
- @standardnotes/auth-server@1.121.0
 - @standardnotes/home-server@1.11.23
2023-07-05 08:21:19 +00:00
Karol Sójko
fecfd54728 feat(auth): add notifications model (#638) 2023-07-05 10:03:01 +02:00
Karol Sójko
17e4162d3e Revert "fix: unplug node-gyp based deps (#637)"
This reverts commit 742209d773.
2023-07-04 12:56:10 +02:00
Karol Sójko
742209d773 fix: unplug node-gyp based deps (#637) 2023-07-04 10:42:44 +02:00
standardci
1fa4b7cf27 chore(release): publish new version
- @standardnotes/home-server@1.11.22
 - @standardnotes/syncing-server@1.50.0
2023-07-03 17:55:21 +00:00
Karol Sójko
5dc5507039 feat: add invite users to a shared vault. (#636)
Co-authored-by: Mo <mo@standardnotes.com>
2023-07-03 19:40:36 +02:00
standardci
3035a20b9f chore(release): publish new version
- @standardnotes/home-server@1.11.21
 - @standardnotes/syncing-server@1.49.0
2023-07-03 16:58:01 +00:00
Karol Sójko
04b3bb034f feat: add creating shared vault file valet tokens. (#635)
Co-authored-by: Mo <mo@standardnotes.com>
2023-07-03 18:43:32 +02:00
standardci
bf84be0136 chore(release): publish new version
- @standardnotes/home-server@1.11.20
 - @standardnotes/syncing-server@1.48.0
2023-07-03 10:14:10 +00:00
Karol Sójko
890cf48749 feat: add shared vault invite model. (#634)
Co-authored-by: Mo <mo@standardnotes.com>
2023-07-03 11:54:52 +02:00
standardci
2b3436c6ce chore(release): publish new version
- @standardnotes/home-server@1.11.19
 - @standardnotes/syncing-server@1.47.0
2023-06-30 13:25:38 +00:00
Karol Sójko
4df8c3b2e5 feat: add use case for creating shared vaults and adding users to it. (#633)
Co-authored-by: Mo <mo@standardnotes.com>
2023-06-30 15:11:12 +02:00
standardci
25a2696c32 chore(release): publish new version
- @standardnotes/home-server@1.11.18
 - @standardnotes/syncing-server@1.46.0
2023-06-30 11:33:49 +00:00
Karol Sójko
52f879f842 feat: add shared vaults user model. (#632)
Co-authored-by: Mo <mo@standardnotes.com>
2023-06-30 13:19:31 +02:00
standardci
4f70fa156d chore(release): publish new version
- @standardnotes/analytics@2.24.5
 - @standardnotes/api-gateway@1.65.2
 - @standardnotes/auth-server@1.120.2
 - @standardnotes/domain-core@1.19.0
 - @standardnotes/event-store@1.11.2
 - @standardnotes/files-server@1.19.2
 - @standardnotes/home-server@1.11.17
 - @standardnotes/revisions-server@1.23.6
 - @standardnotes/scheduler-server@1.20.4
 - @standardnotes/settings@1.21.9
 - @standardnotes/syncing-server@1.45.0
 - @standardnotes/websockets-server@1.9.5
2023-06-30 11:00:32 +00:00
Karol Sójko
38e77f04be feat: add shared vaults model. (#631)
Co-authored-by: Mo <mo@standardnotes.com>
2023-06-30 12:44:27 +02:00
standardci
060206ddd4 chore(release): publish new version
- @standardnotes/analytics@2.24.4
 - @standardnotes/api-gateway@1.65.1
 - @standardnotes/auth-server@1.120.1
 - @standardnotes/domain-events-infra@1.12.7
 - @standardnotes/domain-events@2.112.1
 - @standardnotes/event-store@1.11.1
 - @standardnotes/files-server@1.19.1
 - @standardnotes/home-server@1.11.16
 - @standardnotes/revisions-server@1.23.5
 - @standardnotes/scheduler-server@1.20.3
 - @standardnotes/security@1.8.1
 - @standardnotes/syncing-server@1.44.6
 - @standardnotes/websockets-server@1.9.4
2023-06-30 10:24:00 +00:00
Mo
0bc0909386 chore: types lint (#630) 2023-06-30 05:07:47 -05:00
standardci
667d528a8c chore(release): publish new version
- @standardnotes/analytics@2.24.3
 - @standardnotes/api-gateway@1.65.0
 - @standardnotes/auth-server@1.120.0
 - @standardnotes/common@1.49.0
 - @standardnotes/domain-events-infra@1.12.6
 - @standardnotes/domain-events@2.112.0
 - @standardnotes/event-store@1.11.0
 - @standardnotes/files-server@1.19.0
 - @standardnotes/home-server@1.11.15
 - @standardnotes/revisions-server@1.23.4
 - @standardnotes/scheduler-server@1.20.2
 - @standardnotes/security@1.8.0
 - @standardnotes/syncing-server@1.44.5
 - @standardnotes/websockets-server@1.9.3
2023-06-30 09:47:02 +00:00
Karol Sójko
fa7fbe26e7 feat: shared vaults functionality in api-gateway,auth,files,common,security,domain-events. (#629)
Co-authored-by: Mo <mo@standardnotes.com>
2023-06-30 11:31:25 +02:00
standardci
ba422a29d0 chore(release): publish new version
- @standardnotes/auth-server@1.119.6
 - @standardnotes/home-server@1.11.14
2023-06-28 16:11:23 +00:00
Karol Sójko
d220ec5bf7 fix(auth): add debug logs for authentication method resolver 2023-06-28 17:56:59 +02:00
standardci
7baf5492bc chore(release): publish new version
- @standardnotes/api-gateway@1.64.3
 - @standardnotes/auth-server@1.119.5
 - @standardnotes/home-server@1.11.13
 - @standardnotes/syncing-server@1.44.4
2023-06-28 12:45:50 +00:00
Karol Sójko
d5a8409bb5 fix: add debug logs for invalid-auth responses 2023-06-28 14:30:39 +02:00
641 changed files with 19792 additions and 5445 deletions

View File

@@ -50,14 +50,30 @@ jobs:
run: docker/is-available.sh http://localhost:3123 $(pwd)/logs
- name: Run E2E Test Suite
run: yarn dlx mocha-headless-chrome --timeout 1200000 -f http://localhost:9001/mocha/test.html
run: yarn dlx mocha-headless-chrome --timeout 1800000 -f http://localhost:9001/mocha/test.html
- name: Show logs on failure
if: ${{ failure() }}
run: |
echo "# Errors:"
tail -n 100 logs/*.err
echo "# Logs:"
tail -n 100 logs/*.log
e2e-home-server:
name: (Home Server) E2E Test Suite
strategy:
fail-fast: false
matrix:
db_type: [mysql, sqlite]
cache_type: [redis, memory]
include:
- cache_type: redis
db_type: mysql
redis_port: 6380
- cache_type: redis
db_type: sqlite
redis_port: 6381
runs-on: ubuntu-latest
@@ -69,14 +85,14 @@ jobs:
cache:
image: redis
ports:
- 6379:6379
- ${{ matrix.redis_port }}:6379
db:
image: mysql
ports:
- 3306:3306
- 3307:3306
env:
MYSQL_ROOT_PASSWORD: root
MYSQL_DATABASE: standardnotes
MYSQL_DATABASE: standardnotes_${{ matrix.cache_type }}
MYSQL_USER: standardnotes
MYSQL_PASSWORD: standardnotes
@@ -106,18 +122,22 @@ jobs:
sed -i "s/PSEUDO_KEY_PARAMS_KEY=/PSEUDO_KEY_PARAMS_KEY=$(openssl rand -hex 32)/g" packages/home-server/.env
sed -i "s/VALET_TOKEN_SECRET=/VALET_TOKEN_SECRET=$(openssl rand -hex 32)/g" packages/home-server/.env
echo "ACCESS_TOKEN_AGE=4" >> packages/home-server/.env
echo "REFRESH_TOKEN_AGE=7" >> packages/home-server/.env
echo "REFRESH_TOKEN_AGE=10" >> packages/home-server/.env
echo "REVISIONS_FREQUENCY=5" >> packages/home-server/.env
echo "DB_HOST=db" >> packages/home-server/.env
echo "DB_PORT=3306" >> packages/home-server/.env
echo "DB_HOST=localhost" >> packages/home-server/.env
echo "DB_PORT=3307" >> packages/home-server/.env
echo "DB_DATABASE=standardnotes_${{ matrix.cache_type }}" >> packages/home-server/.env
echo "DB_SQLITE_DATABASE_PATH=sqlite_${{ matrix.cache_type }}.db" >> packages/home-server/.env
echo "DB_USERNAME=standardnotes" >> packages/home-server/.env
echo "DB_PASSWORD=standardnotes" >> packages/home-server/.env
echo "DB_TYPE=${{ matrix.db_type }}" >> packages/home-server/.env
echo "REDIS_URL=redis://cache" >> packages/home-server/.env
echo "REDIS_URL=redis://localhost:${{ matrix.redis_port }}" >> packages/home-server/.env
echo "CACHE_TYPE=${{ matrix.cache_type }}" >> packages/home-server/.env
echo "FILES_SERVER_URL=http://localhost:3123" >> packages/home-server/.env
echo "E2E_TESTING=true" >> packages/home-server/.env
- name: Run Server
run: nohup yarn workspace @standardnotes/home-server start &
run: nohup yarn workspace @standardnotes/home-server start > logs/output.log 2>&1 &
env:
PORT: 3123
@@ -125,4 +145,8 @@ jobs:
run: for i in {1..30}; do curl -s http://localhost:3123/healthcheck && break || sleep 1; done
- name: Run E2E Test Suite
run: yarn dlx mocha-headless-chrome --timeout 1200000 -f http://localhost:9001/mocha/test.html?skip_paid_features=true
run: yarn dlx mocha-headless-chrome --timeout 1800000 -f http://localhost:9001/mocha/test.html
- name: Show logs on failure
if: ${{ failure() }}
run: tail -n 500 logs/output.log

96
.pnp.cjs generated
View File

@@ -4560,17 +4560,16 @@ const RAW_RUNTIME_STATE =
}]\
]],\
["@standardnotes/api", [\
["npm:1.26.10", {\
"packageLocation": "./.yarn/cache/@standardnotes-api-npm-1.26.10-f6165cafd3-3c3561aec8.zip/node_modules/@standardnotes/api/",\
["npm:1.26.26", {\
"packageLocation": "./.yarn/cache/@standardnotes-api-npm-1.26.26-4338a5fe92-db41aedfa3.zip/node_modules/@standardnotes/api/",\
"packageDependencies": [\
["@standardnotes/api", "npm:1.26.10"],\
["@standardnotes/api", "npm:1.26.26"],\
["@standardnotes/common", "workspace:packages/common"],\
["@standardnotes/domain-core", "workspace:packages/domain-core"],\
["@standardnotes/encryption", "npm:1.21.38"],\
["@standardnotes/models", "npm:1.45.5"],\
["@standardnotes/responses", "npm:1.13.24"],\
["@standardnotes/models", "npm:1.46.8"],\
["@standardnotes/responses", "npm:1.13.27"],\
["@standardnotes/security", "workspace:packages/security"],\
["@standardnotes/utils", "npm:1.16.5"],\
["@standardnotes/utils", "npm:1.17.5"],\
["reflect-metadata", "npm:0.1.13"]\
],\
"linkType": "HARD"\
@@ -4635,17 +4634,17 @@ const RAW_RUNTIME_STATE =
["@newrelic/winston-enricher", "virtual:c66bf20e88479ada0172094776519a9f51acc4731d22079b60a295bcec7ea42d5545cbce58a77a50d932bf953298799135e99707486e343da6d99ba1d167bdbd#npm:4.0.1"],\
["@simplewebauthn/server", "npm:7.2.0"],\
["@simplewebauthn/typescript-types", "npm:7.0.0"],\
["@standardnotes/api", "npm:1.26.10"],\
["@standardnotes/api", "npm:1.26.26"],\
["@standardnotes/common", "workspace:packages/common"],\
["@standardnotes/domain-core", "workspace:packages/domain-core"],\
["@standardnotes/domain-events", "workspace:packages/domain-events"],\
["@standardnotes/domain-events-infra", "workspace:packages/domain-events-infra"],\
["@standardnotes/features", "npm:1.59.5"],\
["@standardnotes/features", "npm:1.59.7"],\
["@standardnotes/predicates", "workspace:packages/predicates"],\
["@standardnotes/responses", "npm:1.13.24"],\
["@standardnotes/responses", "npm:1.13.27"],\
["@standardnotes/security", "workspace:packages/security"],\
["@standardnotes/settings", "workspace:packages/settings"],\
["@standardnotes/sncrypto-common", "npm:1.13.3"],\
["@standardnotes/sncrypto-common", "npm:1.13.4"],\
["@standardnotes/sncrypto-node", "workspace:packages/sncrypto-node"],\
["@standardnotes/time", "workspace:packages/time"],\
["@types/bcryptjs", "npm:2.4.2"],\
@@ -4781,21 +4780,6 @@ const RAW_RUNTIME_STATE =
"linkType": "SOFT"\
}]\
]],\
["@standardnotes/encryption", [\
["npm:1.21.38", {\
"packageLocation": "./.yarn/cache/@standardnotes-encryption-npm-1.21.38-d08c3d4766-1393840523.zip/node_modules/@standardnotes/encryption/",\
"packageDependencies": [\
["@standardnotes/encryption", "npm:1.21.38"],\
["@standardnotes/common", "workspace:packages/common"],\
["@standardnotes/models", "npm:1.45.5"],\
["@standardnotes/responses", "npm:1.13.24"],\
["@standardnotes/sncrypto-common", "npm:1.13.3"],\
["@standardnotes/utils", "npm:1.16.5"],\
["reflect-metadata", "npm:0.1.13"]\
],\
"linkType": "HARD"\
}]\
]],\
["@standardnotes/event-store", [\
["workspace:packages/event-store", {\
"packageLocation": "./packages/event-store/",\
@@ -4831,10 +4815,10 @@ const RAW_RUNTIME_STATE =
}]\
]],\
["@standardnotes/features", [\
["npm:1.59.5", {\
"packageLocation": "./.yarn/cache/@standardnotes-features-npm-1.59.5-83c83acde9-173b1f5d52.zip/node_modules/@standardnotes/features/",\
["npm:1.59.7", {\
"packageLocation": "./.yarn/cache/@standardnotes-features-npm-1.59.7-27c3e5296e-1632d64cc1.zip/node_modules/@standardnotes/features/",\
"packageDependencies": [\
["@standardnotes/features", "npm:1.59.5"],\
["@standardnotes/features", "npm:1.59.7"],\
["@standardnotes/common", "workspace:packages/common"],\
["@standardnotes/domain-core", "workspace:packages/domain-core"],\
["@standardnotes/security", "workspace:packages/security"],\
@@ -4855,7 +4839,7 @@ const RAW_RUNTIME_STATE =
["@standardnotes/domain-events", "workspace:packages/domain-events"],\
["@standardnotes/domain-events-infra", "workspace:packages/domain-events-infra"],\
["@standardnotes/security", "workspace:packages/security"],\
["@standardnotes/sncrypto-common", "npm:1.13.3"],\
["@standardnotes/sncrypto-common", "npm:1.13.4"],\
["@standardnotes/sncrypto-node", "workspace:packages/sncrypto-node"],\
["@standardnotes/time", "workspace:packages/time"],\
["@types/connect-busboy", "npm:1.0.0"],\
@@ -4935,14 +4919,16 @@ const RAW_RUNTIME_STATE =
}]\
]],\
["@standardnotes/models", [\
["npm:1.45.5", {\
"packageLocation": "./.yarn/cache/@standardnotes-models-npm-1.45.5-29326e959c-15f26c11b2.zip/node_modules/@standardnotes/models/",\
["npm:1.46.8", {\
"packageLocation": "./.yarn/cache/@standardnotes-models-npm-1.46.8-bc0390832e-8404340f27.zip/node_modules/@standardnotes/models/",\
"packageDependencies": [\
["@standardnotes/models", "npm:1.45.5"],\
["@standardnotes/models", "npm:1.46.8"],\
["@standardnotes/common", "workspace:packages/common"],\
["@standardnotes/features", "npm:1.59.5"],\
["@standardnotes/responses", "npm:1.13.24"],\
["@standardnotes/utils", "npm:1.16.5"],\
["@standardnotes/domain-core", "workspace:packages/domain-core"],\
["@standardnotes/features", "npm:1.59.7"],\
["@standardnotes/responses", "npm:1.13.27"],\
["@standardnotes/sncrypto-common", "npm:1.13.4"],\
["@standardnotes/utils", "npm:1.17.5"],\
["lodash", "npm:4.17.21"]\
],\
"linkType": "HARD"\
@@ -4967,12 +4953,12 @@ const RAW_RUNTIME_STATE =
}]\
]],\
["@standardnotes/responses", [\
["npm:1.13.24", {\
"packageLocation": "./.yarn/cache/@standardnotes-responses-npm-1.13.24-3b4167c7ea-3bcfee90f0.zip/node_modules/@standardnotes/responses/",\
["npm:1.13.27", {\
"packageLocation": "./.yarn/cache/@standardnotes-responses-npm-1.13.27-829dec3e6e-9bf55e5f02.zip/node_modules/@standardnotes/responses/",\
"packageDependencies": [\
["@standardnotes/responses", "npm:1.13.24"],\
["@standardnotes/responses", "npm:1.13.27"],\
["@standardnotes/common", "workspace:packages/common"],\
["@standardnotes/features", "npm:1.59.5"],\
["@standardnotes/features", "npm:1.59.7"],\
["@standardnotes/security", "workspace:packages/security"],\
["reflect-metadata", "npm:0.1.13"]\
],\
@@ -4987,12 +4973,12 @@ const RAW_RUNTIME_STATE =
["@aws-sdk/client-s3", "npm:3.342.0"],\
["@aws-sdk/client-sqs", "npm:3.342.0"],\
["@newrelic/winston-enricher", "virtual:c66bf20e88479ada0172094776519a9f51acc4731d22079b60a295bcec7ea42d5545cbce58a77a50d932bf953298799135e99707486e343da6d99ba1d167bdbd#npm:4.0.1"],\
["@standardnotes/api", "npm:1.26.10"],\
["@standardnotes/api", "npm:1.26.26"],\
["@standardnotes/common", "workspace:packages/common"],\
["@standardnotes/domain-core", "workspace:packages/domain-core"],\
["@standardnotes/domain-events", "workspace:packages/domain-events"],\
["@standardnotes/domain-events-infra", "workspace:packages/domain-events-infra"],\
["@standardnotes/responses", "npm:1.13.24"],\
["@standardnotes/responses", "npm:1.13.27"],\
["@standardnotes/security", "workspace:packages/security"],\
["@standardnotes/time", "workspace:packages/time"],\
["@types/cors", "npm:2.8.13"],\
@@ -5129,10 +5115,10 @@ const RAW_RUNTIME_STATE =
}]\
]],\
["@standardnotes/sncrypto-common", [\
["npm:1.13.3", {\
"packageLocation": "./.yarn/cache/@standardnotes-sncrypto-common-npm-1.13.3-97ef3850ce-a73af90962.zip/node_modules/@standardnotes/sncrypto-common/",\
["npm:1.13.4", {\
"packageLocation": "./.yarn/cache/@standardnotes-sncrypto-common-npm-1.13.4-3186513fa6-48e0e207f2.zip/node_modules/@standardnotes/sncrypto-common/",\
"packageDependencies": [\
["@standardnotes/sncrypto-common", "npm:1.13.3"],\
["@standardnotes/sncrypto-common", "npm:1.13.4"],\
["reflect-metadata", "npm:0.1.13"]\
],\
"linkType": "HARD"\
@@ -5143,7 +5129,7 @@ const RAW_RUNTIME_STATE =
"packageLocation": "./packages/sncrypto-node/",\
"packageDependencies": [\
["@standardnotes/sncrypto-node", "workspace:packages/sncrypto-node"],\
["@standardnotes/sncrypto-common", "npm:1.13.3"],\
["@standardnotes/sncrypto-common", "npm:1.13.4"],\
["@types/jest", "npm:29.5.2"],\
["@types/node", "npm:20.2.5"],\
["@typescript-eslint/eslint-plugin", "virtual:fd909b174d079e30b336c4ce72c38a88c1e447767b1a8dd7655e07719a1e31b97807f0931368724fc78897ff15e6a6d00b83316c0f76d11f85111f342e08bb79#npm:5.59.8"],\
@@ -5171,14 +5157,15 @@ const RAW_RUNTIME_STATE =
["@aws-sdk/client-sns", "npm:3.342.0"],\
["@aws-sdk/client-sqs", "npm:3.342.0"],\
["@newrelic/winston-enricher", "virtual:c66bf20e88479ada0172094776519a9f51acc4731d22079b60a295bcec7ea42d5545cbce58a77a50d932bf953298799135e99707486e343da6d99ba1d167bdbd#npm:4.0.1"],\
["@standardnotes/api", "npm:1.26.10"],\
["@standardnotes/api", "npm:1.26.26"],\
["@standardnotes/common", "workspace:packages/common"],\
["@standardnotes/domain-core", "workspace:packages/domain-core"],\
["@standardnotes/domain-events", "workspace:packages/domain-events"],\
["@standardnotes/domain-events-infra", "workspace:packages/domain-events-infra"],\
["@standardnotes/responses", "npm:1.13.24"],\
["@standardnotes/responses", "npm:1.13.27"],\
["@standardnotes/security", "workspace:packages/security"],\
["@standardnotes/settings", "workspace:packages/settings"],\
["@standardnotes/sncrypto-node", "workspace:packages/sncrypto-node"],\
["@standardnotes/time", "workspace:packages/time"],\
["@types/cors", "npm:2.8.13"],\
["@types/dotenv", "npm:8.2.0"],\
@@ -5188,6 +5175,7 @@ const RAW_RUNTIME_STATE =
["@types/newrelic", "npm:9.14.0"],\
["@types/node", "npm:20.2.5"],\
["@types/prettyjson", "npm:0.0.30"],\
["@types/semver", "npm:7.5.0"],\
["@types/ua-parser-js", "npm:0.7.36"],\
["@types/uuid", "npm:8.3.4"],\
["@typescript-eslint/eslint-plugin", "virtual:fd909b174d079e30b336c4ce72c38a88c1e447767b1a8dd7655e07719a1e31b97807f0931368724fc78897ff15e6a6d00b83316c0f76d11f85111f342e08bb79#npm:5.59.8"],\
@@ -5210,6 +5198,7 @@ const RAW_RUNTIME_STATE =
["prettier", "npm:2.8.8"],\
["prettyjson", "npm:1.2.5"],\
["reflect-metadata", "npm:0.1.13"],\
["semver", "npm:7.5.1"],\
["sqlite3", "virtual:31b5a94a105c89c9294c3d524a7f8929fe63ee5a2efadf21951ca4c0cfd2ecf02e8f4ef5a066bbda091f1e3a56e57c6749069a080618c96b22e51131a330fc4a#npm:5.1.6"],\
["ts-jest", "virtual:fd909b174d079e30b336c4ce72c38a88c1e447767b1a8dd7655e07719a1e31b97807f0931368724fc78897ff15e6a6d00b83316c0f76d11f85111f342e08bb79#npm:29.1.0"],\
["typeorm", "virtual:365b8c88cdf194291829ee28b79556e2328175d26a621363e703848100bea0042e9500db2a1206c9bbc3a4a76a1d169639ef774b2ea3a1a98584a9936b58c6be#npm:0.3.16"],\
@@ -5244,10 +5233,10 @@ const RAW_RUNTIME_STATE =
}]\
]],\
["@standardnotes/utils", [\
["npm:1.16.5", {\
"packageLocation": "./.yarn/cache/@standardnotes-utils-npm-1.16.5-47f537f49f-d5caa7181f.zip/node_modules/@standardnotes/utils/",\
["npm:1.17.5", {\
"packageLocation": "./.yarn/cache/@standardnotes-utils-npm-1.17.5-210b60222d-47e8520174.zip/node_modules/@standardnotes/utils/",\
"packageDependencies": [\
["@standardnotes/utils", "npm:1.16.5"],\
["@standardnotes/utils", "npm:1.17.5"],\
["@standardnotes/common", "workspace:packages/common"],\
["dompurify", "npm:2.4.5"],\
["lodash", "npm:4.17.21"],\
@@ -5263,14 +5252,13 @@ const RAW_RUNTIME_STATE =
["@standardnotes/websockets-server", "workspace:packages/websockets"],\
["@aws-sdk/client-sqs", "npm:3.342.0"],\
["@newrelic/winston-enricher", "virtual:c66bf20e88479ada0172094776519a9f51acc4731d22079b60a295bcec7ea42d5545cbce58a77a50d932bf953298799135e99707486e343da6d99ba1d167bdbd#npm:4.0.1"],\
["@standardnotes/api", "npm:1.26.10"],\
["@standardnotes/api", "npm:1.26.26"],\
["@standardnotes/common", "workspace:packages/common"],\
["@standardnotes/domain-core", "workspace:packages/domain-core"],\
["@standardnotes/domain-events", "workspace:packages/domain-events"],\
["@standardnotes/domain-events-infra", "workspace:packages/domain-events-infra"],\
["@standardnotes/responses", "npm:1.13.24"],\
["@standardnotes/responses", "npm:1.13.27"],\
["@standardnotes/security", "workspace:packages/security"],\
["@standardnotes/utils", "npm:1.16.5"],\
["@types/cors", "npm:2.8.13"],\
["@types/express", "npm:4.17.17"],\
["@types/ioredis", "npm:5.0.0"],\

View File

@@ -3,6 +3,7 @@ services:
image: standardnotes/server
env_file: .env
container_name: server_self_hosted
restart: unless-stopped
ports:
- 3000:3000
- 3125:3104

View File

@@ -12,12 +12,15 @@
},
"scripts": {
"lint": "yarn workspaces foreach -p -j 10 --verbose run lint",
"lint:fix": "yarn workspaces foreach -p -j 10 --verbose run lint:fix",
"clean": "yarn workspaces foreach -p --verbose run clean",
"setup:env": "cp .env.sample .env && yarn workspaces foreach -p --verbose run setup:env",
"release": "lerna version --conventional-graduate --conventional-commits --yes -m \"chore(release): publish new version\"",
"publish": "lerna publish from-git --yes --no-verify-access --loglevel verbose",
"postversion": "./scripts/push-tags-one-by-one.sh",
"upgrade:snjs": "yarn workspaces foreach --verbose run upgrade:snjs"
"upgrade:snjs": "yarn workspaces foreach --verbose run upgrade:snjs",
"e2e": "yarn build packages/home-server && PORT=3123 yarn workspace @standardnotes/home-server start",
"start": "yarn build packages/home-server && yarn workspace @standardnotes/home-server start"
},
"devDependencies": {
"@commitlint/cli": "^17.0.2",

View File

@@ -3,6 +3,76 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [2.25.9](https://github.com/standardnotes/server/compare/@standardnotes/analytics@2.25.8...@standardnotes/analytics@2.25.9) (2023-08-08)
**Note:** Version bump only for package @standardnotes/analytics
## [2.25.8](https://github.com/standardnotes/server/compare/@standardnotes/analytics@2.25.7...@standardnotes/analytics@2.25.8) (2023-08-03)
**Note:** Version bump only for package @standardnotes/analytics
## [2.25.7](https://github.com/standardnotes/server/compare/@standardnotes/analytics@2.25.6...@standardnotes/analytics@2.25.7) (2023-08-02)
**Note:** Version bump only for package @standardnotes/analytics
## [2.25.6](https://github.com/standardnotes/server/compare/@standardnotes/analytics@2.25.5...@standardnotes/analytics@2.25.6) (2023-07-27)
**Note:** Version bump only for package @standardnotes/analytics
## [2.25.5](https://github.com/standardnotes/server/compare/@standardnotes/analytics@2.25.4...@standardnotes/analytics@2.25.5) (2023-07-26)
**Note:** Version bump only for package @standardnotes/analytics
## [2.25.4](https://github.com/standardnotes/server/compare/@standardnotes/analytics@2.25.3...@standardnotes/analytics@2.25.4) (2023-07-26)
**Note:** Version bump only for package @standardnotes/analytics
## [2.25.3](https://github.com/standardnotes/server/compare/@standardnotes/analytics@2.25.2...@standardnotes/analytics@2.25.3) (2023-07-21)
**Note:** Version bump only for package @standardnotes/analytics
## [2.25.2](https://github.com/standardnotes/server/compare/@standardnotes/analytics@2.25.1...@standardnotes/analytics@2.25.2) (2023-07-21)
**Note:** Version bump only for package @standardnotes/analytics
## [2.25.1](https://github.com/standardnotes/server/compare/@standardnotes/analytics@2.25.0...@standardnotes/analytics@2.25.1) (2023-07-19)
**Note:** Version bump only for package @standardnotes/analytics
# [2.25.0](https://github.com/standardnotes/server/compare/@standardnotes/analytics@2.24.9...@standardnotes/analytics@2.25.0) (2023-07-17)
### Features
* **syncing-server:** refactor syncing to decouple getting and saving items ([#659](https://github.com/standardnotes/server/issues/659)) ([cb74b23](https://github.com/standardnotes/server/commit/cb74b23e45b207136e299ce8a3db2c04dc87e21e))
## [2.24.9](https://github.com/standardnotes/server/compare/@standardnotes/analytics@2.24.8...@standardnotes/analytics@2.24.9) (2023-07-12)
**Note:** Version bump only for package @standardnotes/analytics
## [2.24.8](https://github.com/standardnotes/server/compare/@standardnotes/analytics@2.24.7...@standardnotes/analytics@2.24.8) (2023-07-07)
**Note:** Version bump only for package @standardnotes/analytics
## [2.24.7](https://github.com/standardnotes/server/compare/@standardnotes/analytics@2.24.6...@standardnotes/analytics@2.24.7) (2023-07-06)
**Note:** Version bump only for package @standardnotes/analytics
## [2.24.6](https://github.com/standardnotes/server/compare/@standardnotes/analytics@2.24.5...@standardnotes/analytics@2.24.6) (2023-07-05)
**Note:** Version bump only for package @standardnotes/analytics
## [2.24.5](https://github.com/standardnotes/server/compare/@standardnotes/analytics@2.24.4...@standardnotes/analytics@2.24.5) (2023-06-30)
**Note:** Version bump only for package @standardnotes/analytics
## [2.24.4](https://github.com/standardnotes/server/compare/@standardnotes/analytics@2.24.3...@standardnotes/analytics@2.24.4) (2023-06-30)
**Note:** Version bump only for package @standardnotes/analytics
## [2.24.3](https://github.com/standardnotes/server/compare/@standardnotes/analytics@2.24.2...@standardnotes/analytics@2.24.3) (2023-06-30)
**Note:** Version bump only for package @standardnotes/analytics
## [2.24.2](https://github.com/standardnotes/server/compare/@standardnotes/analytics@2.24.1...@standardnotes/analytics@2.24.2) (2023-06-28)
**Note:** Version bump only for package @standardnotes/analytics

View File

@@ -1,6 +1,6 @@
{
"name": "@standardnotes/analytics",
"version": "2.24.2",
"version": "2.25.9",
"engines": {
"node": ">=18.0.0 <21.0.0"
},

View File

@@ -3,10 +3,6 @@ import { Result, Entity, UniqueEntityId } from '@standardnotes/domain-core'
import { StatisticMeasureProps } from './StatisticMeasureProps'
export class StatisticMeasure extends Entity<StatisticMeasureProps> {
get id(): UniqueEntityId {
return this._id
}
get name(): string {
return this.props.name.value
}

View File

@@ -3,10 +3,6 @@ import { Entity, Result, UniqueEntityId } from '@standardnotes/domain-core'
import { SubscriptionProps } from './SubscriptionProps'
export class Subscription extends Entity<SubscriptionProps> {
get id(): UniqueEntityId {
return this._id
}
private constructor(props: SubscriptionProps, id?: UniqueEntityId) {
super(props, id)
}

View File

@@ -3,10 +3,6 @@ import { Entity, Result, UniqueEntityId } from '@standardnotes/domain-core'
import { UserProps } from './UserProps'
export class User extends Entity<UserProps> {
get id(): UniqueEntityId {
return this._id
}
private constructor(props: UserProps, id?: UniqueEntityId) {
super(props, id)
}

View File

@@ -3,6 +3,120 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.70.1](https://github.com/standardnotes/api-gateway/compare/@standardnotes/api-gateway@1.70.0...@standardnotes/api-gateway@1.70.1) (2023-08-08)
**Note:** Version bump only for package @standardnotes/api-gateway
# [1.70.0](https://github.com/standardnotes/api-gateway/compare/@standardnotes/api-gateway@1.69.3...@standardnotes/api-gateway@1.70.0) (2023-08-07)
### Features
* **syncing-server:** limit shared vaults creation based on role ([#687](https://github.com/standardnotes/api-gateway/issues/687)) ([19b8921](https://github.com/standardnotes/api-gateway/commit/19b8921f286ff8f88c427e8ddd4512a8d61edb4f))
## [1.69.3](https://github.com/standardnotes/api-gateway/compare/@standardnotes/api-gateway@1.69.2...@standardnotes/api-gateway@1.69.3) (2023-08-03)
**Note:** Version bump only for package @standardnotes/api-gateway
## [1.69.2](https://github.com/standardnotes/api-gateway/compare/@standardnotes/api-gateway@1.69.1...@standardnotes/api-gateway@1.69.2) (2023-08-02)
**Note:** Version bump only for package @standardnotes/api-gateway
## [1.69.1](https://github.com/standardnotes/api-gateway/compare/@standardnotes/api-gateway@1.69.0...@standardnotes/api-gateway@1.69.1) (2023-07-31)
### Bug Fixes
* **api-gateway:** remove duplicating req/res objects on return raw response from payments ([79d71ca](https://github.com/standardnotes/api-gateway/commit/79d71ca161cc18135fcd1a83b021662e189b3ddb))
# [1.69.0](https://github.com/standardnotes/api-gateway/compare/@standardnotes/api-gateway@1.68.1...@standardnotes/api-gateway@1.69.0) (2023-07-31)
### Features
* refactor deleting account ([#676](https://github.com/standardnotes/api-gateway/issues/676)) ([0d5dcdd](https://github.com/standardnotes/api-gateway/commit/0d5dcdd8ec2336e41e7604c4157f79a89163ed29))
## [1.68.1](https://github.com/standardnotes/api-gateway/compare/@standardnotes/api-gateway@1.68.0...@standardnotes/api-gateway@1.68.1) (2023-07-27)
**Note:** Version bump only for package @standardnotes/api-gateway
# [1.68.0](https://github.com/standardnotes/api-gateway/compare/@standardnotes/api-gateway@1.67.4...@standardnotes/api-gateway@1.68.0) (2023-07-27)
### Features
* **syncing-server:** add deleting outbound messages ([e8ba49e](https://github.com/standardnotes/api-gateway/commit/e8ba49ecca38ab10c0ea0e1f4cf4db9fb17366db))
## [1.67.4](https://github.com/standardnotes/api-gateway/compare/@standardnotes/api-gateway@1.67.3...@standardnotes/api-gateway@1.67.4) (2023-07-26)
**Note:** Version bump only for package @standardnotes/api-gateway
## [1.67.3](https://github.com/standardnotes/api-gateway/compare/@standardnotes/api-gateway@1.67.2...@standardnotes/api-gateway@1.67.3) (2023-07-26)
**Note:** Version bump only for package @standardnotes/api-gateway
## [1.67.2](https://github.com/standardnotes/api-gateway/compare/@standardnotes/api-gateway@1.67.1...@standardnotes/api-gateway@1.67.2) (2023-07-21)
**Note:** Version bump only for package @standardnotes/api-gateway
## [1.67.1](https://github.com/standardnotes/api-gateway/compare/@standardnotes/api-gateway@1.67.0...@standardnotes/api-gateway@1.67.1) (2023-07-21)
**Note:** Version bump only for package @standardnotes/api-gateway
# [1.67.0](https://github.com/standardnotes/api-gateway/compare/@standardnotes/api-gateway@1.66.1...@standardnotes/api-gateway@1.67.0) (2023-07-20)
### Features
* **syncing-server:** add shared vaults, invites, messages and notifications to sync response ([#665](https://github.com/standardnotes/api-gateway/issues/665)) ([efa4d7f](https://github.com/standardnotes/api-gateway/commit/efa4d7fc6007ef668e3de3b04853ac11b2d13c30))
## [1.66.1](https://github.com/standardnotes/api-gateway/compare/@standardnotes/api-gateway@1.66.0...@standardnotes/api-gateway@1.66.1) (2023-07-19)
### Bug Fixes
* add missing imports and exports for controllers ([#664](https://github.com/standardnotes/api-gateway/issues/664)) ([aee6e60](https://github.com/standardnotes/api-gateway/commit/aee6e6058359e2b5231cc13387656f837699300f))
# [1.66.0](https://github.com/standardnotes/api-gateway/compare/@standardnotes/api-gateway@1.65.7...@standardnotes/api-gateway@1.66.0) (2023-07-19)
### Features
* **syncing-server:** add persistence of shared vaults with users and invites + controllers ([#662](https://github.com/standardnotes/api-gateway/issues/662)) ([3f21a35](https://github.com/standardnotes/api-gateway/commit/3f21a358d24d70daf541aa62dc86cd9e29500e62))
## [1.65.7](https://github.com/standardnotes/api-gateway/compare/@standardnotes/api-gateway@1.65.6...@standardnotes/api-gateway@1.65.7) (2023-07-17)
**Note:** Version bump only for package @standardnotes/api-gateway
## [1.65.6](https://github.com/standardnotes/api-gateway/compare/@standardnotes/api-gateway@1.65.5...@standardnotes/api-gateway@1.65.6) (2023-07-12)
**Note:** Version bump only for package @standardnotes/api-gateway
## [1.65.5](https://github.com/standardnotes/api-gateway/compare/@standardnotes/api-gateway@1.65.4...@standardnotes/api-gateway@1.65.5) (2023-07-07)
**Note:** Version bump only for package @standardnotes/api-gateway
## [1.65.4](https://github.com/standardnotes/api-gateway/compare/@standardnotes/api-gateway@1.65.3...@standardnotes/api-gateway@1.65.4) (2023-07-06)
**Note:** Version bump only for package @standardnotes/api-gateway
## [1.65.3](https://github.com/standardnotes/api-gateway/compare/@standardnotes/api-gateway@1.65.2...@standardnotes/api-gateway@1.65.3) (2023-07-05)
**Note:** Version bump only for package @standardnotes/api-gateway
## [1.65.2](https://github.com/standardnotes/api-gateway/compare/@standardnotes/api-gateway@1.65.1...@standardnotes/api-gateway@1.65.2) (2023-06-30)
**Note:** Version bump only for package @standardnotes/api-gateway
## [1.65.1](https://github.com/standardnotes/api-gateway/compare/@standardnotes/api-gateway@1.65.0...@standardnotes/api-gateway@1.65.1) (2023-06-30)
**Note:** Version bump only for package @standardnotes/api-gateway
# [1.65.0](https://github.com/standardnotes/api-gateway/compare/@standardnotes/api-gateway@1.64.3...@standardnotes/api-gateway@1.65.0) (2023-06-30)
### Features
* shared vaults functionality in api-gateway,auth,files,common,security,domain-events. ([#629](https://github.com/standardnotes/api-gateway/issues/629)) ([fa7fbe2](https://github.com/standardnotes/api-gateway/commit/fa7fbe26e7b0707fc21d71e04af76870f5248baf))
## [1.64.3](https://github.com/standardnotes/api-gateway/compare/@standardnotes/api-gateway@1.64.2...@standardnotes/api-gateway@1.64.3) (2023-06-28)
### Bug Fixes
* add debug logs for invalid-auth responses ([d5a8409](https://github.com/standardnotes/api-gateway/commit/d5a8409bb5d35b9caf410a36ea0d5cb747129e8d))
## [1.64.2](https://github.com/standardnotes/api-gateway/compare/@standardnotes/api-gateway@1.64.1...@standardnotes/api-gateway@1.64.2) (2023-06-22)
### Bug Fixes

View File

@@ -16,6 +16,10 @@ import '../src/Controller/v1/OfflineController'
import '../src/Controller/v1/FilesController'
import '../src/Controller/v1/SubscriptionInvitesController'
import '../src/Controller/v1/AuthenticatorsController'
import '../src/Controller/v1/MessagesController'
import '../src/Controller/v1/SharedVaultsController'
import '../src/Controller/v1/SharedVaultInvitesController'
import '../src/Controller/v1/SharedVaultUsersController'
import '../src/Controller/v2/PaymentsControllerV2'
import '../src/Controller/v2/ActionsControllerV2'
@@ -42,31 +46,32 @@ void container.load().then((container) => {
server.setConfig((app) => {
app.use((_request: Request, response: Response, next: NextFunction) => {
response.setHeader('X-API-Gateway-Version', container.get(TYPES.VERSION))
response.setHeader('X-API-Gateway-Version', container.get(TYPES.ApiGateway_VERSION))
next()
})
/* eslint-disable */
app.use(helmet({
contentSecurityPolicy: {
directives: {
defaultSrc: ["https: 'self'"],
baseUri: ["'self'"],
childSrc: ["*", "blob:"],
connectSrc: ["*"],
fontSrc: ["*", "'self'"],
formAction: ["'self'"],
frameAncestors: ["*", "*.standardnotes.org", "*.standardnotes.com"],
frameSrc: ["*", "blob:"],
imgSrc: ["'self'", "*", "data:"],
manifestSrc: ["'self'"],
mediaSrc: ["'self'"],
objectSrc: ["'self'"],
scriptSrc: ["'self'"],
styleSrc: ["'self'"]
}
}
}))
/* eslint-enable */
app.use(
helmet({
contentSecurityPolicy: {
directives: {
defaultSrc: ["https: 'self'"],
baseUri: ["'self'"],
childSrc: ['*', 'blob:'],
connectSrc: ['*'],
fontSrc: ['*', "'self'"],
formAction: ["'self'"],
frameAncestors: ['*', '*.standardnotes.org', '*.standardnotes.com'],
frameSrc: ['*', 'blob:'],
imgSrc: ["'self'", '*', 'data:'],
manifestSrc: ["'self'"],
mediaSrc: ["'self'"],
objectSrc: ["'self'"],
scriptSrc: ["'self'"],
styleSrc: ["'self'"],
},
},
}),
)
app.use(json({ limit: '50mb' }))
app.use(
text({
@@ -82,7 +87,7 @@ void container.load().then((container) => {
)
})
const logger: winston.Logger = container.get(TYPES.Logger)
const logger: winston.Logger = container.get(TYPES.ApiGateway_Logger)
server.setErrorConfig((app) => {
app.use((error: Record<string, unknown>, _request: Request, response: Response, _next: NextFunction) => {

View File

@@ -1,6 +1,6 @@
{
"name": "@standardnotes/api-gateway",
"version": "1.64.2",
"version": "1.70.1",
"engines": {
"node": ">=18.0.0 <21.0.0"
},
@@ -21,6 +21,7 @@
"clean": "rm -fr dist",
"build": "tsc --build",
"lint": "eslint . --ext .ts",
"lint:fix": "eslint . --fix --ext .ts",
"setup:env": "cp .env.sample .env",
"start": "yarn node dist/bin/server.js",
"upgrade:snjs": "yarn ncu -u '@standardnotes/*'"

View File

@@ -57,7 +57,7 @@ export class ContainerConfigLoader {
defaultMeta: { service: 'api-gateway' },
})
}
container.bind<winston.Logger>(TYPES.Logger).toConstantValue(logger)
container.bind<winston.Logger>(TYPES.ApiGateway_Logger).toConstantValue(logger)
if (!isConfiguredForInMemoryCache) {
const redisUrl = env.get('REDIS_URL')
@@ -68,36 +68,39 @@ export class ContainerConfigLoader {
} else {
redis = new Redis(redisUrl)
}
container.bind(TYPES.Redis).toConstantValue(redis)
container.bind(TYPES.ApiGateway_Redis).toConstantValue(redis)
}
container.bind<AxiosInstance>(TYPES.HTTPClient).toConstantValue(axios.create())
container.bind<AxiosInstance>(TYPES.ApiGateway_HTTPClient).toConstantValue(axios.create())
// env vars
container.bind(TYPES.SYNCING_SERVER_JS_URL).toConstantValue(env.get('SYNCING_SERVER_JS_URL', true))
container.bind(TYPES.AUTH_SERVER_URL).toConstantValue(env.get('AUTH_SERVER_URL', true))
container.bind(TYPES.REVISIONS_SERVER_URL).toConstantValue(env.get('REVISIONS_SERVER_URL', true))
container.bind(TYPES.EMAIL_SERVER_URL).toConstantValue(env.get('EMAIL_SERVER_URL', true))
container.bind(TYPES.PAYMENTS_SERVER_URL).toConstantValue(env.get('PAYMENTS_SERVER_URL', true))
container.bind(TYPES.FILES_SERVER_URL).toConstantValue(env.get('FILES_SERVER_URL', true))
container.bind(TYPES.WEB_SOCKET_SERVER_URL).toConstantValue(env.get('WEB_SOCKET_SERVER_URL', true))
container.bind(TYPES.AUTH_JWT_SECRET).toConstantValue(env.get('AUTH_JWT_SECRET'))
container.bind(TYPES.ApiGateway_SYNCING_SERVER_JS_URL).toConstantValue(env.get('SYNCING_SERVER_JS_URL', true))
container.bind(TYPES.ApiGateway_AUTH_SERVER_URL).toConstantValue(env.get('AUTH_SERVER_URL', true))
container.bind(TYPES.ApiGateway_REVISIONS_SERVER_URL).toConstantValue(env.get('REVISIONS_SERVER_URL', true))
container.bind(TYPES.ApiGateway_EMAIL_SERVER_URL).toConstantValue(env.get('EMAIL_SERVER_URL', true))
container.bind(TYPES.ApiGateway_PAYMENTS_SERVER_URL).toConstantValue(env.get('PAYMENTS_SERVER_URL', true))
container.bind(TYPES.ApiGateway_FILES_SERVER_URL).toConstantValue(env.get('FILES_SERVER_URL', true))
container.bind(TYPES.ApiGateway_WEB_SOCKET_SERVER_URL).toConstantValue(env.get('WEB_SOCKET_SERVER_URL', true))
container.bind(TYPES.ApiGateway_AUTH_JWT_SECRET).toConstantValue(env.get('AUTH_JWT_SECRET'))
container
.bind(TYPES.HTTP_CALL_TIMEOUT)
.bind(TYPES.ApiGateway_HTTP_CALL_TIMEOUT)
.toConstantValue(env.get('HTTP_CALL_TIMEOUT', true) ? +env.get('HTTP_CALL_TIMEOUT', true) : 60_000)
container.bind(TYPES.VERSION).toConstantValue(env.get('VERSION', true) ?? 'development')
container.bind(TYPES.CROSS_SERVICE_TOKEN_CACHE_TTL).toConstantValue(+env.get('CROSS_SERVICE_TOKEN_CACHE_TTL', true))
container.bind(TYPES.ApiGateway_VERSION).toConstantValue(env.get('VERSION', true) ?? 'development')
container
.bind(TYPES.ApiGateway_CROSS_SERVICE_TOKEN_CACHE_TTL)
.toConstantValue(+env.get('CROSS_SERVICE_TOKEN_CACHE_TTL', true))
container.bind(TYPES.ApiGateway_IS_CONFIGURED_FOR_HOME_SERVER).toConstantValue(isConfiguredForHomeServer)
// Middleware
container
.bind<RequiredCrossServiceTokenMiddleware>(TYPES.RequiredCrossServiceTokenMiddleware)
.bind<RequiredCrossServiceTokenMiddleware>(TYPES.ApiGateway_RequiredCrossServiceTokenMiddleware)
.to(RequiredCrossServiceTokenMiddleware)
container
.bind<OptionalCrossServiceTokenMiddleware>(TYPES.OptionalCrossServiceTokenMiddleware)
.bind<OptionalCrossServiceTokenMiddleware>(TYPES.ApiGateway_OptionalCrossServiceTokenMiddleware)
.to(OptionalCrossServiceTokenMiddleware)
container.bind<WebSocketAuthMiddleware>(TYPES.WebSocketAuthMiddleware).to(WebSocketAuthMiddleware)
container.bind<WebSocketAuthMiddleware>(TYPES.ApiGateway_WebSocketAuthMiddleware).to(WebSocketAuthMiddleware)
container
.bind<SubscriptionTokenAuthMiddleware>(TYPES.SubscriptionTokenAuthMiddleware)
.bind<SubscriptionTokenAuthMiddleware>(TYPES.ApiGateway_SubscriptionTokenAuthMiddleware)
.to(SubscriptionTokenAuthMiddleware)
// Services
@@ -106,24 +109,26 @@ export class ContainerConfigLoader {
throw new Error('Service container is required when configured for home server')
}
container
.bind<ServiceProxyInterface>(TYPES.ServiceProxy)
.bind<ServiceProxyInterface>(TYPES.ApiGateway_ServiceProxy)
.toConstantValue(
new DirectCallServiceProxy(configuration.serviceContainer, container.get(TYPES.FILES_SERVER_URL)),
new DirectCallServiceProxy(configuration.serviceContainer, container.get(TYPES.ApiGateway_FILES_SERVER_URL)),
)
} else {
container.bind<ServiceProxyInterface>(TYPES.ServiceProxy).to(HttpServiceProxy)
container.bind<ServiceProxyInterface>(TYPES.ApiGateway_ServiceProxy).to(HttpServiceProxy)
}
container.bind<TimerInterface>(TYPES.Timer).toConstantValue(new Timer())
container.bind<TimerInterface>(TYPES.ApiGateway_Timer).toConstantValue(new Timer())
if (isConfiguredForHomeServer) {
container
.bind<CrossServiceTokenCacheInterface>(TYPES.CrossServiceTokenCache)
.toConstantValue(new InMemoryCrossServiceTokenCache(container.get(TYPES.Timer)))
.bind<CrossServiceTokenCacheInterface>(TYPES.ApiGateway_CrossServiceTokenCache)
.toConstantValue(new InMemoryCrossServiceTokenCache(container.get(TYPES.ApiGateway_Timer)))
} else {
container.bind<CrossServiceTokenCacheInterface>(TYPES.CrossServiceTokenCache).to(RedisCrossServiceTokenCache)
container
.bind<CrossServiceTokenCacheInterface>(TYPES.ApiGateway_CrossServiceTokenCache)
.to(RedisCrossServiceTokenCache)
}
container
.bind<EndpointResolverInterface>(TYPES.EndpointResolver)
.bind<EndpointResolverInterface>(TYPES.ApiGateway_EndpointResolver)
.toConstantValue(new EndpointResolver(isConfiguredForHomeServer))
logger.debug('Configuration complete')

View File

@@ -1,29 +1,28 @@
export const TYPES = {
Logger: Symbol.for('Logger'),
Redis: Symbol.for('Redis'),
HTTPClient: Symbol.for('HTTPClient'),
ApiGateway_Logger: Symbol.for('ApiGateway_Logger'),
ApiGateway_Redis: Symbol.for('ApiGateway_Redis'),
ApiGateway_HTTPClient: Symbol.for('ApiGateway_HTTPClient'),
// env vars
SYNCING_SERVER_JS_URL: Symbol.for('SYNCING_SERVER_JS_URL'),
AUTH_SERVER_URL: Symbol.for('AUTH_SERVER_URL'),
PAYMENTS_SERVER_URL: Symbol.for('PAYMENTS_SERVER_URL'),
FILES_SERVER_URL: Symbol.for('FILES_SERVER_URL'),
REVISIONS_SERVER_URL: Symbol.for('REVISIONS_SERVER_URL'),
EMAIL_SERVER_URL: Symbol.for('EMAIL_SERVER_URL'),
WEB_SOCKET_SERVER_URL: Symbol.for('WEB_SOCKET_SERVER_URL'),
AUTH_JWT_SECRET: Symbol.for('AUTH_JWT_SECRET'),
HTTP_CALL_TIMEOUT: Symbol.for('HTTP_CALL_TIMEOUT'),
VERSION: Symbol.for('VERSION'),
CROSS_SERVICE_TOKEN_CACHE_TTL: Symbol.for('CROSS_SERVICE_TOKEN_CACHE_TTL'),
ApiGateway_SYNCING_SERVER_JS_URL: Symbol.for('ApiGateway_SYNCING_SERVER_JS_URL'),
ApiGateway_AUTH_SERVER_URL: Symbol.for('ApiGateway_AUTH_SERVER_URL'),
ApiGateway_PAYMENTS_SERVER_URL: Symbol.for('ApiGateway_PAYMENTS_SERVER_URL'),
ApiGateway_FILES_SERVER_URL: Symbol.for('ApiGateway_FILES_SERVER_URL'),
ApiGateway_REVISIONS_SERVER_URL: Symbol.for('ApiGateway_REVISIONS_SERVER_URL'),
ApiGateway_EMAIL_SERVER_URL: Symbol.for('ApiGateway_EMAIL_SERVER_URL'),
ApiGateway_WEB_SOCKET_SERVER_URL: Symbol.for('ApiGateway_WEB_SOCKET_SERVER_URL'),
ApiGateway_AUTH_JWT_SECRET: Symbol.for('ApiGateway_AUTH_JWT_SECRET'),
ApiGateway_HTTP_CALL_TIMEOUT: Symbol.for('ApiGateway_HTTP_CALL_TIMEOUT'),
ApiGateway_VERSION: Symbol.for('ApiGateway_VERSION'),
ApiGateway_CROSS_SERVICE_TOKEN_CACHE_TTL: Symbol.for('ApiGateway_CROSS_SERVICE_TOKEN_CACHE_TTL'),
ApiGateway_IS_CONFIGURED_FOR_HOME_SERVER: Symbol.for('ApiGateway_IS_CONFIGURED_FOR_HOME_SERVER'),
// Middleware
RequiredCrossServiceTokenMiddleware: Symbol.for('RequiredCrossServiceTokenMiddleware'),
OptionalCrossServiceTokenMiddleware: Symbol.for('OptionalCrossServiceTokenMiddleware'),
WebSocketAuthMiddleware: Symbol.for('WebSocketAuthMiddleware'),
SubscriptionTokenAuthMiddleware: Symbol.for('SubscriptionTokenAuthMiddleware'),
ApiGateway_RequiredCrossServiceTokenMiddleware: Symbol.for('ApiGateway_RequiredCrossServiceTokenMiddleware'),
ApiGateway_OptionalCrossServiceTokenMiddleware: Symbol.for('ApiGateway_OptionalCrossServiceTokenMiddleware'),
ApiGateway_WebSocketAuthMiddleware: Symbol.for('ApiGateway_WebSocketAuthMiddleware'),
ApiGateway_SubscriptionTokenAuthMiddleware: Symbol.for('ApiGateway_SubscriptionTokenAuthMiddleware'),
// Services
ServiceProxy: Symbol.for('ServiceProxy'),
CrossServiceTokenCache: Symbol.for('CrossServiceTokenCache'),
Timer: Symbol.for('Timer'),
EndpointResolver: Symbol.for('EndpointResolver'),
ApiGateway_ServiceProxy: Symbol.for('ApiGateway_ServiceProxy'),
ApiGateway_CrossServiceTokenCache: Symbol.for('ApiGateway_CrossServiceTokenCache'),
ApiGateway_Timer: Symbol.for('ApiGateway_Timer'),
ApiGateway_EndpointResolver: Symbol.for('ApiGateway_EndpointResolver'),
}
// export default TYPES

View File

@@ -1,5 +1,4 @@
import { CrossServiceTokenData } from '@standardnotes/security'
import { RoleName } from '@standardnotes/domain-core'
import { TimerInterface } from '@standardnotes/time'
import { NextFunction, Request, Response } from 'express'
import { BaseMiddleware } from 'inversify-express-utils'
@@ -17,7 +16,7 @@ export abstract class AuthMiddleware extends BaseMiddleware {
private crossServiceTokenCacheTTL: number,
private crossServiceTokenCache: CrossServiceTokenCacheInterface,
private timer: TimerInterface,
private logger: Logger,
protected logger: Logger,
) {
super()
}
@@ -51,10 +50,6 @@ export abstract class AuthMiddleware extends BaseMiddleware {
const decodedToken = <CrossServiceTokenData>verify(crossServiceToken, this.jwtSecret, { algorithms: ['HS256'] })
response.locals.freeUser =
decodedToken.roles.length === 1 &&
decodedToken.roles.find((role) => role.name === RoleName.NAMES.CoreUser) !== undefined
if (this.crossServiceTokenCacheTTL && !crossServiceTokenFetchedFromCache) {
await this.crossServiceTokenCache.set({
authorizationHeaderValue: authHeaderValue,

View File

@@ -9,7 +9,7 @@ export class LegacyController extends BaseHttpController {
private AUTH_ROUTES: Map<string, string>
private PARAMETRIZED_AUTH_ROUTES: Map<string, string>
constructor(@inject(TYPES.ServiceProxy) private httpService: ServiceProxyInterface) {
constructor(@inject(TYPES.ApiGateway_ServiceProxy) private httpService: ServiceProxyInterface) {
super()
this.AUTH_ROUTES = new Map([
@@ -29,17 +29,17 @@ export class LegacyController extends BaseHttpController {
])
}
@httpPost('/items/sync', TYPES.RequiredCrossServiceTokenMiddleware)
@httpPost('/items/sync', TYPES.ApiGateway_RequiredCrossServiceTokenMiddleware)
async legacyItemsSync(request: Request, response: Response): Promise<void> {
await this.httpService.callLegacySyncingServer(request, response, request.path.substring(1), request.body)
}
@httpGet('/items/:item_id/revisions', TYPES.RequiredCrossServiceTokenMiddleware)
@httpGet('/items/:item_id/revisions', TYPES.ApiGateway_RequiredCrossServiceTokenMiddleware)
async legacyGetRevisions(request: Request, response: Response): Promise<void> {
await this.httpService.callLegacySyncingServer(request, response, request.path.substring(1), request.body)
}
@httpGet('/items/:item_id/revisions/:id', TYPES.RequiredCrossServiceTokenMiddleware)
@httpGet('/items/:item_id/revisions/:id', TYPES.ApiGateway_RequiredCrossServiceTokenMiddleware)
async legacyGetRevision(request: Request, response: Response): Promise<void> {
await this.httpService.callLegacySyncingServer(request, response, request.path.substring(1), request.body)
}

View File

@@ -11,12 +11,12 @@ import { AuthMiddleware } from './AuthMiddleware'
@injectable()
export class OptionalCrossServiceTokenMiddleware extends AuthMiddleware {
constructor(
@inject(TYPES.ServiceProxy) serviceProxy: ServiceProxyInterface,
@inject(TYPES.AUTH_JWT_SECRET) jwtSecret: string,
@inject(TYPES.CROSS_SERVICE_TOKEN_CACHE_TTL) crossServiceTokenCacheTTL: number,
@inject(TYPES.CrossServiceTokenCache) crossServiceTokenCache: CrossServiceTokenCacheInterface,
@inject(TYPES.Timer) timer: TimerInterface,
@inject(TYPES.Logger) logger: Logger,
@inject(TYPES.ApiGateway_ServiceProxy) serviceProxy: ServiceProxyInterface,
@inject(TYPES.ApiGateway_AUTH_JWT_SECRET) jwtSecret: string,
@inject(TYPES.ApiGateway_CROSS_SERVICE_TOKEN_CACHE_TTL) crossServiceTokenCacheTTL: number,
@inject(TYPES.ApiGateway_CrossServiceTokenCache) crossServiceTokenCache: CrossServiceTokenCacheInterface,
@inject(TYPES.ApiGateway_Timer) timer: TimerInterface,
@inject(TYPES.ApiGateway_Logger) logger: Logger,
) {
super(serviceProxy, jwtSecret, crossServiceTokenCacheTTL, crossServiceTokenCache, timer, logger)
}

View File

@@ -11,12 +11,12 @@ import { AuthMiddleware } from './AuthMiddleware'
@injectable()
export class RequiredCrossServiceTokenMiddleware extends AuthMiddleware {
constructor(
@inject(TYPES.ServiceProxy) serviceProxy: ServiceProxyInterface,
@inject(TYPES.AUTH_JWT_SECRET) jwtSecret: string,
@inject(TYPES.CROSS_SERVICE_TOKEN_CACHE_TTL) crossServiceTokenCacheTTL: number,
@inject(TYPES.CrossServiceTokenCache) crossServiceTokenCache: CrossServiceTokenCacheInterface,
@inject(TYPES.Timer) timer: TimerInterface,
@inject(TYPES.Logger) logger: Logger,
@inject(TYPES.ApiGateway_ServiceProxy) serviceProxy: ServiceProxyInterface,
@inject(TYPES.ApiGateway_AUTH_JWT_SECRET) jwtSecret: string,
@inject(TYPES.ApiGateway_CROSS_SERVICE_TOKEN_CACHE_TTL) crossServiceTokenCacheTTL: number,
@inject(TYPES.ApiGateway_CrossServiceTokenCache) crossServiceTokenCache: CrossServiceTokenCacheInterface,
@inject(TYPES.ApiGateway_Timer) timer: TimerInterface,
@inject(TYPES.ApiGateway_Logger) logger: Logger,
) {
super(serviceProxy, jwtSecret, crossServiceTokenCacheTTL, crossServiceTokenCache, timer, logger)
}
@@ -42,6 +42,8 @@ export class RequiredCrossServiceTokenMiddleware extends AuthMiddleware {
_next: NextFunction,
): boolean {
if (!authHeaderValue) {
this.logger.debug('Missing auth header')
response.status(401).send({
error: {
tag: 'invalid-auth',

View File

@@ -11,10 +11,10 @@ import { TokenAuthenticationMethod } from './TokenAuthenticationMethod'
@injectable()
export class SubscriptionTokenAuthMiddleware extends BaseMiddleware {
constructor(
@inject(TYPES.HTTPClient) private httpClient: AxiosInstance,
@inject(TYPES.AUTH_SERVER_URL) private authServerUrl: string,
@inject(TYPES.AUTH_JWT_SECRET) private jwtSecret: string,
@inject(TYPES.Logger) private logger: Logger,
@inject(TYPES.ApiGateway_HTTPClient) private httpClient: AxiosInstance,
@inject(TYPES.ApiGateway_AUTH_SERVER_URL) private authServerUrl: string,
@inject(TYPES.ApiGateway_AUTH_JWT_SECRET) private jwtSecret: string,
@inject(TYPES.ApiGateway_Logger) private logger: Logger,
) {
super()
}

View File

@@ -1,5 +1,4 @@
import { CrossServiceTokenData } from '@standardnotes/security'
import { RoleName } from '@standardnotes/domain-core'
import { NextFunction, Request, Response } from 'express'
import { inject, injectable } from 'inversify'
import { BaseMiddleware } from 'inversify-express-utils'
@@ -12,10 +11,10 @@ import { TYPES } from '../Bootstrap/Types'
@injectable()
export class WebSocketAuthMiddleware extends BaseMiddleware {
constructor(
@inject(TYPES.HTTPClient) private httpClient: AxiosInstance,
@inject(TYPES.AUTH_SERVER_URL) private authServerUrl: string,
@inject(TYPES.AUTH_JWT_SECRET) private jwtSecret: string,
@inject(TYPES.Logger) private logger: Logger,
@inject(TYPES.ApiGateway_HTTPClient) private httpClient: AxiosInstance,
@inject(TYPES.ApiGateway_AUTH_SERVER_URL) private authServerUrl: string,
@inject(TYPES.ApiGateway_AUTH_JWT_SECRET) private jwtSecret: string,
@inject(TYPES.ApiGateway_Logger) private logger: Logger,
) {
super()
}
@@ -60,9 +59,6 @@ export class WebSocketAuthMiddleware extends BaseMiddleware {
const decodedToken = <CrossServiceTokenData>verify(crossServiceToken, this.jwtSecret, { algorithms: ['HS256'] })
response.locals.freeUser =
decodedToken.roles.length === 1 &&
decodedToken.roles.find((role) => role.name === RoleName.NAMES.CoreUser) !== undefined
response.locals.user = decodedToken.user
response.locals.roles = decodedToken.roles
} catch (error) {

View File

@@ -4,6 +4,7 @@ export * from './SubscriptionTokenAuthMiddleware'
export * from './TokenAuthenticationMethod'
export * from './WebSocketAuthMiddleware'
export * from './v1/ActionsController'
export * from './v1/MessagesController'
export * from './v1/AuthenticatorsController'
export * from './v1/FilesController'
export * from './v1/InvoicesController'
@@ -12,6 +13,9 @@ export * from './v1/OfflineController'
export * from './v1/PaymentsController'
export * from './v1/RevisionsController'
export * from './v1/SessionsController'
export * from './v1/SharedVaultInvitesController'
export * from './v1/SharedVaultUsersController'
export * from './v1/SharedVaultsController'
export * from './v1/SubscriptionInvitesController'
export * from './v1/TokensController'
export * from './v1/UsersController'

View File

@@ -8,8 +8,8 @@ import { EndpointResolverInterface } from '../../Service/Resolver/EndpointResolv
@controller('/v1')
export class ActionsController extends BaseHttpController {
constructor(
@inject(TYPES.ServiceProxy) private serviceProxy: ServiceProxyInterface,
@inject(TYPES.EndpointResolver) private endpointResolver: EndpointResolverInterface,
@inject(TYPES.ApiGateway_ServiceProxy) private serviceProxy: ServiceProxyInterface,
@inject(TYPES.ApiGateway_EndpointResolver) private endpointResolver: EndpointResolverInterface,
) {
super()
}
@@ -24,7 +24,7 @@ export class ActionsController extends BaseHttpController {
)
}
@httpGet('/login-params', TYPES.OptionalCrossServiceTokenMiddleware)
@httpGet('/login-params', TYPES.ApiGateway_OptionalCrossServiceTokenMiddleware)
async loginParams(request: Request, response: Response): Promise<void> {
await this.serviceProxy.callAuthServer(
request,
@@ -34,7 +34,7 @@ export class ActionsController extends BaseHttpController {
)
}
@httpPost('/logout', TYPES.OptionalCrossServiceTokenMiddleware)
@httpPost('/logout', TYPES.ApiGateway_OptionalCrossServiceTokenMiddleware)
async logout(request: Request, response: Response): Promise<void> {
await this.serviceProxy.callAuthServer(
request,
@@ -54,7 +54,7 @@ export class ActionsController extends BaseHttpController {
)
}
@httpPost('/recovery/codes', TYPES.RequiredCrossServiceTokenMiddleware)
@httpPost('/recovery/codes', TYPES.ApiGateway_RequiredCrossServiceTokenMiddleware)
async recoveryCodes(request: Request, response: Response): Promise<void> {
await this.serviceProxy.callAuthServer(
request,

View File

@@ -9,13 +9,13 @@ import { EndpointResolverInterface } from '../../Service/Resolver/EndpointResolv
@controller('/v1/authenticators')
export class AuthenticatorsController extends BaseHttpController {
constructor(
@inject(TYPES.ServiceProxy) private httpService: ServiceProxyInterface,
@inject(TYPES.EndpointResolver) private endpointResolver: EndpointResolverInterface,
@inject(TYPES.ApiGateway_ServiceProxy) private httpService: ServiceProxyInterface,
@inject(TYPES.ApiGateway_EndpointResolver) private endpointResolver: EndpointResolverInterface,
) {
super()
}
@httpDelete('/:authenticatorId', TYPES.RequiredCrossServiceTokenMiddleware)
@httpDelete('/:authenticatorId', TYPES.ApiGateway_RequiredCrossServiceTokenMiddleware)
async delete(request: Request, response: Response): Promise<void> {
await this.httpService.callAuthServer(
request,
@@ -29,7 +29,7 @@ export class AuthenticatorsController extends BaseHttpController {
)
}
@httpGet('/', TYPES.RequiredCrossServiceTokenMiddleware)
@httpGet('/', TYPES.ApiGateway_RequiredCrossServiceTokenMiddleware)
async list(request: Request, response: Response): Promise<void> {
await this.httpService.callAuthServer(
request,
@@ -39,7 +39,7 @@ export class AuthenticatorsController extends BaseHttpController {
)
}
@httpGet('/generate-registration-options', TYPES.RequiredCrossServiceTokenMiddleware)
@httpGet('/generate-registration-options', TYPES.ApiGateway_RequiredCrossServiceTokenMiddleware)
async generateRegistrationOptions(request: Request, response: Response): Promise<void> {
await this.httpService.callAuthServer(
request,
@@ -59,7 +59,7 @@ export class AuthenticatorsController extends BaseHttpController {
)
}
@httpPost('/verify-registration', TYPES.RequiredCrossServiceTokenMiddleware)
@httpPost('/verify-registration', TYPES.ApiGateway_RequiredCrossServiceTokenMiddleware)
async verifyRegistration(request: Request, response: Response): Promise<void> {
await this.httpService.callAuthServer(
request,

View File

@@ -9,13 +9,13 @@ import { EndpointResolverInterface } from '../../Service/Resolver/EndpointResolv
@controller('/v1/files')
export class FilesController extends BaseHttpController {
constructor(
@inject(TYPES.ServiceProxy) private httpService: ServiceProxyInterface,
@inject(TYPES.EndpointResolver) private endpointResolver: EndpointResolverInterface,
@inject(TYPES.ApiGateway_ServiceProxy) private httpService: ServiceProxyInterface,
@inject(TYPES.ApiGateway_EndpointResolver) private endpointResolver: EndpointResolverInterface,
) {
super()
}
@httpPost('/valet-tokens', TYPES.RequiredCrossServiceTokenMiddleware)
@httpPost('/valet-tokens', TYPES.ApiGateway_RequiredCrossServiceTokenMiddleware)
async createToken(request: Request, response: Response): Promise<void> {
await this.httpService.callAuthServer(
request,

View File

@@ -6,11 +6,11 @@ import { ServiceProxyInterface } from '../../Service/Http/ServiceProxyInterface'
@controller('/v1')
export class InvoicesController extends BaseHttpController {
constructor(@inject(TYPES.ServiceProxy) private httpService: ServiceProxyInterface) {
constructor(@inject(TYPES.ApiGateway_ServiceProxy) private httpService: ServiceProxyInterface) {
super()
}
@httpPost('/invoices/send-latest', TYPES.SubscriptionTokenAuthMiddleware)
@httpPost('/invoices/send-latest', TYPES.ApiGateway_SubscriptionTokenAuthMiddleware)
async sendLatestInvoice(request: Request, response: Response): Promise<void> {
await this.httpService.callPaymentsServer(request, response, 'api/pro_users/send-invoice', request.body)
}

View File

@@ -5,11 +5,11 @@ import { TYPES } from '../../Bootstrap/Types'
import { ServiceProxyInterface } from '../../Service/Http/ServiceProxyInterface'
import { EndpointResolverInterface } from '../../Service/Resolver/EndpointResolverInterface'
@controller('/v1/items', TYPES.RequiredCrossServiceTokenMiddleware)
@controller('/v1/items', TYPES.ApiGateway_RequiredCrossServiceTokenMiddleware)
export class ItemsController extends BaseHttpController {
constructor(
@inject(TYPES.ServiceProxy) private serviceProxy: ServiceProxyInterface,
@inject(TYPES.EndpointResolver) private endpointResolver: EndpointResolverInterface,
@inject(TYPES.ApiGateway_ServiceProxy) private serviceProxy: ServiceProxyInterface,
@inject(TYPES.ApiGateway_EndpointResolver) private endpointResolver: EndpointResolverInterface,
) {
super()
}

View File

@@ -0,0 +1,70 @@
import { Request, Response } from 'express'
import { inject } from 'inversify'
import { BaseHttpController, controller, httpDelete, httpGet, httpPost } from 'inversify-express-utils'
import { TYPES } from '../../Bootstrap/Types'
import { ServiceProxyInterface } from '../../Service/Http/ServiceProxyInterface'
import { EndpointResolverInterface } from '../../Service/Resolver/EndpointResolverInterface'
@controller('/v1/messages', TYPES.ApiGateway_RequiredCrossServiceTokenMiddleware)
export class MessagesController extends BaseHttpController {
constructor(
@inject(TYPES.ApiGateway_ServiceProxy) private httpService: ServiceProxyInterface,
@inject(TYPES.ApiGateway_EndpointResolver) private endpointResolver: EndpointResolverInterface,
) {
super()
}
@httpGet('/')
async getMessages(request: Request, response: Response): Promise<void> {
await this.httpService.callSyncingServer(
request,
response,
this.endpointResolver.resolveEndpointOrMethodIdentifier('GET', 'messages/'),
request.body,
)
}
@httpGet('/outbound')
async getMessagesSent(request: Request, response: Response): Promise<void> {
await this.httpService.callSyncingServer(
request,
response,
this.endpointResolver.resolveEndpointOrMethodIdentifier('GET', 'messages/outbound'),
request.body,
)
}
@httpPost('/')
async sendMessage(request: Request, response: Response): Promise<void> {
await this.httpService.callSyncingServer(
request,
response,
this.endpointResolver.resolveEndpointOrMethodIdentifier('POST', 'messages/'),
request.body,
)
}
@httpDelete('/inbound')
async deleteMessagesSentToUser(request: Request, response: Response): Promise<void> {
await this.httpService.callSyncingServer(
request,
response,
this.endpointResolver.resolveEndpointOrMethodIdentifier('DELETE', 'messages/inbound'),
request.body,
)
}
@httpDelete('/:messageUuid')
async deleteMessage(request: Request, response: Response): Promise<void> {
await this.httpService.callSyncingServer(
request,
response,
this.endpointResolver.resolveEndpointOrMethodIdentifier(
'DELETE',
'messages/:messageUuid',
request.params.messageUuid,
),
request.body,
)
}
}

View File

@@ -9,8 +9,8 @@ import { EndpointResolverInterface } from '../../Service/Resolver/EndpointResolv
@controller('/v1/offline')
export class OfflineController extends BaseHttpController {
constructor(
@inject(TYPES.ServiceProxy) private httpService: ServiceProxyInterface,
@inject(TYPES.EndpointResolver) private endpointResolver: EndpointResolverInterface,
@inject(TYPES.ApiGateway_ServiceProxy) private httpService: ServiceProxyInterface,
@inject(TYPES.ApiGateway_EndpointResolver) private endpointResolver: EndpointResolverInterface,
) {
super()
}

View File

@@ -6,7 +6,7 @@ import { ServiceProxyInterface } from '../../Service/Http/ServiceProxyInterface'
@controller('/v1')
export class PaymentsController extends BaseHttpController {
constructor(@inject(TYPES.ServiceProxy) private httpService: ServiceProxyInterface) {
constructor(@inject(TYPES.ApiGateway_ServiceProxy) private httpService: ServiceProxyInterface) {
super()
}
@@ -40,12 +40,12 @@ export class PaymentsController extends BaseHttpController {
await this.httpService.callPaymentsServer(request, response, 'api/extensions', request.body)
}
@httpPost('/subscriptions/tiered', TYPES.SubscriptionTokenAuthMiddleware)
@httpPost('/subscriptions/tiered', TYPES.ApiGateway_SubscriptionTokenAuthMiddleware)
async createTieredSubscription(request: Request, response: Response): Promise<void> {
await this.httpService.callPaymentsServer(request, response, 'api/subscriptions/tiered', request.body)
}
@httpPost('/subscriptions/apple_iap_confirm', TYPES.SubscriptionTokenAuthMiddleware)
@httpPost('/subscriptions/apple_iap_confirm', TYPES.ApiGateway_SubscriptionTokenAuthMiddleware)
async appleIAPConfirm(request: Request, response: Response): Promise<void> {
await this.httpService.callPaymentsServer(request, response, 'api/subscriptions/apple_iap_confirm', request.body)
}
@@ -140,7 +140,7 @@ export class PaymentsController extends BaseHttpController {
)
}
@httpPost('/payments/stripe-setup-intent', TYPES.SubscriptionTokenAuthMiddleware)
@httpPost('/payments/stripe-setup-intent', TYPES.ApiGateway_SubscriptionTokenAuthMiddleware)
async createStripeSetupIntent(request: Request, response: Response): Promise<void> {
await this.httpService.callPaymentsServer(request, response, 'api/pro_users/stripe-setup-intent', request.body)
}

View File

@@ -1,7 +1,7 @@
import { BaseHttpController, controller, httpDelete, httpGet, results } from 'inversify-express-utils'
import { TYPES } from '../../Bootstrap/Types'
@controller('/v1/items/:item_id/revisions', TYPES.RequiredCrossServiceTokenMiddleware)
@controller('/v1/items/:item_id/revisions', TYPES.ApiGateway_RequiredCrossServiceTokenMiddleware)
export class RevisionsController extends BaseHttpController {
@httpGet('/')
async getRevisions(): Promise<results.JsonResult> {

View File

@@ -8,13 +8,13 @@ import { EndpointResolverInterface } from '../../Service/Resolver/EndpointResolv
@controller('/v1/sessions')
export class SessionsController extends BaseHttpController {
constructor(
@inject(TYPES.ServiceProxy) private httpService: ServiceProxyInterface,
@inject(TYPES.EndpointResolver) private endpointResolver: EndpointResolverInterface,
@inject(TYPES.ApiGateway_ServiceProxy) private httpService: ServiceProxyInterface,
@inject(TYPES.ApiGateway_EndpointResolver) private endpointResolver: EndpointResolverInterface,
) {
super()
}
@httpGet('/', TYPES.RequiredCrossServiceTokenMiddleware)
@httpGet('/', TYPES.ApiGateway_RequiredCrossServiceTokenMiddleware)
async getSessions(request: Request, response: Response): Promise<void> {
await this.httpService.callAuthServer(
request,
@@ -23,7 +23,7 @@ export class SessionsController extends BaseHttpController {
)
}
@httpDelete('/:uuid', TYPES.RequiredCrossServiceTokenMiddleware)
@httpDelete('/:uuid', TYPES.ApiGateway_RequiredCrossServiceTokenMiddleware)
async deleteSession(request: Request, response: Response): Promise<void> {
await this.httpService.callAuthServer(
request,
@@ -35,7 +35,7 @@ export class SessionsController extends BaseHttpController {
)
}
@httpDelete('/', TYPES.RequiredCrossServiceTokenMiddleware)
@httpDelete('/', TYPES.ApiGateway_RequiredCrossServiceTokenMiddleware)
async deleteSessions(request: Request, response: Response): Promise<void> {
await this.httpService.callAuthServer(
request,

View File

@@ -0,0 +1,158 @@
import { Request, Response } from 'express'
import { inject } from 'inversify'
import { BaseHttpController, controller, httpDelete, httpGet, httpPatch, httpPost } from 'inversify-express-utils'
import { TYPES } from '../../Bootstrap/Types'
import { ServiceProxyInterface } from '../../Service/Http/ServiceProxyInterface'
import { EndpointResolverInterface } from '../../Service/Resolver/EndpointResolverInterface'
@controller('/v1/shared-vaults', TYPES.ApiGateway_RequiredCrossServiceTokenMiddleware)
export class SharedVaultInvitesController extends BaseHttpController {
constructor(
@inject(TYPES.ApiGateway_ServiceProxy) private httpService: ServiceProxyInterface,
@inject(TYPES.ApiGateway_EndpointResolver) private endpointResolver: EndpointResolverInterface,
) {
super()
}
@httpPost('/:sharedVaultUuid/invites')
async createSharedVaultInvite(request: Request, response: Response): Promise<void> {
await this.httpService.callSyncingServer(
request,
response,
this.endpointResolver.resolveEndpointOrMethodIdentifier(
'POST',
'shared-vaults/:sharedVaultUuid/invites',
request.params.sharedVaultUuid,
),
request.body,
)
}
@httpPatch('/:sharedVaultUuid/invites/:inviteUuid')
async updateSharedVaultInvite(request: Request, response: Response): Promise<void> {
await this.httpService.callSyncingServer(
request,
response,
this.endpointResolver.resolveEndpointOrMethodIdentifier(
'PATCH',
'shared-vaults/:sharedVaultUuid/invites/:inviteUuid',
request.params.sharedVaultUuid,
request.params.inviteUuid,
),
request.body,
)
}
@httpPost('/:sharedVaultUuid/invites/:inviteUuid/accept')
async acceptSharedVaultInvite(request: Request, response: Response): Promise<void> {
await this.httpService.callSyncingServer(
request,
response,
this.endpointResolver.resolveEndpointOrMethodIdentifier(
'POST',
'shared-vaults/:sharedVaultUuid/invites/:inviteUuid/accept',
request.params.sharedVaultUuid,
request.params.inviteUuid,
),
request.body,
)
}
@httpPost('/:sharedVaultUuid/invites/:inviteUuid/decline')
async declineSharedVaultInvite(request: Request, response: Response): Promise<void> {
await this.httpService.callSyncingServer(
request,
response,
this.endpointResolver.resolveEndpointOrMethodIdentifier(
'POST',
'shared-vaults/:sharedVaultUuid/invites/:inviteUuid/decline',
request.params.sharedVaultUuid,
request.params.inviteUuid,
),
request.body,
)
}
@httpDelete('/invites/inbound')
async deleteInboundUserInvites(request: Request, response: Response): Promise<void> {
await this.httpService.callSyncingServer(
request,
response,
this.endpointResolver.resolveEndpointOrMethodIdentifier('DELETE', 'shared-vaults/invites/inbound'),
request.body,
)
}
@httpDelete('/invites/outbound')
async deleteOutboundUserInvites(request: Request, response: Response): Promise<void> {
await this.httpService.callSyncingServer(
request,
response,
this.endpointResolver.resolveEndpointOrMethodIdentifier('DELETE', 'shared-vaults/invites/outbound'),
request.body,
)
}
@httpGet('/invites/outbound')
async getOutboundUserInvites(request: Request, response: Response): Promise<void> {
await this.httpService.callSyncingServer(
request,
response,
this.endpointResolver.resolveEndpointOrMethodIdentifier('GET', 'shared-vaults/invites/outbound'),
request.body,
)
}
@httpGet('/invites')
async getUserInvites(request: Request, response: Response): Promise<void> {
await this.httpService.callSyncingServer(
request,
response,
this.endpointResolver.resolveEndpointOrMethodIdentifier('GET', 'shared-vaults/invites'),
request.body,
)
}
@httpGet('/:sharedVaultUuid/invites')
async getSharedVaultInvites(request: Request, response: Response): Promise<void> {
await this.httpService.callSyncingServer(
request,
response,
this.endpointResolver.resolveEndpointOrMethodIdentifier(
'GET',
'shared-vaults/:sharedVaultUuid/invites',
request.params.sharedVaultUuid,
),
request.body,
)
}
@httpDelete('/:sharedVaultUuid/invites/:inviteUuid')
async deleteSharedVaultInvite(request: Request, response: Response): Promise<void> {
await this.httpService.callSyncingServer(
request,
response,
this.endpointResolver.resolveEndpointOrMethodIdentifier(
'DELETE',
'shared-vaults/:sharedVaultUuid/invites/:inviteUuid',
request.params.sharedVaultUuid,
request.params.inviteUuid,
),
request.body,
)
}
@httpDelete('/:sharedVaultUuid/invites')
async deleteAllSharedVaultInvites(request: Request, response: Response): Promise<void> {
await this.httpService.callSyncingServer(
request,
response,
this.endpointResolver.resolveEndpointOrMethodIdentifier(
'DELETE',
'shared-vaults/:sharedVaultUuid/invites',
request.params.sharedVaultUuid,
),
request.body,
)
}
}

View File

@@ -0,0 +1,45 @@
import { Request, Response } from 'express'
import { inject } from 'inversify'
import { BaseHttpController, controller, httpDelete, httpGet } from 'inversify-express-utils'
import { TYPES } from '../../Bootstrap/Types'
import { ServiceProxyInterface } from '../../Service/Http/ServiceProxyInterface'
import { EndpointResolverInterface } from '../../Service/Resolver/EndpointResolverInterface'
@controller('/v1/shared-vaults/:sharedVaultUuid/users', TYPES.ApiGateway_RequiredCrossServiceTokenMiddleware)
export class SharedVaultUsersController extends BaseHttpController {
constructor(
@inject(TYPES.ApiGateway_ServiceProxy) private httpService: ServiceProxyInterface,
@inject(TYPES.ApiGateway_EndpointResolver) private endpointResolver: EndpointResolverInterface,
) {
super()
}
@httpGet('/')
async getSharedVaultUsers(request: Request, response: Response): Promise<void> {
await this.httpService.callSyncingServer(
request,
response,
this.endpointResolver.resolveEndpointOrMethodIdentifier(
'GET',
'shared-vaults/:sharedVaultUuid/users',
request.params.sharedVaultUuid,
),
request.body,
)
}
@httpDelete('/:userUuid')
async removeUserFromSharedVault(request: Request, response: Response): Promise<void> {
await this.httpService.callSyncingServer(
request,
response,
this.endpointResolver.resolveEndpointOrMethodIdentifier(
'DELETE',
'shared-vaults/:sharedVaultUuid/users/:userUuid',
request.params.sharedVaultUuid,
request.params.userUuid,
),
request.body,
)
}
}

View File

@@ -0,0 +1,64 @@
import { Request, Response } from 'express'
import { inject } from 'inversify'
import { BaseHttpController, controller, httpDelete, httpGet, httpPost } from 'inversify-express-utils'
import { TYPES } from '../../Bootstrap/Types'
import { ServiceProxyInterface } from '../../Service/Http/ServiceProxyInterface'
import { EndpointResolverInterface } from '../../Service/Resolver/EndpointResolverInterface'
@controller('/v1/shared-vaults', TYPES.ApiGateway_RequiredCrossServiceTokenMiddleware)
export class SharedVaultsController extends BaseHttpController {
constructor(
@inject(TYPES.ApiGateway_ServiceProxy) private httpService: ServiceProxyInterface,
@inject(TYPES.ApiGateway_EndpointResolver) private endpointResolver: EndpointResolverInterface,
) {
super()
}
@httpGet('/')
async getSharedVaults(request: Request, response: Response): Promise<void> {
await this.httpService.callSyncingServer(
request,
response,
this.endpointResolver.resolveEndpointOrMethodIdentifier('GET', 'shared-vaults/'),
request.body,
)
}
@httpPost('/')
async createSharedVault(request: Request, response: Response): Promise<void> {
await this.httpService.callSyncingServer(
request,
response,
this.endpointResolver.resolveEndpointOrMethodIdentifier('POST', 'shared-vaults/'),
request.body,
)
}
@httpDelete('/:sharedVaultUuid')
async deleteSharedVault(request: Request, response: Response): Promise<void> {
await this.httpService.callSyncingServer(
request,
response,
this.endpointResolver.resolveEndpointOrMethodIdentifier(
'DELETE',
'shared-vaults/:sharedVaultUuid',
request.params.sharedVaultUuid,
),
request.body,
)
}
@httpPost('/:sharedVaultUuid/valet-tokens')
async createValetTokenForSharedVaultFile(request: Request, response: Response): Promise<void> {
await this.httpService.callSyncingServer(
request,
response,
this.endpointResolver.resolveEndpointOrMethodIdentifier(
'POST',
'shared-vaults/:sharedVaultUuid/valet-tokens',
request.params.sharedVaultUuid,
),
request.body,
)
}
}

View File

@@ -9,13 +9,13 @@ import { EndpointResolverInterface } from '../../Service/Resolver/EndpointResolv
@controller('/v1/subscription-invites')
export class SubscriptionInvitesController extends BaseHttpController {
constructor(
@inject(TYPES.ServiceProxy) private httpService: ServiceProxyInterface,
@inject(TYPES.EndpointResolver) private endpointResolver: EndpointResolverInterface,
@inject(TYPES.ApiGateway_ServiceProxy) private httpService: ServiceProxyInterface,
@inject(TYPES.ApiGateway_EndpointResolver) private endpointResolver: EndpointResolverInterface,
) {
super()
}
@httpPost('/', TYPES.RequiredCrossServiceTokenMiddleware)
@httpPost('/', TYPES.ApiGateway_RequiredCrossServiceTokenMiddleware)
async inviteToSubscriptionSharing(request: Request, response: Response): Promise<void> {
await this.httpService.callAuthServer(
request,
@@ -25,7 +25,7 @@ export class SubscriptionInvitesController extends BaseHttpController {
)
}
@httpGet('/', TYPES.RequiredCrossServiceTokenMiddleware)
@httpGet('/', TYPES.ApiGateway_RequiredCrossServiceTokenMiddleware)
async listInvites(request: Request, response: Response): Promise<void> {
await this.httpService.callAuthServer(
request,
@@ -35,7 +35,7 @@ export class SubscriptionInvitesController extends BaseHttpController {
)
}
@httpDelete('/:inviteUuid', TYPES.RequiredCrossServiceTokenMiddleware)
@httpDelete('/:inviteUuid', TYPES.ApiGateway_RequiredCrossServiceTokenMiddleware)
async cancelSubscriptionSharing(request: Request, response: Response): Promise<void> {
await this.httpService.callAuthServer(
request,
@@ -48,7 +48,7 @@ export class SubscriptionInvitesController extends BaseHttpController {
)
}
@httpPost('/:inviteUuid/accept', TYPES.RequiredCrossServiceTokenMiddleware)
@httpPost('/:inviteUuid/accept', TYPES.ApiGateway_RequiredCrossServiceTokenMiddleware)
async acceptInvite(request: Request, response: Response): Promise<void> {
await this.httpService.callAuthServer(
request,

View File

@@ -9,13 +9,13 @@ import { EndpointResolverInterface } from '../../Service/Resolver/EndpointResolv
@controller('/v1/subscription-tokens')
export class TokensController extends BaseHttpController {
constructor(
@inject(TYPES.ServiceProxy) private httpService: ServiceProxyInterface,
@inject(TYPES.EndpointResolver) private endpointResolver: EndpointResolverInterface,
@inject(TYPES.ApiGateway_ServiceProxy) private httpService: ServiceProxyInterface,
@inject(TYPES.ApiGateway_EndpointResolver) private endpointResolver: EndpointResolverInterface,
) {
super()
}
@httpPost('/', TYPES.RequiredCrossServiceTokenMiddleware)
@httpPost('/', TYPES.ApiGateway_RequiredCrossServiceTokenMiddleware)
async createToken(request: Request, response: Response): Promise<void> {
await this.httpService.callAuthServer(
request,

View File

@@ -20,9 +20,10 @@ import { EndpointResolverInterface } from '../../Service/Resolver/EndpointResolv
@controller('/v1/users')
export class UsersController extends BaseHttpController {
constructor(
@inject(TYPES.ServiceProxy) private httpService: ServiceProxyInterface,
@inject(TYPES.EndpointResolver) private endpointResolver: EndpointResolverInterface,
@inject(TYPES.Logger) private logger: Logger,
@inject(TYPES.ApiGateway_ServiceProxy) private httpService: ServiceProxyInterface,
@inject(TYPES.ApiGateway_EndpointResolver) private endpointResolver: EndpointResolverInterface,
@inject(TYPES.ApiGateway_Logger) private logger: Logger,
@inject(TYPES.ApiGateway_IS_CONFIGURED_FOR_HOME_SERVER) private isConfiguredForHomeServer: boolean,
) {
super()
}
@@ -32,12 +33,12 @@ export class UsersController extends BaseHttpController {
await this.httpService.callPaymentsServer(request, response, 'api/pro_users/claim-account', request.body)
}
@httpPost('/send-activation-code', TYPES.SubscriptionTokenAuthMiddleware)
@httpPost('/send-activation-code', TYPES.ApiGateway_SubscriptionTokenAuthMiddleware)
async sendActivationCode(request: Request, response: Response): Promise<void> {
await this.httpService.callPaymentsServer(request, response, 'api/pro_users/send-activation-code', request.body)
}
@httpPatch('/:userId', TYPES.RequiredCrossServiceTokenMiddleware)
@httpPatch('/:userId', TYPES.ApiGateway_RequiredCrossServiceTokenMiddleware)
async updateUser(request: Request, response: Response): Promise<void> {
await this.httpService.callAuthServer(
request,
@@ -47,7 +48,7 @@ export class UsersController extends BaseHttpController {
)
}
@httpPut('/:userUuid/password', TYPES.RequiredCrossServiceTokenMiddleware)
@httpPut('/:userUuid/password', TYPES.ApiGateway_RequiredCrossServiceTokenMiddleware)
async changePassword(request: Request, response: Response): Promise<void> {
this.logger.debug(
'[DEPRECATED] use endpoint /v1/users/:userUuid/attributes/credentials instead of /v1/users/:userUuid/password',
@@ -65,7 +66,7 @@ export class UsersController extends BaseHttpController {
)
}
@httpPut('/:userUuid/attributes/credentials', TYPES.RequiredCrossServiceTokenMiddleware)
@httpPut('/:userUuid/attributes/credentials', TYPES.ApiGateway_RequiredCrossServiceTokenMiddleware)
async changeCredentials(request: Request, response: Response): Promise<void> {
await this.httpService.callAuthServer(
request,
@@ -79,7 +80,7 @@ export class UsersController extends BaseHttpController {
)
}
@httpGet('/:userId/params', TYPES.RequiredCrossServiceTokenMiddleware)
@httpGet('/:userId/params', TYPES.ApiGateway_RequiredCrossServiceTokenMiddleware)
async getKeyParams(request: Request, response: Response): Promise<void> {
await this.httpService.callAuthServer(
request,
@@ -88,12 +89,12 @@ export class UsersController extends BaseHttpController {
)
}
@all('/:userId/mfa', TYPES.RequiredCrossServiceTokenMiddleware)
@all('/:userId/mfa', TYPES.ApiGateway_RequiredCrossServiceTokenMiddleware)
async blockMFA(): Promise<results.StatusCodeResult> {
return this.statusCode(401)
}
@httpPost('/:userUuid/integrations/listed', TYPES.RequiredCrossServiceTokenMiddleware)
@httpPost('/:userUuid/integrations/listed', TYPES.ApiGateway_RequiredCrossServiceTokenMiddleware)
async createListedAccount(request: Request, response: Response): Promise<void> {
await this.httpService.callAuthServer(
request,
@@ -113,7 +114,7 @@ export class UsersController extends BaseHttpController {
)
}
@httpGet('/:userUuid/settings', TYPES.RequiredCrossServiceTokenMiddleware)
@httpGet('/:userUuid/settings', TYPES.ApiGateway_RequiredCrossServiceTokenMiddleware)
async listSettings(request: Request, response: Response): Promise<void> {
await this.httpService.callAuthServer(
request,
@@ -126,7 +127,7 @@ export class UsersController extends BaseHttpController {
)
}
@httpPut('/:userUuid/settings', TYPES.RequiredCrossServiceTokenMiddleware)
@httpPut('/:userUuid/settings', TYPES.ApiGateway_RequiredCrossServiceTokenMiddleware)
async putSetting(request: Request, response: Response): Promise<void> {
await this.httpService.callAuthServer(
request,
@@ -140,7 +141,7 @@ export class UsersController extends BaseHttpController {
)
}
@httpGet('/:userUuid/settings/:settingName', TYPES.RequiredCrossServiceTokenMiddleware)
@httpGet('/:userUuid/settings/:settingName', TYPES.ApiGateway_RequiredCrossServiceTokenMiddleware)
async getSetting(request: Request, response: Response): Promise<void> {
await this.httpService.callAuthServer(
request,
@@ -154,7 +155,7 @@ export class UsersController extends BaseHttpController {
)
}
@httpDelete('/:userUuid/settings/:settingName', TYPES.RequiredCrossServiceTokenMiddleware)
@httpDelete('/:userUuid/settings/:settingName', TYPES.ApiGateway_RequiredCrossServiceTokenMiddleware)
async deleteSetting(request: Request, response: Response): Promise<void> {
await this.httpService.callAuthServer(
request,
@@ -169,7 +170,10 @@ export class UsersController extends BaseHttpController {
)
}
@httpGet('/:userUuid/subscription-settings/:subscriptionSettingName', TYPES.RequiredCrossServiceTokenMiddleware)
@httpGet(
'/:userUuid/subscription-settings/:subscriptionSettingName',
TYPES.ApiGateway_RequiredCrossServiceTokenMiddleware,
)
async getSubscriptionSetting(request: Request, response: Response): Promise<void> {
await this.httpService.callAuthServer(
request,
@@ -183,7 +187,7 @@ export class UsersController extends BaseHttpController {
)
}
@httpGet('/:userUuid/features', TYPES.RequiredCrossServiceTokenMiddleware)
@httpGet('/:userUuid/features', TYPES.ApiGateway_RequiredCrossServiceTokenMiddleware)
async getFeatures(request: Request, response: Response): Promise<void> {
await this.httpService.callAuthServer(
request,
@@ -196,7 +200,7 @@ export class UsersController extends BaseHttpController {
)
}
@httpGet('/:userUuid/subscription', TYPES.RequiredCrossServiceTokenMiddleware)
@httpGet('/:userUuid/subscription', TYPES.ApiGateway_RequiredCrossServiceTokenMiddleware)
async getSubscription(request: Request, response: Response): Promise<void> {
await this.httpService.callAuthServer(
request,
@@ -209,7 +213,7 @@ export class UsersController extends BaseHttpController {
)
}
@httpGet('/subscription', TYPES.SubscriptionTokenAuthMiddleware)
@httpGet('/subscription', TYPES.ApiGateway_SubscriptionTokenAuthMiddleware)
async getSubscriptionBySubscriptionToken(request: Request, response: Response): Promise<void> {
if (response.locals.tokenAuthenticationMethod === TokenAuthenticationMethod.OfflineSubscriptionToken) {
await this.httpService.callAuthServer(
@@ -232,12 +236,20 @@ export class UsersController extends BaseHttpController {
)
}
@httpDelete('/:userUuid', TYPES.RequiredCrossServiceTokenMiddleware)
@httpDelete('/:userUuid', TYPES.ApiGateway_RequiredCrossServiceTokenMiddleware)
async deleteUser(request: Request, response: Response): Promise<void> {
await this.httpService.callPaymentsServer(request, response, 'api/account', request.body)
if (!this.isConfiguredForHomeServer) {
await this.httpService.callPaymentsServer(request, response, 'api/account', request.body, true)
}
await this.httpService.callAuthServer(
request,
response,
this.endpointResolver.resolveEndpointOrMethodIdentifier('DELETE', 'users/:userUuid', request.params.userUuid),
)
}
@httpPost('/:userUuid/requests', TYPES.RequiredCrossServiceTokenMiddleware)
@httpPost('/:userUuid/requests', TYPES.ApiGateway_RequiredCrossServiceTokenMiddleware)
async submitRequest(request: Request, response: Response): Promise<void> {
await this.httpService.callAuthServer(
request,

View File

@@ -10,14 +10,14 @@ import { EndpointResolverInterface } from '../../Service/Resolver/EndpointResolv
@controller('/v1/sockets')
export class WebSocketsController extends BaseHttpController {
constructor(
@inject(TYPES.ServiceProxy) private httpService: ServiceProxyInterface,
@inject(TYPES.EndpointResolver) private endpointResolver: EndpointResolverInterface,
@inject(TYPES.Logger) private logger: Logger,
@inject(TYPES.ApiGateway_ServiceProxy) private httpService: ServiceProxyInterface,
@inject(TYPES.ApiGateway_EndpointResolver) private endpointResolver: EndpointResolverInterface,
@inject(TYPES.ApiGateway_Logger) private logger: Logger,
) {
super()
}
@httpPost('/tokens', TYPES.RequiredCrossServiceTokenMiddleware)
@httpPost('/tokens', TYPES.ApiGateway_RequiredCrossServiceTokenMiddleware)
async createWebSocketConnectionToken(request: Request, response: Response): Promise<void> {
await this.httpService.callWebSocketServer(
request,
@@ -27,7 +27,7 @@ export class WebSocketsController extends BaseHttpController {
)
}
@httpPost('/connections', TYPES.WebSocketAuthMiddleware)
@httpPost('/connections', TYPES.ApiGateway_WebSocketAuthMiddleware)
async createWebSocketConnection(request: Request, response: Response): Promise<void> {
if (!request.headers.connectionid) {
this.logger.error('Could not create a websocket connection. Missing connection id header.')

View File

@@ -9,8 +9,8 @@ import { EndpointResolverInterface } from '../../Service/Resolver/EndpointResolv
@controller('/v2')
export class ActionsControllerV2 extends BaseHttpController {
constructor(
@inject(TYPES.ServiceProxy) private serviceProxy: ServiceProxyInterface,
@inject(TYPES.EndpointResolver) private endpointResolver: EndpointResolverInterface,
@inject(TYPES.ApiGateway_ServiceProxy) private serviceProxy: ServiceProxyInterface,
@inject(TYPES.ApiGateway_EndpointResolver) private endpointResolver: EndpointResolverInterface,
) {
super()
}
@@ -25,7 +25,7 @@ export class ActionsControllerV2 extends BaseHttpController {
)
}
@httpPost('/login-params', TYPES.OptionalCrossServiceTokenMiddleware)
@httpPost('/login-params', TYPES.ApiGateway_OptionalCrossServiceTokenMiddleware)
async loginParams(request: Request, response: Response): Promise<void> {
await this.serviceProxy.callAuthServer(
request,

View File

@@ -6,7 +6,7 @@ import { ServiceProxyInterface } from '../../Service/Http/ServiceProxyInterface'
@controller('/v2')
export class PaymentsControllerV2 extends BaseHttpController {
constructor(@inject(TYPES.ServiceProxy) private httpService: ServiceProxyInterface) {
constructor(@inject(TYPES.ApiGateway_ServiceProxy) private httpService: ServiceProxyInterface) {
super()
}
@@ -15,22 +15,22 @@ export class PaymentsControllerV2 extends BaseHttpController {
await this.httpService.callPaymentsServer(request, response, 'api/subscriptions/features', request.body)
}
@httpGet('/subscriptions/tailored', TYPES.SubscriptionTokenAuthMiddleware)
@httpGet('/subscriptions/tailored', TYPES.ApiGateway_SubscriptionTokenAuthMiddleware)
async getTailoredSubscriptionsWithFeatures(request: Request, response: Response): Promise<void> {
await this.httpService.callPaymentsServer(request, response, 'api/subscriptions/features', request.body)
}
@httpGet('/subscriptions/deltas', TYPES.SubscriptionTokenAuthMiddleware)
@httpGet('/subscriptions/deltas', TYPES.ApiGateway_SubscriptionTokenAuthMiddleware)
async getSubscriptionDeltasForChangingPlan(request: Request, response: Response): Promise<void> {
await this.httpService.callPaymentsServer(request, response, 'api/subscriptions/deltas', request.body)
}
@httpPost('/subscriptions/deltas/apply', TYPES.SubscriptionTokenAuthMiddleware)
@httpPost('/subscriptions/deltas/apply', TYPES.ApiGateway_SubscriptionTokenAuthMiddleware)
async applySubscriptionDelta(request: Request, response: Response): Promise<void> {
await this.httpService.callPaymentsServer(request, response, 'api/subscriptions/deltas/apply', request.body)
}
@httpPost('/subscriptions/change-payment-method', TYPES.SubscriptionTokenAuthMiddleware)
@httpPost('/subscriptions/change-payment-method', TYPES.ApiGateway_SubscriptionTokenAuthMiddleware)
async changePaymentMethod(request: Request, response: Response): Promise<void> {
await this.httpService.callPaymentsServer(
request,
@@ -40,7 +40,7 @@ export class PaymentsControllerV2 extends BaseHttpController {
)
}
@httpGet('/subscriptions/:subscriptionId', TYPES.SubscriptionTokenAuthMiddleware)
@httpGet('/subscriptions/:subscriptionId', TYPES.ApiGateway_SubscriptionTokenAuthMiddleware)
async getSubscription(request: Request, response: Response): Promise<void> {
await this.httpService.callPaymentsServer(
request,
@@ -50,7 +50,7 @@ export class PaymentsControllerV2 extends BaseHttpController {
)
}
@httpDelete('/subscriptions/:subscriptionId', TYPES.SubscriptionTokenAuthMiddleware)
@httpDelete('/subscriptions/:subscriptionId', TYPES.ApiGateway_SubscriptionTokenAuthMiddleware)
async cancelSubscription(request: Request, response: Response): Promise<void> {
await this.httpService.callPaymentsServer(
request,
@@ -60,7 +60,7 @@ export class PaymentsControllerV2 extends BaseHttpController {
)
}
@httpPatch('/subscriptions/:subscriptionId', TYPES.SubscriptionTokenAuthMiddleware)
@httpPatch('/subscriptions/:subscriptionId', TYPES.ApiGateway_SubscriptionTokenAuthMiddleware)
async updateSubscription(request: Request, response: Response): Promise<void> {
await this.httpService.callPaymentsServer(
request,

View File

@@ -6,11 +6,11 @@ import { TYPES } from '../../Bootstrap/Types'
import { ServiceProxyInterface } from '../../Service/Http/ServiceProxyInterface'
import { EndpointResolverInterface } from '../../Service/Resolver/EndpointResolverInterface'
@controller('/v2/items/:itemUuid/revisions', TYPES.RequiredCrossServiceTokenMiddleware)
@controller('/v2/items/:itemUuid/revisions', TYPES.ApiGateway_RequiredCrossServiceTokenMiddleware)
export class RevisionsControllerV2 extends BaseHttpController {
constructor(
@inject(TYPES.ServiceProxy) private httpService: ServiceProxyInterface,
@inject(TYPES.EndpointResolver) private endpointResolver: EndpointResolverInterface,
@inject(TYPES.ApiGateway_ServiceProxy) private httpService: ServiceProxyInterface,
@inject(TYPES.ApiGateway_EndpointResolver) private endpointResolver: EndpointResolverInterface,
) {
super()
}

View File

@@ -9,7 +9,7 @@ export class RedisCrossServiceTokenCache implements CrossServiceTokenCacheInterf
private readonly PREFIX = 'cst'
private readonly USER_CST_PREFIX = 'user-cst'
constructor(@inject(TYPES.Redis) private redisClient: IORedis.Redis) {}
constructor(@inject(TYPES.ApiGateway_Redis) private redisClient: IORedis.Redis) {}
async set(dto: {
authorizationHeaderValue: string

View File

@@ -11,17 +11,17 @@ import { ServiceProxyInterface } from './ServiceProxyInterface'
@injectable()
export class HttpServiceProxy implements ServiceProxyInterface {
constructor(
@inject(TYPES.HTTPClient) private httpClient: AxiosInstance,
@inject(TYPES.AUTH_SERVER_URL) private authServerUrl: string,
@inject(TYPES.SYNCING_SERVER_JS_URL) private syncingServerJsUrl: string,
@inject(TYPES.PAYMENTS_SERVER_URL) private paymentsServerUrl: string,
@inject(TYPES.FILES_SERVER_URL) private filesServerUrl: string,
@inject(TYPES.WEB_SOCKET_SERVER_URL) private webSocketServerUrl: string,
@inject(TYPES.REVISIONS_SERVER_URL) private revisionsServerUrl: string,
@inject(TYPES.EMAIL_SERVER_URL) private emailServerUrl: string,
@inject(TYPES.HTTP_CALL_TIMEOUT) private httpCallTimeout: number,
@inject(TYPES.CrossServiceTokenCache) private crossServiceTokenCache: CrossServiceTokenCacheInterface,
@inject(TYPES.Logger) private logger: Logger,
@inject(TYPES.ApiGateway_HTTPClient) private httpClient: AxiosInstance,
@inject(TYPES.ApiGateway_AUTH_SERVER_URL) private authServerUrl: string,
@inject(TYPES.ApiGateway_SYNCING_SERVER_JS_URL) private syncingServerJsUrl: string,
@inject(TYPES.ApiGateway_PAYMENTS_SERVER_URL) private paymentsServerUrl: string,
@inject(TYPES.ApiGateway_FILES_SERVER_URL) private filesServerUrl: string,
@inject(TYPES.ApiGateway_WEB_SOCKET_SERVER_URL) private webSocketServerUrl: string,
@inject(TYPES.ApiGateway_REVISIONS_SERVER_URL) private revisionsServerUrl: string,
@inject(TYPES.ApiGateway_EMAIL_SERVER_URL) private emailServerUrl: string,
@inject(TYPES.ApiGateway_HTTP_CALL_TIMEOUT) private httpCallTimeout: number,
@inject(TYPES.ApiGateway_CrossServiceTokenCache) private crossServiceTokenCache: CrossServiceTokenCacheInterface,
@inject(TYPES.ApiGateway_Logger) private logger: Logger,
) {}
async validateSession(
@@ -130,19 +130,26 @@ export class HttpServiceProxy implements ServiceProxyInterface {
response: Response,
endpointOrMethodIdentifier: string,
payload?: Record<string, unknown> | string,
): Promise<void> {
returnRawResponse?: boolean,
): Promise<void | Response<unknown, Record<string, unknown>>> {
if (!this.paymentsServerUrl) {
this.logger.debug('Payments Server URL not defined. Skipped request to Payments API.')
return
}
await this.callServerWithLegacyFormat(
const rawResponse = await this.callServerWithLegacyFormat(
this.paymentsServerUrl,
request,
response,
endpointOrMethodIdentifier,
payload,
returnRawResponse,
)
if (returnRawResponse) {
return rawResponse
}
}
async callAuthServerWithLegacyFormat(
@@ -279,7 +286,8 @@ export class HttpServiceProxy implements ServiceProxyInterface {
response: Response,
endpointOrMethodIdentifier: string,
payload?: Record<string, unknown> | string,
): Promise<void> {
returnRawResponse?: boolean,
): Promise<void | Response<unknown, Record<string, unknown>>> {
const serviceResponse = await this.getServerResponse(
serverUrl,
request,
@@ -295,9 +303,21 @@ export class HttpServiceProxy implements ServiceProxyInterface {
this.applyResponseHeaders(serviceResponse, response)
if (serviceResponse.request._redirectable._redirectCount > 0) {
response.status(302).redirect(serviceResponse.request.res.responseUrl)
response.status(302)
if (returnRawResponse) {
return response
}
response.redirect(serviceResponse.request.res.responseUrl)
} else {
response.status(serviceResponse.status).send(serviceResponse.data)
response.status(serviceResponse.status)
if (returnRawResponse) {
return response
}
response.send(serviceResponse.data)
}
}

View File

@@ -42,7 +42,8 @@ export interface ServiceProxyInterface {
response: Response,
endpointOrMethodIdentifier: string,
payload?: Record<string, unknown> | string,
): Promise<void>
returnRawResponse?: boolean,
): Promise<void | Response<unknown, Record<string, unknown>>>
callWebSocketServer(
request: Request,
response: Response,

View File

@@ -43,6 +43,7 @@ export class EndpointResolver implements EndpointResolverInterface {
['[PATCH]:users/:userId', 'auth.users.update'],
['[PUT]:users/:userUuid/attributes/credentials', 'auth.users.updateCredentials'],
['[PUT]:auth/params', 'auth.users.getKeyParams'],
['[DELETE]:users/:userUuid', 'auth.users.delete'],
['[POST]:listed', 'auth.users.createListedAccount'],
['[POST]:auth', 'auth.users.register'],
['[GET]:users/:userUuid/settings', 'auth.users.getSettings'],
@@ -62,6 +63,32 @@ export class EndpointResolver implements EndpointResolverInterface {
['[GET]:items/:itemUuid/revisions', 'revisions.revisions.getRevisions'],
['[GET]:items/:itemUuid/revisions/:id', 'revisions.revisions.getRevision'],
['[DELETE]:items/:itemUuid/revisions/:id', 'revisions.revisions.deleteRevision'],
// Messages Controller
['[GET]:messages/', 'sync.messages.get-received'],
['[GET]:messages/outbound', 'sync.messages.get-sent'],
['[POST]:messages/', 'sync.messages.send'],
['[DELETE]:messages/inbound', 'sync.messages.delete-all'],
['[DELETE]:messages/:messageUuid', 'sync.messages.delete'],
// Shared Vaults Controller
['[GET]:shared-vaults/', 'sync.shared-vaults.get-vaults'],
['[POST]:shared-vaults/', 'sync.shared-vaults.create-vault'],
['[DELETE]:shared-vaults/:sharedVaultUuid', 'sync.shared-vaults.delete-vault'],
['[POST]:shared-vaults/:sharedVaultUuid/valet-tokens', 'sync.shared-vaults.create-file-valet-token'],
// Shared Vault Invites Controller
['[POST]:shared-vaults/:sharedVaultUuid/invites', 'sync.shared-vault-invites.create'],
['[PATCH]:shared-vaults/:sharedVaultUuid/invites/:inviteUuid', 'sync.shared-vault-invites.update'],
['[POST]:shared-vaults/:sharedVaultUuid/invites/:inviteUuid/accept', 'sync.shared-vault-invites.accept'],
['[POST]:shared-vaults/:sharedVaultUuid/invites/:inviteUuid/decline', 'sync.shared-vault-invites.decline'],
['[DELETE]:shared-vaults/invites/inbound', 'sync.shared-vault-invites.delete-inbound'],
['[DELETE]:shared-vaults/invites/outbound', 'sync.shared-vault-invites.delete-outbound'],
['[GET]:shared-vaults/invites/outbound', 'sync.shared-vault-invites.get-outbound'],
['[GET]:shared-vaults/invites', 'sync.shared-vault-invites.get-user-invites'],
['[GET]:shared-vaults/:sharedVaultUuid/invites', 'sync.shared-vault-invites.get-vault-invites'],
['[DELETE]:shared-vaults/:sharedVaultUuid/invites/:inviteUuid', 'sync.shared-vault-invites.delete-invite'],
['[DELETE]:shared-vaults/:sharedVaultUuid/invites', 'sync.shared-vault-invites.delete-all'],
// Shared Vault Users Controller
['[GET]:shared-vaults/:sharedVaultUuid/users', 'sync.shared-vault-users.get-users'],
['[DELETE]:shared-vaults/:sharedVaultUuid/users/:userUuid', 'sync.shared-vault-users.remove-user'],
])
resolveEndpointOrMethodIdentifier(method: string, endpoint: string, ...params: string[]): string {
@@ -75,7 +102,7 @@ export class EndpointResolver implements EndpointResolverInterface {
const identifier = this.endpointToIdentifierMap.get(`[${method}]:${endpoint}`)
if (!identifier) {
throw new Error(`Endpoint ${endpoint} not found`)
throw new Error(`Endpoint [${method}]:${endpoint} not found`)
}
return identifier

View File

@@ -3,6 +3,174 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
# [1.131.0](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.130.1...@standardnotes/auth-server@1.131.0) (2023-08-08)
### Features
* update storage quota used for user based on shared vault files ([#689](https://github.com/standardnotes/server/issues/689)) ([5311e74](https://github.com/standardnotes/server/commit/5311e7426617da6fc75593dd0fcbff589ca4fc22))
## [1.130.1](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.130.0...@standardnotes/auth-server@1.130.1) (2023-08-07)
### Bug Fixes
* **auth:** update user agent upon refreshing session token ([#685](https://github.com/standardnotes/server/issues/685)) ([bd5f492](https://github.com/standardnotes/server/commit/bd5f492a733f783c64fa4bc5840b4a9f5c913d3d))
# [1.130.0](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.129.0...@standardnotes/auth-server@1.130.0) (2023-08-07)
### Features
* **auth:** invalidate other sessions for user if the email or password are changed ([#684](https://github.com/standardnotes/server/issues/684)) ([f39d3ac](https://github.com/standardnotes/server/commit/f39d3aca5b7bb9e5f9c1c24cbe2359f30dea835c))
# [1.129.0](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.128.1...@standardnotes/auth-server@1.129.0) (2023-08-03)
### Features
* **auth:** add handling payments account deleted events STA-1769 ([#682](https://github.com/standardnotes/server/issues/682)) ([8e35dfa](https://github.com/standardnotes/server/commit/8e35dfa4b77256f4c0a3294b296a5526fd1020ad))
## [1.128.1](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.128.0...@standardnotes/auth-server@1.128.1) (2023-08-02)
**Note:** Version bump only for package @standardnotes/auth-server
# [1.128.0](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.127.2...@standardnotes/auth-server@1.128.0) (2023-08-02)
### Features
* enable Write Ahead Log mode for SQLite ([#681](https://github.com/standardnotes/server/issues/681)) ([8cd7a13](https://github.com/standardnotes/server/commit/8cd7a138ab56f6a2b0d6c06ef6041ab9b85ae540))
## [1.127.2](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.127.1...@standardnotes/auth-server@1.127.2) (2023-08-01)
### Bug Fixes
* controller naming ([#678](https://github.com/standardnotes/server/issues/678)) ([56f0aef](https://github.com/standardnotes/server/commit/56f0aef21d3fcec7ac7e968cb1c1b071becbbe26))
## [1.127.1](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.127.0...@standardnotes/auth-server@1.127.1) (2023-07-31)
### Bug Fixes
* **auth:** auth middleware on delete account ([318af57](https://github.com/standardnotes/server/commit/318af5757d6c42f580157647b22112a9936765e7))
# [1.127.0](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.126.5...@standardnotes/auth-server@1.127.0) (2023-07-31)
### Features
* refactor deleting account ([#676](https://github.com/standardnotes/server/issues/676)) ([0d5dcdd](https://github.com/standardnotes/server/commit/0d5dcdd8ec2336e41e7604c4157f79a89163ed29))
## [1.126.5](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.126.4...@standardnotes/auth-server@1.126.5) (2023-07-27)
**Note:** Version bump only for package @standardnotes/auth-server
## [1.126.4](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.126.3...@standardnotes/auth-server@1.126.4) (2023-07-26)
**Note:** Version bump only for package @standardnotes/auth-server
## [1.126.3](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.126.2...@standardnotes/auth-server@1.126.3) (2023-07-26)
**Note:** Version bump only for package @standardnotes/auth-server
## [1.126.2](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.126.1...@standardnotes/auth-server@1.126.2) (2023-07-21)
**Note:** Version bump only for package @standardnotes/auth-server
## [1.126.1](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.126.0...@standardnotes/auth-server@1.126.1) (2023-07-21)
**Note:** Version bump only for package @standardnotes/auth-server
# [1.126.0](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.125.1...@standardnotes/auth-server@1.126.0) (2023-07-20)
### Features
* **syncing-server:** add shared vaults, invites, messages and notifications to sync response ([#665](https://github.com/standardnotes/server/issues/665)) ([efa4d7f](https://github.com/standardnotes/server/commit/efa4d7fc6007ef668e3de3b04853ac11b2d13c30))
## [1.125.1](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.125.0...@standardnotes/auth-server@1.125.1) (2023-07-19)
**Note:** Version bump only for package @standardnotes/auth-server
# [1.125.0](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.124.2...@standardnotes/auth-server@1.125.0) (2023-07-17)
### Features
* **syncing-server:** refactor syncing to decouple getting and saving items ([#659](https://github.com/standardnotes/server/issues/659)) ([cb74b23](https://github.com/standardnotes/server/commit/cb74b23e45b207136e299ce8a3db2c04dc87e21e))
## [1.124.2](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.124.1...@standardnotes/auth-server@1.124.2) (2023-07-14)
### Bug Fixes
* **home-server:** allow custom atributtes for activating premium features ([f7190c0](https://github.com/standardnotes/server/commit/f7190c0c9c2d105f97d1cf980ce6a4f0dae34805))
## [1.124.1](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.124.0...@standardnotes/auth-server@1.124.1) (2023-07-13)
### Bug Fixes
* **files:** handling unlimited storage quota on home server ([9be3517](https://github.com/standardnotes/server/commit/9be3517093f8dd7bbdd7507c1e2ff059e6c9a889))
# [1.124.0](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.123.2...@standardnotes/auth-server@1.124.0) (2023-07-13)
### Features
* **auth:** add overriding subscription settings on home server ([#656](https://github.com/standardnotes/server/issues/656)) ([0b82794](https://github.com/standardnotes/server/commit/0b82794e9c7ed82cfc08a92eafc016fbde5c4fcc))
## [1.123.2](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.123.1...@standardnotes/auth-server@1.123.2) (2023-07-12)
**Note:** Version bump only for package @standardnotes/auth-server
## [1.123.1](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.123.0...@standardnotes/auth-server@1.123.1) (2023-07-12)
**Note:** Version bump only for package @standardnotes/auth-server
# [1.123.0](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.122.2...@standardnotes/auth-server@1.123.0) (2023-07-12)
### Features
* domain items ([#655](https://github.com/standardnotes/server/issues/655)) ([a0af8f0](https://github.com/standardnotes/server/commit/a0af8f00252e1219e58cb7e066c11a8e71692e9d))
## [1.122.2](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.122.1...@standardnotes/auth-server@1.122.2) (2023-07-07)
### Bug Fixes
* transfer notifications from auth to syncing-server. ([#648](https://github.com/standardnotes/server/issues/648)) ([c288e5d](https://github.com/standardnotes/server/commit/c288e5d8dc54778a96a9fc33e3c9cae00583fade))
## [1.122.1](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.122.0...@standardnotes/auth-server@1.122.1) (2023-07-06)
**Note:** Version bump only for package @standardnotes/auth-server
# [1.122.0](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.121.0...@standardnotes/auth-server@1.122.0) (2023-07-05)
### Features
* deleting shared vaults. ([#640](https://github.com/standardnotes/server/issues/640)) ([f3161c2](https://github.com/standardnotes/server/commit/f3161c271296159331639814b2dbb2e566cc54c9))
# [1.121.0](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.120.2...@standardnotes/auth-server@1.121.0) (2023-07-05)
### Features
* **auth:** add notifications model ([#638](https://github.com/standardnotes/server/issues/638)) ([fecfd54](https://github.com/standardnotes/server/commit/fecfd5472824b5adae708db95d351e4ad65ee87b))
## [1.120.2](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.120.1...@standardnotes/auth-server@1.120.2) (2023-06-30)
**Note:** Version bump only for package @standardnotes/auth-server
## [1.120.1](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.120.0...@standardnotes/auth-server@1.120.1) (2023-06-30)
**Note:** Version bump only for package @standardnotes/auth-server
# [1.120.0](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.119.6...@standardnotes/auth-server@1.120.0) (2023-06-30)
### Features
* shared vaults functionality in api-gateway,auth,files,common,security,domain-events. ([#629](https://github.com/standardnotes/server/issues/629)) ([fa7fbe2](https://github.com/standardnotes/server/commit/fa7fbe26e7b0707fc21d71e04af76870f5248baf))
## [1.119.6](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.119.5...@standardnotes/auth-server@1.119.6) (2023-06-28)
### Bug Fixes
* **auth:** add debug logs for authentication method resolver ([d220ec5](https://github.com/standardnotes/server/commit/d220ec5bf7509f9eb19dcda71c3667aaf388a35b))
## [1.119.5](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.119.4...@standardnotes/auth-server@1.119.5) (2023-06-28)
### Bug Fixes
* add debug logs for invalid-auth responses ([d5a8409](https://github.com/standardnotes/server/commit/d5a8409bb5d35b9caf410a36ea0d5cb747129e8d))
## [1.119.4](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.119.3...@standardnotes/auth-server@1.119.4) (2023-06-28)
**Note:** Version bump only for package @standardnotes/auth-server

View File

@@ -1,23 +1,23 @@
import 'reflect-metadata'
import '../src/Infra/InversifyExpressUtils/InversifyExpressAuthController'
import '../src/Infra/InversifyExpressUtils/InversifyExpressAuthenticatorsController'
import '../src/Infra/InversifyExpressUtils/InversifyExpressSessionsController'
import '../src/Infra/InversifyExpressUtils/InversifyExpressSubscriptionInvitesController'
import '../src/Infra/InversifyExpressUtils/InversifyExpressUserRequestsController'
import '../src/Infra/InversifyExpressUtils/InversifyExpressWebSocketsController'
import '../src/Infra/InversifyExpressUtils/InversifyExpressUsersController'
import '../src/Infra/InversifyExpressUtils/InversifyExpressValetTokenController'
import '../src/Infra/InversifyExpressUtils/InversifyExpressAdminController'
import '../src/Infra/InversifyExpressUtils/InversifyExpressSubscriptionTokensController'
import '../src/Infra/InversifyExpressUtils/InversifyExpressSubscriptionSettingsController'
import '../src/Infra/InversifyExpressUtils/InversifyExpressSettingsController'
import '../src/Infra/InversifyExpressUtils/InversifyExpressSessionController'
import '../src/Infra/InversifyExpressUtils/InversifyExpressOfflineController'
import '../src/Infra/InversifyExpressUtils/InversifyExpressListedController'
import '../src/Infra/InversifyExpressUtils/InversifyExpressInternalController'
import '../src/Infra/InversifyExpressUtils/InversifyExpressHealthCheckController'
import '../src/Infra/InversifyExpressUtils/InversifyExpressFeaturesController'
import '../src/Infra/InversifyExpressUtils/AnnotatedAuthController'
import '../src/Infra/InversifyExpressUtils/AnnotatedAuthenticatorsController'
import '../src/Infra/InversifyExpressUtils/AnnotatedSessionsController'
import '../src/Infra/InversifyExpressUtils/AnnotatedSubscriptionInvitesController'
import '../src/Infra/InversifyExpressUtils/AnnotatedUserRequestsController'
import '../src/Infra/InversifyExpressUtils/AnnotatedWebSocketsController'
import '../src/Infra/InversifyExpressUtils/AnnotatedUsersController'
import '../src/Infra/InversifyExpressUtils/AnnotatedValetTokenController'
import '../src/Infra/InversifyExpressUtils/AnnotatedAdminController'
import '../src/Infra/InversifyExpressUtils/AnnotatedSubscriptionTokensController'
import '../src/Infra/InversifyExpressUtils/AnnotatedSubscriptionSettingsController'
import '../src/Infra/InversifyExpressUtils/AnnotatedSettingsController'
import '../src/Infra/InversifyExpressUtils/AnnotatedSessionController'
import '../src/Infra/InversifyExpressUtils/AnnotatedOfflineController'
import '../src/Infra/InversifyExpressUtils/AnnotatedListedController'
import '../src/Infra/InversifyExpressUtils/AnnotatedInternalController'
import '../src/Infra/InversifyExpressUtils/AnnotatedHealthCheckController'
import '../src/Infra/InversifyExpressUtils/AnnotatedFeaturesController'
import * as cors from 'cors'
import { urlencoded, json, Request, Response, NextFunction } from 'express'

Binary file not shown.

View File

@@ -1,6 +1,6 @@
{
"name": "@standardnotes/auth-server",
"version": "1.119.4",
"version": "1.131.0",
"engines": {
"node": ">=18.0.0 <21.0.0"
},
@@ -32,7 +32,8 @@
"weekly-backup:email": "yarn node dist/bin/backup.js email weekly",
"content-recalculation": "yarn node dist/bin/content.js",
"typeorm": "typeorm-ts-node-commonjs",
"upgrade:snjs": "yarn ncu -u '@standardnotes/*'"
"upgrade:snjs": "yarn ncu -u '@standardnotes/*'",
"migrate": "yarn build && yarn typeorm migration:run -d dist/src/Bootstrap/DataSource.js"
},
"dependencies": {
"@aws-sdk/client-sns": "^3.332.0",
@@ -41,17 +42,17 @@
"@cbor-extract/cbor-extract-linux-x64": "^2.1.1",
"@simplewebauthn/server": "^7.2.0",
"@simplewebauthn/typescript-types": "^7.0.0",
"@standardnotes/api": "^1.25.3",
"@standardnotes/api": "^1.26.26",
"@standardnotes/common": "workspace:*",
"@standardnotes/domain-core": "workspace:^",
"@standardnotes/domain-events": "workspace:*",
"@standardnotes/domain-events-infra": "workspace:*",
"@standardnotes/features": "^1.58.12",
"@standardnotes/features": "^1.59.7",
"@standardnotes/predicates": "workspace:*",
"@standardnotes/responses": "^1.13.9",
"@standardnotes/responses": "^1.13.27",
"@standardnotes/security": "workspace:*",
"@standardnotes/settings": "workspace:*",
"@standardnotes/sncrypto-common": "^1.9.0",
"@standardnotes/sncrypto-common": "^1.13.4",
"@standardnotes/sncrypto-node": "workspace:*",
"@standardnotes/time": "workspace:*",
"axios": "^1.1.3",

View File

@@ -1,5 +1,9 @@
import { Result, ServiceInterface } from '@standardnotes/domain-core'
export interface AuthServiceInterface extends ServiceInterface {
activatePremiumFeatures(username: string): Promise<Result<string>>
activatePremiumFeatures(dto: {
username: string
subscriptionPlanName?: string
endsAt?: Date
}): Promise<Result<string>>
}

View File

@@ -38,7 +38,7 @@ import { GetUserKeyParams } from '../Domain/UseCase/GetUserKeyParams/GetUserKeyP
import { UpdateUser } from '../Domain/UseCase/UpdateUser'
import { RedisEphemeralSessionRepository } from '../Infra/Redis/RedisEphemeralSessionRepository'
import { GetActiveSessionsForUser } from '../Domain/UseCase/GetActiveSessionsForUser'
import { DeletePreviousSessionsForUser } from '../Domain/UseCase/DeletePreviousSessionsForUser'
import { DeleteOtherSessionsForUser } from '../Domain/UseCase/DeleteOtherSessionsForUser'
import { DeleteSessionForUser } from '../Domain/UseCase/DeleteSessionForUser'
import { Register } from '../Domain/UseCase/Register'
import { LockRepository } from '../Infra/Redis/LockRepository'
@@ -234,24 +234,28 @@ import { OfflineUserAuthMiddleware } from '../Infra/InversifyExpressUtils/Middle
import { LockMiddleware } from '../Infra/InversifyExpressUtils/Middleware/LockMiddleware'
import { RequiredCrossServiceTokenMiddleware } from '../Infra/InversifyExpressUtils/Middleware/RequiredCrossServiceTokenMiddleware'
import { OptionalCrossServiceTokenMiddleware } from '../Infra/InversifyExpressUtils/Middleware/OptionalCrossServiceTokenMiddleware'
import { HomeServerSettingsController } from '../Infra/InversifyExpressUtils/HomeServer/HomeServerSettingsController'
import { HomeServerAdminController } from '../Infra/InversifyExpressUtils/HomeServer/HomeServerAdminController'
import { HomeServerAuthController } from '../Infra/InversifyExpressUtils/HomeServer/HomeServerAuthController'
import { HomeServerAuthenticatorsController } from '../Infra/InversifyExpressUtils/HomeServer/HomeServerAuthenticatorsController'
import { HomeServerFeaturesController } from '../Infra/InversifyExpressUtils/HomeServer/HomeServerFeaturesController'
import { HomeServerListedController } from '../Infra/InversifyExpressUtils/HomeServer/HomeServerListedController'
import { HomeServerOfflineController } from '../Infra/InversifyExpressUtils/HomeServer/HomeServerOfflineController'
import { HomeServerSessionController } from '../Infra/InversifyExpressUtils/HomeServer/HomeServerSessionController'
import { HomeServerSubscriptionInvitesController } from '../Infra/InversifyExpressUtils/HomeServer/HomeServerSubscriptionInvitesController'
import { HomeServerSubscriptionSettingsController } from '../Infra/InversifyExpressUtils/HomeServer/HomeServerSubscriptionSettingsController'
import { HomeServerSubscriptionTokensController } from '../Infra/InversifyExpressUtils/HomeServer/HomeServerSubscriptionTokensController'
import { HomeServerUserRequestsController } from '../Infra/InversifyExpressUtils/HomeServer/HomeServerUserRequestsController'
import { HomeServerUsersController } from '../Infra/InversifyExpressUtils/HomeServer/HomeServerUsersController'
import { HomeServerValetTokenController } from '../Infra/InversifyExpressUtils/HomeServer/HomeServerValetTokenController'
import { HomeServerWebSocketsController } from '../Infra/InversifyExpressUtils/HomeServer/HomeServerWebSocketsController'
import { HomeServerSessionsController } from '../Infra/InversifyExpressUtils/HomeServer/HomeServerSessionsController'
import { BaseSettingsController } from '../Infra/InversifyExpressUtils/Base/BaseSettingsController'
import { BaseAdminController } from '../Infra/InversifyExpressUtils/Base/BaseAdminController'
import { BaseAuthController } from '../Infra/InversifyExpressUtils/Base/BaseAuthController'
import { BaseAuthenticatorsController } from '../Infra/InversifyExpressUtils/Base/BaseAuthenticatorsController'
import { BaseFeaturesController } from '../Infra/InversifyExpressUtils/Base/BaseFeaturesController'
import { BaseListedController } from '../Infra/InversifyExpressUtils/Base/BaseListedController'
import { BaseOfflineController } from '../Infra/InversifyExpressUtils/Base/BaseOfflineController'
import { BaseSessionController } from '../Infra/InversifyExpressUtils/Base/BaseSessionController'
import { BaseSubscriptionInvitesController } from '../Infra/InversifyExpressUtils/Base/BaseSubscriptionInvitesController'
import { BaseSubscriptionSettingsController } from '../Infra/InversifyExpressUtils/Base/BaseSubscriptionSettingsController'
import { BaseSubscriptionTokensController } from '../Infra/InversifyExpressUtils/Base/BaseSubscriptionTokensController'
import { BaseUserRequestsController } from '../Infra/InversifyExpressUtils/Base/BaseUserRequestsController'
import { BaseUsersController } from '../Infra/InversifyExpressUtils/Base/BaseUsersController'
import { BaseValetTokenController } from '../Infra/InversifyExpressUtils/Base/BaseValetTokenController'
import { BaseWebSocketsController } from '../Infra/InversifyExpressUtils/Base/BaseWebSocketsController'
import { BaseSessionsController } from '../Infra/InversifyExpressUtils/Base/BaseSessionsController'
import { Transform } from 'stream'
import { ActivatePremiumFeatures } from '../Domain/UseCase/ActivatePremiumFeatures/ActivatePremiumFeatures'
import { PaymentsAccountDeletedEventHandler } from '../Domain/Handler/PaymentsAccountDeletedEventHandler'
import { UpdateStorageQuotaUsedForUser } from '../Domain/UseCase/UpdateStorageQuotaUsedForUser/UpdateStorageQuotaUsedForUser'
import { SharedVaultFileUploadedEventHandler } from '../Domain/Handler/SharedVaultFileUploadedEventHandler'
import { SharedVaultFileRemovedEventHandler } from '../Domain/Handler/SharedVaultFileRemovedEventHandler'
export class ContainerConfigLoader {
async load(configuration?: {
@@ -793,6 +797,7 @@ export class ContainerConfigLoader {
new ActivatePremiumFeatures(
container.get(TYPES.Auth_UserRepository),
container.get(TYPES.Auth_UserSubscriptionRepository),
container.get(TYPES.Auth_SubscriptionSettingService),
container.get(TYPES.Auth_RoleService),
container.get(TYPES.Auth_Timer),
),
@@ -825,9 +830,7 @@ export class ContainerConfigLoader {
container.bind<UpdateUser>(TYPES.Auth_UpdateUser).to(UpdateUser)
container.bind<Register>(TYPES.Auth_Register).to(Register)
container.bind<GetActiveSessionsForUser>(TYPES.Auth_GetActiveSessionsForUser).to(GetActiveSessionsForUser)
container
.bind<DeletePreviousSessionsForUser>(TYPES.Auth_DeletePreviousSessionsForUser)
.to(DeletePreviousSessionsForUser)
container.bind<DeleteOtherSessionsForUser>(TYPES.Auth_DeleteOtherSessionsForUser).to(DeleteOtherSessionsForUser)
container.bind<DeleteSessionForUser>(TYPES.Auth_DeleteSessionForUser).to(DeleteSessionForUser)
container.bind<ChangeCredentials>(TYPES.Auth_ChangeCredentials).to(ChangeCredentials)
container.bind<GetSettings>(TYPES.Auth_GetSettings).to(GetSettings)
@@ -882,6 +885,15 @@ export class ContainerConfigLoader {
container.bind<VerifyPredicate>(TYPES.Auth_VerifyPredicate).to(VerifyPredicate)
container.bind<CreateCrossServiceToken>(TYPES.Auth_CreateCrossServiceToken).to(CreateCrossServiceToken)
container.bind<ProcessUserRequest>(TYPES.Auth_ProcessUserRequest).to(ProcessUserRequest)
container
.bind<UpdateStorageQuotaUsedForUser>(TYPES.Auth_UpdateStorageQuotaUsedForUser)
.toConstantValue(
new UpdateStorageQuotaUsedForUser(
container.get(TYPES.Auth_UserRepository),
container.get(TYPES.Auth_UserSubscriptionService),
container.get(TYPES.Auth_SubscriptionSettingService),
),
)
// Controller
container
@@ -951,8 +963,38 @@ export class ContainerConfigLoader {
container
.bind<UserEmailChangedEventHandler>(TYPES.Auth_UserEmailChangedEventHandler)
.to(UserEmailChangedEventHandler)
container.bind<FileUploadedEventHandler>(TYPES.Auth_FileUploadedEventHandler).to(FileUploadedEventHandler)
container.bind<FileRemovedEventHandler>(TYPES.Auth_FileRemovedEventHandler).to(FileRemovedEventHandler)
container
.bind<FileUploadedEventHandler>(TYPES.Auth_FileUploadedEventHandler)
.toConstantValue(
new FileUploadedEventHandler(
container.get(TYPES.Auth_UpdateStorageQuotaUsedForUser),
container.get(TYPES.Auth_Logger),
),
)
container
.bind<SharedVaultFileUploadedEventHandler>(TYPES.Auth_SharedVaultFileUploadedEventHandler)
.toConstantValue(
new SharedVaultFileUploadedEventHandler(
container.get(TYPES.Auth_UpdateStorageQuotaUsedForUser),
container.get(TYPES.Auth_Logger),
),
)
container
.bind<FileRemovedEventHandler>(TYPES.Auth_FileRemovedEventHandler)
.toConstantValue(
new FileRemovedEventHandler(
container.get(TYPES.Auth_UpdateStorageQuotaUsedForUser),
container.get(TYPES.Auth_Logger),
),
)
container
.bind<SharedVaultFileRemovedEventHandler>(TYPES.Auth_SharedVaultFileRemovedEventHandler)
.toConstantValue(
new SharedVaultFileRemovedEventHandler(
container.get(TYPES.Auth_UpdateStorageQuotaUsedForUser),
container.get(TYPES.Auth_Logger),
),
)
container
.bind<ListedAccountCreatedEventHandler>(TYPES.Auth_ListedAccountCreatedEventHandler)
.to(ListedAccountCreatedEventHandler)
@@ -977,6 +1019,14 @@ export class ContainerConfigLoader {
container.get(TYPES.Auth_SettingService),
),
)
container
.bind<PaymentsAccountDeletedEventHandler>(TYPES.Auth_PaymentsAccountDeletedEventHandler)
.toConstantValue(
new PaymentsAccountDeletedEventHandler(
container.get(TYPES.Auth_DeleteAccount),
container.get(TYPES.Auth_Logger),
),
)
const eventHandlers: Map<string, DomainEventHandlerInterface> = new Map([
['USER_REGISTERED', container.get(TYPES.Auth_UserRegisteredEventHandler)],
@@ -991,7 +1041,9 @@ export class ContainerConfigLoader {
['SUBSCRIPTION_REASSIGNED', container.get(TYPES.Auth_SubscriptionReassignedEventHandler)],
['USER_EMAIL_CHANGED', container.get(TYPES.Auth_UserEmailChangedEventHandler)],
['FILE_UPLOADED', container.get(TYPES.Auth_FileUploadedEventHandler)],
['SHARED_VAULT_FILE_UPLOADED', container.get(TYPES.Auth_SharedVaultFileUploadedEventHandler)],
['FILE_REMOVED', container.get(TYPES.Auth_FileRemovedEventHandler)],
['SHARED_VAULT_FILE_REMOVED', container.get(TYPES.Auth_SharedVaultFileRemovedEventHandler)],
['LISTED_ACCOUNT_CREATED', container.get(TYPES.Auth_ListedAccountCreatedEventHandler)],
['LISTED_ACCOUNT_DELETED', container.get(TYPES.Auth_ListedAccountDeletedEventHandler)],
[
@@ -1004,6 +1056,7 @@ export class ContainerConfigLoader {
],
['PREDICATE_VERIFICATION_REQUESTED', container.get(TYPES.Auth_PredicateVerificationRequestedEventHandler)],
['EMAIL_SUBSCRIPTION_UNSUBSCRIBED', container.get(TYPES.Auth_EmailSubscriptionUnsubscribedEventHandler)],
['PAYMENTS_ACCOUNT_DELETED', container.get(TYPES.Auth_PaymentsAccountDeletedEventHandler)],
])
if (isConfiguredForHomeServer) {
@@ -1036,9 +1089,9 @@ export class ContainerConfigLoader {
}
container
.bind<HomeServerAuthController>(TYPES.Auth_HomeServerAuthController)
.bind<BaseAuthController>(TYPES.Auth_BaseAuthController)
.toConstantValue(
new HomeServerAuthController(
new BaseAuthController(
container.get(TYPES.Auth_VerifyMFA),
container.get(TYPES.Auth_SignIn),
container.get(TYPES.Auth_GetUserKeyParams),
@@ -1053,42 +1106,42 @@ export class ContainerConfigLoader {
// Inversify Controllers
if (isConfiguredForHomeServer) {
container
.bind<HomeServerAuthenticatorsController>(TYPES.Auth_HomeServerAuthenticatorsController)
.bind<BaseAuthenticatorsController>(TYPES.Auth_BaseAuthenticatorsController)
.toConstantValue(
new HomeServerAuthenticatorsController(
new BaseAuthenticatorsController(
container.get(TYPES.Auth_AuthenticatorsController),
container.get(TYPES.Auth_ControllerContainer),
),
)
container
.bind<HomeServerSubscriptionInvitesController>(TYPES.Auth_HomeServerSubscriptionInvitesController)
.bind<BaseSubscriptionInvitesController>(TYPES.Auth_BaseSubscriptionInvitesController)
.toConstantValue(
new HomeServerSubscriptionInvitesController(
new BaseSubscriptionInvitesController(
container.get(TYPES.Auth_SubscriptionInvitesController),
container.get(TYPES.Auth_ControllerContainer),
),
)
container
.bind<HomeServerUserRequestsController>(TYPES.Auth_HomeServerUserRequestsController)
.bind<BaseUserRequestsController>(TYPES.Auth_BaseUserRequestsController)
.toConstantValue(
new HomeServerUserRequestsController(
new BaseUserRequestsController(
container.get(TYPES.Auth_UserRequestsController),
container.get(TYPES.Auth_ControllerContainer),
),
)
container
.bind<HomeServerWebSocketsController>(TYPES.Auth_HomeServerWebSocketsController)
.bind<BaseWebSocketsController>(TYPES.Auth_BaseWebSocketsController)
.toConstantValue(
new HomeServerWebSocketsController(
new BaseWebSocketsController(
container.get(TYPES.Auth_CreateCrossServiceToken),
container.get(TYPES.Auth_WebSocketConnectionTokenDecoder),
container.get(TYPES.Auth_ControllerContainer),
),
)
container
.bind<HomeServerSessionsController>(TYPES.Auth_HomeServerSessionsController)
.bind<BaseSessionsController>(TYPES.Auth_BaseSessionsController)
.toConstantValue(
new HomeServerSessionsController(
new BaseSessionsController(
container.get(TYPES.Auth_GetActiveSessionsForUser),
container.get(TYPES.Auth_AuthenticateRequest),
container.get(TYPES.Auth_SessionProjector),
@@ -1097,17 +1150,17 @@ export class ContainerConfigLoader {
),
)
container
.bind<HomeServerValetTokenController>(TYPES.Auth_HomeServerValetTokenController)
.bind<BaseValetTokenController>(TYPES.Auth_BaseValetTokenController)
.toConstantValue(
new HomeServerValetTokenController(
new BaseValetTokenController(
container.get(TYPES.Auth_CreateValetToken),
container.get(TYPES.Auth_ControllerContainer),
),
)
container
.bind<HomeServerUsersController>(TYPES.Auth_HomeServerUsersController)
.bind<BaseUsersController>(TYPES.Auth_BaseUsersController)
.toConstantValue(
new HomeServerUsersController(
new BaseUsersController(
container.get(TYPES.Auth_UpdateUser),
container.get(TYPES.Auth_GetUserKeyParams),
container.get(TYPES.Auth_DeleteAccount),
@@ -1119,9 +1172,9 @@ export class ContainerConfigLoader {
),
)
container
.bind<HomeServerAdminController>(TYPES.Auth_HomeServerAdminController)
.bind<BaseAdminController>(TYPES.Auth_BaseAdminController)
.toConstantValue(
new HomeServerAdminController(
new BaseAdminController(
container.get(TYPES.Auth_DeleteSetting),
container.get(TYPES.Auth_UserRepository),
container.get(TYPES.Auth_CreateSubscriptionToken),
@@ -1130,9 +1183,9 @@ export class ContainerConfigLoader {
),
)
container
.bind<HomeServerSubscriptionTokensController>(TYPES.Auth_HomeServerSubscriptionTokensController)
.bind<BaseSubscriptionTokensController>(TYPES.Auth_BaseSubscriptionTokensController)
.toConstantValue(
new HomeServerSubscriptionTokensController(
new BaseSubscriptionTokensController(
container.get(TYPES.Auth_CreateSubscriptionToken),
container.get(TYPES.Auth_AuthenticateSubscriptionToken),
container.get(TYPES.Auth_SettingService),
@@ -1144,17 +1197,17 @@ export class ContainerConfigLoader {
),
)
container
.bind<HomeServerSubscriptionSettingsController>(TYPES.Auth_HomeServerSubscriptionSettingsController)
.bind<BaseSubscriptionSettingsController>(TYPES.Auth_BaseSubscriptionSettingsController)
.toConstantValue(
new HomeServerSubscriptionSettingsController(
new BaseSubscriptionSettingsController(
container.get(TYPES.Auth_GetSetting),
container.get(TYPES.Auth_ControllerContainer),
),
)
container
.bind<HomeServerSettingsController>(TYPES.Auth_HomeServerSettingsController)
.bind<BaseSettingsController>(TYPES.Auth_BaseSettingsController)
.toConstantValue(
new HomeServerSettingsController(
new BaseSettingsController(
container.get(TYPES.Auth_GetSettings),
container.get(TYPES.Auth_GetSetting),
container.get(TYPES.Auth_UpdateSetting),
@@ -1163,19 +1216,19 @@ export class ContainerConfigLoader {
),
)
container
.bind<HomeServerSessionController>(TYPES.Auth_HomeServerSessionController)
.bind<BaseSessionController>(TYPES.Auth_BaseSessionController)
.toConstantValue(
new HomeServerSessionController(
new BaseSessionController(
container.get(TYPES.Auth_DeleteSessionForUser),
container.get(TYPES.Auth_DeletePreviousSessionsForUser),
container.get(TYPES.Auth_DeleteOtherSessionsForUser),
container.get(TYPES.Auth_RefreshSessionToken),
container.get(TYPES.Auth_ControllerContainer),
),
)
container
.bind<HomeServerOfflineController>(TYPES.Auth_HomeServerOfflineController)
.bind<BaseOfflineController>(TYPES.Auth_BaseOfflineController)
.toConstantValue(
new HomeServerOfflineController(
new BaseOfflineController(
container.get(TYPES.Auth_GetUserFeatures),
container.get(TYPES.Auth_GetUserOfflineSubscription),
container.get(TYPES.Auth_CreateOfflineSubscriptionToken),
@@ -1187,17 +1240,17 @@ export class ContainerConfigLoader {
),
)
container
.bind<HomeServerListedController>(TYPES.Auth_HomeServerListedController)
.bind<BaseListedController>(TYPES.Auth_BaseListedController)
.toConstantValue(
new HomeServerListedController(
new BaseListedController(
container.get(TYPES.Auth_CreateListedAccount),
container.get(TYPES.Auth_ControllerContainer),
),
)
container
.bind<HomeServerFeaturesController>(TYPES.Auth_HomeServerFeaturesController)
.bind<BaseFeaturesController>(TYPES.Auth_BaseFeaturesController)
.toConstantValue(
new HomeServerFeaturesController(
new BaseFeaturesController(
container.get(TYPES.Auth_GetUserFeatures),
container.get(TYPES.Auth_ControllerContainer),
),

View File

@@ -20,19 +20,23 @@ import { Env } from './Env'
import { SqliteConnectionOptions } from 'typeorm/driver/sqlite/SqliteConnectionOptions'
export class AppDataSource {
private dataSource: DataSource | undefined
private _dataSource: DataSource | undefined
constructor(private env: Env) {}
getRepository<Entity extends ObjectLiteral>(target: EntityTarget<Entity>): Repository<Entity> {
if (!this.dataSource) {
if (!this._dataSource) {
throw new Error('DataSource not initialized')
}
return this.dataSource.getRepository(target)
return this._dataSource.getRepository(target)
}
async initialize(): Promise<void> {
await this.dataSource.initialize()
}
get dataSource(): DataSource {
this.env.load()
const isConfiguredForMySQL = this.env.get('DB_TYPE') === 'mysql'
@@ -104,17 +108,19 @@ export class AppDataSource {
database: inReplicaMode ? undefined : this.env.get('DB_DATABASE'),
}
this.dataSource = new DataSource(mySQLDataSourceOptions)
this._dataSource = new DataSource(mySQLDataSourceOptions)
} else {
const sqliteDataSourceOptions: SqliteConnectionOptions = {
...commonDataSourceOptions,
type: 'sqlite',
database: this.env.get('DB_SQLITE_DATABASE_PATH'),
enableWAL: true,
busyErrorRetry: 2000,
}
this.dataSource = new DataSource(sqliteDataSourceOptions)
this._dataSource = new DataSource(sqliteDataSourceOptions)
}
await this.dataSource.initialize()
return this._dataSource
}
}

View File

@@ -0,0 +1,7 @@
import { AppDataSource } from './DataSource'
import { Env } from './Env'
const env: Env = new Env()
env.load()
export const MigrationsDataSource = new AppDataSource(env).dataSource

View File

@@ -24,14 +24,18 @@ export class Service implements AuthServiceInterface {
this.serviceContainer.register(this.getId(), this)
}
async activatePremiumFeatures(username: string): Promise<Result<string>> {
async activatePremiumFeatures(dto: {
username: string
subscriptionPlanName?: string
endsAt?: Date
}): Promise<Result<string>> {
if (!this.container) {
return Result.fail('Container not initialized')
}
const activatePremiumFeatures = this.container.get(TYPES.Auth_ActivatePremiumFeatures) as ActivatePremiumFeatures
return activatePremiumFeatures.execute({ username })
return activatePremiumFeatures.execute(dto)
}
async handleRequest(request: never, response: never, endpointOrMethodIdentifier: string): Promise<unknown> {

View File

@@ -113,7 +113,7 @@ const TYPES = {
Auth_UpdateUser: Symbol.for('Auth_UpdateUser'),
Auth_Register: Symbol.for('Auth_Register'),
Auth_GetActiveSessionsForUser: Symbol.for('Auth_GetActiveSessionsForUser'),
Auth_DeletePreviousSessionsForUser: Symbol.for('Auth_DeletePreviousSessionsForUser'),
Auth_DeleteOtherSessionsForUser: Symbol.for('Auth_DeleteOtherSessionsForUser'),
Auth_DeleteSessionForUser: Symbol.for('Auth_DeleteSessionForUser'),
Auth_ChangeCredentials: Symbol.for('Auth_ChangePassword'),
Auth_GetSettings: Symbol.for('Auth_GetSettings'),
@@ -152,6 +152,7 @@ const TYPES = {
Auth_ActivatePremiumFeatures: Symbol.for('Auth_ActivatePremiumFeatures'),
Auth_SignInWithRecoveryCodes: Symbol.for('Auth_SignInWithRecoveryCodes'),
Auth_GetUserKeyParamsRecovery: Symbol.for('Auth_GetUserKeyParamsRecovery'),
Auth_UpdateStorageQuotaUsedForUser: Symbol.for('Auth_UpdateStorageQuotaUsedForUser'),
// Handlers
Auth_UserRegisteredEventHandler: Symbol.for('Auth_UserRegisteredEventHandler'),
Auth_AccountDeletionRequestedEventHandler: Symbol.for('Auth_AccountDeletionRequestedEventHandler'),
@@ -165,7 +166,9 @@ const TYPES = {
Auth_ExtensionKeyGrantedEventHandler: Symbol.for('Auth_ExtensionKeyGrantedEventHandler'),
Auth_UserEmailChangedEventHandler: Symbol.for('Auth_UserEmailChangedEventHandler'),
Auth_FileUploadedEventHandler: Symbol.for('Auth_FileUploadedEventHandler'),
Auth_SharedVaultFileUploadedEventHandler: Symbol.for('Auth_SharedVaultFileUploadedEventHandler'),
Auth_FileRemovedEventHandler: Symbol.for('Auth_FileRemovedEventHandler'),
Auth_SharedVaultFileRemovedEventHandler: Symbol.for('Auth_SharedVaultFileRemovedEventHandler'),
Auth_ListedAccountCreatedEventHandler: Symbol.for('Auth_ListedAccountCreatedEventHandler'),
Auth_ListedAccountDeletedEventHandler: Symbol.for('Auth_ListedAccountDeletedEventHandler'),
Auth_UserDisabledSessionUserAgentLoggingEventHandler: Symbol.for(
@@ -176,6 +179,7 @@ const TYPES = {
),
Auth_PredicateVerificationRequestedEventHandler: Symbol.for('Auth_PredicateVerificationRequestedEventHandler'),
Auth_EmailSubscriptionUnsubscribedEventHandler: Symbol.for('Auth_EmailSubscriptionUnsubscribedEventHandler'),
Auth_PaymentsAccountDeletedEventHandler: Symbol.for('Auth_PaymentsAccountDeletedEventHandler'),
// Services
Auth_DeviceDetector: Symbol.for('Auth_DeviceDetector'),
Auth_SessionService: Symbol.for('Auth_SessionService'),
@@ -217,22 +221,22 @@ const TYPES = {
Auth_ProtocolVersionSelector: Symbol.for('Auth_ProtocolVersionSelector'),
Auth_BooleanSelector: Symbol.for('Auth_BooleanSelector'),
Auth_UserSubscriptionService: Symbol.for('Auth_UserSubscriptionService'),
Auth_HomeServerAuthController: Symbol.for('Auth_HomeServerAuthController'),
Auth_HomeServerAuthenticatorsController: Symbol.for('Auth_HomeServerAuthenticatorsController'),
Auth_HomeServerSubscriptionInvitesController: Symbol.for('Auth_HomeServerSubscriptionInvitesController'),
Auth_HomeServerUserRequestsController: Symbol.for('Auth_HomeServerUserRequestsController'),
Auth_HomeServerWebSocketsController: Symbol.for('Auth_HomeServerWebSocketsController'),
Auth_HomeServerSessionsController: Symbol.for('Auth_HomeServerSessionsController'),
Auth_HomeServerValetTokenController: Symbol.for('Auth_HomeServerValetTokenController'),
Auth_HomeServerUsersController: Symbol.for('Auth_HomeServerUsersController'),
Auth_HomeServerAdminController: Symbol.for('Auth_HomeServerAdminController'),
Auth_HomeServerSubscriptionTokensController: Symbol.for('Auth_HomeServerSubscriptionTokensController'),
Auth_HomeServerSubscriptionSettingsController: Symbol.for('Auth_HomeServerSubscriptionSettingsController'),
Auth_HomeServerSettingsController: Symbol.for('Auth_HomeServerSettingsController'),
Auth_HomeServerSessionController: Symbol.for('Auth_HomeServerSessionController'),
Auth_HomeServerOfflineController: Symbol.for('Auth_HomeServerOfflineController'),
Auth_HomeServerListedController: Symbol.for('Auth_HomeServerListedController'),
Auth_HomeServerFeaturesController: Symbol.for('Auth_HomeServerFeaturesController'),
Auth_BaseAuthController: Symbol.for('Auth_BaseAuthController'),
Auth_BaseAuthenticatorsController: Symbol.for('Auth_BaseAuthenticatorsController'),
Auth_BaseSubscriptionInvitesController: Symbol.for('Auth_BaseSubscriptionInvitesController'),
Auth_BaseUserRequestsController: Symbol.for('Auth_BaseUserRequestsController'),
Auth_BaseWebSocketsController: Symbol.for('Auth_BaseWebSocketsController'),
Auth_BaseSessionsController: Symbol.for('Auth_BaseSessionsController'),
Auth_BaseValetTokenController: Symbol.for('Auth_BaseValetTokenController'),
Auth_BaseUsersController: Symbol.for('Auth_BaseUsersController'),
Auth_BaseAdminController: Symbol.for('Auth_BaseAdminController'),
Auth_BaseSubscriptionTokensController: Symbol.for('Auth_BaseSubscriptionTokensController'),
Auth_BaseSubscriptionSettingsController: Symbol.for('Auth_BaseSubscriptionSettingsController'),
Auth_BaseSettingsController: Symbol.for('Auth_BaseSettingsController'),
Auth_BaseSessionController: Symbol.for('Auth_BaseSessionController'),
Auth_BaseOfflineController: Symbol.for('Auth_BaseOfflineController'),
Auth_BaseListedController: Symbol.for('Auth_BaseListedController'),
Auth_BaseFeaturesController: Symbol.for('Auth_BaseFeaturesController'),
}
export default TYPES

View File

@@ -8,12 +8,12 @@ import { User } from '../Domain/User/User'
import { Register } from '../Domain/UseCase/Register'
import { DomainEventFactoryInterface } from '../Domain/Event/DomainEventFactoryInterface'
import { KeyParamsOrigination, ProtocolVersion } from '@standardnotes/common'
import { ApiVersion } from '@standardnotes/api'
import { SignInWithRecoveryCodes } from '../Domain/UseCase/SignInWithRecoveryCodes/SignInWithRecoveryCodes'
import { GetUserKeyParamsRecovery } from '../Domain/UseCase/GetUserKeyParamsRecovery/GetUserKeyParamsRecovery'
import { GenerateRecoveryCodes } from '../Domain/UseCase/GenerateRecoveryCodes/GenerateRecoveryCodes'
import { Logger } from 'winston'
import { SessionServiceInterface } from '../Domain/Session/SessionServiceInterface'
import { ApiVersion } from '../Domain/Api/ApiVersion'
describe('AuthController', () => {
let clearLoginAttempts: ClearLoginAttempts
@@ -73,7 +73,7 @@ describe('AuthController', () => {
email: 'test@test.te',
password: 'asdzxc',
version: ProtocolVersion.V004,
api: ApiVersion.v0,
api: ApiVersion.v20200115,
origination: KeyParamsOrigination.Registration,
userAgent: 'Google Chrome',
identifier: 'test@test.te',
@@ -103,7 +103,7 @@ describe('AuthController', () => {
email: 'test@test.te',
password: '',
version: ProtocolVersion.V004,
api: ApiVersion.v0,
api: ApiVersion.v20200115,
origination: KeyParamsOrigination.Registration,
userAgent: 'Google Chrome',
identifier: 'test@test.te',
@@ -123,7 +123,7 @@ describe('AuthController', () => {
email: 'test@test.te',
password: 'test',
version: ProtocolVersion.V004,
api: ApiVersion.v0,
api: ApiVersion.v20200115,
origination: KeyParamsOrigination.Registration,
userAgent: 'Google Chrome',
identifier: 'test@test.te',

View File

@@ -1,10 +1,10 @@
import { DomainEventPublisherInterface } from '@standardnotes/domain-events'
import {
ApiVersion,
UserRegistrationRequestParams,
UserServerInterface,
UserDeletionResponseBody,
UserRegistrationResponseBody,
UserUpdateRequestParams,
} from '@standardnotes/api'
import { ErrorTag, HttpResponse, HttpStatusCode } from '@standardnotes/responses'
import { ProtocolVersion } from '@standardnotes/common'
@@ -23,6 +23,8 @@ import { GenerateRecoveryCodes } from '../Domain/UseCase/GenerateRecoveryCodes/G
import { GenerateRecoveryCodesRequestParams } from '../Infra/Http/Request/GenerateRecoveryCodesRequestParams'
import { Logger } from 'winston'
import { SessionServiceInterface } from '../Domain/Session/SessionServiceInterface'
import { ApiVersion } from '../Domain/Api/ApiVersion'
import { UserUpdateResponse } from '@standardnotes/api/dist/Domain/Response/User/UserUpdateResponse'
export class AuthController implements UserServerInterface {
constructor(
@@ -37,6 +39,10 @@ export class AuthController implements UserServerInterface {
private sessionService: SessionServiceInterface,
) {}
async update(_params: UserUpdateRequestParams): Promise<HttpResponse<UserUpdateResponse>> {
throw new Error('Method not implemented.')
}
async deleteAccount(_params: never): Promise<HttpResponse<UserDeletionResponseBody>> {
throw new Error('This method is implemented on the payments server.')
}
@@ -121,7 +127,7 @@ export class AuthController implements UserServerInterface {
async signInWithRecoveryCodes(
params: SignInWithRecoveryCodesRequestParams,
): Promise<HttpResponse<SignInWithRecoveryCodesResponseBody>> {
if (params.apiVersion !== ApiVersion.v0) {
if (params.apiVersion !== ApiVersion.v20200115) {
return {
status: HttpStatusCode.BadRequest,
data: {
@@ -162,7 +168,7 @@ export class AuthController implements UserServerInterface {
async recoveryKeyParams(
params: RecoveryKeyParamsRequestParams,
): Promise<HttpResponse<RecoveryKeyParamsResponseBody>> {
if (params.apiVersion !== ApiVersion.v0) {
if (params.apiVersion !== ApiVersion.v20200115) {
return {
status: HttpStatusCode.BadRequest,
data: {

View File

@@ -7,7 +7,7 @@ import { AcceptSharedSubscriptionInvitation } from '../Domain/UseCase/AcceptShar
import { DeclineSharedSubscriptionInvitation } from '../Domain/UseCase/DeclineSharedSubscriptionInvitation/DeclineSharedSubscriptionInvitation'
import { CancelSharedSubscriptionInvitation } from '../Domain/UseCase/CancelSharedSubscriptionInvitation/CancelSharedSubscriptionInvitation'
import { ListSharedSubscriptionInvitations } from '../Domain/UseCase/ListSharedSubscriptionInvitations/ListSharedSubscriptionInvitations'
import { ApiVersion } from '@standardnotes/api'
import { ApiVersion } from '../Domain/Api/ApiVersion'
describe('SubscriptionInvitesController', () => {
let inviteToSharedSubscription: InviteToSharedSubscription
@@ -53,7 +53,7 @@ describe('SubscriptionInvitesController', () => {
invitations: [],
})
const result = await createController().listInvites({ api: ApiVersion.v0, inviterEmail: 'test@test.te' })
const result = await createController().listInvites({ api: ApiVersion.v20200115, inviterEmail: 'test@test.te' })
expect(listSharedSubscriptionInvitations.execute).toHaveBeenCalledWith({
inviterEmail: 'test@test.te',
@@ -68,7 +68,7 @@ describe('SubscriptionInvitesController', () => {
})
const result = await createController().cancelInvite({
api: ApiVersion.v0,
api: ApiVersion.v20200115,
inviteUuid: '1-2-3',
inviterEmail: 'test@test.te',
})
@@ -87,7 +87,7 @@ describe('SubscriptionInvitesController', () => {
})
const result = await createController().cancelInvite({
api: ApiVersion.v0,
api: ApiVersion.v20200115,
inviteUuid: '1-2-3',
})
@@ -100,7 +100,7 @@ describe('SubscriptionInvitesController', () => {
})
const result = await createController().declineInvite({
api: ApiVersion.v0,
api: ApiVersion.v20200115,
inviteUuid: '1-2-3',
})
@@ -117,7 +117,7 @@ describe('SubscriptionInvitesController', () => {
})
const result = await createController().declineInvite({
api: ApiVersion.v0,
api: ApiVersion.v20200115,
inviteUuid: '1-2-3',
})
@@ -134,7 +134,7 @@ describe('SubscriptionInvitesController', () => {
})
const result = await createController().acceptInvite({
api: ApiVersion.v0,
api: ApiVersion.v20200115,
inviteUuid: '1-2-3',
})
@@ -151,7 +151,7 @@ describe('SubscriptionInvitesController', () => {
})
const result = await createController().acceptInvite({
api: ApiVersion.v0,
api: ApiVersion.v20200115,
inviteUuid: '1-2-3',
})
@@ -168,7 +168,7 @@ describe('SubscriptionInvitesController', () => {
})
const result = await createController().invite({
api: ApiVersion.v0,
api: ApiVersion.v20200115,
identifier: 'invitee@test.te',
inviterUuid: '1-2-3',
inviterEmail: 'test@test.te',
@@ -187,7 +187,7 @@ describe('SubscriptionInvitesController', () => {
it('should not invite to user subscription if the identifier is missing in request', async () => {
const result = await createController().invite({
api: ApiVersion.v0,
api: ApiVersion.v20200115,
identifier: '',
inviterUuid: '1-2-3',
inviterEmail: 'test@test.te',
@@ -205,7 +205,7 @@ describe('SubscriptionInvitesController', () => {
})
const result = await createController().invite({
api: ApiVersion.v0,
api: ApiVersion.v20200115,
identifier: 'invitee@test.te',
inviterUuid: '1-2-3',
inviterEmail: 'test@test.te',

View File

@@ -1,9 +1,5 @@
import { ProtocolVersion } from '@standardnotes/common'
import { SimpleUserProjection } from '../../Projection/SimpleUserProjection'
export interface AuthResponse {
user: {
uuid: string
email: string
protocolVersion: ProtocolVersion
}
user: SimpleUserProjection
}

View File

@@ -30,7 +30,7 @@ describe('AuthResponseFactory20161215', () => {
})
it('should create a 20161215 auth response', async () => {
const response = await createFactory().createResponse({
const result = await createFactory().createResponse({
user,
apiVersion: '20161215',
userAgent: 'Google Chrome',
@@ -38,7 +38,7 @@ describe('AuthResponseFactory20161215', () => {
readonlyAccess: false,
})
expect(response).toEqual({
expect(result.response).toEqual({
user: { foo: 'bar' },
token: 'foobar',
})

View File

@@ -11,6 +11,7 @@ import { User } from '../User/User'
import { AuthResponse20161215 } from './AuthResponse20161215'
import { AuthResponse20200115 } from './AuthResponse20200115'
import { AuthResponseFactoryInterface } from './AuthResponseFactoryInterface'
import { Session } from '../Session/Session'
@injectable()
export class AuthResponseFactory20161215 implements AuthResponseFactoryInterface {
@@ -26,7 +27,7 @@ export class AuthResponseFactory20161215 implements AuthResponseFactoryInterface
userAgent: string
ephemeralSession: boolean
readonlyAccess: boolean
}): Promise<AuthResponse20161215 | AuthResponse20200115> {
}): Promise<{ response: AuthResponse20161215 | AuthResponse20200115; session?: Session }> {
this.logger.debug(`Creating JWT auth response for user ${dto.user.uuid}`)
const data: SessionTokenData = {
@@ -39,12 +40,14 @@ export class AuthResponseFactory20161215 implements AuthResponseFactoryInterface
this.logger.debug(`Created JWT token for user ${dto.user.uuid}: ${token}`)
return {
user: this.userProjector.projectSimple(dto.user) as {
uuid: string
email: string
protocolVersion: ProtocolVersion
response: {
user: this.userProjector.projectSimple(dto.user) as {
uuid: string
email: string
protocolVersion: ProtocolVersion
},
token,
},
token,
}
}
}

View File

@@ -29,7 +29,7 @@ describe('AuthResponseFactory20190520', () => {
})
it('should create a 20161215 auth response', async () => {
const response = await createFactory().createResponse({
const result = await createFactory().createResponse({
user,
apiVersion: '20161215',
userAgent: 'Google Chrome',
@@ -37,7 +37,7 @@ describe('AuthResponseFactory20190520', () => {
readonlyAccess: false,
})
expect(response).toEqual({
expect(result.response).toEqual({
user: { foo: 'bar' },
token: 'foobar',
})

View File

@@ -11,6 +11,7 @@ import { User } from '../User/User'
import { AuthResponseFactory20200115 } from './AuthResponseFactory20200115'
import { DomainEventPublisherInterface } from '@standardnotes/domain-events'
import { DomainEventFactoryInterface } from '../Event/DomainEventFactoryInterface'
import { Session } from '../Session/Session'
describe('AuthResponseFactory20200115', () => {
let sessionService: SessionServiceInterface
@@ -48,8 +49,12 @@ describe('AuthResponseFactory20200115', () => {
}
sessionService = {} as jest.Mocked<SessionServiceInterface>
sessionService.createNewSessionForUser = jest.fn().mockReturnValue(sessionPayload)
sessionService.createNewEphemeralSessionForUser = jest.fn().mockReturnValue(sessionPayload)
sessionService.createNewSessionForUser = jest
.fn()
.mockReturnValue({ sessionHttpRepresentation: sessionPayload, session: {} as jest.Mocked<Session> })
sessionService.createNewEphemeralSessionForUser = jest
.fn()
.mockReturnValue({ sessionHttpRepresentation: sessionPayload, session: {} as jest.Mocked<Session> })
keyParamsFactory = {} as jest.Mocked<KeyParamsFactoryInterface>
keyParamsFactory.create = jest.fn().mockReturnValue({
@@ -76,7 +81,7 @@ describe('AuthResponseFactory20200115', () => {
it('should create a 20161215 auth response if user does not support sessions', async () => {
user.supportsSessions = jest.fn().mockReturnValue(false)
const response = await createFactory().createResponse({
const result = await createFactory().createResponse({
user,
apiVersion: '20161215',
userAgent: 'Google Chrome',
@@ -84,7 +89,7 @@ describe('AuthResponseFactory20200115', () => {
readonlyAccess: false,
})
expect(response).toEqual({
expect(result.response).toEqual({
user: { foo: 'bar' },
token: expect.any(String),
})
@@ -93,7 +98,7 @@ describe('AuthResponseFactory20200115', () => {
it('should create a 20200115 auth response', async () => {
user.supportsSessions = jest.fn().mockReturnValue(true)
const response = await createFactory().createResponse({
const result = await createFactory().createResponse({
user,
apiVersion: '20200115',
userAgent: 'Google Chrome',
@@ -101,7 +106,7 @@ describe('AuthResponseFactory20200115', () => {
readonlyAccess: false,
})
expect(response).toEqual({
expect(result.response).toEqual({
key_params: {
key1: 'value1',
key2: 'value2',
@@ -124,7 +129,7 @@ describe('AuthResponseFactory20200115', () => {
domainEventPublisher.publish = jest.fn().mockRejectedValue(new Error('test'))
user.supportsSessions = jest.fn().mockReturnValue(true)
const response = await createFactory().createResponse({
const result = await createFactory().createResponse({
user,
apiVersion: '20200115',
userAgent: 'Google Chrome',
@@ -132,7 +137,7 @@ describe('AuthResponseFactory20200115', () => {
readonlyAccess: false,
})
expect(response).toEqual({
expect(result.response).toEqual({
key_params: {
key1: 'value1',
key2: 'value2',
@@ -153,7 +158,7 @@ describe('AuthResponseFactory20200115', () => {
it('should create a 20200115 auth response with an ephemeral session', async () => {
user.supportsSessions = jest.fn().mockReturnValue(true)
const response = await createFactory().createResponse({
const result = await createFactory().createResponse({
user,
apiVersion: '20200115',
userAgent: 'Google Chrome',
@@ -161,7 +166,7 @@ describe('AuthResponseFactory20200115', () => {
readonlyAccess: false,
})
expect(response).toEqual({
expect(result.response).toEqual({
key_params: {
key1: 'value1',
key2: 'value2',
@@ -183,11 +188,14 @@ describe('AuthResponseFactory20200115', () => {
user.supportsSessions = jest.fn().mockReturnValue(true)
sessionService.createNewSessionForUser = jest.fn().mockReturnValue({
...sessionPayload,
readonly_access: true,
sessionHttpRepresentation: {
...sessionPayload,
readonly_access: true,
},
session: {} as jest.Mocked<Session>,
})
const response = await createFactory().createResponse({
const result = await createFactory().createResponse({
user,
apiVersion: '20200115',
userAgent: 'Google Chrome',
@@ -195,7 +203,7 @@ describe('AuthResponseFactory20200115', () => {
readonlyAccess: true,
})
expect(response).toEqual({
expect(result.response).toEqual({
key_params: {
key1: 'value1',
key2: 'value2',

View File

@@ -4,13 +4,13 @@ import {
TokenEncoderInterface,
} from '@standardnotes/security'
import { DomainEventPublisherInterface } from '@standardnotes/domain-events'
import { ProtocolVersion } from '@standardnotes/common'
import { SessionBody } from '@standardnotes/responses'
import { inject, injectable } from 'inversify'
import { Logger } from 'winston'
import TYPES from '../../Bootstrap/Types'
import { ProjectorInterface } from '../../Projection/ProjectorInterface'
import { SimpleUserProjection } from '../../Projection/SimpleUserProjection'
import { SessionServiceInterface } from '../Session/SessionServiceInterface'
import { KeyParamsFactoryInterface } from '../User/KeyParamsFactoryInterface'
import { User } from '../User/User'
@@ -19,6 +19,7 @@ import { DomainEventFactoryInterface } from '../Event/DomainEventFactoryInterfac
import { AuthResponse20161215 } from './AuthResponse20161215'
import { AuthResponse20200115 } from './AuthResponse20200115'
import { Session } from '../Session/Session'
@injectable()
export class AuthResponseFactory20200115 extends AuthResponseFactory20190520 {
@@ -40,25 +41,28 @@ export class AuthResponseFactory20200115 extends AuthResponseFactory20190520 {
userAgent: string
ephemeralSession: boolean
readonlyAccess: boolean
}): Promise<AuthResponse20161215 | AuthResponse20200115> {
}): Promise<{ response: AuthResponse20161215 | AuthResponse20200115; session?: Session }> {
if (!dto.user.supportsSessions()) {
this.logger.debug(`User ${dto.user.uuid} does not support sessions. Falling back to JWT auth response`)
return super.createResponse(dto)
}
const sessionPayload = await this.createSession(dto)
const sessionCreationResult = await this.createSession(dto)
this.logger.debug('Created session payload for user %s: %O', dto.user.uuid, sessionPayload)
this.logger.debug(
'Created session payload for user %s: %O',
dto.user.uuid,
sessionCreationResult.sessionHttpRepresentation,
)
return {
session: sessionPayload,
key_params: this.keyParamsFactory.create(dto.user, true),
user: this.userProjector.projectSimple(dto.user) as {
uuid: string
email: string
protocolVersion: ProtocolVersion
response: {
session: sessionCreationResult.sessionHttpRepresentation,
key_params: this.keyParamsFactory.create(dto.user, true),
user: this.userProjector.projectSimple(dto.user) as SimpleUserProjection,
},
session: sessionCreationResult.session,
}
}
@@ -68,12 +72,12 @@ export class AuthResponseFactory20200115 extends AuthResponseFactory20190520 {
userAgent: string
ephemeralSession: boolean
readonlyAccess: boolean
}): Promise<SessionBody> {
}): Promise<{ sessionHttpRepresentation: SessionBody; session: Session }> {
if (dto.ephemeralSession) {
return this.sessionService.createNewEphemeralSessionForUser(dto)
}
const session = this.sessionService.createNewSessionForUser(dto)
const sessionCreationResult = await this.sessionService.createNewSessionForUser(dto)
try {
await this.domainEventPublisher.publish(
@@ -83,6 +87,6 @@ export class AuthResponseFactory20200115 extends AuthResponseFactory20190520 {
this.logger.error(`Failed to publish session created event: ${(error as Error).message}`)
}
return session
return sessionCreationResult
}
}

View File

@@ -1,3 +1,4 @@
import { Session } from '../Session/Session'
import { User } from '../User/User'
import { AuthResponse20161215 } from './AuthResponse20161215'
import { AuthResponse20200115 } from './AuthResponse20200115'
@@ -9,5 +10,5 @@ export interface AuthResponseFactoryInterface {
userAgent: string
ephemeralSession: boolean
readonlyAccess: boolean
}): Promise<AuthResponse20161215 | AuthResponse20200115>
}): Promise<{ response: AuthResponse20161215 | AuthResponse20200115; session?: Session }>
}

View File

@@ -9,6 +9,7 @@ import { User } from '../User/User'
import { UserRepositoryInterface } from '../User/UserRepositoryInterface'
import { AuthenticationMethodResolver } from './AuthenticationMethodResolver'
import { Logger } from 'winston'
describe('AuthenticationMethodResolver', () => {
let userRepository: UserRepositoryInterface
@@ -18,14 +19,20 @@ describe('AuthenticationMethodResolver', () => {
let user: User
let session: Session
let revokedSession: RevokedSession
let logger: Logger
const createResolver = () =>
new AuthenticationMethodResolver(userRepository, sessionService, sessionTokenDecoder, fallbackTokenDecoder)
new AuthenticationMethodResolver(userRepository, sessionService, sessionTokenDecoder, fallbackTokenDecoder, logger)
beforeEach(() => {
logger = {} as jest.Mocked<Logger>
logger.debug = jest.fn()
user = {} as jest.Mocked<User>
session = {} as jest.Mocked<Session>
session = {
userUuid: '00000000-0000-0000-0000-000000000000',
} as jest.Mocked<Session>
revokedSession = {} as jest.Mocked<RevokedSession>
@@ -33,7 +40,7 @@ describe('AuthenticationMethodResolver', () => {
userRepository.findOneByUuid = jest.fn().mockReturnValue(user)
sessionService = {} as jest.Mocked<SessionServiceInterface>
sessionService.getSessionFromToken = jest.fn()
sessionService.getSessionFromToken = jest.fn().mockReturnValue({ session: undefined, isEphemeral: false })
sessionService.getRevokedSessionFromToken = jest.fn()
sessionService.markRevokedSessionAsReceived = jest.fn().mockReturnValue(revokedSession)
@@ -45,19 +52,25 @@ describe('AuthenticationMethodResolver', () => {
})
it('should resolve jwt authentication method', async () => {
sessionTokenDecoder.decodeToken = jest.fn().mockReturnValue({ user_uuid: '123' })
sessionTokenDecoder.decodeToken = jest.fn().mockReturnValue({ user_uuid: '00000000-0000-0000-0000-000000000000' })
expect(await createResolver().resolve('test')).toEqual({
claims: {
user_uuid: '123',
user_uuid: '00000000-0000-0000-0000-000000000000',
},
type: 'jwt',
user,
})
})
it('should not resolve jwt authentication method with invalid user uuid', async () => {
sessionTokenDecoder.decodeToken = jest.fn().mockReturnValue({ user_uuid: 'invalid' })
expect(await createResolver().resolve('test')).toBeUndefined
})
it('should resolve session authentication method', async () => {
sessionService.getSessionFromToken = jest.fn().mockReturnValue(session)
sessionService.getSessionFromToken = jest.fn().mockReturnValue({ session, isEphemeral: false })
expect(await createResolver().resolve('test')).toEqual({
session,
@@ -66,6 +79,14 @@ describe('AuthenticationMethodResolver', () => {
})
})
it('should not resolve session authentication method with invalid user uuid on session', async () => {
sessionService.getSessionFromToken = jest
.fn()
.mockReturnValue({ session: { userUuid: 'invalid' }, isEphemeral: false })
expect(await createResolver().resolve('test')).toBeUndefined
})
it('should resolve archvied session authentication method', async () => {
sessionService.getRevokedSessionFromToken = jest.fn().mockReturnValue(revokedSession)

View File

@@ -5,6 +5,8 @@ import { SessionServiceInterface } from '../Session/SessionServiceInterface'
import { UserRepositoryInterface } from '../User/UserRepositoryInterface'
import { AuthenticationMethod } from './AuthenticationMethod'
import { AuthenticationMethodResolverInterface } from './AuthenticationMethodResolverInterface'
import { Logger } from 'winston'
import { Uuid } from '@standardnotes/domain-core'
@injectable()
export class AuthenticationMethodResolver implements AuthenticationMethodResolverInterface {
@@ -14,33 +16,54 @@ export class AuthenticationMethodResolver implements AuthenticationMethodResolve
@inject(TYPES.Auth_SessionTokenDecoder) private sessionTokenDecoder: TokenDecoderInterface<SessionTokenData>,
@inject(TYPES.Auth_FallbackSessionTokenDecoder)
private fallbackSessionTokenDecoder: TokenDecoderInterface<SessionTokenData>,
@inject(TYPES.Auth_Logger) private logger: Logger,
) {}
async resolve(token: string): Promise<AuthenticationMethod | undefined> {
let decodedToken: SessionTokenData | undefined = this.sessionTokenDecoder.decodeToken(token)
if (decodedToken === undefined) {
this.logger.debug('Could not decode token with primary decoder, trying fallback decoder.')
decodedToken = this.fallbackSessionTokenDecoder.decodeToken(token)
}
if (decodedToken) {
this.logger.debug('Token decoded successfully. User found.')
const userUuidOrError = Uuid.create(decodedToken.user_uuid as string)
if (userUuidOrError.isFailed()) {
return undefined
}
const userUuid = userUuidOrError.getValue()
return {
type: 'jwt',
user: await this.userRepository.findOneByUuid(<string>decodedToken.user_uuid),
user: await this.userRepository.findOneByUuid(userUuid),
claims: decodedToken,
}
}
const session = await this.sessionService.getSessionFromToken(token)
const { session } = await this.sessionService.getSessionFromToken(token)
if (session) {
this.logger.debug('Token decoded successfully. Session found.')
const userUuidOrError = Uuid.create(session.userUuid)
if (userUuidOrError.isFailed()) {
return undefined
}
const userUuid = userUuidOrError.getValue()
return {
type: 'session_token',
user: await this.userRepository.findOneByUuid(session.userUuid),
user: await this.userRepository.findOneByUuid(userUuid),
session: session,
}
}
const revokedSession = await this.sessionService.getRevokedSessionFromToken(token)
if (revokedSession) {
this.logger.debug('Token decoded successfully. Revoked session found.')
return {
type: 'revoked',
revokedSession: await this.sessionService.markRevokedSessionAsReceived(revokedSession),
@@ -48,6 +71,8 @@ export class AuthenticationMethodResolver implements AuthenticationMethodResolve
}
}
this.logger.debug('Could not decode token.')
return undefined
}
}

View File

@@ -3,10 +3,6 @@ import { Entity, Result, UniqueEntityId } from '@standardnotes/domain-core'
import { AuthenticatorProps } from './AuthenticatorProps'
export class Authenticator extends Entity<AuthenticatorProps> {
get id(): UniqueEntityId {
return this._id
}
private constructor(props: AuthenticatorProps, id?: UniqueEntityId) {
super(props, id)
}

View File

@@ -3,10 +3,6 @@ import { Entity, Result, UniqueEntityId } from '@standardnotes/domain-core'
import { AuthenticatorChallengeProps } from './AuthenticatorChallengeProps'
export class AuthenticatorChallenge extends Entity<AuthenticatorChallengeProps> {
get id(): UniqueEntityId {
return this._id
}
private constructor(props: AuthenticatorChallengeProps, id?: UniqueEntityId) {
super(props, id)
}

View File

@@ -3,10 +3,6 @@ import { Entity, Result, UniqueEntityId } from '@standardnotes/domain-core'
import { EmergencyAccessInvitationProps } from './EmergencyAccessInvitationProps'
export class EmergencyAccessInvitation extends Entity<EmergencyAccessInvitationProps> {
get id(): UniqueEntityId {
return this._id
}
private constructor(props: EmergencyAccessInvitationProps, id?: UniqueEntityId) {
super(props, id)
}

View File

@@ -50,7 +50,7 @@ describe('AccountDeletionRequestedEventHandler', () => {
ephemeralSession = {
uuid: '2-3-4',
userUuid: '1-2-3',
userUuid: '00000000-0000-0000-0000-000000000000',
} as jest.Mocked<EphemeralSession>
ephemeralSessionRepository = {} as jest.Mocked<EphemeralSessionRepositoryInterface>
@@ -68,7 +68,7 @@ describe('AccountDeletionRequestedEventHandler', () => {
event = {} as jest.Mocked<AccountDeletionRequestedEvent>
event.createdAt = new Date(1)
event.payload = {
userUuid: '1-2-3',
userUuid: '00000000-0000-0000-0000-000000000000',
userCreatedAtTimestamp: 1,
regularSubscriptionUuid: '2-3-4',
}
@@ -84,6 +84,14 @@ describe('AccountDeletionRequestedEventHandler', () => {
expect(userRepository.remove).toHaveBeenCalledWith(user)
})
it('should not remove a user with invalid uuid', async () => {
event.payload.userUuid = 'invalid'
await createHandler().handle(event)
expect(userRepository.remove).not.toHaveBeenCalled()
})
it('should not remove a user if one does not exist', async () => {
userRepository.findOneByUuid = jest.fn().mockReturnValue(null)
@@ -100,6 +108,6 @@ describe('AccountDeletionRequestedEventHandler', () => {
expect(sessionRepository.remove).toHaveBeenCalledWith(session)
expect(revokedSessionRepository.remove).toHaveBeenCalledWith(revokedSession)
expect(ephemeralSessionRepository.deleteOne).toHaveBeenCalledWith('2-3-4', '1-2-3')
expect(ephemeralSessionRepository.deleteOne).toHaveBeenCalledWith('2-3-4', '00000000-0000-0000-0000-000000000000')
})
})

View File

@@ -6,6 +6,7 @@ import { EphemeralSessionRepositoryInterface } from '../Session/EphemeralSession
import { RevokedSessionRepositoryInterface } from '../Session/RevokedSessionRepositoryInterface'
import { SessionRepositoryInterface } from '../Session/SessionRepositoryInterface'
import { UserRepositoryInterface } from '../User/UserRepositoryInterface'
import { Uuid } from '@standardnotes/domain-core'
@injectable()
export class AccountDeletionRequestedEventHandler implements DomainEventHandlerInterface {
@@ -19,19 +20,27 @@ export class AccountDeletionRequestedEventHandler implements DomainEventHandlerI
) {}
async handle(event: AccountDeletionRequestedEvent): Promise<void> {
const user = await this.userRepository.findOneByUuid(event.payload.userUuid)
if (user === null) {
const userUuidOrError = Uuid.create(event.payload.userUuid)
if (userUuidOrError.isFailed()) {
this.logger.warn(`Could not find user with uuid: ${event.payload.userUuid}`)
return
}
const userUuid = userUuidOrError.getValue()
await this.removeSessions(event.payload.userUuid)
const user = await this.userRepository.findOneByUuid(userUuid)
if (user === null) {
this.logger.warn(`Could not find user with uuid: ${userUuid.value}`)
return
}
await this.removeSessions(userUuid.value)
await this.userRepository.remove(user)
this.logger.info(`Finished account cleanup for user: ${event.payload.userUuid}`)
this.logger.info(`Finished account cleanup for user: ${userUuid.value}`)
}
private async removeSessions(userUuid: string): Promise<void> {

View File

@@ -1,142 +0,0 @@
import 'reflect-metadata'
import { FileRemovedEvent } from '@standardnotes/domain-events'
import { Logger } from 'winston'
import { User } from '../User/User'
import { FileRemovedEventHandler } from './FileRemovedEventHandler'
import { SubscriptionSettingServiceInterface } from '../Setting/SubscriptionSettingServiceInterface'
import { UserSubscription } from '../Subscription/UserSubscription'
import { UserSubscriptionType } from '../Subscription/UserSubscriptionType'
import { UserSubscriptionServiceInterface } from '../Subscription/UserSubscriptionServiceInterface'
describe('FileRemovedEventHandler', () => {
let userSubscriptionService: UserSubscriptionServiceInterface
let logger: Logger
let user: User
let event: FileRemovedEvent
let subscriptionSettingService: SubscriptionSettingServiceInterface
let regularSubscription: UserSubscription
let sharedSubscription: UserSubscription
const createHandler = () => new FileRemovedEventHandler(userSubscriptionService, subscriptionSettingService, logger)
beforeEach(() => {
user = {
uuid: '123',
} as jest.Mocked<User>
regularSubscription = {
uuid: '1-2-3',
subscriptionType: UserSubscriptionType.Regular,
user: Promise.resolve(user),
} as jest.Mocked<UserSubscription>
sharedSubscription = {
uuid: '2-3-4',
subscriptionType: UserSubscriptionType.Shared,
user: Promise.resolve(user),
} as jest.Mocked<UserSubscription>
userSubscriptionService = {} as jest.Mocked<UserSubscriptionServiceInterface>
userSubscriptionService.findRegularSubscriptionForUserUuid = jest
.fn()
.mockReturnValue({ regularSubscription, sharedSubscription: null })
subscriptionSettingService = {} as jest.Mocked<SubscriptionSettingServiceInterface>
subscriptionSettingService.findSubscriptionSettingWithDecryptedValue = jest.fn().mockReturnValue(null)
subscriptionSettingService.createOrReplace = jest.fn()
event = {} as jest.Mocked<FileRemovedEvent>
event.createdAt = new Date(1)
event.payload = {
userUuid: '1-2-3',
fileByteSize: 123,
filePath: '1-2-3/2-3-4',
fileName: '2-3-4',
regularSubscriptionUuid: '4-5-6',
}
logger = {} as jest.Mocked<Logger>
logger.warn = jest.fn()
})
it('should do nothing a bytes used setting does not exist', async () => {
await createHandler().handle(event)
expect(subscriptionSettingService.createOrReplace).not.toHaveBeenCalled()
})
it('should not do anything if a user subscription is not found', async () => {
subscriptionSettingService.findSubscriptionSettingWithDecryptedValue = jest.fn().mockReturnValue({
value: 345,
})
userSubscriptionService.findRegularSubscriptionForUserUuid = jest
.fn()
.mockReturnValue({ regularSubscription: null, sharedSubscription: null })
await createHandler().handle(event)
expect(subscriptionSettingService.createOrReplace).not.toHaveBeenCalled()
})
it('should update a bytes used setting', async () => {
subscriptionSettingService.findSubscriptionSettingWithDecryptedValue = jest.fn().mockReturnValue({
value: 345,
})
await createHandler().handle(event)
expect(subscriptionSettingService.createOrReplace).toHaveBeenCalledWith({
props: {
name: 'FILE_UPLOAD_BYTES_USED',
sensitive: false,
unencryptedValue: '222',
serverEncryptionVersion: 0,
},
userSubscription: {
uuid: '1-2-3',
subscriptionType: 'regular',
user: Promise.resolve(user),
},
})
})
it('should update a bytes used setting on both shared and regular subscription', async () => {
userSubscriptionService.findRegularSubscriptionForUserUuid = jest
.fn()
.mockReturnValue({ regularSubscription, sharedSubscription })
subscriptionSettingService.findSubscriptionSettingWithDecryptedValue = jest.fn().mockReturnValue({
value: 345,
})
await createHandler().handle(event)
expect(subscriptionSettingService.createOrReplace).toHaveBeenNthCalledWith(1, {
props: {
name: 'FILE_UPLOAD_BYTES_USED',
sensitive: false,
unencryptedValue: '222',
serverEncryptionVersion: 0,
},
userSubscription: {
uuid: '1-2-3',
subscriptionType: 'regular',
user: Promise.resolve(user),
},
})
expect(subscriptionSettingService.createOrReplace).toHaveBeenNthCalledWith(2, {
props: {
name: 'FILE_UPLOAD_BYTES_USED',
sensitive: false,
unencryptedValue: '222',
serverEncryptionVersion: 0,
},
userSubscription: {
uuid: '2-3-4',
subscriptionType: 'shared',
user: Promise.resolve(user),
},
})
})
})

View File

@@ -1,62 +1,19 @@
import { DomainEventHandlerInterface, FileRemovedEvent } from '@standardnotes/domain-events'
import { SettingName } from '@standardnotes/settings'
import { inject, injectable } from 'inversify'
import { Logger } from 'winston'
import TYPES from '../../Bootstrap/Types'
import { EncryptionVersion } from '../Encryption/EncryptionVersion'
import { SubscriptionSettingServiceInterface } from '../Setting/SubscriptionSettingServiceInterface'
import { UserSubscription } from '../Subscription/UserSubscription'
import { UserSubscriptionServiceInterface } from '../Subscription/UserSubscriptionServiceInterface'
import { UpdateStorageQuotaUsedForUser } from '../UseCase/UpdateStorageQuotaUsedForUser/UpdateStorageQuotaUsedForUser'
@injectable()
export class FileRemovedEventHandler implements DomainEventHandlerInterface {
constructor(
@inject(TYPES.Auth_UserSubscriptionService) private userSubscriptionService: UserSubscriptionServiceInterface,
@inject(TYPES.Auth_SubscriptionSettingService)
private subscriptionSettingService: SubscriptionSettingServiceInterface,
@inject(TYPES.Auth_Logger) private logger: Logger,
) {}
constructor(private updateStorageQuotaUsedForUserUseCase: UpdateStorageQuotaUsedForUser, private logger: Logger) {}
async handle(event: FileRemovedEvent): Promise<void> {
const { regularSubscription, sharedSubscription } =
await this.userSubscriptionService.findRegularSubscriptionForUserUuid(event.payload.userUuid)
if (regularSubscription === null) {
this.logger.warn(`Could not find regular user subscription for user with uuid: ${event.payload.userUuid}`)
return
}
await this.updateUploadBytesUsedSetting(regularSubscription, event.payload.fileByteSize)
if (sharedSubscription !== null) {
await this.updateUploadBytesUsedSetting(sharedSubscription, event.payload.fileByteSize)
}
}
private async updateUploadBytesUsedSetting(subscription: UserSubscription, byteSize: number): Promise<void> {
const user = await subscription.user
const bytesUsedSetting = await this.subscriptionSettingService.findSubscriptionSettingWithDecryptedValue({
userUuid: user.uuid,
userSubscriptionUuid: subscription.uuid,
subscriptionSettingName: SettingName.create(SettingName.NAMES.FileUploadBytesUsed).getValue(),
const result = await this.updateStorageQuotaUsedForUserUseCase.execute({
userUuid: event.payload.userUuid,
bytesUsed: -event.payload.fileByteSize,
})
if (bytesUsedSetting === null) {
this.logger.warn(`Could not find bytes used setting for user with uuid: ${user.uuid}`)
return
if (result.isFailed()) {
this.logger.error(`Failed to update storage quota used for user: ${result.getError()}`)
}
const bytesUsed = bytesUsedSetting.value as string
await this.subscriptionSettingService.createOrReplace({
userSubscription: subscription,
props: {
name: SettingName.NAMES.FileUploadBytesUsed,
unencryptedValue: (+bytesUsed - byteSize).toString(),
sensitive: false,
serverEncryptionVersion: EncryptionVersion.Unencrypted,
},
})
}
}

View File

@@ -1,67 +1,19 @@
import { DomainEventHandlerInterface, FileUploadedEvent } from '@standardnotes/domain-events'
import { SettingName } from '@standardnotes/settings'
import { inject, injectable } from 'inversify'
import { Logger } from 'winston'
import TYPES from '../../Bootstrap/Types'
import { EncryptionVersion } from '../Encryption/EncryptionVersion'
import { SubscriptionSettingServiceInterface } from '../Setting/SubscriptionSettingServiceInterface'
import { UserSubscription } from '../Subscription/UserSubscription'
import { UserSubscriptionServiceInterface } from '../Subscription/UserSubscriptionServiceInterface'
import { UserRepositoryInterface } from '../User/UserRepositoryInterface'
import { UpdateStorageQuotaUsedForUser } from '../UseCase/UpdateStorageQuotaUsedForUser/UpdateStorageQuotaUsedForUser'
@injectable()
export class FileUploadedEventHandler implements DomainEventHandlerInterface {
constructor(
@inject(TYPES.Auth_UserRepository) private userRepository: UserRepositoryInterface,
@inject(TYPES.Auth_UserSubscriptionService) private userSubscriptionService: UserSubscriptionServiceInterface,
@inject(TYPES.Auth_SubscriptionSettingService)
private subscriptionSettingService: SubscriptionSettingServiceInterface,
@inject(TYPES.Auth_Logger) private logger: Logger,
) {}
constructor(private updateStorageQuotaUsedForUserUseCase: UpdateStorageQuotaUsedForUser, private logger: Logger) {}
async handle(event: FileUploadedEvent): Promise<void> {
const user = await this.userRepository.findOneByUuid(event.payload.userUuid)
if (user === null) {
this.logger.warn(`Could not find user with uuid: ${event.payload.userUuid}`)
return
}
const { regularSubscription, sharedSubscription } =
await this.userSubscriptionService.findRegularSubscriptionForUserUuid(event.payload.userUuid)
if (regularSubscription === null) {
this.logger.warn(`Could not find regular user subscription for user with uuid: ${event.payload.userUuid}`)
return
}
await this.updateUploadBytesUsedSetting(regularSubscription, event.payload.fileByteSize)
if (sharedSubscription !== null) {
await this.updateUploadBytesUsedSetting(sharedSubscription, event.payload.fileByteSize)
}
}
private async updateUploadBytesUsedSetting(subscription: UserSubscription, byteSize: number): Promise<void> {
let bytesUsed = '0'
const bytesUsedSetting = await this.subscriptionSettingService.findSubscriptionSettingWithDecryptedValue({
userUuid: (await subscription.user).uuid,
userSubscriptionUuid: subscription.uuid,
subscriptionSettingName: SettingName.create(SettingName.NAMES.FileUploadBytesUsed).getValue(),
const result = await this.updateStorageQuotaUsedForUserUseCase.execute({
userUuid: event.payload.userUuid,
bytesUsed: event.payload.fileByteSize,
})
if (bytesUsedSetting !== null) {
bytesUsed = bytesUsedSetting.value as string
}
await this.subscriptionSettingService.createOrReplace({
userSubscription: subscription,
props: {
name: SettingName.NAMES.FileUploadBytesUsed,
unencryptedValue: (+bytesUsed + byteSize).toString(),
sensitive: false,
serverEncryptionVersion: EncryptionVersion.Unencrypted,
},
})
if (result.isFailed()) {
this.logger.error(`Failed to update storage quota used for user: ${result.getError()}`)
}
}
}

View File

@@ -0,0 +1,48 @@
import { Logger } from 'winston'
import { Result } from '@standardnotes/domain-core'
import { PaymentsAccountDeletedEvent } from '@standardnotes/domain-events'
import { DeleteAccount } from '../UseCase/DeleteAccount/DeleteAccount'
import { PaymentsAccountDeletedEventHandler } from './PaymentsAccountDeletedEventHandler'
describe('PaymentsAccountDeletedEventHandler', () => {
let deleteAccountUseCase: DeleteAccount
let logger: Logger
let event: PaymentsAccountDeletedEvent
const createHandler = () => new PaymentsAccountDeletedEventHandler(deleteAccountUseCase, logger)
beforeEach(() => {
deleteAccountUseCase = {} as jest.Mocked<DeleteAccount>
deleteAccountUseCase.execute = jest.fn().mockResolvedValue(Result.ok('success'))
logger = {} as jest.Mocked<Logger>
logger.error = jest.fn()
event = {
payload: {
username: 'username',
},
} as jest.Mocked<PaymentsAccountDeletedEvent>
})
it('should delete account', async () => {
const handler = createHandler()
await handler.handle(event)
expect(deleteAccountUseCase.execute).toHaveBeenCalledWith({
username: 'username',
})
})
it('should log error if delete account fails', async () => {
const handler = createHandler()
deleteAccountUseCase.execute = jest.fn().mockResolvedValue(Result.fail('error'))
await handler.handle(event)
expect(logger.error).toHaveBeenCalledWith('Failed to delete account for user username: error')
})
})

View File

@@ -0,0 +1,18 @@
import { DomainEventHandlerInterface, PaymentsAccountDeletedEvent } from '@standardnotes/domain-events'
import { Logger } from 'winston'
import { DeleteAccount } from '../UseCase/DeleteAccount/DeleteAccount'
export class PaymentsAccountDeletedEventHandler implements DomainEventHandlerInterface {
constructor(private deleteAccountUseCase: DeleteAccount, private logger: Logger) {}
async handle(event: PaymentsAccountDeletedEvent): Promise<void> {
const result = await this.deleteAccountUseCase.execute({
username: event.payload.username,
})
if (result.isFailed()) {
this.logger.error(`Failed to delete account for user ${event.payload.username}: ${result.getError()}`)
}
}
}

View File

@@ -0,0 +1,19 @@
import { DomainEventHandlerInterface, SharedVaultFileRemovedEvent } from '@standardnotes/domain-events'
import { Logger } from 'winston'
import { UpdateStorageQuotaUsedForUser } from '../UseCase/UpdateStorageQuotaUsedForUser/UpdateStorageQuotaUsedForUser'
export class SharedVaultFileRemovedEventHandler implements DomainEventHandlerInterface {
constructor(private updateStorageQuotaUsedForUserUseCase: UpdateStorageQuotaUsedForUser, private logger: Logger) {}
async handle(event: SharedVaultFileRemovedEvent): Promise<void> {
const result = await this.updateStorageQuotaUsedForUserUseCase.execute({
userUuid: event.payload.vaultOwnerUuid,
bytesUsed: -event.payload.fileByteSize,
})
if (result.isFailed()) {
this.logger.error(`Failed to update storage quota used for user: ${result.getError()}`)
}
}
}

View File

@@ -0,0 +1,19 @@
import { DomainEventHandlerInterface, SharedVaultFileUploadedEvent } from '@standardnotes/domain-events'
import { Logger } from 'winston'
import { UpdateStorageQuotaUsedForUser } from '../UseCase/UpdateStorageQuotaUsedForUser/UpdateStorageQuotaUsedForUser'
export class SharedVaultFileUploadedEventHandler implements DomainEventHandlerInterface {
constructor(private updateStorageQuotaUsedForUserUseCase: UpdateStorageQuotaUsedForUser, private logger: Logger) {}
async handle(event: SharedVaultFileUploadedEvent): Promise<void> {
const result = await this.updateStorageQuotaUsedForUserUseCase.execute({
userUuid: event.payload.vaultOwnerUuid,
bytesUsed: event.payload.fileByteSize,
})
if (result.isFailed()) {
this.logger.error(`Failed to update storage quota used for user: ${result.getError()}`)
}
}
}

View File

@@ -114,8 +114,6 @@ describe('SubscriptionPurchasedEventHandler', () => {
expect(subscriptionSettingService.applyDefaultSubscriptionSettingsForSubscription).toHaveBeenCalledWith(
subscription,
SubscriptionName.ProPlan,
'123',
)
})

View File

@@ -66,11 +66,7 @@ export class SubscriptionPurchasedEventHandler implements DomainEventHandlerInte
await this.addUserRole(user, event.payload.subscriptionName)
await this.subscriptionSettingService.applyDefaultSubscriptionSettingsForSubscription(
userSubscription,
event.payload.subscriptionName,
user.uuid,
)
await this.subscriptionSettingService.applyDefaultSubscriptionSettingsForSubscription(userSubscription)
}
private async addUserRole(user: User, subscriptionName: string): Promise<void> {

View File

@@ -94,8 +94,6 @@ describe('SubscriptionReassignedEventHandler', () => {
expect(subscriptionSettingService.applyDefaultSubscriptionSettingsForSubscription).toHaveBeenCalledWith(
subscription,
SubscriptionName.ProPlan,
'123',
)
})

View File

@@ -63,11 +63,7 @@ export class SubscriptionReassignedEventHandler implements DomainEventHandlerInt
},
})
await this.subscriptionSettingService.applyDefaultSubscriptionSettingsForSubscription(
userSubscription,
event.payload.subscriptionName,
user.uuid,
)
await this.subscriptionSettingService.applyDefaultSubscriptionSettingsForSubscription(userSubscription)
}
private async addUserRole(user: User, subscriptionName: string): Promise<void> {

View File

@@ -129,8 +129,6 @@ describe('SubscriptionSyncRequestedEventHandler', () => {
expect(subscriptionSettingService.applyDefaultSubscriptionSettingsForSubscription).toHaveBeenCalledWith(
subscription,
SubscriptionName.ProPlan,
'123',
)
expect(settingService.createOrReplace).toHaveBeenCalledWith({

View File

@@ -95,11 +95,7 @@ export class SubscriptionSyncRequestedEventHandler implements DomainEventHandler
await this.roleService.addUserRole(user, event.payload.subscriptionName)
await this.subscriptionSettingService.applyDefaultSubscriptionSettingsForSubscription(
userSubscription,
event.payload.subscriptionName,
user.uuid,
)
await this.subscriptionSettingService.applyDefaultSubscriptionSettingsForSubscription(userSubscription)
await this.settingService.createOrReplace({
user,

View File

@@ -214,13 +214,25 @@ describe('RoleService', () => {
})
it('should indicate if a user has given permission', async () => {
const userHasPermission = await createService().userHasPermission('1-2-3', PermissionName.DailyEmailBackup)
const userHasPermission = await createService().userHasPermission(
'00000000-0000-0000-0000-000000000000',
PermissionName.DailyEmailBackup,
)
expect(userHasPermission).toBeTruthy()
})
it('should not indiciate if a user has permission if the user uuid is invalid', async () => {
const userHasPermission = await createService().userHasPermission('invalid', PermissionName.DailyEmailBackup)
expect(userHasPermission).toBeFalsy()
})
it('should indicate if a user does not have a given permission', async () => {
const userHasPermission = await createService().userHasPermission('1-2-3', PermissionName.MarkdownProEditor)
const userHasPermission = await createService().userHasPermission(
'00000000-0000-0000-0000-000000000000',
PermissionName.MarkdownProEditor,
)
expect(userHasPermission).toBeFalsy()
})
@@ -228,7 +240,10 @@ describe('RoleService', () => {
it('should indicate user does not have a permission if user could not be found', async () => {
userRepository.findOneByUuid = jest.fn().mockReturnValue(null)
const userHasPermission = await createService().userHasPermission('1-2-3', PermissionName.MarkdownProEditor)
const userHasPermission = await createService().userHasPermission(
'00000000-0000-0000-0000-000000000000',
PermissionName.MarkdownProEditor,
)
expect(userHasPermission).toBeFalsy()
})

View File

@@ -13,6 +13,7 @@ import { RoleToSubscriptionMapInterface } from './RoleToSubscriptionMapInterface
import { OfflineUserSubscriptionRepositoryInterface } from '../Subscription/OfflineUserSubscriptionRepositoryInterface'
import { Role } from './Role'
import { OfflineUserSubscription } from '../Subscription/OfflineUserSubscription'
import { Uuid } from '@standardnotes/domain-core'
@injectable()
export class RoleService implements RoleServiceInterface {
@@ -26,10 +27,16 @@ export class RoleService implements RoleServiceInterface {
@inject(TYPES.Auth_Logger) private logger: Logger,
) {}
async userHasPermission(userUuid: string, permissionName: PermissionName): Promise<boolean> {
async userHasPermission(userUuidString: string, permissionName: PermissionName): Promise<boolean> {
const userUuidOrError = Uuid.create(userUuidString)
if (userUuidOrError.isFailed()) {
return false
}
const userUuid = userUuidOrError.getValue()
const user = await this.userRepository.findOneByUuid(userUuid)
if (user === null) {
this.logger.warn(`Could not find user with uuid ${userUuid} for permissions check`)
this.logger.warn(`Could not find user with uuid ${userUuid.value} for permissions check`)
return false
}

View File

@@ -4,13 +4,6 @@ export interface EphemeralSessionRepositoryInterface {
findOneByUuid(uuid: string): Promise<EphemeralSession | null>
findOneByUuidAndUserUuid(uuid: string, userUuid: string): Promise<EphemeralSession | null>
findAllByUserUuid(userUuid: string): Promise<Array<EphemeralSession>>
updateTokensAndExpirationDates(
uuid: string,
hashedAccessToken: string,
hashedRefreshToken: string,
accessExpiration: Date,
refreshExpiration: Date,
): Promise<void>
deleteOne(uuid: string, userUuid: string): Promise<void>
save(ephemeralSession: EphemeralSession): Promise<void>
}

View File

@@ -1,3 +1,5 @@
import { Uuid } from '@standardnotes/domain-core'
import { Session } from './Session'
export interface SessionRepositoryInterface {
@@ -5,10 +7,8 @@ export interface SessionRepositoryInterface {
findOneByUuidAndUserUuid(uuid: string, userUuid: string): Promise<Session | null>
findAllByRefreshExpirationAndUserUuid(userUuid: string): Promise<Array<Session>>
findAllByUserUuid(userUuid: string): Promise<Array<Session>>
deleteAllByUserUuid(userUuid: string, currentSessionUuid: string): Promise<void>
deleteAllByUserUuidExceptOne(dto: { userUuid: Uuid; currentSessionUuid: Uuid }): Promise<void>
deleteOneByUuid(uuid: string): Promise<void>
updateHashedTokens(uuid: string, hashedAccessToken: string, hashedRefreshToken: string): Promise<void>
updatedTokenExpirationDates(uuid: string, accessExpiration: Date, refreshExpiration: Date): Promise<void>
save(session: Session): Promise<Session>
remove(session: Session): Promise<Session>
clearUserAgentByUserUuid(userUuid: string): Promise<void>

View File

@@ -24,8 +24,8 @@ describe('SessionService', () => {
let sessionRepository: SessionRepositoryInterface
let ephemeralSessionRepository: EphemeralSessionRepositoryInterface
let revokedSessionRepository: RevokedSessionRepositoryInterface
let session: Session
let ephemeralSession: EphemeralSession
let existingSession: Session
let existingEphemeralSession: EphemeralSession
let revokedSession: RevokedSession
let settingService: SettingServiceInterface
let deviceDetector: UAParser
@@ -54,14 +54,14 @@ describe('SessionService', () => {
)
beforeEach(() => {
session = {} as jest.Mocked<Session>
session.uuid = '2e1e43'
session.userUuid = '1-2-3'
session.userAgent = 'Chrome'
session.apiVersion = ApiVersion.v20200115
session.hashedAccessToken = '4e07408562bedb8b60ce05c1decfe3ad16b72230967de01f640b7e4729b49fce'
session.hashedRefreshToken = '4e07408562bedb8b60ce05c1decfe3ad16b72230967de01f640b7e4729b49fce'
session.readonlyAccess = false
existingSession = {} as jest.Mocked<Session>
existingSession.uuid = '2e1e43'
existingSession.userUuid = '1-2-3'
existingSession.userAgent = 'Chrome'
existingSession.apiVersion = ApiVersion.v20200115
existingSession.hashedAccessToken = '4e07408562bedb8b60ce05c1decfe3ad16b72230967de01f640b7e4729b49fce'
existingSession.hashedRefreshToken = '4e07408562bedb8b60ce05c1decfe3ad16b72230967de01f640b7e4729b49fce'
existingSession.readonlyAccess = false
revokedSession = {} as jest.Mocked<RevokedSession>
revokedSession.uuid = '2e1e43'
@@ -69,9 +69,7 @@ describe('SessionService', () => {
sessionRepository = {} as jest.Mocked<SessionRepositoryInterface>
sessionRepository.findOneByUuid = jest.fn().mockReturnValue(null)
sessionRepository.deleteOneByUuid = jest.fn()
sessionRepository.save = jest.fn().mockReturnValue(session)
sessionRepository.updateHashedTokens = jest.fn()
sessionRepository.updatedTokenExpirationDates = jest.fn()
sessionRepository.save = jest.fn().mockReturnValue(existingSession)
settingService = {} as jest.Mocked<SettingServiceInterface>
settingService.findSettingWithDecryptedValue = jest.fn().mockReturnValue(null)
@@ -79,17 +77,18 @@ describe('SessionService', () => {
ephemeralSessionRepository = {} as jest.Mocked<EphemeralSessionRepositoryInterface>
ephemeralSessionRepository.save = jest.fn()
ephemeralSessionRepository.findOneByUuid = jest.fn()
ephemeralSessionRepository.updateTokensAndExpirationDates = jest.fn()
ephemeralSessionRepository.deleteOne = jest.fn()
revokedSessionRepository = {} as jest.Mocked<RevokedSessionRepositoryInterface>
revokedSessionRepository.save = jest.fn()
ephemeralSession = {} as jest.Mocked<EphemeralSession>
ephemeralSession.uuid = '2-3-4'
ephemeralSession.userAgent = 'Mozilla Firefox'
ephemeralSession.hashedAccessToken = '4e07408562bedb8b60ce05c1decfe3ad16b72230967de01f640b7e4729b49fce'
ephemeralSession.hashedRefreshToken = '4e07408562bedb8b60ce05c1decfe3ad16b72230967de01f640b7e4729b49fce'
existingEphemeralSession = {} as jest.Mocked<EphemeralSession>
existingEphemeralSession.uuid = '2-3-4'
existingEphemeralSession.userUuid = '1-2-3'
existingEphemeralSession.userAgent = 'Mozilla Firefox'
existingEphemeralSession.hashedAccessToken = '4e07408562bedb8b60ce05c1decfe3ad16b72230967de01f640b7e4729b49fce'
existingEphemeralSession.hashedRefreshToken = '4e07408562bedb8b60ce05c1decfe3ad16b72230967de01f640b7e4729b49fce'
existingEphemeralSession.readonlyAccess = false
timer = {} as jest.Mocked<TimerInterface>
timer.convertStringDateToMilliseconds = jest.fn().mockReturnValue(123)
@@ -138,7 +137,7 @@ describe('SessionService', () => {
})
it('should refresh access and refresh tokens for a session', async () => {
expect(await createService().refreshTokens(session)).toEqual({
expect(await createService().refreshTokens({ session: existingSession, isEphemeral: false })).toEqual({
access_expiration: 123,
access_token: expect.any(String),
refresh_token: expect.any(String),
@@ -146,15 +145,28 @@ describe('SessionService', () => {
readonly_access: false,
})
expect(sessionRepository.updateHashedTokens).toHaveBeenCalled()
expect(sessionRepository.updatedTokenExpirationDates).toHaveBeenCalled()
expect(sessionRepository.save).toHaveBeenCalled()
expect(ephemeralSessionRepository.save).not.toHaveBeenCalled()
})
it('should refresh access and refresh tokens for an ephemeral session', async () => {
expect(await createService().refreshTokens({ session: existingEphemeralSession, isEphemeral: true })).toEqual({
access_expiration: 123,
access_token: expect.any(String),
refresh_token: expect.any(String),
refresh_expiration: 123,
readonly_access: false,
})
expect(sessionRepository.save).not.toHaveBeenCalled()
expect(ephemeralSessionRepository.save).toHaveBeenCalled()
})
it('should create new session for a user', async () => {
const user = {} as jest.Mocked<User>
user.uuid = '123'
const sessionPayload = await createService().createNewSessionForUser({
const result = await createService().createNewSessionForUser({
user,
apiVersion: '003',
userAgent: 'Google Chrome',
@@ -176,7 +188,7 @@ describe('SessionService', () => {
readonlyAccess: false,
})
expect(sessionPayload).toEqual({
expect(result.sessionHttpRepresentation).toEqual({
access_expiration: 123,
access_token: expect.any(String),
refresh_expiration: 123,
@@ -190,7 +202,7 @@ describe('SessionService', () => {
user.email = 'demo@standardnotes.com'
user.uuid = '123'
const sessionPayload = await createService().createNewSessionForUser({
const result = await createService().createNewSessionForUser({
user,
apiVersion: '003',
userAgent: 'Google Chrome',
@@ -212,7 +224,7 @@ describe('SessionService', () => {
readonlyAccess: true,
})
expect(sessionPayload).toEqual({
expect(result.sessionHttpRepresentation).toEqual({
access_expiration: 123,
access_token: expect.any(String),
refresh_expiration: 123,
@@ -229,7 +241,7 @@ describe('SessionService', () => {
value: LogSessionUserAgentOption.Disabled,
} as jest.Mocked<Setting>)
const sessionPayload = await createService().createNewSessionForUser({
const result = await createService().createNewSessionForUser({
user,
apiVersion: '003',
userAgent: 'Google Chrome',
@@ -250,7 +262,7 @@ describe('SessionService', () => {
readonlyAccess: false,
})
expect(sessionPayload).toEqual({
expect(result.sessionHttpRepresentation).toEqual({
access_expiration: 123,
access_token: expect.any(String),
refresh_expiration: 123,
@@ -305,7 +317,7 @@ describe('SessionService', () => {
user.uuid = '123'
user.email = 'test@test.te'
const sessionPayload = await createService().createNewSessionForUser({
const result = await createService().createNewSessionForUser({
user,
apiVersion: '003',
userAgent: 'Google Chrome',
@@ -317,7 +329,7 @@ describe('SessionService', () => {
username: 'test@test.te',
subscriptionPlanName: null,
})
expect(sessionPayload).toEqual({
expect(result.sessionHttpRepresentation).toEqual({
access_expiration: 123,
access_token: expect.any(String),
refresh_expiration: 123,
@@ -333,7 +345,7 @@ describe('SessionService', () => {
user.uuid = '123'
user.email = 'test@test.te'
const sessionPayload = await createService().createNewSessionForUser({
const result = await createService().createNewSessionForUser({
user,
apiVersion: '003',
userAgent: 'Google Chrome',
@@ -345,7 +357,7 @@ describe('SessionService', () => {
username: 'test@test.te',
subscriptionPlanName: null,
})
expect(sessionPayload).toEqual({
expect(result.sessionHttpRepresentation).toEqual({
access_expiration: 123,
access_token: expect.any(String),
refresh_expiration: 123,
@@ -361,7 +373,7 @@ describe('SessionService', () => {
user.uuid = '123'
user.email = 'test@test.te'
const sessionPayload = await createService().createNewSessionForUser({
const result = await createService().createNewSessionForUser({
user,
apiVersion: '003',
userAgent: 'Google Chrome',
@@ -373,7 +385,7 @@ describe('SessionService', () => {
username: 'test@test.te',
subscriptionPlanName: null,
})
expect(sessionPayload).toEqual({
expect(result.sessionHttpRepresentation).toEqual({
access_expiration: 123,
access_token: expect.any(String),
refresh_expiration: 123,
@@ -386,7 +398,7 @@ describe('SessionService', () => {
const user = {} as jest.Mocked<User>
user.uuid = '123'
const sessionPayload = await createService().createNewEphemeralSessionForUser({
const result = await createService().createNewEphemeralSessionForUser({
user,
apiVersion: '003',
userAgent: 'Google Chrome',
@@ -408,7 +420,7 @@ describe('SessionService', () => {
readonlyAccess: false,
})
expect(sessionPayload).toEqual({
expect(result.sessionHttpRepresentation).toEqual({
access_expiration: 123,
access_token: expect.any(String),
refresh_expiration: 123,
@@ -420,7 +432,7 @@ describe('SessionService', () => {
it('should delete a session by token', async () => {
sessionRepository.findOneByUuid = jest.fn().mockImplementation((uuid) => {
if (uuid === '2') {
return session
return existingSession
}
return null
@@ -429,13 +441,28 @@ describe('SessionService', () => {
await createService().deleteSessionByToken('1:2:3')
expect(sessionRepository.deleteOneByUuid).toHaveBeenCalledWith('2e1e43')
expect(ephemeralSessionRepository.deleteOne).toHaveBeenCalledWith('2e1e43', '1-2-3')
expect(ephemeralSessionRepository.deleteOne).not.toHaveBeenCalled()
})
it('should delete an ephemeral session by token', async () => {
ephemeralSessionRepository.findOneByUuid = jest.fn().mockImplementation((uuid) => {
if (uuid === '2') {
return existingEphemeralSession
}
return null
})
await createService().deleteSessionByToken('1:2:3')
expect(sessionRepository.deleteOneByUuid).not.toHaveBeenCalled()
expect(ephemeralSessionRepository.deleteOne).toHaveBeenCalledWith('2-3-4', '1-2-3')
})
it('should not delete a session by token if session is not found', async () => {
sessionRepository.findOneByUuid = jest.fn().mockImplementation((uuid) => {
if (uuid === '2') {
return session
return existingSession
}
return null
@@ -448,13 +475,13 @@ describe('SessionService', () => {
})
it('should determine if a refresh token is valid', async () => {
expect(createService().isRefreshTokenMatchingHashedSessionToken(session, '1:2:3')).toBeTruthy()
expect(createService().isRefreshTokenMatchingHashedSessionToken(session, '1:2:4')).toBeFalsy()
expect(createService().isRefreshTokenMatchingHashedSessionToken(session, '1:2')).toBeFalsy()
expect(createService().isRefreshTokenMatchingHashedSessionToken(existingSession, '1:2:3')).toBeTruthy()
expect(createService().isRefreshTokenMatchingHashedSessionToken(existingSession, '1:2:4')).toBeFalsy()
expect(createService().isRefreshTokenMatchingHashedSessionToken(existingSession, '1:2')).toBeFalsy()
})
it('should return device info based on user agent', () => {
expect(createService().getDeviceInfo(session)).toEqual('Chrome 69.0 on Mac 10.13')
expect(createService().getDeviceInfo(existingSession)).toEqual('Chrome 69.0 on Mac 10.13')
})
it('should return device info based on undefined user agent', () => {
@@ -463,7 +490,7 @@ describe('SessionService', () => {
browser: { name: undefined, version: undefined },
os: { name: undefined, version: undefined },
})
expect(createService().getDeviceInfo(session)).toEqual('Unknown Client on Unknown OS')
expect(createService().getDeviceInfo(existingSession)).toEqual('Unknown Client on Unknown OS')
})
it('should return a shorter info based on lack of client in user agent', () => {
@@ -473,7 +500,7 @@ describe('SessionService', () => {
os: { name: 'iOS', version: '10.3' },
})
expect(createService().getDeviceInfo(session)).toEqual('iOS 10.3')
expect(createService().getDeviceInfo(existingSession)).toEqual('iOS 10.3')
})
it('should return a shorter info based on lack of os in user agent', () => {
@@ -483,13 +510,13 @@ describe('SessionService', () => {
os: { name: '', version: '' },
})
expect(createService().getDeviceInfo(session)).toEqual('Chrome 69.0')
expect(createService().getDeviceInfo(existingSession)).toEqual('Chrome 69.0')
})
it('should return unknown client and os if user agent is cleaned out', () => {
session.userAgent = null
existingSession.userAgent = null
expect(createService().getDeviceInfo(session)).toEqual('Unknown Client on Unknown OS')
expect(createService().getDeviceInfo(existingSession)).toEqual('Unknown Client on Unknown OS')
})
it('should return a shorter info based on partial os in user agent', () => {
@@ -499,7 +526,7 @@ describe('SessionService', () => {
os: { name: 'Windows', version: '' },
})
expect(createService().getDeviceInfo(session)).toEqual('Chrome 69.0 on Windows')
expect(createService().getDeviceInfo(existingSession)).toEqual('Chrome 69.0 on Windows')
deviceDetector.getResult = jest.fn().mockReturnValue({
ua: 'dummy-data',
@@ -507,7 +534,7 @@ describe('SessionService', () => {
os: { name: '', version: '7' },
})
expect(createService().getDeviceInfo(session)).toEqual('Chrome 69.0 on 7')
expect(createService().getDeviceInfo(existingSession)).toEqual('Chrome 69.0 on 7')
})
it('should return a shorter info based on partial client in user agent', () => {
@@ -517,7 +544,7 @@ describe('SessionService', () => {
os: { name: 'Windows', version: '7' },
})
expect(createService().getDeviceInfo(session)).toEqual('69.0 on Windows 7')
expect(createService().getDeviceInfo(existingSession)).toEqual('69.0 on Windows 7')
deviceDetector.getResult = jest.fn().mockReturnValue({
ua: 'dummy-data',
@@ -525,7 +552,7 @@ describe('SessionService', () => {
os: { name: 'Windows', version: '7' },
})
expect(createService().getDeviceInfo(session)).toEqual('Chrome on Windows 7')
expect(createService().getDeviceInfo(existingSession)).toEqual('Chrome on Windows 7')
})
it('should return a shorter info based on iOS agent', () => {
@@ -538,7 +565,7 @@ describe('SessionService', () => {
cpu: { architecture: undefined },
})
expect(createService().getDeviceInfo(session)).toEqual('iOS')
expect(createService().getDeviceInfo(existingSession)).toEqual('iOS')
})
it('should return a shorter info based on partial client and partial os in user agent', () => {
@@ -548,7 +575,7 @@ describe('SessionService', () => {
os: { name: 'Windows', version: '' },
})
expect(createService().getDeviceInfo(session)).toEqual('69.0 on Windows')
expect(createService().getDeviceInfo(existingSession)).toEqual('69.0 on Windows')
deviceDetector.getResult = jest.fn().mockReturnValue({
ua: 'dummy-data',
@@ -556,7 +583,7 @@ describe('SessionService', () => {
os: { name: '', version: '7' },
})
expect(createService().getDeviceInfo(session)).toEqual('Chrome on 7')
expect(createService().getDeviceInfo(existingSession)).toEqual('Chrome on 7')
})
it('should return only Android os for okHttp client', () => {
@@ -569,7 +596,7 @@ describe('SessionService', () => {
cpu: { architecture: undefined },
})
expect(createService().getDeviceInfo(session)).toEqual('Android')
expect(createService().getDeviceInfo(existingSession)).toEqual('Android')
})
it('should detect the StandardNotes app in user agent', () => {
@@ -582,7 +609,7 @@ describe('SessionService', () => {
cpu: { architecture: undefined },
})
expect(createService().getDeviceInfo(session)).toEqual('Standard Notes Desktop 3.5.18 on Mac OS 10.16.0')
expect(createService().getDeviceInfo(existingSession)).toEqual('Standard Notes Desktop 3.5.18 on Mac OS 10.16.0')
})
it('should return unknown device info as fallback', () => {
@@ -590,70 +617,72 @@ describe('SessionService', () => {
throw new Error('something bad happened')
})
expect(createService().getDeviceInfo(session)).toEqual('Unknown Client on Unknown OS')
expect(createService().getDeviceInfo(existingSession)).toEqual('Unknown Client on Unknown OS')
})
it('should retrieve a session from a session token', async () => {
sessionRepository.findOneByUuid = jest.fn().mockImplementation((uuid) => {
if (uuid === '2') {
return session
return existingSession
}
return null
})
const result = await createService().getSessionFromToken('1:2:3')
const { session, isEphemeral } = await createService().getSessionFromToken('1:2:3')
expect(result).toEqual(session)
expect(session).toEqual(session)
expect(isEphemeral).toBeFalsy()
})
it('should retrieve an ephemeral session from a session token', async () => {
ephemeralSessionRepository.findOneByUuid = jest.fn().mockReturnValue(ephemeralSession)
ephemeralSessionRepository.findOneByUuid = jest.fn().mockReturnValue(existingEphemeralSession)
sessionRepository.findOneByUuid = jest.fn().mockReturnValue(null)
const result = await createService().getSessionFromToken('1:2:3')
const { session, isEphemeral } = await createService().getSessionFromToken('1:2:3')
expect(result).toEqual(ephemeralSession)
expect(session).toEqual(existingEphemeralSession)
expect(isEphemeral).toBeTruthy()
})
it('should not retrieve a session from a session token that has access token missing', async () => {
sessionRepository.findOneByUuid = jest.fn().mockImplementation((uuid) => {
if (uuid === '2') {
return session
return existingSession
}
return null
})
const result = await createService().getSessionFromToken('1:2')
const { session } = await createService().getSessionFromToken('1:2')
expect(result).toBeUndefined()
expect(session).toBeUndefined()
})
it('should not retrieve a session that is missing', async () => {
sessionRepository.findOneByUuid = jest.fn().mockReturnValue(null)
const result = await createService().getSessionFromToken('1:2:3')
const { session } = await createService().getSessionFromToken('1:2:3')
expect(result).toBeUndefined()
expect(session).toBeUndefined()
})
it('should not retrieve a session from a session token that has invalid access token', async () => {
sessionRepository.findOneByUuid = jest.fn().mockImplementation((uuid) => {
if (uuid === '2') {
return session
return existingSession
}
return null
})
const result = await createService().getSessionFromToken('1:2:4')
const { session } = await createService().getSessionFromToken('1:2:4')
expect(result).toBeUndefined()
expect(session).toBeUndefined()
})
it('should revoked a session', async () => {
await createService().createRevokedSession(session)
await createService().createRevokedSession(existingSession)
expect(revokedSessionRepository.save).toHaveBeenCalledWith({
uuid: '2e1e43',

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