aboutsummaryrefslogtreecommitdiffstats
path: root/src/models
diff options
context:
space:
mode:
authorLibravatar Kristóf Marussy <kristof@marussy.com>2021-06-03 19:01:01 +0200
committerLibravatar GitHub <noreply@github.com>2021-06-03 19:01:01 +0200
commit2ad39ffb1cb0d0e5f79d6948f798ca79ed73c76c (patch)
treedcb679119cf4963126a3520b7c62ae4b032e0225 /src/models
parentUpgraded electron to '13.1.0'. (diff)
downloadferdium-app-2ad39ffb1cb0d0e5f79d6948f798ca79ed73c76c.tar.gz
ferdium-app-2ad39ffb1cb0d0e5f79d6948f798ca79ed73c76c.tar.zst
ferdium-app-2ad39ffb1cb0d0e5f79d6948f798ca79ed73c76c.zip
Expose Chrome version to todos webview (fix #1211) (#1478)
* Expose Chrome version to todos webview (fix #1211) The TickTick todo service fails to load if the Chrome version number does not appear in the User-Agent string. However, login to Google Tasks is prevented by the same. We adopt the "chromeless" User-Agent logic from the service webview, which selectively exposes the Chrome version everywhere except the Google login screen. The common logic was moved into the userAgent-helpers module. * Refactor user agent switching * "Chromeless" user agent switching is extracted into a separate model * Both the service and the todos webview uses the same model
Diffstat (limited to 'src/models')
-rw-r--r--src/models/Service.js39
-rw-r--r--src/models/UserAgent.js80
2 files changed, 88 insertions, 31 deletions
diff --git a/src/models/Service.js b/src/models/Service.js
index b01881beb..0d1dff431 100644
--- a/src/models/Service.js
+++ b/src/models/Service.js
@@ -4,9 +4,9 @@ import { webContents } from '@electron/remote';
4import normalizeUrl from 'normalize-url'; 4import normalizeUrl from 'normalize-url';
5import path from 'path'; 5import path from 'path';
6 6
7import userAgent from '../helpers/userAgent-helpers';
8import { TODOS_RECIPE_ID, todosStore } from '../features/todos'; 7import { TODOS_RECIPE_ID, todosStore } from '../features/todos';
9import { isValidExternalURL } from '../helpers/url-helpers'; 8import { isValidExternalURL } from '../helpers/url-helpers';
9import UserAgent from './UserAgent';
10 10
11const debug = require('debug')('Ferdi:Service'); 11const debug = require('debug')('Ferdi:Service');
12 12
@@ -94,7 +94,7 @@ export default class Service {
94 94
95 @observable lostRecipeReloadAttempt = 0; 95 @observable lostRecipeReloadAttempt = 0;
96 96
97 @observable chromelessUserAgent = false; 97 @observable userAgentModel = null;
98 98
99 constructor(data, recipe) { 99 constructor(data, recipe) {
100 if (!data) { 100 if (!data) {
@@ -156,6 +156,8 @@ export default class Service {
156 this.isHibernating = true; 156 this.isHibernating = true;
157 } 157 }
158 158
159 this.userAgentModel = new UserAgent(recipe.overrideUserAgent);
160
159 autorun(() => { 161 autorun(() => {
160 if (!this.isEnabled) { 162 if (!this.isEnabled) {
161 this.webview = null; 163 this.webview = null;
@@ -234,12 +236,7 @@ export default class Service {
234 } 236 }
235 237
236 @computed get userAgent() { 238 @computed get userAgent() {
237 let ua = userAgent(this.chromelessUserAgent); 239 return this.userAgentModel.userAgent;
238 if (typeof this.recipe.overrideUserAgent === 'function') {
239 ua = this.recipe.overrideUserAgent();
240 }
241
242 return ua;
243 } 240 }
244 241
245 @computed get partition() { 242 @computed get partition() {
@@ -250,6 +247,8 @@ export default class Service {
250 initializeWebViewEvents({ handleIPCMessage, openWindow, stores }) { 247 initializeWebViewEvents({ handleIPCMessage, openWindow, stores }) {
251 const webviewWebContents = webContents.fromId(this.webview.getWebContentsId()); 248 const webviewWebContents = webContents.fromId(this.webview.getWebContentsId());
252 249
250 this.userAgentModel.setWebviewReference(this.webview);
251
253 // If the recipe has implemented modifyRequestHeaders, 252 // If the recipe has implemented modifyRequestHeaders,
254 // Send those headers to ipcMain so that it can be set in session 253 // Send those headers to ipcMain so that it can be set in session
255 if (typeof this.recipe.modifyRequestHeaders === 'function') { 254 if (typeof this.recipe.modifyRequestHeaders === 'function') {
@@ -263,23 +262,6 @@ export default class Service {
263 debug(this.name, 'modifyRequestHeaders is not defined in the recipe'); 262 debug(this.name, 'modifyRequestHeaders is not defined in the recipe');
264 } 263 }
265 264
266 const handleUserAgent = (url, forwardingHack = false) => {
267 if (url.startsWith('https://accounts.google.com')) {
268 if (!this.chromelessUserAgent) {
269 debug('Setting user agent to chromeless for url', url);
270 this.webview.setUserAgent(userAgent(true));
271 if (forwardingHack) {
272 this.webview.loadURL(url);
273 }
274 this.chromelessUserAgent = true;
275 }
276 } else if (this.chromelessUserAgent) {
277 debug('Setting user agent to contain chrome');
278 this.webview.setUserAgent(this.userAgent);
279 this.chromelessUserAgent = false;
280 }
281 };
282
283 this.webview.addEventListener('ipc-message', e => handleIPCMessage({ 265 this.webview.addEventListener('ipc-message', e => handleIPCMessage({
284 serviceId: this.id, 266 serviceId: this.id,
285 channel: e.channel, 267 channel: e.channel,
@@ -306,8 +288,6 @@ export default class Service {
306 } 288 }
307 }); 289 });
308 290
309 this.webview.addEventListener('will-navigate', event => handleUserAgent(event.url, true));
310
311 this.webview.addEventListener('did-start-loading', (event) => { 291 this.webview.addEventListener('did-start-loading', (event) => {
312 debug('Did start load', this.name, event); 292 debug('Did start load', this.name, event);
313 293
@@ -325,10 +305,7 @@ export default class Service {
325 }; 305 };
326 306
327 this.webview.addEventListener('did-frame-finish-load', didLoad.bind(this)); 307 this.webview.addEventListener('did-frame-finish-load', didLoad.bind(this));
328 this.webview.addEventListener('did-navigate', (event) => { 308 this.webview.addEventListener('did-navigate', didLoad.bind(this));
329 handleUserAgent(event.url);
330 didLoad();
331 });
332 309
333 this.webview.addEventListener('did-fail-load', (event) => { 310 this.webview.addEventListener('did-fail-load', (event) => {
334 debug('Service failed to load', this.name, event); 311 debug('Service failed to load', this.name, event);
diff --git a/src/models/UserAgent.js b/src/models/UserAgent.js
new file mode 100644
index 000000000..f51f2e5a6
--- /dev/null
+++ b/src/models/UserAgent.js
@@ -0,0 +1,80 @@
1import {
2 action,
3 computed,
4 observe,
5 observable,
6} from 'mobx';
7
8import defaultUserAgent, { isChromeless } from '../helpers/userAgent-helpers';
9
10const debug = require('debug')('Ferdi:UserAgent');
11
12export default class UserAgent {
13 _willNavigateListener = null;
14
15 _didNavigateListener = null;
16
17 @observable.ref webview = null;
18
19 @observable chromelessUserAgent = false;
20
21 @observable getUserAgent = defaultUserAgent;
22
23 constructor(overrideUserAgent = null) {
24 if (typeof overrideUserAgent === 'function') {
25 this.getUserAgent = overrideUserAgent;
26 }
27
28 observe(this, 'webview', (change) => {
29 const { oldValue, newValue } = change;
30 if (oldValue !== null) {
31 this._removeWebviewEvents(oldValue);
32 }
33 if (newValue !== null) {
34 this._addWebviewEvents(newValue);
35 }
36 });
37 }
38
39 @computed get userAgent() {
40 return this.chromelessUserAgent ? defaultUserAgent(true) : this.getUserAgent();
41 }
42
43 @action setWebviewReference(webview) {
44 this.webview = webview;
45 }
46
47 @action _handleNavigate(url, forwardingHack = false) {
48 if (isChromeless(url)) {
49 if (!this.chromelessUserAgent) {
50 debug('Setting user agent to chromeless for url', url);
51 this.chromelessUserAgent = true;
52 this.webview.userAgent = this.userAgent;
53 if (forwardingHack) {
54 this.webview.loadURL(url);
55 }
56 }
57 } else if (this.chromelessUserAgent) {
58 debug('Setting user agent to contain chrome for url', url);
59 this.chromelessUserAgent = false;
60 this.webview.userAgent = this.userAgent;
61 }
62 }
63
64 _addWebviewEvents(webview) {
65 debug('Adding event handlers');
66
67 this._willNavigateListener = event => this._handleNavigate(event.url, true);
68 webview.addEventListener('will-navigate', this._willNavigateListener);
69
70 this._didNavigateListener = event => this._handleNavigate(event.url);
71 webview.addEventListener('did-navigate', this._didNavigateListener);
72 }
73
74 _removeWebviewEvents(webview) {
75 debug('Removing event handlers');
76
77 webview.removeEventListener('will-navigate', this._willNavigateListener);
78 webview.removeEventListener('did-navigate', this._didNavigateListener);
79 }
80}