diff options
-rw-r--r-- | README.md | 4 | ||||
-rw-r--r-- | app/Controllers/Http/DashboardController.js | 155 | ||||
-rw-r--r-- | app/Controllers/Http/UserController.js | 11 | ||||
-rw-r--r-- | app/Exceptions/Handler.js | 2 | ||||
-rw-r--r-- | config/session.js | 99 | ||||
-rw-r--r-- | config/shield.js | 145 | ||||
-rw-r--r-- | package-lock.json | 91 | ||||
-rw-r--r-- | package.json | 2 | ||||
-rw-r--r-- | public/css/main.css | 69 | ||||
-rw-r--r-- | resources/views/dashboard/account.edge | 63 | ||||
-rw-r--r-- | resources/views/dashboard/data.edge | 167 | ||||
-rw-r--r-- | resources/views/dashboard/delete.edge | 31 | ||||
-rw-r--r-- | resources/views/dashboard/login.edge | 42 | ||||
-rw-r--r-- | resources/views/layouts/main.edge | 18 | ||||
-rw-r--r-- | start/app.js | 3 | ||||
-rw-r--r-- | start/kernel.js | 6 | ||||
-rw-r--r-- | start/routes.js | 23 |
17 files changed, 925 insertions, 6 deletions
@@ -1,6 +1,10 @@ | |||
1 | # ferdi-server | 1 | # ferdi-server |
2 | Unofficial Franz server replacement for use with the Ferdi Client. | 2 | Unofficial Franz server replacement for use with the Ferdi Client. |
3 | 3 | ||
4 | ## Why use a custom ferdi-server? | ||
5 | A custom ferdi-server allows you to experience the full potential of the Ferdi client. | ||
6 | |||
7 | |||
4 | ## Features | 8 | ## Features |
5 | - [x] User registration and login | 9 | - [x] User registration and login |
6 | - [x] Service creation, download, listing and removing | 10 | - [x] Service creation, download, listing and removing |
diff --git a/app/Controllers/Http/DashboardController.js b/app/Controllers/Http/DashboardController.js new file mode 100644 index 0000000..aa8127f --- /dev/null +++ b/app/Controllers/Http/DashboardController.js | |||
@@ -0,0 +1,155 @@ | |||
1 | 'use strict' | ||
2 | |||
3 | const { | ||
4 | validateAll | ||
5 | } = use('Validator'); | ||
6 | |||
7 | const crypto = require('crypto'); | ||
8 | |||
9 | class DashboardController { | ||
10 | async login({ | ||
11 | request, | ||
12 | response, | ||
13 | auth, | ||
14 | session | ||
15 | }) { | ||
16 | const validation = await validateAll(request.all(), { | ||
17 | mail: 'required|email', | ||
18 | password: 'required', | ||
19 | }); | ||
20 | if (validation.fails()) { | ||
21 | session.withErrors({ | ||
22 | type: 'danger', | ||
23 | message: 'Invalid mail or password' | ||
24 | }).flashExcept(['password']); | ||
25 | return response.redirect('back'); | ||
26 | } | ||
27 | |||
28 | let { | ||
29 | mail, | ||
30 | password | ||
31 | } = request.all() | ||
32 | |||
33 | const hashedPassword = crypto.createHash('sha256').update(password).digest('base64'); | ||
34 | |||
35 | try { | ||
36 | await auth.authenticator('session').attempt(mail, hashedPassword) | ||
37 | } catch (error) { | ||
38 | session.flash({ | ||
39 | type: 'danger', | ||
40 | message: 'Invalid mail or password' | ||
41 | }) | ||
42 | return response.redirect('back'); | ||
43 | } | ||
44 | return response.redirect('/user/account'); | ||
45 | } | ||
46 | |||
47 | async account({ | ||
48 | auth, | ||
49 | view | ||
50 | }) { | ||
51 | try { | ||
52 | await auth.check() | ||
53 | } catch (error) { | ||
54 | return response.redirect('/user/login'); | ||
55 | } | ||
56 | |||
57 | return view.render('dashboard.account', { | ||
58 | username: auth.user.username, | ||
59 | email: auth.user.email | ||
60 | }); | ||
61 | } | ||
62 | |||
63 | async edit({ | ||
64 | auth, | ||
65 | request, | ||
66 | session, | ||
67 | view, | ||
68 | response | ||
69 | }) { | ||
70 | let validation = await validateAll(request.all(), { | ||
71 | username: 'required', | ||
72 | email: 'required' | ||
73 | }); | ||
74 | if (validation.fails()) { | ||
75 | session.withErrors(validation.messages()).flashExcept(['password']); | ||
76 | return response.redirect('back'); | ||
77 | } | ||
78 | |||
79 | // Check new username | ||
80 | if (request.input('username') !== auth.user.username) { | ||
81 | validation = await validateAll(request.all(), { | ||
82 | username: 'required|unique:users,username', | ||
83 | email: 'required' | ||
84 | }); | ||
85 | if (validation.fails()) { | ||
86 | session.withErrors(validation.messages()).flashExcept(['password']); | ||
87 | return response.redirect('back'); | ||
88 | } | ||
89 | } | ||
90 | |||
91 | // Check new email | ||
92 | if (request.input('email') !== auth.user.email) { | ||
93 | validation = await validateAll(request.all(), { | ||
94 | username: 'required', | ||
95 | email: 'required|email|unique:users,email' | ||
96 | }); | ||
97 | if (validation.fails()) { | ||
98 | session.withErrors(validation.messages()).flashExcept(['password']); | ||
99 | return response.redirect('back'); | ||
100 | } | ||
101 | } | ||
102 | |||
103 | // Update user account | ||
104 | auth.user.username = request.input('username'); | ||
105 | auth.user.email = request.input('email'); | ||
106 | if (!!request.input('password')) { | ||
107 | const hashedPassword = crypto.createHash('sha256').update(request.input('password')).digest('base64'); | ||
108 | auth.user.password = hashedPassword; | ||
109 | } | ||
110 | auth.user.save(); | ||
111 | |||
112 | return view.render('dashboard.account', { | ||
113 | username: auth.user.username, | ||
114 | email: auth.user.email, | ||
115 | success: true | ||
116 | }); | ||
117 | } | ||
118 | |||
119 | async data({ | ||
120 | auth, | ||
121 | view | ||
122 | }) { | ||
123 | const general = auth.user; | ||
124 | const services = (await auth.user.services().fetch()).toJSON(); | ||
125 | const workspaces = (await auth.user.workspaces().fetch()).toJSON(); | ||
126 | |||
127 | return view.render('dashboard.data', { | ||
128 | username: general.username, | ||
129 | mail: general.email, | ||
130 | created: general.created_at, | ||
131 | updated: general.updated_at, | ||
132 | services, | ||
133 | workspaces, | ||
134 | }); | ||
135 | } | ||
136 | |||
137 | logout({ | ||
138 | auth, | ||
139 | response | ||
140 | }) { | ||
141 | auth.authenticator('session').logout(); | ||
142 | return response.redirect('/user/login'); | ||
143 | } | ||
144 | |||
145 | delete({ | ||
146 | auth, | ||
147 | response | ||
148 | }) { | ||
149 | auth.user.delete(); | ||
150 | auth.authenticator('session').logout(); | ||
151 | return response.redirect('/user/login'); | ||
152 | } | ||
153 | } | ||
154 | |||
155 | module.exports = DashboardController | ||
diff --git a/app/Controllers/Http/UserController.js b/app/Controllers/Http/UserController.js index 2a75f6e..ced27bb 100644 --- a/app/Controllers/Http/UserController.js +++ b/app/Controllers/Http/UserController.js | |||
@@ -192,9 +192,9 @@ class UserController { | |||
192 | 192 | ||
193 | if(Env.get('CONNECT_WITH_FRANZ') == 'false') { | 193 | if(Env.get('CONNECT_WITH_FRANZ') == 'false') { |
194 | await User.create({ | 194 | await User.create({ |
195 | email: userInf.email, | 195 | email, |
196 | password: hashedPassword, | 196 | password: hashedPassword, |
197 | username: userInf.firstname | 197 | username: 'Franz' |
198 | }); | 198 | }); |
199 | 199 | ||
200 | return response.send('Your account has been created but due to this server\'s configuration, we could not import your Franz account data.\n\nIf you are the server owner, please set CONNECT_WITH_FRANZ to true to enable account imports.') | 200 | return response.send('Your account has been created but due to this server\'s configuration, we could not import your Franz account data.\n\nIf you are the server owner, please set CONNECT_WITH_FRANZ to true to enable account imports.') |
@@ -231,13 +231,18 @@ class UserController { | |||
231 | } | 231 | } |
232 | 232 | ||
233 | // Get user information | 233 | // Get user information |
234 | let userInf; | 234 | let userInf = false; |
235 | try { | 235 | try { |
236 | userInf = await franzRequest('me', 'GET', token) | 236 | userInf = await franzRequest('me', 'GET', token) |
237 | console.log('A', userInf) | ||
237 | } catch (e) { | 238 | } catch (e) { |
238 | const errorMessage = 'Could not get your user info from Franz. Please check your credentials or try again later.\nError: ' + e; | 239 | const errorMessage = 'Could not get your user info from Franz. Please check your credentials or try again later.\nError: ' + e; |
239 | return response.status(401).send(errorMessage) | 240 | return response.status(401).send(errorMessage) |
240 | } | 241 | } |
242 | if (!userInf) { | ||
243 | const errorMessage = 'Could not get your user info from Franz. Please check your credentials or try again later.\nError: ' + e; | ||
244 | return response.status(401).send(errorMessage) | ||
245 | } | ||
241 | 246 | ||
242 | // Create user in DB | 247 | // Create user in DB |
243 | let user; | 248 | let user; |
diff --git a/app/Exceptions/Handler.js b/app/Exceptions/Handler.js index 94d7246..efa2e0b 100644 --- a/app/Exceptions/Handler.js +++ b/app/Exceptions/Handler.js | |||
@@ -23,6 +23,8 @@ class ExceptionHandler extends BaseExceptionHandler { | |||
23 | async handle (error, { request, response }) { | 23 | async handle (error, { request, response }) { |
24 | if (error.name === 'ValidationException') { | 24 | if (error.name === 'ValidationException') { |
25 | return response.status(400).send('Invalid arguments') | 25 | return response.status(400).send('Invalid arguments') |
26 | } else if (error.name === 'InvalidSessionException') { | ||
27 | return response.status(401).redirect('/user/login'); | ||
26 | } | 28 | } |
27 | 29 | ||
28 | response.status(error.status).send(error.message) | 30 | response.status(error.status).send(error.message) |
diff --git a/config/session.js b/config/session.js new file mode 100644 index 0000000..f49b9b7 --- /dev/null +++ b/config/session.js | |||
@@ -0,0 +1,99 @@ | |||
1 | 'use strict' | ||
2 | |||
3 | const Env = use('Env') | ||
4 | |||
5 | module.exports = { | ||
6 | /* | ||
7 | |-------------------------------------------------------------------------- | ||
8 | | Session Driver | ||
9 | |-------------------------------------------------------------------------- | ||
10 | | | ||
11 | | The session driver to be used for storing session values. It can be | ||
12 | | cookie, file or redis. | ||
13 | | | ||
14 | | For `redis` driver, make sure to install and register `@adonisjs/redis` | ||
15 | | | ||
16 | */ | ||
17 | driver: Env.get('SESSION_DRIVER', 'cookie'), | ||
18 | |||
19 | /* | ||
20 | |-------------------------------------------------------------------------- | ||
21 | | Cookie Name | ||
22 | |-------------------------------------------------------------------------- | ||
23 | | | ||
24 | | The name of the cookie to be used for saving session id. Session ids | ||
25 | | are signed and encrypted. | ||
26 | | | ||
27 | */ | ||
28 | cookieName: 'adonis-session', | ||
29 | |||
30 | /* | ||
31 | |-------------------------------------------------------------------------- | ||
32 | | Clear session when browser closes | ||
33 | |-------------------------------------------------------------------------- | ||
34 | | | ||
35 | | If this value is true, the session cookie will be temporary and will be | ||
36 | | removed when browser closes. | ||
37 | | | ||
38 | */ | ||
39 | clearWithBrowser: true, | ||
40 | |||
41 | /* | ||
42 | |-------------------------------------------------------------------------- | ||
43 | | Session age | ||
44 | |-------------------------------------------------------------------------- | ||
45 | | | ||
46 | | This value is only used when `clearWithBrowser` is set to false. The | ||
47 | | age must be a valid https://npmjs.org/package/ms string or should | ||
48 | | be in milliseconds. | ||
49 | | | ||
50 | | Valid values are: | ||
51 | | '2h', '10d', '5y', '2.5 hrs' | ||
52 | | | ||
53 | */ | ||
54 | age: '2h', | ||
55 | |||
56 | /* | ||
57 | |-------------------------------------------------------------------------- | ||
58 | | Cookie options | ||
59 | |-------------------------------------------------------------------------- | ||
60 | | | ||
61 | | Cookie options defines the options to be used for setting up session | ||
62 | | cookie | ||
63 | | | ||
64 | */ | ||
65 | cookie: { | ||
66 | httpOnly: true, | ||
67 | path: '/', | ||
68 | sameSite: false | ||
69 | }, | ||
70 | |||
71 | /* | ||
72 | |-------------------------------------------------------------------------- | ||
73 | | Sessions location | ||
74 | |-------------------------------------------------------------------------- | ||
75 | | | ||
76 | | If driver is set to file, we need to define the relative location from | ||
77 | | the temporary path or absolute url to any location. | ||
78 | | | ||
79 | */ | ||
80 | file: { | ||
81 | location: 'sessions' | ||
82 | }, | ||
83 | |||
84 | /* | ||
85 | |-------------------------------------------------------------------------- | ||
86 | | Redis config | ||
87 | |-------------------------------------------------------------------------- | ||
88 | | | ||
89 | | The configuration for the redis driver. | ||
90 | | | ||
91 | */ | ||
92 | redis: { | ||
93 | host: '127.0.0.1', | ||
94 | port: 6379, | ||
95 | password: null, | ||
96 | db: 0, | ||
97 | keyPrefix: '' | ||
98 | } | ||
99 | } | ||
diff --git a/config/shield.js b/config/shield.js new file mode 100644 index 0000000..3d4526a --- /dev/null +++ b/config/shield.js | |||
@@ -0,0 +1,145 @@ | |||
1 | 'use strict' | ||
2 | |||
3 | module.exports = { | ||
4 | /* | ||
5 | |-------------------------------------------------------------------------- | ||
6 | | Content Security Policy | ||
7 | |-------------------------------------------------------------------------- | ||
8 | | | ||
9 | | Content security policy filters out the origins not allowed to execute | ||
10 | | and load resources like scripts, styles and fonts. There are wide | ||
11 | | variety of options to choose from. | ||
12 | */ | ||
13 | csp: { | ||
14 | /* | ||
15 | |-------------------------------------------------------------------------- | ||
16 | | Directives | ||
17 | |-------------------------------------------------------------------------- | ||
18 | | | ||
19 | | All directives are defined in camelCase and here is the list of | ||
20 | | available directives and their possible values. | ||
21 | | | ||
22 | | https://content-security-policy.com | ||
23 | | | ||
24 | | @example | ||
25 | | directives: { | ||
26 | | defaultSrc: ['self', '@nonce', 'cdnjs.cloudflare.com'] | ||
27 | | } | ||
28 | | | ||
29 | */ | ||
30 | directives: { | ||
31 | }, | ||
32 | /* | ||
33 | |-------------------------------------------------------------------------- | ||
34 | | Report only | ||
35 | |-------------------------------------------------------------------------- | ||
36 | | | ||
37 | | Setting `reportOnly=true` will not block the scripts from running and | ||
38 | | instead report them to a URL. | ||
39 | | | ||
40 | */ | ||
41 | reportOnly: false, | ||
42 | /* | ||
43 | |-------------------------------------------------------------------------- | ||
44 | | Set all headers | ||
45 | |-------------------------------------------------------------------------- | ||
46 | | | ||
47 | | Headers staring with `X` have been depreciated, since all major browsers | ||
48 | | supports the standard CSP header. So its better to disable deperciated | ||
49 | | headers, unless you want them to be set. | ||
50 | | | ||
51 | */ | ||
52 | setAllHeaders: false, | ||
53 | |||
54 | /* | ||
55 | |-------------------------------------------------------------------------- | ||
56 | | Disable on android | ||
57 | |-------------------------------------------------------------------------- | ||
58 | | | ||
59 | | Certain versions of android are buggy with CSP policy. So you can set | ||
60 | | this value to true, to disable it for Android versions with buggy | ||
61 | | behavior. | ||
62 | | | ||
63 | | Here is an issue reported on a different package, but helpful to read | ||
64 | | if you want to know the behavior. https://github.com/helmetjs/helmet/pull/82 | ||
65 | | | ||
66 | */ | ||
67 | disableAndroid: true | ||
68 | }, | ||
69 | |||
70 | /* | ||
71 | |-------------------------------------------------------------------------- | ||
72 | | X-XSS-Protection | ||
73 | |-------------------------------------------------------------------------- | ||
74 | | | ||
75 | | X-XSS Protection saves from applications from XSS attacks. It is adopted | ||
76 | | by IE and later followed by some other browsers. | ||
77 | | | ||
78 | | Learn more at https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-XSS-Protection | ||
79 | | | ||
80 | */ | ||
81 | xss: { | ||
82 | enabled: true, | ||
83 | enableOnOldIE: false | ||
84 | }, | ||
85 | |||
86 | /* | ||
87 | |-------------------------------------------------------------------------- | ||
88 | | Iframe Options | ||
89 | |-------------------------------------------------------------------------- | ||
90 | | | ||
91 | | xframe defines whether or not your website can be embedded inside an | ||
92 | | iframe. Choose from one of the following options. | ||
93 | | @available options | ||
94 | | DENY, SAMEORIGIN, ALLOW-FROM http://example.com | ||
95 | | | ||
96 | | Learn more at https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Frame-Options | ||
97 | */ | ||
98 | xframe: 'DENY', | ||
99 | |||
100 | /* | ||
101 | |-------------------------------------------------------------------------- | ||
102 | | No Sniff | ||
103 | |-------------------------------------------------------------------------- | ||
104 | | | ||
105 | | Browsers have a habit of sniffing content-type of a response. Which means | ||
106 | | files with .txt extension containing Javascript code will be executed as | ||
107 | | Javascript. You can disable this behavior by setting nosniff to false. | ||
108 | | | ||
109 | | Learn more at https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Frame-Options | ||
110 | | | ||
111 | */ | ||
112 | nosniff: true, | ||
113 | |||
114 | /* | ||
115 | |-------------------------------------------------------------------------- | ||
116 | | No Open | ||
117 | |-------------------------------------------------------------------------- | ||
118 | | | ||
119 | | IE users can execute webpages in the context of your website, which is | ||
120 | | a serious security risk. Below option will manage this for you. | ||
121 | | | ||
122 | */ | ||
123 | noopen: true, | ||
124 | |||
125 | /* | ||
126 | |-------------------------------------------------------------------------- | ||
127 | | CSRF Protection | ||
128 | |-------------------------------------------------------------------------- | ||
129 | | | ||
130 | | CSRF Protection adds another layer of security by making sure, actionable | ||
131 | | routes does have a valid token to execute an action. | ||
132 | | | ||
133 | */ | ||
134 | csrf: { | ||
135 | enable: true, | ||
136 | methods: ['POST', 'PUT', 'DELETE'], | ||
137 | filterUris: [], | ||
138 | cookieOptions: { | ||
139 | httpOnly: false, | ||
140 | sameSite: true, | ||
141 | path: '/', | ||
142 | maxAge: 7200 | ||
143 | } | ||
144 | } | ||
145 | } | ||
diff --git a/package-lock.json b/package-lock.json index dfc1308..0a8707b 100644 --- a/package-lock.json +++ b/package-lock.json | |||
@@ -299,6 +299,49 @@ | |||
299 | } | 299 | } |
300 | } | 300 | } |
301 | }, | 301 | }, |
302 | "@adonisjs/session": { | ||
303 | "version": "1.0.29", | ||
304 | "resolved": "https://registry.npmjs.org/@adonisjs/session/-/session-1.0.29.tgz", | ||
305 | "integrity": "sha512-dr8P/WUrt50uLZt5SZ8C1uhp4FXzGPh1dNUeS0Lur95ftzHri6S+suBXQ4DM+sNiZQn7iaVylYwsFqUlOkp8gQ==", | ||
306 | "requires": { | ||
307 | "@adonisjs/generic-exceptions": "^2.0.1", | ||
308 | "bson": "^1.1.0", | ||
309 | "debug": "^4.1.0", | ||
310 | "fs-extra": "^7.0.0", | ||
311 | "lodash": "^4.17.11", | ||
312 | "ms": "^2.1.1", | ||
313 | "type-of-is": "^3.5.1", | ||
314 | "uuid": "^3.3.2" | ||
315 | }, | ||
316 | "dependencies": { | ||
317 | "debug": { | ||
318 | "version": "4.1.1", | ||
319 | "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", | ||
320 | "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", | ||
321 | "requires": { | ||
322 | "ms": "^2.1.1" | ||
323 | } | ||
324 | }, | ||
325 | "ms": { | ||
326 | "version": "2.1.2", | ||
327 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", | ||
328 | "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" | ||
329 | } | ||
330 | } | ||
331 | }, | ||
332 | "@adonisjs/shield": { | ||
333 | "version": "1.0.8", | ||
334 | "resolved": "https://registry.npmjs.org/@adonisjs/shield/-/shield-1.0.8.tgz", | ||
335 | "integrity": "sha512-bFPuDIlChrp7ihbwjl8OVCw/b57pG0yn/1rrzFXP2XBpIUTbOFdQxzDlvydHxsyg90/pAup/4qtmdulywczg2g==", | ||
336 | "requires": { | ||
337 | "@adonisjs/generic-exceptions": "^2.0.1", | ||
338 | "csrf": "^3.0.6", | ||
339 | "node-cookie": "^2.1.1", | ||
340 | "node-csp": "^1.0.1", | ||
341 | "node-guard": "^1.0.0", | ||
342 | "uuid": "^3.3.2" | ||
343 | } | ||
344 | }, | ||
302 | "@adonisjs/validator": { | 345 | "@adonisjs/validator": { |
303 | "version": "5.0.6", | 346 | "version": "5.0.6", |
304 | "resolved": "https://registry.npmjs.org/@adonisjs/validator/-/validator-5.0.6.tgz", | 347 | "resolved": "https://registry.npmjs.org/@adonisjs/validator/-/validator-5.0.6.tgz", |
@@ -836,6 +879,11 @@ | |||
836 | "to-regex": "^3.0.1" | 879 | "to-regex": "^3.0.1" |
837 | } | 880 | } |
838 | }, | 881 | }, |
882 | "bson": { | ||
883 | "version": "1.1.1", | ||
884 | "resolved": "https://registry.npmjs.org/bson/-/bson-1.1.1.tgz", | ||
885 | "integrity": "sha512-jCGVYLoYMHDkOsbwJZBCqwMHyH4c+wzgI9hG7Z6SZJRXWr+x58pdIbm2i9a/jFGCkRJqRUr8eoI7lDWa0hTkxg==" | ||
886 | }, | ||
839 | "btoa": { | 887 | "btoa": { |
840 | "version": "1.2.1", | 888 | "version": "1.2.1", |
841 | "resolved": "https://registry.npmjs.org/btoa/-/btoa-1.2.1.tgz", | 889 | "resolved": "https://registry.npmjs.org/btoa/-/btoa-1.2.1.tgz", |
@@ -1240,6 +1288,16 @@ | |||
1240 | "which": "^1.2.9" | 1288 | "which": "^1.2.9" |
1241 | } | 1289 | } |
1242 | }, | 1290 | }, |
1291 | "csrf": { | ||
1292 | "version": "3.1.0", | ||
1293 | "resolved": "https://registry.npmjs.org/csrf/-/csrf-3.1.0.tgz", | ||
1294 | "integrity": "sha512-uTqEnCvWRk042asU6JtapDTcJeeailFy4ydOQS28bj1hcLnYRiqi8SsD2jS412AY1I/4qdOwWZun774iqywf9w==", | ||
1295 | "requires": { | ||
1296 | "rndm": "1.2.0", | ||
1297 | "tsscmp": "1.0.6", | ||
1298 | "uid-safe": "2.1.5" | ||
1299 | } | ||
1300 | }, | ||
1243 | "dashdash": { | 1301 | "dashdash": { |
1244 | "version": "1.14.1", | 1302 | "version": "1.14.1", |
1245 | "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", | 1303 | "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", |
@@ -2721,6 +2779,14 @@ | |||
2721 | } | 2779 | } |
2722 | } | 2780 | } |
2723 | }, | 2781 | }, |
2782 | "node-csp": { | ||
2783 | "version": "1.0.1", | ||
2784 | "resolved": "https://registry.npmjs.org/node-csp/-/node-csp-1.0.1.tgz", | ||
2785 | "integrity": "sha1-MF6yN3yY2oQVq7sDcW76HU6wznI=", | ||
2786 | "requires": { | ||
2787 | "platform": "^1.3.1" | ||
2788 | } | ||
2789 | }, | ||
2724 | "node-exceptions": { | 2790 | "node-exceptions": { |
2725 | "version": "3.0.0", | 2791 | "version": "3.0.0", |
2726 | "resolved": "https://registry.npmjs.org/node-exceptions/-/node-exceptions-3.0.0.tgz", | 2792 | "resolved": "https://registry.npmjs.org/node-exceptions/-/node-exceptions-3.0.0.tgz", |
@@ -2731,6 +2797,11 @@ | |||
2731 | "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.0.tgz", | 2797 | "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.0.tgz", |
2732 | "integrity": "sha512-8dG4H5ujfvFiqDmVu9fQ5bOHUC15JMjMY/Zumv26oOvvVJjM67KF8koCWIabKQ1GJIa9r2mMZscBq/TbdOcmNA==" | 2798 | "integrity": "sha512-8dG4H5ujfvFiqDmVu9fQ5bOHUC15JMjMY/Zumv26oOvvVJjM67KF8koCWIabKQ1GJIa9r2mMZscBq/TbdOcmNA==" |
2733 | }, | 2799 | }, |
2800 | "node-guard": { | ||
2801 | "version": "1.0.0", | ||
2802 | "resolved": "https://registry.npmjs.org/node-guard/-/node-guard-1.0.0.tgz", | ||
2803 | "integrity": "sha1-5FSb63kcOxyEJ1WlJztzvosICjQ=" | ||
2804 | }, | ||
2734 | "node-pre-gyp": { | 2805 | "node-pre-gyp": { |
2735 | "version": "0.11.0", | 2806 | "version": "0.11.0", |
2736 | "resolved": "https://registry.npmjs.org/node-pre-gyp/-/node-pre-gyp-0.11.0.tgz", | 2807 | "resolved": "https://registry.npmjs.org/node-pre-gyp/-/node-pre-gyp-0.11.0.tgz", |
@@ -3093,6 +3164,11 @@ | |||
3093 | "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", | 3164 | "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", |
3094 | "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==" | 3165 | "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==" |
3095 | }, | 3166 | }, |
3167 | "platform": { | ||
3168 | "version": "1.3.5", | ||
3169 | "resolved": "https://registry.npmjs.org/platform/-/platform-1.3.5.tgz", | ||
3170 | "integrity": "sha512-TuvHS8AOIZNAlE77WUDiR4rySV/VMptyMfcfeoMgs4P8apaZM3JrnbzBiixKUv+XR6i+BXrQh8WAnjaSPFO65Q==" | ||
3171 | }, | ||
3096 | "pluralize": { | 3172 | "pluralize": { |
3097 | "version": "7.0.0", | 3173 | "version": "7.0.0", |
3098 | "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-7.0.0.tgz", | 3174 | "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-7.0.0.tgz", |
@@ -3778,6 +3854,11 @@ | |||
3778 | "glob": "^7.1.3" | 3854 | "glob": "^7.1.3" |
3779 | } | 3855 | } |
3780 | }, | 3856 | }, |
3857 | "rndm": { | ||
3858 | "version": "1.2.0", | ||
3859 | "resolved": "https://registry.npmjs.org/rndm/-/rndm-1.2.0.tgz", | ||
3860 | "integrity": "sha1-8z/pz7Urv9UgqhgyO8ZdsRCht2w=" | ||
3861 | }, | ||
3781 | "safe-buffer": { | 3862 | "safe-buffer": { |
3782 | "version": "5.2.0", | 3863 | "version": "5.2.0", |
3783 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.0.tgz", | 3864 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.0.tgz", |
@@ -4543,6 +4624,11 @@ | |||
4543 | "resolved": "https://registry.npmjs.org/triple-beam/-/triple-beam-1.3.0.tgz", | 4624 | "resolved": "https://registry.npmjs.org/triple-beam/-/triple-beam-1.3.0.tgz", |
4544 | "integrity": "sha512-XrHUvV5HpdLmIj4uVMxHggLbFSZYIn7HEWsqePZcI50pco+MPqJ50wMGY794X7AOOhxOBAjbkqfAbEe/QMp2Lw==" | 4625 | "integrity": "sha512-XrHUvV5HpdLmIj4uVMxHggLbFSZYIn7HEWsqePZcI50pco+MPqJ50wMGY794X7AOOhxOBAjbkqfAbEe/QMp2Lw==" |
4545 | }, | 4626 | }, |
4627 | "tsscmp": { | ||
4628 | "version": "1.0.6", | ||
4629 | "resolved": "https://registry.npmjs.org/tsscmp/-/tsscmp-1.0.6.tgz", | ||
4630 | "integrity": "sha512-LxhtAkPDTkVCMQjt2h6eBVY28KCjikZqZfMcC15YBeNjkgUpdCfBu5HoiOTDu86v6smE8yOjyEktJ8hlbANHQA==" | ||
4631 | }, | ||
4546 | "tunnel-agent": { | 4632 | "tunnel-agent": { |
4547 | "version": "0.6.0", | 4633 | "version": "0.6.0", |
4548 | "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", | 4634 | "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", |
@@ -4565,6 +4651,11 @@ | |||
4565 | "mime-types": "~2.1.24" | 4651 | "mime-types": "~2.1.24" |
4566 | } | 4652 | } |
4567 | }, | 4653 | }, |
4654 | "type-of-is": { | ||
4655 | "version": "3.5.1", | ||
4656 | "resolved": "https://registry.npmjs.org/type-of-is/-/type-of-is-3.5.1.tgz", | ||
4657 | "integrity": "sha1-7sL8ibgo2/mQDrZBbu4w9P4PzTE=" | ||
4658 | }, | ||
4568 | "uid-safe": { | 4659 | "uid-safe": { |
4569 | "version": "2.1.5", | 4660 | "version": "2.1.5", |
4570 | "resolved": "https://registry.npmjs.org/uid-safe/-/uid-safe-2.1.5.tgz", | 4661 | "resolved": "https://registry.npmjs.org/uid-safe/-/uid-safe-2.1.5.tgz", |
diff --git a/package.json b/package.json index e63e7de..927c513 100644 --- a/package.json +++ b/package.json | |||
@@ -25,6 +25,8 @@ | |||
25 | "@adonisjs/framework": "^5.0.9", | 25 | "@adonisjs/framework": "^5.0.9", |
26 | "@adonisjs/ignitor": "^2.0.8", | 26 | "@adonisjs/ignitor": "^2.0.8", |
27 | "@adonisjs/lucid": "^6.1.3", | 27 | "@adonisjs/lucid": "^6.1.3", |
28 | "@adonisjs/session": "^1.0.29", | ||
29 | "@adonisjs/shield": "^1.0.8", | ||
28 | "@adonisjs/validator": "^5.0.6", | 30 | "@adonisjs/validator": "^5.0.6", |
29 | "atob": "^2.1.2", | 31 | "atob": "^2.1.2", |
30 | "btoa": "^1.2.1", | 32 | "btoa": "^1.2.1", |
diff --git a/public/css/main.css b/public/css/main.css new file mode 100644 index 0000000..a1c5653 --- /dev/null +++ b/public/css/main.css | |||
@@ -0,0 +1,69 @@ | |||
1 | input { | ||
2 | margin-bottom: 1rem; | ||
3 | width: 100%; | ||
4 | padding: 0.5rem; | ||
5 | } | ||
6 | |||
7 | button, .button { | ||
8 | display: flex; | ||
9 | overflow: hidden; | ||
10 | padding: 12px 12px; | ||
11 | cursor: pointer; | ||
12 | width: 100%; | ||
13 | -webkit-user-select: none; | ||
14 | -moz-user-select: none; | ||
15 | -ms-user-select: none; | ||
16 | user-select: none; | ||
17 | transition: all 150ms linear; | ||
18 | text-align: center; | ||
19 | white-space: nowrap; | ||
20 | text-decoration: none !important; | ||
21 | text-transform: none; | ||
22 | text-transform: capitalize; | ||
23 | color: #fff !important; | ||
24 | border: 0 none; | ||
25 | border-radius: 4px; | ||
26 | font-size: 13px; | ||
27 | font-weight: 500; | ||
28 | line-height: 1.3; | ||
29 | -webkit-appearance: none; | ||
30 | -moz-appearance: none; | ||
31 | appearance: none; | ||
32 | justify-content: center; | ||
33 | align-items: center; | ||
34 | flex: 0 0 160px; | ||
35 | box-shadow: 2px 5px 10px #e4e4e4; | ||
36 | color: #FFFFFF; | ||
37 | background: #161616; | ||
38 | } | ||
39 | |||
40 | #dropzone { | ||
41 | width: 100%; | ||
42 | height: 30vh; | ||
43 | background-color: #ebebeb; | ||
44 | |||
45 | display: flex; | ||
46 | align-items: center; | ||
47 | justify-content: center; | ||
48 | text-align: center; | ||
49 | |||
50 | cursor: pointer; | ||
51 | } | ||
52 | |||
53 | #dropzone p { | ||
54 | font-size: 0.85rem; | ||
55 | } | ||
56 | |||
57 | #files { | ||
58 | display: none; | ||
59 | } | ||
60 | |||
61 | .alert { | ||
62 | background-color: #e7a8a6; | ||
63 | padding: 0.8rem; | ||
64 | margin-bottom: 1rem; | ||
65 | } | ||
66 | |||
67 | td { | ||
68 | word-break: break-all; | ||
69 | } \ No newline at end of file | ||
diff --git a/resources/views/dashboard/account.edge b/resources/views/dashboard/account.edge new file mode 100644 index 0000000..0361fa4 --- /dev/null +++ b/resources/views/dashboard/account.edge | |||
@@ -0,0 +1,63 @@ | |||
1 | @layout('layouts.main') | ||
2 | |||
3 | @section('content') | ||
4 | <h2>Your Ferdi account</h2> | ||
5 | @if(flashMessage('error')) | ||
6 | <div class="alert"> | ||
7 | {{ flashMessage('error') }} | ||
8 | </div> | ||
9 | @endif | ||
10 | @if(old('message')) | ||
11 | <div class="alert"> | ||
12 | {{ old('message') }} | ||
13 | </div> | ||
14 | @endif | ||
15 | @if(flashMessage('notification')) | ||
16 | <div class="alert"> | ||
17 | {{ flashMessage('notification.message') }} | ||
18 | </div> | ||
19 | @endif | ||
20 | @if(success === true) | ||
21 | <div class="alert" style="background-color:#28C76F;"> | ||
22 | Sucessfully updated your user account | ||
23 | </div> | ||
24 | @endif | ||
25 | |||
26 | <form action="/user/account" method="POST"> | ||
27 | {{ csrfField() }} | ||
28 | <div> | ||
29 | <label>Name</label> | ||
30 | <div> | ||
31 | <input type="text" value="{{ old('name', username) }}" placeholder="Name" name="username" required> | ||
32 | </div> | ||
33 | </div> | ||
34 | <div> | ||
35 | <label>E-Mail</label> | ||
36 | <div> | ||
37 | <input type="email" value="{{ old('email', email) }}" placeholder="E-Mail" name="email" required> | ||
38 | </div> | ||
39 | </div> | ||
40 | <div> | ||
41 | <label>Password</label> | ||
42 | <div> | ||
43 | <input type="password" placeholder="*********" name="password"> | ||
44 | </div> | ||
45 | </div> | ||
46 | <div> | ||
47 | <button style="background-color:#28C76F;margin-bottom:1rem;">Change settings</button> | ||
48 | </div> | ||
49 | </form> | ||
50 | |||
51 | <div> | ||
52 | <a class="button" href="/user/delete" style="background-color:#F6416C;margin-bottom:1rem;">Delete my account</a> | ||
53 | </div> | ||
54 | <div> | ||
55 | <a class="button" href="/user/data" style="margin-bottom:1rem;">My account data</a> | ||
56 | </div> | ||
57 | <div> | ||
58 | <a class="button" href="/user/logout">Logout</a> | ||
59 | </div> | ||
60 | |||
61 | </div> | ||
62 | |||
63 | @endsection \ No newline at end of file | ||
diff --git a/resources/views/dashboard/data.edge b/resources/views/dashboard/data.edge new file mode 100644 index 0000000..1935229 --- /dev/null +++ b/resources/views/dashboard/data.edge | |||
@@ -0,0 +1,167 @@ | |||
1 | @layout('layouts.main') | ||
2 | |||
3 | @section('content') | ||
4 | <h2>Your Ferdi account data</h2> | ||
5 | @if(flashMessage('error')) | ||
6 | <div class="alert"> | ||
7 | {{ flashMessage('error') }} | ||
8 | </div> | ||
9 | @endif | ||
10 | @if(old('message')) | ||
11 | <div class="alert"> | ||
12 | {{ old('message') }} | ||
13 | </div> | ||
14 | @endif | ||
15 | |||
16 | <h4>General account data</h4> | ||
17 | <table> | ||
18 | <tr> | ||
19 | <th> | ||
20 | Name | ||
21 | </th> | ||
22 | <th> | ||
23 | Value | ||
24 | </th> | ||
25 | </tr> | ||
26 | <tr> | ||
27 | <td> | ||
28 | |||
29 | </td> | ||
30 | <td> | ||
31 | {{ mail }} | ||
32 | </td> | ||
33 | </tr> | ||
34 | <tr> | ||
35 | <td> | ||
36 | Username | ||
37 | </td> | ||
38 | <td> | ||
39 | {{ username }} | ||
40 | </td> | ||
41 | </tr> | ||
42 | <tr> | ||
43 | <td> | ||
44 | Created account on | ||
45 | </td> | ||
46 | <td> | ||
47 | {{ created }} | ||
48 | </td> | ||
49 | </tr> | ||
50 | <tr> | ||
51 | <td> | ||
52 | Last account update on | ||
53 | </td> | ||
54 | <td> | ||
55 | {{ updated }} | ||
56 | </td> | ||
57 | </tr> | ||
58 | </table> | ||
59 | |||
60 | <h4>Your services</h4> | ||
61 | <table> | ||
62 | <tr> | ||
63 | <th> | ||
64 | Service ID | ||
65 | </th> | ||
66 | <th> | ||
67 | Name | ||
68 | </th> | ||
69 | <th> | ||
70 | Recipe ID | ||
71 | </th> | ||
72 | <th> | ||
73 | Settings | ||
74 | </th> | ||
75 | <th> | ||
76 | Created | ||
77 | </th> | ||
78 | <th> | ||
79 | Last updated | ||
80 | </th> | ||
81 | </tr> | ||
82 | |||
83 | @each(service in services) | ||
84 | <tr> | ||
85 | <td> | ||
86 | {{ service.serviceId }} | ||
87 | </td> | ||
88 | <td> | ||
89 | {{ service.name }} | ||
90 | </td> | ||
91 | <td> | ||
92 | {{ service.recipeId }} | ||
93 | </td> | ||
94 | <td> | ||
95 | {{ service.settings }} | ||
96 | </td> | ||
97 | <td> | ||
98 | {{ service.created_at }} | ||
99 | </td> | ||
100 | <td> | ||
101 | {{ service.updated_at }} | ||
102 | </td> | ||
103 | </tr> | ||
104 | @endeach | ||
105 | </table> | ||
106 | |||
107 | |||
108 | <h4>Your workspaces</h4> | ||
109 | <table> | ||
110 | <tr> | ||
111 | <th> | ||
112 | Service ID | ||
113 | </th> | ||
114 | <th> | ||
115 | Name | ||
116 | </th> | ||
117 | <th> | ||
118 | Order | ||
119 | </th> | ||
120 | <th> | ||
121 | Services | ||
122 | </th> | ||
123 | <th> | ||
124 | Data | ||
125 | </th> | ||
126 | <th> | ||
127 | Created | ||
128 | </th> | ||
129 | <th> | ||
130 | Last updated | ||
131 | </th> | ||
132 | </tr> | ||
133 | |||
134 | @each(workspace in workspaces) | ||
135 | <tr> | ||
136 | <td> | ||
137 | {{ workspace.workspaceId }} | ||
138 | </td> | ||
139 | <td> | ||
140 | {{ workspace.name }} | ||
141 | </td> | ||
142 | <td> | ||
143 | {{ workspace.order }} | ||
144 | </td> | ||
145 | <td> | ||
146 | {{ workspace.services }} | ||
147 | </td> | ||
148 | <td> | ||
149 | {{ workspace.data }} | ||
150 | </td> | ||
151 | <td> | ||
152 | {{ workspace.created_at }} | ||
153 | </td> | ||
154 | <td> | ||
155 | {{ workspace.updated_at }} | ||
156 | </td> | ||
157 | </tr> | ||
158 | @endeach | ||
159 | </table> | ||
160 | |||
161 | <div> | ||
162 | <a class="button" href="/user/account">Back to my account</a> | ||
163 | </div> | ||
164 | |||
165 | </div> | ||
166 | |||
167 | @endsection \ No newline at end of file | ||
diff --git a/resources/views/dashboard/delete.edge b/resources/views/dashboard/delete.edge new file mode 100644 index 0000000..d3fc0df --- /dev/null +++ b/resources/views/dashboard/delete.edge | |||
@@ -0,0 +1,31 @@ | |||
1 | @layout('layouts.main') | ||
2 | |||
3 | @section('content') | ||
4 | <h2>Delete Ferdi account</h2> | ||
5 | @if(flashMessage('error')) | ||
6 | <div class="alert"> | ||
7 | {{ flashMessage('error') }} | ||
8 | </div> | ||
9 | @endif | ||
10 | @if(old('message')) | ||
11 | <div class="alert"> | ||
12 | {{ old('message') }} | ||
13 | </div> | ||
14 | @endif | ||
15 | |||
16 | <form action="/user/delete" method="POST"> | ||
17 | <p>Are you sure, that you want to delete your Ferdi account?</p> | ||
18 | <p>This will <b>permanently</b> delete all your account settings, services and workspaces.</p> | ||
19 | <div> | ||
20 | {{ csrfField() }} | ||
21 | <button style="background-color:#F6416C;margin-bottom:1rem;">Yes, delete account</button> | ||
22 | </div> | ||
23 | </form> | ||
24 | |||
25 | <div> | ||
26 | <a class="button" href="/user/account" style="background-color:#28C76F;">Cancel</a> | ||
27 | </div> | ||
28 | |||
29 | </div> | ||
30 | |||
31 | @endsection \ No newline at end of file | ||
diff --git a/resources/views/dashboard/login.edge b/resources/views/dashboard/login.edge new file mode 100644 index 0000000..58e97ba --- /dev/null +++ b/resources/views/dashboard/login.edge | |||
@@ -0,0 +1,42 @@ | |||
1 | @layout('layouts.main') | ||
2 | |||
3 | @section('content') | ||
4 | <h2>Login</h2> | ||
5 | @if(flashMessage('error')) | ||
6 | <div class="alert"> | ||
7 | {{ flashMessage('error') }} | ||
8 | </div> | ||
9 | @endif | ||
10 | @if(old('message')) | ||
11 | <div class="alert"> | ||
12 | {{ old('message') }} | ||
13 | </div> | ||
14 | @endif | ||
15 | <form action="/user/login" method="POST"> | ||
16 | {{ csrfField() }} | ||
17 | <div> | ||
18 | <label>E-Mail</label> | ||
19 | <div> | ||
20 | <input type="email" value="{{ old('mail', '') }}" placeholder="E-Mail" name="mail"> | ||
21 | </div> | ||
22 | </div> | ||
23 | <div> | ||
24 | <label>Password</label> | ||
25 | <div> | ||
26 | <input type="password" placeholder="*********" name="password"> | ||
27 | </div> | ||
28 | </div> | ||
29 | <div> | ||
30 | <button>Login</button> | ||
31 | By logging in, you accept the <a href="/terms">Terms of Service</a> and <a href="/privacy">Privacy policy</a>. | ||
32 | |||
33 | </div> | ||
34 | <div> | ||
35 | <p>Not a member yet? Register in the Ferdi app or <a href="../import">import your Franz account</a>.</p> | ||
36 | </div> | ||
37 | </form> | ||
38 | <br /> | ||
39 | |||
40 | </div> | ||
41 | |||
42 | @endsection \ No newline at end of file | ||
diff --git a/resources/views/layouts/main.edge b/resources/views/layouts/main.edge new file mode 100644 index 0000000..b6cc8ca --- /dev/null +++ b/resources/views/layouts/main.edge | |||
@@ -0,0 +1,18 @@ | |||
1 | <!DOCTYPE html> | ||
2 | <html lang="en"> | ||
3 | |||
4 | <head> | ||
5 | <meta charset="UTF-8"> | ||
6 | <meta name="viewport" content="width=device-width, initial-scale=1.0"> | ||
7 | <meta http-equiv="X-UA-Compatible" content="ie=edge"> | ||
8 | <title>ferdi-server</title> | ||
9 | |||
10 | {{ style('css/vanilla') }} | ||
11 | {{ style('css/main') }} | ||
12 | </head> | ||
13 | |||
14 | <body> | ||
15 | @!section('content') | ||
16 | </body> | ||
17 | |||
18 | </html> | ||
diff --git a/start/app.js b/start/app.js index 0c32499..9cf2735 100644 --- a/start/app.js +++ b/start/app.js | |||
@@ -18,6 +18,9 @@ const providers = [ | |||
18 | '@adonisjs/lucid/providers/LucidProvider', | 18 | '@adonisjs/lucid/providers/LucidProvider', |
19 | '@adonisjs/drive/providers/DriveProvider', | 19 | '@adonisjs/drive/providers/DriveProvider', |
20 | '@adonisjs/validator/providers/ValidatorProvider', | 20 | '@adonisjs/validator/providers/ValidatorProvider', |
21 | '@adonisjs/framework/providers/ViewProvider', | ||
22 | '@adonisjs/session/providers/SessionProvider', | ||
23 | '@adonisjs/shield/providers/ShieldProvider', | ||
21 | ] | 24 | ] |
22 | 25 | ||
23 | /* | 26 | /* |
diff --git a/start/kernel.js b/start/kernel.js index 3c2d26d..18fb5bf 100644 --- a/start/kernel.js +++ b/start/kernel.js | |||
@@ -15,7 +15,8 @@ const Server = use('Server') | |||
15 | const globalMiddleware = [ | 15 | const globalMiddleware = [ |
16 | 'Adonis/Middleware/BodyParser', | 16 | 'Adonis/Middleware/BodyParser', |
17 | 'App/Middleware/ConvertEmptyStringsToNull', | 17 | 'App/Middleware/ConvertEmptyStringsToNull', |
18 | 'Adonis/Middleware/AuthInit' | 18 | 'Adonis/Middleware/AuthInit', |
19 | 'Adonis/Middleware/Session', | ||
19 | ] | 20 | ] |
20 | 21 | ||
21 | /* | 22 | /* |
@@ -37,7 +38,8 @@ const globalMiddleware = [ | |||
37 | */ | 38 | */ |
38 | const namedMiddleware = { | 39 | const namedMiddleware = { |
39 | auth: 'Adonis/Middleware/Auth', | 40 | auth: 'Adonis/Middleware/Auth', |
40 | guest: 'Adonis/Middleware/AllowGuestOnly' | 41 | guest: 'Adonis/Middleware/AllowGuestOnly', |
42 | shield: 'Adonis/Middleware/Shield', | ||
41 | } | 43 | } |
42 | 44 | ||
43 | /* | 45 | /* |
diff --git a/start/routes.js b/start/routes.js index 52f26b9..364eff9 100644 --- a/start/routes.js +++ b/start/routes.js | |||
@@ -60,7 +60,26 @@ Route.group(() => { | |||
60 | Route.get('announcements/:version', 'StaticController.announcement') | 60 | Route.get('announcements/:version', 'StaticController.announcement') |
61 | }).prefix('v1') | 61 | }).prefix('v1') |
62 | 62 | ||
63 | // Dashboard | 63 | // User dashboard |
64 | Route.group(() => { | ||
65 | // Auth | ||
66 | Route.get('login', ({view}) => { | ||
67 | return view.render('dashboard.login'); | ||
68 | }).middleware('guest'); | ||
69 | Route.post('login', 'DashboardController.login').middleware('guest') | ||
70 | |||
71 | // Dashboard | ||
72 | Route.get('account', 'DashboardController.account').middleware('auth:session') | ||
73 | Route.post('account', 'DashboardController.edit').middleware('auth:session') | ||
74 | Route.get('data', 'DashboardController.data').middleware('auth:session') | ||
75 | Route.get('delete', ({view}) => { | ||
76 | return view.render('dashboard.delete'); | ||
77 | }).middleware('auth:session'); | ||
78 | Route.post('delete', 'DashboardController.delete').middleware('auth:session') | ||
79 | Route.get('logout', 'DashboardController.logout').middleware('auth:session') | ||
80 | }).prefix('user').middleware('shield') | ||
81 | |||
82 | // Recipe creation | ||
64 | Route.post('new', 'RecipeController.create') | 83 | Route.post('new', 'RecipeController.create') |
65 | Route.get('new', ({ response }) => { | 84 | Route.get('new', ({ response }) => { |
66 | if (Env.get('IS_CREATION_ENABLED') == 'false') { | 85 | if (Env.get('IS_CREATION_ENABLED') == 'false') { |
@@ -69,6 +88,8 @@ Route.get('new', ({ response }) => { | |||
69 | return response.redirect('/new.html') | 88 | return response.redirect('/new.html') |
70 | } | 89 | } |
71 | }) | 90 | }) |
91 | |||
92 | // Franz account import | ||
72 | Route.post('import', 'UserController.import') | 93 | Route.post('import', 'UserController.import') |
73 | Route.get('import', ({ response }) => response.redirect('/import.html')) | 94 | Route.get('import', ({ response }) => response.redirect('/import.html')) |
74 | 95 | ||