TopicMatcher::matchesTopicSelectors()   A
last analyzed

Complexity

Conditions 5
Paths 5

Size

Total Lines 17
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 8
CRAP Score 5

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 5
eloc 8
c 1
b 0
f 0
nc 5
nop 2
dl 0
loc 17
ccs 8
cts 8
cp 1
crap 5
rs 9.6111
1
<?php
2
3
namespace BenTools\MercurePHP\Security;
4
5
use BenTools\MercurePHP\Model\Message;
6
use Lcobucci\JWT\Token;
7
use Rize\UriTemplate;
8
9
final class TopicMatcher
10
{
11
    public static function matchesTopicSelectors(string $topic, array $topicSelectors): bool
12 25
    {
13
        if (\in_array($topic, $topicSelectors, true)) {
14 25
            return true;
15 15
        }
16
17
        if (\in_array('*', $topicSelectors, true)) {
18 23
            return true;
19 7
        }
20
21
        foreach ($topicSelectors as $topicSelector) {
22 20
            if (self::matchesUriTemplate($topic, $topicSelector)) {
23 16
                return true;
24 11
            }
25
        }
26
27
        return false;
28 19
    }
29
30
    private static function matchesUriTemplate(string $topic, string $topicSelector): bool
31 16
    {
32
        static $uriTemplate;
33 16
        $uriTemplate ??= new UriTemplate();
34 16
35
        return false !== \strpos($topicSelector, '{')
36 16
            && null !== $uriTemplate->extract($topicSelector, $topic, true);
37 16
    }
38
39
    public static function canSubscribeToTopic(string $topic, ?Token $token, bool $allowAnonymous): bool
40 10
    {
41
        if (true === $allowAnonymous) {
42 10
            return true;
43 4
        }
44
45
        if (null === $token) {
46 6
            return false;
47 2
        }
48
49
        try {
50
            $claim = (array) $token->getClaim('mercure');
51 4
        } catch (\OutOfBoundsException $e) {
52
            return false;
53
        }
54
55
        $allowedTopics = $claim['subscribe'] ?? [];
56 4
        $deniedTopics = $claim['subscribe_exclude'] ?? [];
57 4
58
        return self::matchesTopicSelectors($topic, $allowedTopics)
59 4
            && !self::matchesTopicSelectors($topic, $deniedTopics);
60 4
    }
61
62
    public static function canUpdateTopic(string $topic, Token $token, bool $privateUpdate): bool
63 11
    {
64
        try {
65
            $claim = (array) $token->getClaim('mercure');
66 11
        } catch (\OutOfBoundsException $e) {
67
            return false;
68
        }
69
70
        $allowedTopics = $claim['publish'] ?? null;
71 11
        $deniedTopics = $claim['publish_exclude'] ?? [];
72 11
73
        // If not defined, then the publisher MUST NOT be authorized to dispatch any update
74
        if (null === $allowedTopics || !\is_array($allowedTopics)) {
75 11
            return false;
76
        }
77
78
        if (true === $privateUpdate) {
79 11
            return self::matchesTopicSelectors($topic, $allowedTopics ?? [])
80 4
            && !self::matchesTopicSelectors($topic, $deniedTopics);
81 4
        }
82
83
        return !self::matchesTopicSelectors($topic, $deniedTopics);
84 7
    }
85
86
    public static function canReceiveUpdate(
87 9
        string $topic,
88
        Message $message,
89
        array $subscribedTopics,
90
        ?Token $token,
91
        bool $allowAnonymous
92
    ): bool {
93
        if (!self::matchesTopicSelectors($topic, $subscribedTopics)) {
94 9
            return false;
95 8
        }
96
97
        if (null === $token && false === $allowAnonymous) {
98 9
            return false;
99 2
        }
100
101
        if (!$message->isPrivate()) {
102 7
            return true;
103 4
        }
104
105
        if (null === $token) {
106 3
            return false;
107 1
        }
108
109
        try {
110
            $claim = (array) $token->getClaim('mercure');
111 2
        } catch (\OutOfBoundsException $e) {
112
            return false;
113
        }
114
115
        $allowedTopics = $claim['subscribe'] ?? [];
116 2
        $deniedTopics = $claim['subscribe_exclude'] ?? [];
117 2
118
        return self::matchesTopicSelectors($topic, $allowedTopics)
119 2
            && !self::matchesTopicSelectors($topic, $deniedTopics);
120 2
    }
121
}
122