aboutsummaryrefslogtreecommitdiffstats
path: root/src/internal-server/app/Controllers/Http/UserController.js
diff options
context:
space:
mode:
Diffstat (limited to 'src/internal-server/app/Controllers/Http/UserController.js')
-rw-r--r--src/internal-server/app/Controllers/Http/UserController.js176
1 files changed, 95 insertions, 81 deletions
diff --git a/src/internal-server/app/Controllers/Http/UserController.js b/src/internal-server/app/Controllers/Http/UserController.js
index 994dcc0dc..7b71aac14 100644
--- a/src/internal-server/app/Controllers/Http/UserController.js
+++ b/src/internal-server/app/Controllers/Http/UserController.js
@@ -1,34 +1,37 @@
1const User = use('App/Models/User'); 1const User = use('App/Models/User');
2const Service = use('App/Models/Service'); 2const Service = use('App/Models/Service');
3const Workspace = use('App/Models/Workspace'); 3const Workspace = use('App/Models/Workspace');
4const { 4const { validateAll } = use('Validator');
5 validateAll,
6} = use('Validator');
7 5
8const btoa = require('btoa'); 6const btoa = require('btoa');
9const fetch = require('node-fetch'); 7const fetch = require('node-fetch');
10const uuid = require('uuid/v4'); 8const uuid = require('uuid/v4');
11const crypto = require('crypto'); 9const crypto = require('crypto');
12const { DEFAULT_APP_SETTINGS, API_VERSION } = require('../../../../environment'); 10const {
11 DEFAULT_APP_SETTINGS,
12 API_VERSION,
13} = require('../../../../environment');
13const { default: userAgent } = require('../../../../helpers/userAgent-helpers'); 14const { default: userAgent } = require('../../../../helpers/userAgent-helpers');
14 15
15const apiRequest = (url, route, method, auth) => new Promise((resolve, reject) => { 16const apiRequest = (url, route, method, auth) =>
16 try { 17 new Promise((resolve, reject) => {
17 fetch(`${url}/${API_VERSION}/${route}`, { 18 try {
18 method, 19 fetch(`${url}/${API_VERSION}/${route}`, {
19 headers: { 20 method,
20 Authorization: `Bearer ${auth}`, 21 headers: {
21 'User-Agent': userAgent(), 22 Authorization: `Bearer ${auth}`,
22 }, 23 'User-Agent': userAgent(),
23 }) 24 },
24 .then(data => data.json()) 25 })
25 .then(json => resolve(json)); 26 .then(data => data.json())
26 } catch (e) { 27 .then(json => resolve(json));
27 reject(); 28 } catch {
28 } 29 reject();
29}); 30 }
31 });
30 32
31const LOGIN_SUCCESS_TOKEN = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJGZXJkaSBJbnRlcm5hbCBTZXJ2ZXIiLCJpYXQiOjE1NzEwNDAyMTUsImV4cCI6MjUzMzk1NDE3ODQ0LCJhdWQiOiJnZXRmZXJkaS5jb20iLCJzdWIiOiJmZXJkaUBsb2NhbGhvc3QiLCJ1c2VySWQiOiIxIn0.9_TWFGp6HROv8Yg82Rt6i1-95jqWym40a-HmgrdMC6M'; 33const LOGIN_SUCCESS_TOKEN =
34 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJGZXJkaSBJbnRlcm5hbCBTZXJ2ZXIiLCJpYXQiOjE1NzEwNDAyMTUsImV4cCI6MjUzMzk1NDE3ODQ0LCJhdWQiOiJnZXRmZXJkaS5jb20iLCJzdWIiOiJmZXJkaUBsb2NhbGhvc3QiLCJ1c2VySWQiOiIxIn0.9_TWFGp6HROv8Yg82Rt6i1-95jqWym40a-HmgrdMC6M';
32 35
33const DEFAULT_USER_DATA = { 36const DEFAULT_USER_DATA = {
34 accountType: 'individual', 37 accountType: 'individual',
@@ -45,10 +48,7 @@ const DEFAULT_USER_DATA = {
45 48
46class UserController { 49class UserController {
47 // Register a new user 50 // Register a new user
48 async signup({ 51 async signup({ request, response }) {
49 request,
50 response,
51 }) {
52 // Validate user input 52 // Validate user input
53 const validation = await validateAll(request.all(), { 53 const validation = await validateAll(request.all(), {
54 firstname: 'required', 54 firstname: 'required',
@@ -70,10 +70,7 @@ class UserController {
70 } 70 }
71 71
72 // Login using an existing user 72 // Login using an existing user
73 async login({ 73 async login({ request, response }) {
74 request,
75 response,
76 }) {
77 if (!request.header('Authorization')) { 74 if (!request.header('Authorization')) {
78 return response.status(401).send({ 75 return response.status(401).send({
79 message: 'Please provide authorization', 76 message: 'Please provide authorization',
@@ -88,23 +85,21 @@ class UserController {
88 } 85 }
89 86
90 // Return information about the current user 87 // Return information about the current user
91 async me({ 88 async me({ response }) {
92 response,
93 }) {
94 const user = await User.find(1); 89 const user = await User.find(1);
95 90
96 const settings = typeof user.settings === 'string' ? JSON.parse(user.settings) : user.settings; 91 const settings =
92 typeof user.settings === 'string'
93 ? JSON.parse(user.settings)
94 : user.settings;
97 95
98 return response.send({ 96 return response.send({
99 ...DEFAULT_USER_DATA, 97 ...DEFAULT_USER_DATA,
100 ...settings || {}, 98 ...settings,
101 }); 99 });
102 } 100 }
103 101
104 async updateMe({ 102 async updateMe({ request, response }) {
105 request,
106 response,
107 }) {
108 const user = await User.find(1); 103 const user = await User.find(1);
109 104
110 let settings = user.settings || {}; 105 let settings = user.settings || {};
@@ -125,16 +120,11 @@ class UserController {
125 ...DEFAULT_USER_DATA, 120 ...DEFAULT_USER_DATA,
126 ...newSettings, 121 ...newSettings,
127 }, 122 },
128 status: [ 123 status: ['data-updated'],
129 'data-updated',
130 ],
131 }); 124 });
132 } 125 }
133 126
134 async import({ 127 async import({ request, response }) {
135 request,
136 response,
137 }) {
138 // Validate user input 128 // Validate user input
139 const validation = await validateAll(request.all(), { 129 const validation = await validateAll(request.all(), {
140 email: 'required|email', 130 email: 'required|email',
@@ -142,7 +132,8 @@ class UserController {
142 server: 'required', 132 server: 'required',
143 }); 133 });
144 if (validation.fails()) { 134 if (validation.fails()) {
145 let errorMessage = 'There was an error while trying to import your account:\n'; 135 let errorMessage =
136 'There was an error while trying to import your account:\n';
146 for (const message of validation.messages()) { 137 for (const message of validation.messages()) {
147 if (message.validation === 'required') { 138 if (message.validation === 'required') {
148 errorMessage += `- Please make sure to supply your ${message.field}\n`; 139 errorMessage += `- Please make sure to supply your ${message.field}\n`;
@@ -155,13 +146,12 @@ class UserController {
155 return response.status(401).send(errorMessage); 146 return response.status(401).send(errorMessage);
156 } 147 }
157 148
158 const { 149 const { email, password, server } = request.all();
159 email,
160 password,
161 server,
162 } = request.all();
163 150
164 const hashedPassword = crypto.createHash('sha256').update(password).digest('base64'); 151 const hashedPassword = crypto
152 .createHash('sha256')
153 .update(password)
154 .digest('base64');
165 155
166 // Try to get an authentication token 156 // Try to get an authentication token
167 let token; 157 let token;
@@ -178,16 +168,17 @@ class UserController {
178 const content = await rawResponse.json(); 168 const content = await rawResponse.json();
179 169
180 if (!content.message || content.message !== 'Successfully logged in') { 170 if (!content.message || content.message !== 'Successfully logged in') {
181 const errorMessage = 'Could not login into Franz with your supplied credentials. Please check and try again'; 171 const errorMessage =
172 'Could not login into Franz with your supplied credentials. Please check and try again';
182 return response.status(401).send(errorMessage); 173 return response.status(401).send(errorMessage);
183 } 174 }
184 175
185 // eslint-disable-next-line prefer-destructuring 176 // eslint-disable-next-line prefer-destructuring
186 token = content.token; 177 token = content.token;
187 } catch (e) { 178 } catch (error) {
188 return response.status(401).send({ 179 return response.status(401).send({
189 message: 'Cannot login to Franz', 180 message: 'Cannot login to Franz',
190 error: e, 181 error,
191 }); 182 });
192 } 183 }
193 184
@@ -195,12 +186,13 @@ class UserController {
195 let userInf = false; 186 let userInf = false;
196 try { 187 try {
197 userInf = await apiRequest(server, 'me', 'GET', token); 188 userInf = await apiRequest(server, 'me', 'GET', token);
198 } catch (e) { 189 } catch (error) {
199 const errorMessage = `Could not get your user info from Franz. Please check your credentials or try again later.\nError: ${e}`; 190 const errorMessage = `Could not get your user info from Franz. Please check your credentials or try again later.\nError: ${error}`;
200 return response.status(401).send(errorMessage); 191 return response.status(401).send(errorMessage);
201 } 192 }
202 if (!userInf) { 193 if (!userInf) {
203 const errorMessage = 'Could not get your user info from Franz. Please check your credentials or try again later'; 194 const errorMessage =
195 'Could not get your user info from Franz. Please check your credentials or try again later';
204 return response.status(401).send(errorMessage); 196 return response.status(401).send(errorMessage);
205 } 197 }
206 198
@@ -213,8 +205,8 @@ class UserController {
213 for (const service of services) { 205 for (const service of services) {
214 await this._createAndCacheService(service, serviceIdTranslation); // eslint-disable-line no-await-in-loop 206 await this._createAndCacheService(service, serviceIdTranslation); // eslint-disable-line no-await-in-loop
215 } 207 }
216 } catch (e) { 208 } catch (error) {
217 const errorMessage = `Could not import your services into our system.\nError: ${e}`; 209 const errorMessage = `Could not import your services into our system.\nError: ${error}`;
218 return response.status(401).send(errorMessage); 210 return response.status(401).send(errorMessage);
219 } 211 }
220 212
@@ -225,12 +217,14 @@ class UserController {
225 for (const workspace of workspaces) { 217 for (const workspace of workspaces) {
226 await this._createWorkspace(workspace, serviceIdTranslation); // eslint-disable-line no-await-in-loop 218 await this._createWorkspace(workspace, serviceIdTranslation); // eslint-disable-line no-await-in-loop
227 } 219 }
228 } catch (e) { 220 } catch (error) {
229 const errorMessage = `Could not import your workspaces into our system.\nError: ${e}`; 221 const errorMessage = `Could not import your workspaces into our system.\nError: ${error}`;
230 return response.status(401).send(errorMessage); 222 return response.status(401).send(errorMessage);
231 } 223 }
232 224
233 return response.send('Your account has been imported. You can now use your Franz account in Ferdi.'); 225 return response.send(
226 'Your account has been imported. You can now use your Franz account in Ferdi.',
227 );
234 } 228 }
235 229
236 // Account import/export 230 // Account import/export
@@ -255,10 +249,7 @@ class UserController {
255 .send(exportData); 249 .send(exportData);
256 } 250 }
257 251
258 async importFerdi({ 252 async importFerdi({ request, response }) {
259 request,
260 response,
261 }) {
262 const validation = await validateAll(request.all(), { 253 const validation = await validateAll(request.all(), {
263 file: 'required', 254 file: 'required',
264 }); 255 });
@@ -269,8 +260,10 @@ class UserController {
269 let file; 260 let file;
270 try { 261 try {
271 file = JSON.parse(request.input('file')); 262 file = JSON.parse(request.input('file'));
272 } catch (e) { 263 } catch {
273 return response.send('Could not import: Invalid file, could not read file'); 264 return response.send(
265 'Could not import: Invalid file, could not read file',
266 );
274 } 267 }
275 268
276 if (!file || !file.services || !file.workspaces) { 269 if (!file || !file.services || !file.workspaces) {
@@ -284,8 +277,8 @@ class UserController {
284 for (const service of file.services) { 277 for (const service of file.services) {
285 await this._createAndCacheService(service, serviceIdTranslation); // eslint-disable-line no-await-in-loop 278 await this._createAndCacheService(service, serviceIdTranslation); // eslint-disable-line no-await-in-loop
286 } 279 }
287 } catch (e) { 280 } catch (error) {
288 const errorMessage = `Could not import your services into our system.\nError: ${e}`; 281 const errorMessage = `Could not import your services into our system.\nError: ${error}`;
289 return response.send(errorMessage); 282 return response.send(errorMessage);
290 } 283 }
291 284
@@ -294,8 +287,8 @@ class UserController {
294 for (const workspace of file.workspaces) { 287 for (const workspace of file.workspaces) {
295 await this._createWorkspace(workspace, serviceIdTranslation); // eslint-disable-line no-await-in-loop 288 await this._createWorkspace(workspace, serviceIdTranslation); // eslint-disable-line no-await-in-loop
296 } 289 }
297 } catch (e) { 290 } catch (error) {
298 const errorMessage = `Could not import your workspaces into our system.\nError: ${e}`; 291 const errorMessage = `Could not import your workspaces into our system.\nError: ${error}`;
299 return response.status(401).send(errorMessage); 292 return response.status(401).send(errorMessage);
300 } 293 }
301 294
@@ -306,15 +299,29 @@ class UserController {
306 let newWorkspaceId; 299 let newWorkspaceId;
307 do { 300 do {
308 newWorkspaceId = uuid(); 301 newWorkspaceId = uuid();
309 } while ((await Workspace.query().where('workspaceId', newWorkspaceId).fetch()).rows.length > 0); // eslint-disable-line no-await-in-loop 302 } while (
310 303 (await Workspace.query().where('workspaceId', newWorkspaceId).fetch())
311 if (workspace.services && typeof (workspace.services) === 'string' && workspace.services.length > 0) { 304 .rows.length > 0
305 ); // eslint-disable-line no-await-in-loop
306
307 if (
308 workspace.services &&
309 typeof workspace.services === 'string' &&
310 workspace.services.length > 0
311 ) {
312 workspace.services = JSON.parse(workspace.services); 312 workspace.services = JSON.parse(workspace.services);
313 } 313 }
314 const services = (workspace.services && typeof (workspace.services) === 'object') ? 314 const services =
315 workspace.services.map(oldServiceId => serviceIdTranslation[oldServiceId]) : 315 workspace.services && typeof workspace.services === 'object'
316 []; 316 ? workspace.services.map(
317 if (workspace.data && typeof (workspace.data) === 'string' && workspace.data.length > 0) { 317 oldServiceId => serviceIdTranslation[oldServiceId],
318 )
319 : [];
320 if (
321 workspace.data &&
322 typeof workspace.data === 'string' &&
323 workspace.data.length > 0
324 ) {
318 workspace.data = JSON.parse(workspace.data); 325 workspace.data = JSON.parse(workspace.data);
319 } 326 }
320 327
@@ -332,12 +339,19 @@ class UserController {
332 let newServiceId; 339 let newServiceId;
333 do { 340 do {
334 newServiceId = uuid(); 341 newServiceId = uuid();
335 } while ((await Service.query().where('serviceId', newServiceId).fetch()).rows.length > 0); // eslint-disable-line no-await-in-loop 342 } while (
343 (await Service.query().where('serviceId', newServiceId).fetch()).rows
344 .length > 0
345 ); // eslint-disable-line no-await-in-loop
336 346
337 // store the old serviceId as the key for future lookup 347 // store the old serviceId as the key for future lookup
338 serviceIdTranslation[service.serviceId] = newServiceId; 348 serviceIdTranslation[service.serviceId] = newServiceId;
339 349
340 if (service.settings && typeof (service.settings) === 'string' && service.settings.length > 0) { 350 if (
351 service.settings &&
352 typeof service.settings === 'string' &&
353 service.settings.length > 0
354 ) {
341 service.settings = JSON.parse(service.settings); 355 service.settings = JSON.parse(service.settings);
342 } 356 }
343 357