-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #9 from greatislander/php-7.4-compatibility
feat: support PHP 7.4 (resolves #8)
- Loading branch information
Showing
6 changed files
with
229 additions
and
11 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
<?php | ||
|
||
namespace Pressbooks\Sniffs; | ||
|
||
use PHP_CodeSniffer\Util; | ||
|
||
trait ExtraSniffCode { | ||
/** | ||
* Duplicates ignore statements from a legacy sniff. | ||
* | ||
* This allows overriding an existing sniff and retaining the existing | ||
* ignore statements. | ||
* | ||
* @param string $legacy Legacy sniff code | ||
*/ | ||
protected function duplicate_ignores( $legacy ) { | ||
$expression = sprintf( '/^%s(\..+)?$/', preg_quote( $legacy ) ); | ||
$base_code = Util\Common::getSniffCode( get_class( $this ) ); | ||
|
||
foreach ( $this->phpcsFile->tokenizer->ignoredLines as $line => $ignored ) { | ||
$additional = []; | ||
|
||
if ( empty( $ignored ) ) { | ||
continue; | ||
} | ||
|
||
// Find any code which matches the legacy value. | ||
foreach ( $ignored as $code => $value ) { | ||
if ( preg_match( $expression, $code, $matches ) ) { | ||
// Duplicate as the new code. | ||
$new_code = $base_code; | ||
if ( ! empty( $matches[1] ) ) { | ||
$new_code .= $matches[1]; | ||
} | ||
|
||
$additional[ $new_code ] = $value; | ||
} | ||
} | ||
|
||
if ( ! empty( $additional ) ) { | ||
$this->phpcsFile->tokenizer->ignoredLines[ $line ] = array_merge( $ignored, $additional ); | ||
} | ||
} | ||
|
||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
<?php | ||
|
||
namespace Pressbooks\Sniffs\Security; | ||
|
||
use Pressbooks\Sniffs\ExtraSniffCode; | ||
use PHP_CodeSniffer\Files\File as PhpcsFile; | ||
use WordPressCS\WordPress\Sniffs\Security\EscapeOutputSniff as WPCSEscapeOutputSniff; | ||
|
||
/** | ||
* Verify all strings are escaped. | ||
* | ||
* This is subclassed from WPCS, as we need to disable warnings for error | ||
* logging, as we don't output those to the page. | ||
* | ||
* @see https://github.com/WordPress/WordPress-Coding-Standards/issues/1864 | ||
*/ | ||
class EscapeOutputSniff extends WPCSEscapeOutputSniff { | ||
use ExtraSniffCode; | ||
|
||
/** | ||
* Allowed functions which are treated by WPCS as printing functions. | ||
* | ||
* @var array | ||
*/ | ||
protected $hmSafePrintingFunctions = [ | ||
'_deprecated_argument' => true, | ||
'_deprecated_constructor' => true, | ||
'_deprecated_file' => true, | ||
'_deprecated_function' => true, | ||
'_deprecated_hook' => true, | ||
'_doing_it_wrong' => true, | ||
'trigger_error' => true, | ||
'user_error' => true, | ||
]; | ||
|
||
/** | ||
* Printing functions that incorporate unsafe values. | ||
* | ||
* This is overridden from the parent class to allow unescaped | ||
* translated text. | ||
* | ||
* @var array | ||
*/ | ||
protected $unsafePrintingFunctions = []; | ||
|
||
/** | ||
* Constructor. | ||
* | ||
* Removes non-printing functions from the property. | ||
*/ | ||
public function __construct() { | ||
// Remove error logging functions from output functions. | ||
foreach ( $this->hmSafePrintingFunctions as $function => $val ) { | ||
unset( $this->printingFunctions[ $function ] ); | ||
} | ||
} | ||
|
||
/** | ||
* Override init to duplicate any ignores. | ||
* | ||
* @param PhpcsFile $phpcsFile | ||
*/ | ||
protected function init( PhpcsFile $phpcsFile ) { | ||
parent::init( $phpcsFile ); | ||
|
||
$this->duplicate_ignores( 'WordPress.Security.EscapeOutput' ); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
106 changes: 106 additions & 0 deletions
106
Pressbooks/Sniffs/Security/ValidatedSanitizedInputSniff.php
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,106 @@ | ||
<?php | ||
|
||
namespace Pressbooks\Sniffs\Security; | ||
|
||
use Pressbooks\Sniffs\ExtraSniffCode; | ||
use PHP_CodeSniffer\Files\File as PhpcsFile; | ||
use WordPressCS\WordPress\Sniffs\Security\ValidatedSanitizedInputSniff as WPCSValidatedSanitizedInputSniff; | ||
|
||
class ValidatedSanitizedInputSniff extends WPCSValidatedSanitizedInputSniff { | ||
use ExtraSniffCode; | ||
|
||
/** | ||
* Keys to allow in the $_SERVER variable. | ||
* | ||
* Set this to override. | ||
* | ||
* @var array | ||
*/ | ||
public $allowedServerKeys = [ | ||
'HTTP_HOST', | ||
|
||
// User-Agent is forced to a static value when passing through | ||
// CloudFront, so is safe to use. | ||
'HTTP_USER_AGENT', | ||
|
||
'HTTPS', | ||
'REMOTE_ADDR', | ||
'REQUEST_METHOD', | ||
'REQUEST_TIME', | ||
'REQUEST_TIME_FLOAT', | ||
'REQUEST_URI', | ||
'QUERY_STRING', | ||
'SERVER_ADDR', | ||
]; | ||
|
||
/** | ||
* Override init to duplicate any ignores. | ||
* | ||
* @param PhpcsFile $phpcsFile | ||
*/ | ||
protected function init( PhpcsFile $phpcsFile ) { | ||
parent::init( $phpcsFile ); | ||
|
||
$this->duplicate_ignores( 'WordPress.Security.ValidatedSanitizedInput' ); | ||
} | ||
|
||
/** | ||
* Process a token for validation and sanitisation. | ||
* | ||
* @param int $stackPtr | ||
* @return void | ||
*/ | ||
public function process_token( $stackPtr ) { | ||
// Process our custom server rules first. | ||
if ( $this->tokens[ $stackPtr ]['content'] === '$_SERVER' ) { | ||
$pass = $this->check_server_variable( $stackPtr ); | ||
if ( $pass ) { | ||
// Variable is fine, skip upstream checks. | ||
return; | ||
} | ||
} | ||
|
||
// Not an allowed usage, so run the regular check on it. | ||
return parent::process_token( $stackPtr ); | ||
} | ||
|
||
/** | ||
* Check whether a $_SERVER variable is constant and allowed. | ||
* | ||
* @param int $stackPtr Current token to check. | ||
* @return bool True if this is a $_SERVER variable and is safe, false to run regular checks. | ||
*/ | ||
protected function check_server_variable( $stackPtr ) { | ||
$key = $this->get_array_access_key( $stackPtr ); | ||
|
||
// Find the next non-whitespace token. | ||
$open_bracket = $this->phpcsFile->findNext( T_WHITESPACE, ( $stackPtr + 1 ), null, true ); | ||
if ( $this->tokens[ $open_bracket ]['code'] !== T_OPEN_SQUARE_BRACKET ) { | ||
// No index access, run regular checks. | ||
return false; | ||
} | ||
|
||
$index_token = $this->phpcsFile->findNext( T_WHITESPACE, ( $open_bracket + 1 ), null, true ); | ||
if ( $this->tokens[ $index_token ]['code'] !== T_CONSTANT_ENCAPSED_STRING ) { | ||
// Dynamic string, run regular checks. | ||
return false; | ||
} | ||
|
||
// Possible constant string, check there's no further dynamic parts. | ||
$maybe_close_bracket = $this->phpcsFile->findNext( T_WHITESPACE, ( $index_token + 1 ), null, true ); | ||
if ( $this->tokens[ $maybe_close_bracket ]['code'] !== T_CLOSE_SQUARE_BRACKET ) { | ||
// Dynamic string, run regular checks. | ||
return false; | ||
} | ||
|
||
// Constant string, check if it's allowed. | ||
$key = $this->strip_quotes( $this->tokens[ $index_token ]['content'] ); | ||
if ( ! in_array( $key, $this->allowedServerKeys, true ) ) { | ||
// Unsafe key, requires sanitising. | ||
return false; | ||
} | ||
|
||
// Safe key, allow it. | ||
return true; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters