Browse Source

Merge pull request #2038 from yann300/bugFix2

Mix - Add validation for input parameters
cl-refactor
Gav Wood 10 years ago
parent
commit
1c13824cb8
  1. 35
      mix/QBigInt.cpp
  2. 3
      mix/QBigInt.h
  3. 1
      mix/qml.qrc
  4. 7
      mix/qml/QIntTypeView.qml
  5. 23
      mix/qml/TransactionDialog.qml
  6. 125
      mix/qml/js/InputValidator.js

35
mix/QBigInt.cpp

@ -57,3 +57,38 @@ QBigInt* QBigInt::divide(QBigInt* const& _value) const
BigIntVariant toDivide = _value->internalValue(); BigIntVariant toDivide = _value->internalValue();
return new QBigInt(boost::apply_visitor(mix::divide(), m_internalValue, toDivide)); return new QBigInt(boost::apply_visitor(mix::divide(), m_internalValue, toDivide));
} }
QVariantMap QBigInt::checkAgainst(QString const& _type) const
{
QVariantMap ret;
QString type = _type;
QString capacity = type.replace("uint", "").replace("int", "");
if (capacity.isEmpty())
capacity = "256";
bigint range = 256^(capacity.toInt() / 8);
bigint value = boost::get<bigint>(this->internalValue());
ret.insert("valid", true);
if (_type.startsWith("uint") && value > range - 1)
{
ret.insert("minValue", "0");
std::ostringstream s;
s << range - 1;
ret.insert("maxValue", QString::fromStdString(s.str()));
if (value > range)
ret["valid"] = false;
}
else if (_type.startsWith("int"))
{
range = range / 2;
std::ostringstream s;
s << -range;
ret.insert("minValue", QString::fromStdString(s.str()));
s.str("");
s.clear();
s << range - 1;
ret.insert("maxValue", QString::fromStdString(s.str()));
if (-range > value || value > range - 1)
ret["valid"] = false;
}
return ret;
}

3
mix/QBigInt.h

@ -84,6 +84,7 @@ public:
Q_INVOKABLE QString value() const; Q_INVOKABLE QString value() const;
/// Set the value of the BigInteger used. Will use u256 type. Invokable from QML. /// Set the value of the BigInteger used. Will use u256 type. Invokable from QML.
Q_INVOKABLE void setValue(QString const& _value) { m_internalValue = dev::jsToU256(_value.toStdString()); } Q_INVOKABLE void setValue(QString const& _value) { m_internalValue = dev::jsToU256(_value.toStdString()); }
Q_INVOKABLE void setBigInt(QString const& _value) { m_internalValue = bigint(_value.toStdString()); }
/// Subtract by @a _value. Invokable from QML. /// Subtract by @a _value. Invokable from QML.
Q_INVOKABLE QBigInt* subtract(QBigInt* const& _value) const; Q_INVOKABLE QBigInt* subtract(QBigInt* const& _value) const;
/// Add @a _value to the current big integer. Invokable from QML. /// Add @a _value to the current big integer. Invokable from QML.
@ -92,6 +93,8 @@ public:
Q_INVOKABLE QBigInt* multiply(QBigInt* const& _value) const; Q_INVOKABLE QBigInt* multiply(QBigInt* const& _value) const;
/// divide by @a _value. Invokable from QML. /// divide by @a _value. Invokable from QML.
Q_INVOKABLE QBigInt* divide(QBigInt* const& _value) const; Q_INVOKABLE QBigInt* divide(QBigInt* const& _value) const;
/// check if the current value satisfy the given type
Q_INVOKABLE QVariantMap checkAgainst(QString const& _type) const;
protected: protected:
BigIntVariant m_internalValue; BigIntVariant m_internalValue;

1
mix/qml.qrc

@ -63,5 +63,6 @@
<file>qml/js/Printer.js</file> <file>qml/js/Printer.js</file>
<file>qml/js/ansi2html.js</file> <file>qml/js/ansi2html.js</file>
<file>qml/js/NetworkDeployment.js</file> <file>qml/js/NetworkDeployment.js</file>
<file>qml/js/InputValidator.js</file>
</qresource> </qresource>
</RCC> </RCC>

7
mix/qml/QIntTypeView.qml

@ -21,8 +21,15 @@ Item
clip: true clip: true
selectByMouse: true selectByMouse: true
text: value text: value
anchors.fill: parent
font.pointSize: dbgStyle.general.basicFontSize font.pointSize: dbgStyle.general.basicFontSize
color: dbgStyle.general.basicColor color: dbgStyle.general.basicColor
MouseArea {
id: mouseArea
anchors.fill: parent
hoverEnabled: true
onClicked: textinput.forceActiveFocus()
}
} }
} }
} }

