@rpcbase/server 0.380.0 → 0.381.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +15 -72
- package/src/getDerivedKey.ts +20 -0
- package/src/hashPassword.ts +24 -0
- package/src/index.ts +3 -0
- package/src/initServer.ts +68 -0
- package/src/types/index.ts +7 -0
- package/src/types/session.d.ts +10 -0
- package/boot/server.js +0 -36
- package/boot/shared.js +0 -17
- package/boot/worker.js +0 -37
- package/constants/keys.ts +0 -1
- package/database.js +0 -96
- package/express/custom_cors.js +0 -80
- package/express/dev_save_coverage.js +0 -18
- package/express/index.js +0 -93
- package/express/setup_handlers.js +0 -49
- package/files.ts +0 -1
- package/firebase.js +0 -33
- package/get_object_id.ts +0 -39
- package/index.js +0 -17
- package/mailer/index.js +0 -31
- package/mongoose/index.ts +0 -16
- package/mongoose/plugins/disable_default_timestamps_plugin.ts +0 -5
- package/mongoose/plugins/disable_default_version_key_plugin.ts +0 -5
- package/mongoose/plugins/object_id_plugin.ts +0 -31
- package/openai.js +0 -10
- package/publish-output.txt +0 -0
- package/queue/dispatch_indexer_queue.js +0 -22
- package/queue/dispatch_worker_queue.js +0 -38
- package/queue/index.js +0 -110
- package/queue/register_queue_listener.js +0 -180
- package/redis.js +0 -2
- package/rts/index.js +0 -444
- package/search/constants.ts +0 -1
- package/search/ensure_index.ts +0 -53
- package/search/get_client.ts +0 -15
- package/search/index.ts +0 -3
- package/src/access-control/apply_policies.js +0 -104
- package/src/access-control/get_added_fields.js +0 -23
- package/src/access-control/get_policies.js +0 -29
- package/src/access-control/hooks/doc_pre_create.js +0 -26
- package/src/access-control/hooks/query_pre_delete.js +0 -30
- package/src/access-control/index.js +0 -6
- package/src/access-control/mongoose_plugin.js +0 -136
- package/src/api/index.js +0 -6
- package/src/api/stored-values/get_stored_values.js +0 -41
- package/src/api/stored-values/index.js +0 -8
- package/src/api/stored-values/set_stored_values.js +0 -31
- package/src/auth/check_session.js +0 -43
- package/src/auth/forgot_password_email.html +0 -515
- package/src/auth/get_account.js +0 -35
- package/src/auth/get_accounts.js +0 -42
- package/src/auth/index.js +0 -24
- package/src/auth/reset_password.js +0 -70
- package/src/auth/set_new_password.js +0 -63
- package/src/auth/set_new_password_email.html +0 -3
- package/src/auth/sign_in.js +0 -61
- package/src/auth/sign_out.js +0 -11
- package/src/auth/sign_up.js +0 -56
- package/src/client/client_router.js +0 -105
- package/src/files/constants.ts +0 -9
- package/src/files/finalize_file_upload.ts +0 -25
- package/src/files/helpers/get_grid_fs_bucket.ts +0 -20
- package/src/files/index.js +0 -5
- package/src/files/tasks/finalize_file_upload/apply_img_preview.ts +0 -49
- package/src/files/tasks/finalize_file_upload/constants.ts +0 -23
- package/src/files/tasks/finalize_file_upload/download_file.ts +0 -98
- package/src/files/tasks/finalize_file_upload/get_text_vectors.ts +0 -13
- package/src/files/tasks/finalize_file_upload/helpers/convert_pdf_to_png.ts +0 -34
- package/src/files/tasks/finalize_file_upload/helpers/exec.ts +0 -5
- package/src/files/tasks/finalize_file_upload/helpers/get_metadata.ts +0 -18
- package/src/files/tasks/finalize_file_upload/index.ts +0 -53
- package/src/files/tasks/finalize_file_upload/run_ocr.ts +0 -42
- package/src/files/tasks/index.ts +0 -6
- package/src/files/upload_chunk.ts +0 -83
- package/src/helpers/sim_test_inject.ts +0 -21
- package/src/models/Invite.js +0 -23
- package/src/models/Notification.js +0 -44
- package/src/models/Policy.ts +0 -13
- package/src/models/ResetPasswordToken.js +0 -14
- package/src/models/SearchHistory.ts +0 -22
- package/src/models/User.js +0 -42
- package/src/models/UserStoredValues.js +0 -18
- package/src/models/index.js +0 -7
- package/src/notitications/ack_notification.js +0 -26
- package/src/notitications/get_notifications.js +0 -39
- package/src/notitications/llt/README.md +0 -8
- package/src/notitications/llt/get_llts.js +0 -42
- package/src/notitications/set_seen.js +0 -26
- package/src/sessions/index.js +0 -27
- package/src/sessions/session_proxy_middleware.js +0 -18
- package/src/sessions/session_store_middleware.js +0 -106
- package/src/sessions/warning_proxy_middleware.js +0 -17
- package/src/tasks/index.js +0 -8
- package/src/tasks/index_item.js +0 -8
- package/store/index.js +0 -31
package/package.json
CHANGED
|
@@ -1,88 +1,31 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rpcbase/server",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"
|
|
5
|
-
"main": "./index.
|
|
3
|
+
"version": "0.381.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"main": "./src/index.ts",
|
|
6
6
|
"scripts": {
|
|
7
|
-
"
|
|
8
|
-
|
|
9
|
-
"publishConfig": {
|
|
10
|
-
"registry": "https://registry.npmjs.org/"
|
|
7
|
+
"build": "tsc --watch",
|
|
8
|
+
"release": "wireit"
|
|
11
9
|
},
|
|
12
10
|
"wireit": {
|
|
13
|
-
"
|
|
14
|
-
"command": "
|
|
15
|
-
"
|
|
16
|
-
"firebase/entry*.js",
|
|
17
|
-
"firebase/webpack.config.js"
|
|
18
|
-
],
|
|
19
|
-
"output": [
|
|
20
|
-
"firebase/index.js",
|
|
21
|
-
"firebase/sw.js"
|
|
22
|
-
]
|
|
23
|
-
},
|
|
24
|
-
"build": {
|
|
25
|
-
"dependencies": [
|
|
26
|
-
"build-firebase"
|
|
27
|
-
]
|
|
28
|
-
},
|
|
29
|
-
"test": {
|
|
30
|
-
"command": "echo 'no tests specified, exiting'",
|
|
11
|
+
"release": {
|
|
12
|
+
"command": "../../scripts/publish.js",
|
|
13
|
+
"dependencies": [],
|
|
31
14
|
"files": [
|
|
32
|
-
"
|
|
33
|
-
"!coverage/",
|
|
34
|
-
"!node_modules/"
|
|
15
|
+
"package.json"
|
|
35
16
|
],
|
|
36
|
-
"output": [
|
|
37
|
-
"coverage/"
|
|
38
|
-
]
|
|
39
|
-
},
|
|
40
|
-
"apply-version": {
|
|
41
|
-
"command": "node ../../scripts/prflow/apply-prerelease-versions.js $BRANCH_NAME",
|
|
17
|
+
"output": [],
|
|
42
18
|
"env": {
|
|
43
|
-
"
|
|
19
|
+
"NPM_RELEASE_CHANNEL": {
|
|
44
20
|
"external": true
|
|
45
21
|
}
|
|
46
22
|
}
|
|
47
|
-
},
|
|
48
|
-
"release": {
|
|
49
|
-
"command": "npm publish --tag $NPM_RELEASE_CHANNEL | tee publish-output.txt",
|
|
50
|
-
"dependencies": [
|
|
51
|
-
"test",
|
|
52
|
-
"apply-version"
|
|
53
|
-
],
|
|
54
|
-
"files": [
|
|
55
|
-
"package.json"
|
|
56
|
-
],
|
|
57
|
-
"output": [
|
|
58
|
-
"publish-output.txt"
|
|
59
|
-
]
|
|
60
23
|
}
|
|
61
24
|
},
|
|
62
25
|
"dependencies": {
|
|
63
|
-
"
|
|
64
|
-
"@sentry/node": "8.36.0",
|
|
65
|
-
"bluebird": "3.7.2",
|
|
66
|
-
"body-parser": "1.20.3",
|
|
67
|
-
"bull": "4.16.3",
|
|
68
|
-
"connect-redis": "7.1.1",
|
|
69
|
-
"cors": "2.8.5",
|
|
70
|
-
"debug": "4.3.7",
|
|
71
|
-
"dotenv": "16.4.5",
|
|
72
|
-
"express": "4.21.1",
|
|
26
|
+
"connect-redis": "8.0.1",
|
|
73
27
|
"express-session": "1.18.1",
|
|
74
|
-
"
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
"mongoose": "8.7.3",
|
|
78
|
-
"openai": "4.69.0",
|
|
79
|
-
"pdf2pic": "3.1.3",
|
|
80
|
-
"picocolors": "1.1.1",
|
|
81
|
-
"postmark": "4.0.5",
|
|
82
|
-
"redis": "4.7.0",
|
|
83
|
-
"request-ip": "3.3.0",
|
|
84
|
-
"sift": "17.1.3",
|
|
85
|
-
"socket.io": "4.8.1",
|
|
86
|
-
"validator": "13.12.0"
|
|
87
|
-
}
|
|
28
|
+
"redis": "4.7.0"
|
|
29
|
+
},
|
|
30
|
+
"devDependencies": {}
|
|
88
31
|
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import assert from "assert"
|
|
2
|
+
import { hkdfSync } from "crypto"
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
export const getDerivedKey = (
|
|
6
|
+
masterKey: string,
|
|
7
|
+
info: string,
|
|
8
|
+
length: number = 32, // Default to 256-bit keys
|
|
9
|
+
salt: string = "",
|
|
10
|
+
): string => {
|
|
11
|
+
assert(masterKey?.length > 32, "MASTER_KEY must be longer than 32 chars.")
|
|
12
|
+
|
|
13
|
+
return Buffer.from(hkdfSync(
|
|
14
|
+
"sha256",
|
|
15
|
+
masterKey,
|
|
16
|
+
Buffer.from(salt),
|
|
17
|
+
Buffer.from(info),
|
|
18
|
+
length,
|
|
19
|
+
)).toString("hex")
|
|
20
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { scrypt } from "crypto"
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
export async function hashPassword(password: string, salt: string): Promise<Buffer> {
|
|
5
|
+
const keyLength = 64 // Length of the derived key
|
|
6
|
+
const options = {
|
|
7
|
+
N: 8192, // CPU/memory cost parameter
|
|
8
|
+
r: 8, // Block size
|
|
9
|
+
p: 1 // Parallelization factor
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
// Return a Promise-wrapped scrypt call
|
|
13
|
+
const derivedKey = await new Promise<Buffer>((resolve, reject) => {
|
|
14
|
+
scrypt(password, salt, keyLength, options, (err, derivedKey) => {
|
|
15
|
+
if (err) {
|
|
16
|
+
reject(err)
|
|
17
|
+
} else {
|
|
18
|
+
resolve(derivedKey)
|
|
19
|
+
}
|
|
20
|
+
})
|
|
21
|
+
})
|
|
22
|
+
|
|
23
|
+
return derivedKey
|
|
24
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { Application } from "express"
|
|
2
|
+
import session, { SessionOptions } from "express-session"
|
|
3
|
+
import {RedisStore} from "connect-redis"
|
|
4
|
+
import {createClient} from "redis"
|
|
5
|
+
|
|
6
|
+
import { getDerivedKey } from "./getDerivedKey"
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
const SESSION_STORE_HOST = "localhost"
|
|
10
|
+
const SESSION_STORE_PORT = "6379"
|
|
11
|
+
|
|
12
|
+
const isProduction = process.env.NODE_ENV === "production"
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
export const initServer = async (app: Application, serverEnv: { [key: string]: string | undefined }) => {
|
|
16
|
+
|
|
17
|
+
const sessionSecret = getDerivedKey(serverEnv.MASTER_KEY!, "express_session_key")
|
|
18
|
+
|
|
19
|
+
const reconnectStrategy = (retries: number) => {
|
|
20
|
+
console.log("redis_client::reconnectStrategy::retrying with arg", retries)
|
|
21
|
+
if (retries < 5) {
|
|
22
|
+
console.log("retry count:", retries, "retrying in 1s")
|
|
23
|
+
return 4000
|
|
24
|
+
} else {
|
|
25
|
+
return new Error("max retries expiered")
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const redisClient = createClient({
|
|
30
|
+
socket: {
|
|
31
|
+
host: SESSION_STORE_HOST,
|
|
32
|
+
port: Number(SESSION_STORE_PORT),
|
|
33
|
+
reconnectStrategy,
|
|
34
|
+
connectTimeout: 10000,
|
|
35
|
+
keepAlive: 0,
|
|
36
|
+
},
|
|
37
|
+
})
|
|
38
|
+
|
|
39
|
+
redisClient.on("ready", () => {
|
|
40
|
+
console.log("session-storage::redis_client connected")
|
|
41
|
+
})
|
|
42
|
+
|
|
43
|
+
redisClient.on("error", (error) => {
|
|
44
|
+
console.log("session-storage::redis_client ERROR", error)
|
|
45
|
+
})
|
|
46
|
+
|
|
47
|
+
redisClient.connect()
|
|
48
|
+
|
|
49
|
+
const sessionConfig: SessionOptions = {
|
|
50
|
+
name: "session",
|
|
51
|
+
store: new RedisStore({client: redisClient}),
|
|
52
|
+
proxy: true,
|
|
53
|
+
resave: false,
|
|
54
|
+
saveUninitialized: false,
|
|
55
|
+
secret: sessionSecret,
|
|
56
|
+
cookie: {
|
|
57
|
+
maxAge: 1000 * 3600 * 24 * 90 // 90 days
|
|
58
|
+
},
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
if (isProduction) {
|
|
62
|
+
sessionConfig.cookie!.secure = true
|
|
63
|
+
// sessionConfig.cookie.domain = ""
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
app.use(session(sessionConfig))
|
|
67
|
+
|
|
68
|
+
}
|
package/boot/server.js
DELETED
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
/* @flow */
|
|
2
|
-
// MUST COME FIRST!
|
|
3
|
-
require("./shared")
|
|
4
|
-
//
|
|
5
|
-
const rb_server_plugin = require("rb-plugin-server")
|
|
6
|
-
|
|
7
|
-
const http = require("http")
|
|
8
|
-
|
|
9
|
-
const {client_router, express} = require("../")
|
|
10
|
-
|
|
11
|
-
const {init_rts} = require("../rts")
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
const {SERVER_PORT} = process.env
|
|
15
|
-
|
|
16
|
-
const app = express()
|
|
17
|
-
const server = http.createServer(app)
|
|
18
|
-
|
|
19
|
-
init_rts(server)
|
|
20
|
-
|
|
21
|
-
rb_server_plugin.default(app)
|
|
22
|
-
|
|
23
|
-
client_router(app)
|
|
24
|
-
|
|
25
|
-
server.listen(SERVER_PORT, "0.0.0.0", () => {
|
|
26
|
-
console.log(`listening on 0.0.0.0:${SERVER_PORT}`)
|
|
27
|
-
})
|
|
28
|
-
|
|
29
|
-
// graceful exit handler
|
|
30
|
-
process.on("SIGTERM", () => {
|
|
31
|
-
server.close(() => {
|
|
32
|
-
process.exit(0)
|
|
33
|
-
})
|
|
34
|
-
})
|
|
35
|
-
|
|
36
|
-
module.exports = app
|
package/boot/shared.js
DELETED
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
/* @flow */
|
|
2
|
-
if (typeof __RB_IS_WEBPACK__ === "undefined") {
|
|
3
|
-
throw new Error("cannot run without webpack bundling")
|
|
4
|
-
}
|
|
5
|
-
|
|
6
|
-
require("@rpcbase/std/extend-expect")
|
|
7
|
-
|
|
8
|
-
const mongoose = require("../mongoose")
|
|
9
|
-
|
|
10
|
-
require("../src/models")
|
|
11
|
-
|
|
12
|
-
require("../src/access-control")(mongoose)
|
|
13
|
-
|
|
14
|
-
const {database, firebase} = require("../")
|
|
15
|
-
|
|
16
|
-
database()
|
|
17
|
-
firebase.setup()
|
package/boot/worker.js
DELETED
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
/* @flow */
|
|
2
|
-
require("./shared")
|
|
3
|
-
|
|
4
|
-
require("rb-plugin-worker")
|
|
5
|
-
require("../src/tasks")
|
|
6
|
-
|
|
7
|
-
const register_queue_listener = require("../queue/register_queue_listener")
|
|
8
|
-
|
|
9
|
-
const queue = require("../queue")
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
queue.start()
|
|
13
|
-
|
|
14
|
-
let _queue_listener
|
|
15
|
-
|
|
16
|
-
register_queue_listener()
|
|
17
|
-
.then((arg) => {
|
|
18
|
-
_queue_listener = arg
|
|
19
|
-
})
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
const handle_graceful_exit = async() => {
|
|
23
|
-
const close_fns = [
|
|
24
|
-
queue.instance().close,
|
|
25
|
-
]
|
|
26
|
-
|
|
27
|
-
if (_queue_listener) {
|
|
28
|
-
close_fns.push(_queue_listener.close)
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
await Promise.allSettled(close_fns.map(fn => fn()))
|
|
32
|
-
|
|
33
|
-
process.exit(0)
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
process.on("SIGTERM", handle_graceful_exit)
|
|
37
|
-
// process.on("SIGINT", handle_graceful_exit)
|
package/constants/keys.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export const SEARCH_INDEX_PREFIX = "rb-indexer"
|
package/database.js
DELETED
|
@@ -1,96 +0,0 @@
|
|
|
1
|
-
/* @flow */
|
|
2
|
-
const isPort = require("validator/lib/isPort")
|
|
3
|
-
|
|
4
|
-
// const {is_docker} = require("@rpcbase/std")
|
|
5
|
-
const is_docker = () => true
|
|
6
|
-
|
|
7
|
-
const mongoose = require("./mongoose")
|
|
8
|
-
|
|
9
|
-
const pack = require("./package.json")
|
|
10
|
-
|
|
11
|
-
// load internal models
|
|
12
|
-
require("./src/models/User")
|
|
13
|
-
require("./src/models/Invite")
|
|
14
|
-
require("./src/models/ResetPasswordToken")
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
const {RB_APP_NAME, DATABASE_PORT} = process.env
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
// database can be set by env variable or passed as paramaters to
|
|
21
|
-
|
|
22
|
-
if (typeof DATABASE_PORT !== "string" || !isPort(DATABASE_PORT)) {
|
|
23
|
-
throw new Error("expected DATABASE_PORT to be a valid port number")
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
if (typeof RB_APP_NAME !== "string") {
|
|
27
|
-
throw new Error("expected RB_APP_NAME in env to be a string")
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
const get_mongo_url = () => {
|
|
32
|
-
const conn_suffix = `?directConnection=true&replicaSet=rs0`
|
|
33
|
-
|
|
34
|
-
let url
|
|
35
|
-
|
|
36
|
-
// connect via tcp in docker
|
|
37
|
-
if (is_docker()) {
|
|
38
|
-
const hostname = "database" // "127.0.0.1"
|
|
39
|
-
url = `mongodb://${hostname}:${DATABASE_PORT}/${conn_suffix}`
|
|
40
|
-
}
|
|
41
|
-
// when running natively, prefer the unix socket
|
|
42
|
-
else {
|
|
43
|
-
const uds_root_path = `/tmp/sockets-${RB_APP_NAME}/`
|
|
44
|
-
url = `mongodb://${encodeURIComponent(uds_root_path)}mongodb-${DATABASE_PORT}.sock`
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
return url
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
module.exports = async() => {
|
|
52
|
-
// set listeners before attempting to connect
|
|
53
|
-
mongoose.connection.on("connected", () => {
|
|
54
|
-
console.log("mongoose connected")
|
|
55
|
-
})
|
|
56
|
-
|
|
57
|
-
mongoose.connection.on("disconnected", (arg) => {
|
|
58
|
-
// TODO: add tracing
|
|
59
|
-
console.log("Mongoose disconnected", arg)
|
|
60
|
-
})
|
|
61
|
-
|
|
62
|
-
// TODO: should we be retrying in dev only
|
|
63
|
-
mongoose.connection.on("error", (err) => {
|
|
64
|
-
// replicaSet has no primary, retry connecting in a moment
|
|
65
|
-
console.log("mongoose connection error", err)
|
|
66
|
-
})
|
|
67
|
-
|
|
68
|
-
const mongo_url = get_mongo_url()
|
|
69
|
-
console.log("connect mongo_url", mongo_url)
|
|
70
|
-
|
|
71
|
-
const connect_opts = {
|
|
72
|
-
dbName: RB_APP_NAME,
|
|
73
|
-
minPoolSize: 8,
|
|
74
|
-
// maxPoolSize: 1024 * 1024,
|
|
75
|
-
// TODO: setting this to a low value adds ~3s delay to requests... WHY
|
|
76
|
-
maxPoolSize: 512,
|
|
77
|
-
family: 4, // force ipv4
|
|
78
|
-
driverInfo: {
|
|
79
|
-
name: `${pack.name}/database`,
|
|
80
|
-
version: pack.version,
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
// INFO: on reconnects
|
|
85
|
-
// https://jira.mongodb.org/browse/NODE-834?focusedCommentId=1412582&page=com.atlassian.jira.plugin.system.issuetabpanels%3Acomment-tabpanel#comment-1412582
|
|
86
|
-
// The driver will fail on first connect if it cannot connect to the host. This is by design to ensure quick failure on unreachable hosts. Reconnect behavior only kicks in once the driver has performed the initial connect.
|
|
87
|
-
try {
|
|
88
|
-
await mongoose.connect(mongo_url, connect_opts)
|
|
89
|
-
} catch (err) {
|
|
90
|
-
// TODO: handle error ?
|
|
91
|
-
console.log("mongoose connect SERVER GOT ERROR")
|
|
92
|
-
console.log(err)
|
|
93
|
-
console.log("JSON:", JSON.stringify(err, null, 2))
|
|
94
|
-
console.log("resaon", err.reason)
|
|
95
|
-
}
|
|
96
|
-
}
|
package/express/custom_cors.js
DELETED
|
@@ -1,80 +0,0 @@
|
|
|
1
|
-
/* @flow */
|
|
2
|
-
const debug = require("debug")
|
|
3
|
-
const cors = require("cors")
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
const log = debug("rb:cors")
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
const {RB_SKIP_CORS_PATHS, NODE_ENV, APP_DOMAIN, CLIENT_PORT} = process.env
|
|
10
|
-
|
|
11
|
-
const is_production = NODE_ENV === "production"
|
|
12
|
-
|
|
13
|
-
const custom_cors = (app) => {
|
|
14
|
-
|
|
15
|
-
const skip_paths = (RB_SKIP_CORS_PATHS || "").split(",").filter((p) => !!p)
|
|
16
|
-
|
|
17
|
-
// CORS
|
|
18
|
-
const cors_origins = is_production ?
|
|
19
|
-
// https://stackoverflow.com/questions/14003332/access-control-allow-origin-wildcard-subdomains-ports-and-protocols
|
|
20
|
-
// production
|
|
21
|
-
[
|
|
22
|
-
`https://www.${APP_DOMAIN}`,
|
|
23
|
-
`https://${APP_DOMAIN}`,
|
|
24
|
-
`https://admin.${APP_DOMAIN}`,
|
|
25
|
-
// This is used for the posthog player to retrieve the css and assets files
|
|
26
|
-
`https://app.posthog.com`,
|
|
27
|
-
`https://eu.posthog.com`,
|
|
28
|
-
] :
|
|
29
|
-
// local dev origins
|
|
30
|
-
// TODO: fixme, make this dynamic!
|
|
31
|
-
[
|
|
32
|
-
`http://127.0.0.1:${CLIENT_PORT}`,
|
|
33
|
-
`http://localhost:${CLIENT_PORT}`,
|
|
34
|
-
// `http://192.168.1.83:${CLIENT_PORT}`,
|
|
35
|
-
// `http://192.168.1.140:${CLIENT_PORT}`,
|
|
36
|
-
`http://admin.localhost:${CLIENT_PORT}`,
|
|
37
|
-
// TODO: WARNING: TMP hardcoded port
|
|
38
|
-
"http://127.0.0.1:8090", // TMP: used by inspected app from admin
|
|
39
|
-
"http://127.0.0.1:8091", // TMP: used by inspected app from admin
|
|
40
|
-
"http://127.0.0.1:9292", // TMP
|
|
41
|
-
// disgusting, sort this out
|
|
42
|
-
"http://localhost:8090", // TMP: used by inspected app from admin
|
|
43
|
-
"http://localhost:8091", // TMP: used by inspected app from admin
|
|
44
|
-
"http://localhost:9292", // TMP
|
|
45
|
-
// posthog
|
|
46
|
-
`https://app.posthog.com`,
|
|
47
|
-
`https://eu.posthog.com`,
|
|
48
|
-
]
|
|
49
|
-
|
|
50
|
-
if (APP_DOMAIN) {
|
|
51
|
-
cors_origins.push(`http://${APP_DOMAIN}`)
|
|
52
|
-
cors_origins.push(`https://${APP_DOMAIN}`)
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
log("cors origins", JSON.stringify(cors_origins, null, 2))
|
|
56
|
-
|
|
57
|
-
const cors_middleware = cors({
|
|
58
|
-
origin: cors_origins,
|
|
59
|
-
methods: ["GET", "POST"],
|
|
60
|
-
credentials: true, // IMPORTANT: required to enable set-cookie
|
|
61
|
-
preflightContinue: false,
|
|
62
|
-
maxAge: 3600, // 1h, (TODO: set to 24h in prod when stable)
|
|
63
|
-
})
|
|
64
|
-
|
|
65
|
-
// TODO: can this be removed ??
|
|
66
|
-
app.use((req, res, next) => {
|
|
67
|
-
for (const skip_path of skip_paths) {
|
|
68
|
-
if (req.url.startsWith(skip_path)) {
|
|
69
|
-
log("skip path", req.url)
|
|
70
|
-
next()
|
|
71
|
-
return
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
cors_middleware(req, res, next)
|
|
76
|
-
})
|
|
77
|
-
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
module.exports = custom_cors
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
/* @flow */
|
|
2
|
-
const debug = require("debug")
|
|
3
|
-
|
|
4
|
-
const log = debug("rb:coverage")
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
const is_production = process.env.NODE_ENV === "production"
|
|
8
|
-
|
|
9
|
-
module.exports = (app) => {
|
|
10
|
-
app.post("/api/__dev_save_coverage", (req, res) => {
|
|
11
|
-
if (is_production) {
|
|
12
|
-
console.warn("refusing to save coverage in production")
|
|
13
|
-
return res.status(500).end()
|
|
14
|
-
}
|
|
15
|
-
// log("sending coverage for", req.body.path_key)
|
|
16
|
-
res.json(global.__coverage__)
|
|
17
|
-
})
|
|
18
|
-
}
|
package/express/index.js
DELETED
|
@@ -1,93 +0,0 @@
|
|
|
1
|
-
/* @flow */
|
|
2
|
-
const debug = require("debug")
|
|
3
|
-
const express = require("express")
|
|
4
|
-
const body_parser = require("body-parser")
|
|
5
|
-
const request_ip = require("request-ip")
|
|
6
|
-
const Sentry = require("@sentry/node")
|
|
7
|
-
|
|
8
|
-
// functional middlewares
|
|
9
|
-
const auth = require("../src/auth")
|
|
10
|
-
const api = require("../src/api")
|
|
11
|
-
const files = require("../src/files")
|
|
12
|
-
const sessions = require("../src/sessions")
|
|
13
|
-
|
|
14
|
-
const dev_save_coverage = require("./dev_save_coverage")
|
|
15
|
-
const custom_cors = require("./custom_cors")
|
|
16
|
-
const setup_handlers = require("./setup_handlers")
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
const log = debug("rb:server")
|
|
20
|
-
|
|
21
|
-
const {APP_DOMAIN, NODE_ENV, SENTRY_DSN, CLIENT_PORT} = process.env
|
|
22
|
-
|
|
23
|
-
const is_production = NODE_ENV === "production"
|
|
24
|
-
|
|
25
|
-
const has_sentry = !!SENTRY_DSN
|
|
26
|
-
|
|
27
|
-
// TODO: document this
|
|
28
|
-
// we could have a larger size, but it's good practice to keep it small to prevent body upload ddos attacks
|
|
29
|
-
const BODY_MAX_SIZE_MB = 16
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
log("server is production:", JSON.stringify(is_production))
|
|
33
|
-
|
|
34
|
-
module.exports = () => {
|
|
35
|
-
|
|
36
|
-
const app = express()
|
|
37
|
-
|
|
38
|
-
setup_handlers(app)
|
|
39
|
-
|
|
40
|
-
if (has_sentry && is_production) {
|
|
41
|
-
Sentry.init({
|
|
42
|
-
dsn: SENTRY_DSN,
|
|
43
|
-
integrations: [
|
|
44
|
-
// enable HTTP calls tracing
|
|
45
|
-
new Sentry.Integrations.Http({
|
|
46
|
-
tracing: true
|
|
47
|
-
}),
|
|
48
|
-
// enable Express.js middleware tracing
|
|
49
|
-
new Sentry.Integrations.Express({
|
|
50
|
-
app
|
|
51
|
-
}),
|
|
52
|
-
],
|
|
53
|
-
// Performance Monitoring
|
|
54
|
-
tracesSampleRate: 0.5, // Capture 100% of the transactions, reduce in production!,
|
|
55
|
-
})
|
|
56
|
-
|
|
57
|
-
// Trace incoming requests
|
|
58
|
-
app.use(Sentry.Handlers.requestHandler())
|
|
59
|
-
app.use(Sentry.Handlers.tracingHandler())
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
app.use(request_ip.mw())
|
|
63
|
-
|
|
64
|
-
app.use(body_parser.json({limit: `${BODY_MAX_SIZE_MB}mb`}))
|
|
65
|
-
|
|
66
|
-
app.set("trust proxy", 1)
|
|
67
|
-
|
|
68
|
-
app.disable("x-powered-by")
|
|
69
|
-
|
|
70
|
-
// tmp disable aggressive caching
|
|
71
|
-
app.set("etag", false)
|
|
72
|
-
|
|
73
|
-
app.use((req, res, next) => {
|
|
74
|
-
res.set("Cache-Control", "no-store")
|
|
75
|
-
next()
|
|
76
|
-
})
|
|
77
|
-
|
|
78
|
-
custom_cors(app)
|
|
79
|
-
|
|
80
|
-
const pong_res = {app: `app_name:${JSON.stringify(process.env.RB_APP_NAME)}`, message: "pong"}
|
|
81
|
-
app.get("/__ping", (req, res) => res.json(pong_res))
|
|
82
|
-
app.post("/__ping", (req, res) => res.json(pong_res))
|
|
83
|
-
|
|
84
|
-
sessions(app)
|
|
85
|
-
|
|
86
|
-
auth(app)
|
|
87
|
-
api(app)
|
|
88
|
-
files(app)
|
|
89
|
-
|
|
90
|
-
dev_save_coverage(app)
|
|
91
|
-
|
|
92
|
-
return app
|
|
93
|
-
}
|
|
@@ -1,49 +0,0 @@
|
|
|
1
|
-
/* @flow */
|
|
2
|
-
|
|
3
|
-
const setup_handlers = (app) => {
|
|
4
|
-
const original_get = app.get.bind(app)
|
|
5
|
-
const original_post = app.post.bind(app)
|
|
6
|
-
|
|
7
|
-
// function to sequentially execute handlers
|
|
8
|
-
function apply_handlers(handlers, req, res, next) {
|
|
9
|
-
const handler = handlers.shift()
|
|
10
|
-
if (handler) {
|
|
11
|
-
Promise.resolve(handler(req, res, function(err) {
|
|
12
|
-
if (err) {
|
|
13
|
-
return next(err)
|
|
14
|
-
}
|
|
15
|
-
apply_handlers(handlers, req, res, next)
|
|
16
|
-
})).catch(next)
|
|
17
|
-
} else {
|
|
18
|
-
next()
|
|
19
|
-
}
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
// app.get
|
|
23
|
-
app.get = function (path, ...handlers) {
|
|
24
|
-
original_get(path, (req, res, next) => apply_handlers([...handlers], req, res, next))
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
// app.post
|
|
28
|
-
app.post = function (path, ...handlers) {
|
|
29
|
-
original_post(path, (req, res, next) => apply_handlers([...handlers], req, res, next))
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
// app.handler
|
|
33
|
-
app.handler = (path, fn) => {
|
|
34
|
-
|
|
35
|
-
const resolved_fn = typeof fn === "function" ? fn : fn.default
|
|
36
|
-
|
|
37
|
-
app.post(path, async (req, res, next) => {
|
|
38
|
-
try {
|
|
39
|
-
const result = await resolved_fn(req.body, {req, res})
|
|
40
|
-
res.json(result)
|
|
41
|
-
} catch (err) {
|
|
42
|
-
next(err)
|
|
43
|
-
}
|
|
44
|
-
})
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
module.exports = setup_handlers
|
package/files.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export * from "./src/files/finalize_file_upload"
|