@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
@@ -1,515 +0,0 @@
1
- <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
2
- <html xmlns="http://www.w3.org/1999/xhtml">
3
- <head>
4
- <meta name="viewport" content="width=device-width, initial-scale=1.0" />
5
- <meta name="x-apple-disable-message-reformatting" />
6
- <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
7
- <meta name="color-scheme" content="light dark" />
8
- <meta name="supported-color-schemes" content="light dark" />
9
- <title></title>
10
- <style type="text/css" rel="stylesheet" media="all">
11
- /* Base ------------------------------ */
12
-
13
- @import url("https://fonts.googleapis.com/css?family=Nunito+Sans:400,700&display=swap");
14
- body {
15
- width: 100% !important;
16
- height: 100%;
17
- margin: 0;
18
- -webkit-text-size-adjust: none;
19
- }
20
-
21
- a {
22
- color: #3869D4;
23
- }
24
-
25
- a img {
26
- border: none;
27
- }
28
-
29
- td {
30
- word-break: break-word;
31
- }
32
-
33
- .preheader {
34
- display: none !important;
35
- visibility: hidden;
36
- mso-hide: all;
37
- font-size: 1px;
38
- line-height: 1px;
39
- max-height: 0;
40
- max-width: 0;
41
- opacity: 0;
42
- overflow: hidden;
43
- }
44
- /* Type ------------------------------ */
45
-
46
- body,
47
- td,
48
- th {
49
- font-family: "Nunito Sans", Helvetica, Arial, sans-serif;
50
- }
51
-
52
- h1 {
53
- margin-top: 0;
54
- color: #333333;
55
- font-size: 22px;
56
- font-weight: bold;
57
- text-align: left;
58
- }
59
-
60
- h2 {
61
- margin-top: 0;
62
- color: #333333;
63
- font-size: 16px;
64
- font-weight: bold;
65
- text-align: left;
66
- }
67
-
68
- h3 {
69
- margin-top: 0;
70
- color: #333333;
71
- font-size: 14px;
72
- font-weight: bold;
73
- text-align: left;
74
- }
75
-
76
- td,
77
- th {
78
- font-size: 16px;
79
- }
80
-
81
- p,
82
- ul,
83
- ol,
84
- blockquote {
85
- margin: .4em 0 1.1875em;
86
- font-size: 16px;
87
- line-height: 1.625;
88
- }
89
-
90
- p.sub {
91
- font-size: 13px;
92
- }
93
- /* Utilities ------------------------------ */
94
-
95
- .align-right {
96
- text-align: right;
97
- }
98
-
99
- .align-left {
100
- text-align: left;
101
- }
102
-
103
- .align-center {
104
- text-align: center;
105
- }
106
- /* Buttons ------------------------------ */
107
-
108
- .button {
109
- background-color: #3869D4;
110
- border-top: 10px solid #3869D4;
111
- border-right: 18px solid #3869D4;
112
- border-bottom: 10px solid #3869D4;
113
- border-left: 18px solid #3869D4;
114
- display: inline-block;
115
- color: #FFF;
116
- text-decoration: none;
117
- border-radius: 3px;
118
- box-shadow: 0 2px 3px rgba(0, 0, 0, 0.16);
119
- -webkit-text-size-adjust: none;
120
- box-sizing: border-box;
121
- }
122
-
123
- .button--green {
124
- background-color: #22BC66;
125
- border-top: 10px solid #22BC66;
126
- border-right: 18px solid #22BC66;
127
- border-bottom: 10px solid #22BC66;
128
- border-left: 18px solid #22BC66;
129
- }
130
-
131
- .button--red {
132
- background-color: #FF6136;
133
- border-top: 10px solid #FF6136;
134
- border-right: 18px solid #FF6136;
135
- border-bottom: 10px solid #FF6136;
136
- border-left: 18px solid #FF6136;
137
- }
138
-
139
- @media only screen and (max-width: 500px) {
140
- .button {
141
- width: 100% !important;
142
- text-align: center !important;
143
- }
144
- }
145
- /* Attribute list ------------------------------ */
146
-
147
- .attributes {
148
- margin: 0 0 21px;
149
- }
150
-
151
- .attributes_content {
152
- background-color: #F4F4F7;
153
- padding: 16px;
154
- }
155
-
156
- .attributes_item {
157
- padding: 0;
158
- }
159
- /* Related Items ------------------------------ */
160
-
161
- .related {
162
- width: 100%;
163
- margin: 0;
164
- padding: 25px 0 0 0;
165
- -premailer-width: 100%;
166
- -premailer-cellpadding: 0;
167
- -premailer-cellspacing: 0;
168
- }
169
-
170
- .related_item {
171
- padding: 10px 0;
172
- color: #CBCCCF;
173
- font-size: 15px;
174
- line-height: 18px;
175
- }
176
-
177
- .related_item-title {
178
- display: block;
179
- margin: .5em 0 0;
180
- }
181
-
182
- .related_item-thumb {
183
- display: block;
184
- padding-bottom: 10px;
185
- }
186
-
187
- .related_heading {
188
- border-top: 1px solid #CBCCCF;
189
- text-align: center;
190
- padding: 25px 0 10px;
191
- }
192
- /* Discount Code ------------------------------ */
193
-
194
- .discount {
195
- width: 100%;
196
- margin: 0;
197
- padding: 24px;
198
- -premailer-width: 100%;
199
- -premailer-cellpadding: 0;
200
- -premailer-cellspacing: 0;
201
- background-color: #F4F4F7;
202
- border: 2px dashed #CBCCCF;
203
- }
204
-
205
- .discount_heading {
206
- text-align: center;
207
- }
208
-
209
- .discount_body {
210
- text-align: center;
211
- font-size: 15px;
212
- }
213
- /* Social Icons ------------------------------ */
214
-
215
- .social {
216
- width: auto;
217
- }
218
-
219
- .social td {
220
- padding: 0;
221
- width: auto;
222
- }
223
-
224
- .social_icon {
225
- height: 20px;
226
- margin: 0 8px 10px 8px;
227
- padding: 0;
228
- }
229
- /* Data table ------------------------------ */
230
-
231
- .purchase {
232
- width: 100%;
233
- margin: 0;
234
- padding: 35px 0;
235
- -premailer-width: 100%;
236
- -premailer-cellpadding: 0;
237
- -premailer-cellspacing: 0;
238
- }
239
-
240
- .purchase_content {
241
- width: 100%;
242
- margin: 0;
243
- padding: 25px 0 0 0;
244
- -premailer-width: 100%;
245
- -premailer-cellpadding: 0;
246
- -premailer-cellspacing: 0;
247
- }
248
-
249
- .purchase_item {
250
- padding: 10px 0;
251
- color: #51545E;
252
- font-size: 15px;
253
- line-height: 18px;
254
- }
255
-
256
- .purchase_heading {
257
- padding-bottom: 8px;
258
- border-bottom: 1px solid #EAEAEC;
259
- }
260
-
261
- .purchase_heading p {
262
- margin: 0;
263
- color: #85878E;
264
- font-size: 12px;
265
- }
266
-
267
- .purchase_footer {
268
- padding-top: 15px;
269
- border-top: 1px solid #EAEAEC;
270
- }
271
-
272
- .purchase_total {
273
- margin: 0;
274
- text-align: right;
275
- font-weight: bold;
276
- color: #333333;
277
- }
278
-
279
- .purchase_total--label {
280
- padding: 0 15px 0 0;
281
- }
282
-
283
- body {
284
- background-color: #F4F4F7;
285
- color: #51545E;
286
- }
287
-
288
- p {
289
- color: #51545E;
290
- }
291
-
292
- p.sub {
293
- color: #6B6E76;
294
- }
295
-
296
- .email-wrapper {
297
- width: 100%;
298
- margin: 0;
299
- padding: 0;
300
- -premailer-width: 100%;
301
- -premailer-cellpadding: 0;
302
- -premailer-cellspacing: 0;
303
- background-color: #F4F4F7;
304
- }
305
-
306
- .email-content {
307
- width: 100%;
308
- margin: 0;
309
- padding: 0;
310
- -premailer-width: 100%;
311
- -premailer-cellpadding: 0;
312
- -premailer-cellspacing: 0;
313
- }
314
- /* Masthead ----------------------- */
315
-
316
- .email-masthead {
317
- padding: 25px 0;
318
- text-align: center;
319
- }
320
-
321
- .email-masthead_logo {
322
- width: 94px;
323
- }
324
-
325
- .email-masthead_name {
326
- font-size: 16px;
327
- font-weight: bold;
328
- color: #A8AAAF;
329
- text-decoration: none;
330
- text-shadow: 0 1px 0 white;
331
- }
332
- /* Body ------------------------------ */
333
-
334
- .email-body {
335
- width: 100%;
336
- margin: 0;
337
- padding: 0;
338
- -premailer-width: 100%;
339
- -premailer-cellpadding: 0;
340
- -premailer-cellspacing: 0;
341
- background-color: #FFFFFF;
342
- }
343
-
344
- .email-body_inner {
345
- width: 570px;
346
- margin: 0 auto;
347
- padding: 0;
348
- -premailer-width: 570px;
349
- -premailer-cellpadding: 0;
350
- -premailer-cellspacing: 0;
351
- background-color: #FFFFFF;
352
- }
353
-
354
- .email-footer {
355
- width: 570px;
356
- margin: 0 auto;
357
- padding: 0;
358
- -premailer-width: 570px;
359
- -premailer-cellpadding: 0;
360
- -premailer-cellspacing: 0;
361
- text-align: center;
362
- }
363
-
364
- .email-footer p {
365
- color: #6B6E76;
366
- }
367
-
368
- .body-action {
369
- width: 100%;
370
- margin: 30px auto;
371
- padding: 0;
372
- -premailer-width: 100%;
373
- -premailer-cellpadding: 0;
374
- -premailer-cellspacing: 0;
375
- text-align: center;
376
- }
377
-
378
- .body-sub {
379
- margin-top: 25px;
380
- padding-top: 25px;
381
- border-top: 1px solid #EAEAEC;
382
- }
383
-
384
- .content-cell {
385
- padding: 35px;
386
- }
387
- /*Media Queries ------------------------------ */
388
-
389
- @media only screen and (max-width: 600px) {
390
- .email-body_inner,
391
- .email-footer {
392
- width: 100% !important;
393
- }
394
- }
395
-
396
- @media (prefers-color-scheme: dark) {
397
- body,
398
- .email-body,
399
- .email-body_inner,
400
- .email-content,
401
- .email-wrapper,
402
- .email-masthead,
403
- .email-footer {
404
- background-color: #333333 !important;
405
- color: #FFF !important;
406
- }
407
- p,
408
- ul,
409
- ol,
410
- blockquote,
411
- h1,
412
- h2,
413
- h3,
414
- span,
415
- .purchase_item {
416
- color: #FFF !important;
417
- }
418
- .attributes_content,
419
- .discount {
420
- background-color: #222 !important;
421
- }
422
- .email-masthead_name {
423
- text-shadow: none !important;
424
- }
425
- }
426
-
427
- :root {
428
- color-scheme: light dark;
429
- supported-color-schemes: light dark;
430
- }
431
- </style>
432
- <!--[if mso]>
433
- <style type="text/css">
434
- .f-fallback {
435
- font-family: Arial, sans-serif;
436
- }
437
- </style>
438
- <![endif]-->
439
- </head>
440
- <body>
441
- <span class="preheader">Your password reset link is ready</span>
442
- <table class="email-wrapper" width="100%" cellpadding="0" cellspacing="0" role="presentation">
443
- <tr>
444
- <td align="center">
445
- <table class="email-content" width="100%" cellpadding="0" cellspacing="0" role="presentation">
446
- <tr>
447
- <td class="email-masthead">
448
- <a href="https://example.com" class="f-fallback email-masthead_name">
449
- [Product Name]
450
- </a>
451
- </td>
452
- </tr>
453
- <!-- Email Body -->
454
- <tr>
455
- <td class="email-body" width="100%" cellpadding="0" cellspacing="0">
456
- <table class="email-body_inner" align="center" width="570" cellpadding="0" cellspacing="0" role="presentation">
457
- <!-- Body content -->
458
- <tr>
459
- <td class="content-cell">
460
- <div class="f-fallback">
461
- <h1>Your password reset link</h1>
462
- <p>The password reset link you have requested is ready. If you did not request a password reset, ignore this email.</p>
463
- <!-- Action -->
464
- <table class="body-action" align="center" width="100%" cellpadding="0" cellspacing="0" role="presentation">
465
- <tr>
466
- <td align="center">
467
- <!-- Border based button
468
- https://litmus.com/blog/a-guide-to-bulletproof-buttons-in-email-design -->
469
- <table width="100%" border="0" cellspacing="0" cellpadding="0" role="presentation">
470
- <tr>
471
- <td align="center">
472
- <a href="<%= reset_url %>" class="f-fallback button" target="_blank">Reset My Password</a>
473
- </td>
474
- </tr>
475
- </table>
476
- </td>
477
- </tr>
478
- </table>
479
-
480
- <table class="body-sub" role="presentation">
481
- <tr>
482
- <td>
483
- <p class="f-fallback sub">If you’re having trouble with the button above, copy and paste the URL below into your web browser.</p>
484
- <p class="f-fallback sub"><%= reset_url %></p>
485
- </td>
486
- </tr>
487
- </table>
488
- </div>
489
- </td>
490
- </tr>
491
- </table>
492
- </td>
493
- </tr>
494
- <tr>
495
- <td>
496
- <table class="email-footer" align="center" width="570" cellpadding="0" cellspacing="0" role="presentation">
497
- <tr>
498
- <td class="content-cell" align="center">
499
- <p class="f-fallback sub align-center">&copy; 2022 [Product Name]. All rights reserved.</p>
500
- <p class="f-fallback sub align-center">
501
- [Company Name, LLC]
502
- <br>1234 Street Rd.
503
- <br>Suite 1234
504
- </p>
505
- </td>
506
- </tr>
507
- </table>
508
- </td>
509
- </tr>
510
- </table>
511
- </td>
512
- </tr>
513
- </table>
514
- </body>
515
- </html>
@@ -1,35 +0,0 @@
1
- /* @flow */
2
- const assert = require("assert")
3
-
4
- const mongoose = require("../../mongoose")
5
- const User = require("../models/User")
6
-
7
-
8
- const get_account = async(payload, ctx) => {
9
- const {user_id} = payload
10
- assert(user_id, "missing user_id")
11
-
12
- // verify we are only requesting our own account's info
13
- const session_user_id = ctx.req.session.user_id
14
- assert(user_id === session_user_id, "user ids don't match")
15
-
16
- const user = await User.findOne(
17
- {_id: user_id},
18
- {
19
- email: 1,
20
- first_name: 1,
21
- last_name: 1,
22
- initials: 1,
23
- avatar_color: 1,
24
- },
25
- {ctx},
26
- )
27
-
28
- return {
29
- status: "ok",
30
- // when user has been deleted return null, this case shouldn't really happen though
31
- user: user?.toObject() || null,
32
- }
33
- }
34
-
35
- module.exports = get_account
@@ -1,42 +0,0 @@
1
- /* @flow */
2
- const Promise = require("bluebird")
3
-
4
- const get_account = require("./get_account")
5
-
6
-
7
- const is_dev = process.env.NODE_ENV === "development"
8
-
9
- // TODO: RM this method when live reload works in dev mode behind the reverse proxy
10
- const MAX_CONCURRENCY = 256
11
-
12
- const get_accounts = async(payload, ctx) => {
13
- if (!is_dev)
14
- throw new Error(
15
- "cannot call the get_accounts api when NODE_ENV isn't development, this api must be called through the reverse proxy",
16
- )
17
-
18
- const user_ids = [ctx.req.session.user_id, ctx.req.session.user_id, ctx.req.session.user_id]
19
-
20
- const accounts = await Promise.map(
21
- user_ids,
22
- async(user_id) => {
23
- if (!user_id) return null
24
- const res = await get_account({user_id}, ctx)
25
-
26
- return {
27
- user: res.user,
28
- tenant: {
29
- name: "MOCK",
30
- },
31
- }
32
- },
33
- {concurrency: MAX_CONCURRENCY},
34
- )
35
-
36
- return {
37
- status: "ok",
38
- accounts: accounts.filter((account) => !!account),
39
- }
40
- }
41
-
42
- module.exports = get_accounts
package/src/auth/index.js DELETED
@@ -1,24 +0,0 @@
1
- /* @flow */
2
- const sign_up = require("./sign_up")
3
- const sign_in = require("./sign_in")
4
- const sign_out = require("./sign_out")
5
- const reset_password = require("./reset_password")
6
- const set_new_password = require("./set_new_password")
7
- const check_session = require("./check_session")
8
-
9
- const get_accounts = require("./get_accounts")
10
- const get_account = require("./get_account")
11
-
12
-
13
- module.exports = (app) => {
14
- app.handler("/rb-api/v1/auth/sign_in", sign_in)
15
- app.handler("/rb-api/v1/auth/sign_out", sign_out)
16
-
17
- app.handler("/rb-api/v1/auth/reset_password", reset_password)
18
- app.handler("/rb-api/v1/auth/set_new_password", set_new_password)
19
-
20
- app.handler("/rb-api/v1/auth/check_session", check_session)
21
-
22
- app.handler("/rb-api/v1/auth/get_account", get_account)
23
- app.handler("/rb-api/v1/auth/get_accounts", get_accounts)
24
- }
@@ -1,70 +0,0 @@
1
- /* @flow */
2
- const _template = require("lodash/template")
3
- const fs = require("fs")
4
- const path = require("path")
5
- const debug = require("debug")
6
- const isEmail = require("validator/lib/isEmail")
7
-
8
- const {hash_password} = require("@rpcbase/std/crypto/hash")
9
- const {get_random_str} = require("@rpcbase/std/crypto/get_random_str")
10
-
11
- const mailer = require("../../mailer")
12
- const mongoose = require("../../mongoose")
13
-
14
- const ResetPasswordToken = require("../models/ResetPasswordToken")
15
- const User = require("../models/User")
16
-
17
- const log = debug("rb:auth:reset_password")
18
-
19
- const {APP_DOMAIN, MAILER_FROM_EMAIL} = process.env
20
-
21
- const email_tpl = _template(require("./forgot_password_email.html"))
22
-
23
-
24
- const reset_password = async({email}, ctx) => {
25
- if (!isEmail(email)) {
26
- throw new Error("reset_password:: invalid email")
27
- }
28
-
29
- const user = await User.findOne({email}, null, {ctx})
30
-
31
- if (!user) {
32
- log("attempting to reset password for a user that was not found", email)
33
- // TODO: add random delay to prevent detecting if account exists based on response time
34
- return {status: "ok"}
35
- }
36
-
37
- const token = get_random_str(32)
38
- const token_hash = await hash_password(token)
39
-
40
- const reset_token = new ResetPasswordToken({
41
- user_id: user._id,
42
- token_hash,
43
- })
44
-
45
- await reset_token.save()
46
-
47
- const reset_url = `https://${APP_DOMAIN}/set-new-password?uid=${user._id}&token=${token}`
48
-
49
- log("will send reset password email to", user.email)
50
-
51
- const res = await mailer.sendEmail({
52
- From: MAILER_FROM_EMAIL,
53
- To: user.email,
54
- Subject: "Your password reset link",
55
- HtmlBody: email_tpl({
56
- reset_url,
57
- }),
58
- })
59
-
60
- log("res", res)
61
-
62
- // cleanup if email wasn't sent
63
- if (res.Message !== "OK") {
64
- await reset_token.delete()
65
- }
66
-
67
- return {status: "ok"}
68
- }
69
-
70
- module.exports = reset_password