@strapi/admin 4.4.0-beta.1 → 4.4.0-beta.3

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.
Files changed (97) hide show
  1. package/admin/src/StrapiApp.js +4 -12
  2. package/admin/src/components/Providers/index.js +14 -10
  3. package/admin/src/content-manager/components/FieldTypeIcon/index.js +31 -1
  4. package/admin/src/content-manager/components/Inputs/index.js +30 -10
  5. package/admin/src/content-manager/pages/EditSettingsView/components/FormModal.js +7 -2
  6. package/admin/src/content-manager/pages/EditSettingsView/index.js +2 -1
  7. package/admin/src/content-manager/pages/EditView/index.js +91 -84
  8. package/admin/src/core/apis/CustomFields.js +80 -0
  9. package/admin/src/core/apis/index.js +1 -0
  10. package/admin/src/hooks/index.js +0 -1
  11. package/admin/src/pages/AuthPage/utils/forms.js +2 -2
  12. package/admin/src/pages/SettingsPage/pages/ApiTokens/EditView/index.js +180 -452
  13. package/admin/src/pages/SettingsPage/pages/ApiTokens/EditView/utils/schema.js +1 -2
  14. package/admin/src/pages/SettingsPage/pages/ApiTokens/ListView/DynamicTable/DeleteButton/index.js +0 -1
  15. package/admin/src/pages/SettingsPage/pages/ApiTokens/ListView/DynamicTable/UpdateButton/index.js +36 -3
  16. package/admin/src/pages/SettingsPage/pages/ApiTokens/ListView/DynamicTable/index.js +11 -13
  17. package/admin/src/pages/SettingsPage/pages/ApiTokens/ListView/index.js +2 -3
  18. package/admin/src/pages/SettingsPage/pages/ApiTokens/ListView/utils/tableHeaders.js +8 -8
  19. package/admin/src/pages/SettingsPage/pages/ApiTokens/ProtectedEditView/index.js +1 -1
  20. package/admin/src/pages/SettingsPage/pages/Users/ListPage/ModalForm/utils/schema.js +1 -1
  21. package/admin/src/pages/SettingsPage/pages/Users/utils/validations/users/profile.js +2 -2
  22. package/admin/src/permissions/defaultPermissions.js +6 -2
  23. package/admin/src/translations/en.json +0 -17
  24. package/build/524.40377968.chunk.js +644 -0
  25. package/build/{Admin-authenticatedApp.3a31a087.chunk.js → Admin-authenticatedApp.50e41ff2.chunk.js} +1 -1
  26. package/build/{Admin_homePage.6d5e3236.chunk.js → Admin_homePage.118926e0.chunk.js} +1 -1
  27. package/build/{Admin_profilePage.83991a6c.chunk.js → Admin_profilePage.9d50ac44.chunk.js} +4 -4
  28. package/build/{Admin_settingsPage.fc9c607a.chunk.js → Admin_settingsPage.98a711e5.chunk.js} +16 -16
  29. package/build/admin-app.8bc3e80f.chunk.js +112 -0
  30. package/build/admin-edit-roles-page.554ba3fa.chunk.js +1 -0
  31. package/build/{admin-edit-users.5bebf473.chunk.js → admin-edit-users.c585212f.chunk.js} +2 -2
  32. package/build/{admin-users.dccd5f4c.chunk.js → admin-users.97a08630.chunk.js} +1 -1
  33. package/build/api-tokens-create-page.4c262d6e.chunk.js +1 -0
  34. package/build/api-tokens-edit-page.10a9d368.chunk.js +1 -0
  35. package/build/api-tokens-list-page.442c9f3c.chunk.js +15 -0
  36. package/build/content-manager.2a6f876d.chunk.js +1178 -0
  37. package/build/content-type-builder-list-view.5b3cd768.chunk.js +194 -0
  38. package/build/content-type-builder-translation-en-json.f985c9c4.chunk.js +1 -0
  39. package/build/content-type-builder.d4610e20.chunk.js +145 -0
  40. package/build/en-json.12bc5a14.chunk.js +1 -0
  41. package/build/index.html +1 -1
  42. package/build/{main.cdfda31e.js → main.fdc482f3.js} +1151 -1151
  43. package/build/{runtime~main.fa8f8898.js → runtime~main.29105d25.js} +2 -2
  44. package/build/sso-settings-page.445184e0.chunk.js +1 -0
  45. package/build/{webhook-edit-page.9e46fc3f.chunk.js → webhook-edit-page.d2ea3351.chunk.js} +1 -1
  46. package/package.json +7 -8
  47. package/server/bootstrap.js +1 -19
  48. package/server/config/admin-actions.js +0 -20
  49. package/server/content-types/api-token.js +1 -25
  50. package/server/content-types/index.js +0 -1
  51. package/server/controllers/api-token.js +1 -24
  52. package/server/controllers/index.js +0 -1
  53. package/server/routes/api-tokens.js +0 -11
  54. package/server/routes/index.js +0 -2
  55. package/server/services/api-token.js +29 -310
  56. package/server/services/constants.js +0 -10
  57. package/server/services/permission/engine-hooks.js +82 -0
  58. package/server/services/permission/engine.js +226 -36
  59. package/server/services/permission.js +1 -4
  60. package/server/strategies/admin.js +1 -7
  61. package/server/strategies/api-token.js +11 -71
  62. package/server/validation/api-tokens.js +2 -12
  63. package/server/validation/common-validators.js +1 -1
  64. package/admin/src/contexts/ApiTokenPermissions/index.js +0 -24
  65. package/admin/src/hooks/useRegenerate/index.js +0 -34
  66. package/admin/src/pages/SettingsPage/pages/ApiTokens/EditView/components/ActionBoundRoutes/index.js +0 -56
  67. package/admin/src/pages/SettingsPage/pages/ApiTokens/EditView/components/BoundRoute/getMethodColor.js +0 -41
  68. package/admin/src/pages/SettingsPage/pages/ApiTokens/EditView/components/BoundRoute/index.js +0 -72
  69. package/admin/src/pages/SettingsPage/pages/ApiTokens/EditView/components/CollapsableContentType/CheckBoxWrapper.js +0 -30
  70. package/admin/src/pages/SettingsPage/pages/ApiTokens/EditView/components/CollapsableContentType/index.js +0 -150
  71. package/admin/src/pages/SettingsPage/pages/ApiTokens/EditView/components/ContenTypesSection/index.js +0 -37
  72. package/admin/src/pages/SettingsPage/pages/ApiTokens/EditView/components/Permissions/index.js +0 -40
  73. package/admin/src/pages/SettingsPage/pages/ApiTokens/EditView/components/Regenerate/index.js +0 -68
  74. package/admin/src/pages/SettingsPage/pages/ApiTokens/EditView/init.js +0 -13
  75. package/admin/src/pages/SettingsPage/pages/ApiTokens/EditView/reducer.js +0 -55
  76. package/admin/src/pages/SettingsPage/pages/ApiTokens/EditView/utils/getDateOfExpiration.js +0 -16
  77. package/admin/src/pages/SettingsPage/pages/ApiTokens/EditView/utils/index.js +0 -5
  78. package/admin/src/pages/SettingsPage/pages/ApiTokens/EditView/utils/transformPermissionsData.js +0 -36
  79. package/admin/src/pages/SettingsPage/pages/ApiTokens/ListView/DynamicTable/DefaultButton/index.js +0 -63
  80. package/admin/src/pages/SettingsPage/pages/ApiTokens/ListView/DynamicTable/ReadButton/index.js +0 -19
  81. package/build/4235.982b5799.chunk.js +0 -30
  82. package/build/611.a91aff91.chunk.js +0 -158
  83. package/build/7379.d246dd38.chunk.js +0 -1
  84. package/build/admin-app.41b6472c.chunk.js +0 -112
  85. package/build/admin-edit-roles-page.4dd6bcb9.chunk.js +0 -1
  86. package/build/api-tokens-create-page.29cc87b6.chunk.js +0 -1
  87. package/build/api-tokens-edit-page.c294a88f.chunk.js +0 -1
  88. package/build/api-tokens-list-page.bb36535f.chunk.js +0 -16
  89. package/build/content-manager.fb5ee865.chunk.js +0 -1178
  90. package/build/content-type-builder-list-view.8cc534e0.chunk.js +0 -194
  91. package/build/content-type-builder-translation-en-json.201bfb78.chunk.js +0 -1
  92. package/build/content-type-builder.42cecba9.chunk.js +0 -142
  93. package/build/en-json.a9918c93.chunk.js +0 -1
  94. package/build/sso-settings-page.9ceb0140.chunk.js +0 -1
  95. package/server/content-types/api-token-permission.js +0 -36
  96. package/server/controllers/content-api.js +0 -15
  97. package/server/routes/content-api.js +0 -20
