mirror of
https://github.com/standardnotes/server
synced 2026-05-13 00:57:17 -04:00
Compare commits
41 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| ce081274da | |||
| fd997f4849 | |||
| 3ddd671c47 | |||
| c19de13cac | |||
| f65809ef30 | |||
| 2823ed8612 | |||
| 420bf9ec54 | |||
| 5f67e5efda | |||
| daed1a77a0 | |||
| b39eb09d91 | |||
| f6ec8626e5 | |||
| 97b12f2131 | |||
| 8e4e36513a | |||
| c8bf4ab3a0 | |||
| 3fa01a328b | |||
| 60686dcdbd | |||
| fddd17e531 | |||
| f99750169f | |||
| daad76d0dd | |||
| b3542e2fab | |||
| a9b1543e20 | |||
| e6d8e5c5f2 | |||
| c24353cc24 | |||
| 4855e1d5f5 | |||
| 5d3fb9a537 | |||
| b55d80a7cd | |||
| 16f92bdc99 | |||
| 4c5738416a | |||
| 45d4920e0f | |||
| 94e738532a | |||
| c4ae12d53f | |||
| 4ff78452f9 | |||
| 9465f2ecd8 | |||
| 93c2f1f12f | |||
| ca8a3fc77d | |||
| 00936e06bc | |||
| a6dea50d74 | |||
| 28b04e6a4a | |||
| d228a86f48 | |||
| 0cb234aa47 | |||
| 6b554c28b7 |
@@ -61,13 +61,6 @@ updates:
|
|||||||
allow:
|
allow:
|
||||||
- dependency-type: "direct"
|
- dependency-type: "direct"
|
||||||
|
|
||||||
- package-ecosystem: "npm"
|
|
||||||
directory: "/packages/event-store"
|
|
||||||
schedule:
|
|
||||||
interval: "daily"
|
|
||||||
allow:
|
|
||||||
- dependency-type: "direct"
|
|
||||||
|
|
||||||
- package-ecosystem: "npm"
|
- package-ecosystem: "npm"
|
||||||
directory: "/packages/files"
|
directory: "/packages/files"
|
||||||
schedule:
|
schedule:
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
Binary file not shown.
BIN
Binary file not shown.
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
Binary file not shown.
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -3,6 +3,20 @@
|
|||||||
All notable changes to this project will be documented in this file.
|
All notable changes to this project will be documented in this file.
|
||||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||||
|
|
||||||
|
## [2.33.2](https://github.com/standardnotes/server/compare/@standardnotes/analytics@2.33.1...@standardnotes/analytics@2.33.2) (2023-11-13)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @standardnotes/analytics
|
||||||
|
|
||||||
|
## [2.33.1](https://github.com/standardnotes/server/compare/@standardnotes/analytics@2.33.0...@standardnotes/analytics@2.33.1) (2023-11-13)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @standardnotes/analytics
|
||||||
|
|
||||||
|
# [2.33.0](https://github.com/standardnotes/server/compare/@standardnotes/analytics@2.32.6...@standardnotes/analytics@2.33.0) (2023-11-10)
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* add graceful shutdown procedures upon SIGTERM ([#923](https://github.com/standardnotes/server/issues/923)) ([c24353c](https://github.com/standardnotes/server/commit/c24353cc24ebf4b40ff9a2cec8e37cfdef109e37))
|
||||||
|
|
||||||
## [2.32.6](https://github.com/standardnotes/server/compare/@standardnotes/analytics@2.32.5...@standardnotes/analytics@2.32.6) (2023-11-07)
|
## [2.32.6](https://github.com/standardnotes/server/compare/@standardnotes/analytics@2.32.5...@standardnotes/analytics@2.32.6) (2023-11-07)
|
||||||
|
|
||||||
**Note:** Version bump only for package @standardnotes/analytics
|
**Note:** Version bump only for package @standardnotes/analytics
|
||||||
|
|||||||
@@ -22,5 +22,11 @@ void container.load().then((container) => {
|
|||||||
|
|
||||||
const subscriber = container.get<DomainEventSubscriberInterface>(TYPES.DomainEventSubscriber)
|
const subscriber = container.get<DomainEventSubscriberInterface>(TYPES.DomainEventSubscriber)
|
||||||
|
|
||||||
|
process.on('SIGTERM', () => {
|
||||||
|
logger.info('SIGTERM received. Stopping worker...')
|
||||||
|
subscriber.stop()
|
||||||
|
logger.info('Worker stopped.')
|
||||||
|
})
|
||||||
|
|
||||||
subscriber.start()
|
subscriber.start()
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -6,12 +6,12 @@ COMMAND=$1 && shift 1
|
|||||||
case "$COMMAND" in
|
case "$COMMAND" in
|
||||||
'start-worker' )
|
'start-worker' )
|
||||||
echo "[Docker] Starting Worker..."
|
echo "[Docker] Starting Worker..."
|
||||||
node docker/entrypoint-worker.js
|
exec node docker/entrypoint-worker.js
|
||||||
;;
|
;;
|
||||||
|
|
||||||
'report' )
|
'report' )
|
||||||
echo "[Docker] Starting Usage Report Generation..."
|
echo "[Docker] Starting Usage Report Generation..."
|
||||||
node docker/entrypoint-report.js
|
exec node docker/entrypoint-report.js
|
||||||
;;
|
;;
|
||||||
|
|
||||||
* )
|
* )
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@standardnotes/analytics",
|
"name": "@standardnotes/analytics",
|
||||||
"version": "2.32.6",
|
"version": "2.33.2",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=18.0.0 <21.0.0"
|
"node": ">=18.0.0 <21.0.0"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -3,6 +3,86 @@
|
|||||||
All notable changes to this project will be documented in this file.
|
All notable changes to this project will be documented in this file.
|
||||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||||
|
|
||||||
|
## [1.83.5](https://github.com/standardnotes/api-gateway/compare/@standardnotes/api-gateway@1.83.4...@standardnotes/api-gateway@1.83.5) (2023-11-14)
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **api-gateway:** remove the verify body function ([3ddd671](https://github.com/standardnotes/api-gateway/commit/3ddd671c4797482a396844e804b4b45b82dbff2d))
|
||||||
|
* **api-gateway:** remove unused imports ([fd997f4](https://github.com/standardnotes/api-gateway/commit/fd997f4849ed01ef3ae4baf52b5895012fa711d4))
|
||||||
|
|
||||||
|
## [1.83.4](https://github.com/standardnotes/api-gateway/compare/@standardnotes/api-gateway@1.83.3...@standardnotes/api-gateway@1.83.4) (2023-11-14)
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **api-gateway:** add verification if json is valid on request ([420bf9e](https://github.com/standardnotes/api-gateway/commit/420bf9ec5460a9693cc382e9164b4bdbb9b769a1))
|
||||||
|
* **api-gateway:** buffer encoding ([2823ed8](https://github.com/standardnotes/api-gateway/commit/2823ed8612cb9797d43e847edac5e2bdc0fe7426))
|
||||||
|
* **api-gateway:** checking for buffer length ([f65809e](https://github.com/standardnotes/api-gateway/commit/f65809ef3052d05df2e3f012a9b6340d18a6deae))
|
||||||
|
|
||||||
|
## [1.83.3](https://github.com/standardnotes/api-gateway/compare/@standardnotes/api-gateway@1.83.2...@standardnotes/api-gateway@1.83.3) (2023-11-13)
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **api-gateway:** add application version to the error logs ([daed1a7](https://github.com/standardnotes/api-gateway/commit/daed1a77a02559a8487896b6fb8299befe8a2d96))
|
||||||
|
* **api-gateway:** add request method to the debug logs ([b39eb09](https://github.com/standardnotes/api-gateway/commit/b39eb09d91f0ea9482d27578faecdf57ed2ea48e))
|
||||||
|
|
||||||
|
## [1.83.2](https://github.com/standardnotes/api-gateway/compare/@standardnotes/api-gateway@1.83.1...@standardnotes/api-gateway@1.83.2) (2023-11-13)
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **api-gateway:** debug log on error thrown body representation ([c8bf4ab](https://github.com/standardnotes/api-gateway/commit/c8bf4ab3a0ab757092077fc594e3ca7e090116b4))
|
||||||
|
|
||||||
|
## [1.83.1](https://github.com/standardnotes/api-gateway/compare/@standardnotes/api-gateway@1.83.0...@standardnotes/api-gateway@1.83.1) (2023-11-13)
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **api-gateway:** add debug logs for errors on parsing ([60686dc](https://github.com/standardnotes/api-gateway/commit/60686dcdbd59c0d99cd1857a82ad62baed088b25))
|
||||||
|
|
||||||
|
# [1.83.0](https://github.com/standardnotes/api-gateway/compare/@standardnotes/api-gateway@1.82.1...@standardnotes/api-gateway@1.83.0) (2023-11-10)
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **api-gateway:** add more info on error logs ([f997501](https://github.com/standardnotes/api-gateway/commit/f99750169f4d24cdc7530184af2230c687f3e166))
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* add keep-alive connections to subservices ([#924](https://github.com/standardnotes/api-gateway/issues/924)) ([daad76d](https://github.com/standardnotes/api-gateway/commit/daad76d0ddae34c59dce45eedc4a055c4a11456d))
|
||||||
|
|
||||||
|
## [1.82.1](https://github.com/standardnotes/api-gateway/compare/@standardnotes/api-gateway@1.82.0...@standardnotes/api-gateway@1.82.1) (2023-11-10)
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **api-gateway:** websockets calls logs severity ([a9b1543](https://github.com/standardnotes/api-gateway/commit/a9b1543e204afeab1fa2e008327c39cf306a247c))
|
||||||
|
|
||||||
|
# [1.82.0](https://github.com/standardnotes/api-gateway/compare/@standardnotes/api-gateway@1.81.14...@standardnotes/api-gateway@1.82.0) (2023-11-10)
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* add graceful shutdown procedures upon SIGTERM ([#923](https://github.com/standardnotes/api-gateway/issues/923)) ([c24353c](https://github.com/standardnotes/api-gateway/commit/c24353cc24ebf4b40ff9a2cec8e37cfdef109e37))
|
||||||
|
|
||||||
|
## [1.81.14](https://github.com/standardnotes/api-gateway/compare/@standardnotes/api-gateway@1.81.13...@standardnotes/api-gateway@1.81.14) (2023-11-10)
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **api-gateway:** add logs about calling web sockets with minimal format ([5d3fb9a](https://github.com/standardnotes/api-gateway/commit/5d3fb9a537f6971cfe8ae3c5ea449806cc4de8a0))
|
||||||
|
|
||||||
|
## [1.81.13](https://github.com/standardnotes/api-gateway/compare/@standardnotes/api-gateway@1.81.12...@standardnotes/api-gateway@1.81.13) (2023-11-09)
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **api-gateway:** add possibility to configure keep-alive timeout ([#920](https://github.com/standardnotes/api-gateway/issues/920)) ([16f92bd](https://github.com/standardnotes/api-gateway/commit/16f92bdc990ded5c3f1fe5af1e6e4a113a9954de))
|
||||||
|
|
||||||
|
## [1.81.12](https://github.com/standardnotes/api-gateway/compare/@standardnotes/api-gateway@1.81.11...@standardnotes/api-gateway@1.81.12) (2023-11-09)
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* reduce websockets api communication data ([#919](https://github.com/standardnotes/api-gateway/issues/919)) ([c4ae12d](https://github.com/standardnotes/api-gateway/commit/c4ae12d53fc166879f90a4c5dbad1ab1cb4797e2))
|
||||||
|
|
||||||
|
## [1.81.11](https://github.com/standardnotes/api-gateway/compare/@standardnotes/api-gateway@1.81.10...@standardnotes/api-gateway@1.81.11) (2023-11-07)
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **api-gateway:** remove calling both auth and payments on account deletion request ([6b554c2](https://github.com/standardnotes/api-gateway/commit/6b554c28b731a9080d7ad2942d3fa05c01dcabf2))
|
||||||
|
|
||||||
## [1.81.10](https://github.com/standardnotes/api-gateway/compare/@standardnotes/api-gateway@1.81.9...@standardnotes/api-gateway@1.81.10) (2023-11-07)
|
## [1.81.10](https://github.com/standardnotes/api-gateway/compare/@standardnotes/api-gateway@1.81.9...@standardnotes/api-gateway@1.81.10) (2023-11-07)
|
||||||
|
|
||||||
**Note:** Version bump only for package @standardnotes/api-gateway
|
**Note:** Version bump only for package @standardnotes/api-gateway
|
||||||
|
|||||||
@@ -90,8 +90,15 @@ void container.load().then((container) => {
|
|||||||
const logger: winston.Logger = container.get(TYPES.ApiGateway_Logger)
|
const logger: winston.Logger = container.get(TYPES.ApiGateway_Logger)
|
||||||
|
|
||||||
server.setErrorConfig((app) => {
|
server.setErrorConfig((app) => {
|
||||||
app.use((error: Record<string, unknown>, _request: Request, response: Response, _next: NextFunction) => {
|
app.use((error: Record<string, unknown>, request: Request, response: Response, _next: NextFunction) => {
|
||||||
logger.error(error.stack)
|
logger.error(
|
||||||
|
`[URL: |${request.method}| ${request.url}][SNJS: ${request.headers['x-snjs-version']}][Application: ${request.headers['x-application-version']}] Error thrown: ${error.stack}`,
|
||||||
|
)
|
||||||
|
logger.debug(
|
||||||
|
`[URL: |${request.method}| ${request.url}][SNJS: ${request.headers['x-snjs-version']}][Application: ${
|
||||||
|
request.headers['x-application-version']
|
||||||
|
}] Request body: ${JSON.stringify(request.body)}`,
|
||||||
|
)
|
||||||
|
|
||||||
response.status(500).send({
|
response.status(500).send({
|
||||||
error: {
|
error: {
|
||||||
@@ -102,9 +109,18 @@ void container.load().then((container) => {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
const serverInstance = server.build()
|
const serverInstance = server.build().listen(env.get('PORT'))
|
||||||
|
|
||||||
serverInstance.listen(env.get('PORT'))
|
const keepAliveTimeout = env.get('KEEP_ALIVE_TIMEOUT', true) ? +env.get('KEEP_ALIVE_TIMEOUT', true) : 5000
|
||||||
|
|
||||||
|
serverInstance.keepAliveTimeout = keepAliveTimeout
|
||||||
|
|
||||||
|
process.on('SIGTERM', () => {
|
||||||
|
logger.info('SIGTERM signal received: closing HTTP server')
|
||||||
|
serverInstance.close(() => {
|
||||||
|
logger.info('HTTP server closed')
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
logger.info(`Server started on port ${process.env.PORT}`)
|
logger.info(`Server started on port ${process.env.PORT}`)
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ COMMAND=$1 && shift 1
|
|||||||
case "$COMMAND" in
|
case "$COMMAND" in
|
||||||
'start-web' )
|
'start-web' )
|
||||||
echo "Starting Web..."
|
echo "Starting Web..."
|
||||||
node docker/entrypoint-server.js
|
exec node docker/entrypoint-server.js
|
||||||
;;
|
;;
|
||||||
|
|
||||||
* )
|
* )
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@standardnotes/api-gateway",
|
"name": "@standardnotes/api-gateway",
|
||||||
"version": "1.81.10",
|
"version": "1.83.5",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=18.0.0 <21.0.0"
|
"node": ">=18.0.0 <21.0.0"
|
||||||
},
|
},
|
||||||
@@ -31,7 +31,8 @@
|
|||||||
"@standardnotes/domain-events-infra": "workspace:*",
|
"@standardnotes/domain-events-infra": "workspace:*",
|
||||||
"@standardnotes/security": "workspace:*",
|
"@standardnotes/security": "workspace:*",
|
||||||
"@standardnotes/time": "workspace:*",
|
"@standardnotes/time": "workspace:*",
|
||||||
"axios": "^1.1.3",
|
"agentkeepalive": "^4.5.0",
|
||||||
|
"axios": "^1.6.1",
|
||||||
"cors": "2.8.5",
|
"cors": "2.8.5",
|
||||||
"dotenv": "^16.0.1",
|
"dotenv": "^16.0.1",
|
||||||
"express": "^4.18.2",
|
"express": "^4.18.2",
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
import * as winston from 'winston'
|
import * as winston from 'winston'
|
||||||
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
import * as AgentKeepAlive from 'agentkeepalive'
|
||||||
const axios = require('axios')
|
import axios, { AxiosInstance } from 'axios'
|
||||||
import { AxiosInstance } from 'axios'
|
|
||||||
import Redis from 'ioredis'
|
import Redis from 'ioredis'
|
||||||
import { Container } from 'inversify'
|
import { Container } from 'inversify'
|
||||||
import { Timer, TimerInterface } from '@standardnotes/time'
|
import { Timer, TimerInterface } from '@standardnotes/time'
|
||||||
@@ -70,7 +69,17 @@ export class ContainerConfigLoader {
|
|||||||
container.bind(TYPES.ApiGateway_Redis).toConstantValue(redis)
|
container.bind(TYPES.ApiGateway_Redis).toConstantValue(redis)
|
||||||
}
|
}
|
||||||
|
|
||||||
container.bind<AxiosInstance>(TYPES.ApiGateway_HTTPClient).toConstantValue(axios.create())
|
container.bind<AxiosInstance>(TYPES.ApiGateway_HTTPClient).toConstantValue(
|
||||||
|
axios.create({
|
||||||
|
httpAgent: new AgentKeepAlive({
|
||||||
|
keepAlive: true,
|
||||||
|
timeout: env.get('AGENT_KEEP_ALIVE_TIMEOUT', true) ? +env.get('AGENT_KEEP_ALIVE_TIMEOUT', true) : 8_000,
|
||||||
|
freeSocketTimeout: env.get('AGENT_KEEP_ALIVE_FREE_SOCKET_TIMEOUT', true)
|
||||||
|
? +env.get('AGENT_KEEP_ALIVE_FREE_SOCKET_TIMEOUT', true)
|
||||||
|
: 4_000,
|
||||||
|
}),
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
|
||||||
// env vars
|
// env vars
|
||||||
container.bind(TYPES.ApiGateway_SYNCING_SERVER_JS_URL).toConstantValue(env.get('SYNCING_SERVER_JS_URL', true))
|
container.bind(TYPES.ApiGateway_SYNCING_SERVER_JS_URL).toConstantValue(env.get('SYNCING_SERVER_JS_URL', true))
|
||||||
|
|||||||
@@ -23,7 +23,6 @@ export class UsersController extends BaseHttpController {
|
|||||||
@inject(TYPES.ApiGateway_ServiceProxy) private httpService: ServiceProxyInterface,
|
@inject(TYPES.ApiGateway_ServiceProxy) private httpService: ServiceProxyInterface,
|
||||||
@inject(TYPES.ApiGateway_EndpointResolver) private endpointResolver: EndpointResolverInterface,
|
@inject(TYPES.ApiGateway_EndpointResolver) private endpointResolver: EndpointResolverInterface,
|
||||||
@inject(TYPES.ApiGateway_Logger) private logger: Logger,
|
@inject(TYPES.ApiGateway_Logger) private logger: Logger,
|
||||||
@inject(TYPES.ApiGateway_IS_CONFIGURED_FOR_HOME_SERVER) private isConfiguredForHomeServer: boolean,
|
|
||||||
) {
|
) {
|
||||||
super()
|
super()
|
||||||
}
|
}
|
||||||
@@ -238,10 +237,6 @@ export class UsersController extends BaseHttpController {
|
|||||||
|
|
||||||
@httpDelete('/:userUuid', TYPES.ApiGateway_RequiredCrossServiceTokenMiddleware)
|
@httpDelete('/:userUuid', TYPES.ApiGateway_RequiredCrossServiceTokenMiddleware)
|
||||||
async deleteUser(request: Request, response: Response): Promise<void> {
|
async deleteUser(request: Request, response: Response): Promise<void> {
|
||||||
if (!this.isConfiguredForHomeServer) {
|
|
||||||
await this.httpService.callPaymentsServer(request, response, 'api/account', request.body, true)
|
|
||||||
}
|
|
||||||
|
|
||||||
await this.httpService.callAuthServer(
|
await this.httpService.callAuthServer(
|
||||||
request,
|
request,
|
||||||
response,
|
response,
|
||||||
|
|||||||
@@ -143,7 +143,21 @@ export class HttpServiceProxy implements ServiceProxyInterface {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
await this.callServer(this.webSocketServerUrl, request, response, endpointOrMethodIdentifier, payload)
|
const isARequestComingFromApiGatewayAndShouldBeKeptInMinimalFormat = request.headers.connectionid !== undefined
|
||||||
|
this.logger.debug(
|
||||||
|
`Calling websockets service: ${endpointOrMethodIdentifier}. Format is minimal: ${isARequestComingFromApiGatewayAndShouldBeKeptInMinimalFormat}`,
|
||||||
|
)
|
||||||
|
if (isARequestComingFromApiGatewayAndShouldBeKeptInMinimalFormat) {
|
||||||
|
await this.callServerWithLegacyFormat(
|
||||||
|
this.webSocketServerUrl,
|
||||||
|
request,
|
||||||
|
response,
|
||||||
|
endpointOrMethodIdentifier,
|
||||||
|
payload,
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
await this.callServer(this.webSocketServerUrl, request, response, endpointOrMethodIdentifier, payload)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async callPaymentsServer(
|
async callPaymentsServer(
|
||||||
@@ -151,7 +165,6 @@ export class HttpServiceProxy implements ServiceProxyInterface {
|
|||||||
response: Response,
|
response: Response,
|
||||||
endpointOrMethodIdentifier: string,
|
endpointOrMethodIdentifier: string,
|
||||||
payload?: Record<string, unknown> | string,
|
payload?: Record<string, unknown> | string,
|
||||||
returnRawResponse?: boolean,
|
|
||||||
): Promise<void | Response<unknown, Record<string, unknown>>> {
|
): Promise<void | Response<unknown, Record<string, unknown>>> {
|
||||||
if (!this.paymentsServerUrl) {
|
if (!this.paymentsServerUrl) {
|
||||||
this.logger.debug('Payments Server URL not defined. Skipped request to Payments API.')
|
this.logger.debug('Payments Server URL not defined. Skipped request to Payments API.')
|
||||||
@@ -159,18 +172,13 @@ export class HttpServiceProxy implements ServiceProxyInterface {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
const rawResponse = await this.callServerWithLegacyFormat(
|
await this.callServerWithLegacyFormat(
|
||||||
this.paymentsServerUrl,
|
this.paymentsServerUrl,
|
||||||
request,
|
request,
|
||||||
response,
|
response,
|
||||||
endpointOrMethodIdentifier,
|
endpointOrMethodIdentifier,
|
||||||
payload,
|
payload,
|
||||||
returnRawResponse,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
if (returnRawResponse) {
|
|
||||||
return rawResponse
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async callAuthServerWithLegacyFormat(
|
async callAuthServerWithLegacyFormat(
|
||||||
@@ -345,7 +353,6 @@ export class HttpServiceProxy implements ServiceProxyInterface {
|
|||||||
response: Response,
|
response: Response,
|
||||||
endpointOrMethodIdentifier: string,
|
endpointOrMethodIdentifier: string,
|
||||||
payload?: Record<string, unknown> | string,
|
payload?: Record<string, unknown> | string,
|
||||||
returnRawResponse?: boolean,
|
|
||||||
): Promise<void | Response<unknown, Record<string, unknown>>> {
|
): Promise<void | Response<unknown, Record<string, unknown>>> {
|
||||||
const serviceResponse = await this.getServerResponse(
|
const serviceResponse = await this.getServerResponse(
|
||||||
serverUrl,
|
serverUrl,
|
||||||
@@ -364,18 +371,10 @@ export class HttpServiceProxy implements ServiceProxyInterface {
|
|||||||
if (serviceResponse.request._redirectable._redirectCount > 0) {
|
if (serviceResponse.request._redirectable._redirectCount > 0) {
|
||||||
response.status(302)
|
response.status(302)
|
||||||
|
|
||||||
if (returnRawResponse) {
|
|
||||||
return response
|
|
||||||
}
|
|
||||||
|
|
||||||
response.redirect(serviceResponse.request.res.responseUrl)
|
response.redirect(serviceResponse.request.res.responseUrl)
|
||||||
} else {
|
} else {
|
||||||
response.status(serviceResponse.status)
|
response.status(serviceResponse.status)
|
||||||
|
|
||||||
if (returnRawResponse) {
|
|
||||||
return response
|
|
||||||
}
|
|
||||||
|
|
||||||
response.send(serviceResponse.data)
|
response.send(serviceResponse.data)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -42,7 +42,6 @@ export interface ServiceProxyInterface {
|
|||||||
response: Response,
|
response: Response,
|
||||||
endpointOrMethodIdentifier: string,
|
endpointOrMethodIdentifier: string,
|
||||||
payload?: Record<string, unknown> | string,
|
payload?: Record<string, unknown> | string,
|
||||||
returnRawResponse?: boolean,
|
|
||||||
): Promise<void | Response<unknown, Record<string, unknown>>>
|
): Promise<void | Response<unknown, Record<string, unknown>>>
|
||||||
callWebSocketServer(
|
callWebSocketServer(
|
||||||
request: Request,
|
request: Request,
|
||||||
|
|||||||
@@ -6,4 +6,4 @@ sh supervisor/wait-for.sh localhost $AUTH_SERVER_PORT
|
|||||||
sh supervisor/wait-for.sh localhost $FILES_SERVER_PORT
|
sh supervisor/wait-for.sh localhost $FILES_SERVER_PORT
|
||||||
sh supervisor/wait-for.sh localhost $REVISIONS_SERVER_PORT
|
sh supervisor/wait-for.sh localhost $REVISIONS_SERVER_PORT
|
||||||
sh supervisor/wait-for.sh localhost $SYNCING_SERVER_PORT
|
sh supervisor/wait-for.sh localhost $SYNCING_SERVER_PORT
|
||||||
node docker/entrypoint-server.js
|
exec node docker/entrypoint-server.js
|
||||||
|
|||||||
@@ -3,6 +3,50 @@
|
|||||||
All notable changes to this project will be documented in this file.
|
All notable changes to this project will be documented in this file.
|
||||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||||
|
|
||||||
|
## [1.169.2](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.169.1...@standardnotes/auth-server@1.169.2) (2023-11-13)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @standardnotes/auth-server
|
||||||
|
|
||||||
|
## [1.169.1](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.169.0...@standardnotes/auth-server@1.169.1) (2023-11-13)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @standardnotes/auth-server
|
||||||
|
|
||||||
|
# [1.169.0](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.168.0...@standardnotes/auth-server@1.169.0) (2023-11-10)
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* add keep-alive connections to subservices ([#924](https://github.com/standardnotes/server/issues/924)) ([daad76d](https://github.com/standardnotes/server/commit/daad76d0ddae34c59dce45eedc4a055c4a11456d))
|
||||||
|
|
||||||
|
# [1.168.0](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.167.2...@standardnotes/auth-server@1.168.0) (2023-11-10)
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* add graceful shutdown procedures upon SIGTERM ([#923](https://github.com/standardnotes/server/issues/923)) ([c24353c](https://github.com/standardnotes/server/commit/c24353cc24ebf4b40ff9a2cec8e37cfdef109e37))
|
||||||
|
|
||||||
|
## [1.167.2](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.167.1...@standardnotes/auth-server@1.167.2) (2023-11-08)
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* add logs about sending websocket events to clients ([9465f2e](https://github.com/standardnotes/server/commit/9465f2ecd8e8f0bf3ebeeb3976227b1b105aded0))
|
||||||
|
|
||||||
|
## [1.167.1](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.167.0...@standardnotes/auth-server@1.167.1) (2023-11-08)
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **auth:** path to delete accounts script ([ca8a3fc](https://github.com/standardnotes/server/commit/ca8a3fc77d91410f0dee8c3ddef29c09947c9cf5))
|
||||||
|
|
||||||
|
# [1.167.0](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.166.0...@standardnotes/auth-server@1.167.0) (2023-11-08)
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* script to mass delete accounts from CSV source ([#913](https://github.com/standardnotes/server/issues/913)) ([a6dea50](https://github.com/standardnotes/server/commit/a6dea50d745ff6f051fd9ede168aef27036159c3))
|
||||||
|
|
||||||
|
# [1.166.0](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.165.4...@standardnotes/auth-server@1.166.0) (2023-11-07)
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* **auth:** add triggering post setting update actions ([#905](https://github.com/standardnotes/server/issues/905)) ([d228a86](https://github.com/standardnotes/server/commit/d228a86f48c9ff62b7810244c347abf7770e2b9f))
|
||||||
|
|
||||||
## [1.165.4](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.165.3...@standardnotes/auth-server@1.165.4) (2023-11-07)
|
## [1.165.4](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.165.3...@standardnotes/auth-server@1.165.4) (2023-11-07)
|
||||||
|
|
||||||
### Bug Fixes
|
### Bug Fixes
|
||||||
|
|||||||
+11
-84
@@ -1,9 +1,5 @@
|
|||||||
import 'reflect-metadata'
|
import 'reflect-metadata'
|
||||||
|
|
||||||
import { SettingName } from '@standardnotes/domain-core'
|
|
||||||
|
|
||||||
import { Stream } from 'stream'
|
|
||||||
|
|
||||||
import { Logger } from 'winston'
|
import { Logger } from 'winston'
|
||||||
import * as dayjs from 'dayjs'
|
import * as dayjs from 'dayjs'
|
||||||
import * as utc from 'dayjs/plugin/utc'
|
import * as utc from 'dayjs/plugin/utc'
|
||||||
@@ -11,78 +7,13 @@ import * as utc from 'dayjs/plugin/utc'
|
|||||||
import { ContainerConfigLoader } from '../src/Bootstrap/Container'
|
import { ContainerConfigLoader } from '../src/Bootstrap/Container'
|
||||||
import TYPES from '../src/Bootstrap/Types'
|
import TYPES from '../src/Bootstrap/Types'
|
||||||
import { Env } from '../src/Bootstrap/Env'
|
import { Env } from '../src/Bootstrap/Env'
|
||||||
import { DomainEventPublisherInterface } from '@standardnotes/domain-events'
|
import { TriggerEmailBackupForAllUsers } from '../src/Domain/UseCase/TriggerEmailBackupForAllUsers/TriggerEmailBackupForAllUsers'
|
||||||
import { DomainEventFactoryInterface } from '../src/Domain/Event/DomainEventFactoryInterface'
|
|
||||||
import { SettingRepositoryInterface } from '../src/Domain/Setting/SettingRepositoryInterface'
|
|
||||||
import { MuteFailedBackupsEmailsOption } from '@standardnotes/settings'
|
|
||||||
import { RoleServiceInterface } from '../src/Domain/Role/RoleServiceInterface'
|
|
||||||
import { PermissionName } from '@standardnotes/features'
|
|
||||||
import { GetUserKeyParams } from '../src/Domain/UseCase/GetUserKeyParams/GetUserKeyParams'
|
|
||||||
|
|
||||||
const inputArgs = process.argv.slice(2)
|
const inputArgs = process.argv.slice(2)
|
||||||
const backupProvider = inputArgs[0]
|
const backupFrequency = inputArgs[0]
|
||||||
const backupFrequency = inputArgs[1]
|
|
||||||
|
|
||||||
const requestBackups = async (
|
const requestBackups = async (triggerEmailBackupForAllUsers: TriggerEmailBackupForAllUsers): Promise<void> => {
|
||||||
settingRepository: SettingRepositoryInterface,
|
await triggerEmailBackupForAllUsers.execute({ backupFrequency })
|
||||||
roleService: RoleServiceInterface,
|
|
||||||
domainEventFactory: DomainEventFactoryInterface,
|
|
||||||
domainEventPublisher: DomainEventPublisherInterface,
|
|
||||||
getUserKeyParamsUseCase: GetUserKeyParams,
|
|
||||||
): Promise<void> => {
|
|
||||||
const settingName = SettingName.create(SettingName.NAMES.EmailBackupFrequency).getValue()
|
|
||||||
const permissionName = PermissionName.DailyEmailBackup
|
|
||||||
const muteEmailsSettingName = SettingName.NAMES.MuteFailedBackupsEmails
|
|
||||||
const muteEmailsSettingValue = MuteFailedBackupsEmailsOption.Muted
|
|
||||||
|
|
||||||
const stream = await settingRepository.streamAllByNameAndValue(settingName, backupFrequency)
|
|
||||||
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
stream
|
|
||||||
.pipe(
|
|
||||||
new Stream.Transform({
|
|
||||||
objectMode: true,
|
|
||||||
transform: async (setting, _encoding, callback) => {
|
|
||||||
const userIsPermittedForEmailBackups = await roleService.userHasPermission(
|
|
||||||
setting.setting_user_uuid,
|
|
||||||
permissionName,
|
|
||||||
)
|
|
||||||
if (!userIsPermittedForEmailBackups) {
|
|
||||||
callback()
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
let userHasEmailsMuted = false
|
|
||||||
const emailsMutedSetting = await settingRepository.findOneByNameAndUserUuid(
|
|
||||||
muteEmailsSettingName,
|
|
||||||
setting.setting_user_uuid,
|
|
||||||
)
|
|
||||||
if (emailsMutedSetting !== null && emailsMutedSetting.props.value !== null) {
|
|
||||||
userHasEmailsMuted = emailsMutedSetting.props.value === muteEmailsSettingValue
|
|
||||||
}
|
|
||||||
|
|
||||||
const keyParamsResponse = await getUserKeyParamsUseCase.execute({
|
|
||||||
userUuid: setting.setting_user_uuid,
|
|
||||||
authenticated: false,
|
|
||||||
})
|
|
||||||
|
|
||||||
await domainEventPublisher.publish(
|
|
||||||
domainEventFactory.createEmailBackupRequestedEvent(
|
|
||||||
setting.setting_user_uuid,
|
|
||||||
emailsMutedSetting?.id.toString() as string,
|
|
||||||
userHasEmailsMuted,
|
|
||||||
keyParamsResponse.keyParams,
|
|
||||||
),
|
|
||||||
)
|
|
||||||
|
|
||||||
callback()
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
)
|
|
||||||
.on('finish', resolve)
|
|
||||||
.on('error', reject)
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const container = new ContainerConfigLoader('worker')
|
const container = new ContainerConfigLoader('worker')
|
||||||
@@ -94,24 +25,20 @@ void container.load().then((container) => {
|
|||||||
|
|
||||||
const logger: Logger = container.get(TYPES.Auth_Logger)
|
const logger: Logger = container.get(TYPES.Auth_Logger)
|
||||||
|
|
||||||
logger.info(`Starting ${backupFrequency} ${backupProvider} backup requesting...`)
|
logger.info(`Starting ${backupFrequency} email backup requesting...`)
|
||||||
|
|
||||||
const settingRepository: SettingRepositoryInterface = container.get(TYPES.Auth_SettingRepository)
|
const triggerEmailBackupForAllUsers: TriggerEmailBackupForAllUsers = container.get(
|
||||||
const roleService: RoleServiceInterface = container.get(TYPES.Auth_RoleService)
|
TYPES.Auth_TriggerEmailBackupForAllUsers,
|
||||||
const domainEventFactory: DomainEventFactoryInterface = container.get(TYPES.Auth_DomainEventFactory)
|
|
||||||
const domainEventPublisher: DomainEventPublisherInterface = container.get(TYPES.Auth_DomainEventPublisher)
|
|
||||||
const getUserKeyParamsUseCase: GetUserKeyParams = container.get(TYPES.Auth_GetUserKeyParams)
|
|
||||||
|
|
||||||
Promise.resolve(
|
|
||||||
requestBackups(settingRepository, roleService, domainEventFactory, domainEventPublisher, getUserKeyParamsUseCase),
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
Promise.resolve(requestBackups(triggerEmailBackupForAllUsers))
|
||||||
.then(() => {
|
.then(() => {
|
||||||
logger.info(`${backupFrequency} ${backupProvider} backup requesting complete`)
|
logger.info(`${backupFrequency} email backup requesting complete`)
|
||||||
|
|
||||||
process.exit(0)
|
process.exit(0)
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
logger.error(`Could not finish ${backupFrequency} ${backupProvider} backup requesting: ${error.message}`)
|
logger.error(`Could not finish ${backupFrequency} email backup requesting: ${error.message}`)
|
||||||
|
|
||||||
process.exit(1)
|
process.exit(1)
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -0,0 +1,43 @@
|
|||||||
|
import 'reflect-metadata'
|
||||||
|
|
||||||
|
import { Logger } from 'winston'
|
||||||
|
|
||||||
|
import { ContainerConfigLoader } from '../src/Bootstrap/Container'
|
||||||
|
import TYPES from '../src/Bootstrap/Types'
|
||||||
|
import { Env } from '../src/Bootstrap/Env'
|
||||||
|
import { DeleteAccountsFromCSVFile } from '../src/Domain/UseCase/DeleteAccountsFromCSVFile/DeleteAccountsFromCSVFile'
|
||||||
|
|
||||||
|
const inputArgs = process.argv.slice(2)
|
||||||
|
const fileName = inputArgs[0]
|
||||||
|
const mode = inputArgs[1]
|
||||||
|
|
||||||
|
const deleteAccounts = async (deleteAccountsFromCSVFile: DeleteAccountsFromCSVFile): Promise<void> => {
|
||||||
|
await deleteAccountsFromCSVFile.execute({
|
||||||
|
fileName,
|
||||||
|
dryRun: mode !== 'delete',
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const container = new ContainerConfigLoader('worker')
|
||||||
|
void container.load().then((container) => {
|
||||||
|
const env: Env = new Env()
|
||||||
|
env.load()
|
||||||
|
|
||||||
|
const logger: Logger = container.get(TYPES.Auth_Logger)
|
||||||
|
|
||||||
|
logger.info('Starting mass accounts deletion from CSV file')
|
||||||
|
|
||||||
|
const deleteAccountsFromCSVFile = container.get<DeleteAccountsFromCSVFile>(TYPES.Auth_DeleteAccountsFromCSVFile)
|
||||||
|
|
||||||
|
Promise.resolve(deleteAccounts(deleteAccountsFromCSVFile))
|
||||||
|
.then(() => {
|
||||||
|
logger.info('Accounts deleted.')
|
||||||
|
|
||||||
|
process.exit(0)
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
logger.error(`Could not delete accounts: ${error.message}`)
|
||||||
|
|
||||||
|
process.exit(1)
|
||||||
|
})
|
||||||
|
})
|
||||||
@@ -64,9 +64,18 @@ void container.load().then((container) => {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
const serverInstance = server.build()
|
const serverInstance = server.build().listen(env.get('PORT'))
|
||||||
|
|
||||||
serverInstance.listen(env.get('PORT'))
|
const keepAliveTimeout = env.get('KEEP_ALIVE_TIMEOUT', true) ? +env.get('KEEP_ALIVE_TIMEOUT', true) : 5000
|
||||||
|
|
||||||
|
serverInstance.keepAliveTimeout = keepAliveTimeout
|
||||||
|
|
||||||
|
process.on('SIGTERM', () => {
|
||||||
|
logger.info('SIGTERM signal received: closing HTTP server')
|
||||||
|
serverInstance.close(() => {
|
||||||
|
logger.info('HTTP server closed')
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
logger.info(`Server started on port ${process.env.PORT}`)
|
logger.info(`Server started on port ${process.env.PORT}`)
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -22,5 +22,11 @@ void container.load().then((container) => {
|
|||||||
|
|
||||||
const subscriber = container.get<DomainEventSubscriberInterface>(TYPES.Auth_DomainEventSubscriber)
|
const subscriber = container.get<DomainEventSubscriberInterface>(TYPES.Auth_DomainEventSubscriber)
|
||||||
|
|
||||||
|
process.on('SIGTERM', () => {
|
||||||
|
logger.info('SIGTERM received. Stopping worker...')
|
||||||
|
subscriber.stop()
|
||||||
|
logger.info('Worker stopped.')
|
||||||
|
})
|
||||||
|
|
||||||
subscriber.start()
|
subscriber.start()
|
||||||
})
|
})
|
||||||
|
|||||||
+1
-1
@@ -4,7 +4,7 @@ const path = require('path')
|
|||||||
|
|
||||||
const pnp = require(path.normalize(path.resolve(__dirname, '../../..', '.pnp.cjs'))).setup()
|
const pnp = require(path.normalize(path.resolve(__dirname, '../../..', '.pnp.cjs'))).setup()
|
||||||
|
|
||||||
const index = require(path.normalize(path.resolve(__dirname, '../dist/bin/worker.js')))
|
const index = require(path.normalize(path.resolve(__dirname, '../dist/bin/delete_accounts.js')))
|
||||||
|
|
||||||
Object.defineProperty(exports, '__esModule', { value: true })
|
Object.defineProperty(exports, '__esModule', { value: true })
|
||||||
|
|
||||||
@@ -6,53 +6,45 @@ COMMAND=$1 && shift 1
|
|||||||
case "$COMMAND" in
|
case "$COMMAND" in
|
||||||
'start-web' )
|
'start-web' )
|
||||||
echo "[Docker] Starting Web..."
|
echo "[Docker] Starting Web..."
|
||||||
node docker/entrypoint-server.js
|
exec node docker/entrypoint-server.js
|
||||||
;;
|
;;
|
||||||
|
|
||||||
'start-worker' )
|
'start-worker' )
|
||||||
echo "[Docker] Starting Worker..."
|
echo "[Docker] Starting Worker..."
|
||||||
node docker/entrypoint-worker.js
|
exec node docker/entrypoint-worker.js
|
||||||
;;
|
;;
|
||||||
|
|
||||||
'cleanup' )
|
'cleanup' )
|
||||||
echo "[Docker] Starting Cleanup..."
|
echo "[Docker] Starting Cleanup..."
|
||||||
node docker/entrypoint-cleanup.js
|
exec node docker/entrypoint-cleanup.js
|
||||||
;;
|
;;
|
||||||
|
|
||||||
'stats' )
|
'stats' )
|
||||||
echo "[Docker] Starting Persisting Stats..."
|
echo "[Docker] Starting Persisting Stats..."
|
||||||
node docker/entrypoint-stats.js
|
exec node docker/entrypoint-stats.js
|
||||||
;;
|
;;
|
||||||
|
|
||||||
'email-daily-backup' )
|
'email-daily-backup' )
|
||||||
echo "[Docker] Starting Email Daily Backup..."
|
echo "[Docker] Starting Email Daily Backup..."
|
||||||
node docker/entrypoint-backup.js email daily
|
exec node docker/entrypoint-backup.js daily
|
||||||
;;
|
;;
|
||||||
|
|
||||||
'email-weekly-backup' )
|
'email-weekly-backup' )
|
||||||
echo "[Docker] Starting Email Weekly Backup..."
|
echo "[Docker] Starting Email Weekly Backup..."
|
||||||
node docker/entrypoint-backup.js email weekly
|
exec node docker/entrypoint-backup.js weekly
|
||||||
;;
|
;;
|
||||||
|
|
||||||
'email-backup' )
|
'email-backup' )
|
||||||
echo "[Docker] Starting Email Backup For Single User..."
|
echo "[Docker] Starting Email Backup For Single User..."
|
||||||
EMAIL=$1 && shift 1
|
EMAIL=$1 && shift 1
|
||||||
node docker/entrypoint-user-email-backup.js $EMAIL
|
exec node docker/entrypoint-user-email-backup.js $EMAIL
|
||||||
;;
|
;;
|
||||||
|
|
||||||
'dropbox-daily-backup' )
|
'delete-accounts' )
|
||||||
echo "[Docker] Starting Dropbox Daily Backup..."
|
echo "[Docker] Starting Accounts Deleting from CSV..."
|
||||||
node docker/entrypoint-backup.js dropbox daily
|
FILE_NAME=$1 && shift 1
|
||||||
;;
|
MODE=$1 && shift 1
|
||||||
|
exec node docker/entrypoint-delete-accounts.js $FILE_NAME $MODE
|
||||||
'google-drive-daily-backup' )
|
|
||||||
echo "[Docker] Starting Google Drive Daily Backup..."
|
|
||||||
node docker/entrypoint-backup.js google_drive daily
|
|
||||||
;;
|
|
||||||
|
|
||||||
'one-drive-daily-backup' )
|
|
||||||
echo "[Docker] Starting One Drive Daily Backup..."
|
|
||||||
node docker/entrypoint-backup.js one_drive daily
|
|
||||||
;;
|
;;
|
||||||
|
|
||||||
* )
|
* )
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@standardnotes/auth-server",
|
"name": "@standardnotes/auth-server",
|
||||||
"version": "1.165.4",
|
"version": "1.169.2",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=18.0.0 <21.0.0"
|
"node": ">=18.0.0 <21.0.0"
|
||||||
},
|
},
|
||||||
@@ -24,17 +24,15 @@
|
|||||||
"worker": "yarn node dist/bin/worker.js",
|
"worker": "yarn node dist/bin/worker.js",
|
||||||
"cleanup": "yarn node dist/bin/cleanup.js",
|
"cleanup": "yarn node dist/bin/cleanup.js",
|
||||||
"stats": "yarn node dist/bin/stats.js",
|
"stats": "yarn node dist/bin/stats.js",
|
||||||
"daily-backup:email": "yarn node dist/bin/backup.js email daily",
|
"daily-backup:email": "yarn node dist/bin/backup.js daily",
|
||||||
"user-email-backup": "yarn node dist/bin/user_email_backup.js",
|
"user-email-backup": "yarn node dist/bin/user_email_backup.js",
|
||||||
"daily-backup:dropbox": "yarn node dist/bin/backup.js dropbox daily",
|
"weekly-backup:email": "yarn node dist/bin/backup.js weekly",
|
||||||
"daily-backup:google_drive": "yarn node dist/bin/backup.js google_drive daily",
|
|
||||||
"daily-backup:one_drive": "yarn node dist/bin/backup.js one_drive daily",
|
|
||||||
"weekly-backup:email": "yarn node dist/bin/backup.js email weekly",
|
|
||||||
"content-recalculation": "yarn node dist/bin/content.js",
|
"content-recalculation": "yarn node dist/bin/content.js",
|
||||||
"typeorm": "typeorm-ts-node-commonjs",
|
"typeorm": "typeorm-ts-node-commonjs",
|
||||||
"migrate": "yarn build && yarn typeorm migration:run -d dist/src/Bootstrap/DataSource.js"
|
"migrate": "yarn build && yarn typeorm migration:run -d dist/src/Bootstrap/DataSource.js"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@aws-sdk/client-s3": "^3.445.0",
|
||||||
"@aws-sdk/client-sns": "^3.427.0",
|
"@aws-sdk/client-sns": "^3.427.0",
|
||||||
"@aws-sdk/client-sqs": "^3.427.0",
|
"@aws-sdk/client-sqs": "^3.427.0",
|
||||||
"@cbor-extract/cbor-extract-linux-arm64": "^2.1.1",
|
"@cbor-extract/cbor-extract-linux-arm64": "^2.1.1",
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import * as winston from 'winston'
|
|||||||
import Redis from 'ioredis'
|
import Redis from 'ioredis'
|
||||||
import { SNSClient, SNSClientConfig } from '@aws-sdk/client-sns'
|
import { SNSClient, SNSClientConfig } from '@aws-sdk/client-sns'
|
||||||
import { SQSClient, SQSClientConfig } from '@aws-sdk/client-sqs'
|
import { SQSClient, SQSClientConfig } from '@aws-sdk/client-sqs'
|
||||||
|
import { S3Client } from '@aws-sdk/client-s3'
|
||||||
import { Container } from 'inversify'
|
import { Container } from 'inversify'
|
||||||
import {
|
import {
|
||||||
DomainEventHandlerInterface,
|
DomainEventHandlerInterface,
|
||||||
@@ -130,8 +131,6 @@ import { ListedAccountCreatedEventHandler } from '../Domain/Handler/ListedAccoun
|
|||||||
import { ListedAccountDeletedEventHandler } from '../Domain/Handler/ListedAccountDeletedEventHandler'
|
import { ListedAccountDeletedEventHandler } from '../Domain/Handler/ListedAccountDeletedEventHandler'
|
||||||
import { FileRemovedEventHandler } from '../Domain/Handler/FileRemovedEventHandler'
|
import { FileRemovedEventHandler } from '../Domain/Handler/FileRemovedEventHandler'
|
||||||
import { UserDisabledSessionUserAgentLoggingEventHandler } from '../Domain/Handler/UserDisabledSessionUserAgentLoggingEventHandler'
|
import { UserDisabledSessionUserAgentLoggingEventHandler } from '../Domain/Handler/UserDisabledSessionUserAgentLoggingEventHandler'
|
||||||
import { SettingInterpreterInterface } from '../Domain/Setting/SettingInterpreterInterface'
|
|
||||||
import { SettingInterpreter } from '../Domain/Setting/SettingInterpreter'
|
|
||||||
import { SettingCrypterInterface } from '../Domain/Setting/SettingCrypterInterface'
|
import { SettingCrypterInterface } from '../Domain/Setting/SettingCrypterInterface'
|
||||||
import { SettingCrypter } from '../Domain/Setting/SettingCrypter'
|
import { SettingCrypter } from '../Domain/Setting/SettingCrypter'
|
||||||
import { SharedSubscriptionInvitationRepositoryInterface } from '../Domain/SharedSubscription/SharedSubscriptionInvitationRepositoryInterface'
|
import { SharedSubscriptionInvitationRepositoryInterface } from '../Domain/SharedSubscription/SharedSubscriptionInvitationRepositoryInterface'
|
||||||
@@ -275,6 +274,12 @@ import { SubscriptionSettingPersistenceMapper } from '../Mapping/Persistence/Sub
|
|||||||
import { ApplyDefaultSettings } from '../Domain/UseCase/ApplyDefaultSettings/ApplyDefaultSettings'
|
import { ApplyDefaultSettings } from '../Domain/UseCase/ApplyDefaultSettings/ApplyDefaultSettings'
|
||||||
import { AuthResponseFactoryResolverInterface } from '../Domain/Auth/AuthResponseFactoryResolverInterface'
|
import { AuthResponseFactoryResolverInterface } from '../Domain/Auth/AuthResponseFactoryResolverInterface'
|
||||||
import { UserInvitedToSharedVaultEventHandler } from '../Domain/Handler/UserInvitedToSharedVaultEventHandler'
|
import { UserInvitedToSharedVaultEventHandler } from '../Domain/Handler/UserInvitedToSharedVaultEventHandler'
|
||||||
|
import { TriggerPostSettingUpdateActions } from '../Domain/UseCase/TriggerPostSettingUpdateActions/TriggerPostSettingUpdateActions'
|
||||||
|
import { TriggerEmailBackupForUser } from '../Domain/UseCase/TriggerEmailBackupForUser/TriggerEmailBackupForUser'
|
||||||
|
import { TriggerEmailBackupForAllUsers } from '../Domain/UseCase/TriggerEmailBackupForAllUsers/TriggerEmailBackupForAllUsers'
|
||||||
|
import { CSVFileReaderInterface } from '../Domain/CSV/CSVFileReaderInterface'
|
||||||
|
import { S3CsvFileReader } from '../Infra/S3/S3CsvFileReader'
|
||||||
|
import { DeleteAccountsFromCSVFile } from '../Domain/UseCase/DeleteAccountsFromCSVFile/DeleteAccountsFromCSVFile'
|
||||||
|
|
||||||
export class ContainerConfigLoader {
|
export class ContainerConfigLoader {
|
||||||
constructor(private mode: 'server' | 'worker' = 'server') {}
|
constructor(private mode: 'server' | 'worker' = 'server') {}
|
||||||
@@ -369,6 +374,19 @@ export class ContainerConfigLoader {
|
|||||||
}
|
}
|
||||||
const sqsClient = new SQSClient(sqsConfig)
|
const sqsClient = new SQSClient(sqsConfig)
|
||||||
container.bind<SQSClient>(TYPES.Auth_SQS).toConstantValue(sqsClient)
|
container.bind<SQSClient>(TYPES.Auth_SQS).toConstantValue(sqsClient)
|
||||||
|
|
||||||
|
container.bind<S3Client>(TYPES.Auth_S3).toConstantValue(
|
||||||
|
new S3Client({
|
||||||
|
apiVersion: 'latest',
|
||||||
|
region: env.get('S3_AWS_REGION', true),
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
|
||||||
|
container
|
||||||
|
.bind<CSVFileReaderInterface>(TYPES.Auth_CSVFileReader)
|
||||||
|
.toConstantValue(
|
||||||
|
new S3CsvFileReader(env.get('S3_AUTH_SCRIPTS_DATA_BUCKET', true), container.get<S3Client>(TYPES.Auth_S3)),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
container.bind(TYPES.Auth_SNS_TOPIC_ARN).toConstantValue(env.get('SNS_TOPIC_ARN', true))
|
container.bind(TYPES.Auth_SNS_TOPIC_ARN).toConstantValue(env.get('SNS_TOPIC_ARN', true))
|
||||||
@@ -772,16 +790,6 @@ export class ContainerConfigLoader {
|
|||||||
container.get<winston.Logger>(TYPES.Auth_Logger),
|
container.get<winston.Logger>(TYPES.Auth_Logger),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
container
|
|
||||||
.bind<SettingInterpreterInterface>(TYPES.Auth_SettingInterpreter)
|
|
||||||
.toConstantValue(
|
|
||||||
new SettingInterpreter(
|
|
||||||
container.get<DomainEventPublisherInterface>(TYPES.Auth_DomainEventPublisher),
|
|
||||||
container.get<DomainEventFactoryInterface>(TYPES.Auth_DomainEventFactory),
|
|
||||||
container.get<SettingRepositoryInterface>(TYPES.Auth_SettingRepository),
|
|
||||||
container.get<GetUserKeyParams>(TYPES.Auth_GetUserKeyParams),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
|
|
||||||
container.bind<OfflineSettingServiceInterface>(TYPES.Auth_OfflineSettingService).to(OfflineSettingService)
|
container.bind<OfflineSettingServiceInterface>(TYPES.Auth_OfflineSettingService).to(OfflineSettingService)
|
||||||
container.bind<ContentDecoderInterface>(TYPES.Auth_ContenDecoder).toConstantValue(new ContentDecoder())
|
container.bind<ContentDecoderInterface>(TYPES.Auth_ContenDecoder).toConstantValue(new ContentDecoder())
|
||||||
@@ -1231,6 +1239,46 @@ export class ContainerConfigLoader {
|
|||||||
container.get<GetSharedOrRegularSubscriptionForUser>(TYPES.Auth_GetSharedOrRegularSubscriptionForUser),
|
container.get<GetSharedOrRegularSubscriptionForUser>(TYPES.Auth_GetSharedOrRegularSubscriptionForUser),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
container
|
||||||
|
.bind<TriggerEmailBackupForUser>(TYPES.Auth_TriggerEmailBackupForUser)
|
||||||
|
.toConstantValue(
|
||||||
|
new TriggerEmailBackupForUser(
|
||||||
|
container.get<RoleServiceInterface>(TYPES.Auth_RoleService),
|
||||||
|
container.get<GetSetting>(TYPES.Auth_GetSetting),
|
||||||
|
container.get<GetUserKeyParams>(TYPES.Auth_GetUserKeyParams),
|
||||||
|
container.get<DomainEventPublisherInterface>(TYPES.Auth_DomainEventPublisher),
|
||||||
|
container.get<DomainEventFactoryInterface>(TYPES.Auth_DomainEventFactory),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
container
|
||||||
|
.bind<TriggerEmailBackupForAllUsers>(TYPES.Auth_TriggerEmailBackupForAllUsers)
|
||||||
|
.toConstantValue(
|
||||||
|
new TriggerEmailBackupForAllUsers(
|
||||||
|
container.get<SettingRepositoryInterface>(TYPES.Auth_SettingRepository),
|
||||||
|
container.get<TriggerEmailBackupForUser>(TYPES.Auth_TriggerEmailBackupForUser),
|
||||||
|
container.get<winston.Logger>(TYPES.Auth_Logger),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
container
|
||||||
|
.bind<TriggerPostSettingUpdateActions>(TYPES.Auth_TriggerPostSettingUpdateActions)
|
||||||
|
.toConstantValue(
|
||||||
|
new TriggerPostSettingUpdateActions(
|
||||||
|
container.get<DomainEventPublisherInterface>(TYPES.Auth_DomainEventPublisher),
|
||||||
|
container.get<DomainEventFactoryInterface>(TYPES.Auth_DomainEventFactory),
|
||||||
|
container.get<TriggerEmailBackupForUser>(TYPES.Auth_TriggerEmailBackupForUser),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
if (!isConfiguredForHomeServer) {
|
||||||
|
container
|
||||||
|
.bind<DeleteAccountsFromCSVFile>(TYPES.Auth_DeleteAccountsFromCSVFile)
|
||||||
|
.toConstantValue(
|
||||||
|
new DeleteAccountsFromCSVFile(
|
||||||
|
container.get<CSVFileReaderInterface>(TYPES.Auth_CSVFileReader),
|
||||||
|
container.get<DeleteAccount>(TYPES.Auth_DeleteAccount),
|
||||||
|
container.get<winston.Logger>(TYPES.Auth_Logger),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
// Controller
|
// Controller
|
||||||
container
|
container
|
||||||
@@ -1655,11 +1703,13 @@ export class ContainerConfigLoader {
|
|||||||
container.get<GetAllSettingsForUser>(TYPES.Auth_GetAllSettingsForUser),
|
container.get<GetAllSettingsForUser>(TYPES.Auth_GetAllSettingsForUser),
|
||||||
container.get<GetSetting>(TYPES.Auth_GetSetting),
|
container.get<GetSetting>(TYPES.Auth_GetSetting),
|
||||||
container.get<SetSettingValue>(TYPES.Auth_SetSettingValue),
|
container.get<SetSettingValue>(TYPES.Auth_SetSettingValue),
|
||||||
|
container.get<TriggerPostSettingUpdateActions>(TYPES.Auth_TriggerPostSettingUpdateActions),
|
||||||
container.get<DeleteSetting>(TYPES.Auth_DeleteSetting),
|
container.get<DeleteSetting>(TYPES.Auth_DeleteSetting),
|
||||||
container.get<MapperInterface<Setting, SettingHttpRepresentation>>(TYPES.Auth_SettingHttpMapper),
|
container.get<MapperInterface<Setting, SettingHttpRepresentation>>(TYPES.Auth_SettingHttpMapper),
|
||||||
container.get<MapperInterface<SubscriptionSetting, SubscriptionSettingHttpRepresentation>>(
|
container.get<MapperInterface<SubscriptionSetting, SubscriptionSettingHttpRepresentation>>(
|
||||||
TYPES.Auth_SubscriptionSettingHttpMapper,
|
TYPES.Auth_SubscriptionSettingHttpMapper,
|
||||||
),
|
),
|
||||||
|
container.get<winston.Logger>(TYPES.Auth_Logger),
|
||||||
container.get<ControllerContainerInterface>(TYPES.Auth_ControllerContainer),
|
container.get<ControllerContainerInterface>(TYPES.Auth_ControllerContainer),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ const TYPES = {
|
|||||||
Auth_Redis: Symbol.for('Auth_Redis'),
|
Auth_Redis: Symbol.for('Auth_Redis'),
|
||||||
Auth_SNS: Symbol.for('Auth_SNS'),
|
Auth_SNS: Symbol.for('Auth_SNS'),
|
||||||
Auth_SQS: Symbol.for('Auth_SQS'),
|
Auth_SQS: Symbol.for('Auth_SQS'),
|
||||||
|
Auth_S3: Symbol.for('Auth_S3'),
|
||||||
// Mapping
|
// Mapping
|
||||||
Auth_SessionTracePersistenceMapper: Symbol.for('Auth_SessionTracePersistenceMapper'),
|
Auth_SessionTracePersistenceMapper: Symbol.for('Auth_SessionTracePersistenceMapper'),
|
||||||
Auth_AuthenticatorChallengePersistenceMapper: Symbol.for('Auth_AuthenticatorChallengePersistenceMapper'),
|
Auth_AuthenticatorChallengePersistenceMapper: Symbol.for('Auth_AuthenticatorChallengePersistenceMapper'),
|
||||||
@@ -164,6 +165,10 @@ const TYPES = {
|
|||||||
Auth_DesignateSurvivor: Symbol.for('Auth_DesignateSurvivor'),
|
Auth_DesignateSurvivor: Symbol.for('Auth_DesignateSurvivor'),
|
||||||
Auth_GetSharedOrRegularSubscriptionForUser: Symbol.for('Auth_GetSharedOrRegularSubscriptionForUser'),
|
Auth_GetSharedOrRegularSubscriptionForUser: Symbol.for('Auth_GetSharedOrRegularSubscriptionForUser'),
|
||||||
Auth_DisableEmailSettingBasedOnEmailSubscription: Symbol.for('Auth_DisableEmailSettingBasedOnEmailSubscription'),
|
Auth_DisableEmailSettingBasedOnEmailSubscription: Symbol.for('Auth_DisableEmailSettingBasedOnEmailSubscription'),
|
||||||
|
Auth_TriggerPostSettingUpdateActions: Symbol.for('Auth_TriggerPostSettingUpdateActions'),
|
||||||
|
Auth_TriggerEmailBackupForUser: Symbol.for('Auth_TriggerEmailBackupForUser'),
|
||||||
|
Auth_TriggerEmailBackupForAllUsers: Symbol.for('Auth_TriggerEmailBackupForAllUsers'),
|
||||||
|
Auth_DeleteAccountsFromCSVFile: Symbol.for('Auth_DeleteAccountsFromCSVFile'),
|
||||||
// Handlers
|
// Handlers
|
||||||
Auth_AccountDeletionRequestedEventHandler: Symbol.for('Auth_AccountDeletionRequestedEventHandler'),
|
Auth_AccountDeletionRequestedEventHandler: Symbol.for('Auth_AccountDeletionRequestedEventHandler'),
|
||||||
Auth_SubscriptionPurchasedEventHandler: Symbol.for('Auth_SubscriptionPurchasedEventHandler'),
|
Auth_SubscriptionPurchasedEventHandler: Symbol.for('Auth_SubscriptionPurchasedEventHandler'),
|
||||||
@@ -230,7 +235,6 @@ const TYPES = {
|
|||||||
Auth_SubscriptionSettingsAssociationService: Symbol.for('Auth_SubscriptionSettingsAssociationService'),
|
Auth_SubscriptionSettingsAssociationService: Symbol.for('Auth_SubscriptionSettingsAssociationService'),
|
||||||
Auth_FeatureService: Symbol.for('Auth_FeatureService'),
|
Auth_FeatureService: Symbol.for('Auth_FeatureService'),
|
||||||
Auth_SettingCrypter: Symbol.for('Auth_SettingCrypter'),
|
Auth_SettingCrypter: Symbol.for('Auth_SettingCrypter'),
|
||||||
Auth_SettingInterpreter: Symbol.for('Auth_SettingInterpreter'),
|
|
||||||
Auth_ProtocolVersionSelector: Symbol.for('Auth_ProtocolVersionSelector'),
|
Auth_ProtocolVersionSelector: Symbol.for('Auth_ProtocolVersionSelector'),
|
||||||
Auth_BooleanSelector: Symbol.for('Auth_BooleanSelector'),
|
Auth_BooleanSelector: Symbol.for('Auth_BooleanSelector'),
|
||||||
Auth_BaseAuthController: Symbol.for('Auth_BaseAuthController'),
|
Auth_BaseAuthController: Symbol.for('Auth_BaseAuthController'),
|
||||||
@@ -249,6 +253,7 @@ const TYPES = {
|
|||||||
Auth_BaseOfflineController: Symbol.for('Auth_BaseOfflineController'),
|
Auth_BaseOfflineController: Symbol.for('Auth_BaseOfflineController'),
|
||||||
Auth_BaseListedController: Symbol.for('Auth_BaseListedController'),
|
Auth_BaseListedController: Symbol.for('Auth_BaseListedController'),
|
||||||
Auth_BaseFeaturesController: Symbol.for('Auth_BaseFeaturesController'),
|
Auth_BaseFeaturesController: Symbol.for('Auth_BaseFeaturesController'),
|
||||||
|
Auth_CSVFileReader: Symbol.for('Auth_CSVFileReader'),
|
||||||
}
|
}
|
||||||
|
|
||||||
export default TYPES
|
export default TYPES
|
||||||
|
|||||||
@@ -0,0 +1,5 @@
|
|||||||
|
import { Result } from '@standardnotes/domain-core'
|
||||||
|
|
||||||
|
export interface CSVFileReaderInterface {
|
||||||
|
getValues(fileName: string): Promise<Result<string[]>>
|
||||||
|
}
|
||||||
@@ -1,153 +0,0 @@
|
|||||||
import {
|
|
||||||
DomainEventPublisherInterface,
|
|
||||||
EmailBackupRequestedEvent,
|
|
||||||
MuteEmailsSettingChangedEvent,
|
|
||||||
UserDisabledSessionUserAgentLoggingEvent,
|
|
||||||
} from '@standardnotes/domain-events'
|
|
||||||
import { EmailBackupFrequency, LogSessionUserAgentOption, MuteMarketingEmailsOption } from '@standardnotes/settings'
|
|
||||||
import 'reflect-metadata'
|
|
||||||
import { Logger } from 'winston'
|
|
||||||
import { DomainEventFactoryInterface } from '../Event/DomainEventFactoryInterface'
|
|
||||||
import { User } from '../User/User'
|
|
||||||
import { Setting } from './Setting'
|
|
||||||
import { SettingCrypterInterface } from './SettingCrypterInterface'
|
|
||||||
|
|
||||||
import { SettingInterpreter } from './SettingInterpreter'
|
|
||||||
import { SettingRepositoryInterface } from './SettingRepositoryInterface'
|
|
||||||
import { GetUserKeyParams } from '../UseCase/GetUserKeyParams/GetUserKeyParams'
|
|
||||||
import { KeyParamsData } from '@standardnotes/responses'
|
|
||||||
import { Uuid, Timestamps, UniqueEntityId, SettingName } from '@standardnotes/domain-core'
|
|
||||||
|
|
||||||
describe('SettingInterpreter', () => {
|
|
||||||
let user: User
|
|
||||||
let domainEventPublisher: DomainEventPublisherInterface
|
|
||||||
let domainEventFactory: DomainEventFactoryInterface
|
|
||||||
let settingRepository: SettingRepositoryInterface
|
|
||||||
let settingCrypter: SettingCrypterInterface
|
|
||||||
let logger: Logger
|
|
||||||
let getUserKeyParams: GetUserKeyParams
|
|
||||||
|
|
||||||
const createInterpreter = () =>
|
|
||||||
new SettingInterpreter(domainEventPublisher, domainEventFactory, settingRepository, getUserKeyParams)
|
|
||||||
|
|
||||||
beforeEach(() => {
|
|
||||||
user = {
|
|
||||||
uuid: '4-5-6',
|
|
||||||
email: 'test@test.te',
|
|
||||||
} as jest.Mocked<User>
|
|
||||||
|
|
||||||
settingRepository = {} as jest.Mocked<SettingRepositoryInterface>
|
|
||||||
settingRepository.findLastByNameAndUserUuid = jest.fn().mockReturnValue(null)
|
|
||||||
settingRepository.findOneByNameAndUserUuid = jest.fn().mockReturnValue(null)
|
|
||||||
|
|
||||||
settingCrypter = {} as jest.Mocked<SettingCrypterInterface>
|
|
||||||
settingCrypter.decryptSettingValue = jest.fn().mockReturnValue('decrypted')
|
|
||||||
|
|
||||||
domainEventPublisher = {} as jest.Mocked<DomainEventPublisherInterface>
|
|
||||||
domainEventPublisher.publish = jest.fn()
|
|
||||||
|
|
||||||
domainEventFactory = {} as jest.Mocked<DomainEventFactoryInterface>
|
|
||||||
domainEventFactory.createEmailBackupRequestedEvent = jest
|
|
||||||
.fn()
|
|
||||||
.mockReturnValue({} as jest.Mocked<EmailBackupRequestedEvent>)
|
|
||||||
domainEventFactory.createUserDisabledSessionUserAgentLoggingEvent = jest
|
|
||||||
.fn()
|
|
||||||
.mockReturnValue({} as jest.Mocked<UserDisabledSessionUserAgentLoggingEvent>)
|
|
||||||
domainEventFactory.createMuteEmailsSettingChangedEvent = jest
|
|
||||||
.fn()
|
|
||||||
.mockReturnValue({} as jest.Mocked<MuteEmailsSettingChangedEvent>)
|
|
||||||
|
|
||||||
logger = {} as jest.Mocked<Logger>
|
|
||||||
logger.debug = jest.fn()
|
|
||||||
logger.warn = jest.fn()
|
|
||||||
logger.error = jest.fn()
|
|
||||||
|
|
||||||
getUserKeyParams = {} as jest.Mocked<GetUserKeyParams>
|
|
||||||
getUserKeyParams.execute = jest.fn().mockReturnValue({ keyParams: {} as jest.Mocked<KeyParamsData> })
|
|
||||||
})
|
|
||||||
|
|
||||||
it('should trigger session cleanup if user is disabling session user agent logging', async () => {
|
|
||||||
await createInterpreter().interpretSettingUpdated(
|
|
||||||
SettingName.NAMES.LogSessionUserAgent,
|
|
||||||
user,
|
|
||||||
LogSessionUserAgentOption.Disabled,
|
|
||||||
)
|
|
||||||
|
|
||||||
expect(domainEventPublisher.publish).toHaveBeenCalled()
|
|
||||||
expect(domainEventFactory.createUserDisabledSessionUserAgentLoggingEvent).toHaveBeenCalledWith({
|
|
||||||
userUuid: '4-5-6',
|
|
||||||
email: 'test@test.te',
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
it('should trigger backup if email backup setting is created - emails not muted', async () => {
|
|
||||||
await createInterpreter().interpretSettingUpdated(
|
|
||||||
SettingName.NAMES.EmailBackupFrequency,
|
|
||||||
user,
|
|
||||||
EmailBackupFrequency.Daily,
|
|
||||||
)
|
|
||||||
|
|
||||||
expect(domainEventPublisher.publish).toHaveBeenCalled()
|
|
||||||
expect(domainEventFactory.createEmailBackupRequestedEvent).toHaveBeenCalledWith('4-5-6', '', false, {})
|
|
||||||
})
|
|
||||||
|
|
||||||
it('should trigger backup if email backup setting is created - emails muted', async () => {
|
|
||||||
const setting = Setting.create(
|
|
||||||
{
|
|
||||||
name: SettingName.NAMES.MuteFailedBackupsEmails,
|
|
||||||
value: 'muted',
|
|
||||||
serverEncryptionVersion: 0,
|
|
||||||
userUuid: Uuid.create('00000000-0000-0000-0000-000000000000').getValue(),
|
|
||||||
sensitive: false,
|
|
||||||
timestamps: Timestamps.create(123, 123).getValue(),
|
|
||||||
},
|
|
||||||
new UniqueEntityId('7fb54003-1dd2-40bd-8900-2bacd6cf629c'),
|
|
||||||
).getValue()
|
|
||||||
|
|
||||||
settingRepository.findOneByNameAndUserUuid = jest.fn().mockReturnValue(setting)
|
|
||||||
|
|
||||||
await createInterpreter().interpretSettingUpdated(
|
|
||||||
SettingName.NAMES.EmailBackupFrequency,
|
|
||||||
user,
|
|
||||||
EmailBackupFrequency.Daily,
|
|
||||||
)
|
|
||||||
|
|
||||||
expect(domainEventPublisher.publish).toHaveBeenCalled()
|
|
||||||
expect(domainEventFactory.createEmailBackupRequestedEvent).toHaveBeenCalledWith(
|
|
||||||
'4-5-6',
|
|
||||||
'7fb54003-1dd2-40bd-8900-2bacd6cf629c',
|
|
||||||
true,
|
|
||||||
{},
|
|
||||||
)
|
|
||||||
})
|
|
||||||
|
|
||||||
it('should not trigger backup if email backup setting is disabled', async () => {
|
|
||||||
settingRepository.findOneByNameAndUserUuid = jest.fn().mockReturnValue(null)
|
|
||||||
|
|
||||||
await createInterpreter().interpretSettingUpdated(
|
|
||||||
SettingName.NAMES.EmailBackupFrequency,
|
|
||||||
user,
|
|
||||||
EmailBackupFrequency.Disabled,
|
|
||||||
)
|
|
||||||
|
|
||||||
expect(domainEventPublisher.publish).not.toHaveBeenCalled()
|
|
||||||
expect(domainEventFactory.createEmailBackupRequestedEvent).not.toHaveBeenCalled()
|
|
||||||
})
|
|
||||||
|
|
||||||
it('should trigger mute subscription emails rejection if mute setting changed', async () => {
|
|
||||||
settingRepository.findOneByNameAndUserUuid = jest.fn().mockReturnValue(null)
|
|
||||||
|
|
||||||
await createInterpreter().interpretSettingUpdated(
|
|
||||||
SettingName.NAMES.MuteMarketingEmails,
|
|
||||||
user,
|
|
||||||
MuteMarketingEmailsOption.Muted,
|
|
||||||
)
|
|
||||||
|
|
||||||
expect(domainEventPublisher.publish).toHaveBeenCalled()
|
|
||||||
expect(domainEventFactory.createMuteEmailsSettingChangedEvent).toHaveBeenCalledWith({
|
|
||||||
emailSubscriptionRejectionLevel: 'MARKETING',
|
|
||||||
mute: true,
|
|
||||||
username: 'test@test.te',
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
|
||||||
@@ -1,113 +0,0 @@
|
|||||||
import { DomainEventPublisherInterface } from '@standardnotes/domain-events'
|
|
||||||
import { EmailLevel, SettingName } from '@standardnotes/domain-core'
|
|
||||||
import { EmailBackupFrequency, LogSessionUserAgentOption, MuteFailedBackupsEmailsOption } from '@standardnotes/settings'
|
|
||||||
|
|
||||||
import { DomainEventFactoryInterface } from '../Event/DomainEventFactoryInterface'
|
|
||||||
import { User } from '../User/User'
|
|
||||||
import { SettingInterpreterInterface } from './SettingInterpreterInterface'
|
|
||||||
import { SettingRepositoryInterface } from './SettingRepositoryInterface'
|
|
||||||
import { GetUserKeyParams } from '../UseCase/GetUserKeyParams/GetUserKeyParams'
|
|
||||||
|
|
||||||
export class SettingInterpreter implements SettingInterpreterInterface {
|
|
||||||
private readonly emailSettingToSubscriptionRejectionLevelMap: Map<string, string> = new Map([
|
|
||||||
[SettingName.NAMES.MuteFailedBackupsEmails, EmailLevel.LEVELS.FailedEmailBackup],
|
|
||||||
[SettingName.NAMES.MuteFailedCloudBackupsEmails, EmailLevel.LEVELS.FailedCloudBackup],
|
|
||||||
[SettingName.NAMES.MuteMarketingEmails, EmailLevel.LEVELS.Marketing],
|
|
||||||
[SettingName.NAMES.MuteSignInEmails, EmailLevel.LEVELS.SignIn],
|
|
||||||
])
|
|
||||||
|
|
||||||
constructor(
|
|
||||||
private domainEventPublisher: DomainEventPublisherInterface,
|
|
||||||
private domainEventFactory: DomainEventFactoryInterface,
|
|
||||||
private settingRepository: SettingRepositoryInterface,
|
|
||||||
private getUserKeyParams: GetUserKeyParams,
|
|
||||||
) {}
|
|
||||||
|
|
||||||
async interpretSettingUpdated(
|
|
||||||
updatedSettingName: string,
|
|
||||||
user: User,
|
|
||||||
unencryptedValue: string | null,
|
|
||||||
): Promise<void> {
|
|
||||||
if (this.isChangingMuteEmailsSetting(updatedSettingName)) {
|
|
||||||
await this.triggerEmailSubscriptionChange(user, updatedSettingName, unencryptedValue)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.isEnablingEmailBackupSetting(updatedSettingName, unencryptedValue)) {
|
|
||||||
await this.triggerEmailBackup(user.uuid)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.isDisablingSessionUserAgentLogging(updatedSettingName, unencryptedValue)) {
|
|
||||||
await this.triggerSessionUserAgentCleanup(user)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private async triggerEmailBackup(userUuid: string): Promise<void> {
|
|
||||||
let userHasEmailsMuted = false
|
|
||||||
let muteEmailsSettingUuid = ''
|
|
||||||
const muteFailedEmailsBackupSetting = await this.settingRepository.findOneByNameAndUserUuid(
|
|
||||||
SettingName.NAMES.MuteFailedBackupsEmails,
|
|
||||||
userUuid,
|
|
||||||
)
|
|
||||||
if (muteFailedEmailsBackupSetting !== null) {
|
|
||||||
userHasEmailsMuted = muteFailedEmailsBackupSetting.props.value === MuteFailedBackupsEmailsOption.Muted
|
|
||||||
muteEmailsSettingUuid = muteFailedEmailsBackupSetting.id.toString()
|
|
||||||
}
|
|
||||||
|
|
||||||
const keyParamsResponse = await this.getUserKeyParams.execute({
|
|
||||||
authenticated: false,
|
|
||||||
userUuid,
|
|
||||||
})
|
|
||||||
|
|
||||||
await this.domainEventPublisher.publish(
|
|
||||||
this.domainEventFactory.createEmailBackupRequestedEvent(
|
|
||||||
userUuid,
|
|
||||||
muteEmailsSettingUuid,
|
|
||||||
userHasEmailsMuted,
|
|
||||||
keyParamsResponse.keyParams,
|
|
||||||
),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
private isChangingMuteEmailsSetting(settingName: string): boolean {
|
|
||||||
return [
|
|
||||||
SettingName.NAMES.MuteFailedBackupsEmails,
|
|
||||||
SettingName.NAMES.MuteFailedCloudBackupsEmails,
|
|
||||||
SettingName.NAMES.MuteMarketingEmails,
|
|
||||||
SettingName.NAMES.MuteSignInEmails,
|
|
||||||
].includes(settingName)
|
|
||||||
}
|
|
||||||
|
|
||||||
private isEnablingEmailBackupSetting(settingName: string, newValue: string | null): boolean {
|
|
||||||
return (
|
|
||||||
settingName === SettingName.NAMES.EmailBackupFrequency &&
|
|
||||||
[EmailBackupFrequency.Daily, EmailBackupFrequency.Weekly].includes(newValue as EmailBackupFrequency)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
private isDisablingSessionUserAgentLogging(settingName: string, newValue: string | null): boolean {
|
|
||||||
return SettingName.NAMES.LogSessionUserAgent === settingName && LogSessionUserAgentOption.Disabled === newValue
|
|
||||||
}
|
|
||||||
|
|
||||||
private async triggerEmailSubscriptionChange(
|
|
||||||
user: User,
|
|
||||||
settingName: string,
|
|
||||||
unencryptedValue: string | null,
|
|
||||||
): Promise<void> {
|
|
||||||
await this.domainEventPublisher.publish(
|
|
||||||
this.domainEventFactory.createMuteEmailsSettingChangedEvent({
|
|
||||||
username: user.email,
|
|
||||||
mute: unencryptedValue === 'muted',
|
|
||||||
emailSubscriptionRejectionLevel: this.emailSettingToSubscriptionRejectionLevelMap.get(settingName) as string,
|
|
||||||
}),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
private async triggerSessionUserAgentCleanup(user: User) {
|
|
||||||
await this.domainEventPublisher.publish(
|
|
||||||
this.domainEventFactory.createUserDisabledSessionUserAgentLoggingEvent({
|
|
||||||
userUuid: user.uuid,
|
|
||||||
email: user.email,
|
|
||||||
}),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
import { User } from '../User/User'
|
|
||||||
|
|
||||||
export interface SettingInterpreterInterface {
|
|
||||||
interpretSettingUpdated(updatedSettingName: string, user: User, newUnencryptedValue: string | null): Promise<void>
|
|
||||||
}
|
|
||||||
@@ -1,4 +1,3 @@
|
|||||||
import { ReadStream } from 'fs'
|
|
||||||
import { SettingName } from '@standardnotes/domain-core'
|
import { SettingName } from '@standardnotes/domain-core'
|
||||||
|
|
||||||
import { DeleteSettingDto } from '../UseCase/DeleteSetting/DeleteSettingDto'
|
import { DeleteSettingDto } from '../UseCase/DeleteSetting/DeleteSettingDto'
|
||||||
@@ -10,8 +9,8 @@ export interface SettingRepositoryInterface {
|
|||||||
findOneByNameAndUserUuid(name: string, userUuid: string): Promise<Setting | null>
|
findOneByNameAndUserUuid(name: string, userUuid: string): Promise<Setting | null>
|
||||||
findLastByNameAndUserUuid(name: string, userUuid: string): Promise<Setting | null>
|
findLastByNameAndUserUuid(name: string, userUuid: string): Promise<Setting | null>
|
||||||
findAllByUserUuid(userUuid: string): Promise<Setting[]>
|
findAllByUserUuid(userUuid: string): Promise<Setting[]>
|
||||||
streamAllByNameAndValue(name: SettingName, value: string): Promise<ReadStream>
|
countAllByNameAndValue(dto: { name: SettingName; value: string }): Promise<number>
|
||||||
streamAllByName(name: SettingName): Promise<ReadStream>
|
findAllByNameAndValue(dto: { name: SettingName; value: string; offset: number; limit: number }): Promise<Setting[]>
|
||||||
deleteByUserUuid(dto: DeleteSettingDto): Promise<void>
|
deleteByUserUuid(dto: DeleteSettingDto): Promise<void>
|
||||||
insert(setting: Setting): Promise<void>
|
insert(setting: Setting): Promise<void>
|
||||||
update(setting: Setting): Promise<void>
|
update(setting: Setting): Promise<void>
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user