wiki.techinc.nl/includes/htmlform/fields/HTMLUserTextField.php
Bartosz Dziewoński 6f95c290c0 HTMLUserTextField: Fix validation
When 'exists' was false (the default), other validation was skipped.

Change the default 'iprangelimits' to allow any range, to avoid issues
with code that relied on the previous broken behavior.

Bug: T177329
Bug: T311948
Change-Id: I55cad7a5395da70105e20ce33e3a8e3834a4f4ad
2022-07-14 02:41:03 +02:00

137 lines
3.5 KiB
PHP

<?php
use MediaWiki\Widget\UserInputWidget;
use Wikimedia\IPUtils;
/**
* Implements a text input field for user names.
* Automatically auto-completes if using the OOUI display format.
*
* Optional parameters:
* 'exists' - Whether to validate that the user already exists
* 'ipallowed' - Whether an IP address is interpreted as "valid"
* 'iprange' - Whether an IP address range is interpreted as "valid"
* 'iprangelimits' - Specifies the valid IP ranges for IPv4 and IPv6 in an array.
*
* @stable to extend
* @since 1.26
*/
class HTMLUserTextField extends HTMLTextField {
/**
* @stable to call
* @inheritDoc
*/
public function __construct( $params ) {
$params = wfArrayPlus2d( $params, [
'exists' => false,
'ipallowed' => false,
'iprange' => false,
'iprangelimits' => [
'IPv4' => 0,
'IPv6' => 0,
],
]
);
parent::__construct( $params );
}
public function validate( $value, $alldata ) {
// If the value is null, reset it to an empty string which is what is expected by the parent.
if ( $value === null ) {
$value = '';
}
// If the value is empty, there are no additional checks that can be performed.
if ( $value === '' ) {
return parent::validate( $value, $alldata );
}
// check if the input is a valid username
$user = User::newFromName( $value );
if ( $user ) {
// check if the user exists, if requested
if ( $this->mParams['exists'] && !$user->isRegistered() ) {
return $this->msg( 'htmlform-user-not-exists', $user->getName() );
}
} else {
// not a valid username
$valid = false;
// check if the input is a valid IP address
if ( $this->mParams['ipallowed'] && IPUtils::isValid( $value ) ) {
$valid = true;
}
// check if the input is a valid IP range
if ( $this->mParams['iprange'] ) {
$rangeError = $this->isValidIPRange( $value );
if ( $rangeError === true ) {
$valid = true;
} elseif ( $rangeError !== false ) {
return $rangeError;
}
}
if ( !$valid ) {
return $this->msg( 'htmlform-user-not-valid', $value );
}
}
return parent::validate( $value, $alldata );
}
protected function isValidIPRange( $value ) {
$cidrIPRanges = $this->mParams['iprangelimits'];
if ( !IPUtils::isValidRange( $value ) ) {
return false;
}
list( $ip, $range ) = explode( '/', $value, 2 );
if (
( IPUtils::isIPv4( $ip ) && $cidrIPRanges['IPv4'] == 32 ) ||
( IPUtils::isIPv6( $ip ) && $cidrIPRanges['IPv6'] == 128 )
) {
// Range block effectively disabled
return $this->msg( 'ip_range_toolow' );
}
if (
( IPUtils::isIPv4( $ip ) && $range > 32 ) ||
( IPUtils::isIPv6( $ip ) && $range > 128 )
) {
// Dodgy range
return $this->msg( 'ip_range_invalid' );
}
if ( IPUtils::isIPv4( $ip ) && $range < $cidrIPRanges['IPv4'] ) {
return $this->msg( 'ip_range_exceeded', $cidrIPRanges['IPv4'] );
}
if ( IPUtils::isIPv6( $ip ) && $range < $cidrIPRanges['IPv6'] ) {
return $this->msg( 'ip_range_exceeded', $cidrIPRanges['IPv6'] );
}
return true;
}
protected function getInputWidget( $params ) {
return new UserInputWidget( $params );
}
protected function shouldInfuseOOUI() {
return true;
}
protected function getOOUIModules() {
return [ 'mediawiki.widgets.UserInputWidget' ];
}
public function getInputHtml( $value ) {
// add the required module and css class for user suggestions in non-OOUI mode
$this->mParent->getOutput()->addModules( 'mediawiki.userSuggest' );
$this->mClass .= ' mw-autocomplete-user';
// return parent html
return parent::getInputHTML( $value );
}
}