mirror of
https://github.com/strapi/strapi.git
synced 2025-07-27 02:44:13 +00:00
110 lines
2.6 KiB
JavaScript
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,
|
|
};
|