diff --git a/src/applications/conduit/call/ConduitCall.php b/src/applications/conduit/call/ConduitCall.php --- a/src/applications/conduit/call/ConduitCall.php +++ b/src/applications/conduit/call/ConduitCall.php @@ -15,7 +15,7 @@ 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 @@ "'".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 --- a/src/applications/conduit/controller/PhabricatorConduitAPIController.php +++ b/src/applications/conduit/controller/PhabricatorConduitAPIController.php @@ -25,9 +25,11 @@ 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 @@ $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 @@ $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 @@ } } - 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 --- 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 --- 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 --- 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 --- 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 --- 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 --- a/src/applications/conduit/parametertype/ConduitListParameterType.php +++ b/src/applications/conduit/parametertype/ConduitListParameterType.php @@ -14,8 +14,8 @@ 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 @@ 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 --- 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 --- 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 --- a/src/applications/conduit/parametertype/ConduitParameterType.php +++ b/src/applications/conduit/parametertype/ConduitParameterType.php @@ -30,12 +30,12 @@ } - 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 @@ 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 @@ 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 --- 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 --- 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 --- 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 --- 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 --- 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 --- 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 --- a/src/applications/conduit/protocol/ConduitAPIRequest.php +++ b/src/applications/conduit/protocol/ConduitAPIRequest.php @@ -6,9 +6,11 @@ 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 @@ 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 --- a/src/applications/search/engine/PhabricatorApplicationSearchEngine.php +++ b/src/applications/search/engine/PhabricatorApplicationSearchEngine.php @@ -1115,7 +1115,9 @@ 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 --- a/src/applications/search/field/PhabricatorSearchField.php +++ b/src/applications/search/field/PhabricatorSearchField.php @@ -323,10 +323,14 @@ $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 --- a/src/applications/transactions/editengine/PhabricatorEditEngine.php +++ b/src/applications/transactions/editengine/PhabricatorEditEngine.php @@ -1903,7 +1903,10 @@ $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(