@strapi/admin 4.6.2 → 4.7.0-exp.3d6a31eb083e9d44afcf98f68c107fb7567e5720

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/content-manager/components/CollectionTypeFormWrapper/index.js +0 -2
  2. package/admin/src/hooks/useRegenerate/index.js +2 -2
  3. package/admin/src/hooks/useSettingsMenu/utils/defaultGlobalLinks.js +7 -0
  4. package/admin/src/pages/HomePage/CloudBox.js +83 -0
  5. package/admin/src/pages/HomePage/ContentBlocks.js +2 -0
  6. package/admin/src/pages/HomePage/assets/strapi-cloud-background.png +0 -0
  7. package/admin/src/pages/HomePage/assets/strapi-cloud-flags.svg +1 -0
  8. package/admin/src/pages/HomePage/assets/strapi-cloud-icon.svg +1 -0
  9. package/admin/src/pages/SettingsPage/{pages/ApiTokens/EditView/components → components/Tokens}/FormHead/index.js +36 -19
  10. package/admin/src/pages/SettingsPage/components/Tokens/FormiTokenContainer/LifeSpanInput.js +95 -0
  11. package/admin/src/pages/SettingsPage/components/Tokens/LifeSpanInput/index.js +97 -0
  12. package/admin/src/pages/SettingsPage/components/Tokens/Regenerate/index.js +73 -0
  13. package/admin/src/pages/SettingsPage/{pages/ApiTokens/ListView/DynamicTable → components/Tokens/Table}/DeleteButton/index.js +19 -6
  14. package/admin/src/pages/SettingsPage/components/Tokens/Table/index.js +145 -0
  15. package/admin/src/pages/SettingsPage/{pages/ApiTokens/EditView/components/ContentBox → components/Tokens/TokenBox}/index.js +19 -16
  16. package/admin/src/pages/SettingsPage/components/Tokens/TokenDescription/index.js +51 -0
  17. package/admin/src/pages/SettingsPage/components/Tokens/TokenName/index.js +46 -0
  18. package/admin/src/pages/SettingsPage/components/Tokens/TokenTypeSelect/index.js +69 -0
  19. package/admin/src/pages/SettingsPage/components/Tokens/constants.js +2 -0
  20. package/admin/src/pages/SettingsPage/pages/ApiTokens/EditView/components/CollapsableContentType/index.js +3 -1
  21. package/admin/src/pages/SettingsPage/pages/ApiTokens/EditView/components/FormApiTokenContainer/index.js +53 -150
  22. package/admin/src/pages/SettingsPage/pages/ApiTokens/EditView/components/Regenerate/index.js +5 -1
  23. package/admin/src/pages/SettingsPage/pages/ApiTokens/EditView/index.js +46 -17
  24. package/admin/src/pages/SettingsPage/pages/ApiTokens/ListView/index.js +16 -16
  25. package/admin/src/pages/SettingsPage/pages/TransferTokens/EditView/components/FormTransferTokenContainer/index.js +101 -0
  26. package/admin/src/pages/SettingsPage/pages/TransferTokens/EditView/components/LoadingView/index.js +48 -0
  27. package/admin/src/pages/SettingsPage/pages/TransferTokens/EditView/index.js +219 -0
  28. package/admin/src/pages/SettingsPage/pages/TransferTokens/EditView/utils/getDateOfExpiration.js +16 -0
  29. package/admin/src/pages/SettingsPage/pages/TransferTokens/EditView/utils/index.js +4 -0
  30. package/admin/src/pages/SettingsPage/pages/TransferTokens/EditView/utils/schema.js +10 -0
  31. package/admin/src/pages/SettingsPage/pages/TransferTokens/ListView/index.js +194 -0
  32. package/admin/src/pages/SettingsPage/pages/TransferTokens/ListView/utils/tableHeaders.js +48 -0
  33. package/admin/src/pages/SettingsPage/pages/TransferTokens/ProtectedCreateView/index.js +14 -0
  34. package/admin/src/pages/SettingsPage/pages/TransferTokens/ProtectedEditView/index.js +14 -0
  35. package/admin/src/pages/SettingsPage/pages/TransferTokens/ProtectedListView/index.js +12 -0
  36. package/admin/src/pages/SettingsPage/utils/defaultRoutes.js +33 -0
  37. package/admin/src/permissions/defaultPermissions.js +8 -0
  38. package/admin/src/translations/en.json +15 -0
  39. package/build/27d16aefee06412db90a.png +0 -0
  40. package/build/4049.16583eee.chunk.js +1 -0
  41. package/build/4649.b7e84a29.chunk.js +30 -0
  42. package/build/7259.3f04094f.chunk.js +1 -0
  43. package/build/{Admin-authenticatedApp.dd16edad.chunk.js → Admin-authenticatedApp.368164a1.chunk.js} +6 -6
  44. package/build/Admin_homePage.1f10437f.chunk.js +78 -0
  45. package/build/{Admin_settingsPage.3cd54156.chunk.js → Admin_settingsPage.5a329b58.chunk.js} +25 -25
  46. package/build/{admin-app.3a084127.chunk.js → admin-app.df9adf93.chunk.js} +26 -26
  47. package/build/{api-tokens-create-page.a31c7fba.chunk.js → api-tokens-create-page.4328b852.chunk.js} +1 -1
  48. package/build/{api-tokens-edit-page.64fef287.chunk.js → api-tokens-edit-page.bce5050f.chunk.js} +1 -1
  49. package/build/api-tokens-list-page.149903c8.chunk.js +16 -0
  50. package/build/bb3108f7fd1e6179bde1.svg +1 -0
  51. package/build/bb4d0d527bdfb161bc5a.svg +1 -0
  52. package/build/{content-manager.d04b738f.chunk.js → content-manager.6ed87531.chunk.js} +1 -1
  53. package/build/en-json.8e5451b1.chunk.js +1 -0
  54. package/build/index.html +1 -1
  55. package/build/{main.9c01de7f.js → main.8009bfe8.js} +1 -0
  56. package/build/runtime~main.725b20df.js +2 -0
  57. package/build/transfer-tokens-create-page.a1f14bb1.chunk.js +1 -0
  58. package/build/transfer-tokens-edit-page.00ee1c74.chunk.js +1 -0
  59. package/build/transfer-tokens-list-page.1e15926d.chunk.js +16 -0
  60. package/package.json +9 -9
  61. package/server/bootstrap.js +2 -0
  62. package/server/config/admin-actions.js +48 -0
  63. package/server/content-types/index.js +2 -0
  64. package/server/content-types/transfer-token-permission.js +36 -0
  65. package/server/content-types/transfer-token.js +66 -0
  66. package/server/controllers/api-token.js +4 -5
  67. package/server/controllers/index.js +1 -0
  68. package/server/controllers/transfer/index.js +13 -0
  69. package/server/controllers/transfer/runner.js +24 -0
  70. package/server/controllers/transfer/token.js +131 -0
  71. package/server/register.js +2 -9
  72. package/server/routes/index.js +2 -0
  73. package/server/routes/transfer.js +95 -0
  74. package/server/services/api-token.js +2 -3
  75. package/server/services/constants.js +6 -0
  76. package/server/services/index.js +1 -0
  77. package/server/services/transfer/index.js +6 -0
  78. package/server/services/transfer/permission.js +22 -0
  79. package/server/services/transfer/token.js +409 -0
  80. package/server/strategies/api-token.js +4 -2
  81. package/server/strategies/data-transfer.js +107 -0
  82. package/server/strategies/index.js +1 -0
  83. package/server/utils/index.d.ts +2 -0
  84. package/server/validation/api-tokens.js +1 -6
  85. package/server/validation/transfer/index.js +5 -0
  86. package/server/validation/transfer/token.js +34 -0
  87. package/admin/src/pages/SettingsPage/pages/ApiTokens/EditView/components/FormBody/index.js +0 -77
  88. package/admin/src/pages/SettingsPage/pages/ApiTokens/ListView/DynamicTable/index.js +0 -110
  89. package/build/1341.5d48c79b.chunk.js +0 -1
  90. package/build/4318.9b1ac9bc.chunk.js +0 -30
  91. package/build/Admin_homePage.4b878f04.chunk.js +0 -72
  92. package/build/api-tokens-list-page.370459ba.chunk.js +0 -16
  93. package/build/en-json.9cada7f3.chunk.js +0 -1
  94. package/build/runtime~main.bb1389c9.js +0 -2
  95. package/admin/src/pages/SettingsPage/{pages/ApiTokens/ListView/DynamicTable → components/Tokens/Table}/DefaultButton/index.js +1 -1
  96. /package/admin/src/pages/SettingsPage/{pages/ApiTokens/ListView/DynamicTable → components/Tokens/Table}/ReadButton/index.js +0 -0
  97. /package/admin/src/pages/SettingsPage/{pages/ApiTokens/ListView/DynamicTable → components/Tokens/Table}/UpdateButton/index.js +0 -0
