cozy-harvest-lib 32.4.4 → 32.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -3,6 +3,16 @@
3
3
  All notable changes to this project will be documented in this file.
4
4
  See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
5
5
 
6
+ # [32.5.0](https://github.com/cozy/cozy-libs/compare/cozy-harvest-lib@32.4.5...cozy-harvest-lib@32.5.0) (2025-09-01)
7
+
8
+ ### Features
9
+
10
+ - Remove usage of useless isMobileApp method ([e26ce64](https://github.com/cozy/cozy-libs/commit/e26ce64c2a6231aaab09ba04e28e31a1262bd0fd))
11
+
12
+ ## [32.4.5](https://github.com/cozy/cozy-libs/compare/cozy-harvest-lib@32.4.4...cozy-harvest-lib@32.4.5) (2025-08-21)
13
+
14
+ **Note:** Version bump only for package cozy-harvest-lib
15
+
6
16
  ## [32.4.4](https://github.com/cozy/cozy-libs/compare/cozy-harvest-lib@32.4.3...cozy-harvest-lib@32.4.4) (2025-08-19)
7
17
 
8
18
  **Note:** Version bump only for package cozy-harvest-lib
@@ -10,45 +10,6 @@ var OAUTH_POPUP_WIDTH = 800;
10
10
  export var OAUTH_SERVICE_CLOSED = 'CLOSED';
11
11
  export var OAUTH_SERVICE_ERROR = 'ERROR';
12
12
  export var OAUTH_SERVICE_OK = 'OK';
13
- /**
14
- * Monitor URL changes for mobile apps and in app browsers
15
- * @param {import('cozy-client/types/types').KonnectorsDoctype} konnector
16
- *
17
- * The provider redirect us to something like : oauthcallback.mycozy.cloud/?account=A&state=b
18
- * So we listen to the URL change with these informations, and we try to handle it.
19
- * It works well on iOS or when we are logged on the same device on the web, but it will
20
- * fail on Android if we're ne logged in the browser. Why ?
21
- * Our oauthcallback.mycozy.cloud/?account=A&state=b checks if we're logged, if not the server
22
- * sends an http redirect.
23
- * On Android, the 'loadstart' event is not dispatched by the browser when it get a redirect.
24
- * The inAppBrowser follows the URL and arrive on :
25
- * https://my.mycozy.cloud/auth?redirect=https://home.cozy.cloud/?account=a&state=b
26
- * So if we don't have account & state searchParams we have to check if we've a redirect searchParams
27
- * init it and search if we have inside this url an account and state params
28
- */
29
-
30
- function handleUrlChange(konnector) {
31
- return function (resolve) {
32
- return function (event) {
33
- var url = event.url;
34
- var oAuthData = extractOAuthDataFromUrl(url);
35
-
36
- if (oAuthData) {
37
- return handleOAuthData(oAuthData, konnector, resolve);
38
- }
39
-
40
- var redirect = url.searchParams.get('redirect');
41
-
42
- if (redirect) {
43
- var redirectOAuthData = extractOAuthDataFromUrl(new URL(redirect));
44
-
45
- if (redirectOAuthData) {
46
- return handleOAuthData(redirectOAuthData, konnector, resolve);
47
- }
48
- }
49
- };
50
- };
51
- }
52
13
  /**
53
14
  * Handles OAuth data. OAuth data may be provided by different way:
54
15
  * * realtime message from web apps (see handleMessage)
@@ -60,7 +21,6 @@ function handleUrlChange(konnector) {
60
21
  * @returns <void>
61
22
  */
62
23
 
63
-
64
24
  function handleOAuthData(data, konnector, resolve) {
65
25
  if (!checkOAuthData(konnector, data)) return;
66
26
 
@@ -87,34 +47,6 @@ function handleOAuthData(data, konnector, resolve) {
87
47
  * @property {String} [finalLocation] - final query string added to the redirected url
88
48
  */
89
49
 
90
- /**
91
- * Extract OAuthData from url search params if any
92
- *
93
- * @param {URL} url
94
- * @returns {OAuthData|null} OAuthData
95
- */
96
-
97
-
98
- function extractOAuthDataFromUrl(url) {
99
- var account = url.searchParams.get('account');
100
- var state = url.searchParams.get('state');
101
- var error = url.searchParams.get('error');
102
-
103
- if (account && state) {
104
- var oAuthData = {
105
- key: account,
106
- oAuthStateKey: state
107
- };
108
-
109
- if (error) {
110
- oAuthData.error = error;
111
- }
112
-
113
- return oAuthData;
114
- }
115
-
116
- return null;
117
- }
118
50
  /**
119
51
  * @typedef OAuthServiceResult
120
52
  * @property {"OK"|"CLOSED"|"ERROR"} result
@@ -443,7 +375,6 @@ export function openOAuthWindow(_ref5) {
443
375
  title: title || '',
444
376
  width: OAUTH_POPUP_WIDTH,
445
377
  height: OAUTH_POPUP_HEIGHT,
446
- handleUrlChange: handleUrlChange(konnector),
447
378
  registerRealtime: registerRealtime({
448
379
  konnector: konnector,
449
380
  client: client
@@ -9,7 +9,7 @@ function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { va
9
9
  import util from 'util';
10
10
  import { openOAuthWindow, OAUTH_SERVICE_OK } from 'components/OAuthService';
11
11
  import MicroEE from 'microee';
12
- import { isMobileApp, isFlagshipApp } from 'cozy-device-helper';
12
+ import { isFlagshipApp } from 'cozy-device-helper';
13
13
  import { OAUTH_REALTIME_CHANNEL, terminateOAuth } from '../helpers/oauth';
14
14
  import PopupMock from '../helpers/windowWrapperMocks';
15
15
  jest.mock('../helpers/oauth', function () {
@@ -69,7 +69,6 @@ var client = {
69
69
  };
70
70
  jest.mock('cozy-device-helper', function () {
71
71
  return {
72
- isMobileApp: jest.fn(),
73
72
  isFlagshipApp: jest.fn()
74
73
  };
75
74
  });
@@ -156,94 +155,15 @@ describe('OAuthService', function () {
156
155
  }, _callee);
157
156
  })));
158
157
  });
159
- describe('with intentsApi', function () {
160
- beforeEach(function () {
161
- isMobileApp.mockReturnValue(true);
162
- });
163
- it('should render', /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee2() {
164
- var closePromise, intentsApi, promise, result;
165
- return _regeneratorRuntime.wrap(function _callee2$(_context2) {
166
- while (1) {
167
- switch (_context2.prev = _context2.next) {
168
- case 0:
169
- closePromise = new Promise(function () {});
170
- intentsApi = {
171
- fetchSessionCode: jest.fn().mockResolvedValue('somesessioncode'),
172
- showInAppBrowser: jest.fn().mockImplementation(function () {
173
- return closePromise;
174
- }),
175
- closeInAppBrowser: jest.fn().mockResolvedValue()
176
- };
177
- promise = openOAuthWindow({
178
- client: client,
179
- konnector: {
180
- slug: 'ameli'
181
- },
182
- redirectSlug: 'home',
183
- extraParams: {
184
- extraParam1: 'extraParamValue'
185
- },
186
- title: 'popup title',
187
- account: {
188
- _id: 'someaccountid'
189
- },
190
- intentsApi: intentsApi
191
- });
192
- expect(isPending(promise)).toBe(true);
193
- expect(terminateOAuth).not.toHaveBeenCalled();
194
- _context2.next = 7;
195
- return sleep(100);
196
-
197
- case 7:
198
- // lets time to show inAppBrowser before realtime event occurs
199
- mockCozyRealtime.emitRealtimeEvent('notified', 'io.cozy.accounts', OAUTH_REALTIME_CHANNEL, {
200
- _id: 'oauth-popup',
201
- data: {
202
- error: null,
203
- finalLocation: 'connection_id=194&state=someuuid',
204
- key: null,
205
- oAuthStateKey: 'someuuid'
206
- }
207
- });
208
- _context2.next = 10;
209
- return promise;
210
-
211
- case 10:
212
- result = _context2.sent;
213
- expect(result).toStrictEqual({
214
- result: OAUTH_SERVICE_OK,
215
- key: null,
216
- data: {
217
- error: null,
218
- finalLocation: 'connection_id=194&state=someuuid',
219
- key: null,
220
- oAuthStateKey: 'someuuid'
221
- }
222
- });
223
- expect(terminateOAuth).toHaveBeenCalled();
224
- expect(intentsApi.fetchSessionCode).toHaveBeenCalledTimes(1);
225
- expect(intentsApi.showInAppBrowser).toHaveBeenCalled(); // TODO test url mock nonce
226
-
227
- expect(intentsApi.closeInAppBrowser).toHaveBeenCalled();
228
-
229
- case 16:
230
- case "end":
231
- return _context2.stop();
232
- }
233
- }
234
- }, _callee2);
235
- })));
236
- });
237
158
  describe('on web', function () {
238
159
  beforeEach(function () {
239
- isMobileApp.mockReturnValue(false);
240
160
  isFlagshipApp.mockReturnValue(false);
241
161
  });
242
- it('should render', /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee3() {
162
+ it('should render', /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee2() {
243
163
  var promise, result;
244
- return _regeneratorRuntime.wrap(function _callee3$(_context3) {
164
+ return _regeneratorRuntime.wrap(function _callee2$(_context2) {
245
165
  while (1) {
246
- switch (_context3.prev = _context3.next) {
166
+ switch (_context2.prev = _context2.next) {
247
167
  case 0:
248
168
  promise = openOAuthWindow({
249
169
  client: client,
@@ -270,11 +190,11 @@ describe('OAuthService', function () {
270
190
  oAuthStateKey: 'someuuid'
271
191
  }
272
192
  });
273
- _context3.next = 6;
193
+ _context2.next = 6;
274
194
  return promise;
275
195
 
276
196
  case 6:
277
- result = _context3.sent;
197
+ result = _context2.sent;
278
198
  expect(result).toStrictEqual({
279
199
  result: OAUTH_SERVICE_OK,
280
200
  key: null,
@@ -289,10 +209,10 @@ describe('OAuthService', function () {
289
209
 
290
210
  case 9:
291
211
  case "end":
292
- return _context3.stop();
212
+ return _context2.stop();
293
213
  }
294
214
  }
295
- }, _callee3);
215
+ }, _callee2);
296
216
  })));
297
217
  });
298
218
  });
@@ -300,10 +220,4 @@ describe('OAuthService', function () {
300
220
 
301
221
  var isPending = function isPending(promise) {
302
222
  return util.inspect(promise).includes('pending');
303
- };
304
-
305
- function sleep(ms) {
306
- return new Promise(function (resolve) {
307
- return setTimeout(resolve, ms);
308
- });
309
- }
223
+ };
@@ -11,7 +11,6 @@ function _isNativeReflectConstruct() { if (typeof Reflect === "undefined" || !Re
11
11
 
12
12
  import PropTypes from 'prop-types';
13
13
  import { PureComponent } from 'react';
14
- import { isMobileApp } from 'cozy-device-helper';
15
14
  /**
16
15
  * Customized function to get dimensions and position for a centered
17
16
  * popup window
@@ -73,24 +72,6 @@ export var Popup = /*#__PURE__*/function (_PureComponent) {
73
72
  value: function componentWillUnmount() {
74
73
  this.killPopup();
75
74
  }
76
- }, {
77
- key: "addListeners",
78
- value: function addListeners(popup) {
79
- // rest of instructions only on mobile app
80
- if (!isMobileApp()) return;
81
- popup.addEventListener('loadstart', this.handleUrlChange);
82
- popup.addEventListener('exit', this.handleClose);
83
- }
84
- }, {
85
- key: "removeListeners",
86
- value: function removeListeners(popup) {
87
- // rest of instructions only if popup is still opened
88
- if (popup.closed) return; // rest of instructions only on mobile app
89
-
90
- if (!isMobileApp()) return;
91
- popup.removeEventListener('loadstart', this.handleUrlChange);
92
- popup.removeEventListener('exit', this.handleClose);
93
- }
94
75
  }, {
95
76
  key: "handleClose",
96
77
  value: function handleClose(popup) {
@@ -131,7 +112,6 @@ export var Popup = /*#__PURE__*/function (_PureComponent) {
131
112
  popup.focus();
132
113
  }
133
114
 
134
- this.addListeners(popup);
135
115
  this.startMonitoringClosing(popup);
136
116
  this.setState({
137
117
  popup: popup
@@ -141,7 +121,6 @@ export var Popup = /*#__PURE__*/function (_PureComponent) {
141
121
  key: "killPopup",
142
122
  value: function killPopup() {
143
123
  var popup = this.state.popup;
144
- this.removeListeners(popup);
145
124
  this.stopMonitoringClosing();
146
125
  if (!popup.closed) popup.close();
147
126
  }
@@ -1,5 +1,4 @@
1
1
  // @ts-check
2
- import { isMobileApp } from 'cozy-device-helper';
3
2
  import { popupCenter } from './Popup';
4
3
  import { windowOpen } from '../helpers/windowWrapper';
5
4
  /**
@@ -15,7 +14,6 @@ import { windowOpen } from '../helpers/windowWrapper';
15
14
  * @param {String} options.title - Title of the popup
16
15
  * @param {Number} options.width - Width of the popup
17
16
  * @param {Number} options.height - Height of the popup
18
- * @param {Function} options.handleUrlChange - Function to call when popup url changes
19
17
  * @param {Function} options.registerRealtime - Function to call to register realtime events
20
18
  * @returns {Promise<OpenWindowResult>}
21
19
  */
@@ -25,7 +23,6 @@ export function openWindow(_ref) {
25
23
  title = _ref.title,
26
24
  width = _ref.width,
27
25
  height = _ref.height,
28
- handleUrlChange = _ref.handleUrlChange,
29
26
  registerRealtime = _ref.registerRealtime;
30
27
 
31
28
  var _popupCenter = popupCenter(width, height),
@@ -49,10 +46,6 @@ export function openWindow(_ref) {
49
46
  var unregisterRealtime;
50
47
 
51
48
  var cleanAndResolve = function cleanAndResolve(data) {
52
- if (handleUrlChange) {
53
- removeListeners(popup, handleUrlChange);
54
- }
55
-
56
49
  stopMonitoringClosing(checkClosedInterval);
57
50
 
58
51
  if (registerRealtime) {
@@ -63,10 +56,6 @@ export function openWindow(_ref) {
63
56
  resolve(data);
64
57
  };
65
58
 
66
- if (handleUrlChange) {
67
- addListeners(popup, cleanAndResolve, handleUrlChange);
68
- }
69
-
70
59
  if (registerRealtime) {
71
60
  unregisterRealtime = registerRealtime(cleanAndResolve);
72
61
  }
@@ -113,50 +102,4 @@ function startMonitoringClosing(popup, resolve) {
113
102
 
114
103
  function stopMonitoringClosing(checkClosedInterval) {
115
104
  clearInterval(checkClosedInterval);
116
- }
117
- /**
118
- * Removes all listeners
119
- *
120
- * @param {Object} popup - Current popup
121
- * @param {Function} handleUrlChange - handleUrlChange function not to listen anymore
122
- * @returns <void>
123
- */
124
-
125
-
126
- function removeListeners(popup, handleUrlChange) {
127
- // rest of instructions only if popup is still opened
128
- if (popup.closed) return; // rest of instructions only on mobile app
129
-
130
- if (!isMobileApp()) return;
131
- popup.removeEventListener('loadstart', handleUrlChange);
132
- popup.removeEventListener('exit', handleClose);
133
- }
134
- /**
135
- * Add listeners
136
- *
137
- * @param {Object} popup
138
- * @param {Function} resolve
139
- * @param {Function} handleUrlChange
140
- * @returns <void>
141
- */
142
-
143
-
144
- function addListeners(popup, resolve, handleUrlChange) {
145
- // rest of instructions only on mobile app
146
- if (!isMobileApp()) return;
147
- popup.addEventListener('loadstart', handleUrlChange(resolve));
148
- popup.addEventListener('exit', handleClose(resolve));
149
- }
150
- /**
151
- * Function called when the popup is closed
152
- *
153
- * @param {Function} resolve
154
- * @returns {Function}
155
- */
156
-
157
-
158
- function handleClose(resolve) {
159
- return function (popup) {
160
- resolve(popup);
161
- };
162
105
  }
@@ -2,7 +2,6 @@ import _asyncToGenerator from "@babel/runtime/helpers/asyncToGenerator";
2
2
  import _regeneratorRuntime from "@babel/runtime/regenerator";
3
3
  import util from 'util';
4
4
  import { openWindow } from 'components/PopupService';
5
- import { isMobileApp } from 'cozy-device-helper';
6
5
  import PopupMock from '../helpers/windowWrapperMocks';
7
6
  var mockPopup = new PopupMock();
8
7
  jest.mock('../helpers/windowWrapper', function () {
@@ -12,15 +11,8 @@ jest.mock('../helpers/windowWrapper', function () {
12
11
  })
13
12
  };
14
13
  });
15
- jest.mock('cozy-device-helper', function () {
16
- return {
17
- isMobileApp: jest.fn()
18
- };
19
- });
20
14
  describe('PopupService', function () {
21
15
  describe('openWindow', function () {
22
- var handleUrlChange = jest.fn();
23
- var handleUrlChangeWrapper = jest.fn().mockReturnValue(handleUrlChange);
24
16
  var unregisterRealtime = jest.fn();
25
17
  var registerRealtime = jest.fn().mockReturnValue(unregisterRealtime);
26
18
  beforeEach(function () {
@@ -29,47 +21,34 @@ describe('PopupService', function () {
29
21
  afterEach(function () {
30
22
  jest.clearAllMocks();
31
23
  });
32
- describe('on Cordova', function () {
33
- beforeEach(function () {
34
- isMobileApp.mockReturnValue(true);
35
- });
24
+ describe('on web', function () {
36
25
  it('should render', /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee() {
37
26
  var promise, result;
38
27
  return _regeneratorRuntime.wrap(function _callee$(_context) {
39
28
  while (1) {
40
29
  switch (_context.prev = _context.next) {
41
30
  case 0:
42
- promise = openWindow({
43
- url: 'http://cozy.tools',
44
- title: 'SOME_TITLE',
45
- width: '20',
46
- height: '30',
47
- handleUrlChange: handleUrlChangeWrapper
48
- });
31
+ promise = openWindow('http://cozy.tools', 'SOME_TITLE', 'SOME_OPTIONS');
49
32
  expect(mockPopup.focus).toHaveBeenCalled();
50
- expect(mockPopup.addEventListener).toHaveBeenCalledWith('loadstart', expect.anything());
51
- expect(mockPopup.addEventListener).toHaveBeenCalledWith('exit', expect.anything());
52
33
  expect(isPending(promise)).toBeTruthy();
53
- mockPopup.emit('exit', {
54
- POPUP: 'data'
55
- });
56
- _context.next = 8;
34
+ mockPopup.close();
35
+ _context.next = 6;
57
36
  return promise;
58
37
 
59
- case 8:
38
+ case 6:
60
39
  result = _context.sent;
61
40
  expect(result).toStrictEqual({
62
- POPUP: 'data'
41
+ result: 'CLOSED'
63
42
  });
64
43
 
65
- case 10:
44
+ case 8:
66
45
  case "end":
67
46
  return _context.stop();
68
47
  }
69
48
  }
70
49
  }, _callee);
71
50
  })));
72
- it('should call handUrlChange', /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee2() {
51
+ it('should accept registerRealtime parameter', /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee2() {
73
52
  var promise, result;
74
53
  return _regeneratorRuntime.wrap(function _callee2$(_context2) {
75
54
  while (1) {
@@ -80,100 +59,28 @@ describe('PopupService', function () {
80
59
  title: 'SOME_TITLE',
81
60
  width: '20',
82
61
  height: '30',
83
- handleUrlChange: handleUrlChangeWrapper
84
- });
85
- expect(isPending(promise)).toBeTruthy();
86
- mockPopup.emit('loadstart', 'HELLO');
87
- expect(handleUrlChangeWrapper).toHaveBeenCalled();
88
- expect(handleUrlChange).toHaveBeenCalledWith('HELLO');
89
- mockPopup.emit('exit', {
90
- POPUP: 'data'
91
- });
92
- _context2.next = 8;
93
- return promise;
94
-
95
- case 8:
96
- result = _context2.sent;
97
- expect(result).toStrictEqual({
98
- POPUP: 'data'
99
- });
100
-
101
- case 10:
102
- case "end":
103
- return _context2.stop();
104
- }
105
- }
106
- }, _callee2);
107
- })));
108
- });
109
- describe('on web', function () {
110
- beforeEach(function () {
111
- isMobileApp.mockReturnValue(false);
112
- });
113
- it('should render', /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee3() {
114
- var promise, result;
115
- return _regeneratorRuntime.wrap(function _callee3$(_context3) {
116
- while (1) {
117
- switch (_context3.prev = _context3.next) {
118
- case 0:
119
- promise = openWindow('http://cozy.tools', 'SOME_TITLE', 'SOME_OPTIONS');
120
- expect(mockPopup.focus).toHaveBeenCalled();
121
- expect(mockPopup.addEventListener).not.toHaveBeenCalledWith('loadstart', expect.anything());
122
- expect(mockPopup.addEventListener).not.toHaveBeenCalledWith('exit', expect.anything());
123
- expect(isPending(promise)).toBeTruthy();
124
- mockPopup.close();
125
- _context3.next = 8;
126
- return promise;
127
-
128
- case 8:
129
- result = _context3.sent;
130
- expect(result).toStrictEqual({
131
- result: 'CLOSED'
132
- });
133
-
134
- case 10:
135
- case "end":
136
- return _context3.stop();
137
- }
138
- }
139
- }, _callee3);
140
- })));
141
- it('should accept registerRealtime parameter', /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee4() {
142
- var promise, result;
143
- return _regeneratorRuntime.wrap(function _callee4$(_context4) {
144
- while (1) {
145
- switch (_context4.prev = _context4.next) {
146
- case 0:
147
- promise = openWindow({
148
- url: 'http://cozy.tools',
149
- title: 'SOME_TITLE',
150
- width: '20',
151
- height: '30',
152
- handleUrlChange: handleUrlChangeWrapper,
153
62
  registerRealtime: registerRealtime
154
63
  });
155
64
  expect(isPending(promise)).toBeTruthy();
156
65
  expect(registerRealtime).toHaveBeenCalledTimes(1);
157
66
  expect(unregisterRealtime).not.toHaveBeenCalled();
158
- mockPopup.emit('loadstart', 'HELLO');
159
- expect(handleUrlChange).not.toHaveBeenCalled();
160
67
  mockPopup.close();
161
- _context4.next = 9;
68
+ _context2.next = 7;
162
69
  return promise;
163
70
 
164
- case 9:
165
- result = _context4.sent;
71
+ case 7:
72
+ result = _context2.sent;
166
73
  expect(result).toStrictEqual({
167
74
  result: 'CLOSED'
168
75
  });
169
76
  expect(unregisterRealtime).toHaveBeenCalledTimes(1);
170
77
 
171
- case 12:
78
+ case 10:
172
79
  case "end":
173
- return _context4.stop();
80
+ return _context2.stop();
174
81
  }
175
82
  }
176
- }, _callee4);
83
+ }, _callee2);
177
84
  })));
178
85
  });
179
86
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cozy-harvest-lib",
3
- "version": "32.4.4",
3
+ "version": "32.5.0",
4
4
  "description": "Provides logic, modules and components for Cozy's harvest applications.",
5
5
  "main": "dist/index.js",
6
6
  "author": "Cozy",
@@ -71,10 +71,10 @@
71
71
  "cozy-intent": "^2.30.0",
72
72
  "cozy-interapp": "^0.16.0",
73
73
  "cozy-keys-lib": "^6.1.1",
74
- "cozy-realtime": "^5.6.4",
74
+ "cozy-realtime": "^5.7.0",
75
75
  "cozy-tsconfig": "^1.8.1",
76
76
  "cozy-ui": "^115.0.2",
77
- "cozy-viewer": "^23.1.4",
77
+ "cozy-viewer": "^23.2.0",
78
78
  "enzyme": "3.11.0",
79
79
  "enzyme-adapter-react-16": "1.15.6",
80
80
  "form-data": "4.0.0",
@@ -110,5 +110,5 @@
110
110
  "react-router-dom": ">=6.14.2"
111
111
  },
112
112
  "sideEffects": false,
113
- "gitHead": "e65ef0b285982ef58269f766870bcb26fee91ef4"
113
+ "gitHead": "110b201fa4ddf5c89dfa634b88b6e495b410e90f"
114
114
  }
@@ -17,41 +17,6 @@ export const OAUTH_SERVICE_CLOSED = 'CLOSED'
17
17
  export const OAUTH_SERVICE_ERROR = 'ERROR'
18
18
  export const OAUTH_SERVICE_OK = 'OK'
19
19
 
20
- /**
21
- * Monitor URL changes for mobile apps and in app browsers
22
- * @param {import('cozy-client/types/types').KonnectorsDoctype} konnector
23
- *
24
- * The provider redirect us to something like : oauthcallback.mycozy.cloud/?account=A&state=b
25
- * So we listen to the URL change with these informations, and we try to handle it.
26
- * It works well on iOS or when we are logged on the same device on the web, but it will
27
- * fail on Android if we're ne logged in the browser. Why ?
28
- * Our oauthcallback.mycozy.cloud/?account=A&state=b checks if we're logged, if not the server
29
- * sends an http redirect.
30
- * On Android, the 'loadstart' event is not dispatched by the browser when it get a redirect.
31
- * The inAppBrowser follows the URL and arrive on :
32
- * https://my.mycozy.cloud/auth?redirect=https://home.cozy.cloud/?account=a&state=b
33
- * So if we don't have account & state searchParams we have to check if we've a redirect searchParams
34
- * init it and search if we have inside this url an account and state params
35
- */
36
- function handleUrlChange(konnector) {
37
- return resolve => {
38
- return event => {
39
- const { url } = event
40
- const oAuthData = extractOAuthDataFromUrl(url)
41
- if (oAuthData) {
42
- return handleOAuthData(oAuthData, konnector, resolve)
43
- }
44
- const redirect = url.searchParams.get('redirect')
45
- if (redirect) {
46
- const redirectOAuthData = extractOAuthDataFromUrl(new URL(redirect))
47
- if (redirectOAuthData) {
48
- return handleOAuthData(redirectOAuthData, konnector, resolve)
49
- }
50
- }
51
- }
52
- }
53
- }
54
-
55
20
  /**
56
21
  * Handles OAuth data. OAuth data may be provided by different way:
57
22
  * * realtime message from web apps (see handleMessage)
@@ -89,26 +54,6 @@ function handleOAuthData(data, konnector, resolve) {
89
54
  * @property {String} [finalLocation] - final query string added to the redirected url
90
55
  */
91
56
 
92
- /**
93
- * Extract OAuthData from url search params if any
94
- *
95
- * @param {URL} url
96
- * @returns {OAuthData|null} OAuthData
97
- */
98
- function extractOAuthDataFromUrl(url) {
99
- const account = url.searchParams.get('account')
100
- const state = url.searchParams.get('state')
101
- const error = url.searchParams.get('error')
102
- if (account && state) {
103
- const oAuthData = { key: account, oAuthStateKey: state }
104
- if (error) {
105
- oAuthData.error = error
106
- }
107
- return oAuthData
108
- }
109
- return null
110
- }
111
-
112
57
  /**
113
58
  * @typedef OAuthServiceResult
114
59
  * @property {"OK"|"CLOSED"|"ERROR"} result
@@ -331,7 +276,6 @@ export function openOAuthWindow({
331
276
  title: title || '',
332
277
  width: OAUTH_POPUP_WIDTH,
333
278
  height: OAUTH_POPUP_HEIGHT,
334
- handleUrlChange: handleUrlChange(konnector),
335
279
  registerRealtime: registerRealtime({ konnector, client })
336
280
  })
337
281
  }
@@ -3,7 +3,7 @@ import util from 'util'
3
3
  import { openOAuthWindow, OAUTH_SERVICE_OK } from 'components/OAuthService'
4
4
  import MicroEE from 'microee'
5
5
 
6
- import { isMobileApp, isFlagshipApp } from 'cozy-device-helper'
6
+ import { isFlagshipApp } from 'cozy-device-helper'
7
7
 
8
8
  import { OAUTH_REALTIME_CHANNEL, terminateOAuth } from '../helpers/oauth'
9
9
  import PopupMock from '../helpers/windowWrapperMocks'
@@ -60,7 +60,6 @@ const client = {
60
60
  }
61
61
 
62
62
  jest.mock('cozy-device-helper', () => ({
63
- isMobileApp: jest.fn(),
64
63
  isFlagshipApp: jest.fn()
65
64
  }))
66
65
 
@@ -135,71 +134,8 @@ describe('OAuthService', () => {
135
134
  })
136
135
  })
137
136
 
138
- describe('with intentsApi', () => {
139
- beforeEach(() => {
140
- isMobileApp.mockReturnValue(true)
141
- })
142
-
143
- it('should render', async () => {
144
- let closePromise = new Promise(() => {})
145
- const intentsApi = {
146
- fetchSessionCode: jest.fn().mockResolvedValue('somesessioncode'),
147
- showInAppBrowser: jest.fn().mockImplementation(() => {
148
- return closePromise
149
- }),
150
- closeInAppBrowser: jest.fn().mockResolvedValue()
151
- }
152
- const promise = openOAuthWindow({
153
- client,
154
- konnector: { slug: 'ameli' },
155
- redirectSlug: 'home',
156
- extraParams: { extraParam1: 'extraParamValue' },
157
- title: 'popup title',
158
- account: { _id: 'someaccountid' },
159
- intentsApi
160
- })
161
-
162
- expect(isPending(promise)).toBe(true)
163
- expect(terminateOAuth).not.toHaveBeenCalled()
164
-
165
- await sleep(100) // lets time to show inAppBrowser before realtime event occurs
166
-
167
- mockCozyRealtime.emitRealtimeEvent(
168
- 'notified',
169
- 'io.cozy.accounts',
170
- OAUTH_REALTIME_CHANNEL,
171
- {
172
- _id: 'oauth-popup',
173
- data: {
174
- error: null,
175
- finalLocation: 'connection_id=194&state=someuuid',
176
- key: null,
177
- oAuthStateKey: 'someuuid'
178
- }
179
- }
180
- )
181
- const result = await promise
182
- expect(result).toStrictEqual({
183
- result: OAUTH_SERVICE_OK,
184
- key: null,
185
- data: {
186
- error: null,
187
- finalLocation: 'connection_id=194&state=someuuid',
188
- key: null,
189
- oAuthStateKey: 'someuuid'
190
- }
191
- })
192
-
193
- expect(terminateOAuth).toHaveBeenCalled()
194
- expect(intentsApi.fetchSessionCode).toHaveBeenCalledTimes(1)
195
- expect(intentsApi.showInAppBrowser).toHaveBeenCalled() // TODO test url mock nonce
196
- expect(intentsApi.closeInAppBrowser).toHaveBeenCalled()
197
- })
198
- })
199
-
200
137
  describe('on web', () => {
201
138
  beforeEach(() => {
202
- isMobileApp.mockReturnValue(false)
203
139
  isFlagshipApp.mockReturnValue(false)
204
140
  })
205
141
 
@@ -251,7 +187,3 @@ describe('OAuthService', () => {
251
187
  const isPending = promise => {
252
188
  return util.inspect(promise).includes('pending')
253
189
  }
254
-
255
- function sleep(ms) {
256
- return new Promise(resolve => setTimeout(resolve, ms))
257
- }
@@ -1,8 +1,6 @@
1
1
  import PropTypes from 'prop-types'
2
2
  import { PureComponent } from 'react'
3
3
 
4
- import { isMobileApp } from 'cozy-device-helper'
5
-
6
4
  /**
7
5
  * Customized function to get dimensions and position for a centered
8
6
  * popup window
@@ -61,23 +59,6 @@ export class Popup extends PureComponent {
61
59
  this.killPopup()
62
60
  }
63
61
 
64
- addListeners(popup) {
65
- // rest of instructions only on mobile app
66
- if (!isMobileApp()) return
67
- popup.addEventListener('loadstart', this.handleUrlChange)
68
- popup.addEventListener('exit', this.handleClose)
69
- }
70
-
71
- removeListeners(popup) {
72
- // rest of instructions only if popup is still opened
73
- if (popup.closed) return
74
-
75
- // rest of instructions only on mobile app
76
- if (!isMobileApp()) return
77
- popup.removeEventListener('loadstart', this.handleUrlChange)
78
- popup.removeEventListener('exit', this.handleClose)
79
- }
80
-
81
62
  handleClose(popup) {
82
63
  this.killPopup()
83
64
 
@@ -111,14 +92,12 @@ export class Popup extends PureComponent {
111
92
  popup.focus()
112
93
  }
113
94
 
114
- this.addListeners(popup)
115
95
  this.startMonitoringClosing(popup)
116
96
  this.setState({ popup })
117
97
  }
118
98
 
119
99
  killPopup() {
120
100
  const { popup } = this.state
121
- this.removeListeners(popup)
122
101
  this.stopMonitoringClosing()
123
102
  if (!popup.closed) popup.close()
124
103
  }
@@ -1,6 +1,4 @@
1
1
  // @ts-check
2
- import { isMobileApp } from 'cozy-device-helper'
3
-
4
2
  import { popupCenter } from './Popup'
5
3
  import { windowOpen } from '../helpers/windowWrapper'
6
4
 
@@ -17,18 +15,10 @@ import { windowOpen } from '../helpers/windowWrapper'
17
15
  * @param {String} options.title - Title of the popup
18
16
  * @param {Number} options.width - Width of the popup
19
17
  * @param {Number} options.height - Height of the popup
20
- * @param {Function} options.handleUrlChange - Function to call when popup url changes
21
18
  * @param {Function} options.registerRealtime - Function to call to register realtime events
22
19
  * @returns {Promise<OpenWindowResult>}
23
20
  */
24
- export function openWindow({
25
- url,
26
- title,
27
- width,
28
- height,
29
- handleUrlChange,
30
- registerRealtime
31
- }) {
21
+ export function openWindow({ url, title, width, height, registerRealtime }) {
32
22
  const { w, h, top, left } = popupCenter(width, height)
33
23
  const popup = windowOpen(
34
24
  url,
@@ -51,9 +41,6 @@ export function openWindow({
51
41
  let checkClosedInterval
52
42
  let unregisterRealtime
53
43
  const cleanAndResolve = data => {
54
- if (handleUrlChange) {
55
- removeListeners(popup, handleUrlChange)
56
- }
57
44
  stopMonitoringClosing(checkClosedInterval)
58
45
  if (registerRealtime) {
59
46
  unregisterRealtime()
@@ -61,9 +48,6 @@ export function openWindow({
61
48
  if (!popup.closed) popup.close()
62
49
  resolve(data)
63
50
  }
64
- if (handleUrlChange) {
65
- addListeners(popup, cleanAndResolve, handleUrlChange)
66
- }
67
51
  if (registerRealtime) {
68
52
  unregisterRealtime = registerRealtime(cleanAndResolve)
69
53
  }
@@ -107,47 +91,3 @@ function startMonitoringClosing(popup, resolve) {
107
91
  function stopMonitoringClosing(checkClosedInterval) {
108
92
  clearInterval(checkClosedInterval)
109
93
  }
110
-
111
- /**
112
- * Removes all listeners
113
- *
114
- * @param {Object} popup - Current popup
115
- * @param {Function} handleUrlChange - handleUrlChange function not to listen anymore
116
- * @returns <void>
117
- */
118
- function removeListeners(popup, handleUrlChange) {
119
- // rest of instructions only if popup is still opened
120
- if (popup.closed) return
121
-
122
- // rest of instructions only on mobile app
123
- if (!isMobileApp()) return
124
- popup.removeEventListener('loadstart', handleUrlChange)
125
- popup.removeEventListener('exit', handleClose)
126
- }
127
-
128
- /**
129
- * Add listeners
130
- *
131
- * @param {Object} popup
132
- * @param {Function} resolve
133
- * @param {Function} handleUrlChange
134
- * @returns <void>
135
- */
136
- function addListeners(popup, resolve, handleUrlChange) {
137
- // rest of instructions only on mobile app
138
- if (!isMobileApp()) return
139
- popup.addEventListener('loadstart', handleUrlChange(resolve))
140
- popup.addEventListener('exit', handleClose(resolve))
141
- }
142
-
143
- /**
144
- * Function called when the popup is closed
145
- *
146
- * @param {Function} resolve
147
- * @returns {Function}
148
- */
149
- function handleClose(resolve) {
150
- return popup => {
151
- resolve(popup)
152
- }
153
- }
@@ -2,8 +2,6 @@ import util from 'util'
2
2
 
3
3
  import { openWindow } from 'components/PopupService'
4
4
 
5
- import { isMobileApp } from 'cozy-device-helper'
6
-
7
5
  import PopupMock from '../helpers/windowWrapperMocks'
8
6
 
9
7
  const mockPopup = new PopupMock()
@@ -13,14 +11,8 @@ jest.mock('../helpers/windowWrapper', () => ({
13
11
  })
14
12
  }))
15
13
 
16
- jest.mock('cozy-device-helper', () => ({
17
- isMobileApp: jest.fn()
18
- }))
19
-
20
14
  describe('PopupService', () => {
21
15
  describe('openWindow', () => {
22
- const handleUrlChange = jest.fn()
23
- const handleUrlChangeWrapper = jest.fn().mockReturnValue(handleUrlChange)
24
16
  const unregisterRealtime = jest.fn()
25
17
  const registerRealtime = jest.fn().mockReturnValue(unregisterRealtime)
26
18
 
@@ -32,64 +24,7 @@ describe('PopupService', () => {
32
24
  jest.clearAllMocks()
33
25
  })
34
26
 
35
- describe('on Cordova', () => {
36
- beforeEach(() => {
37
- isMobileApp.mockReturnValue(true)
38
- })
39
-
40
- it('should render', async () => {
41
- const promise = openWindow({
42
- url: 'http://cozy.tools',
43
- title: 'SOME_TITLE',
44
- width: '20',
45
- height: '30',
46
- handleUrlChange: handleUrlChangeWrapper
47
- })
48
-
49
- expect(mockPopup.focus).toHaveBeenCalled()
50
- expect(mockPopup.addEventListener).toHaveBeenCalledWith(
51
- 'loadstart',
52
- expect.anything()
53
- )
54
- expect(mockPopup.addEventListener).toHaveBeenCalledWith(
55
- 'exit',
56
- expect.anything()
57
- )
58
-
59
- expect(isPending(promise)).toBeTruthy()
60
-
61
- mockPopup.emit('exit', { POPUP: 'data' })
62
- const result = await promise
63
-
64
- expect(result).toStrictEqual({ POPUP: 'data' })
65
- })
66
-
67
- it('should call handUrlChange', async () => {
68
- const promise = openWindow({
69
- url: 'http://cozy.tools',
70
- title: 'SOME_TITLE',
71
- width: '20',
72
- height: '30',
73
- handleUrlChange: handleUrlChangeWrapper
74
- })
75
-
76
- expect(isPending(promise)).toBeTruthy()
77
-
78
- mockPopup.emit('loadstart', 'HELLO')
79
- expect(handleUrlChangeWrapper).toHaveBeenCalled()
80
- expect(handleUrlChange).toHaveBeenCalledWith('HELLO')
81
-
82
- mockPopup.emit('exit', { POPUP: 'data' })
83
- const result = await promise
84
- expect(result).toStrictEqual({ POPUP: 'data' })
85
- })
86
- })
87
-
88
27
  describe('on web', () => {
89
- beforeEach(() => {
90
- isMobileApp.mockReturnValue(false)
91
- })
92
-
93
28
  it('should render', async () => {
94
29
  const promise = openWindow(
95
30
  'http://cozy.tools',
@@ -98,14 +33,6 @@ describe('PopupService', () => {
98
33
  )
99
34
 
100
35
  expect(mockPopup.focus).toHaveBeenCalled()
101
- expect(mockPopup.addEventListener).not.toHaveBeenCalledWith(
102
- 'loadstart',
103
- expect.anything()
104
- )
105
- expect(mockPopup.addEventListener).not.toHaveBeenCalledWith(
106
- 'exit',
107
- expect.anything()
108
- )
109
36
 
110
37
  expect(isPending(promise)).toBeTruthy()
111
38
 
@@ -120,7 +47,6 @@ describe('PopupService', () => {
120
47
  title: 'SOME_TITLE',
121
48
  width: '20',
122
49
  height: '30',
123
- handleUrlChange: handleUrlChangeWrapper,
124
50
  registerRealtime
125
51
  })
126
52
 
@@ -129,9 +55,6 @@ describe('PopupService', () => {
129
55
  expect(registerRealtime).toHaveBeenCalledTimes(1)
130
56
  expect(unregisterRealtime).not.toHaveBeenCalled()
131
57
 
132
- mockPopup.emit('loadstart', 'HELLO')
133
- expect(handleUrlChange).not.toHaveBeenCalled()
134
-
135
58
  mockPopup.close()
136
59
  const result = await promise
137
60
  expect(result).toStrictEqual({ result: 'CLOSED' })