Compare commits

..

38 Commits

Author SHA1 Message Date
standardci
dbb0e4a974 chore(release): publish new version
- @standardnotes/api-gateway@1.91.0
 - @standardnotes/files-server@1.38.0
 - @standardnotes/home-server@1.23.0
2024-03-20 15:04:32 +00:00
Karol Sójko
5c02435ee4 feat: add CORS_ORIGIN_STRICT_MODE_ENABLED env var to determine if CORS origin should be restricted 2024-03-20 15:59:43 +01:00
standardci
0a1e555b13 chore(release): publish new version
- @standardnotes/api-gateway@1.90.3
 - @standardnotes/home-server@1.22.68
2024-03-18 10:22:49 +00:00
Karol Sójko
be668d7d7a fix(api-gateway): response headers cors issue - fixes #1046 2024-03-18 11:17:52 +01:00
standardci
87e50ec941 chore(release): publish new version
- @standardnotes/api-gateway@1.90.2
 - @standardnotes/files-server@1.37.12
 - @standardnotes/home-server@1.22.67
2024-03-18 08:48:11 +00:00
Karol Sójko
6d7ca1b926 fix: cors issues on clients - fixes #1046 (#1049) 2024-03-18 09:43:58 +01:00
standardci
00bfaaa53d chore(release): publish new version
- @standardnotes/auth-server@1.178.3
 - @standardnotes/home-server@1.22.66
2024-03-18 08:12:46 +00:00
Karol Sójko
f939caf2d9 fix(auth): allow registration on new api versions - fixes #1046 (#1048) 2024-03-18 09:08:16 +01:00
standardci
0f3615ee65 chore(release): publish new version
- @standardnotes/auth-server@1.178.2
 - @standardnotes/home-server@1.22.65
 - @standardnotes/syncing-server@1.136.2
2024-03-15 10:25:31 +00:00
Karol Sójko
567bcf26b5 tmp: disable e2e and deployment to ecs 2024-03-15 11:20:38 +01:00
Karol Sójko
9d49764b84 fix: allow handling of new api version 2024-03-15 11:17:46 +01:00
standardci
5c9f493b67 chore(release): publish new version
- @standardnotes/auth-server@1.178.1
 - @standardnotes/home-server@1.22.64
