aboutsummaryrefslogtreecommitdiffstats
path: root/app
diff options
context:
space:
mode:
authorLibravatar vantezzen <properly@protonmail.com>2019-08-28 12:10:16 +0200
committerLibravatar vantezzen <properly@protonmail.com>2019-08-28 12:10:16 +0200
commit4f39dce953ea8e197105ee9042fa376c120087ce (patch)
treeda953ea5837b8547c04ec1d3de383dfd4f2ca502 /app
parentMerge branch 'master' of https://github.com/vantezzen/ferdi-server (diff)
downloadferdium-server-4f39dce953ea8e197105ee9042fa376c120087ce.tar.gz
ferdium-server-4f39dce953ea8e197105ee9042fa376c120087ce.tar.zst
ferdium-server-4f39dce953ea8e197105ee9042fa376c120087ce.zip
Add import Franz account feature
Diffstat (limited to 'app')
-rw-r--r--app/Controllers/Http/UserController.js170
1 files changed, 170 insertions, 0 deletions
diff --git a/app/Controllers/Http/UserController.js b/app/Controllers/Http/UserController.js
index 084b023..7c6cece 100644
--- a/app/Controllers/Http/UserController.js
+++ b/app/Controllers/Http/UserController.js
@@ -1,10 +1,39 @@
1'use strict' 1'use strict'
2 2
3const User = use('App/Models/User'); 3const User = use('App/Models/User');
4const Service = use('App/Models/Service');
5const Workspace = use('App/Models/Workspace');
4const { 6const {
5 validateAll 7 validateAll
6} = use('Validator'); 8} = use('Validator');
9
7const atob = require('atob'); 10const atob = require('atob');
11const btoa = require('btoa');
12const fetch = require('node-fetch');
13const uuid = require('uuid/v4');
14const crypto = require('crypto');
15
16const franzRequest = async (route, method, auth) => {
17 return new Promise(async (resolve, reject) => {
18 const base = 'https://api.franzinfra.com/v1/';
19 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
21 try {
22 const rawResponse = await fetch(base + route, {
23 method,
24 headers: {
25 'Authorization': 'Bearer ' + auth,
26 'User-Agent': user
27 },
28 });
29 const content = await rawResponse.json();
30
31 resolve(content);
32 } catch (e) {
33 reject();
34 }
35 })
36}
8 37
9class UserController { 38class UserController {
10 39
@@ -127,6 +156,147 @@ class UserController {
127 locale: "en-US" 156 locale: "en-US"
128 }); 157 });
129 } 158 }
159
160
161
162 async import({
163 request,
164 response
165 }) {
166 // Validate user input
167 const validation = await validateAll(request.all(), {
168 email: 'required|email|unique:users,email',
169 password: 'required'
170 });
171 if (validation.fails()) {
172 let errorMessage = "There was an error while trying to import your account:\n";
173 for (const message of validation.messages()) {
174 if (message.validation == 'required') {
175 errorMessage += '- Please make sure to supply your ' + message.field + '\n'
176 } else if (message.validation == 'unique') {
177 errorMessage += '- There is already a user with this email.\n'
178 } else {
179 errorMessage += message.message + '\n';
180 }
181 }
182 return response.status(401).send(errorMessage)
183 }
184
185 const {
186 email,
187 password
188 } = request.all()
189
190 const hashedPassword = crypto.createHash('sha256').update(password).digest('base64');
191
192 const base = 'https://api.franzinfra.com/v1/';
193 const userAgent = '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';
194
195 // Try to get an authentication token
196 let token;
197 try {
198 const basicToken = btoa(email + ':' + hashedPassword)
199
200 const rawResponse = await fetch(base + 'auth/login', {
201 method: 'POST',
202 headers: {
203 'Authorization': 'Basic ' + basicToken,
204 'User-Agent': userAgent
205 },
206 });
207 const content = await rawResponse.json();
208
209 if (!content.message || content.message !== 'Successfully logged in') {
210 const errorMessage = 'Could not login into Franz with your supplied credentials. Please check and try again';
211 return response.status(401).send(errorMessage)
212 }
213
214 token = content.token;
215 } catch (e) {
216 return response.status(401).send({
217 "message": "Cannot login to Franz",
218 "error": e
219 })
220 }
221
222 // Get user information
223 let userInf;
224 try {
225 userInf = await franzRequest('me', 'GET', token)
226 } catch (e) {
227 const errorMessage = 'Could not get your user info from Franz. Please check your credentials or try again later.\nError: ' + e;
228 return response.status(401).send(errorMessage)
229 }
230
231 // Create user in DB
232 let user;
233 try {
234 user = await User.create({
235 email: userInf.email,
236 password: hashedPassword,
237 username: userInf.firstname
238 });
239 } catch (e) {
240 const errorMessage = 'Could not create your user in our system.\nError: ' + e;
241 return response.status(401).send(errorMessage)
242 }
243
244 let serviceIdTranslation = {};
245
246 // Import services
247 try {
248 const services = await franzRequest('me/services', 'GET', token)
249
250 for (const service of services) {
251 // Get new, unused uuid
252 let serviceId;
253 do {
254 serviceId = uuid();
255 } while ((await Service.query().where('serviceId', serviceId).fetch()).rows.length > 0)
256
257 await Service.create({
258 userId: user.id,
259 serviceId,
260 name: service.name,
261 recipeId: service.recipeId,
262 settings: JSON.stringify(service)
263 });
264
265 serviceIdTranslation[service.id] = serviceId;
266 }
267 } catch (e) {
268 const errorMessage = 'Could not import your services into our system.\nError: ' + e;
269 return response.status(401).send(errorMessage)
270 }
271
272 // Import workspaces
273 try {
274 const workspaces = await franzRequest('workspace', 'GET', token)
275
276 for (const workspace of workspaces) {
277 let workspaceId;
278 do {
279 workspaceId = uuid();
280 } while ((await Workspace.query().where('workspaceId', workspaceId).fetch()).rows.length > 0)
281
282 const services = workspace.services.map(service => serviceIdTranslation[service])
283
284 await Workspace.create({
285 userId: auth.user.id,
286 workspaceId,
287 name: workspace.name,
288 order: workspace.order,
289 services: JSON.stringify(services),
290 data: JSON.stringify({})
291 });
292 }
293 } catch (e) {
294 const errorMessage = 'Could not import your workspaces into our system.\nError: ' + e;
295 return response.status(401).send(errorMessage)
296 }
297
298 return response.send('Your account has been imported. You can now use your Franz account in Ferdi.')
299 }
130} 300}
131 301
132module.exports = UserController 302module.exports = UserController