diff --git a/src/applications/conduit/call/ConduitCall.php b/src/applications/conduit/call/ConduitCall.php index 017d96ae8b..6be49daef0 100644 --- a/src/applications/conduit/call/ConduitCall.php +++ b/src/applications/conduit/call/ConduitCall.php @@ -15,7 +15,7 @@ final class ConduitCall extends Phobject { private $request; private $user; - public function __construct($method, array $params) { + public function __construct($method, array $params, $strictly_typed = true) { $this->method = $method; $this->handler = $this->buildMethodHandler($method); @@ -41,7 +41,7 @@ final class ConduitCall extends Phobject { "'".implode("', '", array_keys($invalid_params))."'")); } - $this->request = new ConduitAPIRequest($params); + $this->request = new ConduitAPIRequest($params, $strictly_typed); } public function getAPIRequest() { diff --git a/src/applications/conduit/controller/PhabricatorConduitAPIController.php b/src/applications/conduit/controller/PhabricatorConduitAPIController.php index b9e8b1b15e..991865b564 100644 --- a/src/applications/conduit/controller/PhabricatorConduitAPIController.php +++ b/src/applications/conduit/controller/PhabricatorConduitAPIController.php @@ -25,9 +25,11 @@ final class PhabricatorConduitAPIController try { - list($metadata, $params) = $this->decodeConduitParams($request, $method); + list($metadata, $params, $strictly_typed) = $this->decodeConduitParams( + $request, + $method); - $call = new ConduitCall($method, $params); + $call = new ConduitCall($method, $params, $strictly_typed); $method_implementation = $call->getMethodImplementation(); $result = null; @@ -638,7 +640,7 @@ final class PhabricatorConduitAPIController $metadata = idx($params, '__conduit__', array()); unset($params['__conduit__']); - return array($metadata, $params); + return array($metadata, $params, true); } // Otherwise, look for a single parameter called 'params' which has the @@ -659,7 +661,7 @@ final class PhabricatorConduitAPIController $metadata = idx($params, '__conduit__', array()); unset($params['__conduit__']); - return array($metadata, $params); + return array($metadata, $params, true); } // If we do not have `params`, assume this is a simple HTTP request with @@ -675,7 +677,7 @@ final class PhabricatorConduitAPIController } } - return array($metadata, $params); + return array($metadata, $params, false); } private function authorizeOAuthMethodAccess( diff --git a/src/applications/conduit/parametertype/ConduitBoolParameterType.php b/src/applications/conduit/parametertype/ConduitBoolParameterType.php index fe1564350f..7ad9dd13e5 100644 --- a/src/applications/conduit/parametertype/ConduitBoolParameterType.php +++ b/src/applications/conduit/parametertype/ConduitBoolParameterType.php @@ -3,17 +3,9 @@ final class ConduitBoolParameterType extends ConduitParameterType { - protected function getParameterValue(array $request, $key) { - $value = parent::getParameterValue($request, $key); - - if (!is_bool($value)) { - $this->raiseValidationException( - $request, - $key, - pht('Expected boolean (true or false), got something else.')); - } - - return $value; + protected function getParameterValue(array $request, $key, $strict) { + $value = parent::getParameterValue($request, $key, $strict); + return $this->parseBoolValue($request, $key, $value, $strict); } protected function getParameterTypeName() { diff --git a/src/applications/conduit/parametertype/ConduitColumnsParameterType.php b/src/applications/conduit/parametertype/ConduitColumnsParameterType.php index c6669fae06..1892747892 100644 --- a/src/applications/conduit/parametertype/ConduitColumnsParameterType.php +++ b/src/applications/conduit/parametertype/ConduitColumnsParameterType.php @@ -3,10 +3,10 @@ final class ConduitColumnsParameterType extends ConduitParameterType { - protected function getParameterValue(array $request, $key) { + protected function getParameterValue(array $request, $key, $strict) { // We don't do any meaningful validation here because the transaction // itself validates everything and the input format is flexible. - return parent::getParameterValue($request, $key); + return parent::getParameterValue($request, $key, $strict); } protected function getParameterTypeName() { diff --git a/src/applications/conduit/parametertype/ConduitEpochParameterType.php b/src/applications/conduit/parametertype/ConduitEpochParameterType.php index 1594186e5c..e8fe095c50 100644 --- a/src/applications/conduit/parametertype/ConduitEpochParameterType.php +++ b/src/applications/conduit/parametertype/ConduitEpochParameterType.php @@ -3,15 +3,9 @@ final class ConduitEpochParameterType extends ConduitParameterType { - protected function getParameterValue(array $request, $key) { - $value = parent::getParameterValue($request, $key); - - if (!is_int($value)) { - $this->raiseValidationException( - $request, - $key, - pht('Expected epoch timestamp as integer, got something else.')); - } + protected function getParameterValue(array $request, $key, $strict) { + $value = parent::getParameterValue($request, $key, $strict); + $value = $this->parseIntValue($request, $key, $value, $strict); if ($value <= 0) { $this->raiseValidationException( diff --git a/src/applications/conduit/parametertype/ConduitIntListParameterType.php b/src/applications/conduit/parametertype/ConduitIntListParameterType.php index 07c87dcd8a..7733977d0e 100644 --- a/src/applications/conduit/parametertype/ConduitIntListParameterType.php +++ b/src/applications/conduit/parametertype/ConduitIntListParameterType.php @@ -3,19 +3,11 @@ final class ConduitIntListParameterType extends ConduitListParameterType { - protected function getParameterValue(array $request, $key) { - $list = parent::getParameterValue($request, $key); + protected function getParameterValue(array $request, $key, $strict) { + $list = parent::getParameterValue($request, $key, $strict); foreach ($list as $idx => $item) { - if (!is_int($item)) { - $this->raiseValidationException( - $request, - $key, - pht( - 'Expected a list of integers, but item with index "%s" is '. - 'not an integer.', - $idx)); - } + $list[$idx] = $this->parseIntValue($request, $key.'['.$idx.']', $item); } return $list; diff --git a/src/applications/conduit/parametertype/ConduitIntParameterType.php b/src/applications/conduit/parametertype/ConduitIntParameterType.php index 54f66fdf6c..e0d91e5d93 100644 --- a/src/applications/conduit/parametertype/ConduitIntParameterType.php +++ b/src/applications/conduit/parametertype/ConduitIntParameterType.php @@ -3,17 +3,9 @@ final class ConduitIntParameterType extends ConduitParameterType { - protected function getParameterValue(array $request, $key) { - $value = parent::getParameterValue($request, $key); - - if (!is_int($value)) { - $this->raiseValidationException( - $request, - $key, - pht('Expected integer, got something else.')); - } - - return $value; + protected function getParameterValue(array $request, $key, $strict) { + $value = parent::getParameterValue($request, $key, $strict); + return $this->parseIntValue($request, $key, $value, $strict); } protected function getParameterTypeName() { diff --git a/src/applications/conduit/parametertype/ConduitListParameterType.php b/src/applications/conduit/parametertype/ConduitListParameterType.php index 6ec3898ac2..aebadeb175 100644 --- a/src/applications/conduit/parametertype/ConduitListParameterType.php +++ b/src/applications/conduit/parametertype/ConduitListParameterType.php @@ -14,8 +14,8 @@ abstract class ConduitListParameterType return $this->allowEmptyList; } - protected function getParameterValue(array $request, $key) { - $value = parent::getParameterValue($request, $key); + protected function getParameterValue(array $request, $key, $strict) { + $value = parent::getParameterValue($request, $key, $strict); if (!is_array($value)) { $this->raiseValidationException( @@ -48,17 +48,18 @@ abstract class ConduitListParameterType return $value; } - protected function validateStringList(array $request, $key, array $list) { + protected function parseStringList( + array $request, + $key, + array $list, + $strict) { + foreach ($list as $idx => $item) { - if (!is_string($item)) { - $this->raiseValidationException( - $request, - $key, - pht( - 'Expected a list of strings, but item with index "%s" is '. - 'not a string.', - $idx)); - } + $list[$idx] = $this->parseStringValue( + $request, + $key.'['.$idx.']', + $item, + $strict); } return $list; diff --git a/src/applications/conduit/parametertype/ConduitPHIDListParameterType.php b/src/applications/conduit/parametertype/ConduitPHIDListParameterType.php index 60199dbe45..bbe89b6d43 100644 --- a/src/applications/conduit/parametertype/ConduitPHIDListParameterType.php +++ b/src/applications/conduit/parametertype/ConduitPHIDListParameterType.php @@ -3,9 +3,9 @@ final class ConduitPHIDListParameterType extends ConduitListParameterType { - protected function getParameterValue(array $request, $key) { - $list = parent::getParameterValue($request, $key); - return $this->validateStringList($request, $key, $list); + protected function getParameterValue(array $request, $key, $strict) { + $list = parent::getParameterValue($request, $key, $strict); + return $this->parseStringList($request, $key, $list, $strict); } protected function getParameterTypeName() { diff --git a/src/applications/conduit/parametertype/ConduitPHIDParameterType.php b/src/applications/conduit/parametertype/ConduitPHIDParameterType.php index f182758071..3bb45697dc 100644 --- a/src/applications/conduit/parametertype/ConduitPHIDParameterType.php +++ b/src/applications/conduit/parametertype/ConduitPHIDParameterType.php @@ -3,8 +3,8 @@ final class ConduitPHIDParameterType extends ConduitParameterType { - protected function getParameterValue(array $request, $key) { - $value = parent::getParameterValue($request, $key); + protected function getParameterValue(array $request, $key, $strict) { + $value = parent::getParameterValue($request, $key, $strict); if (!is_string($value)) { $this->raiseValidationException( diff --git a/src/applications/conduit/parametertype/ConduitParameterType.php b/src/applications/conduit/parametertype/ConduitParameterType.php index 011401433e..4eca31d96c 100644 --- a/src/applications/conduit/parametertype/ConduitParameterType.php +++ b/src/applications/conduit/parametertype/ConduitParameterType.php @@ -30,12 +30,12 @@ abstract class ConduitParameterType extends Phobject { } - final public function getValue(array $request, $key) { + final public function getValue(array $request, $key, $strict = true) { if (!$this->getExists($request, $key)) { return $this->getParameterDefault(); } - return $this->getParameterValue($request, $key); + return $this->getParameterValue($request, $key, $strict); } final public function getKeys($key) { @@ -85,7 +85,7 @@ abstract class ConduitParameterType extends Phobject { return array_key_exists($key, $request); } - protected function getParameterValue(array $request, $key) { + protected function getParameterValue(array $request, $key, $strict) { return $request[$key]; } @@ -93,6 +93,53 @@ abstract class ConduitParameterType extends Phobject { return array($key); } + protected function parseStringValue(array $request, $key, $value, $strict) { + if (!is_string($value)) { + $this->raiseValidationException( + $request, + $key, + pht('Expected string, got something else.')); + } + return $value; + } + + protected function parseIntValue(array $request, $key, $value, $strict) { + if (!$strict && is_string($value) && ctype_digit($value)) { + $value = $value + 0; + if (!is_int($value)) { + $this->raiseValidationException( + $request, + $key, + pht('Integer overflow.')); + } + } else if (!is_int($value)) { + $this->raiseValidationException( + $request, + $key, + pht('Expected integer, got something else.')); + } + return $value; + } + + protected function parseBoolValue(array $request, $key, $value, $strict) { + $bool_strings = array( + '0' => false, + '1' => true, + 'false' => false, + 'true' => true, + ); + + if (!$strict && is_string($value) && isset($bool_strings[$value])) { + $value = $bool_strings[$value]; + } else if (!is_bool($value)) { + $this->raiseValidationException( + $request, + $key, + pht('Expected boolean (true or false), got something else.')); + } + return $value; + } + abstract protected function getParameterTypeName(); diff --git a/src/applications/conduit/parametertype/ConduitPointsParameterType.php b/src/applications/conduit/parametertype/ConduitPointsParameterType.php index 5b330aabd1..9e5be819f2 100644 --- a/src/applications/conduit/parametertype/ConduitPointsParameterType.php +++ b/src/applications/conduit/parametertype/ConduitPointsParameterType.php @@ -3,8 +3,8 @@ final class ConduitPointsParameterType extends ConduitParameterType { - protected function getParameterValue(array $request, $key) { - $value = parent::getParameterValue($request, $key); + protected function getParameterValue(array $request, $key, $strict) { + $value = parent::getParameterValue($request, $key, $strict); if (($value !== null) && !is_numeric($value)) { $this->raiseValidationException( diff --git a/src/applications/conduit/parametertype/ConduitProjectListParameterType.php b/src/applications/conduit/parametertype/ConduitProjectListParameterType.php index c26db7febf..bd504c7eb4 100644 --- a/src/applications/conduit/parametertype/ConduitProjectListParameterType.php +++ b/src/applications/conduit/parametertype/ConduitProjectListParameterType.php @@ -3,9 +3,9 @@ final class ConduitProjectListParameterType extends ConduitListParameterType { - protected function getParameterValue(array $request, $key) { - $list = parent::getParameterValue($request, $key); - $list = $this->validateStringList($request, $key, $list); + protected function getParameterValue(array $request, $key, $strict) { + $list = parent::getParameterValue($request, $key, $strict); + $list = $this->parseStringList($request, $key, $list, $strict); return id(new PhabricatorProjectPHIDResolver()) ->setViewer($this->getViewer()) ->resolvePHIDs($list); diff --git a/src/applications/conduit/parametertype/ConduitStringListParameterType.php b/src/applications/conduit/parametertype/ConduitStringListParameterType.php index 664a1ded99..20c9389f81 100644 --- a/src/applications/conduit/parametertype/ConduitStringListParameterType.php +++ b/src/applications/conduit/parametertype/ConduitStringListParameterType.php @@ -3,9 +3,9 @@ final class ConduitStringListParameterType extends ConduitListParameterType { - protected function getParameterValue(array $request, $key) { - $list = parent::getParameterValue($request, $key); - return $this->validateStringList($request, $key, $list); + protected function getParameterValue(array $request, $key, $strict) { + $list = parent::getParameterValue($request, $key, $strict); + return $this->parseStringList($request, $key, $list, $strict); } protected function getParameterTypeName() { diff --git a/src/applications/conduit/parametertype/ConduitStringParameterType.php b/src/applications/conduit/parametertype/ConduitStringParameterType.php index b93490fc73..f10f3731e2 100644 --- a/src/applications/conduit/parametertype/ConduitStringParameterType.php +++ b/src/applications/conduit/parametertype/ConduitStringParameterType.php @@ -3,17 +3,9 @@ final class ConduitStringParameterType extends ConduitParameterType { - protected function getParameterValue(array $request, $key) { - $value = parent::getParameterValue($request, $key); - - if (!is_string($value)) { - $this->raiseValidationException( - $request, - $key, - pht('Expected string, got something else.')); - } - - return $value; + protected function getParameterValue(array $request, $key, $strict) { + $value = parent::getParameterValue($request, $key, $strict); + return $this->parseStringValue($request, $key, $value, $strict); } protected function getParameterTypeName() { diff --git a/src/applications/conduit/parametertype/ConduitUserListParameterType.php b/src/applications/conduit/parametertype/ConduitUserListParameterType.php index ad6555146d..85a9095ac5 100644 --- a/src/applications/conduit/parametertype/ConduitUserListParameterType.php +++ b/src/applications/conduit/parametertype/ConduitUserListParameterType.php @@ -3,9 +3,9 @@ final class ConduitUserListParameterType extends ConduitListParameterType { - protected function getParameterValue(array $request, $key) { - $list = parent::getParameterValue($request, $key); - $list = $this->validateStringList($request, $key, $list); + protected function getParameterValue(array $request, $key, $strict) { + $list = parent::getParameterValue($request, $key, $strict); + $list = $this->parseStringList($request, $key, $list, $strict); return id(new PhabricatorUserPHIDResolver()) ->setViewer($this->getViewer()) ->resolvePHIDs($list); diff --git a/src/applications/conduit/parametertype/ConduitUserParameterType.php b/src/applications/conduit/parametertype/ConduitUserParameterType.php index 3590d1a405..ede7f1f466 100644 --- a/src/applications/conduit/parametertype/ConduitUserParameterType.php +++ b/src/applications/conduit/parametertype/ConduitUserParameterType.php @@ -3,8 +3,8 @@ final class ConduitUserParameterType extends ConduitParameterType { - protected function getParameterValue(array $request, $key) { - $value = parent::getParameterValue($request, $key); + protected function getParameterValue(array $request, $key, $strict) { + $value = parent::getParameterValue($request, $key, $strict); if ($value === null) { return null; diff --git a/src/applications/conduit/protocol/ConduitAPIRequest.php b/src/applications/conduit/protocol/ConduitAPIRequest.php index 47cc31fba0..3a2818a47a 100644 --- a/src/applications/conduit/protocol/ConduitAPIRequest.php +++ b/src/applications/conduit/protocol/ConduitAPIRequest.php @@ -6,9 +6,11 @@ final class ConduitAPIRequest extends Phobject { private $user; private $isClusterRequest = false; private $oauthToken; + private $isStrictlyTyped = true; - public function __construct(array $params) { + public function __construct(array $params, $strictly_typed) { $this->params = $params; + $this->isStrictlyTyped = $strictly_typed; } public function getValue($key, $default = null) { @@ -68,6 +70,10 @@ final class ConduitAPIRequest extends Phobject { return $this->isClusterRequest; } + public function getIsStrictlyTyped() { + return $this->isStrictlyTyped; + } + public function newContentSource() { return PhabricatorContentSource::newForSource( PhabricatorConduitContentSource::SOURCECONST); diff --git a/src/applications/search/engine/PhabricatorApplicationSearchEngine.php b/src/applications/search/engine/PhabricatorApplicationSearchEngine.php index a1279ad8ae..221703b7fd 100644 --- a/src/applications/search/engine/PhabricatorApplicationSearchEngine.php +++ b/src/applications/search/engine/PhabricatorApplicationSearchEngine.php @@ -1115,7 +1115,9 @@ abstract class PhabricatorApplicationSearchEngine extends Phobject { continue; } - $value = $field->readValueFromConduitRequest($constraints); + $value = $field->readValueFromConduitRequest( + $constraints, + $request->getIsStrictlyTyped()); $saved_query->setParameter($field->getKey(), $value); } diff --git a/src/applications/search/field/PhabricatorSearchField.php b/src/applications/search/field/PhabricatorSearchField.php index d31aeb1950..f45befead6 100644 --- a/src/applications/search/field/PhabricatorSearchField.php +++ b/src/applications/search/field/PhabricatorSearchField.php @@ -323,10 +323,14 @@ abstract class PhabricatorSearchField extends Phobject { $this->getConduitKey()); } - public function readValueFromConduitRequest(array $constraints) { + public function readValueFromConduitRequest( + array $constraints, + $strict = true) { + return $this->getConduitParameterType()->getValue( $constraints, - $this->getConduitKey()); + $this->getConduitKey(), + $strict); } public function getValidConstraintKeys() { diff --git a/src/applications/transactions/editengine/PhabricatorEditEngine.php b/src/applications/transactions/editengine/PhabricatorEditEngine.php index 2805162336..8a71509c99 100644 --- a/src/applications/transactions/editengine/PhabricatorEditEngine.php +++ b/src/applications/transactions/editengine/PhabricatorEditEngine.php @@ -1903,7 +1903,10 @@ abstract class PhabricatorEditEngine $parameter_type->setViewer($viewer); try { - $xaction['value'] = $parameter_type->getValue($xaction, 'value'); + $xaction['value'] = $parameter_type->getValue( + $xaction, + 'value', + $request->getIsStrictlyTyped()); } catch (Exception $ex) { throw new PhutilProxyException( pht(