diff --git a/src/Controller/DashboardController.php b/src/Controller/DashboardController.php index 206277509..fc7365d66 100644 --- a/src/Controller/DashboardController.php +++ b/src/Controller/DashboardController.php @@ -79,6 +79,14 @@ class DashboardController extends AppController $stateUserQuery = $stateUserTable->find('all')->where(['public_key' => $public_key_bin]); if($stateUserQuery->count() == 1) { $stateUser = $stateUserQuery->first(); + if($stateUser->first_name != $json['user']['first_name'] || + $stateUser->last_name != $json['user']['last_name']) { + $stateUser->first_name = $json['user']['first_name']; + $stateUser->last_name = $json['user']['last_name']; + if(!$stateUserTable->save($stateUser)) { + $this->Flash->error(__('error updating state user ' . json_encode($stateUser->errors()))); + } + } $session->write('StateUser.id', $stateUser['id']); //echo $stateUser['id']; } else { @@ -86,7 +94,9 @@ class DashboardController extends AppController $newStateUser->public_key = $public_key_bin; $newStateUser->first_name = $json['user']['first_name']; $newStateUser->last_name = $json['user']['last_name']; - $stateUserTable->save($newStateUser); + if(!$stateUserTable->save($newStateUser)) { + $this->Flash->error(__('error saving state user ' . json_encode($newStateUser->errors()))); + } $session->write('StateUser.id', $newStateUser->id); //echo $newStateUser->id; } diff --git a/src/Model/Entity/StateUser.php b/src/Model/Entity/StateUser.php index 59bd19e9a..a6e8c40da 100644 --- a/src/Model/Entity/StateUser.php +++ b/src/Model/Entity/StateUser.php @@ -33,6 +33,9 @@ class StateUser extends Entity 'index_id' => true, 'state_group_id' => true, 'public_key' => true, + 'email' => true, + 'first_name' => true, + 'last_name' => true, 'index' => true, 'state_group' => true, 'state_balances' => true, diff --git a/src/Model/Entity/Transaction.php b/src/Model/Entity/Transaction.php index 98948adae..d4ebf68c4 100644 --- a/src/Model/Entity/Transaction.php +++ b/src/Model/Entity/Transaction.php @@ -37,6 +37,7 @@ class Transaction extends Entity 'state_group_id' => true, 'transaction_type_id' => true, 'tx_hash' => true, + 'memo' => true, 'received' => true, 'state_group' => true, 'transaction_type' => true, diff --git a/src/Model/Table/TransactionsTable.php b/src/Model/Table/TransactionsTable.php index 99c2473b8..75659a5b2 100644 --- a/src/Model/Table/TransactionsTable.php +++ b/src/Model/Table/TransactionsTable.php @@ -87,8 +87,11 @@ class TransactionsTable extends Table ->allowEmptyString('id', null, 'create'); $validator - ->requirePresence('tx_hash', 'create') - ->notEmptyString('tx_hash'); + //->requirePresence('tx_hash', 'create') + ->allowEmptyString('tx_hash', null, 'create'); + + $validator + ->allowEmptyString('memo', null, 'create'); $validator ->dateTime('received') diff --git a/src/Model/Transactions/Transaction.php b/src/Model/Transactions/Transaction.php index eb818f38b..eae0546fc 100644 --- a/src/Model/Transactions/Transaction.php +++ b/src/Model/Transactions/Transaction.php @@ -10,57 +10,115 @@ namespace Model\Transactions; //use Model\Messages\Gradido\Transaction; //use Model\Messages\Gradido\TransactionBody; +use Cake\ORM\TableRegistry; +use Cake\Datasource\ConnectionManager; class Transaction extends TransactionBase { private $mProtoTransaction = null; - private $mProtoTransactionBody = null; - private $errors = []; + private $mTransactionBody = null; public function __construct($base64Data) { $transactionBin = base64_decode($base64Data); if($transactionBin == FALSE) { //$this->addError('base64 decode failed'); - $this->addError(['data' => $base64Data, 'bin' => $transactionBin, 'msg' => 'base64 decode error']); + $this->addError('Transaction', ['data' => $base64Data, 'bin' => $transactionBin, 'msg' => 'base64 decode error']); } else { $this->mProtoTransaction = new \Model\Messages\Gradido\Transaction(); $this->mProtoTransaction->mergeFromString($transactionBin); + //echo 'serialize to json:
'; + //echo $this->mProtoTransaction->serializeToJsonString(); - $this->mProtoTransactionBody = new \Model\Messages\Gradido\TransactionBody(); - $this->mProtoTransactionBody->mergeFromString($this->mProtoTransaction->getBodyBytes()); - - $data = $this->mProtoTransactionBody->getData(); - var_dump($data); + $this->mTransactionBody = new TransactionBody($this->mProtoTransaction->getBodyBytes()); } } + public function getTransactionBody() { + return $this->mTransactionBody; + } + + public function getFirstPublic() { + $sigPairs = $this->mProtoTransaction->getSigMap()->getSigPair(); + return $sigPairs[0]->getPubKey(); + } + public function validate() { $sigPairs = $this->mProtoTransaction->getSigMap()->getSigPair(); $bodyBytes = $this->mProtoTransaction->getBodyBytes(); + + if(!$sigPairs || count($sigPairs) < 1) { + $this->addError('Transaction::validate', 'no signature found'); + return false; + } + // 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('signature for key ' . bin2hex($pubkey) . ' isn\'t valid ' ); + $this->addError('Transaction::validate', 'signature for key ' . bin2hex($pubkey) . ' isn\'t valid ' ); return false; } } + if(!$this->mTransactionBody->validate($sigPairs)) { + $this->addErrors($this->mTransactionBody->getErrors()); + return false; + } + return true; } - public function getErrors() { - return $this->errors; + public function save() + { + $connection = ConnectionManager::get('default'); + $connection->begin(); + //id transaction_id signature pubkey + + if (!$this->mTransactionBody->save($this->getFirstPublic())) { + $this->addErrors($this->mTransactionBody->getErrors()); + $connection->rollback(); + return false; + } + + // save transaction signatures + $transactionsSignaturesTable = TableRegistry::getTableLocator()->get('transaction_signatures'); + $transactionId = $this->mTransactionBody->getTransactionID(); + //signature pubkey + + $sigPairs = $this->mProtoTransaction->getSigMap()->getSigPair(); + echo "sigPairs: "; var_dump($sigPairs); + $signatureEntitys = []; + foreach($sigPairs as $sigPair) { + $signatureEntity = $transactionsSignaturesTable->newEntity(); + + $signatureEntity->transaction_id = $transactionId; + $signatureEntity->signature = $sigPair->getEd25519(); + $signatureEntity->pubkey = $sigPair->getPubKey(); + array_push($signatureEntitys, $signatureEntity); + } + //debug($signatureEntitys); + if(!$transactionsSignaturesTable->saveMany($signatureEntitys)) { + foreach($signatureEntitys as $entity) { + $errors = $entity->getErrors(); + if(!$errors && count($errors) > 0) { + $pubkeyHex = bin2hex($entity->pubkey); + $this->addError('Transaction::save', 'error saving signature for pubkey: ' . $pubkeyHex . ', with errors: ' . json_encode($errors) ); + } + } + $connection->rollback(); + return false; + } + + $connection->commit(); + return true; } + + + - public function hasErrors() { - return count($this->errors) > 0; - } - - private function addError($message) { - array_push($this->errors, $message); - } + } \ No newline at end of file diff --git a/src/Model/Transactions/TransactionBase.php b/src/Model/Transactions/TransactionBase.php index c9ba5cdcd..e8f299216 100644 --- a/src/Model/Transactions/TransactionBase.php +++ b/src/Model/Transactions/TransactionBase.php @@ -2,6 +2,42 @@ namespace Model\Transactions; +use Cake\ORM\TableRegistry; + class TransactionBase { + private $errors = []; + public function getErrors() { + return errors; + } + + public function addError($functionName, $errorName) { + array_push($this->errors, [$functionName => $errorName]); + } + + public function addErrors($errors) { + $this->errors = array_merge($this->errors, $errors); + } + + public function hasErrors() { + return count($this->errors) > 0; + } + + protected function getStateUserId($publicKey) { + $stateUsersTable = TableRegistry::getTableLocator()->get('state_users'); + $stateUser = $stateUsersTable->find('all')->select(['id'])->where(['public_key' => $publicKey])->first(); + if($stateUser) { + return $stateUser->id; + } + // create new entry + $stateUserEntity = $stateUsersTable->newEntity(); + $stateUserEntity->public_key = $publicKey; + if($stateUsersTable->save($stateUserEntity)) { + return $stateUserEntity->id; + } else { + $this->addError('TransactionBase::getStateUserId', 'error saving new state user with error: ' . json_encode($stateUserEntity->getErrors())); + } + + return NULL; + } } \ No newline at end of file diff --git a/src/Model/Transactions/TransactionBody.php b/src/Model/Transactions/TransactionBody.php index 175552736..943e46dc8 100644 --- a/src/Model/Transactions/TransactionBody.php +++ b/src/Model/Transactions/TransactionBody.php @@ -2,6 +2,76 @@ namespace Model\Transactions; +use Cake\ORM\TableRegistry; + class TransactionBody extends TransactionBase { + private $mProtoTransactionBody = null; + private $mSpecificTransaction = null; + private $mTransactionID = 0; + + public function __construct($bodyBytes) { + $this->mProtoTransactionBody = new \Model\Messages\Gradido\TransactionBody(); + $this->mProtoTransactionBody->mergeFromString($bodyBytes); + switch($this->mProtoTransactionBody->getData()) { + case 'creation' : $this->mSpecificTransaction = new TransactionCreation($this->mProtoTransactionBody->getCreation()); break; + case 'transfer' : $this->mSpecificTransaction = new TransactionTransfer($this->mProtoTransactionBody->getTransfer()); break; + } + } + + public function validate($sigPairs) { + if(!$this->mSpecificTransaction->validate($sigPairs)) { + $this->addErrors($this->mSpecificTransaction->getErrors()); + return false; + } + return true; + } + + public function getSpecificTransaction() { + return $this->mSpecificTransaction; + } + + public function getMemo() { + return $this->mProtoTransactionBody->getMemo(); + } + + public function getTransactionTypeName() + { + return $this->mProtoTransactionBody->getData(); + } + + public function save($firstPublic) { + $transactionsTable = TableRegistry::getTableLocator()->get('transactions'); + $transactionEntity = $transactionsTable->newEntity(); + + // transaction type id + $transactionTypesTable = TableRegistry::getTableLocator()->get('transaction_types'); + + $typeName = $this->getTransactionTypeName(); + $transactionType = $transactionTypesTable->find('all')->where(['name' => $typeName])->select(['id'])->first(); + if($transactionType == NULL) { + $this->addError('TransactionBody::save', 'zero type id for type: ' . $typeName); + return false; + } + $transactionEntity->transaction_type_id = $transactionType->id; + $transactionEntity->memo = $this->getMemo(); + + if ($transactionsTable->save($transactionEntity)) { + // success + $this->mTransactionID = $transactionEntity->id; + if(!$this->mSpecificTransaction->save($transactionEntity->id, $firstPublic)) { + $this->addErrors($this->mSpecificTransaction->getErrors()); + return false; + } + } else { + $this->addError('TransactionBody::save', 'error saving transaction with: ' . json_encode($transactionEntity->getError())); + return false; + } + return true; + } + + public function getTransactionID() { + return $this->mTransactionID; + } + } diff --git a/src/Model/Transactions/TransactionCreation.php b/src/Model/Transactions/TransactionCreation.php index 4f60849f2..554f9ce00 100644 --- a/src/Model/Transactions/TransactionCreation.php +++ b/src/Model/Transactions/TransactionCreation.php @@ -4,6 +4,76 @@ namespace Model\Transactions; //use App\Model\Transactions\TransactionBase; +use Cake\ORM\TableRegistry; + class TransactionCreation extends TransactionBase { + private $protoTransactionCreation; + private $transactionCreationsTable; + + public function __construct($protoTransactionCreation) { + $this->protoTransactionCreation = $protoTransactionCreation; + $this->transactionCreationsTable = TableRegistry::getTableLocator()->get('transaction_creations'); + } + + public function getAmount() { + return $this->protoTransactionCreation->getReceiverAmount()->getAmount(); + } + + public function getReceiverPublic() { + return $this->protoTransactionCreation->getReceiverAmount()->getEd25519ReceiverPubkey(); + } + + public function getIdentHash() { + return $this->protoTransactionCreation->getIdentHash(); + } + + public function validate($sigPairs) { + // check if receiver public is not in signature list + $receiverPublic = $this->getReceiverPublic(); + foreach($sigPairs as $sigPair) { + $pubkey = $sigPair->getPubKey(); + if($pubkey == $receiverPublic) { + $this->addError('TransactionCreation::validate', 'receiver aren\'t allowed to sign creation Transaction'); + return false; + } + } + + // check if creation threshold for this month isn't reached + $existingCreations = $this->transactionCreationsTable + ->find('all') + ->group('ident_hash') + ->where(['ident_hash' => $this->getIdentHash()]); + $existingCreations->select(['amount_sum' => $existingCreations->func()->sum('amount')]); + debug($existingCreations); + if($existingCreations->count() > 0) { + var_dump($existingCreations->toArray()); + } + return true; + } + + public function save($transaction_id, $firstPublic) { + + $transactionCreationEntity = $this->transactionCreationsTable->newEntity(); + + $transactionCreationEntity->transaction_id = $transaction_id; + + // state user id + $state_user_id = $this->getStateUserId($firstPublic); + if(!$state_user_id) { + $this->addError('TransactionCreation::save', 'couldn\'t get state user id'); + return false; + } + $transactionCreationEntity->state_user_id = $state_user_id; + $transactionCreationEntity->amount = $this->getAmount(); + $transactionCreationEntity->ident_hash = $this->getIdentHash(); + + if(!$this->transactionCreationsTable->save($transactionCreationEntity)) { + $this->addError('TransactionCreation::save', 'error saving transactionCreation with errors: ' . json_encode($transactionCreationEntity->getErrors())); + return false; + } + + return true; + } + } diff --git a/src/Model/Transactions/TransactionTransfer.php b/src/Model/Transactions/TransactionTransfer.php index e8357cc79..89eb36bda 100644 --- a/src/Model/Transactions/TransactionTransfer.php +++ b/src/Model/Transactions/TransactionTransfer.php @@ -5,6 +5,18 @@ namespace Model\Transactions; //use App\Model\Transactions\TransactionBase; class TransactionTransfer extends TransactionBase { - + private $protoTransactionTransfer; + + public function __construct($protoTransactionTransfer) { + $this->protoTransactionTransfer = $protoTransactionTransfer; + } + + public function validate($sigPairs) { + return true; + } + + public function save($transaction_id, $firstPublic) { + return true; + } } diff --git a/src/Template/Layout/frontend.ctp b/src/Template/Layout/frontend.ctp index 9c30a36da..d393355b4 100644 --- a/src/Template/Layout/frontend.ctp +++ b/src/Template/Layout/frontend.ctp @@ -40,7 +40,7 @@ $transactionPendings = $session->read('Transactions.pending');

Community Server in Entwicklung

-

Alpha 0.4.4

+

Alpha 0.5.0