@commercetools-frontend/permissions 22.2.0 → 22.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/commercetools-frontend-permissions.cjs.dev.js +63 -77
- package/dist/commercetools-frontend-permissions.cjs.prod.js +62 -76
- package/dist/commercetools-frontend-permissions.esm.js +63 -77
- package/dist/declarations/src/components/authorized/authorized.d.ts +1 -1
- package/dist/declarations/src/components/restricted-by-permissions/restricted-by-permissions.d.ts +1 -1
- package/package.json +21 -7
|
@@ -53,47 +53,52 @@ var _Object$entries__default = /*#__PURE__*/_interopDefault(_Object$entries);
|
|
|
53
53
|
var upperFirst__default = /*#__PURE__*/_interopDefault(upperFirst);
|
|
54
54
|
|
|
55
55
|
// NOTE: This string will be replaced on build time with the package version.
|
|
56
|
-
var version = "22.
|
|
56
|
+
var version = "22.3.0";
|
|
57
|
+
|
|
58
|
+
// Permissions
|
|
59
|
+
|
|
60
|
+
// Action rights
|
|
61
|
+
|
|
62
|
+
// Data fences
|
|
63
|
+
|
|
64
|
+
// Potentially a union type.
|
|
57
65
|
|
|
58
66
|
// Build the permission key from the definition to match it to the format coming from the API.
|
|
59
67
|
const toCanCase = permissionName => "can".concat(permissionName);
|
|
60
|
-
|
|
61
68
|
const getIsViewPermission = demandedPermission => _startsWithInstanceProperty__default["default"](demandedPermission).call(demandedPermission, 'View');
|
|
69
|
+
const toManageCase = permissionName => permissionName.replace('View', 'Manage');
|
|
62
70
|
|
|
63
|
-
|
|
71
|
+
// Check that the user permissions match EXACTLY the required permission.
|
|
64
72
|
// The shapes of the arguments are:
|
|
65
73
|
// - demandedPermission:
|
|
66
74
|
// 'ViewProducts'
|
|
67
75
|
// - actualPermissions:
|
|
68
76
|
// { canViewProducts: true, canManageOrders: false }
|
|
69
|
-
|
|
70
|
-
|
|
71
77
|
const hasExactPermission = (demandedPermission, actualPermissions) => actualPermissions[toCanCase(demandedPermission)];
|
|
78
|
+
const getInferredManagePermission = (demandedPermission, actualPermissions) => actualPermissions[toCanCase(toManageCase(demandedPermission))];
|
|
72
79
|
|
|
73
|
-
|
|
80
|
+
// Check that the user permissions match the required MANAGE permission.
|
|
74
81
|
// The shapes of the arguments are:
|
|
75
82
|
// - demandedPermission:
|
|
76
83
|
// 'ViewProducts'
|
|
77
84
|
// - actualPermissions:
|
|
78
85
|
// { canViewProducts: true, canManageOrders: false }
|
|
79
|
-
|
|
80
|
-
|
|
81
86
|
const doesManagePermissionInferViewPermission = (demandedPermission, actualPermissions) => {
|
|
82
87
|
const isDemandedPermissionViewPermission = getIsViewPermission(demandedPermission);
|
|
83
88
|
const isViewPermissionInferredByManagePermission = Boolean(getInferredManagePermission(demandedPermission, actualPermissions));
|
|
84
89
|
return isDemandedPermissionViewPermission && isViewPermissionInferredByManagePermission;
|
|
85
|
-
};
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
// Check if the demanded permissions contain any unnecessary
|
|
86
93
|
// implied permissions.
|
|
87
94
|
// E.g. ViewCustomerGroup is implied by ManageCustomerGroup.
|
|
88
|
-
|
|
89
|
-
|
|
90
95
|
const getImpliedPermissions = permissions => {
|
|
91
96
|
const viewPermissions = _filterInstanceProperty__default["default"](permissions).call(permissions, permission => _startsWithInstanceProperty__default["default"](permission).call(permission, 'View'));
|
|
92
|
-
|
|
93
97
|
const impliedPermissions = _filterInstanceProperty__default["default"](viewPermissions).call(viewPermissions, viewPermission => _includesInstanceProperty__default["default"](permissions).call(permissions, toManageCase(viewPermission)));
|
|
94
|
-
|
|
95
98
|
return impliedPermissions;
|
|
96
|
-
};
|
|
99
|
+
};
|
|
100
|
+
|
|
101
|
+
// Check the user permissions using one of the defined matchers.
|
|
97
102
|
// The shapes of the arguments are:
|
|
98
103
|
// - demandedPermission:
|
|
99
104
|
// 'ViewProducts'
|
|
@@ -102,27 +107,32 @@ const getImpliedPermissions = permissions => {
|
|
|
102
107
|
// NOTE: in case the `actualPermissions` are not defined, fall back to an empty object.
|
|
103
108
|
// This might be the case when the permissions for a user/project could not be loaded
|
|
104
109
|
// (e.g. project not found).
|
|
110
|
+
const hasPermission = (demandedPermission, actualPermissions) =>
|
|
111
|
+
// First checking the existence of the exact permission
|
|
112
|
+
hasExactPermission(demandedPermission, actualPermissions || {}) ||
|
|
113
|
+
// Then checking if a view permission is inferred as a manage permission
|
|
114
|
+
doesManagePermissionInferViewPermission(demandedPermission, actualPermissions || {});
|
|
105
115
|
|
|
106
|
-
|
|
107
|
-
hasExactPermission(demandedPermission, actualPermissions || {}) || // Then checking if a view permission is inferred as a manage permission
|
|
108
|
-
doesManagePermissionInferViewPermission(demandedPermission, actualPermissions || {}); // Check the user action rights using one of the defined matchers.
|
|
116
|
+
// Check the user action rights using one of the defined matchers.
|
|
109
117
|
// The shapes of the arguments are:
|
|
110
118
|
// - demandedActionRight:
|
|
111
119
|
// '{ group: 'products', name: 'editPrices' }'
|
|
112
120
|
// - actualActionRights:
|
|
113
121
|
// { orders: { canEditPrices: false }, products: { canEditPrices: true } }
|
|
114
|
-
|
|
115
122
|
const hasActionRight = (demandedActionRight, actualActionRights) => {
|
|
116
123
|
const actionRightGroup = actualActionRights && actualActionRights[demandedActionRight.group];
|
|
117
124
|
return Boolean(actionRightGroup && actionRightGroup[toCanCase(demandedActionRight.name)]);
|
|
118
|
-
};
|
|
125
|
+
};
|
|
126
|
+
|
|
127
|
+
// Check that the user permissions match EVERY one of the required permissions.
|
|
119
128
|
// The shapes of the arguments are:
|
|
120
129
|
// - demandedPermissions:
|
|
121
130
|
// ['ViewProducts', 'ManageOrders']
|
|
122
131
|
// - actualPermissions:
|
|
123
132
|
// { canViewProducts: true, canManageOrders: false }
|
|
133
|
+
const hasEveryPermissions = (demandedPermissions, actualPermissions) => _everyInstanceProperty__default["default"](demandedPermissions).call(demandedPermissions, permission => hasPermission(permission, actualPermissions));
|
|
124
134
|
|
|
125
|
-
|
|
135
|
+
// Check that the user action rights match EVERY one of the required action rights.
|
|
126
136
|
// The shapes of the arguments are:
|
|
127
137
|
// - demandedActionRights:
|
|
128
138
|
// [
|
|
@@ -131,16 +141,15 @@ const hasEveryPermissions = (demandedPermissions, actualPermissions) => _everyIn
|
|
|
131
141
|
// ]
|
|
132
142
|
// - actualActionRights:
|
|
133
143
|
// { products: { canEditPrices: true, canPublishProducts: true } }
|
|
144
|
+
const hasEveryActionRight = (demandedActionRights, actualActionRights) => _everyInstanceProperty__default["default"](demandedActionRights).call(demandedActionRights, actionRight => hasActionRight(actionRight, actualActionRights));
|
|
134
145
|
|
|
135
|
-
|
|
146
|
+
// Check that the user permissions match SOME one of the required permissions.
|
|
136
147
|
// The shapes of the arguments are:
|
|
137
148
|
// - demandedPermissions:
|
|
138
149
|
// ['ViewProducts', 'ManageOrders']
|
|
139
150
|
// - actualPermissions:
|
|
140
151
|
// { canViewProducts: true, canManageOrders: false }
|
|
141
|
-
|
|
142
152
|
const hasSomePermissions = (demandedPermissions, actualPermissions) => _someInstanceProperty__default["default"](demandedPermissions).call(demandedPermissions, permission => hasPermission(permission, actualPermissions));
|
|
143
|
-
|
|
144
153
|
const getHasDemandedDataFence = options => {
|
|
145
154
|
if (!options.selectDataFenceData) return false;
|
|
146
155
|
const hasDemandedPermission = hasPermission(options.demandedDataFence.name, {
|
|
@@ -153,45 +162,38 @@ const getHasDemandedDataFence = options => {
|
|
|
153
162
|
name: options.demandedDataFence.name,
|
|
154
163
|
actualDataFenceValues: _valuesInstanceProperty__default["default"](options.actualDataFence.dataFenceValue)
|
|
155
164
|
});
|
|
156
|
-
|
|
157
165
|
if (!selectedDataFenceData) {
|
|
158
166
|
sentry.reportErrorToSentry(new Error("missing mapper for type \"".concat(options.demandedDataFence.type, "\"")), {
|
|
159
167
|
extra: options.demandedDataFence.type
|
|
160
168
|
});
|
|
161
169
|
return false;
|
|
162
|
-
}
|
|
163
|
-
|
|
170
|
+
}
|
|
164
171
|
|
|
172
|
+
// it is enough to only have a subset of demanded dataFence data belonging to actual dataFence values
|
|
165
173
|
return _someInstanceProperty__default["default"](selectedDataFenceData).call(selectedDataFenceData, value => {
|
|
166
174
|
var _context;
|
|
167
|
-
|
|
168
175
|
return _includesInstanceProperty__default["default"](_context = _valuesInstanceProperty__default["default"](options.actualDataFence.dataFenceValue)).call(_context, value);
|
|
169
176
|
});
|
|
170
177
|
};
|
|
171
|
-
|
|
172
178
|
const getDataFenceByTypeAndGroup = (actualDataFences, demandedDataFenceType, demandedDataFenceGroup) => {
|
|
173
179
|
if (!actualDataFences) return null;
|
|
174
|
-
|
|
175
180
|
if (demandedDataFenceType in actualDataFences) {
|
|
176
181
|
switch (demandedDataFenceType) {
|
|
177
182
|
case 'store':
|
|
178
183
|
{
|
|
179
184
|
const actualDataFence = actualDataFences[demandedDataFenceType];
|
|
180
|
-
|
|
181
185
|
if (actualDataFence && demandedDataFenceGroup in actualDataFence) {
|
|
182
186
|
return actualDataFence[demandedDataFenceGroup];
|
|
183
187
|
}
|
|
184
|
-
|
|
185
188
|
break;
|
|
186
189
|
}
|
|
187
190
|
}
|
|
188
191
|
}
|
|
189
|
-
|
|
190
192
|
return null;
|
|
191
193
|
};
|
|
192
|
-
|
|
193
194
|
const getIsPermissionOverwritingDataFence = (actualPermissions, demandedDataFence) => {
|
|
194
195
|
if (!actualPermissions) return false;
|
|
196
|
+
|
|
195
197
|
/**
|
|
196
198
|
* NOTE:
|
|
197
199
|
* A data fence relates, exists in relation to a general permission.
|
|
@@ -202,20 +204,16 @@ const getIsPermissionOverwritingDataFence = (actualPermissions, demandedDataFenc
|
|
|
202
204
|
* Given the user _does not_ have manage access on the data fence's group
|
|
203
205
|
* Then the data fence itself takes precedence
|
|
204
206
|
*/
|
|
205
|
-
|
|
206
207
|
const demandedPermissionByDataFence = "Manage".concat(upperFirst__default["default"](demandedDataFence.group));
|
|
207
208
|
if (hasExactPermission(demandedPermissionByDataFence, actualPermissions)) return true;
|
|
208
209
|
return false;
|
|
209
210
|
};
|
|
210
|
-
|
|
211
211
|
const hasSomeDataFence = options => {
|
|
212
212
|
var _context2;
|
|
213
|
-
|
|
214
213
|
// Datafences applied should be combined with an OR, that is why we use
|
|
215
214
|
// `some` and not `every`
|
|
216
215
|
return _someInstanceProperty__default["default"](_context2 = options.demandedDataFences).call(_context2, demandedDataFence => {
|
|
217
216
|
var _context3;
|
|
218
|
-
|
|
219
217
|
// Given that dataFence structure on `applicationContext`, we get the value by a path
|
|
220
218
|
// e.g given dataFence with { store: { orders: { canManageOrders: { values: } } } }
|
|
221
219
|
// we read the dataFence by the [type] and [group]
|
|
@@ -223,26 +221,23 @@ const hasSomeDataFence = options => {
|
|
|
223
221
|
// with value = there is a dataFence to apply, overrules `hasDemandedProjectPermissions`
|
|
224
222
|
// without value = there is no dataFence to apply, overruled by `hasDemandedProjectPermissions`
|
|
225
223
|
const actualDataFenceByTypeAndGroup = getDataFenceByTypeAndGroup(options.actualDataFences, demandedDataFence.type, demandedDataFence.group);
|
|
226
|
-
if (!actualDataFenceByTypeAndGroup) return false;
|
|
224
|
+
if (!actualDataFenceByTypeAndGroup) return false;
|
|
227
225
|
|
|
226
|
+
// we try to find if the demanded dataFence is available inside the actual datafences
|
|
228
227
|
const specificActualDataFence = _findInstanceProperty__default["default"](_context3 = _Object$entries__default["default"](actualDataFenceByTypeAndGroup)).call(_context3, _ref => {
|
|
229
228
|
let _ref2 = _slicedToArray(_ref, 2),
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
229
|
+
dataFenceName = _ref2[0],
|
|
230
|
+
dataFenceValue = _ref2[1];
|
|
233
231
|
// Either the manage permission matches or the
|
|
234
232
|
// a demanded view permission is implied by a manage permission.
|
|
235
233
|
const doesDataFenceMatchByName = dataFenceName === toCanCase(demandedDataFence.name) || dataFenceName === toCanCase(toManageCase(demandedDataFence.name));
|
|
236
234
|
const doesDataFenceHaveValue = Boolean(dataFenceValue);
|
|
237
235
|
return doesDataFenceMatchByName && doesDataFenceHaveValue;
|
|
238
236
|
});
|
|
239
|
-
|
|
240
237
|
if (!specificActualDataFence) return false;
|
|
241
|
-
|
|
242
238
|
const _specificActualDataFe = _slicedToArray(specificActualDataFence, 2),
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
239
|
+
dataFenceName = _specificActualDataFe[0],
|
|
240
|
+
dataFenceValue = _specificActualDataFe[1];
|
|
246
241
|
const actualDataFence = {
|
|
247
242
|
name: dataFenceName,
|
|
248
243
|
// we do the type casting because at this point we are sure that
|
|
@@ -259,21 +254,27 @@ const hasSomeDataFence = options => {
|
|
|
259
254
|
});
|
|
260
255
|
};
|
|
261
256
|
|
|
257
|
+
// Permissions
|
|
258
|
+
|
|
259
|
+
// Action rights
|
|
260
|
+
|
|
261
|
+
// Data fences
|
|
262
|
+
|
|
262
263
|
// Log a warning only once, and not on each render.
|
|
263
264
|
const useWarning = (condition, message) => {
|
|
264
265
|
react.useEffect(() => {
|
|
265
|
-
process.env.NODE_ENV !== "production" ? warning__default["default"](condition, message) : void 0;
|
|
266
|
+
process.env.NODE_ENV !== "production" ? warning__default["default"](condition, message) : void 0;
|
|
267
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
266
268
|
}, []);
|
|
267
269
|
};
|
|
268
|
-
|
|
269
270
|
const useIsAuthorized = _ref => {
|
|
270
271
|
let demandedPermissions = _ref.demandedPermissions,
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
272
|
+
demandedActionRights = _ref.demandedActionRights,
|
|
273
|
+
demandedDataFences = _ref.demandedDataFences,
|
|
274
|
+
selectDataFenceData = _ref.selectDataFenceData,
|
|
275
|
+
_ref$shouldMatchSomeP = _ref.shouldMatchSomePermissions,
|
|
276
|
+
shouldMatchSomePermissions = _ref$shouldMatchSomeP === void 0 ? false : _ref$shouldMatchSomeP,
|
|
277
|
+
projectPermissions = _ref.projectPermissions;
|
|
277
278
|
const impliedPermissions = getImpliedPermissions(demandedPermissions);
|
|
278
279
|
useWarning(!demandedActionRights || demandedActionRights.length === 1, "@commercetools-frontend/permissions: It is recommended to pass a single demanded action right while using the hook, HoC or component multiple times.");
|
|
279
280
|
useWarning(!demandedPermissions || demandedPermissions.length === 1, "@commercetools-frontend/permissions: It is recommended to pass a single demanded permission while using the hook, HoC or component multiple times.");
|
|
@@ -281,28 +282,24 @@ const useIsAuthorized = _ref => {
|
|
|
281
282
|
useWarning(!impliedPermissions || impliedPermissions.length === 0, "@commercetools-frontend/permissions: Demanded permissions contain implied permissions. These are implied: ".concat(impliedPermissions.join(', '), "."));
|
|
282
283
|
const actualPermissions = applicationShellConnectors.useApplicationContext(applicationContext => {
|
|
283
284
|
var _projectPermissions$p;
|
|
284
|
-
|
|
285
285
|
return (_projectPermissions$p = projectPermissions === null || projectPermissions === void 0 ? void 0 : projectPermissions.permissions) !== null && _projectPermissions$p !== void 0 ? _projectPermissions$p : applicationContext.permissions;
|
|
286
286
|
});
|
|
287
287
|
const actualActionRights = applicationShellConnectors.useApplicationContext(applicationContext => {
|
|
288
288
|
var _projectPermissions$a;
|
|
289
|
-
|
|
290
289
|
return (_projectPermissions$a = projectPermissions === null || projectPermissions === void 0 ? void 0 : projectPermissions.actionRights) !== null && _projectPermissions$a !== void 0 ? _projectPermissions$a : applicationContext.actionRights;
|
|
291
290
|
});
|
|
292
291
|
const actualDataFences = applicationShellConnectors.useApplicationContext(applicationContext => {
|
|
293
292
|
var _projectPermissions$d;
|
|
294
|
-
|
|
295
293
|
return (_projectPermissions$d = projectPermissions === null || projectPermissions === void 0 ? void 0 : projectPermissions.dataFences) !== null && _projectPermissions$d !== void 0 ? _projectPermissions$d : applicationContext.dataFences;
|
|
296
|
-
});
|
|
294
|
+
});
|
|
297
295
|
|
|
296
|
+
// if the user has no permissions and no dataFences assigned to them, they are not authorized
|
|
298
297
|
if (!actualPermissions && !actualDataFences) return false;
|
|
299
298
|
let hasDemandedDataFences = false;
|
|
300
|
-
|
|
301
299
|
if (demandedDataFences && demandedDataFences.length > 0) {
|
|
302
300
|
if (!selectDataFenceData) {
|
|
303
301
|
sentry.reportErrorToSentry(new Error("@commercetools-frontend/permissions/Authorized: Missing data fences selector \"selectDataFenceData\"."));
|
|
304
302
|
}
|
|
305
|
-
|
|
306
303
|
hasDemandedDataFences = hasSomeDataFence({
|
|
307
304
|
actualPermissions,
|
|
308
305
|
demandedDataFences,
|
|
@@ -310,7 +307,6 @@ const useIsAuthorized = _ref => {
|
|
|
310
307
|
selectDataFenceData
|
|
311
308
|
});
|
|
312
309
|
}
|
|
313
|
-
|
|
314
310
|
const hasDemandedPermissions = shouldMatchSomePermissions ? hasSomePermissions(demandedPermissions, actualPermissions) : hasEveryPermissions(demandedPermissions, actualPermissions);
|
|
315
311
|
const hasDemandedActionRights = hasEveryActionRight(demandedActionRights || [], actualActionRights);
|
|
316
312
|
return hasDemandedDataFences || hasDemandedPermissions && hasDemandedActionRights;
|
|
@@ -321,21 +317,17 @@ const getDisplayName = Component => {
|
|
|
321
317
|
if (typeof Component === 'string') {
|
|
322
318
|
return Component;
|
|
323
319
|
}
|
|
324
|
-
|
|
325
320
|
if (!Component) {
|
|
326
321
|
return undefined;
|
|
327
322
|
}
|
|
328
|
-
|
|
329
323
|
return Component.displayName || Component.name || 'Component';
|
|
330
324
|
};
|
|
331
325
|
|
|
332
326
|
function ownKeys$1(object, enumerableOnly) { var keys = _Object$keys__default["default"](object); if (_Object$getOwnPropertySymbols__default["default"]) { var symbols = _Object$getOwnPropertySymbols__default["default"](object); enumerableOnly && (symbols = _filterInstanceProperty__default["default"](symbols).call(symbols, function (sym) { return _Object$getOwnPropertyDescriptor__default["default"](object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; }
|
|
333
|
-
|
|
334
327
|
function _objectSpread$1(target) { for (var i = 1; i < arguments.length; i++) { var _context, _context2; var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? _forEachInstanceProperty__default["default"](_context = ownKeys$1(Object(source), !0)).call(_context, function (key) { _defineProperty(target, key, source[key]); }) : _Object$getOwnPropertyDescriptors__default["default"] ? _Object$defineProperties__default["default"](target, _Object$getOwnPropertyDescriptors__default["default"](source)) : _forEachInstanceProperty__default["default"](_context2 = ownKeys$1(Object(source))).call(_context2, function (key) { _Object$defineProperty__default["default"](target, key, _Object$getOwnPropertyDescriptor__default["default"](source, key)); }); } return target; }
|
|
335
328
|
const defaultProps = {
|
|
336
329
|
shouldMatchSomePermissions: false
|
|
337
330
|
};
|
|
338
|
-
|
|
339
331
|
const Authorized = props => {
|
|
340
332
|
const isAuthorized = useIsAuthorized({
|
|
341
333
|
demandedPermissions: props.demandedPermissions,
|
|
@@ -349,7 +341,6 @@ const Authorized = props => {
|
|
|
349
341
|
children: props.render(isAuthorized)
|
|
350
342
|
});
|
|
351
343
|
};
|
|
352
|
-
|
|
353
344
|
Authorized.propTypes = {
|
|
354
345
|
demandedPermissions: _pt__default["default"].arrayOf(_pt__default["default"].string).isRequired,
|
|
355
346
|
demandedActionRights: _pt__default["default"].arrayOf(_pt__default["default"].shape({
|
|
@@ -372,7 +363,6 @@ Authorized.propTypes = {
|
|
|
372
363
|
};
|
|
373
364
|
Authorized.displayName = 'Authorized';
|
|
374
365
|
Authorized.defaultProps = defaultProps;
|
|
375
|
-
|
|
376
366
|
const injectAuthorized = function (demandedPermissions) {
|
|
377
367
|
let options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
|
|
378
368
|
let propName = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 'isAuthorized';
|
|
@@ -387,14 +377,18 @@ const injectAuthorized = function (demandedPermissions) {
|
|
|
387
377
|
[propName]: isAuthorized
|
|
388
378
|
}))
|
|
389
379
|
});
|
|
390
|
-
|
|
391
380
|
WrappedComponent.displayName = "withUserPermissions(".concat(getDisplayName(Component), ")");
|
|
392
381
|
return WrappedComponent;
|
|
393
382
|
};
|
|
394
383
|
};
|
|
395
384
|
|
|
396
|
-
const getHasChildren = children => react.Children.count(children) > 0;
|
|
385
|
+
const getHasChildren = children => react.Children.count(children) > 0;
|
|
386
|
+
|
|
387
|
+
// Permissions
|
|
388
|
+
|
|
389
|
+
// Action rights
|
|
397
390
|
|
|
391
|
+
// Data fences
|
|
398
392
|
|
|
399
393
|
const RestrictedByPermissions = props => {
|
|
400
394
|
!!(typeof props.children === 'function' && !isNil__default["default"](props.unauthorizedComponent)) ? process.env.NODE_ENV !== "production" ? invariant__default["default"](false, '@commercetools-frontend/permissions/RestrictedByPermissions: You provided both `children` and `unauthorizedComponent`. Please provide only one of them.') : invariant__default["default"](false) : void 0;
|
|
@@ -412,7 +406,6 @@ const RestrictedByPermissions = props => {
|
|
|
412
406
|
if (typeof props.render === 'function') return props.render({
|
|
413
407
|
isAuthorized
|
|
414
408
|
});
|
|
415
|
-
|
|
416
409
|
if (isAuthorized) {
|
|
417
410
|
if (props.children && getHasChildren(props.children)) return react.Children.only(props.children);
|
|
418
411
|
} else if (!isAuthorized) {
|
|
@@ -420,12 +413,10 @@ const RestrictedByPermissions = props => {
|
|
|
420
413
|
return /*#__PURE__*/react.createElement(props.unauthorizedComponent);
|
|
421
414
|
}
|
|
422
415
|
}
|
|
423
|
-
|
|
424
416
|
return null;
|
|
425
417
|
}
|
|
426
418
|
});
|
|
427
419
|
};
|
|
428
|
-
|
|
429
420
|
RestrictedByPermissions.propTypes = process.env.NODE_ENV !== "production" ? {
|
|
430
421
|
shouldMatchSomePermissions: _pt__default["default"].bool,
|
|
431
422
|
permissions: _pt__default["default"].arrayOf(_pt__default["default"].string).isRequired,
|
|
@@ -451,9 +442,7 @@ RestrictedByPermissions.propTypes = process.env.NODE_ENV !== "production" ? {
|
|
|
451
442
|
RestrictedByPermissions.displayName = 'RestrictedByPermissions';
|
|
452
443
|
|
|
453
444
|
function ownKeys(object, enumerableOnly) { var keys = _Object$keys__default["default"](object); if (_Object$getOwnPropertySymbols__default["default"]) { var symbols = _Object$getOwnPropertySymbols__default["default"](object); enumerableOnly && (symbols = _filterInstanceProperty__default["default"](symbols).call(symbols, function (sym) { return _Object$getOwnPropertyDescriptor__default["default"](object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; }
|
|
454
|
-
|
|
455
445
|
function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var _context, _context2; var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? _forEachInstanceProperty__default["default"](_context = ownKeys(Object(source), !0)).call(_context, function (key) { _defineProperty(target, key, source[key]); }) : _Object$getOwnPropertyDescriptors__default["default"] ? _Object$defineProperties__default["default"](target, _Object$getOwnPropertyDescriptors__default["default"](source)) : _forEachInstanceProperty__default["default"](_context2 = ownKeys(Object(source))).call(_context2, function (key) { _Object$defineProperty__default["default"](target, key, _Object$getOwnPropertyDescriptor__default["default"](source, key)); }); } return target; }
|
|
456
|
-
|
|
457
446
|
const branchOnPermissions = function (demandedPermissions, FallbackComponent) {
|
|
458
447
|
let options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {
|
|
459
448
|
shouldMatchSomePermissions: false
|
|
@@ -469,15 +458,12 @@ const branchOnPermissions = function (demandedPermissions, FallbackComponent) {
|
|
|
469
458
|
if (isAuthorized) {
|
|
470
459
|
return jsxRuntime.jsx(Component, _objectSpread({}, props));
|
|
471
460
|
}
|
|
472
|
-
|
|
473
461
|
if (FallbackComponent) {
|
|
474
462
|
return jsxRuntime.jsx(FallbackComponent, {});
|
|
475
463
|
}
|
|
476
|
-
|
|
477
464
|
return jsxRuntime.jsx(jsxRuntime.Fragment, {});
|
|
478
465
|
}
|
|
479
466
|
});
|
|
480
|
-
|
|
481
467
|
WrappedComponent.displayName = "branchOnPermissions(".concat(getDisplayName(Component), ")");
|
|
482
468
|
return WrappedComponent;
|
|
483
469
|
};
|
|
@@ -52,47 +52,52 @@ var _Object$entries__default = /*#__PURE__*/_interopDefault(_Object$entries);
|
|
|
52
52
|
var upperFirst__default = /*#__PURE__*/_interopDefault(upperFirst);
|
|
53
53
|
|
|
54
54
|
// NOTE: This string will be replaced on build time with the package version.
|
|
55
|
-
var version = "22.
|
|
55
|
+
var version = "22.3.0";
|
|
56
|
+
|
|
57
|
+
// Permissions
|
|
58
|
+
|
|
59
|
+
// Action rights
|
|
60
|
+
|
|
61
|
+
// Data fences
|
|
62
|
+
|
|
63
|
+
// Potentially a union type.
|
|
56
64
|
|
|
57
65
|
// Build the permission key from the definition to match it to the format coming from the API.
|
|
58
66
|
const toCanCase = permissionName => "can".concat(permissionName);
|
|
59
|
-
|
|
60
67
|
const getIsViewPermission = demandedPermission => _startsWithInstanceProperty__default["default"](demandedPermission).call(demandedPermission, 'View');
|
|
68
|
+
const toManageCase = permissionName => permissionName.replace('View', 'Manage');
|
|
61
69
|
|
|
62
|
-
|
|
70
|
+
// Check that the user permissions match EXACTLY the required permission.
|
|
63
71
|
// The shapes of the arguments are:
|
|
64
72
|
// - demandedPermission:
|
|
65
73
|
// 'ViewProducts'
|
|
66
74
|
// - actualPermissions:
|
|
67
75
|
// { canViewProducts: true, canManageOrders: false }
|
|
68
|
-
|
|
69
|
-
|
|
70
76
|
const hasExactPermission = (demandedPermission, actualPermissions) => actualPermissions[toCanCase(demandedPermission)];
|
|
77
|
+
const getInferredManagePermission = (demandedPermission, actualPermissions) => actualPermissions[toCanCase(toManageCase(demandedPermission))];
|
|
71
78
|
|
|
72
|
-
|
|
79
|
+
// Check that the user permissions match the required MANAGE permission.
|
|
73
80
|
// The shapes of the arguments are:
|
|
74
81
|
// - demandedPermission:
|
|
75
82
|
// 'ViewProducts'
|
|
76
83
|
// - actualPermissions:
|
|
77
84
|
// { canViewProducts: true, canManageOrders: false }
|
|
78
|
-
|
|
79
|
-
|
|
80
85
|
const doesManagePermissionInferViewPermission = (demandedPermission, actualPermissions) => {
|
|
81
86
|
const isDemandedPermissionViewPermission = getIsViewPermission(demandedPermission);
|
|
82
87
|
const isViewPermissionInferredByManagePermission = Boolean(getInferredManagePermission(demandedPermission, actualPermissions));
|
|
83
88
|
return isDemandedPermissionViewPermission && isViewPermissionInferredByManagePermission;
|
|
84
|
-
};
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
// Check if the demanded permissions contain any unnecessary
|
|
85
92
|
// implied permissions.
|
|
86
93
|
// E.g. ViewCustomerGroup is implied by ManageCustomerGroup.
|
|
87
|
-
|
|
88
|
-
|
|
89
94
|
const getImpliedPermissions = permissions => {
|
|
90
95
|
const viewPermissions = _filterInstanceProperty__default["default"](permissions).call(permissions, permission => _startsWithInstanceProperty__default["default"](permission).call(permission, 'View'));
|
|
91
|
-
|
|
92
96
|
const impliedPermissions = _filterInstanceProperty__default["default"](viewPermissions).call(viewPermissions, viewPermission => _includesInstanceProperty__default["default"](permissions).call(permissions, toManageCase(viewPermission)));
|
|
93
|
-
|
|
94
97
|
return impliedPermissions;
|
|
95
|
-
};
|
|
98
|
+
};
|
|
99
|
+
|
|
100
|
+
// Check the user permissions using one of the defined matchers.
|
|
96
101
|
// The shapes of the arguments are:
|
|
97
102
|
// - demandedPermission:
|
|
98
103
|
// 'ViewProducts'
|
|
@@ -101,27 +106,32 @@ const getImpliedPermissions = permissions => {
|
|
|
101
106
|
// NOTE: in case the `actualPermissions` are not defined, fall back to an empty object.
|
|
102
107
|
// This might be the case when the permissions for a user/project could not be loaded
|
|
103
108
|
// (e.g. project not found).
|
|
109
|
+
const hasPermission = (demandedPermission, actualPermissions) =>
|
|
110
|
+
// First checking the existence of the exact permission
|
|
111
|
+
hasExactPermission(demandedPermission, actualPermissions || {}) ||
|
|
112
|
+
// Then checking if a view permission is inferred as a manage permission
|
|
113
|
+
doesManagePermissionInferViewPermission(demandedPermission, actualPermissions || {});
|
|
104
114
|
|
|
105
|
-
|
|
106
|
-
hasExactPermission(demandedPermission, actualPermissions || {}) || // Then checking if a view permission is inferred as a manage permission
|
|
107
|
-
doesManagePermissionInferViewPermission(demandedPermission, actualPermissions || {}); // Check the user action rights using one of the defined matchers.
|
|
115
|
+
// Check the user action rights using one of the defined matchers.
|
|
108
116
|
// The shapes of the arguments are:
|
|
109
117
|
// - demandedActionRight:
|
|
110
118
|
// '{ group: 'products', name: 'editPrices' }'
|
|
111
119
|
// - actualActionRights:
|
|
112
120
|
// { orders: { canEditPrices: false }, products: { canEditPrices: true } }
|
|
113
|
-
|
|
114
121
|
const hasActionRight = (demandedActionRight, actualActionRights) => {
|
|
115
122
|
const actionRightGroup = actualActionRights && actualActionRights[demandedActionRight.group];
|
|
116
123
|
return Boolean(actionRightGroup && actionRightGroup[toCanCase(demandedActionRight.name)]);
|
|
117
|
-
};
|
|
124
|
+
};
|
|
125
|
+
|
|
126
|
+
// Check that the user permissions match EVERY one of the required permissions.
|
|
118
127
|
// The shapes of the arguments are:
|
|
119
128
|
// - demandedPermissions:
|
|
120
129
|
// ['ViewProducts', 'ManageOrders']
|
|
121
130
|
// - actualPermissions:
|
|
122
131
|
// { canViewProducts: true, canManageOrders: false }
|
|
132
|
+
const hasEveryPermissions = (demandedPermissions, actualPermissions) => _everyInstanceProperty__default["default"](demandedPermissions).call(demandedPermissions, permission => hasPermission(permission, actualPermissions));
|
|
123
133
|
|
|
124
|
-
|
|
134
|
+
// Check that the user action rights match EVERY one of the required action rights.
|
|
125
135
|
// The shapes of the arguments are:
|
|
126
136
|
// - demandedActionRights:
|
|
127
137
|
// [
|
|
@@ -130,16 +140,15 @@ const hasEveryPermissions = (demandedPermissions, actualPermissions) => _everyIn
|
|
|
130
140
|
// ]
|
|
131
141
|
// - actualActionRights:
|
|
132
142
|
// { products: { canEditPrices: true, canPublishProducts: true } }
|
|
143
|
+
const hasEveryActionRight = (demandedActionRights, actualActionRights) => _everyInstanceProperty__default["default"](demandedActionRights).call(demandedActionRights, actionRight => hasActionRight(actionRight, actualActionRights));
|
|
133
144
|
|
|
134
|
-
|
|
145
|
+
// Check that the user permissions match SOME one of the required permissions.
|
|
135
146
|
// The shapes of the arguments are:
|
|
136
147
|
// - demandedPermissions:
|
|
137
148
|
// ['ViewProducts', 'ManageOrders']
|
|
138
149
|
// - actualPermissions:
|
|
139
150
|
// { canViewProducts: true, canManageOrders: false }
|
|
140
|
-
|
|
141
151
|
const hasSomePermissions = (demandedPermissions, actualPermissions) => _someInstanceProperty__default["default"](demandedPermissions).call(demandedPermissions, permission => hasPermission(permission, actualPermissions));
|
|
142
|
-
|
|
143
152
|
const getHasDemandedDataFence = options => {
|
|
144
153
|
if (!options.selectDataFenceData) return false;
|
|
145
154
|
const hasDemandedPermission = hasPermission(options.demandedDataFence.name, {
|
|
@@ -152,45 +161,38 @@ const getHasDemandedDataFence = options => {
|
|
|
152
161
|
name: options.demandedDataFence.name,
|
|
153
162
|
actualDataFenceValues: _valuesInstanceProperty__default["default"](options.actualDataFence.dataFenceValue)
|
|
154
163
|
});
|
|
155
|
-
|
|
156
164
|
if (!selectedDataFenceData) {
|
|
157
165
|
sentry.reportErrorToSentry(new Error("missing mapper for type \"".concat(options.demandedDataFence.type, "\"")), {
|
|
158
166
|
extra: options.demandedDataFence.type
|
|
159
167
|
});
|
|
160
168
|
return false;
|
|
161
|
-
}
|
|
162
|
-
|
|
169
|
+
}
|
|
163
170
|
|
|
171
|
+
// it is enough to only have a subset of demanded dataFence data belonging to actual dataFence values
|
|
164
172
|
return _someInstanceProperty__default["default"](selectedDataFenceData).call(selectedDataFenceData, value => {
|
|
165
173
|
var _context;
|
|
166
|
-
|
|
167
174
|
return _includesInstanceProperty__default["default"](_context = _valuesInstanceProperty__default["default"](options.actualDataFence.dataFenceValue)).call(_context, value);
|
|
168
175
|
});
|
|
169
176
|
};
|
|
170
|
-
|
|
171
177
|
const getDataFenceByTypeAndGroup = (actualDataFences, demandedDataFenceType, demandedDataFenceGroup) => {
|
|
172
178
|
if (!actualDataFences) return null;
|
|
173
|
-
|
|
174
179
|
if (demandedDataFenceType in actualDataFences) {
|
|
175
180
|
switch (demandedDataFenceType) {
|
|
176
181
|
case 'store':
|
|
177
182
|
{
|
|
178
183
|
const actualDataFence = actualDataFences[demandedDataFenceType];
|
|
179
|
-
|
|
180
184
|
if (actualDataFence && demandedDataFenceGroup in actualDataFence) {
|
|
181
185
|
return actualDataFence[demandedDataFenceGroup];
|
|
182
186
|
}
|
|
183
|
-
|
|
184
187
|
break;
|
|
185
188
|
}
|
|
186
189
|
}
|
|
187
190
|
}
|
|
188
|
-
|
|
189
191
|
return null;
|
|
190
192
|
};
|
|
191
|
-
|
|
192
193
|
const getIsPermissionOverwritingDataFence = (actualPermissions, demandedDataFence) => {
|
|
193
194
|
if (!actualPermissions) return false;
|
|
195
|
+
|
|
194
196
|
/**
|
|
195
197
|
* NOTE:
|
|
196
198
|
* A data fence relates, exists in relation to a general permission.
|
|
@@ -201,20 +203,16 @@ const getIsPermissionOverwritingDataFence = (actualPermissions, demandedDataFenc
|
|
|
201
203
|
* Given the user _does not_ have manage access on the data fence's group
|
|
202
204
|
* Then the data fence itself takes precedence
|
|
203
205
|
*/
|
|
204
|
-
|
|
205
206
|
const demandedPermissionByDataFence = "Manage".concat(upperFirst__default["default"](demandedDataFence.group));
|
|
206
207
|
if (hasExactPermission(demandedPermissionByDataFence, actualPermissions)) return true;
|
|
207
208
|
return false;
|
|
208
209
|
};
|
|
209
|
-
|
|
210
210
|
const hasSomeDataFence = options => {
|
|
211
211
|
var _context2;
|
|
212
|
-
|
|
213
212
|
// Datafences applied should be combined with an OR, that is why we use
|
|
214
213
|
// `some` and not `every`
|
|
215
214
|
return _someInstanceProperty__default["default"](_context2 = options.demandedDataFences).call(_context2, demandedDataFence => {
|
|
216
215
|
var _context3;
|
|
217
|
-
|
|
218
216
|
// Given that dataFence structure on `applicationContext`, we get the value by a path
|
|
219
217
|
// e.g given dataFence with { store: { orders: { canManageOrders: { values: } } } }
|
|
220
218
|
// we read the dataFence by the [type] and [group]
|
|
@@ -222,26 +220,23 @@ const hasSomeDataFence = options => {
|
|
|
222
220
|
// with value = there is a dataFence to apply, overrules `hasDemandedProjectPermissions`
|
|
223
221
|
// without value = there is no dataFence to apply, overruled by `hasDemandedProjectPermissions`
|
|
224
222
|
const actualDataFenceByTypeAndGroup = getDataFenceByTypeAndGroup(options.actualDataFences, demandedDataFence.type, demandedDataFence.group);
|
|
225
|
-
if (!actualDataFenceByTypeAndGroup) return false;
|
|
223
|
+
if (!actualDataFenceByTypeAndGroup) return false;
|
|
226
224
|
|
|
225
|
+
// we try to find if the demanded dataFence is available inside the actual datafences
|
|
227
226
|
const specificActualDataFence = _findInstanceProperty__default["default"](_context3 = _Object$entries__default["default"](actualDataFenceByTypeAndGroup)).call(_context3, _ref => {
|
|
228
227
|
let _ref2 = _slicedToArray(_ref, 2),
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
228
|
+
dataFenceName = _ref2[0],
|
|
229
|
+
dataFenceValue = _ref2[1];
|
|
232
230
|
// Either the manage permission matches or the
|
|
233
231
|
// a demanded view permission is implied by a manage permission.
|
|
234
232
|
const doesDataFenceMatchByName = dataFenceName === toCanCase(demandedDataFence.name) || dataFenceName === toCanCase(toManageCase(demandedDataFence.name));
|
|
235
233
|
const doesDataFenceHaveValue = Boolean(dataFenceValue);
|
|
236
234
|
return doesDataFenceMatchByName && doesDataFenceHaveValue;
|
|
237
235
|
});
|
|
238
|
-
|
|
239
236
|
if (!specificActualDataFence) return false;
|
|
240
|
-
|
|
241
237
|
const _specificActualDataFe = _slicedToArray(specificActualDataFence, 2),
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
238
|
+
dataFenceName = _specificActualDataFe[0],
|
|
239
|
+
dataFenceValue = _specificActualDataFe[1];
|
|
245
240
|
const actualDataFence = {
|
|
246
241
|
name: dataFenceName,
|
|
247
242
|
// we do the type casting because at this point we are sure that
|
|
@@ -258,20 +253,26 @@ const hasSomeDataFence = options => {
|
|
|
258
253
|
});
|
|
259
254
|
};
|
|
260
255
|
|
|
256
|
+
// Permissions
|
|
257
|
+
|
|
258
|
+
// Action rights
|
|
259
|
+
|
|
260
|
+
// Data fences
|
|
261
|
+
|
|
261
262
|
// Log a warning only once, and not on each render.
|
|
262
263
|
const useWarning = (condition, message) => {
|
|
263
264
|
react.useEffect(() => {
|
|
265
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
264
266
|
}, []);
|
|
265
267
|
};
|
|
266
|
-
|
|
267
268
|
const useIsAuthorized = _ref => {
|
|
268
269
|
let demandedPermissions = _ref.demandedPermissions,
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
270
|
+
demandedActionRights = _ref.demandedActionRights,
|
|
271
|
+
demandedDataFences = _ref.demandedDataFences,
|
|
272
|
+
selectDataFenceData = _ref.selectDataFenceData,
|
|
273
|
+
_ref$shouldMatchSomeP = _ref.shouldMatchSomePermissions,
|
|
274
|
+
shouldMatchSomePermissions = _ref$shouldMatchSomeP === void 0 ? false : _ref$shouldMatchSomeP,
|
|
275
|
+
projectPermissions = _ref.projectPermissions;
|
|
275
276
|
const impliedPermissions = getImpliedPermissions(demandedPermissions);
|
|
276
277
|
useWarning(!demandedActionRights || demandedActionRights.length === 1);
|
|
277
278
|
useWarning(!demandedPermissions || demandedPermissions.length === 1);
|
|
@@ -279,28 +280,24 @@ const useIsAuthorized = _ref => {
|
|
|
279
280
|
useWarning(!impliedPermissions || impliedPermissions.length === 0, "@commercetools-frontend/permissions: Demanded permissions contain implied permissions. These are implied: ".concat(impliedPermissions.join(', '), "."));
|
|
280
281
|
const actualPermissions = applicationShellConnectors.useApplicationContext(applicationContext => {
|
|
281
282
|
var _projectPermissions$p;
|
|
282
|
-
|
|
283
283
|
return (_projectPermissions$p = projectPermissions === null || projectPermissions === void 0 ? void 0 : projectPermissions.permissions) !== null && _projectPermissions$p !== void 0 ? _projectPermissions$p : applicationContext.permissions;
|
|
284
284
|
});
|
|
285
285
|
const actualActionRights = applicationShellConnectors.useApplicationContext(applicationContext => {
|
|
286
286
|
var _projectPermissions$a;
|
|
287
|
-
|
|
288
287
|
return (_projectPermissions$a = projectPermissions === null || projectPermissions === void 0 ? void 0 : projectPermissions.actionRights) !== null && _projectPermissions$a !== void 0 ? _projectPermissions$a : applicationContext.actionRights;
|
|
289
288
|
});
|
|
290
289
|
const actualDataFences = applicationShellConnectors.useApplicationContext(applicationContext => {
|
|
291
290
|
var _projectPermissions$d;
|
|
292
|
-
|
|
293
291
|
return (_projectPermissions$d = projectPermissions === null || projectPermissions === void 0 ? void 0 : projectPermissions.dataFences) !== null && _projectPermissions$d !== void 0 ? _projectPermissions$d : applicationContext.dataFences;
|
|
294
|
-
});
|
|
292
|
+
});
|
|
295
293
|
|
|
294
|
+
// if the user has no permissions and no dataFences assigned to them, they are not authorized
|
|
296
295
|
if (!actualPermissions && !actualDataFences) return false;
|
|
297
296
|
let hasDemandedDataFences = false;
|
|
298
|
-
|
|
299
297
|
if (demandedDataFences && demandedDataFences.length > 0) {
|
|
300
298
|
if (!selectDataFenceData) {
|
|
301
299
|
sentry.reportErrorToSentry(new Error("@commercetools-frontend/permissions/Authorized: Missing data fences selector \"selectDataFenceData\"."));
|
|
302
300
|
}
|
|
303
|
-
|
|
304
301
|
hasDemandedDataFences = hasSomeDataFence({
|
|
305
302
|
actualPermissions,
|
|
306
303
|
demandedDataFences,
|
|
@@ -308,7 +305,6 @@ const useIsAuthorized = _ref => {
|
|
|
308
305
|
selectDataFenceData
|
|
309
306
|
});
|
|
310
307
|
}
|
|
311
|
-
|
|
312
308
|
const hasDemandedPermissions = shouldMatchSomePermissions ? hasSomePermissions(demandedPermissions, actualPermissions) : hasEveryPermissions(demandedPermissions, actualPermissions);
|
|
313
309
|
const hasDemandedActionRights = hasEveryActionRight(demandedActionRights || [], actualActionRights);
|
|
314
310
|
return hasDemandedDataFences || hasDemandedPermissions && hasDemandedActionRights;
|
|
@@ -319,21 +315,17 @@ const getDisplayName = Component => {
|
|
|
319
315
|
if (typeof Component === 'string') {
|
|
320
316
|
return Component;
|
|
321
317
|
}
|
|
322
|
-
|
|
323
318
|
if (!Component) {
|
|
324
319
|
return undefined;
|
|
325
320
|
}
|
|
326
|
-
|
|
327
321
|
return Component.displayName || Component.name || 'Component';
|
|
328
322
|
};
|
|
329
323
|
|
|
330
324
|
function ownKeys$1(object, enumerableOnly) { var keys = _Object$keys__default["default"](object); if (_Object$getOwnPropertySymbols__default["default"]) { var symbols = _Object$getOwnPropertySymbols__default["default"](object); enumerableOnly && (symbols = _filterInstanceProperty__default["default"](symbols).call(symbols, function (sym) { return _Object$getOwnPropertyDescriptor__default["default"](object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; }
|
|
331
|
-
|
|
332
325
|
function _objectSpread$1(target) { for (var i = 1; i < arguments.length; i++) { var _context, _context2; var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? _forEachInstanceProperty__default["default"](_context = ownKeys$1(Object(source), !0)).call(_context, function (key) { _defineProperty(target, key, source[key]); }) : _Object$getOwnPropertyDescriptors__default["default"] ? _Object$defineProperties__default["default"](target, _Object$getOwnPropertyDescriptors__default["default"](source)) : _forEachInstanceProperty__default["default"](_context2 = ownKeys$1(Object(source))).call(_context2, function (key) { _Object$defineProperty__default["default"](target, key, _Object$getOwnPropertyDescriptor__default["default"](source, key)); }); } return target; }
|
|
333
326
|
const defaultProps = {
|
|
334
327
|
shouldMatchSomePermissions: false
|
|
335
328
|
};
|
|
336
|
-
|
|
337
329
|
const Authorized = props => {
|
|
338
330
|
const isAuthorized = useIsAuthorized({
|
|
339
331
|
demandedPermissions: props.demandedPermissions,
|
|
@@ -347,7 +339,6 @@ const Authorized = props => {
|
|
|
347
339
|
children: props.render(isAuthorized)
|
|
348
340
|
});
|
|
349
341
|
};
|
|
350
|
-
|
|
351
342
|
Authorized.propTypes = {
|
|
352
343
|
demandedPermissions: _pt__default["default"].arrayOf(_pt__default["default"].string).isRequired,
|
|
353
344
|
demandedActionRights: _pt__default["default"].arrayOf(_pt__default["default"].shape({
|
|
@@ -370,7 +361,6 @@ Authorized.propTypes = {
|
|
|
370
361
|
};
|
|
371
362
|
Authorized.displayName = 'Authorized';
|
|
372
363
|
Authorized.defaultProps = defaultProps;
|
|
373
|
-
|
|
374
364
|
const injectAuthorized = function (demandedPermissions) {
|
|
375
365
|
let options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
|
|
376
366
|
let propName = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 'isAuthorized';
|
|
@@ -385,14 +375,18 @@ const injectAuthorized = function (demandedPermissions) {
|
|
|
385
375
|
[propName]: isAuthorized
|
|
386
376
|
}))
|
|
387
377
|
});
|
|
388
|
-
|
|
389
378
|
WrappedComponent.displayName = "withUserPermissions(".concat(getDisplayName(Component), ")");
|
|
390
379
|
return WrappedComponent;
|
|
391
380
|
};
|
|
392
381
|
};
|
|
393
382
|
|
|
394
|
-
const getHasChildren = children => react.Children.count(children) > 0;
|
|
383
|
+
const getHasChildren = children => react.Children.count(children) > 0;
|
|
384
|
+
|
|
385
|
+
// Permissions
|
|
386
|
+
|
|
387
|
+
// Action rights
|
|
395
388
|
|
|
389
|
+
// Data fences
|
|
396
390
|
|
|
397
391
|
const RestrictedByPermissions = props => {
|
|
398
392
|
!!(typeof props.children === 'function' && !isNil__default["default"](props.unauthorizedComponent)) ? invariant__default["default"](false) : void 0;
|
|
@@ -410,7 +404,6 @@ const RestrictedByPermissions = props => {
|
|
|
410
404
|
if (typeof props.render === 'function') return props.render({
|
|
411
405
|
isAuthorized
|
|
412
406
|
});
|
|
413
|
-
|
|
414
407
|
if (isAuthorized) {
|
|
415
408
|
if (props.children && getHasChildren(props.children)) return react.Children.only(props.children);
|
|
416
409
|
} else if (!isAuthorized) {
|
|
@@ -418,19 +411,15 @@ const RestrictedByPermissions = props => {
|
|
|
418
411
|
return /*#__PURE__*/react.createElement(props.unauthorizedComponent);
|
|
419
412
|
}
|
|
420
413
|
}
|
|
421
|
-
|
|
422
414
|
return null;
|
|
423
415
|
}
|
|
424
416
|
});
|
|
425
417
|
};
|
|
426
|
-
|
|
427
418
|
RestrictedByPermissions.propTypes = {};
|
|
428
419
|
RestrictedByPermissions.displayName = 'RestrictedByPermissions';
|
|
429
420
|
|
|
430
421
|
function ownKeys(object, enumerableOnly) { var keys = _Object$keys__default["default"](object); if (_Object$getOwnPropertySymbols__default["default"]) { var symbols = _Object$getOwnPropertySymbols__default["default"](object); enumerableOnly && (symbols = _filterInstanceProperty__default["default"](symbols).call(symbols, function (sym) { return _Object$getOwnPropertyDescriptor__default["default"](object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; }
|
|
431
|
-
|
|
432
422
|
function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var _context, _context2; var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? _forEachInstanceProperty__default["default"](_context = ownKeys(Object(source), !0)).call(_context, function (key) { _defineProperty(target, key, source[key]); }) : _Object$getOwnPropertyDescriptors__default["default"] ? _Object$defineProperties__default["default"](target, _Object$getOwnPropertyDescriptors__default["default"](source)) : _forEachInstanceProperty__default["default"](_context2 = ownKeys(Object(source))).call(_context2, function (key) { _Object$defineProperty__default["default"](target, key, _Object$getOwnPropertyDescriptor__default["default"](source, key)); }); } return target; }
|
|
433
|
-
|
|
434
423
|
const branchOnPermissions = function (demandedPermissions, FallbackComponent) {
|
|
435
424
|
let options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {
|
|
436
425
|
shouldMatchSomePermissions: false
|
|
@@ -446,15 +435,12 @@ const branchOnPermissions = function (demandedPermissions, FallbackComponent) {
|
|
|
446
435
|
if (isAuthorized) {
|
|
447
436
|
return jsxRuntime.jsx(Component, _objectSpread({}, props));
|
|
448
437
|
}
|
|
449
|
-
|
|
450
438
|
if (FallbackComponent) {
|
|
451
439
|
return jsxRuntime.jsx(FallbackComponent, {});
|
|
452
440
|
}
|
|
453
|
-
|
|
454
441
|
return jsxRuntime.jsx(jsxRuntime.Fragment, {});
|
|
455
442
|
}
|
|
456
443
|
});
|
|
457
|
-
|
|
458
444
|
WrappedComponent.displayName = "branchOnPermissions(".concat(getDisplayName(Component), ")");
|
|
459
445
|
return WrappedComponent;
|
|
460
446
|
};
|
|
@@ -26,47 +26,52 @@ import upperFirst from 'lodash/upperFirst';
|
|
|
26
26
|
import { jsx, Fragment } from '@emotion/react/jsx-runtime';
|
|
27
27
|
|
|
28
28
|
// NOTE: This string will be replaced on build time with the package version.
|
|
29
|
-
var version = "22.
|
|
29
|
+
var version = "22.3.0";
|
|
30
|
+
|
|
31
|
+
// Permissions
|
|
32
|
+
|
|
33
|
+
// Action rights
|
|
34
|
+
|
|
35
|
+
// Data fences
|
|
36
|
+
|
|
37
|
+
// Potentially a union type.
|
|
30
38
|
|
|
31
39
|
// Build the permission key from the definition to match it to the format coming from the API.
|
|
32
40
|
const toCanCase = permissionName => "can".concat(permissionName);
|
|
33
|
-
|
|
34
41
|
const getIsViewPermission = demandedPermission => _startsWithInstanceProperty(demandedPermission).call(demandedPermission, 'View');
|
|
42
|
+
const toManageCase = permissionName => permissionName.replace('View', 'Manage');
|
|
35
43
|
|
|
36
|
-
|
|
44
|
+
// Check that the user permissions match EXACTLY the required permission.
|
|
37
45
|
// The shapes of the arguments are:
|
|
38
46
|
// - demandedPermission:
|
|
39
47
|
// 'ViewProducts'
|
|
40
48
|
// - actualPermissions:
|
|
41
49
|
// { canViewProducts: true, canManageOrders: false }
|
|
42
|
-
|
|
43
|
-
|
|
44
50
|
const hasExactPermission = (demandedPermission, actualPermissions) => actualPermissions[toCanCase(demandedPermission)];
|
|
51
|
+
const getInferredManagePermission = (demandedPermission, actualPermissions) => actualPermissions[toCanCase(toManageCase(demandedPermission))];
|
|
45
52
|
|
|
46
|
-
|
|
53
|
+
// Check that the user permissions match the required MANAGE permission.
|
|
47
54
|
// The shapes of the arguments are:
|
|
48
55
|
// - demandedPermission:
|
|
49
56
|
// 'ViewProducts'
|
|
50
57
|
// - actualPermissions:
|
|
51
58
|
// { canViewProducts: true, canManageOrders: false }
|
|
52
|
-
|
|
53
|
-
|
|
54
59
|
const doesManagePermissionInferViewPermission = (demandedPermission, actualPermissions) => {
|
|
55
60
|
const isDemandedPermissionViewPermission = getIsViewPermission(demandedPermission);
|
|
56
61
|
const isViewPermissionInferredByManagePermission = Boolean(getInferredManagePermission(demandedPermission, actualPermissions));
|
|
57
62
|
return isDemandedPermissionViewPermission && isViewPermissionInferredByManagePermission;
|
|
58
|
-
};
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
// Check if the demanded permissions contain any unnecessary
|
|
59
66
|
// implied permissions.
|
|
60
67
|
// E.g. ViewCustomerGroup is implied by ManageCustomerGroup.
|
|
61
|
-
|
|
62
|
-
|
|
63
68
|
const getImpliedPermissions = permissions => {
|
|
64
69
|
const viewPermissions = _filterInstanceProperty(permissions).call(permissions, permission => _startsWithInstanceProperty(permission).call(permission, 'View'));
|
|
65
|
-
|
|
66
70
|
const impliedPermissions = _filterInstanceProperty(viewPermissions).call(viewPermissions, viewPermission => _includesInstanceProperty(permissions).call(permissions, toManageCase(viewPermission)));
|
|
67
|
-
|
|
68
71
|
return impliedPermissions;
|
|
69
|
-
};
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
// Check the user permissions using one of the defined matchers.
|
|
70
75
|
// The shapes of the arguments are:
|
|
71
76
|
// - demandedPermission:
|
|
72
77
|
// 'ViewProducts'
|
|
@@ -75,27 +80,32 @@ const getImpliedPermissions = permissions => {
|
|
|
75
80
|
// NOTE: in case the `actualPermissions` are not defined, fall back to an empty object.
|
|
76
81
|
// This might be the case when the permissions for a user/project could not be loaded
|
|
77
82
|
// (e.g. project not found).
|
|
83
|
+
const hasPermission = (demandedPermission, actualPermissions) =>
|
|
84
|
+
// First checking the existence of the exact permission
|
|
85
|
+
hasExactPermission(demandedPermission, actualPermissions || {}) ||
|
|
86
|
+
// Then checking if a view permission is inferred as a manage permission
|
|
87
|
+
doesManagePermissionInferViewPermission(demandedPermission, actualPermissions || {});
|
|
78
88
|
|
|
79
|
-
|
|
80
|
-
hasExactPermission(demandedPermission, actualPermissions || {}) || // Then checking if a view permission is inferred as a manage permission
|
|
81
|
-
doesManagePermissionInferViewPermission(demandedPermission, actualPermissions || {}); // Check the user action rights using one of the defined matchers.
|
|
89
|
+
// Check the user action rights using one of the defined matchers.
|
|
82
90
|
// The shapes of the arguments are:
|
|
83
91
|
// - demandedActionRight:
|
|
84
92
|
// '{ group: 'products', name: 'editPrices' }'
|
|
85
93
|
// - actualActionRights:
|
|
86
94
|
// { orders: { canEditPrices: false }, products: { canEditPrices: true } }
|
|
87
|
-
|
|
88
95
|
const hasActionRight = (demandedActionRight, actualActionRights) => {
|
|
89
96
|
const actionRightGroup = actualActionRights && actualActionRights[demandedActionRight.group];
|
|
90
97
|
return Boolean(actionRightGroup && actionRightGroup[toCanCase(demandedActionRight.name)]);
|
|
91
|
-
};
|
|
98
|
+
};
|
|
99
|
+
|
|
100
|
+
// Check that the user permissions match EVERY one of the required permissions.
|
|
92
101
|
// The shapes of the arguments are:
|
|
93
102
|
// - demandedPermissions:
|
|
94
103
|
// ['ViewProducts', 'ManageOrders']
|
|
95
104
|
// - actualPermissions:
|
|
96
105
|
// { canViewProducts: true, canManageOrders: false }
|
|
106
|
+
const hasEveryPermissions = (demandedPermissions, actualPermissions) => _everyInstanceProperty(demandedPermissions).call(demandedPermissions, permission => hasPermission(permission, actualPermissions));
|
|
97
107
|
|
|
98
|
-
|
|
108
|
+
// Check that the user action rights match EVERY one of the required action rights.
|
|
99
109
|
// The shapes of the arguments are:
|
|
100
110
|
// - demandedActionRights:
|
|
101
111
|
// [
|
|
@@ -104,16 +114,15 @@ const hasEveryPermissions = (demandedPermissions, actualPermissions) => _everyIn
|
|
|
104
114
|
// ]
|
|
105
115
|
// - actualActionRights:
|
|
106
116
|
// { products: { canEditPrices: true, canPublishProducts: true } }
|
|
117
|
+
const hasEveryActionRight = (demandedActionRights, actualActionRights) => _everyInstanceProperty(demandedActionRights).call(demandedActionRights, actionRight => hasActionRight(actionRight, actualActionRights));
|
|
107
118
|
|
|
108
|
-
|
|
119
|
+
// Check that the user permissions match SOME one of the required permissions.
|
|
109
120
|
// The shapes of the arguments are:
|
|
110
121
|
// - demandedPermissions:
|
|
111
122
|
// ['ViewProducts', 'ManageOrders']
|
|
112
123
|
// - actualPermissions:
|
|
113
124
|
// { canViewProducts: true, canManageOrders: false }
|
|
114
|
-
|
|
115
125
|
const hasSomePermissions = (demandedPermissions, actualPermissions) => _someInstanceProperty(demandedPermissions).call(demandedPermissions, permission => hasPermission(permission, actualPermissions));
|
|
116
|
-
|
|
117
126
|
const getHasDemandedDataFence = options => {
|
|
118
127
|
if (!options.selectDataFenceData) return false;
|
|
119
128
|
const hasDemandedPermission = hasPermission(options.demandedDataFence.name, {
|
|
@@ -126,45 +135,38 @@ const getHasDemandedDataFence = options => {
|
|
|
126
135
|
name: options.demandedDataFence.name,
|
|
127
136
|
actualDataFenceValues: _valuesInstanceProperty(options.actualDataFence.dataFenceValue)
|
|
128
137
|
});
|
|
129
|
-
|
|
130
138
|
if (!selectedDataFenceData) {
|
|
131
139
|
reportErrorToSentry(new Error("missing mapper for type \"".concat(options.demandedDataFence.type, "\"")), {
|
|
132
140
|
extra: options.demandedDataFence.type
|
|
133
141
|
});
|
|
134
142
|
return false;
|
|
135
|
-
}
|
|
136
|
-
|
|
143
|
+
}
|
|
137
144
|
|
|
145
|
+
// it is enough to only have a subset of demanded dataFence data belonging to actual dataFence values
|
|
138
146
|
return _someInstanceProperty(selectedDataFenceData).call(selectedDataFenceData, value => {
|
|
139
147
|
var _context;
|
|
140
|
-
|
|
141
148
|
return _includesInstanceProperty(_context = _valuesInstanceProperty(options.actualDataFence.dataFenceValue)).call(_context, value);
|
|
142
149
|
});
|
|
143
150
|
};
|
|
144
|
-
|
|
145
151
|
const getDataFenceByTypeAndGroup = (actualDataFences, demandedDataFenceType, demandedDataFenceGroup) => {
|
|
146
152
|
if (!actualDataFences) return null;
|
|
147
|
-
|
|
148
153
|
if (demandedDataFenceType in actualDataFences) {
|
|
149
154
|
switch (demandedDataFenceType) {
|
|
150
155
|
case 'store':
|
|
151
156
|
{
|
|
152
157
|
const actualDataFence = actualDataFences[demandedDataFenceType];
|
|
153
|
-
|
|
154
158
|
if (actualDataFence && demandedDataFenceGroup in actualDataFence) {
|
|
155
159
|
return actualDataFence[demandedDataFenceGroup];
|
|
156
160
|
}
|
|
157
|
-
|
|
158
161
|
break;
|
|
159
162
|
}
|
|
160
163
|
}
|
|
161
164
|
}
|
|
162
|
-
|
|
163
165
|
return null;
|
|
164
166
|
};
|
|
165
|
-
|
|
166
167
|
const getIsPermissionOverwritingDataFence = (actualPermissions, demandedDataFence) => {
|
|
167
168
|
if (!actualPermissions) return false;
|
|
169
|
+
|
|
168
170
|
/**
|
|
169
171
|
* NOTE:
|
|
170
172
|
* A data fence relates, exists in relation to a general permission.
|
|
@@ -175,20 +177,16 @@ const getIsPermissionOverwritingDataFence = (actualPermissions, demandedDataFenc
|
|
|
175
177
|
* Given the user _does not_ have manage access on the data fence's group
|
|
176
178
|
* Then the data fence itself takes precedence
|
|
177
179
|
*/
|
|
178
|
-
|
|
179
180
|
const demandedPermissionByDataFence = "Manage".concat(upperFirst(demandedDataFence.group));
|
|
180
181
|
if (hasExactPermission(demandedPermissionByDataFence, actualPermissions)) return true;
|
|
181
182
|
return false;
|
|
182
183
|
};
|
|
183
|
-
|
|
184
184
|
const hasSomeDataFence = options => {
|
|
185
185
|
var _context2;
|
|
186
|
-
|
|
187
186
|
// Datafences applied should be combined with an OR, that is why we use
|
|
188
187
|
// `some` and not `every`
|
|
189
188
|
return _someInstanceProperty(_context2 = options.demandedDataFences).call(_context2, demandedDataFence => {
|
|
190
189
|
var _context3;
|
|
191
|
-
|
|
192
190
|
// Given that dataFence structure on `applicationContext`, we get the value by a path
|
|
193
191
|
// e.g given dataFence with { store: { orders: { canManageOrders: { values: } } } }
|
|
194
192
|
// we read the dataFence by the [type] and [group]
|
|
@@ -196,26 +194,23 @@ const hasSomeDataFence = options => {
|
|
|
196
194
|
// with value = there is a dataFence to apply, overrules `hasDemandedProjectPermissions`
|
|
197
195
|
// without value = there is no dataFence to apply, overruled by `hasDemandedProjectPermissions`
|
|
198
196
|
const actualDataFenceByTypeAndGroup = getDataFenceByTypeAndGroup(options.actualDataFences, demandedDataFence.type, demandedDataFence.group);
|
|
199
|
-
if (!actualDataFenceByTypeAndGroup) return false;
|
|
197
|
+
if (!actualDataFenceByTypeAndGroup) return false;
|
|
200
198
|
|
|
199
|
+
// we try to find if the demanded dataFence is available inside the actual datafences
|
|
201
200
|
const specificActualDataFence = _findInstanceProperty(_context3 = _Object$entries(actualDataFenceByTypeAndGroup)).call(_context3, _ref => {
|
|
202
201
|
let _ref2 = _slicedToArray(_ref, 2),
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
202
|
+
dataFenceName = _ref2[0],
|
|
203
|
+
dataFenceValue = _ref2[1];
|
|
206
204
|
// Either the manage permission matches or the
|
|
207
205
|
// a demanded view permission is implied by a manage permission.
|
|
208
206
|
const doesDataFenceMatchByName = dataFenceName === toCanCase(demandedDataFence.name) || dataFenceName === toCanCase(toManageCase(demandedDataFence.name));
|
|
209
207
|
const doesDataFenceHaveValue = Boolean(dataFenceValue);
|
|
210
208
|
return doesDataFenceMatchByName && doesDataFenceHaveValue;
|
|
211
209
|
});
|
|
212
|
-
|
|
213
210
|
if (!specificActualDataFence) return false;
|
|
214
|
-
|
|
215
211
|
const _specificActualDataFe = _slicedToArray(specificActualDataFence, 2),
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
212
|
+
dataFenceName = _specificActualDataFe[0],
|
|
213
|
+
dataFenceValue = _specificActualDataFe[1];
|
|
219
214
|
const actualDataFence = {
|
|
220
215
|
name: dataFenceName,
|
|
221
216
|
// we do the type casting because at this point we are sure that
|
|
@@ -232,21 +227,27 @@ const hasSomeDataFence = options => {
|
|
|
232
227
|
});
|
|
233
228
|
};
|
|
234
229
|
|
|
230
|
+
// Permissions
|
|
231
|
+
|
|
232
|
+
// Action rights
|
|
233
|
+
|
|
234
|
+
// Data fences
|
|
235
|
+
|
|
235
236
|
// Log a warning only once, and not on each render.
|
|
236
237
|
const useWarning = (condition, message) => {
|
|
237
238
|
useEffect(() => {
|
|
238
|
-
process.env.NODE_ENV !== "production" ? warning(condition, message) : void 0;
|
|
239
|
+
process.env.NODE_ENV !== "production" ? warning(condition, message) : void 0;
|
|
240
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
239
241
|
}, []);
|
|
240
242
|
};
|
|
241
|
-
|
|
242
243
|
const useIsAuthorized = _ref => {
|
|
243
244
|
let demandedPermissions = _ref.demandedPermissions,
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
245
|
+
demandedActionRights = _ref.demandedActionRights,
|
|
246
|
+
demandedDataFences = _ref.demandedDataFences,
|
|
247
|
+
selectDataFenceData = _ref.selectDataFenceData,
|
|
248
|
+
_ref$shouldMatchSomeP = _ref.shouldMatchSomePermissions,
|
|
249
|
+
shouldMatchSomePermissions = _ref$shouldMatchSomeP === void 0 ? false : _ref$shouldMatchSomeP,
|
|
250
|
+
projectPermissions = _ref.projectPermissions;
|
|
250
251
|
const impliedPermissions = getImpliedPermissions(demandedPermissions);
|
|
251
252
|
useWarning(!demandedActionRights || demandedActionRights.length === 1, "@commercetools-frontend/permissions: It is recommended to pass a single demanded action right while using the hook, HoC or component multiple times.");
|
|
252
253
|
useWarning(!demandedPermissions || demandedPermissions.length === 1, "@commercetools-frontend/permissions: It is recommended to pass a single demanded permission while using the hook, HoC or component multiple times.");
|
|
@@ -254,28 +255,24 @@ const useIsAuthorized = _ref => {
|
|
|
254
255
|
useWarning(!impliedPermissions || impliedPermissions.length === 0, "@commercetools-frontend/permissions: Demanded permissions contain implied permissions. These are implied: ".concat(impliedPermissions.join(', '), "."));
|
|
255
256
|
const actualPermissions = useApplicationContext(applicationContext => {
|
|
256
257
|
var _projectPermissions$p;
|
|
257
|
-
|
|
258
258
|
return (_projectPermissions$p = projectPermissions === null || projectPermissions === void 0 ? void 0 : projectPermissions.permissions) !== null && _projectPermissions$p !== void 0 ? _projectPermissions$p : applicationContext.permissions;
|
|
259
259
|
});
|
|
260
260
|
const actualActionRights = useApplicationContext(applicationContext => {
|
|
261
261
|
var _projectPermissions$a;
|
|
262
|
-
|
|
263
262
|
return (_projectPermissions$a = projectPermissions === null || projectPermissions === void 0 ? void 0 : projectPermissions.actionRights) !== null && _projectPermissions$a !== void 0 ? _projectPermissions$a : applicationContext.actionRights;
|
|
264
263
|
});
|
|
265
264
|
const actualDataFences = useApplicationContext(applicationContext => {
|
|
266
265
|
var _projectPermissions$d;
|
|
267
|
-
|
|
268
266
|
return (_projectPermissions$d = projectPermissions === null || projectPermissions === void 0 ? void 0 : projectPermissions.dataFences) !== null && _projectPermissions$d !== void 0 ? _projectPermissions$d : applicationContext.dataFences;
|
|
269
|
-
});
|
|
267
|
+
});
|
|
270
268
|
|
|
269
|
+
// if the user has no permissions and no dataFences assigned to them, they are not authorized
|
|
271
270
|
if (!actualPermissions && !actualDataFences) return false;
|
|
272
271
|
let hasDemandedDataFences = false;
|
|
273
|
-
|
|
274
272
|
if (demandedDataFences && demandedDataFences.length > 0) {
|
|
275
273
|
if (!selectDataFenceData) {
|
|
276
274
|
reportErrorToSentry(new Error("@commercetools-frontend/permissions/Authorized: Missing data fences selector \"selectDataFenceData\"."));
|
|
277
275
|
}
|
|
278
|
-
|
|
279
276
|
hasDemandedDataFences = hasSomeDataFence({
|
|
280
277
|
actualPermissions,
|
|
281
278
|
demandedDataFences,
|
|
@@ -283,7 +280,6 @@ const useIsAuthorized = _ref => {
|
|
|
283
280
|
selectDataFenceData
|
|
284
281
|
});
|
|
285
282
|
}
|
|
286
|
-
|
|
287
283
|
const hasDemandedPermissions = shouldMatchSomePermissions ? hasSomePermissions(demandedPermissions, actualPermissions) : hasEveryPermissions(demandedPermissions, actualPermissions);
|
|
288
284
|
const hasDemandedActionRights = hasEveryActionRight(demandedActionRights || [], actualActionRights);
|
|
289
285
|
return hasDemandedDataFences || hasDemandedPermissions && hasDemandedActionRights;
|
|
@@ -294,21 +290,17 @@ const getDisplayName = Component => {
|
|
|
294
290
|
if (typeof Component === 'string') {
|
|
295
291
|
return Component;
|
|
296
292
|
}
|
|
297
|
-
|
|
298
293
|
if (!Component) {
|
|
299
294
|
return undefined;
|
|
300
295
|
}
|
|
301
|
-
|
|
302
296
|
return Component.displayName || Component.name || 'Component';
|
|
303
297
|
};
|
|
304
298
|
|
|
305
299
|
function ownKeys$1(object, enumerableOnly) { var keys = _Object$keys(object); if (_Object$getOwnPropertySymbols) { var symbols = _Object$getOwnPropertySymbols(object); enumerableOnly && (symbols = _filterInstanceProperty(symbols).call(symbols, function (sym) { return _Object$getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; }
|
|
306
|
-
|
|
307
300
|
function _objectSpread$1(target) { for (var i = 1; i < arguments.length; i++) { var _context, _context2; var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? _forEachInstanceProperty(_context = ownKeys$1(Object(source), !0)).call(_context, function (key) { _defineProperty(target, key, source[key]); }) : _Object$getOwnPropertyDescriptors ? _Object$defineProperties(target, _Object$getOwnPropertyDescriptors(source)) : _forEachInstanceProperty(_context2 = ownKeys$1(Object(source))).call(_context2, function (key) { _Object$defineProperty(target, key, _Object$getOwnPropertyDescriptor(source, key)); }); } return target; }
|
|
308
301
|
const defaultProps = {
|
|
309
302
|
shouldMatchSomePermissions: false
|
|
310
303
|
};
|
|
311
|
-
|
|
312
304
|
const Authorized = props => {
|
|
313
305
|
const isAuthorized = useIsAuthorized({
|
|
314
306
|
demandedPermissions: props.demandedPermissions,
|
|
@@ -322,7 +314,6 @@ const Authorized = props => {
|
|
|
322
314
|
children: props.render(isAuthorized)
|
|
323
315
|
});
|
|
324
316
|
};
|
|
325
|
-
|
|
326
317
|
Authorized.propTypes = {
|
|
327
318
|
demandedPermissions: _pt.arrayOf(_pt.string).isRequired,
|
|
328
319
|
demandedActionRights: _pt.arrayOf(_pt.shape({
|
|
@@ -345,7 +336,6 @@ Authorized.propTypes = {
|
|
|
345
336
|
};
|
|
346
337
|
Authorized.displayName = 'Authorized';
|
|
347
338
|
Authorized.defaultProps = defaultProps;
|
|
348
|
-
|
|
349
339
|
const injectAuthorized = function (demandedPermissions) {
|
|
350
340
|
let options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
|
|
351
341
|
let propName = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 'isAuthorized';
|
|
@@ -360,14 +350,18 @@ const injectAuthorized = function (demandedPermissions) {
|
|
|
360
350
|
[propName]: isAuthorized
|
|
361
351
|
}))
|
|
362
352
|
});
|
|
363
|
-
|
|
364
353
|
WrappedComponent.displayName = "withUserPermissions(".concat(getDisplayName(Component), ")");
|
|
365
354
|
return WrappedComponent;
|
|
366
355
|
};
|
|
367
356
|
};
|
|
368
357
|
|
|
369
|
-
const getHasChildren = children => Children.count(children) > 0;
|
|
358
|
+
const getHasChildren = children => Children.count(children) > 0;
|
|
359
|
+
|
|
360
|
+
// Permissions
|
|
361
|
+
|
|
362
|
+
// Action rights
|
|
370
363
|
|
|
364
|
+
// Data fences
|
|
371
365
|
|
|
372
366
|
const RestrictedByPermissions = props => {
|
|
373
367
|
!!(typeof props.children === 'function' && !isNil(props.unauthorizedComponent)) ? process.env.NODE_ENV !== "production" ? invariant(false, '@commercetools-frontend/permissions/RestrictedByPermissions: You provided both `children` and `unauthorizedComponent`. Please provide only one of them.') : invariant(false) : void 0;
|
|
@@ -385,7 +379,6 @@ const RestrictedByPermissions = props => {
|
|
|
385
379
|
if (typeof props.render === 'function') return props.render({
|
|
386
380
|
isAuthorized
|
|
387
381
|
});
|
|
388
|
-
|
|
389
382
|
if (isAuthorized) {
|
|
390
383
|
if (props.children && getHasChildren(props.children)) return Children.only(props.children);
|
|
391
384
|
} else if (!isAuthorized) {
|
|
@@ -393,12 +386,10 @@ const RestrictedByPermissions = props => {
|
|
|
393
386
|
return /*#__PURE__*/createElement(props.unauthorizedComponent);
|
|
394
387
|
}
|
|
395
388
|
}
|
|
396
|
-
|
|
397
389
|
return null;
|
|
398
390
|
}
|
|
399
391
|
});
|
|
400
392
|
};
|
|
401
|
-
|
|
402
393
|
RestrictedByPermissions.propTypes = process.env.NODE_ENV !== "production" ? {
|
|
403
394
|
shouldMatchSomePermissions: _pt.bool,
|
|
404
395
|
permissions: _pt.arrayOf(_pt.string).isRequired,
|
|
@@ -424,9 +415,7 @@ RestrictedByPermissions.propTypes = process.env.NODE_ENV !== "production" ? {
|
|
|
424
415
|
RestrictedByPermissions.displayName = 'RestrictedByPermissions';
|
|
425
416
|
|
|
426
417
|
function ownKeys(object, enumerableOnly) { var keys = _Object$keys(object); if (_Object$getOwnPropertySymbols) { var symbols = _Object$getOwnPropertySymbols(object); enumerableOnly && (symbols = _filterInstanceProperty(symbols).call(symbols, function (sym) { return _Object$getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; }
|
|
427
|
-
|
|
428
418
|
function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var _context, _context2; var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? _forEachInstanceProperty(_context = ownKeys(Object(source), !0)).call(_context, function (key) { _defineProperty(target, key, source[key]); }) : _Object$getOwnPropertyDescriptors ? _Object$defineProperties(target, _Object$getOwnPropertyDescriptors(source)) : _forEachInstanceProperty(_context2 = ownKeys(Object(source))).call(_context2, function (key) { _Object$defineProperty(target, key, _Object$getOwnPropertyDescriptor(source, key)); }); } return target; }
|
|
429
|
-
|
|
430
419
|
const branchOnPermissions = function (demandedPermissions, FallbackComponent) {
|
|
431
420
|
let options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {
|
|
432
421
|
shouldMatchSomePermissions: false
|
|
@@ -442,15 +431,12 @@ const branchOnPermissions = function (demandedPermissions, FallbackComponent) {
|
|
|
442
431
|
if (isAuthorized) {
|
|
443
432
|
return jsx(Component, _objectSpread({}, props));
|
|
444
433
|
}
|
|
445
|
-
|
|
446
434
|
if (FallbackComponent) {
|
|
447
435
|
return jsx(FallbackComponent, {});
|
|
448
436
|
}
|
|
449
|
-
|
|
450
437
|
return jsx(Fragment, {});
|
|
451
438
|
}
|
|
452
439
|
});
|
|
453
|
-
|
|
454
440
|
WrappedComponent.displayName = "branchOnPermissions(".concat(getDisplayName(Component), ")");
|
|
455
441
|
return WrappedComponent;
|
|
456
442
|
};
|
|
@@ -31,7 +31,7 @@ type Props = {
|
|
|
31
31
|
children?: never;
|
|
32
32
|
};
|
|
33
33
|
declare const Authorized: {
|
|
34
|
-
(props: Props): import("@emotion/react/jsx-
|
|
34
|
+
(props: Props): import("@emotion/react/types/jsx-namespace").EmotionJSX.Element;
|
|
35
35
|
displayName: string;
|
|
36
36
|
defaultProps: Pick<Props, "shouldMatchSomePermissions">;
|
|
37
37
|
};
|
package/dist/declarations/src/components/restricted-by-permissions/restricted-by-permissions.d.ts
CHANGED
|
@@ -35,7 +35,7 @@ type Props = {
|
|
|
35
35
|
children?: TRenderProp | ReactNode;
|
|
36
36
|
};
|
|
37
37
|
declare const RestrictedByPermissions: {
|
|
38
|
-
(props: Props): import("@emotion/react/jsx-
|
|
38
|
+
(props: Props): import("@emotion/react/types/jsx-namespace").EmotionJSX.Element;
|
|
39
39
|
displayName: string;
|
|
40
40
|
};
|
|
41
41
|
export default RestrictedByPermissions;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@commercetools-frontend/permissions",
|
|
3
|
-
"version": "22.
|
|
3
|
+
"version": "22.3.0",
|
|
4
4
|
"description": "React components to declaratively handle MC permissions",
|
|
5
5
|
"bugs": "https://github.com/commercetools/merchant-center-application-kit/issues",
|
|
6
6
|
"repository": {
|
|
@@ -9,20 +9,30 @@
|
|
|
9
9
|
"directory": "packages/permissions"
|
|
10
10
|
},
|
|
11
11
|
"homepage": "https://docs.commercetools.com/custom-applications/api-reference/commercetools-frontend-permissions",
|
|
12
|
-
"keywords": [
|
|
12
|
+
"keywords": [
|
|
13
|
+
"javascript",
|
|
14
|
+
"frontend",
|
|
15
|
+
"react",
|
|
16
|
+
"toolkit"
|
|
17
|
+
],
|
|
13
18
|
"license": "MIT",
|
|
14
19
|
"publishConfig": {
|
|
15
20
|
"access": "public"
|
|
16
21
|
},
|
|
17
22
|
"main": "dist/commercetools-frontend-permissions.cjs.js",
|
|
18
23
|
"module": "dist/commercetools-frontend-permissions.esm.js",
|
|
19
|
-
"files": [
|
|
24
|
+
"files": [
|
|
25
|
+
"dist",
|
|
26
|
+
"package.json",
|
|
27
|
+
"LICENSE",
|
|
28
|
+
"README.md"
|
|
29
|
+
],
|
|
20
30
|
"dependencies": {
|
|
21
31
|
"@babel/runtime": "^7.20.13",
|
|
22
32
|
"@babel/runtime-corejs3": "^7.20.13",
|
|
23
|
-
"@commercetools-frontend/application-shell-connectors": "22.
|
|
24
|
-
"@commercetools-frontend/sentry": "22.
|
|
25
|
-
"@emotion/react": "11.
|
|
33
|
+
"@commercetools-frontend/application-shell-connectors": "22.3.0",
|
|
34
|
+
"@commercetools-frontend/sentry": "22.3.0",
|
|
35
|
+
"@emotion/react": "11.11.0",
|
|
26
36
|
"@types/lodash": "^4.14.191",
|
|
27
37
|
"@types/prop-types": "^15.7.5",
|
|
28
38
|
"@types/react": "^17.0.53",
|
|
@@ -32,9 +42,13 @@
|
|
|
32
42
|
"tiny-warning": "1.0.3"
|
|
33
43
|
},
|
|
34
44
|
"devDependencies": {
|
|
45
|
+
"@types/jest": "^29.5.1",
|
|
46
|
+
"@types/testing-library__jest-dom": "^5.14.5",
|
|
47
|
+
"jest": "29.5.0",
|
|
48
|
+
"jest-mock": "29.5.0",
|
|
35
49
|
"react": "17.0.2"
|
|
36
50
|
},
|
|
37
51
|
"peerDependencies": {
|
|
38
52
|
"react": "17.x"
|
|
39
53
|
}
|
|
40
|
-
}
|
|
54
|
+
}
|