1+ <?php
2+
3+ /**
4+ * \DrupalSecurity\Sniffs\Yaml\ViewAccessSniff.
5+ *
6+ * @category PHP
7+ * @package PHP_CodeSniffer
8+ * @link http://pear.php.net/package/PHP_CodeSniffer
9+ */
10+ namespace DrupalSecurity \Sniffs \Yaml ;
11+
12+ use PHP_CodeSniffer \Files \File ;
13+ use PHP_CodeSniffer \Sniffs \Sniff ;
14+ use Symfony \Component \Yaml \Yaml ;
15+ use Symfony \Component \Yaml \Exception \ParseException ;
16+
17+ /**
18+ * Checks if there are potential security issue in views.view.*.yml
19+ * files.
20+ *
21+ *
22+ * @category Yaml
23+ * @package PHP_CodeSniffer
24+ * @link http://pear.php.net/package/PHP_CodeSniffer
25+ */
26+ class ViewAccessSniff implements Sniff {
27+
28+ /**
29+ * Returns an array of tokens this test wants to listen for.
30+ *
31+ * @return array<int|string>
32+ */
33+ public function register () {
34+ return [
35+ T_INLINE_HTML
36+ ];
37+ }
38+
39+ // end register()
40+
41+ /**
42+ * Processes this test, when one of its tokens is encountered.
43+ *
44+ * @param \PHP_CodeSniffer\Files\File $phpcsFile
45+ * The current file being processed.
46+ * @param int $stackPtr
47+ * The position of the current token
48+ * in the stack passed in $tokens.
49+ *
50+ * @return void|int
51+ */
52+ public function process (File $ phpcsFile , $ stackPtr ) {
53+ $ lines = $ phpcsFile ->getTokens ();
54+
55+ $ fileExtension = strtolower (substr ($ phpcsFile ->getFilename (), -3 ));
56+ $ fileNameStartWith = strtolower (substr (basename ($ phpcsFile ->getFilename ()), 0 , 11 ));
57+ if ($ fileExtension !== 'yml ' || $ fileNameStartWith !== 'views.view. ' ) {
58+ return ($ phpcsFile ->numTokens + 1 );
59+ }
60+
61+ $ contents = file_get_contents ($ phpcsFile ->getFilename ());
62+ try {
63+ $ info = Yaml::parse ($ contents );
64+ }
65+ catch (ParseException $ e ) {
66+ // If the YAML is invalid we ignore this file.
67+ return ($ phpcsFile ->numTokens + 1 );
68+ }
69+
70+ if (!isset ($ info ['display ' ])) {
71+ return ($ phpcsFile ->numTokens + 1 );
72+ }
73+ // Start checking open access to a view.
74+ foreach ($ info ['display ' ] as $ display_name => $ display_properties ) {
75+ if (isset ($ display_properties ['display_options ' ]['access ' ]['type ' ])) {
76+ $ access_setting = $ display_properties ['display_options ' ]['access ' ];
77+ // Check unrestricted access.
78+ if (strtolower (trim ($ access_setting ['type ' ])) === 'none ' ) {
79+ $ warning = "Open access to $ display_name display found " ;
80+ $ line_num = $ this ->getTheLineNumber ($ display_name , $ lines );
81+ $ phpcsFile ->addWarning ($ warning , $ line_num ?: 0 , 'OpenAccess ' );
82+ }
83+ // Check 'View published content' permission.
84+ elseif (strtolower (trim ($ access_setting ['type ' ])) === 'perm ' ) {
85+ if (isset ($ access_setting ['options ' ]['perm ' ]) && strtolower (trim ($ access_setting ['options ' ]['perm ' ])) === 'access content ' )
86+ {
87+ $ warning = "Open access to $ display_name display found " ;
88+ $ line_num = $ this ->getTheLineNumber ($ display_name , $ lines );
89+ $ phpcsFile ->addWarning ($ warning , $ line_num , 'OpenAccess ' );
90+ }
91+ }
92+ // Check anonymous role access.
93+ elseif (strtolower (trim ($ access_setting ['type ' ])) === 'role ' ) {
94+ if (isset ($ access_setting ['options ' ]['role ' ]))
95+ {
96+ if (is_array ($ access_setting ['options ' ]['role ' ]) && array_key_exists ('anonymous ' , $ access_setting ['options ' ]['role ' ])) {
97+ $ warning = "Open access to $ display_name display found " ;
98+ $ line_num = $ this ->getTheLineNumber ($ display_name , $ lines );
99+ $ phpcsFile ->addWarning ($ warning , $ line_num , 'OpenAccess ' );
100+ }
101+ }
102+ }
103+ }
104+ }
105+
106+ return ($ phpcsFile ->numTokens + 1 );
107+ }
108+
109+ /**
110+ * Get the line number of the display options.
111+ *
112+ * @param string $displayName
113+ * @param array $lines
114+ * @return int|boolean
115+ * Return the line number if the display option line found,
116+ * otherwise return false.
117+ */
118+ private function getTheLineNumber (string $ displayName , array $ lines ) {
119+ $ found_display = false ;
120+ $ found_display_section = false ;
121+ $ display_options_start = 0 ;
122+ foreach ($ lines as $ line_num => $ line ) {
123+ if ($ found_display ) {
124+ if ($ display_options_start ) {
125+ $ key = explode (': ' , $ line ['content ' ]);
126+ $ property_name = $ key [0 ] ?? '' ;
127+ if (strtolower (trim ($ property_name )) === 'access ' ) {
128+ return $ line_num ;
129+ }
130+ }
131+ else {
132+ $ key = explode (': ' , $ line ['content ' ]);
133+ $ property_name = $ key [0 ] ?? '' ;
134+ if (strtolower (trim ($ property_name )) === 'display_options ' ) {
135+ $ display_options_start = $ line_num ;
136+ }
137+ }
138+ }
139+ elseif ($ found_display_section ) {
140+ $ key = explode (': ' , $ line ['content ' ]);
141+ $ property_name = $ key [0 ] ?? '' ;
142+ if (strtolower (trim ($ property_name )) === $ displayName ) {
143+ $ found_display = $ line_num ;
144+ }
145+ }
146+ else {
147+ $ key = explode (': ' , $ line ['content ' ]);
148+ $ property_name = $ key [0 ] ?? '' ;
149+ if ($ property_name === 'display ' ) {
150+ $ found_display_section = $ line_num ;
151+ }
152+ }
153+ }
154+
155+ return false ;
156+ }
157+ }
0 commit comments