@@ -78,6 +78,7 @@ module.exports = async () => {
78
78
  const userService = getService('user');
79
79
  const roleService = getService('role');
80
80
  const apiTokenService = getService('api-token');
81
+ const transferService = getService('transfer');
81
82
  const tokenService = getService('token');
82
83
 
83
84
  await roleService.createRolesIfNoneExist();
@@ -93,5 +94,6 @@ module.exports = async () => {
93
94
  await syncAPITokensPermissions();
94
95
 
95
96
  apiTokenService.checkSaltIsDefined();
97
+ transferService.token.checkSaltIsDefined();
96
98
  tokenService.checkSecretIsDefined();
97
99
  };
@@ -164,5 +164,53 @@ module.exports = {
164
164
  section: 'settings',
165
165
  category: 'project',
166
166
  },
167
+ {
168
+ uid: 'transfer.tokens.access',
169
+ displayName: 'Access the transfer tokens settings page',
170
+ pluginName: 'admin',
171
+ section: 'settings',
172
+ category: 'transfer tokens',
173
+ subCategory: 'transfer tokens',
174
+ },
175
+ {
176
+ uid: 'transfer.tokens.create',
177
+ displayName: 'Create (generate)',
178
+ pluginName: 'admin',
179
+ section: 'settings',
180
+ category: 'transfer tokens',
181
+ subCategory: 'general',
182
+ },
183
+ {
184
+ uid: 'transfer.tokens.read',
185
+ displayName: 'Read',
186
+ pluginName: 'admin',
187
+ section: 'settings',
188
+ category: 'transfer tokens',
189
+ subCategory: 'general',
190
+ },
191
+ {
192
+ uid: 'transfer.tokens.update',
193
+ displayName: 'Update',
194
+ pluginName: 'admin',
195
+ section: 'settings',
196
+ category: 'transfer tokens',
197
+ subCategory: 'general',
198
+ },
199
+ {
200
+ uid: 'transfer.tokens.regenerate',
201
+ displayName: 'Regenerate',
202
+ pluginName: 'admin',
203
+ section: 'settings',
204
+ category: 'transfer tokens',
205
+ subCategory: 'general',
206
+ },
207
+ {
208
+ uid: 'transfer.tokens.delete',
209
+ displayName: 'Delete (revoke)',
210
+ pluginName: 'admin',
211
+ section: 'settings',
212
+ category: 'transfer tokens',
213
+ subCategory: 'general',
214
+ },
167
215
  ],
