diff options
Diffstat (limited to 'app/Controllers/Http/UserController.js')
-rw-r--r-- | app/Controllers/Http/UserController.js | 213 |
1 files changed, 101 insertions, 112 deletions
diff --git a/app/Controllers/Http/UserController.js b/app/Controllers/Http/UserController.js index ced27bb..1e67092 100644 --- a/app/Controllers/Http/UserController.js +++ b/app/Controllers/Http/UserController.js | |||
@@ -1,12 +1,10 @@ | |||
1 | 'use strict' | ||
2 | |||
3 | const User = use('App/Models/User'); | 1 | const User = use('App/Models/User'); |
4 | const Service = use('App/Models/Service'); | 2 | const Service = use('App/Models/Service'); |
5 | const Workspace = use('App/Models/Workspace'); | 3 | const Workspace = use('App/Models/Workspace'); |
6 | const { | 4 | const { |
7 | validateAll | 5 | validateAll, |
8 | } = use('Validator'); | 6 | } = use('Validator'); |
9 | const Env = use('Env') | 7 | const Env = use('Env'); |
10 | 8 | ||
11 | const atob = require('atob'); | 9 | const atob = require('atob'); |
12 | const btoa = require('btoa'); | 10 | const btoa = require('btoa'); |
@@ -14,49 +12,44 @@ const fetch = require('node-fetch'); | |||
14 | const uuid = require('uuid/v4'); | 12 | const uuid = require('uuid/v4'); |
15 | const crypto = require('crypto'); | 13 | const crypto = require('crypto'); |
16 | 14 | ||
17 | const franzRequest = async (route, method, auth) => { | 15 | const franzRequest = (route, method, auth) => new Promise((resolve, reject) => { |
18 | return new Promise(async (resolve, reject) => { | 16 | const base = 'https://api.franzinfra.com/v1/'; |
19 | const base = 'https://api.franzinfra.com/v1/'; | 17 | const user = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Ferdi/5.3.0-beta.1 Chrome/69.0.3497.128 Electron/4.2.4 Safari/537.36'; |
20 | const user = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Ferdi/5.3.0-beta.1 Chrome/69.0.3497.128 Electron/4.2.4 Safari/537.36'; | 18 | |
21 | 19 | try { | |
22 | try { | 20 | fetch(base + route, { |
23 | const rawResponse = await fetch(base + route, { | 21 | method, |
24 | method, | 22 | headers: { |
25 | headers: { | 23 | Authorization: `Bearer ${auth}`, |
26 | 'Authorization': 'Bearer ' + auth, | 24 | 'User-Agent': user, |
27 | 'User-Agent': user | 25 | }, |
28 | }, | 26 | }) |
29 | }); | 27 | .then((data) => data.json()) |
30 | const content = await rawResponse.json(); | 28 | .then((json) => resolve(json)); |
31 | 29 | } catch (e) { | |
32 | resolve(content); | 30 | reject(); |
33 | } catch (e) { | 31 | } |
34 | reject(); | 32 | }); |
35 | } | ||
36 | }) | ||
37 | } | ||
38 | 33 | ||
39 | class UserController { | 34 | class UserController { |
40 | |||
41 | // Register a new user | 35 | // Register a new user |
42 | async signup({ | 36 | async signup({ |
43 | request, | 37 | request, |
44 | response, | 38 | response, |
45 | auth, | 39 | auth, |
46 | session | ||
47 | }) { | 40 | }) { |
48 | // Validate user input | 41 | // Validate user input |
49 | const validation = await validateAll(request.all(), { | 42 | const validation = await validateAll(request.all(), { |
50 | firstname: 'required', | 43 | firstname: 'required', |
51 | email: 'required|email|unique:users,email', | 44 | email: 'required|email|unique:users,email', |
52 | password: 'required' | 45 | password: 'required', |
53 | }); | 46 | }); |
54 | if (validation.fails()) { | 47 | if (validation.fails()) { |
55 | return response.status(401).send({ | 48 | return response.status(401).send({ |
56 | "message": "Invalid POST arguments", | 49 | message: 'Invalid POST arguments', |
57 | "messages": validation.messages(), | 50 | messages: validation.messages(), |
58 | "status": 401 | 51 | status: 401, |
59 | }) | 52 | }); |
60 | } | 53 | } |
61 | 54 | ||
62 | const data = request.only(['firstname', 'email', 'password']); | 55 | const data = request.only(['firstname', 'email', 'password']); |
@@ -67,21 +60,21 @@ class UserController { | |||
67 | user = await User.create({ | 60 | user = await User.create({ |
68 | email: data.email, | 61 | email: data.email, |
69 | password: data.password, | 62 | password: data.password, |
70 | username: data.firstname | 63 | username: data.firstname, |
71 | }); | 64 | }); |
72 | } catch (e) { | 65 | } catch (e) { |
73 | return response.status(401).send({ | 66 | return response.status(401).send({ |
74 | "message": "E-Mail Address already in use", | 67 | message: 'E-Mail Address already in use', |
75 | "status": 401 | 68 | status: 401, |
76 | }) | 69 | }); |
77 | } | 70 | } |
78 | 71 | ||
79 | // Generate new auth token | 72 | // Generate new auth token |
80 | const token = await auth.generate(user) | 73 | const token = await auth.generate(user); |
81 | 74 | ||
82 | return response.send({ | 75 | return response.send({ |
83 | "message": "Successfully created account", | 76 | message: 'Successfully created account', |
84 | "token": token.token | 77 | token: token.token, |
85 | }); | 78 | }); |
86 | } | 79 | } |
87 | 80 | ||
@@ -89,115 +82,112 @@ class UserController { | |||
89 | async login({ | 82 | async login({ |
90 | request, | 83 | request, |
91 | response, | 84 | response, |
92 | auth | 85 | auth, |
93 | }) { | 86 | }) { |
94 | if (!request.header('Authorization')) { | 87 | if (!request.header('Authorization')) { |
95 | return response.status(401).send({ | 88 | return response.status(401).send({ |
96 | "message": "Please provide authorization", | 89 | message: 'Please provide authorization', |
97 | "status": 401 | 90 | status: 401, |
98 | }) | 91 | }); |
99 | } | 92 | } |
100 | 93 | ||
101 | // Get auth data from auth token | 94 | // Get auth data from auth token |
102 | const authHeader = atob(request.header('Authorization').replace('Basic ', '')).split(':'); | 95 | const authHeader = atob(request.header('Authorization').replace('Basic ', '')).split(':'); |
103 | 96 | ||
104 | // Check if user with email exists | 97 | // Check if user with email exists |
105 | let user = (await User.query().where('email', authHeader[0]).first()); | 98 | const user = (await User.query().where('email', authHeader[0]).first()); |
106 | if (!user || !user.email) { | 99 | if (!user || !user.email) { |
107 | return response.status(401).send({ | 100 | return response.status(401).send({ |
108 | "message": "User credentials not valid (Invalid mail)", | 101 | message: 'User credentials not valid (Invalid mail)', |
109 | "code": "invalid-credentials", | 102 | code: 'invalid-credentials', |
110 | "status": 401 | 103 | status: 401, |
111 | }); | 104 | }); |
112 | } | 105 | } |
113 | 106 | ||
114 | // Try to login | 107 | // Try to login |
115 | let token; | 108 | let token; |
116 | try { | 109 | try { |
117 | token = await auth.attempt(user.email, authHeader[1]) | 110 | token = await auth.attempt(user.email, authHeader[1]); |
118 | } catch (e) { | 111 | } catch (e) { |
119 | return response.status(401).send({ | 112 | return response.status(401).send({ |
120 | "message": "User credentials not valid", | 113 | message: 'User credentials not valid', |
121 | "code": "invalid-credentials", | 114 | code: 'invalid-credentials', |
122 | "status": 401 | 115 | status: 401, |
123 | }); | 116 | }); |
124 | } | 117 | } |
125 | 118 | ||
126 | return response.send({ | 119 | return response.send({ |
127 | "message": "Successfully logged in", | 120 | message: 'Successfully logged in', |
128 | "token": token.token | 121 | token: token.token, |
129 | }); | 122 | }); |
130 | } | 123 | } |
131 | 124 | ||
132 | // Return information about the current user | 125 | // Return information about the current user |
133 | async me({ | 126 | async me({ |
134 | request, | ||
135 | response, | 127 | response, |
136 | auth, | 128 | auth, |
137 | session | ||
138 | }) { | 129 | }) { |
139 | try { | 130 | try { |
140 | await auth.getUser() | 131 | await auth.getUser(); |
141 | } catch (error) { | 132 | } catch (error) { |
142 | response.send('Missing or invalid api token') | 133 | response.send('Missing or invalid api token'); |
143 | } | 134 | } |
144 | 135 | ||
145 | return response.send({ | 136 | return response.send({ |
146 | accountType: "individual", | 137 | accountType: 'individual', |
147 | beta: false, | 138 | beta: false, |
148 | donor: {}, | 139 | donor: {}, |
149 | email: auth.user.email, | 140 | email: auth.user.email, |
150 | emailValidated: true, | 141 | emailValidated: true, |
151 | features: {}, | 142 | features: {}, |
152 | firstname: "Franz", | 143 | firstname: 'Franz', |
153 | id: "82c1cf9d-ab58-4da2-b55e-aaa41d2142d8", | 144 | id: '82c1cf9d-ab58-4da2-b55e-aaa41d2142d8', |
154 | isPremium: true, | 145 | isPremium: true, |
155 | isSubscriptionOwner: true, | 146 | isSubscriptionOwner: true, |
156 | lastname: "Franz", | 147 | lastname: 'Franz', |
157 | locale: "en-US" | 148 | locale: 'en-US', |
158 | }); | 149 | }); |
159 | } | 150 | } |
160 | 151 | ||
161 | 152 | ||
162 | |||
163 | async import({ | 153 | async import({ |
164 | request, | 154 | request, |
165 | response | 155 | response, |
166 | }) { | 156 | }) { |
167 | // Validate user input | 157 | // Validate user input |
168 | const validation = await validateAll(request.all(), { | 158 | const validation = await validateAll(request.all(), { |
169 | email: 'required|email|unique:users,email', | 159 | email: 'required|email|unique:users,email', |
170 | password: 'required' | 160 | password: 'required', |
171 | }); | 161 | }); |
172 | if (validation.fails()) { | 162 | if (validation.fails()) { |
173 | let errorMessage = "There was an error while trying to import your account:\n"; | 163 | let errorMessage = 'There was an error while trying to import your account:\n'; |
174 | for (const message of validation.messages()) { | 164 | for (const message of validation.messages()) { |
175 | if (message.validation == 'required') { | 165 | if (message.validation === 'required') { |
176 | errorMessage += '- Please make sure to supply your ' + message.field + '\n' | 166 | errorMessage += `- Please make sure to supply your ${message.field}\n`; |
177 | } else if (message.validation == 'unique') { | 167 | } else if (message.validation === 'unique') { |
178 | errorMessage += '- There is already a user with this email.\n' | 168 | errorMessage += '- There is already a user with this email.\n'; |
179 | } else { | 169 | } else { |
180 | errorMessage += message.message + '\n'; | 170 | errorMessage += `${message.message}\n`; |
181 | } | 171 | } |
182 | } | 172 | } |
183 | return response.status(401).send(errorMessage) | 173 | return response.status(401).send(errorMessage); |
184 | } | 174 | } |
185 | 175 | ||
186 | const { | 176 | const { |
187 | email, | 177 | email, |
188 | password | 178 | password, |
189 | } = request.all() | 179 | } = request.all(); |
190 | 180 | ||
191 | const hashedPassword = crypto.createHash('sha256').update(password).digest('base64'); | 181 | const hashedPassword = crypto.createHash('sha256').update(password).digest('base64'); |
192 | 182 | ||
193 | if(Env.get('CONNECT_WITH_FRANZ') == 'false') { | 183 | if (Env.get('CONNECT_WITH_FRANZ') == 'false') { // eslint-disable-line eqeqeq |
194 | await User.create({ | 184 | await User.create({ |
195 | email, | 185 | email, |
196 | password: hashedPassword, | 186 | password: hashedPassword, |
197 | username: 'Franz' | 187 | username: 'Franz', |
198 | }); | 188 | }); |
199 | 189 | ||
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.') | 190 | 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.'); |
201 | } | 191 | } |
202 | 192 | ||
203 | const base = 'https://api.franzinfra.com/v1/'; | 193 | const base = 'https://api.franzinfra.com/v1/'; |
@@ -206,42 +196,41 @@ class UserController { | |||
206 | // Try to get an authentication token | 196 | // Try to get an authentication token |
207 | let token; | 197 | let token; |
208 | try { | 198 | try { |
209 | const basicToken = btoa(email + ':' + hashedPassword) | 199 | const basicToken = btoa(`${email}:${hashedPassword}`); |
210 | 200 | ||
211 | const rawResponse = await fetch(base + 'auth/login', { | 201 | const rawResponse = await fetch(`${base}auth/login`, { |
212 | method: 'POST', | 202 | method: 'POST', |
213 | headers: { | 203 | headers: { |
214 | 'Authorization': 'Basic ' + basicToken, | 204 | Authorization: `Basic ${basicToken}`, |
215 | 'User-Agent': userAgent | 205 | 'User-Agent': userAgent, |
216 | }, | 206 | }, |
217 | }); | 207 | }); |
218 | const content = await rawResponse.json(); | 208 | const content = await rawResponse.json(); |
219 | 209 | ||
220 | if (!content.message || content.message !== 'Successfully logged in') { | 210 | if (!content.message || content.message !== 'Successfully logged in') { |
221 | const errorMessage = 'Could not login into Franz with your supplied credentials. Please check and try again'; | 211 | const errorMessage = 'Could not login into Franz with your supplied credentials. Please check and try again'; |
222 | return response.status(401).send(errorMessage) | 212 | return response.status(401).send(errorMessage); |
223 | } | 213 | } |
224 | 214 | ||
225 | token = content.token; | 215 | token = content.token; |
226 | } catch (e) { | 216 | } catch (e) { |
227 | return response.status(401).send({ | 217 | return response.status(401).send({ |
228 | "message": "Cannot login to Franz", | 218 | message: 'Cannot login to Franz', |
229 | "error": e | 219 | error: e, |
230 | }) | 220 | }); |
231 | } | 221 | } |
232 | 222 | ||
233 | // Get user information | 223 | // Get user information |
234 | let userInf = false; | 224 | let userInf = false; |
235 | try { | 225 | try { |
236 | userInf = await franzRequest('me', 'GET', token) | 226 | userInf = await franzRequest('me', 'GET', token); |
237 | console.log('A', userInf) | ||
238 | } catch (e) { | 227 | } catch (e) { |
239 | const errorMessage = 'Could not get your user info from Franz. Please check your credentials or try again later.\nError: ' + e; | 228 | const errorMessage = `Could not get your user info from Franz. Please check your credentials or try again later.\nError: ${e}`; |
240 | return response.status(401).send(errorMessage) | 229 | return response.status(401).send(errorMessage); |
241 | } | 230 | } |
242 | if (!userInf) { | 231 | if (!userInf) { |
243 | const errorMessage = 'Could not get your user info from Franz. Please check your credentials or try again later.\nError: ' + e; | 232 | const errorMessage = 'Could not get your user info from Franz. Please check your credentials or try again later'; |
244 | return response.status(401).send(errorMessage) | 233 | return response.status(401).send(errorMessage); |
245 | } | 234 | } |
246 | 235 | ||
247 | // Create user in DB | 236 | // Create user in DB |
@@ -250,69 +239,69 @@ class UserController { | |||
250 | user = await User.create({ | 239 | user = await User.create({ |
251 | email: userInf.email, | 240 | email: userInf.email, |
252 | password: hashedPassword, | 241 | password: hashedPassword, |
253 | username: userInf.firstname | 242 | username: userInf.firstname, |
254 | }); | 243 | }); |
255 | } catch (e) { | 244 | } catch (e) { |
256 | const errorMessage = 'Could not create your user in our system.\nError: ' + e; | 245 | const errorMessage = `Could not create your user in our system.\nError: ${e}`; |
257 | return response.status(401).send(errorMessage) | 246 | return response.status(401).send(errorMessage); |
258 | } | 247 | } |
259 | 248 | ||
260 | let serviceIdTranslation = {}; | 249 | const serviceIdTranslation = {}; |
261 | 250 | ||
262 | // Import services | 251 | // Import services |
263 | try { | 252 | try { |
264 | const services = await franzRequest('me/services', 'GET', token) | 253 | const services = await franzRequest('me/services', 'GET', token); |
265 | 254 | ||
266 | for (const service of services) { | 255 | for (const service of services) { |
267 | // Get new, unused uuid | 256 | // Get new, unused uuid |
268 | let serviceId; | 257 | let serviceId; |
269 | do { | 258 | do { |
270 | serviceId = uuid(); | 259 | serviceId = uuid(); |
271 | } while ((await Service.query().where('serviceId', serviceId).fetch()).rows.length > 0) | 260 | } while ((await Service.query().where('serviceId', serviceId).fetch()).rows.length > 0); // eslint-disable-line no-await-in-loop |
272 | 261 | ||
273 | await Service.create({ | 262 | await Service.create({ // eslint-disable-line no-await-in-loop |
274 | userId: user.id, | 263 | userId: user.id, |
275 | serviceId, | 264 | serviceId, |
276 | name: service.name, | 265 | name: service.name, |
277 | recipeId: service.recipeId, | 266 | recipeId: service.recipeId, |
278 | settings: JSON.stringify(service) | 267 | settings: JSON.stringify(service), |
279 | }); | 268 | }); |
280 | 269 | ||
281 | serviceIdTranslation[service.id] = serviceId; | 270 | serviceIdTranslation[service.id] = serviceId; |
282 | } | 271 | } |
283 | } catch (e) { | 272 | } catch (e) { |
284 | const errorMessage = 'Could not import your services into our system.\nError: ' + e; | 273 | const errorMessage = `Could not import your services into our system.\nError: ${e}`; |
285 | return response.status(401).send(errorMessage) | 274 | return response.status(401).send(errorMessage); |
286 | } | 275 | } |
287 | 276 | ||
288 | // Import workspaces | 277 | // Import workspaces |
289 | try { | 278 | try { |
290 | const workspaces = await franzRequest('workspace', 'GET', token) | 279 | const workspaces = await franzRequest('workspace', 'GET', token); |
291 | 280 | ||
292 | for (const workspace of workspaces) { | 281 | for (const workspace of workspaces) { |
293 | let workspaceId; | 282 | let workspaceId; |
294 | do { | 283 | do { |
295 | workspaceId = uuid(); | 284 | workspaceId = uuid(); |
296 | } while ((await Workspace.query().where('workspaceId', workspaceId).fetch()).rows.length > 0) | 285 | } while ((await Workspace.query().where('workspaceId', workspaceId).fetch()).rows.length > 0); // eslint-disable-line no-await-in-loop |
297 | 286 | ||
298 | const services = workspace.services.map(service => serviceIdTranslation[service]) | 287 | const services = workspace.services.map((service) => serviceIdTranslation[service]); |
299 | 288 | ||
300 | await Workspace.create({ | 289 | await Workspace.create({ // eslint-disable-line no-await-in-loop |
301 | userId: auth.user.id, | 290 | userId: user.id, |
302 | workspaceId, | 291 | workspaceId, |
303 | name: workspace.name, | 292 | name: workspace.name, |
304 | order: workspace.order, | 293 | order: workspace.order, |
305 | services: JSON.stringify(services), | 294 | services: JSON.stringify(services), |
306 | data: JSON.stringify({}) | 295 | data: JSON.stringify({}), |
307 | }); | 296 | }); |
308 | } | 297 | } |
309 | } catch (e) { | 298 | } catch (e) { |
310 | const errorMessage = 'Could not import your workspaces into our system.\nError: ' + e; | 299 | const errorMessage = `Could not import your workspaces into our system.\nError: ${e}`; |
311 | return response.status(401).send(errorMessage) | 300 | return response.status(401).send(errorMessage); |
312 | } | 301 | } |
313 | 302 | ||
314 | return response.send('Your account has been imported. You can now use your Franz account in Ferdi.') | 303 | return response.send('Your account has been imported. You can now use your Franz account in Ferdi.'); |
315 | } | 304 | } |
316 | } | 305 | } |
317 | 306 | ||
318 | module.exports = UserController | 307 | module.exports = UserController; |