feat: depromisify fastify-jwt-authz (#49550)

This commit is contained in:
Oliver Eyton-Williams
2023-03-06 16:25:40 +05:30
committed by GitHub
parent f45d8b06dc
commit 113036dad6
2 changed files with 94 additions and 31 deletions
+71
View File
@@ -218,4 +218,75 @@ describe('fastify-jwt-authz', { only: true }, () => {
assert.strictEqual(res.statusCode, 200);
assert.strictEqual(resData.foo, 'bar');
});
it('should throw an error when there is no callback', async () => {
const fastify = Fastify();
await fastify.register(jwtAuthz);
fastify.get(
'/test7',
{
preHandler: function (request, _reply, done) {
request.user = {
name: 'sample',
scope: 123
};
request.jwtAuthz(['baz']);
done();
}
},
function () {
return { foo: 'bar' };
}
);
fastify.listen({ port: 0 }, function () {
fastify.server.unref();
});
const res = await fastify.inject({
method: 'GET',
url: '/test7'
});
const resData: ErrorResponse = res.json();
assert.strictEqual(res.statusCode, 500);
assert.strictEqual(resData.message, 'request.user.scope must be a string');
});
it('should verify user scope when there is no callback', async () => {
const fastify = Fastify();
await fastify.register(jwtAuthz);
fastify.get(
'/test8',
{
preHandler: function (request, _reply, done) {
request.user = {
name: 'sample',
scope: 'user manager'
};
request.jwtAuthz(['user']);
done();
}
},
function () {
return { foo: 'bar' };
}
);
fastify.listen({ port: 0 }, function () {
fastify.server.unref();
});
const res = await fastify.inject({
method: 'GET',
url: '/test8'
});
const resData: { foo: string } = res.json();
assert.strictEqual(res.statusCode, 200);
assert.strictEqual(resData.foo, 'bar');
});
});
+23 -31
View File
@@ -26,49 +26,41 @@ import { FastifyPluginCallback, FastifyRequest } from 'fastify';
import fp from 'fastify-plugin';
interface UserObject {
scope: string;
scope?: string;
}
export interface JwtAuthz {
(scopes: string[], callback: (err?: Error) => void): Promise<void>;
interface JwtAuthz {
(scopes: string[], callback?: (err?: Error) => void): void;
}
const fastifyJwtAuthz: FastifyPluginCallback = (fastify, _opts, done) => {
fastify.decorateRequest('jwtAuthz', checkScopes);
fastify.decorateRequest('jwtAuthz', jwtAuthz);
done();
function checkScopes(user: UserObject, scopes: string[]) {
if (scopes.length === 0) return Error('Scopes cannot be empty');
function checkScopes(
this: FastifyRequest,
scopes: string[],
callback: (err?: Error) => void
) {
if (callback === undefined) {
return new Promise((resolve, reject) => {
void this.jwtAuthz(scopes, function (err) {
return err ? reject(err) : resolve(null);
});
});
}
if (!user) return Error('request.user does not exist');
if (scopes.length === 0) {
return callback(new Error('Scopes cannot be empty'));
}
const user = this.user as UserObject;
if (!user) {
return callback(new Error('request.user does not exist'));
}
if (typeof user.scope !== 'string') {
return callback(new Error('request.user.scope must be a string'));
}
if (typeof user.scope !== 'string')
return Error('request.user.scope must be a string');
const userScopes = user.scope.split(' ');
const allowed = scopes.some(scope => {
return userScopes.indexOf(scope) !== -1;
});
const sufficientScope = scopes.some(scope => userScopes.includes(scope));
return callback(allowed ? undefined : new Error('Insufficient scope'));
if (!sufficientScope) return Error('Insufficient scope');
}
function jwtAuthz(
this: FastifyRequest,
scopes: string[],
callback?: (err?: Error) => void
) {
const err = checkScopes(this.user as UserObject, scopes);
if (callback) return callback(err);
if (err) throw err;
}
done();
};
declare module 'fastify' {