@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.
Files changed (96) hide show
  1. package/package.json +15 -72
  2. package/src/getDerivedKey.ts +20 -0
  3. package/src/hashPassword.ts +24 -0
  4. package/src/index.ts +3 -0
  5. package/src/initServer.ts +68 -0
  6. package/src/types/index.ts +7 -0
  7. package/src/types/session.d.ts +10 -0
  8. package/boot/server.js +0 -36
  9. package/boot/shared.js +0 -17
  10. package/boot/worker.js +0 -37
  11. package/constants/keys.ts +0 -1
  12. package/database.js +0 -96
  13. package/express/custom_cors.js +0 -80
  14. package/express/dev_save_coverage.js +0 -18
  15. package/express/index.js +0 -93
  16. package/express/setup_handlers.js +0 -49
  17. package/files.ts +0 -1
  18. package/firebase.js +0 -33
  19. package/get_object_id.ts +0 -39
  20. package/index.js +0 -17
  21. package/mailer/index.js +0 -31
  22. package/mongoose/index.ts +0 -16
  23. package/mongoose/plugins/disable_default_timestamps_plugin.ts +0 -5
  24. package/mongoose/plugins/disable_default_version_key_plugin.ts +0 -5
  25. package/mongoose/plugins/object_id_plugin.ts +0 -31
  26. package/openai.js +0 -10
  27. package/publish-output.txt +0 -0
  28. package/queue/dispatch_indexer_queue.js +0 -22
  29. package/queue/dispatch_worker_queue.js +0 -38
  30. package/queue/index.js +0 -110
  31. package/queue/register_queue_listener.js +0 -180
  32. package/redis.js +0 -2
  33. package/rts/index.js +0 -444
  34. package/search/constants.ts +0 -1
  35. package/search/ensure_index.ts +0 -53
  36. package/search/get_client.ts +0 -15
  37. package/search/index.ts +0 -3
  38. package/src/access-control/apply_policies.js +0 -104
  39. package/src/access-control/get_added_fields.js +0 -23
  40. package/src/access-control/get_policies.js +0 -29
  41. package/src/access-control/hooks/doc_pre_create.js +0 -26
  42. package/src/access-control/hooks/query_pre_delete.js +0 -30
  43. package/src/access-control/index.js +0 -6
  44. package/src/access-control/mongoose_plugin.js +0 -136
  45. package/src/api/index.js +0 -6
  46. package/src/api/stored-values/get_stored_values.js +0 -41
  47. package/src/api/stored-values/index.js +0 -8
  48. package/src/api/stored-values/set_stored_values.js +0 -31
  49. package/src/auth/check_session.js +0 -43
  50. package/src/auth/forgot_password_email.html +0 -515
  51. package/src/auth/get_account.js +0 -35
  52. package/src/auth/get_accounts.js +0 -42
  53. package/src/auth/index.js +0 -24
  54. package/src/auth/reset_password.js +0 -70
  55. package/src/auth/set_new_password.js +0 -63
  56. package/src/auth/set_new_password_email.html +0 -3
  57. package/src/auth/sign_in.js +0 -61
  58. package/src/auth/sign_out.js +0 -11
  59. package/src/auth/sign_up.js +0 -56
  60. package/src/client/client_router.js +0 -105
  61. package/src/files/constants.ts +0 -9
  62. package/src/files/finalize_file_upload.ts +0 -25
  63. package/src/files/helpers/get_grid_fs_bucket.ts +0 -20
  64. package/src/files/index.js +0 -5
  65. package/src/files/tasks/finalize_file_upload/apply_img_preview.ts +0 -49
  66. package/src/files/tasks/finalize_file_upload/constants.ts +0 -23
  67. package/src/files/tasks/finalize_file_upload/download_file.ts +0 -98
  68. package/src/files/tasks/finalize_file_upload/get_text_vectors.ts +0 -13
  69. package/src/files/tasks/finalize_file_upload/helpers/convert_pdf_to_png.ts +0 -34
  70. package/src/files/tasks/finalize_file_upload/helpers/exec.ts +0 -5
  71. package/src/files/tasks/finalize_file_upload/helpers/get_metadata.ts +0 -18
  72. package/src/files/tasks/finalize_file_upload/index.ts +0 -53
  73. package/src/files/tasks/finalize_file_upload/run_ocr.ts +0 -42
  74. package/src/files/tasks/index.ts +0 -6
  75. package/src/files/upload_chunk.ts +0 -83
  76. package/src/helpers/sim_test_inject.ts +0 -21
  77. package/src/models/Invite.js +0 -23
  78. package/src/models/Notification.js +0 -44
  79. package/src/models/Policy.ts +0 -13
  80. package/src/models/ResetPasswordToken.js +0 -14
  81. package/src/models/SearchHistory.ts +0 -22
  82. package/src/models/User.js +0 -42
  83. package/src/models/UserStoredValues.js +0 -18
  84. package/src/models/index.js +0 -7
  85. package/src/notitications/ack_notification.js +0 -26
  86. package/src/notitications/get_notifications.js +0 -39
  87. package/src/notitications/llt/README.md +0 -8
  88. package/src/notitications/llt/get_llts.js +0 -42
  89. package/src/notitications/set_seen.js +0 -26
  90. package/src/sessions/index.js +0 -27
  91. package/src/sessions/session_proxy_middleware.js +0 -18
  92. package/src/sessions/session_store_middleware.js +0 -106
  93. package/src/sessions/warning_proxy_middleware.js +0 -17
  94. package/src/tasks/index.js +0 -8
  95. package/src/tasks/index_item.js +0 -8
  96. package/store/index.js +0 -31
