feat: add grpc sessions validation server (#928)
* feat: add grpc sessions validation server * feat: add client implementation on api gateway * fix: response codes * fix: errored response * feat: add configuring grpc as optional service proxy * fix env vars * fix linter issue
This commit is contained in:
parent
ce081274da
commit
4f62cac213
65 changed files with 1415 additions and 42 deletions
3
.github/workflows/e2e-self-hosted.yml
vendored
3
.github/workflows/e2e-self-hosted.yml
vendored
|
@ -17,6 +17,8 @@ jobs:
|
|||
name: (Self Hosting) E2E Test Suite
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
service_proxy_type: [http, grpc]
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
services:
|
||||
|
@ -42,6 +44,7 @@ jobs:
|
|||
env:
|
||||
DB_TYPE: mysql
|
||||
CACHE_TYPE: redis
|
||||
SERVICE_PROXY_TYPE: ${{ matrix.service_proxy_type }}
|
||||
|
||||
- name: Wait for server to start
|
||||
run: docker/is-available.sh http://localhost:3123 $(pwd)/logs
|
||||
|
|
95
.pnp.cjs
generated
95
.pnp.cjs
generated
|
@ -45,6 +45,10 @@ const RAW_RUNTIME_STATE =
|
|||
"name": "@standardnotes/files-server",\
|
||||
"reference": "workspace:packages/files"\
|
||||
},\
|
||||
{\
|
||||
"name": "@standardnotes/grpc",\
|
||||
"reference": "workspace:packages/grpc"\
|
||||
},\
|
||||
{\
|
||||
"name": "@standardnotes/home-server",\
|
||||
"reference": "workspace:packages/home-server"\
|
||||
|
@ -97,6 +101,7 @@ const RAW_RUNTIME_STATE =
|
|||
["@standardnotes/domain-events", ["workspace:packages/domain-events"]],\
|
||||
["@standardnotes/domain-events-infra", ["workspace:packages/domain-events-infra"]],\
|
||||
["@standardnotes/files-server", ["workspace:packages/files"]],\
|
||||
["@standardnotes/grpc", ["workspace:packages/grpc"]],\
|
||||
["@standardnotes/home-server", ["workspace:packages/home-server"]],\
|
||||
["@standardnotes/predicates", ["workspace:packages/predicates"]],\
|
||||
["@standardnotes/revisions-server", ["workspace:packages/revisions"]],\
|
||||
|
@ -2669,6 +2674,15 @@ const RAW_RUNTIME_STATE =
|
|||
}]\
|
||||
]],\
|
||||
["@grpc/grpc-js", [\
|
||||
["npm:1.9.10", {\
|
||||
"packageLocation": "./.yarn/cache/@grpc-grpc-js-npm-1.9.10-28317a9d2d-243cf994e6.zip/node_modules/@grpc/grpc-js/",\
|
||||
"packageDependencies": [\
|
||||
["@grpc/grpc-js", "npm:1.9.10"],\
|
||||
["@grpc/proto-loader", "npm:0.7.10"],\
|
||||
["@types/node", "npm:20.2.5"]\
|
||||
],\
|
||||
"linkType": "HARD"\
|
||||
}],\
|
||||
["npm:1.9.5", {\
|
||||
"packageLocation": "./.yarn/cache/@grpc-grpc-js-npm-1.9.5-9b0cd6b5ed-5499d964d2.zip/node_modules/@grpc/grpc-js/",\
|
||||
"packageDependencies": [\
|
||||
|
@ -3570,6 +3584,22 @@ const RAW_RUNTIME_STATE =
|
|||
["tar", "npm:6.1.15"]\
|
||||
],\
|
||||
"linkType": "HARD"\
|
||||
}],\
|
||||
["npm:1.0.11", {\
|
||||
"packageLocation": "./.yarn/cache/@mapbox-node-pre-gyp-npm-1.0.11-5547f15a2b-59529a2444.zip/node_modules/@mapbox/node-pre-gyp/",\
|
||||
"packageDependencies": [\
|
||||
["@mapbox/node-pre-gyp", "npm:1.0.11"],\
|
||||
["detect-libc", "npm:2.0.1"],\
|
||||
["https-proxy-agent", "npm:5.0.1"],\
|
||||
["make-dir", "npm:3.1.0"],\
|
||||
["node-fetch", "virtual:0f92dfe7f9dc4fd492639d4a5b7805c2b27442bf599fd4f370b22a7966ba078f5d4525e2a8e8af29369f20e1833ed084bd52be59679efaa6c1c6c10cdbcd8baa#npm:2.6.11"],\
|
||||
["nopt", "npm:5.0.0"],\
|
||||
["npmlog", "npm:5.0.1"],\
|
||||
["rimraf", "npm:3.0.2"],\
|
||||
["semver", "npm:7.5.1"],\
|
||||
["tar", "npm:6.1.15"]\
|
||||
],\
|
||||
"linkType": "HARD"\
|
||||
}]\
|
||||
]],\
|
||||
["@nodelib/fs.scandir", [\
|
||||
|
@ -6371,9 +6401,11 @@ const RAW_RUNTIME_STATE =
|
|||
"packageLocation": "./packages/api-gateway/",\
|
||||
"packageDependencies": [\
|
||||
["@standardnotes/api-gateway", "workspace:packages/api-gateway"],\
|
||||
["@grpc/grpc-js", "npm:1.9.10"],\
|
||||
["@standardnotes/domain-core", "workspace:packages/domain-core"],\
|
||||
["@standardnotes/domain-events", "workspace:packages/domain-events"],\
|
||||
["@standardnotes/domain-events-infra", "workspace:packages/domain-events-infra"],\
|
||||
["@standardnotes/grpc", "workspace:packages/grpc"],\
|
||||
["@standardnotes/security", "workspace:packages/security"],\
|
||||
["@standardnotes/time", "workspace:packages/time"],\
|
||||
["@types/cors", "npm:2.8.13"],\
|
||||
|
@ -6419,6 +6451,7 @@ const RAW_RUNTIME_STATE =
|
|||
["@aws-sdk/client-sqs", "npm:3.427.0"],\
|
||||
["@cbor-extract/cbor-extract-linux-arm64", "npm:2.1.1"],\
|
||||
["@cbor-extract/cbor-extract-linux-x64", "npm:2.1.1"],\
|
||||
["@grpc/grpc-js", "npm:1.9.10"],\
|
||||
["@simplewebauthn/server", "npm:8.1.1"],\
|
||||
["@simplewebauthn/typescript-types", "npm:8.0.0"],\
|
||||
["@standardnotes/api", "npm:1.26.26"],\
|
||||
|
@ -6427,6 +6460,7 @@ const RAW_RUNTIME_STATE =
|
|||
["@standardnotes/domain-events", "workspace:packages/domain-events"],\
|
||||
["@standardnotes/domain-events-infra", "workspace:packages/domain-events-infra"],\
|
||||
["@standardnotes/features", "npm:1.59.7"],\
|
||||
["@standardnotes/grpc", "workspace:packages/grpc"],\
|
||||
["@standardnotes/predicates", "workspace:packages/predicates"],\
|
||||
["@standardnotes/responses", "npm:1.13.27"],\
|
||||
["@standardnotes/security", "workspace:packages/security"],\
|
||||
|
@ -6639,6 +6673,21 @@ const RAW_RUNTIME_STATE =
|
|||
"linkType": "SOFT"\
|
||||
}]\
|
||||
]],\
|
||||
["@standardnotes/grpc", [\
|
||||
["workspace:packages/grpc", {\
|
||||
"packageLocation": "./packages/grpc/",\
|
||||
"packageDependencies": [\
|
||||
["@standardnotes/grpc", "workspace:packages/grpc"],\
|
||||
["@grpc/grpc-js", "npm:1.9.10"],\
|
||||
["@types/google-protobuf", "npm:3.15.10"],\
|
||||
["google-protobuf", "npm:3.21.2"],\
|
||||
["grpc-tools", "npm:1.12.4"],\
|
||||
["grpc_tools_node_protoc_ts", "npm:5.3.3"],\
|
||||
["typescript", "patch:typescript@npm%3A5.0.4#optional!builtin<compat/typescript>::version=5.0.4&hash=b5f058"]\
|
||||
],\
|
||||
"linkType": "SOFT"\
|
||||
}]\
|
||||
]],\
|
||||
["@standardnotes/home-server", [\
|
||||
["workspace:packages/home-server", {\
|
||||
"packageLocation": "./packages/home-server/",\
|
||||
|
@ -7284,6 +7333,15 @@ const RAW_RUNTIME_STATE =
|
|||
"linkType": "HARD"\
|
||||
}]\
|
||||
]],\
|
||||
["@types/google-protobuf", [\
|
||||
["npm:3.15.10", {\
|
||||
"packageLocation": "./.yarn/cache/@types-google-protobuf-npm-3.15.10-cbaa6c3e6c-29efde966f.zip/node_modules/@types/google-protobuf/",\
|
||||
"packageDependencies": [\
|
||||
["@types/google-protobuf", "npm:3.15.10"]\
|
||||
],\
|
||||
"linkType": "HARD"\
|
||||
}]\
|
||||
]],\
|
||||
["@types/graceful-fs", [\
|
||||
["npm:4.1.6", {\
|
||||
"packageLocation": "./.yarn/cache/@types-graceful-fs-npm-4.1.6-1eadcf742d-c3070ccdc9.zip/node_modules/@types/graceful-fs/",\
|
||||
|
@ -11296,6 +11354,22 @@ const RAW_RUNTIME_STATE =
|
|||
"linkType": "HARD"\
|
||||
}]\
|
||||
]],\
|
||||
["google-protobuf", [\
|
||||
["npm:3.15.8", {\
|
||||
"packageLocation": "./.yarn/cache/google-protobuf-npm-3.15.8-75df975b6c-0b1ea24a55.zip/node_modules/google-protobuf/",\
|
||||
"packageDependencies": [\
|
||||
["google-protobuf", "npm:3.15.8"]\
|
||||
],\
|
||||
"linkType": "HARD"\
|
||||
}],\
|
||||
["npm:3.21.2", {\
|
||||
"packageLocation": "./.yarn/cache/google-protobuf-npm-3.21.2-7c82de39ab-b376c2e47f.zip/node_modules/google-protobuf/",\
|
||||
"packageDependencies": [\
|
||||
["google-protobuf", "npm:3.21.2"]\
|
||||
],\
|
||||
"linkType": "HARD"\
|
||||
}]\
|
||||
]],\
|
||||
["graceful-fs", [\
|
||||
["npm:4.2.11", {\
|
||||
"packageLocation": "./.yarn/cache/graceful-fs-npm-4.2.11-24bb648a68-bf152d0ed1.zip/node_modules/graceful-fs/",\
|
||||
|
@ -11314,6 +11388,27 @@ const RAW_RUNTIME_STATE =
|
|||
"linkType": "HARD"\
|
||||
}]\
|
||||
]],\
|
||||
["grpc-tools", [\
|
||||
["npm:1.12.4", {\
|
||||
"packageLocation": "./.yarn/unplugged/grpc-tools-npm-1.12.4-956df6794d/node_modules/grpc-tools/",\
|
||||
"packageDependencies": [\
|
||||
["grpc-tools", "npm:1.12.4"],\
|
||||
["@mapbox/node-pre-gyp", "npm:1.0.11"]\
|
||||
],\
|
||||
"linkType": "HARD"\
|
||||
}]\
|
||||
]],\
|
||||
["grpc_tools_node_protoc_ts", [\
|
||||
["npm:5.3.3", {\
|
||||
"packageLocation": "./.yarn/unplugged/grpc_tools_node_protoc_ts-npm-5.3.3-297a345c26/node_modules/grpc_tools_node_protoc_ts/",\
|
||||
"packageDependencies": [\
|
||||
["grpc_tools_node_protoc_ts", "npm:5.3.3"],\
|
||||
["google-protobuf", "npm:3.15.8"],\
|
||||
["handlebars", "npm:4.7.7"]\
|
||||
],\
|
||||
"linkType": "HARD"\
|
||||
}]\
|
||||
]],\
|
||||
["handlebars", [\
|
||||
["npm:4.7.7", {\
|
||||
"packageLocation": "./.yarn/cache/handlebars-npm-4.7.7-a9ccfabf80-617b1e689b.zip/node_modules/handlebars/",\
|
||||
|
|
BIN
.yarn/cache/@grpc-grpc-js-npm-1.9.10-28317a9d2d-243cf994e6.zip
vendored
Normal file
BIN
.yarn/cache/@grpc-grpc-js-npm-1.9.10-28317a9d2d-243cf994e6.zip
vendored
Normal file
Binary file not shown.
BIN
.yarn/cache/@mapbox-node-pre-gyp-npm-1.0.11-5547f15a2b-59529a2444.zip
vendored
Normal file
BIN
.yarn/cache/@mapbox-node-pre-gyp-npm-1.0.11-5547f15a2b-59529a2444.zip
vendored
Normal file
Binary file not shown.
BIN
.yarn/cache/@types-google-protobuf-npm-3.15.10-cbaa6c3e6c-29efde966f.zip
vendored
Normal file
BIN
.yarn/cache/@types-google-protobuf-npm-3.15.10-cbaa6c3e6c-29efde966f.zip
vendored
Normal file
Binary file not shown.
BIN
.yarn/cache/google-protobuf-npm-3.15.8-75df975b6c-0b1ea24a55.zip
vendored
Normal file
BIN
.yarn/cache/google-protobuf-npm-3.15.8-75df975b6c-0b1ea24a55.zip
vendored
Normal file
Binary file not shown.
BIN
.yarn/cache/google-protobuf-npm-3.21.2-7c82de39ab-b376c2e47f.zip
vendored
Normal file
BIN
.yarn/cache/google-protobuf-npm-3.21.2-7c82de39ab-b376c2e47f.zip
vendored
Normal file
Binary file not shown.
BIN
.yarn/cache/grpc-tools-npm-1.12.4-956df6794d-56852c756f.zip
vendored
Normal file
BIN
.yarn/cache/grpc-tools-npm-1.12.4-956df6794d-56852c756f.zip
vendored
Normal file
Binary file not shown.
BIN
.yarn/cache/grpc_tools_node_protoc_ts-npm-5.3.3-297a345c26-96fe57b04a.zip
vendored
Normal file
BIN
.yarn/cache/grpc_tools_node_protoc_ts-npm-5.3.3-297a345c26-96fe57b04a.zip
vendored
Normal file
Binary file not shown.
|
@ -26,6 +26,7 @@ services:
|
|||
ports:
|
||||
- 3123:3000
|
||||
- 3125:3104
|
||||
- 50051:50051
|
||||
volumes:
|
||||
- ./logs:/var/lib/server/logs
|
||||
networks:
|
||||
|
|
|
@ -18,6 +18,10 @@ if [ -z "$AUTH_SERVER_PORT" ]; then
|
|||
export AUTH_SERVER_PORT=3103
|
||||
fi
|
||||
|
||||
if [ -z "$AUTH_SERVER_GRPC_PORT" ]; then
|
||||
export AUTH_SERVER_GRPC_PORT=50051
|
||||
fi
|
||||
|
||||
export FILES_SERVER_PORT=3104
|
||||
|
||||
if [ -z "$REVISIONS_SERVER_PORT" ]; then
|
||||
|
@ -353,6 +357,7 @@ export API_GATEWAY_VERSION=local
|
|||
|
||||
export API_GATEWAY_SYNCING_SERVER_JS_URL=http://localhost:$SYNCING_SERVER_PORT
|
||||
export API_GATEWAY_AUTH_SERVER_URL=http://localhost:$AUTH_SERVER_PORT
|
||||
export API_GATEWAY_AUTH_SERVER_GRPC_URL=0.0.0.0:$AUTH_SERVER_GRPC_PORT
|
||||
export API_GATEWAY_REVISIONS_SERVER_URL=http://localhost:$REVISIONS_SERVER_PORT
|
||||
if [ -z "$PUBLIC_FILES_SERVER_URL" ]; then
|
||||
export PUBLIC_FILES_SERVER_URL=http://localhost:3125
|
||||
|
|
10
package.json
10
package.json
|
@ -39,5 +39,13 @@
|
|||
"ts-node": "^10.9.1",
|
||||
"typescript": "^5.0.4"
|
||||
},
|
||||
"packageManager": "yarn@4.0.0-rc.51"
|
||||
"packageManager": "yarn@4.0.0-rc.51",
|
||||
"dependenciesMeta": {
|
||||
"grpc-tools@1.12.4": {
|
||||
"unplugged": true
|
||||
},
|
||||
"grpc_tools_node_protoc_ts@5.3.3": {
|
||||
"unplugged": true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@ PORT=3000
|
|||
|
||||
SYNCING_SERVER_JS_URL=http://syncing_server_js:3000
|
||||
AUTH_SERVER_URL=http://auth:3000
|
||||
AUTH_SERVER_GRPC_URL=http://auth:50051
|
||||
WEB_SOCKET_SERVER_URL=http://websockets:3000
|
||||
PAYMENTS_SERVER_URL=http://payments:3000
|
||||
FILES_SERVER_URL=http://files:3000
|
||||
|
|
|
@ -111,7 +111,7 @@ void container.load().then((container) => {
|
|||
|
||||
const serverInstance = server.build().listen(env.get('PORT'))
|
||||
|
||||
const keepAliveTimeout = env.get('KEEP_ALIVE_TIMEOUT', true) ? +env.get('KEEP_ALIVE_TIMEOUT', true) : 5000
|
||||
const keepAliveTimeout = env.get('HTTP_KEEP_ALIVE_TIMEOUT', true) ? +env.get('HTTP_KEEP_ALIVE_TIMEOUT', true) : 5000
|
||||
|
||||
serverInstance.keepAliveTimeout = keepAliveTimeout
|
||||
|
||||
|
|
|
@ -26,9 +26,11 @@
|
|||
"start": "yarn node dist/bin/server.js"
|
||||
},
|
||||
"dependencies": {
|
||||
"@grpc/grpc-js": "^1.9.10",
|
||||
"@standardnotes/domain-core": "workspace:^",
|
||||
"@standardnotes/domain-events": "workspace:*",
|
||||
"@standardnotes/domain-events-infra": "workspace:*",
|
||||
"@standardnotes/grpc": "workspace:^",
|
||||
"@standardnotes/security": "workspace:*",
|
||||
"@standardnotes/time": "workspace:*",
|
||||
"agentkeepalive": "^4.5.0",
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import * as winston from 'winston'
|
||||
import * as AgentKeepAlive from 'agentkeepalive'
|
||||
import * as grpc from '@grpc/grpc-js'
|
||||
import axios, { AxiosInstance } from 'axios'
|
||||
import Redis from 'ioredis'
|
||||
import { Container } from 'inversify'
|
||||
|
@ -7,20 +8,22 @@ import { Timer, TimerInterface } from '@standardnotes/time'
|
|||
|
||||
import { Env } from './Env'
|
||||
import { TYPES } from './Types'
|
||||
import { ServiceProxyInterface } from '../Service/Http/ServiceProxyInterface'
|
||||
import { ServiceProxyInterface } from '../Service/Proxy/ServiceProxyInterface'
|
||||
import { HttpServiceProxy } from '../Service/Http/HttpServiceProxy'
|
||||
import { SubscriptionTokenAuthMiddleware } from '../Controller/SubscriptionTokenAuthMiddleware'
|
||||
import { CrossServiceTokenCacheInterface } from '../Service/Cache/CrossServiceTokenCacheInterface'
|
||||
import { RedisCrossServiceTokenCache } from '../Infra/Redis/RedisCrossServiceTokenCache'
|
||||
import { WebSocketAuthMiddleware } from '../Controller/WebSocketAuthMiddleware'
|
||||
import { InMemoryCrossServiceTokenCache } from '../Infra/InMemory/InMemoryCrossServiceTokenCache'
|
||||
import { DirectCallServiceProxy } from '../Service/Proxy/DirectCallServiceProxy'
|
||||
import { DirectCallServiceProxy } from '../Service/DirectCall/DirectCallServiceProxy'
|
||||
import { ServiceContainerInterface } from '@standardnotes/domain-core'
|
||||
import { EndpointResolverInterface } from '../Service/Resolver/EndpointResolverInterface'
|
||||
import { EndpointResolver } from '../Service/Resolver/EndpointResolver'
|
||||
import { RequiredCrossServiceTokenMiddleware } from '../Controller/RequiredCrossServiceTokenMiddleware'
|
||||
import { OptionalCrossServiceTokenMiddleware } from '../Controller/OptionalCrossServiceTokenMiddleware'
|
||||
import { Transform } from 'stream'
|
||||
import { ISessionsClient, SessionsClient } from '@standardnotes/grpc'
|
||||
import { GRPCServiceProxy } from '../Service/gRPC/GRPCServiceProxy'
|
||||
|
||||
export class ContainerConfigLoader {
|
||||
async load(configuration?: {
|
||||
|
@ -69,14 +72,16 @@ export class ContainerConfigLoader {
|
|||
container.bind(TYPES.ApiGateway_Redis).toConstantValue(redis)
|
||||
}
|
||||
|
||||
const httpAgentKeepAliveTimeout = env.get('HTTP_AGENT_KEEP_ALIVE_TIMEOUT', true)
|
||||
? +env.get('HTTP_AGENT_KEEP_ALIVE_TIMEOUT', true)
|
||||
: 4_000
|
||||
|
||||
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,
|
||||
timeout: 2 * httpAgentKeepAliveTimeout,
|
||||
freeSocketTimeout: httpAgentKeepAliveTimeout,
|
||||
}),
|
||||
}),
|
||||
)
|
||||
|
@ -124,7 +129,44 @@ export class ContainerConfigLoader {
|
|||
new DirectCallServiceProxy(configuration.serviceContainer, container.get(TYPES.ApiGateway_FILES_SERVER_URL)),
|
||||
)
|
||||
} else {
|
||||
container.bind<ServiceProxyInterface>(TYPES.ApiGateway_ServiceProxy).to(HttpServiceProxy)
|
||||
const isConfiguredForGRPCProxy = env.get('SERVICE_PROXY_TYPE', true) === 'grpc'
|
||||
if (isConfiguredForGRPCProxy) {
|
||||
container.bind(TYPES.ApiGateway_AUTH_SERVER_GRPC_URL).toConstantValue(env.get('AUTH_SERVER_GRPC_URL'))
|
||||
const grpcAgentKeepAliveTimeout = env.get('GRPC_AGENT_KEEP_ALIVE_TIMEOUT', true)
|
||||
? +env.get('GRPC_AGENT_KEEP_ALIVE_TIMEOUT', true)
|
||||
: 8_000
|
||||
container.bind<ISessionsClient>(TYPES.ApiGateway_GRPCSessionsClient).toConstantValue(
|
||||
new SessionsClient(
|
||||
container.get<string>(TYPES.ApiGateway_AUTH_SERVER_GRPC_URL),
|
||||
grpc.credentials.createInsecure(),
|
||||
{
|
||||
'grpc.keepalive_time_ms': grpcAgentKeepAliveTimeout * 2,
|
||||
'grpc.keepalive_timeout_ms': grpcAgentKeepAliveTimeout,
|
||||
},
|
||||
),
|
||||
)
|
||||
container
|
||||
.bind<ServiceProxyInterface>(TYPES.ApiGateway_ServiceProxy)
|
||||
.toConstantValue(
|
||||
new GRPCServiceProxy(
|
||||
container.get<AxiosInstance>(TYPES.ApiGateway_HTTPClient),
|
||||
container.get<string>(TYPES.ApiGateway_AUTH_SERVER_URL),
|
||||
container.get<string>(TYPES.ApiGateway_SYNCING_SERVER_JS_URL),
|
||||
container.get<string>(TYPES.ApiGateway_PAYMENTS_SERVER_URL),
|
||||
container.get<string>(TYPES.ApiGateway_FILES_SERVER_URL),
|
||||
container.get<string>(TYPES.ApiGateway_WEB_SOCKET_SERVER_URL),
|
||||
container.get<string>(TYPES.ApiGateway_REVISIONS_SERVER_URL),
|
||||
container.get<string>(TYPES.ApiGateway_EMAIL_SERVER_URL),
|
||||
container.get<number>(TYPES.ApiGateway_HTTP_CALL_TIMEOUT),
|
||||
container.get<CrossServiceTokenCacheInterface>(TYPES.ApiGateway_CrossServiceTokenCache),
|
||||
container.get<winston.Logger>(TYPES.ApiGateway_Logger),
|
||||
container.get<TimerInterface>(TYPES.ApiGateway_Timer),
|
||||
container.get<ISessionsClient>(TYPES.ApiGateway_GRPCSessionsClient),
|
||||
),
|
||||
)
|
||||
} else {
|
||||
container.bind<ServiceProxyInterface>(TYPES.ApiGateway_ServiceProxy).to(HttpServiceProxy)
|
||||
}
|
||||
}
|
||||
|
||||
if (isConfiguredForHomeServer) {
|
||||
|
|
|
@ -5,6 +5,7 @@ export const TYPES = {
|
|||
// env vars
|
||||
ApiGateway_SYNCING_SERVER_JS_URL: Symbol.for('ApiGateway_SYNCING_SERVER_JS_URL'),
|
||||
ApiGateway_AUTH_SERVER_URL: Symbol.for('ApiGateway_AUTH_SERVER_URL'),
|
||||
ApiGateway_AUTH_SERVER_GRPC_URL: Symbol.for('ApiGateway_AUTH_SERVER_GRPC_URL'),
|
||||
ApiGateway_PAYMENTS_SERVER_URL: Symbol.for('ApiGateway_PAYMENTS_SERVER_URL'),
|
||||
ApiGateway_FILES_SERVER_URL: Symbol.for('ApiGateway_FILES_SERVER_URL'),
|
||||
ApiGateway_REVISIONS_SERVER_URL: Symbol.for('ApiGateway_REVISIONS_SERVER_URL'),
|
||||
|
@ -28,4 +29,5 @@ export const TYPES = {
|
|||
ApiGateway_CrossServiceTokenCache: Symbol.for('ApiGateway_CrossServiceTokenCache'),
|
||||
ApiGateway_Timer: Symbol.for('ApiGateway_Timer'),
|
||||
ApiGateway_EndpointResolver: Symbol.for('ApiGateway_EndpointResolver'),
|
||||
ApiGateway_GRPCSessionsClient: Symbol.for('ApiGateway_GRPCSessionsClient'),
|
||||
}
|
||||
|
|
|
@ -7,7 +7,7 @@ import { AxiosError } from 'axios'
|
|||
import { Logger } from 'winston'
|
||||
|
||||
import { CrossServiceTokenCacheInterface } from '../Service/Cache/CrossServiceTokenCacheInterface'
|
||||
import { ServiceProxyInterface } from '../Service/Http/ServiceProxyInterface'
|
||||
import { ServiceProxyInterface } from '../Service/Proxy/ServiceProxyInterface'
|
||||
|
||||
export abstract class AuthMiddleware extends BaseMiddleware {
|
||||
constructor(
|
||||
|
|
|
@ -2,7 +2,7 @@ import { Request, Response } from 'express'
|
|||
import { inject } from 'inversify'
|
||||
import { controller, all, BaseHttpController, httpPost, httpGet, results, httpDelete } from 'inversify-express-utils'
|
||||
import { TYPES } from '../Bootstrap/Types'
|
||||
import { ServiceProxyInterface } from '../Service/Http/ServiceProxyInterface'
|
||||
import { ServiceProxyInterface } from '../Service/Proxy/ServiceProxyInterface'
|
||||
|
||||
@controller('')
|
||||
export class LegacyController extends BaseHttpController {
|
||||
|
|
|
@ -5,7 +5,7 @@ import { Logger } from 'winston'
|
|||
|
||||
import { TYPES } from '../Bootstrap/Types'
|
||||
import { CrossServiceTokenCacheInterface } from '../Service/Cache/CrossServiceTokenCacheInterface'
|
||||
import { ServiceProxyInterface } from '../Service/Http/ServiceProxyInterface'
|
||||
import { ServiceProxyInterface } from '../Service/Proxy/ServiceProxyInterface'
|
||||
import { AuthMiddleware } from './AuthMiddleware'
|
||||
|
||||
@injectable()
|
||||
|
|
|
@ -5,7 +5,7 @@ import { Logger } from 'winston'
|
|||
|
||||
import { TYPES } from '../Bootstrap/Types'
|
||||
import { CrossServiceTokenCacheInterface } from '../Service/Cache/CrossServiceTokenCacheInterface'
|
||||
import { ServiceProxyInterface } from '../Service/Http/ServiceProxyInterface'
|
||||
import { ServiceProxyInterface } from '../Service/Proxy/ServiceProxyInterface'
|
||||
import { AuthMiddleware } from './AuthMiddleware'
|
||||
|
||||
@injectable()
|
||||
|
|
|
@ -2,7 +2,7 @@ import { Request, Response } from 'express'
|
|||
import { inject } from 'inversify'
|
||||
import { BaseHttpController, controller, httpGet, httpPost } from 'inversify-express-utils'
|
||||
import { TYPES } from '../../Bootstrap/Types'
|
||||
import { ServiceProxyInterface } from '../../Service/Http/ServiceProxyInterface'
|
||||
import { ServiceProxyInterface } from '../../Service/Proxy/ServiceProxyInterface'
|
||||
import { EndpointResolverInterface } from '../../Service/Resolver/EndpointResolverInterface'
|
||||
|
||||
@controller('/v1')
|
||||
|
|
|
@ -3,7 +3,7 @@ import { Request, Response } from 'express'
|
|||
import { controller, BaseHttpController, httpPost, httpGet, httpDelete } from 'inversify-express-utils'
|
||||
|
||||
import { TYPES } from '../../Bootstrap/Types'
|
||||
import { ServiceProxyInterface } from '../../Service/Http/ServiceProxyInterface'
|
||||
import { ServiceProxyInterface } from '../../Service/Proxy/ServiceProxyInterface'
|
||||
import { EndpointResolverInterface } from '../../Service/Resolver/EndpointResolverInterface'
|
||||
|
||||
@controller('/v1/authenticators')
|
||||
|
|
|
@ -3,7 +3,7 @@ import { inject } from 'inversify'
|
|||
import { BaseHttpController, controller, httpPost } from 'inversify-express-utils'
|
||||
|
||||
import { TYPES } from '../../Bootstrap/Types'
|
||||
import { ServiceProxyInterface } from '../../Service/Http/ServiceProxyInterface'
|
||||
import { ServiceProxyInterface } from '../../Service/Proxy/ServiceProxyInterface'
|
||||
import { EndpointResolverInterface } from '../../Service/Resolver/EndpointResolverInterface'
|
||||
|
||||
@controller('/v1/files')
|
||||
|
|
|
@ -2,7 +2,7 @@ import { Request, Response } from 'express'
|
|||
import { BaseHttpController, controller, httpPost } from 'inversify-express-utils'
|
||||
import { inject } from 'inversify'
|
||||
import { TYPES } from '../../Bootstrap/Types'
|
||||
import { ServiceProxyInterface } from '../../Service/Http/ServiceProxyInterface'
|
||||
import { ServiceProxyInterface } from '../../Service/Proxy/ServiceProxyInterface'
|
||||
|
||||
@controller('/v1')
|
||||
export class InvoicesController extends BaseHttpController {
|
||||
|
|
|
@ -2,7 +2,7 @@ import { Request, Response } from 'express'
|
|||
import { inject } from 'inversify'
|
||||
import { BaseHttpController, controller, httpGet, httpPost } from 'inversify-express-utils'
|
||||
import { TYPES } from '../../Bootstrap/Types'
|
||||
import { ServiceProxyInterface } from '../../Service/Http/ServiceProxyInterface'
|
||||
import { ServiceProxyInterface } from '../../Service/Proxy/ServiceProxyInterface'
|
||||
import { EndpointResolverInterface } from '../../Service/Resolver/EndpointResolverInterface'
|
||||
|
||||
@controller('/v1/items', TYPES.ApiGateway_RequiredCrossServiceTokenMiddleware)
|
||||
|
|
|
@ -2,7 +2,7 @@ import { Request, Response } from 'express'
|
|||
import { inject } from 'inversify'
|
||||
import { BaseHttpController, controller, httpDelete, httpGet, httpPost } from 'inversify-express-utils'
|
||||
import { TYPES } from '../../Bootstrap/Types'
|
||||
import { ServiceProxyInterface } from '../../Service/Http/ServiceProxyInterface'
|
||||
import { ServiceProxyInterface } from '../../Service/Proxy/ServiceProxyInterface'
|
||||
import { EndpointResolverInterface } from '../../Service/Resolver/EndpointResolverInterface'
|
||||
|
||||
@controller('/v1/messages', TYPES.ApiGateway_RequiredCrossServiceTokenMiddleware)
|
||||
|
|
|
@ -3,7 +3,7 @@ import { inject } from 'inversify'
|
|||
import { BaseHttpController, controller, httpGet, httpPost } from 'inversify-express-utils'
|
||||
|
||||
import { TYPES } from '../../Bootstrap/Types'
|
||||
import { ServiceProxyInterface } from '../../Service/Http/ServiceProxyInterface'
|
||||
import { ServiceProxyInterface } from '../../Service/Proxy/ServiceProxyInterface'
|
||||
import { EndpointResolverInterface } from '../../Service/Resolver/EndpointResolverInterface'
|
||||
|
||||
@controller('/v1/offline')
|
||||
|
|
|
@ -2,7 +2,7 @@ import { Request, Response } from 'express'
|
|||
import { inject } from 'inversify'
|
||||
import { all, BaseHttpController, controller, httpDelete, httpGet, httpPost } from 'inversify-express-utils'
|
||||
import { TYPES } from '../../Bootstrap/Types'
|
||||
import { ServiceProxyInterface } from '../../Service/Http/ServiceProxyInterface'
|
||||
import { ServiceProxyInterface } from '../../Service/Proxy/ServiceProxyInterface'
|
||||
|
||||
@controller('/v1')
|
||||
export class PaymentsController extends BaseHttpController {
|
||||
|
|
|
@ -2,7 +2,7 @@ import { Request, Response } from 'express'
|
|||
import { inject } from 'inversify'
|
||||
import { BaseHttpController, controller, httpDelete, httpGet, httpPost } from 'inversify-express-utils'
|
||||
import { TYPES } from '../../Bootstrap/Types'
|
||||
import { ServiceProxyInterface } from '../../Service/Http/ServiceProxyInterface'
|
||||
import { ServiceProxyInterface } from '../../Service/Proxy/ServiceProxyInterface'
|
||||
import { EndpointResolverInterface } from '../../Service/Resolver/EndpointResolverInterface'
|
||||
|
||||
@controller('/v1/sessions')
|
||||
|
|
|
@ -2,7 +2,7 @@ import { Request, Response } from 'express'
|
|||
import { inject } from 'inversify'
|
||||
import { BaseHttpController, controller, httpDelete, httpGet, httpPatch, httpPost } from 'inversify-express-utils'
|
||||
import { TYPES } from '../../Bootstrap/Types'
|
||||
import { ServiceProxyInterface } from '../../Service/Http/ServiceProxyInterface'
|
||||
import { ServiceProxyInterface } from '../../Service/Proxy/ServiceProxyInterface'
|
||||
import { EndpointResolverInterface } from '../../Service/Resolver/EndpointResolverInterface'
|
||||
|
||||
@controller('/v1/shared-vaults', TYPES.ApiGateway_RequiredCrossServiceTokenMiddleware)
|
||||
|
|
|
@ -2,7 +2,7 @@ import { Request, Response } from 'express'
|
|||
import { inject } from 'inversify'
|
||||
import { BaseHttpController, controller, httpDelete, httpGet, httpPost } from 'inversify-express-utils'
|
||||
import { TYPES } from '../../Bootstrap/Types'
|
||||
import { ServiceProxyInterface } from '../../Service/Http/ServiceProxyInterface'
|
||||
import { ServiceProxyInterface } from '../../Service/Proxy/ServiceProxyInterface'
|
||||
import { EndpointResolverInterface } from '../../Service/Resolver/EndpointResolverInterface'
|
||||
|
||||
@controller('/v1/shared-vaults/:sharedVaultUuid/users', TYPES.ApiGateway_RequiredCrossServiceTokenMiddleware)
|
||||
|
|
|
@ -2,7 +2,7 @@ import { Request, Response } from 'express'
|
|||
import { inject } from 'inversify'
|
||||
import { BaseHttpController, controller, httpDelete, httpGet, httpPost } from 'inversify-express-utils'
|
||||
import { TYPES } from '../../Bootstrap/Types'
|
||||
import { ServiceProxyInterface } from '../../Service/Http/ServiceProxyInterface'
|
||||
import { ServiceProxyInterface } from '../../Service/Proxy/ServiceProxyInterface'
|
||||
import { EndpointResolverInterface } from '../../Service/Resolver/EndpointResolverInterface'
|
||||
|
||||
@controller('/v1/shared-vaults', TYPES.ApiGateway_RequiredCrossServiceTokenMiddleware)
|
||||
|
|
|
@ -3,7 +3,7 @@ import { inject } from 'inversify'
|
|||
import { BaseHttpController, controller, httpDelete, httpGet, httpPost } from 'inversify-express-utils'
|
||||
|
||||
import { TYPES } from '../../Bootstrap/Types'
|
||||
import { ServiceProxyInterface } from '../../Service/Http/ServiceProxyInterface'
|
||||
import { ServiceProxyInterface } from '../../Service/Proxy/ServiceProxyInterface'
|
||||
import { EndpointResolverInterface } from '../../Service/Resolver/EndpointResolverInterface'
|
||||
|
||||
@controller('/v1/subscription-invites')
|
||||
|
|
|
@ -3,7 +3,7 @@ import { inject } from 'inversify'
|
|||
import { BaseHttpController, controller, httpPost } from 'inversify-express-utils'
|
||||
|
||||
import { TYPES } from '../../Bootstrap/Types'
|
||||
import { ServiceProxyInterface } from '../../Service/Http/ServiceProxyInterface'
|
||||
import { ServiceProxyInterface } from '../../Service/Proxy/ServiceProxyInterface'
|
||||
import { EndpointResolverInterface } from '../../Service/Resolver/EndpointResolverInterface'
|
||||
|
||||
@controller('/v1/subscription-tokens')
|
||||
|
|
|
@ -13,7 +13,7 @@ import {
|
|||
} from 'inversify-express-utils'
|
||||
import { Logger } from 'winston'
|
||||
import { TYPES } from '../../Bootstrap/Types'
|
||||
import { ServiceProxyInterface } from '../../Service/Http/ServiceProxyInterface'
|
||||
import { ServiceProxyInterface } from '../../Service/Proxy/ServiceProxyInterface'
|
||||
import { TokenAuthenticationMethod } from '../TokenAuthenticationMethod'
|
||||
import { EndpointResolverInterface } from '../../Service/Resolver/EndpointResolverInterface'
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@ import { BaseHttpController, controller, httpDelete, httpPost } from 'inversify-
|
|||
import { Logger } from 'winston'
|
||||
|
||||
import { TYPES } from '../../Bootstrap/Types'
|
||||
import { ServiceProxyInterface } from '../../Service/Http/ServiceProxyInterface'
|
||||
import { ServiceProxyInterface } from '../../Service/Proxy/ServiceProxyInterface'
|
||||
import { EndpointResolverInterface } from '../../Service/Resolver/EndpointResolverInterface'
|
||||
|
||||
@controller('/v1/sockets')
|
||||
|
|
|
@ -3,7 +3,7 @@ import { inject } from 'inversify'
|
|||
import { BaseHttpController, controller, httpPost } from 'inversify-express-utils'
|
||||
|
||||
import { TYPES } from '../../Bootstrap/Types'
|
||||
import { ServiceProxyInterface } from '../../Service/Http/ServiceProxyInterface'
|
||||
import { ServiceProxyInterface } from '../../Service/Proxy/ServiceProxyInterface'
|
||||
import { EndpointResolverInterface } from '../../Service/Resolver/EndpointResolverInterface'
|
||||
|
||||
@controller('/v2')
|
||||
|
|
|
@ -2,7 +2,7 @@ import { Request, Response } from 'express'
|
|||
import { BaseHttpController, controller, httpDelete, httpGet, httpPatch, httpPost } from 'inversify-express-utils'
|
||||
import { inject } from 'inversify'
|
||||
import { TYPES } from '../../Bootstrap/Types'
|
||||
import { ServiceProxyInterface } from '../../Service/Http/ServiceProxyInterface'
|
||||
import { ServiceProxyInterface } from '../../Service/Proxy/ServiceProxyInterface'
|
||||
|
||||
@controller('/v2')
|
||||
export class PaymentsControllerV2 extends BaseHttpController {
|
||||
|
|
|
@ -3,7 +3,7 @@ import { inject } from 'inversify'
|
|||
import { BaseHttpController, controller, httpDelete, httpGet } from 'inversify-express-utils'
|
||||
|
||||
import { TYPES } from '../../Bootstrap/Types'
|
||||
import { ServiceProxyInterface } from '../../Service/Http/ServiceProxyInterface'
|
||||
import { ServiceProxyInterface } from '../../Service/Proxy/ServiceProxyInterface'
|
||||
import { EndpointResolverInterface } from '../../Service/Resolver/EndpointResolverInterface'
|
||||
|
||||
@controller('/v2', TYPES.ApiGateway_RequiredCrossServiceTokenMiddleware)
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { Request, Response } from 'express'
|
||||
import { ServiceContainerInterface, ServiceIdentifier } from '@standardnotes/domain-core'
|
||||
|
||||
import { ServiceProxyInterface } from '../Http/ServiceProxyInterface'
|
||||
import { ServiceProxyInterface } from '../Proxy/ServiceProxyInterface'
|
||||
|
||||
export class DirectCallServiceProxy implements ServiceProxyInterface {
|
||||
constructor(
|
|
@ -6,7 +6,7 @@ import { Logger } from 'winston'
|
|||
|
||||
import { TYPES } from '../../Bootstrap/Types'
|
||||
import { CrossServiceTokenCacheInterface } from '../Cache/CrossServiceTokenCacheInterface'
|
||||
import { ServiceProxyInterface } from './ServiceProxyInterface'
|
||||
import { ServiceProxyInterface } from '../Proxy/ServiceProxyInterface'
|
||||
import { TimerInterface } from '@standardnotes/time'
|
||||
|
||||
@injectable()
|
||||
|
|
440
packages/api-gateway/src/Service/gRPC/GRPCServiceProxy.ts
Normal file
440
packages/api-gateway/src/Service/gRPC/GRPCServiceProxy.ts
Normal file
|
@ -0,0 +1,440 @@
|
|||
import { AxiosInstance, AxiosError, AxiosResponse, Method } from 'axios'
|
||||
import { Request, Response } from 'express'
|
||||
import { Logger } from 'winston'
|
||||
import { TimerInterface } from '@standardnotes/time'
|
||||
import { ISessionsClient, AuthorizationHeader, SessionValidationResponse } from '@standardnotes/grpc'
|
||||
import * as grpc from '@grpc/grpc-js'
|
||||
|
||||
import { CrossServiceTokenCacheInterface } from '../Cache/CrossServiceTokenCacheInterface'
|
||||
import { ServiceProxyInterface } from '../Proxy/ServiceProxyInterface'
|
||||
|
||||
export class GRPCServiceProxy implements ServiceProxyInterface {
|
||||
constructor(
|
||||
private httpClient: AxiosInstance,
|
||||
private authServerUrl: string,
|
||||
private syncingServerJsUrl: string,
|
||||
private paymentsServerUrl: string,
|
||||
private filesServerUrl: string,
|
||||
private webSocketServerUrl: string,
|
||||
private revisionsServerUrl: string,
|
||||
private emailServerUrl: string,
|
||||
private httpCallTimeout: number,
|
||||
private crossServiceTokenCache: CrossServiceTokenCacheInterface,
|
||||
private logger: Logger,
|
||||
private timer: TimerInterface,
|
||||
private sessionsClient: ISessionsClient,
|
||||
) {}
|
||||
|
||||
async validateSession(headers: {
|
||||
authorization: string
|
||||
sharedVaultOwnerContext?: string
|
||||
}): Promise<{ status: number; data: unknown; headers: { contentType: string } }> {
|
||||
return new Promise((resolve, reject) => {
|
||||
try {
|
||||
const request = new AuthorizationHeader()
|
||||
request.setBearerToken(headers.authorization)
|
||||
|
||||
const metadata = new grpc.Metadata()
|
||||
metadata.set('x-shared-vault-owner-context', headers.sharedVaultOwnerContext ?? '')
|
||||
|
||||
this.sessionsClient.validate(
|
||||
request,
|
||||
metadata,
|
||||
(error: grpc.ServiceError | null, response: SessionValidationResponse) => {
|
||||
if (error) {
|
||||
const responseCode = error.metadata.get('x-auth-error-response-code').pop()
|
||||
if (responseCode) {
|
||||
return resolve({
|
||||
status: +responseCode,
|
||||
data: {
|
||||
error: {
|
||||
message: error.metadata.get('x-auth-error-message').pop(),
|
||||
tag: error.metadata.get('x-auth-error-tag').pop(),
|
||||
},
|
||||
},
|
||||
headers: {
|
||||
contentType: 'application/json',
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
return reject(error)
|
||||
}
|
||||
|
||||
return resolve({
|
||||
status: 200,
|
||||
data: {
|
||||
authToken: response.getCrossServiceToken(),
|
||||
},
|
||||
headers: {
|
||||
contentType: 'application/json',
|
||||
},
|
||||
})
|
||||
},
|
||||
)
|
||||
} catch (error) {
|
||||
return reject(error)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
async callSyncingServer(
|
||||
request: Request,
|
||||
response: Response,
|
||||
endpointOrMethodIdentifier: string,
|
||||
payload?: Record<string, unknown> | string,
|
||||
): Promise<void> {
|
||||
await this.callServer(this.syncingServerJsUrl, request, response, endpointOrMethodIdentifier, payload)
|
||||
}
|
||||
|
||||
async callRevisionsServer(
|
||||
request: Request,
|
||||
response: Response,
|
||||
endpointOrMethodIdentifier: string,
|
||||
payload?: Record<string, unknown> | string,
|
||||
): Promise<void> {
|
||||
if (!this.revisionsServerUrl) {
|
||||
response.status(400).send({ message: 'Revisions Server not configured' })
|
||||
|
||||
return
|
||||
}
|
||||
await this.callServer(this.revisionsServerUrl, request, response, endpointOrMethodIdentifier, payload)
|
||||
}
|
||||
|
||||
async callLegacySyncingServer(
|
||||
request: Request,
|
||||
response: Response,
|
||||
endpointOrMethodIdentifier: string,
|
||||
payload?: Record<string, unknown> | string,
|
||||
): Promise<void> {
|
||||
await this.callServerWithLegacyFormat(
|
||||
this.syncingServerJsUrl,
|
||||
request,
|
||||
response,
|
||||
endpointOrMethodIdentifier,
|
||||
payload,
|
||||
)
|
||||
}
|
||||
|
||||
async callAuthServer(
|
||||
request: Request,
|
||||
response: Response,
|
||||
endpointOrMethodIdentifier: string,
|
||||
payload?: Record<string, unknown> | string,
|
||||
): Promise<void> {
|
||||
await this.callServer(this.authServerUrl, request, response, endpointOrMethodIdentifier, payload)
|
||||
}
|
||||
|
||||
async callEmailServer(
|
||||
request: Request,
|
||||
response: Response,
|
||||
endpointOrMethodIdentifier: string,
|
||||
payload?: Record<string, unknown> | string,
|
||||
): Promise<void> {
|
||||
if (!this.emailServerUrl) {
|
||||
response.status(400).send({ message: 'Email Server not configured' })
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
await this.callServer(this.emailServerUrl, request, response, endpointOrMethodIdentifier, payload)
|
||||
}
|
||||
|
||||
async callWebSocketServer(
|
||||
request: Request,
|
||||
response: Response,
|
||||
endpointOrMethodIdentifier: string,
|
||||
payload?: Record<string, unknown> | string,
|
||||
): Promise<void> {
|
||||
if (!this.webSocketServerUrl) {
|
||||
this.logger.debug('Websockets Server URL not defined. Skipped request to WebSockets API.')
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
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(
|
||||
request: Request,
|
||||
response: Response,
|
||||
endpointOrMethodIdentifier: string,
|
||||
payload?: Record<string, unknown> | string,
|
||||
): Promise<void | Response<unknown, Record<string, unknown>>> {
|
||||
if (!this.paymentsServerUrl) {
|
||||
this.logger.debug('Payments Server URL not defined. Skipped request to Payments API.')
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
await this.callServerWithLegacyFormat(
|
||||
this.paymentsServerUrl,
|
||||
request,
|
||||
response,
|
||||
endpointOrMethodIdentifier,
|
||||
payload,
|
||||
)
|
||||
}
|
||||
|
||||
async callAuthServerWithLegacyFormat(
|
||||
request: Request,
|
||||
response: Response,
|
||||
endpointOrMethodIdentifier: string,
|
||||
payload?: Record<string, unknown> | string,
|
||||
): Promise<void> {
|
||||
await this.callServerWithLegacyFormat(this.authServerUrl, request, response, endpointOrMethodIdentifier, payload)
|
||||
}
|
||||
|
||||
private async getServerResponse(
|
||||
serverUrl: string,
|
||||
request: Request,
|
||||
response: Response,
|
||||
endpointOrMethodIdentifier: string,
|
||||
payload?: Record<string, unknown> | string,
|
||||
retryAttempt?: number,
|
||||
): Promise<AxiosResponse | undefined> {
|
||||
try {
|
||||
const headers: Record<string, string> = {}
|
||||
for (const headerName of Object.keys(request.headers)) {
|
||||
headers[headerName] = request.headers[headerName] as string
|
||||
}
|
||||
|
||||
delete headers.host
|
||||
delete headers['content-length']
|
||||
|
||||
if (response.locals.authToken) {
|
||||
headers['X-Auth-Token'] = response.locals.authToken
|
||||
}
|
||||
|
||||
if (response.locals.offlineAuthToken) {
|
||||
headers['X-Auth-Offline-Token'] = response.locals.offlineAuthToken
|
||||
}
|
||||
|
||||
this.logger.debug(`Calling [${request.method}] ${serverUrl}/${endpointOrMethodIdentifier},
|
||||
headers: ${JSON.stringify(headers)},
|
||||
query: ${JSON.stringify(request.query)},
|
||||
payload: ${JSON.stringify(payload)}`)
|
||||
|
||||
const serviceResponse = await this.httpClient.request({
|
||||
method: request.method as Method,
|
||||
headers,
|
||||
url: `${serverUrl}/${endpointOrMethodIdentifier}`,
|
||||
data: this.getRequestData(payload),
|
||||
maxContentLength: Infinity,
|
||||
maxBodyLength: Infinity,
|
||||
params: request.query,
|
||||
timeout: this.httpCallTimeout,
|
||||
validateStatus: (status: number) => {
|
||||
return status >= 200 && status < 500
|
||||
},
|
||||
})
|
||||
|
||||
if (serviceResponse.headers['x-invalidate-cache']) {
|
||||
const userUuid = serviceResponse.headers['x-invalidate-cache']
|
||||
await this.crossServiceTokenCache.invalidate(userUuid)
|
||||
}
|
||||
|
||||
if (retryAttempt) {
|
||||
this.logger.debug(
|
||||
`Request to ${serverUrl}/${endpointOrMethodIdentifier} succeeded after ${retryAttempt} retries`,
|
||||
)
|
||||
}
|
||||
|
||||
return serviceResponse
|
||||
} catch (error) {
|
||||
const requestDidNotMakeIt = this.requestTimedOutOrDidNotReachDestination(error as Record<string, unknown>)
|
||||
const tooManyRetryAttempts = retryAttempt && retryAttempt > 2
|
||||
if (!tooManyRetryAttempts && requestDidNotMakeIt) {
|
||||
await this.timer.sleep(50)
|
||||
|
||||
const nextRetryAttempt = retryAttempt ? retryAttempt + 1 : 1
|
||||
|
||||
this.logger.debug(
|
||||
`Retrying request to ${serverUrl}/${endpointOrMethodIdentifier} for the ${nextRetryAttempt} time`,
|
||||
)
|
||||
|
||||
return this.getServerResponse(
|
||||
serverUrl,
|
||||
request,
|
||||
response,
|
||||
endpointOrMethodIdentifier,
|
||||
payload,
|
||||
nextRetryAttempt,
|
||||
)
|
||||
}
|
||||
|
||||
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: ${detailedErrorMessage}`,
|
||||
)
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
const errorCode =
|
||||
(error as AxiosError).isAxiosError && !isNaN(+((error as AxiosError).code as string))
|
||||
? +((error as AxiosError).code as string)
|
||||
: 500
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
private async callServer(
|
||||
serverUrl: string,
|
||||
request: Request,
|
||||
response: Response,
|
||||
endpointOrMethodIdentifier: string,
|
||||
payload?: Record<string, unknown> | string,
|
||||
): Promise<void> {
|
||||
const serviceResponse = await this.getServerResponse(
|
||||
serverUrl,
|
||||
request,
|
||||
response,
|
||||
endpointOrMethodIdentifier,
|
||||
payload,
|
||||
)
|
||||
|
||||
this.logger.debug(`Response from underlying server: ${JSON.stringify(serviceResponse?.data)},
|
||||
headers: ${JSON.stringify(serviceResponse?.headers)}`)
|
||||
|
||||
if (!serviceResponse) {
|
||||
return
|
||||
}
|
||||
|
||||
this.applyResponseHeaders(serviceResponse, response)
|
||||
|
||||
if (this.responseShouldNotBeDecorated(serviceResponse)) {
|
||||
response.status(serviceResponse.status).send(serviceResponse.data)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
response.status(serviceResponse.status).send({
|
||||
meta: {
|
||||
auth: {
|
||||
userUuid: response.locals.user?.uuid,
|
||||
roles: response.locals.roles,
|
||||
},
|
||||
server: {
|
||||
filesServerUrl: this.filesServerUrl,
|
||||
},
|
||||
},
|
||||
data: serviceResponse.data,
|
||||
})
|
||||
}
|
||||
|
||||
private async callServerWithLegacyFormat(
|
||||
serverUrl: string,
|
||||
request: Request,
|
||||
response: Response,
|
||||
endpointOrMethodIdentifier: string,
|
||||
payload?: Record<string, unknown> | string,
|
||||
): Promise<void | Response<unknown, Record<string, unknown>>> {
|
||||
const serviceResponse = await this.getServerResponse(
|
||||
serverUrl,
|
||||
request,
|
||||
response,
|
||||
endpointOrMethodIdentifier,
|
||||
payload,
|
||||
)
|
||||
|
||||
if (!serviceResponse) {
|
||||
return
|
||||
}
|
||||
|
||||
this.applyResponseHeaders(serviceResponse, response)
|
||||
|
||||
if (serviceResponse.request._redirectable._redirectCount > 0) {
|
||||
response.status(302)
|
||||
|
||||
response.redirect(serviceResponse.request.res.responseUrl)
|
||||
} else {
|
||||
response.status(serviceResponse.status)
|
||||
|
||||
response.send(serviceResponse.data)
|
||||
}
|
||||
}
|
||||
|
||||
private getRequestData(
|
||||
payload: Record<string, unknown> | string | undefined,
|
||||
): Record<string, unknown> | string | undefined {
|
||||
if (
|
||||
payload === '' ||
|
||||
payload === null ||
|
||||
payload === undefined ||
|
||||
(typeof payload === 'object' && Object.keys(payload).length === 0)
|
||||
) {
|
||||
return undefined
|
||||
}
|
||||
|
||||
return payload
|
||||
}
|
||||
|
||||
private responseShouldNotBeDecorated(serviceResponse: AxiosResponse): boolean {
|
||||
return (
|
||||
serviceResponse.headers['content-type'] !== undefined &&
|
||||
serviceResponse.headers['content-type'].toLowerCase().includes('text/html')
|
||||
)
|
||||
}
|
||||
|
||||
private applyResponseHeaders(serviceResponse: AxiosResponse, response: Response): void {
|
||||
const returnedHeadersFromUnderlyingService = [
|
||||
'access-control-allow-methods',
|
||||
'access-control-allow-origin',
|
||||
'access-control-expose-headers',
|
||||
'authorization',
|
||||
'content-type',
|
||||
'x-ssjs-version',
|
||||
'x-auth-version',
|
||||
]
|
||||
|
||||
returnedHeadersFromUnderlyingService.map((headerName) => {
|
||||
const headerValue = serviceResponse.headers[headerName]
|
||||
if (headerValue) {
|
||||
response.setHeader(headerName, headerValue)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
private requestTimedOutOrDidNotReachDestination(error: Record<string, unknown>): boolean {
|
||||
return (
|
||||
('code' in error && error.code === 'ETIMEDOUT') ||
|
||||
('response' in error &&
|
||||
'status' in (error.response as Record<string, unknown>) &&
|
||||
[503, 504].includes((error.response as Record<string, unknown>).status as number))
|
||||
)
|
||||
}
|
||||
}
|
|
@ -13,6 +13,7 @@ AUTH_JWT_TTL=60000
|
|||
ENCRYPTION_SERVER_KEY=change-me-!
|
||||
|
||||
PORT=3000
|
||||
GRPC_PORT=50051
|
||||
|
||||
DB_HOST=127.0.0.1
|
||||
DB_REPLICA_HOST=127.0.0.1
|
||||
|
|
|
@ -20,6 +20,7 @@ import '../src/Infra/InversifyExpressUtils/AnnotatedHealthCheckController'
|
|||
import '../src/Infra/InversifyExpressUtils/AnnotatedFeaturesController'
|
||||
|
||||
import * as cors from 'cors'
|
||||
import * as grpc from '@grpc/grpc-js'
|
||||
import { urlencoded, json, Request, Response, NextFunction } from 'express'
|
||||
import * as winston from 'winston'
|
||||
import * as dayjs from 'dayjs'
|
||||
|
@ -29,6 +30,10 @@ import { InversifyExpressServer } from 'inversify-express-utils'
|
|||
import { ContainerConfigLoader } from '../src/Bootstrap/Container'
|
||||
import TYPES from '../src/Bootstrap/Types'
|
||||
import { Env } from '../src/Bootstrap/Env'
|
||||
import { SessionsServer } from '../src/Infra/gRPC/SessionsServer'
|
||||
import { SessionsService } from '@standardnotes/grpc'
|
||||
import { AuthenticateRequest } from '../src/Domain/UseCase/AuthenticateRequest'
|
||||
import { CreateCrossServiceToken } from '../src/Domain/UseCase/CreateCrossServiceToken/CreateCrossServiceToken'
|
||||
|
||||
const container = new ContainerConfigLoader()
|
||||
void container.load().then((container) => {
|
||||
|
@ -66,9 +71,42 @@ void container.load().then((container) => {
|
|||
|
||||
const serverInstance = server.build().listen(env.get('PORT'))
|
||||
|
||||
const keepAliveTimeout = env.get('KEEP_ALIVE_TIMEOUT', true) ? +env.get('KEEP_ALIVE_TIMEOUT', true) : 5000
|
||||
const httpKeepAliveTimeout = env.get('HTTP_KEEP_ALIVE_TIMEOUT', true)
|
||||
? +env.get('HTTP_KEEP_ALIVE_TIMEOUT', true)
|
||||
: 10_000
|
||||
|
||||
serverInstance.keepAliveTimeout = keepAliveTimeout
|
||||
serverInstance.keepAliveTimeout = httpKeepAliveTimeout
|
||||
|
||||
const grpcKeepAliveTimeout = env.get('GRPC_KEEP_ALIVE_TIMEOUT', true)
|
||||
? +env.get('GRPC_KEEP_ALIVE_TIMEOUT', true)
|
||||
: 10_000
|
||||
|
||||
const grpcServer = new grpc.Server({
|
||||
'grpc.keepalive_time_ms': grpcKeepAliveTimeout * 2,
|
||||
'grpc.keepalive_timeout_ms': grpcKeepAliveTimeout,
|
||||
})
|
||||
|
||||
const gRPCPort = env.get('GRPC_PORT', true) ? +env.get('GRPC_PORT', true) : 50051
|
||||
|
||||
const sessionsServer = new SessionsServer(
|
||||
container.get<AuthenticateRequest>(TYPES.Auth_AuthenticateRequest),
|
||||
container.get<CreateCrossServiceToken>(TYPES.Auth_CreateCrossServiceToken),
|
||||
)
|
||||
|
||||
grpcServer.addService(SessionsService, {
|
||||
validate: sessionsServer.validate.bind(sessionsServer),
|
||||
})
|
||||
grpcServer.bindAsync(`0.0.0.0:${gRPCPort}`, grpc.ServerCredentials.createInsecure(), (error, port) => {
|
||||
if (error) {
|
||||
logger.error(`Failed to bind gRPC server: ${error.message}`)
|
||||
}
|
||||
|
||||
logger.info(`gRPC server bound on port ${port}`)
|
||||
|
||||
grpcServer.start()
|
||||
|
||||
logger.info('gRPC server started')
|
||||
})
|
||||
|
||||
process.on('SIGTERM', () => {
|
||||
logger.info('SIGTERM signal received: closing HTTP server')
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
"lint:fix": "eslint . --fix --ext .ts",
|
||||
"pretest": "yarn lint && yarn build",
|
||||
"test": "jest --coverage --no-cache --config=./jest.config.js --maxWorkers=50%",
|
||||
"grpc": "yarn node dist/bin/grpc.js",
|
||||
"start": "yarn node dist/bin/server.js",
|
||||
"worker": "yarn node dist/bin/worker.js",
|
||||
"cleanup": "yarn node dist/bin/cleanup.js",
|
||||
|
@ -37,6 +38,7 @@
|
|||
"@aws-sdk/client-sqs": "^3.427.0",
|
||||
"@cbor-extract/cbor-extract-linux-arm64": "^2.1.1",
|
||||
"@cbor-extract/cbor-extract-linux-x64": "^2.1.1",
|
||||
"@grpc/grpc-js": "^1.9.10",
|
||||
"@simplewebauthn/server": "^8.1.1",
|
||||
"@simplewebauthn/typescript-types": "^8.0.0",
|
||||
"@standardnotes/api": "^1.26.26",
|
||||
|
@ -45,6 +47,7 @@
|
|||
"@standardnotes/domain-events": "workspace:*",
|
||||
"@standardnotes/domain-events-infra": "workspace:*",
|
||||
"@standardnotes/features": "^1.59.7",
|
||||
"@standardnotes/grpc": "workspace:^",
|
||||
"@standardnotes/predicates": "workspace:*",
|
||||
"@standardnotes/responses": "^1.13.27",
|
||||
"@standardnotes/security": "workspace:*",
|
||||
|
|
74
packages/auth/src/Infra/gRPC/SessionsServer.ts
Normal file
74
packages/auth/src/Infra/gRPC/SessionsServer.ts
Normal file
|
@ -0,0 +1,74 @@
|
|||
import * as grpc from '@grpc/grpc-js'
|
||||
import { Status } from '@grpc/grpc-js/build/src/constants'
|
||||
|
||||
import { AuthorizationHeader, ISessionsServer, SessionValidationResponse } from '@standardnotes/grpc'
|
||||
|
||||
import { AuthenticateRequest } from '../../Domain/UseCase/AuthenticateRequest'
|
||||
import { User } from '../../Domain/User/User'
|
||||
import { CreateCrossServiceToken } from '../../Domain/UseCase/CreateCrossServiceToken/CreateCrossServiceToken'
|
||||
|
||||
export class SessionsServer implements ISessionsServer {
|
||||
constructor(
|
||||
private authenticateRequest: AuthenticateRequest,
|
||||
private createCrossServiceToken: CreateCrossServiceToken,
|
||||
) {}
|
||||
|
||||
async validate(
|
||||
call: grpc.ServerUnaryCall<AuthorizationHeader, SessionValidationResponse>,
|
||||
callback: grpc.sendUnaryData<SessionValidationResponse>,
|
||||
): Promise<void> {
|
||||
const authenticateRequestResponse = await this.authenticateRequest.execute({
|
||||
authorizationHeader: call.request.getBearerToken(),
|
||||
})
|
||||
|
||||
if (!authenticateRequestResponse.success) {
|
||||
const metadata = new grpc.Metadata()
|
||||
metadata.set('x-auth-error-message', authenticateRequestResponse.errorMessage as string)
|
||||
metadata.set('x-auth-error-tag', authenticateRequestResponse.errorTag as string)
|
||||
metadata.set('x-auth-error-response-code', authenticateRequestResponse.responseCode.toString())
|
||||
return callback(
|
||||
{
|
||||
code: Status.PERMISSION_DENIED,
|
||||
message: authenticateRequestResponse.errorMessage,
|
||||
name: authenticateRequestResponse.errorTag,
|
||||
metadata,
|
||||
},
|
||||
null,
|
||||
)
|
||||
}
|
||||
|
||||
const user = authenticateRequestResponse.user as User
|
||||
|
||||
const sharedVaultOwnerMetadata = call.metadata.get('x-shared-vault-owner-context')
|
||||
let sharedVaultOwnerContext = undefined
|
||||
if (sharedVaultOwnerMetadata.length > 0 && sharedVaultOwnerMetadata[0].length > 0) {
|
||||
sharedVaultOwnerContext = sharedVaultOwnerMetadata[0].toString()
|
||||
}
|
||||
|
||||
const resultOrError = await this.createCrossServiceToken.execute({
|
||||
user,
|
||||
session: authenticateRequestResponse.session,
|
||||
sharedVaultOwnerContext,
|
||||
})
|
||||
if (resultOrError.isFailed()) {
|
||||
const metadata = new grpc.Metadata()
|
||||
metadata.set('x-auth-error-message', resultOrError.getError())
|
||||
metadata.set('x-auth-error-response-code', '400')
|
||||
|
||||
return callback(
|
||||
{
|
||||
code: Status.INVALID_ARGUMENT,
|
||||
message: resultOrError.getError(),
|
||||
name: 'INVALID_ARGUMENT',
|
||||
metadata,
|
||||
},
|
||||
null,
|
||||
)
|
||||
}
|
||||
|
||||
const response = new SessionValidationResponse()
|
||||
response.setCrossServiceToken(resultOrError.getValue())
|
||||
|
||||
callback(null, response)
|
||||
}
|
||||
}
|
|
@ -91,7 +91,7 @@ void container.load().then((container) => {
|
|||
|
||||
const serverInstance = server.build().listen(env.get('PORT'))
|
||||
|
||||
const keepAliveTimeout = env.get('KEEP_ALIVE_TIMEOUT', true) ? +env.get('KEEP_ALIVE_TIMEOUT', true) : 5000
|
||||
const keepAliveTimeout = env.get('HTTP_KEEP_ALIVE_TIMEOUT', true) ? +env.get('HTTP_KEEP_ALIVE_TIMEOUT', true) : 5000
|
||||
|
||||
serverInstance.keepAliveTimeout = keepAliveTimeout
|
||||
|
||||
|
|
41
packages/grpc/lib/auth_grpc_pb.d.ts
vendored
Normal file
41
packages/grpc/lib/auth_grpc_pb.d.ts
vendored
Normal file
|
@ -0,0 +1,41 @@
|
|||
// package: auth
|
||||
// file: auth.proto
|
||||
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
|
||||
import * as grpc from "@grpc/grpc-js";
|
||||
import * as auth_pb from "./auth_pb";
|
||||
|
||||
interface ISessionsService extends grpc.ServiceDefinition<grpc.UntypedServiceImplementation> {
|
||||
validate: ISessionsService_Ivalidate;
|
||||
}
|
||||
|
||||
interface ISessionsService_Ivalidate extends grpc.MethodDefinition<auth_pb.AuthorizationHeader, auth_pb.SessionValidationResponse> {
|
||||
path: "/auth.Sessions/validate";
|
||||
requestStream: false;
|
||||
responseStream: false;
|
||||
requestSerialize: grpc.serialize<auth_pb.AuthorizationHeader>;
|
||||
requestDeserialize: grpc.deserialize<auth_pb.AuthorizationHeader>;
|
||||
responseSerialize: grpc.serialize<auth_pb.SessionValidationResponse>;
|
||||
responseDeserialize: grpc.deserialize<auth_pb.SessionValidationResponse>;
|
||||
}
|
||||
|
||||
export const SessionsService: ISessionsService;
|
||||
|
||||
export interface ISessionsServer {
|
||||
validate: grpc.handleUnaryCall<auth_pb.AuthorizationHeader, auth_pb.SessionValidationResponse>;
|
||||
}
|
||||
|
||||
export interface ISessionsClient {
|
||||
validate(request: auth_pb.AuthorizationHeader, callback: (error: grpc.ServiceError | null, response: auth_pb.SessionValidationResponse) => void): grpc.ClientUnaryCall;
|
||||
validate(request: auth_pb.AuthorizationHeader, metadata: grpc.Metadata, callback: (error: grpc.ServiceError | null, response: auth_pb.SessionValidationResponse) => void): grpc.ClientUnaryCall;
|
||||
validate(request: auth_pb.AuthorizationHeader, metadata: grpc.Metadata, options: Partial<grpc.CallOptions>, callback: (error: grpc.ServiceError | null, response: auth_pb.SessionValidationResponse) => void): grpc.ClientUnaryCall;
|
||||
}
|
||||
|
||||
export class SessionsClient extends grpc.Client implements ISessionsClient {
|
||||
constructor(address: string, credentials: grpc.ChannelCredentials, options?: object);
|
||||
public validate(request: auth_pb.AuthorizationHeader, callback: (error: grpc.ServiceError | null, response: auth_pb.SessionValidationResponse) => void): grpc.ClientUnaryCall;
|
||||
public validate(request: auth_pb.AuthorizationHeader, metadata: grpc.Metadata, callback: (error: grpc.ServiceError | null, response: auth_pb.SessionValidationResponse) => void): grpc.ClientUnaryCall;
|
||||
public validate(request: auth_pb.AuthorizationHeader, metadata: grpc.Metadata, options: Partial<grpc.CallOptions>, callback: (error: grpc.ServiceError | null, response: auth_pb.SessionValidationResponse) => void): grpc.ClientUnaryCall;
|
||||
}
|
44
packages/grpc/lib/auth_grpc_pb.js
Normal file
44
packages/grpc/lib/auth_grpc_pb.js
Normal file
|
@ -0,0 +1,44 @@
|
|||
// GENERATED CODE -- DO NOT EDIT!
|
||||
|
||||
'use strict';
|
||||
var grpc = require('@grpc/grpc-js');
|
||||
var auth_pb = require('./auth_pb.js');
|
||||
|
||||
function serialize_auth_AuthorizationHeader(arg) {
|
||||
if (!(arg instanceof auth_pb.AuthorizationHeader)) {
|
||||
throw new Error('Expected argument of type auth.AuthorizationHeader');
|
||||
}
|
||||
return Buffer.from(arg.serializeBinary());
|
||||
}
|
||||
|
||||
function deserialize_auth_AuthorizationHeader(buffer_arg) {
|
||||
return auth_pb.AuthorizationHeader.deserializeBinary(new Uint8Array(buffer_arg));
|
||||
}
|
||||
|
||||
function serialize_auth_SessionValidationResponse(arg) {
|
||||
if (!(arg instanceof auth_pb.SessionValidationResponse)) {
|
||||
throw new Error('Expected argument of type auth.SessionValidationResponse');
|
||||
}
|
||||
return Buffer.from(arg.serializeBinary());
|
||||
}
|
||||
|
||||
function deserialize_auth_SessionValidationResponse(buffer_arg) {
|
||||
return auth_pb.SessionValidationResponse.deserializeBinary(new Uint8Array(buffer_arg));
|
||||
}
|
||||
|
||||
|
||||
var SessionsService = exports.SessionsService = {
|
||||
validate: {
|
||||
path: '/auth.Sessions/validate',
|
||||
requestStream: false,
|
||||
responseStream: false,
|
||||
requestType: auth_pb.AuthorizationHeader,
|
||||
responseType: auth_pb.SessionValidationResponse,
|
||||
requestSerialize: serialize_auth_AuthorizationHeader,
|
||||
requestDeserialize: deserialize_auth_AuthorizationHeader,
|
||||
responseSerialize: serialize_auth_SessionValidationResponse,
|
||||
responseDeserialize: deserialize_auth_SessionValidationResponse,
|
||||
},
|
||||
};
|
||||
|
||||
exports.SessionsClient = grpc.makeGenericClientConstructor(SessionsService);
|
47
packages/grpc/lib/auth_pb.d.ts
vendored
Normal file
47
packages/grpc/lib/auth_pb.d.ts
vendored
Normal file
|
@ -0,0 +1,47 @@
|
|||
// package: auth
|
||||
// file: auth.proto
|
||||
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
|
||||
import * as jspb from "google-protobuf";
|
||||
|
||||
export class AuthorizationHeader extends jspb.Message {
|
||||
getBearerToken(): string;
|
||||
setBearerToken(value: string): AuthorizationHeader;
|
||||
|
||||
serializeBinary(): Uint8Array;
|
||||
toObject(includeInstance?: boolean): AuthorizationHeader.AsObject;
|
||||
static toObject(includeInstance: boolean, msg: AuthorizationHeader): AuthorizationHeader.AsObject;
|
||||
static extensions: {[key: number]: jspb.ExtensionFieldInfo<jspb.Message>};
|
||||
static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo<jspb.Message>};
|
||||
static serializeBinaryToWriter(message: AuthorizationHeader, writer: jspb.BinaryWriter): void;
|
||||
static deserializeBinary(bytes: Uint8Array): AuthorizationHeader;
|
||||
static deserializeBinaryFromReader(message: AuthorizationHeader, reader: jspb.BinaryReader): AuthorizationHeader;
|
||||
}
|
||||
|
||||
export namespace AuthorizationHeader {
|
||||
export type AsObject = {
|
||||
bearerToken: string,
|
||||
}
|
||||
}
|
||||
|
||||
export class SessionValidationResponse extends jspb.Message {
|
||||
getCrossServiceToken(): string;
|
||||
setCrossServiceToken(value: string): SessionValidationResponse;
|
||||
|
||||
serializeBinary(): Uint8Array;
|
||||
toObject(includeInstance?: boolean): SessionValidationResponse.AsObject;
|
||||
static toObject(includeInstance: boolean, msg: SessionValidationResponse): SessionValidationResponse.AsObject;
|
||||
static extensions: {[key: number]: jspb.ExtensionFieldInfo<jspb.Message>};
|
||||
static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo<jspb.Message>};
|
||||
static serializeBinaryToWriter(message: SessionValidationResponse, writer: jspb.BinaryWriter): void;
|
||||
static deserializeBinary(bytes: Uint8Array): SessionValidationResponse;
|
||||
static deserializeBinaryFromReader(message: SessionValidationResponse, reader: jspb.BinaryReader): SessionValidationResponse;
|
||||
}
|
||||
|
||||
export namespace SessionValidationResponse {
|
||||
export type AsObject = {
|
||||
crossServiceToken: string,
|
||||
}
|
||||
}
|
328
packages/grpc/lib/auth_pb.js
Normal file
328
packages/grpc/lib/auth_pb.js
Normal file
|
@ -0,0 +1,328 @@
|
|||
// source: auth.proto
|
||||
/**
|
||||
* @fileoverview
|
||||
* @enhanceable
|
||||
* @suppress {missingRequire} reports error on implicit type usages.
|
||||
* @suppress {messageConventions} JS Compiler reports an error if a variable or
|
||||
* field starts with 'MSG_' and isn't a translatable message.
|
||||
* @public
|
||||
*/
|
||||
// GENERATED CODE -- DO NOT EDIT!
|
||||
/* eslint-disable */
|
||||
// @ts-nocheck
|
||||
|
||||
var jspb = require('google-protobuf');
|
||||
var goog = jspb;
|
||||
var global = (function() {
|
||||
if (this) { return this; }
|
||||
if (typeof window !== 'undefined') { return window; }
|
||||
if (typeof global !== 'undefined') { return global; }
|
||||
if (typeof self !== 'undefined') { return self; }
|
||||
return Function('return this')();
|
||||
}.call(null));
|
||||
|
||||
goog.exportSymbol('proto.auth.AuthorizationHeader', null, global);
|
||||
goog.exportSymbol('proto.auth.SessionValidationResponse', null, global);
|
||||
/**
|
||||
* Generated by JsPbCodeGenerator.
|
||||
* @param {Array=} opt_data Optional initial data array, typically from a
|
||||
* server response, or constructed directly in Javascript. The array is used
|
||||
* in place and becomes part of the constructed object. It is not cloned.
|
||||
* If no data is provided, the constructed object will be empty, but still
|
||||
* valid.
|
||||
* @extends {jspb.Message}
|
||||
* @constructor
|
||||
*/
|
||||
proto.auth.AuthorizationHeader = function(opt_data) {
|
||||
jspb.Message.initialize(this, opt_data, 0, -1, null, null);
|
||||
};
|
||||
goog.inherits(proto.auth.AuthorizationHeader, jspb.Message);
|
||||
if (goog.DEBUG && !COMPILED) {
|
||||
/**
|
||||
* @public
|
||||
* @override
|
||||
*/
|
||||
proto.auth.AuthorizationHeader.displayName = 'proto.auth.AuthorizationHeader';
|
||||
}
|
||||
/**
|
||||
* Generated by JsPbCodeGenerator.
|
||||
* @param {Array=} opt_data Optional initial data array, typically from a
|
||||
* server response, or constructed directly in Javascript. The array is used
|
||||
* in place and becomes part of the constructed object. It is not cloned.
|
||||
* If no data is provided, the constructed object will be empty, but still
|
||||
* valid.
|
||||
* @extends {jspb.Message}
|
||||
* @constructor
|
||||
*/
|
||||
proto.auth.SessionValidationResponse = function(opt_data) {
|
||||
jspb.Message.initialize(this, opt_data, 0, -1, null, null);
|
||||
};
|
||||
goog.inherits(proto.auth.SessionValidationResponse, jspb.Message);
|
||||
if (goog.DEBUG && !COMPILED) {
|
||||
/**
|
||||
* @public
|
||||
* @override
|
||||
*/
|
||||
proto.auth.SessionValidationResponse.displayName = 'proto.auth.SessionValidationResponse';
|
||||
}
|
||||
|
||||
|
||||
|
||||
if (jspb.Message.GENERATE_TO_OBJECT) {
|
||||
/**
|
||||
* Creates an object representation of this proto.
|
||||
* Field names that are reserved in JavaScript and will be renamed to pb_name.
|
||||
* Optional fields that are not set will be set to undefined.
|
||||
* To access a reserved field use, foo.pb_<name>, eg, foo.pb_default.
|
||||
* For the list of reserved names please see:
|
||||
* net/proto2/compiler/js/internal/generator.cc#kKeyword.
|
||||
* @param {boolean=} opt_includeInstance Deprecated. whether to include the
|
||||
* JSPB instance for transitional soy proto support:
|
||||
* http://goto/soy-param-migration
|
||||
* @return {!Object}
|
||||
*/
|
||||
proto.auth.AuthorizationHeader.prototype.toObject = function(opt_includeInstance) {
|
||||
return proto.auth.AuthorizationHeader.toObject(opt_includeInstance, this);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Static version of the {@see toObject} method.
|
||||
* @param {boolean|undefined} includeInstance Deprecated. Whether to include
|
||||
* the JSPB instance for transitional soy proto support:
|
||||
* http://goto/soy-param-migration
|
||||
* @param {!proto.auth.AuthorizationHeader} msg The msg instance to transform.
|
||||
* @return {!Object}
|
||||
* @suppress {unusedLocalVariables} f is only used for nested messages
|
||||
*/
|
||||
proto.auth.AuthorizationHeader.toObject = function(includeInstance, msg) {
|
||||
var f, obj = {
|
||||
bearerToken: jspb.Message.getFieldWithDefault(msg, 1, "")
|
||||
};
|
||||
|
||||
if (includeInstance) {
|
||||
obj.$jspbMessageInstance = msg;
|
||||
}
|
||||
return obj;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Deserializes binary data (in protobuf wire format).
|
||||
* @param {jspb.ByteSource} bytes The bytes to deserialize.
|
||||
* @return {!proto.auth.AuthorizationHeader}
|
||||
*/
|
||||
proto.auth.AuthorizationHeader.deserializeBinary = function(bytes) {
|
||||
var reader = new jspb.BinaryReader(bytes);
|
||||
var msg = new proto.auth.AuthorizationHeader;
|
||||
return proto.auth.AuthorizationHeader.deserializeBinaryFromReader(msg, reader);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Deserializes binary data (in protobuf wire format) from the
|
||||
* given reader into the given message object.
|
||||
* @param {!proto.auth.AuthorizationHeader} msg The message object to deserialize into.
|
||||
* @param {!jspb.BinaryReader} reader The BinaryReader to use.
|
||||
* @return {!proto.auth.AuthorizationHeader}
|
||||
*/
|
||||
proto.auth.AuthorizationHeader.deserializeBinaryFromReader = function(msg, reader) {
|
||||
while (reader.nextField()) {
|
||||
if (reader.isEndGroup()) {
|
||||
break;
|
||||
}
|
||||
var field = reader.getFieldNumber();
|
||||
switch (field) {
|
||||
case 1:
|
||||
var value = /** @type {string} */ (reader.readString());
|
||||
msg.setBearerToken(value);
|
||||
break;
|
||||
default:
|
||||
reader.skipField();
|
||||
break;
|
||||
}
|
||||
}
|
||||
return msg;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Serializes the message to binary data (in protobuf wire format).
|
||||
* @return {!Uint8Array}
|
||||
*/
|
||||
proto.auth.AuthorizationHeader.prototype.serializeBinary = function() {
|
||||
var writer = new jspb.BinaryWriter();
|
||||
proto.auth.AuthorizationHeader.serializeBinaryToWriter(this, writer);
|
||||
return writer.getResultBuffer();
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Serializes the given message to binary data (in protobuf wire
|
||||
* format), writing to the given BinaryWriter.
|
||||
* @param {!proto.auth.AuthorizationHeader} message
|
||||
* @param {!jspb.BinaryWriter} writer
|
||||
* @suppress {unusedLocalVariables} f is only used for nested messages
|
||||
*/
|
||||
proto.auth.AuthorizationHeader.serializeBinaryToWriter = function(message, writer) {
|
||||
var f = undefined;
|
||||
f = message.getBearerToken();
|
||||
if (f.length > 0) {
|
||||
writer.writeString(
|
||||
1,
|
||||
f
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* optional string bearer_token = 1;
|
||||
* @return {string}
|
||||
*/
|
||||
proto.auth.AuthorizationHeader.prototype.getBearerToken = function() {
|
||||
return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 1, ""));
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {string} value
|
||||
* @return {!proto.auth.AuthorizationHeader} returns this
|
||||
*/
|
||||
proto.auth.AuthorizationHeader.prototype.setBearerToken = function(value) {
|
||||
return jspb.Message.setProto3StringField(this, 1, value);
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
if (jspb.Message.GENERATE_TO_OBJECT) {
|
||||
/**
|
||||
* Creates an object representation of this proto.
|
||||
* Field names that are reserved in JavaScript and will be renamed to pb_name.
|
||||
* Optional fields that are not set will be set to undefined.
|
||||
* To access a reserved field use, foo.pb_<name>, eg, foo.pb_default.
|
||||
* For the list of reserved names please see:
|
||||
* net/proto2/compiler/js/internal/generator.cc#kKeyword.
|
||||
* @param {boolean=} opt_includeInstance Deprecated. whether to include the
|
||||
* JSPB instance for transitional soy proto support:
|
||||
* http://goto/soy-param-migration
|
||||
* @return {!Object}
|
||||
*/
|
||||
proto.auth.SessionValidationResponse.prototype.toObject = function(opt_includeInstance) {
|
||||
return proto.auth.SessionValidationResponse.toObject(opt_includeInstance, this);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Static version of the {@see toObject} method.
|
||||
* @param {boolean|undefined} includeInstance Deprecated. Whether to include
|
||||
* the JSPB instance for transitional soy proto support:
|
||||
* http://goto/soy-param-migration
|
||||
* @param {!proto.auth.SessionValidationResponse} msg The msg instance to transform.
|
||||
* @return {!Object}
|
||||
* @suppress {unusedLocalVariables} f is only used for nested messages
|
||||
*/
|
||||
proto.auth.SessionValidationResponse.toObject = function(includeInstance, msg) {
|
||||
var f, obj = {
|
||||
crossServiceToken: jspb.Message.getFieldWithDefault(msg, 1, "")
|
||||
};
|
||||
|
||||
if (includeInstance) {
|
||||
obj.$jspbMessageInstance = msg;
|
||||
}
|
||||
return obj;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Deserializes binary data (in protobuf wire format).
|
||||
* @param {jspb.ByteSource} bytes The bytes to deserialize.
|
||||
* @return {!proto.auth.SessionValidationResponse}
|
||||
*/
|
||||
proto.auth.SessionValidationResponse.deserializeBinary = function(bytes) {
|
||||
var reader = new jspb.BinaryReader(bytes);
|
||||
var msg = new proto.auth.SessionValidationResponse;
|
||||
return proto.auth.SessionValidationResponse.deserializeBinaryFromReader(msg, reader);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Deserializes binary data (in protobuf wire format) from the
|
||||
* given reader into the given message object.
|
||||
* @param {!proto.auth.SessionValidationResponse} msg The message object to deserialize into.
|
||||
* @param {!jspb.BinaryReader} reader The BinaryReader to use.
|
||||
* @return {!proto.auth.SessionValidationResponse}
|
||||
*/
|
||||
proto.auth.SessionValidationResponse.deserializeBinaryFromReader = function(msg, reader) {
|
||||
while (reader.nextField()) {
|
||||
if (reader.isEndGroup()) {
|
||||
break;
|
||||
}
|
||||
var field = reader.getFieldNumber();
|
||||
switch (field) {
|
||||
case 1:
|
||||
var value = /** @type {string} */ (reader.readString());
|
||||
msg.setCrossServiceToken(value);
|
||||
break;
|
||||
default:
|
||||
reader.skipField();
|
||||
break;
|
||||
}
|
||||
}
|
||||
return msg;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Serializes the message to binary data (in protobuf wire format).
|
||||
* @return {!Uint8Array}
|
||||
*/
|
||||
proto.auth.SessionValidationResponse.prototype.serializeBinary = function() {
|
||||
var writer = new jspb.BinaryWriter();
|
||||
proto.auth.SessionValidationResponse.serializeBinaryToWriter(this, writer);
|
||||
return writer.getResultBuffer();
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Serializes the given message to binary data (in protobuf wire
|
||||
* format), writing to the given BinaryWriter.
|
||||
* @param {!proto.auth.SessionValidationResponse} message
|
||||
* @param {!jspb.BinaryWriter} writer
|
||||
* @suppress {unusedLocalVariables} f is only used for nested messages
|
||||
*/
|
||||
proto.auth.SessionValidationResponse.serializeBinaryToWriter = function(message, writer) {
|
||||
var f = undefined;
|
||||
f = message.getCrossServiceToken();
|
||||
if (f.length > 0) {
|
||||
writer.writeString(
|
||||
1,
|
||||
f
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* optional string cross_service_token = 1;
|
||||
* @return {string}
|
||||
*/
|
||||
proto.auth.SessionValidationResponse.prototype.getCrossServiceToken = function() {
|
||||
return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 1, ""));
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {string} value
|
||||
* @return {!proto.auth.SessionValidationResponse} returns this
|
||||
*/
|
||||
proto.auth.SessionValidationResponse.prototype.setCrossServiceToken = function(value) {
|
||||
return jspb.Message.setProto3StringField(this, 1, value);
|
||||
};
|
||||
|
||||
|
||||
goog.object.extend(exports, proto.auth);
|
2
packages/grpc/lib/index.d.ts
vendored
Normal file
2
packages/grpc/lib/index.d.ts
vendored
Normal file
|
@ -0,0 +1,2 @@
|
|||
export * from './auth_grpc_pb'
|
||||
export * from './auth_pb'
|
18
packages/grpc/lib/index.js
Normal file
18
packages/grpc/lib/index.js
Normal file
|
@ -0,0 +1,18 @@
|
|||
"use strict";
|
||||
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
||||
if (k2 === undefined) k2 = k;
|
||||
var desc = Object.getOwnPropertyDescriptor(m, k);
|
||||
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
||||
desc = { enumerable: true, get: function() { return m[k]; } };
|
||||
}
|
||||
Object.defineProperty(o, k2, desc);
|
||||
}) : (function(o, m, k, k2) {
|
||||
if (k2 === undefined) k2 = k;
|
||||
o[k2] = m[k];
|
||||
}));
|
||||
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
||||
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
__exportStar(require("./auth_grpc_pb"), exports);
|
||||
__exportStar(require("./auth_pb"), exports);
|
33
packages/grpc/package.json
Normal file
33
packages/grpc/package.json
Normal file
|
@ -0,0 +1,33 @@
|
|||
{
|
||||
"name": "@standardnotes/grpc",
|
||||
"version": "1.0.0",
|
||||
"engines": {
|
||||
"node": ">=18.0.0 <21.0.0"
|
||||
},
|
||||
"description": "gRPC definitions for Standard Notes",
|
||||
"author": "Standard Notes",
|
||||
"main": "lib/index.js",
|
||||
"types": "lib/index.d.ts",
|
||||
"files": [
|
||||
"lib/**/*.js",
|
||||
"lib/**/*.d.ts"
|
||||
],
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
},
|
||||
"license": "AGPL-3.0-or-later",
|
||||
"scripts": {
|
||||
"clean": "rm -fr dist",
|
||||
"build": "tsc --build"
|
||||
},
|
||||
"dependencies": {
|
||||
"@grpc/grpc-js": "^1.9.10",
|
||||
"google-protobuf": "^3.21.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/google-protobuf": "^3",
|
||||
"grpc-tools": "^1.12.4",
|
||||
"grpc_tools_node_protoc_ts": "^5.3.3",
|
||||
"typescript": "^5.0.4"
|
||||
}
|
||||
}
|
15
packages/grpc/proto/auth.proto
Normal file
15
packages/grpc/proto/auth.proto
Normal file
|
@ -0,0 +1,15 @@
|
|||
syntax = "proto3";
|
||||
|
||||
package auth;
|
||||
|
||||
message AuthorizationHeader {
|
||||
string bearer_token = 1;
|
||||
}
|
||||
|
||||
message SessionValidationResponse {
|
||||
string cross_service_token = 1;
|
||||
}
|
||||
|
||||
service Sessions {
|
||||
rpc validate(AuthorizationHeader) returns (SessionValidationResponse) {}
|
||||
}
|
20
packages/grpc/scripts/build-protos.sh
Executable file
20
packages/grpc/scripts/build-protos.sh
Executable file
|
@ -0,0 +1,20 @@
|
|||
#!/bin/bash
|
||||
|
||||
PROTO_DEST=./lib
|
||||
|
||||
mkdir -p ${PROTO_DEST}
|
||||
|
||||
# generate js codes via grpc-tools
|
||||
yarn run grpc_tools_node_protoc \
|
||||
--js_out=import_style=commonjs,binary:${PROTO_DEST} \
|
||||
--grpc_out=${PROTO_DEST} \
|
||||
--plugin=protoc-gen-grpc=../../.yarn/unplugged/grpc-tools-npm-1.12.4-956df6794d/node_modules/grpc-tools/bin/protoc_plugin.js \
|
||||
-I ./proto \
|
||||
proto/*.proto
|
||||
|
||||
# generate d.ts codes
|
||||
yarn run grpc_tools_node_protoc \
|
||||
--plugin=protoc-gen-ts=../../.yarn/unplugged/grpc_tools_node_protoc_ts-npm-5.3.3-297a345c26/node_modules/grpc_tools_node_protoc_ts/bin/protoc-gen-ts \
|
||||
--ts_out=${PROTO_DEST} \
|
||||
-I ./proto \
|
||||
proto/*.proto
|
9
packages/grpc/tsconfig.json
Normal file
9
packages/grpc/tsconfig.json
Normal file
|
@ -0,0 +1,9 @@
|
|||
{
|
||||
"extends": "../../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"composite": true,
|
||||
"outDir": "./lib",
|
||||
},
|
||||
"include": [],
|
||||
"references": []
|
||||
}
|
|
@ -176,7 +176,9 @@ export class HomeServer implements HomeServerInterface {
|
|||
|
||||
const serverInstance = server.build().listen(port)
|
||||
|
||||
const keepAliveTimeout = env.get('KEEP_ALIVE_TIMEOUT', true) ? +env.get('KEEP_ALIVE_TIMEOUT', true) : 5000
|
||||
const keepAliveTimeout = env.get('HTTP_KEEP_ALIVE_TIMEOUT', true)
|
||||
? +env.get('HTTP_KEEP_ALIVE_TIMEOUT', true)
|
||||
: 5000
|
||||
|
||||
serverInstance.keepAliveTimeout = keepAliveTimeout
|
||||
|
||||
|
|
|
@ -45,7 +45,7 @@ void container.load().then((container) => {
|
|||
|
||||
const serverInstance = server.build().listen(env.get('PORT'))
|
||||
|
||||
const keepAliveTimeout = env.get('KEEP_ALIVE_TIMEOUT', true) ? +env.get('KEEP_ALIVE_TIMEOUT', true) : 5000
|
||||
const keepAliveTimeout = env.get('HTTP_KEEP_ALIVE_TIMEOUT', true) ? +env.get('HTTP_KEEP_ALIVE_TIMEOUT', true) : 5000
|
||||
|
||||
serverInstance.keepAliveTimeout = keepAliveTimeout
|
||||
|
||||
|
|
|
@ -74,7 +74,7 @@ void container.load().then((container) => {
|
|||
|
||||
const serverInstance = server.build().listen(env.get('PORT'))
|
||||
|
||||
const keepAliveTimeout = env.get('KEEP_ALIVE_TIMEOUT', true) ? +env.get('KEEP_ALIVE_TIMEOUT', true) : 5000
|
||||
const keepAliveTimeout = env.get('HTTP_KEEP_ALIVE_TIMEOUT', true) ? +env.get('HTTP_KEEP_ALIVE_TIMEOUT', true) : 5000
|
||||
|
||||
serverInstance.keepAliveTimeout = keepAliveTimeout
|
||||
|
||||
|
|
|
@ -46,7 +46,7 @@ void container.load().then((container) => {
|
|||
|
||||
const serverInstance = server.build().listen(env.get('PORT'))
|
||||
|
||||
const keepAliveTimeout = env.get('KEEP_ALIVE_TIMEOUT', true) ? +env.get('KEEP_ALIVE_TIMEOUT', true) : 5000
|
||||
const keepAliveTimeout = env.get('HTTP_KEEP_ALIVE_TIMEOUT', true) ? +env.get('HTTP_KEEP_ALIVE_TIMEOUT', true) : 5000
|
||||
|
||||
serverInstance.keepAliveTimeout = keepAliveTimeout
|
||||
|
||||
|
|
|
@ -47,6 +47,9 @@
|
|||
{
|
||||
"path": "./packages/files"
|
||||
},
|
||||
{
|
||||
"path": "./packages/grpc"
|
||||
},
|
||||
{
|
||||
"path": "./packages/predicates"
|
||||
},
|
||||
|
|
98
yarn.lock
98
yarn.lock
|
@ -2341,6 +2341,16 @@ __metadata:
|
|||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@grpc/grpc-js@npm:^1.9.10":
|
||||
version: 1.9.10
|
||||
resolution: "@grpc/grpc-js@npm:1.9.10"
|
||||
dependencies:
|
||||
"@grpc/proto-loader": "npm:^0.7.8"
|
||||
"@types/node": "npm:>=12.12.47"
|
||||
checksum: 243cf994e6487ec9b6b24b155468c598e7f100491b3a274a963abd897b751d831149362b3c47c2d7c905df3d0fd0fa294ce8cba33efdde61f48e326b6e657e06
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@grpc/proto-loader@npm:^0.7.8":
|
||||
version: 0.7.10
|
||||
resolution: "@grpc/proto-loader@npm:0.7.10"
|
||||
|
@ -2980,6 +2990,25 @@ __metadata:
|
|||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@mapbox/node-pre-gyp@npm:^1.0.5":
|
||||
version: 1.0.11
|
||||
resolution: "@mapbox/node-pre-gyp@npm:1.0.11"
|
||||
dependencies:
|
||||
detect-libc: "npm:^2.0.0"
|
||||
https-proxy-agent: "npm:^5.0.0"
|
||||
make-dir: "npm:^3.1.0"
|
||||
node-fetch: "npm:^2.6.7"
|
||||
nopt: "npm:^5.0.0"
|
||||
npmlog: "npm:^5.0.1"
|
||||
rimraf: "npm:^3.0.2"
|
||||
semver: "npm:^7.3.5"
|
||||
tar: "npm:^6.1.11"
|
||||
bin:
|
||||
node-pre-gyp: bin/node-pre-gyp
|
||||
checksum: 59529a2444e44fddb63057152452b00705aa58059079191126c79ac1388ae4565625afa84ed4dd1bf017d1111ab6e47907f7c5192e06d83c9496f2f3e708680a
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@nodelib/fs.scandir@npm:2.1.5":
|
||||
version: 2.1.5
|
||||
resolution: "@nodelib/fs.scandir@npm:2.1.5"
|
||||
|
@ -5235,9 +5264,11 @@ __metadata:
|
|||
version: 0.0.0-use.local
|
||||
resolution: "@standardnotes/api-gateway@workspace:packages/api-gateway"
|
||||
dependencies:
|
||||
"@grpc/grpc-js": "npm:^1.9.10"
|
||||
"@standardnotes/domain-core": "workspace:^"
|
||||
"@standardnotes/domain-events": "workspace:*"
|
||||
"@standardnotes/domain-events-infra": "workspace:*"
|
||||
"@standardnotes/grpc": "workspace:^"
|
||||
"@standardnotes/security": "workspace:*"
|
||||
"@standardnotes/time": "workspace:*"
|
||||
"@types/cors": "npm:^2.8.9"
|
||||
|
@ -5296,6 +5327,7 @@ __metadata:
|
|||
"@aws-sdk/client-sqs": "npm:^3.427.0"
|
||||
"@cbor-extract/cbor-extract-linux-arm64": "npm:^2.1.1"
|
||||
"@cbor-extract/cbor-extract-linux-x64": "npm:^2.1.1"
|
||||
"@grpc/grpc-js": "npm:^1.9.10"
|
||||
"@simplewebauthn/server": "npm:^8.1.1"
|
||||
"@simplewebauthn/typescript-types": "npm:^8.0.0"
|
||||
"@standardnotes/api": "npm:^1.26.26"
|
||||
|
@ -5304,6 +5336,7 @@ __metadata:
|
|||
"@standardnotes/domain-events": "workspace:*"
|
||||
"@standardnotes/domain-events-infra": "workspace:*"
|
||||
"@standardnotes/features": "npm:^1.59.7"
|
||||
"@standardnotes/grpc": "workspace:^"
|
||||
"@standardnotes/predicates": "workspace:*"
|
||||
"@standardnotes/responses": "npm:^1.13.27"
|
||||
"@standardnotes/security": "workspace:*"
|
||||
|
@ -5504,6 +5537,19 @@ __metadata:
|
|||
languageName: unknown
|
||||
linkType: soft
|
||||
|
||||
"@standardnotes/grpc@workspace:^, @standardnotes/grpc@workspace:packages/grpc":
|
||||
version: 0.0.0-use.local
|
||||
resolution: "@standardnotes/grpc@workspace:packages/grpc"
|
||||
dependencies:
|
||||
"@grpc/grpc-js": "npm:^1.9.10"
|
||||
"@types/google-protobuf": "npm:^3"
|
||||
google-protobuf: "npm:^3.21.2"
|
||||
grpc-tools: "npm:^1.12.4"
|
||||
grpc_tools_node_protoc_ts: "npm:^5.3.3"
|
||||
typescript: "npm:^5.0.4"
|
||||
languageName: unknown
|
||||
linkType: soft
|
||||
|
||||
"@standardnotes/home-server@workspace:packages/home-server":
|
||||
version: 0.0.0-use.local
|
||||
resolution: "@standardnotes/home-server@workspace:packages/home-server"
|
||||
|
@ -5691,6 +5737,11 @@ __metadata:
|
|||
ini: "npm:^4.1.1"
|
||||
ts-node: "npm:^10.9.1"
|
||||
typescript: "npm:^5.0.4"
|
||||
dependenciesMeta:
|
||||
grpc-tools@1.12.4:
|
||||
unplugged: true
|
||||
grpc_tools_node_protoc_ts@5.3.3:
|
||||
unplugged: true
|
||||
languageName: unknown
|
||||
linkType: soft
|
||||
|
||||
|
@ -6093,6 +6144,13 @@ __metadata:
|
|||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@types/google-protobuf@npm:^3":
|
||||
version: 3.15.10
|
||||
resolution: "@types/google-protobuf@npm:3.15.10"
|
||||
checksum: 29efde966ff47ae824ffe2bccfc999a3adf355745a606a24177ada0e6b7892ea49b2fdd0355400c2140dbd9175bf1d1109f20ce6fdb40ec833724ade439d03d6
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@types/graceful-fs@npm:^4.1.3":
|
||||
version: 4.1.6
|
||||
resolution: "@types/graceful-fs@npm:4.1.6"
|
||||
|
@ -9460,6 +9518,20 @@ __metadata:
|
|||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"google-protobuf@npm:3.15.8":
|
||||
version: 3.15.8
|
||||
resolution: "google-protobuf@npm:3.15.8"
|
||||
checksum: 0b1ea24a552e0870b658b975ce5090c13f35793dc4ff8a733ad9c27990126eb9bd375fa9d3204af4f634930ae358d8b5e78f9f4cdb1f700e35b4d857f0aac742
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"google-protobuf@npm:^3.21.2":
|
||||
version: 3.21.2
|
||||
resolution: "google-protobuf@npm:3.21.2"
|
||||
checksum: b376c2e47fb0419b41b901e4da8f3827fe9594ffb7887708b9c241f36005d0b9f2edc7b3f05795f6793924a241e767f67831732eae0f23bdbb337b56a6ab4e26
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"graceful-fs@npm:^4.1.2, graceful-fs@npm:^4.1.6, graceful-fs@npm:^4.2.0, graceful-fs@npm:^4.2.11, graceful-fs@npm:^4.2.4, graceful-fs@npm:^4.2.6, graceful-fs@npm:^4.2.9":
|
||||
version: 4.2.11
|
||||
resolution: "graceful-fs@npm:4.2.11"
|
||||
|
@ -9474,7 +9546,31 @@ __metadata:
|
|||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"handlebars@npm:^4.7.7":
|
||||
"grpc-tools@npm:^1.12.4":
|
||||
version: 1.12.4
|
||||
resolution: "grpc-tools@npm:1.12.4"
|
||||
dependencies:
|
||||
"@mapbox/node-pre-gyp": "npm:^1.0.5"
|
||||
bin:
|
||||
grpc_tools_node_protoc: bin/protoc.js
|
||||
grpc_tools_node_protoc_plugin: bin/protoc_plugin.js
|
||||
checksum: 56852c756fe34be5f3b2cf75b1d432886b17ad32d438cacbcf8d30e980c7361a8e8325b1e626ce99826b8dbf1364145bedbedeb6d7feb916c4801481810a05d1
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"grpc_tools_node_protoc_ts@npm:^5.3.3":
|
||||
version: 5.3.3
|
||||
resolution: "grpc_tools_node_protoc_ts@npm:5.3.3"
|
||||
dependencies:
|
||||
google-protobuf: "npm:3.15.8"
|
||||
handlebars: "npm:4.7.7"
|
||||
bin:
|
||||
protoc-gen-ts: bin/protoc-gen-ts
|
||||
checksum: 96fe57b04a7d9e7e656678fab14dd4fc8027849abbb487a7eae4d2841651aa9a481402d5b9df34b4ac3bac6f190551db2e647127d6f6736d5f89ea2fa791ff33
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"handlebars@npm:4.7.7, handlebars@npm:^4.7.7":
|
||||
version: 4.7.7
|
||||
resolution: "handlebars@npm:4.7.7"
|
||||
dependencies:
|
||||
|
|
Loading…
Reference in a new issue