diff options
author | 2021-06-03 19:01:01 +0200 | |
---|---|---|
committer | 2021-06-03 19:01:01 +0200 | |
commit | 2ad39ffb1cb0d0e5f79d6948f798ca79ed73c76c (patch) | |
tree | dcb679119cf4963126a3520b7c62ae4b032e0225 /src/models | |
parent | Upgraded electron to '13.1.0'. (diff) | |
download | ferdium-app-2ad39ffb1cb0d0e5f79d6948f798ca79ed73c76c.tar.gz ferdium-app-2ad39ffb1cb0d0e5f79d6948f798ca79ed73c76c.tar.zst ferdium-app-2ad39ffb1cb0d0e5f79d6948f798ca79ed73c76c.zip |
* 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.js | 39 | ||||
-rw-r--r-- | src/models/UserAgent.js | 80 |
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'; | |||
4 | import normalizeUrl from 'normalize-url'; | 4 | import normalizeUrl from 'normalize-url'; |
5 | import path from 'path'; | 5 | import path from 'path'; |
6 | 6 | ||
7 | import userAgent from '../helpers/userAgent-helpers'; | ||
8 | import { TODOS_RECIPE_ID, todosStore } from '../features/todos'; | 7 | import { TODOS_RECIPE_ID, todosStore } from '../features/todos'; |
9 | import { isValidExternalURL } from '../helpers/url-helpers'; | 8 | import { isValidExternalURL } from '../helpers/url-helpers'; |
9 | import UserAgent from './UserAgent'; | ||
10 | 10 | ||
11 | const debug = require('debug')('Ferdi:Service'); | 11 | const 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 @@ | |||
1 | import { | ||
2 | action, | ||
3 | computed, | ||
4 | observe, | ||
5 | observable, | ||
6 | } from 'mobx'; | ||
7 | |||
8 | import defaultUserAgent, { isChromeless } from '../helpers/userAgent-helpers'; | ||
9 | |||
10 | const debug = require('debug')('Ferdi:UserAgent'); | ||
11 | |||
12 | export 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 | } | ||