@@ -23,75 +23,113 @@ final class PermissionMatcher
2323 */
2424 public static function matches (string $ permission , array $ grants ): bool
2525 {
26- if (! self ::isValid ($ permission )) {
26+ $ permissionSegments = self ::splitIfValid ($ permission );
27+
28+ if ($ permissionSegments === null ) {
2729 return false ;
2830 }
2931
32+ $ permissionSegmentCount = count ($ permissionSegments );
33+
3034 foreach ($ grants as $ grant ) {
31- if (! self ::isValid ($ grant )) {
35+ if ($ grant === $ permission ) {
36+ return true ;
37+ }
38+
39+ $ wildcardPosition = strpos ($ grant , '* ' );
40+
41+ if ($ wildcardPosition === false ) {
3242 continue ;
3343 }
3444
35- if ($ grant === $ permission ) {
36- return true ;
45+ if (
46+ $ wildcardPosition > 0
47+ && $ wildcardPosition === strlen ($ grant ) - 1
48+ && $ grant [$ wildcardPosition - 1 ] === '. '
49+ ) {
50+ $ prefix = substr ($ grant , 0 , $ wildcardPosition - 1 );
51+
52+ if (self ::isLiteral ($ prefix ) && str_starts_with ($ permission , $ prefix . '. ' )) {
53+ return true ;
54+ }
55+
56+ continue ;
3757 }
3858
39- if (str_contains ($ grant , '* ' ) && self ::matchesWildcardGrant ($ grant , $ permission )) {
59+ $ grantSegments = self ::splitIfValid ($ grant );
60+
61+ if ($ grantSegments === null ) {
62+ continue ;
63+ }
64+
65+ if (self ::matchesWildcardGrant ($ grantSegments , $ permissionSegments , $ permissionSegmentCount )) {
4066 return true ;
4167 }
4268 }
4369
4470 return false ;
4571 }
4672
47- private static function matchesWildcardGrant (string $ grant , string $ permission ): bool
73+ /**
74+ * @param list<string> $grantSegments
75+ * @param list<string> $permissionSegments
76+ */
77+ private static function matchesWildcardGrant (array $ grantSegments , array $ permissionSegments , int $ permissionSegmentCount ): bool
4878 {
49- $ grantSegments = explode ('. ' , $ grant );
50- $ permissionSegments = explode ('. ' , $ permission );
79+ $ grantSegmentCount = count ($ grantSegments );
5180
52- if (end ( $ grantSegments) === '* ' ) {
53- array_pop ( $ grantSegments ) ;
81+ if ($ grantSegments[ $ grantSegmentCount - 1 ] === '* ' ) {
82+ $ grantSegmentCount -- ;
5483
55- return count ( $ permissionSegments ) > count ( $ grantSegments )
56- && self ::segmentsMatch ($ grantSegments , array_slice ( $ permissionSegments , 0 , count ( $ grantSegments )) );
84+ return $ permissionSegmentCount > $ grantSegmentCount
85+ && self ::segmentsMatch ($ grantSegments , $ permissionSegments , $ grantSegmentCount );
5786 }
5887
59- return self ::segmentsMatch ($ grantSegments , $ permissionSegments );
88+ return $ permissionSegmentCount === $ grantSegmentCount
89+ && self ::segmentsMatch ($ grantSegments , $ permissionSegments , $ grantSegmentCount );
6090 }
6191
6292 /**
6393 * @param list<string> $grantSegments
6494 * @param list<string> $permissionSegments
6595 */
66- private static function segmentsMatch (array $ grantSegments , array $ permissionSegments ): bool
96+ private static function segmentsMatch (array $ grantSegments , array $ permissionSegments, int $ segmentCount ): bool
6797 {
68- if (count ($ grantSegments ) !== count ($ permissionSegments )) {
69- return false ;
70- }
71-
72- foreach ($ grantSegments as $ index => $ grantSegment ) {
73- if ($ grantSegment !== '* ' && $ grantSegment !== $ permissionSegments [$ index ]) {
98+ for ($ index = 0 ; $ index < $ segmentCount ; $ index ++) {
99+ if ($ grantSegments [$ index ] !== '* ' && $ grantSegments [$ index ] !== $ permissionSegments [$ index ]) {
74100 return false ;
75101 }
76102 }
77103
78104 return true ;
79105 }
80106
81- private static function isValid (string $ permission ): bool
107+ /**
108+ * @return list<string>|null
109+ */
110+ private static function splitIfValid (string $ permission ): ?array
82111 {
83- $ segments = explode ('. ' , $ permission );
84-
85- if ($ segments === ['* ' ] || $ segments [0 ] === '* ' ) {
86- return false ;
112+ if ($ permission === '' || str_starts_with ($ permission , '* ' )) {
113+ return null ;
87114 }
88115
116+ $ segments = explode ('. ' , $ permission );
117+
89118 foreach ($ segments as $ segment ) {
90119 if ($ segment === '' || ($ segment !== '* ' && str_contains ($ segment , '* ' ))) {
91- return false ;
120+ return null ;
92121 }
93122 }
94123
95- return true ;
124+ return $ segments ;
125+ }
126+
127+ private static function isLiteral (string $ permission ): bool
128+ {
129+ return $ permission !== ''
130+ && ! str_contains ($ permission , '* ' )
131+ && ! str_contains ($ permission , '.. ' )
132+ && ! str_starts_with ($ permission , '. ' )
133+ && ! str_ends_with ($ permission , '. ' );
96134 }
97135}
0 commit comments