Merge branch 'api-token-v2/backend/regenerate-token' into api-token-v2/regenerate-tokens-api

This commit is contained in:
Ben Irvin 2022-08-18 13:48:06 +02:00
commit 7098ae95be
4 changed files with 77 additions and 5 deletions

View File

@ -38,6 +38,20 @@ module.exports = {
ctx.created({ data: apiToken });
},
async regenerate(ctx) {
const { body } = ctx.request;
const apiTokenService = getService('api-token');
const alreadyExists = await apiTokenService.exists({ name: body.id });
if (!alreadyExists) {
ctx.notFound('API Token not found');
return;
}
const accessToken = await apiTokenService.regenerate(body.id);
ctx.created({ data: accessToken });
},
async list(ctx) {
const apiTokenService = getService('api-token');
const apiTokens = await apiTokenService.list();
@ -60,7 +74,6 @@ module.exports = {
if (!apiToken) {
ctx.notFound('API Token not found');
return;
}

View File

@ -56,4 +56,15 @@ module.exports = [
],
},
},
{
method: 'PUT',
path: '/api-tokens/:id/regenerate',
handler: 'api-token.regenerate',
config: {
policies: [
'admin::isAuthenticatedAdmin',
{ name: 'admin::hasPermissions', config: { actions: ['admin::api-tokens.update'] } },
],
},
},
];

View File

@ -242,6 +242,32 @@ describe('API Token', () => {
});
});
describe('regenerate', () => {
test('It regenerates the accessKey', async () => {
const update = jest.fn(({ data }) => Promise.resolve(data));
global.strapi = {
query() {
return { update };
},
config: {
get: jest.fn(() => ''),
},
};
const id = 1;
const res = await apiTokenService.regenerate(id);
expect(update).toHaveBeenCalledWith(id, {
select: ['id', 'accessKey'],
data: {
accessKey: apiTokenService.hash(mockedApiToken.hexedString),
},
});
expect(res).toEqual({ accessKey: mockedApiToken.hexedString });
});
});
describe('update', () => {
test('Updates a non-custom token', async () => {
const token = {
@ -327,7 +353,7 @@ describe('API Token', () => {
// first call to load original permissions
.mockResolvedValueOnce(
Promise.resolve(
originalToken.permissions.map(p => {
originalToken.permissions.map((p) => {
return {
action: p,
};
@ -337,7 +363,7 @@ describe('API Token', () => {
// second call to check new permissions
.mockResolvedValueOnce(
Promise.resolve(
updatedAttributes.permissions.map(p => {
updatedAttributes.permissions.map((p) => {
return {
action: p,
};
@ -433,7 +459,7 @@ describe('API Token', () => {
// first call to load original permissions
.mockResolvedValueOnce(
Promise.resolve(
originalToken.permissions.map(p => {
originalToken.permissions.map((p) => {
return {
action: p,
};
@ -443,7 +469,7 @@ describe('API Token', () => {
// second call to check new permissions
.mockResolvedValueOnce(
Promise.resolve(
originalToken.permissions.map(p => {
originalToken.permissions.map((p) => {
return {
action: p,
};

View File

@ -130,6 +130,27 @@ const create = async (attributes) => {
return result;
};
/**
* @param {string|number} id
*
* @returns {Promise<ApiToken>}
*/
const regenerate = async (id) => {
const accessKey = crypto.randomBytes(128).toString('hex');
const apiToken = await strapi.query('admin::api-token').update(id, {
select: ['id', 'accessKey'],
data: {
accessKey: hash(accessKey),
},
});
return {
...apiToken,
accessKey,
};
};
/**
* @returns {void}
*/
@ -341,6 +362,7 @@ const mapTokenPermissions = (token) => {
module.exports = {
create,
regenerate,
exists,
checkSaltIsDefined,
hash,