cozy-harvest-lib 9.2.7 → 9.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,40 @@
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
+ # [9.5.0](https://github.com/cozy/cozy-libs/compare/cozy-harvest-lib@9.4.0...cozy-harvest-lib@9.5.0) (2022-05-23)
7
+
8
+
9
+ ### Features
10
+
11
+ * Handle banks with mulitple bank ids ([a944201](https://github.com/cozy/cozy-libs/commit/a944201ca5752766a49689f42531c84f03798002))
12
+
13
+
14
+
15
+
16
+
17
+ # [9.4.0](https://github.com/cozy/cozy-libs/compare/cozy-harvest-lib@9.3.0...cozy-harvest-lib@9.4.0) (2022-05-18)
18
+
19
+
20
+ ### Features
21
+
22
+ * **harvest:** HandleOAuthResponse can deal with cozy-data from DOM ([7c6ac1a](https://github.com/cozy/cozy-libs/commit/7c6ac1a8de7dd2b136530d0aafdb1e3f9e28fa56))
23
+ * **harvest:** OAuthFormWrapperComp can be passed to TriggerManager ([76ee8b7](https://github.com/cozy/cozy-libs/commit/76ee8b74d9314d3c66593dfe925880e6a296b420))
24
+
25
+
26
+
27
+
28
+
29
+ # [9.3.0](https://github.com/cozy/cozy-libs/compare/cozy-harvest-lib@9.2.7...cozy-harvest-lib@9.3.0) (2022-05-17)
30
+
31
+
32
+ ### Features
33
+
34
+ * Remove useVaultClient call in LegacyTriggerManager ([439e603](https://github.com/cozy/cozy-libs/commit/439e603cef915e9fede72ae293ae35ca330347eb))
35
+
36
+
37
+
38
+
39
+
6
40
  ## [9.2.7](https://github.com/cozy/cozy-libs/compare/cozy-harvest-lib@9.2.6...cozy-harvest-lib@9.2.7) (2022-05-14)
7
41
 
8
42
 
@@ -1,6 +1,5 @@
1
1
  import _extends from "@babel/runtime/helpers/extends";
2
2
  import _objectWithoutProperties from "@babel/runtime/helpers/objectWithoutProperties";
3
- import _defineProperty from "@babel/runtime/helpers/defineProperty";
4
3
  import _asyncToGenerator from "@babel/runtime/helpers/asyncToGenerator";
5
4
  import _classCallCheck from "@babel/runtime/helpers/classCallCheck";
6
5
  import _createClass from "@babel/runtime/helpers/createClass";
@@ -10,9 +9,6 @@ import _possibleConstructorReturn from "@babel/runtime/helpers/possibleConstruct
10
9
  import _getPrototypeOf from "@babel/runtime/helpers/getPrototypeOf";
11
10
  var _excluded = ["onLaunch", "onSuccess", "onLoginSuccess", "onError", "initialTrigger"],
12
11
  _excluded2 = ["vaultUnlockFormProps"];
13
-
14
- var _DumbTriggerManager$p;
15
-
16
12
  import _regeneratorRuntime from "@babel/runtime/regenerator";
17
13
 
18
14
  function _createSuper(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct(); return function _createSuperInternal() { var Super = _getPrototypeOf(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = _getPrototypeOf(this).constructor; result = Reflect.construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return _possibleConstructorReturn(this, result); }; }
@@ -28,7 +24,7 @@ import { Account } from 'cozy-doctypes';
28
24
  import { translate } from 'cozy-ui/transpiled/react/I18n';
29
25
  import Spinner from 'cozy-ui/transpiled/react/Spinner';
30
26
  import { ModalBackButton } from 'cozy-ui/transpiled/react/Modal';
31
- import { CipherType, withVaultUnlockContext, VaultUnlockPlaceholder, VaultUnlockProvider, useVaultClient, CozyUtils } from 'cozy-keys-lib';
27
+ import { CipherType, withVaultUnlockContext, VaultUnlockPlaceholder, VaultUnlockProvider, CozyUtils } from 'cozy-keys-lib';
32
28
  import AccountForm from './AccountForm';
33
29
  import OAuthForm from './OAuthForm';
34
30
  import { fetchAccount } from '../connections/accounts';
@@ -510,7 +506,8 @@ export var DumbTriggerManager = /*#__PURE__*/function (_Component) {
510
506
  fieldOptions = _this$props5.fieldOptions,
511
507
  flow = _this$props5.flow,
512
508
  flowState = _this$props5.flowState,
513
- client = _this$props5.client;
509
+ client = _this$props5.client,
510
+ OAuthFormWrapperComp = _this$props5.OAuthFormWrapperComp;
514
511
  var submitting = flowState.running;
515
512
  var _this$state = this.state,
516
513
  account = _this$state.account,
@@ -525,13 +522,14 @@ export var DumbTriggerManager = /*#__PURE__*/function (_Component) {
525
522
  var konnectorPolicy = findKonnectorPolicy(konnector);
526
523
 
527
524
  if (oauth || konnectorPolicy.isBIWebView) {
528
- return /*#__PURE__*/React.createElement(OAuthForm, {
525
+ var Wrapper = OAuthFormWrapperComp ? OAuthFormWrapperComp : React.Fragment;
526
+ return /*#__PURE__*/React.createElement(Wrapper, null, /*#__PURE__*/React.createElement(OAuthForm, {
529
527
  client: client,
530
528
  flow: flow,
531
529
  account: account,
532
530
  konnector: konnector,
533
531
  onSuccess: this.handleOAuthAccountId
534
- });
532
+ }));
535
533
  }
536
534
 
537
535
  if (showSpinner) {
@@ -568,7 +566,7 @@ export var DumbTriggerManager = /*#__PURE__*/function (_Component) {
568
566
 
569
567
  return DumbTriggerManager;
570
568
  }(Component);
571
- DumbTriggerManager.propTypes = (_DumbTriggerManager$p = {
569
+ DumbTriggerManager.propTypes = {
572
570
  /**
573
571
  * Account document. Used to get initial form values.
574
572
  * If no account is passed, AccountForm will use empty initial values.
@@ -609,21 +607,21 @@ DumbTriggerManager.propTypes = (_DumbTriggerManager$p = {
609
607
  vaultClient: PropTypes.object,
610
608
  client: PropTypes.object,
611
609
  onError: PropTypes.func,
612
- showUnlockForm: PropTypes.func
613
- }, _defineProperty(_DumbTriggerManager$p, "onVaultDismiss", PropTypes.func), _defineProperty(_DumbTriggerManager$p, "error", PropTypes.any), _defineProperty(_DumbTriggerManager$p, "showError", PropTypes.bool), _defineProperty(_DumbTriggerManager$p, "fieldOptions", PropTypes.object), _defineProperty(_DumbTriggerManager$p, "flow", PropTypes.object), _defineProperty(_DumbTriggerManager$p, "flowState", PropTypes.object), _DumbTriggerManager$p);
610
+ showUnlockForm: PropTypes.func,
611
+ error: PropTypes.any,
612
+
613
+ /**
614
+ * Used to have options on fields (forceEncryptedPlaceholder or focus)
615
+ */
616
+ fieldOptions: PropTypes.object,
617
+ flow: PropTypes.object,
618
+ flowState: PropTypes.object,
619
+ // Used to inject a component around OAuthForm, and so customize the UI from the app
620
+ OAuthFormWrapperComp: PropTypes.node
621
+ };
614
622
  var TriggerManager = compose(translate(), withClient, withVaultUnlockContext, withConnectionFlow())(DumbTriggerManager); // TriggerManager is exported wrapped in FlowProvider to avoid breaking changes.
615
623
 
616
624
  var LegacyTriggerManager = function LegacyTriggerManager(props) {
617
- // Since the 4.1.0 of cozy-keys-lib, we
618
- // render children even if vaultClient is
619
- // not defined yet. In that case we we were
620
- // displaying TriggerManager without vaultClient.
621
- // It was raising an error.
622
- // The current fix, is to not display the
623
- // TriggerManager when vaultClient is null.
624
- var vaultClient = useVaultClient();
625
- if (!vaultClient) return null;
626
-
627
625
  var onLaunch = props.onLaunch,
628
626
  onSuccess = props.onSuccess,
629
627
  onLoginSuccess = props.onLoginSuccess,
@@ -1,8 +1,9 @@
1
1
  import uuid from 'uuid/v4';
2
- import * as konnectors from './konnectors';
2
+ import get from 'lodash/get';
3
3
  import CozyClient from 'cozy-client';
4
4
  import CozyRealtime from 'cozy-realtime';
5
- import get from 'lodash/get';
5
+ import { readCozyDataFromDOM } from 'cozy-ui/transpiled/react/helpers/appDataset';
6
+ import * as konnectors from './konnectors';
6
7
  export var OAUTH_REALTIME_CHANNEL = 'oauth-popup';
7
8
  /**
8
9
  * Checks that the given data for the given konnector is consistent with the
@@ -51,10 +52,11 @@ export var handleOAuthResponse = function handleOAuthResponse() {
51
52
  var client = options.client;
52
53
 
53
54
  if (!client) {
54
- var root = document.querySelector('[role=application]');
55
+ var domain = readCozyDataFromDOM('domain');
56
+ var token = readCozyDataFromDOM('token');
55
57
  client = new CozyClient({
56
- uri: "".concat(window.location.protocol, "//").concat(root.dataset.cozyDomain),
57
- token: root.dataset.cozyToken
58
+ uri: "".concat(window.location.protocol, "//").concat(domain),
59
+ token: token
58
60
  });
59
61
  }
60
62
 
@@ -18,8 +18,11 @@ import { getBIConnection } from './bi-http';
18
18
  import assert from '../assert';
19
19
  import logger from '../logger';
20
20
  import flag from 'cozy-flags';
21
- import { fetchExtraOAuthUrlParams, createTemporaryToken, setBIConnectionId, saveBIConfig, findAccountWithBiConnection, convertBIErrortoKonnectorJobError, isBudgetInsightConnector } from './budget-insight';
21
+ import { setBIConnectionId, saveBIConfig, findAccountWithBiConnection, convertBIErrortoKonnectorJobError, isBudgetInsightConnector } from './budget-insight';
22
22
  import { KonnectorJobError } from '../helpers/konnectors';
23
+ import { waitForRealtimeEvent } from './jobUtils';
24
+ import '../types';
25
+ var TEMP_TOKEN_TIMOUT_S = 60;
23
26
  export var isBiWebViewConnector = function isBiWebViewConnector(konnector) {
24
27
  return flag('harvest.bi.webview') && isBudgetInsightConnector(konnector);
25
28
  };
@@ -116,19 +119,19 @@ export var checkBIConnection = /*#__PURE__*/function () {
116
119
 
117
120
  export var handleOAuthAccount = /*#__PURE__*/function () {
118
121
  var _ref4 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee2(_ref3) {
119
- var account, flow, konnector, client, t, cozyBankId, biWebviewAccount, connectionId;
122
+ var account, flow, konnector, client, t, cozyBankIds, biWebviewAccount, connectionId;
120
123
  return _regeneratorRuntime.wrap(function _callee2$(_context2) {
121
124
  while (1) {
122
125
  switch (_context2.prev = _context2.next) {
123
126
  case 0:
124
127
  account = _ref3.account, flow = _ref3.flow, konnector = _ref3.konnector, client = _ref3.client, t = _ref3.t;
125
- cozyBankId = getCozyBankId({
128
+ cozyBankIds = getCozyBankIds({
126
129
  konnector: konnector,
127
130
  account: account
128
131
  });
129
- biWebviewAccount = _objectSpread(_objectSpread({}, account), cozyBankId ? {
132
+ biWebviewAccount = _objectSpread(_objectSpread({}, account), cozyBankIds ? {
130
133
  auth: {
131
- bankId: cozyBankId
134
+ bankIds: cozyBankIds
132
135
  }
133
136
  } : {});
134
137
  connectionId = getWebviewBIConnectionId(biWebviewAccount);
@@ -240,26 +243,125 @@ export var onBIAccountCreation = /*#__PURE__*/function () {
240
243
  return _ref6.apply(this, arguments);
241
244
  };
242
245
  }();
246
+ export var fetchExtraOAuthUrlParams = /*#__PURE__*/function () {
247
+ var _ref8 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee4(_ref7) {
248
+ var client, konnector, account, _yield$createTemporar, token, biBankId, biBankIds;
249
+
250
+ return _regeneratorRuntime.wrap(function _callee4$(_context4) {
251
+ while (1) {
252
+ switch (_context4.prev = _context4.next) {
253
+ case 0:
254
+ client = _ref7.client, konnector = _ref7.konnector, account = _ref7.account;
255
+ _context4.next = 3;
256
+ return createTemporaryToken({
257
+ client: client,
258
+ konnector: konnector,
259
+ account: account
260
+ });
261
+
262
+ case 3:
263
+ _yield$createTemporar = _context4.sent;
264
+ token = _yield$createTemporar.code;
265
+ biBankId = _yield$createTemporar.biBankId;
266
+ biBankIds = _yield$createTemporar.biBankIds;
267
+ return _context4.abrupt("return", {
268
+ id_connector: biBankId || biBankIds,
269
+ token: token
270
+ });
271
+
272
+ case 8:
273
+ case "end":
274
+ return _context4.stop();
275
+ }
276
+ }
277
+ }, _callee4);
278
+ }));
279
+
280
+ return function fetchExtraOAuthUrlParams(_x4) {
281
+ return _ref8.apply(this, arguments);
282
+ };
283
+ }();
243
284
  /**
244
285
  * Finds the current bankIid in a given konnector or account
245
286
  *
246
287
  * @param {io.cozy.accounts} options.account The account content
247
288
  * @param {io.cozy.konnectors} options.konnector connector manifest content
289
+ * @return {Array<String>} - list of bank ids
248
290
  */
249
291
 
250
- export var getCozyBankId = function getCozyBankId(_ref7) {
251
- var _konnector$parameters, _account$auth;
292
+ export var getCozyBankIds = function getCozyBankIds(_ref9) {
293
+ var _konnector$parameters, _account$auth, _konnector$fields, _konnector$fields$ban;
252
294
 
253
- var konnector = _ref7.konnector,
254
- account = _ref7.account;
295
+ var konnector = _ref9.konnector,
296
+ account = _ref9.account;
255
297
  var cozyBankId = (konnector === null || konnector === void 0 ? void 0 : (_konnector$parameters = konnector.parameters) === null || _konnector$parameters === void 0 ? void 0 : _konnector$parameters.bankId) || (account === null || account === void 0 ? void 0 : (_account$auth = account.auth) === null || _account$auth === void 0 ? void 0 : _account$auth.bankId);
256
298
 
257
- if (!cozyBankId) {
299
+ if (cozyBankId) {
300
+ return [cozyBankId];
301
+ }
302
+
303
+ var cozyBankIds = konnector === null || konnector === void 0 ? void 0 : (_konnector$fields = konnector.fields) === null || _konnector$fields === void 0 ? void 0 : (_konnector$fields$ban = _konnector$fields.bankId) === null || _konnector$fields$ban === void 0 ? void 0 : _konnector$fields$ban.options.map(function (opt) {
304
+ return opt === null || opt === void 0 ? void 0 : opt.value;
305
+ });
306
+
307
+ if (!(cozyBankIds !== null && cozyBankIds !== void 0 && cozyBankIds.length)) {
258
308
  logger.error('Could not find any bank id');
259
309
  }
260
310
 
261
- return cozyBankId;
311
+ return cozyBankIds;
262
312
  };
313
+ /**
314
+ * Gets a temporary token corresponding to the current BI user
315
+ *
316
+ * @param {CozyClient} options.client - CozyClient instance
317
+ * @param {io.cozy.konnectors} options.konnector connector manifest content
318
+ * @param {io.cozy.accounts} options.account The account content
319
+ *
320
+ * @returns {createTemporaryTokenResponse}
321
+ */
322
+
323
+ export var createTemporaryToken = /*#__PURE__*/function () {
324
+ var _ref11 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee5(_ref10) {
325
+ var client, konnector, account, cozyBankIds, jobResponse, event;
326
+ return _regeneratorRuntime.wrap(function _callee5$(_context5) {
327
+ while (1) {
328
+ switch (_context5.prev = _context5.next) {
329
+ case 0:
330
+ client = _ref10.client, konnector = _ref10.konnector, account = _ref10.account;
331
+ assert(konnector.slug, 'createTemporaryToken: konnector passed in options has no slug');
332
+ cozyBankIds = getCozyBankIds({
333
+ konnector: konnector,
334
+ account: account
335
+ });
336
+ assert(cozyBankIds.length, 'createTemporaryToken: Could not determine cozyBankId from account or konnector');
337
+ _context5.next = 6;
338
+ return client.stackClient.jobs.create('konnector', {
339
+ mode: 'getTemporaryToken',
340
+ konnector: konnector.slug,
341
+ bankIds: cozyBankIds
342
+ }, {}, true);
343
+
344
+ case 6:
345
+ jobResponse = _context5.sent;
346
+ _context5.next = 9;
347
+ return waitForRealtimeEvent(client, jobResponse.data.attributes, 'result', TEMP_TOKEN_TIMOUT_S * 1000);
348
+
349
+ case 9:
350
+ event = _context5.sent;
351
+ return _context5.abrupt("return", event.data.result);
352
+
353
+ case 11:
354
+ case "end":
355
+ return _context5.stop();
356
+ }
357
+ }
358
+ }, _callee5);
359
+ }));
360
+
361
+ return function createTemporaryToken(_x5) {
362
+ return _ref11.apply(this, arguments);
363
+ };
364
+ }();
263
365
  export var konnectorPolicy = {
264
366
  isBIWebView: true,
265
367
  name: 'budget-insight-webview',
@@ -113,7 +113,7 @@ describe('handleOAuthAccount', function () {
113
113
  t: t,
114
114
  account: _objectSpread(_objectSpread(_objectSpread({}, account), {
115
115
  auth: {
116
- bankId: TEST_BANK_COZY_ID
116
+ bankIds: [TEST_BANK_COZY_ID]
117
117
  }
118
118
  }), {
119
119
  data: {
@@ -34,6 +34,7 @@ import { mkConnAuth, biErrorMap } from 'cozy-bi-auth';
34
34
  import { KonnectorJobError } from '../helpers/konnectors';
35
35
  import { LOGIN_SUCCESS_EVENT } from '../models/flowEvents';
36
36
  import logger from '../logger';
37
+ import '../types';
37
38
  var DECOUPLED_ERROR = 'decoupled';
38
39
  var ADDITIONAL_INFORMATION_NEEDED_ERROR = 'additionalInformationNeeded';
39
40
  var TEMP_TOKEN_TIMOUT_S = 60;
@@ -401,19 +402,6 @@ export var resumeBIConnection = function resumeBIConnection(flow) {
401
402
  resume: 'true'
402
403
  });
403
404
  };
404
- /**
405
- * @typedef biConnection
406
- * @property {number} id
407
- * @property {number} id_user
408
- * @property {number} id_connector
409
- * @property {string|null} state - ( wrongpass | additionalInformationNeeded | websiteUnavailable | actionNeeded | SCARequired | decoupled | passwordExpired | webauthRequired | rateLimiting | bug). Null indicates a success
410
- * @property {string|null} last_update - Date string: Last successful update.
411
- * @property {string|null} created - Date string: Creation date
412
- * @property {boolean} active - Whether this connection is active and will be automatically synced.
413
- * @property {string|null} last_push - Date string: Last successfull push
414
- * @property {string|null} next_try - Date string: Date of next synchronization.
415
- */
416
-
417
405
  /**
418
406
  * Checks for any number 2FA and/or decoupled requests
419
407
  *
package/dist/types.js ADDED
@@ -0,0 +1,22 @@
1
+ /**
2
+ * @typedef createTemporaryTokenResponse
3
+ * @property {String} code - the temporary token
4
+ * @property {String} url - BI environment url
5
+ * @property {String} bankId - Cozy bank id corresponding to the current connector (deprecated once bi webviews are in production)
6
+ * @property {String} biBankId - BI bank id corresponding to the bankId translated by the connector (deprecated once bi webviews are in production)
7
+ * @property {Array<String>} bankIds - Cozy bank ids corresponding to the current connector
8
+ * @property {Array<String>} biBankIds - BI bank ids corresponding to the bankIds translated by the connector
9
+ */
10
+
11
+ /**
12
+ * @typedef biConnection
13
+ * @property {number} id
14
+ * @property {number} id_user
15
+ * @property {number} id_connector
16
+ * @property {string|null} state - ( wrongpass | additionalInformationNeeded | websiteUnavailable | actionNeeded | SCARequired | decoupled | passwordExpired | webauthRequired | rateLimiting | bug). Null indicates a success
17
+ * @property {string|null} last_update - Date string: Last successful update.
18
+ * @property {string|null} created - Date string: Creation date
19
+ * @property {boolean} active - Whether this connection is active and will be automatically synced.
20
+ * @property {string|null} last_push - Date string: Last successfull push
21
+ * @property {string|null} next_try - Date string: Date of next synchronization.
22
+ */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cozy-harvest-lib",
3
- "version": "9.2.7",
3
+ "version": "9.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",
@@ -87,5 +87,5 @@
87
87
  "react-router-dom": "^5.0.1"
88
88
  },
89
89
  "sideEffects": false,
90
- "gitHead": "a29540278e4a6456a14cb04d95e99d8c39bf4c6d"
90
+ "gitHead": "d941e5ac9af1ce3e4394034f8a989431d233e84f"
91
91
  }
@@ -15,7 +15,6 @@ import {
15
15
  withVaultUnlockContext,
16
16
  VaultUnlockPlaceholder,
17
17
  VaultUnlockProvider,
18
- useVaultClient,
19
18
  CozyUtils
20
19
  } from 'cozy-keys-lib'
21
20
 
@@ -313,8 +312,16 @@ export class DumbTriggerManager extends Component {
313
312
  }
314
313
 
315
314
  render() {
316
- const { konnector, showError, t, fieldOptions, flow, flowState, client } =
317
- this.props
315
+ const {
316
+ konnector,
317
+ showError,
318
+ t,
319
+ fieldOptions,
320
+ flow,
321
+ flowState,
322
+ client,
323
+ OAuthFormWrapperComp
324
+ } = this.props
318
325
 
319
326
  const submitting = flowState.running
320
327
 
@@ -329,14 +336,19 @@ export class DumbTriggerManager extends Component {
329
336
  const konnectorPolicy = findKonnectorPolicy(konnector)
330
337
 
331
338
  if (oauth || konnectorPolicy.isBIWebView) {
339
+ const Wrapper = OAuthFormWrapperComp
340
+ ? OAuthFormWrapperComp
341
+ : React.Fragment
332
342
  return (
333
- <OAuthForm
334
- client={client}
335
- flow={flow}
336
- account={account}
337
- konnector={konnector}
338
- onSuccess={this.handleOAuthAccountId}
339
- />
343
+ <Wrapper>
344
+ <OAuthForm
345
+ client={client}
346
+ flow={flow}
347
+ account={account}
348
+ konnector={konnector}
349
+ onSuccess={this.handleOAuthAccountId}
350
+ />
351
+ </Wrapper>
340
352
  )
341
353
  }
342
354
 
@@ -424,21 +436,15 @@ DumbTriggerManager.propTypes = {
424
436
  client: PropTypes.object,
425
437
  onError: PropTypes.func,
426
438
  showUnlockForm: PropTypes.func,
427
- onVaultDismiss: PropTypes.func,
428
439
  error: PropTypes.any,
429
- /**
430
- * Indicates if the AccountForm has to show errors. Sometimes errors may be
431
- * displayed elsewhere. However, a KonnectorJobError corresponding to a login
432
- * error is always displayed.
433
- * @type {Boolean}
434
- */
435
- showError: PropTypes.bool,
436
440
  /**
437
441
  * Used to have options on fields (forceEncryptedPlaceholder or focus)
438
442
  */
439
443
  fieldOptions: PropTypes.object,
440
444
  flow: PropTypes.object,
441
- flowState: PropTypes.object
445
+ flowState: PropTypes.object,
446
+ // Used to inject a component around OAuthForm, and so customize the UI from the app
447
+ OAuthFormWrapperComp: PropTypes.node
442
448
  }
443
449
 
444
450
  const TriggerManager = compose(
@@ -450,15 +456,6 @@ const TriggerManager = compose(
450
456
 
451
457
  // TriggerManager is exported wrapped in FlowProvider to avoid breaking changes.
452
458
  const LegacyTriggerManager = props => {
453
- // Since the 4.1.0 of cozy-keys-lib, we
454
- // render children even if vaultClient is
455
- // not defined yet. In that case we we were
456
- // displaying TriggerManager without vaultClient.
457
- // It was raising an error.
458
- // The current fix, is to not display the
459
- // TriggerManager when vaultClient is null.
460
- const vaultClient = useVaultClient()
461
- if (!vaultClient) return null
462
459
  const {
463
460
  onLaunch,
464
461
  onSuccess,
@@ -1,9 +1,11 @@
1
1
  import uuid from 'uuid/v4'
2
+ import get from 'lodash/get'
2
3
 
3
- import * as konnectors from './konnectors'
4
4
  import CozyClient from 'cozy-client'
5
5
  import CozyRealtime from 'cozy-realtime'
6
- import get from 'lodash/get'
6
+ import { readCozyDataFromDOM } from 'cozy-ui/transpiled/react/helpers/appDataset'
7
+
8
+ import * as konnectors from './konnectors'
7
9
 
8
10
  export const OAUTH_REALTIME_CHANNEL = 'oauth-popup'
9
11
 
@@ -55,10 +57,12 @@ export const handleOAuthResponse = (options = {}) => {
55
57
  if (!realtime) {
56
58
  let client = options.client
57
59
  if (!client) {
58
- const root = document.querySelector('[role=application]')
60
+ const domain = readCozyDataFromDOM('domain')
61
+ const token = readCozyDataFromDOM('token')
62
+
59
63
  client = new CozyClient({
60
- uri: `${window.location.protocol}//${root.dataset.cozyDomain}`,
61
- token: root.dataset.cozyToken
64
+ uri: `${window.location.protocol}//${domain}`,
65
+ token: token
62
66
  })
63
67
  }
64
68
  realtime = new CozyRealtime({ client })
@@ -9,8 +9,6 @@ import assert from '../assert'
9
9
  import logger from '../logger'
10
10
  import flag from 'cozy-flags'
11
11
  import {
12
- fetchExtraOAuthUrlParams,
13
- createTemporaryToken,
14
12
  setBIConnectionId,
15
13
  saveBIConfig,
16
14
  findAccountWithBiConnection,
@@ -18,6 +16,10 @@ import {
18
16
  isBudgetInsightConnector
19
17
  } from './budget-insight'
20
18
  import { KonnectorJobError } from '../helpers/konnectors'
19
+ import { waitForRealtimeEvent } from './jobUtils'
20
+ import '../types'
21
+
22
+ const TEMP_TOKEN_TIMOUT_S = 60
21
23
 
22
24
  export const isBiWebViewConnector = konnector =>
23
25
  flag('harvest.bi.webview') && isBudgetInsightConnector(konnector)
@@ -94,10 +96,10 @@ export const handleOAuthAccount = async ({
94
96
  client,
95
97
  t
96
98
  }) => {
97
- const cozyBankId = getCozyBankId({ konnector, account })
99
+ const cozyBankIds = getCozyBankIds({ konnector, account })
98
100
  let biWebviewAccount = {
99
101
  ...account,
100
- ...(cozyBankId ? { auth: { bankId: cozyBankId } } : {})
102
+ ...(cozyBankIds ? { auth: { bankIds: cozyBankIds } } : {})
101
103
  }
102
104
 
103
105
  const connectionId = getWebviewBIConnectionId(biWebviewAccount)
@@ -167,18 +169,81 @@ export const onBIAccountCreation = async ({
167
169
  return await flow.saveAccount(setBIConnectionId(account, biConnection.id))
168
170
  }
169
171
 
172
+ export const fetchExtraOAuthUrlParams = async ({
173
+ client,
174
+ konnector,
175
+ account
176
+ }) => {
177
+ const {
178
+ code: token,
179
+ biBankId,
180
+ biBankIds
181
+ } = await createTemporaryToken({
182
+ client,
183
+ konnector,
184
+ account
185
+ })
186
+
187
+ return { id_connector: biBankId || biBankIds, token }
188
+ }
189
+
170
190
  /**
171
191
  * Finds the current bankIid in a given konnector or account
172
192
  *
173
193
  * @param {io.cozy.accounts} options.account The account content
174
194
  * @param {io.cozy.konnectors} options.konnector connector manifest content
195
+ * @return {Array<String>} - list of bank ids
175
196
  */
176
- export const getCozyBankId = ({ konnector, account }) => {
197
+ export const getCozyBankIds = ({ konnector, account }) => {
177
198
  const cozyBankId = konnector?.parameters?.bankId || account?.auth?.bankId
178
- if (!cozyBankId) {
199
+
200
+ if (cozyBankId) {
201
+ return [cozyBankId]
202
+ }
203
+
204
+ const cozyBankIds = konnector?.fields?.bankId?.options.map(opt => opt?.value)
205
+ if (!cozyBankIds?.length) {
179
206
  logger.error('Could not find any bank id')
180
207
  }
181
- return cozyBankId
208
+ return cozyBankIds
209
+ }
210
+
211
+ /**
212
+ * Gets a temporary token corresponding to the current BI user
213
+ *
214
+ * @param {CozyClient} options.client - CozyClient instance
215
+ * @param {io.cozy.konnectors} options.konnector connector manifest content
216
+ * @param {io.cozy.accounts} options.account The account content
217
+ *
218
+ * @returns {createTemporaryTokenResponse}
219
+ */
220
+ export const createTemporaryToken = async ({ client, konnector, account }) => {
221
+ assert(
222
+ konnector.slug,
223
+ 'createTemporaryToken: konnector passed in options has no slug'
224
+ )
225
+ const cozyBankIds = getCozyBankIds({ konnector, account })
226
+ assert(
227
+ cozyBankIds.length,
228
+ 'createTemporaryToken: Could not determine cozyBankId from account or konnector'
229
+ )
230
+ const jobResponse = await client.stackClient.jobs.create(
231
+ 'konnector',
232
+ {
233
+ mode: 'getTemporaryToken',
234
+ konnector: konnector.slug,
235
+ bankIds: cozyBankIds
236
+ },
237
+ {},
238
+ true
239
+ )
240
+ const event = await waitForRealtimeEvent(
241
+ client,
242
+ jobResponse.data.attributes,
243
+ 'result',
244
+ TEMP_TOKEN_TIMOUT_S * 1000
245
+ )
246
+ return event.data.result
182
247
  }
183
248
 
184
249
  export const konnectorPolicy = {
@@ -69,7 +69,7 @@ describe('handleOAuthAccount', () => {
69
69
  t,
70
70
  account: {
71
71
  ...account,
72
- ...{ auth: { bankId: TEST_BANK_COZY_ID } },
72
+ ...{ auth: { bankIds: [TEST_BANK_COZY_ID] } },
73
73
  ...{ data: { auth: { bi: { connId: 12 } } } }
74
74
  }
75
75
  })
@@ -27,6 +27,7 @@ import { mkConnAuth, biErrorMap } from 'cozy-bi-auth'
27
27
  import { KonnectorJobError } from '../helpers/konnectors'
28
28
  import { LOGIN_SUCCESS_EVENT } from '../models/flowEvents'
29
29
  import logger from '../logger'
30
+ import '../types'
30
31
 
31
32
  const DECOUPLED_ERROR = 'decoupled'
32
33
  const ADDITIONAL_INFORMATION_NEEDED_ERROR = 'additionalInformationNeeded'
@@ -292,19 +293,6 @@ export const resumeBIConnection = flow => {
292
293
  return updateBIConnectionFromFlow(flow, { resume: 'true' })
293
294
  }
294
295
 
295
- /**
296
- * @typedef biConnection
297
- * @property {number} id
298
- * @property {number} id_user
299
- * @property {number} id_connector
300
- * @property {string|null} state - ( wrongpass | additionalInformationNeeded | websiteUnavailable | actionNeeded | SCARequired | decoupled | passwordExpired | webauthRequired | rateLimiting | bug). Null indicates a success
301
- * @property {string|null} last_update - Date string: Last successful update.
302
- * @property {string|null} created - Date string: Creation date
303
- * @property {boolean} active - Whether this connection is active and will be automatically synced.
304
- * @property {string|null} last_push - Date string: Last successfull push
305
- * @property {string|null} next_try - Date string: Date of next synchronization.
306
- */
307
-
308
296
  /**
309
297
  * Checks for any number 2FA and/or decoupled requests
310
298
  *
package/src/types.js ADDED
@@ -0,0 +1,22 @@
1
+ /**
2
+ * @typedef createTemporaryTokenResponse
3
+ * @property {String} code - the temporary token
4
+ * @property {String} url - BI environment url
5
+ * @property {String} bankId - Cozy bank id corresponding to the current connector (deprecated once bi webviews are in production)
6
+ * @property {String} biBankId - BI bank id corresponding to the bankId translated by the connector (deprecated once bi webviews are in production)
7
+ * @property {Array<String>} bankIds - Cozy bank ids corresponding to the current connector
8
+ * @property {Array<String>} biBankIds - BI bank ids corresponding to the bankIds translated by the connector
9
+ */
10
+
11
+ /**
12
+ * @typedef biConnection
13
+ * @property {number} id
14
+ * @property {number} id_user
15
+ * @property {number} id_connector
16
+ * @property {string|null} state - ( wrongpass | additionalInformationNeeded | websiteUnavailable | actionNeeded | SCARequired | decoupled | passwordExpired | webauthRequired | rateLimiting | bug). Null indicates a success
17
+ * @property {string|null} last_update - Date string: Last successful update.
18
+ * @property {string|null} created - Date string: Creation date
19
+ * @property {boolean} active - Whether this connection is active and will be automatically synced.
20
+ * @property {string|null} last_push - Date string: Last successfull push
21
+ * @property {string|null} next_try - Date string: Date of next synchronization.
22
+ */