@@ -1,36 +1,107 @@
1
1
  'use strict';
2
2
 
3
- const { curry, isArray, isEmpty, difference } = require('lodash/fp');
4
- const permissions = require('@strapi/permissions');
5
-
3
+ const {
4
+ curry,
5
+ map,
6
+ filter,
7
+ propEq,
8
+ isFunction,
9
+ isBoolean,
10
+ isArray,
11
+ isNil,
12
+ isEmpty,
13
+ isObject,
14
+ prop,
15
+ merge,
16
+ pick,
17
+ difference,
18
+ cloneDeep,
19
+ } = require('lodash/fp');
20
+ const { AbilityBuilder, Ability } = require('@casl/ability');
21
+ const sift = require('sift');
6
22
  const permissionDomain = require('../../domain/permission/index');
7
23
  const { getService } = require('../../utils');
24
+ const {
25
+ createEngineHooks,
26
+ createWillEvaluateContext,
27
+ createWillRegisterContext,
28
+ } = require('./engine-hooks');
29
+
30
+ const allowedOperations = [
31
+ '$or',
32
+ '$and',
33
+ '$eq',
34
+ '$ne',
35
+ '$in',
36
+ '$nin',
37
+ '$lt',
38
+ '$lte',
39
+ '$gt',
40
+ '$gte',
41
+ '$exists',
42
+ '$elemMatch',
43
+ ];
44
+ const operations = pick(allowedOperations, sift);
45
+
46
+ const conditionsMatcher = (conditions) => {
47
+ return sift.createQueryTester(conditions, { operations });
48
+ };
49
+
50
+ module.exports = (conditionProvider) => {
51
+ const state = {
52
+ hooks: createEngineHooks(),
53
+ };
54
+
55
+ return {
56
+ hooks: state.hooks,
57
+
58
+ /**
59
+ * Generate an ability based on the given user (using associated roles & permissions)
60
+ * @param user
61
+ * @param options
62
+ * @returns {Promise<Ability>}
63
+ */
64
+ async generateUserAbility(user, options) {
65
+ const permissions = await getService('permission').findUserPermissions(user);
66
+ const abilityCreator = this.generateAbilityCreatorFor(user);
8
67
 
9
- module.exports = (params) => {
10
- const { providers } = params;
68
+ return abilityCreator(permissions, options);
69
+ },
11
70
 
12
- const engine = permissions.engine
13
- .new({ providers })
14
71
  /**
15
- * Validate the permission's action exists in the action registry
72
+ * Create an ability factory for a specific user
73
+ * @param user
74
+ * @returns {function(*, *): Promise<Ability>}
16
75
  */
17
- .on('before-format::validate.permission', ({ permission }) => {
18
- const action = providers.action.get(permission.action);
76
+ generateAbilityCreatorFor(user) {
77
+ return async (permissions, options) => {
78
+ const { can, build } = new AbilityBuilder(Ability);
79
+
80
+ for (const permission of permissions) {
81
+ const registerFn = this.createRegisterFunction(can, permission, user);
82
+
83
+ await this.evaluate({ permission, user, options, registerFn });
84
+ }
85
+
86
+ return build({ conditionsMatcher });
87
+ };
88
+ },
89
+
90
+ /**
91
+ * Validate, invalidate and transform the permission attributes
92
+ * @param {Permission} permission
93
+ * @returns {null|Permission}
94
+ */
95
+ formatPermission(permission) {
96
+ const { actionProvider } = getService('permission');
97
+
98
+ const action = actionProvider.get(permission.action);
19
99
 
20
100
  // If the action isn't registered into the action provider, then ignore the permission
21
101
  if (!action) {
22
- strapi.log.debug(
23
- `Unknown action "${permission.action}" supplied when registering a new permission in engine`
24
- );
25
- return false;
102
+ return null;
26
103
  }
27
- })
28
104
 
29
- /**
30
- * Remove invalid properties from the permission based on the action (applyToProperties)
31
- */
32
- .on('format.permission', (permission) => {
33
- const action = providers.action.get(permission.action);
34
105
  const properties = permission.properties || {};
35
106
 
36
107
  // Only keep the properties allowed by the action (action.applyToProperties)
@@ -45,34 +116,153 @@ module.exports = (params) => {
45
116
  permission
46
117
  );
47
118
 
119
+ // If the `fields` property is an empty array, then ignore the permission
120
+ const { fields } = properties;
121
+
122
+ if (isArray(fields) && isEmpty(fields)) {
123
+ return null;
124
+ }
125
+
48
126
  return permissionWithSanitizedProperties;
49
- })
127
+ },
50
128
 
51
129
  /**
52
- * Ignore the permission if the fields property is an empty array (access to no field)
130
+ * Update the permission components through various processing
131
+ * @param {Permission} permission
132
+ * @returns {Promise<void>}
53
133
  */
54
- .on('after-format::validate.permission', ({ permission }) => {
55
- const { fields } = permission.properties;
134
+ async applyPermissionProcessors(permission) {
135
+ const context = createWillEvaluateContext(permission);
56
136
 
57
- if (isArray(fields) && isEmpty(fields)) {
58
- return false;
137
+ // 1. Trigger willEvaluatePermission hook and await transformation operated on the permission
138
+ await state.hooks.willEvaluatePermission.call(context);
139
+ },
140
+
141
+ /**
142
+ * Register new rules using `registerFn` based on valid permission's conditions
143
+ * @param options {object}
144
+ * @param options.permission {object}
145
+ * @param options.user {object}
146
+ * @param options.options {object | undefined}
147
+ * @param options.registerFn {Function}
148
+ * @returns {Promise<void>}
149
+ */
150
+ async evaluate(options) {
151
+ const { user, registerFn, options: conditionOptions } = options;
152
+
153
+ // Assert options.permission validity and format it
154
+ const permission = this.formatPermission(options.permission);
155
+
156
+ // If options.permission is invalid, then ignore the permission
157
+ if (permission === null) {
158
+ return;
59
159
  }
60
- });
61
160
 
62
- return {
63
- get hooks() {
64
- return engine.hooks;
161
+ await this.applyPermissionProcessors(permission);
162
+
163
+ // Extract the up-to-date components from the permission
164
+ const { action, subject, properties = {}, conditions } = permission;
165
+
166
+ // Register the permission if there is no condition
167
+ if (isEmpty(conditions)) {
168
+ return registerFn({ action, subject, fields: properties.fields });
169
+ }
170
+
171
+ /** Set of functions used to resolve + evaluate conditions & register the permission if allowed */
172
+
173
+ // 1. Replace each condition name by its associated value
174
+ const resolveConditions = map(conditionProvider.get);
175
+
176
+ // 2. Filter conditions, only keep those whose handler is a function
177
+ const filterValidConditions = filter((condition) => isFunction(condition.handler));
178
+
179
+ // 3. Evaluate the conditions handler and returns an object
180
+ // containing both the original condition and its result
181
+ const evaluateConditions = (conditions) => {
182
+ return Promise.all(
183
+ conditions.map(async (condition) => ({
184
+ condition,
185
+ result: await condition.handler(
186
+ user,
187
+ merge(conditionOptions, { permission: cloneDeep(permission) })
188
+ ),
189
+ }))
190
+ );
191
+ };
192
+
193
+ // 4. Only keeps booleans or objects as condition's result
194
+ const filterValidResults = filter(({ result }) => isBoolean(result) || isObject(result));
195
+
196
+ /**/
197
+
198
+ const evaluatedConditions = await Promise.resolve(conditions)
199
+ .then(resolveConditions)
200
+ .then(filterValidConditions)
201
+ .then(evaluateConditions)
202
+ .then(filterValidResults);
203
+
204
+ // Utils
205
+ const resultPropEq = propEq('result');
206
+ const pickResults = map(prop('result'));
207
+
208
+ if (evaluatedConditions.every(resultPropEq(false))) {
209
+ return;
210
+ }
211
+
212
+ // If there is no condition or if one of them return true, register the permission as is
213
+ if (isEmpty(evaluatedConditions) || evaluatedConditions.some(resultPropEq(true))) {
214
+ return registerFn({ action, subject, fields: properties.fields });
215
+ }
216
+
217
+ const results = pickResults(evaluatedConditions).filter(isObject);
218
+
219
+ if (isEmpty(results)) {
220
+ return registerFn({ action, subject, fields: properties.fields });
221
+ }
222
+
223
+ // Register the permission
224
+ return registerFn({
225
+ action,
226
+ subject,
227
+ fields: properties.fields,
228
+ condition: { $and: [{ $or: results }] },
229
+ });
65
230
  },
66
231
 
67
232
  /**
68
- * Generate an ability based on the given user (using associated roles & permissions)
69
- * @param user
70
- * @returns {Promise<Ability>}
233
+ * Encapsulate a register function with custom params to fit `evaluatePermission`'s syntax
234
+ * @param can
235
+ * @param {Permission} permission
236
+ * @param {object} user
237
+ * @returns {function}
71
238
  */
72
- async generateUserAbility(user) {
73
- const permissions = await getService('permission').findUserPermissions(user);
239
+ createRegisterFunction(can, permission, user) {
240
+ const registerToCasl = (caslPermission) => {
241
+ const { action, subject, fields, condition } = caslPermission;
242
+
243
+ can(
244
+ action,
245
+ isNil(subject) ? 'all' : subject,
246
+ fields,
247
+ isObject(condition) ? condition : undefined
248
+ );
249
+ };
250
+
251
+ const runWillRegisterHook = async (caslPermission) => {
252
+ const hookContext = createWillRegisterContext(caslPermission, {
253
+ permission,
254
+ user,
255
+ });
256
+
257
+ await state.hooks.willRegisterPermission.call(hookContext);
258
+
259
+ return caslPermission;
260
+ };
74
261
 
75
- return engine.generateAbility(permissions, user);
262
+ return async (caslPermission) => {
263
+ await runWillRegisterHook(caslPermission);
264
+ registerToCasl(caslPermission);
265
+ };
76
266
  },
77
267
 
78
268
  /**
@@ -10,14 +10,11 @@ const permissionQueries = require('./permission/queries');
10
10
 
11
11
  const actionProvider = createActionProvider();
12
12
  const conditionProvider = createConditionProvider();
13
+ const engine = createPermissionEngine(conditionProvider);
13
14
  const sectionsBuilder = createSectionsBuilder();
14
15
 
15
16
  const sanitizePermission = domain.sanitizePermissionFields;
16
17
 
17
- const engine = createPermissionEngine({
18
- providers: { action: actionProvider, condition: conditionProvider },
19
- });
20
-
21
18
  module.exports = {
22
19
  // Queries / Actions
23
20
  ...permissionQueries,
@@ -33,16 +33,10 @@ const authenticate = async (ctx) => {
33
33
 
34
34
  const userAbility = await getService('permission').engine.generateUserAbility(user);
35
35
 
36
- // TODO: use the ability from ctx.state.auth instead of
37
- // ctx.state.userAbility, and remove the assign below
38
36
  ctx.state.userAbility = userAbility;
39
37
  ctx.state.user = user;
40
38
 
41
- return {
42
- authenticated: true,
43
- credentials: user,
44
- ability: userAbility,
45
- };
39
+ return { authenticated: true, credentials: user };
46
40
  };
47
41
 
48
42
  /** @type {import('.').AuthStrategy} */
@@ -1,6 +1,5 @@
1
1
  'use strict';
2
2
 
3
- const { castArray, isNil } = require('lodash/fp');
4
3
  const { UnauthorizedError, ForbiddenError } = require('@strapi/utils').errors;
5
4
  const constants = require('../services/constants');
6
5
  const { getService } = require('../utils');
@@ -21,10 +20,7 @@ const extractToken = (ctx) => {
21
20
  return null;
22
21
  };
23
22
 
24
- /**
25
- * Authenticate the validity of the token
26
- *
27
- * @type {import('.').AuthenticateFunction} */
23
+ /** @type {import('.').AuthenticateFunction} */
28
24
  const authenticate = async (ctx) => {
29
25
  const apiTokenService = getService('api-token');
30
26
  const token = extractToken(ctx);
@@ -37,89 +33,33 @@ const authenticate = async (ctx) => {
37
33
  accessKey: apiTokenService.hash(token),
38
34
  });
39
35
 
40
- // token not found
41
36
  if (!apiToken) {
42
37
  return { authenticated: false };
43
38
  }
44
39
 
45
- const currentDate = new Date();
46
-
47
- if (!isNil(apiToken.expiresAt)) {
48
- const expirationDate = new Date(apiToken.expiresAt);
49
- // token has expired
50
- if (expirationDate < currentDate) {
51
- return { authenticated: false, error: new UnauthorizedError('Token expired') };
52
- }
53
- }
54
-
55
- // update lastUsedAt
56
- await apiTokenService.update(apiToken.id, {
57
- lastUsedAt: currentDate,
58
- });
59
-
60
- if (apiToken.type === constants.API_TOKEN_TYPE.CUSTOM) {
61
- const ability = await strapi.contentAPI.permissions.engine.generateAbility(
62
- apiToken.permissions.map((action) => ({ action }))
63
- );
64
-
65
- return { authenticated: true, ability, credentials: apiToken };
66
- }
67
-
68
40
  return { authenticated: true, credentials: apiToken };
69
41
  };
70
42
 
71
- /**
72
- * Verify the token has the required abilities for the requested scope
73
- *
74
- * @type {import('.').VerifyFunction} */
43
+ /** @type {import('.').VerifyFunction} */
75
44
  const verify = (auth, config) => {
76
- const { credentials: apiToken, ability } = auth;
45
+ const { credentials: apiToken } = auth;
77
46
 
78
47
  if (!apiToken) {
79
- throw new UnauthorizedError('Token not found');
80
- }
81
-
82
- const currentDate = new Date();
83
-
84
- if (!isNil(apiToken.expiresAt)) {
85
- const expirationDate = new Date(apiToken.expiresAt);
86
- // token has expired
87
- if (expirationDate < currentDate) {
88
- throw new UnauthorizedError('Token expired');
89
- }
48
+ throw new UnauthorizedError();
90
49
  }
91
50
 
92
- // Full access
93
51
  if (apiToken.type === constants.API_TOKEN_TYPE.FULL_ACCESS) {
94
52
  return;
95
53
  }
96
54
 
97
- // Read only
98
- if (apiToken.type === constants.API_TOKEN_TYPE.READ_ONLY) {
99
- /**
100
- * If you don't have `full-access` you can only access `find` and `findOne`
101
- * scopes. If the route has no scope, then you can't get access to it.
102
- */
103
- const scopes = castArray(config.scope);
104
-
105
- if (config.scope && scopes.every(isReadScope)) {
106
- return;
107
- }
108
- }
55
+ /**
56
+ * If you don't have `full-access` you can only access `find` and `findOne`
57
+ * scopes. If the route has no scope, then you can't get access to it.
58
+ */
109
59
 
110
- // Custom
111
- else if (apiToken.type === constants.API_TOKEN_TYPE.CUSTOM) {
112
- if (!ability) {
113
- throw new ForbiddenError();
114
- }
115
-
116
- const scopes = castArray(config.scope);
117
-
118
- const isAllowed = scopes.every((scope) => ability.can(scope));
119
-
120
- if (isAllowed) {
121
- return;
122
- }
60
+ const scopes = Array.isArray(config.scope) ? config.scope : [config.scope];
61
+ if (config.scope && scopes.every(isReadScope)) {
62
+ return;
123
63
  }
124
64
 
125
65
  throw new ForbiddenError();
@@ -9,16 +9,8 @@ const apiTokenCreationSchema = yup
9
9
  name: yup.string().min(1).required(),
10
10
  description: yup.string().optional(),
11
11
  type: yup.string().oneOf(Object.values(constants.API_TOKEN_TYPE)).required(),
12
- permissions: yup.array().of(yup.string()).nullable(),
13
- lifespan: yup
14
- .number()
15
- .integer()
16
- .min(1)
17
- .oneOf(Object.values(constants.API_TOKEN_LIFESPANS))
18
- .nullable(),
19
12
  })
20
- .noUnknown()
21
- .strict();
13
+ .noUnknown();
22
14
 
23
15
  const apiTokenUpdateSchema = yup
24
16
  .object()
@@ -26,10 +18,8 @@ const apiTokenUpdateSchema = yup
26
18
  name: yup.string().min(1).notNull(),
27
19
  description: yup.string().nullable(),
28
20
  type: yup.string().oneOf(Object.values(constants.API_TOKEN_TYPE)).notNull(),
29
- permissions: yup.array().of(yup.string()).nullable(),
30
21
  })
31
- .noUnknown()
32
- .strict();
22
+ .noUnknown();
33
23
 
34
24
  module.exports = {
35
25
  validateApiTokenCreationInput: validateYupSchema(apiTokenCreationSchema),
@@ -16,7 +16,7 @@ const getActionFromProvider = (actionId) => {
16
16
 
17
17
  const email = yup.string().email().lowercase();
18
18
 
19
- const firstname = yup.string().min(1);
19
+ const firstname = yup.string().trim().min(1);
20
20
 
21
21
  const lastname = yup.string();
22
22
 
@@ -1,24 +0,0 @@
1
- import React, { createContext, useContext } from 'react';
2
- import PropTypes from 'prop-types';
3
-
4
- const ApiTokenPermissionsContext = createContext({});
5
-
6
- const ApiTokenPermissionsContextProvider = ({ children, ...rest }) => {
7
- return (
8
- <ApiTokenPermissionsContext.Provider value={rest}>
9
- {children}
10
- </ApiTokenPermissionsContext.Provider>
11
- );
12
- };
13
-
14
- const useApiTokenPermissionsContext = () => useContext(ApiTokenPermissionsContext);
15
-
16
- ApiTokenPermissionsContextProvider.propTypes = {
17
- children: PropTypes.node.isRequired,
18
- };
19
-
20
- export {
21
- ApiTokenPermissionsContext,
22
- ApiTokenPermissionsContextProvider,
23
- useApiTokenPermissionsContext,
24
- };
@@ -1,34 +0,0 @@
1
- import { useState } from 'react';
2
- import { get } from 'lodash';
3
- import { useNotification } from '@strapi/helper-plugin';
4
- import { axiosInstance } from '../../core/utils';
5
-
6
- const useRegenerate = (id, onRegenerate) => {
7
- const [isLoadingConfirmation, setIsLoadingConfirmation] = useState(false);
8
- const toggleNotification = useNotification();
9
-
10
- const regenerateData = async () => {
11
- try {
12
- const {
13
- data: {
14
- data: { accessKey },
15
- },
16
- } = await axiosInstance.post(`/admin/api-tokens/${id}/regenerate`);
17
- setIsLoadingConfirmation(false);
18
- onRegenerate(accessKey);
19
- } catch (error) {
20
- setIsLoadingConfirmation(false);
21
- toggleNotification({
22
- type: 'warning',
23
- message: get(error, 'response.data.message', 'notification.error'),
24
- });
25
- }
26
- };
27
-
28
- return {
29
- regenerateData,
30
- isLoadingConfirmation,
31
- };
32
- };
33
-
34
- export default useRegenerate;
@@ -1,56 +0,0 @@
1
- import React from 'react';
2
- import { useIntl } from 'react-intl';
3
- import { Typography } from '@strapi/design-system/Typography';
4
- import { Stack } from '@strapi/design-system/Stack';
5
- import { GridItem } from '@strapi/design-system/Grid';
6
- import BoundRoute from '../BoundRoute';
7
- import { useApiTokenPermissionsContext } from '../../../../../../../contexts/ApiTokenPermissions';
8
-
9
- const ActionBoundRoutes = () => {
10
- const {
11
- value: { selectedAction, routes },
12
- } = useApiTokenPermissionsContext();
13
- const { formatMessage } = useIntl();
14
- const actionSection = selectedAction?.split('.')[0];
15
-
16
- return (
17
- <GridItem
18
- col={5}
19
- background="neutral150"
20
- paddingTop={6}
21
- paddingBottom={6}
22
- paddingLeft={7}
23
- paddingRight={7}
24
- style={{ minHeight: '100%' }}
25
- >
26
- {selectedAction ? (
27
- <Stack spacing={2}>
28
- {routes[actionSection]?.map((route) => {
29
- return route.config.auth?.scope?.includes(selectedAction) ||
30
- route.handler === selectedAction ? (
31
- <BoundRoute key={route.handler} route={route} />
32
- ) : null;
33
- })}
34
- </Stack>
35
- ) : (
36
- <Stack spacing={2}>
37
- <Typography variant="delta" as="h3">
38
- {formatMessage({
39
- id: 'Settings.apiTokens.createPage.permissions.header.title',
40
- defaultMessage: 'Advanced settings',
41
- })}
42
- </Typography>
43
- <Typography as="p" textColor="neutral600">
44
- {formatMessage({
45
- id: 'Settings.apiTokens.createPage.permissions.header.hint',
46
- defaultMessage:
47
- "Select the application's actions or the plugin's actions and click on the cog icon to display the bound route",
48
- })}
49
- </Typography>
50
- </Stack>
51
- )}
52
- </GridItem>
53
- );
54
- };
55
-
56
- export default ActionBoundRoutes;
@@ -1,41 +0,0 @@
1
- const getMethodColor = (verb) => {
2
- switch (verb) {
3
- case 'POST': {
4
- return {
5
- text: 'success600',
6
- border: 'success200',
7
- background: 'success100',
8
- };
9
- }
10
- case 'GET': {
11
- return {
12
- text: 'secondary600',
13
- border: 'secondary200',
14
- background: 'secondary100',
15
- };
16
- }
17
- case 'PUT': {
18
- return {
19
- text: 'warning600',
20
- border: 'warning200',
21
- background: 'warning100',
22
- };
23
- }
24
- case 'DELETE': {
25
- return {
26
- text: 'danger600',
27
- border: 'danger200',
28
- background: 'danger100',
29
- };
30
- }
31
- default: {
32
- return {
33
- text: 'neutral600',
34
- border: 'neutral200',
35
- background: 'neutral100',
36
- };
37
- }
38
- }
39
- };
40
-
41
- export default getMethodColor;