2023-03-02 22:16:29 +01:00

110 lines
2.6 KiB
JavaScript

'use strict';
const {
errors: { UnauthorizedError, ForbiddenError },
} = require('@strapi/utils');
const { castArray, isNil } = require('lodash/fp');
const { getService } = require('../utils');
const extractToken = (ctx) => {
if (ctx.request && ctx.request.header && ctx.request.header.authorization) {
const parts = ctx.request.header.authorization.split(/\s+/);
if (parts[0].toLowerCase() !== 'bearer' || parts.length !== 2) {
return null;
}
return parts[1];
}
return null;
};
/**
* Authenticate the validity of the token
*
* @type {import('.').AuthenticateFunction}
*/
const authenticate = async (ctx) => {
const { token: tokenService } = getService('transfer');
const token = extractToken(ctx);
if (!token) {
return { authenticated: false };
}
const transferToken = await tokenService.getBy({ accessKey: tokenService.hash(token) });
// Check if the token exists
if (!transferToken) {
return { authenticated: false };
}
// Check if the token has expired
const currentDate = new Date();
if (!isNil(transferToken.expiresAt)) {
const expirationDate = new Date(transferToken.expiresAt);
if (expirationDate < currentDate) {
return { authenticated: false, error: new UnauthorizedError('Token expired') };
}
}
// Update token metadata
await strapi.query('admin::transfer-token').update({
where: { id: transferToken.id },
data: { lastUsedAt: currentDate },
});
// Generate an ability based on the token permissions
const ability = await getService('transfer').permission.engine.generateAbility(
transferToken.permissions.map((action) => ({ action }))
);
return { authenticated: true, ability, credentials: transferToken };
};
/**
* Verify the token has the required abilities for the requested scope
*
* @type {import('.').VerifyFunction}
*/
const verify = async (auth, config = {}) => {
const { credentials: transferToken, ability } = auth;
if (!transferToken) {
throw new UnauthorizedError('Token not found');
}
const currentDate = new Date();
if (!isNil(transferToken.expiresAt)) {
const expirationDate = new Date(transferToken.expiresAt);
// token has expired
if (expirationDate < currentDate) {
throw new UnauthorizedError('Token expired');
}
}
if (!ability) {
throw new ForbiddenError();
}
const scopes = castArray(config.scope ?? []);
const isAllowed = scopes.every((scope) => ability.can(scope));
if (!isAllowed) {
throw new ForbiddenError();
}
};
/** @type {import('.').AuthStrategy} */
module.exports = {
name: 'data-transfer',
authenticate,
verify,
};