mirror of
https://github.com/standardnotes/server
synced 2026-06-07 03:39:31 -04:00
Compare commits
52 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 84cbeaf3be | |||
| 578ce0e74e | |||
| 532be7c358 | |||
| d406272f07 | |||
| 9de3352885 | |||
| 8575d20f7b | |||
| 102d4b1e8a | |||
| 1a57c247b2 | |||
| dbb0e4a974 | |||
| 5c02435ee4 | |||
| 0a1e555b13 | |||
| be668d7d7a | |||
| 87e50ec941 | |||
| 6d7ca1b926 | |||
| 00bfaaa53d | |||
| f939caf2d9 | |||
| 0f3615ee65 | |||
| 567bcf26b5 | |||
| 9d49764b84 | |||
| 5c9f493b67 | |||
| 4fe8e9a79f | |||
| f975dd9697 | |||
| 10832f7001 | |||
| 86b050865f | |||
| 6f07aaf87a | |||
| 634e8bd2d0 | |||
| 6853dfbf66 | |||
| 136cf252a1 | |||
| cad28ebba5 | |||
| 460fdf9eaf | |||
| bec1b502ad | |||
| 70bbf11db5 | |||
| c00c7becae | |||
| 89dc6c19bf | |||
| 972a91d59f | |||
| 045358ddbf | |||
| c7217a92ba | |||
| 3da7a21cde | |||
| 351e18f638 | |||
| 4f2129c4e0 | |||
| d7a1c667dd | |||
| 4de0bfa36d | |||
| 0443de88ce | |||
| f830bac873 | |||
| 517ae5ded9 | |||
| 6062f85000 | |||
| e2205c3849 | |||
| 0b46eff16e | |||
| df67982bca | |||
| d44866b3c0 | |||
| 6ee18bffe6 | |||
| a881dd2d79 |
+6
-1
@@ -17,6 +17,9 @@ SYNCING_SERVER_LOG_LEVEL=debug
|
|||||||
FILES_SERVER_LOG_LEVEL=debug
|
FILES_SERVER_LOG_LEVEL=debug
|
||||||
REVISIONS_SERVER_LOG_LEVEL=debug
|
REVISIONS_SERVER_LOG_LEVEL=debug
|
||||||
API_GATEWAY_LOG_LEVEL=debug
|
API_GATEWAY_LOG_LEVEL=debug
|
||||||
|
COOKIE_DOMAIN=localhost
|
||||||
|
COOKIE_SECURE=false
|
||||||
|
COOKIE_PARTITIONED=false
|
||||||
|
|
||||||
MYSQL_DATABASE=standard_notes_db
|
MYSQL_DATABASE=standard_notes_db
|
||||||
MYSQL_USER=std_notes_user
|
MYSQL_USER=std_notes_user
|
||||||
@@ -27,4 +30,6 @@ AUTH_JWT_SECRET=f95259c5e441f5a4646d76422cfb3df4c4488842901aa50b6c51b8be2e0040e9
|
|||||||
AUTH_SERVER_ENCRYPTION_SERVER_KEY=1087415dfde3093797f9a7ca93a49e7d7aa1861735eb0d32aae9c303b8c3d060
|
AUTH_SERVER_ENCRYPTION_SERVER_KEY=1087415dfde3093797f9a7ca93a49e7d7aa1861735eb0d32aae9c303b8c3d060
|
||||||
VALET_TOKEN_SECRET=4b886819ebe1e908077c6cae96311b48a8416bd60cc91c03060e15bdf6b30d1f
|
VALET_TOKEN_SECRET=4b886819ebe1e908077c6cae96311b48a8416bd60cc91c03060e15bdf6b30d1f
|
||||||
|
|
||||||
SYNCING_SERVER_CONTENT_SIZE_TRANSFER_LIMIT=1000000
|
SYNCING_SERVER_CONTENT_SIZE_TRANSFER_LIMIT=100000
|
||||||
|
|
||||||
|
HTTP_REQUEST_PAYLOAD_LIMIT_MEGABYTES=1
|
||||||
|
|||||||
@@ -42,26 +42,26 @@ jobs:
|
|||||||
workspace_name: ${{ inputs.workspace_name }}
|
workspace_name: ${{ inputs.workspace_name }}
|
||||||
secrets: inherit
|
secrets: inherit
|
||||||
|
|
||||||
deploy-web:
|
# deploy-web:
|
||||||
if: ${{ inputs.deploy_web }}
|
# if: ${{ inputs.deploy_web }}
|
||||||
|
|
||||||
needs: publish
|
# needs: publish
|
||||||
|
|
||||||
name: Deploy Web
|
# name: Deploy Web
|
||||||
uses: standardnotes/server/.github/workflows/common-deploy.yml@main
|
# uses: standardnotes/server/.github/workflows/common-deploy.yml@main
|
||||||
with:
|
# with:
|
||||||
service_name: ${{ inputs.service_name }}
|
# service_name: ${{ inputs.service_name }}
|
||||||
docker_image: ${{ inputs.service_name }}:${{ github.sha }}
|
# docker_image: ${{ inputs.service_name }}:${{ github.sha }}
|
||||||
secrets: inherit
|
# secrets: inherit
|
||||||
|
|
||||||
deploy-worker:
|
# deploy-worker:
|
||||||
if: ${{ inputs.deploy_worker }}
|
# if: ${{ inputs.deploy_worker }}
|
||||||
|
|
||||||
needs: publish
|
# needs: publish
|
||||||
|
|
||||||
name: Deploy Worker
|
# name: Deploy Worker
|
||||||
uses: standardnotes/server/.github/workflows/common-deploy.yml@main
|
# uses: standardnotes/server/.github/workflows/common-deploy.yml@main
|
||||||
with:
|
# with:
|
||||||
service_name: ${{ inputs.service_name }}-worker
|
# service_name: ${{ inputs.service_name }}-worker
|
||||||
docker_image: ${{ inputs.service_name }}:${{ github.sha }}
|
# docker_image: ${{ inputs.service_name }}:${{ github.sha }}
|
||||||
secrets: inherit
|
# secrets: inherit
|
||||||
|
|||||||
@@ -46,7 +46,7 @@ jobs:
|
|||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Set up Node
|
- name: Set up Node
|
||||||
uses: actions/setup-node@v3
|
uses: actions/setup-node@v4
|
||||||
with:
|
with:
|
||||||
registry-url: 'https://registry.npmjs.org'
|
registry-url: 'https://registry.npmjs.org'
|
||||||
node-version-file: '.nvmrc'
|
node-version-file: '.nvmrc'
|
||||||
@@ -70,7 +70,8 @@ jobs:
|
|||||||
echo "ACCESS_TOKEN_AGE=4" >> packages/home-server/.env
|
echo "ACCESS_TOKEN_AGE=4" >> packages/home-server/.env
|
||||||
echo "REFRESH_TOKEN_AGE=10" >> packages/home-server/.env
|
echo "REFRESH_TOKEN_AGE=10" >> packages/home-server/.env
|
||||||
echo "REVISIONS_FREQUENCY=2" >> 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_HOST=localhost" >> packages/home-server/.env
|
||||||
echo "DB_PORT=3306" >> packages/home-server/.env
|
echo "DB_PORT=3306" >> packages/home-server/.env
|
||||||
echo "DB_DATABASE=standardnotes" >> packages/home-server/.env
|
echo "DB_DATABASE=standardnotes" >> packages/home-server/.env
|
||||||
@@ -93,11 +94,11 @@ jobs:
|
|||||||
run: for i in {1..30}; do curl -s http://localhost:3123/healthcheck && break || sleep 1; done
|
run: for i in {1..30}; do curl -s http://localhost:3123/healthcheck && break || sleep 1; done
|
||||||
|
|
||||||
- name: Run E2E Test Suite
|
- name: Run E2E Test Suite
|
||||||
run: yarn dlx mocha-headless-chrome --timeout 3600000 -f http://localhost:9001/mocha/test.html?suite=${{ inputs.suite }}
|
run: yarn dlx mocha-headless-chrome --timeout 3600000 -a no-sandbox -a disable-setuid-sandbox -f http://localhost:9001/mocha/test.html?suite=${{ inputs.suite }}
|
||||||
|
|
||||||
- name: Archive failed run logs
|
- name: Archive failed run logs
|
||||||
if: ${{ failure() }}
|
if: ${{ failure() }}
|
||||||
uses: actions/upload-artifact@v3
|
uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: home-server-failure-logs-${{ inputs.suite }}-${{ matrix.db_type }}-${{ matrix.cache_type }}
|
name: home-server-failure-logs-${{ inputs.suite }}-${{ matrix.db_type }}-${{ matrix.cache_type }}
|
||||||
retention-days: 5
|
retention-days: 5
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ jobs:
|
|||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Set up Node
|
- name: Set up Node
|
||||||
uses: actions/setup-node@v3
|
uses: actions/setup-node@v4
|
||||||
with:
|
with:
|
||||||
registry-url: 'https://registry.npmjs.org'
|
registry-url: 'https://registry.npmjs.org'
|
||||||
node-version-file: '.nvmrc'
|
node-version-file: '.nvmrc'
|
||||||
@@ -57,11 +57,11 @@ jobs:
|
|||||||
run: docker/is-available.sh http://localhost:3123 $(pwd)/logs
|
run: docker/is-available.sh http://localhost:3123 $(pwd)/logs
|
||||||
|
|
||||||
- name: Run E2E Test Suite
|
- name: Run E2E Test Suite
|
||||||
run: yarn dlx mocha-headless-chrome --timeout 3600000 -f http://localhost:9001/mocha/test.html?suite=${{ inputs.suite }}
|
run: yarn dlx mocha-headless-chrome --timeout 3600000 -a no-sandbox -a disable-setuid-sandbox -f http://localhost:9001/mocha/test.html?suite=${{ inputs.suite }}
|
||||||
|
|
||||||
- name: Archive failed run logs
|
- name: Archive failed run logs
|
||||||
if: ${{ failure() }}
|
if: ${{ failure() }}
|
||||||
uses: actions/upload-artifact@v3
|
uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: self-hosted-failure-logs-${{ inputs.suite }}
|
name: self-hosted-failure-logs-${{ inputs.suite }}
|
||||||
retention-days: 5
|
retention-days: 5
|
||||||
|
|||||||
@@ -13,14 +13,14 @@ jobs:
|
|||||||
|
|
||||||
- name: Cache build
|
- name: Cache build
|
||||||
id: cache-build
|
id: cache-build
|
||||||
uses: actions/cache@v3
|
uses: actions/cache@v4
|
||||||
with:
|
with:
|
||||||
path: |
|
path: |
|
||||||
packages/**/dist
|
packages/**/dist
|
||||||
key: ${{ runner.os }}-build-${{ github.sha }}
|
key: ${{ runner.os }}-build-${{ github.sha }}
|
||||||
|
|
||||||
- name: Set up Node
|
- name: Set up Node
|
||||||
uses: actions/setup-node@v3
|
uses: actions/setup-node@v4
|
||||||
with:
|
with:
|
||||||
registry-url: 'https://registry.npmjs.org'
|
registry-url: 'https://registry.npmjs.org'
|
||||||
node-version-file: '.nvmrc'
|
node-version-file: '.nvmrc'
|
||||||
@@ -41,14 +41,14 @@ jobs:
|
|||||||
|
|
||||||
- name: Cache build
|
- name: Cache build
|
||||||
id: cache-build
|
id: cache-build
|
||||||
uses: actions/cache@v3
|
uses: actions/cache@v4
|
||||||
with:
|
with:
|
||||||
path: |
|
path: |
|
||||||
packages/**/dist
|
packages/**/dist
|
||||||
key: ${{ runner.os }}-build-${{ github.sha }}
|
key: ${{ runner.os }}-build-${{ github.sha }}
|
||||||
|
|
||||||
- name: Set up Node
|
- name: Set up Node
|
||||||
uses: actions/setup-node@v3
|
uses: actions/setup-node@v4
|
||||||
with:
|
with:
|
||||||
registry-url: 'https://registry.npmjs.org'
|
registry-url: 'https://registry.npmjs.org'
|
||||||
node-version-file: '.nvmrc'
|
node-version-file: '.nvmrc'
|
||||||
@@ -73,14 +73,14 @@ jobs:
|
|||||||
|
|
||||||
- name: Cache build
|
- name: Cache build
|
||||||
id: cache-build
|
id: cache-build
|
||||||
uses: actions/cache@v3
|
uses: actions/cache@v4
|
||||||
with:
|
with:
|
||||||
path: |
|
path: |
|
||||||
packages/**/dist
|
packages/**/dist
|
||||||
key: ${{ runner.os }}-build-${{ github.sha }}
|
key: ${{ runner.os }}-build-${{ github.sha }}
|
||||||
|
|
||||||
- name: Set up Node
|
- name: Set up Node
|
||||||
uses: actions/setup-node@v3
|
uses: actions/setup-node@v4
|
||||||
with:
|
with:
|
||||||
registry-url: 'https://registry.npmjs.org'
|
registry-url: 'https://registry.npmjs.org'
|
||||||
node-version-file: '.nvmrc'
|
node-version-file: '.nvmrc'
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ jobs:
|
|||||||
|
|
||||||
- name: Cache build
|
- name: Cache build
|
||||||
id: cache-build
|
id: cache-build
|
||||||
uses: actions/cache@v3
|
uses: actions/cache@v4
|
||||||
with:
|
with:
|
||||||
path: |
|
path: |
|
||||||
packages/**/dist
|
packages/**/dist
|
||||||
@@ -44,7 +44,7 @@ jobs:
|
|||||||
|
|
||||||
- name: Cache build
|
- name: Cache build
|
||||||
id: cache-build
|
id: cache-build
|
||||||
uses: actions/cache@v3
|
uses: actions/cache@v4
|
||||||
with:
|
with:
|
||||||
path: |
|
path: |
|
||||||
packages/**/dist
|
packages/**/dist
|
||||||
@@ -76,7 +76,7 @@ jobs:
|
|||||||
|
|
||||||
- name: Cache build
|
- name: Cache build
|
||||||
id: cache-build
|
id: cache-build
|
||||||
uses: actions/cache@v3
|
uses: actions/cache@v4
|
||||||
with:
|
with:
|
||||||
path: |
|
path: |
|
||||||
packages/**/dist
|
packages/**/dist
|
||||||
@@ -134,7 +134,7 @@ jobs:
|
|||||||
|
|
||||||
- name: Cache build
|
- name: Cache build
|
||||||
id: cache-build
|
id: cache-build
|
||||||
uses: actions/cache@v3
|
uses: actions/cache@v4
|
||||||
with:
|
with:
|
||||||
path: |
|
path: |
|
||||||
packages/**/dist
|
packages/**/dist
|
||||||
@@ -154,7 +154,7 @@ jobs:
|
|||||||
git_commit_gpgsign: true
|
git_commit_gpgsign: true
|
||||||
|
|
||||||
- name: Set up Node
|
- name: Set up Node
|
||||||
uses: actions/setup-node@v3
|
uses: actions/setup-node@v4
|
||||||
with:
|
with:
|
||||||
registry-url: 'https://registry.npmjs.org'
|
registry-url: 'https://registry.npmjs.org'
|
||||||
node-version-file: '.nvmrc'
|
node-version-file: '.nvmrc'
|
||||||
|
|||||||
@@ -466,6 +466,54 @@ const RAW_RUNTIME_STATE =
|
|||||||
["tslib", "npm:2.5.2"]\
|
["tslib", "npm:2.5.2"]\
|
||||||
],\
|
],\
|
||||||
"linkType": "HARD"\
|
"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", [\
|
["@aws-sdk/client-sqs", [\
|
||||||
@@ -607,6 +655,50 @@ const RAW_RUNTIME_STATE =
|
|||||||
["tslib", "npm:2.5.2"]\
|
["tslib", "npm:2.5.2"]\
|
||||||
],\
|
],\
|
||||||
"linkType": "HARD"\
|
"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", [\
|
["@aws-sdk/client-sts", [\
|
||||||
@@ -703,6 +795,53 @@ const RAW_RUNTIME_STATE =
|
|||||||
["tslib", "npm:2.5.2"]\
|
["tslib", "npm:2.5.2"]\
|
||||||
],\
|
],\
|
||||||
"linkType": "HARD"\
|
"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", [\
|
["@aws-sdk/core", [\
|
||||||
@@ -731,6 +870,19 @@ const RAW_RUNTIME_STATE =
|
|||||||
["tslib", "npm:2.5.2"]\
|
["tslib", "npm:2.5.2"]\
|
||||||
],\
|
],\
|
||||||
"linkType": "HARD"\
|
"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", [\
|
["@aws-sdk/credential-provider-env", [\
|
||||||
@@ -755,6 +907,17 @@ const RAW_RUNTIME_STATE =
|
|||||||
["tslib", "npm:2.5.2"]\
|
["tslib", "npm:2.5.2"]\
|
||||||
],\
|
],\
|
||||||
"linkType": "HARD"\
|
"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", [\
|
["@aws-sdk/credential-provider-ini", [\
|
||||||
@@ -791,6 +954,23 @@ const RAW_RUNTIME_STATE =
|
|||||||
["tslib", "npm:2.5.2"]\
|
["tslib", "npm:2.5.2"]\
|
||||||
],\
|
],\
|
||||||
"linkType": "HARD"\
|
"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", [\
|
["@aws-sdk/credential-provider-node", [\
|
||||||
@@ -829,6 +1009,24 @@ const RAW_RUNTIME_STATE =
|
|||||||
["tslib", "npm:2.5.2"]\
|
["tslib", "npm:2.5.2"]\
|
||||||
],\
|
],\
|
||||||
"linkType": "HARD"\
|
"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", [\
|
["@aws-sdk/credential-provider-process", [\
|
||||||
@@ -855,6 +1053,18 @@ const RAW_RUNTIME_STATE =
|
|||||||
["tslib", "npm:2.5.2"]\
|
["tslib", "npm:2.5.2"]\
|
||||||
],\
|
],\
|
||||||
"linkType": "HARD"\
|
"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", [\
|
["@aws-sdk/credential-provider-sso", [\
|
||||||
@@ -885,6 +1095,20 @@ const RAW_RUNTIME_STATE =
|
|||||||
["tslib", "npm:2.5.2"]\
|
["tslib", "npm:2.5.2"]\
|
||||||
],\
|
],\
|
||||||
"linkType": "HARD"\
|
"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", [\
|
["@aws-sdk/credential-provider-web-identity", [\
|
||||||
@@ -909,6 +1133,17 @@ const RAW_RUNTIME_STATE =
|
|||||||
["tslib", "npm:2.5.2"]\
|
["tslib", "npm:2.5.2"]\
|
||||||
],\
|
],\
|
||||||
"linkType": "HARD"\
|
"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", [\
|
["@aws-sdk/middleware-bucket-endpoint", [\
|
||||||
@@ -979,6 +1214,17 @@ const RAW_RUNTIME_STATE =
|
|||||||
["tslib", "npm:2.5.2"]\
|
["tslib", "npm:2.5.2"]\
|
||||||
],\
|
],\
|
||||||
"linkType": "HARD"\
|
"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", [\
|
["@aws-sdk/middleware-location-constraint", [\
|
||||||
@@ -1013,6 +1259,16 @@ const RAW_RUNTIME_STATE =
|
|||||||
["tslib", "npm:2.5.2"]\
|
["tslib", "npm:2.5.2"]\
|
||||||
],\
|
],\
|
||||||
"linkType": "HARD"\
|
"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", [\
|
["@aws-sdk/middleware-recursion-detection", [\
|
||||||
@@ -1037,6 +1293,17 @@ const RAW_RUNTIME_STATE =
|
|||||||
["tslib", "npm:2.5.2"]\
|
["tslib", "npm:2.5.2"]\
|
||||||
],\
|
],\
|
||||||
"linkType": "HARD"\
|
"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", [\
|
["@aws-sdk/middleware-sdk-s3", [\
|
||||||
@@ -1099,6 +1366,20 @@ const RAW_RUNTIME_STATE =
|
|||||||
["tslib", "npm:2.5.2"]\
|
["tslib", "npm:2.5.2"]\
|
||||||
],\
|
],\
|
||||||
"linkType": "HARD"\
|
"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", [\
|
["@aws-sdk/middleware-ssec", [\
|
||||||
@@ -1137,6 +1418,18 @@ const RAW_RUNTIME_STATE =
|
|||||||
["tslib", "npm:2.5.2"]\
|
["tslib", "npm:2.5.2"]\
|
||||||
],\
|
],\
|
||||||
"linkType": "HARD"\
|
"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", [\
|
["@aws-sdk/region-config-resolver", [\
|
||||||
@@ -1163,6 +1456,19 @@ const RAW_RUNTIME_STATE =
|
|||||||
["tslib", "npm:2.5.2"]\
|
["tslib", "npm:2.5.2"]\
|
||||||
],\
|
],\
|
||||||
"linkType": "HARD"\
|
"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", [\
|
["@aws-sdk/signature-v4-multi-region", [\
|
||||||
@@ -1268,6 +1574,50 @@ const RAW_RUNTIME_STATE =
|
|||||||
["tslib", "npm:2.5.2"]\
|
["tslib", "npm:2.5.2"]\
|
||||||
],\
|
],\
|
||||||
"linkType": "HARD"\
|
"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", [\
|
["@aws-sdk/types", [\
|
||||||
@@ -1296,6 +1646,15 @@ const RAW_RUNTIME_STATE =
|
|||||||
["tslib", "npm:2.5.2"]\
|
["tslib", "npm:2.5.2"]\
|
||||||
],\
|
],\
|
||||||
"linkType": "HARD"\
|
"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", [\
|
["@aws-sdk/util-arn-parser", [\
|
||||||
@@ -1328,6 +1687,17 @@ const RAW_RUNTIME_STATE =
|
|||||||
["tslib", "npm:2.5.2"]\
|
["tslib", "npm:2.5.2"]\
|
||||||
],\
|
],\
|
||||||
"linkType": "HARD"\
|
"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", [\
|
["@aws-sdk/util-locate-window", [\
|
||||||
@@ -1362,6 +1732,17 @@ const RAW_RUNTIME_STATE =
|
|||||||
["tslib", "npm:2.5.2"]\
|
["tslib", "npm:2.5.2"]\
|
||||||
],\
|
],\
|
||||||
"linkType": "HARD"\
|
"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", [\
|
["@aws-sdk/util-user-agent-node", [\
|
||||||
@@ -1379,6 +1760,30 @@ const RAW_RUNTIME_STATE =
|
|||||||
],\
|
],\
|
||||||
"linkType": "SOFT"\
|
"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", {\
|
["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/",\
|
"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": [\
|
"packageDependencies": [\
|
||||||
@@ -5951,7 +6356,7 @@ const RAW_RUNTIME_STATE =
|
|||||||
["ioredis", "npm:5.3.2"],\
|
["ioredis", "npm:5.3.2"],\
|
||||||
["jest", "virtual:fd909b174d079e30b336c4ce72c38a88c1e447767b1a8dd7655e07719a1e31b97807f0931368724fc78897ff15e6a6d00b83316c0f76d11f85111f342e08bb79#npm:29.5.0"],\
|
["jest", "virtual:fd909b174d079e30b336c4ce72c38a88c1e447767b1a8dd7655e07719a1e31b97807f0931368724fc78897ff15e6a6d00b83316c0f76d11f85111f342e08bb79#npm:29.5.0"],\
|
||||||
["mixpanel", "npm:0.17.0"],\
|
["mixpanel", "npm:0.17.0"],\
|
||||||
["mysql2", "npm:3.3.3"],\
|
["mysql2", "npm:3.9.7"],\
|
||||||
["prettier", "npm:3.0.3"],\
|
["prettier", "npm:3.0.3"],\
|
||||||
["reflect-metadata", "npm:0.2.1"],\
|
["reflect-metadata", "npm:0.2.1"],\
|
||||||
["ts-jest", "virtual:fd909b174d079e30b336c4ce72c38a88c1e447767b1a8dd7655e07719a1e31b97807f0931368724fc78897ff15e6a6d00b83316c0f76d11f85111f342e08bb79#npm:29.1.0"],\
|
["ts-jest", "virtual:fd909b174d079e30b336c4ce72c38a88c1e447767b1a8dd7655e07719a1e31b97807f0931368724fc78897ff15e6a6d00b83316c0f76d11f85111f342e08bb79#npm:29.1.0"],\
|
||||||
@@ -5983,6 +6388,7 @@ const RAW_RUNTIME_STATE =
|
|||||||
"packageLocation": "./packages/api-gateway/",\
|
"packageLocation": "./packages/api-gateway/",\
|
||||||
"packageDependencies": [\
|
"packageDependencies": [\
|
||||||
["@standardnotes/api-gateway", "workspace:packages/api-gateway"],\
|
["@standardnotes/api-gateway", "workspace:packages/api-gateway"],\
|
||||||
|
["@aws-sdk/client-sns", "npm:3.490.0"],\
|
||||||
["@grpc/grpc-js", "npm:1.9.13"],\
|
["@grpc/grpc-js", "npm:1.9.13"],\
|
||||||
["@standardnotes/domain-core", "workspace:packages/domain-core"],\
|
["@standardnotes/domain-core", "workspace:packages/domain-core"],\
|
||||||
["@standardnotes/domain-events", "workspace:packages/domain-events"],\
|
["@standardnotes/domain-events", "workspace:packages/domain-events"],\
|
||||||
@@ -5990,6 +6396,7 @@ const RAW_RUNTIME_STATE =
|
|||||||
["@standardnotes/grpc", "workspace:packages/grpc"],\
|
["@standardnotes/grpc", "workspace:packages/grpc"],\
|
||||||
["@standardnotes/security", "workspace:packages/security"],\
|
["@standardnotes/security", "workspace:packages/security"],\
|
||||||
["@standardnotes/time", "workspace:packages/time"],\
|
["@standardnotes/time", "workspace:packages/time"],\
|
||||||
|
["@types/cookie-parser", "npm:1.4.6"],\
|
||||||
["@types/cors", "npm:2.8.13"],\
|
["@types/cors", "npm:2.8.13"],\
|
||||||
["@types/express", "npm:4.17.17"],\
|
["@types/express", "npm:4.17.17"],\
|
||||||
["@types/ioredis", "npm:5.0.0"],\
|
["@types/ioredis", "npm:5.0.0"],\
|
||||||
@@ -6001,6 +6408,7 @@ const RAW_RUNTIME_STATE =
|
|||||||
["@typescript-eslint/parser", "virtual:fd909b174d079e30b336c4ce72c38a88c1e447767b1a8dd7655e07719a1e31b97807f0931368724fc78897ff15e6a6d00b83316c0f76d11f85111f342e08bb79#npm:6.5.0"],\
|
["@typescript-eslint/parser", "virtual:fd909b174d079e30b336c4ce72c38a88c1e447767b1a8dd7655e07719a1e31b97807f0931368724fc78897ff15e6a6d00b83316c0f76d11f85111f342e08bb79#npm:6.5.0"],\
|
||||||
["agentkeepalive", "npm:4.5.0"],\
|
["agentkeepalive", "npm:4.5.0"],\
|
||||||
["axios", "npm:1.6.1"],\
|
["axios", "npm:1.6.1"],\
|
||||||
|
["cookie-parser", "npm:1.4.6"],\
|
||||||
["cors", "npm:2.8.5"],\
|
["cors", "npm:2.8.5"],\
|
||||||
["dotenv", "npm:16.1.3"],\
|
["dotenv", "npm:16.1.3"],\
|
||||||
["eslint", "npm:8.41.0"],\
|
["eslint", "npm:8.41.0"],\
|
||||||
@@ -6051,6 +6459,7 @@ const RAW_RUNTIME_STATE =
|
|||||||
["@standardnotes/sncrypto-node", "workspace:packages/sncrypto-node"],\
|
["@standardnotes/sncrypto-node", "workspace:packages/sncrypto-node"],\
|
||||||
["@standardnotes/time", "workspace:packages/time"],\
|
["@standardnotes/time", "workspace:packages/time"],\
|
||||||
["@types/bcryptjs", "npm:2.4.2"],\
|
["@types/bcryptjs", "npm:2.4.2"],\
|
||||||
|
["@types/cookie-parser", "npm:1.4.6"],\
|
||||||
["@types/cors", "npm:2.8.13"],\
|
["@types/cors", "npm:2.8.13"],\
|
||||||
["@types/express", "npm:4.17.17"],\
|
["@types/express", "npm:4.17.17"],\
|
||||||
["@types/ioredis", "npm:5.0.0"],\
|
["@types/ioredis", "npm:5.0.0"],\
|
||||||
@@ -6062,7 +6471,10 @@ const RAW_RUNTIME_STATE =
|
|||||||
["@types/uuid", "npm:9.0.3"],\
|
["@types/uuid", "npm:9.0.3"],\
|
||||||
["@typescript-eslint/eslint-plugin", "virtual:fd909b174d079e30b336c4ce72c38a88c1e447767b1a8dd7655e07719a1e31b97807f0931368724fc78897ff15e6a6d00b83316c0f76d11f85111f342e08bb79#npm:6.5.0"],\
|
["@typescript-eslint/eslint-plugin", "virtual:fd909b174d079e30b336c4ce72c38a88c1e447767b1a8dd7655e07719a1e31b97807f0931368724fc78897ff15e6a6d00b83316c0f76d11f85111f342e08bb79#npm:6.5.0"],\
|
||||||
["@typescript-eslint/parser", "virtual:fd909b174d079e30b336c4ce72c38a88c1e447767b1a8dd7655e07719a1e31b97807f0931368724fc78897ff15e6a6d00b83316c0f76d11f85111f342e08bb79#npm:6.5.0"],\
|
["@typescript-eslint/parser", "virtual:fd909b174d079e30b336c4ce72c38a88c1e447767b1a8dd7655e07719a1e31b97807f0931368724fc78897ff15e6a6d00b83316c0f76d11f85111f342e08bb79#npm:6.5.0"],\
|
||||||
|
["agentkeepalive", "npm:4.5.0"],\
|
||||||
|
["axios", "npm:1.6.7"],\
|
||||||
["bcryptjs", "npm:2.4.3"],\
|
["bcryptjs", "npm:2.4.3"],\
|
||||||
|
["cookie-parser", "npm:1.4.6"],\
|
||||||
["cors", "npm:2.8.5"],\
|
["cors", "npm:2.8.5"],\
|
||||||
["dayjs", "npm:1.11.7"],\
|
["dayjs", "npm:1.11.7"],\
|
||||||
["dotenv", "npm:16.1.3"],\
|
["dotenv", "npm:16.1.3"],\
|
||||||
@@ -6073,7 +6485,7 @@ const RAW_RUNTIME_STATE =
|
|||||||
["inversify-express-utils", "npm:6.4.3"],\
|
["inversify-express-utils", "npm:6.4.3"],\
|
||||||
["ioredis", "npm:5.3.2"],\
|
["ioredis", "npm:5.3.2"],\
|
||||||
["jest", "virtual:fd909b174d079e30b336c4ce72c38a88c1e447767b1a8dd7655e07719a1e31b97807f0931368724fc78897ff15e6a6d00b83316c0f76d11f85111f342e08bb79#npm:29.5.0"],\
|
["jest", "virtual:fd909b174d079e30b336c4ce72c38a88c1e447767b1a8dd7655e07719a1e31b97807f0931368724fc78897ff15e6a6d00b83316c0f76d11f85111f342e08bb79#npm:29.5.0"],\
|
||||||
["mysql2", "npm:3.3.3"],\
|
["mysql2", "npm:3.9.7"],\
|
||||||
["otplib", "npm:12.0.1"],\
|
["otplib", "npm:12.0.1"],\
|
||||||
["prettier", "npm:3.0.3"],\
|
["prettier", "npm:3.0.3"],\
|
||||||
["prettyjson", "npm:1.2.5"],\
|
["prettyjson", "npm:1.2.5"],\
|
||||||
@@ -6283,10 +6695,12 @@ const RAW_RUNTIME_STATE =
|
|||||||
["@standardnotes/files-server", "workspace:packages/files"],\
|
["@standardnotes/files-server", "workspace:packages/files"],\
|
||||||
["@standardnotes/revisions-server", "workspace:packages/revisions"],\
|
["@standardnotes/revisions-server", "workspace:packages/revisions"],\
|
||||||
["@standardnotes/syncing-server", "workspace:packages/syncing-server"],\
|
["@standardnotes/syncing-server", "workspace:packages/syncing-server"],\
|
||||||
|
["@types/cookie-parser", "npm:1.4.6"],\
|
||||||
["@types/cors", "npm:2.8.13"],\
|
["@types/cors", "npm:2.8.13"],\
|
||||||
["@types/express", "npm:4.17.17"],\
|
["@types/express", "npm:4.17.17"],\
|
||||||
["@typescript-eslint/eslint-plugin", "virtual:fd909b174d079e30b336c4ce72c38a88c1e447767b1a8dd7655e07719a1e31b97807f0931368724fc78897ff15e6a6d00b83316c0f76d11f85111f342e08bb79#npm:6.5.0"],\
|
["@typescript-eslint/eslint-plugin", "virtual:fd909b174d079e30b336c4ce72c38a88c1e447767b1a8dd7655e07719a1e31b97807f0931368724fc78897ff15e6a6d00b83316c0f76d11f85111f342e08bb79#npm:6.5.0"],\
|
||||||
["@typescript-eslint/parser", "virtual:fd909b174d079e30b336c4ce72c38a88c1e447767b1a8dd7655e07719a1e31b97807f0931368724fc78897ff15e6a6d00b83316c0f76d11f85111f342e08bb79#npm:6.5.0"],\
|
["@typescript-eslint/parser", "virtual:fd909b174d079e30b336c4ce72c38a88c1e447767b1a8dd7655e07719a1e31b97807f0931368724fc78897ff15e6a6d00b83316c0f76d11f85111f342e08bb79#npm:6.5.0"],\
|
||||||
|
["cookie-parser", "npm:1.4.6"],\
|
||||||
["cors", "npm:2.8.5"],\
|
["cors", "npm:2.8.5"],\
|
||||||
["dotenv", "npm:16.1.3"],\
|
["dotenv", "npm:16.1.3"],\
|
||||||
["eslint", "npm:8.41.0"],\
|
["eslint", "npm:8.41.0"],\
|
||||||
@@ -6384,7 +6798,7 @@ const RAW_RUNTIME_STATE =
|
|||||||
["inversify-express-utils", "npm:6.4.3"],\
|
["inversify-express-utils", "npm:6.4.3"],\
|
||||||
["ioredis", "npm:5.3.2"],\
|
["ioredis", "npm:5.3.2"],\
|
||||||
["jest", "virtual:fd909b174d079e30b336c4ce72c38a88c1e447767b1a8dd7655e07719a1e31b97807f0931368724fc78897ff15e6a6d00b83316c0f76d11f85111f342e08bb79#npm:29.5.0"],\
|
["jest", "virtual:fd909b174d079e30b336c4ce72c38a88c1e447767b1a8dd7655e07719a1e31b97807f0931368724fc78897ff15e6a6d00b83316c0f76d11f85111f342e08bb79#npm:29.5.0"],\
|
||||||
["mysql2", "npm:3.3.3"],\
|
["mysql2", "npm:3.9.7"],\
|
||||||
["prettier", "npm:3.0.3"],\
|
["prettier", "npm:3.0.3"],\
|
||||||
["reflect-metadata", "npm:0.2.1"],\
|
["reflect-metadata", "npm:0.2.1"],\
|
||||||
["sqlite3", "virtual:31b5a94a105c89c9294c3d524a7f8929fe63ee5a2efadf21951ca4c0cfd2ecf02e8f4ef5a066bbda091f1e3a56e57c6749069a080618c96b22e51131a330fc4a#npm:5.1.6"],\
|
["sqlite3", "virtual:31b5a94a105c89c9294c3d524a7f8929fe63ee5a2efadf21951ca4c0cfd2ecf02e8f4ef5a066bbda091f1e3a56e57c6749069a080618c96b22e51131a330fc4a#npm:5.1.6"],\
|
||||||
@@ -6403,6 +6817,7 @@ const RAW_RUNTIME_STATE =
|
|||||||
["@standardnotes/scheduler-server", "workspace:packages/scheduler"],\
|
["@standardnotes/scheduler-server", "workspace:packages/scheduler"],\
|
||||||
["@aws-sdk/client-sns", "npm:3.484.0"],\
|
["@aws-sdk/client-sns", "npm:3.484.0"],\
|
||||||
["@aws-sdk/client-sqs", "npm:3.484.0"],\
|
["@aws-sdk/client-sqs", "npm:3.484.0"],\
|
||||||
|
["@standardnotes/common", "workspace:packages/common"],\
|
||||||
["@standardnotes/domain-core", "workspace:packages/domain-core"],\
|
["@standardnotes/domain-core", "workspace:packages/domain-core"],\
|
||||||
["@standardnotes/domain-events", "workspace:packages/domain-events"],\
|
["@standardnotes/domain-events", "workspace:packages/domain-events"],\
|
||||||
["@standardnotes/domain-events-infra", "workspace:packages/domain-events-infra"],\
|
["@standardnotes/domain-events-infra", "workspace:packages/domain-events-infra"],\
|
||||||
@@ -6420,7 +6835,7 @@ const RAW_RUNTIME_STATE =
|
|||||||
["inversify", "npm:6.0.1"],\
|
["inversify", "npm:6.0.1"],\
|
||||||
["ioredis", "npm:5.3.2"],\
|
["ioredis", "npm:5.3.2"],\
|
||||||
["jest", "virtual:fd909b174d079e30b336c4ce72c38a88c1e447767b1a8dd7655e07719a1e31b97807f0931368724fc78897ff15e6a6d00b83316c0f76d11f85111f342e08bb79#npm:29.5.0"],\
|
["jest", "virtual:fd909b174d079e30b336c4ce72c38a88c1e447767b1a8dd7655e07719a1e31b97807f0931368724fc78897ff15e6a6d00b83316c0f76d11f85111f342e08bb79#npm:29.5.0"],\
|
||||||
["mysql2", "npm:3.3.3"],\
|
["mysql2", "npm:3.9.7"],\
|
||||||
["prettier", "npm:3.0.3"],\
|
["prettier", "npm:3.0.3"],\
|
||||||
["reflect-metadata", "npm:0.2.1"],\
|
["reflect-metadata", "npm:0.2.1"],\
|
||||||
["ts-jest", "virtual:fd909b174d079e30b336c4ce72c38a88c1e447767b1a8dd7655e07719a1e31b97807f0931368724fc78897ff15e6a6d00b83316c0f76d11f85111f342e08bb79#npm:29.1.0"],\
|
["ts-jest", "virtual:fd909b174d079e30b336c4ce72c38a88c1e447767b1a8dd7655e07719a1e31b97807f0931368724fc78897ff15e6a6d00b83316c0f76d11f85111f342e08bb79#npm:29.1.0"],\
|
||||||
@@ -6571,7 +6986,7 @@ const RAW_RUNTIME_STATE =
|
|||||||
["ioredis", "npm:5.3.2"],\
|
["ioredis", "npm:5.3.2"],\
|
||||||
["jest", "virtual:fd909b174d079e30b336c4ce72c38a88c1e447767b1a8dd7655e07719a1e31b97807f0931368724fc78897ff15e6a6d00b83316c0f76d11f85111f342e08bb79#npm:29.5.0"],\
|
["jest", "virtual:fd909b174d079e30b336c4ce72c38a88c1e447767b1a8dd7655e07719a1e31b97807f0931368724fc78897ff15e6a6d00b83316c0f76d11f85111f342e08bb79#npm:29.5.0"],\
|
||||||
["jsonwebtoken", "npm:9.0.0"],\
|
["jsonwebtoken", "npm:9.0.0"],\
|
||||||
["mysql2", "npm:3.3.3"],\
|
["mysql2", "npm:3.9.7"],\
|
||||||
["prettier", "npm:3.0.3"],\
|
["prettier", "npm:3.0.3"],\
|
||||||
["prettyjson", "npm:1.2.5"],\
|
["prettyjson", "npm:1.2.5"],\
|
||||||
["reflect-metadata", "npm:0.2.1"],\
|
["reflect-metadata", "npm:0.2.1"],\
|
||||||
@@ -6651,7 +7066,7 @@ const RAW_RUNTIME_STATE =
|
|||||||
["inversify-express-utils", "npm:6.4.3"],\
|
["inversify-express-utils", "npm:6.4.3"],\
|
||||||
["ioredis", "npm:5.3.2"],\
|
["ioredis", "npm:5.3.2"],\
|
||||||
["jest", "virtual:fd909b174d079e30b336c4ce72c38a88c1e447767b1a8dd7655e07719a1e31b97807f0931368724fc78897ff15e6a6d00b83316c0f76d11f85111f342e08bb79#npm:29.5.0"],\
|
["jest", "virtual:fd909b174d079e30b336c4ce72c38a88c1e447767b1a8dd7655e07719a1e31b97807f0931368724fc78897ff15e6a6d00b83316c0f76d11f85111f342e08bb79#npm:29.5.0"],\
|
||||||
["mysql2", "npm:3.3.3"],\
|
["mysql2", "npm:3.9.7"],\
|
||||||
["prettier", "npm:3.0.3"],\
|
["prettier", "npm:3.0.3"],\
|
||||||
["reflect-metadata", "npm:0.2.1"],\
|
["reflect-metadata", "npm:0.2.1"],\
|
||||||
["ts-jest", "virtual:fd909b174d079e30b336c4ce72c38a88c1e447767b1a8dd7655e07719a1e31b97807f0931368724fc78897ff15e6a6d00b83316c0f76d11f85111f342e08bb79#npm:29.1.0"],\
|
["ts-jest", "virtual:fd909b174d079e30b336c4ce72c38a88c1e447767b1a8dd7655e07719a1e31b97807f0931368724fc78897ff15e6a6d00b83316c0f76d11f85111f342e08bb79#npm:29.1.0"],\
|
||||||
@@ -6831,6 +7246,16 @@ const RAW_RUNTIME_STATE =
|
|||||||
"linkType": "HARD"\
|
"linkType": "HARD"\
|
||||||
}]\
|
}]\
|
||||||
]],\
|
]],\
|
||||||
|
["@types/cookie-parser", [\
|
||||||
|
["npm:1.4.6", {\
|
||||||
|
"packageLocation": "./.yarn/cache/@types-cookie-parser-npm-1.4.6-27287e1e43-b1bbb17bc4.zip/node_modules/@types/cookie-parser/",\
|
||||||
|
"packageDependencies": [\
|
||||||
|
["@types/cookie-parser", "npm:1.4.6"],\
|
||||||
|
["@types/express", "npm:4.17.17"]\
|
||||||
|
],\
|
||||||
|
"linkType": "HARD"\
|
||||||
|
}]\
|
||||||
|
]],\
|
||||||
["@types/cors", [\
|
["@types/cors", [\
|
||||||
["npm:2.8.13", {\
|
["npm:2.8.13", {\
|
||||||
"packageLocation": "./.yarn/cache/@types-cors-npm-2.8.13-4b8ac1068f-7ef197ea19.zip/node_modules/@types/cors/",\
|
"packageLocation": "./.yarn/cache/@types-cors-npm-2.8.13-4b8ac1068f-7ef197ea19.zip/node_modules/@types/cors/",\
|
||||||
@@ -8091,6 +8516,16 @@ const RAW_RUNTIME_STATE =
|
|||||||
["proxy-from-env", "npm:1.1.0"]\
|
["proxy-from-env", "npm:1.1.0"]\
|
||||||
],\
|
],\
|
||||||
"linkType": "HARD"\
|
"linkType": "HARD"\
|
||||||
|
}],\
|
||||||
|
["npm:1.6.7", {\
|
||||||
|
"packageLocation": "./.yarn/cache/axios-npm-1.6.7-d7b9974d1b-a1932b089e.zip/node_modules/axios/",\
|
||||||
|
"packageDependencies": [\
|
||||||
|
["axios", "npm:1.6.7"],\
|
||||||
|
["follow-redirects", "virtual:d7b9974d1bba76881cc57a280a16dd4914416a6fc4923c2efbb6328057412974da1e719cef1530b7a62b97d85d828f7e1d49b5f6de3b5b0854d49902ec87827c#npm:1.15.5"],\
|
||||||
|
["form-data", "npm:4.0.0"],\
|
||||||
|
["proxy-from-env", "npm:1.1.0"]\
|
||||||
|
],\
|
||||||
|
"linkType": "HARD"\
|
||||||
}]\
|
}]\
|
||||||
]],\
|
]],\
|
||||||
["babel-jest", [\
|
["babel-jest", [\
|
||||||
@@ -9202,6 +9637,13 @@ const RAW_RUNTIME_STATE =
|
|||||||
}]\
|
}]\
|
||||||
]],\
|
]],\
|
||||||
["cookie", [\
|
["cookie", [\
|
||||||
|
["npm:0.4.1", {\
|
||||||
|
"packageLocation": "./.yarn/cache/cookie-npm-0.4.1-cc5e2ebb42-0f2defd60a.zip/node_modules/cookie/",\
|
||||||
|
"packageDependencies": [\
|
||||||
|
["cookie", "npm:0.4.1"]\
|
||||||
|
],\
|
||||||
|
"linkType": "HARD"\
|
||||||
|
}],\
|
||||||
["npm:0.5.0", {\
|
["npm:0.5.0", {\
|
||||||
"packageLocation": "./.yarn/cache/cookie-npm-0.5.0-e2d58a161a-aae7911ddc.zip/node_modules/cookie/",\
|
"packageLocation": "./.yarn/cache/cookie-npm-0.5.0-e2d58a161a-aae7911ddc.zip/node_modules/cookie/",\
|
||||||
"packageDependencies": [\
|
"packageDependencies": [\
|
||||||
@@ -9210,6 +9652,17 @@ const RAW_RUNTIME_STATE =
|
|||||||
"linkType": "HARD"\
|
"linkType": "HARD"\
|
||||||
}]\
|
}]\
|
||||||
]],\
|
]],\
|
||||||
|
["cookie-parser", [\
|
||||||
|
["npm:1.4.6", {\
|
||||||
|
"packageLocation": "./.yarn/cache/cookie-parser-npm-1.4.6-a68f84d02a-1e5a63aa82.zip/node_modules/cookie-parser/",\
|
||||||
|
"packageDependencies": [\
|
||||||
|
["cookie-parser", "npm:1.4.6"],\
|
||||||
|
["cookie", "npm:0.4.1"],\
|
||||||
|
["cookie-signature", "npm:1.0.6"]\
|
||||||
|
],\
|
||||||
|
"linkType": "HARD"\
|
||||||
|
}]\
|
||||||
|
]],\
|
||||||
["cookie-signature", [\
|
["cookie-signature", [\
|
||||||
["npm:1.0.6", {\
|
["npm:1.0.6", {\
|
||||||
"packageLocation": "./.yarn/cache/cookie-signature-npm-1.0.6-93f325f7f0-f4e1b0a98a.zip/node_modules/cookie-signature/",\
|
"packageLocation": "./.yarn/cache/cookie-signature-npm-1.0.6-93f325f7f0-f4e1b0a98a.zip/node_modules/cookie-signature/",\
|
||||||
@@ -10458,6 +10911,26 @@ const RAW_RUNTIME_STATE =
|
|||||||
],\
|
],\
|
||||||
"linkType": "SOFT"\
|
"linkType": "SOFT"\
|
||||||
}],\
|
}],\
|
||||||
|
["npm:1.15.5", {\
|
||||||
|
"packageLocation": "./.yarn/cache/follow-redirects-npm-1.15.5-9d14db76ca-d467f13c1c.zip/node_modules/follow-redirects/",\
|
||||||
|
"packageDependencies": [\
|
||||||
|
["follow-redirects", "npm:1.15.5"]\
|
||||||
|
],\
|
||||||
|
"linkType": "SOFT"\
|
||||||
|
}],\
|
||||||
|
["virtual:d7b9974d1bba76881cc57a280a16dd4914416a6fc4923c2efbb6328057412974da1e719cef1530b7a62b97d85d828f7e1d49b5f6de3b5b0854d49902ec87827c#npm:1.15.5", {\
|
||||||
|
"packageLocation": "./.yarn/__virtual__/follow-redirects-virtual-393395f3f6/0/cache/follow-redirects-npm-1.15.5-9d14db76ca-d467f13c1c.zip/node_modules/follow-redirects/",\
|
||||||
|
"packageDependencies": [\
|
||||||
|
["follow-redirects", "virtual:d7b9974d1bba76881cc57a280a16dd4914416a6fc4923c2efbb6328057412974da1e719cef1530b7a62b97d85d828f7e1d49b5f6de3b5b0854d49902ec87827c#npm:1.15.5"],\
|
||||||
|
["@types/debug", null],\
|
||||||
|
["debug", null]\
|
||||||
|
],\
|
||||||
|
"packagePeers": [\
|
||||||
|
"@types/debug",\
|
||||||
|
"debug"\
|
||||||
|
],\
|
||||||
|
"linkType": "HARD"\
|
||||||
|
}],\
|
||||||
["virtual:ffaff76449f02e83712a7d24e03c564489516739c78ebeffb0fbcdb3893ad9a0e48504f9acfa70fe6f16debe9c8dabde3679d63bf648278ea98a5ff38cf77a9e#npm:1.15.2", {\
|
["virtual:ffaff76449f02e83712a7d24e03c564489516739c78ebeffb0fbcdb3893ad9a0e48504f9acfa70fe6f16debe9c8dabde3679d63bf648278ea98a5ff38cf77a9e#npm:1.15.2", {\
|
||||||
"packageLocation": "./.yarn/__virtual__/follow-redirects-virtual-c2d5794c26/0/cache/follow-redirects-npm-1.15.2-1ec1dd82be-8be0d39919.zip/node_modules/follow-redirects/",\
|
"packageLocation": "./.yarn/__virtual__/follow-redirects-virtual-c2d5794c26/0/cache/follow-redirects-npm-1.15.2-1ec1dd82be-8be0d39919.zip/node_modules/follow-redirects/",\
|
||||||
"packageDependencies": [\
|
"packageDependencies": [\
|
||||||
@@ -13377,10 +13850,10 @@ const RAW_RUNTIME_STATE =
|
|||||||
}]\
|
}]\
|
||||||
]],\
|
]],\
|
||||||
["mysql2", [\
|
["mysql2", [\
|
||||||
["npm:3.3.3", {\
|
["npm:3.9.7", {\
|
||||||
"packageLocation": "./.yarn/cache/mysql2-npm-3.3.3-d2fe8cf512-4bf7ace8f1.zip/node_modules/mysql2/",\
|
"packageLocation": "./.yarn/cache/mysql2-npm-3.9.7-8fe89e50ac-7f43b17cc0.zip/node_modules/mysql2/",\
|
||||||
"packageDependencies": [\
|
"packageDependencies": [\
|
||||||
["mysql2", "npm:3.3.3"],\
|
["mysql2", "npm:3.9.7"],\
|
||||||
["denque", "npm:2.1.0"],\
|
["denque", "npm:2.1.0"],\
|
||||||
["generate-function", "npm:2.3.1"],\
|
["generate-function", "npm:2.3.1"],\
|
||||||
["iconv-lite", "npm:0.6.3"],\
|
["iconv-lite", "npm:0.6.3"],\
|
||||||
@@ -16430,7 +16903,7 @@ const RAW_RUNTIME_STATE =
|
|||||||
["mkdirp", "npm:2.1.6"],\
|
["mkdirp", "npm:2.1.6"],\
|
||||||
["mongodb", null],\
|
["mongodb", null],\
|
||||||
["mssql", null],\
|
["mssql", null],\
|
||||||
["mysql2", "npm:3.3.3"],\
|
["mysql2", "npm:3.9.7"],\
|
||||||
["oracledb", null],\
|
["oracledb", null],\
|
||||||
["pg", null],\
|
["pg", null],\
|
||||||
["pg-native", null],\
|
["pg-native", null],\
|
||||||
@@ -16522,7 +16995,7 @@ const RAW_RUNTIME_STATE =
|
|||||||
["mkdirp", "npm:2.1.6"],\
|
["mkdirp", "npm:2.1.6"],\
|
||||||
["mongodb", null],\
|
["mongodb", null],\
|
||||||
["mssql", null],\
|
["mssql", null],\
|
||||||
["mysql2", "npm:3.3.3"],\
|
["mysql2", "npm:3.9.7"],\
|
||||||
["oracledb", null],\
|
["oracledb", null],\
|
||||||
["pg", null],\
|
["pg", null],\
|
||||||
["pg-native", null],\
|
["pg-native", null],\
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
BIN
Binary file not shown.
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -54,7 +54,6 @@ services:
|
|||||||
ports:
|
ports:
|
||||||
- 3306
|
- 3306
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
command: --default-authentication-plugin=mysql_native_password --character-set-server=utf8mb4 --collation-server=utf8mb4_general_ci
|
|
||||||
volumes:
|
volumes:
|
||||||
- ./data/mysql:/var/lib/mysql
|
- ./data/mysql:/var/lib/mysql
|
||||||
- ./data/import:/docker-entrypoint-initdb.d
|
- ./data/import:/docker-entrypoint-initdb.d
|
||||||
|
|||||||
@@ -39,7 +39,6 @@ services:
|
|||||||
expose:
|
expose:
|
||||||
- 3306
|
- 3306
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
command: --default-authentication-plugin=mysql_native_password --character-set-server=utf8mb4 --collation-server=utf8mb4_general_ci
|
|
||||||
volumes:
|
volumes:
|
||||||
- ./data/mysql:/var/lib/mysql
|
- ./data/mysql:/var/lib/mysql
|
||||||
- ./data/import:/docker-entrypoint-initdb.d
|
- ./data/import:/docker-entrypoint-initdb.d
|
||||||
|
|||||||
+2
-2
@@ -21,7 +21,7 @@
|
|||||||
"publish": "lerna publish from-git --yes --no-verify-access --loglevel verbose",
|
"publish": "lerna publish from-git --yes --no-verify-access --loglevel verbose",
|
||||||
"postversion": "./scripts/push-tags-one-by-one.sh",
|
"postversion": "./scripts/push-tags-one-by-one.sh",
|
||||||
"e2e": "yarn build && PORT=3123 yarn workspace @standardnotes/home-server start",
|
"e2e": "yarn build && PORT=3123 yarn workspace @standardnotes/home-server start",
|
||||||
"start": "yarn workspace @standardnotes/home-server run build && yarn workspace @standardnotes/home-server start"
|
"start": "yarn build && yarn workspace @standardnotes/home-server start"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@commitlint/cli": "^17.0.2",
|
"@commitlint/cli": "^17.0.2",
|
||||||
@@ -39,7 +39,7 @@
|
|||||||
"ts-node": "^10.9.1",
|
"ts-node": "^10.9.1",
|
||||||
"typescript": "^5.0.4"
|
"typescript": "^5.0.4"
|
||||||
},
|
},
|
||||||
"packageManager": "yarn@4.0.2",
|
"packageManager": "yarn@4.1.0",
|
||||||
"dependenciesMeta": {
|
"dependenciesMeta": {
|
||||||
"grpc-tools@1.12.4": {
|
"grpc-tools@1.12.4": {
|
||||||
"unplugged": true
|
"unplugged": true
|
||||||
|
|||||||
@@ -3,6 +3,18 @@
|
|||||||
All notable changes to this project will be documented in this file.
|
All notable changes to this project will be documented in this file.
|
||||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||||
|
|
||||||
|
## [2.34.17](https://github.com/standardnotes/server/compare/@standardnotes/analytics@2.34.16...@standardnotes/analytics@2.34.17) (2024-06-18)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @standardnotes/analytics
|
||||||
|
|
||||||
|
## [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)
|
## [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
|
**Note:** Version bump only for package @standardnotes/analytics
|
||||||
|
|||||||
@@ -10,6 +10,12 @@ RUN corepack enable
|
|||||||
|
|
||||||
COPY ./ /workspace
|
COPY ./ /workspace
|
||||||
|
|
||||||
|
WORKDIR /workspace
|
||||||
|
|
||||||
|
RUN yarn install --immutable
|
||||||
|
|
||||||
|
RUN yarn build
|
||||||
|
|
||||||
WORKDIR /workspace/packages/analytics
|
WORKDIR /workspace/packages/analytics
|
||||||
|
|
||||||
ENTRYPOINT [ "/workspace/packages/analytics/docker/entrypoint.sh" ]
|
ENTRYPOINT [ "/workspace/packages/analytics/docker/entrypoint.sh" ]
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@standardnotes/analytics",
|
"name": "@standardnotes/analytics",
|
||||||
"version": "2.34.14",
|
"version": "2.34.17",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=18.0.0 <21.0.0"
|
"node": ">=18.0.0 <21.0.0"
|
||||||
},
|
},
|
||||||
@@ -24,7 +24,7 @@
|
|||||||
"build": "tsc --build",
|
"build": "tsc --build",
|
||||||
"lint": "eslint . --ext .ts",
|
"lint": "eslint . --ext .ts",
|
||||||
"lint:fix": "eslint . --ext .ts --fix",
|
"lint:fix": "eslint . --ext .ts --fix",
|
||||||
"test": "jest --coverage --no-cache --config=./jest.config.js --maxWorkers=50%",
|
"test": "jest --coverage --no-cache --config=./jest.config.js --maxWorkers=2",
|
||||||
"worker": "yarn node dist/bin/worker.js",
|
"worker": "yarn node dist/bin/worker.js",
|
||||||
"report": "yarn node dist/bin/report.js",
|
"report": "yarn node dist/bin/report.js",
|
||||||
"setup:env": "cp .env.sample .env",
|
"setup:env": "cp .env.sample .env",
|
||||||
@@ -57,7 +57,7 @@
|
|||||||
"inversify": "^6.0.1",
|
"inversify": "^6.0.1",
|
||||||
"ioredis": "^5.2.4",
|
"ioredis": "^5.2.4",
|
||||||
"mixpanel": "^0.17.0",
|
"mixpanel": "^0.17.0",
|
||||||
"mysql2": "^3.0.1",
|
"mysql2": "^3.9.7",
|
||||||
"reflect-metadata": "^0.2.1",
|
"reflect-metadata": "^0.2.1",
|
||||||
"typeorm": "^0.3.17",
|
"typeorm": "^0.3.17",
|
||||||
"winston": "^3.8.1"
|
"winston": "^3.8.1"
|
||||||
|
|||||||
@@ -5,6 +5,8 @@ import { AnalyticsActivity } from '../Analytics/AnalyticsActivity'
|
|||||||
import { StatisticMeasureName } from '../Statistics/StatisticMeasureName'
|
import { StatisticMeasureName } from '../Statistics/StatisticMeasureName'
|
||||||
import { Period } from '../Time/Period'
|
import { Period } from '../Time/Period'
|
||||||
|
|
||||||
|
import { safeHtml } from '@standardnotes/common'
|
||||||
|
|
||||||
const countActiveUsers = (measureName: string, data: any): { yesterday: number; last30Days: number } => {
|
const countActiveUsers = (measureName: string, data: any): { yesterday: number; last30Days: number } => {
|
||||||
const totalActiveUsersLast30DaysIncludingToday = data.statisticsOverTime.find(
|
const totalActiveUsersLast30DaysIncludingToday = data.statisticsOverTime.find(
|
||||||
(a: { name: string; period: number }) => a.name === measureName && a.period === 27,
|
(a: { name: string; period: number }) => a.name === measureName && a.period === 27,
|
||||||
@@ -567,7 +569,7 @@ export const html = (data: any, timer: TimerInterface) => {
|
|||||||
const totalActivePlusUsers = countActiveUsers(StatisticMeasureName.NAMES.ActivePlusUsers, data)
|
const totalActivePlusUsers = countActiveUsers(StatisticMeasureName.NAMES.ActivePlusUsers, data)
|
||||||
const totalActiveProUsers = countActiveUsers(StatisticMeasureName.NAMES.ActiveProUsers, data)
|
const totalActiveProUsers = countActiveUsers(StatisticMeasureName.NAMES.ActiveProUsers, data)
|
||||||
|
|
||||||
return ` <div>
|
return safeHtml` <div>
|
||||||
<p>Hello,</p>
|
<p>Hello,</p>
|
||||||
<p>
|
<p>
|
||||||
<strong>Here are some statistics from yesterday:</strong>
|
<strong>Here are some statistics from yesterday:</strong>
|
||||||
|
|||||||
@@ -3,6 +3,38 @@
|
|||||||
All notable changes to this project will be documented in this file.
|
All notable changes to this project will be documented in this file.
|
||||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||||
|
|
||||||
|
## [1.92.1](https://github.com/standardnotes/server/compare/@standardnotes/api-gateway@1.91.0...@standardnotes/api-gateway@1.92.1) (2024-06-18)
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **api-gateway:** bump version ([102d4b1](https://github.com/standardnotes/server/commit/102d4b1e8ab000fc97d01c621654b6fc65e37d32))
|
||||||
|
|
||||||
|
## [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
|
||||||
|
|
||||||
## [1.89.17](https://github.com/standardnotes/server/compare/@standardnotes/api-gateway@1.89.16...@standardnotes/api-gateway@1.89.17) (2024-01-04)
|
## [1.89.17](https://github.com/standardnotes/server/compare/@standardnotes/api-gateway@1.89.16...@standardnotes/api-gateway@1.89.17) (2024-01-04)
|
||||||
|
|
||||||
### Bug Fixes
|
### Bug Fixes
|
||||||
|
|||||||
@@ -10,6 +10,12 @@ RUN corepack enable
|
|||||||
|
|
||||||
COPY ./ /workspace
|
COPY ./ /workspace
|
||||||
|
|
||||||
|
WORKDIR /workspace
|
||||||
|
|
||||||
|
RUN yarn install --immutable
|
||||||
|
|
||||||
|
RUN yarn build
|
||||||
|
|
||||||
WORKDIR /workspace/packages/api-gateway
|
WORKDIR /workspace/packages/api-gateway
|
||||||
|
|
||||||
ENTRYPOINT [ "/workspace/packages/api-gateway/docker/entrypoint.sh" ]
|
ENTRYPOINT [ "/workspace/packages/api-gateway/docker/entrypoint.sh" ]
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ import '../src/Controller/v2/RevisionsControllerV2'
|
|||||||
|
|
||||||
import helmet from 'helmet'
|
import helmet from 'helmet'
|
||||||
import * as cors from 'cors'
|
import * as cors from 'cors'
|
||||||
|
import * as cookieParser from 'cookie-parser'
|
||||||
import { text, json, Request, Response, NextFunction } from 'express'
|
import { text, json, Request, Response, NextFunction } from 'express'
|
||||||
import * as winston from 'winston'
|
import * as winston from 'winston'
|
||||||
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
||||||
@@ -36,15 +37,35 @@ import { InversifyExpressServer } from 'inversify-express-utils'
|
|||||||
import { ContainerConfigLoader } from '../src/Bootstrap/Container'
|
import { ContainerConfigLoader } from '../src/Bootstrap/Container'
|
||||||
import { TYPES } from '../src/Bootstrap/Types'
|
import { TYPES } from '../src/Bootstrap/Types'
|
||||||
import { Env } from '../src/Bootstrap/Env'
|
import { Env } from '../src/Bootstrap/Env'
|
||||||
|
import { ResponseLocals } from '../src/Controller/ResponseLocals'
|
||||||
|
|
||||||
const container = new ContainerConfigLoader()
|
const container = new ContainerConfigLoader()
|
||||||
void container.load().then((container) => {
|
void container.load().then((container) => {
|
||||||
const env: Env = new Env()
|
const env: Env = new Env()
|
||||||
env.load()
|
env.load()
|
||||||
|
|
||||||
|
const requestPayloadLimit = env.get('HTTP_REQUEST_PAYLOAD_LIMIT_MEGABYTES', true)
|
||||||
|
? `${+env.get('HTTP_REQUEST_PAYLOAD_LIMIT_MEGABYTES', true)}mb`
|
||||||
|
: '50mb'
|
||||||
|
|
||||||
|
const logger: winston.Logger = container.get(TYPES.ApiGateway_Logger)
|
||||||
|
|
||||||
const server = new InversifyExpressServer(container)
|
const server = new InversifyExpressServer(container)
|
||||||
|
|
||||||
server.setConfig((app) => {
|
server.setConfig((app) => {
|
||||||
|
app.use((request: Request, _response: Response, next: NextFunction) => {
|
||||||
|
if (request.hostname.includes('standardnotes.org')) {
|
||||||
|
logger.warn('Request is using deprecated domain', {
|
||||||
|
origin: request.headers.origin,
|
||||||
|
method: request.method,
|
||||||
|
url: request.url,
|
||||||
|
snjs: request.headers['x-snjs-version'],
|
||||||
|
application: request.headers['x-application-version'],
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
next()
|
||||||
|
})
|
||||||
app.use((_request: Request, response: Response, next: NextFunction) => {
|
app.use((_request: Request, response: Response, next: NextFunction) => {
|
||||||
response.setHeader('X-API-Gateway-Version', container.get(TYPES.ApiGateway_VERSION))
|
response.setHeader('X-API-Gateway-Version', container.get(TYPES.ApiGateway_VERSION))
|
||||||
next()
|
next()
|
||||||
@@ -72,13 +93,57 @@ void container.load().then((container) => {
|
|||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
|
|
||||||
app.use(json({ limit: '50mb' }))
|
app.use(cookieParser())
|
||||||
|
|
||||||
|
app.use(json({ limit: requestPayloadLimit }))
|
||||||
app.use(
|
app.use(
|
||||||
text({
|
text({
|
||||||
type: ['text/plain', 'application/x-www-form-urlencoded', 'application/x-www-form-urlencoded; charset=utf-8'],
|
type: ['text/plain', 'application/x-www-form-urlencoded', 'application/x-www-form-urlencoded; charset=utf-8'],
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
app.use(cors())
|
const corsAllowedOrigins = container.get<string[]>(TYPES.ApiGateway_CORS_ALLOWED_ORIGINS)
|
||||||
|
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(
|
app.use(
|
||||||
robots({
|
robots({
|
||||||
UserAgent: '*',
|
UserAgent: '*',
|
||||||
@@ -87,16 +152,18 @@ void container.load().then((container) => {
|
|||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
const logger: winston.Logger = container.get(TYPES.ApiGateway_Logger)
|
|
||||||
|
|
||||||
server.setErrorConfig((app) => {
|
server.setErrorConfig((app) => {
|
||||||
app.use((error: Record<string, unknown>, request: Request, response: Response, _next: NextFunction) => {
|
app.use((error: Record<string, unknown>, request: Request, response: Response, _next: NextFunction) => {
|
||||||
|
const locals = response.locals as ResponseLocals
|
||||||
|
|
||||||
logger.error(`${error.stack}`, {
|
logger.error(`${error.stack}`, {
|
||||||
|
origin: request.headers.origin,
|
||||||
|
codeTag: 'server.ts',
|
||||||
method: request.method,
|
method: request.method,
|
||||||
url: request.url,
|
url: request.url,
|
||||||
snjs: request.headers['x-snjs-version'],
|
snjs: request.headers['x-snjs-version'],
|
||||||
application: request.headers['x-application-version'],
|
application: request.headers['x-application-version'],
|
||||||
userId: response.locals.user ? response.locals.user.uuid : undefined,
|
userId: locals.user ? locals.user.uuid : undefined,
|
||||||
})
|
})
|
||||||
logger.debug(
|
logger.debug(
|
||||||
`[URL: |${request.method}| ${request.url}][SNJS: ${request.headers['x-snjs-version']}][Application: ${
|
`[URL: |${request.method}| ${request.url}][SNJS: ${request.headers['x-snjs-version']}][Application: ${
|
||||||
@@ -104,6 +171,16 @@ void container.load().then((container) => {
|
|||||||
}] Request body: ${JSON.stringify(request.body)}`,
|
}] 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({
|
response.status(500).send({
|
||||||
error: {
|
error: {
|
||||||
message:
|
message:
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@standardnotes/api-gateway",
|
"name": "@standardnotes/api-gateway",
|
||||||
"version": "1.89.17",
|
"version": "1.92.1",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=18.0.0 <21.0.0"
|
"node": ">=18.0.0 <21.0.0"
|
||||||
},
|
},
|
||||||
@@ -31,6 +31,7 @@
|
|||||||
"start": "yarn node dist/bin/server.js"
|
"start": "yarn node dist/bin/server.js"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@aws-sdk/client-sns": "^3.490.0",
|
||||||
"@grpc/grpc-js": "^1.9.13",
|
"@grpc/grpc-js": "^1.9.13",
|
||||||
"@standardnotes/domain-core": "workspace:^",
|
"@standardnotes/domain-core": "workspace:^",
|
||||||
"@standardnotes/domain-events": "workspace:*",
|
"@standardnotes/domain-events": "workspace:*",
|
||||||
@@ -40,6 +41,7 @@
|
|||||||
"@standardnotes/time": "workspace:*",
|
"@standardnotes/time": "workspace:*",
|
||||||
"agentkeepalive": "^4.5.0",
|
"agentkeepalive": "^4.5.0",
|
||||||
"axios": "^1.6.1",
|
"axios": "^1.6.1",
|
||||||
|
"cookie-parser": "^1.4.6",
|
||||||
"cors": "2.8.5",
|
"cors": "2.8.5",
|
||||||
"dotenv": "^16.0.1",
|
"dotenv": "^16.0.1",
|
||||||
"express": "^4.18.2",
|
"express": "^4.18.2",
|
||||||
@@ -54,6 +56,7 @@
|
|||||||
"winston": "^3.8.1"
|
"winston": "^3.8.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"@types/cookie-parser": "^1",
|
||||||
"@types/cors": "^2.8.9",
|
"@types/cors": "^2.8.9",
|
||||||
"@types/express": "^4.17.14",
|
"@types/express": "^4.17.14",
|
||||||
"@types/ioredis": "^5.0.0",
|
"@types/ioredis": "^5.0.0",
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import * as winston from 'winston'
|
import * as winston from 'winston'
|
||||||
import * as AgentKeepAlive from 'agentkeepalive'
|
import * as AgentKeepAlive from 'agentkeepalive'
|
||||||
import * as grpc from '@grpc/grpc-js'
|
import * as grpc from '@grpc/grpc-js'
|
||||||
|
import { SNSClient, SNSClientConfig } from '@aws-sdk/client-sns'
|
||||||
import axios, { AxiosInstance } from 'axios'
|
import axios, { AxiosInstance } from 'axios'
|
||||||
import Redis from 'ioredis'
|
import Redis from 'ioredis'
|
||||||
import { Container } from 'inversify'
|
import { Container } from 'inversify'
|
||||||
@@ -29,6 +30,10 @@ import { SyncResponseHttpRepresentation } from '../Mapping/Sync/Http/SyncRespons
|
|||||||
import { SyncRequestGRPCMapper } from '../Mapping/Sync/GRPC/SyncRequestGRPCMapper'
|
import { SyncRequestGRPCMapper } from '../Mapping/Sync/GRPC/SyncRequestGRPCMapper'
|
||||||
import { SyncResponseGRPCMapper } from '../Mapping/Sync/GRPC/SyncResponseGRPCMapper'
|
import { SyncResponseGRPCMapper } from '../Mapping/Sync/GRPC/SyncResponseGRPCMapper'
|
||||||
import { GRPCWebSocketAuthMiddleware } from '../Controller/GRPCWebSocketAuthMiddleware'
|
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 {
|
export class ContainerConfigLoader {
|
||||||
async load(configuration?: {
|
async load(configuration?: {
|
||||||
@@ -51,6 +56,34 @@ export class ContainerConfigLoader {
|
|||||||
.bind<boolean>(TYPES.ApiGateway_IS_CONFIGURED_FOR_HOME_SERVER_OR_SELF_HOSTING)
|
.bind<boolean>(TYPES.ApiGateway_IS_CONFIGURED_FOR_HOME_SERVER_OR_SELF_HOSTING)
|
||||||
.toConstantValue(isConfiguredForHomeServerOrSelfHosting)
|
.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()]
|
const winstonFormatters = [winston.format.splat(), winston.format.json()]
|
||||||
|
|
||||||
let logger: winston.Logger
|
let logger: winston.Logger
|
||||||
@@ -109,6 +142,10 @@ export class ContainerConfigLoader {
|
|||||||
.bind(TYPES.ApiGateway_CROSS_SERVICE_TOKEN_CACHE_TTL)
|
.bind(TYPES.ApiGateway_CROSS_SERVICE_TOKEN_CACHE_TTL)
|
||||||
.toConstantValue(+env.get('CROSS_SERVICE_TOKEN_CACHE_TTL', true))
|
.toConstantValue(+env.get('CROSS_SERVICE_TOKEN_CACHE_TTL', true))
|
||||||
container.bind(TYPES.ApiGateway_IS_CONFIGURED_FOR_HOME_SERVER).toConstantValue(isConfiguredForHomeServer)
|
container.bind(TYPES.ApiGateway_IS_CONFIGURED_FOR_HOME_SERVER).toConstantValue(isConfiguredForHomeServer)
|
||||||
|
container
|
||||||
|
.bind<string[]>(TYPES.ApiGateway_CORS_ALLOWED_ORIGINS)
|
||||||
|
.toConstantValue(env.get('CORS_ALLOWED_ORIGINS', true) ? env.get('CORS_ALLOWED_ORIGINS', true).split(',') : [])
|
||||||
|
container.bind<string>(TYPES.ApiGateway_CAPTCHA_UI_URL).toConstantValue(env.get('CAPTCHA_UI_URL', true))
|
||||||
|
|
||||||
// Middleware
|
// Middleware
|
||||||
container
|
container
|
||||||
@@ -124,14 +161,14 @@ export class ContainerConfigLoader {
|
|||||||
// Services
|
// Services
|
||||||
container.bind<TimerInterface>(TYPES.ApiGateway_Timer).toConstantValue(new Timer())
|
container.bind<TimerInterface>(TYPES.ApiGateway_Timer).toConstantValue(new Timer())
|
||||||
|
|
||||||
if (isConfiguredForHomeServer) {
|
if (isConfiguredForInMemoryCache) {
|
||||||
container
|
container
|
||||||
.bind<CrossServiceTokenCacheInterface>(TYPES.ApiGateway_CrossServiceTokenCache)
|
.bind<CrossServiceTokenCacheInterface>(TYPES.ApiGateway_CrossServiceTokenCache)
|
||||||
.toConstantValue(new InMemoryCrossServiceTokenCache(container.get(TYPES.ApiGateway_Timer)))
|
.toConstantValue(new InMemoryCrossServiceTokenCache(container.get(TYPES.ApiGateway_Timer)))
|
||||||
} else {
|
} else {
|
||||||
container
|
container
|
||||||
.bind<CrossServiceTokenCacheInterface>(TYPES.ApiGateway_CrossServiceTokenCache)
|
.bind<CrossServiceTokenCacheInterface>(TYPES.ApiGateway_CrossServiceTokenCache)
|
||||||
.to(RedisCrossServiceTokenCache)
|
.toConstantValue(new RedisCrossServiceTokenCache(container.get(TYPES.ApiGateway_Redis)))
|
||||||
}
|
}
|
||||||
container
|
container
|
||||||
.bind<EndpointResolverInterface>(TYPES.ApiGateway_EndpointResolver)
|
.bind<EndpointResolverInterface>(TYPES.ApiGateway_EndpointResolver)
|
||||||
@@ -192,6 +229,10 @@ export class ContainerConfigLoader {
|
|||||||
.bind<MapperInterface<SyncResponse, SyncResponseHttpRepresentation>>(TYPES.Mapper_SyncResponseGRPCMapper)
|
.bind<MapperInterface<SyncResponse, SyncResponseHttpRepresentation>>(TYPES.Mapper_SyncResponseGRPCMapper)
|
||||||
.toConstantValue(new SyncResponseGRPCMapper())
|
.toConstantValue(new SyncResponseGRPCMapper())
|
||||||
|
|
||||||
|
container
|
||||||
|
.bind<DomainEventFactoryInterface>(TYPES.ApiGateway_DomainEventFactory)
|
||||||
|
.toConstantValue(new DomainEventFactory(container.get<TimerInterface>(TYPES.ApiGateway_Timer)))
|
||||||
|
|
||||||
container
|
container
|
||||||
.bind<GRPCSyncingServerServiceProxy>(TYPES.ApiGateway_GRPCSyncingServerServiceProxy)
|
.bind<GRPCSyncingServerServiceProxy>(TYPES.ApiGateway_GRPCSyncingServerServiceProxy)
|
||||||
.toConstantValue(
|
.toConstantValue(
|
||||||
@@ -202,6 +243,10 @@ export class ContainerConfigLoader {
|
|||||||
TYPES.Mapper_SyncResponseGRPCMapper,
|
TYPES.Mapper_SyncResponseGRPCMapper,
|
||||||
),
|
),
|
||||||
container.get<winston.Logger>(TYPES.ApiGateway_Logger),
|
container.get<winston.Logger>(TYPES.ApiGateway_Logger),
|
||||||
|
container.get<DomainEventFactoryInterface>(TYPES.ApiGateway_DomainEventFactory),
|
||||||
|
isConfiguredForHomeServerOrSelfHosting
|
||||||
|
? undefined
|
||||||
|
: container.get<DomainEventPublisherInterface>(TYPES.ApiGateway_DomainEventPublisher),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
container
|
container
|
||||||
|
|||||||
@@ -2,7 +2,12 @@ export const TYPES = {
|
|||||||
ApiGateway_Logger: Symbol.for('ApiGateway_Logger'),
|
ApiGateway_Logger: Symbol.for('ApiGateway_Logger'),
|
||||||
ApiGateway_Redis: Symbol.for('ApiGateway_Redis'),
|
ApiGateway_Redis: Symbol.for('ApiGateway_Redis'),
|
||||||
ApiGateway_HTTPClient: Symbol.for('ApiGateway_HTTPClient'),
|
ApiGateway_HTTPClient: Symbol.for('ApiGateway_HTTPClient'),
|
||||||
|
ApiGateway_SNS: Symbol.for('ApiGateway_SNS'),
|
||||||
|
ApiGateway_DomainEventPublisher: Symbol.for('ApiGateway_DomainEventPublisher'),
|
||||||
// env vars
|
// env vars
|
||||||
|
ApiGateway_CORS_ALLOWED_ORIGINS: Symbol.for('ApiGateway_CORS_ALLOWED_ORIGINS'),
|
||||||
|
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_SYNCING_SERVER_JS_URL: Symbol.for('ApiGateway_SYNCING_SERVER_JS_URL'),
|
||||||
ApiGateway_AUTH_SERVER_URL: Symbol.for('ApiGateway_AUTH_SERVER_URL'),
|
ApiGateway_AUTH_SERVER_URL: Symbol.for('ApiGateway_AUTH_SERVER_URL'),
|
||||||
ApiGateway_AUTH_SERVER_GRPC_URL: Symbol.for('ApiGateway_AUTH_SERVER_GRPC_URL'),
|
ApiGateway_AUTH_SERVER_GRPC_URL: Symbol.for('ApiGateway_AUTH_SERVER_GRPC_URL'),
|
||||||
@@ -20,6 +25,7 @@ export const TYPES = {
|
|||||||
ApiGateway_IS_CONFIGURED_FOR_HOME_SERVER_OR_SELF_HOSTING: Symbol.for(
|
ApiGateway_IS_CONFIGURED_FOR_HOME_SERVER_OR_SELF_HOSTING: Symbol.for(
|
||||||
'ApiGateway_IS_CONFIGURED_FOR_HOME_SERVER_OR_SELF_HOSTING',
|
'ApiGateway_IS_CONFIGURED_FOR_HOME_SERVER_OR_SELF_HOSTING',
|
||||||
),
|
),
|
||||||
|
ApiGateway_CAPTCHA_UI_URL: Symbol.for('ApiGateway_CAPTCHA_UI_URL'),
|
||||||
// Middleware
|
// Middleware
|
||||||
ApiGateway_RequiredCrossServiceTokenMiddleware: Symbol.for('ApiGateway_RequiredCrossServiceTokenMiddleware'),
|
ApiGateway_RequiredCrossServiceTokenMiddleware: Symbol.for('ApiGateway_RequiredCrossServiceTokenMiddleware'),
|
||||||
ApiGateway_OptionalCrossServiceTokenMiddleware: Symbol.for('ApiGateway_OptionalCrossServiceTokenMiddleware'),
|
ApiGateway_OptionalCrossServiceTokenMiddleware: Symbol.for('ApiGateway_OptionalCrossServiceTokenMiddleware'),
|
||||||
@@ -29,6 +35,7 @@ export const TYPES = {
|
|||||||
Mapper_SyncRequestGRPCMapper: Symbol.for('Mapper_SyncRequestGRPCMapper'),
|
Mapper_SyncRequestGRPCMapper: Symbol.for('Mapper_SyncRequestGRPCMapper'),
|
||||||
Mapper_SyncResponseGRPCMapper: Symbol.for('Mapper_SyncResponseGRPCMapper'),
|
Mapper_SyncResponseGRPCMapper: Symbol.for('Mapper_SyncResponseGRPCMapper'),
|
||||||
// Services
|
// Services
|
||||||
|
ApiGateway_DomainEventFactory: Symbol.for('ApiGateway_DomainEventFactory'),
|
||||||
ApiGateway_GRPCSyncingServerServiceProxy: Symbol.for('ApiGateway_GRPCSyncingServerServiceProxy'),
|
ApiGateway_GRPCSyncingServerServiceProxy: Symbol.for('ApiGateway_GRPCSyncingServerServiceProxy'),
|
||||||
ApiGateway_ServiceProxy: Symbol.for('ApiGateway_ServiceProxy'),
|
ApiGateway_ServiceProxy: Symbol.for('ApiGateway_ServiceProxy'),
|
||||||
ApiGateway_CrossServiceTokenCache: Symbol.for('ApiGateway_CrossServiceTokenCache'),
|
ApiGateway_CrossServiceTokenCache: Symbol.for('ApiGateway_CrossServiceTokenCache'),
|
||||||
|
|||||||
@@ -8,6 +8,8 @@ import { Logger } from 'winston'
|
|||||||
|
|
||||||
import { CrossServiceTokenCacheInterface } from '../Service/Cache/CrossServiceTokenCacheInterface'
|
import { CrossServiceTokenCacheInterface } from '../Service/Cache/CrossServiceTokenCacheInterface'
|
||||||
import { ServiceProxyInterface } from '../Service/Proxy/ServiceProxyInterface'
|
import { ServiceProxyInterface } from '../Service/Proxy/ServiceProxyInterface'
|
||||||
|
import { ResponseLocals } from './ResponseLocals'
|
||||||
|
import { RoleName } from '@standardnotes/domain-core'
|
||||||
|
|
||||||
export abstract class AuthMiddleware extends BaseMiddleware {
|
export abstract class AuthMiddleware extends BaseMiddleware {
|
||||||
constructor(
|
constructor(
|
||||||
@@ -40,9 +42,33 @@ export abstract class AuthMiddleware extends BaseMiddleware {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (crossServiceToken === null) {
|
if (crossServiceToken === null) {
|
||||||
|
const cookiesFromHeaders = new Map<string, string[]>()
|
||||||
|
request.headers.cookie?.split(';').forEach((cookie) => {
|
||||||
|
const parts = cookie.split('=')
|
||||||
|
if (parts.length === 2) {
|
||||||
|
const existingCookies = cookiesFromHeaders.get(parts[0].trim())
|
||||||
|
if (existingCookies) {
|
||||||
|
existingCookies.push(parts[1].trim())
|
||||||
|
cookiesFromHeaders.set(parts[0].trim(), existingCookies)
|
||||||
|
} else {
|
||||||
|
cookiesFromHeaders.set(parts[0].trim(), [parts[1].trim()])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
const authResponse = await this.serviceProxy.validateSession({
|
const authResponse = await this.serviceProxy.validateSession({
|
||||||
authorization: authHeaderValue,
|
headers: {
|
||||||
sharedVaultOwnerContext: sharedVaultOwnerContextHeaderValue,
|
authorization: authHeaderValue.replace('Bearer ', ''),
|
||||||
|
sharedVaultOwnerContext: sharedVaultOwnerContextHeaderValue,
|
||||||
|
},
|
||||||
|
requestMetadata: {
|
||||||
|
snjs: request.headers['x-snjs-version'] as string,
|
||||||
|
application: request.headers['x-application-version'] as string,
|
||||||
|
url: request.url,
|
||||||
|
method: request.method,
|
||||||
|
userAgent: request.headers['user-agent'],
|
||||||
|
secChUa: request.headers['sec-ch-ua'] as string,
|
||||||
|
},
|
||||||
|
cookies: cookiesFromHeaders,
|
||||||
})
|
})
|
||||||
|
|
||||||
if (!this.handleSessionValidationResponse(authResponse, response, next)) {
|
if (!this.handleSessionValidationResponse(authResponse, response, next)) {
|
||||||
@@ -55,33 +81,27 @@ export abstract class AuthMiddleware extends BaseMiddleware {
|
|||||||
crossServiceTokenFetchedFromCache = false
|
crossServiceTokenFetchedFromCache = false
|
||||||
}
|
}
|
||||||
|
|
||||||
response.locals.authToken = crossServiceToken
|
const decodedToken = <CrossServiceTokenData>verify(crossServiceToken, this.jwtSecret, { algorithms: ['HS256'] })
|
||||||
|
|
||||||
const decodedToken = <CrossServiceTokenData>(
|
|
||||||
verify(response.locals.authToken, this.jwtSecret, { algorithms: ['HS256'] })
|
|
||||||
)
|
|
||||||
|
|
||||||
if (this.crossServiceTokenCacheTTL && !crossServiceTokenFetchedFromCache) {
|
if (this.crossServiceTokenCacheTTL && !crossServiceTokenFetchedFromCache) {
|
||||||
await this.crossServiceTokenCache.set({
|
await this.crossServiceTokenCache.set({
|
||||||
key: cacheKey,
|
key: cacheKey,
|
||||||
encodedCrossServiceToken: response.locals.authToken,
|
encodedCrossServiceToken: crossServiceToken,
|
||||||
expiresAtInSeconds: this.getCrossServiceTokenCacheExpireTimestamp(decodedToken),
|
expiresAtInSeconds: this.getCrossServiceTokenCacheExpireTimestamp(decodedToken),
|
||||||
userUuid: decodedToken.user.uuid,
|
userUuid: decodedToken.user.uuid,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
response.locals.user = decodedToken.user
|
Object.assign(response.locals, {
|
||||||
response.locals.session = decodedToken.session
|
authToken: crossServiceToken,
|
||||||
response.locals.roles = decodedToken.roles
|
user: decodedToken.user,
|
||||||
response.locals.sharedVaultOwnerContext = decodedToken.shared_vault_owner_context
|
session: decodedToken.session,
|
||||||
response.locals.readOnlyAccess = decodedToken.session?.readonly_access ?? false
|
roles: decodedToken.roles,
|
||||||
if (response.locals.readOnlyAccess) {
|
sharedVaultOwnerContext: decodedToken.shared_vault_owner_context,
|
||||||
this.logger.debug('User operates on read-only access', {
|
readOnlyAccess: decodedToken.session?.readonly_access ?? false,
|
||||||
codeTag: 'AuthMiddleware',
|
isFreeUser: decodedToken.roles.length === 1 && decodedToken.roles[0].name === RoleName.NAMES.CoreUser,
|
||||||
userId: response.locals.user.uuid,
|
belongsToSharedVaults: decodedToken.belongs_to_shared_vaults ?? [],
|
||||||
})
|
} as ResponseLocals)
|
||||||
}
|
|
||||||
response.locals.belongsToSharedVaults = decodedToken.belongs_to_shared_vaults ?? []
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
let detailedErrorMessage = (error as Error).message
|
let detailedErrorMessage = (error as Error).message
|
||||||
if (error instanceof AxiosError) {
|
if (error instanceof AxiosError) {
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import { verify } from 'jsonwebtoken'
|
|||||||
import { Logger } from 'winston'
|
import { Logger } from 'winston'
|
||||||
import { ConnectionValidationResponse, IAuthClient, WebsocketConnectionAuthorizationHeader } from '@standardnotes/grpc'
|
import { ConnectionValidationResponse, IAuthClient, WebsocketConnectionAuthorizationHeader } from '@standardnotes/grpc'
|
||||||
import { RoleName } from '@standardnotes/domain-core'
|
import { RoleName } from '@standardnotes/domain-core'
|
||||||
|
import { ResponseLocals } from './ResponseLocals'
|
||||||
|
|
||||||
export class GRPCWebSocketAuthMiddleware extends BaseMiddleware {
|
export class GRPCWebSocketAuthMiddleware extends BaseMiddleware {
|
||||||
constructor(
|
constructor(
|
||||||
@@ -90,15 +91,17 @@ export class GRPCWebSocketAuthMiddleware extends BaseMiddleware {
|
|||||||
|
|
||||||
const crossServiceToken = authResponse.data.authToken as string
|
const crossServiceToken = authResponse.data.authToken as string
|
||||||
|
|
||||||
response.locals.authToken = crossServiceToken
|
|
||||||
|
|
||||||
const decodedToken = <CrossServiceTokenData>verify(crossServiceToken, this.jwtSecret, { algorithms: ['HS256'] })
|
const decodedToken = <CrossServiceTokenData>verify(crossServiceToken, this.jwtSecret, { algorithms: ['HS256'] })
|
||||||
|
|
||||||
response.locals.user = decodedToken.user
|
Object.assign(response.locals, {
|
||||||
response.locals.session = decodedToken.session
|
authToken: crossServiceToken,
|
||||||
response.locals.roles = decodedToken.roles
|
user: decodedToken.user,
|
||||||
response.locals.isFreeUser =
|
session: decodedToken.session,
|
||||||
decodedToken.roles.length === 1 && decodedToken.roles[0].name === RoleName.NAMES.CoreUser
|
roles: decodedToken.roles,
|
||||||
|
isFreeUser: decodedToken.roles.length === 1 && decodedToken.roles[0].name === RoleName.NAMES.CoreUser,
|
||||||
|
readOnlyAccess: decodedToken.session?.readonly_access ?? false,
|
||||||
|
hasContentLimit: decodedToken.hasContentLimit,
|
||||||
|
} as ResponseLocals)
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
this.logger.error(
|
this.logger.error(
|
||||||
`Could not pass the request to websocket connection validation on underlying service: ${
|
`Could not pass the request to websocket connection validation on underlying service: ${
|
||||||
|
|||||||
@@ -20,8 +20,6 @@ export class LegacyController extends BaseHttpController {
|
|||||||
['DELETE:/session', 'DELETE:session'],
|
['DELETE:/session', 'DELETE:session'],
|
||||||
['DELETE:/session/all', 'DELETE:session/all'],
|
['DELETE:/session/all', 'DELETE:session/all'],
|
||||||
['POST:/session/refresh', 'POST:session/refresh'],
|
['POST:/session/refresh', 'POST:session/refresh'],
|
||||||
['POST:/auth/sign_in', 'POST:auth/sign_in'],
|
|
||||||
['GET:/auth/params', 'GET:auth/params'],
|
|
||||||
])
|
])
|
||||||
|
|
||||||
this.PARAMETRIZED_AUTH_ROUTES = new Map([
|
this.PARAMETRIZED_AUTH_ROUTES = new Map([
|
||||||
|
|||||||
@@ -0,0 +1,5 @@
|
|||||||
|
export interface OfflineResponseLocals {
|
||||||
|
offlineAuthToken: string
|
||||||
|
userEmail: string
|
||||||
|
featuresToken: string
|
||||||
|
}
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
import { Role } from '@standardnotes/security'
|
||||||
|
|
||||||
|
export interface ResponseLocals {
|
||||||
|
authToken: string
|
||||||
|
user: {
|
||||||
|
uuid: string
|
||||||
|
email: string
|
||||||
|
}
|
||||||
|
roles: Array<Role>
|
||||||
|
session?: {
|
||||||
|
uuid: string
|
||||||
|
api_version: string
|
||||||
|
created_at: string
|
||||||
|
updated_at: string
|
||||||
|
device_info: string
|
||||||
|
readonly_access: boolean
|
||||||
|
access_expiration: string
|
||||||
|
refresh_expiration: string
|
||||||
|
}
|
||||||
|
readOnlyAccess: boolean
|
||||||
|
isFreeUser: boolean
|
||||||
|
belongsToSharedVaults?: Array<{
|
||||||
|
shared_vault_uuid: string
|
||||||
|
permission: string
|
||||||
|
}>
|
||||||
|
sharedVaultOwnerContext?: {
|
||||||
|
upload_bytes_limit: number
|
||||||
|
}
|
||||||
|
hasContentLimit: boolean
|
||||||
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
import { TokenAuthenticationMethod } from './TokenAuthenticationMethod'
|
||||||
|
|
||||||
|
export interface SubscriptionResponseLocals {
|
||||||
|
tokenAuthenticationMethod: TokenAuthenticationMethod
|
||||||
|
}
|
||||||
@@ -7,6 +7,9 @@ import { AxiosError, AxiosInstance, AxiosResponse } from 'axios'
|
|||||||
import { Logger } from 'winston'
|
import { Logger } from 'winston'
|
||||||
import { TYPES } from '../Bootstrap/Types'
|
import { TYPES } from '../Bootstrap/Types'
|
||||||
import { TokenAuthenticationMethod } from './TokenAuthenticationMethod'
|
import { TokenAuthenticationMethod } from './TokenAuthenticationMethod'
|
||||||
|
import { ResponseLocals } from './ResponseLocals'
|
||||||
|
import { OfflineResponseLocals } from './OfflineResponseLocals'
|
||||||
|
import { SubscriptionResponseLocals } from './SubscriptionResponseLocals'
|
||||||
|
|
||||||
@injectable()
|
@injectable()
|
||||||
export class SubscriptionTokenAuthMiddleware extends BaseMiddleware {
|
export class SubscriptionTokenAuthMiddleware extends BaseMiddleware {
|
||||||
@@ -34,13 +37,16 @@ export class SubscriptionTokenAuthMiddleware extends BaseMiddleware {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
response.locals.tokenAuthenticationMethod = email
|
const locals = {
|
||||||
? TokenAuthenticationMethod.OfflineSubscriptionToken
|
tokenAuthenticationMethod: email
|
||||||
: TokenAuthenticationMethod.SubscriptionToken
|
? TokenAuthenticationMethod.OfflineSubscriptionToken
|
||||||
|
: TokenAuthenticationMethod.SubscriptionToken,
|
||||||
|
} as SubscriptionResponseLocals
|
||||||
|
Object.assign(response.locals, locals)
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const url =
|
const url =
|
||||||
response.locals.tokenAuthenticationMethod == TokenAuthenticationMethod.OfflineSubscriptionToken
|
locals.tokenAuthenticationMethod == TokenAuthenticationMethod.OfflineSubscriptionToken
|
||||||
? `${this.authServerUrl}/offline/subscription-tokens/${subscriptionToken}/validate`
|
? `${this.authServerUrl}/offline/subscription-tokens/${subscriptionToken}/validate`
|
||||||
: `${this.authServerUrl}/subscription-tokens/${subscriptionToken}/validate`
|
: `${this.authServerUrl}/subscription-tokens/${subscriptionToken}/validate`
|
||||||
|
|
||||||
@@ -65,7 +71,7 @@ export class SubscriptionTokenAuthMiddleware extends BaseMiddleware {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if (response.locals.tokenAuthenticationMethod == TokenAuthenticationMethod.OfflineSubscriptionToken) {
|
if (locals.tokenAuthenticationMethod == TokenAuthenticationMethod.OfflineSubscriptionToken) {
|
||||||
this.handleOfflineAuthTokenValidationResponse(response, authResponse)
|
this.handleOfflineAuthTokenValidationResponse(response, authResponse)
|
||||||
|
|
||||||
return next()
|
return next()
|
||||||
@@ -101,24 +107,26 @@ export class SubscriptionTokenAuthMiddleware extends BaseMiddleware {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private handleOfflineAuthTokenValidationResponse(response: Response, authResponse: AxiosResponse) {
|
private handleOfflineAuthTokenValidationResponse(response: Response, authResponse: AxiosResponse) {
|
||||||
response.locals.offlineAuthToken = authResponse.data.authToken
|
|
||||||
|
|
||||||
const decodedToken = <OfflineUserTokenData>(
|
const decodedToken = <OfflineUserTokenData>(
|
||||||
verify(authResponse.data.authToken, this.jwtSecret, { algorithms: ['HS256'] })
|
verify(authResponse.data.authToken, this.jwtSecret, { algorithms: ['HS256'] })
|
||||||
)
|
)
|
||||||
|
|
||||||
response.locals.offlineUserEmail = decodedToken.userEmail
|
Object.assign(response.locals, {
|
||||||
response.locals.offlineFeaturesToken = decodedToken.featuresToken
|
offlineAuthToken: authResponse.data.authToken,
|
||||||
|
userEmail: decodedToken.userEmail,
|
||||||
|
featuresToken: decodedToken.featuresToken,
|
||||||
|
} as OfflineResponseLocals)
|
||||||
}
|
}
|
||||||
|
|
||||||
private handleAuthTokenValidationResponse(response: Response, authResponse: AxiosResponse) {
|
private handleAuthTokenValidationResponse(response: Response, authResponse: AxiosResponse) {
|
||||||
response.locals.authToken = authResponse.data.authToken
|
|
||||||
|
|
||||||
const decodedToken = <CrossServiceTokenData>(
|
const decodedToken = <CrossServiceTokenData>(
|
||||||
verify(authResponse.data.authToken, this.jwtSecret, { algorithms: ['HS256'] })
|
verify(authResponse.data.authToken, this.jwtSecret, { algorithms: ['HS256'] })
|
||||||
)
|
)
|
||||||
|
|
||||||
response.locals.user = decodedToken.user
|
Object.assign(response.locals, {
|
||||||
response.locals.roles = decodedToken.roles
|
authToken: authResponse.data.authToken,
|
||||||
|
user: decodedToken.user,
|
||||||
|
roles: decodedToken.roles,
|
||||||
|
} as ResponseLocals)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import { AxiosError, AxiosInstance } from 'axios'
|
|||||||
import { Logger } from 'winston'
|
import { Logger } from 'winston'
|
||||||
|
|
||||||
import { TYPES } from '../Bootstrap/Types'
|
import { TYPES } from '../Bootstrap/Types'
|
||||||
|
import { ResponseLocals } from './ResponseLocals'
|
||||||
|
|
||||||
@injectable()
|
@injectable()
|
||||||
export class WebSocketAuthMiddleware extends BaseMiddleware {
|
export class WebSocketAuthMiddleware extends BaseMiddleware {
|
||||||
@@ -55,13 +56,14 @@ export class WebSocketAuthMiddleware extends BaseMiddleware {
|
|||||||
|
|
||||||
const crossServiceToken = authResponse.data.authToken
|
const crossServiceToken = authResponse.data.authToken
|
||||||
|
|
||||||
response.locals.authToken = crossServiceToken
|
|
||||||
|
|
||||||
const decodedToken = <CrossServiceTokenData>verify(crossServiceToken, this.jwtSecret, { algorithms: ['HS256'] })
|
const decodedToken = <CrossServiceTokenData>verify(crossServiceToken, this.jwtSecret, { algorithms: ['HS256'] })
|
||||||
|
|
||||||
response.locals.user = decodedToken.user
|
Object.assign(response.locals, {
|
||||||
response.locals.session = decodedToken.session
|
authToken: crossServiceToken,
|
||||||
response.locals.roles = decodedToken.roles
|
user: decodedToken.user,
|
||||||
|
session: decodedToken.session,
|
||||||
|
roles: decodedToken.roles,
|
||||||
|
} as ResponseLocals)
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
const errorMessage = (error as AxiosError).isAxiosError
|
const errorMessage = (error as AxiosError).isAxiosError
|
||||||
? JSON.stringify((error as AxiosError).response?.data)
|
? JSON.stringify((error as AxiosError).response?.data)
|
||||||
|
|||||||
@@ -4,12 +4,14 @@ import { BaseHttpController, controller, httpGet, httpPost } from 'inversify-exp
|
|||||||
import { TYPES } from '../../Bootstrap/Types'
|
import { TYPES } from '../../Bootstrap/Types'
|
||||||
import { ServiceProxyInterface } from '../../Service/Proxy/ServiceProxyInterface'
|
import { ServiceProxyInterface } from '../../Service/Proxy/ServiceProxyInterface'
|
||||||
import { EndpointResolverInterface } from '../../Service/Resolver/EndpointResolverInterface'
|
import { EndpointResolverInterface } from '../../Service/Resolver/EndpointResolverInterface'
|
||||||
|
import { JsonResult } from 'inversify-express-utils/lib/results'
|
||||||
|
|
||||||
@controller('/v1')
|
@controller('/v1')
|
||||||
export class ActionsController extends BaseHttpController {
|
export class ActionsController extends BaseHttpController {
|
||||||
constructor(
|
constructor(
|
||||||
@inject(TYPES.ApiGateway_ServiceProxy) private serviceProxy: ServiceProxyInterface,
|
@inject(TYPES.ApiGateway_ServiceProxy) private serviceProxy: ServiceProxyInterface,
|
||||||
@inject(TYPES.ApiGateway_EndpointResolver) private endpointResolver: EndpointResolverInterface,
|
@inject(TYPES.ApiGateway_EndpointResolver) private endpointResolver: EndpointResolverInterface,
|
||||||
|
@inject(TYPES.ApiGateway_CAPTCHA_UI_URL) private captchaUIUrl: string,
|
||||||
) {
|
) {
|
||||||
super()
|
super()
|
||||||
}
|
}
|
||||||
@@ -19,7 +21,7 @@ export class ActionsController extends BaseHttpController {
|
|||||||
await this.serviceProxy.callAuthServer(
|
await this.serviceProxy.callAuthServer(
|
||||||
request,
|
request,
|
||||||
response,
|
response,
|
||||||
this.endpointResolver.resolveEndpointOrMethodIdentifier('POST', 'auth/sign_in'),
|
this.endpointResolver.resolveEndpointOrMethodIdentifier('POST', 'auth/pkce_sign_in'),
|
||||||
request.body,
|
request.body,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -29,7 +31,7 @@ export class ActionsController extends BaseHttpController {
|
|||||||
await this.serviceProxy.callAuthServer(
|
await this.serviceProxy.callAuthServer(
|
||||||
request,
|
request,
|
||||||
response,
|
response,
|
||||||
this.endpointResolver.resolveEndpointOrMethodIdentifier('GET', 'auth/params'),
|
this.endpointResolver.resolveEndpointOrMethodIdentifier('POST', 'auth/pkce_params'),
|
||||||
request.body,
|
request.body,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -83,4 +85,11 @@ export class ActionsController extends BaseHttpController {
|
|||||||
request.body,
|
request.body,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@httpGet('/meta')
|
||||||
|
async serverMetadata(): Promise<JsonResult> {
|
||||||
|
return this.json({
|
||||||
|
captchaUIUrl: this.captchaUIUrl,
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ import {
|
|||||||
controller,
|
controller,
|
||||||
httpDelete,
|
httpDelete,
|
||||||
httpGet,
|
httpGet,
|
||||||
httpPatch,
|
|
||||||
httpPost,
|
httpPost,
|
||||||
httpPut,
|
httpPut,
|
||||||
results,
|
results,
|
||||||
@@ -16,6 +15,8 @@ import { TYPES } from '../../Bootstrap/Types'
|
|||||||
import { ServiceProxyInterface } from '../../Service/Proxy/ServiceProxyInterface'
|
import { ServiceProxyInterface } from '../../Service/Proxy/ServiceProxyInterface'
|
||||||
import { TokenAuthenticationMethod } from '../TokenAuthenticationMethod'
|
import { TokenAuthenticationMethod } from '../TokenAuthenticationMethod'
|
||||||
import { EndpointResolverInterface } from '../../Service/Resolver/EndpointResolverInterface'
|
import { EndpointResolverInterface } from '../../Service/Resolver/EndpointResolverInterface'
|
||||||
|
import { ResponseLocals } from '../ResponseLocals'
|
||||||
|
import { SubscriptionResponseLocals } from '../SubscriptionResponseLocals'
|
||||||
|
|
||||||
@controller('/v1/users')
|
@controller('/v1/users')
|
||||||
export class UsersController extends BaseHttpController {
|
export class UsersController extends BaseHttpController {
|
||||||
@@ -37,16 +38,6 @@ export class UsersController extends BaseHttpController {
|
|||||||
await this.httpService.callPaymentsServer(request, response, 'api/pro_users/send-activation-code', request.body)
|
await this.httpService.callPaymentsServer(request, response, 'api/pro_users/send-activation-code', request.body)
|
||||||
}
|
}
|
||||||
|
|
||||||
@httpPatch('/:userId', TYPES.ApiGateway_RequiredCrossServiceTokenMiddleware)
|
|
||||||
async updateUser(request: Request, response: Response): Promise<void> {
|
|
||||||
await this.httpService.callAuthServer(
|
|
||||||
request,
|
|
||||||
response,
|
|
||||||
this.endpointResolver.resolveEndpointOrMethodIdentifier('PATCH', 'users/:userId', request.params.userId),
|
|
||||||
request.body,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
@httpPut('/:userUuid/password', TYPES.ApiGateway_RequiredCrossServiceTokenMiddleware)
|
@httpPut('/:userUuid/password', TYPES.ApiGateway_RequiredCrossServiceTokenMiddleware)
|
||||||
async changePassword(request: Request, response: Response): Promise<void> {
|
async changePassword(request: Request, response: Response): Promise<void> {
|
||||||
this.logger.debug(
|
this.logger.debug(
|
||||||
@@ -84,7 +75,7 @@ export class UsersController extends BaseHttpController {
|
|||||||
await this.httpService.callAuthServer(
|
await this.httpService.callAuthServer(
|
||||||
request,
|
request,
|
||||||
response,
|
response,
|
||||||
this.endpointResolver.resolveEndpointOrMethodIdentifier('GET', 'auth/params'),
|
this.endpointResolver.resolveEndpointOrMethodIdentifier('POST', 'auth/pkce_params'),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -140,6 +131,20 @@ export class UsersController extends BaseHttpController {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@httpPut('/:userUuid/subscription-settings', TYPES.ApiGateway_RequiredCrossServiceTokenMiddleware)
|
||||||
|
async putSubscriptionSetting(request: Request, response: Response): Promise<void> {
|
||||||
|
await this.httpService.callAuthServer(
|
||||||
|
request,
|
||||||
|
response,
|
||||||
|
this.endpointResolver.resolveEndpointOrMethodIdentifier(
|
||||||
|
'PUT',
|
||||||
|
'users/:userUuid/subscription-settings',
|
||||||
|
request.params.userUuid,
|
||||||
|
),
|
||||||
|
request.body,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
@httpGet('/:userUuid/settings/:settingName', TYPES.ApiGateway_RequiredCrossServiceTokenMiddleware)
|
@httpGet('/:userUuid/settings/:settingName', TYPES.ApiGateway_RequiredCrossServiceTokenMiddleware)
|
||||||
async getSetting(request: Request, response: Response): Promise<void> {
|
async getSetting(request: Request, response: Response): Promise<void> {
|
||||||
await this.httpService.callAuthServer(
|
await this.httpService.callAuthServer(
|
||||||
@@ -214,7 +219,9 @@ export class UsersController extends BaseHttpController {
|
|||||||
|
|
||||||
@httpGet('/subscription', TYPES.ApiGateway_SubscriptionTokenAuthMiddleware)
|
@httpGet('/subscription', TYPES.ApiGateway_SubscriptionTokenAuthMiddleware)
|
||||||
async getSubscriptionBySubscriptionToken(request: Request, response: Response): Promise<void> {
|
async getSubscriptionBySubscriptionToken(request: Request, response: Response): Promise<void> {
|
||||||
if (response.locals.tokenAuthenticationMethod === TokenAuthenticationMethod.OfflineSubscriptionToken) {
|
const locals = response.locals as SubscriptionResponseLocals & ResponseLocals
|
||||||
|
|
||||||
|
if (locals.tokenAuthenticationMethod === TokenAuthenticationMethod.OfflineSubscriptionToken) {
|
||||||
await this.httpService.callAuthServer(
|
await this.httpService.callAuthServer(
|
||||||
request,
|
request,
|
||||||
response,
|
response,
|
||||||
@@ -227,11 +234,7 @@ export class UsersController extends BaseHttpController {
|
|||||||
await this.httpService.callAuthServer(
|
await this.httpService.callAuthServer(
|
||||||
request,
|
request,
|
||||||
response,
|
response,
|
||||||
this.endpointResolver.resolveEndpointOrMethodIdentifier(
|
this.endpointResolver.resolveEndpointOrMethodIdentifier('GET', 'users/:userUuid/subscription', locals.user.uuid),
|
||||||
'GET',
|
|
||||||
'users/:userUuid/subscription',
|
|
||||||
response.locals.user.uuid,
|
|
||||||
),
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
import { ContentSizesFixRequestedEvent } from '@standardnotes/domain-events'
|
||||||
|
|
||||||
|
export interface DomainEventFactoryInterface {
|
||||||
|
createContentSizesFixRequestedEvent(dto: { userUuid: string }): ContentSizesFixRequestedEvent
|
||||||
|
}
|
||||||
@@ -1,15 +1,12 @@
|
|||||||
import { inject, injectable } from 'inversify'
|
|
||||||
import * as IORedis from 'ioredis'
|
import * as IORedis from 'ioredis'
|
||||||
import { TYPES } from '../../Bootstrap/Types'
|
|
||||||
|
|
||||||
import { CrossServiceTokenCacheInterface } from '../../Service/Cache/CrossServiceTokenCacheInterface'
|
import { CrossServiceTokenCacheInterface } from '../../Service/Cache/CrossServiceTokenCacheInterface'
|
||||||
|
|
||||||
@injectable()
|
|
||||||
export class RedisCrossServiceTokenCache implements CrossServiceTokenCacheInterface {
|
export class RedisCrossServiceTokenCache implements CrossServiceTokenCacheInterface {
|
||||||
private readonly PREFIX = 'cst'
|
private readonly PREFIX = 'cst'
|
||||||
private readonly USER_CST_PREFIX = 'user-cst'
|
private readonly USER_CST_PREFIX = 'user-cst'
|
||||||
|
|
||||||
constructor(@inject(TYPES.ApiGateway_Redis) private redisClient: IORedis.Redis) {}
|
constructor(private redisClient: IORedis.Redis) {}
|
||||||
|
|
||||||
async set(dto: {
|
async set(dto: {
|
||||||
key: string
|
key: string
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import { Request, Response } from 'express'
|
|||||||
import { ServiceContainerInterface, ServiceIdentifier } from '@standardnotes/domain-core'
|
import { ServiceContainerInterface, ServiceIdentifier } from '@standardnotes/domain-core'
|
||||||
|
|
||||||
import { ServiceProxyInterface } from '../Proxy/ServiceProxyInterface'
|
import { ServiceProxyInterface } from '../Proxy/ServiceProxyInterface'
|
||||||
|
import { ResponseLocals } from '../../Controller/ResponseLocals'
|
||||||
|
|
||||||
export class DirectCallServiceProxy implements ServiceProxyInterface {
|
export class DirectCallServiceProxy implements ServiceProxyInterface {
|
||||||
constructor(
|
constructor(
|
||||||
@@ -9,23 +10,44 @@ export class DirectCallServiceProxy implements ServiceProxyInterface {
|
|||||||
private filesServerUrl: string,
|
private filesServerUrl: string,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
async validateSession(
|
async validateSession(dto: {
|
||||||
headers: {
|
headers: {
|
||||||
authorization: string
|
authorization: string
|
||||||
sharedVaultOwnerContext?: string
|
sharedVaultOwnerContext?: string
|
||||||
},
|
}
|
||||||
_retryAttempt?: number,
|
cookies?: Map<string, string[]>
|
||||||
): Promise<{ status: number; data: unknown; headers: { contentType: string } }> {
|
snjs?: string
|
||||||
|
application?: string
|
||||||
|
retryAttempt?: number
|
||||||
|
}): Promise<{
|
||||||
|
status: number
|
||||||
|
data: unknown
|
||||||
|
headers: {
|
||||||
|
contentType: string
|
||||||
|
}
|
||||||
|
}> {
|
||||||
const authService = this.serviceContainer.get(ServiceIdentifier.create(ServiceIdentifier.NAMES.Auth).getValue())
|
const authService = this.serviceContainer.get(ServiceIdentifier.create(ServiceIdentifier.NAMES.Auth).getValue())
|
||||||
if (!authService) {
|
if (!authService) {
|
||||||
throw new Error('Auth service not found')
|
throw new Error('Auth service not found')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let stringOfCookies = ''
|
||||||
|
for (const cookieName of dto.cookies?.keys() ?? []) {
|
||||||
|
for (const cookieValue of dto.cookies?.get(cookieName) as string[]) {
|
||||||
|
stringOfCookies += `${cookieName}=${cookieValue}; `
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const serviceResponse = (await authService.handleRequest(
|
const serviceResponse = (await authService.handleRequest(
|
||||||
{
|
{
|
||||||
|
body: {
|
||||||
|
authTokenFromHeaders: dto.headers.authorization,
|
||||||
|
sharedVaultOwnerContext: dto.headers.sharedVaultOwnerContext,
|
||||||
|
},
|
||||||
headers: {
|
headers: {
|
||||||
authorization: headers.authorization,
|
'x-snjs-version': dto.snjs,
|
||||||
'x-shared-vault-owner-context': headers.sharedVaultOwnerContext,
|
'x-application-version': dto.application,
|
||||||
|
cookie: stringOfCookies.trim(),
|
||||||
},
|
},
|
||||||
} as never,
|
} as never,
|
||||||
{} as never,
|
{} as never,
|
||||||
@@ -134,11 +156,13 @@ export class DirectCallServiceProxy implements ServiceProxyInterface {
|
|||||||
response: Response,
|
response: Response,
|
||||||
serviceResponse: { statusCode: number; json: Record<string, unknown> },
|
serviceResponse: { statusCode: number; json: Record<string, unknown> },
|
||||||
): void {
|
): void {
|
||||||
|
const locals = response.locals as ResponseLocals
|
||||||
|
|
||||||
void response.status(serviceResponse.statusCode).send({
|
void response.status(serviceResponse.statusCode).send({
|
||||||
meta: {
|
meta: {
|
||||||
auth: {
|
auth: {
|
||||||
userUuid: response.locals.user?.uuid,
|
userUuid: locals.user?.uuid,
|
||||||
roles: response.locals.roles,
|
roles: locals.roles,
|
||||||
},
|
},
|
||||||
server: {
|
server: {
|
||||||
filesServerUrl: this.filesServerUrl,
|
filesServerUrl: this.filesServerUrl,
|
||||||
|
|||||||
@@ -8,6 +8,8 @@ import { TYPES } from '../../Bootstrap/Types'
|
|||||||
import { CrossServiceTokenCacheInterface } from '../Cache/CrossServiceTokenCacheInterface'
|
import { CrossServiceTokenCacheInterface } from '../Cache/CrossServiceTokenCacheInterface'
|
||||||
import { ServiceProxyInterface } from '../Proxy/ServiceProxyInterface'
|
import { ServiceProxyInterface } from '../Proxy/ServiceProxyInterface'
|
||||||
import { TimerInterface } from '@standardnotes/time'
|
import { TimerInterface } from '@standardnotes/time'
|
||||||
|
import { ResponseLocals } from '../../Controller/ResponseLocals'
|
||||||
|
import { OfflineResponseLocals } from '../../Controller/OfflineResponseLocals'
|
||||||
|
|
||||||
@injectable()
|
@injectable()
|
||||||
export class HttpServiceProxy implements ServiceProxyInterface {
|
export class HttpServiceProxy implements ServiceProxyInterface {
|
||||||
@@ -26,20 +28,51 @@ export class HttpServiceProxy implements ServiceProxyInterface {
|
|||||||
@inject(TYPES.ApiGateway_Timer) private timer: TimerInterface,
|
@inject(TYPES.ApiGateway_Timer) private timer: TimerInterface,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
async validateSession(
|
async validateSession(dto: {
|
||||||
headers: {
|
headers: {
|
||||||
authorization: string
|
authorization: string
|
||||||
sharedVaultOwnerContext?: string
|
sharedVaultOwnerContext?: string
|
||||||
},
|
}
|
||||||
retryAttempt?: number,
|
requestMetadata: {
|
||||||
): Promise<{ status: number; data: unknown; headers: { contentType: string } }> {
|
url: string
|
||||||
|
method: string
|
||||||
|
snjs?: string
|
||||||
|
application?: string
|
||||||
|
userAgent?: string
|
||||||
|
secChUa?: string
|
||||||
|
}
|
||||||
|
cookies?: Map<string, string[]>
|
||||||
|
retryAttempt?: number
|
||||||
|
}): Promise<{
|
||||||
|
status: number
|
||||||
|
data: unknown
|
||||||
|
headers: {
|
||||||
|
contentType: string
|
||||||
|
}
|
||||||
|
}> {
|
||||||
try {
|
try {
|
||||||
|
let stringOfCookies = ''
|
||||||
|
for (const cookieName of dto.cookies?.keys() ?? []) {
|
||||||
|
for (const cookieValue of dto.cookies?.get(cookieName) as string[]) {
|
||||||
|
stringOfCookies += `${cookieName}=${cookieValue}; `
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const authResponse = await this.httpClient.request({
|
const authResponse = await this.httpClient.request({
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: headers.authorization,
|
|
||||||
Accept: 'application/json',
|
Accept: 'application/json',
|
||||||
'x-shared-vault-owner-context': headers.sharedVaultOwnerContext,
|
Cookie: stringOfCookies.trim(),
|
||||||
|
'x-snjs-version': dto.requestMetadata.snjs,
|
||||||
|
'x-application-version': dto.requestMetadata.application,
|
||||||
|
'x-origin-user-agent': dto.requestMetadata.userAgent,
|
||||||
|
'x-origin-sec-ch-ua': dto.requestMetadata.secChUa,
|
||||||
|
'x-origin-url': dto.requestMetadata.url,
|
||||||
|
'x-origin-method': dto.requestMetadata.method,
|
||||||
|
},
|
||||||
|
data: {
|
||||||
|
authTokenFromHeaders: dto.headers.authorization,
|
||||||
|
sharedVaultOwnerContext: dto.headers.sharedVaultOwnerContext,
|
||||||
},
|
},
|
||||||
validateStatus: (status: number) => {
|
validateStatus: (status: number) => {
|
||||||
return status >= 200 && status < 500
|
return status >= 200 && status < 500
|
||||||
@@ -56,13 +89,18 @@ export class HttpServiceProxy implements ServiceProxyInterface {
|
|||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
const requestDidNotMakeIt = this.requestTimedOutOrDidNotReachDestination(error as Record<string, unknown>)
|
const requestDidNotMakeIt = this.requestTimedOutOrDidNotReachDestination(error as Record<string, unknown>)
|
||||||
const tooManyRetryAttempts = retryAttempt && retryAttempt > 2
|
const tooManyRetryAttempts = dto.retryAttempt && dto.retryAttempt > 2
|
||||||
if (!tooManyRetryAttempts && requestDidNotMakeIt) {
|
if (!tooManyRetryAttempts && requestDidNotMakeIt) {
|
||||||
await this.timer.sleep(50)
|
await this.timer.sleep(50)
|
||||||
|
|
||||||
const nextRetryAttempt = retryAttempt ? retryAttempt + 1 : 1
|
const nextRetryAttempt = dto.retryAttempt ? dto.retryAttempt + 1 : 1
|
||||||
|
|
||||||
return this.validateSession(headers, nextRetryAttempt)
|
return this.validateSession({
|
||||||
|
headers: dto.headers,
|
||||||
|
cookies: dto.cookies,
|
||||||
|
requestMetadata: dto.requestMetadata,
|
||||||
|
retryAttempt: nextRetryAttempt,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
throw error
|
throw error
|
||||||
@@ -176,21 +214,32 @@ export class HttpServiceProxy implements ServiceProxyInterface {
|
|||||||
endpoint: string,
|
endpoint: string,
|
||||||
payload?: Record<string, unknown> | string,
|
payload?: Record<string, unknown> | string,
|
||||||
): Promise<AxiosResponse | undefined> {
|
): Promise<AxiosResponse | undefined> {
|
||||||
|
const locals = response.locals as ResponseLocals | OfflineResponseLocals
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const headers: Record<string, string> = {}
|
const headers: Record<string, string> = {}
|
||||||
for (const headerName of Object.keys(request.headers)) {
|
for (const headerName of Object.keys(request.headers)) {
|
||||||
headers[headerName] = request.headers[headerName] as string
|
headers[headerName] = request.headers[headerName] as string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
headers['x-origin-url'] = request.url
|
||||||
|
headers['x-origin-method'] = request.method
|
||||||
|
headers['x-snjs-version'] = request.headers['x-snjs-version'] as string
|
||||||
|
headers['x-application-version'] = request.headers['x-application-version'] as string
|
||||||
|
headers['x-origin-user-agent'] = request.headers['user-agent'] as string
|
||||||
|
headers['x-origin-sec-ch-ua'] = request.headers['sec-ch-ua'] as string
|
||||||
|
|
||||||
delete headers.host
|
delete headers.host
|
||||||
delete headers['content-length']
|
delete headers['content-length']
|
||||||
|
|
||||||
if (response.locals.authToken) {
|
headers.cookie = request.headers.cookie as string
|
||||||
headers['X-Auth-Token'] = response.locals.authToken
|
|
||||||
|
if ('authToken' in locals && locals.authToken) {
|
||||||
|
headers['X-Auth-Token'] = locals.authToken
|
||||||
}
|
}
|
||||||
|
|
||||||
if (response.locals.offlineAuthToken) {
|
if ('offlineAuthToken' in locals && locals.offlineAuthToken) {
|
||||||
headers['X-Auth-Offline-Token'] = response.locals.offlineAuthToken
|
headers['X-Auth-Offline-Token'] = locals.offlineAuthToken
|
||||||
}
|
}
|
||||||
|
|
||||||
const serviceResponse = await this.httpClient.request({
|
const serviceResponse = await this.httpClient.request({
|
||||||
@@ -222,7 +271,7 @@ export class HttpServiceProxy implements ServiceProxyInterface {
|
|||||||
this.logger.error(
|
this.logger.error(
|
||||||
`Could not pass the request to ${serverUrl}/${endpoint} on underlying service: ${detailedErrorMessage}`,
|
`Could not pass the request to ${serverUrl}/${endpoint} on underlying service: ${detailedErrorMessage}`,
|
||||||
{
|
{
|
||||||
userId: response.locals.user ? response.locals.user.uuid : undefined,
|
userId: (locals as ResponseLocals).user ? (locals as ResponseLocals).user.uuid : undefined,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -257,6 +306,7 @@ export class HttpServiceProxy implements ServiceProxyInterface {
|
|||||||
endpoint: string,
|
endpoint: string,
|
||||||
payload?: Record<string, unknown> | string,
|
payload?: Record<string, unknown> | string,
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
|
const locals = response.locals as ResponseLocals
|
||||||
const serviceResponse = await this.getServerResponse(serverUrl, request, response, endpoint, payload)
|
const serviceResponse = await this.getServerResponse(serverUrl, request, response, endpoint, payload)
|
||||||
|
|
||||||
if (!serviceResponse) {
|
if (!serviceResponse) {
|
||||||
@@ -274,8 +324,8 @@ export class HttpServiceProxy implements ServiceProxyInterface {
|
|||||||
response.status(serviceResponse.status).send({
|
response.status(serviceResponse.status).send({
|
||||||
meta: {
|
meta: {
|
||||||
auth: {
|
auth: {
|
||||||
userUuid: response.locals.user?.uuid,
|
userUuid: locals.user?.uuid,
|
||||||
roles: response.locals.roles,
|
roles: locals.roles,
|
||||||
},
|
},
|
||||||
server: {
|
server: {
|
||||||
filesServerUrl: this.filesServerUrl,
|
filesServerUrl: this.filesServerUrl,
|
||||||
@@ -335,13 +385,11 @@ export class HttpServiceProxy implements ServiceProxyInterface {
|
|||||||
|
|
||||||
private applyResponseHeaders(serviceResponse: AxiosResponse, response: Response): void {
|
private applyResponseHeaders(serviceResponse: AxiosResponse, response: Response): void {
|
||||||
const returnedHeadersFromUnderlyingService = [
|
const returnedHeadersFromUnderlyingService = [
|
||||||
'access-control-allow-methods',
|
|
||||||
'access-control-allow-origin',
|
|
||||||
'access-control-expose-headers',
|
|
||||||
'authorization',
|
|
||||||
'content-type',
|
'content-type',
|
||||||
'x-ssjs-version',
|
'authorization',
|
||||||
'x-auth-version',
|
'set-cookie',
|
||||||
|
'access-control-expose-headers',
|
||||||
|
'x-captcha-required',
|
||||||
]
|
]
|
||||||
|
|
||||||
returnedHeadersFromUnderlyingService.map((headerName) => {
|
returnedHeadersFromUnderlyingService.map((headerName) => {
|
||||||
|
|||||||
@@ -49,13 +49,22 @@ export interface ServiceProxyInterface {
|
|||||||
endpointOrMethodIdentifier: string,
|
endpointOrMethodIdentifier: string,
|
||||||
payload?: Record<string, unknown> | string,
|
payload?: Record<string, unknown> | string,
|
||||||
): Promise<void>
|
): Promise<void>
|
||||||
validateSession(
|
validateSession(dto: {
|
||||||
headers: {
|
headers: {
|
||||||
authorization: string
|
authorization: string
|
||||||
sharedVaultOwnerContext?: string
|
sharedVaultOwnerContext?: string
|
||||||
},
|
}
|
||||||
retryAttempt?: number,
|
requestMetadata: {
|
||||||
): Promise<{
|
url: string
|
||||||
|
method: string
|
||||||
|
snjs?: string
|
||||||
|
application?: string
|
||||||
|
userAgent?: string
|
||||||
|
secChUa?: string
|
||||||
|
}
|
||||||
|
cookies?: Map<string, string[]>
|
||||||
|
retryAttempt?: number
|
||||||
|
}): Promise<{
|
||||||
status: number
|
status: number
|
||||||
data: unknown
|
data: unknown
|
||||||
headers: {
|
headers: {
|
||||||
|
|||||||
@@ -7,8 +7,6 @@ export class EndpointResolver implements EndpointResolverInterface {
|
|||||||
// Auth Middleware
|
// Auth Middleware
|
||||||
['[POST]:sessions/validate', 'auth.sessions.validate'],
|
['[POST]:sessions/validate', 'auth.sessions.validate'],
|
||||||
// Actions Controller
|
// Actions Controller
|
||||||
['[POST]:auth/sign_in', 'auth.signIn'],
|
|
||||||
['[GET]:auth/params', 'auth.params'],
|
|
||||||
['[POST]:auth/sign_out', 'auth.signOut'],
|
['[POST]:auth/sign_out', 'auth.signOut'],
|
||||||
['[POST]:auth/recovery/codes', 'auth.generateRecoveryCodes'],
|
['[POST]:auth/recovery/codes', 'auth.generateRecoveryCodes'],
|
||||||
['[POST]:auth/recovery/login', 'auth.signInWithRecoveryCodes'],
|
['[POST]:auth/recovery/login', 'auth.signInWithRecoveryCodes'],
|
||||||
@@ -40,7 +38,6 @@ export class EndpointResolver implements EndpointResolverInterface {
|
|||||||
// Tokens Controller
|
// Tokens Controller
|
||||||
['[POST]:subscription-tokens', 'auth.subscription-tokens.create'],
|
['[POST]:subscription-tokens', 'auth.subscription-tokens.create'],
|
||||||
// Users Controller
|
// Users Controller
|
||||||
['[PATCH]:users/:userId', 'auth.users.update'],
|
|
||||||
['[PUT]:users/:userUuid/attributes/credentials', 'auth.users.updateCredentials'],
|
['[PUT]:users/:userUuid/attributes/credentials', 'auth.users.updateCredentials'],
|
||||||
['[DELETE]:users/:userUuid', 'auth.users.delete'],
|
['[DELETE]:users/:userUuid', 'auth.users.delete'],
|
||||||
['[POST]:listed', 'auth.users.createListedAccount'],
|
['[POST]:listed', 'auth.users.createListedAccount'],
|
||||||
@@ -49,6 +46,7 @@ export class EndpointResolver implements EndpointResolverInterface {
|
|||||||
['[PUT]:users/:userUuid/settings', 'auth.users.updateSetting'],
|
['[PUT]:users/:userUuid/settings', 'auth.users.updateSetting'],
|
||||||
['[GET]:users/:userUuid/settings/:settingName', 'auth.users.getSetting'],
|
['[GET]:users/:userUuid/settings/:settingName', 'auth.users.getSetting'],
|
||||||
['[DELETE]:users/:userUuid/settings/:settingName', 'auth.users.deleteSetting'],
|
['[DELETE]:users/:userUuid/settings/:settingName', 'auth.users.deleteSetting'],
|
||||||
|
['[PUT]:users/:userUuid/subscription-settings', 'auth.users.updateSubscriptionSetting'],
|
||||||
['[GET]:users/:userUuid/subscription-settings/:subscriptionSettingName', 'auth.users.getSubscriptionSetting'],
|
['[GET]:users/:userUuid/subscription-settings/:subscriptionSettingName', 'auth.users.getSubscriptionSetting'],
|
||||||
['[GET]:users/:userUuid/features', 'auth.users.getFeatures'],
|
['[GET]:users/:userUuid/features', 'auth.users.getFeatures'],
|
||||||
['[GET]:users/:userUuid/subscription', 'auth.users.getSubscription'],
|
['[GET]:users/:userUuid/subscription', 'auth.users.getSubscription'],
|
||||||
|
|||||||
@@ -2,13 +2,15 @@ import { AxiosInstance, AxiosError, AxiosResponse, Method } from 'axios'
|
|||||||
import { Request, Response } from 'express'
|
import { Request, Response } from 'express'
|
||||||
import { Logger } from 'winston'
|
import { Logger } from 'winston'
|
||||||
import { TimerInterface } from '@standardnotes/time'
|
import { TimerInterface } from '@standardnotes/time'
|
||||||
import { IAuthClient, AuthorizationHeader, SessionValidationResponse } from '@standardnotes/grpc'
|
import { Cookie, IAuthClient, RequestValidationOptions, SessionValidationResponse } from '@standardnotes/grpc'
|
||||||
import * as grpc from '@grpc/grpc-js'
|
import * as grpc from '@grpc/grpc-js'
|
||||||
|
|
||||||
import { CrossServiceTokenCacheInterface } from '../Cache/CrossServiceTokenCacheInterface'
|
import { CrossServiceTokenCacheInterface } from '../Cache/CrossServiceTokenCacheInterface'
|
||||||
import { ServiceProxyInterface } from '../Proxy/ServiceProxyInterface'
|
import { ServiceProxyInterface } from '../Proxy/ServiceProxyInterface'
|
||||||
import { GRPCSyncingServerServiceProxy } from './GRPCSyncingServerServiceProxy'
|
import { GRPCSyncingServerServiceProxy } from './GRPCSyncingServerServiceProxy'
|
||||||
import { Status } from '@grpc/grpc-js/build/src/constants'
|
import { Status } from '@grpc/grpc-js/build/src/constants'
|
||||||
|
import { ResponseLocals } from '../../Controller/ResponseLocals'
|
||||||
|
import { OfflineResponseLocals } from '../../Controller/OfflineResponseLocals'
|
||||||
|
|
||||||
export class GRPCServiceProxy implements ServiceProxyInterface {
|
export class GRPCServiceProxy implements ServiceProxyInterface {
|
||||||
constructor(
|
constructor(
|
||||||
@@ -28,23 +30,56 @@ export class GRPCServiceProxy implements ServiceProxyInterface {
|
|||||||
private gRPCSyncingServerServiceProxy: GRPCSyncingServerServiceProxy,
|
private gRPCSyncingServerServiceProxy: GRPCSyncingServerServiceProxy,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
async validateSession(
|
async validateSession(dto: {
|
||||||
headers: {
|
headers: {
|
||||||
authorization: string
|
authorization: string
|
||||||
sharedVaultOwnerContext?: string
|
sharedVaultOwnerContext?: string
|
||||||
},
|
}
|
||||||
retryAttempt?: number,
|
requestMetadata: {
|
||||||
): Promise<{ status: number; data: unknown; headers: { contentType: string } }> {
|
url: string
|
||||||
|
method: string
|
||||||
|
snjs?: string
|
||||||
|
application?: string
|
||||||
|
userAgent?: string
|
||||||
|
secChUa?: string
|
||||||
|
}
|
||||||
|
cookies?: Map<string, string[]>
|
||||||
|
retryAttempt?: number
|
||||||
|
}): Promise<{
|
||||||
|
status: number
|
||||||
|
data: unknown
|
||||||
|
headers: {
|
||||||
|
contentType: string
|
||||||
|
}
|
||||||
|
}> {
|
||||||
const promise = new Promise((resolve, reject) => {
|
const promise = new Promise((resolve, reject) => {
|
||||||
try {
|
try {
|
||||||
const request = new AuthorizationHeader()
|
const request = new RequestValidationOptions()
|
||||||
request.setBearerToken(headers.authorization)
|
request.setBearerToken(dto.headers.authorization)
|
||||||
|
|
||||||
const metadata = new grpc.Metadata()
|
for (const cookieName of dto.cookies?.keys() ?? []) {
|
||||||
metadata.set('x-shared-vault-owner-context', headers.sharedVaultOwnerContext ?? '')
|
for (const cookieValue of dto.cookies?.get(cookieName) as string[]) {
|
||||||
|
const cookie = new Cookie()
|
||||||
|
cookie.setName(cookieName)
|
||||||
|
cookie.setValue(cookieValue)
|
||||||
|
|
||||||
|
request.addCookie(cookie)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (dto.headers.sharedVaultOwnerContext) {
|
||||||
|
request.setSharedVaultOwnerContext(dto.headers.sharedVaultOwnerContext)
|
||||||
|
}
|
||||||
|
|
||||||
this.logger.debug('[GRPCServiceProxy] Validating session via gRPC')
|
this.logger.debug('[GRPCServiceProxy] Validating session via gRPC')
|
||||||
|
|
||||||
|
const metadata = new grpc.Metadata()
|
||||||
|
metadata.set('x-snjs-version', dto.requestMetadata.snjs as string)
|
||||||
|
metadata.set('x-application-version', dto.requestMetadata.application as string)
|
||||||
|
metadata.set('x-origin-user-agent', dto.requestMetadata.userAgent as string)
|
||||||
|
metadata.set('x-origin-sec-ch-ua', dto.requestMetadata.secChUa as string)
|
||||||
|
metadata.set('x-origin-url', dto.requestMetadata.url)
|
||||||
|
metadata.set('x-origin-method', dto.requestMetadata.method)
|
||||||
|
|
||||||
this.authClient.validate(
|
this.authClient.validate(
|
||||||
request,
|
request,
|
||||||
metadata,
|
metadata,
|
||||||
@@ -88,8 +123,8 @@ export class GRPCServiceProxy implements ServiceProxyInterface {
|
|||||||
try {
|
try {
|
||||||
const result = await promise
|
const result = await promise
|
||||||
|
|
||||||
if (retryAttempt) {
|
if (dto.retryAttempt) {
|
||||||
this.logger.debug(`Request to Auth Server succeeded after ${retryAttempt} retries`)
|
this.logger.info(`Request to Auth Server succeeded after ${dto.retryAttempt} retries`)
|
||||||
}
|
}
|
||||||
|
|
||||||
return result as { status: number; data: unknown; headers: { contentType: string } }
|
return result as { status: number; data: unknown; headers: { contentType: string } }
|
||||||
@@ -97,15 +132,20 @@ export class GRPCServiceProxy implements ServiceProxyInterface {
|
|||||||
const requestDidNotMakeIt =
|
const requestDidNotMakeIt =
|
||||||
'code' in (error as Record<string, unknown>) && (error as Record<string, unknown>).code === Status.UNAVAILABLE
|
'code' in (error as Record<string, unknown>) && (error as Record<string, unknown>).code === Status.UNAVAILABLE
|
||||||
|
|
||||||
const tooManyRetryAttempts = retryAttempt && retryAttempt > 2
|
const tooManyRetryAttempts = dto.retryAttempt && dto.retryAttempt > 2
|
||||||
if (!tooManyRetryAttempts && requestDidNotMakeIt) {
|
if (!tooManyRetryAttempts && requestDidNotMakeIt) {
|
||||||
await this.timer.sleep(50)
|
await this.timer.sleep(50)
|
||||||
|
|
||||||
const nextRetryAttempt = retryAttempt ? retryAttempt + 1 : 1
|
const nextRetryAttempt = dto.retryAttempt ? dto.retryAttempt + 1 : 1
|
||||||
|
|
||||||
this.logger.debug(`Retrying request to Auth Server for the ${nextRetryAttempt} time`)
|
this.logger.warn(`Retrying request to Auth Server for the ${nextRetryAttempt} time`)
|
||||||
|
|
||||||
return this.validateSession(headers, nextRetryAttempt)
|
return this.validateSession({
|
||||||
|
headers: dto.headers,
|
||||||
|
cookies: dto.cookies,
|
||||||
|
requestMetadata: dto.requestMetadata,
|
||||||
|
retryAttempt: nextRetryAttempt,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
throw error
|
throw error
|
||||||
@@ -135,13 +175,15 @@ export class GRPCServiceProxy implements ServiceProxyInterface {
|
|||||||
response: Response,
|
response: Response,
|
||||||
payload?: Record<string, unknown> | string,
|
payload?: Record<string, unknown> | string,
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
|
const locals = response.locals as ResponseLocals
|
||||||
|
|
||||||
const result = await this.gRPCSyncingServerServiceProxy.sync(request, response, payload)
|
const result = await this.gRPCSyncingServerServiceProxy.sync(request, response, payload)
|
||||||
|
|
||||||
response.status(result.status).send({
|
response.status(result.status).send({
|
||||||
meta: {
|
meta: {
|
||||||
auth: {
|
auth: {
|
||||||
userUuid: response.locals.user?.uuid,
|
userUuid: locals.user?.uuid,
|
||||||
roles: response.locals.roles,
|
roles: locals.roles,
|
||||||
},
|
},
|
||||||
server: {
|
server: {
|
||||||
filesServerUrl: this.filesServerUrl,
|
filesServerUrl: this.filesServerUrl,
|
||||||
@@ -250,6 +292,8 @@ export class GRPCServiceProxy implements ServiceProxyInterface {
|
|||||||
payload?: Record<string, unknown> | string,
|
payload?: Record<string, unknown> | string,
|
||||||
retryAttempt?: number,
|
retryAttempt?: number,
|
||||||
): Promise<AxiosResponse | undefined> {
|
): Promise<AxiosResponse | undefined> {
|
||||||
|
const locals = response.locals as ResponseLocals | OfflineResponseLocals
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const headers: Record<string, string> = {}
|
const headers: Record<string, string> = {}
|
||||||
for (const headerName of Object.keys(request.headers)) {
|
for (const headerName of Object.keys(request.headers)) {
|
||||||
@@ -259,12 +303,14 @@ export class GRPCServiceProxy implements ServiceProxyInterface {
|
|||||||
delete headers.host
|
delete headers.host
|
||||||
delete headers['content-length']
|
delete headers['content-length']
|
||||||
|
|
||||||
if (response.locals.authToken) {
|
headers.cookie = request.headers.cookie as string
|
||||||
headers['X-Auth-Token'] = response.locals.authToken
|
|
||||||
|
if ('authToken' in locals && locals.authToken) {
|
||||||
|
headers['X-Auth-Token'] = locals.authToken
|
||||||
}
|
}
|
||||||
|
|
||||||
if (response.locals.offlineAuthToken) {
|
if ('offlineAuthToken' in locals && locals.offlineAuthToken) {
|
||||||
headers['X-Auth-Offline-Token'] = response.locals.offlineAuthToken
|
headers['X-Auth-Offline-Token'] = locals.offlineAuthToken
|
||||||
}
|
}
|
||||||
|
|
||||||
const serviceResponse = await this.httpClient.request({
|
const serviceResponse = await this.httpClient.request({
|
||||||
@@ -314,7 +360,7 @@ export class GRPCServiceProxy implements ServiceProxyInterface {
|
|||||||
? `Request to ${serverUrl}/${endpoint} timed out after ${retryAttempt} retries`
|
? `Request to ${serverUrl}/${endpoint} timed out after ${retryAttempt} retries`
|
||||||
: `Could not pass the request to ${serverUrl}/${endpoint} on underlying service: ${detailedErrorMessage}`,
|
: `Could not pass the request to ${serverUrl}/${endpoint} on underlying service: ${detailedErrorMessage}`,
|
||||||
{
|
{
|
||||||
userId: response.locals.user ? response.locals.user.uuid : undefined,
|
userId: (locals as ResponseLocals).user ? (locals as ResponseLocals).user.uuid : undefined,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -349,6 +395,8 @@ export class GRPCServiceProxy implements ServiceProxyInterface {
|
|||||||
endpoint: string,
|
endpoint: string,
|
||||||
payload?: Record<string, unknown> | string,
|
payload?: Record<string, unknown> | string,
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
|
const locals = response.locals as ResponseLocals
|
||||||
|
|
||||||
const serviceResponse = await this.getServerResponse(serverUrl, request, response, endpoint, payload)
|
const serviceResponse = await this.getServerResponse(serverUrl, request, response, endpoint, payload)
|
||||||
|
|
||||||
if (!serviceResponse) {
|
if (!serviceResponse) {
|
||||||
@@ -366,8 +414,8 @@ export class GRPCServiceProxy implements ServiceProxyInterface {
|
|||||||
response.status(serviceResponse.status).send({
|
response.status(serviceResponse.status).send({
|
||||||
meta: {
|
meta: {
|
||||||
auth: {
|
auth: {
|
||||||
userUuid: response.locals.user?.uuid,
|
userUuid: locals.user?.uuid,
|
||||||
roles: response.locals.roles,
|
roles: locals.roles,
|
||||||
},
|
},
|
||||||
server: {
|
server: {
|
||||||
filesServerUrl: this.filesServerUrl,
|
filesServerUrl: this.filesServerUrl,
|
||||||
@@ -427,13 +475,11 @@ export class GRPCServiceProxy implements ServiceProxyInterface {
|
|||||||
|
|
||||||
private applyResponseHeaders(serviceResponse: AxiosResponse, response: Response): void {
|
private applyResponseHeaders(serviceResponse: AxiosResponse, response: Response): void {
|
||||||
const returnedHeadersFromUnderlyingService = [
|
const returnedHeadersFromUnderlyingService = [
|
||||||
'access-control-allow-methods',
|
|
||||||
'access-control-allow-origin',
|
|
||||||
'access-control-expose-headers',
|
|
||||||
'authorization',
|
|
||||||
'content-type',
|
'content-type',
|
||||||
'x-ssjs-version',
|
'authorization',
|
||||||
'x-auth-version',
|
'set-cookie',
|
||||||
|
'access-control-expose-headers',
|
||||||
|
'x-captcha-required',
|
||||||
]
|
]
|
||||||
|
|
||||||
returnedHeadersFromUnderlyingService.map((headerName) => {
|
returnedHeadersFromUnderlyingService.map((headerName) => {
|
||||||
|
|||||||
@@ -1,18 +1,23 @@
|
|||||||
import { Request, Response } from 'express'
|
import { Request, Response } from 'express'
|
||||||
import { ISyncingClient, SyncRequest, SyncResponse } from '@standardnotes/grpc'
|
import { ISyncingClient, SyncRequest, SyncResponse } from '@standardnotes/grpc'
|
||||||
|
import { DomainEventPublisherInterface } from '@standardnotes/domain-events'
|
||||||
import { MapperInterface } from '@standardnotes/domain-core'
|
import { MapperInterface } from '@standardnotes/domain-core'
|
||||||
import { Metadata } from '@grpc/grpc-js'
|
import { Metadata } from '@grpc/grpc-js'
|
||||||
|
|
||||||
import { SyncResponseHttpRepresentation } from '../../Mapping/Sync/Http/SyncResponseHttpRepresentation'
|
|
||||||
import { Status } from '@grpc/grpc-js/build/src/constants'
|
import { Status } from '@grpc/grpc-js/build/src/constants'
|
||||||
import { Logger } from 'winston'
|
import { Logger } from 'winston'
|
||||||
|
|
||||||
|
import { SyncResponseHttpRepresentation } from '../../Mapping/Sync/Http/SyncResponseHttpRepresentation'
|
||||||
|
import { ResponseLocals } from '../../Controller/ResponseLocals'
|
||||||
|
import { DomainEventFactoryInterface } from '../../Event/DomainEventFactoryInterface'
|
||||||
|
|
||||||
export class GRPCSyncingServerServiceProxy {
|
export class GRPCSyncingServerServiceProxy {
|
||||||
constructor(
|
constructor(
|
||||||
private syncingClient: ISyncingClient,
|
private syncingClient: ISyncingClient,
|
||||||
private syncRequestGRPCMapper: MapperInterface<Record<string, unknown>, SyncRequest>,
|
private syncRequestGRPCMapper: MapperInterface<Record<string, unknown>, SyncRequest>,
|
||||||
private syncResponseGRPCMapper: MapperInterface<SyncResponse, SyncResponseHttpRepresentation>,
|
private syncResponseGRPCMapper: MapperInterface<SyncResponse, SyncResponseHttpRepresentation>,
|
||||||
private logger: Logger,
|
private logger: Logger,
|
||||||
|
private domainEventFactory: DomainEventFactoryInterface,
|
||||||
|
private domainEventPublisher?: DomainEventPublisherInterface,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
async sync(
|
async sync(
|
||||||
@@ -20,24 +25,27 @@ export class GRPCSyncingServerServiceProxy {
|
|||||||
response: Response,
|
response: Response,
|
||||||
payload?: Record<string, unknown> | string,
|
payload?: Record<string, unknown> | string,
|
||||||
): Promise<{ status: number; data: unknown }> {
|
): Promise<{ status: number; data: unknown }> {
|
||||||
|
const locals = response.locals as ResponseLocals
|
||||||
|
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
try {
|
try {
|
||||||
const syncRequest = this.syncRequestGRPCMapper.toProjection(payload as Record<string, unknown>)
|
const syncRequest = this.syncRequestGRPCMapper.toProjection(payload as Record<string, unknown>)
|
||||||
|
|
||||||
const metadata = new Metadata()
|
const metadata = new Metadata()
|
||||||
metadata.set('x-user-uuid', response.locals.user.uuid)
|
metadata.set('x-user-uuid', locals.user.uuid)
|
||||||
metadata.set('x-snjs-version', request.headers['x-snjs-version'] as string)
|
metadata.set('x-snjs-version', request.headers['x-snjs-version'] as string)
|
||||||
metadata.set('x-read-only-access', response.locals.readOnlyAccess ? 'true' : 'false')
|
metadata.set('x-read-only-access', locals.readOnlyAccess ? 'true' : 'false')
|
||||||
if (response.locals.readOnlyAccess) {
|
if (locals.readOnlyAccess) {
|
||||||
this.logger.debug('Syncing with read-only access', {
|
this.logger.debug('Syncing with read-only access', {
|
||||||
codeTag: 'GRPCSyncingServerServiceProxy',
|
codeTag: 'GRPCSyncingServerServiceProxy',
|
||||||
userId: response.locals.user.uuid,
|
userId: locals.user.uuid,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
if (response.locals.session) {
|
if (locals.session) {
|
||||||
metadata.set('x-session-uuid', response.locals.session.uuid)
|
metadata.set('x-session-uuid', locals.session.uuid)
|
||||||
}
|
}
|
||||||
metadata.set('x-is-free-user', response.locals.isFreeUser ? 'true' : 'false')
|
metadata.set('x-is-free-user', locals.isFreeUser ? 'true' : 'false')
|
||||||
|
metadata.set('x-has-content-limit', locals.hasContentLimit ? 'true' : 'false')
|
||||||
|
|
||||||
this.syncingClient.syncItems(syncRequest, metadata, (error, syncResponse) => {
|
this.syncingClient.syncItems(syncRequest, metadata, (error, syncResponse) => {
|
||||||
if (error) {
|
if (error) {
|
||||||
@@ -52,10 +60,16 @@ export class GRPCSyncingServerServiceProxy {
|
|||||||
if (error.code === Status.INTERNAL) {
|
if (error.code === Status.INTERNAL) {
|
||||||
this.logger.error(`Internal gRPC error: ${error.message}. Payload: ${JSON.stringify(payload)}`, {
|
this.logger.error(`Internal gRPC error: ${error.message}. Payload: ${JSON.stringify(payload)}`, {
|
||||||
codeTag: 'GRPCSyncingServerServiceProxy',
|
codeTag: 'GRPCSyncingServerServiceProxy',
|
||||||
userId: response.locals.user.uuid,
|
userId: locals.user.uuid,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (error.code === Status.RESOURCE_EXHAUSTED && this.domainEventPublisher !== undefined) {
|
||||||
|
void this.domainEventPublisher.publish(
|
||||||
|
this.domainEventFactory.createContentSizesFixRequestedEvent({ userUuid: locals.user.uuid }),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
return reject(error)
|
return reject(error)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -68,7 +82,7 @@ export class GRPCSyncingServerServiceProxy {
|
|||||||
) {
|
) {
|
||||||
this.logger.error(`Internal gRPC error: ${JSON.stringify(error)}. Payload: ${JSON.stringify(payload)}`, {
|
this.logger.error(`Internal gRPC error: ${JSON.stringify(error)}. Payload: ${JSON.stringify(payload)}`, {
|
||||||
codeTag: 'GRPCSyncingServerServiceProxy.catch',
|
codeTag: 'GRPCSyncingServerServiceProxy.catch',
|
||||||
userId: response.locals.user.uuid,
|
userId: locals.user.uuid,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -29,6 +29,11 @@ CACHE_TYPE=redis
|
|||||||
|
|
||||||
DISABLE_USER_REGISTRATION=false
|
DISABLE_USER_REGISTRATION=false
|
||||||
|
|
||||||
|
COOKIE_DOMAIN=
|
||||||
|
COOKIE_SAME_SITE=
|
||||||
|
COOKIE_SECURE=
|
||||||
|
COOKIE_PARTITIONED=
|
||||||
|
|
||||||
ACCESS_TOKEN_AGE=5184000
|
ACCESS_TOKEN_AGE=5184000
|
||||||
REFRESH_TOKEN_AGE=31556926
|
REFRESH_TOKEN_AGE=31556926
|
||||||
|
|
||||||
@@ -49,6 +54,10 @@ VALET_TOKEN_TTL=
|
|||||||
|
|
||||||
WEB_SOCKET_CONNECTION_TOKEN_SECRET=
|
WEB_SOCKET_CONNECTION_TOKEN_SECRET=
|
||||||
|
|
||||||
|
# Human verfication
|
||||||
|
CAPTCHA_SERVER_URL=
|
||||||
|
CAPTCHA_UI_URL=
|
||||||
|
|
||||||
# (Optional) U2F Setup
|
# (Optional) U2F Setup
|
||||||
U2F_RELYING_PARTY_ID=
|
U2F_RELYING_PARTY_ID=
|
||||||
U2F_RELYING_PARTY_NAME=
|
U2F_RELYING_PARTY_NAME=
|
||||||
|
|||||||
@@ -3,6 +3,57 @@
|
|||||||
All notable changes to this project will be documented in this file.
|
All notable changes to this project will be documented in this file.
|
||||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||||
|
|
||||||
|
## [1.178.5](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.178.3...@standardnotes/auth-server@1.178.5) (2024-06-18)
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* bump versions on packages ([8575d20](https://github.com/standardnotes/server/commit/8575d20f7b79f5220da7cced0041ae12b72e1e49))
|
||||||
|
|
||||||
|
# [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
|
||||||
|
|
||||||
|
* **auth:** check for user agent persisting on session during a session refresh ([#1016](https://github.com/standardnotes/server/issues/1016)) ([0b46eff](https://github.com/standardnotes/server/commit/0b46eff16ea0c32cac91ead04474303500359f4f))
|
||||||
|
|
||||||
|
## [1.177.14](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.177.13...@standardnotes/auth-server@1.177.14) (2024-01-08)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @standardnotes/auth-server
|
||||||
|
|
||||||
## [1.177.13](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.177.12...@standardnotes/auth-server@1.177.13) (2024-01-04)
|
## [1.177.13](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.177.12...@standardnotes/auth-server@1.177.13) (2024-01-04)
|
||||||
|
|
||||||
**Note:** Version bump only for package @standardnotes/auth-server
|
**Note:** Version bump only for package @standardnotes/auth-server
|
||||||
|
|||||||
@@ -10,6 +10,12 @@ RUN corepack enable
|
|||||||
|
|
||||||
COPY ./ /workspace
|
COPY ./ /workspace
|
||||||
|
|
||||||
|
WORKDIR /workspace
|
||||||
|
|
||||||
|
RUN yarn install --immutable
|
||||||
|
|
||||||
|
RUN yarn build
|
||||||
|
|
||||||
WORKDIR /workspace/packages/auth
|
WORKDIR /workspace/packages/auth
|
||||||
|
|
||||||
ENTRYPOINT [ "/workspace/packages/auth/docker/entrypoint.sh" ]
|
ENTRYPOINT [ "/workspace/packages/auth/docker/entrypoint.sh" ]
|
||||||
|
|||||||
@@ -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)
|
||||||
|
})
|
||||||
|
})
|
||||||
@@ -20,6 +20,7 @@ import '../src/Infra/InversifyExpressUtils/AnnotatedHealthCheckController'
|
|||||||
import '../src/Infra/InversifyExpressUtils/AnnotatedFeaturesController'
|
import '../src/Infra/InversifyExpressUtils/AnnotatedFeaturesController'
|
||||||
|
|
||||||
import * as cors from 'cors'
|
import * as cors from 'cors'
|
||||||
|
import * as cookieParser from 'cookie-parser'
|
||||||
import * as grpc from '@grpc/grpc-js'
|
import * as grpc from '@grpc/grpc-js'
|
||||||
import { urlencoded, json, Request, Response, NextFunction } from 'express'
|
import { urlencoded, json, Request, Response, NextFunction } from 'express'
|
||||||
import * as winston from 'winston'
|
import * as winston from 'winston'
|
||||||
@@ -35,6 +36,7 @@ import { AuthService } from '@standardnotes/grpc'
|
|||||||
import { AuthenticateRequest } from '../src/Domain/UseCase/AuthenticateRequest'
|
import { AuthenticateRequest } from '../src/Domain/UseCase/AuthenticateRequest'
|
||||||
import { CreateCrossServiceToken } from '../src/Domain/UseCase/CreateCrossServiceToken/CreateCrossServiceToken'
|
import { CreateCrossServiceToken } from '../src/Domain/UseCase/CreateCrossServiceToken/CreateCrossServiceToken'
|
||||||
import { TokenDecoderInterface, WebSocketConnectionTokenData } from '@standardnotes/security'
|
import { TokenDecoderInterface, WebSocketConnectionTokenData } from '@standardnotes/security'
|
||||||
|
import { ResponseLocals } from '../src/Infra/InversifyExpressUtils/ResponseLocals'
|
||||||
|
|
||||||
const container = new ContainerConfigLoader()
|
const container = new ContainerConfigLoader()
|
||||||
void container.load().then((container) => {
|
void container.load().then((container) => {
|
||||||
@@ -52,6 +54,7 @@ void container.load().then((container) => {
|
|||||||
})
|
})
|
||||||
app.use(json())
|
app.use(json())
|
||||||
app.use(urlencoded({ extended: true }))
|
app.use(urlencoded({ extended: true }))
|
||||||
|
app.use(cookieParser())
|
||||||
app.use(cors())
|
app.use(cors())
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -59,12 +62,13 @@ void container.load().then((container) => {
|
|||||||
|
|
||||||
server.setErrorConfig((app) => {
|
server.setErrorConfig((app) => {
|
||||||
app.use((error: Record<string, unknown>, request: Request, response: Response, _next: NextFunction) => {
|
app.use((error: Record<string, unknown>, request: Request, response: Response, _next: NextFunction) => {
|
||||||
|
const locals = response.locals as ResponseLocals
|
||||||
logger.error(`${error.stack}`, {
|
logger.error(`${error.stack}`, {
|
||||||
method: request.method,
|
method: request.method,
|
||||||
url: request.url,
|
url: request.url,
|
||||||
snjs: request.headers['x-snjs-version'],
|
snjs: request.headers['x-snjs-version'],
|
||||||
application: request.headers['x-application-version'],
|
application: request.headers['x-application-version'],
|
||||||
userId: response.locals.user ? response.locals.user.uuid : undefined,
|
userId: locals.user ? locals.user.uuid : undefined,
|
||||||
})
|
})
|
||||||
|
|
||||||
response.status(500).send({
|
response.status(500).send({
|
||||||
|
|||||||
@@ -9,28 +9,23 @@ import TYPES from '../src/Bootstrap/Types'
|
|||||||
import { Env } from '../src/Bootstrap/Env'
|
import { Env } from '../src/Bootstrap/Env'
|
||||||
import { DomainEventPublisherInterface } from '@standardnotes/domain-events'
|
import { DomainEventPublisherInterface } from '@standardnotes/domain-events'
|
||||||
import { DomainEventFactoryInterface } from '../src/Domain/Event/DomainEventFactoryInterface'
|
import { DomainEventFactoryInterface } from '../src/Domain/Event/DomainEventFactoryInterface'
|
||||||
import { SettingRepositoryInterface } from '../src/Domain/Setting/SettingRepositoryInterface'
|
|
||||||
import { MuteFailedBackupsEmailsOption } from '@standardnotes/settings'
|
|
||||||
import { RoleServiceInterface } from '../src/Domain/Role/RoleServiceInterface'
|
import { RoleServiceInterface } from '../src/Domain/Role/RoleServiceInterface'
|
||||||
import { PermissionName } from '@standardnotes/features'
|
import { PermissionName } from '@standardnotes/features'
|
||||||
import { UserRepositoryInterface } from '../src/Domain/User/UserRepositoryInterface'
|
import { UserRepositoryInterface } from '../src/Domain/User/UserRepositoryInterface'
|
||||||
import { GetUserKeyParams } from '../src/Domain/UseCase/GetUserKeyParams/GetUserKeyParams'
|
import { GetUserKeyParams } from '../src/Domain/UseCase/GetUserKeyParams/GetUserKeyParams'
|
||||||
import { Email, SettingName } from '@standardnotes/domain-core'
|
import { Email } from '@standardnotes/domain-core'
|
||||||
|
|
||||||
const inputArgs = process.argv.slice(2)
|
const inputArgs = process.argv.slice(2)
|
||||||
const backupEmail = inputArgs[0]
|
const backupEmail = inputArgs[0]
|
||||||
|
|
||||||
const requestBackups = async (
|
const requestBackups = async (
|
||||||
userRepository: UserRepositoryInterface,
|
userRepository: UserRepositoryInterface,
|
||||||
settingRepository: SettingRepositoryInterface,
|
|
||||||
roleService: RoleServiceInterface,
|
roleService: RoleServiceInterface,
|
||||||
domainEventFactory: DomainEventFactoryInterface,
|
domainEventFactory: DomainEventFactoryInterface,
|
||||||
domainEventPublisher: DomainEventPublisherInterface,
|
domainEventPublisher: DomainEventPublisherInterface,
|
||||||
getUserKeyParamsUseCase: GetUserKeyParams,
|
getUserKeyParamsUseCase: GetUserKeyParams,
|
||||||
): Promise<void> => {
|
): Promise<void> => {
|
||||||
const permissionName = PermissionName.DailyEmailBackup
|
const permissionName = PermissionName.DailyEmailBackup
|
||||||
const muteEmailsSettingName = SettingName.NAMES.MuteFailedBackupsEmails
|
|
||||||
const muteEmailsSettingValue = MuteFailedBackupsEmailsOption.Muted
|
|
||||||
|
|
||||||
const emailOrError = Email.create(backupEmail)
|
const emailOrError = Email.create(backupEmail)
|
||||||
if (emailOrError.isFailed()) {
|
if (emailOrError.isFailed()) {
|
||||||
@@ -48,24 +43,13 @@ const requestBackups = async (
|
|||||||
throw new Error(`User ${backupEmail} is not permitted for email backups`)
|
throw new Error(`User ${backupEmail} is not permitted for email backups`)
|
||||||
}
|
}
|
||||||
|
|
||||||
let userHasEmailsMuted = false
|
|
||||||
const emailsMutedSetting = await settingRepository.findOneByNameAndUserUuid(muteEmailsSettingName, user.uuid)
|
|
||||||
if (emailsMutedSetting !== null && emailsMutedSetting.props.value !== null) {
|
|
||||||
userHasEmailsMuted = emailsMutedSetting.props.value === muteEmailsSettingValue
|
|
||||||
}
|
|
||||||
|
|
||||||
const keyParamsResponse = await getUserKeyParamsUseCase.execute({
|
const keyParamsResponse = await getUserKeyParamsUseCase.execute({
|
||||||
userUuid: user.uuid,
|
userUuid: user.uuid,
|
||||||
authenticated: false,
|
authenticated: false,
|
||||||
})
|
})
|
||||||
|
|
||||||
await domainEventPublisher.publish(
|
await domainEventPublisher.publish(
|
||||||
domainEventFactory.createEmailBackupRequestedEvent(
|
domainEventFactory.createEmailBackupRequestedEvent(user.uuid, keyParamsResponse.keyParams),
|
||||||
user.uuid,
|
|
||||||
emailsMutedSetting?.id.toString() as string,
|
|
||||||
userHasEmailsMuted,
|
|
||||||
keyParamsResponse.keyParams,
|
|
||||||
),
|
|
||||||
)
|
)
|
||||||
|
|
||||||
return
|
return
|
||||||
@@ -82,7 +66,6 @@ void container.load().then((container) => {
|
|||||||
|
|
||||||
logger.info(`Starting email backup requesting for ${backupEmail} ...`)
|
logger.info(`Starting email backup requesting for ${backupEmail} ...`)
|
||||||
|
|
||||||
const settingRepository: SettingRepositoryInterface = container.get(TYPES.Auth_SettingRepository)
|
|
||||||
const userRepository: UserRepositoryInterface = container.get(TYPES.Auth_UserRepository)
|
const userRepository: UserRepositoryInterface = container.get(TYPES.Auth_UserRepository)
|
||||||
const roleService: RoleServiceInterface = container.get(TYPES.Auth_RoleService)
|
const roleService: RoleServiceInterface = container.get(TYPES.Auth_RoleService)
|
||||||
const domainEventFactory: DomainEventFactoryInterface = container.get(TYPES.Auth_DomainEventFactory)
|
const domainEventFactory: DomainEventFactoryInterface = container.get(TYPES.Auth_DomainEventFactory)
|
||||||
@@ -90,14 +73,7 @@ void container.load().then((container) => {
|
|||||||
const getUserKeyParamsUseCase: GetUserKeyParams = container.get(TYPES.Auth_GetUserKeyParams)
|
const getUserKeyParamsUseCase: GetUserKeyParams = container.get(TYPES.Auth_GetUserKeyParams)
|
||||||
|
|
||||||
Promise.resolve(
|
Promise.resolve(
|
||||||
requestBackups(
|
requestBackups(userRepository, roleService, domainEventFactory, domainEventPublisher, getUserKeyParamsUseCase),
|
||||||
userRepository,
|
|
||||||
settingRepository,
|
|
||||||
roleService,
|
|
||||||
domainEventFactory,
|
|
||||||
domainEventPublisher,
|
|
||||||
getUserKeyParamsUseCase,
|
|
||||||
),
|
|
||||||
)
|
)
|
||||||
.then(() => {
|
.then(() => {
|
||||||
logger.info(`Email backup requesting complete for ${backupEmail}`)
|
logger.info(`Email backup requesting complete for ${backupEmail}`)
|
||||||
|
|||||||
@@ -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
|
||||||
@@ -42,6 +42,10 @@ case "$COMMAND" in
|
|||||||
exec node docker/entrypoint-fix-roles.js
|
exec node docker/entrypoint-fix-roles.js
|
||||||
;;
|
;;
|
||||||
|
|
||||||
|
'fix-subscriptions' )
|
||||||
|
exec node docker/entrypoint-fix-subscriptions.js
|
||||||
|
;;
|
||||||
|
|
||||||
'delete-accounts' )
|
'delete-accounts' )
|
||||||
FILE_NAME=$1 && shift 1
|
FILE_NAME=$1 && shift 1
|
||||||
MODE=$1 && shift 1
|
MODE=$1 && shift 1
|
||||||
|
|||||||
@@ -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
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
import { MigrationInterface, QueryRunner } from 'typeorm'
|
||||||
|
|
||||||
|
export class UserRolesContentLimit1707759514236 implements MigrationInterface {
|
||||||
|
public async up(queryRunner: QueryRunner): Promise<void> {
|
||||||
|
await queryRunner.query(
|
||||||
|
'INSERT INTO `permissions` (uuid, name) VALUES ("f8b4ced2-6a59-49f8-9ade-416a5f5ffc61", "server:content-limit")',
|
||||||
|
)
|
||||||
|
await queryRunner.query(
|
||||||
|
'INSERT INTO `roles` (uuid, name, version) VALUES ("ab2e15c9-9252-43f3-829c-6f0af3315791", "CORE_USER", 4)',
|
||||||
|
)
|
||||||
|
await queryRunner.query(
|
||||||
|
'INSERT INTO `role_permissions` (permission_uuid, role_uuid) VALUES \
|
||||||
|
("b04a7670-934e-4ab1-b8a3-0f27ff159511", "ab2e15c9-9252-43f3-829c-6f0af3315791"), \
|
||||||
|
("eb0575a2-6e26-49e3-9501-f2e75d7dbda3", "ab2e15c9-9252-43f3-829c-6f0af3315791"), \
|
||||||
|
("f8b4ced2-6a59-49f8-9ade-416a5f5ffc61", "ab2e15c9-9252-43f3-829c-6f0af3315791") \
|
||||||
|
',
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
public async down(queryRunner: QueryRunner): Promise<void> {
|
||||||
|
await queryRunner.query('DELETE FROM `role_permissions` WHERE role_uuid="ab2e15c9-9252-43f3-829c-6f0af3315791"')
|
||||||
|
await queryRunner.query('DELETE FROM `permissions` WHERE uuid="f8b4ced2-6a59-49f8-9ade-416a5f5ffc61"')
|
||||||
|
await queryRunner.query('DELETE FROM `roles` WHERE uuid="ab2e15c9-9252-43f3-829c-6f0af3315791"')
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
import { MigrationInterface, QueryRunner } from 'typeorm'
|
||||||
|
|
||||||
|
export class AddSessionVersion1707813542369 implements MigrationInterface {
|
||||||
|
name = 'AddSessionVersion1707813542369'
|
||||||
|
|
||||||
|
public async up(queryRunner: QueryRunner): Promise<void> {
|
||||||
|
await queryRunner.query('ALTER TABLE `sessions` ADD `version` smallint NULL DEFAULT 1')
|
||||||
|
}
|
||||||
|
|
||||||
|
public async down(queryRunner: QueryRunner): Promise<void> {
|
||||||
|
await queryRunner.query('ALTER TABLE `sessions` DROP COLUMN `version`')
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
import { MigrationInterface, QueryRunner } from 'typeorm'
|
||||||
|
|
||||||
|
export class AddSessionPrivateIdentifier1709133001993 implements MigrationInterface {
|
||||||
|
name = 'AddSessionPrivateIdentifier1709133001993'
|
||||||
|
|
||||||
|
public async up(queryRunner: QueryRunner): Promise<void> {
|
||||||
|
await queryRunner.query(
|
||||||
|
"ALTER TABLE `sessions` ADD `private_identifier` varchar(36) NULL COMMENT 'Used to identify a session without exposing the UUID in client-side cookies.'",
|
||||||
|
)
|
||||||
|
await queryRunner.query('CREATE INDEX `index_sessions_on_private_identifier` ON `sessions` (`private_identifier`)')
|
||||||
|
}
|
||||||
|
|
||||||
|
public async down(queryRunner: QueryRunner): Promise<void> {
|
||||||
|
await queryRunner.query('DROP INDEX `index_sessions_on_private_identifier` ON `sessions`')
|
||||||
|
await queryRunner.query('ALTER TABLE `sessions` DROP COLUMN `private_identifier`')
|
||||||
|
}
|
||||||
|
}
|
||||||
+19
@@ -0,0 +1,19 @@
|
|||||||
|
import { MigrationInterface, QueryRunner } from 'typeorm'
|
||||||
|
|
||||||
|
export class AddRevokedSessionPrivateIdentifier1709206805226 implements MigrationInterface {
|
||||||
|
name = 'AddRevokedSessionPrivateIdentifier1709206805226'
|
||||||
|
|
||||||
|
public async up(queryRunner: QueryRunner): Promise<void> {
|
||||||
|
await queryRunner.query(
|
||||||
|
"ALTER TABLE `revoked_sessions` ADD `private_identifier` varchar(36) NULL COMMENT 'Used to identify a session without exposing the UUID in client-side cookies.'",
|
||||||
|
)
|
||||||
|
await queryRunner.query(
|
||||||
|
'CREATE INDEX `index_revoked_sessions_on_private_identifier` ON `revoked_sessions` (`private_identifier`)',
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
public async down(queryRunner: QueryRunner): Promise<void> {
|
||||||
|
await queryRunner.query('DROP INDEX `index_revoked_sessions_on_private_identifier` ON `revoked_sessions`')
|
||||||
|
await queryRunner.query('ALTER TABLE `revoked_sessions` DROP COLUMN `private_identifier`')
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
import { MigrationInterface, QueryRunner } from 'typeorm'
|
||||||
|
|
||||||
|
export class AddApplicationAndSnjsToSessions1710236132439 implements MigrationInterface {
|
||||||
|
name = 'AddApplicationAndSnjsToSessions1710236132439'
|
||||||
|
|
||||||
|
public async up(queryRunner: QueryRunner): Promise<void> {
|
||||||
|
await queryRunner.query('ALTER TABLE `sessions` ADD `application` varchar(255) NULL')
|
||||||
|
await queryRunner.query('ALTER TABLE `sessions` ADD `snjs` varchar(255) NULL')
|
||||||
|
}
|
||||||
|
|
||||||
|
public async down(queryRunner: QueryRunner): Promise<void> {
|
||||||
|
await queryRunner.query('ALTER TABLE `sessions` DROP COLUMN `snjs`')
|
||||||
|
await queryRunner.query('ALTER TABLE `sessions` DROP COLUMN `application`')
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
import { MigrationInterface, QueryRunner } from 'typeorm'
|
||||||
|
|
||||||
|
export class UserRolesContentLimit1707759514236 implements MigrationInterface {
|
||||||
|
public async up(queryRunner: QueryRunner): Promise<void> {
|
||||||
|
await queryRunner.query(
|
||||||
|
'INSERT INTO `permissions` (uuid, name) VALUES ("f8b4ced2-6a59-49f8-9ade-416a5f5ffc61", "server:content-limit")',
|
||||||
|
)
|
||||||
|
await queryRunner.query(
|
||||||
|
'INSERT INTO `roles` (uuid, name, version) VALUES ("ab2e15c9-9252-43f3-829c-6f0af3315791", "CORE_USER", 4)',
|
||||||
|
)
|
||||||
|
await queryRunner.query(
|
||||||
|
'INSERT INTO `role_permissions` (permission_uuid, role_uuid) VALUES \
|
||||||
|
("b04a7670-934e-4ab1-b8a3-0f27ff159511", "ab2e15c9-9252-43f3-829c-6f0af3315791"), \
|
||||||
|
("eb0575a2-6e26-49e3-9501-f2e75d7dbda3", "ab2e15c9-9252-43f3-829c-6f0af3315791"), \
|
||||||
|
("f8b4ced2-6a59-49f8-9ade-416a5f5ffc61", "ab2e15c9-9252-43f3-829c-6f0af3315791") \
|
||||||
|
',
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
public async down(queryRunner: QueryRunner): Promise<void> {
|
||||||
|
await queryRunner.query('DELETE FROM `role_permissions` WHERE role_uuid="ab2e15c9-9252-43f3-829c-6f0af3315791"')
|
||||||
|
await queryRunner.query('DELETE FROM `permissions` WHERE uuid="f8b4ced2-6a59-49f8-9ade-416a5f5ffc61"')
|
||||||
|
await queryRunner.query('DELETE FROM `roles` WHERE uuid="ab2e15c9-9252-43f3-829c-6f0af3315791"')
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
import { MigrationInterface, QueryRunner } from 'typeorm'
|
||||||
|
|
||||||
|
export class AddSessionVersion1707813542369 implements MigrationInterface {
|
||||||
|
name = 'AddSessionVersion1707813542369'
|
||||||
|
|
||||||
|
public async up(queryRunner: QueryRunner): Promise<void> {
|
||||||
|
await queryRunner.query('ALTER TABLE `sessions` ADD `version` smallint NULL DEFAULT 1')
|
||||||
|
}
|
||||||
|
|
||||||
|
public async down(queryRunner: QueryRunner): Promise<void> {
|
||||||
|
await queryRunner.query('ALTER TABLE `sessions` DROP COLUMN `version`')
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
import { MigrationInterface, QueryRunner } from 'typeorm'
|
||||||
|
|
||||||
|
export class AddSessionPrivateIdentifier1709133169237 implements MigrationInterface {
|
||||||
|
name = 'AddSessionPrivateIdentifier1709133169237'
|
||||||
|
|
||||||
|
public async up(queryRunner: QueryRunner): Promise<void> {
|
||||||
|
await queryRunner.query('DROP INDEX "index_sessions_on_updated_at"')
|
||||||
|
await queryRunner.query('DROP INDEX "index_sessions_on_user_uuid"')
|
||||||
|
await queryRunner.query(
|
||||||
|
'CREATE TABLE "temporary_sessions" ("uuid" varchar PRIMARY KEY NOT NULL, "user_uuid" varchar(255), "hashed_access_token" varchar(255) NOT NULL, "hashed_refresh_token" varchar(255) NOT NULL, "access_expiration" datetime NOT NULL DEFAULT (CURRENT_TIMESTAMP), "refresh_expiration" datetime NOT NULL, "api_version" varchar(255), "user_agent" text, "created_at" datetime NOT NULL, "updated_at" datetime NOT NULL, "readonly_access" tinyint NOT NULL DEFAULT (0), "version" smallint DEFAULT (1), "private_identifier" varchar(36))',
|
||||||
|
)
|
||||||
|
await queryRunner.query(
|
||||||
|
'INSERT INTO "temporary_sessions"("uuid", "user_uuid", "hashed_access_token", "hashed_refresh_token", "access_expiration", "refresh_expiration", "api_version", "user_agent", "created_at", "updated_at", "readonly_access", "version") SELECT "uuid", "user_uuid", "hashed_access_token", "hashed_refresh_token", "access_expiration", "refresh_expiration", "api_version", "user_agent", "created_at", "updated_at", "readonly_access", "version" FROM "sessions"',
|
||||||
|
)
|
||||||
|
await queryRunner.query('DROP TABLE "sessions"')
|
||||||
|
await queryRunner.query('ALTER TABLE "temporary_sessions" RENAME TO "sessions"')
|
||||||
|
await queryRunner.query('CREATE INDEX "index_sessions_on_updated_at" ON "sessions" ("updated_at") ')
|
||||||
|
await queryRunner.query('CREATE INDEX "index_sessions_on_user_uuid" ON "sessions" ("user_uuid") ')
|
||||||
|
await queryRunner.query('CREATE INDEX "index_sessions_on_private_identifier" ON "sessions" ("private_identifier") ')
|
||||||
|
}
|
||||||
|
|
||||||
|
public async down(queryRunner: QueryRunner): Promise<void> {
|
||||||
|
await queryRunner.query('DROP INDEX "index_sessions_on_private_identifier"')
|
||||||
|
await queryRunner.query('DROP INDEX "index_sessions_on_user_uuid"')
|
||||||
|
await queryRunner.query('DROP INDEX "index_sessions_on_updated_at"')
|
||||||
|
await queryRunner.query('ALTER TABLE "sessions" RENAME TO "temporary_sessions"')
|
||||||
|
await queryRunner.query(
|
||||||
|
'CREATE TABLE "sessions" ("uuid" varchar PRIMARY KEY NOT NULL, "user_uuid" varchar(255), "hashed_access_token" varchar(255) NOT NULL, "hashed_refresh_token" varchar(255) NOT NULL, "access_expiration" datetime NOT NULL DEFAULT (CURRENT_TIMESTAMP), "refresh_expiration" datetime NOT NULL, "api_version" varchar(255), "user_agent" text, "created_at" datetime NOT NULL, "updated_at" datetime NOT NULL, "readonly_access" tinyint NOT NULL DEFAULT (0), "version" smallint DEFAULT (1))',
|
||||||
|
)
|
||||||
|
await queryRunner.query(
|
||||||
|
'INSERT INTO "sessions"("uuid", "user_uuid", "hashed_access_token", "hashed_refresh_token", "access_expiration", "refresh_expiration", "api_version", "user_agent", "created_at", "updated_at", "readonly_access", "version") SELECT "uuid", "user_uuid", "hashed_access_token", "hashed_refresh_token", "access_expiration", "refresh_expiration", "api_version", "user_agent", "created_at", "updated_at", "readonly_access", "version" FROM "temporary_sessions"',
|
||||||
|
)
|
||||||
|
await queryRunner.query('DROP TABLE "temporary_sessions"')
|
||||||
|
await queryRunner.query('CREATE INDEX "index_sessions_on_user_uuid" ON "sessions" ("user_uuid") ')
|
||||||
|
await queryRunner.query('CREATE INDEX "index_sessions_on_updated_at" ON "sessions" ("updated_at") ')
|
||||||
|
}
|
||||||
|
}
|
||||||
+34
@@ -0,0 +1,34 @@
|
|||||||
|
import { MigrationInterface, QueryRunner } from 'typeorm'
|
||||||
|
|
||||||
|
export class AddRevokedSessionPrivateIdentifier1709208455658 implements MigrationInterface {
|
||||||
|
name = 'AddRevokedSessionPrivateIdentifier1709208455658'
|
||||||
|
|
||||||
|
public async up(queryRunner: QueryRunner): Promise<void> {
|
||||||
|
await queryRunner.query('DROP INDEX "index_revoked_sessions_on_user_uuid"')
|
||||||
|
await queryRunner.query(
|
||||||
|
'CREATE TABLE "temporary_revoked_sessions" ("uuid" varchar PRIMARY KEY NOT NULL, "user_uuid" varchar(36) NOT NULL, "received" tinyint NOT NULL DEFAULT (0), "created_at" datetime NOT NULL, "received_at" datetime, "user_agent" text, "api_version" varchar(255), "private_identifier" varchar(36), CONSTRAINT "FK_edaf18faca67e682be39b5ecae5" FOREIGN KEY ("user_uuid") REFERENCES "users" ("uuid") ON DELETE CASCADE ON UPDATE NO ACTION)',
|
||||||
|
)
|
||||||
|
await queryRunner.query(
|
||||||
|
'INSERT INTO "temporary_revoked_sessions"("uuid", "user_uuid", "received", "created_at", "received_at", "user_agent", "api_version") SELECT "uuid", "user_uuid", "received", "created_at", "received_at", "user_agent", "api_version" FROM "revoked_sessions"',
|
||||||
|
)
|
||||||
|
await queryRunner.query('DROP TABLE "revoked_sessions"')
|
||||||
|
await queryRunner.query('ALTER TABLE "temporary_revoked_sessions" RENAME TO "revoked_sessions"')
|
||||||
|
await queryRunner.query('CREATE INDEX "index_revoked_sessions_on_user_uuid" ON "revoked_sessions" ("user_uuid") ')
|
||||||
|
await queryRunner.query(
|
||||||
|
'CREATE INDEX "index_revoked_sessions_on_private_identifier" ON "revoked_sessions" ("private_identifier") ',
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
public async down(queryRunner: QueryRunner): Promise<void> {
|
||||||
|
await queryRunner.query('DROP INDEX "index_revoked_sessions_on_user_uuid"')
|
||||||
|
await queryRunner.query('ALTER TABLE "revoked_sessions" RENAME TO "temporary_revoked_sessions"')
|
||||||
|
await queryRunner.query(
|
||||||
|
'CREATE TABLE "revoked_sessions" ("uuid" varchar PRIMARY KEY NOT NULL, "user_uuid" varchar(36) NOT NULL, "received" tinyint NOT NULL DEFAULT (0), "created_at" datetime NOT NULL, "received_at" datetime, "user_agent" text, "api_version" varchar(255), CONSTRAINT "FK_edaf18faca67e682be39b5ecae5" FOREIGN KEY ("user_uuid") REFERENCES "users" ("uuid") ON DELETE CASCADE ON UPDATE NO ACTION)',
|
||||||
|
)
|
||||||
|
await queryRunner.query(
|
||||||
|
'INSERT INTO "revoked_sessions"("uuid", "user_uuid", "received", "created_at", "received_at", "user_agent", "api_version") SELECT "uuid", "user_uuid", "received", "created_at", "received_at", "user_agent", "api_version" FROM "temporary_revoked_sessions"',
|
||||||
|
)
|
||||||
|
await queryRunner.query('DROP TABLE "temporary_revoked_sessions"')
|
||||||
|
await queryRunner.query('CREATE INDEX "index_revoked_sessions_on_user_uuid" ON "revoked_sessions" ("user_uuid") ')
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
import { MigrationInterface, QueryRunner } from 'typeorm'
|
||||||
|
|
||||||
|
export class AddApplicationAndSnjsToSessions1710236132439 implements MigrationInterface {
|
||||||
|
name = 'AddApplicationAndSnjsToSessions1710236132439'
|
||||||
|
|
||||||
|
public async up(queryRunner: QueryRunner): Promise<void> {
|
||||||
|
await queryRunner.query('ALTER TABLE `sessions` ADD `application` varchar(255) NULL')
|
||||||
|
await queryRunner.query('ALTER TABLE `sessions` ADD `snjs` varchar(255) NULL')
|
||||||
|
}
|
||||||
|
|
||||||
|
public async down(queryRunner: QueryRunner): Promise<void> {
|
||||||
|
await queryRunner.query('ALTER TABLE `sessions` DROP COLUMN `snjs`')
|
||||||
|
await queryRunner.query('ALTER TABLE `sessions` DROP COLUMN `application`')
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,10 +1,10 @@
|
|||||||
{
|
{
|
||||||
"name": "@standardnotes/auth-server",
|
"name": "@standardnotes/auth-server",
|
||||||
"version": "1.177.13",
|
"version": "1.178.5",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=18.0.0 <21.0.0"
|
"node": ">=18.0.0 <21.0.0"
|
||||||
},
|
},
|
||||||
"description": "Auth Server",
|
"description": "Auth Server for SN",
|
||||||
"main": "dist/src/index.js",
|
"main": "dist/src/index.js",
|
||||||
"typings": "dist/src/index.d.ts",
|
"typings": "dist/src/index.d.ts",
|
||||||
"author": "Karol Sójko <karol@standardnotes.com>",
|
"author": "Karol Sójko <karol@standardnotes.com>",
|
||||||
@@ -24,8 +24,7 @@
|
|||||||
"build": "tsc --build",
|
"build": "tsc --build",
|
||||||
"lint": "eslint . --ext .ts",
|
"lint": "eslint . --ext .ts",
|
||||||
"lint:fix": "eslint . --fix --ext .ts",
|
"lint:fix": "eslint . --fix --ext .ts",
|
||||||
"pretest": "yarn lint && yarn build",
|
"test": "jest --coverage --no-cache --config=./jest.config.js --maxWorkers=2",
|
||||||
"test": "jest --coverage --no-cache --config=./jest.config.js --maxWorkers=50%",
|
|
||||||
"start": "yarn node dist/bin/server.js",
|
"start": "yarn node dist/bin/server.js",
|
||||||
"worker": "yarn node dist/bin/worker.js",
|
"worker": "yarn node dist/bin/worker.js",
|
||||||
"cleanup": "yarn node dist/bin/cleanup.js",
|
"cleanup": "yarn node dist/bin/cleanup.js",
|
||||||
@@ -60,7 +59,10 @@
|
|||||||
"@standardnotes/sncrypto-common": "^1.13.4",
|
"@standardnotes/sncrypto-common": "^1.13.4",
|
||||||
"@standardnotes/sncrypto-node": "workspace:*",
|
"@standardnotes/sncrypto-node": "workspace:*",
|
||||||
"@standardnotes/time": "workspace:*",
|
"@standardnotes/time": "workspace:*",
|
||||||
|
"agentkeepalive": "^4.5.0",
|
||||||
|
"axios": "^1.6.7",
|
||||||
"bcryptjs": "2.4.3",
|
"bcryptjs": "2.4.3",
|
||||||
|
"cookie-parser": "^1.4.6",
|
||||||
"cors": "2.8.5",
|
"cors": "2.8.5",
|
||||||
"dayjs": "^1.11.6",
|
"dayjs": "^1.11.6",
|
||||||
"dotenv": "^16.0.1",
|
"dotenv": "^16.0.1",
|
||||||
@@ -68,7 +70,7 @@
|
|||||||
"inversify": "^6.0.1",
|
"inversify": "^6.0.1",
|
||||||
"inversify-express-utils": "^6.4.3",
|
"inversify-express-utils": "^6.4.3",
|
||||||
"ioredis": "^5.2.4",
|
"ioredis": "^5.2.4",
|
||||||
"mysql2": "^3.0.1",
|
"mysql2": "^3.9.7",
|
||||||
"otplib": "12.0.1",
|
"otplib": "12.0.1",
|
||||||
"prettyjson": "^1.2.5",
|
"prettyjson": "^1.2.5",
|
||||||
"reflect-metadata": "^0.2.1",
|
"reflect-metadata": "^0.2.1",
|
||||||
@@ -80,6 +82,7 @@
|
|||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/bcryptjs": "^2.4.2",
|
"@types/bcryptjs": "^2.4.2",
|
||||||
|
"@types/cookie-parser": "^1",
|
||||||
"@types/cors": "^2.8.9",
|
"@types/cors": "^2.8.9",
|
||||||
"@types/express": "^4.17.14",
|
"@types/express": "^4.17.14",
|
||||||
"@types/ioredis": "^5.0.0",
|
"@types/ioredis": "^5.0.0",
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
import * as winston from 'winston'
|
import * as winston from 'winston'
|
||||||
|
import * as AgentKeepAlive from 'agentkeepalive'
|
||||||
import Redis from 'ioredis'
|
import Redis from 'ioredis'
|
||||||
import { SNSClient, SNSClientConfig } from '@aws-sdk/client-sns'
|
import { SNSClient, SNSClientConfig } from '@aws-sdk/client-sns'
|
||||||
|
import axios, { AxiosInstance } from 'axios'
|
||||||
import { SQSClient, SQSClientConfig } from '@aws-sdk/client-sqs'
|
import { SQSClient, SQSClientConfig } from '@aws-sdk/client-sqs'
|
||||||
import { S3Client } from '@aws-sdk/client-s3'
|
import { S3Client } from '@aws-sdk/client-s3'
|
||||||
import { Container } from 'inversify'
|
import { Container } from 'inversify'
|
||||||
@@ -36,13 +38,11 @@ import { AuthResponseFactoryResolver } from '../Domain/Auth/AuthResponseFactoryR
|
|||||||
import { ClearLoginAttempts } from '../Domain/UseCase/ClearLoginAttempts'
|
import { ClearLoginAttempts } from '../Domain/UseCase/ClearLoginAttempts'
|
||||||
import { IncreaseLoginAttempts } from '../Domain/UseCase/IncreaseLoginAttempts'
|
import { IncreaseLoginAttempts } from '../Domain/UseCase/IncreaseLoginAttempts'
|
||||||
import { GetUserKeyParams } from '../Domain/UseCase/GetUserKeyParams/GetUserKeyParams'
|
import { GetUserKeyParams } from '../Domain/UseCase/GetUserKeyParams/GetUserKeyParams'
|
||||||
import { UpdateUser } from '../Domain/UseCase/UpdateUser'
|
|
||||||
import { RedisEphemeralSessionRepository } from '../Infra/Redis/RedisEphemeralSessionRepository'
|
import { RedisEphemeralSessionRepository } from '../Infra/Redis/RedisEphemeralSessionRepository'
|
||||||
import { GetActiveSessionsForUser } from '../Domain/UseCase/GetActiveSessionsForUser'
|
import { GetActiveSessionsForUser } from '../Domain/UseCase/GetActiveSessionsForUser'
|
||||||
import { DeleteOtherSessionsForUser } from '../Domain/UseCase/DeleteOtherSessionsForUser'
|
import { DeleteOtherSessionsForUser } from '../Domain/UseCase/DeleteOtherSessionsForUser'
|
||||||
import { DeleteSessionForUser } from '../Domain/UseCase/DeleteSessionForUser'
|
import { DeleteSessionForUser } from '../Domain/UseCase/DeleteSessionForUser'
|
||||||
import { Register } from '../Domain/UseCase/Register'
|
import { Register } from '../Domain/UseCase/Register'
|
||||||
import { LockRepository } from '../Infra/Redis/LockRepository'
|
|
||||||
import { TypeORMRevokedSessionRepository } from '../Infra/TypeORM/TypeORMRevokedSessionRepository'
|
import { TypeORMRevokedSessionRepository } from '../Infra/TypeORM/TypeORMRevokedSessionRepository'
|
||||||
import { AuthenticationMethodResolver } from '../Domain/Auth/AuthenticationMethodResolver'
|
import { AuthenticationMethodResolver } from '../Domain/Auth/AuthenticationMethodResolver'
|
||||||
import { RevokedSession } from '../Domain/Session/RevokedSession'
|
import { RevokedSession } from '../Domain/Session/RevokedSession'
|
||||||
@@ -284,6 +284,21 @@ import { AccountDeletionVerificationPassedEventHandler } from '../Domain/Handler
|
|||||||
import { RenewSharedSubscriptions } from '../Domain/UseCase/RenewSharedSubscriptions/RenewSharedSubscriptions'
|
import { RenewSharedSubscriptions } from '../Domain/UseCase/RenewSharedSubscriptions/RenewSharedSubscriptions'
|
||||||
import { FixStorageQuotaForUser } from '../Domain/UseCase/FixStorageQuotaForUser/FixStorageQuotaForUser'
|
import { FixStorageQuotaForUser } from '../Domain/UseCase/FixStorageQuotaForUser/FixStorageQuotaForUser'
|
||||||
import { FileQuotaRecalculatedEventHandler } from '../Domain/Handler/FileQuotaRecalculatedEventHandler'
|
import { FileQuotaRecalculatedEventHandler } from '../Domain/Handler/FileQuotaRecalculatedEventHandler'
|
||||||
|
import { SessionServiceInterface } from '../Domain/Session/SessionServiceInterface'
|
||||||
|
import { SubscriptionStateFetchedEventHandler } from '../Domain/Handler/SubscriptionStateFetchedEventHandler'
|
||||||
|
import { CaptchaServerInterface } from '../Domain/HumanVerification/CaptchaServerInterface'
|
||||||
|
import { VerifyHumanInteraction } from '../Domain/UseCase/VerifyHumanInteraction/VerifyHumanInteraction'
|
||||||
|
import { HttpCaptchaServer } from '../Infra/Http/HumanVerification/HttpCaptchaServer'
|
||||||
|
import { CookieFactoryInterface } from '../Domain/Auth/Cookies/CookieFactoryInterface'
|
||||||
|
import { CookieFactory } from '../Domain/Auth/Cookies/CookieFactory'
|
||||||
|
import { RedisLockRepository } from '../Infra/Redis/RedisLockRepository'
|
||||||
|
import { DeleteSessionByToken } from '../Domain/UseCase/DeleteSessionByToken/DeleteSessionByToken'
|
||||||
|
import { GetSessionFromToken } from '../Domain/UseCase/GetSessionFromToken/GetSessionFromToken'
|
||||||
|
import { CooldownSessionTokens } from '../Domain/UseCase/CooldownSessionTokens/CooldownSessionTokens'
|
||||||
|
import { SessionTokensCooldownRepositoryInterface } from '../Domain/Session/SessionTokensCooldownRepositoryInterface'
|
||||||
|
import { RedisSessionTokensCooldownRepository } from '../Infra/Redis/RedisSessionTokensCooldownRepository'
|
||||||
|
import { InMemorySessionTokensCooldownRepository } from '../Infra/InMemory/InMemorySessionTokensCooldownRepository'
|
||||||
|
import { GetCooldownSessionTokens } from '../Domain/UseCase/GetCooldownSessionTokens/GetCooldownSessionTokens'
|
||||||
|
|
||||||
export class ContainerConfigLoader {
|
export class ContainerConfigLoader {
|
||||||
constructor(private mode: 'server' | 'worker' = 'server') {}
|
constructor(private mode: 'server' | 'worker' = 'server') {}
|
||||||
@@ -328,6 +343,8 @@ export class ContainerConfigLoader {
|
|||||||
const isConfiguredForSelfHosting = env.get('MODE', true) === 'self-hosted'
|
const isConfiguredForSelfHosting = env.get('MODE', true) === 'self-hosted'
|
||||||
const isConfiguredForHomeServerOrSelfHosting = isConfiguredForHomeServer || isConfiguredForSelfHosting
|
const isConfiguredForHomeServerOrSelfHosting = isConfiguredForHomeServer || isConfiguredForSelfHosting
|
||||||
const isConfiguredForInMemoryCache = env.get('CACHE_TYPE', true) === 'memory'
|
const isConfiguredForInMemoryCache = env.get('CACHE_TYPE', true) === 'memory'
|
||||||
|
const captchaServerUrl = env.get('CAPTCHA_SERVER_URL', true)
|
||||||
|
const captchaUIUrl = env.get('CAPTCHA_UI_URL', true)
|
||||||
|
|
||||||
container
|
container
|
||||||
.bind<boolean>(TYPES.Auth_IS_CONFIGURED_FOR_HOME_SERVER_OR_SELF_HOSTING)
|
.bind<boolean>(TYPES.Auth_IS_CONFIGURED_FOR_HOME_SERVER_OR_SELF_HOSTING)
|
||||||
@@ -595,9 +612,17 @@ export class ContainerConfigLoader {
|
|||||||
container
|
container
|
||||||
.bind(TYPES.Auth_MAX_LOGIN_ATTEMPTS)
|
.bind(TYPES.Auth_MAX_LOGIN_ATTEMPTS)
|
||||||
.toConstantValue(env.get('MAX_LOGIN_ATTEMPTS', true) ? +env.get('MAX_LOGIN_ATTEMPTS', true) : 6)
|
.toConstantValue(env.get('MAX_LOGIN_ATTEMPTS', true) ? +env.get('MAX_LOGIN_ATTEMPTS', true) : 6)
|
||||||
|
container
|
||||||
|
.bind(TYPES.Auth_MAX_CAPTCHA_LOGIN_ATTEMPTS)
|
||||||
|
.toConstantValue(env.get('MAX_CAPTCHA_LOGIN_ATTEMPTS', true) ? +env.get('MAX_CAPTCHA_LOGIN_ATTEMPTS', true) : 6)
|
||||||
container
|
container
|
||||||
.bind(TYPES.Auth_FAILED_LOGIN_LOCKOUT)
|
.bind(TYPES.Auth_FAILED_LOGIN_LOCKOUT)
|
||||||
.toConstantValue(env.get('FAILED_LOGIN_LOCKOUT', true) ? +env.get('FAILED_LOGIN_LOCKOUT', true) : 3600)
|
.toConstantValue(env.get('FAILED_LOGIN_LOCKOUT', true) ? +env.get('FAILED_LOGIN_LOCKOUT', true) : 3600)
|
||||||
|
container
|
||||||
|
.bind(TYPES.Auth_FAILED_LOGIN_CAPTCHA_LOCKOUT)
|
||||||
|
.toConstantValue(
|
||||||
|
env.get('FAILED_LOGIN_CAPTCHA_LOCKOUT', true) ? +env.get('FAILED_LOGIN_CAPTCHA_LOCKOUT', true) : 86400,
|
||||||
|
)
|
||||||
container.bind(TYPES.Auth_PSEUDO_KEY_PARAMS_KEY).toConstantValue(env.get('PSEUDO_KEY_PARAMS_KEY'))
|
container.bind(TYPES.Auth_PSEUDO_KEY_PARAMS_KEY).toConstantValue(env.get('PSEUDO_KEY_PARAMS_KEY'))
|
||||||
container
|
container
|
||||||
.bind(TYPES.Auth_EPHEMERAL_SESSION_AGE)
|
.bind(TYPES.Auth_EPHEMERAL_SESSION_AGE)
|
||||||
@@ -631,6 +656,10 @@ export class ContainerConfigLoader {
|
|||||||
container
|
container
|
||||||
.bind(TYPES.Auth_READONLY_USERS)
|
.bind(TYPES.Auth_READONLY_USERS)
|
||||||
.toConstantValue(env.get('READONLY_USERS', true) ? env.get('READONLY_USERS', true).split(',') : [])
|
.toConstantValue(env.get('READONLY_USERS', true) ? env.get('READONLY_USERS', true).split(',') : [])
|
||||||
|
container.bind(TYPES.Auth_CAPTCHA_SERVER_URL).toConstantValue(captchaServerUrl)
|
||||||
|
container.bind(TYPES.Auth_CAPTCHA_UI_URL).toConstantValue(captchaUIUrl)
|
||||||
|
container.bind<boolean>(TYPES.Auth_HUMAN_VERIFICATION_ENABLED).toConstantValue(!!captchaServerUrl && !!captchaUIUrl)
|
||||||
|
container.bind<boolean>(TYPES.Auth_FORCE_LEGACY_SESSIONS).toConstantValue(env.get('E2E_TESTING', true) === 'true')
|
||||||
|
|
||||||
if (isConfiguredForInMemoryCache) {
|
if (isConfiguredForInMemoryCache) {
|
||||||
container
|
container
|
||||||
@@ -650,6 +679,7 @@ export class ContainerConfigLoader {
|
|||||||
container.get(TYPES.Auth_Timer),
|
container.get(TYPES.Auth_Timer),
|
||||||
container.get(TYPES.Auth_MAX_LOGIN_ATTEMPTS),
|
container.get(TYPES.Auth_MAX_LOGIN_ATTEMPTS),
|
||||||
container.get(TYPES.Auth_FAILED_LOGIN_LOCKOUT),
|
container.get(TYPES.Auth_FAILED_LOGIN_LOCKOUT),
|
||||||
|
container.get(TYPES.Auth_FAILED_LOGIN_CAPTCHA_LOCKOUT),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
container
|
container
|
||||||
@@ -677,9 +707,21 @@ export class ContainerConfigLoader {
|
|||||||
container.get(TYPES.Auth_Timer),
|
container.get(TYPES.Auth_Timer),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
container
|
||||||
|
.bind<SessionTokensCooldownRepositoryInterface>(TYPES.Auth_SessionTokensCooldownRepository)
|
||||||
|
.toConstantValue(new InMemorySessionTokensCooldownRepository())
|
||||||
} else {
|
} else {
|
||||||
container.bind<PKCERepositoryInterface>(TYPES.Auth_PKCERepository).to(RedisPKCERepository)
|
container.bind<PKCERepositoryInterface>(TYPES.Auth_PKCERepository).to(RedisPKCERepository)
|
||||||
container.bind<LockRepositoryInterface>(TYPES.Auth_LockRepository).to(LockRepository)
|
container
|
||||||
|
.bind<LockRepositoryInterface>(TYPES.Auth_LockRepository)
|
||||||
|
.toConstantValue(
|
||||||
|
new RedisLockRepository(
|
||||||
|
container.get<Redis>(TYPES.Auth_Redis),
|
||||||
|
container.get<number>(TYPES.Auth_MAX_LOGIN_ATTEMPTS),
|
||||||
|
container.get<number>(TYPES.Auth_FAILED_LOGIN_LOCKOUT),
|
||||||
|
container.get<number>(TYPES.Auth_FAILED_LOGIN_CAPTCHA_LOCKOUT),
|
||||||
|
),
|
||||||
|
)
|
||||||
container
|
container
|
||||||
.bind<EphemeralSessionRepositoryInterface>(TYPES.Auth_EphemeralSessionRepository)
|
.bind<EphemeralSessionRepositoryInterface>(TYPES.Auth_EphemeralSessionRepository)
|
||||||
.to(RedisEphemeralSessionRepository)
|
.to(RedisEphemeralSessionRepository)
|
||||||
@@ -689,6 +731,9 @@ export class ContainerConfigLoader {
|
|||||||
container
|
container
|
||||||
.bind<SubscriptionTokenRepositoryInterface>(TYPES.Auth_SubscriptionTokenRepository)
|
.bind<SubscriptionTokenRepositoryInterface>(TYPES.Auth_SubscriptionTokenRepository)
|
||||||
.to(RedisSubscriptionTokenRepository)
|
.to(RedisSubscriptionTokenRepository)
|
||||||
|
container
|
||||||
|
.bind<SessionTokensCooldownRepositoryInterface>(TYPES.Auth_SessionTokensCooldownRepository)
|
||||||
|
.toConstantValue(new RedisSessionTokensCooldownRepository(container.get<Redis>(TYPES.Auth_Redis)))
|
||||||
}
|
}
|
||||||
|
|
||||||
container
|
container
|
||||||
@@ -738,6 +783,41 @@ export class ContainerConfigLoader {
|
|||||||
container.get<UserSubscriptionRepositoryInterface>(TYPES.Auth_UserSubscriptionRepository),
|
container.get<UserSubscriptionRepositoryInterface>(TYPES.Auth_UserSubscriptionRepository),
|
||||||
container.get<string[]>(TYPES.Auth_READONLY_USERS),
|
container.get<string[]>(TYPES.Auth_READONLY_USERS),
|
||||||
container.get<GetSetting>(TYPES.Auth_GetSetting),
|
container.get<GetSetting>(TYPES.Auth_GetSetting),
|
||||||
|
container.get<boolean>(TYPES.Auth_FORCE_LEGACY_SESSIONS),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
container
|
||||||
|
.bind<GetCooldownSessionTokens>(TYPES.Auth_GetCooldownSessionTokens)
|
||||||
|
.toConstantValue(
|
||||||
|
new GetCooldownSessionTokens(
|
||||||
|
container.get<SessionTokensCooldownRepositoryInterface>(TYPES.Auth_SessionTokensCooldownRepository),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
container
|
||||||
|
.bind<GetSessionFromToken>(TYPES.Auth_GetSessionFromToken)
|
||||||
|
.toConstantValue(
|
||||||
|
new GetSessionFromToken(
|
||||||
|
container.get<SessionRepositoryInterface>(TYPES.Auth_SessionRepository),
|
||||||
|
container.get<EphemeralSessionRepositoryInterface>(TYPES.Auth_EphemeralSessionRepository),
|
||||||
|
container.get<GetCooldownSessionTokens>(TYPES.Auth_GetCooldownSessionTokens),
|
||||||
|
container.get<winston.Logger>(TYPES.Auth_Logger),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
container
|
||||||
|
.bind<DeleteSessionByToken>(TYPES.Auth_DeleteSessionByToken)
|
||||||
|
.toConstantValue(
|
||||||
|
new DeleteSessionByToken(
|
||||||
|
container.get<GetSessionFromToken>(TYPES.Auth_GetSessionFromToken),
|
||||||
|
container.get<SessionRepositoryInterface>(TYPES.Auth_SessionRepository),
|
||||||
|
container.get<EphemeralSessionRepositoryInterface>(TYPES.Auth_EphemeralSessionRepository),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
container
|
||||||
|
.bind<CooldownSessionTokens>(TYPES.Auth_CooldownSessionTokens)
|
||||||
|
.toConstantValue(
|
||||||
|
new CooldownSessionTokens(
|
||||||
|
env.get('COOLDOWN_SESSION_TOKENS_TTL', true) ? +env.get('COOLDOWN_SESSION_TOKENS_TTL', true) : 120,
|
||||||
|
container.get<SessionTokensCooldownRepositoryInterface>(TYPES.Auth_SessionTokensCooldownRepository),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
container.bind<AuthResponseFactory20161215>(TYPES.Auth_AuthResponseFactory20161215).to(AuthResponseFactory20161215)
|
container.bind<AuthResponseFactory20161215>(TYPES.Auth_AuthResponseFactory20161215).to(AuthResponseFactory20161215)
|
||||||
@@ -778,7 +858,16 @@ export class ContainerConfigLoader {
|
|||||||
.toConstantValue(new TokenEncoder<ValetTokenData>(container.get(TYPES.Auth_VALET_TOKEN_SECRET)))
|
.toConstantValue(new TokenEncoder<ValetTokenData>(container.get(TYPES.Auth_VALET_TOKEN_SECRET)))
|
||||||
container
|
container
|
||||||
.bind<AuthenticationMethodResolver>(TYPES.Auth_AuthenticationMethodResolver)
|
.bind<AuthenticationMethodResolver>(TYPES.Auth_AuthenticationMethodResolver)
|
||||||
.to(AuthenticationMethodResolver)
|
.toConstantValue(
|
||||||
|
new AuthenticationMethodResolver(
|
||||||
|
container.get<UserRepositoryInterface>(TYPES.Auth_UserRepository),
|
||||||
|
container.get<SessionServiceInterface>(TYPES.Auth_SessionService),
|
||||||
|
container.get<TokenDecoderInterface<SessionTokenData>>(TYPES.Auth_SessionTokenDecoder),
|
||||||
|
container.get<TokenDecoderInterface<SessionTokenData>>(TYPES.Auth_FallbackSessionTokenDecoder),
|
||||||
|
container.get<GetSessionFromToken>(TYPES.Auth_GetSessionFromToken),
|
||||||
|
container.get<winston.Logger>(TYPES.Auth_Logger),
|
||||||
|
),
|
||||||
|
)
|
||||||
container.bind<DomainEventFactory>(TYPES.Auth_DomainEventFactory).to(DomainEventFactory)
|
container.bind<DomainEventFactory>(TYPES.Auth_DomainEventFactory).to(DomainEventFactory)
|
||||||
container
|
container
|
||||||
.bind<SettingsAssociationServiceInterface>(TYPES.Auth_SettingsAssociationService)
|
.bind<SettingsAssociationServiceInterface>(TYPES.Auth_SettingsAssociationService)
|
||||||
@@ -817,6 +906,43 @@ export class ContainerConfigLoader {
|
|||||||
.bind<SelectorInterface<boolean>>(TYPES.Auth_BooleanSelector)
|
.bind<SelectorInterface<boolean>>(TYPES.Auth_BooleanSelector)
|
||||||
.toConstantValue(new DeterministicSelector<boolean>())
|
.toConstantValue(new DeterministicSelector<boolean>())
|
||||||
|
|
||||||
|
const httpAgentKeepAliveTimeout = env.get('HTTP_AGENT_KEEP_ALIVE_TIMEOUT', true)
|
||||||
|
? +env.get('HTTP_AGENT_KEEP_ALIVE_TIMEOUT', true)
|
||||||
|
: 4_000
|
||||||
|
|
||||||
|
container.bind<AxiosInstance>(TYPES.Auth_HTTPClient).toConstantValue(
|
||||||
|
axios.create({
|
||||||
|
httpAgent: new AgentKeepAlive({
|
||||||
|
keepAlive: true,
|
||||||
|
timeout: 2 * httpAgentKeepAliveTimeout,
|
||||||
|
freeSocketTimeout: httpAgentKeepAliveTimeout,
|
||||||
|
}),
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
|
||||||
|
container
|
||||||
|
.bind<CaptchaServerInterface>(TYPES.Auth_CaptchaServer)
|
||||||
|
.toConstantValue(
|
||||||
|
new HttpCaptchaServer(
|
||||||
|
container.get(TYPES.Auth_Logger),
|
||||||
|
container.get(TYPES.Auth_HTTPClient),
|
||||||
|
container.get(TYPES.Auth_CAPTCHA_SERVER_URL),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
container
|
||||||
|
.bind<CookieFactoryInterface>(TYPES.Auth_CookieFactory)
|
||||||
|
.toConstantValue(
|
||||||
|
new CookieFactory(
|
||||||
|
['None', 'Lax', 'Strict'].includes(env.get('COOKIE_SAME_SITE', true))
|
||||||
|
? (env.get('COOKIE_SAME_SITE', true) as 'None' | 'Lax' | 'Strict')
|
||||||
|
: 'None',
|
||||||
|
env.get('COOKIE_DOMAIN', true) ?? 'standardnotes.com',
|
||||||
|
env.get('COOKIE_SECURE', true) ? env.get('COOKIE_SECURE', true) === 'true' : true,
|
||||||
|
env.get('COOKIE_PARTITIONED', true) ? env.get('COOKIE_PARTITIONED', true) === 'true' : true,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
// Middleware
|
// Middleware
|
||||||
container.bind<SessionMiddleware>(TYPES.Auth_SessionMiddleware).to(SessionMiddleware)
|
container.bind<SessionMiddleware>(TYPES.Auth_SessionMiddleware).to(SessionMiddleware)
|
||||||
container.bind<LockMiddleware>(TYPES.Auth_LockMiddleware).to(LockMiddleware)
|
container.bind<LockMiddleware>(TYPES.Auth_LockMiddleware).to(LockMiddleware)
|
||||||
@@ -951,6 +1077,7 @@ export class ContainerConfigLoader {
|
|||||||
new SetSubscriptionSettingValue(
|
new SetSubscriptionSettingValue(
|
||||||
container.get<SubscriptionSettingRepositoryInterface>(TYPES.Auth_SubscriptionSettingRepository),
|
container.get<SubscriptionSettingRepositoryInterface>(TYPES.Auth_SubscriptionSettingRepository),
|
||||||
container.get<GetSubscriptionSetting>(TYPES.Auth_GetSubscriptionSetting),
|
container.get<GetSubscriptionSetting>(TYPES.Auth_GetSubscriptionSetting),
|
||||||
|
container.get<SettingsAssociationServiceInterface>(TYPES.Auth_SettingsAssociationService),
|
||||||
container.get<TimerInterface>(TYPES.Auth_Timer),
|
container.get<TimerInterface>(TYPES.Auth_Timer),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
@@ -986,8 +1113,45 @@ export class ContainerConfigLoader {
|
|||||||
.toConstantValue(new CleanupExpiredSessions(container.get(TYPES.Auth_SessionRepository)))
|
.toConstantValue(new CleanupExpiredSessions(container.get(TYPES.Auth_SessionRepository)))
|
||||||
container.bind<AuthenticateUser>(TYPES.Auth_AuthenticateUser).to(AuthenticateUser)
|
container.bind<AuthenticateUser>(TYPES.Auth_AuthenticateUser).to(AuthenticateUser)
|
||||||
container.bind<AuthenticateRequest>(TYPES.Auth_AuthenticateRequest).to(AuthenticateRequest)
|
container.bind<AuthenticateRequest>(TYPES.Auth_AuthenticateRequest).to(AuthenticateRequest)
|
||||||
container.bind<RefreshSessionToken>(TYPES.Auth_RefreshSessionToken).to(RefreshSessionToken)
|
container
|
||||||
container.bind<SignIn>(TYPES.Auth_SignIn).to(SignIn)
|
.bind<RefreshSessionToken>(TYPES.Auth_RefreshSessionToken)
|
||||||
|
.toConstantValue(
|
||||||
|
new RefreshSessionToken(
|
||||||
|
container.get<SessionServiceInterface>(TYPES.Auth_SessionService),
|
||||||
|
container.get<DomainEventFactoryInterface>(TYPES.Auth_DomainEventFactory),
|
||||||
|
container.get<DomainEventPublisherInterface>(TYPES.Auth_DomainEventPublisher),
|
||||||
|
container.get<TimerInterface>(TYPES.Auth_Timer),
|
||||||
|
container.get<GetSetting>(TYPES.Auth_GetSetting),
|
||||||
|
container.get<CooldownSessionTokens>(TYPES.Auth_CooldownSessionTokens),
|
||||||
|
container.get<GetSessionFromToken>(TYPES.Auth_GetSessionFromToken),
|
||||||
|
container.get<winston.Logger>(TYPES.Auth_Logger),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
container
|
||||||
|
.bind<VerifyHumanInteraction>(TYPES.Auth_VerifyHumanInteraction)
|
||||||
|
.toConstantValue(
|
||||||
|
new VerifyHumanInteraction(
|
||||||
|
container.get(TYPES.Auth_HUMAN_VERIFICATION_ENABLED),
|
||||||
|
container.get<CaptchaServerInterface>(TYPES.Auth_CaptchaServer),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
container
|
||||||
|
.bind<SignIn>(TYPES.Auth_SignIn)
|
||||||
|
.toConstantValue(
|
||||||
|
new SignIn(
|
||||||
|
container.get<UserRepositoryInterface>(TYPES.Auth_UserRepository),
|
||||||
|
container.get<AuthResponseFactoryResolverInterface>(TYPES.Auth_AuthResponseFactoryResolver),
|
||||||
|
container.get<DomainEventPublisherInterface>(TYPES.Auth_DomainEventPublisher),
|
||||||
|
container.get<DomainEventFactoryInterface>(TYPES.Auth_DomainEventFactory),
|
||||||
|
container.get<SessionServiceInterface>(TYPES.Auth_SessionService),
|
||||||
|
container.get<PKCERepositoryInterface>(TYPES.Auth_PKCERepository),
|
||||||
|
container.get<CrypterInterface>(TYPES.Auth_Crypter),
|
||||||
|
container.get<winston.Logger>(TYPES.Auth_Logger),
|
||||||
|
container.get<number>(TYPES.Auth_MAX_LOGIN_ATTEMPTS),
|
||||||
|
container.get<LockRepositoryInterface>(TYPES.Auth_LockRepository),
|
||||||
|
container.get<VerifyHumanInteraction>(TYPES.Auth_VerifyHumanInteraction),
|
||||||
|
),
|
||||||
|
)
|
||||||
container
|
container
|
||||||
.bind<VerifyMFA>(TYPES.Auth_VerifyMFA)
|
.bind<VerifyMFA>(TYPES.Auth_VerifyMFA)
|
||||||
.toConstantValue(
|
.toConstantValue(
|
||||||
@@ -1004,8 +1168,24 @@ export class ContainerConfigLoader {
|
|||||||
container.get<winston.Logger>(TYPES.Auth_Logger),
|
container.get<winston.Logger>(TYPES.Auth_Logger),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
container.bind<ClearLoginAttempts>(TYPES.Auth_ClearLoginAttempts).to(ClearLoginAttempts)
|
container
|
||||||
container.bind<IncreaseLoginAttempts>(TYPES.Auth_IncreaseLoginAttempts).to(IncreaseLoginAttempts)
|
.bind<ClearLoginAttempts>(TYPES.Auth_ClearLoginAttempts)
|
||||||
|
.toConstantValue(
|
||||||
|
new ClearLoginAttempts(
|
||||||
|
container.get<UserRepositoryInterface>(TYPES.Auth_UserRepository),
|
||||||
|
container.get<LockRepositoryInterface>(TYPES.Auth_LockRepository),
|
||||||
|
container.get<winston.Logger>(TYPES.Auth_Logger),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
container
|
||||||
|
.bind<IncreaseLoginAttempts>(TYPES.Auth_IncreaseLoginAttempts)
|
||||||
|
.toConstantValue(
|
||||||
|
new IncreaseLoginAttempts(
|
||||||
|
container.get<UserRepositoryInterface>(TYPES.Auth_UserRepository),
|
||||||
|
container.get<LockRepositoryInterface>(TYPES.Auth_LockRepository),
|
||||||
|
container.get<number>(TYPES.Auth_MAX_LOGIN_ATTEMPTS),
|
||||||
|
),
|
||||||
|
)
|
||||||
container
|
container
|
||||||
.bind<GetUserKeyParamsRecovery>(TYPES.Auth_GetUserKeyParamsRecovery)
|
.bind<GetUserKeyParamsRecovery>(TYPES.Auth_GetUserKeyParamsRecovery)
|
||||||
.toConstantValue(
|
.toConstantValue(
|
||||||
@@ -1016,7 +1196,6 @@ export class ContainerConfigLoader {
|
|||||||
container.get<GetSetting>(TYPES.Auth_GetSetting),
|
container.get<GetSetting>(TYPES.Auth_GetSetting),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
container.bind<UpdateUser>(TYPES.Auth_UpdateUser).to(UpdateUser)
|
|
||||||
container
|
container
|
||||||
.bind<ApplyDefaultSettings>(TYPES.Auth_ApplyDefaultSettings)
|
.bind<ApplyDefaultSettings>(TYPES.Auth_ApplyDefaultSettings)
|
||||||
.toConstantValue(
|
.toConstantValue(
|
||||||
@@ -1117,6 +1296,9 @@ export class ContainerConfigLoader {
|
|||||||
container.get<ClearLoginAttempts>(TYPES.Auth_ClearLoginAttempts),
|
container.get<ClearLoginAttempts>(TYPES.Auth_ClearLoginAttempts),
|
||||||
container.get<DeleteSetting>(TYPES.Auth_DeleteSetting),
|
container.get<DeleteSetting>(TYPES.Auth_DeleteSetting),
|
||||||
container.get<AuthenticatorRepositoryInterface>(TYPES.Auth_AuthenticatorRepository),
|
container.get<AuthenticatorRepositoryInterface>(TYPES.Auth_AuthenticatorRepository),
|
||||||
|
container.get<number>(TYPES.Auth_MAX_LOGIN_ATTEMPTS),
|
||||||
|
container.get<LockRepositoryInterface>(TYPES.Auth_LockRepository),
|
||||||
|
container.get<VerifyHumanInteraction>(TYPES.Auth_VerifyHumanInteraction),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
container
|
container
|
||||||
@@ -1249,7 +1431,6 @@ export class ContainerConfigLoader {
|
|||||||
.toConstantValue(
|
.toConstantValue(
|
||||||
new TriggerEmailBackupForUser(
|
new TriggerEmailBackupForUser(
|
||||||
container.get<RoleServiceInterface>(TYPES.Auth_RoleService),
|
container.get<RoleServiceInterface>(TYPES.Auth_RoleService),
|
||||||
container.get<GetSetting>(TYPES.Auth_GetSetting),
|
|
||||||
container.get<GetUserKeyParams>(TYPES.Auth_GetUserKeyParams),
|
container.get<GetUserKeyParams>(TYPES.Auth_GetUserKeyParams),
|
||||||
container.get<DomainEventPublisherInterface>(TYPES.Auth_DomainEventPublisher),
|
container.get<DomainEventPublisherInterface>(TYPES.Auth_DomainEventPublisher),
|
||||||
container.get<DomainEventFactoryInterface>(TYPES.Auth_DomainEventFactory),
|
container.get<DomainEventFactoryInterface>(TYPES.Auth_DomainEventFactory),
|
||||||
@@ -1324,15 +1505,9 @@ export class ContainerConfigLoader {
|
|||||||
.bind<AuthController>(TYPES.Auth_AuthController)
|
.bind<AuthController>(TYPES.Auth_AuthController)
|
||||||
.toConstantValue(
|
.toConstantValue(
|
||||||
new AuthController(
|
new AuthController(
|
||||||
container.get(TYPES.Auth_ClearLoginAttempts),
|
container.get<GetUserKeyParamsRecovery>(TYPES.Auth_GetUserKeyParamsRecovery),
|
||||||
container.get(TYPES.Auth_Register),
|
container.get<GenerateRecoveryCodes>(TYPES.Auth_GenerateRecoveryCodes),
|
||||||
container.get(TYPES.Auth_DomainEventPublisher),
|
container.get<winston.Logger>(TYPES.Auth_Logger),
|
||||||
container.get(TYPES.Auth_DomainEventFactory),
|
|
||||||
container.get(TYPES.Auth_SignInWithRecoveryCodes),
|
|
||||||
container.get(TYPES.Auth_GetUserKeyParamsRecovery),
|
|
||||||
container.get(TYPES.Auth_GenerateRecoveryCodes),
|
|
||||||
container.get(TYPES.Auth_Logger),
|
|
||||||
container.get(TYPES.Auth_SessionService),
|
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
container
|
container
|
||||||
@@ -1409,6 +1584,7 @@ export class ContainerConfigLoader {
|
|||||||
container.get<SetSettingValue>(TYPES.Auth_SetSettingValue),
|
container.get<SetSettingValue>(TYPES.Auth_SetSettingValue),
|
||||||
container.get<OfflineSettingServiceInterface>(TYPES.Auth_OfflineSettingService),
|
container.get<OfflineSettingServiceInterface>(TYPES.Auth_OfflineSettingService),
|
||||||
container.get<ContentDecoderInterface>(TYPES.Auth_ContenDecoder),
|
container.get<ContentDecoderInterface>(TYPES.Auth_ContenDecoder),
|
||||||
|
container.get<RenewSharedSubscriptions>(TYPES.Auth_RenewSharedSubscriptions),
|
||||||
container.get<winston.Logger>(TYPES.Auth_Logger),
|
container.get<winston.Logger>(TYPES.Auth_Logger),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
@@ -1566,6 +1742,16 @@ export class ContainerConfigLoader {
|
|||||||
container.get<winston.Logger>(TYPES.Auth_Logger),
|
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([
|
const eventHandlers: Map<string, DomainEventHandlerInterface> = new Map([
|
||||||
['ACCOUNT_DELETION_REQUESTED', container.get(TYPES.Auth_AccountDeletionRequestedEventHandler)],
|
['ACCOUNT_DELETION_REQUESTED', container.get(TYPES.Auth_AccountDeletionRequestedEventHandler)],
|
||||||
@@ -1607,6 +1793,7 @@ export class ContainerConfigLoader {
|
|||||||
'FILE_QUOTA_RECALCULATED',
|
'FILE_QUOTA_RECALCULATED',
|
||||||
container.get<FileQuotaRecalculatedEventHandler>(TYPES.Auth_FileQuotaRecalculatedEventHandler),
|
container.get<FileQuotaRecalculatedEventHandler>(TYPES.Auth_FileQuotaRecalculatedEventHandler),
|
||||||
],
|
],
|
||||||
|
['SUBSCRIPTION_STATE_FETCHED', container.get(TYPES.Auth_SubscriptionStateFetchedEventHandler)],
|
||||||
])
|
])
|
||||||
|
|
||||||
if (isConfiguredForHomeServer) {
|
if (isConfiguredForHomeServer) {
|
||||||
@@ -1639,14 +1826,23 @@ export class ContainerConfigLoader {
|
|||||||
.bind<BaseAuthController>(TYPES.Auth_BaseAuthController)
|
.bind<BaseAuthController>(TYPES.Auth_BaseAuthController)
|
||||||
.toConstantValue(
|
.toConstantValue(
|
||||||
new BaseAuthController(
|
new BaseAuthController(
|
||||||
container.get(TYPES.Auth_VerifyMFA),
|
container.get<VerifyMFA>(TYPES.Auth_VerifyMFA),
|
||||||
container.get(TYPES.Auth_SignIn),
|
container.get<SignIn>(TYPES.Auth_SignIn),
|
||||||
container.get(TYPES.Auth_GetUserKeyParams),
|
container.get<GetUserKeyParams>(TYPES.Auth_GetUserKeyParams),
|
||||||
container.get(TYPES.Auth_ClearLoginAttempts),
|
container.get<ClearLoginAttempts>(TYPES.Auth_ClearLoginAttempts),
|
||||||
container.get(TYPES.Auth_IncreaseLoginAttempts),
|
container.get<IncreaseLoginAttempts>(TYPES.Auth_IncreaseLoginAttempts),
|
||||||
container.get(TYPES.Auth_Logger),
|
container.get<winston.Logger>(TYPES.Auth_Logger),
|
||||||
container.get(TYPES.Auth_AuthController),
|
container.get<AuthController>(TYPES.Auth_AuthController),
|
||||||
container.get(TYPES.Auth_ControllerContainer),
|
container.get<Register>(TYPES.Auth_Register),
|
||||||
|
container.get<DomainEventPublisherInterface>(TYPES.Auth_DomainEventPublisher),
|
||||||
|
container.get<DomainEventFactoryInterface>(TYPES.Auth_DomainEventFactory),
|
||||||
|
container.get<SessionServiceInterface>(TYPES.Auth_SessionService),
|
||||||
|
container.get<VerifyHumanInteraction>(TYPES.Auth_VerifyHumanInteraction),
|
||||||
|
container.get<CookieFactoryInterface>(TYPES.Auth_CookieFactory),
|
||||||
|
container.get<SignInWithRecoveryCodes>(TYPES.Auth_SignInWithRecoveryCodes),
|
||||||
|
container.get<DeleteSessionByToken>(TYPES.Auth_DeleteSessionByToken),
|
||||||
|
container.get<string>(TYPES.Auth_CAPTCHA_UI_URL),
|
||||||
|
container.get<ControllerContainerInterface>(TYPES.Auth_ControllerContainer),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -1708,12 +1904,12 @@ export class ContainerConfigLoader {
|
|||||||
.bind<BaseUsersController>(TYPES.Auth_BaseUsersController)
|
.bind<BaseUsersController>(TYPES.Auth_BaseUsersController)
|
||||||
.toConstantValue(
|
.toConstantValue(
|
||||||
new BaseUsersController(
|
new BaseUsersController(
|
||||||
container.get<UpdateUser>(TYPES.Auth_UpdateUser),
|
|
||||||
container.get<DeleteAccount>(TYPES.Auth_DeleteAccount),
|
container.get<DeleteAccount>(TYPES.Auth_DeleteAccount),
|
||||||
container.get<GetUserSubscription>(TYPES.Auth_GetUserSubscription),
|
container.get<GetUserSubscription>(TYPES.Auth_GetUserSubscription),
|
||||||
container.get<ClearLoginAttempts>(TYPES.Auth_ClearLoginAttempts),
|
container.get<ClearLoginAttempts>(TYPES.Auth_ClearLoginAttempts),
|
||||||
container.get<IncreaseLoginAttempts>(TYPES.Auth_IncreaseLoginAttempts),
|
container.get<IncreaseLoginAttempts>(TYPES.Auth_IncreaseLoginAttempts),
|
||||||
container.get<ChangeCredentials>(TYPES.Auth_ChangeCredentials),
|
container.get<ChangeCredentials>(TYPES.Auth_ChangeCredentials),
|
||||||
|
container.get<CookieFactoryInterface>(TYPES.Auth_CookieFactory),
|
||||||
container.get<ControllerContainerInterface>(TYPES.Auth_ControllerContainer),
|
container.get<ControllerContainerInterface>(TYPES.Auth_ControllerContainer),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
@@ -1721,11 +1917,12 @@ export class ContainerConfigLoader {
|
|||||||
.bind<BaseAdminController>(TYPES.Auth_BaseAdminController)
|
.bind<BaseAdminController>(TYPES.Auth_BaseAdminController)
|
||||||
.toConstantValue(
|
.toConstantValue(
|
||||||
new BaseAdminController(
|
new BaseAdminController(
|
||||||
container.get(TYPES.Auth_DeleteSetting),
|
container.get<DeleteSetting>(TYPES.Auth_DeleteSetting),
|
||||||
container.get(TYPES.Auth_UserRepository),
|
container.get<GetSetting>(TYPES.Auth_GetSetting),
|
||||||
container.get(TYPES.Auth_CreateSubscriptionToken),
|
container.get<UserRepositoryInterface>(TYPES.Auth_UserRepository),
|
||||||
container.get(TYPES.Auth_CreateOfflineSubscriptionToken),
|
container.get<CreateSubscriptionToken>(TYPES.Auth_CreateSubscriptionToken),
|
||||||
container.get(TYPES.Auth_ControllerContainer),
|
container.get<CreateOfflineSubscriptionToken>(TYPES.Auth_CreateOfflineSubscriptionToken),
|
||||||
|
container.get<ControllerContainerInterface>(TYPES.Auth_ControllerContainer),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
container
|
container
|
||||||
@@ -1748,9 +1945,12 @@ export class ContainerConfigLoader {
|
|||||||
new BaseSubscriptionSettingsController(
|
new BaseSubscriptionSettingsController(
|
||||||
container.get<GetSubscriptionSetting>(TYPES.Auth_GetSubscriptionSetting),
|
container.get<GetSubscriptionSetting>(TYPES.Auth_GetSubscriptionSetting),
|
||||||
container.get<GetSharedOrRegularSubscriptionForUser>(TYPES.Auth_GetSharedOrRegularSubscriptionForUser),
|
container.get<GetSharedOrRegularSubscriptionForUser>(TYPES.Auth_GetSharedOrRegularSubscriptionForUser),
|
||||||
|
container.get<SetSubscriptionSettingValue>(TYPES.Auth_SetSubscriptionSettingValue),
|
||||||
|
container.get<TriggerPostSettingUpdateActions>(TYPES.Auth_TriggerPostSettingUpdateActions),
|
||||||
container.get<MapperInterface<SubscriptionSetting, SubscriptionSettingHttpRepresentation>>(
|
container.get<MapperInterface<SubscriptionSetting, SubscriptionSettingHttpRepresentation>>(
|
||||||
TYPES.Auth_SubscriptionSettingHttpMapper,
|
TYPES.Auth_SubscriptionSettingHttpMapper,
|
||||||
),
|
),
|
||||||
|
container.get<winston.Logger>(TYPES.Auth_Logger),
|
||||||
container.get<ControllerContainerInterface>(TYPES.Auth_ControllerContainer),
|
container.get<ControllerContainerInterface>(TYPES.Auth_ControllerContainer),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
@@ -1775,10 +1975,11 @@ export class ContainerConfigLoader {
|
|||||||
.bind<BaseSessionController>(TYPES.Auth_BaseSessionController)
|
.bind<BaseSessionController>(TYPES.Auth_BaseSessionController)
|
||||||
.toConstantValue(
|
.toConstantValue(
|
||||||
new BaseSessionController(
|
new BaseSessionController(
|
||||||
container.get(TYPES.Auth_DeleteSessionForUser),
|
container.get<DeleteSessionForUser>(TYPES.Auth_DeleteSessionForUser),
|
||||||
container.get(TYPES.Auth_DeleteOtherSessionsForUser),
|
container.get<DeleteOtherSessionsForUser>(TYPES.Auth_DeleteOtherSessionsForUser),
|
||||||
container.get(TYPES.Auth_RefreshSessionToken),
|
container.get<RefreshSessionToken>(TYPES.Auth_RefreshSessionToken),
|
||||||
container.get(TYPES.Auth_ControllerContainer),
|
container.get<CookieFactoryInterface>(TYPES.Auth_CookieFactory),
|
||||||
|
container.get<ControllerContainerInterface>(TYPES.Auth_ControllerContainer),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
container
|
container
|
||||||
|
|||||||
@@ -34,6 +34,7 @@ const TYPES = {
|
|||||||
Auth_UserSubscriptionRepository: Symbol.for('Auth_UserSubscriptionRepository'),
|
Auth_UserSubscriptionRepository: Symbol.for('Auth_UserSubscriptionRepository'),
|
||||||
Auth_OfflineUserSubscriptionRepository: Symbol.for('Auth_OfflineUserSubscriptionRepository'),
|
Auth_OfflineUserSubscriptionRepository: Symbol.for('Auth_OfflineUserSubscriptionRepository'),
|
||||||
Auth_SubscriptionTokenRepository: Symbol.for('Auth_SubscriptionTokenRepository'),
|
Auth_SubscriptionTokenRepository: Symbol.for('Auth_SubscriptionTokenRepository'),
|
||||||
|
Auth_SessionTokensCooldownRepository: Symbol.for('Auth_SessionTokensCooldownRepository'),
|
||||||
Auth_OfflineSubscriptionTokenRepository: Symbol.for('Auth_OfflineSubscriptionTokenRepository'),
|
Auth_OfflineSubscriptionTokenRepository: Symbol.for('Auth_OfflineSubscriptionTokenRepository'),
|
||||||
Auth_SharedSubscriptionInvitationRepository: Symbol.for('Auth_SharedSubscriptionInvitationRepository'),
|
Auth_SharedSubscriptionInvitationRepository: Symbol.for('Auth_SharedSubscriptionInvitationRepository'),
|
||||||
Auth_PKCERepository: Symbol.for('Auth_PKCERepository'),
|
Auth_PKCERepository: Symbol.for('Auth_PKCERepository'),
|
||||||
@@ -84,7 +85,9 @@ const TYPES = {
|
|||||||
Auth_REFRESH_TOKEN_AGE: Symbol.for('Auth_REFRESH_TOKEN_AGE'),
|
Auth_REFRESH_TOKEN_AGE: Symbol.for('Auth_REFRESH_TOKEN_AGE'),
|
||||||
Auth_EPHEMERAL_SESSION_AGE: Symbol.for('Auth_EPHEMERAL_SESSION_AGE'),
|
Auth_EPHEMERAL_SESSION_AGE: Symbol.for('Auth_EPHEMERAL_SESSION_AGE'),
|
||||||
Auth_MAX_LOGIN_ATTEMPTS: Symbol.for('Auth_MAX_LOGIN_ATTEMPTS'),
|
Auth_MAX_LOGIN_ATTEMPTS: Symbol.for('Auth_MAX_LOGIN_ATTEMPTS'),
|
||||||
|
Auth_MAX_CAPTCHA_LOGIN_ATTEMPTS: Symbol.for('Auth_MAX_CAPTCHA_LOGIN_ATTEMPTS'),
|
||||||
Auth_FAILED_LOGIN_LOCKOUT: Symbol.for('Auth_FAILED_LOGIN_LOCKOUT'),
|
Auth_FAILED_LOGIN_LOCKOUT: Symbol.for('Auth_FAILED_LOGIN_LOCKOUT'),
|
||||||
|
Auth_FAILED_LOGIN_CAPTCHA_LOCKOUT: Symbol.for('Auth_FAILED_LOGIN_CAPTCHA_LOCKOUT'),
|
||||||
Auth_PSEUDO_KEY_PARAMS_KEY: Symbol.for('Auth_PSEUDO_KEY_PARAMS_KEY'),
|
Auth_PSEUDO_KEY_PARAMS_KEY: Symbol.for('Auth_PSEUDO_KEY_PARAMS_KEY'),
|
||||||
Auth_REDIS_URL: Symbol.for('Auth_REDIS_URL'),
|
Auth_REDIS_URL: Symbol.for('Auth_REDIS_URL'),
|
||||||
Auth_DISABLE_USER_REGISTRATION: Symbol.for('Auth_DISABLE_USER_REGISTRATION'),
|
Auth_DISABLE_USER_REGISTRATION: Symbol.for('Auth_DISABLE_USER_REGISTRATION'),
|
||||||
@@ -100,6 +103,10 @@ const TYPES = {
|
|||||||
Auth_U2F_REQUIRE_USER_VERIFICATION: Symbol.for('Auth_U2F_REQUIRE_USER_VERIFICATION'),
|
Auth_U2F_REQUIRE_USER_VERIFICATION: Symbol.for('Auth_U2F_REQUIRE_USER_VERIFICATION'),
|
||||||
Auth_READONLY_USERS: Symbol.for('Auth_READONLY_USERS'),
|
Auth_READONLY_USERS: Symbol.for('Auth_READONLY_USERS'),
|
||||||
Auth_IS_CONFIGURED_FOR_HOME_SERVER_OR_SELF_HOSTING: Symbol.for('Auth_IS_CONFIGURED_FOR_HOME_SERVER_OR_SELF_HOSTING'),
|
Auth_IS_CONFIGURED_FOR_HOME_SERVER_OR_SELF_HOSTING: Symbol.for('Auth_IS_CONFIGURED_FOR_HOME_SERVER_OR_SELF_HOSTING'),
|
||||||
|
Auth_CAPTCHA_SERVER_URL: Symbol.for('Auth_CAPTCHA_SERVER_URL'),
|
||||||
|
Auth_CAPTCHA_UI_URL: Symbol.for('Auth_CAPTCHA_UI_URL'),
|
||||||
|
Auth_HUMAN_VERIFICATION_ENABLED: Symbol.for('Auth_HUMAN_VERIFICATION_ENABLED'),
|
||||||
|
Auth_FORCE_LEGACY_SESSIONS: Symbol.for('Auth_FORCE_LEGACY_SESSIONS'),
|
||||||
// use cases
|
// use cases
|
||||||
Auth_AuthenticateUser: Symbol.for('Auth_AuthenticateUser'),
|
Auth_AuthenticateUser: Symbol.for('Auth_AuthenticateUser'),
|
||||||
Auth_AuthenticateRequest: Symbol.for('Auth_AuthenticateRequest'),
|
Auth_AuthenticateRequest: Symbol.for('Auth_AuthenticateRequest'),
|
||||||
@@ -109,7 +116,6 @@ const TYPES = {
|
|||||||
Auth_ClearLoginAttempts: Symbol.for('Auth_ClearLoginAttempts'),
|
Auth_ClearLoginAttempts: Symbol.for('Auth_ClearLoginAttempts'),
|
||||||
Auth_IncreaseLoginAttempts: Symbol.for('Auth_IncreaseLoginAttempts'),
|
Auth_IncreaseLoginAttempts: Symbol.for('Auth_IncreaseLoginAttempts'),
|
||||||
Auth_GetUserKeyParams: Symbol.for('Auth_GetUserKeyParams'),
|
Auth_GetUserKeyParams: Symbol.for('Auth_GetUserKeyParams'),
|
||||||
Auth_UpdateUser: Symbol.for('Auth_UpdateUser'),
|
|
||||||
Auth_Register: Symbol.for('Auth_Register'),
|
Auth_Register: Symbol.for('Auth_Register'),
|
||||||
Auth_GetActiveSessionsForUser: Symbol.for('Auth_GetActiveSessionsForUser'),
|
Auth_GetActiveSessionsForUser: Symbol.for('Auth_GetActiveSessionsForUser'),
|
||||||
Auth_DeleteOtherSessionsForUser: Symbol.for('Auth_DeleteOtherSessionsForUser'),
|
Auth_DeleteOtherSessionsForUser: Symbol.for('Auth_DeleteOtherSessionsForUser'),
|
||||||
@@ -158,6 +164,10 @@ const TYPES = {
|
|||||||
Auth_ApplyDefaultSettings: Symbol.for('Auth_ApplyDefaultSettings'),
|
Auth_ApplyDefaultSettings: Symbol.for('Auth_ApplyDefaultSettings'),
|
||||||
Auth_ActivatePremiumFeatures: Symbol.for('Auth_ActivatePremiumFeatures'),
|
Auth_ActivatePremiumFeatures: Symbol.for('Auth_ActivatePremiumFeatures'),
|
||||||
Auth_SignInWithRecoveryCodes: Symbol.for('Auth_SignInWithRecoveryCodes'),
|
Auth_SignInWithRecoveryCodes: Symbol.for('Auth_SignInWithRecoveryCodes'),
|
||||||
|
Auth_GetSessionFromToken: Symbol.for('Auth_GetSessionFromToken'),
|
||||||
|
Auth_DeleteSessionByToken: Symbol.for('Auth_DeleteSessionByToken'),
|
||||||
|
Auth_CooldownSessionTokens: Symbol.for('Auth_CooldownSessionTokens'),
|
||||||
|
Auth_GetCooldownSessionTokens: Symbol.for('Auth_GetCooldownSessionTokens'),
|
||||||
Auth_GetUserKeyParamsRecovery: Symbol.for('Auth_GetUserKeyParamsRecovery'),
|
Auth_GetUserKeyParamsRecovery: Symbol.for('Auth_GetUserKeyParamsRecovery'),
|
||||||
Auth_UpdateStorageQuotaUsedForUser: Symbol.for('Auth_UpdateStorageQuotaUsedForUser'),
|
Auth_UpdateStorageQuotaUsedForUser: Symbol.for('Auth_UpdateStorageQuotaUsedForUser'),
|
||||||
Auth_AddSharedVaultUser: Symbol.for('Auth_AddSharedVaultUser'),
|
Auth_AddSharedVaultUser: Symbol.for('Auth_AddSharedVaultUser'),
|
||||||
@@ -171,6 +181,7 @@ const TYPES = {
|
|||||||
Auth_DeleteAccountsFromCSVFile: Symbol.for('Auth_DeleteAccountsFromCSVFile'),
|
Auth_DeleteAccountsFromCSVFile: Symbol.for('Auth_DeleteAccountsFromCSVFile'),
|
||||||
Auth_RenewSharedSubscriptions: Symbol.for('Auth_RenewSharedSubscriptions'),
|
Auth_RenewSharedSubscriptions: Symbol.for('Auth_RenewSharedSubscriptions'),
|
||||||
Auth_FixStorageQuotaForUser: Symbol.for('Auth_FixStorageQuotaForUser'),
|
Auth_FixStorageQuotaForUser: Symbol.for('Auth_FixStorageQuotaForUser'),
|
||||||
|
Auth_VerifyHumanInteraction: Symbol.for('Auth_VerifyHumanInteraction'),
|
||||||
// Handlers
|
// Handlers
|
||||||
Auth_AccountDeletionRequestedEventHandler: Symbol.for('Auth_AccountDeletionRequestedEventHandler'),
|
Auth_AccountDeletionRequestedEventHandler: Symbol.for('Auth_AccountDeletionRequestedEventHandler'),
|
||||||
Auth_AccountDeletionVerificationPassedEventHandler: Symbol.for('Auth_AccountDeletionVerificationPassedEventHandler'),
|
Auth_AccountDeletionVerificationPassedEventHandler: Symbol.for('Auth_AccountDeletionVerificationPassedEventHandler'),
|
||||||
@@ -205,7 +216,9 @@ const TYPES = {
|
|||||||
),
|
),
|
||||||
Auth_UserInvitedToSharedVaultEventHandler: Symbol.for('Auth_UserInvitedToSharedVaultEventHandler'),
|
Auth_UserInvitedToSharedVaultEventHandler: Symbol.for('Auth_UserInvitedToSharedVaultEventHandler'),
|
||||||
Auth_FileQuotaRecalculatedEventHandler: Symbol.for('Auth_FileQuotaRecalculatedEventHandler'),
|
Auth_FileQuotaRecalculatedEventHandler: Symbol.for('Auth_FileQuotaRecalculatedEventHandler'),
|
||||||
|
Auth_SubscriptionStateFetchedEventHandler: Symbol.for('Auth_SubscriptionStateFetchedEventHandler'),
|
||||||
// Services
|
// Services
|
||||||
|
Auth_CookieFactory: Symbol.for('Auth_CookieFactory'),
|
||||||
Auth_DeviceDetector: Symbol.for('Auth_DeviceDetector'),
|
Auth_DeviceDetector: Symbol.for('Auth_DeviceDetector'),
|
||||||
Auth_SessionService: Symbol.for('Auth_SessionService'),
|
Auth_SessionService: Symbol.for('Auth_SessionService'),
|
||||||
Auth_OfflineSettingService: Symbol.for('Auth_OfflineSettingService'),
|
Auth_OfflineSettingService: Symbol.for('Auth_OfflineSettingService'),
|
||||||
@@ -258,6 +271,8 @@ const TYPES = {
|
|||||||
Auth_BaseListedController: Symbol.for('Auth_BaseListedController'),
|
Auth_BaseListedController: Symbol.for('Auth_BaseListedController'),
|
||||||
Auth_BaseFeaturesController: Symbol.for('Auth_BaseFeaturesController'),
|
Auth_BaseFeaturesController: Symbol.for('Auth_BaseFeaturesController'),
|
||||||
Auth_CSVFileReader: Symbol.for('Auth_CSVFileReader'),
|
Auth_CSVFileReader: Symbol.for('Auth_CSVFileReader'),
|
||||||
|
Auth_CaptchaServer: Symbol.for('Auth_CaptchaServer'),
|
||||||
|
Auth_HTTPClient: Symbol.for('Auth_HTTPClient'),
|
||||||
}
|
}
|
||||||
|
|
||||||
export default TYPES
|
export default TYPES
|
||||||
|
|||||||
@@ -1,149 +0,0 @@
|
|||||||
import 'reflect-metadata'
|
|
||||||
|
|
||||||
import { DomainEventInterface, DomainEventPublisherInterface } from '@standardnotes/domain-events'
|
|
||||||
|
|
||||||
import { AuthController } from './AuthController'
|
|
||||||
import { ClearLoginAttempts } from '../Domain/UseCase/ClearLoginAttempts'
|
|
||||||
import { User } from '../Domain/User/User'
|
|
||||||
import { Register } from '../Domain/UseCase/Register'
|
|
||||||
import { DomainEventFactoryInterface } from '../Domain/Event/DomainEventFactoryInterface'
|
|
||||||
import { KeyParamsOrigination, ProtocolVersion } from '@standardnotes/common'
|
|
||||||
import { SignInWithRecoveryCodes } from '../Domain/UseCase/SignInWithRecoveryCodes/SignInWithRecoveryCodes'
|
|
||||||
import { GetUserKeyParamsRecovery } from '../Domain/UseCase/GetUserKeyParamsRecovery/GetUserKeyParamsRecovery'
|
|
||||||
import { GenerateRecoveryCodes } from '../Domain/UseCase/GenerateRecoveryCodes/GenerateRecoveryCodes'
|
|
||||||
import { Logger } from 'winston'
|
|
||||||
import { SessionServiceInterface } from '../Domain/Session/SessionServiceInterface'
|
|
||||||
import { ApiVersion } from '../Domain/Api/ApiVersion'
|
|
||||||
|
|
||||||
describe('AuthController', () => {
|
|
||||||
let clearLoginAttempts: ClearLoginAttempts
|
|
||||||
let register: Register
|
|
||||||
let domainEventPublisher: DomainEventPublisherInterface
|
|
||||||
let domainEventFactory: DomainEventFactoryInterface
|
|
||||||
let event: DomainEventInterface
|
|
||||||
let user: User
|
|
||||||
let doSignInWithRecoveryCodes: SignInWithRecoveryCodes
|
|
||||||
let getUserKeyParamsRecovery: GetUserKeyParamsRecovery
|
|
||||||
let doGenerateRecoveryCodes: GenerateRecoveryCodes
|
|
||||||
let logger: Logger
|
|
||||||
let sessionService: SessionServiceInterface
|
|
||||||
|
|
||||||
const createController = () =>
|
|
||||||
new AuthController(
|
|
||||||
clearLoginAttempts,
|
|
||||||
register,
|
|
||||||
domainEventPublisher,
|
|
||||||
domainEventFactory,
|
|
||||||
doSignInWithRecoveryCodes,
|
|
||||||
getUserKeyParamsRecovery,
|
|
||||||
doGenerateRecoveryCodes,
|
|
||||||
logger,
|
|
||||||
sessionService,
|
|
||||||
)
|
|
||||||
|
|
||||||
beforeEach(() => {
|
|
||||||
register = {} as jest.Mocked<Register>
|
|
||||||
register.execute = jest.fn()
|
|
||||||
|
|
||||||
user = {} as jest.Mocked<User>
|
|
||||||
user.email = 'test@test.te'
|
|
||||||
|
|
||||||
clearLoginAttempts = {} as jest.Mocked<ClearLoginAttempts>
|
|
||||||
clearLoginAttempts.execute = jest.fn()
|
|
||||||
|
|
||||||
event = {} as jest.Mocked<DomainEventInterface>
|
|
||||||
|
|
||||||
domainEventPublisher = {} as jest.Mocked<DomainEventPublisherInterface>
|
|
||||||
domainEventPublisher.publish = jest.fn()
|
|
||||||
|
|
||||||
domainEventFactory = {} as jest.Mocked<DomainEventFactoryInterface>
|
|
||||||
domainEventFactory.createUserRegisteredEvent = jest.fn().mockReturnValue(event)
|
|
||||||
|
|
||||||
logger = {} as jest.Mocked<Logger>
|
|
||||||
logger.debug = jest.fn()
|
|
||||||
|
|
||||||
sessionService = {} as jest.Mocked<SessionServiceInterface>
|
|
||||||
sessionService.deleteSessionByToken = jest.fn().mockReturnValue('1-2-3')
|
|
||||||
})
|
|
||||||
|
|
||||||
it('should register a user', async () => {
|
|
||||||
register.execute = jest.fn().mockReturnValue({ success: true, authResponse: { user } })
|
|
||||||
|
|
||||||
const response = await createController().register({
|
|
||||||
email: 'test@test.te',
|
|
||||||
password: 'asdzxc',
|
|
||||||
version: ProtocolVersion.V004,
|
|
||||||
api: ApiVersion.v20200115,
|
|
||||||
origination: KeyParamsOrigination.Registration,
|
|
||||||
userAgent: 'Google Chrome',
|
|
||||||
identifier: 'test@test.te',
|
|
||||||
pw_nonce: '11',
|
|
||||||
ephemeral: false,
|
|
||||||
})
|
|
||||||
|
|
||||||
expect(register.execute).toHaveBeenCalledWith({
|
|
||||||
apiVersion: '20200115',
|
|
||||||
kpOrigination: 'registration',
|
|
||||||
updatedWithUserAgent: 'Google Chrome',
|
|
||||||
ephemeralSession: false,
|
|
||||||
version: '004',
|
|
||||||
email: 'test@test.te',
|
|
||||||
password: 'asdzxc',
|
|
||||||
pwNonce: '11',
|
|
||||||
})
|
|
||||||
|
|
||||||
expect(domainEventPublisher.publish).toHaveBeenCalledWith(event)
|
|
||||||
|
|
||||||
expect(response.status).toEqual(200)
|
|
||||||
expect(response.data).toEqual({ user: { email: 'test@test.te' } })
|
|
||||||
})
|
|
||||||
|
|
||||||
it('should not register a user if request param is missing', async () => {
|
|
||||||
const response = await createController().register({
|
|
||||||
email: 'test@test.te',
|
|
||||||
password: '',
|
|
||||||
version: ProtocolVersion.V004,
|
|
||||||
api: ApiVersion.v20200115,
|
|
||||||
origination: KeyParamsOrigination.Registration,
|
|
||||||
userAgent: 'Google Chrome',
|
|
||||||
identifier: 'test@test.te',
|
|
||||||
pw_nonce: '11',
|
|
||||||
ephemeral: false,
|
|
||||||
})
|
|
||||||
|
|
||||||
expect(domainEventPublisher.publish).not.toHaveBeenCalled()
|
|
||||||
|
|
||||||
expect(response.status).toEqual(400)
|
|
||||||
})
|
|
||||||
|
|
||||||
it('should respond with error if registering a user fails', async () => {
|
|
||||||
register.execute = jest.fn().mockReturnValue({ success: false, errorMessage: 'Something bad happened' })
|
|
||||||
|
|
||||||
const response = await createController().register({
|
|
||||||
email: 'test@test.te',
|
|
||||||
password: 'test',
|
|
||||||
version: ProtocolVersion.V004,
|
|
||||||
api: ApiVersion.v20200115,
|
|
||||||
origination: KeyParamsOrigination.Registration,
|
|
||||||
userAgent: 'Google Chrome',
|
|
||||||
identifier: 'test@test.te',
|
|
||||||
pw_nonce: '11',
|
|
||||||
ephemeral: false,
|
|
||||||
})
|
|
||||||
|
|
||||||
expect(domainEventPublisher.publish).not.toHaveBeenCalled()
|
|
||||||
|
|
||||||
expect(response.status).toEqual(400)
|
|
||||||
})
|
|
||||||
|
|
||||||
it('should throw error on the delete user method as it is still a part of the payments server', async () => {
|
|
||||||
let caughtError = null
|
|
||||||
try {
|
|
||||||
await createController().deleteAccount({} as never)
|
|
||||||
} catch (error) {
|
|
||||||
caughtError = error
|
|
||||||
}
|
|
||||||
|
|
||||||
expect(caughtError).not.toBeNull()
|
|
||||||
})
|
|
||||||
})
|
|
||||||
@@ -1,42 +1,23 @@
|
|||||||
import { DomainEventPublisherInterface } from '@standardnotes/domain-events'
|
import { UserDeletionResponseBody, UserUpdateRequestParams } from '@standardnotes/api'
|
||||||
import {
|
import { HttpResponse, HttpStatusCode } from '@standardnotes/responses'
|
||||||
UserRegistrationRequestParams,
|
|
||||||
UserServerInterface,
|
|
||||||
UserDeletionResponseBody,
|
|
||||||
UserRegistrationResponseBody,
|
|
||||||
UserUpdateRequestParams,
|
|
||||||
} from '@standardnotes/api'
|
|
||||||
import { ErrorTag, HttpResponse, HttpStatusCode } from '@standardnotes/responses'
|
|
||||||
import { ProtocolVersion } from '@standardnotes/common'
|
|
||||||
|
|
||||||
import { ClearLoginAttempts } from '../Domain/UseCase/ClearLoginAttempts'
|
|
||||||
import { Register } from '../Domain/UseCase/Register'
|
|
||||||
import { DomainEventFactoryInterface } from '../Domain/Event/DomainEventFactoryInterface'
|
|
||||||
import { SignInWithRecoveryCodes } from '../Domain/UseCase/SignInWithRecoveryCodes/SignInWithRecoveryCodes'
|
|
||||||
import { SignInWithRecoveryCodesRequestParams } from '../Infra/Http/Request/SignInWithRecoveryCodesRequestParams'
|
|
||||||
import { GetUserKeyParamsRecovery } from '../Domain/UseCase/GetUserKeyParamsRecovery/GetUserKeyParamsRecovery'
|
import { GetUserKeyParamsRecovery } from '../Domain/UseCase/GetUserKeyParamsRecovery/GetUserKeyParamsRecovery'
|
||||||
import { RecoveryKeyParamsRequestParams } from '../Infra/Http/Request/RecoveryKeyParamsRequestParams'
|
import { RecoveryKeyParamsRequestParams } from '../Infra/Http/Request/RecoveryKeyParamsRequestParams'
|
||||||
import { SignInWithRecoveryCodesResponseBody } from '../Infra/Http/Response/SignInWithRecoveryCodesResponseBody'
|
|
||||||
import { RecoveryKeyParamsResponseBody } from '../Infra/Http/Response/RecoveryKeyParamsResponseBody'
|
import { RecoveryKeyParamsResponseBody } from '../Infra/Http/Response/RecoveryKeyParamsResponseBody'
|
||||||
import { GenerateRecoveryCodesResponseBody } from '../Infra/Http/Response/GenerateRecoveryCodesResponseBody'
|
import { GenerateRecoveryCodesResponseBody } from '../Infra/Http/Response/GenerateRecoveryCodesResponseBody'
|
||||||
import { GenerateRecoveryCodes } from '../Domain/UseCase/GenerateRecoveryCodes/GenerateRecoveryCodes'
|
import { GenerateRecoveryCodes } from '../Domain/UseCase/GenerateRecoveryCodes/GenerateRecoveryCodes'
|
||||||
import { GenerateRecoveryCodesRequestParams } from '../Infra/Http/Request/GenerateRecoveryCodesRequestParams'
|
import { GenerateRecoveryCodesRequestParams } from '../Infra/Http/Request/GenerateRecoveryCodesRequestParams'
|
||||||
import { Logger } from 'winston'
|
import { Logger } from 'winston'
|
||||||
import { SessionServiceInterface } from '../Domain/Session/SessionServiceInterface'
|
|
||||||
import { ApiVersion } from '../Domain/Api/ApiVersion'
|
|
||||||
import { UserUpdateResponse } from '@standardnotes/api/dist/Domain/Response/User/UserUpdateResponse'
|
import { UserUpdateResponse } from '@standardnotes/api/dist/Domain/Response/User/UserUpdateResponse'
|
||||||
|
|
||||||
export class AuthController implements UserServerInterface {
|
/**
|
||||||
|
* DEPRECATED: This controller is deprecated and will be removed in the future.
|
||||||
|
*/
|
||||||
|
export class AuthController {
|
||||||
constructor(
|
constructor(
|
||||||
private clearLoginAttempts: ClearLoginAttempts,
|
|
||||||
private registerUser: Register,
|
|
||||||
private domainEventPublisher: DomainEventPublisherInterface,
|
|
||||||
private domainEventFactory: DomainEventFactoryInterface,
|
|
||||||
private doSignInWithRecoveryCodes: SignInWithRecoveryCodes,
|
|
||||||
private getUserKeyParamsRecovery: GetUserKeyParamsRecovery,
|
private getUserKeyParamsRecovery: GetUserKeyParamsRecovery,
|
||||||
private doGenerateRecoveryCodes: GenerateRecoveryCodes,
|
private doGenerateRecoveryCodes: GenerateRecoveryCodes,
|
||||||
private logger: Logger,
|
private logger: Logger,
|
||||||
private sessionService: SessionServiceInterface,
|
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
async update(_params: UserUpdateRequestParams): Promise<HttpResponse<UserUpdateResponse>> {
|
async update(_params: UserUpdateRequestParams): Promise<HttpResponse<UserUpdateResponse>> {
|
||||||
@@ -47,57 +28,6 @@ export class AuthController implements UserServerInterface {
|
|||||||
throw new Error('This method is implemented on the payments server.')
|
throw new Error('This method is implemented on the payments server.')
|
||||||
}
|
}
|
||||||
|
|
||||||
async register(params: UserRegistrationRequestParams): Promise<HttpResponse<UserRegistrationResponseBody>> {
|
|
||||||
if (!params.email || !params.password) {
|
|
||||||
return {
|
|
||||||
status: HttpStatusCode.BadRequest,
|
|
||||||
data: {
|
|
||||||
error: {
|
|
||||||
message: 'Please enter an email and a password to register.',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const registerResult = await this.registerUser.execute({
|
|
||||||
email: params.email,
|
|
||||||
password: params.password,
|
|
||||||
updatedWithUserAgent: params.userAgent as string,
|
|
||||||
apiVersion: params.api,
|
|
||||||
ephemeralSession: params.ephemeral,
|
|
||||||
pwNonce: params.pw_nonce,
|
|
||||||
kpOrigination: params.origination,
|
|
||||||
kpCreated: params.created,
|
|
||||||
version: params.version,
|
|
||||||
})
|
|
||||||
|
|
||||||
if (!registerResult.success) {
|
|
||||||
return {
|
|
||||||
status: HttpStatusCode.BadRequest,
|
|
||||||
data: {
|
|
||||||
error: {
|
|
||||||
message: registerResult.errorMessage,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
await this.clearLoginAttempts.execute({ email: registerResult.authResponse.user.email as string })
|
|
||||||
|
|
||||||
await this.domainEventPublisher.publish(
|
|
||||||
this.domainEventFactory.createUserRegisteredEvent({
|
|
||||||
userUuid: <string>registerResult.authResponse.user.uuid,
|
|
||||||
email: <string>registerResult.authResponse.user.email,
|
|
||||||
protocolVersion: (<string>registerResult.authResponse.user.protocolVersion) as ProtocolVersion,
|
|
||||||
}),
|
|
||||||
)
|
|
||||||
|
|
||||||
return {
|
|
||||||
status: HttpStatusCode.Success,
|
|
||||||
data: registerResult.authResponse,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async generateRecoveryCodes(
|
async generateRecoveryCodes(
|
||||||
params: GenerateRecoveryCodesRequestParams,
|
params: GenerateRecoveryCodesRequestParams,
|
||||||
): Promise<HttpResponse<GenerateRecoveryCodesResponseBody>> {
|
): Promise<HttpResponse<GenerateRecoveryCodesResponseBody>> {
|
||||||
@@ -124,62 +54,11 @@ export class AuthController implements UserServerInterface {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async signInWithRecoveryCodes(
|
|
||||||
params: SignInWithRecoveryCodesRequestParams,
|
|
||||||
): Promise<HttpResponse<SignInWithRecoveryCodesResponseBody>> {
|
|
||||||
if (params.apiVersion !== ApiVersion.v20200115) {
|
|
||||||
return {
|
|
||||||
status: HttpStatusCode.BadRequest,
|
|
||||||
data: {
|
|
||||||
error: {
|
|
||||||
message: 'Invalid API version.',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const result = await this.doSignInWithRecoveryCodes.execute({
|
|
||||||
userAgent: params.userAgent,
|
|
||||||
username: params.username,
|
|
||||||
password: params.password,
|
|
||||||
codeVerifier: params.codeVerifier,
|
|
||||||
recoveryCodes: params.recoveryCodes,
|
|
||||||
})
|
|
||||||
|
|
||||||
if (result.isFailed()) {
|
|
||||||
this.logger.debug(`Failed to sign in with recovery codes: ${result.getError()}`)
|
|
||||||
|
|
||||||
return {
|
|
||||||
status: HttpStatusCode.Unauthorized,
|
|
||||||
data: {
|
|
||||||
error: {
|
|
||||||
message: 'Invalid login credentials.',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
status: HttpStatusCode.Success,
|
|
||||||
data: result.getValue(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async recoveryKeyParams(
|
async recoveryKeyParams(
|
||||||
params: RecoveryKeyParamsRequestParams,
|
params: RecoveryKeyParamsRequestParams,
|
||||||
): Promise<HttpResponse<RecoveryKeyParamsResponseBody>> {
|
): Promise<HttpResponse<RecoveryKeyParamsResponseBody>> {
|
||||||
if (params.apiVersion !== ApiVersion.v20200115) {
|
|
||||||
return {
|
|
||||||
status: HttpStatusCode.BadRequest,
|
|
||||||
data: {
|
|
||||||
error: {
|
|
||||||
message: 'Invalid API version.',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const result = await this.getUserKeyParamsRecovery.execute({
|
const result = await this.getUserKeyParamsRecovery.execute({
|
||||||
|
apiVersion: params.apiVersion,
|
||||||
username: params.username,
|
username: params.username,
|
||||||
codeChallenge: params.codeChallenge,
|
codeChallenge: params.codeChallenge,
|
||||||
recoveryCodes: params.recoveryCodes,
|
recoveryCodes: params.recoveryCodes,
|
||||||
@@ -205,33 +84,4 @@ export class AuthController implements UserServerInterface {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async signOut(params: Record<string, unknown>): Promise<HttpResponse> {
|
|
||||||
if (params.readOnlyAccess) {
|
|
||||||
return {
|
|
||||||
status: HttpStatusCode.Unauthorized,
|
|
||||||
data: {
|
|
||||||
error: {
|
|
||||||
tag: ErrorTag.ReadOnlyAccess,
|
|
||||||
message: 'Session has read-only access.',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const userUuid = await this.sessionService.deleteSessionByToken(
|
|
||||||
(params.authorizationHeader as string).replace('Bearer ', ''),
|
|
||||||
)
|
|
||||||
|
|
||||||
let headers = undefined
|
|
||||||
if (userUuid !== null) {
|
|
||||||
headers = new Map([['x-invalidate-cache', userUuid]])
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
status: HttpStatusCode.NoContent,
|
|
||||||
data: {},
|
|
||||||
headers,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -53,7 +53,10 @@ describe('SubscriptionInvitesController', () => {
|
|||||||
invitations: [],
|
invitations: [],
|
||||||
})
|
})
|
||||||
|
|
||||||
const result = await createController().listInvites({ api: ApiVersion.v20200115, inviterEmail: 'test@test.te' })
|
const result = await createController().listInvites({
|
||||||
|
api: ApiVersion.VERSIONS.v20200115,
|
||||||
|
inviterEmail: 'test@test.te',
|
||||||
|
})
|
||||||
|
|
||||||
expect(listSharedSubscriptionInvitations.execute).toHaveBeenCalledWith({
|
expect(listSharedSubscriptionInvitations.execute).toHaveBeenCalledWith({
|
||||||
inviterEmail: 'test@test.te',
|
inviterEmail: 'test@test.te',
|
||||||
@@ -68,7 +71,7 @@ describe('SubscriptionInvitesController', () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
const result = await createController().cancelInvite({
|
const result = await createController().cancelInvite({
|
||||||
api: ApiVersion.v20200115,
|
api: ApiVersion.VERSIONS.v20200115,
|
||||||
inviteUuid: '1-2-3',
|
inviteUuid: '1-2-3',
|
||||||
inviterEmail: 'test@test.te',
|
inviterEmail: 'test@test.te',
|
||||||
})
|
})
|
||||||
@@ -87,7 +90,7 @@ describe('SubscriptionInvitesController', () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
const result = await createController().cancelInvite({
|
const result = await createController().cancelInvite({
|
||||||
api: ApiVersion.v20200115,
|
api: ApiVersion.VERSIONS.v20200115,
|
||||||
inviteUuid: '1-2-3',
|
inviteUuid: '1-2-3',
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -100,7 +103,7 @@ describe('SubscriptionInvitesController', () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
const result = await createController().declineInvite({
|
const result = await createController().declineInvite({
|
||||||
api: ApiVersion.v20200115,
|
api: ApiVersion.VERSIONS.v20200115,
|
||||||
inviteUuid: '1-2-3',
|
inviteUuid: '1-2-3',
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -117,7 +120,7 @@ describe('SubscriptionInvitesController', () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
const result = await createController().declineInvite({
|
const result = await createController().declineInvite({
|
||||||
api: ApiVersion.v20200115,
|
api: ApiVersion.VERSIONS.v20200115,
|
||||||
inviteUuid: '1-2-3',
|
inviteUuid: '1-2-3',
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -134,7 +137,7 @@ describe('SubscriptionInvitesController', () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
const result = await createController().acceptInvite({
|
const result = await createController().acceptInvite({
|
||||||
api: ApiVersion.v20200115,
|
api: ApiVersion.VERSIONS.v20200115,
|
||||||
inviteUuid: '1-2-3',
|
inviteUuid: '1-2-3',
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -151,7 +154,7 @@ describe('SubscriptionInvitesController', () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
const result = await createController().acceptInvite({
|
const result = await createController().acceptInvite({
|
||||||
api: ApiVersion.v20200115,
|
api: ApiVersion.VERSIONS.v20200115,
|
||||||
inviteUuid: '1-2-3',
|
inviteUuid: '1-2-3',
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -168,7 +171,7 @@ describe('SubscriptionInvitesController', () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
const result = await createController().invite({
|
const result = await createController().invite({
|
||||||
api: ApiVersion.v20200115,
|
api: ApiVersion.VERSIONS.v20200115,
|
||||||
identifier: 'invitee@test.te',
|
identifier: 'invitee@test.te',
|
||||||
inviterUuid: '1-2-3',
|
inviterUuid: '1-2-3',
|
||||||
inviterEmail: 'test@test.te',
|
inviterEmail: 'test@test.te',
|
||||||
@@ -187,7 +190,7 @@ describe('SubscriptionInvitesController', () => {
|
|||||||
|
|
||||||
it('should not invite to user subscription if the identifier is missing in request', async () => {
|
it('should not invite to user subscription if the identifier is missing in request', async () => {
|
||||||
const result = await createController().invite({
|
const result = await createController().invite({
|
||||||
api: ApiVersion.v20200115,
|
api: ApiVersion.VERSIONS.v20200115,
|
||||||
identifier: '',
|
identifier: '',
|
||||||
inviterUuid: '1-2-3',
|
inviterUuid: '1-2-3',
|
||||||
inviterEmail: 'test@test.te',
|
inviterEmail: 'test@test.te',
|
||||||
@@ -205,7 +208,7 @@ describe('SubscriptionInvitesController', () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
const result = await createController().invite({
|
const result = await createController().invite({
|
||||||
api: ApiVersion.v20200115,
|
api: ApiVersion.VERSIONS.v20200115,
|
||||||
identifier: 'invitee@test.te',
|
identifier: 'invitee@test.te',
|
||||||
inviterUuid: '1-2-3',
|
inviterUuid: '1-2-3',
|
||||||
inviterEmail: 'test@test.te',
|
inviterEmail: 'test@test.te',
|
||||||
|
|||||||
@@ -0,0 +1,46 @@
|
|||||||
|
import { ApiVersion } from './ApiVersion'
|
||||||
|
|
||||||
|
describe('ApiVersion', () => {
|
||||||
|
it('should create a value object', () => {
|
||||||
|
const valueOrError = ApiVersion.create(ApiVersion.VERSIONS.v20200115)
|
||||||
|
|
||||||
|
expect(valueOrError.isFailed()).toBeFalsy()
|
||||||
|
expect(valueOrError.getValue().value).toEqual('20200115')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should not create an invalid value object', () => {
|
||||||
|
for (const value of ['', undefined, null, 0, 'SOME_VERSION']) {
|
||||||
|
const valueOrError = ApiVersion.create(value as string)
|
||||||
|
|
||||||
|
expect(valueOrError.isFailed()).toBeTruthy()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should tell if the version is supported for registration', () => {
|
||||||
|
const version = ApiVersion.create(ApiVersion.VERSIONS.v20200115).getValue()
|
||||||
|
|
||||||
|
expect(version.isSupportedForRegistration()).toBeTruthy()
|
||||||
|
|
||||||
|
const version2 = ApiVersion.create(ApiVersion.VERSIONS.v20240226).getValue()
|
||||||
|
|
||||||
|
expect(version2.isSupportedForRegistration()).toBeTruthy()
|
||||||
|
|
||||||
|
const version3 = ApiVersion.create(ApiVersion.VERSIONS.v20161215).getValue()
|
||||||
|
|
||||||
|
expect(version3.isSupportedForRegistration()).toBeFalsy()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should tell if the version is supported for recovery sign in', () => {
|
||||||
|
const version = ApiVersion.create(ApiVersion.VERSIONS.v20200115).getValue()
|
||||||
|
|
||||||
|
expect(version.isSupportedForRecoverySignIn()).toBeTruthy()
|
||||||
|
|
||||||
|
const version2 = ApiVersion.create(ApiVersion.VERSIONS.v20240226).getValue()
|
||||||
|
|
||||||
|
expect(version2.isSupportedForRecoverySignIn()).toBeTruthy()
|
||||||
|
|
||||||
|
const version3 = ApiVersion.create(ApiVersion.VERSIONS.v20161215).getValue()
|
||||||
|
|
||||||
|
expect(version3.isSupportedForRecoverySignIn()).toBeFalsy()
|
||||||
|
})
|
||||||
|
})
|
||||||
@@ -1,5 +1,37 @@
|
|||||||
export enum ApiVersion {
|
import { Result, ValueObject } from '@standardnotes/domain-core'
|
||||||
v20161215 = '20161215',
|
|
||||||
v20190520 = '20190520',
|
import { ApiVersionProps } from './ApiVersionProps'
|
||||||
v20200115 = '20200115',
|
|
||||||
|
export class ApiVersion extends ValueObject<ApiVersionProps> {
|
||||||
|
static readonly VERSIONS = {
|
||||||
|
v20161215: '20161215',
|
||||||
|
v20190520: '20190520',
|
||||||
|
v20200115: '20200115',
|
||||||
|
v20240226: '20240226',
|
||||||
|
}
|
||||||
|
|
||||||
|
get value(): string {
|
||||||
|
return this.props.value
|
||||||
|
}
|
||||||
|
|
||||||
|
private constructor(props: ApiVersionProps) {
|
||||||
|
super(props)
|
||||||
|
}
|
||||||
|
|
||||||
|
static create(version: string): Result<ApiVersion> {
|
||||||
|
const isValidVersion = Object.values(this.VERSIONS).includes(version)
|
||||||
|
if (!isValidVersion) {
|
||||||
|
return Result.fail(`Invalid api version: ${version}`)
|
||||||
|
} else {
|
||||||
|
return Result.ok(new ApiVersion({ value: version }))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
isSupportedForRegistration(): boolean {
|
||||||
|
return [ApiVersion.VERSIONS.v20200115, ApiVersion.VERSIONS.v20240226].includes(this.props.value)
|
||||||
|
}
|
||||||
|
|
||||||
|
isSupportedForRecoverySignIn(): boolean {
|
||||||
|
return [ApiVersion.VERSIONS.v20200115, ApiVersion.VERSIONS.v20240226].includes(this.props.value)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,3 @@
|
|||||||
|
export interface ApiVersionProps {
|
||||||
|
value: string
|
||||||
|
}
|
||||||
@@ -3,6 +3,6 @@ import { KeyParamsData, SessionBody } from '@standardnotes/responses'
|
|||||||
import { AuthResponse } from './AuthResponse'
|
import { AuthResponse } from './AuthResponse'
|
||||||
|
|
||||||
export interface AuthResponse20200115 extends AuthResponse {
|
export interface AuthResponse20200115 extends AuthResponse {
|
||||||
session: SessionBody
|
sessionBody: SessionBody
|
||||||
key_params: KeyParamsData
|
keyParams: KeyParamsData
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,10 @@
|
|||||||
|
import { Session } from '../Session/Session'
|
||||||
|
import { AuthResponse20161215 } from './AuthResponse20161215'
|
||||||
|
import { AuthResponse20200115 } from './AuthResponse20200115'
|
||||||
|
|
||||||
|
export interface AuthResponseCreationResult {
|
||||||
|
response?: AuthResponse20200115
|
||||||
|
legacyResponse?: AuthResponse20161215
|
||||||
|
session?: Session
|
||||||
|
cookies?: { accessToken: string; refreshToken: string }
|
||||||
|
}
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user