168
216
  };
@@ -6,4 +6,6 @@ module.exports = {
6
6
  role: { schema: require('./Role') },
7
7
  'api-token': { schema: require('./api-token') },
8
8
  'api-token-permission': { schema: require('./api-token-permission') },
9
+ 'transfer-token': { schema: require('./transfer-token') },
10
+ 'transfer-token-permission': { schema: require('./transfer-token-permission') },
9
11
  };
@@ -0,0 +1,36 @@
1
+ 'use strict';
2
+
3
+ module.exports = {
4
+ collectionName: 'strapi_transfer_token_permissions',
5
+ info: {
6
+ name: 'Transfer Token Permission',
7
+ description: '',
8
+ singularName: 'transfer-token-permission',
9
+ pluralName: 'transfer-token-permissions',
10
+ displayName: 'Transfer Token Permission',
11
+ },
12
+ options: {},
13
+ pluginOptions: {
14
+ 'content-manager': {
15
+ visible: false,
16
+ },
17
+ 'content-type-builder': {
18
+ visible: false,
19
+ },
20
+ },
21
+ attributes: {
22
+ action: {
23
+ type: 'string',
24
+ minLength: 1,
25
+ configurable: false,
26
+ required: true,
27
+ },
28
+ token: {
29
+ configurable: false,
30
+ type: 'relation',
31
+ relation: 'manyToOne',
32
+ inversedBy: 'permissions',
33
+ target: 'admin::transfer-token',
34
+ },
35
+ },
36
+ };
@@ -0,0 +1,66 @@
1
+ 'use strict';
2
+
3
+ module.exports = {
4
+ collectionName: 'strapi_transfer_tokens',
5
+ info: {
6
+ name: 'Transfer Token',
7
+ singularName: 'transfer-token',
8
+ pluralName: 'transfer-tokens',
9
+ displayName: 'Transfer Token',
10
+ description: '',
11
+ },
12
+ options: {},
13
+ pluginOptions: {
14
+ 'content-manager': {
15
+ visible: false,
16
+ },
17
+ 'content-type-builder': {
18
+ visible: false,
19
+ },
20
+ },
21
+ attributes: {
22
+ name: {
23
+ type: 'string',
24
+ minLength: 1,
25
+ configurable: false,
26
+ required: true,
27
+ unique: true,
28
+ },
29
+ description: {
30
+ type: 'string',
31
+ minLength: 1,
32
+ configurable: false,
33
+ required: false,
34
+ default: '',
35
+ },
36
+ accessKey: {
37
+ type: 'string',
38
+ minLength: 1,
39
+ configurable: false,
40
+ required: true,
41
+ },
42
+ lastUsedAt: {
43
+ type: 'datetime',
44
+ configurable: false,
45
+ required: false,
46
+ },
47
+ permissions: {
48
+ type: 'relation',
49
+ target: 'admin::transfer-token-permission',
50
+ relation: 'oneToMany',
51
+ mappedBy: 'token',
52
+ configurable: false,
53
+ required: false,
54
+ },
55
+ expiresAt: {
56
+ type: 'datetime',
57
+ configurable: false,
58
+ required: false,
59
+ },
60
+ lifespan: {
61
+ type: 'biginteger',
62
+ configurable: false,
63
+ required: false,
64
+ },
65
+ },
66
+ };
@@ -2,8 +2,7 @@
2
2
 
