cozy-client 58.1.0 → 58.3.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/dist/CozyClient.js +15 -5
- package/dist/helpers/index.js +6 -0
- package/dist/helpers/urlHelper.js +225 -78
- package/dist/helpers/urlHelper.spec.js +530 -62
- package/dist/index.js +7 -0
- package/package.json +2 -2
- package/types/helpers/index.d.ts +1 -1
- package/types/helpers/urlHelper.d.ts +11 -0
- package/types/index.d.ts +1 -1
package/dist/CozyClient.js
CHANGED
|
@@ -1630,7 +1630,7 @@ var CozyClient = /*#__PURE__*/function () {
|
|
|
1630
1630
|
key: "requestQuery",
|
|
1631
1631
|
value: function () {
|
|
1632
1632
|
var _requestQuery = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee11(definition, options) {
|
|
1633
|
-
var mainResponse, withIncluded;
|
|
1633
|
+
var mainResponse, schema, withIncluded;
|
|
1634
1634
|
return _regenerator.default.wrap(function _callee11$(_context11) {
|
|
1635
1635
|
while (1) {
|
|
1636
1636
|
switch (_context11.prev = _context11.next) {
|
|
@@ -1652,14 +1652,24 @@ var CozyClient = /*#__PURE__*/function () {
|
|
|
1652
1652
|
return _context11.abrupt("return", mainResponse);
|
|
1653
1653
|
|
|
1654
1654
|
case 7:
|
|
1655
|
-
|
|
1655
|
+
schema = this.schema.getDoctypeSchema(definition.doctype);
|
|
1656
|
+
|
|
1657
|
+
if (!schema.relationships) {
|
|
1658
|
+
_context11.next = 13;
|
|
1659
|
+
break;
|
|
1660
|
+
}
|
|
1661
|
+
|
|
1662
|
+
_context11.next = 11;
|
|
1656
1663
|
return this.fetchRelationships(mainResponse, this.getIncludesRelationships(definition));
|
|
1657
1664
|
|
|
1658
|
-
case
|
|
1665
|
+
case 11:
|
|
1659
1666
|
withIncluded = _context11.sent;
|
|
1660
1667
|
return _context11.abrupt("return", withIncluded);
|
|
1661
1668
|
|
|
1662
|
-
case
|
|
1669
|
+
case 13:
|
|
1670
|
+
return _context11.abrupt("return", mainResponse);
|
|
1671
|
+
|
|
1672
|
+
case 14:
|
|
1663
1673
|
case "end":
|
|
1664
1674
|
return _context11.stop();
|
|
1665
1675
|
}
|
|
@@ -3133,7 +3143,7 @@ var CozyClient = /*#__PURE__*/function () {
|
|
|
3133
3143
|
CozyClient.hooks = CozyClient.hooks || {};
|
|
3134
3144
|
CozyClient.fetchPolicies = _policies.default; //COZY_CLIENT_VERSION_PACKAGE in replaced by babel. See babel config
|
|
3135
3145
|
|
|
3136
|
-
CozyClient.version = "58.
|
|
3146
|
+
CozyClient.version = "58.3.0";
|
|
3137
3147
|
|
|
3138
3148
|
_microee.default.mixin(CozyClient);
|
|
3139
3149
|
|
package/dist/helpers/index.js
CHANGED
|
@@ -27,6 +27,12 @@ Object.defineProperty(exports, "ensureFirstSlash", {
|
|
|
27
27
|
return _urlHelper.ensureFirstSlash;
|
|
28
28
|
}
|
|
29
29
|
});
|
|
30
|
+
Object.defineProperty(exports, "fetchRegistrationDetails", {
|
|
31
|
+
enumerable: true,
|
|
32
|
+
get: function get() {
|
|
33
|
+
return _urlHelper.fetchRegistrationDetails;
|
|
34
|
+
}
|
|
35
|
+
});
|
|
30
36
|
Object.defineProperty(exports, "rootCozyUrl", {
|
|
31
37
|
enumerable: true,
|
|
32
38
|
get: function get() {
|
|
@@ -5,7 +5,7 @@ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefau
|
|
|
5
5
|
Object.defineProperty(exports, "__esModule", {
|
|
6
6
|
value: true
|
|
7
7
|
});
|
|
8
|
-
exports.rootCozyUrl = exports.InvalidCozyUrlError = exports.BlockedCozyError = exports.InvalidProtocolError = exports.InvalidRedirectLinkError = exports.deconstructRedirectLink = exports.deconstructCozyWebLinkWithSlug = exports.generateWebLink = exports.ensureFirstSlash = void 0;
|
|
8
|
+
exports.fetchRegistrationDetails = exports.rootCozyUrl = exports.InvalidCozyUrlError = exports.BlockedCozyError = exports.InvalidProtocolError = exports.InvalidRedirectLinkError = exports.deconstructRedirectLink = exports.deconstructCozyWebLinkWithSlug = exports.generateWebLink = exports.ensureFirstSlash = void 0;
|
|
9
9
|
|
|
10
10
|
var _toConsumableArray2 = _interopRequireDefault(require("@babel/runtime/helpers/toConsumableArray"));
|
|
11
11
|
|
|
@@ -263,7 +263,7 @@ var uri = function uri(_ref2) {
|
|
|
263
263
|
port = _ref2.port;
|
|
264
264
|
return (protocol !== '' ? "".concat(protocol, "//") : 'https://') + hostname + (port !== '' ? ":".concat(port) : '');
|
|
265
265
|
};
|
|
266
|
-
/*
|
|
266
|
+
/* publicPreloginUrl - Returns a valid URL string to the /public/prelogin API endpoint
|
|
267
267
|
*
|
|
268
268
|
* The built URL will point to the origin generated from the given protocol,
|
|
269
269
|
* hostname and port.
|
|
@@ -277,8 +277,8 @@ var uri = function uri(_ref2) {
|
|
|
277
277
|
*/
|
|
278
278
|
|
|
279
279
|
|
|
280
|
-
var
|
|
281
|
-
return uri(url) + '
|
|
280
|
+
var publicPreloginUrl = function publicPreloginUrl(url) {
|
|
281
|
+
return uri(url) + '/public/prelogin';
|
|
282
282
|
};
|
|
283
283
|
/* isValidOrigin - Checks whether a given URL is a valid Cozy origin
|
|
284
284
|
*
|
|
@@ -307,13 +307,13 @@ var wellKnownUrl = function wellKnownUrl(url) {
|
|
|
307
307
|
|
|
308
308
|
var isValidOrigin = /*#__PURE__*/function () {
|
|
309
309
|
var _ref3 = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee(url) {
|
|
310
|
-
var response, status, responseUri, wasRedirected;
|
|
310
|
+
var response, status, responseUri, wasRedirected, contentType;
|
|
311
311
|
return _regenerator.default.wrap(function _callee$(_context) {
|
|
312
312
|
while (1) {
|
|
313
313
|
switch (_context.prev = _context.next) {
|
|
314
314
|
case 0:
|
|
315
315
|
_context.next = 2;
|
|
316
|
-
return fetch(
|
|
316
|
+
return fetch(publicPreloginUrl(url));
|
|
317
317
|
|
|
318
318
|
case 2:
|
|
319
319
|
response = _context.sent;
|
|
@@ -339,10 +339,37 @@ var isValidOrigin = /*#__PURE__*/function () {
|
|
|
339
339
|
throw new BlockedCozyError(url);
|
|
340
340
|
|
|
341
341
|
case 10:
|
|
342
|
-
|
|
343
|
-
|
|
342
|
+
if (!(status !== 200)) {
|
|
343
|
+
_context.next = 12;
|
|
344
|
+
break;
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
return _context.abrupt("return");
|
|
344
348
|
|
|
345
349
|
case 12:
|
|
350
|
+
wasRedirected = responseUri && url.origin !== new URL(responseUri).origin;
|
|
351
|
+
|
|
352
|
+
if (!wasRedirected) {
|
|
353
|
+
_context.next = 15;
|
|
354
|
+
break;
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
return _context.abrupt("return", false);
|
|
358
|
+
|
|
359
|
+
case 15:
|
|
360
|
+
contentType = response.headers.get('content-type');
|
|
361
|
+
|
|
362
|
+
if (!(!contentType || contentType.indexOf('application/json') === -1)) {
|
|
363
|
+
_context.next = 18;
|
|
364
|
+
break;
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
return _context.abrupt("return", false);
|
|
368
|
+
|
|
369
|
+
case 18:
|
|
370
|
+
return _context.abrupt("return", response.json());
|
|
371
|
+
|
|
372
|
+
case 19:
|
|
346
373
|
case "end":
|
|
347
374
|
return _context.stop();
|
|
348
375
|
}
|
|
@@ -399,83 +426,19 @@ var isValidOrigin = /*#__PURE__*/function () {
|
|
|
399
426
|
|
|
400
427
|
var rootCozyUrl = /*#__PURE__*/function () {
|
|
401
428
|
var _ref4 = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee2(url) {
|
|
402
|
-
var
|
|
403
|
-
|
|
429
|
+
var detail;
|
|
404
430
|
return _regenerator.default.wrap(function _callee2$(_context2) {
|
|
405
431
|
while (1) {
|
|
406
432
|
switch (_context2.prev = _context2.next) {
|
|
407
433
|
case 0:
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
break;
|
|
411
|
-
}
|
|
412
|
-
|
|
413
|
-
throw new InvalidProtocolError(url);
|
|
434
|
+
_context2.next = 2;
|
|
435
|
+
return fetchRegistrationDetails(url);
|
|
414
436
|
|
|
415
437
|
case 2:
|
|
416
|
-
|
|
417
|
-
return
|
|
438
|
+
detail = _context2.sent;
|
|
439
|
+
return _context2.abrupt("return", detail.rootUrl);
|
|
418
440
|
|
|
419
441
|
case 4:
|
|
420
|
-
if (!_context2.sent) {
|
|
421
|
-
_context2.next = 6;
|
|
422
|
-
break;
|
|
423
|
-
}
|
|
424
|
-
|
|
425
|
-
return _context2.abrupt("return", new URL(uri({
|
|
426
|
-
protocol: url.protocol,
|
|
427
|
-
hostname: url.hostname,
|
|
428
|
-
port: url.port
|
|
429
|
-
})));
|
|
430
|
-
|
|
431
|
-
case 6:
|
|
432
|
-
if (!/^[^.-][^.]+-[^.-]+\./.test(url.hostname)) {
|
|
433
|
-
_context2.next = 14;
|
|
434
|
-
break;
|
|
435
|
-
}
|
|
436
|
-
|
|
437
|
-
_url$hostname$split = url.hostname.split('.'), _url$hostname$split2 = (0, _toArray2.default)(_url$hostname$split), subDomain = _url$hostname$split2[0], domain = _url$hostname$split2.slice(1);
|
|
438
|
-
_hostname = [subDomain.replace(/-.+/, '')].concat((0, _toConsumableArray2.default)(domain)).join('.');
|
|
439
|
-
noSlugUrl = new URL(uri({
|
|
440
|
-
protocol: url.protocol,
|
|
441
|
-
hostname: _hostname,
|
|
442
|
-
port: url.port
|
|
443
|
-
}));
|
|
444
|
-
_context2.next = 12;
|
|
445
|
-
return isValidOrigin(noSlugUrl);
|
|
446
|
-
|
|
447
|
-
case 12:
|
|
448
|
-
if (!_context2.sent) {
|
|
449
|
-
_context2.next = 14;
|
|
450
|
-
break;
|
|
451
|
-
}
|
|
452
|
-
|
|
453
|
-
return _context2.abrupt("return", noSlugUrl);
|
|
454
|
-
|
|
455
|
-
case 14:
|
|
456
|
-
// Try to remove the first sub-domain in case its a nested app name
|
|
457
|
-
// eslint-disable-next-line no-unused-vars
|
|
458
|
-
hostname = url.hostname.split('.').splice(1).join('.');
|
|
459
|
-
noSubUrl = new URL(uri({
|
|
460
|
-
protocol: url.protocol,
|
|
461
|
-
hostname: hostname,
|
|
462
|
-
port: url.port
|
|
463
|
-
}));
|
|
464
|
-
_context2.next = 18;
|
|
465
|
-
return isValidOrigin(noSubUrl);
|
|
466
|
-
|
|
467
|
-
case 18:
|
|
468
|
-
if (!_context2.sent) {
|
|
469
|
-
_context2.next = 20;
|
|
470
|
-
break;
|
|
471
|
-
}
|
|
472
|
-
|
|
473
|
-
return _context2.abrupt("return", noSubUrl);
|
|
474
|
-
|
|
475
|
-
case 20:
|
|
476
|
-
throw new InvalidCozyUrlError(url);
|
|
477
|
-
|
|
478
|
-
case 21:
|
|
479
442
|
case "end":
|
|
480
443
|
return _context2.stop();
|
|
481
444
|
}
|
|
@@ -545,4 +508,188 @@ var isResponseAboutBlockedCozy = /*#__PURE__*/function () {
|
|
|
545
508
|
return function isResponseAboutBlockedCozy(_x3) {
|
|
546
509
|
return _ref5.apply(this, arguments);
|
|
547
510
|
};
|
|
548
|
-
}();
|
|
511
|
+
}();
|
|
512
|
+
/**
|
|
513
|
+
* Check if the given url uses the expected protocols (http or https). Throws otherwise
|
|
514
|
+
*
|
|
515
|
+
* @param {URL} url - URL to validate
|
|
516
|
+
*/
|
|
517
|
+
|
|
518
|
+
|
|
519
|
+
var throwIfInvalidProtocol = function throwIfInvalidProtocol(url) {
|
|
520
|
+
if (!['http:', 'https:'].includes(url.protocol)) {
|
|
521
|
+
throw new InvalidProtocolError(url);
|
|
522
|
+
}
|
|
523
|
+
};
|
|
524
|
+
|
|
525
|
+
var mayHaveSlug = function mayHaveSlug(url) {
|
|
526
|
+
return /^[^.-][^.]+-[^.-]+\./.test(url.hostname);
|
|
527
|
+
};
|
|
528
|
+
|
|
529
|
+
var removeSlug = function removeSlug(url) {
|
|
530
|
+
var _url$hostname$split = url.hostname.split('.'),
|
|
531
|
+
_url$hostname$split2 = (0, _toArray2.default)(_url$hostname$split),
|
|
532
|
+
subDomain = _url$hostname$split2[0],
|
|
533
|
+
domain = _url$hostname$split2.slice(1);
|
|
534
|
+
|
|
535
|
+
var hostname = [subDomain.replace(/-.+/, '')].concat((0, _toConsumableArray2.default)(domain)).join('.');
|
|
536
|
+
var noSlugUrl = new URL(uri({
|
|
537
|
+
protocol: url.protocol,
|
|
538
|
+
hostname: hostname,
|
|
539
|
+
port: url.port
|
|
540
|
+
}));
|
|
541
|
+
return noSlugUrl;
|
|
542
|
+
};
|
|
543
|
+
|
|
544
|
+
var removeSubdomain = function removeSubdomain(url) {
|
|
545
|
+
var hostname = url.hostname.split('.').splice(1).join('.');
|
|
546
|
+
var noSubUrl = new URL(uri({
|
|
547
|
+
protocol: url.protocol,
|
|
548
|
+
hostname: hostname,
|
|
549
|
+
port: url.port
|
|
550
|
+
}));
|
|
551
|
+
return noSubUrl;
|
|
552
|
+
};
|
|
553
|
+
/**
|
|
554
|
+
* @typedef {object} RegistrationDetails
|
|
555
|
+
* @property {URL} rootUrl - The Cozy's root URL
|
|
556
|
+
* @property {boolean} isOIDC - True if the Cozy's uses OIDC for login
|
|
557
|
+
*/
|
|
558
|
+
|
|
559
|
+
/**
|
|
560
|
+
* registrationDetails - Get the root URL and prelogin info of a Cozy from more
|
|
561
|
+
* precise ones
|
|
562
|
+
*
|
|
563
|
+
* The goal is to allow users to use any URL copied from their browser as their
|
|
564
|
+
* Cozy URL rather than trying to explain to them what we expect (e.g. when
|
|
565
|
+
* requesting the Cozy URL to connect an app).
|
|
566
|
+
* If we can't get the root URL either because there's no Cozy or the domain
|
|
567
|
+
* does not exist or anything else, we'll throw an InvalidCozyUrlError.
|
|
568
|
+
* Also, since we communicate only via HTTP or HTTPS, we'll throw an
|
|
569
|
+
* InvalidProtocolError if any other protocol is used.
|
|
570
|
+
*
|
|
571
|
+
* This function expects a fully qualified URL thus with a protocol and a valid
|
|
572
|
+
* hostname. If your application accepts Cozy intances as input (e.g. `claude`
|
|
573
|
+
* when the Cozy can be found at `https://claude.mycozy.cloud`), it is your
|
|
574
|
+
* responsibility to add the appropriate domain to the hostname before calling
|
|
575
|
+
* this function.
|
|
576
|
+
*
|
|
577
|
+
* Examples:
|
|
578
|
+
*
|
|
579
|
+
* 1. getting the root URL when your user gives you its instance name
|
|
580
|
+
*
|
|
581
|
+
* const userInput = 'claude'
|
|
582
|
+
* const details = await fetchRegistrationDetails(new URL(`https://${userInput}.mycozy.cloud`))
|
|
583
|
+
* // → returns { rootUrl: new URL('https://claude.mycozy.cloud'), isOIDC: false }
|
|
584
|
+
*
|
|
585
|
+
* 2. getting the root URL when your user gives you a Cozy Drive URL
|
|
586
|
+
*
|
|
587
|
+
* const userInput = 'https://claude-drive.mycozy.cloud/#/folder/io.cozy.files.root-dir'
|
|
588
|
+
* const rootUrl = await fetchRegistrationDetails(new URL(userInput))
|
|
589
|
+
* // → returns { rootUrl: new URL('https://claude.mycozy.cloud'), isOIDC: false }
|
|
590
|
+
*
|
|
591
|
+
* 3. getting the root URL when the Cozy uses nested sub-domains
|
|
592
|
+
*
|
|
593
|
+
* const userInput = 'http://photos.camille.nimbus.com:8080/#/album/1234567890'
|
|
594
|
+
* const rootCozyUrl = await fetchRegistrationDetails(new URL(userInput))
|
|
595
|
+
* // → returns { rootUrl: new URL('http://camille.nimbus.com:8080'), isOIDC: false }
|
|
596
|
+
*
|
|
597
|
+
* 4. getting the root URL when your user gives you an instance from OIDC partners
|
|
598
|
+
*
|
|
599
|
+
* const details = await fetchRegistrationDetails(new URL(`https://alice.someoidcpartener.com`))
|
|
600
|
+
* // → returns { rootUrl: new URL('https://alice.someoidcpartener.com'), isOIDC: true }
|
|
601
|
+
*
|
|
602
|
+
* @param {URL} url The URL from which we'll try to get the root Cozy URL
|
|
603
|
+
*
|
|
604
|
+
* @returns {Promise<RegistrationDetails>} The root Cozy URL
|
|
605
|
+
*/
|
|
606
|
+
|
|
607
|
+
|
|
608
|
+
var fetchRegistrationDetails = /*#__PURE__*/function () {
|
|
609
|
+
var _ref6 = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee4(url) {
|
|
610
|
+
var preloginData, noSlugUrl, noSlugPreloginData, noSubUrl, noSubPreloginData;
|
|
611
|
+
return _regenerator.default.wrap(function _callee4$(_context4) {
|
|
612
|
+
while (1) {
|
|
613
|
+
switch (_context4.prev = _context4.next) {
|
|
614
|
+
case 0:
|
|
615
|
+
throwIfInvalidProtocol(url);
|
|
616
|
+
_context4.next = 3;
|
|
617
|
+
return isValidOrigin(url);
|
|
618
|
+
|
|
619
|
+
case 3:
|
|
620
|
+
preloginData = _context4.sent;
|
|
621
|
+
|
|
622
|
+
if (!preloginData) {
|
|
623
|
+
_context4.next = 6;
|
|
624
|
+
break;
|
|
625
|
+
}
|
|
626
|
+
|
|
627
|
+
return _context4.abrupt("return", {
|
|
628
|
+
rootUrl: new URL(uri({
|
|
629
|
+
protocol: url.protocol,
|
|
630
|
+
hostname: url.hostname,
|
|
631
|
+
port: url.port
|
|
632
|
+
})),
|
|
633
|
+
isOIDC: preloginData.OIDC
|
|
634
|
+
});
|
|
635
|
+
|
|
636
|
+
case 6:
|
|
637
|
+
if (!mayHaveSlug(url)) {
|
|
638
|
+
_context4.next = 13;
|
|
639
|
+
break;
|
|
640
|
+
}
|
|
641
|
+
|
|
642
|
+
noSlugUrl = removeSlug(url);
|
|
643
|
+
_context4.next = 10;
|
|
644
|
+
return isValidOrigin(noSlugUrl);
|
|
645
|
+
|
|
646
|
+
case 10:
|
|
647
|
+
noSlugPreloginData = _context4.sent;
|
|
648
|
+
|
|
649
|
+
if (!noSlugPreloginData) {
|
|
650
|
+
_context4.next = 13;
|
|
651
|
+
break;
|
|
652
|
+
}
|
|
653
|
+
|
|
654
|
+
return _context4.abrupt("return", {
|
|
655
|
+
rootUrl: noSlugUrl,
|
|
656
|
+
isOIDC: noSlugPreloginData.OIDC
|
|
657
|
+
});
|
|
658
|
+
|
|
659
|
+
case 13:
|
|
660
|
+
// Try to remove the first sub-domain in case its a nested app name
|
|
661
|
+
// eslint-disable-next-line no-unused-vars
|
|
662
|
+
noSubUrl = removeSubdomain(url);
|
|
663
|
+
_context4.next = 16;
|
|
664
|
+
return isValidOrigin(noSubUrl);
|
|
665
|
+
|
|
666
|
+
case 16:
|
|
667
|
+
noSubPreloginData = _context4.sent;
|
|
668
|
+
|
|
669
|
+
if (!noSubPreloginData) {
|
|
670
|
+
_context4.next = 19;
|
|
671
|
+
break;
|
|
672
|
+
}
|
|
673
|
+
|
|
674
|
+
return _context4.abrupt("return", {
|
|
675
|
+
rootUrl: noSubUrl,
|
|
676
|
+
isOIDC: noSubPreloginData.OIDC
|
|
677
|
+
});
|
|
678
|
+
|
|
679
|
+
case 19:
|
|
680
|
+
throw new InvalidCozyUrlError(url);
|
|
681
|
+
|
|
682
|
+
case 20:
|
|
683
|
+
case "end":
|
|
684
|
+
return _context4.stop();
|
|
685
|
+
}
|
|
686
|
+
}
|
|
687
|
+
}, _callee4);
|
|
688
|
+
}));
|
|
689
|
+
|
|
690
|
+
return function fetchRegistrationDetails(_x4) {
|
|
691
|
+
return _ref6.apply(this, arguments);
|
|
692
|
+
};
|
|
693
|
+
}();
|
|
694
|
+
|
|
695
|
+
exports.fetchRegistrationDetails = fetchRegistrationDetails;
|
|
@@ -4,6 +4,7 @@ import {
|
|
|
4
4
|
deconstructCozyWebLinkWithSlug,
|
|
5
5
|
deconstructRedirectLink,
|
|
6
6
|
generateWebLink,
|
|
7
|
+
fetchRegistrationDetails,
|
|
7
8
|
rootCozyUrl,
|
|
8
9
|
InvalidRedirectLinkError,
|
|
9
10
|
InvalidCozyUrlError,
|
|
@@ -203,11 +204,14 @@ describe('rootCozyUrl', () => {
|
|
|
203
204
|
|
|
204
205
|
it('should handle cozy-hosted https', async () => {
|
|
205
206
|
fetch.mockOnceIf(
|
|
206
|
-
'https://camillenimbus.mycozy.cloud
|
|
207
|
-
|
|
207
|
+
'https://camillenimbus.mycozy.cloud/public/prelogin',
|
|
208
|
+
fakeCozyPrelogin(),
|
|
208
209
|
{
|
|
209
210
|
status: 200,
|
|
210
|
-
url: 'https://camillenimbus.mycozy.cloud
|
|
211
|
+
url: 'https://camillenimbus.mycozy.cloud/public/prelogin',
|
|
212
|
+
headers: {
|
|
213
|
+
'content-type': 'application/json'
|
|
214
|
+
}
|
|
211
215
|
}
|
|
212
216
|
)
|
|
213
217
|
|
|
@@ -218,11 +222,14 @@ describe('rootCozyUrl', () => {
|
|
|
218
222
|
|
|
219
223
|
it('should handle cozy-hosted https trailing slash', async () => {
|
|
220
224
|
fetch.mockOnceIf(
|
|
221
|
-
'https://camillenimbus.mycozy.cloud
|
|
222
|
-
|
|
225
|
+
'https://camillenimbus.mycozy.cloud/public/prelogin',
|
|
226
|
+
fakeCozyPrelogin(),
|
|
223
227
|
{
|
|
224
228
|
status: 200,
|
|
225
|
-
url: 'https://camillenimbus.mycozy.cloud
|
|
229
|
+
url: 'https://camillenimbus.mycozy.cloud/public/prelogin',
|
|
230
|
+
headers: {
|
|
231
|
+
'content-type': 'application/json'
|
|
232
|
+
}
|
|
226
233
|
}
|
|
227
234
|
)
|
|
228
235
|
|
|
@@ -233,11 +240,14 @@ describe('rootCozyUrl', () => {
|
|
|
233
240
|
|
|
234
241
|
it('should handle cozy-hosted https trailing path', async () => {
|
|
235
242
|
fetch.mockOnceIf(
|
|
236
|
-
'https://camillenimbus.mycozy.cloud
|
|
237
|
-
|
|
243
|
+
'https://camillenimbus.mycozy.cloud/public/prelogin',
|
|
244
|
+
fakeCozyPrelogin(),
|
|
238
245
|
{
|
|
239
246
|
status: 200,
|
|
240
|
-
url: 'https://camillenimbus.mycozy.cloud
|
|
247
|
+
url: 'https://camillenimbus.mycozy.cloud/public/prelogin',
|
|
248
|
+
headers: {
|
|
249
|
+
'content-type': 'application/json'
|
|
250
|
+
}
|
|
241
251
|
}
|
|
242
252
|
)
|
|
243
253
|
|
|
@@ -248,20 +258,22 @@ describe('rootCozyUrl', () => {
|
|
|
248
258
|
|
|
249
259
|
it('should handle cozy-hosted drive web app url', async () => {
|
|
250
260
|
fetch.mockOnceIf(
|
|
251
|
-
'https://camillenimbus-drive.mycozy.cloud
|
|
261
|
+
'https://camillenimbus-drive.mycozy.cloud/public/prelogin',
|
|
252
262
|
{},
|
|
253
263
|
{
|
|
254
264
|
status: 401,
|
|
255
|
-
url:
|
|
256
|
-
'https://camillenimbus-drive.mycozy.cloud/.well-known/change-password'
|
|
265
|
+
url: 'https://camillenimbus-drive.mycozy.cloud/public/prelogin'
|
|
257
266
|
}
|
|
258
267
|
)
|
|
259
268
|
fetch.mockOnceIf(
|
|
260
|
-
'https://camillenimbus.mycozy.cloud
|
|
261
|
-
|
|
269
|
+
'https://camillenimbus.mycozy.cloud/public/prelogin',
|
|
270
|
+
fakeCozyPrelogin(),
|
|
262
271
|
{
|
|
263
272
|
status: 200,
|
|
264
|
-
url: 'https://camillenimbus.mycozy.cloud
|
|
273
|
+
url: 'https://camillenimbus.mycozy.cloud/public/prelogin',
|
|
274
|
+
headers: {
|
|
275
|
+
'content-type': 'application/json'
|
|
276
|
+
}
|
|
265
277
|
}
|
|
266
278
|
)
|
|
267
279
|
|
|
@@ -272,20 +284,22 @@ describe('rootCozyUrl', () => {
|
|
|
272
284
|
|
|
273
285
|
it('should handle cozy-hosted photos album url', async () => {
|
|
274
286
|
fetch.mockOnceIf(
|
|
275
|
-
'https://camillenimbus-photos.mycozy.cloud
|
|
287
|
+
'https://camillenimbus-photos.mycozy.cloud/public/prelogin',
|
|
276
288
|
{},
|
|
277
289
|
{
|
|
278
290
|
status: 401,
|
|
279
|
-
url:
|
|
280
|
-
'https://camillenimbus-photos.mycozy.cloud/.well-known/change-password'
|
|
291
|
+
url: 'https://camillenimbus-photos.mycozy.cloud/public/prelogin'
|
|
281
292
|
}
|
|
282
293
|
)
|
|
283
294
|
fetch.mockOnceIf(
|
|
284
|
-
'https://camillenimbus.mycozy.cloud
|
|
285
|
-
|
|
295
|
+
'https://camillenimbus.mycozy.cloud/public/prelogin',
|
|
296
|
+
fakeCozyPrelogin(),
|
|
286
297
|
{
|
|
287
298
|
status: 200,
|
|
288
|
-
url: 'https://camillenimbus.mycozy.cloud
|
|
299
|
+
url: 'https://camillenimbus.mycozy.cloud/public/prelogin',
|
|
300
|
+
headers: {
|
|
301
|
+
'content-type': 'application/json'
|
|
302
|
+
}
|
|
289
303
|
}
|
|
290
304
|
)
|
|
291
305
|
|
|
@@ -300,20 +314,22 @@ describe('rootCozyUrl', () => {
|
|
|
300
314
|
|
|
301
315
|
it('should handle cozy-hosted app name', async () => {
|
|
302
316
|
fetch.mockOnceIf(
|
|
303
|
-
'https://camillenimbus-drive.mycozy.cloud
|
|
317
|
+
'https://camillenimbus-drive.mycozy.cloud/public/prelogin',
|
|
304
318
|
{},
|
|
305
319
|
{
|
|
306
320
|
status: 401,
|
|
307
|
-
url:
|
|
308
|
-
'https://camillenimbus-drive.mycozy.cloud/.well-known/change-password'
|
|
321
|
+
url: 'https://camillenimbus-drive.mycozy.cloud/public/prelogin'
|
|
309
322
|
}
|
|
310
323
|
)
|
|
311
324
|
fetch.mockOnceIf(
|
|
312
|
-
'https://camillenimbus.mycozy.cloud
|
|
313
|
-
|
|
325
|
+
'https://camillenimbus.mycozy.cloud/public/prelogin',
|
|
326
|
+
fakeCozyPrelogin(),
|
|
314
327
|
{
|
|
315
328
|
status: 200,
|
|
316
|
-
url: 'https://camillenimbus.mycozy.cloud
|
|
329
|
+
url: 'https://camillenimbus.mycozy.cloud/public/prelogin',
|
|
330
|
+
headers: {
|
|
331
|
+
'content-type': 'application/json'
|
|
332
|
+
}
|
|
317
333
|
}
|
|
318
334
|
)
|
|
319
335
|
|
|
@@ -327,7 +343,7 @@ describe('rootCozyUrl', () => {
|
|
|
327
343
|
// `onboarding`) to the Home app (via the login page if the user is not
|
|
328
344
|
// logged in).
|
|
329
345
|
fetch.mockOnceIf(
|
|
330
|
-
'https://camillenimbus-onboarding.mycozy.cloud
|
|
346
|
+
'https://camillenimbus-onboarding.mycozy.cloud/public/prelogin',
|
|
331
347
|
{},
|
|
332
348
|
{
|
|
333
349
|
status: 200,
|
|
@@ -336,11 +352,14 @@ describe('rootCozyUrl', () => {
|
|
|
336
352
|
}
|
|
337
353
|
)
|
|
338
354
|
fetch.mockOnceIf(
|
|
339
|
-
'https://camillenimbus.mycozy.cloud
|
|
340
|
-
|
|
355
|
+
'https://camillenimbus.mycozy.cloud/public/prelogin',
|
|
356
|
+
fakeCozyPrelogin(),
|
|
341
357
|
{
|
|
342
358
|
status: 200,
|
|
343
|
-
url: 'https://camillenimbus.mycozy.cloud
|
|
359
|
+
url: 'https://camillenimbus.mycozy.cloud/public/prelogin',
|
|
360
|
+
headers: {
|
|
361
|
+
'content-type': 'application/json'
|
|
362
|
+
}
|
|
344
363
|
}
|
|
345
364
|
)
|
|
346
365
|
|
|
@@ -351,11 +370,14 @@ describe('rootCozyUrl', () => {
|
|
|
351
370
|
|
|
352
371
|
it('should handle self-hosted https', async () => {
|
|
353
372
|
fetch.mockOnceIf(
|
|
354
|
-
'https://camillenimbus.com
|
|
355
|
-
|
|
373
|
+
'https://camillenimbus.com/public/prelogin',
|
|
374
|
+
fakeCozyPrelogin(),
|
|
356
375
|
{
|
|
357
376
|
status: 200,
|
|
358
|
-
url: 'https://camillenimbus.com
|
|
377
|
+
url: 'https://camillenimbus.com/public/prelogin',
|
|
378
|
+
headers: {
|
|
379
|
+
'content-type': 'application/json'
|
|
380
|
+
}
|
|
359
381
|
}
|
|
360
382
|
)
|
|
361
383
|
|
|
@@ -366,11 +388,14 @@ describe('rootCozyUrl', () => {
|
|
|
366
388
|
|
|
367
389
|
it('should handle self-hosted with dash', async () => {
|
|
368
390
|
fetch.mockOnceIf(
|
|
369
|
-
'https://camille-nimbus.com
|
|
370
|
-
|
|
391
|
+
'https://camille-nimbus.com/public/prelogin',
|
|
392
|
+
fakeCozyPrelogin(),
|
|
371
393
|
{
|
|
372
394
|
status: 200,
|
|
373
|
-
url: 'https://camille-nimbus.com
|
|
395
|
+
url: 'https://camille-nimbus.com/public/prelogin',
|
|
396
|
+
headers: {
|
|
397
|
+
'content-type': 'application/json'
|
|
398
|
+
}
|
|
374
399
|
}
|
|
375
400
|
)
|
|
376
401
|
|
|
@@ -381,11 +406,14 @@ describe('rootCozyUrl', () => {
|
|
|
381
406
|
|
|
382
407
|
it('should handle self-hosted http', async () => {
|
|
383
408
|
fetch.mockOnceIf(
|
|
384
|
-
'http://camille-nimbus.com
|
|
385
|
-
|
|
409
|
+
'http://camille-nimbus.com/public/prelogin',
|
|
410
|
+
fakeCozyPrelogin(),
|
|
386
411
|
{
|
|
387
412
|
status: 200,
|
|
388
|
-
url: 'http://camille-nimbus.com
|
|
413
|
+
url: 'http://camille-nimbus.com/public/prelogin',
|
|
414
|
+
headers: {
|
|
415
|
+
'content-type': 'application/json'
|
|
416
|
+
}
|
|
389
417
|
}
|
|
390
418
|
)
|
|
391
419
|
|
|
@@ -396,11 +424,14 @@ describe('rootCozyUrl', () => {
|
|
|
396
424
|
|
|
397
425
|
it('should handle self-hosted https with port', async () => {
|
|
398
426
|
fetch.mockOnceIf(
|
|
399
|
-
'https://camillenimbus.com:666
|
|
400
|
-
|
|
427
|
+
'https://camillenimbus.com:666/public/prelogin',
|
|
428
|
+
fakeCozyPrelogin(),
|
|
401
429
|
{
|
|
402
430
|
status: 200,
|
|
403
|
-
url: 'https://camillenimbus.com:666
|
|
431
|
+
url: 'https://camillenimbus.com:666/public/prelogin',
|
|
432
|
+
headers: {
|
|
433
|
+
'content-type': 'application/json'
|
|
434
|
+
}
|
|
404
435
|
}
|
|
405
436
|
)
|
|
406
437
|
|
|
@@ -411,19 +442,22 @@ describe('rootCozyUrl', () => {
|
|
|
411
442
|
|
|
412
443
|
it('should handle self-hosted nested drive web app url', async () => {
|
|
413
444
|
fetch.mockOnceIf(
|
|
414
|
-
'https://drive.camillenimbus.com
|
|
445
|
+
'https://drive.camillenimbus.com/public/prelogin',
|
|
415
446
|
{},
|
|
416
447
|
{
|
|
417
448
|
status: 401,
|
|
418
|
-
url: 'https://drive.camillenimbus.com
|
|
449
|
+
url: 'https://drive.camillenimbus.com/public/prelogin'
|
|
419
450
|
}
|
|
420
451
|
)
|
|
421
452
|
fetch.mockOnceIf(
|
|
422
|
-
'https://camillenimbus.com
|
|
423
|
-
|
|
453
|
+
'https://camillenimbus.com/public/prelogin',
|
|
454
|
+
fakeCozyPrelogin(),
|
|
424
455
|
{
|
|
425
456
|
status: 200,
|
|
426
|
-
url: 'https://camillenimbus.com
|
|
457
|
+
url: 'https://camillenimbus.com/public/prelogin',
|
|
458
|
+
headers: {
|
|
459
|
+
'content-type': 'application/json'
|
|
460
|
+
}
|
|
427
461
|
}
|
|
428
462
|
)
|
|
429
463
|
|
|
@@ -434,19 +468,22 @@ describe('rootCozyUrl', () => {
|
|
|
434
468
|
|
|
435
469
|
it('should handle self-hosted flat drive web app url', async () => {
|
|
436
470
|
fetch.mockOnceIf(
|
|
437
|
-
'https://camille-drive.nimbus.com
|
|
471
|
+
'https://camille-drive.nimbus.com/public/prelogin',
|
|
438
472
|
{},
|
|
439
473
|
{
|
|
440
474
|
status: 401,
|
|
441
|
-
url: 'https://camille-drive.nimbus.com
|
|
475
|
+
url: 'https://camille-drive.nimbus.com/public/prelogin'
|
|
442
476
|
}
|
|
443
477
|
)
|
|
444
478
|
fetch.mockOnceIf(
|
|
445
|
-
'https://camille.nimbus.com
|
|
446
|
-
|
|
479
|
+
'https://camille.nimbus.com/public/prelogin',
|
|
480
|
+
fakeCozyPrelogin(),
|
|
447
481
|
{
|
|
448
482
|
status: 200,
|
|
449
|
-
url: 'https://camille.nimbus.com
|
|
483
|
+
url: 'https://camille.nimbus.com/public/prelogin',
|
|
484
|
+
headers: {
|
|
485
|
+
'content-type': 'application/json'
|
|
486
|
+
}
|
|
450
487
|
}
|
|
451
488
|
)
|
|
452
489
|
|
|
@@ -457,11 +494,14 @@ describe('rootCozyUrl', () => {
|
|
|
457
494
|
|
|
458
495
|
it('should handle cozy.localhost', async () => {
|
|
459
496
|
fetch.mockOnceIf(
|
|
460
|
-
'http://cozy.localhost:8080
|
|
461
|
-
|
|
497
|
+
'http://cozy.localhost:8080/public/prelogin',
|
|
498
|
+
fakeCozyPrelogin(),
|
|
462
499
|
{
|
|
463
500
|
status: 200,
|
|
464
|
-
url: 'http://cozy.localhost:8080
|
|
501
|
+
url: 'http://cozy.localhost:8080/public/prelogin',
|
|
502
|
+
headers: {
|
|
503
|
+
'content-type': 'application/json'
|
|
504
|
+
}
|
|
465
505
|
}
|
|
466
506
|
)
|
|
467
507
|
await expect(
|
|
@@ -471,11 +511,11 @@ describe('rootCozyUrl', () => {
|
|
|
471
511
|
|
|
472
512
|
it('expects an http or https protocol', async () => {
|
|
473
513
|
fetch.mockOnceIf(
|
|
474
|
-
'ftp://camillenimbus.com
|
|
514
|
+
'ftp://camillenimbus.com/public/prelogin',
|
|
475
515
|
{},
|
|
476
516
|
{
|
|
477
517
|
status: 200,
|
|
478
|
-
url: 'ftp://camillenimbus.com
|
|
518
|
+
url: 'ftp://camillenimbus.com/public/prelogin'
|
|
479
519
|
}
|
|
480
520
|
)
|
|
481
521
|
|
|
@@ -486,11 +526,11 @@ describe('rootCozyUrl', () => {
|
|
|
486
526
|
|
|
487
527
|
it('rejects if URL points to a valid cozy-stack but no valid Cozy instance', async () => {
|
|
488
528
|
fetch.mockOnceIf(
|
|
489
|
-
'https://missing.mycozy.cloud
|
|
529
|
+
'https://missing.mycozy.cloud/public/prelogin',
|
|
490
530
|
{},
|
|
491
531
|
{
|
|
492
532
|
status: 404,
|
|
493
|
-
url: 'https://missing.mycozy.cloud
|
|
533
|
+
url: 'https://missing.mycozy.cloud/public/prelogin'
|
|
494
534
|
}
|
|
495
535
|
)
|
|
496
536
|
|
|
@@ -518,7 +558,7 @@ describe('rootCozyUrl', () => {
|
|
|
518
558
|
status: 503,
|
|
519
559
|
statusText: '',
|
|
520
560
|
type: 'default',
|
|
521
|
-
url: 'https://camillenimbus.com
|
|
561
|
+
url: 'https://camillenimbus.com/public/prelogin'
|
|
522
562
|
})
|
|
523
563
|
})
|
|
524
564
|
|
|
@@ -546,7 +586,7 @@ describe('rootCozyUrl', () => {
|
|
|
546
586
|
status: 503,
|
|
547
587
|
statusText: '',
|
|
548
588
|
type: 'default',
|
|
549
|
-
url: 'https://camillenimbus.com
|
|
589
|
+
url: 'https://camillenimbus.com/public/prelogin'
|
|
550
590
|
})
|
|
551
591
|
})
|
|
552
592
|
|
|
@@ -555,3 +595,431 @@ describe('rootCozyUrl', () => {
|
|
|
555
595
|
).rejects.toBeInstanceOf(InvalidCozyUrlError)
|
|
556
596
|
})
|
|
557
597
|
})
|
|
598
|
+
|
|
599
|
+
describe('fetchRegistrationDetails', () => {
|
|
600
|
+
beforeAll(() => {
|
|
601
|
+
enableFetchMocks()
|
|
602
|
+
})
|
|
603
|
+
|
|
604
|
+
beforeEach(() => {
|
|
605
|
+
fetch.resetMocks()
|
|
606
|
+
})
|
|
607
|
+
|
|
608
|
+
afterAll(() => {
|
|
609
|
+
disableFetchMocks()
|
|
610
|
+
})
|
|
611
|
+
|
|
612
|
+
it('should handle cozy-hosted https', async () => {
|
|
613
|
+
mockFetchJsonOnce(
|
|
614
|
+
'https://camillenimbus.mycozy.cloud/public/prelogin',
|
|
615
|
+
fakeCozyPrelogin()
|
|
616
|
+
)
|
|
617
|
+
|
|
618
|
+
await expect(
|
|
619
|
+
fetchRegistrationDetails(new URL('https://camillenimbus.mycozy.cloud'))
|
|
620
|
+
).resolves.toStrictEqual({
|
|
621
|
+
rootUrl: new URL('https://camillenimbus.mycozy.cloud/'),
|
|
622
|
+
isOIDC: false
|
|
623
|
+
})
|
|
624
|
+
})
|
|
625
|
+
|
|
626
|
+
it('should handle cozy-hosted https trailing slash', async () => {
|
|
627
|
+
mockFetchJsonOnce(
|
|
628
|
+
'https://camillenimbus.mycozy.cloud/public/prelogin',
|
|
629
|
+
fakeCozyPrelogin()
|
|
630
|
+
)
|
|
631
|
+
|
|
632
|
+
await expect(
|
|
633
|
+
fetchRegistrationDetails(new URL('https://camillenimbus.mycozy.cloud/'))
|
|
634
|
+
).resolves.toStrictEqual({
|
|
635
|
+
rootUrl: new URL('https://camillenimbus.mycozy.cloud/'),
|
|
636
|
+
isOIDC: false
|
|
637
|
+
})
|
|
638
|
+
})
|
|
639
|
+
|
|
640
|
+
it('should handle cozy-hosted https trailing path', async () => {
|
|
641
|
+
mockFetchJsonOnce(
|
|
642
|
+
'https://camillenimbus.mycozy.cloud/public/prelogin',
|
|
643
|
+
fakeCozyPrelogin()
|
|
644
|
+
)
|
|
645
|
+
|
|
646
|
+
await expect(
|
|
647
|
+
fetchRegistrationDetails(
|
|
648
|
+
new URL('https://camillenimbus.mycozy.cloud/some-path')
|
|
649
|
+
)
|
|
650
|
+
).resolves.toStrictEqual({
|
|
651
|
+
rootUrl: new URL('https://camillenimbus.mycozy.cloud/'),
|
|
652
|
+
isOIDC: false
|
|
653
|
+
})
|
|
654
|
+
})
|
|
655
|
+
|
|
656
|
+
it('should handle cozy-hosted drive web app url', async () => {
|
|
657
|
+
mockUnauthorizedOnce(
|
|
658
|
+
'https://camillenimbus-drive.mycozy.cloud/public/prelogin'
|
|
659
|
+
)
|
|
660
|
+
mockFetchJsonOnce(
|
|
661
|
+
'https://camillenimbus.mycozy.cloud/public/prelogin',
|
|
662
|
+
fakeCozyPrelogin()
|
|
663
|
+
)
|
|
664
|
+
|
|
665
|
+
await expect(
|
|
666
|
+
fetchRegistrationDetails(
|
|
667
|
+
new URL('https://camillenimbus-drive.mycozy.cloud/#/folder')
|
|
668
|
+
)
|
|
669
|
+
).resolves.toStrictEqual({
|
|
670
|
+
rootUrl: new URL('https://camillenimbus.mycozy.cloud/'),
|
|
671
|
+
isOIDC: false
|
|
672
|
+
})
|
|
673
|
+
})
|
|
674
|
+
|
|
675
|
+
it('should handle cozy-hosted photos album url', async () => {
|
|
676
|
+
mockUnauthorizedOnce(
|
|
677
|
+
'https://camillenimbus-photos.mycozy.cloud/public/prelogin'
|
|
678
|
+
)
|
|
679
|
+
mockFetchJsonOnce(
|
|
680
|
+
'https://camillenimbus.mycozy.cloud/public/prelogin',
|
|
681
|
+
fakeCozyPrelogin()
|
|
682
|
+
)
|
|
683
|
+
|
|
684
|
+
await expect(
|
|
685
|
+
fetchRegistrationDetails(
|
|
686
|
+
new URL(
|
|
687
|
+
'https://camillenimbus-photos.mycozy.cloud/#/albums/68b5cda502ae29f5fa73fd89f1be4f92'
|
|
688
|
+
)
|
|
689
|
+
)
|
|
690
|
+
).resolves.toStrictEqual({
|
|
691
|
+
rootUrl: new URL('https://camillenimbus.mycozy.cloud/'),
|
|
692
|
+
isOIDC: false
|
|
693
|
+
})
|
|
694
|
+
})
|
|
695
|
+
|
|
696
|
+
it('should handle cozy-hosted app name', async () => {
|
|
697
|
+
mockUnauthorizedOnce(
|
|
698
|
+
'https://camillenimbus-someslug.mycozy.cloud/public/prelogin'
|
|
699
|
+
)
|
|
700
|
+
mockFetchJsonOnce(
|
|
701
|
+
'https://camillenimbus.mycozy.cloud/public/prelogin',
|
|
702
|
+
fakeCozyPrelogin()
|
|
703
|
+
)
|
|
704
|
+
|
|
705
|
+
await expect(
|
|
706
|
+
fetchRegistrationDetails(
|
|
707
|
+
new URL('https://camillenimbus-someslug.mycozy.cloud')
|
|
708
|
+
)
|
|
709
|
+
).resolves.toStrictEqual({
|
|
710
|
+
rootUrl: new URL('https://camillenimbus.mycozy.cloud/'),
|
|
711
|
+
isOIDC: false
|
|
712
|
+
})
|
|
713
|
+
})
|
|
714
|
+
|
|
715
|
+
it('should handle cozy-hosted special app name', async () => {
|
|
716
|
+
// XXX: `cozy-stack` redirects requests for deprecated apps (e.g.
|
|
717
|
+
// `onboarding`) to the Home app (via the login page if the user is not
|
|
718
|
+
// logged in).
|
|
719
|
+
mockRedirectOnce(
|
|
720
|
+
'https://camillenimbus-onboarding.mycozy.cloud/public/prelogin',
|
|
721
|
+
'https://camillenimbus.mycozy.cloud/auth/login?redirect=https%3A%2F%2Fcamillenimbus-home.mycozy.cloud%2F'
|
|
722
|
+
)
|
|
723
|
+
mockFetchJsonOnce(
|
|
724
|
+
'https://camillenimbus.mycozy.cloud/public/prelogin',
|
|
725
|
+
fakeCozyPrelogin()
|
|
726
|
+
)
|
|
727
|
+
|
|
728
|
+
await expect(
|
|
729
|
+
fetchRegistrationDetails(
|
|
730
|
+
new URL('https://camillenimbus-onboarding.mycozy.cloud')
|
|
731
|
+
)
|
|
732
|
+
).resolves.toStrictEqual({
|
|
733
|
+
rootUrl: new URL('https://camillenimbus.mycozy.cloud/'),
|
|
734
|
+
isOIDC: false
|
|
735
|
+
})
|
|
736
|
+
})
|
|
737
|
+
|
|
738
|
+
it('should handle self-hosted https', async () => {
|
|
739
|
+
mockFetchJsonOnce(
|
|
740
|
+
'https://camillenimbus.com/public/prelogin',
|
|
741
|
+
fakeCozyPrelogin()
|
|
742
|
+
)
|
|
743
|
+
|
|
744
|
+
await expect(
|
|
745
|
+
fetchRegistrationDetails(new URL('https://camillenimbus.com'))
|
|
746
|
+
).resolves.toStrictEqual({
|
|
747
|
+
rootUrl: new URL('https://camillenimbus.com/'),
|
|
748
|
+
isOIDC: false
|
|
749
|
+
})
|
|
750
|
+
})
|
|
751
|
+
|
|
752
|
+
it('should handle self-hosted with dash', async () => {
|
|
753
|
+
mockFetchJsonOnce(
|
|
754
|
+
'https://camille-nimbus.com/public/prelogin',
|
|
755
|
+
fakeCozyPrelogin()
|
|
756
|
+
)
|
|
757
|
+
|
|
758
|
+
await expect(
|
|
759
|
+
fetchRegistrationDetails(new URL('https://camille-nimbus.com'))
|
|
760
|
+
).resolves.toStrictEqual({
|
|
761
|
+
rootUrl: new URL('https://camille-nimbus.com/'),
|
|
762
|
+
isOIDC: false
|
|
763
|
+
})
|
|
764
|
+
})
|
|
765
|
+
|
|
766
|
+
it('should handle self-hosted http', async () => {
|
|
767
|
+
mockFetchJsonOnce(
|
|
768
|
+
'http://camille-nimbus.com/public/prelogin',
|
|
769
|
+
fakeCozyPrelogin()
|
|
770
|
+
)
|
|
771
|
+
|
|
772
|
+
await expect(
|
|
773
|
+
fetchRegistrationDetails(new URL('http://camille-nimbus.com'))
|
|
774
|
+
).resolves.toStrictEqual({
|
|
775
|
+
rootUrl: new URL('http://camille-nimbus.com/'),
|
|
776
|
+
isOIDC: false
|
|
777
|
+
})
|
|
778
|
+
})
|
|
779
|
+
|
|
780
|
+
it('should handle self-hosted https with port', async () => {
|
|
781
|
+
mockFetchJsonOnce(
|
|
782
|
+
'https://camillenimbus.com:666/public/prelogin',
|
|
783
|
+
fakeCozyPrelogin()
|
|
784
|
+
)
|
|
785
|
+
|
|
786
|
+
await expect(
|
|
787
|
+
fetchRegistrationDetails(new URL('https://camillenimbus.com:666'))
|
|
788
|
+
).resolves.toStrictEqual({
|
|
789
|
+
rootUrl: new URL('https://camillenimbus.com:666/'),
|
|
790
|
+
isOIDC: false
|
|
791
|
+
})
|
|
792
|
+
})
|
|
793
|
+
|
|
794
|
+
it('should handle self-hosted nested drive web app url', async () => {
|
|
795
|
+
mockUnauthorizedOnce('https://drive.camillenimbus.com/public/prelogin')
|
|
796
|
+
mockFetchJsonOnce(
|
|
797
|
+
'https://camillenimbus.com/public/prelogin',
|
|
798
|
+
fakeCozyPrelogin()
|
|
799
|
+
)
|
|
800
|
+
|
|
801
|
+
await expect(
|
|
802
|
+
fetchRegistrationDetails(
|
|
803
|
+
new URL('https://drive.camillenimbus.com/#/folder')
|
|
804
|
+
)
|
|
805
|
+
).resolves.toStrictEqual({
|
|
806
|
+
rootUrl: new URL('https://camillenimbus.com/'),
|
|
807
|
+
isOIDC: false
|
|
808
|
+
})
|
|
809
|
+
})
|
|
810
|
+
|
|
811
|
+
it('should handle self-hosted flat drive web app url', async () => {
|
|
812
|
+
mockUnauthorizedOnce('https://camille-drive.nimbus.com/public/prelogin')
|
|
813
|
+
mockFetchJsonOnce(
|
|
814
|
+
'https://camille.nimbus.com/public/prelogin',
|
|
815
|
+
fakeCozyPrelogin()
|
|
816
|
+
)
|
|
817
|
+
|
|
818
|
+
await expect(
|
|
819
|
+
fetchRegistrationDetails(
|
|
820
|
+
new URL('https://camille-drive.nimbus.com/#/folder')
|
|
821
|
+
)
|
|
822
|
+
).resolves.toStrictEqual({
|
|
823
|
+
rootUrl: new URL('https://camille.nimbus.com/'),
|
|
824
|
+
isOIDC: false
|
|
825
|
+
})
|
|
826
|
+
})
|
|
827
|
+
|
|
828
|
+
it('should handle cozy.localhost', async () => {
|
|
829
|
+
mockFetchJsonOnce(
|
|
830
|
+
'http://cozy.localhost:8080/public/prelogin',
|
|
831
|
+
fakeCozyPrelogin()
|
|
832
|
+
)
|
|
833
|
+
await expect(
|
|
834
|
+
fetchRegistrationDetails(new URL('http://cozy.localhost:8080'))
|
|
835
|
+
).resolves.toStrictEqual({
|
|
836
|
+
rootUrl: new URL('http://cozy.localhost:8080/'),
|
|
837
|
+
isOIDC: false
|
|
838
|
+
})
|
|
839
|
+
})
|
|
840
|
+
|
|
841
|
+
it('expects an http or https protocol', async () => {
|
|
842
|
+
mockFetchJsonOnce(
|
|
843
|
+
'ftp://camillenimbus.com/public/prelogin',
|
|
844
|
+
fakeCozyPrelogin()
|
|
845
|
+
)
|
|
846
|
+
|
|
847
|
+
await expect(
|
|
848
|
+
fetchRegistrationDetails(new URL('ftp://camillenimbus.com'))
|
|
849
|
+
).rejects.toBeInstanceOf(InvalidProtocolError)
|
|
850
|
+
})
|
|
851
|
+
|
|
852
|
+
it('rejects if URL points to a valid cozy-stack but no valid Cozy instance', async () => {
|
|
853
|
+
mockNotFoundOnce('https://missing.mycozy.cloud/public/prelogin')
|
|
854
|
+
|
|
855
|
+
await expect(
|
|
856
|
+
fetchRegistrationDetails(new URL('https://missing.mycozy.cloud/'))
|
|
857
|
+
).rejects.toBeInstanceOf(InvalidCozyUrlError)
|
|
858
|
+
})
|
|
859
|
+
|
|
860
|
+
it('should reject if Blocked cozy', async () => {
|
|
861
|
+
mockBlockedCozy('https://camillenimbus.com/public/prelogin')
|
|
862
|
+
|
|
863
|
+
await expect(
|
|
864
|
+
fetchRegistrationDetails(new URL('https://camillenimbus.com'))
|
|
865
|
+
).rejects.toBeInstanceOf(BlockedCozyError)
|
|
866
|
+
})
|
|
867
|
+
|
|
868
|
+
it('should reject on 503 error (if not Blocked)', async () => {
|
|
869
|
+
mock503Error('https://camillenimbus.com/public/prelogin')
|
|
870
|
+
|
|
871
|
+
await expect(
|
|
872
|
+
fetchRegistrationDetails(new URL('https://camillenimbus.com'))
|
|
873
|
+
).rejects.toBeInstanceOf(InvalidCozyUrlError)
|
|
874
|
+
})
|
|
875
|
+
|
|
876
|
+
it('should handle OIDC cozy', async () => {
|
|
877
|
+
mockFetchJsonOnce(
|
|
878
|
+
'https://camillenimbus.mycozy.cloud/public/prelogin',
|
|
879
|
+
fakeOidcPrelogin()
|
|
880
|
+
)
|
|
881
|
+
|
|
882
|
+
await expect(
|
|
883
|
+
fetchRegistrationDetails(new URL('https://camillenimbus.mycozy.cloud'))
|
|
884
|
+
).resolves.toStrictEqual({
|
|
885
|
+
rootUrl: new URL('https://camillenimbus.mycozy.cloud/'),
|
|
886
|
+
isOIDC: true
|
|
887
|
+
})
|
|
888
|
+
})
|
|
889
|
+
|
|
890
|
+
it('should reject if non Json response', async () => {
|
|
891
|
+
mockFetchHtmlOnce(
|
|
892
|
+
'https://camillenimbus.com/public/prelogin',
|
|
893
|
+
'<html>Some HTML content</html>'
|
|
894
|
+
)
|
|
895
|
+
|
|
896
|
+
await expect(
|
|
897
|
+
fetchRegistrationDetails(new URL('https://camillenimbus.com'))
|
|
898
|
+
).rejects.toBeInstanceOf(InvalidCozyUrlError)
|
|
899
|
+
})
|
|
900
|
+
})
|
|
901
|
+
|
|
902
|
+
const mockFetchHtmlOnce = (url, response) => {
|
|
903
|
+
fetch.mockOnceIf(url, response, {
|
|
904
|
+
status: 200,
|
|
905
|
+
url: url,
|
|
906
|
+
headers: {
|
|
907
|
+
'content-type': 'text/html; charset=UTF-8'
|
|
908
|
+
}
|
|
909
|
+
})
|
|
910
|
+
}
|
|
911
|
+
|
|
912
|
+
const mockFetchJsonOnce = (url, response) => {
|
|
913
|
+
fetch.mockOnceIf(url, response, {
|
|
914
|
+
status: 200,
|
|
915
|
+
url: url,
|
|
916
|
+
headers: {
|
|
917
|
+
'content-type': 'application/json'
|
|
918
|
+
}
|
|
919
|
+
})
|
|
920
|
+
}
|
|
921
|
+
|
|
922
|
+
const mockRedirectOnce = (url, redirectedUrl) => {
|
|
923
|
+
fetch.mockOnceIf(
|
|
924
|
+
url,
|
|
925
|
+
{},
|
|
926
|
+
{
|
|
927
|
+
status: 200,
|
|
928
|
+
url: redirectedUrl
|
|
929
|
+
}
|
|
930
|
+
)
|
|
931
|
+
}
|
|
932
|
+
|
|
933
|
+
const mockUnauthorizedOnce = url => {
|
|
934
|
+
fetch.mockOnceIf(
|
|
935
|
+
url,
|
|
936
|
+
{},
|
|
937
|
+
{
|
|
938
|
+
status: 401,
|
|
939
|
+
url: url
|
|
940
|
+
}
|
|
941
|
+
)
|
|
942
|
+
}
|
|
943
|
+
|
|
944
|
+
const mockNotFoundOnce = url => {
|
|
945
|
+
fetch.mockOnceIf(
|
|
946
|
+
url,
|
|
947
|
+
{},
|
|
948
|
+
{
|
|
949
|
+
status: 404,
|
|
950
|
+
url: url
|
|
951
|
+
}
|
|
952
|
+
)
|
|
953
|
+
}
|
|
954
|
+
|
|
955
|
+
const mockBlockedCozy = url => {
|
|
956
|
+
fetch.mockResponse(() => {
|
|
957
|
+
return Promise.resolve({
|
|
958
|
+
headers: {
|
|
959
|
+
'content-type': 'application/json; charset=UTF-8'
|
|
960
|
+
},
|
|
961
|
+
body: JSON.stringify([
|
|
962
|
+
{
|
|
963
|
+
status: '503',
|
|
964
|
+
title: 'Blocked',
|
|
965
|
+
code: 'UNKNOWN',
|
|
966
|
+
detail: 'The Cozy is blocked for an unknown reason',
|
|
967
|
+
source: {}
|
|
968
|
+
}
|
|
969
|
+
]),
|
|
970
|
+
ok: false,
|
|
971
|
+
status: 503,
|
|
972
|
+
statusText: '',
|
|
973
|
+
type: 'default',
|
|
974
|
+
url: url
|
|
975
|
+
})
|
|
976
|
+
})
|
|
977
|
+
}
|
|
978
|
+
|
|
979
|
+
const mock503Error = url => {
|
|
980
|
+
fetch.mockResponse(() => {
|
|
981
|
+
return Promise.resolve({
|
|
982
|
+
headers: {
|
|
983
|
+
'content-type': 'application/json; charset=UTF-8'
|
|
984
|
+
},
|
|
985
|
+
body: JSON.stringify([
|
|
986
|
+
{
|
|
987
|
+
status: '503',
|
|
988
|
+
title: 'Some error',
|
|
989
|
+
code: 'UNKNOWN',
|
|
990
|
+
detail: 'Some error description',
|
|
991
|
+
source: {}
|
|
992
|
+
}
|
|
993
|
+
]),
|
|
994
|
+
ok: false,
|
|
995
|
+
status: 503,
|
|
996
|
+
statusText: '',
|
|
997
|
+
type: 'default',
|
|
998
|
+
url: url
|
|
999
|
+
})
|
|
1000
|
+
})
|
|
1001
|
+
}
|
|
1002
|
+
|
|
1003
|
+
const fakeOidcPrelogin = () => {
|
|
1004
|
+
return JSON.stringify({
|
|
1005
|
+
FranceConnect: false,
|
|
1006
|
+
Kdf: 0,
|
|
1007
|
+
KdfIterations: 100000,
|
|
1008
|
+
OIDC: true,
|
|
1009
|
+
locale: 'fr',
|
|
1010
|
+
magic_link: false,
|
|
1011
|
+
name: 'claude'
|
|
1012
|
+
})
|
|
1013
|
+
}
|
|
1014
|
+
|
|
1015
|
+
const fakeCozyPrelogin = () => {
|
|
1016
|
+
return JSON.stringify({
|
|
1017
|
+
FranceConnect: false,
|
|
1018
|
+
Kdf: 0,
|
|
1019
|
+
KdfIterations: 100000,
|
|
1020
|
+
OIDC: false,
|
|
1021
|
+
locale: 'fr',
|
|
1022
|
+
magic_link: false,
|
|
1023
|
+
name: 'claude'
|
|
1024
|
+
})
|
|
1025
|
+
}
|
package/dist/index.js
CHANGED
|
@@ -33,6 +33,7 @@ var _exportNames = {
|
|
|
33
33
|
dehydrate: true,
|
|
34
34
|
generateWebLink: true,
|
|
35
35
|
ensureFirstSlash: true,
|
|
36
|
+
fetchRegistrationDetails: true,
|
|
36
37
|
rootCozyUrl: true,
|
|
37
38
|
InvalidRedirectLinkError: true,
|
|
38
39
|
InvalidCozyUrlError: true,
|
|
@@ -219,6 +220,12 @@ Object.defineProperty(exports, "ensureFirstSlash", {
|
|
|
219
220
|
return _helpers2.ensureFirstSlash;
|
|
220
221
|
}
|
|
221
222
|
});
|
|
223
|
+
Object.defineProperty(exports, "fetchRegistrationDetails", {
|
|
224
|
+
enumerable: true,
|
|
225
|
+
get: function get() {
|
|
226
|
+
return _helpers2.fetchRegistrationDetails;
|
|
227
|
+
}
|
|
228
|
+
});
|
|
222
229
|
Object.defineProperty(exports, "rootCozyUrl", {
|
|
223
230
|
enumerable: true,
|
|
224
231
|
get: function get() {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "cozy-client",
|
|
3
|
-
"version": "58.
|
|
3
|
+
"version": "58.3.0",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"main": "dist/index.node.js",
|
|
6
6
|
"browser": "dist/index.js",
|
|
@@ -74,5 +74,5 @@
|
|
|
74
74
|
"react-native-ios11-devicecheck": "^0.0.3"
|
|
75
75
|
},
|
|
76
76
|
"sideEffects": false,
|
|
77
|
-
"gitHead": "
|
|
77
|
+
"gitHead": "648e72735558114a377f9d3afc2b549bdb6de463"
|
|
78
78
|
}
|
package/types/helpers/index.d.ts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
export { dehydrate } from "./dehydrateHelper";
|
|
2
|
-
export { deconstructCozyWebLinkWithSlug, deconstructRedirectLink, generateWebLink, ensureFirstSlash, rootCozyUrl, InvalidRedirectLinkError, InvalidCozyUrlError, InvalidProtocolError, BlockedCozyError } from "./urlHelper";
|
|
2
|
+
export { deconstructCozyWebLinkWithSlug, deconstructRedirectLink, generateWebLink, ensureFirstSlash, fetchRegistrationDetails, rootCozyUrl, InvalidRedirectLinkError, InvalidCozyUrlError, InvalidProtocolError, BlockedCozyError } from "./urlHelper";
|
|
3
3
|
export { editSettings, getQuery, getSettings, normalizeSettings, saveAfterFetchSettings } from "./settings";
|
|
@@ -26,3 +26,14 @@ export class InvalidCozyUrlError extends Error {
|
|
|
26
26
|
url: any;
|
|
27
27
|
}
|
|
28
28
|
export function rootCozyUrl(url: URL): Promise<URL>;
|
|
29
|
+
export function fetchRegistrationDetails(url: URL): Promise<RegistrationDetails>;
|
|
30
|
+
export type RegistrationDetails = {
|
|
31
|
+
/**
|
|
32
|
+
* - The Cozy's root URL
|
|
33
|
+
*/
|
|
34
|
+
rootUrl: URL;
|
|
35
|
+
/**
|
|
36
|
+
* - True if the Cozy's uses OIDC for login
|
|
37
|
+
*/
|
|
38
|
+
isOIDC: boolean;
|
|
39
|
+
};
|
package/types/index.d.ts
CHANGED
|
@@ -22,7 +22,7 @@ export { manifest, models };
|
|
|
22
22
|
export { QueryDefinition, Q, Mutations, MutationTypes, getDoctypeFromOperation } from "./queries/dsl";
|
|
23
23
|
export { Association, HasMany, HasOne, HasOneInPlace, HasManyInPlace, HasManyTriggers } from "./associations";
|
|
24
24
|
export { isReferencedBy, isReferencedById, getReferencedBy, getReferencedById } from "./associations/helpers";
|
|
25
|
-
export { deconstructCozyWebLinkWithSlug, deconstructRedirectLink, dehydrate, generateWebLink, ensureFirstSlash, rootCozyUrl, InvalidRedirectLinkError, InvalidCozyUrlError, InvalidProtocolError, BlockedCozyError } from "./helpers";
|
|
25
|
+
export { deconstructCozyWebLinkWithSlug, deconstructRedirectLink, dehydrate, generateWebLink, ensureFirstSlash, fetchRegistrationDetails, rootCozyUrl, InvalidRedirectLinkError, InvalidCozyUrlError, InvalidProtocolError, BlockedCozyError } from "./helpers";
|
|
26
26
|
export { cancelable, isQueryLoading, hasQueryBeenLoaded, isQueriesLoading, hasQueriesBeenLoaded } from "./utils";
|
|
27
27
|
export { getQueryFromState, dispatchCreate, dispatchUpdate, dispatchDelete } from "./store";
|
|
28
28
|
export { queryConnect, queryConnectFlat, withClient } from "./hoc";
|