23
mix/qml/TransactionDialog.qml

@ -6,6 +6,7 @@ import QtQuick.Window 2.0
import QtQuick.Controls.Styles 1.3 import QtQuick.Controls.Styles 1.3
import org.ethereum.qml.QEther 1.0 import org.ethereum.qml.QEther 1.0
import "js/TransactionHelper.js" as TransactionHelper import "js/TransactionHelper.js" as TransactionHelper
import "js/InputValidator.js" as InputValidator
import "." import "."
Dialog { Dialog {
@ -503,10 +504,22 @@ Dialog {
anchors.right: parent.right; anchors.right: parent.right;
Button { Button {
text: qsTr("OK"); text: qsTr("OK");
onClicked: { onClicked: {
close(); var invalid = InputValidator.validate(paramsModel, paramValues);
accepted(); if (invalid.length === 0)
{
close();
accepted();
}
else
{
errorDialog.text = qsTr("Some parameters are invalid:\n");
for (var k in invalid)
errorDialog.text += invalid[k].message + "\n";
errorDialog.open();
}
} }
} }
@ -514,6 +527,12 @@ Dialog {
text: qsTr("Cancel"); text: qsTr("Cancel");
onClicked: close(); onClicked: close();
} }
MessageDialog {
id: errorDialog
standardButtons: StandardButton.Ok
icon: StandardIcon.Critical
}
} }
} }
} }

125
mix/qml/js/InputValidator.js

@ -0,0 +1,125 @@
Qt.include("QEtherHelper.js")
var nbRegEx = new RegExp('^[0-9]+$');
function validate(model, values)
{
var inError = [];
for (var k in model)
{
if (values[model[k].name])
{
var type = model[k].type.name;
var res;
if (isContractType(type))
res = validateAddress(type, values[model[k].name]);
else if (type.indexOf("int") !== -1)
res = validateInt(type, values[model[k].name]);
else if (type.indexOf("bytes") !== -1)
res = validateBytes(type, values[model[k].name]);
else if (type.indexOf("bool") !== -1)
res = validateBool(type, values[model[k].name]);
else if (type.indexOf("address") !== -1)
res = validateAddress(type, values[model[k].name]);
else
res.valid = true;
if (!res.valid)
inError.push({ type: type, value: values, message: res.message });
}
}
return inError;
}
function isContractType(_type)
{
for (var k in Object.keys(codeModel.contracts))
{
if ("contract " + Object.keys(codeModel.contracts)[k] === _type)
return true;
}
return false;
}
function validateInt(_type, _value)
{
var ret = { valid: true, message: "" }
if (_value.indexOf("-") === 0)
{
_value = _value.substring(1);
if (_type.indexOf("uint") === -1)
{
ret.valid = false;
ret.message = "uint type cannot represent negative number";
}
}
ret.valid = nbRegEx.test(_value);
if (!ret.valid)
ret.message = _value + " does not represent " + _type + " type.";
else
{
var bigInt = createBigInt(_value);
bigInt.setBigInt(_value);
var result = bigInt.checkAgainst(_type);
if (!result.valid)
{
ret.valid = false;
ret.message = _type + " should be between " + result.minValue + " and " + result.maxValue;
}
}
return ret;
}
function validateAddress(_type, _value)
{
var ret = { valid: true, message: "" }
if (_value.indexOf("<") === 0 && _value.indexOf(">") === _value.length - 1)
{
var v = _value.split(' - ');
if (v.length !== 2 || !nbRegEx.test(v[1].replace(">", ""))) // <Contract - 2>
{
ret.valid = false;
ret.message = _value + " is not a valid token for address type.";
}
}
else if (_value.indexOf("0x") !== 0)
{
ret.valid = false
ret.message = "Address type should start with 0x.";
}
else
{
_value = _value.substring(2);
if (_value.length !== 40)
{
ret.valid = false
ret.message = "Address type should contain 40 characters.";
}
}
return ret;
}
function validateBytes(_type, _value)
{
var ret = { valid: true, message: "" }
if (_value.length > parseInt(_type.replace("bytes", "")) )
{
ret.valid = false;
ret.message = _type + " should not contains more than " + _type.replace("bytes", "") + " characters";
}
return ret;
}
function validateBool(_type, _value)
{
var ret = { valid: true, message: "" }
if (_value !== "1" && _value !== "0")
{
ret.valid = false;
ret.message = _value + " is not in the correct bool format";
}
return ret;
}
function validateEnum(_type, _value)
{
}
Loading…
Cancel
Save