2024-02-09 18:01:17 +00:00
Mo
4fe8e9a79f fix: allow expired offline subscriptions to receive dashboard emails (#1041) 2024-02-09 11:39:47 -06:00
Karol Sójko
f975dd9697 fix: e2e params for max http request payload size (#1037) 2024-02-02 13:06:52 +01:00
standardci
10832f7001 chore(release): publish new version
- @standardnotes/analytics@2.34.16
 - @standardnotes/api-gateway@1.90.1
 - @standardnotes/auth-server@1.178.0
 - @standardnotes/domain-events-infra@1.23.3
 - @standardnotes/domain-events@2.141.0
 - @standardnotes/files-server@1.37.11
 - @standardnotes/home-server@1.22.63
 - @standardnotes/revisions-server@1.51.16
 - @standardnotes/scheduler-server@1.27.21
 - @standardnotes/syncing-server@1.136.1
 - @standardnotes/websockets-server@1.22.12
2024-01-19 10:38:11 +00:00
Karol Sójko
86b050865f feat(auth): add script for fixing subscriptions with missing id state (#1030)
* fix(auth): add subscription id safe guards on handlers

* feat(domain-events): add subscription state events

* feat(domain-events): add subscription state events

* feat(auth): add handling of subscription state fetched events

* feat(auth): add script for fixing subscriptions state
2024-01-19 11:17:33 +01:00
standardci
6f07aaf87a chore(release): publish new version
- @standardnotes/analytics@2.34.15
 - @standardnotes/api-gateway@1.90.0
 - @standardnotes/auth-server@1.177.20
 - @standardnotes/domain-events-infra@1.23.2
 - @standardnotes/domain-events@2.140.0
 - @standardnotes/files-server@1.37.10
 - @standardnotes/home-server@1.22.62
 - @standardnotes/revisions-server@1.51.15
 - @standardnotes/scheduler-server@1.27.20
 - @standardnotes/syncing-server@1.136.0
 - @standardnotes/websockets-server@1.22.11
2024-01-18 13:19:12 +00:00
Karol Sójko
634e8bd2d0 feat: add content sizes fixing upon grpc resource exhausted error (#1029) 2024-01-18 13:58:28 +01:00
standardci
6853dfbf66 chore(release): publish new version
- @standardnotes/api-gateway@1.89.20
 - @standardnotes/home-server@1.22.61
2024-01-18 11:08:11 +00:00
Karol Sójko
136cf252a1 fix(api-gateway): add codetag metadata to error logs 2024-01-18 11:47:26 +01:00
standardci
cad28ebba5 chore(release): publish new version
- @standardnotes/auth-server@1.177.19
 - @standardnotes/home-server@1.22.60
2024-01-17 12:54:44 +00:00
Karol Sójko
460fdf9eaf fix(auth): add server daily email backup permission for all versions of core user role (#1028) 2024-01-17 13:34:00 +01:00
standardci
bec1b502ad chore(release): publish new version
- @standardnotes/home-server@1.22.59
 - @standardnotes/syncing-server@1.135.0
2024-01-17 10:48:28 +00:00
Karol Sójko
70bbf11db5 feat(syncing-server): add procedure to recalculate content sizes (#1027) 2024-01-17 11:27:26 +01:00
standardci
c00c7becae chore(release): publish new version
- @standardnotes/home-server@1.22.58
 - @standardnotes/syncing-server@1.134.1
2024-01-16 10:41:23 +00:00
Karol Sójko
89dc6c19bf fix(syncing-server): missing item operations metric store expiry 2024-01-16 11:20:35 +01:00
standardci
972a91d59f chore(release): publish new version
- @standardnotes/auth-server@1.177.18
 - @standardnotes/home-server@1.22.57
2024-01-15 12:09:42 +00:00
Karol Sójko
045358ddbf fix(auth): add renewal for shared offline subscriptions 2024-01-15 12:42:54 +01:00
Karol Sójko
c7217a92ba fix(auth): add more logs to syncing subscription 2024-01-15 12:39:27 +01:00
standardci
3da7a21cde chore(release): publish new version
- @standardnotes/auth-server@1.177.17
 - @standardnotes/home-server@1.22.56
2024-01-15 10:27:24 +00:00
Karol Sójko
351e18f638 fix(auth): add debug logs for subscription sync requested event 2024-01-15 11:06:19 +01:00
standardci
4f2129c4e0 chore(release): publish new version
- @standardnotes/auth-server@1.177.16
 - @standardnotes/home-server@1.22.55
2024-01-15 09:44:23 +00:00
Karol Sójko
d7a1c667dd fix(auth): update shared subscriptions upon subscription sync (#1022) 2024-01-15 10:23:51 +01:00
standardci
4de0bfa36d chore(release): publish new version
- @standardnotes/home-server@1.22.54
 - @standardnotes/syncing-server@1.134.0
2024-01-12 15:06:26 +00:00
Karol Sójko
0443de88ce feat(syncing-server): reduced abuse thresholds for free users (#1021) 2024-01-12 15:45:00 +01:00
Karol Sójko
f830bac873 fix: reduce the transfer limit on e2e tests (#1020) 2024-01-11 13:12:33 +01:00
standardci
517ae5ded9 chore(release): publish new version
- @standardnotes/api-gateway@1.89.19
 - @standardnotes/files-server@1.37.9
 - @standardnotes/home-server@1.22.53
 - @standardnotes/syncing-server@1.133.6
2024-01-10 14:40:54 +00:00
Karol Sójko
6062f85000 fix: add dedicated http code response upon a request with too large payload (#1019)
* fix: add dedicated http code response upon a request with too large payload

* fix error log
2024-01-10 15:19:26 +01:00
110 changed files with 2361 additions and 155 deletions

4
.github/ci.env vendored
View File

@@ -27,4 +27,6 @@ AUTH_JWT_SECRET=f95259c5e441f5a4646d76422cfb3df4c4488842901aa50b6c51b8be2e0040e9
AUTH_SERVER_ENCRYPTION_SERVER_KEY=1087415dfde3093797f9a7ca93a49e7d7aa1861735eb0d32aae9c303b8c3d060
VALET_TOKEN_SECRET=4b886819ebe1e908077c6cae96311b48a8416bd60cc91c03060e15bdf6b30d1f
SYNCING_SERVER_CONTENT_SIZE_TRANSFER_LIMIT=1000000
SYNCING_SERVER_CONTENT_SIZE_TRANSFER_LIMIT=100000
HTTP_REQUEST_PAYLOAD_LIMIT_MEGABYTES=1

View File

@@ -42,26 +42,26 @@ jobs:
workspace_name: ${{ inputs.workspace_name }}
secrets: inherit
deploy-web:
if: ${{ inputs.deploy_web }}
# deploy-web:
# if: ${{ inputs.deploy_web }}
needs: publish
# needs: publish
name: Deploy Web
uses: standardnotes/server/.github/workflows/common-deploy.yml@main
with:
service_name: ${{ inputs.service_name }}
docker_image: ${{ inputs.service_name }}:${{ github.sha }}
secrets: inherit
# name: Deploy Web
# uses: standardnotes/server/.github/workflows/common-deploy.yml@main
# with:
# service_name: ${{ inputs.service_name }}
# docker_image: ${{ inputs.service_name }}:${{ github.sha }}
# secrets: inherit
deploy-worker:
if: ${{ inputs.deploy_worker }}
# deploy-worker:
# if: ${{ inputs.deploy_worker }}
needs: publish
# needs: publish
name: Deploy Worker
uses: standardnotes/server/.github/workflows/common-deploy.yml@main
with:
service_name: ${{ inputs.service_name }}-worker
docker_image: ${{ inputs.service_name }}:${{ github.sha }}
secrets: inherit
# name: Deploy Worker
# uses: standardnotes/server/.github/workflows/common-deploy.yml@main
# with:
# service_name: ${{ inputs.service_name }}-worker
# docker_image: ${{ inputs.service_name }}:${{ github.sha }}
# secrets: inherit

View File

@@ -70,7 +70,8 @@ jobs:
echo "ACCESS_TOKEN_AGE=4" >> packages/home-server/.env
echo "REFRESH_TOKEN_AGE=10" >> packages/home-server/.env
echo "REVISIONS_FREQUENCY=2" >> packages/home-server/.env
echo "CONTENT_SIZE_TRANSFER_LIMIT=1000000" >> packages/home-server/.env
echo "CONTENT_SIZE_TRANSFER_LIMIT=100000" >> packages/home-server/.env
echo "HTTP_REQUEST_PAYLOAD_LIMIT_MEGABYTES=1" >> packages/home-server/.env
echo "DB_HOST=localhost" >> packages/home-server/.env
echo "DB_PORT=3306" >> packages/home-server/.env
echo "DB_DATABASE=standardnotes" >> packages/home-server/.env

View File

@@ -98,30 +98,32 @@ jobs:
- name: Test
run: yarn test
e2e-base:
needs: build
name: E2E Base Suite
uses: standardnotes/server/.github/workflows/common-e2e.yml@main
with:
snjs_image_tag: 'latest'
suite: 'base'
# e2e-base:
# needs: build
# name: E2E Base Suite
# uses: standardnotes/server/.github/workflows/common-e2e.yml@main
# with:
# snjs_image_tag: 'latest'
# suite: 'base'
e2e-vaults:
needs: build
name: E2E Vaults Suite
uses: standardnotes/server/.github/workflows/common-e2e.yml@main
with:
snjs_image_tag: 'latest'
suite: 'vaults'
# e2e-vaults:
# needs: build
# name: E2E Vaults Suite
# uses: standardnotes/server/.github/workflows/common-e2e.yml@main
# with:
# snjs_image_tag: 'latest'
# suite: 'vaults'
publish-self-hosting:
needs: [ test, lint, e2e-base, e2e-vaults ]
# needs: [ test, lint, e2e-base, e2e-vaults ]
needs: [ test, lint ]
name: Publish Self Hosting Docker Image
uses: standardnotes/server/.github/workflows/common-self-hosting.yml@main
secrets: inherit
publish-services:
needs: [ test, lint, e2e-base, e2e-vaults ]
# needs: [ test, lint, e2e-base, e2e-vaults ]
needs: [ test, lint ]
runs-on: ubuntu-latest

406
.pnp.cjs generated
View File

@@ -466,6 +466,54 @@ const RAW_RUNTIME_STATE =
["tslib", "npm:2.5.2"]\
],\
"linkType": "HARD"\
}],\
["npm:3.490.0", {\
"packageLocation": "./.yarn/cache/@aws-sdk-client-sns-npm-3.490.0-2cd839225d-4d8875521c.zip/node_modules/@aws-sdk/client-sns/",\
"packageDependencies": [\
["@aws-sdk/client-sns", "npm:3.490.0"],\
["@aws-crypto/sha256-browser", "npm:3.0.0"],\
["@aws-crypto/sha256-js", "npm:3.0.0"],\
["@aws-sdk/client-sts", "npm:3.490.0"],\
["@aws-sdk/core", "npm:3.490.0"],\
["@aws-sdk/credential-provider-node", "npm:3.490.0"],\
["@aws-sdk/middleware-host-header", "npm:3.489.0"],\
["@aws-sdk/middleware-logger", "npm:3.489.0"],\
["@aws-sdk/middleware-recursion-detection", "npm:3.489.0"],\
["@aws-sdk/middleware-signing", "npm:3.489.0"],\
["@aws-sdk/middleware-user-agent", "npm:3.489.0"],\
["@aws-sdk/region-config-resolver", "npm:3.489.0"],\
["@aws-sdk/types", "npm:3.489.0"],\
["@aws-sdk/util-endpoints", "npm:3.489.0"],\
["@aws-sdk/util-user-agent-browser", "npm:3.489.0"],\
["@aws-sdk/util-user-agent-node", "virtual:26ec4a89785e0643103d1dd3b2a86d8c63d7fd76dbfb0e516f1dc429fef4581a7306b382504a8b85e8fb995888356d6341786deec607cb64b29957c728540295#npm:3.489.0"],\
["@smithy/config-resolver", "npm:2.0.23"],\
["@smithy/core", "npm:1.2.2"],\
["@smithy/fetch-http-handler", "npm:2.3.2"],\
["@smithy/hash-node", "npm:2.0.18"],\
["@smithy/invalid-dependency", "npm:2.0.16"],\
["@smithy/middleware-content-length", "npm:2.0.18"],\
["@smithy/middleware-endpoint", "npm:2.3.0"],\
["@smithy/middleware-retry", "npm:2.0.26"],\
["@smithy/middleware-serde", "npm:2.0.16"],\
["@smithy/middleware-stack", "npm:2.0.10"],\
["@smithy/node-config-provider", "npm:2.1.9"],\
["@smithy/node-http-handler", "npm:2.2.2"],\
["@smithy/protocol-http", "npm:3.0.12"],\
["@smithy/smithy-client", "npm:2.2.1"],\
["@smithy/types", "npm:2.8.0"],\
["@smithy/url-parser", "npm:2.0.16"],\
["@smithy/util-base64", "npm:2.0.1"],\
["@smithy/util-body-length-browser", "npm:2.0.1"],\
["@smithy/util-body-length-node", "npm:2.1.0"],\
["@smithy/util-defaults-mode-browser", "npm:2.0.24"],\
["@smithy/util-defaults-mode-node", "npm:2.0.32"],\
["@smithy/util-endpoints", "npm:1.0.8"],\
["@smithy/util-retry", "npm:2.0.9"],\
["@smithy/util-utf8", "npm:2.0.2"],\
["fast-xml-parser", "npm:4.2.5"],\
["tslib", "npm:2.5.2"]\
],\
"linkType": "HARD"\
}]\
]],\
["@aws-sdk/client-sqs", [\
@@ -607,6 +655,50 @@ const RAW_RUNTIME_STATE =
["tslib", "npm:2.5.2"]\
],\
"linkType": "HARD"\
}],\
["npm:3.490.0", {\
"packageLocation": "./.yarn/cache/@aws-sdk-client-sso-npm-3.490.0-26ec4a8978-785147e3c2.zip/node_modules/@aws-sdk/client-sso/",\
"packageDependencies": [\
["@aws-sdk/client-sso", "npm:3.490.0"],\
["@aws-crypto/sha256-browser", "npm:3.0.0"],\
["@aws-crypto/sha256-js", "npm:3.0.0"],\
["@aws-sdk/core", "npm:3.490.0"],\
["@aws-sdk/middleware-host-header", "npm:3.489.0"],\
["@aws-sdk/middleware-logger", "npm:3.489.0"],\
["@aws-sdk/middleware-recursion-detection", "npm:3.489.0"],\
["@aws-sdk/middleware-user-agent", "npm:3.489.0"],\
["@aws-sdk/region-config-resolver", "npm:3.489.0"],\
["@aws-sdk/types", "npm:3.489.0"],\
["@aws-sdk/util-endpoints", "npm:3.489.0"],\
["@aws-sdk/util-user-agent-browser", "npm:3.489.0"],\
["@aws-sdk/util-user-agent-node", "virtual:26ec4a89785e0643103d1dd3b2a86d8c63d7fd76dbfb0e516f1dc429fef4581a7306b382504a8b85e8fb995888356d6341786deec607cb64b29957c728540295#npm:3.489.0"],\
["@smithy/config-resolver", "npm:2.0.23"],\
["@smithy/core", "npm:1.2.2"],\
["@smithy/fetch-http-handler", "npm:2.3.2"],\
["@smithy/hash-node", "npm:2.0.18"],\
["@smithy/invalid-dependency", "npm:2.0.16"],\
["@smithy/middleware-content-length", "npm:2.0.18"],\
["@smithy/middleware-endpoint", "npm:2.3.0"],\
["@smithy/middleware-retry", "npm:2.0.26"],\
["@smithy/middleware-serde", "npm:2.0.16"],\
["@smithy/middleware-stack", "npm:2.0.10"],\
["@smithy/node-config-provider", "npm:2.1.9"],\
["@smithy/node-http-handler", "npm:2.2.2"],\
["@smithy/protocol-http", "npm:3.0.12"],\
["@smithy/smithy-client", "npm:2.2.1"],\
["@smithy/types", "npm:2.8.0"],\
["@smithy/url-parser", "npm:2.0.16"],\
["@smithy/util-base64", "npm:2.0.1"],\
["@smithy/util-body-length-browser", "npm:2.0.1"],\
["@smithy/util-body-length-node", "npm:2.1.0"],\
["@smithy/util-defaults-mode-browser", "npm:2.0.24"],\
["@smithy/util-defaults-mode-node", "npm:2.0.32"],\
["@smithy/util-endpoints", "npm:1.0.8"],\
["@smithy/util-retry", "npm:2.0.9"],\
["@smithy/util-utf8", "npm:2.0.2"],\
["tslib", "npm:2.5.2"]\
],\
"linkType": "HARD"\
}]\
]],\
["@aws-sdk/client-sts", [\
@@ -703,6 +795,53 @@ const RAW_RUNTIME_STATE =
["tslib", "npm:2.5.2"]\
],\
"linkType": "HARD"\
}],\
["npm:3.490.0", {\
"packageLocation": "./.yarn/cache/@aws-sdk-client-sts-npm-3.490.0-f3cd7f7c70-19d1b98694.zip/node_modules/@aws-sdk/client-sts/",\
"packageDependencies": [\
["@aws-sdk/client-sts", "npm:3.490.0"],\
["@aws-crypto/sha256-browser", "npm:3.0.0"],\
["@aws-crypto/sha256-js", "npm:3.0.0"],\
["@aws-sdk/core", "npm:3.490.0"],\
["@aws-sdk/credential-provider-node", "npm:3.490.0"],\
["@aws-sdk/middleware-host-header", "npm:3.489.0"],\
["@aws-sdk/middleware-logger", "npm:3.489.0"],\
["@aws-sdk/middleware-recursion-detection", "npm:3.489.0"],\
["@aws-sdk/middleware-user-agent", "npm:3.489.0"],\
["@aws-sdk/region-config-resolver", "npm:3.489.0"],\
["@aws-sdk/types", "npm:3.489.0"],\
["@aws-sdk/util-endpoints", "npm:3.489.0"],\
["@aws-sdk/util-user-agent-browser", "npm:3.489.0"],\
["@aws-sdk/util-user-agent-node", "virtual:26ec4a89785e0643103d1dd3b2a86d8c63d7fd76dbfb0e516f1dc429fef4581a7306b382504a8b85e8fb995888356d6341786deec607cb64b29957c728540295#npm:3.489.0"],\
["@smithy/config-resolver", "npm:2.0.23"],\
["@smithy/core", "npm:1.2.2"],\
["@smithy/fetch-http-handler", "npm:2.3.2"],\
["@smithy/hash-node", "npm:2.0.18"],\
["@smithy/invalid-dependency", "npm:2.0.16"],\
["@smithy/middleware-content-length", "npm:2.0.18"],\
["@smithy/middleware-endpoint", "npm:2.3.0"],\
["@smithy/middleware-retry", "npm:2.0.26"],\
["@smithy/middleware-serde", "npm:2.0.16"],\
["@smithy/middleware-stack", "npm:2.0.10"],\
["@smithy/node-config-provider", "npm:2.1.9"],\
["@smithy/node-http-handler", "npm:2.2.2"],\
["@smithy/protocol-http", "npm:3.0.12"],\
["@smithy/smithy-client", "npm:2.2.1"],\
["@smithy/types", "npm:2.8.0"],\
["@smithy/url-parser", "npm:2.0.16"],\
["@smithy/util-base64", "npm:2.0.1"],\
["@smithy/util-body-length-browser", "npm:2.0.1"],\
["@smithy/util-body-length-node", "npm:2.1.0"],\
["@smithy/util-defaults-mode-browser", "npm:2.0.24"],\
["@smithy/util-defaults-mode-node", "npm:2.0.32"],\
["@smithy/util-endpoints", "npm:1.0.8"],\
["@smithy/util-middleware", "npm:2.0.9"],\
["@smithy/util-retry", "npm:2.0.9"],\
["@smithy/util-utf8", "npm:2.0.2"],\
["fast-xml-parser", "npm:4.2.5"],\
["tslib", "npm:2.5.2"]\
],\
"linkType": "HARD"\
}]\
]],\
["@aws-sdk/core", [\
@@ -731,6 +870,19 @@ const RAW_RUNTIME_STATE =
["tslib", "npm:2.5.2"]\
],\
"linkType": "HARD"\
}],\
["npm:3.490.0", {\
"packageLocation": "./.yarn/cache/@aws-sdk-core-npm-3.490.0-3725a806be-3e81f37825.zip/node_modules/@aws-sdk/core/",\
"packageDependencies": [\
["@aws-sdk/core", "npm:3.490.0"],\
["@smithy/core", "npm:1.2.2"],\
["@smithy/protocol-http", "npm:3.0.12"],\
["@smithy/signature-v4", "npm:2.0.5"],\
["@smithy/smithy-client", "npm:2.2.1"],\
["@smithy/types", "npm:2.8.0"],\
["tslib", "npm:2.5.2"]\
],\
"linkType": "HARD"\
}]\
]],\
["@aws-sdk/credential-provider-env", [\
@@ -755,6 +907,17 @@ const RAW_RUNTIME_STATE =
["tslib", "npm:2.5.2"]\
],\
"linkType": "HARD"\
}],\
["npm:3.489.0", {\
"packageLocation": "./.yarn/cache/@aws-sdk-credential-provider-env-npm-3.489.0-e86b20f5e4-95ab96ee49.zip/node_modules/@aws-sdk/credential-provider-env/",\
"packageDependencies": [\
["@aws-sdk/credential-provider-env", "npm:3.489.0"],\
["@aws-sdk/types", "npm:3.489.0"],\
["@smithy/property-provider", "npm:2.0.5"],\
["@smithy/types", "npm:2.8.0"],\
["tslib", "npm:2.5.2"]\
],\
"linkType": "HARD"\
}]\
]],\
["@aws-sdk/credential-provider-ini", [\
@@ -791,6 +954,23 @@ const RAW_RUNTIME_STATE =
["tslib", "npm:2.5.2"]\
],\
"linkType": "HARD"\
}],\
["npm:3.490.0", {\
"packageLocation": "./.yarn/cache/@aws-sdk-credential-provider-ini-npm-3.490.0-51f9d0faff-4e4cd2633a.zip/node_modules/@aws-sdk/credential-provider-ini/",\
"packageDependencies": [\
["@aws-sdk/credential-provider-ini", "npm:3.490.0"],\
["@aws-sdk/credential-provider-env", "npm:3.489.0"],\
["@aws-sdk/credential-provider-process", "npm:3.489.0"],\
["@aws-sdk/credential-provider-sso", "npm:3.490.0"],\
["@aws-sdk/credential-provider-web-identity", "npm:3.489.0"],\
["@aws-sdk/types", "npm:3.489.0"],\
["@smithy/credential-provider-imds", "npm:2.0.5"],\
["@smithy/property-provider", "npm:2.0.5"],\
["@smithy/shared-ini-file-loader", "npm:2.0.6"],\
["@smithy/types", "npm:2.8.0"],\
["tslib", "npm:2.5.2"]\
],\
"linkType": "HARD"\
}]\
]],\
["@aws-sdk/credential-provider-node", [\
@@ -829,6 +1009,24 @@ const RAW_RUNTIME_STATE =
["tslib", "npm:2.5.2"]\
],\
"linkType": "HARD"\
}],\
["npm:3.490.0", {\
"packageLocation": "./.yarn/cache/@aws-sdk-credential-provider-node-npm-3.490.0-3cbe0ec5e6-2f8141c3e1.zip/node_modules/@aws-sdk/credential-provider-node/",\
"packageDependencies": [\
["@aws-sdk/credential-provider-node", "npm:3.490.0"],\
["@aws-sdk/credential-provider-env", "npm:3.489.0"],\
["@aws-sdk/credential-provider-ini", "npm:3.490.0"],\
["@aws-sdk/credential-provider-process", "npm:3.489.0"],\
["@aws-sdk/credential-provider-sso", "npm:3.490.0"],\
["@aws-sdk/credential-provider-web-identity", "npm:3.489.0"],\
["@aws-sdk/types", "npm:3.489.0"],\
["@smithy/credential-provider-imds", "npm:2.0.5"],\
["@smithy/property-provider", "npm:2.0.5"],\
["@smithy/shared-ini-file-loader", "npm:2.0.6"],\
["@smithy/types", "npm:2.8.0"],\
["tslib", "npm:2.5.2"]\
],\
"linkType": "HARD"\
}]\
]],\
["@aws-sdk/credential-provider-process", [\
@@ -855,6 +1053,18 @@ const RAW_RUNTIME_STATE =
["tslib", "npm:2.5.2"]\
],\
"linkType": "HARD"\
}],\
["npm:3.489.0", {\
"packageLocation": "./.yarn/cache/@aws-sdk-credential-provider-process-npm-3.489.0-9370bfd061-42f4f5f21d.zip/node_modules/@aws-sdk/credential-provider-process/",\
"packageDependencies": [\
["@aws-sdk/credential-provider-process", "npm:3.489.0"],\
["@aws-sdk/types", "npm:3.489.0"],\
["@smithy/property-provider", "npm:2.0.5"],\
["@smithy/shared-ini-file-loader", "npm:2.0.6"],\
["@smithy/types", "npm:2.8.0"],\
["tslib", "npm:2.5.2"]\
],\
"linkType": "HARD"\
}]\
]],\
["@aws-sdk/credential-provider-sso", [\
@@ -885,6 +1095,20 @@ const RAW_RUNTIME_STATE =
["tslib", "npm:2.5.2"]\
],\
"linkType": "HARD"\
}],\
["npm:3.490.0", {\
"packageLocation": "./.yarn/cache/@aws-sdk-credential-provider-sso-npm-3.490.0-9acb6828c0-ef2eff8fbc.zip/node_modules/@aws-sdk/credential-provider-sso/",\
"packageDependencies": [\
["@aws-sdk/credential-provider-sso", "npm:3.490.0"],\
["@aws-sdk/client-sso", "npm:3.490.0"],\
["@aws-sdk/token-providers", "npm:3.489.0"],\
["@aws-sdk/types", "npm:3.489.0"],\
["@smithy/property-provider", "npm:2.0.5"],\
["@smithy/shared-ini-file-loader", "npm:2.0.6"],\
["@smithy/types", "npm:2.8.0"],\
["tslib", "npm:2.5.2"]\
],\
"linkType": "HARD"\
}]\
]],\
["@aws-sdk/credential-provider-web-identity", [\
@@ -909,6 +1133,17 @@ const RAW_RUNTIME_STATE =
["tslib", "npm:2.5.2"]\
],\
"linkType": "HARD"\
}],\
["npm:3.489.0", {\
"packageLocation": "./.yarn/cache/@aws-sdk-credential-provider-web-identity-npm-3.489.0-002a8c8ade-911bc3fd28.zip/node_modules/@aws-sdk/credential-provider-web-identity/",\
"packageDependencies": [\
["@aws-sdk/credential-provider-web-identity", "npm:3.489.0"],\
["@aws-sdk/types", "npm:3.489.0"],\
["@smithy/property-provider", "npm:2.0.5"],\
["@smithy/types", "npm:2.8.0"],\
["tslib", "npm:2.5.2"]\
],\
"linkType": "HARD"\
}]\
]],\
["@aws-sdk/middleware-bucket-endpoint", [\
@@ -979,6 +1214,17 @@ const RAW_RUNTIME_STATE =
["tslib", "npm:2.5.2"]\
],\
"linkType": "HARD"\
}],\
["npm:3.489.0", {\
"packageLocation": "./.yarn/cache/@aws-sdk-middleware-host-header-npm-3.489.0-10c65ea2e3-3f80f71691.zip/node_modules/@aws-sdk/middleware-host-header/",\
"packageDependencies": [\
["@aws-sdk/middleware-host-header", "npm:3.489.0"],\
["@aws-sdk/types", "npm:3.489.0"],\
["@smithy/protocol-http", "npm:3.0.12"],\
["@smithy/types", "npm:2.8.0"],\
["tslib", "npm:2.5.2"]\
],\
"linkType": "HARD"\
}]\
]],\
["@aws-sdk/middleware-location-constraint", [\
@@ -1013,6 +1259,16 @@ const RAW_RUNTIME_STATE =
["tslib", "npm:2.5.2"]\
],\
"linkType": "HARD"\
}],\
["npm:3.489.0", {\
"packageLocation": "./.yarn/cache/@aws-sdk-middleware-logger-npm-3.489.0-ba04fd0161-0bbf9d08c7.zip/node_modules/@aws-sdk/middleware-logger/",\
"packageDependencies": [\
["@aws-sdk/middleware-logger", "npm:3.489.0"],\
["@aws-sdk/types", "npm:3.489.0"],\
["@smithy/types", "npm:2.8.0"],\
["tslib", "npm:2.5.2"]\
],\
"linkType": "HARD"\
}]\
]],\
["@aws-sdk/middleware-recursion-detection", [\
@@ -1037,6 +1293,17 @@ const RAW_RUNTIME_STATE =
["tslib", "npm:2.5.2"]\
],\
"linkType": "HARD"\
}],\
["npm:3.489.0", {\
"packageLocation": "./.yarn/cache/@aws-sdk-middleware-recursion-detection-npm-3.489.0-2cefe5fc6b-91eb0b3b46.zip/node_modules/@aws-sdk/middleware-recursion-detection/",\
"packageDependencies": [\
["@aws-sdk/middleware-recursion-detection", "npm:3.489.0"],\
["@aws-sdk/types", "npm:3.489.0"],\
["@smithy/protocol-http", "npm:3.0.12"],\
["@smithy/types", "npm:2.8.0"],\
["tslib", "npm:2.5.2"]\
],\
"linkType": "HARD"\
}]\
]],\
["@aws-sdk/middleware-sdk-s3", [\
@@ -1099,6 +1366,20 @@ const RAW_RUNTIME_STATE =
["tslib", "npm:2.5.2"]\
],\
"linkType": "HARD"\
}],\
["npm:3.489.0", {\
"packageLocation": "./.yarn/cache/@aws-sdk-middleware-signing-npm-3.489.0-722d97a2fd-6fedba4569.zip/node_modules/@aws-sdk/middleware-signing/",\
"packageDependencies": [\
["@aws-sdk/middleware-signing", "npm:3.489.0"],\
["@aws-sdk/types", "npm:3.489.0"],\
["@smithy/property-provider", "npm:2.0.5"],\
["@smithy/protocol-http", "npm:3.0.12"],\
["@smithy/signature-v4", "npm:2.0.5"],\
["@smithy/types", "npm:2.8.0"],\
["@smithy/util-middleware", "npm:2.0.9"],\
["tslib", "npm:2.5.2"]\
],\
"linkType": "HARD"\
}]\
]],\
["@aws-sdk/middleware-ssec", [\
@@ -1137,6 +1418,18 @@ const RAW_RUNTIME_STATE =
["tslib", "npm:2.5.2"]\
],\
"linkType": "HARD"\
}],\
["npm:3.489.0", {\
"packageLocation": "./.yarn/cache/@aws-sdk-middleware-user-agent-npm-3.489.0-4a9e57c5ff-51fc7a8a03.zip/node_modules/@aws-sdk/middleware-user-agent/",\
"packageDependencies": [\
["@aws-sdk/middleware-user-agent", "npm:3.489.0"],\
["@aws-sdk/types", "npm:3.489.0"],\
["@aws-sdk/util-endpoints", "npm:3.489.0"],\
["@smithy/protocol-http", "npm:3.0.12"],\
["@smithy/types", "npm:2.8.0"],\
["tslib", "npm:2.5.2"]\
],\
"linkType": "HARD"\
}]\
]],\
["@aws-sdk/region-config-resolver", [\
@@ -1163,6 +1456,19 @@ const RAW_RUNTIME_STATE =
["tslib", "npm:2.5.2"]\
],\
"linkType": "HARD"\
}],\
["npm:3.489.0", {\
"packageLocation": "./.yarn/cache/@aws-sdk-region-config-resolver-npm-3.489.0-0721047a4a-045a630c94.zip/node_modules/@aws-sdk/region-config-resolver/",\
"packageDependencies": [\
["@aws-sdk/region-config-resolver", "npm:3.489.0"],\
["@aws-sdk/types", "npm:3.489.0"],\
["@smithy/node-config-provider", "npm:2.1.9"],\
["@smithy/types", "npm:2.8.0"],\
["@smithy/util-config-provider", "npm:2.1.0"],\
["@smithy/util-middleware", "npm:2.0.9"],\
["tslib", "npm:2.5.2"]\
],\
"linkType": "HARD"\
}]\
]],\
["@aws-sdk/signature-v4-multi-region", [\
@@ -1268,6 +1574,50 @@ const RAW_RUNTIME_STATE =
["tslib", "npm:2.5.2"]\
],\
"linkType": "HARD"\
}],\
["npm:3.489.0", {\
"packageLocation": "./.yarn/cache/@aws-sdk-token-providers-npm-3.489.0-05002406d6-ee7a20eff7.zip/node_modules/@aws-sdk/token-providers/",\
"packageDependencies": [\
["@aws-sdk/token-providers", "npm:3.489.0"],\
["@aws-crypto/sha256-browser", "npm:3.0.0"],\
["@aws-crypto/sha256-js", "npm:3.0.0"],\
["@aws-sdk/middleware-host-header", "npm:3.489.0"],\
["@aws-sdk/middleware-logger", "npm:3.489.0"],\
["@aws-sdk/middleware-recursion-detection", "npm:3.489.0"],\
["@aws-sdk/middleware-user-agent", "npm:3.489.0"],\
["@aws-sdk/region-config-resolver", "npm:3.489.0"],\
["@aws-sdk/types", "npm:3.489.0"],\
["@aws-sdk/util-endpoints", "npm:3.489.0"],\
["@aws-sdk/util-user-agent-browser", "npm:3.489.0"],\
["@aws-sdk/util-user-agent-node", "virtual:26ec4a89785e0643103d1dd3b2a86d8c63d7fd76dbfb0e516f1dc429fef4581a7306b382504a8b85e8fb995888356d6341786deec607cb64b29957c728540295#npm:3.489.0"],\
["@smithy/config-resolver", "npm:2.0.23"],\
["@smithy/fetch-http-handler", "npm:2.3.2"],\
["@smithy/hash-node", "npm:2.0.18"],\
["@smithy/invalid-dependency", "npm:2.0.16"],\
["@smithy/middleware-content-length", "npm:2.0.18"],\
["@smithy/middleware-endpoint", "npm:2.3.0"],\
["@smithy/middleware-retry", "npm:2.0.26"],\
["@smithy/middleware-serde", "npm:2.0.16"],\
["@smithy/middleware-stack", "npm:2.0.10"],\
["@smithy/node-config-provider", "npm:2.1.9"],\
["@smithy/node-http-handler", "npm:2.2.2"],\
["@smithy/property-provider", "npm:2.0.5"],\
["@smithy/protocol-http", "npm:3.0.12"],\
["@smithy/shared-ini-file-loader", "npm:2.0.6"],\
["@smithy/smithy-client", "npm:2.2.1"],\
["@smithy/types", "npm:2.8.0"],\
["@smithy/url-parser", "npm:2.0.16"],\
["@smithy/util-base64", "npm:2.0.1"],\
["@smithy/util-body-length-browser", "npm:2.0.1"],\
["@smithy/util-body-length-node", "npm:2.1.0"],\
["@smithy/util-defaults-mode-browser", "npm:2.0.24"],\
["@smithy/util-defaults-mode-node", "npm:2.0.32"],\
["@smithy/util-endpoints", "npm:1.0.8"],\
["@smithy/util-retry", "npm:2.0.9"],\
["@smithy/util-utf8", "npm:2.0.2"],\
["tslib", "npm:2.5.2"]\
],\
"linkType": "HARD"\
}]\
]],\
["@aws-sdk/types", [\
@@ -1296,6 +1646,15 @@ const RAW_RUNTIME_STATE =
["tslib", "npm:2.5.2"]\
],\
"linkType": "HARD"\
}],\
["npm:3.489.0", {\
"packageLocation": "./.yarn/cache/@aws-sdk-types-npm-3.489.0-f0f748fbaa-48778dad14.zip/node_modules/@aws-sdk/types/",\
"packageDependencies": [\
["@aws-sdk/types", "npm:3.489.0"],\
["@smithy/types", "npm:2.8.0"],\
["tslib", "npm:2.5.2"]\
],\
"linkType": "HARD"\
}]\
]],\
["@aws-sdk/util-arn-parser", [\
@@ -1328,6 +1687,17 @@ const RAW_RUNTIME_STATE =
["tslib", "npm:2.5.2"]\
],\
"linkType": "HARD"\
}],\
["npm:3.489.0", {\
"packageLocation": "./.yarn/cache/@aws-sdk-util-endpoints-npm-3.489.0-1f2dd7e944-68f921982f.zip/node_modules/@aws-sdk/util-endpoints/",\
"packageDependencies": [\
["@aws-sdk/util-endpoints", "npm:3.489.0"],\
["@aws-sdk/types", "npm:3.489.0"],\
["@smithy/types", "npm:2.8.0"],\
["@smithy/util-endpoints", "npm:1.0.8"],\
["tslib", "npm:2.5.2"]\
],\
"linkType": "HARD"\
}]\
]],\
["@aws-sdk/util-locate-window", [\
@@ -1362,6 +1732,17 @@ const RAW_RUNTIME_STATE =
["tslib", "npm:2.5.2"]\
],\
"linkType": "HARD"\
}],\
["npm:3.489.0", {\
"packageLocation": "./.yarn/cache/@aws-sdk-util-user-agent-browser-npm-3.489.0-ffb94f7b1d-2bb414b8d8.zip/node_modules/@aws-sdk/util-user-agent-browser/",\
"packageDependencies": [\
["@aws-sdk/util-user-agent-browser", "npm:3.489.0"],\
["@aws-sdk/types", "npm:3.489.0"],\
["@smithy/types", "npm:2.8.0"],\
["bowser", "npm:2.11.0"],\
["tslib", "npm:2.5.2"]\
],\
"linkType": "HARD"\
}]\
]],\
["@aws-sdk/util-user-agent-node", [\
@@ -1379,6 +1760,30 @@ const RAW_RUNTIME_STATE =
],\
"linkType": "SOFT"\
}],\
["npm:3.489.0", {\
"packageLocation": "./.yarn/cache/@aws-sdk-util-user-agent-node-npm-3.489.0-082349e8a9-95dc1e07b6.zip/node_modules/@aws-sdk/util-user-agent-node/",\
"packageDependencies": [\
["@aws-sdk/util-user-agent-node", "npm:3.489.0"]\
],\
"linkType": "SOFT"\
}],\
["virtual:26ec4a89785e0643103d1dd3b2a86d8c63d7fd76dbfb0e516f1dc429fef4581a7306b382504a8b85e8fb995888356d6341786deec607cb64b29957c728540295#npm:3.489.0", {\
"packageLocation": "./.yarn/__virtual__/@aws-sdk-util-user-agent-node-virtual-73c334651c/0/cache/@aws-sdk-util-user-agent-node-npm-3.489.0-082349e8a9-95dc1e07b6.zip/node_modules/@aws-sdk/util-user-agent-node/",\
"packageDependencies": [\
["@aws-sdk/util-user-agent-node", "virtual:26ec4a89785e0643103d1dd3b2a86d8c63d7fd76dbfb0e516f1dc429fef4581a7306b382504a8b85e8fb995888356d6341786deec607cb64b29957c728540295#npm:3.489.0"],\
["@aws-sdk/types", "npm:3.489.0"],\
["@smithy/node-config-provider", "npm:2.1.9"],\
["@smithy/types", "npm:2.8.0"],\
["@types/aws-crt", null],\
["aws-crt", null],\
["tslib", "npm:2.5.2"]\
],\
"packagePeers": [\
"@types/aws-crt",\
"aws-crt"\
],\
"linkType": "HARD"\
}],\
["virtual:5f6733bd23aee10dd05576af160f1b93e0bb4a20b288e9b818dc0b69bdb08ea1a09d5836816f02bdafc9c01487816ae339c6b680c2f7849dfe249436c5f2b499#npm:3.485.0", {\
"packageLocation": "./.yarn/__virtual__/@aws-sdk-util-user-agent-node-virtual-c26ab353dd/0/cache/@aws-sdk-util-user-agent-node-npm-3.485.0-7991a74cb3-e2805ef37b.zip/node_modules/@aws-sdk/util-user-agent-node/",\
"packageDependencies": [\
@@ -5983,6 +6388,7 @@ const RAW_RUNTIME_STATE =
"packageLocation": "./packages/api-gateway/",\
"packageDependencies": [\
["@standardnotes/api-gateway", "workspace:packages/api-gateway"],\
["@aws-sdk/client-sns", "npm:3.490.0"],\
["@grpc/grpc-js", "npm:1.9.13"],\
["@standardnotes/domain-core", "workspace:packages/domain-core"],\
["@standardnotes/domain-events", "workspace:packages/domain-events"],\

Binary file not shown.

Binary file not shown.

View File

@@ -3,6 +3,14 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [2.34.16](https://github.com/standardnotes/server/compare/@standardnotes/analytics@2.34.15...@standardnotes/analytics@2.34.16) (2024-01-19)
**Note:** Version bump only for package @standardnotes/analytics
## [2.34.15](https://github.com/standardnotes/server/compare/@standardnotes/analytics@2.34.14...@standardnotes/analytics@2.34.15) (2024-01-18)
**Note:** Version bump only for package @standardnotes/analytics
## [2.34.14](https://github.com/standardnotes/server/compare/@standardnotes/analytics@2.34.13...@standardnotes/analytics@2.34.14) (2024-01-04)
**Note:** Version bump only for package @standardnotes/analytics

View File

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

View File

@@ -3,6 +3,46 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
# [1.91.0](https://github.com/standardnotes/server/compare/@standardnotes/api-gateway@1.90.3...@standardnotes/api-gateway@1.91.0) (2024-03-20)
### Features
* add CORS_ORIGIN_STRICT_MODE_ENABLED env var to determine if CORS origin should be restricted ([5c02435](https://github.com/standardnotes/server/commit/5c02435ee478b893747d3f9e41062aae12d7ff10))
## [1.90.3](https://github.com/standardnotes/server/compare/@standardnotes/api-gateway@1.90.2...@standardnotes/api-gateway@1.90.3) (2024-03-18)
### Bug Fixes
* **api-gateway:** response headers cors issue - fixes [#1046](https://github.com/standardnotes/server/issues/1046) ([be668d7](https://github.com/standardnotes/server/commit/be668d7d7a1d9128f625a2bfa807e6a91183b488))
## [1.90.2](https://github.com/standardnotes/server/compare/@standardnotes/api-gateway@1.90.1...@standardnotes/api-gateway@1.90.2) (2024-03-18)
### Bug Fixes
* cors issues on clients - fixes [#1046](https://github.com/standardnotes/server/issues/1046) ([#1049](https://github.com/standardnotes/server/issues/1049)) ([6d7ca1b](https://github.com/standardnotes/server/commit/6d7ca1b926fd45d744275bd3c1f4c05b010f76c8))
## [1.90.1](https://github.com/standardnotes/server/compare/@standardnotes/api-gateway@1.90.0...@standardnotes/api-gateway@1.90.1) (2024-01-19)
**Note:** Version bump only for package @standardnotes/api-gateway
# [1.90.0](https://github.com/standardnotes/server/compare/@standardnotes/api-gateway@1.89.20...@standardnotes/api-gateway@1.90.0) (2024-01-18)
### Features
* add content sizes fixing upon grpc resource exhausted error ([#1029](https://github.com/standardnotes/server/issues/1029)) ([634e8bd](https://github.com/standardnotes/server/commit/634e8bd2d0f055abbda1150587ab9a444281e600))
## [1.89.20](https://github.com/standardnotes/server/compare/@standardnotes/api-gateway@1.89.19...@standardnotes/api-gateway@1.89.20) (2024-01-18)
### Bug Fixes
* **api-gateway:** add codetag metadata to error logs ([136cf25](https://github.com/standardnotes/server/commit/136cf252a134efe7d99f79d8622c43dbebbb5ac8))
## [1.89.19](https://github.com/standardnotes/server/compare/@standardnotes/api-gateway@1.89.18...@standardnotes/api-gateway@1.89.19) (2024-01-10)
### Bug Fixes
* add dedicated http code response upon a request with too large payload ([#1019](https://github.com/standardnotes/server/issues/1019)) ([6062f85](https://github.com/standardnotes/server/commit/6062f850000477983315d2d9b7c913956f755ebb))
## [1.89.18](https://github.com/standardnotes/server/compare/@standardnotes/api-gateway@1.89.17...@standardnotes/api-gateway@1.89.18) (2024-01-08)
**Note:** Version bump only for package @standardnotes/api-gateway

View File

@@ -43,6 +43,10 @@ void container.load().then((container) => {
const env: Env = new Env()
env.load()
const requestPayloadLimit = env.get('HTTP_REQUEST_PAYLOAD_LIMIT_MEGABYTES', true)
? `${+env.get('HTTP_REQUEST_PAYLOAD_LIMIT_MEGABYTES', true)}mb`
: '50mb'
const server = new InversifyExpressServer(container)
server.setConfig((app) => {
@@ -73,13 +77,57 @@ void container.load().then((container) => {
}),
)
app.use(json({ limit: '50mb' }))
app.use(json({ limit: requestPayloadLimit }))
app.use(
text({
type: ['text/plain', 'application/x-www-form-urlencoded', 'application/x-www-form-urlencoded; charset=utf-8'],
}),
)
app.use(cors())
const corsAllowedOrigins = env.get('CORS_ALLOWED_ORIGINS', true)
? env.get('CORS_ALLOWED_ORIGINS', true).split(',')
: []
app.use(
cors({
credentials: true,
exposedHeaders: ['x-captcha-required'],
origin: (requestOrigin: string | undefined, callback: (err: Error | null, origin?: string[]) => void) => {
const originStrictModeEnabled = env.get('CORS_ORIGIN_STRICT_MODE_ENABLED', true)
? env.get('CORS_ORIGIN_STRICT_MODE_ENABLED', true) === 'true'
: false
if (!originStrictModeEnabled) {
callback(null, [requestOrigin as string])
return
}
const requstOriginIsNotFilled = !requestOrigin || requestOrigin === 'null'
const requestOriginatesFromTheDesktopApp = requestOrigin?.startsWith('file://')
const requestOriginatesFromClipperForFirefox = requestOrigin?.startsWith('moz-extension://')
const requestOriginatesFromSelfHostedAppOnHttpPort = requestOrigin === 'http://localhost'
const requestOriginatesFromSelfHostedAppOnCustomPort = requestOrigin?.match(/http:\/\/localhost:\d+/) !== null
const requestOriginatesFromSelfHostedApp =
requestOriginatesFromSelfHostedAppOnHttpPort || requestOriginatesFromSelfHostedAppOnCustomPort
const requestIsWhitelisted =
corsAllowedOrigins.length === 0 ||
requstOriginIsNotFilled ||
requestOriginatesFromTheDesktopApp ||
requestOriginatesFromClipperForFirefox ||
requestOriginatesFromSelfHostedApp
if (requestIsWhitelisted) {
callback(null, [requestOrigin as string])
} else {
if (corsAllowedOrigins.includes(requestOrigin)) {
callback(null, [requestOrigin])
} else {
callback(new Error('Not allowed by CORS', { cause: 'origin not allowed' }))
}
}
},
}),
)
app.use(
robots({
UserAgent: '*',
@@ -95,6 +143,7 @@ void container.load().then((container) => {
const locals = response.locals as ResponseLocals
logger.error(`${error.stack}`, {
codeTag: 'server.ts',
method: request.method,
url: request.url,
snjs: request.headers['x-snjs-version'],
@@ -107,6 +156,16 @@ void container.load().then((container) => {
}] Request body: ${JSON.stringify(request.body)}`,
)
if ('type' in error && error.type === 'entity.too.large') {
response.status(413).send({
error: {
message: 'The request payload is too large.',
},
})
return
}
response.status(500).send({
error: {
message:

View File

@@ -1,6 +1,6 @@
{
"name": "@standardnotes/api-gateway",
"version": "1.89.18",
"version": "1.91.0",
"engines": {
"node": ">=18.0.0 <21.0.0"
},
@@ -31,6 +31,7 @@
"start": "yarn node dist/bin/server.js"
},
"dependencies": {
"@aws-sdk/client-sns": "^3.490.0",
"@grpc/grpc-js": "^1.9.13",
"@standardnotes/domain-core": "workspace:^",
"@standardnotes/domain-events": "workspace:*",

View File

@@ -1,6 +1,7 @@
import * as winston from 'winston'
import * as AgentKeepAlive from 'agentkeepalive'
import * as grpc from '@grpc/grpc-js'
import { SNSClient, SNSClientConfig } from '@aws-sdk/client-sns'
import axios, { AxiosInstance } from 'axios'
import Redis from 'ioredis'
import { Container } from 'inversify'
@@ -29,6 +30,10 @@ import { SyncResponseHttpRepresentation } from '../Mapping/Sync/Http/SyncRespons
import { SyncRequestGRPCMapper } from '../Mapping/Sync/GRPC/SyncRequestGRPCMapper'
import { SyncResponseGRPCMapper } from '../Mapping/Sync/GRPC/SyncResponseGRPCMapper'
import { GRPCWebSocketAuthMiddleware } from '../Controller/GRPCWebSocketAuthMiddleware'
import { DomainEventPublisherInterface } from '@standardnotes/domain-events'
import { SNSDomainEventPublisher } from '@standardnotes/domain-events-infra'
import { DomainEventFactoryInterface } from '../Event/DomainEventFactoryInterface'
import { DomainEventFactory } from '../Event/DomainEventFactory'
export class ContainerConfigLoader {
async load(configuration?: {
@@ -51,6 +56,34 @@ export class ContainerConfigLoader {
.bind<boolean>(TYPES.ApiGateway_IS_CONFIGURED_FOR_HOME_SERVER_OR_SELF_HOSTING)
.toConstantValue(isConfiguredForHomeServerOrSelfHosting)
if (!isConfiguredForHomeServerOrSelfHosting) {
const snsConfig: SNSClientConfig = {
region: env.get('SNS_AWS_REGION', true),
}
if (env.get('SNS_ENDPOINT', true)) {
snsConfig.endpoint = env.get('SNS_ENDPOINT', true)
}
if (env.get('SNS_ACCESS_KEY_ID', true) && env.get('SNS_SECRET_ACCESS_KEY', true)) {
snsConfig.credentials = {
accessKeyId: env.get('SNS_ACCESS_KEY_ID', true),
secretAccessKey: env.get('SNS_SECRET_ACCESS_KEY', true),
}
}
const snsClient = new SNSClient(snsConfig)
container.bind<SNSClient>(TYPES.ApiGateway_SNS).toConstantValue(snsClient)
container.bind(TYPES.ApiGateway_SNS_TOPIC_ARN).toConstantValue(env.get('SNS_TOPIC_ARN', true))
container
.bind<DomainEventPublisherInterface>(TYPES.ApiGateway_DomainEventPublisher)
.toConstantValue(
new SNSDomainEventPublisher(
container.get(TYPES.ApiGateway_SNS),
container.get(TYPES.ApiGateway_SNS_TOPIC_ARN),
),
)
}
const winstonFormatters = [winston.format.splat(), winston.format.json()]
let logger: winston.Logger
@@ -192,6 +225,10 @@ export class ContainerConfigLoader {
.bind<MapperInterface<SyncResponse, SyncResponseHttpRepresentation>>(TYPES.Mapper_SyncResponseGRPCMapper)
.toConstantValue(new SyncResponseGRPCMapper())
container
.bind<DomainEventFactoryInterface>(TYPES.ApiGateway_DomainEventFactory)
.toConstantValue(new DomainEventFactory(container.get<TimerInterface>(TYPES.ApiGateway_Timer)))
container
.bind<GRPCSyncingServerServiceProxy>(TYPES.ApiGateway_GRPCSyncingServerServiceProxy)
.toConstantValue(
@@ -202,6 +239,10 @@ export class ContainerConfigLoader {
TYPES.Mapper_SyncResponseGRPCMapper,
),
container.get<winston.Logger>(TYPES.ApiGateway_Logger),
container.get<DomainEventFactoryInterface>(TYPES.ApiGateway_DomainEventFactory),
isConfiguredForHomeServerOrSelfHosting
? undefined
: container.get<DomainEventPublisherInterface>(TYPES.ApiGateway_DomainEventPublisher),
),
)
container

View File

@@ -2,7 +2,11 @@ export const TYPES = {
ApiGateway_Logger: Symbol.for('ApiGateway_Logger'),
ApiGateway_Redis: Symbol.for('ApiGateway_Redis'),
ApiGateway_HTTPClient: Symbol.for('ApiGateway_HTTPClient'),
ApiGateway_SNS: Symbol.for('ApiGateway_SNS'),
ApiGateway_DomainEventPublisher: Symbol.for('ApiGateway_DomainEventPublisher'),
// env vars
ApiGateway_SNS_TOPIC_ARN: Symbol.for('ApiGateway_SNS_TOPIC_ARN'),
ApiGateway_SNS_AWS_REGION: Symbol.for('ApiGateway_SNS_AWS_REGION'),
ApiGateway_SYNCING_SERVER_JS_URL: Symbol.for('ApiGateway_SYNCING_SERVER_JS_URL'),
ApiGateway_AUTH_SERVER_URL: Symbol.for('ApiGateway_AUTH_SERVER_URL'),
ApiGateway_AUTH_SERVER_GRPC_URL: Symbol.for('ApiGateway_AUTH_SERVER_GRPC_URL'),
@@ -29,6 +33,7 @@ export const TYPES = {
Mapper_SyncRequestGRPCMapper: Symbol.for('Mapper_SyncRequestGRPCMapper'),
Mapper_SyncResponseGRPCMapper: Symbol.for('Mapper_SyncResponseGRPCMapper'),
// Services
ApiGateway_DomainEventFactory: Symbol.for('ApiGateway_DomainEventFactory'),
ApiGateway_GRPCSyncingServerServiceProxy: Symbol.for('ApiGateway_GRPCSyncingServerServiceProxy'),
ApiGateway_ServiceProxy: Symbol.for('ApiGateway_ServiceProxy'),
ApiGateway_CrossServiceTokenCache: Symbol.for('ApiGateway_CrossServiceTokenCache'),

View File

@@ -0,0 +1,23 @@
import { TimerInterface } from '@standardnotes/time'
import { DomainEventFactoryInterface } from './DomainEventFactoryInterface'
import { ContentSizesFixRequestedEvent, DomainEventService } from '@standardnotes/domain-events'
export class DomainEventFactory implements DomainEventFactoryInterface {
constructor(private timer: TimerInterface) {}
createContentSizesFixRequestedEvent(dto: { userUuid: string }): ContentSizesFixRequestedEvent {
return {
type: 'CONTENT_SIZES_FIX_REQUESTED',
createdAt: this.timer.getUTCDate(),
meta: {
correlation: {
userIdentifier: dto.userUuid,
userIdentifierType: 'uuid',
},
origin: DomainEventService.Auth,
},
payload: dto,
}
}
}

View File

@@ -0,0 +1,5 @@
import { ContentSizesFixRequestedEvent } from '@standardnotes/domain-events'
export interface DomainEventFactoryInterface {
createContentSizesFixRequestedEvent(dto: { userUuid: string }): ContentSizesFixRequestedEvent
}

View File

@@ -340,13 +340,11 @@ export class HttpServiceProxy implements ServiceProxyInterface {
private applyResponseHeaders(serviceResponse: AxiosResponse, response: Response): void {
const returnedHeadersFromUnderlyingService = [
'access-control-allow-methods',
'access-control-allow-origin',
'access-control-expose-headers',
'authorization',
'content-type',
'x-ssjs-version',
'x-auth-version',
'authorization',
'set-cookie',
'access-control-expose-headers',
'x-captcha-required',
]
returnedHeadersFromUnderlyingService.map((headerName) => {

View File

@@ -435,13 +435,11 @@ export class GRPCServiceProxy implements ServiceProxyInterface {
private applyResponseHeaders(serviceResponse: AxiosResponse, response: Response): void {
const returnedHeadersFromUnderlyingService = [
'access-control-allow-methods',
'access-control-allow-origin',
'access-control-expose-headers',
'authorization',
'content-type',
'x-ssjs-version',
'x-auth-version',
'authorization',
'set-cookie',
'access-control-expose-headers',
'x-captcha-required',
]
returnedHeadersFromUnderlyingService.map((headerName) => {

View File

@@ -1,12 +1,14 @@
import { Request, Response } from 'express'
import { ISyncingClient, SyncRequest, SyncResponse } from '@standardnotes/grpc'
import { DomainEventPublisherInterface } from '@standardnotes/domain-events'
import { MapperInterface } from '@standardnotes/domain-core'
import { Metadata } from '@grpc/grpc-js'
import { SyncResponseHttpRepresentation } from '../../Mapping/Sync/Http/SyncResponseHttpRepresentation'
import { Status } from '@grpc/grpc-js/build/src/constants'
import { Logger } from 'winston'
import { SyncResponseHttpRepresentation } from '../../Mapping/Sync/Http/SyncResponseHttpRepresentation'
import { ResponseLocals } from '../../Controller/ResponseLocals'
import { DomainEventFactoryInterface } from '../../Event/DomainEventFactoryInterface'
export class GRPCSyncingServerServiceProxy {
constructor(
@@ -14,6 +16,8 @@ export class GRPCSyncingServerServiceProxy {
private syncRequestGRPCMapper: MapperInterface<Record<string, unknown>, SyncRequest>,
private syncResponseGRPCMapper: MapperInterface<SyncResponse, SyncResponseHttpRepresentation>,
private logger: Logger,
private domainEventFactory: DomainEventFactoryInterface,
private domainEventPublisher?: DomainEventPublisherInterface,
) {}
async sync(
@@ -59,6 +63,12 @@ export class GRPCSyncingServerServiceProxy {
})
}
if (error.code === Status.RESOURCE_EXHAUSTED && this.domainEventPublisher !== undefined) {
void this.domainEventPublisher.publish(
this.domainEventFactory.createContentSizesFixRequestedEvent({ userUuid: locals.user.uuid }),
)
}
return reject(error)
}

View File

@@ -3,6 +3,59 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.178.3](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.178.2...@standardnotes/auth-server@1.178.3) (2024-03-18)
### Bug Fixes
* **auth:** allow registration on new api versions - fixes [#1046](https://github.com/standardnotes/server/issues/1046) ([#1048](https://github.com/standardnotes/server/issues/1048)) ([f939caf](https://github.com/standardnotes/server/commit/f939caf2d9a781d42989ad6e92a5c7150ff48e19))
## [1.178.2](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.178.1...@standardnotes/auth-server@1.178.2) (2024-03-15)
### Bug Fixes
* allow handling of new api version ([9d49764](https://github.com/standardnotes/server/commit/9d49764b841e73655e19523eddf10498addc9fb4))
## [1.178.1](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.178.0...@standardnotes/auth-server@1.178.1) (2024-02-09)
### Bug Fixes
* allow expired offline subscriptions to receive dashboard emails ([#1041](https://github.com/standardnotes/server/issues/1041)) ([4fe8e9a](https://github.com/standardnotes/server/commit/4fe8e9a79f652f3e39608d6683cb17cc08bb8717))
# [1.178.0](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.177.20...@standardnotes/auth-server@1.178.0) (2024-01-19)
### Features
* **auth:** add script for fixing subscriptions with missing id state ([#1030](https://github.com/standardnotes/server/issues/1030)) ([86b0508](https://github.com/standardnotes/server/commit/86b050865f8090ed33d5ce05528ff0e1e23657ef))
## [1.177.20](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.177.19...@standardnotes/auth-server@1.177.20) (2024-01-18)
**Note:** Version bump only for package @standardnotes/auth-server
## [1.177.19](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.177.18...@standardnotes/auth-server@1.177.19) (2024-01-17)
### Bug Fixes
* **auth:** add server daily email backup permission for all versions of core user role ([#1028](https://github.com/standardnotes/server/issues/1028)) ([460fdf9](https://github.com/standardnotes/server/commit/460fdf9eafe2db629637ba481f2b135ed21560b9))
## [1.177.18](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.177.17...@standardnotes/auth-server@1.177.18) (2024-01-15)
### Bug Fixes
* **auth:** add more logs to syncing subscription ([c7217a9](https://github.com/standardnotes/server/commit/c7217a92ba89d8b5f4963a832aa7561dd146ca0d))
* **auth:** add renewal for shared offline subscriptions ([045358d](https://github.com/standardnotes/server/commit/045358ddbf300996a23bba8d6945b1d7b5f6e862))
## [1.177.17](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.177.16...@standardnotes/auth-server@1.177.17) (2024-01-15)
### Bug Fixes
* **auth:** add debug logs for subscription sync requested event ([351e18f](https://github.com/standardnotes/server/commit/351e18f6389c2dbaa2107e6549be9928c2e8834f))
## [1.177.16](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.177.15...@standardnotes/auth-server@1.177.16) (2024-01-15)
### Bug Fixes
* **auth:** update shared subscriptions upon subscription sync ([#1022](https://github.com/standardnotes/server/issues/1022)) ([d7a1c66](https://github.com/standardnotes/server/commit/d7a1c667dd62dacc1ef15f2a4f408dc07045fcad))
## [1.177.15](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.177.14...@standardnotes/auth-server@1.177.15) (2024-01-09)
### Bug Fixes

View File

@@ -0,0 +1,74 @@
import 'reflect-metadata'
import { Logger } from 'winston'
import { ContainerConfigLoader } from '../src/Bootstrap/Container'
import TYPES from '../src/Bootstrap/Types'
import { Env } from '../src/Bootstrap/Env'
import { UserSubscriptionRepositoryInterface } from '../src/Domain/Subscription/UserSubscriptionRepositoryInterface'
import { DomainEventFactoryInterface } from '../src/Domain/Event/DomainEventFactoryInterface'
import { DomainEventPublisherInterface } from '@standardnotes/domain-events'
import { UserRepositoryInterface } from '../src/Domain/User/UserRepositoryInterface'
import { Uuid } from '@standardnotes/domain-core'
const fixSubscriptions = async (
userRepository: UserRepositoryInterface,
userSubscriptionRepository: UserSubscriptionRepositoryInterface,
domainEventFactory: DomainEventFactoryInterface,
domainEventPublisher: DomainEventPublisherInterface,
): Promise<void> => {
const subscriptions = await userSubscriptionRepository.findBySubscriptionId(0)
for (const subscription of subscriptions) {
const userUuidOrError = Uuid.create(subscription.userUuid)
if (userUuidOrError.isFailed()) {
continue
}
const userUuid = userUuidOrError.getValue()
const user = await userRepository.findOneByUuid(userUuid)
if (!user) {
continue
}
await domainEventPublisher.publish(
domainEventFactory.createSubscriptionStateRequestedEvent({
userEmail: user.email,
}),
)
}
}
const container = new ContainerConfigLoader('worker')
void container.load().then((container) => {
const env: Env = new Env()
env.load()
const logger: Logger = container.get(TYPES.Auth_Logger)
logger.info('Starting to fix subscriptions with missing subscriptionId ...')
const userRepository = container.get<UserRepositoryInterface>(TYPES.Auth_UserRepository)
const userSubscriptionRepository = container.get<UserSubscriptionRepositoryInterface>(
TYPES.Auth_UserSubscriptionRepository,
)
const domainEventFactory = container.get<DomainEventFactoryInterface>(TYPES.Auth_DomainEventFactory)
const domainEventPublisher = container.get<DomainEventPublisherInterface>(TYPES.Auth_DomainEventPublisher)
Promise.resolve(
fixSubscriptions(userRepository, userSubscriptionRepository, domainEventFactory, domainEventPublisher),
)
.then(() => {
logger.info('Finished fixing subscriptions with missing subscriptionId.')
process.exit(0)
})
.catch((error) => {
logger.error('Failed to fix subscriptions with missing subscriptionId.', {
error: error.message,
stack: error.stack,
})
process.exit(1)
})
})

View File

@@ -0,0 +1,11 @@
'use strict'
const path = require('path')
const pnp = require(path.normalize(path.resolve(__dirname, '../../..', '.pnp.cjs'))).setup()
const index = require(path.normalize(path.resolve(__dirname, '../dist/bin/fix_subscriptions.js')))
Object.defineProperty(exports, '__esModule', { value: true })
exports.default = index

View File

@@ -42,6 +42,10 @@ case "$COMMAND" in
exec node docker/entrypoint-fix-roles.js
;;
'fix-subscriptions' )
exec node docker/entrypoint-fix-subscriptions.js
;;
'delete-accounts' )
FILE_NAME=$1 && shift 1
MODE=$1 && shift 1

View File

@@ -0,0 +1,22 @@
import { MigrationInterface, QueryRunner } from 'typeorm'
export class EnableEmailBackupsForAll1705493201352 implements MigrationInterface {
public async up(queryRunner: QueryRunner): Promise<void> {
// Core User v1 Permissions
await queryRunner.query(
'INSERT INTO `role_permissions` (role_uuid, permission_uuid) VALUES \
("bde42e26-628c-44e6-9d76-21b08954b0bf", "eb0575a2-6e26-49e3-9501-f2e75d7dbda3") \
',
)
// Core User v2 Permissions
await queryRunner.query(
'INSERT INTO `role_permissions` (role_uuid, permission_uuid) VALUES \
("23bf88ca-bee1-4a4c-adf0-b7a48749eea7", "eb0575a2-6e26-49e3-9501-f2e75d7dbda3") \
',
)
}
public async down(): Promise<void> {
return
}
}

View File

@@ -0,0 +1,22 @@
import { MigrationInterface, QueryRunner } from 'typeorm'
export class EnableEmailBackupsForAll1705493490376 implements MigrationInterface {
public async up(queryRunner: QueryRunner): Promise<void> {
// Core User v1 Permissions
await queryRunner.query(
'INSERT INTO `role_permissions` (role_uuid, permission_uuid) VALUES \
("bde42e26-628c-44e6-9d76-21b08954b0bf", "eb0575a2-6e26-49e3-9501-f2e75d7dbda3") \
',
)
// Core User v2 Permissions
await queryRunner.query(
'INSERT INTO `role_permissions` (role_uuid, permission_uuid) VALUES \
("23bf88ca-bee1-4a4c-adf0-b7a48749eea7", "eb0575a2-6e26-49e3-9501-f2e75d7dbda3") \
',
)
}
public async down(): Promise<void> {
return
}
}

View File

@@ -1,6 +1,6 @@
{
"name": "@standardnotes/auth-server",
"version": "1.177.15",
"version": "1.178.3",
"engines": {
"node": ">=18.0.0 <21.0.0"
},

View File

@@ -285,6 +285,7 @@ import { RenewSharedSubscriptions } from '../Domain/UseCase/RenewSharedSubscript
import { FixStorageQuotaForUser } from '../Domain/UseCase/FixStorageQuotaForUser/FixStorageQuotaForUser'
import { FileQuotaRecalculatedEventHandler } from '../Domain/Handler/FileQuotaRecalculatedEventHandler'
import { SessionServiceInterface } from '../Domain/Session/SessionServiceInterface'
import { SubscriptionStateFetchedEventHandler } from '../Domain/Handler/SubscriptionStateFetchedEventHandler'
export class ContainerConfigLoader {
constructor(private mode: 'server' | 'worker' = 'server') {}
@@ -1421,6 +1422,7 @@ export class ContainerConfigLoader {
container.get<SetSettingValue>(TYPES.Auth_SetSettingValue),
container.get<OfflineSettingServiceInterface>(TYPES.Auth_OfflineSettingService),
container.get<ContentDecoderInterface>(TYPES.Auth_ContenDecoder),
container.get<RenewSharedSubscriptions>(TYPES.Auth_RenewSharedSubscriptions),
container.get<winston.Logger>(TYPES.Auth_Logger),
),
)
@@ -1578,6 +1580,16 @@ export class ContainerConfigLoader {
container.get<winston.Logger>(TYPES.Auth_Logger),
),
)
container
.bind<SubscriptionStateFetchedEventHandler>(TYPES.Auth_SubscriptionStateFetchedEventHandler)
.toConstantValue(
new SubscriptionStateFetchedEventHandler(
container.get<UserRepositoryInterface>(TYPES.Auth_UserRepository),
container.get<UserSubscriptionRepositoryInterface>(TYPES.Auth_UserSubscriptionRepository),
container.get<OfflineUserSubscriptionRepositoryInterface>(TYPES.Auth_OfflineUserSubscriptionRepository),
container.get<winston.Logger>(TYPES.Auth_Logger),
),
)
const eventHandlers: Map<string, DomainEventHandlerInterface> = new Map([
['ACCOUNT_DELETION_REQUESTED', container.get(TYPES.Auth_AccountDeletionRequestedEventHandler)],
@@ -1619,6 +1631,7 @@ export class ContainerConfigLoader {
'FILE_QUOTA_RECALCULATED',
container.get<FileQuotaRecalculatedEventHandler>(TYPES.Auth_FileQuotaRecalculatedEventHandler),
],
['SUBSCRIPTION_STATE_FETCHED', container.get(TYPES.Auth_SubscriptionStateFetchedEventHandler)],
])
if (isConfiguredForHomeServer) {

View File

@@ -205,6 +205,7 @@ const TYPES = {
),
Auth_UserInvitedToSharedVaultEventHandler: Symbol.for('Auth_UserInvitedToSharedVaultEventHandler'),
Auth_FileQuotaRecalculatedEventHandler: Symbol.for('Auth_FileQuotaRecalculatedEventHandler'),
Auth_SubscriptionStateFetchedEventHandler: Symbol.for('Auth_SubscriptionStateFetchedEventHandler'),
// Services
Auth_DeviceDetector: Symbol.for('Auth_DeviceDetector'),
Auth_SessionService: Symbol.for('Auth_SessionService'),

View File

@@ -2,4 +2,5 @@ export enum ApiVersion {
v20161215 = '20161215',
v20190520 = '20190520',
v20200115 = '20200115',
v20240226 = '20240226',
}

View File

@@ -24,6 +24,7 @@ export class AuthResponseFactoryResolver implements AuthResponseFactoryResolverI
case ApiVersion.v20190520:
return this.authResponseFactory20190520
case ApiVersion.v20200115:
case ApiVersion.v20240226:
return this.authResponseFactory20200115
default:
return this.authResponseFactory20161215

View File

@@ -22,6 +22,7 @@ import {
SessionRefreshedEvent,
AccountDeletionVerificationRequestedEvent,
FileQuotaRecalculationRequestedEvent,
SubscriptionStateRequestedEvent,
} from '@standardnotes/domain-events'
import { Predicate, PredicateVerificationResult } from '@standardnotes/predicates'
import { TimerInterface } from '@standardnotes/time'
@@ -34,6 +35,21 @@ import { KeyParamsData } from '@standardnotes/responses'
@injectable()
export class DomainEventFactory implements DomainEventFactoryInterface {
constructor(@inject(TYPES.Auth_Timer) private timer: TimerInterface) {}
createSubscriptionStateRequestedEvent(dto: { userEmail: string }): SubscriptionStateRequestedEvent {
return {
type: 'SUBSCRIPTION_STATE_REQUESTED',
createdAt: this.timer.getUTCDate(),
meta: {
correlation: {
userIdentifier: dto.userEmail,
userIdentifierType: 'email',
},
origin: DomainEventService.Auth,
},
payload: dto,
}
}
createFileQuotaRecalculationRequestedEvent(dto: { userUuid: string }): FileQuotaRecalculationRequestedEvent {
return {
type: 'FILE_QUOTA_RECALCULATION_REQUESTED',

View File

@@ -20,11 +20,13 @@ import {
SessionRefreshedEvent,
AccountDeletionVerificationRequestedEvent,
FileQuotaRecalculationRequestedEvent,
SubscriptionStateRequestedEvent,
} from '@standardnotes/domain-events'
import { InviteeIdentifierType } from '../SharedSubscription/InviteeIdentifierType'
import { KeyParamsData } from '@standardnotes/responses'
export interface DomainEventFactoryInterface {
createSubscriptionStateRequestedEvent(dto: { userEmail: string }): SubscriptionStateRequestedEvent
createFileQuotaRecalculationRequestedEvent(dto: { userUuid: string }): FileQuotaRecalculationRequestedEvent
createWebSocketMessageRequestedEvent(dto: { userUuid: string; message: JSONString }): WebSocketMessageRequestedEvent
createEmailRequestedEvent(dto: {

View File

@@ -4,6 +4,7 @@ import { inject, injectable } from 'inversify'
import TYPES from '../../Bootstrap/Types'
import { UserSubscriptionRepositoryInterface } from '../Subscription/UserSubscriptionRepositoryInterface'
import { OfflineUserSubscriptionRepositoryInterface } from '../Subscription/OfflineUserSubscriptionRepositoryInterface'
import { Logger } from 'winston'
@injectable()
export class SubscriptionCancelledEventHandler implements DomainEventHandlerInterface {
@@ -12,9 +13,20 @@ export class SubscriptionCancelledEventHandler implements DomainEventHandlerInte
private userSubscriptionRepository: UserSubscriptionRepositoryInterface,
@inject(TYPES.Auth_OfflineUserSubscriptionRepository)
private offlineUserSubscriptionRepository: OfflineUserSubscriptionRepositoryInterface,
@inject(TYPES.Auth_Logger) private logger: Logger,
) {}
async handle(event: SubscriptionCancelledEvent): Promise<void> {
if (!event.payload.subscriptionId) {
this.logger.error('Subscription ID is missing', {
codeTag: 'SubscriptionCancelledEventHandler.handle',
subscriptionId: event.payload.subscriptionId,
userId: event.payload.userEmail,
})
return
}
if (event.payload.offline) {
await this.updateOfflineSubscriptionCancelled(event.payload.subscriptionId, event.payload.timestamp)

View File

@@ -22,6 +22,16 @@ export class SubscriptionExpiredEventHandler implements DomainEventHandlerInterf
) {}
async handle(event: SubscriptionExpiredEvent): Promise<void> {
if (!event.payload.subscriptionId) {
this.logger.error('Subscription ID is missing', {
codeTag: 'SubscriptionExpiredEventHandler.handle',
subscriptionId: event.payload.subscriptionId,
userId: event.payload.userEmail,
})
return
}
if (event.payload.offline) {
await this.updateOfflineSubscriptionEndsAt(event.payload.subscriptionId, event.payload.timestamp)

View File

@@ -25,6 +25,16 @@ export class SubscriptionPurchasedEventHandler implements DomainEventHandlerInte
) {}
async handle(event: SubscriptionPurchasedEvent): Promise<void> {
if (!event.payload.subscriptionId) {
this.logger.error('Subscription ID is missing', {
codeTag: 'SubscriptionPurchasedEventHandler.handle',
subscriptionId: event.payload.subscriptionId,
userId: event.payload.userEmail,
})
return
}
if (event.payload.offline) {
const offlineUserSubscription = await this.createOfflineSubscription(
event.payload.subscriptionId,
@@ -34,6 +44,19 @@ export class SubscriptionPurchasedEventHandler implements DomainEventHandlerInte
event.payload.timestamp,
)
const renewalResult = await this.renewSharedSubscriptions.execute({
inviterEmail: event.payload.userEmail,
newSubscriptionId: event.payload.subscriptionId,
newSubscriptionName: event.payload.subscriptionName,
newSubscriptionExpiresAt: event.payload.subscriptionExpiresAt,
timestamp: event.payload.timestamp,
})
if (renewalResult.isFailed()) {
this.logger.error(`Could not renew shared offline subscriptions: ${renewalResult.getError()}`, {
subscriptionId: event.payload.subscriptionId,
})
}
await this.roleService.setOfflineUserRole(offlineUserSubscription)
return

View File

@@ -22,6 +22,16 @@ export class SubscriptionReassignedEventHandler implements DomainEventHandlerInt
) {}
async handle(event: SubscriptionReassignedEvent): Promise<void> {
if (!event.payload.subscriptionId) {
this.logger.error('Subscription ID is missing', {
codeTag: 'SubscriptionReassignedEventHandler.handle',
subscriptionId: event.payload.subscriptionId,
userId: event.payload.userEmail,
})
return
}
const usernameOrError = Username.create(event.payload.userEmail)
if (usernameOrError.isFailed()) {
return

View File

@@ -22,6 +22,16 @@ export class SubscriptionRefundedEventHandler implements DomainEventHandlerInter
) {}
async handle(event: SubscriptionRefundedEvent): Promise<void> {
if (!event.payload.subscriptionId) {
this.logger.error('Subscription ID is missing', {
codeTag: 'SubscriptionRefundedEventHandler.handle',
subscriptionId: event.payload.subscriptionId,
userId: event.payload.userEmail,
})
return
}
if (event.payload.offline) {
await this.updateOfflineSubscriptionEndsAt(event.payload.subscriptionId, event.payload.timestamp)

View File

@@ -23,6 +23,16 @@ export class SubscriptionRenewedEventHandler implements DomainEventHandlerInterf
) {}
async handle(event: SubscriptionRenewedEvent): Promise<void> {
if (!event.payload.subscriptionId) {
this.logger.error('Subscription ID is missing', {
codeTag: 'SubscriptionRenewedEventHandler.handle',
subscriptionId: event.payload.subscriptionId,
userId: event.payload.userEmail,
})
return
}
if (event.payload.offline) {
const offlineUserSubscription = await this.offlineUserSubscriptionRepository.findOneBySubscriptionId(
event.payload.subscriptionId,

View File

@@ -0,0 +1,123 @@
import { Username } from '@standardnotes/domain-core'
import { DomainEventHandlerInterface, SubscriptionStateFetchedEvent } from '@standardnotes/domain-events'
import { Logger } from 'winston'
import { UserRepositoryInterface } from '../User/UserRepositoryInterface'
import { UserSubscriptionRepositoryInterface } from '../Subscription/UserSubscriptionRepositoryInterface'
import { OfflineUserSubscriptionRepositoryInterface } from '../Subscription/OfflineUserSubscriptionRepositoryInterface'
export class SubscriptionStateFetchedEventHandler implements DomainEventHandlerInterface {
constructor(
private userRepository: UserRepositoryInterface,
private userSubscriptionRepository: UserSubscriptionRepositoryInterface,
private offlineUserSubscriptionRepository: OfflineUserSubscriptionRepositoryInterface,
private logger: Logger,
) {}
async handle(event: SubscriptionStateFetchedEvent): Promise<void> {
if (!event.payload.subscriptionId) {
this.logger.error('Subscription ID is missing', {
codeTag: 'SubscriptionStateFetchedEventHandler.handle',
subscriptionId: event.payload.subscriptionId,
userId: event.payload.userEmail,
})
return
}
this.logger.info('Subscription state update fetched', {
subscriptionId: event.payload.subscriptionId,
})
if (event.payload.offline) {
this.logger.info('Updating offline subscription', {
subscriptionId: event.payload.subscriptionId,
})
const subscription = await this.offlineUserSubscriptionRepository.findOneByEmailAndSubscriptionId(
event.payload.userEmail,
0,
)
if (!subscription) {
this.logger.error('Offline subscription not found', {
subscriptionId: event.payload.subscriptionId,
})
return
}
subscription.planName = event.payload.subscriptionName
subscription.email = event.payload.userEmail
subscription.endsAt = event.payload.subscriptionExpiresAt
subscription.cancelled = event.payload.canceled
if (subscription.subscriptionId !== event.payload.subscriptionId) {
this.logger.warn('Subscription IDs do not match', {
previousSubscriptionId: subscription.subscriptionId,
subscriptionId: event.payload.subscriptionId,
})
}
subscription.subscriptionId = event.payload.subscriptionId
await this.offlineUserSubscriptionRepository.save(subscription)
this.logger.info('Offline subscription updated', {
subscriptionId: event.payload.subscriptionId,
})
return
}
const usernameOrError = Username.create(event.payload.userEmail)
if (usernameOrError.isFailed()) {
this.logger.warn(`Could not update subscription: ${usernameOrError.getError()}`, {
subscriptionId: event.payload.subscriptionId,
})
return
}
const username = usernameOrError.getValue()
const user = await this.userRepository.findOneByUsernameOrEmail(username)
if (user === null) {
this.logger.warn(`Could not find user with email: ${username.value}`, {
subscriptionId: event.payload.subscriptionId,
})
return
}
this.logger.info('Updating subscription', {
userId: user.uuid,
subscriptionId: event.payload.subscriptionId,
})
const subscription = await this.userSubscriptionRepository.findOneByUserUuidAndSubscriptionId(user.uuid, 0)
if (!subscription) {
this.logger.error('Subscription not found', {
userId: user.uuid,
subscriptionId: event.payload.subscriptionId,
})
return
}
subscription.planName = event.payload.subscriptionName
subscription.endsAt = event.payload.subscriptionExpiresAt
subscription.cancelled = event.payload.canceled
if (subscription.subscriptionId !== event.payload.subscriptionId) {
this.logger.warn('Subscription IDs do not match', {
previousSubscriptionId: subscription.subscriptionId,
subscriptionId: event.payload.subscriptionId,
})
}
subscription.subscriptionId = event.payload.subscriptionId
await this.userSubscriptionRepository.save(subscription)
this.logger.info('Subscription updated to current state', {
userId: user.uuid,
subscriptionId: event.payload.subscriptionId,
})
}
}

View File

@@ -16,6 +16,7 @@ import { OfflineSettingName } from '../Setting/OfflineSettingName'
import { UserSubscriptionType } from '../Subscription/UserSubscriptionType'
import { ApplyDefaultSubscriptionSettings } from '../UseCase/ApplyDefaultSubscriptionSettings/ApplyDefaultSubscriptionSettings'
import { SetSettingValue } from '../UseCase/SetSettingValue/SetSettingValue'
import { RenewSharedSubscriptions } from '../UseCase/RenewSharedSubscriptions/RenewSharedSubscriptions'
export class SubscriptionSyncRequestedEventHandler implements DomainEventHandlerInterface {
constructor(
@@ -27,11 +28,30 @@ export class SubscriptionSyncRequestedEventHandler implements DomainEventHandler
private setSettingValue: SetSettingValue,
private offlineSettingService: OfflineSettingServiceInterface,
private contentDecoder: ContentDecoderInterface,
private renewSharedSubscriptions: RenewSharedSubscriptions,
private logger: Logger,
) {}
async handle(event: SubscriptionSyncRequestedEvent): Promise<void> {
if (!event.payload.subscriptionId) {
this.logger.error('Subscription ID is missing', {
codeTag: 'SubscriptionSyncRequestedEventHandler.handle',
subscriptionId: event.payload.subscriptionId,
userId: event.payload.userEmail,
})
return
}
this.logger.info('Subscription sync requested', {
subscriptionId: event.payload.subscriptionId,
})
if (event.payload.offline) {
this.logger.info('Syncing offline subscription', {
subscriptionId: event.payload.subscriptionId,
})
const offlineUserSubscription = await this.createOrUpdateOfflineSubscription(
event.payload.subscriptionId,
event.payload.subscriptionName,
@@ -41,6 +61,19 @@ export class SubscriptionSyncRequestedEventHandler implements DomainEventHandler
event.payload.timestamp,
)
const renewalResult = await this.renewSharedSubscriptions.execute({
inviterEmail: event.payload.userEmail,
newSubscriptionId: event.payload.subscriptionId,
newSubscriptionName: event.payload.subscriptionName,
newSubscriptionExpiresAt: event.payload.subscriptionExpiresAt,
timestamp: event.payload.timestamp,
})
if (renewalResult.isFailed()) {
this.logger.error(`Could not renew shared offline subscriptions for user: ${renewalResult.getError()}`, {
subscriptionId: event.payload.subscriptionId,
})
}
await this.roleService.setOfflineUserRole(offlineUserSubscription)
const offlineFeaturesTokenDecoded = this.contentDecoder.decode(
@@ -60,11 +93,19 @@ export class SubscriptionSyncRequestedEventHandler implements DomainEventHandler
value: offlineFeaturesTokenDecoded.extensionKey,
})
this.logger.info('Offline subscription synced', {
subscriptionId: event.payload.subscriptionId,
})
return
}
const usernameOrError = Username.create(event.payload.userEmail)
if (usernameOrError.isFailed()) {
this.logger.warn(`Could not sync subscription: ${usernameOrError.getError()}`, {
subscriptionId: event.payload.subscriptionId,
})
return
}
const username = usernameOrError.getValue()
@@ -72,10 +113,18 @@ export class SubscriptionSyncRequestedEventHandler implements DomainEventHandler
const user = await this.userRepository.findOneByUsernameOrEmail(username)
if (user === null) {
this.logger.warn(`Could not find user with email: ${username.value}`)
this.logger.warn(`Could not find user with email: ${username.value}`, {
subscriptionId: event.payload.subscriptionId,
})
return
}
this.logger.info('Syncing subscription', {
userId: user.uuid,
subscriptionId: event.payload.subscriptionId,
})
const userSubscription = await this.createOrUpdateSubscription(
event.payload.subscriptionId,
event.payload.subscriptionName,
@@ -85,6 +134,19 @@ export class SubscriptionSyncRequestedEventHandler implements DomainEventHandler
event.payload.timestamp,
)
const renewalResult = await this.renewSharedSubscriptions.execute({
inviterEmail: user.email,
newSubscriptionId: event.payload.subscriptionId,
newSubscriptionName: event.payload.subscriptionName,
newSubscriptionExpiresAt: event.payload.subscriptionExpiresAt,
timestamp: event.payload.timestamp,
})
if (renewalResult.isFailed()) {
this.logger.error(`Could not renew shared subscriptions for user: ${renewalResult.getError()}`, {
userId: user.uuid,
})
}
await this.roleService.addUserRoleBasedOnSubscription(user, event.payload.subscriptionName)
const applyingSettingsResult = await this.applyDefaultSubscriptionSettings.execute({
@@ -107,6 +169,11 @@ export class SubscriptionSyncRequestedEventHandler implements DomainEventHandler
if (result.isFailed()) {
this.logger.error(`Could not set extension key for user ${user.uuid}`)
}
this.logger.info('Subscription synced', {
userId: user.uuid,
subscriptionId: event.payload.subscriptionId,
})
}
private async createOrUpdateSubscription(

View File

@@ -2,6 +2,7 @@ import { OfflineUserSubscription } from './OfflineUserSubscription'
export interface OfflineUserSubscriptionRepositoryInterface {
findOneByEmail(email: string): Promise<OfflineUserSubscription | null>
findOneByEmailAndSubscriptionId(email: string, subscriptionId: number): Promise<OfflineUserSubscription | null>
findOneBySubscriptionId(subscriptionId: number): Promise<OfflineUserSubscription | null>
findByEmail(email: string, activeAfter: number): Promise<OfflineUserSubscription[]>
updateEndsAt(subscriptionId: number, endsAt: number, updatedAt: number): Promise<void>

View File

@@ -89,42 +89,4 @@ describe('CreateOfflineSubscriptionToken', () => {
expect(domainEventFactory.createEmailRequestedEvent).not.toHaveBeenCalled()
expect(domainEventPublisher.publish).not.toHaveBeenCalled()
})
it('should not create an offline subscription token if email has a cancelled subscription', async () => {
offlineUserSubscriptionRepository.findOneByEmail = jest
.fn()
.mockReturnValue({ cancelled: true, endsAt: 100 } as jest.Mocked<OfflineUserSubscription>)
expect(
await createUseCase().execute({
userEmail: 'test@test.com',
}),
).toEqual({
success: false,
error: 'subscription-canceled',
})
expect(offlineSubscriptionTokenRepository.save).not.toHaveBeenCalled()
expect(domainEventFactory.createEmailRequestedEvent).not.toHaveBeenCalled()
expect(domainEventPublisher.publish).not.toHaveBeenCalled()
})
it('should not create an offline subscription token if email has an outdated subscription', async () => {
offlineUserSubscriptionRepository.findOneByEmail = jest
.fn()
.mockReturnValue({ cancelled: false, endsAt: 2 } as jest.Mocked<OfflineUserSubscription>)
expect(
await createUseCase().execute({
userEmail: 'test@test.com',
}),
).toEqual({
success: false,
error: 'subscription-expired',
})
expect(offlineSubscriptionTokenRepository.save).not.toHaveBeenCalled()
expect(domainEventFactory.createEmailRequestedEvent).not.toHaveBeenCalled()
expect(domainEventPublisher.publish).not.toHaveBeenCalled()
})
})

View File

@@ -37,20 +37,6 @@ export class CreateOfflineSubscriptionToken implements UseCaseInterface {
}
}
if (existingSubscription.cancelled) {
return {
success: false,
error: 'subscription-canceled',
}
}
if (existingSubscription.endsAt < this.timer.getTimestampInMicroseconds()) {
return {
success: false,
error: 'subscription-expired',
}
}
const token = await this.cryptoNode.generateRandomKey(128)
const offlineSubscriptionToken = {

View File

@@ -127,6 +127,43 @@ describe('Register', () => {
})
})
it('should register a new user with default set of roles on new api version', async () => {
const role = new Role()
role.name = RoleName.NAMES.CoreUser
roleRepository.findOneByName = jest.fn().mockReturnValueOnce(role)
expect(
await createUseCase().execute({
email: 'test@test.te',
password: 'asdzxc',
updatedWithUserAgent: 'Mozilla',
apiVersion: '20240226',
ephemeralSession: false,
version: '004',
pwCost: 11,
pwSalt: 'qweqwe',
pwNonce: undefined,
}),
).toEqual({ success: true, authResponse: { foo: 'bar' } })
expect(userRepository.save).toHaveBeenCalledWith({
email: 'test@test.te',
encryptedPassword: expect.any(String),
encryptedServerKey: 'test',
serverEncryptionVersion: 1,
pwCost: 11,
pwNonce: undefined,
pwSalt: 'qweqwe',
updatedWithUserAgent: 'Mozilla',
uuid: expect.any(String),
version: '004',
createdAt: new Date(1),
updatedAt: new Date(1),
roles: Promise.resolve([role]),
})
})
it('should fail to register if applying default settings fails', async () => {
applyDefaultSettings.execute = jest.fn().mockReturnValue(Result.fail('error'))

View File

@@ -36,7 +36,7 @@ export class Register implements UseCaseInterface {
const { email, password, apiVersion, ephemeralSession, ...registrationFields } = dto
if (apiVersion !== ApiVersion.v20200115) {
if (![ApiVersion.v20200115, ApiVersion.v20240226].includes(apiVersion as ApiVersion)) {
return {
success: false,
errorMessage: `Unsupported api version: ${apiVersion}`,

View File

@@ -12,6 +12,19 @@ export class TypeORMOfflineUserSubscriptionRepository implements OfflineUserSubs
private ormRepository: Repository<OfflineUserSubscription>,
) {}
async findOneByEmailAndSubscriptionId(
email: string,
subscriptionId: number,
): Promise<OfflineUserSubscription | null> {
return await this.ormRepository
.createQueryBuilder()
.where('email = :email AND subscription_id = :subscriptionId', {
email,
subscriptionId,
})
.getOne()
}
async save(offlineUserSubscription: OfflineUserSubscription): Promise<OfflineUserSubscription> {
return this.ormRepository.save(offlineUserSubscription)
}

View File

@@ -84,6 +84,7 @@ export class TypeORMUserSubscriptionRepository implements UserSubscriptionReposi
userUuid,
subscriptionId,
})
.orderBy('ends_at', 'DESC')
.getOne()
}

View File

@@ -3,6 +3,14 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.23.3](https://github.com/standardnotes/server/compare/@standardnotes/domain-events-infra@1.23.2...@standardnotes/domain-events-infra@1.23.3) (2024-01-19)
**Note:** Version bump only for package @standardnotes/domain-events-infra
## [1.23.2](https://github.com/standardnotes/server/compare/@standardnotes/domain-events-infra@1.23.1...@standardnotes/domain-events-infra@1.23.2) (2024-01-18)
**Note:** Version bump only for package @standardnotes/domain-events-infra
## [1.23.1](https://github.com/standardnotes/server/compare/@standardnotes/domain-events-infra@1.23.0...@standardnotes/domain-events-infra@1.23.1) (2024-01-03)
### Bug Fixes

View File

@@ -1,6 +1,6 @@
{
"name": "@standardnotes/domain-events-infra",
"version": "1.23.1",
"version": "1.23.3",
"engines": {
"node": ">=18.0.0 <21.0.0"
},

View File

@@ -3,6 +3,18 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
# [2.141.0](https://github.com/standardnotes/server/compare/@standardnotes/domain-events@2.140.0...@standardnotes/domain-events@2.141.0) (2024-01-19)
### Features
* **auth:** add script for fixing subscriptions with missing id state ([#1030](https://github.com/standardnotes/server/issues/1030)) ([86b0508](https://github.com/standardnotes/server/commit/86b050865f8090ed33d5ce05528ff0e1e23657ef))
# [2.140.0](https://github.com/standardnotes/server/compare/@standardnotes/domain-events@2.139.3...@standardnotes/domain-events@2.140.0) (2024-01-18)
### Features
* add content sizes fixing upon grpc resource exhausted error ([#1029](https://github.com/standardnotes/server/issues/1029)) ([634e8bd](https://github.com/standardnotes/server/commit/634e8bd2d0f055abbda1150587ab9a444281e600))
## [2.139.3](https://github.com/standardnotes/server/compare/@standardnotes/domain-events@2.139.2...@standardnotes/domain-events@2.139.3) (2023-12-29)
### Bug Fixes

View File

@@ -1,6 +1,6 @@
{
"name": "@standardnotes/domain-events",
"version": "2.139.3",
"version": "2.141.0",
"engines": {
"node": ">=18.0.0 <21.0.0"
},

View File

@@ -0,0 +1,7 @@
import { DomainEventInterface } from './DomainEventInterface'
import { ContentSizesFixRequestedEventPayload } from './ContentSizesFixRequestedEventPayload'
export interface ContentSizesFixRequestedEvent extends DomainEventInterface {
type: 'CONTENT_SIZES_FIX_REQUESTED'
payload: ContentSizesFixRequestedEventPayload
}

View File

@@ -0,0 +1,3 @@
export interface ContentSizesFixRequestedEventPayload {
userUuid: string
}

View File

@@ -0,0 +1,8 @@
import { DomainEventInterface } from './DomainEventInterface'
import { SubscriptionStateFetchedEventPayload } from './SubscriptionStateFetchedEventPayload'
export interface SubscriptionStateFetchedEvent extends DomainEventInterface {
type: 'SUBSCRIPTION_STATE_FETCHED'
payload: SubscriptionStateFetchedEventPayload
}

View File

@@ -0,0 +1,11 @@
export interface SubscriptionStateFetchedEventPayload {
userEmail: string
subscriptionId: number
subscriptionName: string
subscriptionExpiresAt: number
timestamp: number
offline: boolean
canceled: boolean
extensionKey: string
offlineFeaturesToken: string
}

View File

@@ -0,0 +1,8 @@
import { DomainEventInterface } from './DomainEventInterface'
import { SubscriptionStateRequestedEventPayload } from './SubscriptionStateRequestedEventPayload'
export interface SubscriptionStateRequestedEvent extends DomainEventInterface {
type: 'SUBSCRIPTION_STATE_REQUESTED'
payload: SubscriptionStateRequestedEventPayload
}

View File

@@ -0,0 +1,3 @@
export interface SubscriptionStateRequestedEventPayload {
userEmail: string
}

View File

@@ -4,6 +4,8 @@ export * from './Event/AccountDeletionVerificationPassedEvent'
export * from './Event/AccountDeletionVerificationPassedEventPayload'
export * from './Event/AccountDeletionVerificationRequestedEvent'
export * from './Event/AccountDeletionVerificationRequestedEventPayload'
export * from './Event/ContentSizesFixRequestedEvent'
export * from './Event/ContentSizesFixRequestedEventPayload'
export * from './Event/DiscountApplyRequestedEvent'
export * from './Event/DiscountApplyRequestedEventPayload'
export * from './Event/DiscountWithdrawRequestedEvent'
@@ -108,6 +110,10 @@ export * from './Event/SubscriptionExpiredEvent'
export * from './Event/SubscriptionExpiredEventPayload'
export * from './Event/SubscriptionRevertRequestedEvent'
export * from './Event/SubscriptionRevertRequestedEventPayload'
export * from './Event/SubscriptionStateFetchedEvent'
export * from './Event/SubscriptionStateFetchedEventPayload'
export * from './Event/SubscriptionStateRequestedEvent'
export * from './Event/SubscriptionStateRequestedEventPayload'
export * from './Event/SubscriptionSyncRequestedEvent'
export * from './Event/SubscriptionSyncRequestedEventPayload'
export * from './Event/UserAddedToSharedVaultEvent'

View File

@@ -3,6 +3,32 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
# [1.38.0](https://github.com/standardnotes/server/compare/@standardnotes/files-server@1.37.12...@standardnotes/files-server@1.38.0) (2024-03-20)
### Features
* add CORS_ORIGIN_STRICT_MODE_ENABLED env var to determine if CORS origin should be restricted ([5c02435](https://github.com/standardnotes/server/commit/5c02435ee478b893747d3f9e41062aae12d7ff10))
## [1.37.12](https://github.com/standardnotes/server/compare/@standardnotes/files-server@1.37.11...@standardnotes/files-server@1.37.12) (2024-03-18)
### Bug Fixes
* cors issues on clients - fixes [#1046](https://github.com/standardnotes/server/issues/1046) ([#1049](https://github.com/standardnotes/server/issues/1049)) ([6d7ca1b](https://github.com/standardnotes/server/commit/6d7ca1b926fd45d744275bd3c1f4c05b010f76c8))
## [1.37.11](https://github.com/standardnotes/server/compare/@standardnotes/files-server@1.37.10...@standardnotes/files-server@1.37.11) (2024-01-19)
**Note:** Version bump only for package @standardnotes/files-server
## [1.37.10](https://github.com/standardnotes/server/compare/@standardnotes/files-server@1.37.9...@standardnotes/files-server@1.37.10) (2024-01-18)
**Note:** Version bump only for package @standardnotes/files-server
## [1.37.9](https://github.com/standardnotes/server/compare/@standardnotes/files-server@1.37.8...@standardnotes/files-server@1.37.9) (2024-01-10)
### Bug Fixes
* add dedicated http code response upon a request with too large payload ([#1019](https://github.com/standardnotes/server/issues/1019)) ([6062f85](https://github.com/standardnotes/server/commit/6062f850000477983315d2d9b7c913956f755ebb))
## [1.37.8](https://github.com/standardnotes/server/compare/@standardnotes/files-server@1.37.7...@standardnotes/files-server@1.37.8) (2024-01-04)
**Note:** Version bump only for package @standardnotes/files-server

View File

@@ -24,6 +24,10 @@ void container.load().then((container) => {
const env: Env = new Env()
env.load()
const requestPayloadLimit = env.get('HTTP_REQUEST_PAYLOAD_LIMIT_MEGABYTES', true)
? `${+env.get('HTTP_REQUEST_PAYLOAD_LIMIT_MEGABYTES', true)}mb`
: '50mb'
const server = new InversifyExpressServer(container)
server.setConfig((app) => {
@@ -58,12 +62,58 @@ void container.load().then((container) => {
}
}))
/* eslint-enable */
app.use(json({ limit: '50mb' }))
app.use(raw({ limit: '50mb', type: 'application/octet-stream' }))
app.use(urlencoded({ extended: true, limit: '50mb' }))
app.use(json({ limit: requestPayloadLimit }))
app.use(raw({ limit: requestPayloadLimit, type: 'application/octet-stream' }))
app.use(urlencoded({ extended: true, limit: requestPayloadLimit }))
const corsAllowedOrigins = env.get('CORS_ALLOWED_ORIGINS', true)
? env.get('CORS_ALLOWED_ORIGINS', true).split(',')
: []
app.use(
cors({
exposedHeaders: ['Content-Range', 'Accept-Ranges'],
credentials: true,
exposedHeaders: [
'Content-Range',
'Accept-Ranges',
'Access-Control-Allow-Credentials',
'Access-Control-Allow-Origin',
],
origin: (requestOrigin: string | undefined, callback: (err: Error | null, origin?: string[]) => void) => {
const originStrictModeEnabled = env.get('CORS_ORIGIN_STRICT_MODE_ENABLED', true)
? env.get('CORS_ORIGIN_STRICT_MODE_ENABLED', true) === 'true'
: false
if (!originStrictModeEnabled) {
callback(null, [requestOrigin as string])
return
}
const requstOriginIsNotFilled = !requestOrigin || requestOrigin === 'null'
const requestOriginatesFromTheDesktopApp = requestOrigin?.startsWith('file://')
const requestOriginatesFromClipperForFirefox = requestOrigin?.startsWith('moz-extension://')
const requestOriginatesFromSelfHostedAppOnHttpPort = requestOrigin === 'http://localhost'
const requestOriginatesFromSelfHostedAppOnCustomPort = requestOrigin?.match(/http:\/\/localhost:\d+/) !== null
const requestOriginatesFromSelfHostedApp =
requestOriginatesFromSelfHostedAppOnHttpPort || requestOriginatesFromSelfHostedAppOnCustomPort
const requestIsWhitelisted =
corsAllowedOrigins.length === 0 ||
requstOriginIsNotFilled ||
requestOriginatesFromTheDesktopApp ||
requestOriginatesFromClipperForFirefox ||
requestOriginatesFromSelfHostedApp
if (requestIsWhitelisted) {
callback(null, [requestOrigin as string])
} else {
if (corsAllowedOrigins.includes(requestOrigin)) {
callback(null, [requestOrigin])
} else {
callback(new Error('Not allowed by CORS', { cause: 'origin not allowed' }))
}
}
},
}),
)
app.use(

View File

@@ -1,6 +1,6 @@
{
"name": "@standardnotes/files-server",
"version": "1.37.8",
"version": "1.38.0",
"engines": {
"node": ">=18.0.0 <21.0.0"
},

View File

@@ -3,6 +3,80 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
# [1.23.0](https://github.com/standardnotes/server/compare/@standardnotes/home-server@1.22.68...@standardnotes/home-server@1.23.0) (2024-03-20)
### Features
* add CORS_ORIGIN_STRICT_MODE_ENABLED env var to determine if CORS origin should be restricted ([5c02435](https://github.com/standardnotes/server/commit/5c02435ee478b893747d3f9e41062aae12d7ff10))
## [1.22.68](https://github.com/standardnotes/server/compare/@standardnotes/home-server@1.22.67...@standardnotes/home-server@1.22.68) (2024-03-18)
**Note:** Version bump only for package @standardnotes/home-server
## [1.22.67](https://github.com/standardnotes/server/compare/@standardnotes/home-server@1.22.66...@standardnotes/home-server@1.22.67) (2024-03-18)
### Bug Fixes
* cors issues on clients - fixes [#1046](https://github.com/standardnotes/server/issues/1046) ([#1049](https://github.com/standardnotes/server/issues/1049)) ([6d7ca1b](https://github.com/standardnotes/server/commit/6d7ca1b926fd45d744275bd3c1f4c05b010f76c8))
## [1.22.66](https://github.com/standardnotes/server/compare/@standardnotes/home-server@1.22.65...@standardnotes/home-server@1.22.66) (2024-03-18)
**Note:** Version bump only for package @standardnotes/home-server
## [1.22.65](https://github.com/standardnotes/server/compare/@standardnotes/home-server@1.22.64...@standardnotes/home-server@1.22.65) (2024-03-15)
**Note:** Version bump only for package @standardnotes/home-server
## [1.22.64](https://github.com/standardnotes/server/compare/@standardnotes/home-server@1.22.63...@standardnotes/home-server@1.22.64) (2024-02-09)
**Note:** Version bump only for package @standardnotes/home-server
## [1.22.63](https://github.com/standardnotes/server/compare/@standardnotes/home-server@1.22.62...@standardnotes/home-server@1.22.63) (2024-01-19)
**Note:** Version bump only for package @standardnotes/home-server
## [1.22.62](https://github.com/standardnotes/server/compare/@standardnotes/home-server@1.22.61...@standardnotes/home-server@1.22.62) (2024-01-18)
**Note:** Version bump only for package @standardnotes/home-server
## [1.22.61](https://github.com/standardnotes/server/compare/@standardnotes/home-server@1.22.60...@standardnotes/home-server@1.22.61) (2024-01-18)
**Note:** Version bump only for package @standardnotes/home-server
## [1.22.60](https://github.com/standardnotes/server/compare/@standardnotes/home-server@1.22.59...@standardnotes/home-server@1.22.60) (2024-01-17)
**Note:** Version bump only for package @standardnotes/home-server
## [1.22.59](https://github.com/standardnotes/server/compare/@standardnotes/home-server@1.22.58...@standardnotes/home-server@1.22.59) (2024-01-17)
**Note:** Version bump only for package @standardnotes/home-server
## [1.22.58](https://github.com/standardnotes/server/compare/@standardnotes/home-server@1.22.57...@standardnotes/home-server@1.22.58) (2024-01-16)
**Note:** Version bump only for package @standardnotes/home-server
## [1.22.57](https://github.com/standardnotes/server/compare/@standardnotes/home-server@1.22.56...@standardnotes/home-server@1.22.57) (2024-01-15)
**Note:** Version bump only for package @standardnotes/home-server
## [1.22.56](https://github.com/standardnotes/server/compare/@standardnotes/home-server@1.22.55...@standardnotes/home-server@1.22.56) (2024-01-15)
**Note:** Version bump only for package @standardnotes/home-server
## [1.22.55](https://github.com/standardnotes/server/compare/@standardnotes/home-server@1.22.54...@standardnotes/home-server@1.22.55) (2024-01-15)
**Note:** Version bump only for package @standardnotes/home-server
## [1.22.54](https://github.com/standardnotes/server/compare/@standardnotes/home-server@1.22.53...@standardnotes/home-server@1.22.54) (2024-01-12)
**Note:** Version bump only for package @standardnotes/home-server
## [1.22.53](https://github.com/standardnotes/server/compare/@standardnotes/home-server@1.22.52...@standardnotes/home-server@1.22.53) (2024-01-10)
### Bug Fixes
* add dedicated http code response upon a request with too large payload ([#1019](https://github.com/standardnotes/server/issues/1019)) ([6062f85](https://github.com/standardnotes/server/commit/6062f850000477983315d2d9b7c913956f755ebb))
## [1.22.52](https://github.com/standardnotes/server/compare/@standardnotes/home-server@1.22.51...@standardnotes/home-server@1.22.52) (2024-01-09)
**Note:** Version bump only for package @standardnotes/home-server

View File

@@ -1,6 +1,6 @@
{
"name": "@standardnotes/home-server",
"version": "1.22.52",
"version": "1.23.0",
"engines": {
"node": ">=18.0.0 <21.0.0"
},

View File

@@ -53,6 +53,10 @@ export class HomeServer implements HomeServerInterface {
const env: Env = new Env(environmentOverrides)
env.load()
const requestPayloadLimit = env.get('HTTP_REQUEST_PAYLOAD_LIMIT_MEGABYTES', true)
? `${+env.get('HTTP_REQUEST_PAYLOAD_LIMIT_MEGABYTES', true)}mb`
: '50mb'
this.configureLoggers(env, configuration)
const apiGatewayService = new ApiGatewayService(serviceContainer)
@@ -114,8 +118,8 @@ export class HomeServer implements HomeServerInterface {
}
}))
/* eslint-enable */
app.use(json({ limit: '50mb' }))
app.use(raw({ limit: '50mb', type: 'application/octet-stream' }))
app.use(json({ limit: requestPayloadLimit }))
app.use(raw({ limit: requestPayloadLimit, type: 'application/octet-stream' }))
app.use(
text({
type: [
@@ -125,9 +129,50 @@ export class HomeServer implements HomeServerInterface {
],
}),
)
const corsAllowedOrigins = env.get('CORS_ALLOWED_ORIGINS', true)
? env.get('CORS_ALLOWED_ORIGINS', true).split(',')
: []
app.use(
cors({
exposedHeaders: ['Content-Range', 'Accept-Ranges'],
credentials: true,
exposedHeaders: ['Content-Range', 'Accept-Ranges', 'x-captcha-required'],
origin: (requestOrigin: string | undefined, callback: (err: Error | null, origin?: string[]) => void) => {
const originStrictModeEnabled = env.get('CORS_ORIGIN_STRICT_MODE_ENABLED', true)
? env.get('CORS_ORIGIN_STRICT_MODE_ENABLED', true) === 'true'
: false
if (!originStrictModeEnabled) {
callback(null, [requestOrigin as string])
return
}
const requstOriginIsNotFilled = !requestOrigin || requestOrigin === 'null'
const requestOriginatesFromTheDesktopApp = requestOrigin?.startsWith('file://')
const requestOriginatesFromClipperForFirefox = requestOrigin?.startsWith('moz-extension://')
const requestOriginatesFromSelfHostedAppOnHttpPort = requestOrigin === 'http://localhost'
const requestOriginatesFromSelfHostedAppOnCustomPort =
requestOrigin?.match(/http:\/\/localhost:\d+/) !== null
const requestOriginatesFromSelfHostedApp =
requestOriginatesFromSelfHostedAppOnHttpPort || requestOriginatesFromSelfHostedAppOnCustomPort
const requestIsWhitelisted =
corsAllowedOrigins.length === 0 ||
requstOriginIsNotFilled ||
requestOriginatesFromTheDesktopApp ||
requestOriginatesFromClipperForFirefox ||
requestOriginatesFromSelfHostedApp
if (requestIsWhitelisted) {
callback(null, [requestOrigin as string])
} else {
if (corsAllowedOrigins.includes(requestOrigin)) {
callback(null, [requestOrigin])
} else {
callback(new Error('Not allowed by CORS', { cause: 'origin not allowed' }))
}
}
},
}),
)
app.use(
@@ -160,8 +205,24 @@ export class HomeServer implements HomeServerInterface {
const logger: winston.Logger = winston.loggers.get('home-server')
server.setErrorConfig((app) => {
app.use((error: Record<string, unknown>, _request: Request, response: Response, _next: NextFunction) => {
logger.error(error.stack)
app.use((error: Record<string, unknown>, request: Request, response: Response, _next: NextFunction) => {
logger.error(`${error.stack}`, {
method: request.method,
url: request.url,
snjs: request.headers['x-snjs-version'],
application: request.headers['x-application-version'],
userId: response.locals.user ? response.locals.user.uuid : undefined,
})
if ('type' in error && error.type === 'entity.too.large') {
response.status(413).send({
error: {
message: 'The request payload is too large.',
},
})
return
}
response.status(500).send({
error: {

View File

@@ -3,6 +3,14 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.51.16](https://github.com/standardnotes/server/compare/@standardnotes/revisions-server@1.51.15...@standardnotes/revisions-server@1.51.16) (2024-01-19)
**Note:** Version bump only for package @standardnotes/revisions-server
## [1.51.15](https://github.com/standardnotes/server/compare/@standardnotes/revisions-server@1.51.14...@standardnotes/revisions-server@1.51.15) (2024-01-18)
**Note:** Version bump only for package @standardnotes/revisions-server
## [1.51.14](https://github.com/standardnotes/server/compare/@standardnotes/revisions-server@1.51.13...@standardnotes/revisions-server@1.51.14) (2024-01-04)
**Note:** Version bump only for package @standardnotes/revisions-server

View File

@@ -1,6 +1,6 @@
{
"name": "@standardnotes/revisions-server",
"version": "1.51.14",
"version": "1.51.16",
"engines": {
"node": ">=18.0.0 <21.0.0"
},

View File

@@ -3,6 +3,14 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.27.21](https://github.com/standardnotes/server/compare/@standardnotes/scheduler-server@1.27.20...@standardnotes/scheduler-server@1.27.21) (2024-01-19)
**Note:** Version bump only for package @standardnotes/scheduler-server
## [1.27.20](https://github.com/standardnotes/server/compare/@standardnotes/scheduler-server@1.27.19...@standardnotes/scheduler-server@1.27.20) (2024-01-18)
**Note:** Version bump only for package @standardnotes/scheduler-server
## [1.27.19](https://github.com/standardnotes/server/compare/@standardnotes/scheduler-server@1.27.18...@standardnotes/scheduler-server@1.27.19) (2024-01-04)
**Note:** Version bump only for package @standardnotes/scheduler-server

View File

@@ -1,6 +1,6 @@
{
"name": "@standardnotes/scheduler-server",
"version": "1.27.19",
"version": "1.27.21",
"engines": {
"node": ">=18.0.0 <21.0.0"
},

View File

@@ -3,6 +3,46 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.136.2](https://github.com/standardnotes/server/compare/@standardnotes/syncing-server@1.136.1...@standardnotes/syncing-server@1.136.2) (2024-03-15)
### Bug Fixes
* allow handling of new api version ([9d49764](https://github.com/standardnotes/server/commit/9d49764b841e73655e19523eddf10498addc9fb4))
## [1.136.1](https://github.com/standardnotes/server/compare/@standardnotes/syncing-server@1.136.0...@standardnotes/syncing-server@1.136.1) (2024-01-19)
**Note:** Version bump only for package @standardnotes/syncing-server
# [1.136.0](https://github.com/standardnotes/server/compare/@standardnotes/syncing-server@1.135.0...@standardnotes/syncing-server@1.136.0) (2024-01-18)
### Features
* add content sizes fixing upon grpc resource exhausted error ([#1029](https://github.com/standardnotes/server/issues/1029)) ([634e8bd](https://github.com/standardnotes/server/commit/634e8bd2d0f055abbda1150587ab9a444281e600))
# [1.135.0](https://github.com/standardnotes/server/compare/@standardnotes/syncing-server@1.134.1...@standardnotes/syncing-server@1.135.0) (2024-01-17)
### Features
* **syncing-server:** add procedure to recalculate content sizes ([#1027](https://github.com/standardnotes/server/issues/1027)) ([70bbf11](https://github.com/standardnotes/server/commit/70bbf11db504ed6305b9e9922bc38bd4b632b273))
## [1.134.1](https://github.com/standardnotes/server/compare/@standardnotes/syncing-server@1.134.0...@standardnotes/syncing-server@1.134.1) (2024-01-16)
### Bug Fixes
* **syncing-server:** missing item operations metric store expiry ([89dc6c1](https://github.com/standardnotes/server/commit/89dc6c19bf0e4a8c715f085ace5a717151d8fe9f))
# [1.134.0](https://github.com/standardnotes/server/compare/@standardnotes/syncing-server@1.133.6...@standardnotes/syncing-server@1.134.0) (2024-01-12)
### Features
* **syncing-server:** reduced abuse thresholds for free users ([#1021](https://github.com/standardnotes/server/issues/1021)) ([0443de8](https://github.com/standardnotes/server/commit/0443de88ceae3cb7c0793a3457753806b51db6e2))
## [1.133.6](https://github.com/standardnotes/server/compare/@standardnotes/syncing-server@1.133.5...@standardnotes/syncing-server@1.133.6) (2024-01-10)
### Bug Fixes
* add dedicated http code response upon a request with too large payload ([#1019](https://github.com/standardnotes/server/issues/1019)) ([6062f85](https://github.com/standardnotes/server/commit/6062f850000477983315d2d9b7c913956f755ebb))
## [1.133.5](https://github.com/standardnotes/server/compare/@standardnotes/syncing-server@1.133.4...@standardnotes/syncing-server@1.133.5) (2024-01-08)
**Note:** Version bump only for package @standardnotes/syncing-server

View File

@@ -0,0 +1,50 @@
import 'reflect-metadata'
import { Logger } from 'winston'
import { ContainerConfigLoader } from '../src/Bootstrap/Container'
import TYPES from '../src/Bootstrap/Types'
import { Env } from '../src/Bootstrap/Env'
import { FixContentSizes } from '../src/Domain/UseCase/Syncing/FixContentSizes/FixContentSizes'
import { Result } from '@standardnotes/domain-core'
const inputArgs = process.argv.slice(2)
const userUuid = inputArgs[0]
const container = new ContainerConfigLoader('worker')
void container.load().then((container) => {
const env: Env = new Env()
env.load()
const logger: Logger = container.get(TYPES.Sync_Logger)
logger.info('Starting fixing of content sizes', {
userId: userUuid,
})
const fixContentSizes = container.get<FixContentSizes>(TYPES.Sync_FixContentSizes)
Promise.resolve(fixContentSizes.execute({ userUuid }))
.then((result: Result<void>) => {
if (result.isFailed()) {
logger.error(`Error while fixing content sizes: ${result.getError()}`, {
userId: userUuid,
})
process.exit(1)
}
logger.info('Finished fixing of content sizes', {
userId: userUuid,
})
process.exit(0)
})
.catch((error) => {
logger.error(`Error while fixing content sizes: ${error.message}`, {
userId: userUuid,
})
process.exit(1)
})
})

View File

@@ -32,6 +32,10 @@ void container.load().then((container) => {
const env: Env = new Env()
env.load()
const requestPayloadLimit = env.get('HTTP_REQUEST_PAYLOAD_LIMIT_MEGABYTES', true)
? `${+env.get('HTTP_REQUEST_PAYLOAD_LIMIT_MEGABYTES', true)}mb`
: '50mb'
const server = new InversifyExpressServer(container)
server.setConfig((app) => {
@@ -61,8 +65,8 @@ void container.load().then((container) => {
}
}))
/* eslint-enable */
app.use(json({ limit: '50mb' }))
app.use(urlencoded({ extended: true, limit: '50mb', parameterLimit: 5000 }))
app.use(json({ limit: requestPayloadLimit }))
app.use(urlencoded({ extended: true, limit: requestPayloadLimit, parameterLimit: 5000 }))
app.use(cors())
})
@@ -115,8 +119,10 @@ void container.load().then((container) => {
container.get<boolean>(TYPES.Sync_STRICT_ABUSE_PROTECTION),
container.get<number>(TYPES.Sync_ITEM_OPERATIONS_ABUSE_TIMEFRAME_LENGTH_IN_MINUTES),
container.get<number>(TYPES.Sync_ITEM_OPERATIONS_ABUSE_THRESHOLD),
container.get<number>(TYPES.Sync_PAYLOAD_SIZE_ABUSE_THRESHOLD),
container.get<number>(TYPES.Sync_PAYLOAD_SIZE_ABUSE_TIMEFRAME_LENGTH_IN_MINUTES),
container.get<number>(TYPES.Sync_FREE_USERS_ITEM_OPERATIONS_ABUSE_THRESHOLD),
container.get<number>(TYPES.Sync_UPLOAD_BANDWIDTH_ABUSE_THRESHOLD),
container.get<number>(TYPES.Sync_FREE_USERS_UPLOAD_BANDWIDTH_ABUSE_THRESHOLD),
container.get<number>(TYPES.Sync_UPLOAD_BANDWIDTH_ABUSE_TIMEFRAME_LENGTH_IN_MINUTES),
container.get<winston.Logger>(TYPES.Sync_Logger),
)

View File

@@ -0,0 +1,11 @@
'use strict'
const path = require('path')
const pnp = require(path.normalize(path.resolve(__dirname, '../../..', '.pnp.cjs'))).setup()
const index = require(path.normalize(path.resolve(__dirname, '../dist/bin/content_size.js')))
Object.defineProperty(exports, '__esModule', { value: true })
exports.default = index

View File

@@ -16,6 +16,11 @@ case "$COMMAND" in
exec node docker/entrypoint-statistics.js
;;
'content-size' )
EMAIL=$1 && shift 1
exec node docker/entrypoint-content-size.js $EMAIL
;;
* )
echo "[Docker] Unknown command"
;;

View File

@@ -1,6 +1,6 @@
{
"name": "@standardnotes/syncing-server",
"version": "1.133.5",
"version": "1.136.2",
"engines": {
"node": ">=18.0.0 <21.0.0"
},

View File

@@ -167,6 +167,8 @@ import { MetricsStoreInterface } from '../Domain/Metrics/MetricsStoreInterface'
import { RedisMetricStore } from '../Infra/Redis/RedisMetricStore'
import { DummyMetricStore } from '../Infra/Dummy/DummyMetricStore'
import { CheckForTrafficAbuse } from '../Domain/UseCase/Syncing/CheckForTrafficAbuse/CheckForTrafficAbuse'
import { FixContentSizes } from '../Domain/UseCase/Syncing/FixContentSizes/FixContentSizes'
import { ContentSizesFixRequestedEventHandler } from '../Domain/Handler/ContentSizesFixRequestedEventHandler'
export class ContainerConfigLoader {
private readonly DEFAULT_CONTENT_SIZE_TRANSFER_LIMIT = 10_000_000
@@ -479,7 +481,14 @@ export class ContainerConfigLoader {
container
.bind(TYPES.Sync_ITEM_OPERATIONS_ABUSE_THRESHOLD)
.toConstantValue(
env.get('ITEM_OPERATIONS_ABUSE_THRESHOLD', true) ? +env.get('ITEM_OPERATIONS_ABUSE_THRESHOLD', true) : 500,
env.get('ITEM_OPERATIONS_ABUSE_THRESHOLD', true) ? +env.get('ITEM_OPERATIONS_ABUSE_THRESHOLD', true) : 1000,
)
container
.bind(TYPES.Sync_FREE_USERS_ITEM_OPERATIONS_ABUSE_THRESHOLD)
.toConstantValue(
env.get('FREE_USERS_ITEM_OPERATIONS_ABUSE_THRESHOLD', true)
? +env.get('FREE_USERS_ITEM_OPERATIONS_ABUSE_THRESHOLD', true)
: 500,
)
container
.bind(TYPES.Sync_ITEM_OPERATIONS_ABUSE_TIMEFRAME_LENGTH_IN_MINUTES)
@@ -489,15 +498,24 @@ export class ContainerConfigLoader {
: 5,
)
container
.bind(TYPES.Sync_PAYLOAD_SIZE_ABUSE_THRESHOLD)
.bind(TYPES.Sync_UPLOAD_BANDWIDTH_ABUSE_THRESHOLD)
.toConstantValue(
env.get('PAYLOAD_SIZE_ABUSE_THRESHOLD', true) ? +env.get('PAYLOAD_SIZE_ABUSE_THRESHOLD', true) : 20_000_000,
env.get('UPLOAD_BANDWIDTH_ABUSE_THRESHOLD', true)
? +env.get('UPLOAD_BANDWIDTH_ABUSE_THRESHOLD', true)
: 100_000_000,
)
container
.bind(TYPES.Sync_PAYLOAD_SIZE_ABUSE_TIMEFRAME_LENGTH_IN_MINUTES)
.bind(TYPES.Sync_FREE_USERS_UPLOAD_BANDWIDTH_ABUSE_THRESHOLD)
.toConstantValue(
env.get('PAYLOAD_SIZE_ABUSE_TIMEFRAME_LENGTH_IN_MINUTES', true)
? +env.get('PAYLOAD_SIZE_ABUSE_TIMEFRAME_LENGTH_IN_MINUTES', true)
env.get('FREE_USERS_UPLOAD_BANDWIDTH_ABUSE_THRESHOLD', true)
? +env.get('FREE_USERS_UPLOAD_BANDWIDTH_ABUSE_THRESHOLD', true)
: 50_000_000,
)
container
.bind(TYPES.Sync_UPLOAD_BANDWIDTH_ABUSE_TIMEFRAME_LENGTH_IN_MINUTES)
.toConstantValue(
env.get('UPLOAD_BANDWIDTH_ABUSE_TIMEFRAME_LENGTH_IN_MINUTES', true)
? +env.get('UPLOAD_BANDWIDTH_ABUSE_TIMEFRAME_LENGTH_IN_MINUTES', true)
: 5,
)
container.bind(TYPES.Sync_AUTH_JWT_SECRET).toConstantValue(env.get('AUTH_JWT_SECRET'))
@@ -939,6 +957,14 @@ export class ContainerConfigLoader {
container.get<DomainEventPublisherInterface>(TYPES.Sync_DomainEventPublisher),
),
)
container
.bind<FixContentSizes>(TYPES.Sync_FixContentSizes)
.toConstantValue(
new FixContentSizes(
container.get<ItemRepositoryInterface>(TYPES.Sync_SQLItemRepository),
container.get<Logger>(TYPES.Sync_Logger),
),
)
// Services
container
@@ -1051,6 +1077,14 @@ export class ContainerConfigLoader {
container.get<Logger>(TYPES.Sync_Logger),
),
)
container
.bind<ContentSizesFixRequestedEventHandler>(TYPES.Sync_ContentSizesFixRequestedEventHandler)
.toConstantValue(
new ContentSizesFixRequestedEventHandler(
container.get<FixContentSizes>(TYPES.Sync_FixContentSizes),
container.get<Logger>(TYPES.Sync_Logger),
),
)
// Services
container.bind<ContentDecoderInterface>(TYPES.Sync_ContentDecoder).toDynamicValue(() => new ContentDecoder())
@@ -1079,6 +1113,10 @@ export class ContainerConfigLoader {
'SHARED_VAULT_REMOVED',
container.get<SharedVaultRemovedEventHandler>(TYPES.Sync_SharedVaultRemovedEventHandler),
],
[
'CONTENT_SIZES_FIX_REQUESTED',
container.get<ContentSizesFixRequestedEventHandler>(TYPES.Sync_ContentSizesFixRequestedEventHandler),
],
])
if (!isConfiguredForHomeServer) {
container
@@ -1145,8 +1183,10 @@ export class ContainerConfigLoader {
container.get<boolean>(TYPES.Sync_STRICT_ABUSE_PROTECTION),
container.get<number>(TYPES.Sync_ITEM_OPERATIONS_ABUSE_TIMEFRAME_LENGTH_IN_MINUTES),
container.get<number>(TYPES.Sync_ITEM_OPERATIONS_ABUSE_THRESHOLD),
container.get<number>(TYPES.Sync_PAYLOAD_SIZE_ABUSE_THRESHOLD),
container.get<number>(TYPES.Sync_PAYLOAD_SIZE_ABUSE_TIMEFRAME_LENGTH_IN_MINUTES),
container.get<number>(TYPES.Sync_FREE_USERS_ITEM_OPERATIONS_ABUSE_THRESHOLD),
container.get<number>(TYPES.Sync_UPLOAD_BANDWIDTH_ABUSE_THRESHOLD),
container.get<number>(TYPES.Sync_FREE_USERS_UPLOAD_BANDWIDTH_ABUSE_THRESHOLD),
container.get<number>(TYPES.Sync_UPLOAD_BANDWIDTH_ABUSE_TIMEFRAME_LENGTH_IN_MINUTES),
container.get<ControllerContainerInterface>(TYPES.Sync_ControllerContainer),
),
)

View File

@@ -47,9 +47,11 @@ const TYPES = {
'Sync_ITEM_OPERATIONS_ABUSE_TIMEFRAME_LENGTH_IN_MINUTES',
),
Sync_ITEM_OPERATIONS_ABUSE_THRESHOLD: Symbol.for('Sync_ITEM_OPERATIONS_ABUSE_THRESHOLD'),
Sync_PAYLOAD_SIZE_ABUSE_THRESHOLD: Symbol.for('Sync_PAYLOAD_SIZE_ABUSE_THRESHOLD'),
Sync_PAYLOAD_SIZE_ABUSE_TIMEFRAME_LENGTH_IN_MINUTES: Symbol.for(
'Sync_PAYLOAD_SIZE_ABUSE_TIMEFRAME_LENGTH_IN_MINUTES',
Sync_FREE_USERS_ITEM_OPERATIONS_ABUSE_THRESHOLD: Symbol.for('Sync_FREE_USERS_ITEM_OPERATIONS_ABUSE_THRESHOLD'),
Sync_UPLOAD_BANDWIDTH_ABUSE_THRESHOLD: Symbol.for('Sync_UPLOAD_BANDWIDTH_ABUSE_THRESHOLD'),
Sync_FREE_USERS_UPLOAD_BANDWIDTH_ABUSE_THRESHOLD: Symbol.for('Sync_FREE_USERS_UPLOAD_BANDWIDTH_ABUSE_THRESHOLD'),
Sync_UPLOAD_BANDWIDTH_ABUSE_TIMEFRAME_LENGTH_IN_MINUTES: Symbol.for(
'Sync_UPLOAD_BANDWIDTH_ABUSE_TIMEFRAME_LENGTH_IN_MINUTES',
),
// use cases
Sync_SyncItems: Symbol.for('Sync_SyncItems'),
@@ -95,6 +97,7 @@ const TYPES = {
Sync_TransferSharedVaultItems: Symbol.for('Sync_TransferSharedVaultItems'),
Sync_DumpItem: Symbol.for('Sync_DumpItem'),
Sync_CheckForTrafficAbuse: Symbol.for('Sync_CheckForTrafficAbuse'),
Sync_FixContentSizes: Symbol.for('Sync_FixContentSizes'),
// Handlers
Sync_AccountDeletionRequestedEventHandler: Symbol.for('Sync_AccountDeletionRequestedEventHandler'),
Sync_AccountDeletionVerificationRequestedEventHandler: Symbol.for(
@@ -107,6 +110,7 @@ const TYPES = {
Sync_SharedVaultFileUploadedEventHandler: Symbol.for('Sync_SharedVaultFileUploadedEventHandler'),
Sync_SharedVaultFileMovedEventHandler: Symbol.for('Sync_SharedVaultFileMovedEventHandler'),
Sync_SharedVaultRemovedEventHandler: Symbol.for('Sync_SharedVaultRemovedEventHandler'),
Sync_ContentSizesFixRequestedEventHandler: Symbol.for('Sync_ContentSizesFixRequestedEventHandler'),
// Services
Sync_MetricsStore: Symbol.for('Sync_MetricsStore'),
Sync_ContentDecoder: Symbol.for('Sync_ContentDecoder'),

View File

@@ -2,4 +2,5 @@ export enum ApiVersion {
v20161215 = '20161215',
v20190520 = '20190520',
v20200115 = '20200115',
v20240226 = '20240226',
}

View File

@@ -0,0 +1,27 @@
import { ContentSizesFixRequestedEvent, DomainEventHandlerInterface } from '@standardnotes/domain-events'
import { Logger } from 'winston'
import { FixContentSizes } from '../UseCase/Syncing/FixContentSizes/FixContentSizes'
export class ContentSizesFixRequestedEventHandler implements DomainEventHandlerInterface {
constructor(
private fixContentSizes: FixContentSizes,
private logger: Logger,
) {}
async handle(event: ContentSizesFixRequestedEvent): Promise<void> {
const result = await this.fixContentSizes.execute({ userUuid: event.payload.userUuid })
if (result.isFailed()) {
this.logger.error(`Failed to fix content sizes: ${result.getError()}`, {
userId: event.payload.userUuid,
})
return
}
this.logger.info('Finished fixing content sizes', {
userId: event.payload.userUuid,
})
}
}

View File

@@ -249,4 +249,25 @@ describe('Item', () => {
expect(entity.isIdenticalTo(otherEntity)).toBeFalsy()
})
it('should calculate content size of the item', () => {
const entity = Item.create(
{
duplicateOf: null,
itemsKeyId: 'items-key-id',
content: 'content',
contentType: ContentType.create(ContentType.TYPES.Note).getValue(),
encItemKey: 'enc-item-key',
authHash: 'auth-hash',
userUuid: Uuid.create('00000000-0000-0000-0000-000000000000').getValue(),
deleted: false,
updatedWithSession: null,
dates: Dates.create(new Date(123), new Date(123)).getValue(),
timestamps: Timestamps.create(123, 123).getValue(),
},
new UniqueEntityId('00000000-0000-0000-0000-000000000000'),
).getValue()
expect(entity.calculateContentSize()).toEqual(943)
})
})

View File

@@ -16,6 +16,10 @@ export class Item extends Aggregate<ItemProps> {
return Result.ok<Item>(new Item(props, id))
}
calculateContentSize(): number {
return Buffer.byteLength(JSON.stringify(this))
}
get uuid(): Uuid {
const uuidOrError = Uuid.create(this._id.toString())
if (uuidOrError.isFailed()) {

View File

@@ -14,6 +14,7 @@ export class SyncResponseFactoryResolver implements SyncResponseFactoryResolverI
switch (apiVersion) {
case ApiVersion.v20190520:
case ApiVersion.v20200115:
case ApiVersion.v20240226:
return this.syncResponseFactory20200115
default:
return this.syncResponseFactory20161215

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