3
3
  const { stringEquals } = require('@strapi/utils/lib');
4
4
  const { ApplicationError } = require('@strapi/utils').errors;
5
- const { trim } = require('lodash/fp');
6
- const has = require('lodash/has');
5
+ const { trim, has } = require('lodash/fp');
7
6
  const { getService } = require('../utils');
8
7
  const {
9
8
  validateApiTokenCreationInput,
@@ -93,11 +92,11 @@ module.exports = {
93
92
  * - having a space at the end or start of the value.
94
93
  * - having only spaces as value;
95
94
  */
96
- if (has(attributes, 'name')) {
95
+ if (has('name', attributes)) {
97
96
  attributes.name = trim(body.name);
98
97
  }
99
98
 
100
- if (has(attributes, 'description') || attributes.description === null) {
99
+ if (has('description', attributes) || attributes.description === null) {
101
100
  attributes.description = trim(body.description);
102
101
  }
103
102
 
@@ -108,7 +107,7 @@ module.exports = {
108
107
  return ctx.notFound('API Token not found');
109
108
  }
110
109
 
111
- if (has(attributes, 'name')) {
110
+ if (has('name', attributes)) {
112
111
  const nameAlreadyTaken = await apiTokenService.getByName(attributes.name);
113
112
 
114
113
  /**
@@ -7,6 +7,7 @@ module.exports = {
7
7
  authentication: require('./authentication'),
8
8
  permission: require('./permission'),
9
9
  role: require('./role'),
10
+ transfer: require('./transfer'),
10
11
  user: require('./user'),
11
12
  webhooks: require('./webhooks'),
12
13
  'content-api': require('./content-api'),
@@ -0,0 +1,13 @@
1
+ 'use strict';
2
+
3
+ const { mapKeys } = require('lodash/fp');
4
+
5
+ const runner = require('./runner');
6
+ const token = require('./token');
7
+
8
+ const prefixActionsName = (prefix, dict) => mapKeys((key) => `${prefix}-${key}`, dict);
9
+
10
+ module.exports = {
11
+ ...prefixActionsName('runner', runner),
12
+ ...prefixActionsName('token', token),
13
+ };
@@ -0,0 +1,24 @@
1
+ 'use strict';
2
+
3
+ const { remote } = require('@strapi/data-transfer/lib/strapi');
4
+ const { UnauthorizedError } = require('@strapi/utils/lib/errors');
5
+
6
+ const dataTransferAuthStrategy = require('../../strategies/data-transfer');
7
+
8
+ /**
9
+ * @param {import('koa').Context} ctx
10
+ * @param {string} [scope]
11
+ */
12
+ const verify = async (ctx, scope) => {
13
+ const { auth } = ctx.state;
14
+
15
+ if (!auth) {
16
+ throw new UnauthorizedError();
17
+ }
18
+
19
+ await dataTransferAuthStrategy.verify(auth, { scope });
20
+ };
21
+
22
+ module.exports = {
23
+ connect: remote.handlers.createTransferHandler({ verify }),
24
+ };
@@ -0,0 +1,131 @@
1
+ 'use strict';
2
+
3
+ const { trim, has } = require('lodash/fp');
4
+ const {
5
+ errors: { ApplicationError },
6
+ stringEquals,
7
+ } = require('@strapi/utils');
8
+
9
+ const {
10
+ token: { validateTransferTokenCreationInput, validateTransferTokenUpdateInput },
11
+ } = require('../../validation/transfer');
12
+ const { getService } = require('../../utils');
13
+
14
+ module.exports = {
15
+ async list(ctx) {
16
+ const transferService = getService('transfer');
17
+ const transferTokens = await transferService.token.list();
18
+
19
+ ctx.body = { data: transferTokens };
20
+ },
21
+
22
+ async getById(ctx) {
23
+ const { id } = ctx.params;
24
+ const tokenService = getService('transfer').token;
25
+
26
+ const transferToken = await tokenService.getById(id);
27
+
28
+ if (!transferToken) {
29
+ ctx.notFound('Transfer token not found');
30
+ return;
31
+ }
32
+
33
+ ctx.body = { data: transferToken };
34
+ },
35
+
36
+ async create(ctx) {
37
+ const { body } = ctx.request;
38
+ const { token: tokenService } = getService('transfer');
39
+
40
+ /**
41
+ * We trim fields to avoid having issues with either:
42
+ * - having a space at the end or start of the value
43
+ * - having only spaces as value (so that an empty field can be caught in validation)
44
+ */
45
+ const attributes = {
46
+ name: trim(body.name),
47
+ description: trim(body.description),
48
+ permissions: body.permissions,
49
+ lifespan: body.lifespan,
50
+ };
51
+
52
+ await validateTransferTokenCreationInput(attributes);
53
+
54
+ const alreadyExists = await tokenService.exists({ name: attributes.name });
55
+ if (alreadyExists) {
56
+ throw new ApplicationError('Name already taken');
57
+ }
58
+
59
+ const transferTokens = await tokenService.create(attributes);
60
+
61
+ ctx.created({ data: transferTokens });
62
+ },
63
+
64
+ async update(ctx) {
65
+ const { body } = ctx.request;
66
+ const { id } = ctx.params;
67
+ const { token: tokenService } = getService('transfer');
68
+
69
+ const attributes = body;
70
+ /**
71
+ * We trim fields to avoid having issues with either:
72
+ * - having a space at the end or start of the value
73
+ * - having only spaces as value (so that an empty field can be caught in validation)
74
+ */
75
+ if (has('name', attributes)) {
76
+ attributes.name = trim(body.name);
77
+ }
78
+
79
+ if (has('description', attributes) || attributes.description === null) {
80
+ attributes.description = trim(body.description);
81
+ }
82
+
83
+ await validateTransferTokenUpdateInput(attributes);
84
+
85
+ const apiTokenExists = await tokenService.getById(id);
86
+ if (!apiTokenExists) {
87
+ return ctx.notFound('Transfer token not found');
88
+ }
89
+
90
+ if (has('name', attributes)) {
91
+ const nameAlreadyTaken = await tokenService.getByName(attributes.name);
92
+
93
+ /**
94
+ * We cast the ids as string as the one coming from the ctx isn't cast
95
+ * as a Number in case it is supposed to be an integer. It remains
96
+ * as a string. This way we avoid issues with integers in the db.
97
+ */
98
+ if (!!nameAlreadyTaken && !stringEquals(nameAlreadyTaken.id, id)) {
99
+ throw new ApplicationError('Name already taken');
100
+ }
101
+ }
102
+
103
+ const apiToken = await tokenService.update(id, attributes);
104
+
105
+ ctx.body = { data: apiToken };
106
+ },
107
+
108
+ async revoke(ctx) {
109
+ const { id } = ctx.params;
110
+ const { token: tokenService } = getService('transfer');
111
+
112
+ const transferToken = await tokenService.revoke(id);
113
+
114
+ ctx.deleted({ data: transferToken });
115
+ },
116
+
117
+ async regenerate(ctx) {
118
+ const { id } = ctx.params;
119
+ const { token: tokenService } = getService('transfer');
120
+
121
+ const exists = await tokenService.getById(id);
122
+ if (!exists) {
123
+ ctx.notFound('Transfer token not found');
124
+ return;
125
+ }
126
+
127
+ const accessToken = await tokenService.regenerate(id);
128
+
129
+ ctx.created({ data: accessToken });
130
+ },
131
+ };
@@ -1,9 +1,9 @@
1
1
  'use strict';
2
2
 
3
- // const { register: registerDataTransferRoute } = require('@strapi/data-transfer/lib/strapi');
4
-
5
3
  const registerAdminPanelRoute = require('./routes/serve-admin-panel');
4
+
6
5
  const adminAuthStrategy = require('./strategies/admin');
6
+
7
7
  const apiTokenAuthStrategy = require('./strategies/api-token');
8
8
 
9
9
  module.exports = ({ strapi }) => {
@@ -16,11 +16,4 @@ module.exports = ({ strapi }) => {
16
16
  if (strapi.config.serveAdminPanel) {
17
17
  registerAdminPanelRoute({ strapi });
18
18
  }
19
-
20
- // if (
21
- // process.env.STRAPI_EXPERIMENTAL === 'true' &&
22
- // process.env.STRAPI_DISABLE_REMOTE_DATA_TRANSFER !== 'true'
23
- // ) {
24
- // registerDataTransferRoute(strapi);
25
- // }
26
19
  };
@@ -8,6 +8,7 @@ const roles = require('./roles');
8
8
  const webhooks = require('./webhooks');
9
9
  const apiTokens = require('./api-tokens');
10
10
  const contentApi = require('./content-api');
11
+ const transfer = require('./transfer');
11
12
 
12
13
  module.exports = [
13
14
  ...admin,
@@ -18,4 +19,5 @@ module.exports = [
18
19
  ...webhooks,
19
20
  ...apiTokens,
20
21
  ...contentApi,
22
+ ...transfer,
21
23
  ];
@@ -0,0 +1,95 @@
1
+ 'use strict';
2
+
3
+ const dataTransferAuthStrategy = require('../strategies/data-transfer');
4
+
5
+ module.exports = [
6
+ // Transfer route
7
+ {
8
+ method: 'GET',
9
+ path: '/transfer/runner/connect',
10
+ handler: 'transfer.runner-connect',
11
+ config: {
12
+ middlewares: [
13
+ (ctx, next) => {
14
+ if (process.env.STRAPI_DISABLE_REMOTE_DATA_TRANSFER === 'true') {
15
+ return ctx.notFound();
16
+ }
17
+
18
+ return next();
19
+ },
20
+ ],
21
+ // TODO: Allow not passing any scope <> Add a way to prevent assigning one by default
22
+ auth: { strategies: [dataTransferAuthStrategy], scope: ['push'] },
23
+ },
24
+ },
25
+ // Transfer Tokens
26
+ {
27
+ method: 'POST',
28
+ path: '/transfer/tokens',
29
+ handler: 'transfer.token-create',
30
+ config: {
31
+ policies: [
32
+ 'admin::isAuthenticatedAdmin',
33
+ { name: 'admin::hasPermissions', config: { actions: ['admin::transfer.tokens.create'] } },
34
+ ],
35
+ },
36
+ },
37
+ {
38
+ method: 'GET',
39
+ path: '/transfer/tokens',
40
+ handler: 'transfer.token-list',
41
+ config: {
42
+ policies: [
43
+ 'admin::isAuthenticatedAdmin',
44
+ { name: 'admin::hasPermissions', config: { actions: ['admin::transfer.tokens.read'] } },
45
+ ],
46
+ },
47
+ },
48
+ {
49
+ method: 'DELETE',
50
+ path: '/transfer/tokens/:id',
51
+ handler: 'transfer.token-revoke',
52
+ config: {
53
+ policies: [
54
+ 'admin::isAuthenticatedAdmin',
55
+ { name: 'admin::hasPermissions', config: { actions: ['admin::transfer.tokens.delete'] } },
56
+ ],
57
+ },
58
+ },
59
+ {
60
+ method: 'GET',
61
+ path: '/transfer/tokens/:id',
62
+ handler: 'transfer.token-getById',
63
+ config: {
64
+ policies: [
65
+ 'admin::isAuthenticatedAdmin',
66
+ { name: 'admin::hasPermissions', config: { actions: ['admin::transfer.tokens.read'] } },
67
+ ],
68
+ },
69
+ },
70
+ {
71
+ method: 'PUT',
72
+ path: '/transfer/tokens/:id',
73
+ handler: 'transfer.token-update',
74
+ config: {
75
+ policies: [
76
+ 'admin::isAuthenticatedAdmin',
77
+ { name: 'admin::hasPermissions', config: { actions: ['admin::transfer.tokens.update'] } },
78
+ ],
79
+ },
80
+ },
81
+ {
82
+ method: 'POST',
83
+ path: '/transfer/tokens/:id/regenerate',
84
+ handler: 'transfer.token-regenerate',
85
+ config: {
86
+ policies: [
87
+ 'admin::isAuthenticatedAdmin',
88
+ {
89
+ name: 'admin::hasPermissions',
90
+ config: { actions: ['admin::transfer.tokens.regenerate'] },
91
+ },
92
+ ],
93
+ },
94
+ },
95
+ ];
@@ -1,8 +1,7 @@
1
1
  'use strict';
2
2
 
3
3
  const crypto = require('crypto');
4
- const { isNil } = require('lodash/fp');
5
- const { omit, difference, isEmpty, map, isArray, uniq } = require('lodash/fp');
4
+ const { omit, difference, isNil, isEmpty, map, isArray, uniq } = require('lodash/fp');
6
5
  const { ValidationError, NotFoundError } = require('@strapi/utils').errors;
7
6
  const constants = require('./constants');
8
7
 
@@ -78,7 +77,7 @@ const assertCustomTokenPermissionsValidity = (attributes) => {
78
77
  };
79
78
 
80
79
  /**
81
- * Assert that a token's permissions attribute is valid for its type
80
+ * Assert that a token's lifespan is valid
82
81
  *
83
82
  * @param {ApiToken} token
84
83
  */
@@ -24,4 +24,10 @@ module.exports = {
24
24
  DAYS_30: 30 * DAY_IN_MS,
25
25
  DAYS_90: 90 * DAY_IN_MS,
26
26
  },
27
+ TRANSFER_TOKEN_LIFESPANS: {
28
+ UNLIMITED: null,
29
+ DAYS_7: 7 * DAY_IN_MS,
30
+ DAYS_30: 30 * DAY_IN_MS,
31
+ DAYS_90: 90 * DAY_IN_MS,
32
+ },
27
33
  };
@@ -13,5 +13,6 @@ module.exports = {
13
13
  auth: require('./auth'),
14
14
  action: require('./action'),
15
15
  'api-token': require('./api-token'),
16
+ transfer: require('./transfer'),
16
17
  'project-settings': require('./project-settings'),
17
18
  };
@@ -0,0 +1,6 @@
1
+ 'use strict';
2
+
3
+ module.exports = {
4
+ permission: require('./permission'),
5
+ token: require('./token'),
6
+ };
@@ -0,0 +1,22 @@
1
+ 'use strict';
2
+
3
+ const permissions = require('@strapi/permissions');
4
+ const { providerFactory } = require('@strapi/utils');
5
+
6
+ const DEFAULT_TRANSFER_ACTIONS = ['push'];
7
+
8
+ const providers = {
9
+ action: providerFactory(),
10
+ condition: providerFactory(),
11
+ };
12
+
13
+ DEFAULT_TRANSFER_ACTIONS.forEach((action) => {
14
+ providers.action.register(action, { action });
15
+ });
16
+
17
+ const engine = permissions.engine.new({ providers });
18
+
19
+ module.exports = {
20
+ engine,
21
+ providers,
22
+ };