add lifespan and expiresAt fields

This commit is contained in:
Ben Irvin 2022-08-19 16:33:58 +02:00
parent c8af2cef6b
commit 36d37706ce
4 changed files with 58 additions and 2 deletions

View File

@ -60,5 +60,15 @@ module.exports = {
configurable: false,
required: false,
},
expiresAt: {
type: 'datetime',
configurable: false,
required: false,
},
lifespan: {
type: 'number',
configurable: false,
required: false,
},
},
};

View File

@ -10,7 +10,17 @@ describe('API Token', () => {
hexedString: '6170692d746f6b656e5f746573742d72616e646f6d2d6279746573',
};
const SELECT_FIELDS = ['id', 'name', 'description', 'lastUsed', 'type', 'createdAt', 'updatedAt'];
const SELECT_FIELDS = [
'id',
'name',
'description',
'lastUsed',
'type',
'lifespan',
'expiresAt',
'createdAt',
'updatedAt',
];
beforeAll(() => {
jest
@ -48,12 +58,16 @@ describe('API Token', () => {
data: {
...attributes,
accessKey: apiTokenService.hash(mockedApiToken.hexedString),
expiresAt: null,
lifespan: null,
},
populate: ['permissions'],
});
expect(res).toEqual({
...attributes,
accessKey: mockedApiToken.hexedString,
expiresAt: null,
lifespan: null,
});
});
});

View File

@ -1,6 +1,7 @@
'use strict';
const crypto = require('crypto');
const { isNumber, isNil } = require('lodash');
const { omit, difference, isEmpty, map, isArray } = require('lodash/fp');
const { ValidationError, NotFoundError } = require('@strapi/utils').errors;
const constants = require('./constants');
@ -17,6 +18,8 @@ const constants = require('./constants');
* @property {string} [description]
* @property {string} accessKey
* @property {number} lastUsed
* @property {number} lifespan
* @property {number} expiresAt
* @property {TokenType} type
* @property {(number|ApiTokenPermission)[]} [permissions]
*/
@ -30,7 +33,17 @@ const constants = require('./constants');
*/
/** @constant {Array<string>} */
const SELECT_FIELDS = ['id', 'name', 'description', 'lastUsed', 'type', 'createdAt', 'updatedAt'];
const SELECT_FIELDS = [
'id',
'name',
'description',
'lastUsed',
'type',
'lifespan',
'expiresAt',
'createdAt',
'updatedAt',
];
/** @constant {Array<string>} */
const POPULATE_FIELDS = ['permissions'];
@ -75,10 +88,27 @@ const hash = (accessKey) => {
.digest('hex');
};
/**
* @param {number} lifespan
*
* @returns {null|number}
*/
const getExpirationFields = (lifespan) => {
if (!isNumber(lifespan) && !isNil(lifespan)) {
throw new ValidationError('lifespan must be a number or null');
}
return {
lifespan: lifespan || null,
expiresAt: lifespan ? Date.now() + lifespan : null,
};
};
/**
* @param {Object} attributes
* @param {TokenType} attributes.type
* @param {string} attributes.name
* @param {number} attributes.lifespan
* @param {string[]} [attributes.permissions]
* @param {string} [attributes.description]
*
@ -96,6 +126,7 @@ const create = async (attributes) => {
data: {
...omit('permissions', attributes),
accessKey: hash(accessKey),
...getExpirationFields(attributes.lifespan),
},
});

View File

@ -10,6 +10,7 @@ const apiTokenCreationSchema = yup
description: yup.string().optional(),
type: yup.string().oneOf(Object.values(constants.API_TOKEN_TYPE)).required(),
permissions: yup.array().of(yup.string()).nullable(),
lifespan: yup.number().nullable(),
})
.noUnknown();