diff options
-rw-r--r-- | .env.example | 8 | ||||
-rw-r--r-- | app/Controllers/Http/DashboardController.js | 61 | ||||
-rw-r--r-- | app/Models/Token.js | 3 | ||||
-rw-r--r-- | config/mail.js | 101 | ||||
-rw-r--r-- | config/persona.js | 98 | ||||
-rw-r--r-- | package-lock.json | 307 | ||||
-rw-r--r-- | package.json | 2 | ||||
-rw-r--r-- | resources/views/dashboard/forgotPassword.edge | 49 | ||||
-rw-r--r-- | resources/views/dashboard/login.edge | 5 | ||||
-rw-r--r-- | resources/views/dashboard/resetPassword.edge | 64 | ||||
-rw-r--r-- | start/app.js | 2 | ||||
-rw-r--r-- | start/events.js | 23 | ||||
-rw-r--r-- | start/routes.js | 23 |
13 files changed, 744 insertions, 2 deletions
diff --git a/.env.example b/.env.example index bcc4c7c..3346916 100644 --- a/.env.example +++ b/.env.example | |||
@@ -21,4 +21,10 @@ HASH_DRIVER=bcrypt | |||
21 | IS_CREATION_ENABLED=true | 21 | IS_CREATION_ENABLED=true |
22 | IS_DASHBOARD_ENABLED=true | 22 | IS_DASHBOARD_ENABLED=true |
23 | IS_REGISTRATION_ENABLED=true | 23 | IS_REGISTRATION_ENABLED=true |
24 | CONNECT_WITH_FRANZ=true \ No newline at end of file | 24 | CONNECT_WITH_FRANZ=true |
25 | |||
26 | MAIL_CONNECTION=smtp | ||
27 | SMTP_PORT=2525 | ||
28 | SMTP_HOST=127.0.0.1 | ||
29 | MAIL_USERNAME=username | ||
30 | MAIL_PASSWORD=password \ No newline at end of file | ||
diff --git a/app/Controllers/Http/DashboardController.js b/app/Controllers/Http/DashboardController.js index a47beb6..3de4816 100644 --- a/app/Controllers/Http/DashboardController.js +++ b/app/Controllers/Http/DashboardController.js | |||
@@ -5,6 +5,7 @@ const { | |||
5 | 5 | ||
6 | const Service = use('App/Models/Service'); | 6 | const Service = use('App/Models/Service'); |
7 | const Workspace = use('App/Models/Workspace'); | 7 | const Workspace = use('App/Models/Workspace'); |
8 | const Persona = use('Persona'); | ||
8 | 9 | ||
9 | const crypto = require('crypto'); | 10 | const crypto = require('crypto'); |
10 | const uuid = require('uuid/v4'); | 11 | const uuid = require('uuid/v4'); |
@@ -47,6 +48,66 @@ class DashboardController { | |||
47 | return response.redirect('/user/account'); | 48 | return response.redirect('/user/account'); |
48 | } | 49 | } |
49 | 50 | ||
51 | async forgotPassword({ | ||
52 | request, | ||
53 | view, | ||
54 | }) { | ||
55 | const validation = await validateAll(request.all(), { | ||
56 | mail: 'required|email', | ||
57 | }); | ||
58 | if (validation.fails()) { | ||
59 | return view.render('others.message', { | ||
60 | heading: 'Cannot reset your password', | ||
61 | text: 'If your provided E-Mail address is linked to an account, we have just sent an E-Mail to that address.', | ||
62 | }); | ||
63 | } | ||
64 | try { | ||
65 | await Persona.forgotPassword(request.input('mail')); | ||
66 | } catch(e) {} | ||
67 | |||
68 | return view.render('others.message', { | ||
69 | heading: 'Reset password', | ||
70 | text: 'If your provided E-Mail address is linked to an account, we have just sent an E-Mail to that address.', | ||
71 | }); | ||
72 | } | ||
73 | |||
74 | async resetPassword({ | ||
75 | request, | ||
76 | view, | ||
77 | }) { | ||
78 | const validation = await validateAll(request.all(), { | ||
79 | password: 'required', | ||
80 | password_confirmation: 'required', | ||
81 | token: 'required', | ||
82 | }); | ||
83 | if (validation.fails()) { | ||
84 | session.withErrors({ | ||
85 | type: 'danger', | ||
86 | message: 'Passwords do not match', | ||
87 | }); | ||
88 | return response.redirect('back'); | ||
89 | } | ||
90 | |||
91 | const payload = { | ||
92 | password: crypto.createHash('sha256').update(request.input('password')).digest('base64'), | ||
93 | password_confirmation: crypto.createHash('sha256').update(request.input('password_confirmation')).digest('base64'), | ||
94 | } | ||
95 | |||
96 | try { | ||
97 | await Persona.updatePasswordByToken(request.input('token'), payload); | ||
98 | } catch(e) { | ||
99 | return view.render('others.message', { | ||
100 | heading: 'Cannot reset your password', | ||
101 | text: 'Please make sure you are using a valid and recent link to reset your password and that your passwords entered match.', | ||
102 | }); | ||
103 | } | ||
104 | |||
105 | return view.render('others.message', { | ||
106 | heading: 'Reset password', | ||
107 | text: 'Successfully reset your password. You can now login to your account using your new password.', | ||
108 | }); | ||
109 | } | ||
110 | |||
50 | async account({ | 111 | async account({ |
51 | auth, | 112 | auth, |
52 | view, | 113 | view, |
diff --git a/app/Models/Token.js b/app/Models/Token.js index f6bec08..50bcf1d 100644 --- a/app/Models/Token.js +++ b/app/Models/Token.js | |||
@@ -3,6 +3,9 @@ | |||
3 | const Model = use('Model'); | 3 | const Model = use('Model'); |
4 | 4 | ||
5 | class Token extends Model { | 5 | class Token extends Model { |
6 | user() { | ||
7 | return this.belongsTo('App/Models/User') | ||
8 | } | ||
6 | } | 9 | } |
7 | 10 | ||
8 | module.exports = Token; | 11 | module.exports = Token; |
diff --git a/config/mail.js b/config/mail.js new file mode 100644 index 0000000..6b18db2 --- /dev/null +++ b/config/mail.js | |||
@@ -0,0 +1,101 @@ | |||
1 | 'use strict' | ||
2 | |||
3 | const Env = use('Env') | ||
4 | |||
5 | module.exports = { | ||
6 | /* | ||
7 | |-------------------------------------------------------------------------- | ||
8 | | Connection | ||
9 | |-------------------------------------------------------------------------- | ||
10 | | | ||
11 | | Connection to be used for sending emails. Each connection needs to | ||
12 | | define a driver too. | ||
13 | | | ||
14 | */ | ||
15 | connection: Env.get('MAIL_CONNECTION', 'smtp'), | ||
16 | |||
17 | /* | ||
18 | |-------------------------------------------------------------------------- | ||
19 | | SMTP | ||
20 | |-------------------------------------------------------------------------- | ||
21 | | | ||
22 | | Here we define configuration for sending emails via SMTP. | ||
23 | | | ||
24 | */ | ||
25 | smtp: { | ||
26 | driver: 'smtp', | ||
27 | pool: true, | ||
28 | port: Env.get('SMTP_PORT', 2525), | ||
29 | host: Env.get('SMTP_HOST'), | ||
30 | secure: false, | ||
31 | auth: { | ||
32 | user: Env.get('MAIL_USERNAME'), | ||
33 | pass: Env.get('MAIL_PASSWORD') | ||
34 | }, | ||
35 | maxConnections: 5, | ||
36 | maxMessages: 100, | ||
37 | rateLimit: 10 | ||
38 | }, | ||
39 | |||
40 | /* | ||
41 | |-------------------------------------------------------------------------- | ||
42 | | SparkPost | ||
43 | |-------------------------------------------------------------------------- | ||
44 | | | ||
45 | | Here we define configuration for spark post. Extra options can be defined | ||
46 | | inside the `extra` object. | ||
47 | | | ||
48 | | https://developer.sparkpost.com/api/transmissions.html#header-options-attributes | ||
49 | | | ||
50 | | extras: { | ||
51 | | campaign_id: 'sparkpost campaign id', | ||
52 | | options: { // sparkpost options } | ||
53 | | } | ||
54 | | | ||
55 | */ | ||
56 | sparkpost: { | ||
57 | driver: 'sparkpost', | ||
58 | apiKey: Env.get('SPARKPOST_API_KEY'), | ||
59 | extras: {} | ||
60 | }, | ||
61 | |||
62 | /* | ||
63 | |-------------------------------------------------------------------------- | ||
64 | | Mailgun | ||
65 | |-------------------------------------------------------------------------- | ||
66 | | | ||
67 | | Here we define configuration for mailgun. Extra options can be defined | ||
68 | | inside the `extra` object. | ||
69 | | | ||
70 | | https://mailgun-documentation.readthedocs.io/en/latest/api-sending.html#sending | ||
71 | | | ||
72 | | extras: { | ||
73 | | 'o:tag': '', | ||
74 | | 'o:campaign': '',, | ||
75 | | . . . | ||
76 | | } | ||
77 | | | ||
78 | */ | ||
79 | mailgun: { | ||
80 | driver: 'mailgun', | ||
81 | domain: Env.get('MAILGUN_DOMAIN'), | ||
82 | region: Env.get('MAILGUN_API_REGION'), | ||
83 | apiKey: Env.get('MAILGUN_API_KEY'), | ||
84 | extras: {} | ||
85 | }, | ||
86 | |||
87 | /* | ||
88 | |-------------------------------------------------------------------------- | ||
89 | | Ethereal | ||
90 | |-------------------------------------------------------------------------- | ||
91 | | | ||
92 | | Ethereal driver to quickly test emails in your browser. A disposable | ||
93 | | account is created automatically for you. | ||
94 | | | ||
95 | | https://ethereal.email | ||
96 | | | ||
97 | */ | ||
98 | ethereal: { | ||
99 | driver: 'ethereal' | ||
100 | } | ||
101 | } | ||
diff --git a/config/persona.js b/config/persona.js new file mode 100644 index 0000000..71fbc3f --- /dev/null +++ b/config/persona.js | |||
@@ -0,0 +1,98 @@ | |||
1 | 'use strict' | ||
2 | |||
3 | /* | ||
4 | |-------------------------------------------------------------------------- | ||
5 | | Persona | ||
6 | |-------------------------------------------------------------------------- | ||
7 | | | ||
8 | | The persona is a simple and opinionated service to register, login and | ||
9 | | manage user account | ||
10 | | | ||
11 | */ | ||
12 | |||
13 | module.exports = { | ||
14 | /* | ||
15 | |-------------------------------------------------------------------------- | ||
16 | | Uids | ||
17 | |-------------------------------------------------------------------------- | ||
18 | | | ||
19 | | An array of fields, that can be used to indetify a user uniquely. During | ||
20 | | login and reset password, these fields be checked against the user | ||
21 | | input | ||
22 | | | ||
23 | */ | ||
24 | uids: ['email'], | ||
25 | |||
26 | /* | ||
27 | |-------------------------------------------------------------------------- | ||
28 | | Email field | ||
29 | |-------------------------------------------------------------------------- | ||
30 | | | ||
31 | | The name of the email field inside the database and the user payload. | ||
32 | | | ||
33 | */ | ||
34 | email: 'email', | ||
35 | |||
36 | /* | ||
37 | |-------------------------------------------------------------------------- | ||
38 | | Password | ||
39 | |-------------------------------------------------------------------------- | ||
40 | | | ||
41 | | The password field to be used for verifying and storing user password | ||
42 | | | ||
43 | */ | ||
44 | password: 'password', | ||
45 | |||
46 | /* | ||
47 | |-------------------------------------------------------------------------- | ||
48 | | New account state | ||
49 | |-------------------------------------------------------------------------- | ||
50 | | | ||
51 | | State of user when a new account is created | ||
52 | | | ||
53 | */ | ||
54 | newAccountState: 'pending', | ||
55 | |||
56 | /* | ||
57 | |-------------------------------------------------------------------------- | ||
58 | | Verified account state | ||
59 | |-------------------------------------------------------------------------- | ||
60 | | | ||
61 | | State of user after they verify their email address | ||
62 | | | ||
63 | */ | ||
64 | verifiedAccountState: 'active', | ||
65 | |||
66 | /* | ||
67 | |-------------------------------------------------------------------------- | ||
68 | | Model | ||
69 | |-------------------------------------------------------------------------- | ||
70 | | | ||
71 | | The model to be used for verifying and creating users | ||
72 | | | ||
73 | */ | ||
74 | model: 'App/Models/User', | ||
75 | |||
76 | /* | ||
77 | |-------------------------------------------------------------------------- | ||
78 | | Date Format | ||
79 | |-------------------------------------------------------------------------- | ||
80 | | | ||
81 | | The date format for the tokens table. It is required to calculate the | ||
82 | | expiry of a token. | ||
83 | | | ||
84 | */ | ||
85 | dateFormat: 'YYYY-MM-DD HH:mm:ss', | ||
86 | |||
87 | /* | ||
88 | |-------------------------------------------------------------------------- | ||
89 | | Validation messages | ||
90 | |-------------------------------------------------------------------------- | ||
91 | | | ||
92 | | An object of validation messages to be used when validation fails. | ||
93 | | | ||
94 | */ | ||
95 | validationMessages: () => { | ||
96 | return {} | ||
97 | } | ||
98 | } | ||
diff --git a/package-lock.json b/package-lock.json index dbd4d4d..110409b 100644 --- a/package-lock.json +++ b/package-lock.json | |||
@@ -292,6 +292,35 @@ | |||
292 | } | 292 | } |
293 | } | 293 | } |
294 | }, | 294 | }, |
295 | "@adonisjs/mail": { | ||
296 | "version": "3.0.10", | ||
297 | "resolved": "https://registry.npmjs.org/@adonisjs/mail/-/mail-3.0.10.tgz", | ||
298 | "integrity": "sha512-kl+h3TieYllAxcuGA2QGiebBTMAG+p6QkxXnrdtbRp14rfiQZptjDRlhwb/OXZrGHvAXvgYzkhZPlOxsH2uATA==", | ||
299 | "requires": { | ||
300 | "@adonisjs/generic-exceptions": "^2.0.1", | ||
301 | "clone": "^2.1.2", | ||
302 | "debug": "^4.0.1", | ||
303 | "form-data": "^2.3.2", | ||
304 | "get-stream": "^4.0.0", | ||
305 | "got": "8.3.0", | ||
306 | "nodemailer": "^4.6.8" | ||
307 | }, | ||
308 | "dependencies": { | ||
309 | "debug": { | ||
310 | "version": "4.1.1", | ||
311 | "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", | ||
312 | "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", | ||
313 | "requires": { | ||
314 | "ms": "^2.1.1" | ||
315 | } | ||
316 | }, | ||
317 | "ms": { | ||
318 | "version": "2.1.2", | ||
319 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", | ||
320 | "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" | ||
321 | } | ||
322 | } | ||
323 | }, | ||
295 | "@adonisjs/middleware-base": { | 324 | "@adonisjs/middleware-base": { |
296 | "version": "1.0.0", | 325 | "version": "1.0.0", |
297 | "resolved": "https://registry.npmjs.org/@adonisjs/middleware-base/-/middleware-base-1.0.0.tgz", | 326 | "resolved": "https://registry.npmjs.org/@adonisjs/middleware-base/-/middleware-base-1.0.0.tgz", |
@@ -319,6 +348,16 @@ | |||
319 | } | 348 | } |
320 | } | 349 | } |
321 | }, | 350 | }, |
351 | "@adonisjs/persona": { | ||
352 | "version": "1.0.5", | ||
353 | "resolved": "https://registry.npmjs.org/@adonisjs/persona/-/persona-1.0.5.tgz", | ||
354 | "integrity": "sha512-VFdZ2CAx8WhDih/AkIf9ZG+62QESiInC4oAz+p4HNsY7fG0DDlbDX4TBPwSK1YOdiZCE6t2T0AcpChtXiBp5xg==", | ||
355 | "requires": { | ||
356 | "@adonisjs/generic-exceptions": "^2.0.0", | ||
357 | "moment": "^2.22.1", | ||
358 | "rand-token": "^0.4.0" | ||
359 | } | ||
360 | }, | ||
322 | "@adonisjs/session": { | 361 | "@adonisjs/session": { |
323 | "version": "1.0.29", | 362 | "version": "1.0.29", |
324 | "resolved": "https://registry.npmjs.org/@adonisjs/session/-/session-1.0.29.tgz", | 363 | "resolved": "https://registry.npmjs.org/@adonisjs/session/-/session-1.0.29.tgz", |
@@ -523,6 +562,11 @@ | |||
523 | "tslib": "^1.9.3" | 562 | "tslib": "^1.9.3" |
524 | } | 563 | } |
525 | }, | 564 | }, |
565 | "@sindresorhus/is": { | ||
566 | "version": "0.7.0", | ||
567 | "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-0.7.0.tgz", | ||
568 | "integrity": "sha512-ONhaKPIufzzrlNbqtWFFd+jlnemX6lJAgq9ZeiZtS7I1PIf/la7CW4m83rTXRnVnsMbW2k56pGYu7AUFJD9Pow==" | ||
569 | }, | ||
526 | "@slynova/flydrive": { | 570 | "@slynova/flydrive": { |
527 | "version": "0.3.1", | 571 | "version": "0.3.1", |
528 | "resolved": "https://registry.npmjs.org/@slynova/flydrive/-/flydrive-0.3.1.tgz", | 572 | "resolved": "https://registry.npmjs.org/@slynova/flydrive/-/flydrive-0.3.1.tgz", |
@@ -1281,6 +1325,32 @@ | |||
1281 | } | 1325 | } |
1282 | } | 1326 | } |
1283 | }, | 1327 | }, |
1328 | "cacheable-request": { | ||
1329 | "version": "2.1.4", | ||
1330 | "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-2.1.4.tgz", | ||
1331 | "integrity": "sha1-DYCIAbY0KtM8kd+dC0TcCbkeXD0=", | ||
1332 | "requires": { | ||
1333 | "clone-response": "1.0.2", | ||
1334 | "get-stream": "3.0.0", | ||
1335 | "http-cache-semantics": "3.8.1", | ||
1336 | "keyv": "3.0.0", | ||
1337 | "lowercase-keys": "1.0.0", | ||
1338 | "normalize-url": "2.0.1", | ||
1339 | "responselike": "1.0.2" | ||
1340 | }, | ||
1341 | "dependencies": { | ||
1342 | "get-stream": { | ||
1343 | "version": "3.0.0", | ||
1344 | "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz", | ||
1345 | "integrity": "sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ=" | ||
1346 | }, | ||
1347 | "lowercase-keys": { | ||
1348 | "version": "1.0.0", | ||
1349 | "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.0.tgz", | ||
1350 | "integrity": "sha1-TjNms55/VFfjXxMkvfb4jQv8cwY=" | ||
1351 | } | ||
1352 | } | ||
1353 | }, | ||
1284 | "caller": { | 1354 | "caller": { |
1285 | "version": "1.0.1", | 1355 | "version": "1.0.1", |
1286 | "resolved": "https://registry.npmjs.org/caller/-/caller-1.0.1.tgz", | 1356 | "resolved": "https://registry.npmjs.org/caller/-/caller-1.0.1.tgz", |
@@ -1458,6 +1528,14 @@ | |||
1458 | } | 1528 | } |
1459 | } | 1529 | } |
1460 | }, | 1530 | }, |
1531 | "clone-response": { | ||
1532 | "version": "1.0.2", | ||
1533 | "resolved": "https://registry.npmjs.org/clone-response/-/clone-response-1.0.2.tgz", | ||
1534 | "integrity": "sha1-0dyXOSAxTfZ/vrlCI7TuNQI56Ws=", | ||
1535 | "requires": { | ||
1536 | "mimic-response": "^1.0.0" | ||
1537 | } | ||
1538 | }, | ||
1461 | "co-body": { | 1539 | "co-body": { |
1462 | "version": "6.0.0", | 1540 | "version": "6.0.0", |
1463 | "resolved": "https://registry.npmjs.org/co-body/-/co-body-6.0.0.tgz", | 1541 | "resolved": "https://registry.npmjs.org/co-body/-/co-body-6.0.0.tgz", |
@@ -1693,6 +1771,14 @@ | |||
1693 | "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz", | 1771 | "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz", |
1694 | "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=" | 1772 | "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=" |
1695 | }, | 1773 | }, |
1774 | "decompress-response": { | ||
1775 | "version": "3.3.0", | ||
1776 | "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-3.3.0.tgz", | ||
1777 | "integrity": "sha1-gKTdMjdIOEv6JICDYirt7Jgq3/M=", | ||
1778 | "requires": { | ||
1779 | "mimic-response": "^1.0.0" | ||
1780 | } | ||
1781 | }, | ||
1696 | "deep-extend": { | 1782 | "deep-extend": { |
1697 | "version": "0.6.0", | 1783 | "version": "0.6.0", |
1698 | "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", | 1784 | "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", |
@@ -1775,6 +1861,11 @@ | |||
1775 | "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-6.2.0.tgz", | 1861 | "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-6.2.0.tgz", |
1776 | "integrity": "sha512-HygQCKUBSFl8wKQZBSemMywRWcEDNidvNbjGVyZu3nbZ8qq9ubiPoGLMdRDpfSrpkkm9BXYFkpKxxFX38o/76w==" | 1862 | "integrity": "sha512-HygQCKUBSFl8wKQZBSemMywRWcEDNidvNbjGVyZu3nbZ8qq9ubiPoGLMdRDpfSrpkkm9BXYFkpKxxFX38o/76w==" |
1777 | }, | 1863 | }, |
1864 | "duplexer3": { | ||
1865 | "version": "0.1.4", | ||
1866 | "resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.4.tgz", | ||
1867 | "integrity": "sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI=" | ||
1868 | }, | ||
1778 | "ecc-jsbn": { | 1869 | "ecc-jsbn": { |
1779 | "version": "0.1.2", | 1870 | "version": "0.1.2", |
1780 | "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", | 1871 | "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", |
@@ -2673,6 +2764,15 @@ | |||
2673 | "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", | 2764 | "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", |
2674 | "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=" | 2765 | "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=" |
2675 | }, | 2766 | }, |
2767 | "from2": { | ||
2768 | "version": "2.3.0", | ||
2769 | "resolved": "https://registry.npmjs.org/from2/-/from2-2.3.0.tgz", | ||
2770 | "integrity": "sha1-i/tVAr3kpNNs/e6gB/zKIdfjgq8=", | ||
2771 | "requires": { | ||
2772 | "inherits": "^2.0.1", | ||
2773 | "readable-stream": "^2.0.0" | ||
2774 | } | ||
2775 | }, | ||
2676 | "fs-constants": { | 2776 | "fs-constants": { |
2677 | "version": "1.0.0", | 2777 | "version": "1.0.0", |
2678 | "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", | 2778 | "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", |
@@ -2830,6 +2930,42 @@ | |||
2830 | "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", | 2930 | "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", |
2831 | "dev": true | 2931 | "dev": true |
2832 | }, | 2932 | }, |
2933 | "got": { | ||
2934 | "version": "8.3.0", | ||
2935 | "resolved": "https://registry.npmjs.org/got/-/got-8.3.0.tgz", | ||
2936 | "integrity": "sha512-kBNy/S2CGwrYgDSec5KTWGKUvupwkkTVAjIsVFF2shXO13xpZdFP4d4kxa//CLX2tN/rV0aYwK8vY6UKWGn2vQ==", | ||
2937 | "requires": { | ||
2938 | "@sindresorhus/is": "^0.7.0", | ||
2939 | "cacheable-request": "^2.1.1", | ||
2940 | "decompress-response": "^3.3.0", | ||
2941 | "duplexer3": "^0.1.4", | ||
2942 | "get-stream": "^3.0.0", | ||
2943 | "into-stream": "^3.1.0", | ||
2944 | "is-retry-allowed": "^1.1.0", | ||
2945 | "isurl": "^1.0.0-alpha5", | ||
2946 | "lowercase-keys": "^1.0.0", | ||
2947 | "mimic-response": "^1.0.0", | ||
2948 | "p-cancelable": "^0.4.0", | ||
2949 | "p-timeout": "^2.0.1", | ||
2950 | "pify": "^3.0.0", | ||
2951 | "safe-buffer": "^5.1.1", | ||
2952 | "timed-out": "^4.0.1", | ||
2953 | "url-parse-lax": "^3.0.0", | ||
2954 | "url-to-options": "^1.0.1" | ||
2955 | }, | ||
2956 | "dependencies": { | ||
2957 | "get-stream": { | ||
2958 | "version": "3.0.0", | ||
2959 | "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz", | ||
2960 | "integrity": "sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ=" | ||
2961 | }, | ||
2962 | "pify": { | ||
2963 | "version": "3.0.0", | ||
2964 | "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", | ||
2965 | "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=" | ||
2966 | } | ||
2967 | } | ||
2968 | }, | ||
2833 | "graceful-fs": { | 2969 | "graceful-fs": { |
2834 | "version": "4.2.2", | 2970 | "version": "4.2.2", |
2835 | "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.2.tgz", | 2971 | "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.2.tgz", |
@@ -2863,12 +2999,25 @@ | |||
2863 | "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", | 2999 | "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", |
2864 | "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=" | 3000 | "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=" |
2865 | }, | 3001 | }, |
3002 | "has-symbol-support-x": { | ||
3003 | "version": "1.4.2", | ||
3004 | "resolved": "https://registry.npmjs.org/has-symbol-support-x/-/has-symbol-support-x-1.4.2.tgz", | ||
3005 | "integrity": "sha512-3ToOva++HaW+eCpgqZrCfN51IPB+7bJNVT6CUATzueB5Heb8o6Nam0V3HG5dlDvZU1Gn5QLcbahiKw/XVk5JJw==" | ||
3006 | }, | ||
2866 | "has-symbols": { | 3007 | "has-symbols": { |
2867 | "version": "1.0.0", | 3008 | "version": "1.0.0", |
2868 | "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.0.tgz", | 3009 | "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.0.tgz", |
2869 | "integrity": "sha1-uhqPGvKg/DllD1yFA2dwQSIGO0Q=", | 3010 | "integrity": "sha1-uhqPGvKg/DllD1yFA2dwQSIGO0Q=", |
2870 | "dev": true | 3011 | "dev": true |
2871 | }, | 3012 | }, |
3013 | "has-to-string-tag-x": { | ||
3014 | "version": "1.4.1", | ||
3015 | "resolved": "https://registry.npmjs.org/has-to-string-tag-x/-/has-to-string-tag-x-1.4.1.tgz", | ||
3016 | "integrity": "sha512-vdbKfmw+3LoOYVr+mtxHaX5a96+0f3DljYd8JOqvOLsf5mw2Otda2qCDT9qRqLAhrjyQ0h7ual5nOiASpsGNFw==", | ||
3017 | "requires": { | ||
3018 | "has-symbol-support-x": "^1.4.1" | ||
3019 | } | ||
3020 | }, | ||
2872 | "has-unicode": { | 3021 | "has-unicode": { |
2873 | "version": "2.0.1", | 3022 | "version": "2.0.1", |
2874 | "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", | 3023 | "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", |
@@ -2922,6 +3071,11 @@ | |||
2922 | "integrity": "sha512-f/wzC2QaWBs7t9IYqB4T3sR1xviIViXJRJTWBlx2Gf3g0Xi5vI7Yy4koXQ1c9OYDGHN9sBy1DQ2AB8fqZBWhUg==", | 3071 | "integrity": "sha512-f/wzC2QaWBs7t9IYqB4T3sR1xviIViXJRJTWBlx2Gf3g0Xi5vI7Yy4koXQ1c9OYDGHN9sBy1DQ2AB8fqZBWhUg==", |
2923 | "dev": true | 3072 | "dev": true |
2924 | }, | 3073 | }, |
3074 | "http-cache-semantics": { | ||
3075 | "version": "3.8.1", | ||
3076 | "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-3.8.1.tgz", | ||
3077 | "integrity": "sha512-5ai2iksyV8ZXmnZhHH4rWPoxxistEexSi5936zIQ1bnNTW5VnA85B6P/VpXiRM017IgRvb2kKo1a//y+0wSp3w==" | ||
3078 | }, | ||
2925 | "http-errors": { | 3079 | "http-errors": { |
2926 | "version": "1.7.3", | 3080 | "version": "1.7.3", |
2927 | "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.3.tgz", | 3081 | "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.3.tgz", |
@@ -3199,6 +3353,15 @@ | |||
3199 | "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.2.0.tgz", | 3353 | "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.2.0.tgz", |
3200 | "integrity": "sha512-mT34yGKMNceBQUoVn7iCDKDntA7SC6gycMAWzGx1z/CMCTV7b2AAtXlo3nRyHZ1FelRkQbQjprHSYGwzLtkVbw==" | 3354 | "integrity": "sha512-mT34yGKMNceBQUoVn7iCDKDntA7SC6gycMAWzGx1z/CMCTV7b2AAtXlo3nRyHZ1FelRkQbQjprHSYGwzLtkVbw==" |
3201 | }, | 3355 | }, |
3356 | "into-stream": { | ||
3357 | "version": "3.1.0", | ||
3358 | "resolved": "https://registry.npmjs.org/into-stream/-/into-stream-3.1.0.tgz", | ||
3359 | "integrity": "sha1-lvsKk2wSur1v8XUqF9BWFqvQlMY=", | ||
3360 | "requires": { | ||
3361 | "from2": "^2.1.1", | ||
3362 | "p-is-promise": "^1.1.0" | ||
3363 | } | ||
3364 | }, | ||
3202 | "ipaddr.js": { | 3365 | "ipaddr.js": { |
3203 | "version": "1.9.0", | 3366 | "version": "1.9.0", |
3204 | "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.0.tgz", | 3367 | "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.0.tgz", |
@@ -3309,6 +3472,16 @@ | |||
3309 | } | 3472 | } |
3310 | } | 3473 | } |
3311 | }, | 3474 | }, |
3475 | "is-object": { | ||
3476 | "version": "1.0.1", | ||
3477 | "resolved": "https://registry.npmjs.org/is-object/-/is-object-1.0.1.tgz", | ||
3478 | "integrity": "sha1-iVJojF7C/9awPsyF52ngKQMINHA=" | ||
3479 | }, | ||
3480 | "is-plain-obj": { | ||
3481 | "version": "1.1.0", | ||
3482 | "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz", | ||
3483 | "integrity": "sha1-caUMhCnfync8kqOQpKA7OfzVHT4=" | ||
3484 | }, | ||
3312 | "is-plain-object": { | 3485 | "is-plain-object": { |
3313 | "version": "2.0.4", | 3486 | "version": "2.0.4", |
3314 | "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", | 3487 | "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", |
@@ -3340,6 +3513,11 @@ | |||
3340 | "is-unc-path": "^1.0.0" | 3513 | "is-unc-path": "^1.0.0" |
3341 | } | 3514 | } |
3342 | }, | 3515 | }, |
3516 | "is-retry-allowed": { | ||
3517 | "version": "1.2.0", | ||
3518 | "resolved": "https://registry.npmjs.org/is-retry-allowed/-/is-retry-allowed-1.2.0.tgz", | ||
3519 | "integrity": "sha512-RUbUeKwvm3XG2VYamhJL1xFktgjvPzL0Hq8C+6yrWIswDy3BIXGqCxhxkc30N9jqK311gVU137K8Ei55/zVJRg==" | ||
3520 | }, | ||
3343 | "is-stream": { | 3521 | "is-stream": { |
3344 | "version": "1.1.0", | 3522 | "version": "1.1.0", |
3345 | "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", | 3523 | "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", |
@@ -3398,6 +3576,15 @@ | |||
3398 | "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", | 3576 | "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", |
3399 | "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=" | 3577 | "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=" |
3400 | }, | 3578 | }, |
3579 | "isurl": { | ||
3580 | "version": "1.0.0", | ||
3581 | "resolved": "https://registry.npmjs.org/isurl/-/isurl-1.0.0.tgz", | ||
3582 | "integrity": "sha512-1P/yWsxPlDtn7QeRD+ULKQPaIaN6yF368GZ2vDfv0AL0NwpStafjWCDDdn0k8wgFMWpVAqG7oJhxHnlud42i9w==", | ||
3583 | "requires": { | ||
3584 | "has-to-string-tag-x": "^1.2.0", | ||
3585 | "is-object": "^1.0.1" | ||
3586 | } | ||
3587 | }, | ||
3401 | "js-tokens": { | 3588 | "js-tokens": { |
3402 | "version": "4.0.0", | 3589 | "version": "4.0.0", |
3403 | "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", | 3590 | "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", |
@@ -3419,6 +3606,11 @@ | |||
3419 | "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", | 3606 | "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", |
3420 | "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=" | 3607 | "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=" |
3421 | }, | 3608 | }, |
3609 | "json-buffer": { | ||
3610 | "version": "3.0.0", | ||
3611 | "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.0.tgz", | ||
3612 | "integrity": "sha1-Wx85evx11ne96Lz8Dkfh+aPZqJg=" | ||
3613 | }, | ||
3422 | "json-schema": { | 3614 | "json-schema": { |
3423 | "version": "0.2.3", | 3615 | "version": "0.2.3", |
3424 | "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", | 3616 | "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", |
@@ -3512,6 +3704,14 @@ | |||
3512 | "safe-buffer": "^5.0.1" | 3704 | "safe-buffer": "^5.0.1" |
3513 | } | 3705 | } |
3514 | }, | 3706 | }, |
3707 | "keyv": { | ||
3708 | "version": "3.0.0", | ||
3709 | "resolved": "https://registry.npmjs.org/keyv/-/keyv-3.0.0.tgz", | ||
3710 | "integrity": "sha512-eguHnq22OE3uVoSYG0LVWNP+4ppamWr9+zWBe1bsNcovIMy6huUJFPgy4mGwCd/rnl3vOLGW1MTlu4c57CT1xA==", | ||
3711 | "requires": { | ||
3712 | "json-buffer": "3.0.0" | ||
3713 | } | ||
3714 | }, | ||
3515 | "kind-of": { | 3715 | "kind-of": { |
3516 | "version": "6.0.2", | 3716 | "version": "6.0.2", |
3517 | "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", | 3717 | "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", |
@@ -3737,6 +3937,11 @@ | |||
3737 | "js-tokens": "^3.0.0 || ^4.0.0" | 3937 | "js-tokens": "^3.0.0 || ^4.0.0" |
3738 | } | 3938 | } |
3739 | }, | 3939 | }, |
3940 | "lowercase-keys": { | ||
3941 | "version": "1.0.1", | ||
3942 | "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz", | ||
3943 | "integrity": "sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA==" | ||
3944 | }, | ||
3740 | "lru-cache": { | 3945 | "lru-cache": { |
3741 | "version": "4.1.5", | 3946 | "version": "4.1.5", |
3742 | "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz", | 3947 | "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz", |
@@ -3871,6 +4076,11 @@ | |||
3871 | "integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==", | 4076 | "integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==", |
3872 | "dev": true | 4077 | "dev": true |
3873 | }, | 4078 | }, |
4079 | "mimic-response": { | ||
4080 | "version": "1.0.1", | ||
4081 | "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz", | ||
4082 | "integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==" | ||
4083 | }, | ||
3874 | "minimatch": { | 4084 | "minimatch": { |
3875 | "version": "3.0.4", | 4085 | "version": "3.0.4", |
3876 | "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", | 4086 | "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", |
@@ -4166,6 +4376,11 @@ | |||
4166 | "vary": "^1.1.2" | 4376 | "vary": "^1.1.2" |
4167 | } | 4377 | } |
4168 | }, | 4378 | }, |
4379 | "nodemailer": { | ||
4380 | "version": "4.7.0", | ||
4381 | "resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-4.7.0.tgz", | ||
4382 | "integrity": "sha512-IludxDypFpYw4xpzKdMAozBSkzKHmNBvGanUREjJItgJ2NYcK/s8+PggVhj7c2yGFQykKsnnmv1+Aqo0ZfjHmw==" | ||
4383 | }, | ||
4169 | "nopt": { | 4384 | "nopt": { |
4170 | "version": "4.0.1", | 4385 | "version": "4.0.1", |
4171 | "resolved": "https://registry.npmjs.org/nopt/-/nopt-4.0.1.tgz", | 4386 | "resolved": "https://registry.npmjs.org/nopt/-/nopt-4.0.1.tgz", |
@@ -4187,6 +4402,16 @@ | |||
4187 | "validate-npm-package-license": "^3.0.1" | 4402 | "validate-npm-package-license": "^3.0.1" |
4188 | } | 4403 | } |
4189 | }, | 4404 | }, |
4405 | "normalize-url": { | ||
4406 | "version": "2.0.1", | ||
4407 | "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-2.0.1.tgz", | ||
4408 | "integrity": "sha512-D6MUW4K/VzoJ4rJ01JFKxDrtY1v9wrgzCX5f2qj/lzH1m/lW6MhUZFKerVsnyjOhOsYzI9Kqqak+10l4LvLpMw==", | ||
4409 | "requires": { | ||
4410 | "prepend-http": "^2.0.0", | ||
4411 | "query-string": "^5.0.1", | ||
4412 | "sort-keys": "^2.0.0" | ||
4413 | } | ||
4414 | }, | ||
4190 | "npm-bundled": { | 4415 | "npm-bundled": { |
4191 | "version": "1.0.6", | 4416 | "version": "1.0.6", |
4192 | "resolved": "https://registry.npmjs.org/npm-bundled/-/npm-bundled-1.0.6.tgz", | 4417 | "resolved": "https://registry.npmjs.org/npm-bundled/-/npm-bundled-1.0.6.tgz", |
@@ -4690,6 +4915,21 @@ | |||
4690 | "os-tmpdir": "^1.0.0" | 4915 | "os-tmpdir": "^1.0.0" |
4691 | } | 4916 | } |
4692 | }, | 4917 | }, |
4918 | "p-cancelable": { | ||
4919 | "version": "0.4.1", | ||
4920 | "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-0.4.1.tgz", | ||
4921 | "integrity": "sha512-HNa1A8LvB1kie7cERyy21VNeHb2CWJJYqyyC2o3klWFfMGlFmWv2Z7sFgZH8ZiaYL95ydToKTFVXgMV/Os0bBQ==" | ||
4922 | }, | ||
4923 | "p-finally": { | ||
4924 | "version": "1.0.0", | ||
4925 | "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", | ||
4926 | "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=" | ||
4927 | }, | ||
4928 | "p-is-promise": { | ||
4929 | "version": "1.1.0", | ||
4930 | "resolved": "https://registry.npmjs.org/p-is-promise/-/p-is-promise-1.1.0.tgz", | ||
4931 | "integrity": "sha1-nJRWmJ6fZYgBewQ01WCXZ1w9oF4=" | ||
4932 | }, | ||
4693 | "p-limit": { | 4933 | "p-limit": { |
4694 | "version": "1.3.0", | 4934 | "version": "1.3.0", |
4695 | "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", | 4935 | "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", |
@@ -4708,6 +4948,14 @@ | |||
4708 | "p-limit": "^1.1.0" | 4948 | "p-limit": "^1.1.0" |
4709 | } | 4949 | } |
4710 | }, | 4950 | }, |
4951 | "p-timeout": { | ||
4952 | "version": "2.0.1", | ||
4953 | "resolved": "https://registry.npmjs.org/p-timeout/-/p-timeout-2.0.1.tgz", | ||
4954 | "integrity": "sha512-88em58dDVB/KzPEx1X0N3LwFfYZPyDc4B6eF38M1rk9VTZMbxXXgjugz8mmwpS9Ox4BDZ+t6t3QP5+/gazweIA==", | ||
4955 | "requires": { | ||
4956 | "p-finally": "^1.0.0" | ||
4957 | } | ||
4958 | }, | ||
4711 | "p-try": { | 4959 | "p-try": { |
4712 | "version": "1.0.0", | 4960 | "version": "1.0.0", |
4713 | "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", | 4961 | "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", |
@@ -4961,6 +5209,11 @@ | |||
4961 | "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=", | 5209 | "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=", |
4962 | "dev": true | 5210 | "dev": true |
4963 | }, | 5211 | }, |
5212 | "prepend-http": { | ||
5213 | "version": "2.0.0", | ||
5214 | "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-2.0.0.tgz", | ||
5215 | "integrity": "sha1-6SQ0v6XqjBn0HN/UAddBo8gZ2Jc=" | ||
5216 | }, | ||
4964 | "pretty-hrtime": { | 5217 | "pretty-hrtime": { |
4965 | "version": "1.0.3", | 5218 | "version": "1.0.3", |
4966 | "resolved": "https://registry.npmjs.org/pretty-hrtime/-/pretty-hrtime-1.0.3.tgz", | 5219 | "resolved": "https://registry.npmjs.org/pretty-hrtime/-/pretty-hrtime-1.0.3.tgz", |
@@ -5375,6 +5628,16 @@ | |||
5375 | "resolved": "https://registry.npmjs.org/qs/-/qs-6.8.0.tgz", | 5628 | "resolved": "https://registry.npmjs.org/qs/-/qs-6.8.0.tgz", |
5376 | "integrity": "sha512-tPSkj8y92PfZVbinY1n84i1Qdx75lZjMQYx9WZhnkofyxzw2r7Ho39G3/aEvSUdebxpnnM4LZJCtvE/Aq3+s9w==" | 5629 | "integrity": "sha512-tPSkj8y92PfZVbinY1n84i1Qdx75lZjMQYx9WZhnkofyxzw2r7Ho39G3/aEvSUdebxpnnM4LZJCtvE/Aq3+s9w==" |
5377 | }, | 5630 | }, |
5631 | "query-string": { | ||
5632 | "version": "5.1.1", | ||
5633 | "resolved": "https://registry.npmjs.org/query-string/-/query-string-5.1.1.tgz", | ||
5634 | "integrity": "sha512-gjWOsm2SoGlgLEdAGt7a6slVOk9mGiXmPFMqrEhLQ68rhQuBnpfs3+EmlvqKyxnCo9/PPlF+9MtY02S1aFg+Jw==", | ||
5635 | "requires": { | ||
5636 | "decode-uri-component": "^0.2.0", | ||
5637 | "object-assign": "^4.1.0", | ||
5638 | "strict-uri-encode": "^1.0.0" | ||
5639 | } | ||
5640 | }, | ||
5378 | "radio-symbol": { | 5641 | "radio-symbol": { |
5379 | "version": "2.0.0", | 5642 | "version": "2.0.0", |
5380 | "resolved": "https://registry.npmjs.org/radio-symbol/-/radio-symbol-2.0.0.tgz", | 5643 | "resolved": "https://registry.npmjs.org/radio-symbol/-/radio-symbol-2.0.0.tgz", |
@@ -5385,6 +5648,11 @@ | |||
5385 | "is-windows": "^1.0.1" | 5648 | "is-windows": "^1.0.1" |
5386 | } | 5649 | } |
5387 | }, | 5650 | }, |
5651 | "rand-token": { | ||
5652 | "version": "0.4.0", | ||
5653 | "resolved": "https://registry.npmjs.org/rand-token/-/rand-token-0.4.0.tgz", | ||
5654 | "integrity": "sha512-FLNNsir2R+XY8LKsZ+8u/w0qZ4sGit7cpNdznsI77cAVob6UlVPueDKRyjJ3W1Q6FJLgAVH98JvlqqpSaL7NEQ==" | ||
5655 | }, | ||
5388 | "random-bytes": { | 5656 | "random-bytes": { |
5389 | "version": "1.0.0", | 5657 | "version": "1.0.0", |
5390 | "resolved": "https://registry.npmjs.org/random-bytes/-/random-bytes-1.0.0.tgz", | 5658 | "resolved": "https://registry.npmjs.org/random-bytes/-/random-bytes-1.0.0.tgz", |
@@ -5736,6 +6004,14 @@ | |||
5736 | "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz", | 6004 | "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz", |
5737 | "integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=" | 6005 | "integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=" |
5738 | }, | 6006 | }, |
6007 | "responselike": { | ||
6008 | "version": "1.0.2", | ||
6009 | "resolved": "https://registry.npmjs.org/responselike/-/responselike-1.0.2.tgz", | ||
6010 | "integrity": "sha1-kYcg7ztjHFZCvgaPFa3lpG9Loec=", | ||
6011 | "requires": { | ||
6012 | "lowercase-keys": "^1.0.0" | ||
6013 | } | ||
6014 | }, | ||
5739 | "restore-cursor": { | 6015 | "restore-cursor": { |
5740 | "version": "2.0.0", | 6016 | "version": "2.0.0", |
5741 | "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz", | 6017 | "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz", |
@@ -6192,6 +6468,14 @@ | |||
6192 | } | 6468 | } |
6193 | } | 6469 | } |
6194 | }, | 6470 | }, |
6471 | "sort-keys": { | ||
6472 | "version": "2.0.0", | ||
6473 | "resolved": "https://registry.npmjs.org/sort-keys/-/sort-keys-2.0.0.tgz", | ||
6474 | "integrity": "sha1-ZYU1WEhh7JfXMNbPQYIuH1ZoQSg=", | ||
6475 | "requires": { | ||
6476 | "is-plain-obj": "^1.0.0" | ||
6477 | } | ||
6478 | }, | ||
6195 | "source-map": { | 6479 | "source-map": { |
6196 | "version": "0.5.7", | 6480 | "version": "0.5.7", |
6197 | "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", | 6481 | "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", |
@@ -6400,6 +6684,11 @@ | |||
6400 | "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", | 6684 | "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", |
6401 | "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=" | 6685 | "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=" |
6402 | }, | 6686 | }, |
6687 | "strict-uri-encode": { | ||
6688 | "version": "1.1.0", | ||
6689 | "resolved": "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz", | ||
6690 | "integrity": "sha1-J5siXfHVgrH1TmWt3UNS4Y+qBxM=" | ||
6691 | }, | ||
6403 | "string-width": { | 6692 | "string-width": { |
6404 | "version": "2.1.1", | 6693 | "version": "2.1.1", |
6405 | "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", | 6694 | "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", |
@@ -6923,6 +7212,11 @@ | |||
6923 | "resolved": "https://registry.npmjs.org/time-stamp/-/time-stamp-1.1.0.tgz", | 7212 | "resolved": "https://registry.npmjs.org/time-stamp/-/time-stamp-1.1.0.tgz", |
6924 | "integrity": "sha1-dkpaEa9QVhkhsTPztE5hhofg9cM=" | 7213 | "integrity": "sha1-dkpaEa9QVhkhsTPztE5hhofg9cM=" |
6925 | }, | 7214 | }, |
7215 | "timed-out": { | ||
7216 | "version": "4.0.1", | ||
7217 | "resolved": "https://registry.npmjs.org/timed-out/-/timed-out-4.0.1.tgz", | ||
7218 | "integrity": "sha1-8y6srFoXW+ol1/q1Zas+2HQe9W8=" | ||
7219 | }, | ||
6926 | "tmp": { | 7220 | "tmp": { |
6927 | "version": "0.0.33", | 7221 | "version": "0.0.33", |
6928 | "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", | 7222 | "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", |
@@ -7186,6 +7480,19 @@ | |||
7186 | "resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz", | 7480 | "resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz", |
7187 | "integrity": "sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=" | 7481 | "integrity": "sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=" |
7188 | }, | 7482 | }, |
7483 | "url-parse-lax": { | ||
7484 | "version": "3.0.0", | ||
7485 | "resolved": "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-3.0.0.tgz", | ||
7486 | "integrity": "sha1-FrXK/Afb42dsGxmZF3gj1lA6yww=", | ||
7487 | "requires": { | ||
7488 | "prepend-http": "^2.0.0" | ||
7489 | } | ||
7490 | }, | ||
7491 | "url-to-options": { | ||
7492 | "version": "1.0.1", | ||
7493 | "resolved": "https://registry.npmjs.org/url-to-options/-/url-to-options-1.0.1.tgz", | ||
7494 | "integrity": "sha1-FQWgOiiaSMvXpDTvuu7FBV9WM6k=" | ||
7495 | }, | ||
7189 | "use": { | 7496 | "use": { |
7190 | "version": "3.1.1", | 7497 | "version": "3.1.1", |
7191 | "resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz", | 7498 | "resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz", |
diff --git a/package.json b/package.json index ece349d..43e0ac0 100644 --- a/package.json +++ b/package.json | |||
@@ -26,6 +26,8 @@ | |||
26 | "@adonisjs/framework": "^5.0.9", | 26 | "@adonisjs/framework": "^5.0.9", |
27 | "@adonisjs/ignitor": "^2.0.8", | 27 | "@adonisjs/ignitor": "^2.0.8", |
28 | "@adonisjs/lucid": "^6.1.3", | 28 | "@adonisjs/lucid": "^6.1.3", |
29 | "@adonisjs/mail": "^3.0.10", | ||
30 | "@adonisjs/persona": "^1.0.5", | ||
29 | "@adonisjs/session": "^1.0.29", | 31 | "@adonisjs/session": "^1.0.29", |
30 | "@adonisjs/shield": "^1.0.8", | 32 | "@adonisjs/shield": "^1.0.8", |
31 | "@adonisjs/validator": "^5.0.6", | 33 | "@adonisjs/validator": "^5.0.6", |
diff --git a/resources/views/dashboard/forgotPassword.edge b/resources/views/dashboard/forgotPassword.edge new file mode 100644 index 0000000..755c300 --- /dev/null +++ b/resources/views/dashboard/forgotPassword.edge | |||
@@ -0,0 +1,49 @@ | |||
1 | @layout('layouts.v2') | ||
2 | |||
3 | @section('content') | ||
4 | <div class="w-screen h-screen bg-purple-200 flex items-center justify-center"> | ||
5 | <form class="w-full max-w-sm bg-white shadow-md rounded px-8 pt-6 pb-8 mb-4" | ||
6 | action="/user/forgot" method="POST"> | ||
7 | <h1 class="text-gray-700 text-center text-2xl pb-5"> | ||
8 | Forgot Password? | ||
9 | </h1> | ||
10 | |||
11 | @if(flashMessage('error')) | ||
12 | <div class="bg-orange-100 border-l-4 border-orange-500 text-orange-700 p-4"> | ||
13 | {{ flashMessage('error') }} | ||
14 | </div> | ||
15 | @endif | ||
16 | @if(old('message')) | ||
17 | <div class="bg-orange-100 border-l-4 border-orange-500 text-orange-700 p-4"> | ||
18 | {{ old('message') }} | ||
19 | </div> | ||
20 | @endif | ||
21 | |||
22 | {{ csrfField() }} | ||
23 | <div class="mb-4"> | ||
24 | <label class="block text-gray-700 text-sm font-bold mb-2" for="username"> | ||
25 | |||
26 | </label> | ||
27 | <input | ||
28 | class="shadow appearance-none border rounded w-full py-2 px-3 text-gray-700 leading-tight focus:outline-none focus:shadow-outline" | ||
29 | id="mail" | ||
30 | name="mail" | ||
31 | type="text" | ||
32 | placeholder="E-Mail" | ||
33 | value="{{ old('mail', '') }}" | ||
34 | required> | ||
35 | </div> | ||
36 | |||
37 | <button | ||
38 | class="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded focus:outline-none focus:shadow-outline" | ||
39 | type="submit"> | ||
40 | Reset password | ||
41 | </button> | ||
42 | <div class="text-center"> | ||
43 | <a class="w-full font-bold text-sm text-blue-500 hover:text-blue-800" href="/user/login"> | ||
44 | Login instead | ||
45 | </a> | ||
46 | </div> | ||
47 | </form> | ||
48 | </div> | ||
49 | @endsection | ||
diff --git a/resources/views/dashboard/login.edge b/resources/views/dashboard/login.edge index 9b4b52a..dce7360 100644 --- a/resources/views/dashboard/login.edge +++ b/resources/views/dashboard/login.edge | |||
@@ -55,6 +55,11 @@ | |||
55 | By logging in, you accept the <a href="/terms">Terms of Service</a> and <a href="/privacy">Privacy policy</a>. This website uses cookies to log you in. | 55 | By logging in, you accept the <a href="/terms">Terms of Service</a> and <a href="/privacy">Privacy policy</a>. This website uses cookies to log you in. |
56 | </p> | 56 | </p> |
57 | <div class="text-center"> | 57 | <div class="text-center"> |
58 | <a class="w-full font-bold text-sm text-blue-500 hover:text-blue-800" href="/user/forgot"> | ||
59 | Forgot my Password | ||
60 | </a> | ||
61 | </div> | ||
62 | <div class="text-center"> | ||
58 | <a class="w-full font-bold text-sm text-blue-500 hover:text-blue-800" href="../import"> | 63 | <a class="w-full font-bold text-sm text-blue-500 hover:text-blue-800" href="../import"> |
59 | Import your Franz account | 64 | Import your Franz account |
60 | </a> | 65 | </a> |
diff --git a/resources/views/dashboard/resetPassword.edge b/resources/views/dashboard/resetPassword.edge new file mode 100644 index 0000000..d663020 --- /dev/null +++ b/resources/views/dashboard/resetPassword.edge | |||
@@ -0,0 +1,64 @@ | |||
1 | @layout('layouts.v2') | ||
2 | |||
3 | @section('content') | ||
4 | <div class="w-screen h-screen bg-purple-200 flex items-center justify-center"> | ||
5 | <form class="w-full max-w-sm bg-white shadow-md rounded px-8 pt-6 pb-8 mb-4" | ||
6 | action="/user/reset" method="POST"> | ||
7 | <h1 class="text-gray-700 text-center text-2xl pb-5"> | ||
8 | Reset Your Password | ||
9 | </h1> | ||
10 | |||
11 | @if(flashMessage('error')) | ||
12 | <div class="bg-orange-100 border-l-4 border-orange-500 text-orange-700 p-4"> | ||
13 | {{ flashMessage('error') }} | ||
14 | </div> | ||
15 | @endif | ||
16 | @if(old('message')) | ||
17 | <div class="bg-orange-100 border-l-4 border-orange-500 text-orange-700 p-4"> | ||
18 | {{ old('message') }} | ||
19 | </div> | ||
20 | @endif | ||
21 | |||
22 | {{ csrfField() }} | ||
23 | <div class="mb-4"> | ||
24 | <label class="block text-gray-700 text-sm font-bold mb-2" for="password"> | ||
25 | New Password | ||
26 | </label> | ||
27 | <input | ||
28 | class="shadow appearance-none border rounded w-full py-2 px-3 text-gray-700 leading-tight focus:outline-none focus:shadow-outline" | ||
29 | id="password" | ||
30 | name="password" | ||
31 | type="password" | ||
32 | placeholder="New Password" | ||
33 | value="{{ old('password', '') }}" | ||
34 | required> | ||
35 | </div> | ||
36 | <div class="mb-4"> | ||
37 | <label class="block text-gray-700 text-sm font-bold mb-2" for="password_confirmation"> | ||
38 | Confirm Password | ||
39 | </label> | ||
40 | <input | ||
41 | class="shadow appearance-none border rounded w-full py-2 px-3 text-gray-700 leading-tight focus:outline-none focus:shadow-outline" | ||
42 | id="password_confirmation" | ||
43 | name="password_confirmation" | ||
44 | type="password" | ||
45 | placeholder="Confirm Password" | ||
46 | value="{{ old('password_confirmation', '') }}" | ||
47 | required> | ||
48 | </div> | ||
49 | |||
50 | <input type="hidden" name="token" value="{{ token }}"> | ||
51 | |||
52 | <button | ||
53 | class="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded focus:outline-none focus:shadow-outline" | ||
54 | type="submit"> | ||
55 | Reset password | ||
56 | </button> | ||
57 | <div class="text-center"> | ||
58 | <a class="w-full font-bold text-sm text-blue-500 hover:text-blue-800" href="/user/login"> | ||
59 | Login instead | ||
60 | </a> | ||
61 | </div> | ||
62 | </form> | ||
63 | </div> | ||
64 | @endsection | ||
diff --git a/start/app.js b/start/app.js index d0986fe..62a5ac3 100644 --- a/start/app.js +++ b/start/app.js | |||
@@ -20,6 +20,8 @@ const providers = [ | |||
20 | '@adonisjs/framework/providers/ViewProvider', | 20 | '@adonisjs/framework/providers/ViewProvider', |
21 | '@adonisjs/session/providers/SessionProvider', | 21 | '@adonisjs/session/providers/SessionProvider', |
22 | '@adonisjs/shield/providers/ShieldProvider', | 22 | '@adonisjs/shield/providers/ShieldProvider', |
23 | '@adonisjs/persona/providers/PersonaProvider', | ||
24 | '@adonisjs/mail/providers/MailProvider', | ||
23 | ]; | 25 | ]; |
24 | 26 | ||
25 | /* | 27 | /* |
diff --git a/start/events.js b/start/events.js new file mode 100644 index 0000000..0b7e28a --- /dev/null +++ b/start/events.js | |||
@@ -0,0 +1,23 @@ | |||
1 | const Event = use('Event'); | ||
2 | const Mail = use('Mail'); | ||
3 | const Env = use('Env'); | ||
4 | |||
5 | Event.on('forgot::password', async ({ user, token }) => { | ||
6 | const body = ` | ||
7 | Hello ${user.username}, | ||
8 | we just recieved a request to reset your password of your Ferdi account. | ||
9 | Use the link below to reset your password. If you havn't requested this, please ignore this message. | ||
10 | |||
11 | ${Env.get('APP_URL')}/user/reset?token=${encodeURIComponent(token)} | ||
12 | |||
13 | This message was sent automatically. Please do not reply. | ||
14 | `; | ||
15 | console.log('Sending message', body); | ||
16 | try { | ||
17 | await Mail.raw(body, (message) => { | ||
18 | message.subject('[Ferdi] Reset your password') | ||
19 | message.from('noreply@getferdi.com') | ||
20 | message.to(user.email) | ||
21 | }); | ||
22 | } catch(e) {} | ||
23 | }); \ No newline at end of file | ||
diff --git a/start/routes.js b/start/routes.js index b96fa16..1c2d4f3 100644 --- a/start/routes.js +++ b/start/routes.js | |||
@@ -65,16 +65,37 @@ if (Env.get('IS_DASHBOARD_ENABLED') != 'false') { | |||
65 | // Auth | 65 | // Auth |
66 | Route.get('login', ({ view }) => view.render('dashboard.login')).middleware('guest'); | 66 | Route.get('login', ({ view }) => view.render('dashboard.login')).middleware('guest'); |
67 | Route.post('login', 'DashboardController.login').middleware('guest').as('login'); | 67 | Route.post('login', 'DashboardController.login').middleware('guest').as('login'); |
68 | 68 | ||
69 | // Reset password | ||
70 | Route.get('forgot', ({ view }) => view.render('dashboard.forgotPassword')).middleware('guest'); | ||
71 | Route.post('forgot', 'DashboardController.forgotPassword').middleware('guest'); | ||
72 | |||
73 | Route.get('reset', ({ view, request }) => { | ||
74 | const token = request.get().token; | ||
75 | if (token) { | ||
76 | return view.render('dashboard.resetPassword', { token }) | ||
77 | } else { | ||
78 | return view.render('others.message', { | ||
79 | heading: 'Invalid token', | ||
80 | text: 'Please make sure you are using a valid and recent link to reset your password.', | ||
81 | }); | ||
82 | } | ||
83 | }).middleware('guest'); | ||
84 | Route.post('reset', 'DashboardController.resetPassword').middleware('guest'); | ||
85 | |||
69 | // Dashboard | 86 | // Dashboard |
70 | Route.get('account', 'DashboardController.account').middleware('auth:session'); | 87 | Route.get('account', 'DashboardController.account').middleware('auth:session'); |
71 | Route.post('account', 'DashboardController.edit').middleware('auth:session'); | 88 | Route.post('account', 'DashboardController.edit').middleware('auth:session'); |
89 | |||
72 | Route.get('data', 'DashboardController.data').middleware('auth:session'); | 90 | Route.get('data', 'DashboardController.data').middleware('auth:session'); |
91 | |||
73 | Route.get('export', 'DashboardController.export').middleware('auth:session'); | 92 | Route.get('export', 'DashboardController.export').middleware('auth:session'); |
74 | Route.post('transfer', 'DashboardController.import').middleware('auth:session'); | 93 | Route.post('transfer', 'DashboardController.import').middleware('auth:session'); |
75 | Route.get('transfer', ({ view }) => view.render('dashboard.transfer')).middleware('auth:session'); | 94 | Route.get('transfer', ({ view }) => view.render('dashboard.transfer')).middleware('auth:session'); |
95 | |||
76 | Route.get('delete', ({ view }) => view.render('dashboard.delete')).middleware('auth:session'); | 96 | Route.get('delete', ({ view }) => view.render('dashboard.delete')).middleware('auth:session'); |
77 | Route.post('delete', 'DashboardController.delete').middleware('auth:session'); | 97 | Route.post('delete', 'DashboardController.delete').middleware('auth:session'); |
98 | |||
78 | Route.get('logout', 'DashboardController.logout').middleware('auth:session'); | 99 | Route.get('logout', 'DashboardController.logout').middleware('auth:session'); |
79 | 100 | ||
80 | Route.get('*', ({ response }) => response.redirect('/user/account')); | 101 | Route.get('*', ({ response }) => response.redirect('/user/account')); |