diff --git a/src/Controller/StateErrorsController.php b/src/Controller/StateErrorsController.php index 2932b80e6..37d37bdda 100644 --- a/src/Controller/StateErrorsController.php +++ b/src/Controller/StateErrorsController.php @@ -49,7 +49,7 @@ class StateErrorsController extends AppController } $errors = $this->StateErrors->find('all')->where(['state_user_id' => $user['id']])->contain(false); - $transactionTypes = $this->StateErrors->TransactionTypes->find('all')->select(['id', 'name', 'text']); + $transactionTypes = $this->StateErrors->TransactionTypes->find('all')->select(['id', 'name', 'text'])->order(['id']); $this->set('errors', $errors); $this->set('transactionTypes', $transactionTypes->toList()); diff --git a/src/Model/Transactions/TransactionTransfer.php b/src/Model/Transactions/TransactionTransfer.php index 82ec9da9f..085d13908 100644 --- a/src/Model/Transactions/TransactionTransfer.php +++ b/src/Model/Transactions/TransactionTransfer.php @@ -3,11 +3,10 @@ namespace Model\Transactions; //use App\Model\Transactions\TransactionBase; +use Cake\ORM\TableRegistry; class TransactionTransfer extends TransactionBase { private $protoTransactionTransfer; - private $receiver_pubkey_hex; - private $sender_pubkey_hex; public function __construct($protoTransactionTransfer) { $this->protoTransactionTransfer = $protoTransactionTransfer; @@ -50,9 +49,107 @@ class TransactionTransfer extends TransactionBase { } public function validate($sigPairs) { - $this->addError('TransactionTransfer::validate', 'not implemented yet'); - return false; - //return true; + //$this->addError('TransactionTransfer::validate', 'not implemented yet'); + //return false; + //$time = microtime(true); + static $functionName = 'TransactionCreation::validate'; + /* + * // check signature(s) + foreach($sigPairs as $sigPair) { + //echo 'sig Pair: '; var_dump($sigPair); echo "
"; + $pubkey = $sigPair->getPubKey(); + $signature = $sigPair->getEd25519(); + if (!\Sodium\crypto_sign_verify_detached($signature, $bodyBytes, $pubkey)) { + $this->addError('Transaction::validate', 'signature for key ' . bin2hex($pubkey) . ' isn\'t valid ' ); + return false; + } + } + */ + $sigPubHexs = []; + foreach($sigPairs as $sigPair) { + //echo 'sig Pair: '; var_dump($sigPair); echo "
"; + $pubkey = bin2hex($sigPair->getPubKey()); + $hash = TransactionCreation::DRMakeStringHash($pubkey); + if(!isset($sigPubHexs[$hash])) { + $sigPubHexs[$hash] = [$pubkey]; + } else { + array_push($sigPubHexs[$hash], $pubkey); + } + //array_push($sigPubHexs, $pubkey); + } + + $stateUsersTable = TableRegistry::getTableLocator()->get('state_users'); + $senderAmounts = $this->protoTransactionTransfer->getSenderAmounts(); + $senderSum = 0; + $receiverSum = 0; + + $senderPublics = []; + foreach($senderAmounts as $i => $senderAmount) { + $senderPublic = $senderAmount->getEd25519SenderPubkey(); + $senderPublicHex = bin2hex($senderPublic); + array_push($senderPublics, $senderPublic); + + if(strlen($senderPublicHex) != 64) { + $this->addError($functionName, 'invalid sender public key'); + return false; + } + // check if signature exist for sender + $hash = TransactionCreation::DRMakeStringHash($senderPublicHex); + if(!isset($sigPubHexs[$hash]) || in_array($senderPublicHex, $sigPubHexs[$hash]) === FALSE) { + $this->addError($functionName, 'missing signature for sender'); + return false; + } + // check if sender has enough Gradido + $amount = $senderAmount->getAmount(); + $user = $stateUsersTable + ->find('all') + ->select(['id']) + ->where(['public_key' => $senderPublic]) + ->contain(['StateBalances' => ['fields' => ['amount', 'state_user_id']]])->first(); + if(!$user) { + $this->addError($functionName, 'couldn\'t find sender ' . $i .' in db' ); + return false; + } + //var_dump($user); + if(intval($user->state_balances[0]->amount) < intval($amount)) { + $this->addError($functionName, 'sender ' . $i . ' hasn\t enough GDD'); + return false; + } + $senderSum += $amount; + } + $uniqueSenderPublics = array_unique($senderPublics); + if(count($senderPublics) !== count($uniqueSenderPublics)) { + $this->addError($functionName, 'duplicate sender public key'); + return false; + } + + $receiverAmounts = $this->protoTransactionTransfer->getReceiverAmounts(); + $receiverPublics = []; + foreach($receiverAmounts as $reveiverAmount) { + if(strlen($reveiverAmount->getEd25519ReceiverPubkey()) != 32) { + $this->addError($functionName, 'invalid receiver public key'); + return false; + } + array_push($receiverPublics, $reveiverAmount->getEd25519ReceiverPubkey()); + $receiverSum += $reveiverAmount->getAmount(); + } + $uniqueReceiverPublic = array_unique($receiverPublics); + if(count($uniqueReceiverPublic) !== count($receiverPublics)) { + $this->addError($functionName, 'duplicate receiver public key'); + return false; + } + $uniquePublics = array_unique(array_merge($receiverPublics, $senderPublics)); + if(count($uniquePublics) !== count($senderPublics) + count($receiverPublics)) { + // means at least one sender is the same as one receiver + $this->addError($functionName, 'duplicate public in sender and receiver'); + return false; + } + if($senderSum !== $receiverSum) { + $this->addError($functionName, 'sender amount doesn\'t match receiver amount'); + return false; + } + //die("\n"); + return true; } public function save($transaction_id, $firstPublic) { diff --git a/src/Template/StateErrors/show_for_user.ctp b/src/Template/StateErrors/show_for_user.ctp index d3119079c..d2dda0562 100644 --- a/src/Template/StateErrors/show_for_user.ctp +++ b/src/Template/StateErrors/show_for_user.ctp @@ -21,11 +21,25 @@ $this->assign('title', __('Fehlermeldungen')); transaction_type_id]; ?> + $type = $transactionTypes[$error->transaction_type_id-1]; + $errorMessage = ""; + $errorArray = json_decode($error->message_json, true); + if(isset($errorArray['details'])) { + + foreach($errorArray['details'][0] as $function => $errorString) { + $errorMessage = '' . $function . '
' . $errorString; + } + + } else { + $errorMessage = $error->message_json; + } + + + ?> name ?> created ?> - message_json ?> + Html->link(__('Delete'), ['action' => 'deleteForUser', $error->id], ['class' => 'grd-form-bn grd-form-bn-discard']) ?> diff --git a/tests/Fixture/StateBalancesFixture.php b/tests/Fixture/StateBalancesFixture.php index 8db926511..64118f3ed 100644 --- a/tests/Fixture/StateBalancesFixture.php +++ b/tests/Fixture/StateBalancesFixture.php @@ -42,6 +42,12 @@ class StateBalancesFixture extends TestFixture 'modified' => '2019-11-05 18:02:28', 'amount' => 1200 ], + [ + 'id' => 10, + 'state_user_id' => 4, + 'modified' => '2019-11-11 14:58:54', + 'amount' => 1200000 + ] ]; parent::init(); } diff --git a/tests/Fixture/StateUsersFixture.php b/tests/Fixture/StateUsersFixture.php index 28e03e3f3..04654dea9 100644 --- a/tests/Fixture/StateUsersFixture.php +++ b/tests/Fixture/StateUsersFixture.php @@ -49,6 +49,15 @@ class StateUsersFixture extends TestFixture 'first_name' => 'Dario', 'last_name' => 'Rekowski' ], + [ + 'id' => 4, + 'index_id' => 0, + 'group_id' => 0, + 'public_key' => hex2bin('8190bda585ee5f1d9fbf7d06e81e69ec18e13376104cff54b7457eb7d3ef710d'), + 'email' => 'dariofrodo@gmx.de', + 'first_name' => 'Dario', + 'last_name' => 'Frodo' + ], [ 'id' => 11, 'index_id' => 0, diff --git a/tests/TestCase/Controller/TransactionJsonRequestHandlerControllerTest.php b/tests/TestCase/Controller/TransactionJsonRequestHandlerControllerTest.php index 01946fedb..b9b0cc513 100644 --- a/tests/TestCase/Controller/TransactionJsonRequestHandlerControllerTest.php +++ b/tests/TestCase/Controller/TransactionJsonRequestHandlerControllerTest.php @@ -23,6 +23,7 @@ class TransactionJsonRequestHandlerControllerTest extends TestCase 'app.TransactionCreations', 'app.Transactions', 'app.StateUsers', + 'app.StateErrors', 'app.TransactionSignatures', 'app.TransactionSendCoins', 'app.StateBalances', @@ -33,7 +34,8 @@ class TransactionJsonRequestHandlerControllerTest extends TestCase 'validCreation' => 'GmYKZAogYbkjwhjLY6ZKjGLzhgEhKDuVd_N00KMVkLoCzcKRKZkSQJ8wF12eZo3hcMAlAKKJ9WLT-zuSkNmGh7D98UEqH4KoIysnCkXqEya9EBZl9o11_nJ8xmm_nOevuVjR-GfLMQ8qSQoOSGFsbG8gV2VsdCAxMjMSBgiZm4ruBUovCicKIJSuE1uTzZ8zdStOVcQZA6P6oTp1u5C_1BHqHUoaXnEfEKDakwEQtYntlgo', 'validCreation900' => 'GmYKZAogYbkjwhjLY6ZKjGLzhgEhKDuVd_N00KMVkLoCzcKRKZkSQNVZ8Ae3Zbg3G0wZ840fzKan6N4KtTcSe0KYi17kQwFmsl18oFxXv8_s6j1xXFrIKjy1_1Olq0a7xYLErDMkjwYqORIGCNb5iu4FSi8KJwoglK4TW5PNnzN1K05VxBkDo_qhOnW7kL_UEeodShpecR8QgNHKCBC1ie2WCg', 'validCreation1200' => 'GmYKZAogYbkjwhjLY6ZKjGLzhgEhKDuVd_N00KMVkLoCzcKRKZkSQEEey5QMAdldoOTP_jTETHgOQriGsixEY0cziQeRfT_J5YtbI_A6AizEYD-JcxmRmXzv1xjjTgsV39Y32ta2CQkqORIGCIeGi-4FSi8KJwoglK4TW5PNnzN1K05VxBkDo_qhOnW7kL_UEeodShpecR8QgOy4CxC1ie2WCg', - 'notBase64' => 'CgpIYWxsbyBXZW-0EgYIyfSG7gV_LwonCiCboKikqwjZfes9xuqgthFH3' + 'notBase64' => 'CgpIYWxsbyBXZW-0EgYIyfSG7gV_LwonCiCboKikqwjZfes9xuqgthFH3', + 'validTransfer' => 'GmYKZAoggZC9pYXuXx2fv30G6B5p7BjhM3YQTP9Ut0V-t9PvcQ0SQDddHyKzAX3LBV0PuDiPc6lxkUipss5tyuLRpMtFJQnT30tsbYIkA1FXimjMKOoiuLswf4OLLV3bAIYehW-b9AgqYQoFSGFsbG8SBgiJlaPvBUJQCiYKIIGQvaWF7l8dn799BugeaewY4TN2EEz_VLdFfrfT73ENEICfSRImCiDtdleSLxhUgEbMW9DpqIwsykFj3-z_enKEOuGnXrmW8xCAn0k' ]; /*public function setUp() { @@ -125,6 +127,14 @@ class TransactionJsonRequestHandlerControllerTest extends TestCase ); } + public function testValidTransfer() + { + $this->postAndParse( + ['method' => 'putTransaction', 'transaction' => $this->transactions['validTransfer']], + ['state' => 'success'] + ); + } + /*public function testMissingPreviousTransaction() {