diff options
Diffstat (limited to 'src/api')
-rw-r--r-- | src/api/apiBase.js | 32 | ||||
-rw-r--r-- | src/api/server/LocalApi.js | 2 | ||||
-rw-r--r-- | src/api/server/ServerApi.js | 57 |
3 files changed, 61 insertions, 30 deletions
diff --git a/src/api/apiBase.js b/src/api/apiBase.js new file mode 100644 index 000000000..e8d571171 --- /dev/null +++ b/src/api/apiBase.js | |||
@@ -0,0 +1,32 @@ | |||
1 | /** | ||
2 | * Get API base URL from store | ||
3 | */ | ||
4 | import { | ||
5 | API_VERSION, | ||
6 | } from '../environment'; | ||
7 | |||
8 | const apiBase = () => { | ||
9 | let url; | ||
10 | |||
11 | if (!window.ferdi | ||
12 | || !window.ferdi.stores.settings | ||
13 | || !window.ferdi.stores.settings.all | ||
14 | || !window.ferdi.stores.settings.all.app.server) { | ||
15 | // Stores have not yet been loaded - send invalid URL to force a retry when stores are loaded | ||
16 | // "Why 1.1.1.1 as the default, invalid URL?" | ||
17 | // 1.1.1.1 is the server for Cloudflare's DNS service and will be the same across most networks. | ||
18 | // Using a random IP could result in unwanted connections, using localhost could unwantedly | ||
19 | // connect to local develoment servers. | ||
20 | // 1.1.1.1 also sends a status 400 response for invalid routes. Other servers may return status 401 | ||
21 | // on some routes. This would result in Ferdi deleting its current authToken as it thinks it | ||
22 | // has gone invalid. | ||
23 | url = 'https://1.1.1.1'; | ||
24 | } else { | ||
25 | // Load URL from store | ||
26 | url = window.ferdi.stores.settings.all.app.server; | ||
27 | } | ||
28 | |||
29 | return `${url}/${API_VERSION}`; | ||
30 | }; | ||
31 | |||
32 | export default apiBase; | ||
diff --git a/src/api/server/LocalApi.js b/src/api/server/LocalApi.js index ab1604a27..c4abc00e9 100644 --- a/src/api/server/LocalApi.js +++ b/src/api/server/LocalApi.js | |||
@@ -3,7 +3,7 @@ import du from 'du'; | |||
3 | 3 | ||
4 | import { getServicePartitionsDirectory } from '../../helpers/service-helpers.js'; | 4 | import { getServicePartitionsDirectory } from '../../helpers/service-helpers.js'; |
5 | 5 | ||
6 | const debug = require('debug')('Franz:LocalApi'); | 6 | const debug = require('debug')('Ferdi:LocalApi'); |
7 | 7 | ||
8 | const { session } = remote; | 8 | const { session } = remote; |
9 | 9 | ||
diff --git a/src/api/server/ServerApi.js b/src/api/server/ServerApi.js index f56c7b6e4..3d973e586 100644 --- a/src/api/server/ServerApi.js +++ b/src/api/server/ServerApi.js | |||
@@ -15,6 +15,7 @@ import OrderModel from '../../models/Order'; | |||
15 | import { sleep } from '../../helpers/async-helpers'; | 15 | import { sleep } from '../../helpers/async-helpers'; |
16 | 16 | ||
17 | import { API } from '../../environment'; | 17 | import { API } from '../../environment'; |
18 | import apiBase from '../apiBase'; | ||
18 | import { prepareAuthRequest, sendAuthRequest } from '../utils/auth'; | 19 | import { prepareAuthRequest, sendAuthRequest } from '../utils/auth'; |
19 | 20 | ||
20 | import { | 21 | import { |
@@ -27,7 +28,7 @@ import { | |||
27 | removeServicePartitionDirectory, | 28 | removeServicePartitionDirectory, |
28 | } from '../../helpers/service-helpers.js'; | 29 | } from '../../helpers/service-helpers.js'; |
29 | 30 | ||
30 | const debug = require('debug')('Franz:ServerApi'); | 31 | const debug = require('debug')('Ferdi:ServerApi'); |
31 | 32 | ||
32 | module.paths.unshift( | 33 | module.paths.unshift( |
33 | getDevRecipeDirectory(), | 34 | getDevRecipeDirectory(), |
@@ -38,8 +39,6 @@ const { app } = remote; | |||
38 | const { default: fetch } = remote.require('electron-fetch'); | 39 | const { default: fetch } = remote.require('electron-fetch'); |
39 | 40 | ||
40 | const SERVER_URL = API; | 41 | const SERVER_URL = API; |
41 | const API_VERSION = 'v1'; | ||
42 | const API_URL = `${SERVER_URL}/${API_VERSION}`; | ||
43 | 42 | ||
44 | export default class ServerApi { | 43 | export default class ServerApi { |
45 | recipePreviews = []; | 44 | recipePreviews = []; |
@@ -48,7 +47,7 @@ export default class ServerApi { | |||
48 | 47 | ||
49 | // User | 48 | // User |
50 | async login(email, passwordHash) { | 49 | async login(email, passwordHash) { |
51 | const request = await sendAuthRequest(`${API_URL}/auth/login`, { | 50 | const request = await sendAuthRequest(`${apiBase()}/auth/login`, { |
52 | method: 'POST', | 51 | method: 'POST', |
53 | headers: { | 52 | headers: { |
54 | Authorization: `Basic ${window.btoa(`${email}:${passwordHash}`)}`, | 53 | Authorization: `Basic ${window.btoa(`${email}:${passwordHash}`)}`, |
@@ -64,7 +63,7 @@ export default class ServerApi { | |||
64 | } | 63 | } |
65 | 64 | ||
66 | async signup(data) { | 65 | async signup(data) { |
67 | const request = await sendAuthRequest(`${API_URL}/auth/signup`, { | 66 | const request = await sendAuthRequest(`${apiBase()}/auth/signup`, { |
68 | method: 'POST', | 67 | method: 'POST', |
69 | body: JSON.stringify(data), | 68 | body: JSON.stringify(data), |
70 | }, false); | 69 | }, false); |
@@ -78,7 +77,7 @@ export default class ServerApi { | |||
78 | } | 77 | } |
79 | 78 | ||
80 | async activateTrial(data) { | 79 | async activateTrial(data) { |
81 | const request = await sendAuthRequest(`${API_URL}/payment/trial`, { | 80 | const request = await sendAuthRequest(`${apiBase()}/payment/trial`, { |
82 | method: 'POST', | 81 | method: 'POST', |
83 | body: JSON.stringify(data), | 82 | body: JSON.stringify(data), |
84 | }); | 83 | }); |
@@ -92,7 +91,7 @@ export default class ServerApi { | |||
92 | } | 91 | } |
93 | 92 | ||
94 | async inviteUser(data) { | 93 | async inviteUser(data) { |
95 | const request = await sendAuthRequest(`${API_URL}/invite`, { | 94 | const request = await sendAuthRequest(`${apiBase()}/invite`, { |
96 | method: 'POST', | 95 | method: 'POST', |
97 | body: JSON.stringify(data), | 96 | body: JSON.stringify(data), |
98 | }); | 97 | }); |
@@ -105,7 +104,7 @@ export default class ServerApi { | |||
105 | } | 104 | } |
106 | 105 | ||
107 | async retrievePassword(email) { | 106 | async retrievePassword(email) { |
108 | const request = await sendAuthRequest(`${API_URL}/auth/password`, { | 107 | const request = await sendAuthRequest(`${apiBase()}/auth/password`, { |
109 | method: 'POST', | 108 | method: 'POST', |
110 | body: JSON.stringify({ | 109 | body: JSON.stringify({ |
111 | email, | 110 | email, |
@@ -121,7 +120,7 @@ export default class ServerApi { | |||
121 | } | 120 | } |
122 | 121 | ||
123 | async userInfo() { | 122 | async userInfo() { |
124 | const request = await sendAuthRequest(`${API_URL}/me`); | 123 | const request = await sendAuthRequest(`${apiBase()}/me`); |
125 | if (!request.ok) { | 124 | if (!request.ok) { |
126 | throw request; | 125 | throw request; |
127 | } | 126 | } |
@@ -134,7 +133,7 @@ export default class ServerApi { | |||
134 | } | 133 | } |
135 | 134 | ||
136 | async updateUserInfo(data) { | 135 | async updateUserInfo(data) { |
137 | const request = await sendAuthRequest(`${API_URL}/me`, { | 136 | const request = await sendAuthRequest(`${apiBase()}/me`, { |
138 | method: 'PUT', | 137 | method: 'PUT', |
139 | body: JSON.stringify(data), | 138 | body: JSON.stringify(data), |
140 | }); | 139 | }); |
@@ -149,7 +148,7 @@ export default class ServerApi { | |||
149 | } | 148 | } |
150 | 149 | ||
151 | async deleteAccount() { | 150 | async deleteAccount() { |
152 | const request = await sendAuthRequest(`${API_URL}/me`, { | 151 | const request = await sendAuthRequest(`${apiBase()}/me`, { |
153 | method: 'DELETE', | 152 | method: 'DELETE', |
154 | }); | 153 | }); |
155 | if (!request.ok) { | 154 | if (!request.ok) { |
@@ -163,7 +162,7 @@ export default class ServerApi { | |||
163 | 162 | ||
164 | // Services | 163 | // Services |
165 | async getServices() { | 164 | async getServices() { |
166 | const request = await sendAuthRequest(`${API_URL}/me/services`); | 165 | const request = await sendAuthRequest(`${apiBase()}/me/services`); |
167 | if (!request.ok) { | 166 | if (!request.ok) { |
168 | throw request; | 167 | throw request; |
169 | } | 168 | } |
@@ -176,7 +175,7 @@ export default class ServerApi { | |||
176 | } | 175 | } |
177 | 176 | ||
178 | async createService(recipeId, data) { | 177 | async createService(recipeId, data) { |
179 | const request = await sendAuthRequest(`${API_URL}/service`, { | 178 | const request = await sendAuthRequest(`${apiBase()}/service`, { |
180 | method: 'POST', | 179 | method: 'POST', |
181 | body: JSON.stringify(Object.assign({ | 180 | body: JSON.stringify(Object.assign({ |
182 | recipeId, | 181 | recipeId, |
@@ -206,7 +205,7 @@ export default class ServerApi { | |||
206 | await this.uploadServiceIcon(serviceId, data.iconFile); | 205 | await this.uploadServiceIcon(serviceId, data.iconFile); |
207 | } | 206 | } |
208 | 207 | ||
209 | const request = await sendAuthRequest(`${API_URL}/service/${serviceId}`, { | 208 | const request = await sendAuthRequest(`${apiBase()}/service/${serviceId}`, { |
210 | method: 'PUT', | 209 | method: 'PUT', |
211 | body: JSON.stringify(data), | 210 | body: JSON.stringify(data), |
212 | }); | 211 | }); |
@@ -234,7 +233,7 @@ export default class ServerApi { | |||
234 | 233 | ||
235 | delete requestData.headers['Content-Type']; | 234 | delete requestData.headers['Content-Type']; |
236 | 235 | ||
237 | const request = await window.fetch(`${API_URL}/service/${serviceId}`, requestData); | 236 | const request = await window.fetch(`${apiBase()}/service/${serviceId}`, requestData); |
238 | 237 | ||
239 | if (!request.ok) { | 238 | if (!request.ok) { |
240 | throw request; | 239 | throw request; |
@@ -246,7 +245,7 @@ export default class ServerApi { | |||
246 | } | 245 | } |
247 | 246 | ||
248 | async reorderService(data) { | 247 | async reorderService(data) { |
249 | const request = await sendAuthRequest(`${API_URL}/service/reorder`, { | 248 | const request = await sendAuthRequest(`${apiBase()}/service/reorder`, { |
250 | method: 'PUT', | 249 | method: 'PUT', |
251 | body: JSON.stringify(data), | 250 | body: JSON.stringify(data), |
252 | }); | 251 | }); |
@@ -259,7 +258,7 @@ export default class ServerApi { | |||
259 | } | 258 | } |
260 | 259 | ||
261 | async deleteService(id) { | 260 | async deleteService(id) { |
262 | const request = await sendAuthRequest(`${API_URL}/service/${id}`, { | 261 | const request = await sendAuthRequest(`${apiBase()}/service/${id}`, { |
263 | method: 'DELETE', | 262 | method: 'DELETE', |
264 | }); | 263 | }); |
265 | if (!request.ok) { | 264 | if (!request.ok) { |
@@ -275,7 +274,7 @@ export default class ServerApi { | |||
275 | 274 | ||
276 | // Features | 275 | // Features |
277 | async getDefaultFeatures() { | 276 | async getDefaultFeatures() { |
278 | const request = await sendAuthRequest(`${API_URL}/features/default`); | 277 | const request = await sendAuthRequest(`${apiBase()}/features/default`); |
279 | if (!request.ok) { | 278 | if (!request.ok) { |
280 | throw request; | 279 | throw request; |
281 | } | 280 | } |
@@ -287,7 +286,7 @@ export default class ServerApi { | |||
287 | } | 286 | } |
288 | 287 | ||
289 | async getFeatures() { | 288 | async getFeatures() { |
290 | const request = await sendAuthRequest(`${API_URL}/features`); | 289 | const request = await sendAuthRequest(`${apiBase()}/features`); |
291 | if (!request.ok) { | 290 | if (!request.ok) { |
292 | throw request; | 291 | throw request; |
293 | } | 292 | } |
@@ -321,7 +320,7 @@ export default class ServerApi { | |||
321 | } | 320 | } |
322 | 321 | ||
323 | async getRecipeUpdates(recipeVersions) { | 322 | async getRecipeUpdates(recipeVersions) { |
324 | const request = await sendAuthRequest(`${API_URL}/recipes/update`, { | 323 | const request = await sendAuthRequest(`${apiBase()}/recipes/update`, { |
325 | method: 'POST', | 324 | method: 'POST', |
326 | body: JSON.stringify(recipeVersions), | 325 | body: JSON.stringify(recipeVersions), |
327 | }); | 326 | }); |
@@ -335,7 +334,7 @@ export default class ServerApi { | |||
335 | 334 | ||
336 | // Recipes Previews | 335 | // Recipes Previews |
337 | async getRecipePreviews() { | 336 | async getRecipePreviews() { |
338 | const request = await sendAuthRequest(`${API_URL}/recipes`); | 337 | const request = await sendAuthRequest(`${apiBase()}/recipes`); |
339 | if (!request.ok) throw request; | 338 | if (!request.ok) throw request; |
340 | const data = await request.json(); | 339 | const data = await request.json(); |
341 | const recipePreviews = this._mapRecipePreviewModel(data); | 340 | const recipePreviews = this._mapRecipePreviewModel(data); |
@@ -344,7 +343,7 @@ export default class ServerApi { | |||
344 | } | 343 | } |
345 | 344 | ||
346 | async getFeaturedRecipePreviews() { | 345 | async getFeaturedRecipePreviews() { |
347 | const request = await sendAuthRequest(`${API_URL}/recipes/popular`); | 346 | const request = await sendAuthRequest(`${apiBase()}/recipes/popular`); |
348 | if (!request.ok) throw request; | 347 | if (!request.ok) throw request; |
349 | 348 | ||
350 | const data = await request.json(); | 349 | const data = await request.json(); |
@@ -356,7 +355,7 @@ export default class ServerApi { | |||
356 | } | 355 | } |
357 | 356 | ||
358 | async searchRecipePreviews(needle) { | 357 | async searchRecipePreviews(needle) { |
359 | const url = `${API_URL}/recipes/search?needle=${needle}`; | 358 | const url = `${apiBase()}/recipes/search?needle=${needle}`; |
360 | const request = await sendAuthRequest(url); | 359 | const request = await sendAuthRequest(url); |
361 | if (!request.ok) throw request; | 360 | if (!request.ok) throw request; |
362 | 361 | ||
@@ -371,7 +370,7 @@ export default class ServerApi { | |||
371 | const recipesDirectory = path.join(app.getPath('userData'), 'recipes'); | 370 | const recipesDirectory = path.join(app.getPath('userData'), 'recipes'); |
372 | const recipeTempDirectory = path.join(recipesDirectory, 'temp', recipeId); | 371 | const recipeTempDirectory = path.join(recipesDirectory, 'temp', recipeId); |
373 | const archivePath = path.join(recipeTempDirectory, 'recipe.tar.gz'); | 372 | const archivePath = path.join(recipeTempDirectory, 'recipe.tar.gz'); |
374 | const packageUrl = `${API_URL}/recipes/download/${recipeId}`; | 373 | const packageUrl = `${apiBase()}/recipes/download/${recipeId}`; |
375 | 374 | ||
376 | fs.ensureDirSync(recipeTempDirectory); | 375 | fs.ensureDirSync(recipeTempDirectory); |
377 | const res = await fetch(packageUrl); | 376 | const res = await fetch(packageUrl); |
@@ -408,7 +407,7 @@ export default class ServerApi { | |||
408 | 407 | ||
409 | // Payment | 408 | // Payment |
410 | async getPlans() { | 409 | async getPlans() { |
411 | const request = await sendAuthRequest(`${API_URL}/payment/plans`); | 410 | const request = await sendAuthRequest(`${apiBase()}/payment/plans`); |
412 | if (!request.ok) throw request; | 411 | if (!request.ok) throw request; |
413 | const data = await request.json(); | 412 | const data = await request.json(); |
414 | const plan = new PlanModel(data); | 413 | const plan = new PlanModel(data); |
@@ -417,7 +416,7 @@ export default class ServerApi { | |||
417 | } | 416 | } |
418 | 417 | ||
419 | async getHostedPage(planId) { | 418 | async getHostedPage(planId) { |
420 | const request = await sendAuthRequest(`${API_URL}/payment/init`, { | 419 | const request = await sendAuthRequest(`${apiBase()}/payment/init`, { |
421 | method: 'POST', | 420 | method: 'POST', |
422 | body: JSON.stringify({ | 421 | body: JSON.stringify({ |
423 | planId, | 422 | planId, |
@@ -434,7 +433,7 @@ export default class ServerApi { | |||
434 | 433 | ||
435 | // News | 434 | // News |
436 | async getLatestNews() { | 435 | async getLatestNews() { |
437 | const url = `${API_URL}/news?platform=${os.platform()}&arch=${os.arch()}&version=${app.getVersion()}`; | 436 | const url = `${apiBase()}/news?platform=${os.platform()}&arch=${os.arch()}&version=${app.getVersion()}`; |
438 | const request = await sendAuthRequest(url); | 437 | const request = await sendAuthRequest(url); |
439 | if (!request.ok) throw request; | 438 | if (!request.ok) throw request; |
440 | const data = await request.json(); | 439 | const data = await request.json(); |
@@ -444,7 +443,7 @@ export default class ServerApi { | |||
444 | } | 443 | } |
445 | 444 | ||
446 | async hideNews(id) { | 445 | async hideNews(id) { |
447 | const request = await sendAuthRequest(`${API_URL}/news/${id}/read`); | 446 | const request = await sendAuthRequest(`${apiBase()}/news/${id}/read`); |
448 | if (!request.ok) throw request; | 447 | if (!request.ok) throw request; |
449 | debug('ServerApi::hideNews resolves', id); | 448 | debug('ServerApi::hideNews resolves', id); |
450 | } | 449 | } |
@@ -469,7 +468,7 @@ export default class ServerApi { | |||
469 | if (Object.prototype.hasOwnProperty.call(config, 'services')) { | 468 | if (Object.prototype.hasOwnProperty.call(config, 'services')) { |
470 | const services = await Promise.all(config.services.map(async (s) => { | 469 | const services = await Promise.all(config.services.map(async (s) => { |
471 | const service = s; | 470 | const service = s; |
472 | const request = await sendAuthRequest(`${API_URL}/recipes/${s.service}`); | 471 | const request = await sendAuthRequest(`${apiBase()}/recipes/${s.service}`); |
473 | 472 | ||
474 | if (request.status === 200) { | 473 | if (request.status === 200) { |
475 | const data = await request.json(); | 474 | const data = await request.json(); |