Compare commits

...

31 Commits

Author SHA1 Message Date
standardci
b01d1c659d chore(release): publish new version
- @standardnotes/analytics@2.32.5
 - @standardnotes/api-gateway@1.81.9
 - @standardnotes/auth-server@1.165.3
 - @standardnotes/domain-events-infra@1.20.3
 - @standardnotes/event-store@1.13.18
 - @standardnotes/files-server@1.32.4
 - @standardnotes/home-server@1.18.22
 - @standardnotes/revisions-server@1.47.4
 - @standardnotes/scheduler-server@1.26.5
 - @standardnotes/syncing-server@1.120.2
 - @standardnotes/websockets-server@1.17.5
2023-11-07 08:52:34 +00:00
Karol Sójko
751f3b2547 fix: remove open telemetry from code (#903) 2023-11-07 09:15:31 +01:00
standardci
11514e3836 chore(release): publish new version
- @standardnotes/home-server@1.18.21
 - @standardnotes/syncing-server@1.120.1
2023-11-06 15:00:46 +00:00
Karol Sójko
71689c1497 fix(syncing-server): return cursor token upon transfer limit breached (#902)
* fix(syncing-server): return cursor token upon transfer limit breached

* fix e2e env vars
2023-11-06 15:38:28 +01:00
standardci
2742075edc chore(release): publish new version
- @standardnotes/auth-server@1.165.2
 - @standardnotes/home-server@1.18.20
2023-11-03 17:04:35 +00:00
Karol Sójko
7f16232f8b fix(auth): change log severity on user authentication 2023-11-03 17:36:29 +01:00
standardci
0b0703e6d1 chore(release): publish new version
- @standardnotes/api-gateway@1.81.8
 - @standardnotes/auth-server@1.165.1
 - @standardnotes/home-server@1.18.19
2023-11-03 16:27:17 +00:00
Karol Sójko
3e376c44e3 fix: retry attempts on session validation and more verbose logs (#898) 2023-11-03 11:23:02 +01:00
standardci
bfe2d4bb4a chore(release): publish new version
- @standardnotes/auth-server@1.165.0
 - @standardnotes/home-server@1.18.18
 - @standardnotes/syncing-server@1.120.0
2023-11-02 12:01:26 +00:00
Karol Sójko
7253a0a1d9 feat: add shared vault invitation email notifications (#897) 2023-11-02 12:35:01 +01:00
standardci
f2c5810023 chore(release): publish new version
- @standardnotes/home-server@1.18.17
2023-11-02 07:13:07 +00:00
Karol Sójko
2e5b9105b8 fix(home-server): remove unused dep 2023-11-02 07:42:10 +01:00
Karol Sójko
d14411d72e chore: upgrade deps 2023-11-02 07:40:27 +01:00
standardci
5226513b26 chore(release): publish new version
- @standardnotes/auth-server@1.164.2
 - @standardnotes/home-server@1.18.16
2023-11-01 14:18:52 +00:00
Mo
334449f8aa chore: update change email copy 2023-11-01 08:50:37 -05:00
dependabot[bot]
7f43d0c69d chore(deps): bump docker/login-action from 2 to 3 (#832)
Bumps [docker/login-action](https://github.com/docker/login-action) from 2 to 3.
- [Release notes](https://github.com/docker/login-action/releases)
- [Commits](https://github.com/docker/login-action/compare/v2...v3)

---
updated-dependencies:
- dependency-name: docker/login-action
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-11-01 13:33:03 +01:00
dependabot[bot]
6f18276e7a chore(deps): bump crazy-max/ghaction-import-gpg from 5 to 6 (#818)
Bumps [crazy-max/ghaction-import-gpg](https://github.com/crazy-max/ghaction-import-gpg) from 5 to 6.
- [Release notes](https://github.com/crazy-max/ghaction-import-gpg/releases)
- [Commits](https://github.com/crazy-max/ghaction-import-gpg/compare/v5...v6)

---
updated-dependencies:
- dependency-name: crazy-max/ghaction-import-gpg
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-11-01 13:32:41 +01:00
dependabot[bot]
9ff18a18a5 chore(deps): bump aws-actions/amazon-ecr-login from 1 to 2 (#873)
Bumps [aws-actions/amazon-ecr-login](https://github.com/aws-actions/amazon-ecr-login) from 1 to 2.
- [Release notes](https://github.com/aws-actions/amazon-ecr-login/releases)
- [Changelog](https://github.com/aws-actions/amazon-ecr-login/blob/main/CHANGELOG.md)
- [Commits](https://github.com/aws-actions/amazon-ecr-login/compare/v1...v2)

---
updated-dependencies:
- dependency-name: aws-actions/amazon-ecr-login
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-11-01 13:31:49 +01:00
dependabot[bot]
999e72fb1f chore(deps): bump ua-parser-js from 1.0.35 to 1.0.37 (#891)
Bumps [ua-parser-js](https://github.com/faisalman/ua-parser-js) from 1.0.35 to 1.0.37.
- [Release notes](https://github.com/faisalman/ua-parser-js/releases)
- [Changelog](https://github.com/faisalman/ua-parser-js/blob/1.0.37/changelog.md)
- [Commits](https://github.com/faisalman/ua-parser-js/compare/1.0.35...1.0.37)

---
updated-dependencies:
- dependency-name: ua-parser-js
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-11-01 13:31:11 +01:00
standardci
4733e663a3 chore(release): publish new version
- @standardnotes/auth-server@1.164.1
 - @standardnotes/home-server@1.18.15
2023-11-01 11:51:38 +00:00
Karol Sójko
b48eeb16c3 fix(auth): creating valet tokens for shared subscription users (#895)
* fix(auth): creating valet tokens for shared subscription users

* fix(auth): updating storage quota
2023-11-01 12:18:44 +01:00
standardci
0aa2584e82 chore(release): publish new version
- @standardnotes/auth-server@1.164.0
 - @standardnotes/home-server@1.18.14
2023-11-01 08:55:15 +00:00
Karol Sójko
eb8c704d84 feat(auth): add sending email to old email address when the address is changed (#894) 2023-11-01 09:28:00 +01:00
standardci
e93fa14703 chore(release): publish new version
- @standardnotes/api-gateway@1.81.7
 - @standardnotes/files-server@1.32.3
 - @standardnotes/home-server@1.18.13
 - @standardnotes/syncing-server@1.119.4
2023-10-31 14:16:00 +00:00
Karol Sójko
16a6815b69 fix: add fallback methods for 404 requests (#893)
* fix: add fallback methods for 404 requests

* fix: remove fallback controllers exports

* fix: have only one fallback controller expored
2023-10-31 14:44:33 +01:00
standardci
b08e9731b8 chore(release): publish new version
- @standardnotes/auth-server@1.163.2
 - @standardnotes/home-server@1.18.12
2023-10-30 12:23:43 +00:00
Karol Sójko
9bd4fb2d79 fix(auth): checking permissions to update setting only when directly performed by user (#892) 2023-10-30 12:51:31 +01:00
standardci
647aeda1de chore(release): publish new version
- @standardnotes/auth-server@1.163.1
 - @standardnotes/home-server@1.18.11
2023-10-30 11:20:27 +00:00
Karol Sójko
78ff748d91 fix(auth): add more information on the listed creation error 2023-10-30 11:52:26 +01:00
standardci
31f8cf1169 chore(release): publish new version
- @standardnotes/api-gateway@1.81.6
 - @standardnotes/home-server@1.18.10
2023-10-27 10:03:28 +00:00
Karol Sójko
14bcf7b6c9 fix(api-gateway): logs for errors reaching service 2023-10-27 11:36:52 +02:00
95 changed files with 698 additions and 325 deletions

2
.github/ci.env vendored
View File

@@ -26,3 +26,5 @@ MYSQL_ROOT_PASSWORD=changeme123
AUTH_JWT_SECRET=f95259c5e441f5a4646d76422cfb3df4c4488842901aa50b6c51b8be2e0040e9
AUTH_SERVER_ENCRYPTION_SERVER_KEY=1087415dfde3093797f9a7ca93a49e7d7aa1861735eb0d32aae9c303b8c3d060
VALET_TOKEN_SECRET=4b886819ebe1e908077c6cae96311b48a8416bd60cc91c03060e15bdf6b30d1f
SYNCING_SERVER_CONTENT_SIZE_TRANSFER_LIMIT=1000000

View File

@@ -55,7 +55,7 @@ jobs:
run: yarn build
- name: Login to Docker Hub
uses: docker/login-action@v2
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
@@ -69,7 +69,7 @@ jobs:
- name: Login to Amazon ECR
id: login-ecr
uses: aws-actions/amazon-ecr-login@v1
uses: aws-actions/amazon-ecr-login@v2
- name: Set up QEMU
uses: docker/setup-qemu-action@master

View File

@@ -20,7 +20,7 @@ jobs:
- uses: actions/checkout@v4
- name: Login to Docker Hub
uses: docker/login-action@v2
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}

View File

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

View File

@@ -143,7 +143,7 @@ jobs:
git config --global user.email "ci@standardnotes.com"
- name: Import GPG key
uses: crazy-max/ghaction-import-gpg@v5
uses: crazy-max/ghaction-import-gpg@v6
with:
gpg_private_key: ${{ secrets.GPG_PRIVATE_KEY }}
passphrase: ${{ secrets.PASSPHRASE }}

12
.pnp.cjs generated
View File

@@ -5566,7 +5566,7 @@ const RAW_RUNTIME_STATE =
["ts-jest", "virtual:fd909b174d079e30b336c4ce72c38a88c1e447767b1a8dd7655e07719a1e31b97807f0931368724fc78897ff15e6a6d00b83316c0f76d11f85111f342e08bb79#npm:29.1.0"],\
["typeorm", "virtual:31b5a94a105c89c9294c3d524a7f8929fe63ee5a2efadf21951ca4c0cfd2ecf02e8f4ef5a066bbda091f1e3a56e57c6749069a080618c96b22e51131a330fc4a#npm:0.3.17"],\
["typescript", "patch:typescript@npm%3A5.0.4#optional!builtin<compat/typescript>::version=5.0.4&hash=b5f058"],\
["ua-parser-js", "npm:1.0.35"],\
["ua-parser-js", "npm:1.0.37"],\
["uuid", "npm:9.0.0"],\
["winston", "npm:3.9.0"]\
],\
@@ -5785,7 +5785,6 @@ const RAW_RUNTIME_STATE =
["@standardnotes/syncing-server", "workspace:packages/syncing-server"],\
["@types/cors", "npm:2.8.13"],\
["@types/express", "npm:4.17.17"],\
["@types/prettyjson", "npm:0.0.30"],\
["@typescript-eslint/eslint-plugin", "virtual:fd909b174d079e30b336c4ce72c38a88c1e447767b1a8dd7655e07719a1e31b97807f0931368724fc78897ff15e6a6d00b83316c0f76d11f85111f342e08bb79#npm:6.5.0"],\
["@typescript-eslint/parser", "virtual:fd909b174d079e30b336c4ce72c38a88c1e447767b1a8dd7655e07719a1e31b97807f0931368724fc78897ff15e6a6d00b83316c0f76d11f85111f342e08bb79#npm:6.5.0"],\
["cors", "npm:2.8.5"],\
@@ -5798,7 +5797,6 @@ const RAW_RUNTIME_STATE =
["inversify", "npm:6.0.1"],\
["inversify-express-utils", "npm:6.4.3"],\
["prettier", "npm:3.0.3"],\
["prettyjson", "npm:1.2.5"],\
["reflect-metadata", "npm:0.1.13"],\
["typescript", "patch:typescript@npm%3A5.0.4#optional!builtin<compat/typescript>::version=5.0.4&hash=b5f058"],\
["winston", "npm:3.9.0"]\
@@ -6080,7 +6078,7 @@ const RAW_RUNTIME_STATE =
["ts-jest", "virtual:fd909b174d079e30b336c4ce72c38a88c1e447767b1a8dd7655e07719a1e31b97807f0931368724fc78897ff15e6a6d00b83316c0f76d11f85111f342e08bb79#npm:29.1.0"],\
["typeorm", "virtual:31b5a94a105c89c9294c3d524a7f8929fe63ee5a2efadf21951ca4c0cfd2ecf02e8f4ef5a066bbda091f1e3a56e57c6749069a080618c96b22e51131a330fc4a#npm:0.3.17"],\
["typescript", "patch:typescript@npm%3A5.0.4#optional!builtin<compat/typescript>::version=5.0.4&hash=b5f058"],\
["ua-parser-js", "npm:1.0.35"],\
["ua-parser-js", "npm:1.0.37"],\
["uuid", "npm:9.0.0"],\
["winston", "npm:3.9.0"]\
],\
@@ -16149,10 +16147,10 @@ const RAW_RUNTIME_STATE =
}]\
]],\
["ua-parser-js", [\
["npm:1.0.35", {\
"packageLocation": "./.yarn/cache/ua-parser-js-npm-1.0.35-38ecdb7612-b69c99c20f.zip/node_modules/ua-parser-js/",\
["npm:1.0.37", {\
"packageLocation": "./.yarn/cache/ua-parser-js-npm-1.0.37-b79655e1b5-56508f2428.zip/node_modules/ua-parser-js/",\
"packageDependencies": [\
["ua-parser-js", "npm:1.0.35"]\
["ua-parser-js", "npm:1.0.37"]\
],\
"linkType": "HARD"\
}]\

Binary file not shown.

View File

@@ -3,6 +3,12 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [2.32.5](https://github.com/standardnotes/server/compare/@standardnotes/analytics@2.32.4...@standardnotes/analytics@2.32.5) (2023-11-07)
### Bug Fixes
* remove open telemetry from code ([#903](https://github.com/standardnotes/server/issues/903)) ([751f3b2](https://github.com/standardnotes/server/commit/751f3b25476c5be3d663ad8540c43266acd39493))
## [2.32.4](https://github.com/standardnotes/server/compare/@standardnotes/analytics@2.32.3...@standardnotes/analytics@2.32.4) (2023-10-26)
**Note:** Version bump only for package @standardnotes/analytics

View File

@@ -1,11 +1,5 @@
import 'reflect-metadata'
import { OpenTelemetrySDK, OpenTelemetryTracer } from '@standardnotes/domain-events-infra'
import { EmailLevel, ServiceIdentifier } from '@standardnotes/domain-core'
const sdk = new OpenTelemetrySDK({ serviceName: ServiceIdentifier.NAMES.AnalyticsScheduledTask })
sdk.start()
import { Logger } from 'winston'
import { DomainEventPublisherInterface } from '@standardnotes/domain-events'
@@ -22,6 +16,7 @@ import { CalculateMonthlyRecurringRevenue } from '../src/Domain/UseCase/Calculat
import { getBody, getSubject } from '../src/Domain/Email/DailyAnalyticsReport'
import { TimerInterface } from '@standardnotes/time'
import { StatisticMeasureName } from '../src/Domain/Statistics/StatisticMeasureName'
import { EmailLevel } from '@standardnotes/domain-core'
const requestReport = async (
analyticsStore: AnalyticsStoreInterface,
@@ -275,9 +270,6 @@ void container.load().then((container) => {
logger.info(`Sending report to following admins: ${adminEmails}`)
const tracer = new OpenTelemetryTracer()
tracer.startSpan(ServiceIdentifier.NAMES.AnalyticsScheduledTask, 'report')
Promise.resolve(
requestReport(
analyticsStore,
@@ -293,15 +285,11 @@ void container.load().then((container) => {
.then(() => {
logger.info('Usage report generation complete')
tracer.stopSpan()
process.exit(0)
})
.catch((error) => {
logger.error(`Could not finish usage report generation: ${error.message}`)
tracer.stopSpanWithError(error)
process.exit(1)
})
})

View File

@@ -1,11 +1,5 @@
import 'reflect-metadata'
import { OpenTelemetrySDK } from '@standardnotes/domain-events-infra'
import { ServiceIdentifier } from '@standardnotes/domain-core'
const sdk = new OpenTelemetrySDK({ serviceName: ServiceIdentifier.NAMES.AnalyticsWorker })
sdk.start()
import { Logger } from 'winston'
import { DomainEventSubscriberInterface } from '@standardnotes/domain-events'
import * as dayjs from 'dayjs'

View File

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

View File

@@ -7,7 +7,7 @@ import {
DomainEventPublisherInterface,
DomainEventSubscriberInterface,
} from '@standardnotes/domain-events'
import { MapperInterface, ServiceIdentifier } from '@standardnotes/domain-core'
import { MapperInterface } from '@standardnotes/domain-core'
// eslint-disable-next-line @typescript-eslint/no-var-requires
const Mixpanel = require('mixpanel')
@@ -16,9 +16,9 @@ import TYPES from './Types'
import { AppDataSource } from './DataSource'
import { DomainEventFactory } from '../Domain/Event/DomainEventFactory'
import {
SNSOpenTelemetryDomainEventPublisher,
SNSDomainEventPublisher,
SQSDomainEventSubscriber,
SQSEventMessageHandler,
SQSOpenTelemetryDomainEventSubscriber,
} from '@standardnotes/domain-events-infra'
import { Timer, TimerInterface } from '@standardnotes/time'
import { PeriodKeyGeneratorInterface } from '../Domain/Time/PeriodKeyGeneratorInterface'
@@ -139,9 +139,7 @@ export class ContainerConfigLoader {
container
.bind<DomainEventPublisherInterface>(TYPES.DomainEventPublisher)
.toConstantValue(
new SNSOpenTelemetryDomainEventPublisher(container.get(TYPES.SNS), container.get(TYPES.SNS_TOPIC_ARN)),
)
.toConstantValue(new SNSDomainEventPublisher(container.get(TYPES.SNS), container.get(TYPES.SNS_TOPIC_ARN)))
if (env.get('MIXPANEL_TOKEN', true)) {
container.bind<Mixpanel>(TYPES.MixpanelClient).toConstantValue(Mixpanel.init(env.get('MIXPANEL_TOKEN', true)))
}
@@ -242,8 +240,7 @@ export class ContainerConfigLoader {
container
.bind<DomainEventSubscriberInterface>(TYPES.DomainEventSubscriber)
.toConstantValue(
new SQSOpenTelemetryDomainEventSubscriber(
ServiceIdentifier.NAMES.AnalyticsWorker,
new SQSDomainEventSubscriber(
container.get<SQSClient>(TYPES.SQS),
container.get<string>(TYPES.SQS_QUEUE_URL),
container.get<DomainEventMessageHandlerInterface>(TYPES.DomainEventMessageHandler),

View File

@@ -3,6 +3,30 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.81.9](https://github.com/standardnotes/api-gateway/compare/@standardnotes/api-gateway@1.81.8...@standardnotes/api-gateway@1.81.9) (2023-11-07)
### Bug Fixes
* remove open telemetry from code ([#903](https://github.com/standardnotes/api-gateway/issues/903)) ([751f3b2](https://github.com/standardnotes/api-gateway/commit/751f3b25476c5be3d663ad8540c43266acd39493))
## [1.81.8](https://github.com/standardnotes/api-gateway/compare/@standardnotes/api-gateway@1.81.7...@standardnotes/api-gateway@1.81.8) (2023-11-03)
### Bug Fixes
* retry attempts on session validation and more verbose logs ([#898](https://github.com/standardnotes/api-gateway/issues/898)) ([3e376c4](https://github.com/standardnotes/api-gateway/commit/3e376c44e3a6c336dcff3d8ef5eb3ab040d9a561))
## [1.81.7](https://github.com/standardnotes/api-gateway/compare/@standardnotes/api-gateway@1.81.6...@standardnotes/api-gateway@1.81.7) (2023-10-31)
### Bug Fixes
* add fallback methods for 404 requests ([#893](https://github.com/standardnotes/api-gateway/issues/893)) ([16a6815](https://github.com/standardnotes/api-gateway/commit/16a6815b69e344573ae07682f3bac1d44d715d79))
## [1.81.6](https://github.com/standardnotes/api-gateway/compare/@standardnotes/api-gateway@1.81.5...@standardnotes/api-gateway@1.81.6) (2023-10-27)
### Bug Fixes
* **api-gateway:** logs for errors reaching service ([14bcf7b](https://github.com/standardnotes/api-gateway/commit/14bcf7b6c9403c3413e7579f58ea17168d14dce7))
## [1.81.5](https://github.com/standardnotes/api-gateway/compare/@standardnotes/api-gateway@1.81.4...@standardnotes/api-gateway@1.81.5) (2023-10-26)
**Note:** Version bump only for package @standardnotes/api-gateway

View File

@@ -1,11 +1,5 @@
import 'reflect-metadata'
import { OpenTelemetrySDK } from '@standardnotes/domain-events-infra'
import { ServiceIdentifier } from '@standardnotes/domain-core'
const sdk = new OpenTelemetrySDK({ serviceName: ServiceIdentifier.NAMES.ApiGateway })
sdk.start()
import '../src/Controller/LegacyController'
import '../src/Controller/HealthCheckController'

View File

@@ -1,6 +1,6 @@
{
"name": "@standardnotes/api-gateway",
"version": "1.81.5",
"version": "1.81.9",
"engines": {
"node": ">=18.0.0 <21.0.0"
},

View File

@@ -74,13 +74,16 @@ export abstract class AuthMiddleware extends BaseMiddleware {
response.locals.sharedVaultOwnerContext = decodedToken.shared_vault_owner_context
response.locals.belongsToSharedVaults = decodedToken.belongs_to_shared_vaults ?? []
} catch (error) {
const errorMessage = (error as AxiosError).isAxiosError
? JSON.stringify((error as AxiosError).response?.data)
: (error as Error).message
let detailedErrorMessage = (error as Error).message
if (error instanceof AxiosError) {
detailedErrorMessage = `Status: ${error.status}, code: ${error.code}, message: ${error.message}`
}
this.logger.error(`Could not pass the request to sessions/validate on underlying service: ${errorMessage}`)
this.logger.error(
`Could not pass the request to sessions/validate on underlying service: ${detailedErrorMessage}`,
)
this.logger.debug('Response error: %O', (error as AxiosError).response ?? error)
this.logger.debug(`Response error: ${JSON.stringify(error)}`)
if ((error as AxiosError).response?.headers['content-type']) {
response.setHeader('content-type', (error as AxiosError).response?.headers['content-type'] as string)
@@ -91,7 +94,14 @@ export abstract class AuthMiddleware extends BaseMiddleware {
? +((error as AxiosError).code as string)
: 500
response.status(errorCode).send(errorMessage)
const responseErrorMessage = (error as AxiosError).response?.data
response
.status(errorCode)
.send(
responseErrorMessage ??
"Unfortunately, we couldn't handle your request. Please try again or contact our support if the error persists.",
)
return
}

View File

@@ -0,0 +1,9 @@
import { BaseHttpController, all, controller, results } from 'inversify-express-utils'
@controller('')
export class FallbackController extends BaseHttpController {
@all('*')
public async fallback(): Promise<results.NotFoundResult> {
return this.notFound()
}
}

View File

@@ -1,4 +1,5 @@
export * from './AuthMiddleware'
export * from './FallbackController'
export * from './HealthCheckController'
export * from './SubscriptionTokenAuthMiddleware'
export * from './TokenAuthenticationMethod'

View File

@@ -55,10 +55,9 @@ export class HttpServiceProxy implements ServiceProxyInterface {
},
}
} catch (error) {
const requestTimedOut =
'code' in (error as Record<string, unknown>) && (error as Record<string, unknown>).code === 'ETIMEDOUT'
const requestDidNotMakeIt = this.requestTimedOutOrDidNotReachDestination(error as Record<string, unknown>)
const tooManyRetryAttempts = retryAttempt && retryAttempt > 2
if (!tooManyRetryAttempts && requestTimedOut) {
if (!tooManyRetryAttempts && requestDidNotMakeIt) {
await this.timer.sleep(50)
const nextRetryAttempt = retryAttempt ? retryAttempt + 1 : 1
@@ -261,14 +260,15 @@ export class HttpServiceProxy implements ServiceProxyInterface {
)
}
const errorMessage = (error as AxiosError).isAxiosError
? JSON.stringify((error as AxiosError).response?.data)
: (error as Error).message
let detailedErrorMessage = (error as Error).message
if (error instanceof AxiosError) {
detailedErrorMessage = `Status: ${error.status}, code: ${error.code}, message: ${error.message}`
}
this.logger.error(
tooManyRetryAttempts
? `Request to ${serverUrl}/${endpointOrMethodIdentifier} timed out after ${retryAttempt} retries`
: `Could not pass the request to ${serverUrl}/${endpointOrMethodIdentifier} on underlying service: ${errorMessage}`,
: `Could not pass the request to ${serverUrl}/${endpointOrMethodIdentifier} on underlying service: ${detailedErrorMessage}`,
)
this.logger.debug(`Response error: ${JSON.stringify(error)}`)
@@ -282,7 +282,14 @@ export class HttpServiceProxy implements ServiceProxyInterface {
? +((error as AxiosError).code as string)
: 500
response.status(errorCode).send(errorMessage)
const responseErrorMessage = (error as AxiosError).response?.data
response
.status(errorCode)
.send(
responseErrorMessage ??
"Unfortunately, we couldn't handle your request. Please try again or contact our support if the error persists.",
)
}
return

View File

@@ -50,7 +50,13 @@ export interface ServiceProxyInterface {
endpointOrMethodIdentifier: string,
payload?: Record<string, unknown> | string,
): Promise<void>
validateSession(headers: { authorization: string; sharedVaultOwnerContext?: string }): Promise<{
validateSession(
headers: {
authorization: string
sharedVaultOwnerContext?: string
},
retryAttempt?: number,
): Promise<{
status: number
data: unknown
headers: {

View File

@@ -9,10 +9,13 @@ export class DirectCallServiceProxy implements ServiceProxyInterface {
private filesServerUrl: string,
) {}
async validateSession(headers: {
authorization: string
sharedVaultOwnerContext?: string
}): Promise<{ status: number; data: unknown; headers: { contentType: string } }> {
async validateSession(
headers: {
authorization: string
sharedVaultOwnerContext?: string
},
_retryAttempt?: number,
): Promise<{ status: number; data: unknown; headers: { contentType: string } }> {
const authService = this.serviceContainer.get(ServiceIdentifier.create(ServiceIdentifier.NAMES.Auth).getValue())
if (!authService) {
throw new Error('Auth service not found')

View File

@@ -3,6 +3,58 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.165.3](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.165.2...@standardnotes/auth-server@1.165.3) (2023-11-07)
### Bug Fixes
* remove open telemetry from code ([#903](https://github.com/standardnotes/server/issues/903)) ([751f3b2](https://github.com/standardnotes/server/commit/751f3b25476c5be3d663ad8540c43266acd39493))
## [1.165.2](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.165.1...@standardnotes/auth-server@1.165.2) (2023-11-03)
### Bug Fixes
* **auth:** change log severity on user authentication ([7f16232](https://github.com/standardnotes/server/commit/7f16232f8b13e3736801b6dc0af799e0559a3cfa))
## [1.165.1](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.165.0...@standardnotes/auth-server@1.165.1) (2023-11-03)
### Bug Fixes
* retry attempts on session validation and more verbose logs ([#898](https://github.com/standardnotes/server/issues/898)) ([3e376c4](https://github.com/standardnotes/server/commit/3e376c44e3a6c336dcff3d8ef5eb3ab040d9a561))
# [1.165.0](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.164.2...@standardnotes/auth-server@1.165.0) (2023-11-02)
### Features
* add shared vault invitation email notifications ([#897](https://github.com/standardnotes/server/issues/897)) ([7253a0a](https://github.com/standardnotes/server/commit/7253a0a1d92099df844c9baf6541b440bbcb0a68))
## [1.164.2](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.164.1...@standardnotes/auth-server@1.164.2) (2023-11-01)
**Note:** Version bump only for package @standardnotes/auth-server
## [1.164.1](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.164.0...@standardnotes/auth-server@1.164.1) (2023-11-01)
### Bug Fixes
* **auth:** creating valet tokens for shared subscription users ([#895](https://github.com/standardnotes/server/issues/895)) ([b48eeb1](https://github.com/standardnotes/server/commit/b48eeb16c32031e73e9757e34c4b50ca0a3a773d))
# [1.164.0](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.163.2...@standardnotes/auth-server@1.164.0) (2023-11-01)
### Features
* **auth:** add sending email to old email address when the address is changed ([#894](https://github.com/standardnotes/server/issues/894)) ([eb8c704](https://github.com/standardnotes/server/commit/eb8c704d84277130dc0dc51c1fe475a7220612cd))
## [1.163.2](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.163.1...@standardnotes/auth-server@1.163.2) (2023-10-30)
### Bug Fixes
* **auth:** checking permissions to update setting only when directly performed by user ([#892](https://github.com/standardnotes/server/issues/892)) ([9bd4fb2](https://github.com/standardnotes/server/commit/9bd4fb2d794dae032286c68f23d3896b68735bdd))
## [1.163.1](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.163.0...@standardnotes/auth-server@1.163.1) (2023-10-30)
### Bug Fixes
* **auth:** add more information on the listed creation error ([78ff748](https://github.com/standardnotes/server/commit/78ff748d911a5a4063903847ef761822bbb8f4e2))
# [1.163.0](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.162.0...@standardnotes/auth-server@1.163.0) (2023-10-26)
### Features

View File

@@ -1,10 +1,6 @@
import 'reflect-metadata'
import { OpenTelemetrySDK, OpenTelemetryTracer } from '@standardnotes/domain-events-infra'
import { ServiceIdentifier, SettingName } from '@standardnotes/domain-core'
const sdk = new OpenTelemetrySDK({ serviceName: ServiceIdentifier.NAMES.AuthScheduledTask })
sdk.start()
import { SettingName } from '@standardnotes/domain-core'
import { Stream } from 'stream'
@@ -106,24 +102,17 @@ void container.load().then((container) => {
const domainEventPublisher: DomainEventPublisherInterface = container.get(TYPES.Auth_DomainEventPublisher)
const getUserKeyParamsUseCase: GetUserKeyParams = container.get(TYPES.Auth_GetUserKeyParams)
const tracer = new OpenTelemetryTracer()
tracer.startSpan(ServiceIdentifier.NAMES.AuthScheduledTask, 'backup')
Promise.resolve(
requestBackups(settingRepository, roleService, domainEventFactory, domainEventPublisher, getUserKeyParamsUseCase),
)
.then(() => {
logger.info(`${backupFrequency} ${backupProvider} backup requesting complete`)
tracer.stopSpan()
process.exit(0)
})
.catch((error) => {
logger.error(`Could not finish ${backupFrequency} ${backupProvider} backup requesting: ${error.message}`)
tracer.stopSpanWithError(error)
process.exit(1)
})
})

View File

@@ -1,11 +1,5 @@
import 'reflect-metadata'
import { OpenTelemetrySDK, OpenTelemetryTracer } from '@standardnotes/domain-events-infra'
import { ServiceIdentifier } from '@standardnotes/domain-core'
const sdk = new OpenTelemetrySDK({ serviceName: ServiceIdentifier.NAMES.AuthScheduledTask })
sdk.start()
import { Logger } from 'winston'
import { ContainerConfigLoader } from '../src/Bootstrap/Container'
@@ -36,22 +30,15 @@ void container.load().then((container) => {
const cleanupSessionTraces: CleanupSessionTraces = container.get(TYPES.Auth_CleanupSessionTraces)
const cleanupExpiredSessions: CleanupExpiredSessions = container.get(TYPES.Auth_CleanupExpiredSessions)
const tracer = new OpenTelemetryTracer()
tracer.startSpan(ServiceIdentifier.NAMES.AuthScheduledTask, 'cleanup')
Promise.resolve(cleanup(cleanupSessionTraces, cleanupExpiredSessions))
.then(() => {
logger.info('Expired sessions and session traces cleaned.')
tracer.stopSpan()
process.exit(0)
})
.catch((error) => {
logger.error(`Could not clean sessions and session traces: ${error.message}`)
tracer.stopSpanWithError(error)
process.exit(1)
})
})

View File

@@ -1,11 +1,5 @@
import 'reflect-metadata'
import { OpenTelemetrySDK } from '@standardnotes/domain-events-infra'
import { ServiceIdentifier } from '@standardnotes/domain-core'
const sdk = new OpenTelemetrySDK({ serviceName: ServiceIdentifier.NAMES.Auth })
sdk.start()
import '../src/Infra/InversifyExpressUtils/AnnotatedAuthController'
import '../src/Infra/InversifyExpressUtils/AnnotatedAuthenticatorsController'
import '../src/Infra/InversifyExpressUtils/AnnotatedSessionsController'

View File

@@ -1,11 +1,5 @@
import 'reflect-metadata'
import { OpenTelemetrySDK, OpenTelemetryTracer } from '@standardnotes/domain-events-infra'
import { ServiceIdentifier } from '@standardnotes/domain-core'
const sdk = new OpenTelemetrySDK({ serviceName: ServiceIdentifier.NAMES.AuthScheduledTask })
sdk.start()
import { Logger } from 'winston'
import { TimerInterface } from '@standardnotes/time'
@@ -26,9 +20,6 @@ void container.load().then((container) => {
const persistStats: PersistStatistics = container.get(TYPES.Auth_PersistStatistics)
const timer: TimerInterface = container.get(TYPES.Auth_Timer)
const tracer = new OpenTelemetryTracer()
tracer.startSpan(ServiceIdentifier.NAMES.AuthScheduledTask, 'stats')
Promise.resolve(
persistStats.execute({
sessionsInADay: timer.getUTCDateNDaysAgo(1),
@@ -37,15 +28,11 @@ void container.load().then((container) => {
.then(() => {
logger.info('Stats persisted.')
tracer.stopSpan()
process.exit(0)
})
.catch((error) => {
logger.error(`Could not persist stats: ${error.message}`)
tracer.stopSpanWithError(error)
process.exit(1)
})
})

View File

@@ -1,11 +1,5 @@
import 'reflect-metadata'
import { OpenTelemetrySDK, OpenTelemetryTracer } from '@standardnotes/domain-events-infra'
import { Email, ServiceIdentifier, SettingName } from '@standardnotes/domain-core'
const sdk = new OpenTelemetrySDK({ serviceName: ServiceIdentifier.NAMES.AuthScheduledTask })
sdk.start()
import { Logger } from 'winston'
import * as dayjs from 'dayjs'
import * as utc from 'dayjs/plugin/utc'
@@ -21,6 +15,7 @@ import { RoleServiceInterface } from '../src/Domain/Role/RoleServiceInterface'
import { PermissionName } from '@standardnotes/features'
import { UserRepositoryInterface } from '../src/Domain/User/UserRepositoryInterface'
import { GetUserKeyParams } from '../src/Domain/UseCase/GetUserKeyParams/GetUserKeyParams'
import { Email, SettingName } from '@standardnotes/domain-core'
const inputArgs = process.argv.slice(2)
const backupEmail = inputArgs[0]
@@ -94,9 +89,6 @@ void container.load().then((container) => {
const domainEventPublisher: DomainEventPublisherInterface = container.get(TYPES.Auth_DomainEventPublisher)
const getUserKeyParamsUseCase: GetUserKeyParams = container.get(TYPES.Auth_GetUserKeyParams)
const tracer = new OpenTelemetryTracer()
tracer.startSpan(ServiceIdentifier.NAMES.AuthScheduledTask, 'user_email_backup')
Promise.resolve(
requestBackups(
userRepository,
@@ -110,15 +102,11 @@ void container.load().then((container) => {
.then(() => {
logger.info(`Email backup requesting complete for ${backupEmail}`)
tracer.stopSpan()
process.exit(0)
})
.catch((error) => {
logger.error(`Could not finish email backup requesting for ${backupEmail}: ${error.message}`)
tracer.stopSpanWithError(error)
process.exit(1)
})
})

View File

@@ -1,11 +1,5 @@
import 'reflect-metadata'
import { OpenTelemetrySDK } from '@standardnotes/domain-events-infra'
import { ServiceIdentifier } from '@standardnotes/domain-core'
const sdk = new OpenTelemetrySDK({ serviceName: ServiceIdentifier.NAMES.AuthWorker })
sdk.start()
import { Logger } from 'winston'
import { ContainerConfigLoader } from '../src/Bootstrap/Container'

View File

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

View File

@@ -79,9 +79,9 @@ import { ExtensionKeyGrantedEventHandler } from '../Domain/Handler/ExtensionKeyG
import {
DirectCallDomainEventPublisher,
DirectCallEventMessageHandler,
SNSOpenTelemetryDomainEventPublisher,
SNSDomainEventPublisher,
SQSDomainEventSubscriber,
SQSEventMessageHandler,
SQSOpenTelemetryDomainEventSubscriber,
} from '@standardnotes/domain-events-infra'
import { GetUserSubscription } from '../Domain/UseCase/GetUserSubscription/GetUserSubscription'
import { ChangeCredentials } from '../Domain/UseCase/ChangeCredentials/ChangeCredentials'
@@ -170,7 +170,6 @@ import {
ControllerContainer,
ControllerContainerInterface,
MapperInterface,
ServiceIdentifier,
SharedVaultUser,
} from '@standardnotes/domain-core'
import { SessionTracePersistenceMapper } from '../Mapping/SessionTracePersistenceMapper'
@@ -274,6 +273,8 @@ import { TypeORMSetting } from '../Infra/TypeORM/TypeORMSetting'
import { SettingPersistenceMapper } from '../Mapping/Persistence/SettingPersistenceMapper'
import { SubscriptionSettingPersistenceMapper } from '../Mapping/Persistence/SubscriptionSettingPersistenceMapper'
import { ApplyDefaultSettings } from '../Domain/UseCase/ApplyDefaultSettings/ApplyDefaultSettings'
import { AuthResponseFactoryResolverInterface } from '../Domain/Auth/AuthResponseFactoryResolverInterface'
import { UserInvitedToSharedVaultEventHandler } from '../Domain/Handler/UserInvitedToSharedVaultEventHandler'
export class ContainerConfigLoader {
constructor(private mode: 'server' | 'worker' = 'server') {}
@@ -377,10 +378,7 @@ export class ContainerConfigLoader {
.toConstantValue(
isConfiguredForHomeServer
? directCallDomainEventPublisher
: new SNSOpenTelemetryDomainEventPublisher(
container.get(TYPES.Auth_SNS),
container.get(TYPES.Auth_SNS_TOPIC_ARN),
),
: new SNSDomainEventPublisher(container.get(TYPES.Auth_SNS), container.get(TYPES.Auth_SNS_TOPIC_ARN)),
)
// Mapping
@@ -723,7 +721,9 @@ export class ContainerConfigLoader {
container.bind<AuthResponseFactory20161215>(TYPES.Auth_AuthResponseFactory20161215).to(AuthResponseFactory20161215)
container.bind<AuthResponseFactory20190520>(TYPES.Auth_AuthResponseFactory20190520).to(AuthResponseFactory20190520)
container.bind<AuthResponseFactory20200115>(TYPES.Auth_AuthResponseFactory20200115).to(AuthResponseFactory20200115)
container.bind<AuthResponseFactoryResolver>(TYPES.Auth_AuthResponseFactoryResolver).to(AuthResponseFactoryResolver)
container
.bind<AuthResponseFactoryResolverInterface>(TYPES.Auth_AuthResponseFactoryResolver)
.to(AuthResponseFactoryResolver)
container.bind<KeyParamsFactory>(TYPES.Auth_KeyParamsFactory).to(KeyParamsFactory)
container
.bind<TokenDecoderInterface<SessionTokenData>>(TYPES.Auth_SessionTokenDecoder)
@@ -1020,7 +1020,19 @@ export class ContainerConfigLoader {
container.bind<GetActiveSessionsForUser>(TYPES.Auth_GetActiveSessionsForUser).to(GetActiveSessionsForUser)
container.bind<DeleteOtherSessionsForUser>(TYPES.Auth_DeleteOtherSessionsForUser).to(DeleteOtherSessionsForUser)
container.bind<DeleteSessionForUser>(TYPES.Auth_DeleteSessionForUser).to(DeleteSessionForUser)
container.bind<ChangeCredentials>(TYPES.Auth_ChangeCredentials).to(ChangeCredentials)
container
.bind<ChangeCredentials>(TYPES.Auth_ChangeCredentials)
.toConstantValue(
new ChangeCredentials(
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<TimerInterface>(TYPES.Auth_Timer),
container.get<DeleteOtherSessionsForUser>(TYPES.Auth_DeleteOtherSessionsForUser),
container.get<winston.Logger>(TYPES.Auth_Logger),
),
)
container
.bind<GetSettings>(TYPES.Auth_GetSettings)
.toConstantValue(
@@ -1434,6 +1446,15 @@ export class ContainerConfigLoader {
container.get<winston.Logger>(TYPES.Auth_Logger),
),
)
container
.bind<UserInvitedToSharedVaultEventHandler>(TYPES.Auth_UserInvitedToSharedVaultEventHandler)
.toConstantValue(
new UserInvitedToSharedVaultEventHandler(
container.get<UserRepositoryInterface>(TYPES.Auth_UserRepository),
container.get<DomainEventFactoryInterface>(TYPES.Auth_DomainEventFactory),
container.get<DomainEventPublisherInterface>(TYPES.Auth_DomainEventPublisher),
),
)
const eventHandlers: Map<string, DomainEventHandlerInterface> = new Map([
['ACCOUNT_DELETION_REQUESTED', container.get(TYPES.Auth_AccountDeletionRequestedEventHandler)],
@@ -1469,6 +1490,7 @@ export class ContainerConfigLoader {
'USER_DESIGNATED_AS_SURVIVOR_IN_SHARED_VAULT',
container.get(TYPES.Auth_UserDesignatedAsSurvivorInSharedVaultEventHandler),
],
['USER_INVITED_TO_SHARED_VAULT', container.get(TYPES.Auth_UserInvitedToSharedVaultEventHandler)],
])
if (isConfiguredForHomeServer) {
@@ -1488,8 +1510,7 @@ export class ContainerConfigLoader {
container
.bind<DomainEventSubscriberInterface>(TYPES.Auth_DomainEventSubscriber)
.toConstantValue(
new SQSOpenTelemetryDomainEventSubscriber(
ServiceIdentifier.NAMES.AuthWorker,
new SQSDomainEventSubscriber(
container.get<SQSClient>(TYPES.Auth_SQS),
container.get<string>(TYPES.Auth_SQS_QUEUE_URL),
container.get<DomainEventMessageHandlerInterface>(TYPES.Auth_DomainEventMessageHandler),

View File

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

View File

@@ -0,0 +1,9 @@
import { html } from './user-email-changed.html'
export function getSubject(): string {
return 'Confirmation: Your Email Address Has Been Successfully Updated'
}
export function getBody(newEmail: string): string {
return html(newEmail)
}

View File

@@ -0,0 +1,9 @@
import { html } from './user-invited-to-shared-vault.html'
export function getSubject(): string {
return "You're Invited to a Shared Vault!"
}
export function getBody(): string {
return html()
}

View File

@@ -0,0 +1,14 @@
export const html = (newEmail: string) => `
<p>Hello,</p>
<p>We are writing to inform you that your request to update your email address has been successfully processed. The email address associated with your Standard Notes account has now been changed to the following:</p>
<p>New Email Address: ${newEmail}</p>
<p>From now on, you can log in to your account using your new email address. Your password and all other account details remain the same. If you did not initiate this change or have any concerns about this update, please contact our support team by visiting our <a href="https://standardnotes.com/help">help page</a>
or by replying directly to this email.</p>
<p>Best regards,</p>
<p>
Standard Notes
</p>
`

View File

@@ -0,0 +1,21 @@
export const html = () => `
<p>Hello,</p>
<p>You've been invited to join a shared vault. This shared workspace will help you collaborate and securely manage notes and files.</p>
<p>To accept this invitation and access the shared vault, please follow these steps:</p>
<ol>
<li>Go to your account settings.</li>
<li>Navigate to the "Vaults" section.</li>
<li>You will find the invitation there — simply click to accept.</li>
</ol>
<p>If you have any questions, please contact our support team by visiting our <a href="https://standardnotes.com/help">help page</a>
or by replying directly to this email.</p>
<p>Best regards,</p>
<p>
Standard Notes
</p>
`

View File

@@ -53,7 +53,7 @@ export class ListedAccountCreatedEventHandler implements DomainEventHandlerInter
})
if (result.isFailed()) {
this.logger.error(`Could not update listed author secrets for user with uuid ${user.uuid}`)
this.logger.error(`Could not update listed author secrets for user with uuid ${user.uuid}: ${result.getError()}`)
}
}
}

View File

@@ -0,0 +1,41 @@
import {
DomainEventHandlerInterface,
DomainEventPublisherInterface,
UserInvitedToSharedVaultEvent,
} from '@standardnotes/domain-events'
import { EmailLevel, Uuid } from '@standardnotes/domain-core'
import { UserRepositoryInterface } from '../User/UserRepositoryInterface'
import { DomainEventFactoryInterface } from '../Event/DomainEventFactoryInterface'
import { getBody, getSubject } from '../Email/UserInvitedToSharedVault'
export class UserInvitedToSharedVaultEventHandler implements DomainEventHandlerInterface {
constructor(
private userRepository: UserRepositoryInterface,
private domainEventFactory: DomainEventFactoryInterface,
private domainEventPublisher: DomainEventPublisherInterface,
) {}
async handle(event: UserInvitedToSharedVaultEvent): Promise<void> {
const userUuidOrError = Uuid.create(event.payload.invite.user_uuid)
if (userUuidOrError.isFailed()) {
return
}
const userUuid = userUuidOrError.getValue()
const user = await this.userRepository.findOneByUuid(userUuid)
if (!user) {
return
}
await this.domainEventPublisher.publish(
this.domainEventFactory.createEmailRequestedEvent({
body: getBody(),
level: EmailLevel.LEVELS.System,
subject: getSubject(),
messageIdentifier: 'USER_INVITED_TO_SHARED_VAULT',
userEmail: user.email,
}),
)
}
}

View File

@@ -16,7 +16,7 @@ export class AuthenticateRequest implements UseCaseInterface {
async execute(dto: AuthenticateRequestDTO): Promise<AuthenticateRequestResponse> {
if (!dto.authorizationHeader) {
this.logger.debug('Authorization header not provided.')
this.logger.debug('[authenticate-request] Authorization header not provided.')
return {
success: false,
@@ -32,7 +32,9 @@ export class AuthenticateRequest implements UseCaseInterface {
token: dto.authorizationHeader.replace('Bearer ', ''),
})
} catch (error) {
this.logger.error('Error occurred during authentication of a user %o', error)
this.logger.error(
`[authenticate-request] Error occurred during authentication of a user ${(error as Error).message}`,
)
return {
success: false,

View File

@@ -23,6 +23,8 @@ describe('AuthenticateUser', () => {
beforeEach(() => {
logger = {} as jest.Mocked<Logger>
logger.debug = jest.fn()
logger.error = jest.fn()
logger.warn = jest.fn()
user = {} as jest.Mocked<User>
user.supportsSessions = jest.fn().mockReturnValue(false)

View File

@@ -24,7 +24,7 @@ export class AuthenticateUser implements UseCaseInterface {
async execute(dto: AuthenticateUserDTO): Promise<AuthenticateUserResponse> {
const authenticationMethod = await this.authenticationMethodResolver.resolve(dto.token)
if (!authenticationMethod) {
this.logger.debug('No authentication method found for token.')
this.logger.debug(`[authenticate-user] No authentication method found for token: ${dto.token}`)
return {
success: false,
@@ -33,6 +33,8 @@ export class AuthenticateUser implements UseCaseInterface {
}
if (authenticationMethod.type === 'revoked') {
this.logger.debug(`[authenticate-user] Session has been revoked: ${dto.token}`)
return {
success: false,
failureType: 'REVOKED_SESSION',
@@ -41,7 +43,7 @@ export class AuthenticateUser implements UseCaseInterface {
const user = authenticationMethod.user
if (!user) {
this.logger.debug('No user found for authentication method.')
this.logger.debug(`[authenticate-user] No user found for authentication method. Token: ${dto.token}`)
return {
success: false,
@@ -50,7 +52,9 @@ export class AuthenticateUser implements UseCaseInterface {
}
if (authenticationMethod.type == 'jwt' && user.supportsSessions()) {
this.logger.debug('User supports sessions but is trying to authenticate with a JWT.')
this.logger.debug(
`[authenticate-user][${user.uuid}] User supports sessions but is trying to authenticate with a JWT.`,
)
return {
success: false,
@@ -64,7 +68,7 @@ export class AuthenticateUser implements UseCaseInterface {
const encryptedPasswordDigest = crypto.createHash('sha256').update(user.encryptedPassword).digest('hex')
if (!pwHash || !crypto.timingSafeEqual(Buffer.from(pwHash), Buffer.from(encryptedPasswordDigest))) {
this.logger.debug('Password hash does not match.')
this.logger.debug(`[authenticate-user][${user.uuid}] Password hash does not match.`)
return {
success: false,
@@ -76,7 +80,7 @@ export class AuthenticateUser implements UseCaseInterface {
case 'session_token': {
const session = authenticationMethod.session
if (!session) {
this.logger.debug('No session found for authentication method.')
this.logger.debug(`[authenticate-user][${user.uuid}] No session found for authentication method.`)
return {
success: false,
@@ -85,7 +89,7 @@ export class AuthenticateUser implements UseCaseInterface {
}
if (session.refreshExpiration < this.timer.getUTCDate()) {
this.logger.debug('Session refresh token has expired.')
this.logger.debug(`[authenticate-user][${user.uuid}] Session refresh token has expired.`)
return {
success: false,
@@ -94,6 +98,8 @@ export class AuthenticateUser implements UseCaseInterface {
}
if (this.sessionIsExpired(session)) {
this.logger.debug(`[authenticate-user][${user.uuid}] Session access token has expired.`)
return {
success: false,
failureType: 'EXPIRED_TOKEN',

View File

@@ -15,6 +15,7 @@ import { Result, Username } from '@standardnotes/domain-core'
import { DeleteOtherSessionsForUser } from '../DeleteOtherSessionsForUser'
import { ApiVersion } from '../../Api/ApiVersion'
import { Session } from '../../Session/Session'
import { Logger } from 'winston'
describe('ChangeCredentials', () => {
let userRepository: UserRepositoryInterface
@@ -25,6 +26,7 @@ describe('ChangeCredentials', () => {
let timer: TimerInterface
let user: User
let deleteOtherSessionsForUser: DeleteOtherSessionsForUser
let logger: Logger
const createUseCase = () =>
new ChangeCredentials(
@@ -34,9 +36,13 @@ describe('ChangeCredentials', () => {
domainEventFactory,
timer,
deleteOtherSessionsForUser,
logger,
)
beforeEach(() => {
logger = {} as jest.Mocked<Logger>
logger.error = jest.fn()
authResponseFactory = {} as jest.Mocked<AuthResponseFactoryInterface>
authResponseFactory.createResponse = jest
.fn()
@@ -51,7 +57,7 @@ describe('ChangeCredentials', () => {
user.email = 'test@test.te'
userRepository = {} as jest.Mocked<UserRepositoryInterface>
userRepository.save = jest.fn()
userRepository.save = jest.fn().mockImplementation((user: User) => Promise.resolve(user))
userRepository.findOneByUsernameOrEmail = jest.fn().mockReturnValue(user)
domainEventPublisher = {} as jest.Mocked<DomainEventPublisherInterface>

View File

@@ -1,10 +1,8 @@
import * as bcrypt from 'bcryptjs'
import { inject, injectable } from 'inversify'
import { DomainEventPublisherInterface, UserEmailChangedEvent } from '@standardnotes/domain-events'
import { TimerInterface } from '@standardnotes/time'
import { Result, UseCaseInterface, Username } from '@standardnotes/domain-core'
import { EmailLevel, Result, UseCaseInterface, Username } from '@standardnotes/domain-core'
import TYPES from '../../../Bootstrap/Types'
import { AuthResponseFactoryResolverInterface } from '../../Auth/AuthResponseFactoryResolverInterface'
import { User } from '../../User/User'
import { UserRepositoryInterface } from '../../User/UserRepositoryInterface'
@@ -14,18 +12,18 @@ import { DeleteOtherSessionsForUser } from '../DeleteOtherSessionsForUser'
import { AuthResponse20161215 } from '../../Auth/AuthResponse20161215'
import { AuthResponse20200115 } from '../../Auth/AuthResponse20200115'
import { Session } from '../../Session/Session'
import { getBody, getSubject } from '../../Email/UserEmailChanged'
import { Logger } from 'winston'
@injectable()
export class ChangeCredentials implements UseCaseInterface<AuthResponse20161215 | AuthResponse20200115> {
constructor(
@inject(TYPES.Auth_UserRepository) private userRepository: UserRepositoryInterface,
@inject(TYPES.Auth_AuthResponseFactoryResolver)
private userRepository: UserRepositoryInterface,
private authResponseFactoryResolver: AuthResponseFactoryResolverInterface,
@inject(TYPES.Auth_DomainEventPublisher) private domainEventPublisher: DomainEventPublisherInterface,
@inject(TYPES.Auth_DomainEventFactory) private domainEventFactory: DomainEventFactoryInterface,
@inject(TYPES.Auth_Timer) private timer: TimerInterface,
@inject(TYPES.Auth_DeleteOtherSessionsForUser)
private domainEventPublisher: DomainEventPublisherInterface,
private domainEventFactory: DomainEventFactoryInterface,
private timer: TimerInterface,
private deleteOtherSessionsForUserUseCase: DeleteOtherSessionsForUser,
private logger: Logger,
) {}
async execute(dto: ChangeCredentialsDTO): Promise<Result<AuthResponse20161215 | AuthResponse20200115>> {
@@ -41,6 +39,7 @@ export class ChangeCredentials implements UseCaseInterface<AuthResponse20161215
user.encryptedPassword = await bcrypt.hash(dto.newPassword, User.PASSWORD_HASH_COST)
let userEmailChangedEvent: UserEmailChangedEvent | undefined = undefined
const existingEmailAddress = user.email
if (dto.newEmail !== undefined) {
const newUsernameOrError = Username.create(dto.newEmail)
if (newUsernameOrError.isFailed()) {
@@ -78,6 +77,8 @@ export class ChangeCredentials implements UseCaseInterface<AuthResponse20161215
if (userEmailChangedEvent !== undefined) {
await this.domainEventPublisher.publish(userEmailChangedEvent)
await this.sendEmailChangedNotification(existingEmailAddress, updatedUser.email)
}
const authResponseFactory = this.authResponseFactoryResolver.resolveAuthResponseFactoryVersion(dto.apiVersion)
@@ -113,4 +114,21 @@ export class ChangeCredentials implements UseCaseInterface<AuthResponse20161215
})
}
}
private async sendEmailChangedNotification(oldEmail: string, newEmail: string): Promise<void> {
try {
await this.domainEventPublisher.publish(
this.domainEventFactory.createEmailRequestedEvent({
userEmail: oldEmail,
level: EmailLevel.LEVELS.System,
body: getBody(newEmail),
messageIdentifier: 'EMAIL_CHANGED',
subject: getSubject(),
}),
)
} catch (error) {
/* istanbul ignore next */
this.logger.error(`Could not publish email changed request for email: ${(error as Error).message}`)
}
}
}

View File

@@ -12,6 +12,7 @@ import { GetRegularSubscriptionForUser } from '../GetRegularSubscriptionForUser/
import { GetSharedSubscriptionForUser } from '../GetSharedSubscriptionForUser/GetSharedSubscriptionForUser'
import { GetSubscriptionSetting } from '../GetSubscriptionSetting/GetSubscriptionSetting'
import { SettingName } from '@standardnotes/domain-core'
import { UserSubscription } from '../../Subscription/UserSubscription'
export class CreateValetToken implements UseCaseInterface {
constructor(
@@ -27,8 +28,17 @@ export class CreateValetToken implements UseCaseInterface {
async execute(dto: CreateValetTokenDTO): Promise<CreateValetTokenResponseData> {
const { userUuid, ...payload } = dto
let sharedSubscription: UserSubscription | undefined
const sharedSubscriptionOrError = await this.getSharedSubscription.execute({
userUuid,
})
if (!sharedSubscriptionOrError.isFailed()) {
sharedSubscription = sharedSubscriptionOrError.getValue()
}
const regularSubscriptionOrError = await this.getRegularSubscription.execute({
userUuid: dto.userUuid,
userUuid: sharedSubscription ? undefined : dto.userUuid,
subscriptionId: sharedSubscription ? (sharedSubscription.subscriptionId as number) : undefined,
})
if (regularSubscriptionOrError.isFailed()) {
return {
@@ -77,22 +87,13 @@ export class CreateValetToken implements UseCaseInterface {
uploadBytesLimit = +(overwriteWithUserUploadBytesLimitSetting.setting.props.value as string)
}
let sharedSubscriptionUuid = undefined
const sharedSubscriptionOrError = await this.getSharedSubscription.execute({
userUuid,
})
if (!sharedSubscriptionOrError.isFailed()) {
const sharedSubscription = sharedSubscriptionOrError.getValue()
sharedSubscriptionUuid = sharedSubscription.uuid
}
const tokenData: ValetTokenData = {
userUuid: dto.userUuid,
permittedOperation: dto.operation,
permittedResources: dto.resources,
uploadBytesUsed,
uploadBytesLimit,
sharedSubscriptionUuid,
sharedSubscriptionUuid: sharedSubscription ? sharedSubscription.uuid : undefined,
regularSubscriptionUuid: regularSubscription.uuid,
}

View File

@@ -35,7 +35,7 @@ describe('GetRegularSubscriptionForUser', () => {
expect(result.isFailed()).toBe(true)
})
it('returns regular subscription when user subscription is regular', async () => {
it('returns regular subscription for user uuid', async () => {
const useCase = createUseCase()
const result = await useCase.execute({ userUuid: '00000000-0000-0000-0000-000000000000' })
@@ -43,4 +43,31 @@ describe('GetRegularSubscriptionForUser', () => {
expect(result.isFailed()).toBe(false)
expect(result.getValue()).toBe(regularSubscription)
})
it('returns regular subscription for shared subscription id', async () => {
const useCase = createUseCase()
userSubscriptionRepository.findBySubscriptionIdAndType = jest.fn().mockResolvedValue([regularSubscription])
const result = await useCase.execute({ subscriptionId: 1 })
expect(result.isFailed()).toBe(false)
expect(result.getValue()).toBe(regularSubscription)
})
it('returns error if subscription for shared subscription id is not found', async () => {
const useCase = createUseCase()
userSubscriptionRepository.findBySubscriptionIdAndType = jest.fn().mockResolvedValue([])
const result = await useCase.execute({ subscriptionId: 1 })
expect(result.isFailed()).toBe(true)
})
it('returns error if no parameters are specified', async () => {
const useCase = createUseCase()
const result = await useCase.execute({})
expect(result.isFailed()).toBe(true)
})
})

View File

@@ -9,7 +9,18 @@ export class GetRegularSubscriptionForUser implements UseCaseInterface<UserSubsc
constructor(private userSubscriptionRepository: UserSubscriptionRepositoryInterface) {}
async execute(dto: GetRegularSubscriptionForUserDTO): Promise<Result<UserSubscription>> {
const userUuidOrError = Uuid.create(dto.userUuid)
if (dto.userUuid !== undefined) {
return this.getRegularSubscriptionForUser(dto.userUuid)
}
if (dto.subscriptionId !== undefined) {
return this.getRegularSubscriptionForSharedSubscription(dto.subscriptionId)
}
return Result.fail('Invalid parameters.')
}
private async getRegularSubscriptionForUser(userUuidString: string): Promise<Result<UserSubscription>> {
const userUuidOrError = Uuid.create(userUuidString)
if (userUuidOrError.isFailed()) {
return Result.fail(`Could not get regular subscription for user: ${userUuidOrError.getError()}`)
}
@@ -25,4 +36,16 @@ export class GetRegularSubscriptionForUser implements UseCaseInterface<UserSubsc
return Result.ok(userSubscription)
}
private async getRegularSubscriptionForSharedSubscription(subscriptionId: number): Promise<Result<UserSubscription>> {
const userSubscription = await this.userSubscriptionRepository.findBySubscriptionIdAndType(
subscriptionId,
UserSubscriptionType.Regular,
)
if (userSubscription.length === 0) {
return Result.fail(`User subscription for shared subscription ${subscriptionId} not found.`)
}
return Result.ok(userSubscription[0])
}
}

View File

@@ -1,3 +1,4 @@
export interface GetRegularSubscriptionForUserDTO {
userUuid: string
userUuid?: string
subscriptionId?: number
}

View File

@@ -92,6 +92,7 @@ describe('SetSettingValue', () => {
userUuid: '00000000-0000-0000-0000-000000000000',
settingName: SettingName.NAMES.ListedAuthorSecrets,
value: 'value',
checkUserPermissions: true,
})
expect(result.isFailed()).toBe(true)
@@ -108,6 +109,7 @@ describe('SetSettingValue', () => {
userUuid: '00000000-0000-0000-0000-000000000000',
settingName: SettingName.NAMES.MfaSecret,
value: 'value',
checkUserPermissions: true,
})
expect(result.isFailed()).toBe(true)
@@ -140,6 +142,20 @@ describe('SetSettingValue', () => {
expect(settingRepository.update).toHaveBeenCalled()
})
it('should create a setting with checking user permissions', async () => {
const useCase = createUseCase()
const result = await useCase.execute({
userUuid: '00000000-0000-0000-0000-000000000000',
settingName: SettingName.NAMES.MfaSecret,
value: 'value',
checkUserPermissions: true,
})
expect(result.isFailed()).toBe(false)
expect(settingRepository.insert).toHaveBeenCalled()
})
it('should insert a new setting if one does not exist', async () => {
getSetting.execute = jest.fn().mockReturnValue(Result.fail('not found'))

View File

@@ -37,7 +37,7 @@ export class SetSettingValue implements UseCaseInterface<Setting> {
return Result.fail(`Setting ${settingName.value} is a subscription setting!`)
}
if (!(await this.userHasPermissionToUpdateSetting(userUuid, settingName))) {
if (dto.checkUserPermissions && !(await this.userHasPermissionToUpdateSetting(userUuid, settingName))) {
return Result.fail(`User ${userUuid.value} does not have permission to update setting ${settingName.value}.`)
}

View File

@@ -2,4 +2,5 @@ export interface SetSettingValueDTO {
settingName: string
userUuid: string
value: string | null
checkUserPermissions?: boolean
}

View File

@@ -31,9 +31,19 @@ export class UpdateStorageQuotaUsedForUser implements UseCaseInterface<void> {
return Result.fail(`Could not find user with uuid: ${userUuid.value}`)
}
const regularSubscriptionOrError = await this.getRegularSubscription.execute({
const sharedSubscriptionOrError = await this.getSharedSubscription.execute({
userUuid: user.uuid,
})
let sharedSubscription: UserSubscription | undefined
if (!sharedSubscriptionOrError.isFailed()) {
sharedSubscription = sharedSubscriptionOrError.getValue()
await this.updateUploadBytesUsedSetting(sharedSubscription, dto.bytesUsed)
}
const regularSubscriptionOrError = await this.getRegularSubscription.execute({
userUuid: sharedSubscription ? undefined : user.uuid,
subscriptionId: sharedSubscription ? (sharedSubscription.subscriptionId as number) : undefined,
})
if (regularSubscriptionOrError.isFailed()) {
return Result.fail(`Could not find regular user subscription for user with uuid: ${userUuid.value}`)
}
@@ -41,14 +51,6 @@ export class UpdateStorageQuotaUsedForUser implements UseCaseInterface<void> {
await this.updateUploadBytesUsedSetting(regularSubscription, dto.bytesUsed)
const sharedSubscriptionOrError = await this.getSharedSubscription.execute({
userUuid: user.uuid,
})
if (!sharedSubscriptionOrError.isFailed()) {
const sharedSubscription = sharedSubscriptionOrError.getValue()
await this.updateUploadBytesUsedSetting(sharedSubscription, dto.bytesUsed)
}
return Result.ok()
}

View File

@@ -160,6 +160,7 @@ export class BaseSettingsController extends BaseHttpController {
settingName: name,
value,
userUuid: response.locals.user.uuid,
checkUserPermissions: true,
})
if (result.isFailed()) {

View File

@@ -3,6 +3,12 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.20.3](https://github.com/standardnotes/server/compare/@standardnotes/domain-events-infra@1.20.2...@standardnotes/domain-events-infra@1.20.3) (2023-11-07)
### Bug Fixes
* remove open telemetry from code ([#903](https://github.com/standardnotes/server/issues/903)) ([751f3b2](https://github.com/standardnotes/server/commit/751f3b25476c5be3d663ad8540c43266acd39493))
## [1.20.2](https://github.com/standardnotes/server/compare/@standardnotes/domain-events-infra@1.20.1...@standardnotes/domain-events-infra@1.20.2) (2023-10-19)
**Note:** Version bump only for package @standardnotes/domain-events-infra

View File

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

View File

@@ -0,0 +1,36 @@
import { Consumer } from 'sqs-consumer'
import { Message, SQSClient } from '@aws-sdk/client-sqs'
import { DomainEventSubscriberInterface, DomainEventMessageHandlerInterface } from '@standardnotes/domain-events'
import { Logger } from 'winston'
export class SQSDomainEventSubscriber implements DomainEventSubscriberInterface {
constructor(
private sqs: SQSClient,
private queueUrl: string,
private domainEventMessageHandler: DomainEventMessageHandlerInterface,
private logger: Logger,
) {}
start(): void {
const sqsConsumer = Consumer.create({
attributeNames: ['All'],
messageAttributeNames: ['All'],
queueUrl: this.queueUrl,
sqs: this.sqs,
handleMessage: this.handleMessage.bind(this),
})
sqsConsumer.on('error', this.handleError.bind(this))
sqsConsumer.on('processing_error', this.handleError.bind(this))
sqsConsumer.start()
}
async handleMessage(message: Message): Promise<void> {
await this.domainEventMessageHandler.handleMessage(<string>message.Body)
}
handleError(error: Error): void {
this.logger.error('Error occured while handling SQS message: %O', error)
}
}

View File

@@ -15,6 +15,7 @@ export * from './SNS/SNSDomainEventPublisher'
export * from './SNS/SNSOpenTelemetryDomainEventPublisher'
export * from './SQS/SQSBounceNotificiationHandler'
export * from './SQS/SQSDomainEventSubscriber'
export * from './SQS/SQSDomainEventSubscriberFactory'
export * from './SQS/SQSEventMessageHandler'
export * from './SQS/SQSOpenTelemetryDomainEventSubscriber'

View File

@@ -3,6 +3,10 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.13.18](https://github.com/standardnotes/server/compare/@standardnotes/event-store@1.13.17...@standardnotes/event-store@1.13.18) (2023-11-07)
**Note:** Version bump only for package @standardnotes/event-store
## [1.13.17](https://github.com/standardnotes/server/compare/@standardnotes/event-store@1.13.16...@standardnotes/event-store@1.13.17) (2023-10-26)
**Note:** Version bump only for package @standardnotes/event-store

View File

@@ -1,6 +1,6 @@
{
"name": "@standardnotes/event-store",
"version": "1.13.17",
"version": "1.13.18",
"description": "Event Store Service",
"private": true,
"main": "dist/src/index.js",

View File

@@ -3,6 +3,18 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.32.4](https://github.com/standardnotes/files/compare/@standardnotes/files-server@1.32.3...@standardnotes/files-server@1.32.4) (2023-11-07)
### Bug Fixes
* remove open telemetry from code ([#903](https://github.com/standardnotes/files/issues/903)) ([751f3b2](https://github.com/standardnotes/files/commit/751f3b25476c5be3d663ad8540c43266acd39493))
## [1.32.3](https://github.com/standardnotes/files/compare/@standardnotes/files-server@1.32.2...@standardnotes/files-server@1.32.3) (2023-10-31)
### Bug Fixes
* add fallback methods for 404 requests ([#893](https://github.com/standardnotes/files/issues/893)) ([16a6815](https://github.com/standardnotes/files/commit/16a6815b69e344573ae07682f3bac1d44d715d79))
## [1.32.2](https://github.com/standardnotes/files/compare/@standardnotes/files-server@1.32.1...@standardnotes/files-server@1.32.2) (2023-10-26)
**Note:** Version bump only for package @standardnotes/files-server

View File

@@ -1,13 +1,8 @@
import 'reflect-metadata'
import { OpenTelemetrySDK } from '@standardnotes/domain-events-infra'
import { ServiceIdentifier } from '@standardnotes/domain-core'
const sdk = new OpenTelemetrySDK({ serviceName: ServiceIdentifier.NAMES.Files })
sdk.start()
import * as busboy from 'connect-busboy'
import '../src/Infra/InversifyExpress/AnnotatedFallbackController'
import '../src/Infra/InversifyExpress/AnnotatedHealthCheckController'
import '../src/Infra/InversifyExpress/AnnotatedFilesController'
import '../src/Infra/InversifyExpress/AnnotatedSharedVaultFilesController'

View File

@@ -1,11 +1,5 @@
import 'reflect-metadata'
import { OpenTelemetrySDK } from '@standardnotes/domain-events-infra'
import { ServiceIdentifier } from '@standardnotes/domain-core'
const sdk = new OpenTelemetrySDK({ serviceName: ServiceIdentifier.NAMES.FilesWorker })
sdk.start()
import { Logger } from 'winston'
import { ContainerConfigLoader } from '../src/Bootstrap/Container'

View File

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

View File

@@ -16,9 +16,9 @@ import { DomainEventFactory } from '../Domain/Event/DomainEventFactory'
import {
DirectCallDomainEventPublisher,
DirectCallEventMessageHandler,
SNSOpenTelemetryDomainEventPublisher,
SNSDomainEventPublisher,
SQSDomainEventSubscriber,
SQSEventMessageHandler,
SQSOpenTelemetryDomainEventSubscriber,
} from '@standardnotes/domain-events-infra'
import { StreamDownloadFile } from '../Domain/UseCase/StreamDownloadFile/StreamDownloadFile'
import { FileDownloaderInterface } from '../Domain/Services/FileDownloaderInterface'
@@ -52,7 +52,6 @@ import { S3FileMover } from '../Infra/S3/S3FileMover'
import { FSFileMover } from '../Infra/FS/FSFileMover'
import { MoveFile } from '../Domain/UseCase/MoveFile/MoveFile'
import { SharedVaultValetTokenAuthMiddleware } from '../Infra/InversifyExpress/Middleware/SharedVaultValetTokenAuthMiddleware'
import { ServiceIdentifier } from '@standardnotes/domain-core'
export class ContainerConfigLoader {
async load(configuration?: {
@@ -175,10 +174,7 @@ export class ContainerConfigLoader {
container
.bind<DomainEventPublisherInterface>(TYPES.Files_DomainEventPublisher)
.toConstantValue(
new SNSOpenTelemetryDomainEventPublisher(
container.get(TYPES.Files_SNS),
container.get(TYPES.Files_SNS_TOPIC_ARN),
),
new SNSDomainEventPublisher(container.get(TYPES.Files_SNS), container.get(TYPES.Files_SNS_TOPIC_ARN)),
)
}
@@ -301,8 +297,7 @@ export class ContainerConfigLoader {
container
.bind<DomainEventSubscriberInterface>(TYPES.Files_DomainEventSubscriber)
.toConstantValue(
new SQSOpenTelemetryDomainEventSubscriber(
ServiceIdentifier.NAMES.FilesWorker,
new SQSDomainEventSubscriber(
container.get<SQSClient>(TYPES.Files_SQS),
container.get<string>(TYPES.Files_SQS_QUEUE_URL),
container.get<DomainEventMessageHandlerInterface>(TYPES.Files_DomainEventMessageHandler),

View File

@@ -0,0 +1,9 @@
import { BaseHttpController, all, controller, results } from 'inversify-express-utils'
@controller('')
export class AnnotatedFallbackController extends BaseHttpController {
@all('*')
public async fallback(): Promise<results.NotFoundResult> {
return this.notFound()
}
}

View File

@@ -3,6 +3,60 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.18.22](https://github.com/standardnotes/server/compare/@standardnotes/home-server@1.18.21...@standardnotes/home-server@1.18.22) (2023-11-07)
**Note:** Version bump only for package @standardnotes/home-server
## [1.18.21](https://github.com/standardnotes/server/compare/@standardnotes/home-server@1.18.20...@standardnotes/home-server@1.18.21) (2023-11-06)
**Note:** Version bump only for package @standardnotes/home-server
## [1.18.20](https://github.com/standardnotes/server/compare/@standardnotes/home-server@1.18.19...@standardnotes/home-server@1.18.20) (2023-11-03)
**Note:** Version bump only for package @standardnotes/home-server
## [1.18.19](https://github.com/standardnotes/server/compare/@standardnotes/home-server@1.18.18...@standardnotes/home-server@1.18.19) (2023-11-03)
**Note:** Version bump only for package @standardnotes/home-server
## [1.18.18](https://github.com/standardnotes/server/compare/@standardnotes/home-server@1.18.17...@standardnotes/home-server@1.18.18) (2023-11-02)
**Note:** Version bump only for package @standardnotes/home-server
## [1.18.17](https://github.com/standardnotes/server/compare/@standardnotes/home-server@1.18.16...@standardnotes/home-server@1.18.17) (2023-11-02)
### Bug Fixes
* **home-server:** remove unused dep ([2e5b910](https://github.com/standardnotes/server/commit/2e5b9105b8462385f060ed5a4ff8301c675e81b2))
## [1.18.16](https://github.com/standardnotes/server/compare/@standardnotes/home-server@1.18.15...@standardnotes/home-server@1.18.16) (2023-11-01)
**Note:** Version bump only for package @standardnotes/home-server
## [1.18.15](https://github.com/standardnotes/server/compare/@standardnotes/home-server@1.18.14...@standardnotes/home-server@1.18.15) (2023-11-01)
**Note:** Version bump only for package @standardnotes/home-server
## [1.18.14](https://github.com/standardnotes/server/compare/@standardnotes/home-server@1.18.13...@standardnotes/home-server@1.18.14) (2023-11-01)
**Note:** Version bump only for package @standardnotes/home-server
## [1.18.13](https://github.com/standardnotes/server/compare/@standardnotes/home-server@1.18.12...@standardnotes/home-server@1.18.13) (2023-10-31)
**Note:** Version bump only for package @standardnotes/home-server
## [1.18.12](https://github.com/standardnotes/server/compare/@standardnotes/home-server@1.18.11...@standardnotes/home-server@1.18.12) (2023-10-30)
**Note:** Version bump only for package @standardnotes/home-server
## [1.18.11](https://github.com/standardnotes/server/compare/@standardnotes/home-server@1.18.10...@standardnotes/home-server@1.18.11) (2023-10-30)
**Note:** Version bump only for package @standardnotes/home-server
## [1.18.10](https://github.com/standardnotes/server/compare/@standardnotes/home-server@1.18.9...@standardnotes/home-server@1.18.10) (2023-10-27)
**Note:** Version bump only for package @standardnotes/home-server
## [1.18.9](https://github.com/standardnotes/server/compare/@standardnotes/home-server@1.18.8...@standardnotes/home-server@1.18.9) (2023-10-26)
**Note:** Version bump only for package @standardnotes/home-server

View File

@@ -1,6 +1,6 @@
{
"name": "@standardnotes/home-server",
"version": "1.18.9",
"version": "1.18.22",
"engines": {
"node": ">=18.0.0 <21.0.0"
},
@@ -35,14 +35,12 @@
"helmet": "^7.0.0",
"inversify": "^6.0.1",
"inversify-express-utils": "^6.4.3",
"prettyjson": "^1.2.5",
"reflect-metadata": "0.1.13",
"winston": "^3.8.1"
},
"devDependencies": {
"@types/cors": "^2.8.9",
"@types/express": "^4.17.14",
"@types/prettyjson": "^0.0.30",
"@typescript-eslint/eslint-plugin": "^6.5.0",
"@typescript-eslint/parser": "^6.5.0",
"eslint": "^8.39.0",

View File

@@ -3,6 +3,12 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.47.4](https://github.com/standardnotes/server/compare/@standardnotes/revisions-server@1.47.3...@standardnotes/revisions-server@1.47.4) (2023-11-07)
### Bug Fixes
* remove open telemetry from code ([#903](https://github.com/standardnotes/server/issues/903)) ([751f3b2](https://github.com/standardnotes/server/commit/751f3b25476c5be3d663ad8540c43266acd39493))
## [1.47.3](https://github.com/standardnotes/server/compare/@standardnotes/revisions-server@1.47.2...@standardnotes/revisions-server@1.47.3) (2023-10-26)
**Note:** Version bump only for package @standardnotes/revisions-server

View File

@@ -1,11 +1,5 @@
import 'reflect-metadata'
import { OpenTelemetrySDK } from '@standardnotes/domain-events-infra'
import { ServiceIdentifier } from '@standardnotes/domain-core'
const sdk = new OpenTelemetrySDK({ serviceName: ServiceIdentifier.NAMES.Revisions })
sdk.start()
import * as cors from 'cors'
import { urlencoded, json, Request, Response, NextFunction } from 'express'
import * as winston from 'winston'

View File

@@ -1,11 +1,5 @@
import 'reflect-metadata'
import { OpenTelemetrySDK } from '@standardnotes/domain-events-infra'
import { ServiceIdentifier } from '@standardnotes/domain-core'
const sdk = new OpenTelemetrySDK({ serviceName: ServiceIdentifier.NAMES.RevisionsWorker })
sdk.start()
import { Logger } from 'winston'
import TYPES from '../src/Bootstrap/Types'

View File

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

View File

@@ -1,9 +1,4 @@
import {
ControllerContainer,
ControllerContainerInterface,
MapperInterface,
ServiceIdentifier,
} from '@standardnotes/domain-core'
import { ControllerContainer, ControllerContainerInterface, MapperInterface } from '@standardnotes/domain-core'
import { Container, interfaces } from 'inversify'
import { Repository } from 'typeorm'
import * as winston from 'winston'
@@ -34,7 +29,7 @@ import {
SQSEventMessageHandler,
DirectCallEventMessageHandler,
DirectCallDomainEventPublisher,
SQSOpenTelemetryDomainEventSubscriber,
SQSDomainEventSubscriber,
} from '@standardnotes/domain-events-infra'
import { DumpRepositoryInterface } from '../Domain/Dump/DumpRepositoryInterface'
import { AccountDeletionRequestedEventHandler } from '../Domain/Handler/AccountDeletionRequestedEventHandler'
@@ -342,8 +337,7 @@ export class ContainerConfigLoader {
container
.bind<DomainEventSubscriberInterface>(TYPES.Revisions_DomainEventSubscriber)
.toConstantValue(
new SQSOpenTelemetryDomainEventSubscriber(
ServiceIdentifier.NAMES.RevisionsWorker,
new SQSDomainEventSubscriber(
container.get<SQSClient>(TYPES.Revisions_SQS),
container.get<string>(TYPES.Revisions_SQS_QUEUE_URL),
container.get<DomainEventMessageHandlerInterface>(TYPES.Revisions_DomainEventMessageHandler),

View File

@@ -3,6 +3,12 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.26.5](https://github.com/standardnotes/server/compare/@standardnotes/scheduler-server@1.26.4...@standardnotes/scheduler-server@1.26.5) (2023-11-07)
### Bug Fixes
* remove open telemetry from code ([#903](https://github.com/standardnotes/server/issues/903)) ([751f3b2](https://github.com/standardnotes/server/commit/751f3b25476c5be3d663ad8540c43266acd39493))
## [1.26.4](https://github.com/standardnotes/server/compare/@standardnotes/scheduler-server@1.26.3...@standardnotes/scheduler-server@1.26.4) (2023-10-26)
**Note:** Version bump only for package @standardnotes/scheduler-server

View File

@@ -1,11 +1,5 @@
import 'reflect-metadata'
import { OpenTelemetrySDK, OpenTelemetryTracer } from '@standardnotes/domain-events-infra'
import { ServiceIdentifier } from '@standardnotes/domain-core'
const sdk = new OpenTelemetrySDK({ serviceName: ServiceIdentifier.NAMES.SchedulerScheduledTask })
sdk.start()
import { Logger } from 'winston'
import * as dayjs from 'dayjs'
import * as utc from 'dayjs/plugin/utc'
@@ -35,22 +29,15 @@ void container.load().then((container) => {
const verifyPredicates: VerifyPredicates = container.get(TYPES.VerifyPredicates)
const tracer = new OpenTelemetryTracer()
tracer.startSpan(ServiceIdentifier.NAMES.SchedulerScheduledTask, 'verify')
Promise.resolve(verifyJobs(now, verifyPredicates))
.then(() => {
logger.info('Verification of overdue jobs complete.')
tracer.stopSpan()
process.exit(0)
})
.catch((error) => {
logger.error(`Could not finish verification of overdue jobs: ${error.message}`)
tracer.stopSpanWithError(error)
process.exit(1)
})
})

View File

@@ -1,11 +1,5 @@
import 'reflect-metadata'
import { OpenTelemetrySDK } from '@standardnotes/domain-events-infra'
import { ServiceIdentifier } from '@standardnotes/domain-core'
const sdk = new OpenTelemetrySDK({ serviceName: ServiceIdentifier.NAMES.SchedulerWorker })
sdk.start()
import { Logger } from 'winston'
import { DomainEventSubscriberInterface } from '@standardnotes/domain-events'
import * as dayjs from 'dayjs'

View File

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

View File

@@ -15,9 +15,9 @@ import TYPES from './Types'
import { AppDataSource } from './DataSource'
import { DomainEventFactory } from '../Domain/Event/DomainEventFactory'
import {
SNSOpenTelemetryDomainEventPublisher,
SNSDomainEventPublisher,
SQSDomainEventSubscriber,
SQSEventMessageHandler,
SQSOpenTelemetryDomainEventSubscriber,
} from '@standardnotes/domain-events-infra'
import { Timer, TimerInterface } from '@standardnotes/time'
import { PredicateRepositoryInterface } from '../Domain/Predicate/PredicateRepositoryInterface'
@@ -35,7 +35,6 @@ import { VerifyPredicates } from '../Domain/UseCase/VerifyPredicates/VerifyPredi
import { UserRegisteredEventHandler } from '../Domain/Handler/UserRegisteredEventHandler'
import { SubscriptionCancelledEventHandler } from '../Domain/Handler/SubscriptionCancelledEventHandler'
import { ExitDiscountAppliedEventHandler } from '../Domain/Handler/ExitDiscountAppliedEventHandler'
import { ServiceIdentifier } from '@standardnotes/domain-core'
export class ContainerConfigLoader {
async load(): Promise<Container> {
@@ -136,9 +135,7 @@ export class ContainerConfigLoader {
container
.bind<DomainEventPublisherInterface>(TYPES.DomainEventPublisher)
.toConstantValue(
new SNSOpenTelemetryDomainEventPublisher(container.get(TYPES.SNS), container.get(TYPES.SNS_TOPIC_ARN)),
)
.toConstantValue(new SNSDomainEventPublisher(container.get(TYPES.SNS), container.get(TYPES.SNS_TOPIC_ARN)))
const eventHandlers: Map<string, DomainEventHandlerInterface> = new Map([
['PREDICATE_VERIFIED', container.get(TYPES.PredicateVerifiedEventHandler)],
@@ -153,8 +150,7 @@ export class ContainerConfigLoader {
container
.bind<DomainEventSubscriberInterface>(TYPES.DomainEventSubscriber)
.toConstantValue(
new SQSOpenTelemetryDomainEventSubscriber(
ServiceIdentifier.NAMES.SchedulerWorker,
new SQSDomainEventSubscriber(
container.get<SQSClient>(TYPES.SQS),
container.get<string>(TYPES.SQS_QUEUE_URL),
container.get<DomainEventMessageHandlerInterface>(TYPES.DomainEventMessageHandler),

View File

@@ -3,6 +3,30 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.120.2](https://github.com/standardnotes/syncing-server-js/compare/@standardnotes/syncing-server@1.120.1...@standardnotes/syncing-server@1.120.2) (2023-11-07)
### Bug Fixes
* remove open telemetry from code ([#903](https://github.com/standardnotes/syncing-server-js/issues/903)) ([751f3b2](https://github.com/standardnotes/syncing-server-js/commit/751f3b25476c5be3d663ad8540c43266acd39493))
## [1.120.1](https://github.com/standardnotes/syncing-server-js/compare/@standardnotes/syncing-server@1.120.0...@standardnotes/syncing-server@1.120.1) (2023-11-06)
### Bug Fixes
* **syncing-server:** return cursor token upon transfer limit breached ([#902](https://github.com/standardnotes/syncing-server-js/issues/902)) ([71689c1](https://github.com/standardnotes/syncing-server-js/commit/71689c1497728569fc6a07e21fa7bdba68c1bac0))
# [1.120.0](https://github.com/standardnotes/syncing-server-js/compare/@standardnotes/syncing-server@1.119.4...@standardnotes/syncing-server@1.120.0) (2023-11-02)
### Features
* add shared vault invitation email notifications ([#897](https://github.com/standardnotes/syncing-server-js/issues/897)) ([7253a0a](https://github.com/standardnotes/syncing-server-js/commit/7253a0a1d92099df844c9baf6541b440bbcb0a68))
## [1.119.4](https://github.com/standardnotes/syncing-server-js/compare/@standardnotes/syncing-server@1.119.3...@standardnotes/syncing-server@1.119.4) (2023-10-31)
### Bug Fixes
* add fallback methods for 404 requests ([#893](https://github.com/standardnotes/syncing-server-js/issues/893)) ([16a6815](https://github.com/standardnotes/syncing-server-js/commit/16a6815b69e344573ae07682f3bac1d44d715d79))
## [1.119.3](https://github.com/standardnotes/syncing-server-js/compare/@standardnotes/syncing-server@1.119.2...@standardnotes/syncing-server@1.119.3) (2023-10-26)
**Note:** Version bump only for package @standardnotes/syncing-server

View File

@@ -1,11 +1,6 @@
import 'reflect-metadata'
import { OpenTelemetrySDK } from '@standardnotes/domain-events-infra'
import { ServiceIdentifier } from '@standardnotes/domain-core'
const sdk = new OpenTelemetrySDK({ serviceName: ServiceIdentifier.NAMES.SyncingServer })
sdk.start()
import '../src/Infra/InversifyExpressUtils/AnnotatedFallbackController'
import '../src/Infra/InversifyExpressUtils/AnnotatedHealthCheckController'
import '../src/Infra/InversifyExpressUtils/AnnotatedItemsController'
import '../src/Infra/InversifyExpressUtils/AnnotatedMessagesController'

View File

@@ -1,11 +1,5 @@
import 'reflect-metadata'
import { OpenTelemetrySDK } from '@standardnotes/domain-events-infra'
import { ServiceIdentifier } from '@standardnotes/domain-core'
const sdk = new OpenTelemetrySDK({ serviceName: ServiceIdentifier.NAMES.SyncingServerWorker })
sdk.start()
import { Logger } from 'winston'
import TYPES from '../src/Bootstrap/Types'

View File

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

View File

@@ -11,9 +11,9 @@ import { Item } from '../Domain/Item/Item'
import {
DirectCallDomainEventPublisher,
DirectCallEventMessageHandler,
SNSOpenTelemetryDomainEventPublisher,
SNSDomainEventPublisher,
SQSDomainEventSubscriber,
SQSEventMessageHandler,
SQSOpenTelemetryDomainEventSubscriber,
} from '@standardnotes/domain-events-infra'
import { DomainEventFactoryInterface } from '../Domain/Event/DomainEventFactoryInterface'
import { DomainEventFactory } from '../Domain/Event/DomainEventFactory'
@@ -58,7 +58,6 @@ import {
ControllerContainer,
ControllerContainerInterface,
MapperInterface,
ServiceIdentifier,
SharedVaultUser,
} from '@standardnotes/domain-core'
import { BaseItemsController } from '../Infra/InversifyExpressUtils/Base/BaseItemsController'
@@ -252,7 +251,7 @@ export class ContainerConfigLoader {
container
.bind<DomainEventPublisherInterface>(TYPES.Sync_DomainEventPublisher)
.toDynamicValue((context: interfaces.Context) => {
return new SNSOpenTelemetryDomainEventPublisher(
return new SNSDomainEventPublisher(
context.container.get(TYPES.Sync_SNS),
context.container.get(TYPES.Sync_SNS_TOPIC_ARN),
)
@@ -652,6 +651,7 @@ export class ContainerConfigLoader {
container.get<SharedVaultUserRepositoryInterface>(TYPES.Sync_SharedVaultUserRepository),
container.get<TimerInterface>(TYPES.Sync_Timer),
container.get<DomainEventFactoryInterface>(TYPES.Sync_DomainEventFactory),
container.get<DomainEventPublisherInterface>(TYPES.Sync_DomainEventPublisher),
container.get<SendEventToClient>(TYPES.Sync_SendEventToClient),
container.get<Logger>(TYPES.Sync_Logger),
),
@@ -1021,8 +1021,7 @@ export class ContainerConfigLoader {
container
.bind<DomainEventSubscriberInterface>(TYPES.Sync_DomainEventSubscriber)
.toConstantValue(
new SQSOpenTelemetryDomainEventSubscriber(
ServiceIdentifier.NAMES.SyncingServerWorker,
new SQSDomainEventSubscriber(
container.get<SQSClient>(TYPES.Sync_SQS),
container.get<string>(TYPES.Sync_SQS_QUEUE_URL),
container.get<DomainEventMessageHandlerInterface>(TYPES.Sync_DomainEventMessageHandler),

View File

@@ -25,11 +25,14 @@ describe('ItemTransferCalculator', () => {
const result = await createCalculator().computeItemUuidsToFetch(itemContentSizeDescriptors, 50)
expect(result).toEqual([
'00000000-0000-0000-0000-000000000000',
'00000000-0000-0000-0000-000000000001',
'00000000-0000-0000-0000-000000000002',
])
expect(result).toEqual({
uuids: [
'00000000-0000-0000-0000-000000000000',
'00000000-0000-0000-0000-000000000001',
'00000000-0000-0000-0000-000000000002',
],
transferLimitBreachedBeforeEndOfItems: false,
})
})
it('should compute uuids to fetch based on transfer limit - exact limit fit', async () => {
@@ -41,7 +44,10 @@ describe('ItemTransferCalculator', () => {
const result = await createCalculator().computeItemUuidsToFetch(itemContentSizeDescriptors, 40)
expect(result).toEqual(['00000000-0000-0000-0000-000000000000', '00000000-0000-0000-0000-000000000001'])
expect(result).toEqual({
uuids: ['00000000-0000-0000-0000-000000000000', '00000000-0000-0000-0000-000000000001'],
transferLimitBreachedBeforeEndOfItems: true,
})
})
it('should compute uuids to fetch based on transfer limit - content size not defined on an item', async () => {
@@ -53,11 +59,14 @@ describe('ItemTransferCalculator', () => {
const result = await createCalculator().computeItemUuidsToFetch(itemContentSizeDescriptors, 50)
expect(result).toEqual([
'00000000-0000-0000-0000-000000000000',
'00000000-0000-0000-0000-000000000001',
'00000000-0000-0000-0000-000000000002',
])
expect(result).toEqual({
uuids: [
'00000000-0000-0000-0000-000000000000',
'00000000-0000-0000-0000-000000000001',
'00000000-0000-0000-0000-000000000002',
],
transferLimitBreachedBeforeEndOfItems: false,
})
})
it('should compute uuids to fetch based on transfer limit - first item over the limit', async () => {
@@ -69,7 +78,10 @@ describe('ItemTransferCalculator', () => {
const result = await createCalculator().computeItemUuidsToFetch(itemContentSizeDescriptors, 40)
expect(result).toEqual(['00000000-0000-0000-0000-000000000000', '00000000-0000-0000-0000-000000000001'])
expect(result).toEqual({
uuids: ['00000000-0000-0000-0000-000000000000', '00000000-0000-0000-0000-000000000001'],
transferLimitBreachedBeforeEndOfItems: true,
})
})
})

View File

@@ -9,16 +9,17 @@ export class ItemTransferCalculator implements ItemTransferCalculatorInterface {
async computeItemUuidsToFetch(
itemContentSizeDescriptors: ItemContentSizeDescriptor[],
bytesTransferLimit: number,
): Promise<Array<string>> {
): Promise<{ uuids: Array<string>; transferLimitBreachedBeforeEndOfItems: boolean }> {
const itemUuidsToFetch = []
let totalContentSizeInBytes = 0
let transferLimitBreached = false
for (const itemContentSize of itemContentSizeDescriptors) {
const contentSize = itemContentSize.props.contentSize ?? 0
itemUuidsToFetch.push(itemContentSize.props.uuid.value)
totalContentSizeInBytes += contentSize
const transferLimitBreached = this.isTransferLimitBreached({
transferLimitBreached = this.isTransferLimitBreached({
totalContentSizeInBytes,
bytesTransferLimit,
itemUuidsToFetch,
@@ -30,7 +31,11 @@ export class ItemTransferCalculator implements ItemTransferCalculatorInterface {
}
}
return itemUuidsToFetch
return {
uuids: itemUuidsToFetch,
transferLimitBreachedBeforeEndOfItems:
transferLimitBreached && itemUuidsToFetch.length < itemContentSizeDescriptors.length,
}
}
async computeItemUuidBundlesToFetch(

View File

@@ -4,7 +4,7 @@ export interface ItemTransferCalculatorInterface {
computeItemUuidsToFetch(
itemContentSizeDescriptors: ItemContentSizeDescriptor[],
bytesTransferLimit: number,
): Promise<Array<string>>
): Promise<{ uuids: Array<string>; transferLimitBreachedBeforeEndOfItems: boolean }>
computeItemUuidBundlesToFetch(
itemContentSizeDescriptors: ItemContentSizeDescriptor[],
bytesTransferLimit: number,

View File

@@ -1,6 +1,6 @@
import { TimerInterface } from '@standardnotes/time'
import { Uuid, Timestamps, Result, SharedVaultUserPermission, SharedVaultUser } from '@standardnotes/domain-core'
import { UserInvitedToSharedVaultEvent } from '@standardnotes/domain-events'
import { DomainEventPublisherInterface, UserInvitedToSharedVaultEvent } from '@standardnotes/domain-events'
import { Logger } from 'winston'
import { SharedVaultRepositoryInterface } from '../../../SharedVault/SharedVaultRepositoryInterface'
@@ -20,6 +20,7 @@ describe('InviteUserToSharedVault', () => {
let sharedVault: SharedVault
let sharedVaultUser: SharedVaultUser
let domainEventFactory: DomainEventFactoryInterface
let domainEventPublisher: DomainEventPublisherInterface
let sendEventToClientUseCase: SendEventToClient
let logger: Logger
@@ -30,6 +31,7 @@ describe('InviteUserToSharedVault', () => {
sharedVaultUserRepository,
timer,
domainEventFactory,
domainEventPublisher,
sendEventToClientUseCase,
logger,
)
@@ -67,6 +69,9 @@ describe('InviteUserToSharedVault', () => {
type: 'USER_INVITED_TO_SHARED_VAULT',
} as jest.Mocked<UserInvitedToSharedVaultEvent>)
domainEventPublisher = {} as jest.Mocked<DomainEventPublisherInterface>
domainEventPublisher.publish = jest.fn()
sendEventToClientUseCase = {} as jest.Mocked<SendEventToClient>
sendEventToClientUseCase.execute = jest.fn().mockReturnValue(Result.ok())

View File

@@ -9,6 +9,7 @@ import { SharedVaultUserRepositoryInterface } from '../../../SharedVault/User/Sh
import { Logger } from 'winston'
import { DomainEventFactoryInterface } from '../../../Event/DomainEventFactoryInterface'
import { SendEventToClient } from '../../Syncing/SendEventToClient/SendEventToClient'
import { DomainEventPublisherInterface } from '@standardnotes/domain-events'
export class InviteUserToSharedVault implements UseCaseInterface<SharedVaultInvite> {
constructor(
@@ -17,6 +18,7 @@ export class InviteUserToSharedVault implements UseCaseInterface<SharedVaultInvi
private sharedVaultUserRepository: SharedVaultUserRepositoryInterface,
private timer: TimerInterface,
private domainEventFactory: DomainEventFactoryInterface,
private domainEventPublisher: DomainEventPublisherInterface,
private sendEventToClientUseCase: SendEventToClient,
private logger: Logger,
) {}
@@ -101,6 +103,8 @@ export class InviteUserToSharedVault implements UseCaseInterface<SharedVaultInvi
},
})
await this.domainEventPublisher.publish(event)
const result = await this.sendEventToClientUseCase.execute({
userUuid: sharedVaultInvite.props.userUuid.value,
event,

View File

@@ -49,7 +49,9 @@ describe('GetItems', () => {
.mockResolvedValue([ItemContentSizeDescriptor.create('00000000-0000-0000-0000-000000000000', 20).getValue()])
itemTransferCalculator = {} as jest.Mocked<ItemTransferCalculatorInterface>
itemTransferCalculator.computeItemUuidsToFetch = jest.fn().mockResolvedValue(['item-uuid'])
itemTransferCalculator.computeItemUuidsToFetch = jest
.fn()
.mockResolvedValue({ uuids: ['item-uuid'], transferLimitBreachedBeforeEndOfItems: false })
timer = {} as jest.Mocked<TimerInterface>
timer.getTimestampInMicroseconds = jest.fn().mockReturnValue(123)

View File

@@ -60,22 +60,22 @@ export class GetItems implements UseCaseInterface<GetItemsResult> {
}
const itemContentSizeDescriptors = await this.itemRepository.findContentSizeForComputingTransferLimit(itemQuery)
const itemUuidsToFetch = await this.itemTransferCalculator.computeItemUuidsToFetch(
const { uuids, transferLimitBreachedBeforeEndOfItems } = await this.itemTransferCalculator.computeItemUuidsToFetch(
itemContentSizeDescriptors,
this.contentSizeTransferLimit,
)
let items: Array<Item> = []
if (itemUuidsToFetch.length > 0) {
if (uuids.length > 0) {
items = await this.itemRepository.findAll({
uuids: itemUuidsToFetch,
uuids,
sortBy: 'updated_at_timestamp',
sortOrder: 'ASC',
})
}
const totalItemsCount = await this.itemRepository.countAll(itemQuery)
let cursorToken = undefined
if (totalItemsCount > upperBoundLimit) {
const thereAreStillMoreItemsToFetch = await this.stillMoreItemsToFetch(itemQuery, upperBoundLimit)
if (transferLimitBreachedBeforeEndOfItems || thereAreStillMoreItemsToFetch) {
const lastSyncTime = items[items.length - 1].props.timestamps.updatedAt / Time.MicrosecondsInASecond
cursorToken = Buffer.from(`${this.SYNC_TOKEN_VERSION}:${lastSyncTime}`, 'utf-8').toString('base64')
}
@@ -87,6 +87,12 @@ export class GetItems implements UseCaseInterface<GetItemsResult> {
})
}
private async stillMoreItemsToFetch(itemQuery: ItemQuery, upperBoundLimit: number): Promise<boolean> {
const totalItemsCount = await this.itemRepository.countAll(itemQuery)
return totalItemsCount > upperBoundLimit
}
private getLastSyncTime(dto: GetItemsDTO): Result<number | null> {
let token = dto.syncToken
if (dto.cursorToken !== undefined && dto.cursorToken !== null) {

View File

@@ -0,0 +1,9 @@
import { BaseHttpController, all, controller, results } from 'inversify-express-utils'
@controller('')
export class AnnotatedFallbackController extends BaseHttpController {
@all('*')
public async fallback(): Promise<results.NotFoundResult> {
return this.notFound()
}
}

View File

@@ -3,6 +3,12 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.17.5](https://github.com/standardnotes/server/compare/@standardnotes/websockets-server@1.17.4...@standardnotes/websockets-server@1.17.5) (2023-11-07)
### Bug Fixes
* remove open telemetry from code ([#903](https://github.com/standardnotes/server/issues/903)) ([751f3b2](https://github.com/standardnotes/server/commit/751f3b25476c5be3d663ad8540c43266acd39493))
## [1.17.4](https://github.com/standardnotes/server/compare/@standardnotes/websockets-server@1.17.3...@standardnotes/websockets-server@1.17.4) (2023-10-26)
**Note:** Version bump only for package @standardnotes/websockets-server

View File

@@ -1,11 +1,5 @@
import 'reflect-metadata'
import { OpenTelemetrySDK } from '@standardnotes/domain-events-infra'
import { ServiceIdentifier } from '@standardnotes/domain-core'
const sdk = new OpenTelemetrySDK({ serviceName: ServiceIdentifier.NAMES.Websockets })
sdk.start()
import '../src/Infra/InversifyExpressUtils/AnnotatedHealthCheckController'
import '../src/Infra/InversifyExpressUtils/AnnotatedWebSocketsController'

View File

@@ -1,11 +1,5 @@
import 'reflect-metadata'
import { OpenTelemetrySDK } from '@standardnotes/domain-events-infra'
import { ServiceIdentifier } from '@standardnotes/domain-core'
const sdk = new OpenTelemetrySDK({ serviceName: ServiceIdentifier.NAMES.WebsocketsWorker })
sdk.start()
import { Logger } from 'winston'
import { ContainerConfigLoader } from '../src/Bootstrap/Container'

View File

@@ -1,6 +1,6 @@
{
"name": "@standardnotes/websockets-server",
"version": "1.17.4",
"version": "1.17.5",
"engines": {
"node": ">=18.0.0 <21.0.0"
},

View File

@@ -18,7 +18,7 @@ import { RedisWebSocketsConnectionRepository } from '../Infra/Redis/RedisWebSock
import { AddWebSocketsConnection } from '../Domain/UseCase/AddWebSocketsConnection/AddWebSocketsConnection'
import { RemoveWebSocketsConnection } from '../Domain/UseCase/RemoveWebSocketsConnection/RemoveWebSocketsConnection'
import { WebSocketsClientMessenger } from '../Infra/WebSockets/WebSocketsClientMessenger'
import { SQSEventMessageHandler, SQSOpenTelemetryDomainEventSubscriber } from '@standardnotes/domain-events-infra'
import { SQSDomainEventSubscriber, SQSEventMessageHandler } from '@standardnotes/domain-events-infra'
import { ApiGatewayAuthMiddleware } from '../Controller/ApiGatewayAuthMiddleware'
import {
@@ -34,7 +34,6 @@ import { WebSocketsController } from '../Controller/WebSocketsController'
import { WebSocketServerInterface } from '@standardnotes/api'
import { ClientMessengerInterface } from '../Client/ClientMessengerInterface'
import { WebSocketMessageRequestedEventHandler } from '../Domain/Handler/WebSocketMessageRequestedEventHandler'
import { ServiceIdentifier } from '@standardnotes/domain-core'
export class ContainerConfigLoader {
async load(): Promise<Container> {
@@ -145,8 +144,7 @@ export class ContainerConfigLoader {
container
.bind<DomainEventSubscriberInterface>(TYPES.DomainEventSubscriber)
.toConstantValue(
new SQSOpenTelemetryDomainEventSubscriber(
ServiceIdentifier.NAMES.WebsocketsWorker,
new SQSDomainEventSubscriber(
container.get<SQSClient>(TYPES.SQS),
container.get<string>(TYPES.SQS_QUEUE_URL),
container.get<DomainEventMessageHandlerInterface>(TYPES.DomainEventMessageHandler),

View File

@@ -4588,7 +4588,6 @@ __metadata:
"@standardnotes/syncing-server": "workspace:^"
"@types/cors": "npm:^2.8.9"
"@types/express": "npm:^4.17.14"
"@types/prettyjson": "npm:^0.0.30"
"@typescript-eslint/eslint-plugin": "npm:^6.5.0"
"@typescript-eslint/parser": "npm:^6.5.0"
cors: "npm:2.8.5"
@@ -4601,7 +4600,6 @@ __metadata:
inversify: "npm:^6.0.1"
inversify-express-utils: "npm:^6.4.3"
prettier: "npm:^3.0.3"
prettyjson: "npm:^1.2.5"
reflect-metadata: "npm:0.1.13"
typescript: "npm:^5.0.4"
winston: "npm:^3.8.1"
@@ -13486,9 +13484,9 @@ __metadata:
linkType: hard
"ua-parser-js@npm:^1.0.35":
version: 1.0.35
resolution: "ua-parser-js@npm:1.0.35"
checksum: b69c99c20f90e1d441939be591a3e4c848d12b88671953fc0de7664bdcdb660f4e9db236099ae966cfb20504d8894825bbdee0fcc31326f2823bf439eadfc02c
version: 1.0.37
resolution: "ua-parser-js@npm:1.0.37"
checksum: 56508f2428ebac64382c4d41da14189e5013e3e2a5f5918aff4bee3ba77df1f4eaad6f81f90c24999f1cf12cc1596764684497fec07e0ff5182ce9a323a8c05b
languageName: node
linkType: hard