package/rts/index.js DELETED
@@ -1,444 +0,0 @@
1
- /* @flow */
2
- const Promise = require("bluebird")
3
- const _remove = require("lodash/remove")
4
- const _get = require("lodash/get")
5
- const _set = require("lodash/set")
6
- const {Server} = require("socket.io")
7
- const sift = require("sift")
8
- const debug = require("debug")
9
- const colors = require("picocolors")
10
-
11
- const mongoose = require("../mongoose")
12
-
13
-
14
- const log = debug("rb:rts:server")
15
-
16
- const is_production = process.env.NODE_ENV === "production"
17
-
18
- const QUERY_MAX_LIMIT = 4096
19
-
20
- // TODO: there are edge cases in dev where the client reconnects to the server
21
- // but the server already has the query results and sends it multiple times
22
- // the server should ensure it is only registering queries once
23
-
24
- // TODO: does this even support multiple clients ?
25
- // TODO: investigate multiple change streams event triggers per client
26
- // TODO: add tracing
27
- const _sockets = {}
28
- const _handlers = []
29
- const _change_streams = {}
30
- // we index both queries and socket queries
31
- // to avoid going through all queries when a socket disconnects
32
- const _queries = {}
33
- const _socket_queries = {}
34
-
35
-
36
- const get_query_options = (ctx, options) => {
37
- // https://mongoosejs.com/docs/api/query.html#Query.prototype.setOptions()
38
- const query_options = {
39
- ctx,
40
- is_client: true,
41
- //
42
- }
43
-
44
- if (options.sort) {
45
- query_options.sort = options.sort
46
- }
47
-
48
- const limit = typeof options.limit === "number" ? Math.min(QUERY_MAX_LIMIT, Math.abs(options.limit)) : QUERY_MAX_LIMIT
49
- query_options.limit = limit
50
-
51
- return query_options
52
- }
53
-
54
-
55
- // helper to send and update / refresh event to all subscribed queries
56
- const dispatch_doc_change = (model, doc) => {
57
- const model_name = model.modelName
58
- const queries = _queries[model_name] || {}
59
-
60
- // WARNING: INVESTIGATE: there are edge cases where you might want to delete an object
61
- // that was matched, but now it's not anymore because it's been udpated or removed
62
- // rts should still update the query and send a payload to the client
63
- // we could use the new mongodb fullDocumentBeforeChange param in watch,
64
- // but it doesn't seem to be guaranteed to be there
65
-
66
- // filter queries that match the document
67
- const target_queries = Object.keys(queries).filter((query_key) => {
68
- const {query} = queries[query_key]
69
- // console.log("query", query)
70
- const test_fn = sift(query)
71
- return test_fn(doc)
72
- })
73
-
74
- // we don't need to log every missing txn id, it is expected
75
- // if (!doc.__txn_id) {
76
- // console.log(colors.yellow("Warning!"), "change on model:", model.modelName, "matching queries", target_queries, "did not include a valid", colors.yellow("__txn"), "field")
77
- // }
78
-
79
- // TODO: we should not re-run each query here!!!!
80
- // dispatch change to target query clients
81
- target_queries.forEach(async(query_key) => {
82
- const {query, options, sockets} = queries[query_key]
83
-
84
- // TODO: remove this
85
- await Promise.map(sockets, async(socket_id) => {
86
- const s = _sockets[socket_id]
87
- // socket was destroyed
88
- // TODO: remove socket id from _queries when destroyed
89
- if (!s) {
90
- log("NO SOCKET, RETURNING")
91
- return
92
- }
93
- // console.log("dipatch change", query_key)
94
- const ctx = {req: s.request}
95
-
96
- if (!ctx.req.session.user_id) {
97
- console.error("dispatch_doc_change::error", "no user id for client query")
98
- return
99
- }
100
-
101
- const query_options = get_query_options(ctx, options)
102
- // TODO: do not redo query here, use document from change event
103
- const query_promise = model.find(query, options.projection, query_options)
104
- if (query_options.sort) {
105
- query_promise.sort(query_options.sort)
106
- }
107
-
108
- query_promise.limit(query_options.limit)
109
-
110
- // WARNING: DANGER
111
- // TODO: we should not be doing a read here, use doc from event
112
- const data = await query_promise
113
-
114
- const data_buf = JSON.stringify(data)
115
-
116
- log("emit payload")
117
-
118
- s.emit("query_payload", {
119
- model_name,
120
- query_key,
121
- data_buf,
122
- txn_id: doc.__txn_id,
123
- })
124
- }, {concurrency: 1024}) // TODO: tweak concurrency it should be infinite
125
-
126
- })
127
- }
128
-
129
-
130
- // mongoose middleware used to broadcast delete events to appropriate sockets
131
- const mongoose_delete_plugin = (schema) => {
132
- schema.pre("deleteOne", function(next) {
133
- throw new Error("rts::deleteOne is not supported, use findOneAndDelete")
134
- })
135
-
136
- // TODO: add other delete operations
137
- // https://mongoosejs.com/docs/queries.html
138
- schema.post("findOneAndDelete", function(doc) {
139
- dispatch_doc_change(this.model, doc)
140
- })
141
- }
142
-
143
-
144
- // Mongoose transaction plugin to save txn on each doc
145
- // WARNING: query middlewares are not supported yet
146
- // https://mongoosejs.com/docs/middleware.html#types-of-middleware
147
- const mongoose_txn_plugin = (schema, options) => {
148
- // console.log("register TXN plugin on schema", schema)
149
- // WARNING: possible middlewares here:
150
- // https://mongoosejs.com/docs/middleware.html
151
- // this function isn't async but could be?
152
- const apply_txn = /* async */function(next, save_options) {
153
- // TODO: keep an eye on this, this seems to happen for nested schemas that aren't models
154
- if (!save_options) {
155
- next()
156
- return
157
- }
158
-
159
- const {ctx} = save_options
160
- if (!ctx) {
161
- log(colors.yellow("Warning!"), "{ctx} not attached to save")
162
- }
163
-
164
- const txn_id = _get(ctx, ["req", "headers", "rts-txn-id"])
165
-
166
- if (!txn_id) {
167
- log(colors.yellow("Warning!"), "mongoose save request is missing txn_id this will cause issues with rts-client")
168
- } else {
169
- this.set("__txn_id", txn_id)
170
- }
171
-
172
- next()
173
- }
174
-
175
-
176
- schema.pre("save", apply_txn)
177
- }
178
-
179
-
180
- // responds to a change stream "change" event
181
- const get_dispatch_change_handler = (model_name) => async(change) => {
182
- // const queries = _queries[model_name]
183
-
184
- const model = mongoose.model(model_name)
185
-
186
- let doc
187
- if (["insert", "update"].includes(change.operationType)) {
188
- // console.log("rts onChange", change)
189
- doc = change.fullDocument
190
- } else if (change.operationType === "delete") {
191
- console.log("op is delete")
192
- } else if (!["delete", "drop", "invalidate"].includes(change.operationType)) {
193
- console.log("SKIPPING: unknown operation type", change.operationType, change)
194
- return
195
- }
196
-
197
- if (!doc) {
198
- return
199
- }
200
-
201
- dispatch_doc_change(model, doc)
202
- }
203
-
204
-
205
- const add_change_stream = (socket_id, {model_name, query, query_key, options}) => {
206
- if (!model_name) throw new Error("empty model name")
207
-
208
- if (!_change_streams[model_name]) {
209
- log("rts: initializing change stream for model:", model_name)
210
- let model
211
- try {
212
- model = mongoose.model(model_name)
213
- } catch (err) {
214
- console.error("add change stream:ERROR registering model:", model_name)
215
- console.error(err)
216
- return
217
- }
218
-
219
- // TODO: fix this, this has been released
220
- // TODO: implement delete operation fullDocument retrieve,
221
- // when this is released https://jira.mongodb.org/browse/SERVER-36941
222
- const emitter = model.watch({
223
- fullDocument: "updateLookup",
224
- fullDocumentBeforeChange: "whenAvailable",
225
- })
226
-
227
- emitter.on("change", get_dispatch_change_handler(model_name))
228
-
229
- emitter.on("error", (err) => {
230
- console.log("change listener emitter got error", err)
231
- })
232
-
233
- emitter.on("close", () => {
234
- delete _change_streams[model_name]
235
- })
236
-
237
- _change_streams[model_name] = emitter
238
- }
239
-
240
- // save query
241
- if (!_queries[model_name]) {
242
- _queries[model_name] = {}
243
- }
244
-
245
- if (!_queries[model_name][query_key]) {
246
- _queries[model_name][query_key] = {query, options, sockets: []}
247
- }
248
- if (!_queries[model_name][query_key].sockets.includes(socket_id)) {
249
- _queries[model_name][query_key].sockets.push(socket_id)
250
- }
251
-
252
- // save socket_query
253
- if (!_socket_queries[socket_id]) {
254
- _socket_queries[socket_id] = {}
255
- }
256
- if (!_socket_queries[socket_id][model_name]) {
257
- _socket_queries[socket_id][model_name] = {}
258
- }
259
- _socket_queries[socket_id][model_name][query_key] = true
260
- }
261
-
262
-
263
- const run_query = async(socket_id, {model_name, query, query_key, options}) => {
264
- // Check if the model is registered
265
- if (!mongoose.models[model_name]) {
266
- // throw new Error(`Model "${model_name}" is not registered.`)
267
- console.error(colors.red("ERROR: model not registered"), model_name, "will skip query")
268
- return
269
- }
270
-
271
- const model = mongoose.model(model_name)
272
-
273
- log("run_query", {model_name, query, query_key, options})
274
-
275
- if (!query) throw new Error("run_query empty query")
276
-
277
- const s = _sockets[socket_id]
278
- const ctx = {req: s.request}
279
-
280
- // log("initial run_query AUTH", ctx.req.session.user_id)
281
- if (!ctx.req.session.user_id) {
282
- console.warn("no user ID for client query")
283
- s.emit("query_payload", {model_name, query_key, error: "error no user id"})
284
- return
285
- }
286
-
287
- const query_options = get_query_options(ctx, options)
288
- // log("QUERY", query)
289
- const query_promise = model.find(query, options.projection, query_options)
290
-
291
- if (query_options.sort) {
292
- query_promise.sort(query_options.sort)
293
- }
294
-
295
- if (typeof query_options.limit === "number" && query_options.limit >= 0) {
296
- query_promise.limit(query_options.limit)
297
- }
298
-
299
- const data = await query_promise
300
-
301
- const data_buf = JSON.stringify(data)
302
-
303
- s.emit("query_payload", {model_name, query_key, data_buf})
304
- }
305
-
306
-
307
- const remove_query = (socket_id, {model_name, query, query_key}) => {
308
- const sockets = _queries[model_name]?.[query_key]?.sockets || []
309
-
310
- let new_sockets
311
- if (sockets.includes(socket_id)) {
312
- new_sockets = _remove(sockets, (s) => s === socket_id)
313
- } else new_sockets = sockets
314
-
315
- _set(_queries, `${model_name}.${query_key}.sockets`, new_sockets)
316
- }
317
-
318
- const disconnect_handler = (socket_id, reason) => {
319
- if (reason !== "transport close") {
320
- console.log("client disconnected, reason:", reason, "socket:", socket_id)
321
- }
322
-
323
- const local_queries = _socket_queries[socket_id] || {}
324
-
325
- // remove all queries matching that socket id
326
- Object.keys(local_queries)
327
- .forEach((model_name) => {
328
-
329
- Object.keys(local_queries[model_name]).forEach((query_key) => {
330
- const active_sockets = _queries[model_name]?.[query_key]?.sockets || []
331
-
332
- const socket_index = active_sockets.indexOf(socket_id)
333
-
334
- // remove the socket id from the array
335
- if (socket_index > -1) {
336
- // _queries[model_name][query_key].sockets.splice(socket_index, 1)
337
- active_sockets.splice(socket_index, 1)
338
- }
339
-
340
- // remove query if there are no more listeners
341
- if (active_sockets.length === 0) {
342
- delete _queries[model_name]?.[query_key]
343
- }
344
-
345
- // TODO: why the || {} here ?
346
- // remove change stream if there are no more queries on this collection
347
- if (Object.keys(_queries[model_name] || {}).length === 0) {
348
- delete _queries[model_name]
349
- _change_streams[model_name]?.close()
350
- }
351
-
352
- })
353
- })
354
-
355
- // remove socket
356
- delete _sockets[socket_id]
357
- delete _socket_queries[socket_id]
358
- }
359
-
360
-
361
- const init_rts = async(server) => {
362
- // register the delete plugin
363
- mongoose.plugin(mongoose_delete_plugin)
364
- // txn plugin
365
- mongoose.plugin(mongoose_txn_plugin)
366
-
367
- //
368
- const io = new Server(server, {
369
- transports: is_production ? ["websocket", "polling"] : ["websocket"],
370
- allowUpgrades: true,
371
- cors: {
372
- // TODO: dynamic client ports
373
- // TODO: check if is production
374
- origin: `http://localhost:${process.env.CLIENT_PORT}`,
375
- methods: ["GET", "POST"],
376
- credentials: true,
377
- },
378
- })
379
-
380
- //
381
- const has_session_store = process.env.RB_SESSION_STORE === "yes"
382
-
383
- if (has_session_store) {
384
- const session_store_middleware = require("../src/sessions/session_store_middleware")
385
- // socket io session middleware
386
- io.use((socket, next) => {
387
- session_store_middleware(socket.request, {}, next)
388
- })
389
- } else {
390
- const session_proxy_middleware = require("../src/sessions/session_proxy_middleware")
391
- // proxy middleware that checks the rb-tenant-id header
392
- io.use((socket, next) => {
393
- session_proxy_middleware(socket.request, {}, next)
394
- })
395
- }
396
-
397
- // io.on('connection', (socket) => {
398
- // const session = socket.request.session;
399
- // session.connections++;
400
- // session.save();
401
- // });
402
-
403
- io.on("connection", (socket) => {
404
- _sockets[socket.id] = socket
405
-
406
- log("socket connected", socket.id)
407
-
408
- // RTS handlers
409
- socket.on("registerQuery", (payload) => {
410
- add_change_stream(socket.id, payload)
411
- })
412
-
413
- socket.on("remove_query", (payload) => {
414
- remove_query(socket.id, payload)
415
- })
416
-
417
- socket.on("run_query", (payload) => {
418
- try {
419
- run_query(socket.id, payload)
420
- } catch (err) {
421
- console.log("run_query caught error", err)
422
- }
423
- })
424
- // !RTS handlers
425
-
426
- // register_rts_handler: custom server generic handlers
427
- const cleanup_fns = _handlers.map((handler_fn) => handler_fn(socket))
428
-
429
- socket.on("disconnect", (reason) => {
430
- disconnect_handler(socket.id, reason)
431
- cleanup_fns
432
- .filter((fn) => typeof fn === "function")
433
- .forEach((fn) => fn())
434
- })
435
- })
436
- }
437
-
438
-
439
- const register_rts_handler = (handler_fn) => {
440
- _handlers.push(handler_fn)
441
- }
442
-
443
-
444
- module.exports = {init_rts, register_rts_handler}
@@ -1 +0,0 @@
1
- export const DEFAULT_SEARCH_EMBEDDINGS_DIMENSIONS = 2048
@@ -1,53 +0,0 @@
1
- import debug from "debug"
2
- import {get_client} from "./get_client"
3
-
4
-
5
- const log = debug("rb:search:ensure_index")
6
-
7
- export const ensure_index = async({
8
- index_id,
9
- mappings,
10
- }: {
11
- index_id: string;
12
- mappings: any;
13
- }) => {
14
- const client = get_client()
15
-
16
- try {
17
- const exists = await client.indices.exists({index: index_id})
18
-
19
- if (exists) {
20
- await client.indices.putMapping({
21
- index: index_id,
22
- body: mappings,
23
- })
24
- log("updated index mappings", index_id)
25
- return
26
- }
27
- } catch (err) {
28
- console.log(
29
- "Error checking for index existance",
30
- JSON.stringify(err, null, 2),
31
- )
32
- }
33
-
34
- const res = await client.indices.create({
35
- index: index_id,
36
- body: {
37
- mappings,
38
- },
39
- })
40
-
41
- expect(res.acknowledged).toBe(true)
42
- expect(res.index).toBe(index_id)
43
-
44
- log("created index", index_id)
45
- }
46
-
47
- console.log("ensure_index.ts")
48
-
49
- // {
50
- // dynamic: true,
51
- // // date_detection: false,
52
- // properties: mappings_properties,
53
- // }
@@ -1,15 +0,0 @@
1
- import {Client} from "@elastic/elasticsearch"
2
-
3
- // const is_docker = require("@rpcbase/std/is_docker")
4
- const is_docker = () => true
5
-
6
-
7
- const {SEARCH_INDEX_PORT} = process.env
8
- // search indexer
9
- const search_hostname = is_docker() ? "elasticsearch" : "127.0.0.1"
10
- const indexer_cluster_url = `http://${search_hostname}:${SEARCH_INDEX_PORT}`
11
-
12
- export const get_client = () => {
13
- const es_client = new Client({node: indexer_cluster_url})
14
- return es_client
15
- }
package/search/index.ts DELETED
@@ -1,3 +0,0 @@
1
- export * from "./get_client"
2
- export * from "./ensure_index"
3
- export * from "./constants"
@@ -1,104 +0,0 @@
1
- /* @flow */
2
- const _get = require("lodash/get")
3
- const colors = require("picocolors")
4
-
5
- const get_policies = require("./get_policies")
6
-
7
-
8
- const user_types = ["owner", "user", "any"]
9
- const perm_operations = ["create", "read", "update", "delete"]
10
-
11
-
12
- // TODO: add LRU cache for policies
13
-
14
- // Owner
15
- // the creator of the document, or an user_id that is in the "owners" field
16
-
17
- // User
18
- // any authenticated user that belongs in this tenant
19
-
20
- // Any
21
- // most relaxed permission, any client can access the resource
22
-
23
-
24
- // given ac config, operation and document / query,
25
- // check if the user has the permission to run this op
26
- // if the user doesn't have permission, the system should throw an error
27
- const apply_policies = async({collection_name, model_name, operation, fields, user_id, doc}) => {
28
- // TODO: fix rm policy here
29
- // const rule_target = _get(ac_config, `${model_name}.${operation}`)
30
- const rule_target = ""
31
- // console.log("rule target", rule_target)
32
-
33
- const policies = await get_policies({collection_name, model_name, operation, fields, user_id, doc})
34
- console.log("MODEL APPLY POLICIES", {collection_name, model_name, operation, fields, user_id, doc})
35
- return
36
- // console.log("apply_policies", `'${model_name}:${operation}:${rule_target}'`)
37
-
38
- if (!rule_target) {
39
- throw new Error(`undefined rule_target for '${model_name}:${operation}'`)
40
- }
41
-
42
- if (!user_types.includes(rule_target)) {
43
- throw new Error(`expected rule_target '${model_name}:${operation}' to be in '${JSON.stringify(user_types)}', but got '${rule_target}'`)
44
- }
45
-
46
- // Create
47
- if (operation === "create") {
48
- if (["owner", "user"].includes(rule_target)) {
49
- if (!user_id) return new Error("create expected authenticated user_id")
50
- } else {
51
- return false
52
- }
53
- }
54
- // Read
55
- else if (operation === "read") {
56
- if (rule_target === "owner") {
57
- if (!user_id) throw new Error("read::owner invalid user_id")
58
-
59
- const conditions = doc.getQuery()
60
-
61
- // TMP: warn if user supplied _owners, which is currently overwritten for ACL
62
- if (conditions._owners) {
63
- if (JSON.stringify(conditions._owners) !== `{"$in":["${user_id}"]}`) {
64
- console.log(colors.yellow("Warning!"), model_name, "ACL for read is owner, but client is sending _owners in query, the field will be overwritten", "\nreceived conditions._owners:", JSON.stringify(conditions._owners))
65
- }
66
- }
67
-
68
- doc.setQuery({
69
- ...conditions,
70
- _owners: {$in: [user_id]}
71
- })
72
-
73
- }
74
- }
75
- // Update
76
- else if (operation === "update") {
77
- if (rule_target === "owner") {
78
- if (!doc._owners?.includes(user_id)) {
79
- console.log("MODEL:", model_name)
80
- const err = new Error("expected user_id to be in owners to update document")
81
- console.log("failed to update doc:", doc)
82
- return err
83
- }
84
- } else {
85
- throw new Error(`unknown rule target '${rule_target}' for operation ${model_name}::update`)
86
- }
87
- }
88
- // Delete
89
- else if (operation === "delete") {
90
- if (rule_target === "owner") {
91
- if (!doc._owners.includes(user_id)) {
92
- // TODO: add debug logging
93
- return new Error("expected user_id to be in owners to delete document")
94
- }
95
- } else {
96
- throw new Error(`unknown rule target '${rule_target}' for operation ${model_name}::delete`)
97
- }
98
- }
99
-
100
- return false
101
- }
102
-
103
-
104
- module.exports = apply_policies
@@ -1,23 +0,0 @@
1
- /* @flow */
2
-
3
- const get_added_fields = () => {
4
-
5
- return {
6
- _owners: {
7
- type: Array,
8
- of: String,
9
- index: true,
10
- required: true,
11
- },
12
- _viewers: [String],
13
- _editors: [String],
14
- _created_by: String,
15
- _created_at: {
16
- type: Date
17
- }
18
- }
19
-
20
- }
21
-
22
-
23
- module.exports = get_added_fields
@@ -1,29 +0,0 @@
1
- const Policy = require("../models/Policy")
2
-
3
- const DEFAULT_POLICY = {
4
- "create": "user",
5
- "read": "owner",
6
- "update": "owner",
7
- "delete": "owner",
8
- }
9
-
10
- const get_policies = async({collection_name, model_name, operation, user_id, doc}) => {
11
-
12
- const policies = await Policy.find({
13
- $or: [
14
- { collection_name, operations: { $in: [operation] }},
15
- { doc_id: doc._id, operations: { $in: [operation] }},
16
- // TODO: add field level operations
17
- ]
18
- })
19
-
20
- if (!policies) {
21
- return [DEFAULT_POLICY]
22
- }
23
-
24
- console.log("POLICIES", policies)
25
-
26
- return policies
27
- }
28
-
29
- module.exports = get_policies
@@ -1,26 +0,0 @@
1
- /* @flow */
2
- //
3
- // const has_permission = require("../has_permission")
4
- //
5
- // const delay = (time) => new Promise((resolve) => setTimeout(resolve, time))
6
- // // await delay(2000)
7
- //
8
- // module.exports = (schema) => async function(next) {
9
- // const model_name = this.model.modelName
10
- // const operation = "delete"
11
- //
12
- // if (this.op !== "findOneAndDelete") {
13
- // throw new Error(`in pre_delete unknown operation: ${this.op}`)
14
- // }
15
- //
16
- // const filter = this.getFilter()
17
- // const doc = await this.model.findOne(filter)
18
- //
19
- // console.log("DELETE GOT DOC", doc)
20
- // // console.log("THIS", this)
21
- // // console.log("THIS filter", this.getFilter())
22
- // // console.log("SCHEMA DEL", schema)
23
- // // TODO: find a way to check if user can delete this document without reading it
24
- // // console.log("delete got ac config", ac_config)
25
- // next()
26
- // }