Refactored out claim check logic to its own class
This commit is contained in:
		@@ -3,6 +3,7 @@
 | 
			
		||||
namespace NoccyLabs\Mercureact\Http\Middleware;
 | 
			
		||||
 | 
			
		||||
use NoccyLabs\Mercureact\Broker\Message;
 | 
			
		||||
use NoccyLabs\Mercureact\Broker\Security\ClaimChecker;
 | 
			
		||||
use NoccyLabs\Mercureact\Broker\Subscriber\SseSubscriber;
 | 
			
		||||
use NoccyLabs\Mercureact\Broker\TopicManager;
 | 
			
		||||
use NoccyLabs\Mercureact\Configuration;
 | 
			
		||||
@@ -27,6 +28,8 @@ class MercureHandler
 | 
			
		||||
 | 
			
		||||
    private int $seenIdHistorySize = 100;
 | 
			
		||||
 | 
			
		||||
    private ClaimChecker $claimChecker;
 | 
			
		||||
 | 
			
		||||
    public function __construct(
 | 
			
		||||
        private Configuration $config,
 | 
			
		||||
        private TopicManager $topicManager,
 | 
			
		||||
@@ -35,6 +38,7 @@ class MercureHandler
 | 
			
		||||
    {
 | 
			
		||||
        $this->loop = $loop ?? Loop::get();
 | 
			
		||||
        $this->seenIdHistorySize = $this->config->getDuplicateIdHistorySize();
 | 
			
		||||
        $this->claimChecker = new ClaimChecker();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
@@ -94,7 +98,7 @@ class MercureHandler
 | 
			
		||||
        // Grab the JWT token from the requests authorization attribute
 | 
			
		||||
        if ($request->getAttribute('authorized')) {
 | 
			
		||||
            $claims = $request->getAttribute('mercure.subscribe');
 | 
			
		||||
            if (!$this->checkTopicClaims($topics, $claims)) {
 | 
			
		||||
            if (!$this->claimChecker->matchAll($topics, $claims)) {
 | 
			
		||||
                throw new SecurityException(
 | 
			
		||||
                    message: "Insufficient permissions for subscribe", 
 | 
			
		||||
                    code: SecurityException::ERR_NO_PERMISSION
 | 
			
		||||
@@ -112,6 +116,7 @@ class MercureHandler
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        $this->topicManager->subscribe($subscriber, $topics);
 | 
			
		||||
 | 
			
		||||
        $responseStream->on('close', function () use ($subscriber, $topics) {
 | 
			
		||||
            $this->topicManager->unsubscribe($subscriber, $topics);
 | 
			
		||||
        });
 | 
			
		||||
@@ -156,7 +161,7 @@ class MercureHandler
 | 
			
		||||
        if ($request->getAttribute('authorized')) {
 | 
			
		||||
            $claims = $request->getAttribute('mercure.publish');
 | 
			
		||||
            // check topic against publishClaims
 | 
			
		||||
            if (!$this->checkTopicClaims($data['topic']??[], $claims)) {
 | 
			
		||||
            if (!$this->claimChecker->matchAll($data['topic']??[], $claims)) {
 | 
			
		||||
                throw new SecurityException(
 | 
			
		||||
                    message: "Insufficient permissions for publish", 
 | 
			
		||||
                    code: SecurityException::ERR_NO_PERMISSION
 | 
			
		||||
@@ -195,23 +200,4 @@ class MercureHandler
 | 
			
		||||
        return Response::plaintext($message->id."\n");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private function checkTopicClaims(string|array $topic, array $claims): bool
 | 
			
		||||
    {
 | 
			
		||||
        $matched = 0;
 | 
			
		||||
        foreach ((array)$topic as $match) {
 | 
			
		||||
            foreach ($claims as $claim) {
 | 
			
		||||
                if (($claim === "*") || ($claim === $match)) {
 | 
			
		||||
                    $matched++;
 | 
			
		||||
                    break;
 | 
			
		||||
                }
 | 
			
		||||
                // TODO make sure that UriTemplate parsing works
 | 
			
		||||
                if ((new UriTemplate())->extract($claim, $match, true)) {
 | 
			
		||||
                    $matched++;
 | 
			
		||||
                    break;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        return ($matched == count($topic));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user