replace \r\n with \n

This commit is contained in:
einhornimmond 2021-03-31 17:08:37 +02:00
parent 9946cc0e13
commit 55334799cb
31 changed files with 2957 additions and 2957 deletions

View File

@ -1,83 +1,83 @@
<?php
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
namespace App\Controller\Component;
use Cake\Controller\Component;
use Cake\Http\Client;
use Cake\Core\Configure;
use Datto\JsonRpc\Client as JsonRpcClient;
//App\Controller\Component\ComponentRegistry
class JsonRpcRequestClientComponent extends Component
{
var $rpcClient = null;
public function __construct($registry, array $config = array()) {
parent::__construct($registry, $config);
$this->rpcClient = new JsonRpcClient();
}
// @param id: if id = 0 call rand for it
public function request($method, $params = [], $id = 0)
{
if(0 == $id) {
$id = random_int(1, 12000);
}
$this->rpcClient->query($id, $method, $params);
$message = $this->rpcClient->encode();
return $this->sendRequest($message);
// message: {"jsonrpc":"2.0","method":"add","params":[1,2],"id":1}
}
public function sendRequest($message) {
$http = new Client();
try {
$url = $this->pickGradidoNodeUrl();
if(is_array($url)) {
return $url;
}
$response = $http->post($url, $message, ['type' => 'json']);
} catch(Exception $e) {
return ['state' => 'error', 'type' => 'http exception', 'details' => $e->getMessage()];
}
$responseStatus = $response->getStatusCode();
if($responseStatus != 200) {
return ['state' => 'error', 'type' => 'request error', 'msg' => 'server response status code isn\'t 200', 'details' => $responseStatus];
}
//$responseType = $response->getType();
//if($responseType != 'application/json') {
// return ['state' => 'error', 'type' => 'request error', 'msg' => 'server response isn\'t json', 'details' => $responseType];
// }
$json = $response->getJson();
if($json == null) {
//$responseType = $response->getType();
return ['state' => 'error', 'type' => 'request error', 'msg' => 'server response isn\'t valid json'];
}
return $json['result'];
//return ['state' => 'success', 'data' => $json];
}
static public function pickGradidoNodeUrl()
{
$gradidoNodes = Configure::read('GradidoNode');
if(count($gradidoNodes) == 0) {
return ['state' => 'error', 'msg' => 'no gradido nodes in config'];
}
$i = rand(0, count($gradidoNodes)-1);
return $gradidoNodes[$i]['host'] . ':' . $gradidoNodes[$i]['port'];
}
}
<?php
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
namespace App\Controller\Component;
use Cake\Controller\Component;
use Cake\Http\Client;
use Cake\Core\Configure;
use Datto\JsonRpc\Client as JsonRpcClient;
//App\Controller\Component\ComponentRegistry
class JsonRpcRequestClientComponent extends Component
{
var $rpcClient = null;
public function __construct($registry, array $config = array()) {
parent::__construct($registry, $config);
$this->rpcClient = new JsonRpcClient();
}
// @param id: if id = 0 call rand for it
public function request($method, $params = [], $id = 0)
{
if(0 == $id) {
$id = random_int(1, 12000);
}
$this->rpcClient->query($id, $method, $params);
$message = $this->rpcClient->encode();
return $this->sendRequest($message);
// message: {"jsonrpc":"2.0","method":"add","params":[1,2],"id":1}
}
public function sendRequest($message) {
$http = new Client();
try {
$url = $this->pickGradidoNodeUrl();
if(is_array($url)) {
return $url;
}
$response = $http->post($url, $message, ['type' => 'json']);
} catch(Exception $e) {
return ['state' => 'error', 'type' => 'http exception', 'details' => $e->getMessage()];
}
$responseStatus = $response->getStatusCode();
if($responseStatus != 200) {
return ['state' => 'error', 'type' => 'request error', 'msg' => 'server response status code isn\'t 200', 'details' => $responseStatus];
}
//$responseType = $response->getType();
//if($responseType != 'application/json') {
// return ['state' => 'error', 'type' => 'request error', 'msg' => 'server response isn\'t json', 'details' => $responseType];
// }
$json = $response->getJson();
if($json == null) {
//$responseType = $response->getType();
return ['state' => 'error', 'type' => 'request error', 'msg' => 'server response isn\'t valid json'];
}
return $json['result'];
//return ['state' => 'success', 'data' => $json];
}
static public function pickGradidoNodeUrl()
{
$gradidoNodes = Configure::read('GradidoNode');
if(count($gradidoNodes) == 0) {
return ['state' => 'error', 'msg' => 'no gradido nodes in config'];
}
$i = rand(0, count($gradidoNodes)-1);
return $gradidoNodes[$i]['host'] . ':' . $gradidoNodes[$i]['port'];
}
}

View File

@ -22,9 +22,9 @@ class Key extends \Google\Protobuf\Internal\Message
* Optional. Data for populating the Message object.
*
* @type string $ed25519
* ed25519 signature (libsodium default)
* ed25519 signature (libsodium default)
* @type string $ed25519_ref10
* ed25519 ref10 signature
* ed25519 ref10 signature
* }
*/
public function __construct($data = NULL) {
@ -33,7 +33,7 @@ class Key extends \Google\Protobuf\Internal\Message
}
/**
* ed25519 signature (libsodium default)
* ed25519 signature (libsodium default)
*
* Generated from protobuf field <code>bytes ed25519 = 2;</code>
* @return string
@ -44,7 +44,7 @@ class Key extends \Google\Protobuf\Internal\Message
}
/**
* ed25519 signature (libsodium default)
* ed25519 signature (libsodium default)
*
* Generated from protobuf field <code>bytes ed25519 = 2;</code>
* @param string $var
@ -59,7 +59,7 @@ class Key extends \Google\Protobuf\Internal\Message
}
/**
* ed25519 ref10 signature
* ed25519 ref10 signature
*
* Generated from protobuf field <code>bytes ed25519_ref10 = 3;</code>
* @return string
@ -70,7 +70,7 @@ class Key extends \Google\Protobuf\Internal\Message
}
/**
* ed25519 ref10 signature
* ed25519 ref10 signature
*
* Generated from protobuf field <code>bytes ed25519_ref10 = 3;</code>
* @param string $var

View File

@ -22,7 +22,7 @@ class SenderAmount extends \Google\Protobuf\Internal\Message
*/
private $amount = 0;
/**
* sender balance after transaction, including perishability
* sender balance after transaction, including perishability
*
* Generated from protobuf field <code>sint64 senderFinalBalance = 3;</code>
*/
@ -37,7 +37,7 @@ class SenderAmount extends \Google\Protobuf\Internal\Message
* @type string $ed25519_sender_pubkey
* @type int|string $amount
* @type int|string $senderFinalBalance
* sender balance after transaction, including perishability
* sender balance after transaction, including perishability
* }
*/
public function __construct($data = NULL) {
@ -90,7 +90,7 @@ class SenderAmount extends \Google\Protobuf\Internal\Message
}
/**
* sender balance after transaction, including perishability
* sender balance after transaction, including perishability
*
* Generated from protobuf field <code>sint64 senderFinalBalance = 3;</code>
* @return int|string
@ -101,7 +101,7 @@ class SenderAmount extends \Google\Protobuf\Internal\Message
}
/**
* sender balance after transaction, including perishability
* sender balance after transaction, including perishability
*
* Generated from protobuf field <code>sint64 senderFinalBalance = 3;</code>
* @param int|string $var

View File

@ -14,7 +14,7 @@ use Google\Protobuf\Internal\GPBUtil;
class SignatureMap extends \Google\Protobuf\Internal\Message
{
/**
* Each signature pair corresponds to a unique Key required to sign the transaction.
* Each signature pair corresponds to a unique Key required to sign the transaction.
*
* Generated from protobuf field <code>repeated .model.messages.gradido.SignaturePair sigPair = 1;</code>
*/
@ -27,7 +27,7 @@ class SignatureMap extends \Google\Protobuf\Internal\Message
* Optional. Data for populating the Message object.
*
* @type \Model\Messages\Gradido\SignaturePair[]|\Google\Protobuf\Internal\RepeatedField $sigPair
* Each signature pair corresponds to a unique Key required to sign the transaction.
* Each signature pair corresponds to a unique Key required to sign the transaction.
* }
*/
public function __construct($data = NULL) {
@ -36,7 +36,7 @@ class SignatureMap extends \Google\Protobuf\Internal\Message
}
/**
* Each signature pair corresponds to a unique Key required to sign the transaction.
* Each signature pair corresponds to a unique Key required to sign the transaction.
*
* Generated from protobuf field <code>repeated .model.messages.gradido.SignaturePair sigPair = 1;</code>
* @return \Google\Protobuf\Internal\RepeatedField
@ -47,7 +47,7 @@ class SignatureMap extends \Google\Protobuf\Internal\Message
}
/**
* Each signature pair corresponds to a unique Key required to sign the transaction.
* Each signature pair corresponds to a unique Key required to sign the transaction.
*
* Generated from protobuf field <code>repeated .model.messages.gradido.SignaturePair sigPair = 1;</code>
* @param \Model\Messages\Gradido\SignaturePair[]|\Google\Protobuf\Internal\RepeatedField $var

View File

@ -27,9 +27,9 @@ class SignaturePair extends \Google\Protobuf\Internal\Message
*
* @type string $pubKey
* @type string $ed25519
* ed25519 signature (libsodium default)
* ed25519 signature (libsodium default)
* @type string $ed25519_ref10
* ed25519 ref10 signature
* ed25519 ref10 signature
* }
*/
public function __construct($data = NULL) {
@ -60,7 +60,7 @@ class SignaturePair extends \Google\Protobuf\Internal\Message
}
/**
* ed25519 signature (libsodium default)
* ed25519 signature (libsodium default)
*
* Generated from protobuf field <code>bytes ed25519 = 2;</code>
* @return string
@ -71,7 +71,7 @@ class SignaturePair extends \Google\Protobuf\Internal\Message
}
/**
* ed25519 signature (libsodium default)
* ed25519 signature (libsodium default)
*
* Generated from protobuf field <code>bytes ed25519 = 2;</code>
* @param string $var
@ -86,7 +86,7 @@ class SignaturePair extends \Google\Protobuf\Internal\Message
}
/**
* ed25519 ref10 signature
* ed25519 ref10 signature
*
* Generated from protobuf field <code>bytes ed25519_ref10 = 3;</code>
* @return string
@ -97,7 +97,7 @@ class SignaturePair extends \Google\Protobuf\Internal\Message
}
/**
* ed25519 ref10 signature
* ed25519 ref10 signature
*
* Generated from protobuf field <code>bytes ed25519_ref10 = 3;</code>
* @param string $var

View File

@ -9,7 +9,7 @@ use Google\Protobuf\Internal\RepeatedField;
use Google\Protobuf\Internal\GPBUtil;
/**
* need signature from this group and from parent (if it isn't zero)
* need signature from this group and from parent (if it isn't zero)
*
* Generated from protobuf message <code>model.messages.gradido.StateCreateGroup</code>
*/

View File

@ -9,7 +9,7 @@ use Google\Protobuf\Internal\RepeatedField;
use Google\Protobuf\Internal\GPBUtil;
/**
* need signature from this group and from both parents (if it isn't zero)
* need signature from this group and from both parents (if it isn't zero)
*
* Generated from protobuf message <code>model.messages.gradido.StateGroupChangeParent</code>
*/

View File

@ -16,13 +16,13 @@ use Google\Protobuf\Internal\GPBUtil;
class Timestamp extends \Google\Protobuf\Internal\Message
{
/**
* Number of complete seconds since the start of the epoch
* Number of complete seconds since the start of the epoch
*
* Generated from protobuf field <code>int64 seconds = 1;</code>
*/
private $seconds = 0;
/**
* Number of nanoseconds since the start of the last second
* Number of nanoseconds since the start of the last second
*
* Generated from protobuf field <code>int32 nanos = 2;</code>
*/
@ -35,9 +35,9 @@ class Timestamp extends \Google\Protobuf\Internal\Message
* Optional. Data for populating the Message object.
*
* @type int|string $seconds
* Number of complete seconds since the start of the epoch
* Number of complete seconds since the start of the epoch
* @type int $nanos
* Number of nanoseconds since the start of the last second
* Number of nanoseconds since the start of the last second
* }
*/
public function __construct($data = NULL) {
@ -46,7 +46,7 @@ class Timestamp extends \Google\Protobuf\Internal\Message
}
/**
* Number of complete seconds since the start of the epoch
* Number of complete seconds since the start of the epoch
*
* Generated from protobuf field <code>int64 seconds = 1;</code>
* @return int|string
@ -57,7 +57,7 @@ class Timestamp extends \Google\Protobuf\Internal\Message
}
/**
* Number of complete seconds since the start of the epoch
* Number of complete seconds since the start of the epoch
*
* Generated from protobuf field <code>int64 seconds = 1;</code>
* @param int|string $var
@ -72,7 +72,7 @@ class Timestamp extends \Google\Protobuf\Internal\Message
}
/**
* Number of nanoseconds since the start of the last second
* Number of nanoseconds since the start of the last second
*
* Generated from protobuf field <code>int32 nanos = 2;</code>
* @return int
@ -83,7 +83,7 @@ class Timestamp extends \Google\Protobuf\Internal\Message
}
/**
* Number of nanoseconds since the start of the last second
* Number of nanoseconds since the start of the last second
*
* Generated from protobuf field <code>int32 nanos = 2;</code>
* @param int $var

View File

@ -16,7 +16,7 @@ use Google\Protobuf\Internal\GPBUtil;
class TimestampSeconds extends \Google\Protobuf\Internal\Message
{
/**
* Number of complete seconds since the start of the epoch
* Number of complete seconds since the start of the epoch
*
* Generated from protobuf field <code>int64 seconds = 1;</code>
*/
@ -29,7 +29,7 @@ class TimestampSeconds extends \Google\Protobuf\Internal\Message
* Optional. Data for populating the Message object.
*
* @type int|string $seconds
* Number of complete seconds since the start of the epoch
* Number of complete seconds since the start of the epoch
* }
*/
public function __construct($data = NULL) {
@ -38,7 +38,7 @@ class TimestampSeconds extends \Google\Protobuf\Internal\Message
}
/**
* Number of complete seconds since the start of the epoch
* Number of complete seconds since the start of the epoch
*
* Generated from protobuf field <code>int64 seconds = 1;</code>
* @return int|string
@ -49,7 +49,7 @@ class TimestampSeconds extends \Google\Protobuf\Internal\Message
}
/**
* Number of complete seconds since the start of the epoch
* Number of complete seconds since the start of the epoch
*
* Generated from protobuf field <code>int64 seconds = 1;</code>
* @param int|string $var

View File

@ -9,27 +9,27 @@ use Google\Protobuf\Internal\RepeatedField;
use Google\Protobuf\Internal\GPBUtil;
/**
* need signature from group admin or
* percent of group users another than the receiver
* need signature from group admin or
* percent of group users another than the receiver
*
* Generated from protobuf message <code>model.messages.gradido.TransactionCreation</code>
*/
class TransactionCreation extends \Google\Protobuf\Internal\Message
{
/**
* 40 Byte
* 40 Byte
*
* Generated from protobuf field <code>.model.messages.gradido.ReceiverAmount receiverAmount = 1;</code>
*/
private $receiverAmount = null;
/**
* 4 Byte
* 4 Byte
*
* Generated from protobuf field <code>sint32 ident_hash = 2;</code>
*/
private $ident_hash = 0;
/**
* 8 Byte
* 8 Byte
*
* Generated from protobuf field <code>.model.messages.gradido.TimestampSeconds target_date = 3;</code>
*/
@ -42,11 +42,11 @@ class TransactionCreation extends \Google\Protobuf\Internal\Message
* Optional. Data for populating the Message object.
*
* @type \Model\Messages\Gradido\ReceiverAmount $receiverAmount
* 40 Byte
* 40 Byte
* @type int $ident_hash
* 4 Byte
* 4 Byte
* @type \Model\Messages\Gradido\TimestampSeconds $target_date
* 8 Byte
* 8 Byte
* }
*/
public function __construct($data = NULL) {
@ -55,7 +55,7 @@ class TransactionCreation extends \Google\Protobuf\Internal\Message
}
/**
* 40 Byte
* 40 Byte
*
* Generated from protobuf field <code>.model.messages.gradido.ReceiverAmount receiverAmount = 1;</code>
* @return \Model\Messages\Gradido\ReceiverAmount
@ -66,7 +66,7 @@ class TransactionCreation extends \Google\Protobuf\Internal\Message
}
/**
* 40 Byte
* 40 Byte
*
* Generated from protobuf field <code>.model.messages.gradido.ReceiverAmount receiverAmount = 1;</code>
* @param \Model\Messages\Gradido\ReceiverAmount $var
@ -81,7 +81,7 @@ class TransactionCreation extends \Google\Protobuf\Internal\Message
}
/**
* 4 Byte
* 4 Byte
*
* Generated from protobuf field <code>sint32 ident_hash = 2;</code>
* @return int
@ -92,7 +92,7 @@ class TransactionCreation extends \Google\Protobuf\Internal\Message
}
/**
* 4 Byte
* 4 Byte
*
* Generated from protobuf field <code>sint32 ident_hash = 2;</code>
* @param int $var
@ -107,7 +107,7 @@ class TransactionCreation extends \Google\Protobuf\Internal\Message
}
/**
* 8 Byte
* 8 Byte
*
* Generated from protobuf field <code>.model.messages.gradido.TimestampSeconds target_date = 3;</code>
* @return \Model\Messages\Gradido\TimestampSeconds
@ -118,7 +118,7 @@ class TransactionCreation extends \Google\Protobuf\Internal\Message
}
/**
* 8 Byte
* 8 Byte
*
* Generated from protobuf field <code>.model.messages.gradido.TimestampSeconds target_date = 3;</code>
* @param \Model\Messages\Gradido\TimestampSeconds $var

View File

@ -22,9 +22,9 @@ class Key extends \Google\Protobuf\Internal\Message
* Optional. Data for populating the Message object.
*
* @type string $ed25519
* ed25519 signature (libsodium default)
* ed25519 signature (libsodium default)
* @type string $ed25519_ref10
* ed25519 ref10 signature
* ed25519 ref10 signature
* }
*/
public function __construct($data = NULL) {
@ -33,7 +33,7 @@ class Key extends \Google\Protobuf\Internal\Message
}
/**
* ed25519 signature (libsodium default)
* ed25519 signature (libsodium default)
*
* Generated from protobuf field <code>bytes ed25519 = 2;</code>
* @return string
@ -44,7 +44,7 @@ class Key extends \Google\Protobuf\Internal\Message
}
/**
* ed25519 signature (libsodium default)
* ed25519 signature (libsodium default)
*
* Generated from protobuf field <code>bytes ed25519 = 2;</code>
* @param string $var
@ -59,7 +59,7 @@ class Key extends \Google\Protobuf\Internal\Message
}
/**
* ed25519 ref10 signature
* ed25519 ref10 signature
*
* Generated from protobuf field <code>bytes ed25519_ref10 = 3;</code>
* @return string
@ -70,7 +70,7 @@ class Key extends \Google\Protobuf\Internal\Message
}
/**
* ed25519 ref10 signature
* ed25519 ref10 signature
*
* Generated from protobuf field <code>bytes ed25519_ref10 = 3;</code>
* @param string $var

View File

@ -14,7 +14,7 @@ use Google\Protobuf\Internal\GPBUtil;
class SignatureMap extends \Google\Protobuf\Internal\Message
{
/**
* Each signature pair corresponds to a unique Key required to sign the transaction.
* Each signature pair corresponds to a unique Key required to sign the transaction.
*
* Generated from protobuf field <code>repeated .proto.gradido.SignaturePair sigPair = 1;</code>
*/
@ -27,7 +27,7 @@ class SignatureMap extends \Google\Protobuf\Internal\Message
* Optional. Data for populating the Message object.
*
* @type \Proto\Gradido\SignaturePair[]|\Google\Protobuf\Internal\RepeatedField $sigPair
* Each signature pair corresponds to a unique Key required to sign the transaction.
* Each signature pair corresponds to a unique Key required to sign the transaction.
* }
*/
public function __construct($data = NULL) {
@ -36,7 +36,7 @@ class SignatureMap extends \Google\Protobuf\Internal\Message
}
/**
* Each signature pair corresponds to a unique Key required to sign the transaction.
* Each signature pair corresponds to a unique Key required to sign the transaction.
*
* Generated from protobuf field <code>repeated .proto.gradido.SignaturePair sigPair = 1;</code>
* @return \Google\Protobuf\Internal\RepeatedField
@ -47,7 +47,7 @@ class SignatureMap extends \Google\Protobuf\Internal\Message
}
/**
* Each signature pair corresponds to a unique Key required to sign the transaction.
* Each signature pair corresponds to a unique Key required to sign the transaction.
*
* Generated from protobuf field <code>repeated .proto.gradido.SignaturePair sigPair = 1;</code>
* @param \Proto\Gradido\SignaturePair[]|\Google\Protobuf\Internal\RepeatedField $var

View File

@ -27,9 +27,9 @@ class SignaturePair extends \Google\Protobuf\Internal\Message
*
* @type string $pubKey
* @type string $ed25519
* ed25519 signature (libsodium default)
* ed25519 signature (libsodium default)
* @type string $ed25519_ref10
* ed25519 ref10 signature
* ed25519 ref10 signature
* }
*/
public function __construct($data = NULL) {
@ -60,7 +60,7 @@ class SignaturePair extends \Google\Protobuf\Internal\Message
}
/**
* ed25519 signature (libsodium default)
* ed25519 signature (libsodium default)
*
* Generated from protobuf field <code>bytes ed25519 = 2;</code>
* @return string
@ -71,7 +71,7 @@ class SignaturePair extends \Google\Protobuf\Internal\Message
}
/**
* ed25519 signature (libsodium default)
* ed25519 signature (libsodium default)
*
* Generated from protobuf field <code>bytes ed25519 = 2;</code>
* @param string $var
@ -86,7 +86,7 @@ class SignaturePair extends \Google\Protobuf\Internal\Message
}
/**
* ed25519 ref10 signature
* ed25519 ref10 signature
*
* Generated from protobuf field <code>bytes ed25519_ref10 = 3;</code>
* @return string
@ -97,7 +97,7 @@ class SignaturePair extends \Google\Protobuf\Internal\Message
}
/**
* ed25519 ref10 signature
* ed25519 ref10 signature
*
* Generated from protobuf field <code>bytes ed25519_ref10 = 3;</code>
* @param string $var

View File

@ -16,13 +16,13 @@ use Google\Protobuf\Internal\GPBUtil;
class Timestamp extends \Google\Protobuf\Internal\Message
{
/**
* Number of complete seconds since the start of the epoch
* Number of complete seconds since the start of the epoch
*
* Generated from protobuf field <code>int64 seconds = 1;</code>
*/
private $seconds = 0;
/**
* Number of nanoseconds since the start of the last second
* Number of nanoseconds since the start of the last second
*
* Generated from protobuf field <code>int32 nanos = 2;</code>
*/
@ -35,9 +35,9 @@ class Timestamp extends \Google\Protobuf\Internal\Message
* Optional. Data for populating the Message object.
*
* @type int|string $seconds
* Number of complete seconds since the start of the epoch
* Number of complete seconds since the start of the epoch
* @type int $nanos
* Number of nanoseconds since the start of the last second
* Number of nanoseconds since the start of the last second
* }
*/
public function __construct($data = NULL) {
@ -46,7 +46,7 @@ class Timestamp extends \Google\Protobuf\Internal\Message
}
/**
* Number of complete seconds since the start of the epoch
* Number of complete seconds since the start of the epoch
*
* Generated from protobuf field <code>int64 seconds = 1;</code>
* @return int|string
@ -57,7 +57,7 @@ class Timestamp extends \Google\Protobuf\Internal\Message
}
/**
* Number of complete seconds since the start of the epoch
* Number of complete seconds since the start of the epoch
*
* Generated from protobuf field <code>int64 seconds = 1;</code>
* @param int|string $var
@ -72,7 +72,7 @@ class Timestamp extends \Google\Protobuf\Internal\Message
}
/**
* Number of nanoseconds since the start of the last second
* Number of nanoseconds since the start of the last second
*
* Generated from protobuf field <code>int32 nanos = 2;</code>
* @return int
@ -83,7 +83,7 @@ class Timestamp extends \Google\Protobuf\Internal\Message
}
/**
* Number of nanoseconds since the start of the last second
* Number of nanoseconds since the start of the last second
*
* Generated from protobuf field <code>int32 nanos = 2;</code>
* @param int $var

View File

@ -16,7 +16,7 @@ use Google\Protobuf\Internal\GPBUtil;
class TimestampSeconds extends \Google\Protobuf\Internal\Message
{
/**
* Number of complete seconds since the start of the epoch
* Number of complete seconds since the start of the epoch
*
* Generated from protobuf field <code>int64 seconds = 1;</code>
*/
@ -29,7 +29,7 @@ class TimestampSeconds extends \Google\Protobuf\Internal\Message
* Optional. Data for populating the Message object.
*
* @type int|string $seconds
* Number of complete seconds since the start of the epoch
* Number of complete seconds since the start of the epoch
* }
*/
public function __construct($data = NULL) {
@ -38,7 +38,7 @@ class TimestampSeconds extends \Google\Protobuf\Internal\Message
}
/**
* Number of complete seconds since the start of the epoch
* Number of complete seconds since the start of the epoch
*
* Generated from protobuf field <code>int64 seconds = 1;</code>
* @return int|string
@ -49,7 +49,7 @@ class TimestampSeconds extends \Google\Protobuf\Internal\Message
}
/**
* Number of complete seconds since the start of the epoch
* Number of complete seconds since the start of the epoch
*
* Generated from protobuf field <code>int64 seconds = 1;</code>
* @param int|string $var

File diff suppressed because it is too large Load Diff

View File

@ -1,269 +1,269 @@
<?php
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
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 $mTransactionBody = null;
public function __construct($base64Data)
{
//$transactionBin = base64_decode($base64Data, true);
//if($transactionBin == false) {
//sodium_base64_VARIANT_URLSAFE_NO_PADDING
if(is_a($base64Data, '\Model\Messages\Gradido\Transaction')) {
$this->mProtoTransaction = $base64Data;
$this->mTransactionBody = new TransactionBody($this->mProtoTransaction->getBodyBytes());
return;
}
try {
$transactionBin = sodium_base642bin($base64Data, SODIUM_BASE64_VARIANT_URLSAFE_NO_PADDING);
} catch(\SodiumException $e) {
//$this->addError('Transaction', $e->getMessage());// . ' ' . $base64Data);
//return;
$transactionBin = base64_decode($base64Data, true);
if($transactionBin == false) {
$this->addError('Transaction', $e->getMessage());// . ' ' . $base64Data);
return;
}
}
//*/}
if($transactionBin == false) {
//$this->addError('base64 decode failed');
$this->addError('Transaction', 'base64 decode error: ' . $base64Data);
} else {
//var_dump($transactionBin);
$this->mProtoTransaction = new \Model\Messages\Gradido\Transaction();
try {
$this->mProtoTransaction->mergeFromString($transactionBin);
//var_dump($this->mProtoTransaction);
// cannot catch Exception with cakePHP, I don't know why
} catch(\Google\Protobuf\Internal\GPBDecodeException $e) {
//var_dump($e);
$this->addError('Transaction', $e->getMessage());
return;
}//*/
//echo 'serialize to json: <br>';
//echo $this->mProtoTransaction->serializeToJsonString();
//echo "body bytes: <br>";
//var_dump($this->mProtoTransaction->getBodyBytes());
//echo "<br>end body bytes<br>";
$this->mTransactionBody = new TransactionBody($this->mProtoTransaction->getBodyBytes());
}
}
static public function build(\Model\Messages\Gradido\TransactionBody $transactionBody, $senderKeyPair)
{
$protoTransaction = new \Model\Messages\Gradido\Transaction();
$recevied = new \Model\Messages\Gradido\TimestampSeconds();
$recevied->setSeconds(time());
$protoTransaction->setReceived($recevied);
$bodyBytes = $transactionBody->serializeToString();
$sigMap = SignatureMap::build($bodyBytes, [$senderKeyPair]);
$protoTransaction->setSigMap($sigMap->getProto());
$protoTransaction->setBodyBytes($bodyBytes);
return $protoTransaction;
}
public function getTransactionBody() {
return $this->mTransactionBody;
}
public function getFirstPublic() {
$sigPairs = $this->mProtoTransaction->getSigMap()->getSigPair();
return $sigPairs[0]->getPubKey();
}
public function getId() {
return $this->mProtoTransaction->getId();
}
public function validate() {
$sigMap = $this->mProtoTransaction->getSigMap();
if(!$sigMap) {
$this->addError('Transaction', 'signature map is zero');
return false;
}
//var_dump($sigMap);
//die();
$sigPairs = $sigMap->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 "<br>";
$pubkey = $sigPair->getPubKey();
$signature = $sigPair->getEd25519();
//echo "verify bodybytes: <br>" . bin2hex($bodyBytes) . '<br>';
if (!\Sodium\crypto_sign_verify_detached($signature, $bodyBytes, $pubkey)) {
$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 save()
{
$connection = ConnectionManager::get('default');
$connection->begin();
//id transaction_id signature pubkey
if (!$this->mTransactionBody->save($this->getFirstPublic(), $this->mProtoTransaction->getSigMap())) {
$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();
$this->mTransactionBody->getSpecificTransaction()->sendNotificationEmail($this->mTransactionBody->getMemo());
return true;
}
static public function fromTable($id)
{
$transactionsTable = TableRegistry::getTableLocator()->get('transactions');
$transactionEntry = $transactionsTable
->find('all')
->where(['id' => $id])
->contain([
'TransactionCreations',
'TransactionSendCoins',
'TransactionSignatures'])
->first();
//var_dump($transactionEntry->toArray());
$protoTransaction = new \Model\Messages\Gradido\Transaction();
$protoTransaction->setId($transactionEntry->id);
$recevied = new \Model\Messages\Gradido\TimestampSeconds();
$recevied->setSeconds($transactionEntry->received->getTimestamp());
$protoTransaction->setReceived($recevied);
$sigMap = SignatureMap::fromEntity($transactionEntry->transaction_signatures);
$protoTransaction->setSigMap($sigMap->getProto());
//echo "sig map: check<br>";
$protoTransaction->setTxHash(stream_get_contents($transactionEntry->tx_hash));
$body = TransactionBody::fromEntity($transactionEntry->memo, $transactionEntry);
if(is_array($body)) {
return ['state' => 'error', 'msg' => 'error creating body transaction', 'details' => $body];
}
// validate signatures
$sigPairs = $sigMap->getProto()->getSigPair();
if(!$sigPairs || count($sigPairs) < 1) {
return ['state' => 'error', 'msg' => 'error no signatures found'];
}
//echo "verify bodybytes: <br>" . bin2hex($bodyBytes) . '<br>';
$created = new \Model\Messages\Gradido\TimestampSeconds();
$created->setSeconds($recevied->getSeconds());
$body->setCreated($created);
$bodyBytes = $body->serializeToString();
$createTrys = 0;
$createRight = false;
// check signature(s) and
// try to get created field of TransactionBody right, because it wasn't saved
foreach($sigPairs as $sigPair) {
//echo 'sig Pair: '; var_dump($sigPair); echo "<br>";
$pubkey = $sigPair->getPubKey();
$signature = $sigPair->getEd25519();
if(!$createRight) {
while($createTrys < 500) {
if(\Sodium\crypto_sign_verify_detached($signature, $bodyBytes, $pubkey)) {
$createRight = true;
break;
} else {
$createTrys++;
$created->setSeconds($created->getSeconds() - 1);
//$body->setCreated($created);
$bodyBytes = $body->serializeToString();
}
}
}
if (!\Sodium\crypto_sign_verify_detached($signature, $bodyBytes, $pubkey)) {
return ['state' => 'error', 'msg' => 'signature for key ' . bin2hex($pubkey) . ' isn\'t valid '];
}
}
$protoTransaction->setBodyBytes($bodyBytes);
return $protoTransaction;
}
<?php
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
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 $mTransactionBody = null;
public function __construct($base64Data)
{
//$transactionBin = base64_decode($base64Data, true);
//if($transactionBin == false) {
//sodium_base64_VARIANT_URLSAFE_NO_PADDING
if(is_a($base64Data, '\Model\Messages\Gradido\Transaction')) {
$this->mProtoTransaction = $base64Data;
$this->mTransactionBody = new TransactionBody($this->mProtoTransaction->getBodyBytes());
return;
}
try {
$transactionBin = sodium_base642bin($base64Data, SODIUM_BASE64_VARIANT_URLSAFE_NO_PADDING);
} catch(\SodiumException $e) {
//$this->addError('Transaction', $e->getMessage());// . ' ' . $base64Data);
//return;
$transactionBin = base64_decode($base64Data, true);
if($transactionBin == false) {
$this->addError('Transaction', $e->getMessage());// . ' ' . $base64Data);
return;
}
}
//*/}
if($transactionBin == false) {
//$this->addError('base64 decode failed');
$this->addError('Transaction', 'base64 decode error: ' . $base64Data);
} else {
//var_dump($transactionBin);
$this->mProtoTransaction = new \Model\Messages\Gradido\Transaction();
try {
$this->mProtoTransaction->mergeFromString($transactionBin);
//var_dump($this->mProtoTransaction);
// cannot catch Exception with cakePHP, I don't know why
} catch(\Google\Protobuf\Internal\GPBDecodeException $e) {
//var_dump($e);
$this->addError('Transaction', $e->getMessage());
return;
}//*/
//echo 'serialize to json: <br>';
//echo $this->mProtoTransaction->serializeToJsonString();
//echo "body bytes: <br>";
//var_dump($this->mProtoTransaction->getBodyBytes());
//echo "<br>end body bytes<br>";
$this->mTransactionBody = new TransactionBody($this->mProtoTransaction->getBodyBytes());
}
}
static public function build(\Model\Messages\Gradido\TransactionBody $transactionBody, $senderKeyPair)
{
$protoTransaction = new \Model\Messages\Gradido\Transaction();
$recevied = new \Model\Messages\Gradido\TimestampSeconds();
$recevied->setSeconds(time());
$protoTransaction->setReceived($recevied);
$bodyBytes = $transactionBody->serializeToString();
$sigMap = SignatureMap::build($bodyBytes, [$senderKeyPair]);
$protoTransaction->setSigMap($sigMap->getProto());
$protoTransaction->setBodyBytes($bodyBytes);
return $protoTransaction;
}
public function getTransactionBody() {
return $this->mTransactionBody;
}
public function getFirstPublic() {
$sigPairs = $this->mProtoTransaction->getSigMap()->getSigPair();
return $sigPairs[0]->getPubKey();
}
public function getId() {
return $this->mProtoTransaction->getId();
}
public function validate() {
$sigMap = $this->mProtoTransaction->getSigMap();
if(!$sigMap) {
$this->addError('Transaction', 'signature map is zero');
return false;
}
//var_dump($sigMap);
//die();
$sigPairs = $sigMap->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 "<br>";
$pubkey = $sigPair->getPubKey();
$signature = $sigPair->getEd25519();
//echo "verify bodybytes: <br>" . bin2hex($bodyBytes) . '<br>';
if (!\Sodium\crypto_sign_verify_detached($signature, $bodyBytes, $pubkey)) {
$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 save()
{
$connection = ConnectionManager::get('default');
$connection->begin();
//id transaction_id signature pubkey
if (!$this->mTransactionBody->save($this->getFirstPublic(), $this->mProtoTransaction->getSigMap())) {
$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();
$this->mTransactionBody->getSpecificTransaction()->sendNotificationEmail($this->mTransactionBody->getMemo());
return true;
}
static public function fromTable($id)
{
$transactionsTable = TableRegistry::getTableLocator()->get('transactions');
$transactionEntry = $transactionsTable
->find('all')
->where(['id' => $id])
->contain([
'TransactionCreations',
'TransactionSendCoins',
'TransactionSignatures'])
->first();
//var_dump($transactionEntry->toArray());
$protoTransaction = new \Model\Messages\Gradido\Transaction();
$protoTransaction->setId($transactionEntry->id);
$recevied = new \Model\Messages\Gradido\TimestampSeconds();
$recevied->setSeconds($transactionEntry->received->getTimestamp());
$protoTransaction->setReceived($recevied);
$sigMap = SignatureMap::fromEntity($transactionEntry->transaction_signatures);
$protoTransaction->setSigMap($sigMap->getProto());
//echo "sig map: check<br>";
$protoTransaction->setTxHash(stream_get_contents($transactionEntry->tx_hash));
$body = TransactionBody::fromEntity($transactionEntry->memo, $transactionEntry);
if(is_array($body)) {
return ['state' => 'error', 'msg' => 'error creating body transaction', 'details' => $body];
}
// validate signatures
$sigPairs = $sigMap->getProto()->getSigPair();
if(!$sigPairs || count($sigPairs) < 1) {
return ['state' => 'error', 'msg' => 'error no signatures found'];
}
//echo "verify bodybytes: <br>" . bin2hex($bodyBytes) . '<br>';
$created = new \Model\Messages\Gradido\TimestampSeconds();
$created->setSeconds($recevied->getSeconds());
$body->setCreated($created);
$bodyBytes = $body->serializeToString();
$createTrys = 0;
$createRight = false;
// check signature(s) and
// try to get created field of TransactionBody right, because it wasn't saved
foreach($sigPairs as $sigPair) {
//echo 'sig Pair: '; var_dump($sigPair); echo "<br>";
$pubkey = $sigPair->getPubKey();
$signature = $sigPair->getEd25519();
if(!$createRight) {
while($createTrys < 500) {
if(\Sodium\crypto_sign_verify_detached($signature, $bodyBytes, $pubkey)) {
$createRight = true;
break;
} else {
$createTrys++;
$created->setSeconds($created->getSeconds() - 1);
//$body->setCreated($created);
$bodyBytes = $body->serializeToString();
}
}
}
if (!\Sodium\crypto_sign_verify_detached($signature, $bodyBytes, $pubkey)) {
return ['state' => 'error', 'msg' => 'signature for key ' . bin2hex($pubkey) . ' isn\'t valid '];
}
}
$protoTransaction->setBodyBytes($bodyBytes);
return $protoTransaction;
}
}

View File

@ -1,122 +1,122 @@
<?php
namespace Model\Transactions;
use Cake\ORM\TableRegistry;
class TransactionBase {
private $errors = [];
static $tables = [];
public function getErrors() {
return $this->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;
}
public static function getTable($tableName) {
if(!isset(self::$tables[$tableName])) {
self::$tables[$tableName] = TableRegistry::getTableLocator()->get($tableName);
}
return self::$tables[$tableName];
}
protected function getStateUserId($publicKey) {
$stateUsersTable = self::getTable('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;
}
protected function getStateUser($id) {
$stateUsersTable = self::getTable('state_users');
$stateUser = $stateUsersTable->get($id);
if($stateUser) {
return $stateUser;
}
return NULL;
}
protected function updateStateBalance($stateUserId, $addAmountCent, $recordDate) {
$finalBalance = 0;
$stateBalancesTable = self::getTable('stateBalances');
$stateBalanceQuery = $stateBalancesTable
->find('all')
->select(['amount', 'id'])
->contain(false)
->where(['state_user_id' => $stateUserId]);//->first();
//debug($stateBalanceQuery);
if($stateBalanceQuery->count() > 0) {
$stateBalanceEntry = $stateBalanceQuery->first();
$stateBalanceEntry->amount = $stateBalanceEntry->partDecay($recordDate) + $addAmountCent;
$stateBalanceEntry->amount += $addAmountCent;
} else {
$stateBalanceEntry = $stateBalancesTable->newEntity();
$stateBalanceEntry->state_user_id = $stateUserId;
$stateBalanceEntry->amount = $addAmountCent;
}
$stateBalanceEntry->record_date = $recordDate;
$finalBalance = $stateBalanceEntry->amount;
//echo "\ntry to save: "; var_dump($stateBalanceEntry); echo "\n";
if(!$stateBalancesTable->save($stateBalanceEntry)) {
$errors = $stateBalanceEntry->getErrors();
$this->addError('TransactionBase::updateStateBalance', 'error saving state balance with: ' . json_encode($errors));
return false;
}
return $finalBalance;
}
protected function addStateUserTransaction($stateUserId, $transactionId, $transactionTypeId, $balance) {
$stateUserTransactionTable = self::getTable('state_user_transactions');
$stateUserTransactions = $stateUserTransactionTable
->find('all')
->where(['state_user_id' => $stateUserId])
->order(['transaction_id DESC']);
if($stateUserTransactions->count() > 0) {
$stateBalanceTable = self::getTable('state_balances');
$balance_entity = $stateBalanceTable->newEntity();
$balance_entity->amount = $stateUserTransactions->first()->balance;
$balance_entity->record_date = $stateUserTransactions->first()->balance_date;
$balance = $balance_entity->decay + $balance;
}
$entity = $stateUserTransactionTable->newEntity();
$entity->state_user_id = $stateUserId;
$entity->transaction_id = $transactionId;
$entity->transaction_type_id = $transactionTypeId;
$entity->balance = $balance;
if(!$stateUserTransactionTable->save($entity)) {
$errors = $entity->getErrors();
$this->addError('TransactionBase::addStateUserTransaction', 'error saving state user balance with: ' . json_encode($errors));
return false;
}
return true;
}
<?php
namespace Model\Transactions;
use Cake\ORM\TableRegistry;
class TransactionBase {
private $errors = [];
static $tables = [];
public function getErrors() {
return $this->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;
}
public static function getTable($tableName) {
if(!isset(self::$tables[$tableName])) {
self::$tables[$tableName] = TableRegistry::getTableLocator()->get($tableName);
}
return self::$tables[$tableName];
}
protected function getStateUserId($publicKey) {
$stateUsersTable = self::getTable('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;
}
protected function getStateUser($id) {
$stateUsersTable = self::getTable('state_users');
$stateUser = $stateUsersTable->get($id);
if($stateUser) {
return $stateUser;
}
return NULL;
}
protected function updateStateBalance($stateUserId, $addAmountCent, $recordDate) {
$finalBalance = 0;
$stateBalancesTable = self::getTable('stateBalances');
$stateBalanceQuery = $stateBalancesTable
->find('all')
->select(['amount', 'id'])
->contain(false)
->where(['state_user_id' => $stateUserId]);//->first();
//debug($stateBalanceQuery);
if($stateBalanceQuery->count() > 0) {
$stateBalanceEntry = $stateBalanceQuery->first();
$stateBalanceEntry->amount = $stateBalanceEntry->partDecay($recordDate) + $addAmountCent;
$stateBalanceEntry->amount += $addAmountCent;
} else {
$stateBalanceEntry = $stateBalancesTable->newEntity();
$stateBalanceEntry->state_user_id = $stateUserId;
$stateBalanceEntry->amount = $addAmountCent;
}
$stateBalanceEntry->record_date = $recordDate;
$finalBalance = $stateBalanceEntry->amount;
//echo "\ntry to save: "; var_dump($stateBalanceEntry); echo "\n";
if(!$stateBalancesTable->save($stateBalanceEntry)) {
$errors = $stateBalanceEntry->getErrors();
$this->addError('TransactionBase::updateStateBalance', 'error saving state balance with: ' . json_encode($errors));
return false;
}
return $finalBalance;
}
protected function addStateUserTransaction($stateUserId, $transactionId, $transactionTypeId, $balance) {
$stateUserTransactionTable = self::getTable('state_user_transactions');
$stateUserTransactions = $stateUserTransactionTable
->find('all')
->where(['state_user_id' => $stateUserId])
->order(['transaction_id DESC']);
if($stateUserTransactions->count() > 0) {
$stateBalanceTable = self::getTable('state_balances');
$balance_entity = $stateBalanceTable->newEntity();
$balance_entity->amount = $stateUserTransactions->first()->balance;
$balance_entity->record_date = $stateUserTransactions->first()->balance_date;
$balance = $balance_entity->decay + $balance;
}
$entity = $stateUserTransactionTable->newEntity();
$entity->state_user_id = $stateUserId;
$entity->transaction_id = $transactionId;
$entity->transaction_type_id = $transactionTypeId;
$entity->balance = $balance;
if(!$stateUserTransactionTable->save($entity)) {
$errors = $entity->getErrors();
$this->addError('TransactionBase::addStateUserTransaction', 'error saving state user balance with: ' . json_encode($errors));
return false;
}
return true;
}
}

View File

@ -1,46 +1,46 @@
<?php
namespace App\Test\TestCase\Controller;
use App\Controller\AppController;
use Cake\TestSuite\IntegrationTestTrait;
use Cake\TestSuite\TestCase;
/**
* App\Controller\DashboardController Test Case
*
* @uses \App\Controller\DashboardController
*/
class AppControllerTest extends TestCase
{
use IntegrationTestTrait;
/**
* Fixtures
*
* @var array
*/
public $fixtures = [
'app.StateBalances'
];
public function setUp()
{
parent::setUp();
}
/**
* Test initialize method
*
* @return void
*/
public function testInitialize()
{
$this->session(['StateUser.id' => 1]);
$this->get('/');
$this->assertSession(1200, 'StateUser.balance');
//$this->markTestIncomplete('Not implemented yet.');
}
}
<?php
namespace App\Test\TestCase\Controller;
use App\Controller\AppController;
use Cake\TestSuite\IntegrationTestTrait;
use Cake\TestSuite\TestCase;
/**
* App\Controller\DashboardController Test Case
*
* @uses \App\Controller\DashboardController
*/
class AppControllerTest extends TestCase
{
use IntegrationTestTrait;
/**
* Fixtures
*
* @var array
*/
public $fixtures = [
'app.StateBalances'
];
public function setUp()
{
parent::setUp();
}
/**
* Test initialize method
*
* @return void
*/
public function testInitialize()
{
$this->session(['StateUser.id' => 1]);
$this->get('/');
$this->assertSession(1200, 'StateUser.balance');
//$this->markTestIncomplete('Not implemented yet.');
}
}

2
gn

@ -1 +1 @@
Subproject commit a61871987261614102b11ed58791081be1954d3c
Subproject commit 5437e2f882c54efe4f501f7cd0d97f53806d0b74

View File

@ -1,42 +1,42 @@
#ifndef Gradido_LoginServer_INCLUDED
#define Gradido_LoginServer_INCLUDED
#include "Poco/Util/ServerApplication.h"
class Gradido_LoginServer : public Poco::Util::ServerApplication
{
/// The main application class.
///
/// This class handles command-line arguments and
/// configuration files.
/// Start the Gradido_LoginServer executable with the help
/// option (/help on Windows, --help on Unix) for
/// the available command line options.
///
public:
Gradido_LoginServer();
~Gradido_LoginServer();
protected:
void initialize(Application& self);
void uninitialize();
void defineOptions(Poco::Util::OptionSet& options);
void handleOption(const std::string& name, const std::string& value);
void displayHelp();
int main(const std::vector<std::string>& args);
void createConsoleFileAsyncLogger(std::string name, std::string filePath);
private:
bool _helpRequested;
std::string mConfigPath;
};
#endif //Gradido_LoginServer_INCLUDED
#ifndef Gradido_LoginServer_INCLUDED
#define Gradido_LoginServer_INCLUDED
#include "Poco/Util/ServerApplication.h"
class Gradido_LoginServer : public Poco::Util::ServerApplication
{
/// The main application class.
///
/// This class handles command-line arguments and
/// configuration files.
/// Start the Gradido_LoginServer executable with the help
/// option (/help on Windows, --help on Unix) for
/// the available command line options.
///
public:
Gradido_LoginServer();
~Gradido_LoginServer();
protected:
void initialize(Application& self);
void uninitialize();
void defineOptions(Poco::Util::OptionSet& options);
void handleOption(const std::string& name, const std::string& value);
void displayHelp();
int main(const std::vector<std::string>& args);
void createConsoleFileAsyncLogger(std::string name, std::string filePath);
private:
bool _helpRequested;
std::string mConfigPath;
};
#endif //Gradido_LoginServer_INCLUDED

File diff suppressed because it is too large Load Diff

View File

@ -1,18 +1,18 @@
#ifndef AdminNodeServerTestPage_INCLUDED
#define AdminNodeServerTestPage_INCLUDED
#include "Poco/Net/HTTPRequestHandler.h"
#include "PageRequestMessagedHandler.h"
class AdminNodeServerTestPage: public PageRequestMessagedHandler
{
public:
void handleRequest(Poco::Net::HTTPServerRequest& request, Poco::Net::HTTPServerResponse& response);
};
#endif // AdminNodeServerTestPage_INCLUDED
#ifndef AdminNodeServerTestPage_INCLUDED
#define AdminNodeServerTestPage_INCLUDED
#include "Poco/Net/HTTPRequestHandler.h"
#include "PageRequestMessagedHandler.h"
class AdminNodeServerTestPage: public PageRequestMessagedHandler
{
public:
void handleRequest(Poco::Net::HTTPServerRequest& request, Poco::Net::HTTPServerResponse& response);
};
#endif // AdminNodeServerTestPage_INCLUDED

View File

@ -1,20 +1,20 @@
#ifndef LoginPage_INCLUDED
#define LoginPage_INCLUDED
#include "Poco/Net/HTTPRequestHandler.h"
#include "SessionHTTPRequestHandler.h"
class LoginPage: public SessionHTTPRequestHandler
{
public:
LoginPage(Session*);
void handleRequest(Poco::Net::HTTPServerRequest& request, Poco::Net::HTTPServerResponse& response);
};
#endif // LoginPage_INCLUDED
#ifndef LoginPage_INCLUDED
#define LoginPage_INCLUDED
#include "Poco/Net/HTTPRequestHandler.h"
#include "SessionHTTPRequestHandler.h"
class LoginPage: public SessionHTTPRequestHandler
{
public:
LoginPage(Session*);
void handleRequest(Poco::Net::HTTPServerRequest& request, Poco::Net::HTTPServerResponse& response);
};
#endif // LoginPage_INCLUDED

View File

@ -1,123 +1,123 @@
#include "JsonGetUserInfos.h"
#include "../lib/DataTypeConverter.h"
#include "../SingletonManager/SessionManager.h"
#include "../controller/User.h"
#include "../controller/EmailVerificationCode.h"
#include "../ServerConfig.h"
Poco::JSON::Object* JsonGetUserInfos::handle(Poco::Dynamic::Var params)
{
/*
'session_id' => $session_id,
'email' => $email,
'ask' => ['EmailOptIn.Register']
*/
// incoming
int session_id = 0;
std::string email;
Poco::JSON::Array::Ptr askArray;
auto sm = SessionManager::getInstance();
// if is json object
if (params.type() == typeid(Poco::JSON::Object::Ptr)) {
Poco::JSON::Object::Ptr paramJsonObject = params.extract<Poco::JSON::Object::Ptr>();
/// Throws a RangeException if the value does not fit
/// into the result variable.
/// Throws a NotImplementedException if conversion is
/// not available for the given type.
/// Throws InvalidAccessException if Var is empty.
try {
paramJsonObject->get("email").convert(email);
paramJsonObject->get("session_id").convert(session_id);
askArray = paramJsonObject->getArray("ask");
}
catch (Poco::Exception& ex) {
return stateError("json exception", ex.displayText());
}
}
else {
return stateError("parameter format unknown");
}
if (!session_id) {
return stateError("session_id invalid");
}
if (askArray.isNull()) {
return stateError("ask is zero or not an array");
}
auto session = sm->getSession(session_id);
if (!session) {
return customStateError("not found", "session not found");
}
auto user = controller::User::create();
if (1 != user->load(email)) {
return customStateError("not found", "user not found");
}
auto userModel = user->getModel();
Poco::JSON::Object* result = new Poco::JSON::Object;
result->set("state", "success");
Poco::JSON::Array jsonErrorsArray;
Poco::JSON::Object jsonUser;
Poco::JSON::Object jsonServer;
for (auto it = askArray->begin(); it != askArray->end(); it++) {
auto parameter = *it;
std::string parameterString;
try {
parameter.convert(parameterString);
if (parameterString == "EmailVerificationCode.Register") {
try {
auto emailVerificationCode = controller::EmailVerificationCode::load(
userModel->getID(), model::table::EMAIL_OPT_IN_REGISTER
);
if (!emailVerificationCode) {
emailVerificationCode = controller::EmailVerificationCode::create(userModel->getID(), model::table::EMAIL_OPT_IN_REGISTER);
UniLib::controller::TaskPtr insert = new model::table::ModelInsertTask(emailVerificationCode->getModel(), false);
insert->scheduleTask(insert);
}
jsonUser.set("EmailVerificationCode.Register", std::to_string(emailVerificationCode->getModel()->getCode()));
}
catch (Poco::Exception& ex) {
printf("exception: %s\n", ex.displayText().data());
}
}
else if (parameterString == "loginServer.path") {
jsonServer.set("loginServer.path", ServerConfig::g_serverPath);
}
else if (parameterString == "user.pubkeyhex") {
jsonUser.set("pubkeyhex", userModel->getPublicKeyHex());
}
else if (parameterString == "user.first_name") {
jsonUser.set("first_name", userModel->getFirstName());
}
else if (parameterString == "user.last_name") {
jsonUser.set("last_name", userModel->getLastName());
}
else if (parameterString == "user.disabled") {
jsonUser.set("disabled", userModel->isDisabled());
}
else if (parameterString == "user.email_checked") {
jsonUser.set("email_checked", userModel->isEmailChecked());
}
else if (parameterString == "user.identHash") {
auto email = userModel->getEmail();
jsonUser.set("identHash", DRMakeStringHash(email.data(), email.size()));
}
}
catch (Poco::Exception& ex) {
jsonErrorsArray.add("ask parameter invalid");
}
}
result->set("errors", jsonErrorsArray);
result->set("userData", jsonUser);
result->set("server", jsonServer);
return result;
#include "JsonGetUserInfos.h"
#include "../lib/DataTypeConverter.h"
#include "../SingletonManager/SessionManager.h"
#include "../controller/User.h"
#include "../controller/EmailVerificationCode.h"
#include "../ServerConfig.h"
Poco::JSON::Object* JsonGetUserInfos::handle(Poco::Dynamic::Var params)
{
/*
'session_id' => $session_id,
'email' => $email,
'ask' => ['EmailOptIn.Register']
*/
// incoming
int session_id = 0;
std::string email;
Poco::JSON::Array::Ptr askArray;
auto sm = SessionManager::getInstance();
// if is json object
if (params.type() == typeid(Poco::JSON::Object::Ptr)) {
Poco::JSON::Object::Ptr paramJsonObject = params.extract<Poco::JSON::Object::Ptr>();
/// Throws a RangeException if the value does not fit
/// into the result variable.
/// Throws a NotImplementedException if conversion is
/// not available for the given type.
/// Throws InvalidAccessException if Var is empty.
try {
paramJsonObject->get("email").convert(email);
paramJsonObject->get("session_id").convert(session_id);
askArray = paramJsonObject->getArray("ask");
}
catch (Poco::Exception& ex) {
return stateError("json exception", ex.displayText());
}
}
else {
return stateError("parameter format unknown");
}
if (!session_id) {
return stateError("session_id invalid");
}
if (askArray.isNull()) {
return stateError("ask is zero or not an array");
}
auto session = sm->getSession(session_id);
if (!session) {
return customStateError("not found", "session not found");
}
auto user = controller::User::create();
if (1 != user->load(email)) {
return customStateError("not found", "user not found");
}
auto userModel = user->getModel();
Poco::JSON::Object* result = new Poco::JSON::Object;
result->set("state", "success");
Poco::JSON::Array jsonErrorsArray;
Poco::JSON::Object jsonUser;
Poco::JSON::Object jsonServer;
for (auto it = askArray->begin(); it != askArray->end(); it++) {
auto parameter = *it;
std::string parameterString;
try {
parameter.convert(parameterString);
if (parameterString == "EmailVerificationCode.Register") {
try {
auto emailVerificationCode = controller::EmailVerificationCode::load(
userModel->getID(), model::table::EMAIL_OPT_IN_REGISTER
);
if (!emailVerificationCode) {
emailVerificationCode = controller::EmailVerificationCode::create(userModel->getID(), model::table::EMAIL_OPT_IN_REGISTER);
UniLib::controller::TaskPtr insert = new model::table::ModelInsertTask(emailVerificationCode->getModel(), false);
insert->scheduleTask(insert);
}
jsonUser.set("EmailVerificationCode.Register", std::to_string(emailVerificationCode->getModel()->getCode()));
}
catch (Poco::Exception& ex) {
printf("exception: %s\n", ex.displayText().data());
}
}
else if (parameterString == "loginServer.path") {
jsonServer.set("loginServer.path", ServerConfig::g_serverPath);
}
else if (parameterString == "user.pubkeyhex") {
jsonUser.set("pubkeyhex", userModel->getPublicKeyHex());
}
else if (parameterString == "user.first_name") {
jsonUser.set("first_name", userModel->getFirstName());
}
else if (parameterString == "user.last_name") {
jsonUser.set("last_name", userModel->getLastName());
}
else if (parameterString == "user.disabled") {
jsonUser.set("disabled", userModel->isDisabled());
}
else if (parameterString == "user.email_checked") {
jsonUser.set("email_checked", userModel->isEmailChecked());
}
else if (parameterString == "user.identHash") {
auto email = userModel->getEmail();
jsonUser.set("identHash", DRMakeStringHash(email.data(), email.size()));
}
}
catch (Poco::Exception& ex) {
jsonErrorsArray.add("ask parameter invalid");
}
}
result->set("errors", jsonErrorsArray);
result->set("userData", jsonUser);
result->set("server", jsonServer);
return result;
}

View File

@ -1,44 +1,44 @@
#include "JsonLogout.h"
#include "../SingletonManager/SessionManager.h"
Poco::JSON::Object* JsonLogout::handle(Poco::Dynamic::Var params)
{
auto sm = SessionManager::getInstance();
int session_id = 0;
// if is json object
if (params.type() == typeid(Poco::JSON::Object::Ptr)) {
Poco::JSON::Object::Ptr paramJsonObject = params.extract<Poco::JSON::Object::Ptr>();
/// Throws a RangeException if the value does not fit
/// into the result variable.
/// Throws a NotImplementedException if conversion is
/// not available for the given type.
/// Throws InvalidAccessException if Var is empty.
try {
paramJsonObject->get("session_id").convert(session_id);
}
catch (Poco::Exception& ex) {
return stateError("json exception", ex.displayText());
}
}
else {
return stateError("parameter format unknown");
}
auto session = sm->getSession(session_id);
if (!session) {
return stateError("session not found", std::to_string(session_id));
}
if (sm->releaseSession(session_id)) {
return stateSuccess();
}
return stateError("error by releasing session");
#include "JsonLogout.h"
#include "../SingletonManager/SessionManager.h"
Poco::JSON::Object* JsonLogout::handle(Poco::Dynamic::Var params)
{
auto sm = SessionManager::getInstance();
int session_id = 0;
// if is json object
if (params.type() == typeid(Poco::JSON::Object::Ptr)) {
Poco::JSON::Object::Ptr paramJsonObject = params.extract<Poco::JSON::Object::Ptr>();
/// Throws a RangeException if the value does not fit
/// into the result variable.
/// Throws a NotImplementedException if conversion is
/// not available for the given type.
/// Throws InvalidAccessException if Var is empty.
try {
paramJsonObject->get("session_id").convert(session_id);
}
catch (Poco::Exception& ex) {
return stateError("json exception", ex.displayText());
}
}
else {
return stateError("parameter format unknown");
}
auto session = sm->getSession(session_id);
if (!session) {
return stateError("session not found", std::to_string(session_id));
}
if (sm->releaseSession(session_id)) {
return stateSuccess();
}
return stateError("error by releasing session");
}

View File

@ -1,18 +1,18 @@
#ifndef __JSON_INTERFACE_JSON_LOGOUT_
#define __JSON_INTERFACE_JSON_LOGOUT_
#include "JsonRequestHandler.h"
class JsonLogout : public JsonRequestHandler
{
public:
JsonLogout(Poco::Net::IPAddress ip) : mClientIP(ip) {}
Poco::JSON::Object* handle(Poco::Dynamic::Var params);
protected:
Poco::Net::IPAddress mClientIP;
};
#ifndef __JSON_INTERFACE_JSON_LOGOUT_
#define __JSON_INTERFACE_JSON_LOGOUT_
#include "JsonRequestHandler.h"
class JsonLogout : public JsonRequestHandler
{
public:
JsonLogout(Poco::Net::IPAddress ip) : mClientIP(ip) {}
Poco::JSON::Object* handle(Poco::Dynamic::Var params);
protected:
Poco::Net::IPAddress mClientIP;
};
#endif // __JSON_INTERFACE_JSON_LOGOUT_

View File

@ -1,19 +1,19 @@
#ifndef __JSON_INTERFACE_JSON_TRANSACTION_
#define __JSON_INTERFACE_JSON_TRANSACTION_
#include "JsonRequestHandler.h"
class Session;
class JsonTransaction : public JsonRequestHandler
{
public:
Poco::JSON::Object* handle(Poco::Dynamic::Var params);
protected:
bool startProcessingTransaction(Session* session, const std::string& transactionBase64);
};
#ifndef __JSON_INTERFACE_JSON_TRANSACTION_
#define __JSON_INTERFACE_JSON_TRANSACTION_
#include "JsonRequestHandler.h"
class Session;
class JsonTransaction : public JsonRequestHandler
{
public:
Poco::JSON::Object* handle(Poco::Dynamic::Var params);
protected:
bool startProcessingTransaction(Session* session, const std::string& transactionBase64);
};
#endif // __JSON_INTERFACE_JSON_TRANSACTION_

View File

@ -1,173 +1,173 @@
#include "EmailManager.h"
#include "../ServerConfig.h"
#include "../Crypto/Obfus_array.h"
#include "../Crypto/DRRandom.h"
#include "../SingletonManager/LanguageManager.h"
#include "Poco/Net/SecureSMTPClientSession.h"
#include "Poco/Net/SSLException.h"
EmailManager::EmailManager()
: Thread("emails", false), mEmailLog(Poco::Logger::get("emailLog")), mInitalized(false), mDisableEmail(false)
{
}
EmailManager::~EmailManager()
{
exit();
}
EmailManager* EmailManager::getInstance()
{
static EmailManager theOne;
return &theOne;
}
bool EmailManager::init(const Poco::Util::LayeredConfiguration& cfg)
{
try {
mDisableEmail = cfg.getBool("email.disable", false);
if (!mDisableEmail) {
mEmailAccount.sender = cfg.getString("email.sender");
mEmailAccount.admin_receiver = cfg.getString("email.admin_receiver");
mEmailAccount.username = cfg.getString("email.username");
mEmailAccount.password = cfg.getString("email.password");
mEmailAccount.url = cfg.getString("email.smtp.url");
mEmailAccount.port = cfg.getInt("email.smtp.port");
}
}
catch (Poco::Exception& ex) {
printf("email account not set in config: %s\n", ex.displayText().data());
return false;
}
Thread::init("emails");
mInitalized = true;
DISASM_FALSERET;
ServerConfig::g_ServerKeySeed->put(3, DRRandom::r64());
return true;
}
void EmailManager::addEmail(model::Email* email) {
if (mDisableEmail) {
std::string log_message = "Email should be sended to: ";
auto email_user = email->getUser();
Poco::AutoPtr<model::table::User> email_model;
if (email_user) {
email_model = email_user->getModel();
log_message += email_model->getNameWithEmailHtml();
}
if (email_model.isNull()) {
log_message += "<missing>";
}
log_message += ", type: ";
log_message += model::Email::emailTypeString(email->getType());
mEmailLog.log(log_message);
delete email;
return;
}
mPendingEmails.push(email);
condSignal();
}
void EmailManager::exit()
{
model::Email* email = nullptr;
while (mPendingEmails.pop(email)) {
delete email;
}
mInitalized = false;
}
int EmailManager::ThreadFunction()
{
// prepare connection to email server
if (ServerConfig::g_disableEmail) return 0;
if (mPendingEmails.empty()) return 0;
auto lm = LanguageManager::getInstance();
Poco::Net::SecureSMTPClientSession mailClientSession(mEmailAccount.url, mEmailAccount.port);
mailClientSession.login();
try {
mailClientSession.startTLS(ServerConfig::g_SSL_CLient_Context);
mailClientSession.login(Poco::Net::SMTPClientSession::AUTH_LOGIN, mEmailAccount.username, mEmailAccount.password);
}
catch (Poco::Net::SSLException& ex) {
printf("[PrepareEmailTask] ssl certificate error: %s\nPlease make sure you have cacert.pem (CA/root certificates) next to binary from https://curl.haxx.se/docs/caextract.html\n", ex.displayText().data());
return -1;
}
model::Email* email = nullptr;
Poco::AutoPtr<LanguageCatalog> catalogs[2];
// if email list empty, wait 500ms x time before exit thread and closing connection
int timeoutWaits = 20;
while (mPendingEmails.pop(email) || timeoutWaits > 0) {
if (email) {
Poco::Net::MailMessage mailMessage;
mailMessage.setSender(mEmailAccount.sender);
Languages lang_code = ServerConfig::g_default_locale;
auto email_user = email->getUser();
if (email_user) {
Poco::AutoPtr<model::table::User> userModel = email_user->getModel();
if (!userModel.isNull()) {
lang_code = LanguageManager::languageFromString(userModel->getLanguageKey());
if (lang_code > LANG_COUNT) lang_code = ServerConfig::g_default_locale;
}
}
if (catalogs[lang_code].isNull()) {
catalogs[lang_code] = lm->getFreeCatalog(lang_code);
}
if (email->draft(&mailMessage, catalogs[lang_code])) {
mailClientSession.sendMessage(mailMessage);
// add for debugging
if (email_user) {
//printf("send email to %s\n", user_model->getEmail().data());
auto user_model = email_user->getModel();
std::string log_message = "Email sended to: ";
if (user_model) {
log_message += email_user->getModel()->getNameWithEmailHtml();
}
else {
log_message += "<missing>";
}
log_message += ", type: ";
log_message += model::Email::emailTypeString(email->getType());
mEmailLog.log(log_message);
}
}
else {
// error drafting email, shouldn't happend
printf("[EmailManager::ThreadFunction] Error drafting email\n");
}
delete email;
email = nullptr;
}
if (mPendingEmails.empty()) {
Poco::Thread::sleep(500);
timeoutWaits--;
}
}
mailClientSession.close();
return 0;
#include "EmailManager.h"
#include "../ServerConfig.h"
#include "../Crypto/Obfus_array.h"
#include "../Crypto/DRRandom.h"
#include "../SingletonManager/LanguageManager.h"
#include "Poco/Net/SecureSMTPClientSession.h"
#include "Poco/Net/SSLException.h"
EmailManager::EmailManager()
: Thread("emails", false), mEmailLog(Poco::Logger::get("emailLog")), mInitalized(false), mDisableEmail(false)
{
}
EmailManager::~EmailManager()
{
exit();
}
EmailManager* EmailManager::getInstance()
{
static EmailManager theOne;
return &theOne;
}
bool EmailManager::init(const Poco::Util::LayeredConfiguration& cfg)
{
try {
mDisableEmail = cfg.getBool("email.disable", false);
if (!mDisableEmail) {
mEmailAccount.sender = cfg.getString("email.sender");
mEmailAccount.admin_receiver = cfg.getString("email.admin_receiver");
mEmailAccount.username = cfg.getString("email.username");
mEmailAccount.password = cfg.getString("email.password");
mEmailAccount.url = cfg.getString("email.smtp.url");
mEmailAccount.port = cfg.getInt("email.smtp.port");
}
}
catch (Poco::Exception& ex) {
printf("email account not set in config: %s\n", ex.displayText().data());
return false;
}
Thread::init("emails");
mInitalized = true;
DISASM_FALSERET;
ServerConfig::g_ServerKeySeed->put(3, DRRandom::r64());
return true;
}
void EmailManager::addEmail(model::Email* email) {
if (mDisableEmail) {
std::string log_message = "Email should be sended to: ";
auto email_user = email->getUser();
Poco::AutoPtr<model::table::User> email_model;
if (email_user) {
email_model = email_user->getModel();
log_message += email_model->getNameWithEmailHtml();
}
if (email_model.isNull()) {
log_message += "<missing>";
}
log_message += ", type: ";
log_message += model::Email::emailTypeString(email->getType());
mEmailLog.log(log_message);
delete email;
return;
}
mPendingEmails.push(email);
condSignal();
}
void EmailManager::exit()
{
model::Email* email = nullptr;
while (mPendingEmails.pop(email)) {
delete email;
}
mInitalized = false;
}
int EmailManager::ThreadFunction()
{
// prepare connection to email server
if (ServerConfig::g_disableEmail) return 0;
if (mPendingEmails.empty()) return 0;
auto lm = LanguageManager::getInstance();
Poco::Net::SecureSMTPClientSession mailClientSession(mEmailAccount.url, mEmailAccount.port);
mailClientSession.login();
try {
mailClientSession.startTLS(ServerConfig::g_SSL_CLient_Context);
mailClientSession.login(Poco::Net::SMTPClientSession::AUTH_LOGIN, mEmailAccount.username, mEmailAccount.password);
}
catch (Poco::Net::SSLException& ex) {
printf("[PrepareEmailTask] ssl certificate error: %s\nPlease make sure you have cacert.pem (CA/root certificates) next to binary from https://curl.haxx.se/docs/caextract.html\n", ex.displayText().data());
return -1;
}
model::Email* email = nullptr;
Poco::AutoPtr<LanguageCatalog> catalogs[2];
// if email list empty, wait 500ms x time before exit thread and closing connection
int timeoutWaits = 20;
while (mPendingEmails.pop(email) || timeoutWaits > 0) {
if (email) {
Poco::Net::MailMessage mailMessage;
mailMessage.setSender(mEmailAccount.sender);
Languages lang_code = ServerConfig::g_default_locale;
auto email_user = email->getUser();
if (email_user) {
Poco::AutoPtr<model::table::User> userModel = email_user->getModel();
if (!userModel.isNull()) {
lang_code = LanguageManager::languageFromString(userModel->getLanguageKey());
if (lang_code > LANG_COUNT) lang_code = ServerConfig::g_default_locale;
}
}
if (catalogs[lang_code].isNull()) {
catalogs[lang_code] = lm->getFreeCatalog(lang_code);
}
if (email->draft(&mailMessage, catalogs[lang_code])) {
mailClientSession.sendMessage(mailMessage);
// add for debugging
if (email_user) {
//printf("send email to %s\n", user_model->getEmail().data());
auto user_model = email_user->getModel();
std::string log_message = "Email sended to: ";
if (user_model) {
log_message += email_user->getModel()->getNameWithEmailHtml();
}
else {
log_message += "<missing>";
}
log_message += ", type: ";
log_message += model::Email::emailTypeString(email->getType());
mEmailLog.log(log_message);
}
}
else {
// error drafting email, shouldn't happend
printf("[EmailManager::ThreadFunction] Error drafting email\n");
}
delete email;
email = nullptr;
}
if (mPendingEmails.empty()) {
Poco::Thread::sleep(500);
timeoutWaits--;
}
}
mailClientSession.close();
return 0;
}

View File

@ -1,47 +1,47 @@
#include "TransactionId.h"
#include "../../lib/DataTypeConverter.h"
namespace model {
namespace hedera {
TransactionId::TransactionId()
: shard(0), realm(0), num(0)
{
}
TransactionId::TransactionId(const proto::TransactionID& transaction)
{
auto account_id = transaction.accountid();
shard = account_id.shardnum();
realm = account_id.realmnum();
num = account_id.accountnum();
mTransactionValidStart = DataTypeConverter::convertFromProtoTimestamp(transaction.transactionvalidstart());
}
TransactionId::TransactionId(int shard, int realm, int num, Poco::Timestamp transactionValidStart)
: shard(shard), realm(realm), num(num), mTransactionValidStart(transactionValidStart)
{
}
TransactionId::~TransactionId()
{
}
Poco::JSON::Object::Ptr TransactionId::convertToJSON()
{
Poco::JSON::Object::Ptr result = new Poco::JSON::Object;
result->set("transactionValidStart", mTransactionValidStart);
Poco::JSON::Object accountId;
accountId.set("shard", shard);
accountId.set("realm", realm);
accountId.set("num", num);
result->set("accountId", accountId);
return result;
}
}
#include "TransactionId.h"
#include "../../lib/DataTypeConverter.h"
namespace model {
namespace hedera {
TransactionId::TransactionId()
: shard(0), realm(0), num(0)
{
}
TransactionId::TransactionId(const proto::TransactionID& transaction)
{
auto account_id = transaction.accountid();
shard = account_id.shardnum();
realm = account_id.realmnum();
num = account_id.accountnum();
mTransactionValidStart = DataTypeConverter::convertFromProtoTimestamp(transaction.transactionvalidstart());
}
TransactionId::TransactionId(int shard, int realm, int num, Poco::Timestamp transactionValidStart)
: shard(shard), realm(realm), num(num), mTransactionValidStart(transactionValidStart)
{
}
TransactionId::~TransactionId()
{
}
Poco::JSON::Object::Ptr TransactionId::convertToJSON()
{
Poco::JSON::Object::Ptr result = new Poco::JSON::Object;
result->set("transactionValidStart", mTransactionValidStart);
Poco::JSON::Object accountId;
accountId.set("shard", shard);
accountId.set("realm", realm);
accountId.set("num", num);
result->set("accountId", accountId);
return result;
}
}
}

View File

@ -1,424 +1,424 @@
<%@ page class="AdminNodeServerTestPage" %>
<%@ page form="true" %>
<%@ page compressed="true" %>
<%@ page baseClass="PageRequestMessagedHandler" %>
<%@ header include="PageRequestMessagedHandler.h" %>
<%!
#include "../controller/NodeServer.h"
#include "../controller/User.h"
#include "../controller/HederaTopic.h"
#include "../lib/DataTypeConverter.h"
#include "../lib/Profiler.h"
#include "../lib/JsonRPCRequest.h"
#include "../model/gradido/Transaction.h"
#include "Poco/Thread.h"
#include "Poco/DateTime.h"
#include "Poco/JSON/Stringifier.h"
enum PageType
{
PAGE_CHOOSE_TEST,
PAGE_RUN_4_SET_TEST,
PAGE_GET_TRANSACTION_RPC_CALL
};
%>
<%%
const char* pageName = "Node Server Test";
PageType page = PAGE_CHOOSE_TEST;
Poco::AutoPtr<controller::NodeServer> node_server;
Poco::AutoPtr<controller::NodeServer> node_server2;
Poco::AutoPtr<controller::User> user;
Poco::AutoPtr<controller::HederaTopic> hedera_topic;
Poco::AutoPtr<controller::HederaTopic> hedera_topic2;
int hedera_timeout = 4;
int sleep_ms_between_transactions = 1000;
bool steps[8]; memset(steps, 1, 8 * sizeof(bool));
if(!form.empty())
{
auto node_server_id_string = form.get("test-node-servers", "");
if(node_server_id_string != "") {
int node_server_id = 0;
if(DataTypeConverter::NUMBER_PARSE_OKAY == DataTypeConverter::strToInt(node_server_id_string, node_server_id )) {
node_server = controller::NodeServer::load(node_server_id);
}
}
node_server_id_string = form.get("test-node-servers2", "");
if(node_server_id_string != "") {
int node_server_id = 0;
if(DataTypeConverter::NUMBER_PARSE_OKAY == DataTypeConverter::strToInt(node_server_id_string, node_server_id )) {
node_server2 = controller::NodeServer::load(node_server_id);
}
}
auto topic_id_string = form.get("test-hedera-topic", "");
if(topic_id_string != "") {
int topic_id = 0;
if(DataTypeConverter::NUMBER_PARSE_OKAY == DataTypeConverter::strToInt(topic_id_string, topic_id)) {
hedera_topic = controller::HederaTopic::load(topic_id);
}
}
topic_id_string = form.get("test-hedera-topic2", "");
if(topic_id_string != "") {
int topic_id = 0;
if(DataTypeConverter::NUMBER_PARSE_OKAY == DataTypeConverter::strToInt(topic_id_string, topic_id)) {
hedera_topic2 = controller::HederaTopic::load(topic_id);
}
}
auto test_timeout_string = form.get("test-timeout", "");
if(test_timeout_string != "") {
DataTypeConverter::strToInt(test_timeout_string, hedera_timeout);
}
auto test_part_timeout_string = form.get("test-part-timeout", "");
if(test_part_timeout_string != "") {
DataTypeConverter::strToInt(test_part_timeout_string, sleep_ms_between_transactions);
}
auto submit = form.get("submit", "");
if(submit == "Run 6-Test") {
page = PAGE_RUN_4_SET_TEST;
} else if(submit == "json-rpc getTransactions") {
page = PAGE_GET_TRANSACTION_RPC_CALL;
}
std::string step_temp;
for(int i = 0; i < 8; i++) {
std::string name = "step-";
name += std::to_string(i+2);
step_temp = form.get(name, "");
if(step_temp == "1") {
steps[i] = true;
} else {
steps[i] = false;
}
}
}
auto node_servers = controller::NodeServer::load(model::table::NODE_SERVER_GRADIDO_NODE);
auto hedera_topics = controller::HederaTopic::listAll();
%><%@ include file="header_large.cpsp" %>
<%= getErrorsHtml() %>
<div class="center-form-container">
<!-- Tab links -->
<div class="tab">
<button class="tablinks <% if(PAGE_RUN_4_SET_TEST == page) { %> active <% } %>" onclick="openTab(event, 'test-4')">Test 6-Set (3 AddMember, Creation, 2 Transfer)</button>
<button class="tablinks <% if(PAGE_GET_TRANSACTION_RPC_CALL == page) { %> active <% } %>" onclick="openTab(event, 'gn-jsonrpc')" title="call via json-rpc to gradido node with getTransactions">getTransactions</button>
</div>
<div id="test-4" class="tabcontent" <% if(PAGE_RUN_4_SET_TEST == page) { %> style="display:block" <% } %>>
<div class="center-form-title">
<h3>Test 6-Set (3 AddMember, Creation, 2 Transfer)</</h3>
</div>
<div class="center-form-form">
<form method="POST" action="<%= getBaseUrl() %>/adminNodeServerTest">
<p>1. Create three new accounts and show user public keys for comparisation</p>
<p><input class="form-checkbox" type="checkbox" <% if(steps[0]) { %> checked="checked" <% } %> name="step-2" value="1"/> 2. Send a add-member transaction to hedera topic with one signature (first user)</p>
<p><input class="form-checkbox" type="checkbox" <% if(steps[1]) { %> checked="checked" <% } %> name="step-3" value="1"/> 3. Send a add-member transaction to hedera topic with two signatures (first user and second user)</p>
<p><input class="form-checkbox" type="checkbox" <% if(steps[2]) { %> checked="checked" <% } %> name="step-4" value="1"/> 4. Send a creation transaction to second user, signed by first user</p>
<p><input class="form-checkbox" type="checkbox" <% if(steps[3]) { %> checked="checked" <% } %> name="step-5" value="1"/> 5. Send a transfer transaction from second user to first user signed by second user</p>
<p><input class="form-checkbox" type="checkbox" <% if(steps[4]) { %> checked="checked" <% } %> name="step-6" value="1"/> 6. Send a add-member transaction to hedera topic 2 with one signature (third user)</p>
<p><input class="form-checkbox" type="checkbox" <% if(steps[5]) { %> checked="checked" <% } %> name="step-7" value="1"/> 7. Send a cross group transfer from second user to third user signed by second user</p>
<p><input class="form-checkbox" type="checkbox" <% if(steps[6]) { %> checked="checked" <% } %> name="step-8" value="1"/> 8. Wait x seconds to give hedera time to process transactions</p>
<p><input class="form-checkbox" type="checkbox" <% if(steps[7]) { %> checked="checked" <% } %> name="step-9" value="1"/> 9. Ask choosen node for transaction and print result</p>
<fieldset>
<legend>Group 1 </legend>
<label class="form-label" for="test-node-servers">Node Server for tests</label>
<% if(node_servers.size() == 0) { %>
<a href="<%= getBaseUrl() %>/nodes"><span class="link-title">Edit Node-Servers</span></a>
<% } %>
<select name="test-node-servers" id="test-node-servers">
<% for(auto it = node_servers.begin(); it != node_servers.end(); it++) {
auto model = (*it)->getModel();
%>
<option title="<%= model->toString() %>" value="<%= model->getID() %>" <% if(!node_server.isNull() && node_server->getModel()->getID() == model->getID()) {%>selected="selected"<% } %>><%= model->getUrlWithPort() %>, group: <%= model->getGroupId() %></option>
<% } %>
</select>
<label class="form-label" for="test-hedera-topic">Hedera Topic for tests</label>
<% if(hedera_topics.size() == 0) { %>
<a href="<%= getBaseUrl() %>/topic"><span class="link-title">Edit Hedera-Topics</span></a>
<% } %>
<select name="test-hedera-topic" id="test-hedera-topic">
<% for(auto it = hedera_topics.begin(); it != hedera_topics.end(); it++) {
auto model = (*it)->getModel();
auto hedera_account = (*it)->getAutoRenewAccount();
if(hedera_account->getModel()->getNetworkType() != ServerConfig::HEDERA_TESTNET) {
continue;
}
%>
<option title="<%= model->toString() %>" value="<%= model->getID() %>" <% if(!hedera_topic.isNull() && hedera_topic->getModel()->getID() == model->getID()) {%>selected="selected"<% } %>><%= model->getName() %>, group: <%= model->getGroupId() %></option>
<% } %>
</select>
</fieldset>
<fieldset>
<legend>Group 2 </legend>
<label class="form-label" for="test-node-servers2">Node Server for tests</label>
<% if(node_servers.size() == 0) { %>
<a href="<%= getBaseUrl() %>/nodes"><span class="link-title">Edit Node-Servers</span></a>
<% } %>
<select name="test-node-servers2" id="test-node-servers2">
<% for(auto it = node_servers.begin(); it != node_servers.end(); it++) {
auto model = (*it)->getModel();
%>
<option title="<%= model->toString() %>" value="<%= model->getID() %>" <% if(!node_server2.isNull() && node_server2->getModel()->getID() == model->getID()) {%>selected="selected"<% } %>><%= model->getUrlWithPort() %>, group: <%= model->getGroupId() %></option>
<% } %>
</select>
<label class="form-label" for="test-hedera-topic2">Hedera Topic for tests</label>
<% if(hedera_topics.size() == 0) { %>
<a href="<%= getBaseUrl() %>/topic"><span class="link-title">Edit Hedera-Topics</span></a>
<% } %>
<select name="test-hedera-topic2" id="test-hedera-topic2">
<% for(auto it = hedera_topics.begin(); it != hedera_topics.end(); it++) {
auto model = (*it)->getModel();
auto hedera_account = (*it)->getAutoRenewAccount();
if(hedera_account->getModel()->getNetworkType() != ServerConfig::HEDERA_TESTNET) {
continue;
}
%>
<option title="<%= model->toString() %>" value="<%= model->getID() %>" <% if(!hedera_topic2.isNull() && hedera_topic2->getModel()->getID() == model->getID()) {%>selected="selected"<% } %>><%= model->getName() %>, group: <%= model->getGroupId() %></option>
<% } %>
</select>
</fieldset>
<label class="form-label" for="test-timeout">Timeout waiting for hedera in seconds</label>
<input name="test-timeout" id="test-timeout" type="number" value="<%= hedera_timeout %>"> seconds
<label class="form-label" for="test-part-timeout">Timeout between transactions to prevent out-of-order</label>
<input name="test-part-timeout" id="test-part-timeout" type="number" value="<%= sleep_ms_between_transactions %>"> ms
<input class="center-form-submit form-button" type="submit" name="submit" value="Run 6-Test">
</form>
</div>
</div>
<div id="gn-jsonrpc" class="tabcontent" <% if(PAGE_GET_TRANSACTION_RPC_CALL == page) { %> style="display:block" <% } %>>
<div class="center-form-title">
<h3>Test 4-Set (2 AddMember, Creation, Transfer)</</h3>
</div>
<div class="center-form-form">
<form method="POST" action="<%= getBaseUrl() %>/adminNodeServerTest">
<label class="form-label" for="test-node-servers">Node Server to call</label>
<% if(node_servers.size() == 0) { %>
<a href="<%= getBaseUrl() %>/nodes"><span class="link-title">Edit Node-Servers</span></a>
<% } %>
<select name="test-node-servers" id="test-node-servers">
<% for(auto it = node_servers.begin(); it != node_servers.end(); it++) {
auto model = (*it)->getModel();
%>
<option title="<%= model->toString() %>" value="<%= model->getID() %>" <% if(!node_server.isNull() && node_server->getModel()->getID() == model->getID()) {%>selected="selected"<% } %>><%= model->getUrlWithPort() %>, group: <%= model->getGroupId() %></option>
<% } %>
</select>
<input class="center-form-submit form-button" type="submit" name="submit" value="json-rpc getTransactions">
</form>
</div>
</div>
<% if(PAGE_RUN_4_SET_TEST == page && !hedera_topic.isNull() && !node_server.isNull()) { %>
<ul>
<li>
<p>1. Create three new accounts and show user public keys for comparisation: </p>
<%
Profiler time2;
auto group_id = hedera_topic->getModel()->getGroupId();
auto group_id2 = hedera_topic2->getModel()->getGroupId();
auto user_group = controller::Group::load(group_id);
auto user_group2 = controller::Group::load(group_id2);
auto mnemonic_type = ServerConfig::MNEMONIC_BIP0039_SORTED_ORDER;
std::string password1 = "hsaj(2askaslASlllak3wjjeudsaj";
auto user_1 = controller::User::create("testEmail@google.de", "Max", "Mustermann", group_id);
auto passphrase_1 = Passphrase::generate(&ServerConfig::g_Mnemonic_WordLists[mnemonic_type]);
auto gradido_key_pair_1 = KeyPairEd25519::create(passphrase_1);
user_1->setGradidoKeyPair(gradido_key_pair_1);
user_1->login(password1);
std::string password2 = "uweia8saiSale,dsasA";
auto user_2 = controller::User::create("testEmail2@google.de", "MJax", "Mustrermann", group_id);
auto passphrase_2 = Passphrase::generate(&ServerConfig::g_Mnemonic_WordLists[mnemonic_type]);
auto gradido_key_pair_2 = KeyPairEd25519::create(passphrase_2);
user_2->setGradidoKeyPair(gradido_key_pair_2);
user_2->login(password2);
std::string password3 = "jaue_skaiellasealaK";
auto user_3 = controller::User::create("testEmail3@gmail.com", "Morpheus", "Miaufull", group_id2);
auto passphrase_3 = Passphrase::generate(&ServerConfig::g_Mnemonic_WordLists[mnemonic_type]);
auto gradido_key_pair_3 = KeyPairEd25519::create(passphrase_3);
user_3->setGradidoKeyPair(gradido_key_pair_3);
user_3->login(password3);
%>
<fieldset><legend><%= user_group->getModel()->getName() %></legend>
<p>User 1: <%= user_1->getPublicHex() %></p>
<p>User 2: <%= user_2->getPublicHex() %></p>
</fieldset>
<fieldset><legend><%= user_group2->getModel()->getName() %></legend>
<p>User 3: <%= user_3->getPublicHex() %></p>
</fieldset>
<p>Time: <%= time2.string() %>
</li>
<li>
<p>2. Send a add-member transaction to hedera topic with one signature (first user)</p>
<%
time2.reset();
if(!steps[0]) { %>
<p>skipped</p>
<% } else {
auto transaction1 = model::gradido::Transaction::createGroupMemberUpdate(user_1, user_group);
transaction1->getTransactionBody()->getGroupMemberUpdate()->setMinSignatureCount(1);
transaction1->sign(user_1);
auto transaction1_json = transaction1->getTransactionAsJson(true);
%>
<p><%= DataTypeConverter::replaceNewLineWithBr(transaction1_json) %></p>
<% } %>
<p>Time: <%= time2.string() %>
</li>
<li>
<p>3. Send a add-member transaction to hedera topic with two signatures (first user and second user)</p>
<%
time2.reset();
if(!steps[1]) { %>
<p>skipped</p>
<% } else {
auto transaction2 = model::gradido::Transaction::createGroupMemberUpdate(user_2, user_group);
transaction2->getTransactionBody()->getGroupMemberUpdate()->setMinSignatureCount(2);
transaction2->sign(user_2);
// wait before sending fourth transaction, gn seems to crash by more than 3 transaction at nearly the same time
Poco::Thread::sleep(sleep_ms_between_transactions);
transaction2->sign(user_1);
auto transaction2_json = transaction2->getTransactionAsJson(true);
%>
<p><%= DataTypeConverter::replaceNewLineWithBr(transaction2_json) %></p>
<% } %>
<p>Time: <%= time2.string() %>
</li>
<li>
<p>4. Send a creation transaction to second user, signed by first user</p>
<%
time2.reset();
if(!steps[2]) { %>
<p>skipped</p>
<% } else {
auto transaction3 = model::gradido::Transaction::createCreation(user_2, 10000000, Poco::DateTime(), "Test Creation");
// wait before sending fourth transaction, gn seems to crash by more than 3 transaction at nearly the same time
Poco::Thread::sleep(sleep_ms_between_transactions);
transaction3->sign(user_1);
auto transaction3_json = transaction3->getTransactionAsJson(true);
%>
<p><%= DataTypeConverter::replaceNewLineWithBr(transaction3_json) %></p>
<% } %>
<p>Time: <%= time2.string() %></p>
</li>
<li>
<p>5. Send a transfer transaction from second user to first user signed by second user</p>
<%
time2.reset();
if(!steps[3]) { %>
<p>skipped</p>
<% } else {
auto user_1_pubkey = user_1->getModel()->getPublicKeyCopy();
auto transaction4 = model::gradido::Transaction::createTransfer(user_2, user_1_pubkey, user_group, 5000000, "Test Transfer");
// wait before sending fourth transaction, gn seems to crash by more than 3 transaction at nearly the same time
Poco::Thread::sleep(sleep_ms_between_transactions);
transaction4[0]->sign(user_2);
auto transaction4_json = transaction4[0]->getTransactionAsJson(true);
%>
<p><%= DataTypeConverter::replaceNewLineWithBr(transaction4_json) %></p>
<% } %>
<p>Time: <%= time2.string() %></p>
</li>
<li>
<p>6. Send a add-member transaction to hedera topic 2 with one signature (third user)</p>
<%
time2.reset();
if(!steps[4]) { %>
<p>skipped</p>
<% } else {
auto transaction5 = model::gradido::Transaction::createGroupMemberUpdate(user_3, user_group2);
transaction5->getTransactionBody()->getGroupMemberUpdate()->setMinSignatureCount(1);
Poco::Thread::sleep(sleep_ms_between_transactions);
transaction5->sign(user_3);
auto transaction5_json = transaction5->getTransactionAsJson(true);
%>
<p><%= DataTypeConverter::replaceNewLineWithBr(transaction5_json) %></p>
<% } %>
<p>Time: <%= time2.string() %></p>
</li>
<li>
<p>7. Send a cross group transfer from second user to third user signed by second user</p>
<%
time2.reset();
if(!steps[5]) { %>
<p>skipped</p>
<% } else {
auto user_3_pubkey = user_3->getModel()->getPublicKeyCopy();
auto transaction6 = model::gradido::Transaction::createTransfer(user_2, user_3_pubkey, user_group2, 4000000, "Test Group Transfer", false);
if(!transaction6.size()) {
%>
<div class="alert alert-error" role="alert">
<i class="material-icons-outlined">report_problem</i>
<span>Error creating Transaction</span>
</div>
<%
} else {
Poco::Thread::sleep(sleep_ms_between_transactions);
transaction6[0]->sign(user_2);
auto transaction6_json = transaction6[0]->getTransactionAsJson(true);
auto paired_transaction = transaction6[0]->getPairedTransaction();
%>
<p><%= DataTypeConverter::replaceNewLineWithBr(transaction6_json) %></p>
<% if(!paired_transaction.isNull()) {
auto transaction6_2_json = paired_transaction->getTransactionAsJson(true);
%><p><%= DataTypeConverter::replaceNewLineWithBr(transaction6_2_json) %></p>
<% } %>
<% } %>
<% } %>
<p>Time: <%= time2.string() %></p>
</li>
<li>
<p>8. Wait <%= hedera_timeout %> seconds to give hedera time to process transactions</p>
<% if(!steps[6]) { %>
<p>skipped</p>
<% } else {
Poco::Thread::sleep(hedera_timeout * 1000);
} %>
</li>
<li>
<p>9. Ask choosen node for transaction and print result</p>
<% time2.reset();
if(!steps[7] || node_server.isNull()) {
%><p>skipped</p>
<% } else {
auto node_server_model = node_server->getModel();
JsonRPCRequest jsonrpc(node_server_model->getUrl(), node_server_model->getPort());
Poco::JSON::Object params;
params.set("groupAlias", user_group->getModel()->getAlias());
params.set("lastKnownSequenceNumber", 0);
auto gn_answear = jsonrpc.request("getTransactions", params);
if(!gn_answear.isNull()) {
std::stringstream ss;
Poco::JSON::Stringifier::stringify(gn_answear, ss, 4, -1, Poco::JSON_PRESERVE_KEY_ORDER);
std::string answear_string = ss.str(); %>
<%= DataTypeConverter::replaceNewLineWithBr(answear_string) %><%
}
} %>
<p>Time: <%= time2.string() %></p>
</li>
</ul>
<% } else if(PAGE_GET_TRANSACTION_RPC_CALL == page && !node_server.isNull()) {
Profiler time3;
auto node_server_model = node_server->getModel();
auto user_group = controller::Group::load(node_server_model->getGroupId());
JsonRPCRequest jsonrpc(node_server_model->getUrl(), node_server_model->getPort());
Poco::JSON::Object params;
params.set("groupAlias", user_group->getModel()->getAlias());
params.set("lastKnownSequenceNumber", 0);
auto gn_answear = jsonrpc.request("getTransactions", params);
if(!gn_answear.isNull()) {
std::stringstream ss;
Poco::JSON::Stringifier::stringify(gn_answear, ss, 4, -1, Poco::JSON_PRESERVE_KEY_ORDER);
std::string answear_string = ss.str();%>
<%= DataTypeConverter::replaceNewLineWithBr(answear_string) %><%
}
%>
<p>Time: <%= time3.string() %></p>
<% } %>
</div>
<script type="text/javascript" src="<%= ServerConfig::g_php_serverPath %>/js/tabs.js"></script>
<%@ include file="footer.cpsp" %>
<%@ page class="AdminNodeServerTestPage" %>
<%@ page form="true" %>
<%@ page compressed="true" %>
<%@ page baseClass="PageRequestMessagedHandler" %>
<%@ header include="PageRequestMessagedHandler.h" %>
<%!
#include "../controller/NodeServer.h"
#include "../controller/User.h"
#include "../controller/HederaTopic.h"
#include "../lib/DataTypeConverter.h"
#include "../lib/Profiler.h"
#include "../lib/JsonRPCRequest.h"
#include "../model/gradido/Transaction.h"
#include "Poco/Thread.h"
#include "Poco/DateTime.h"
#include "Poco/JSON/Stringifier.h"
enum PageType
{
PAGE_CHOOSE_TEST,
PAGE_RUN_4_SET_TEST,
PAGE_GET_TRANSACTION_RPC_CALL
};
%>
<%%
const char* pageName = "Node Server Test";
PageType page = PAGE_CHOOSE_TEST;
Poco::AutoPtr<controller::NodeServer> node_server;
Poco::AutoPtr<controller::NodeServer> node_server2;
Poco::AutoPtr<controller::User> user;
Poco::AutoPtr<controller::HederaTopic> hedera_topic;
Poco::AutoPtr<controller::HederaTopic> hedera_topic2;
int hedera_timeout = 4;
int sleep_ms_between_transactions = 1000;
bool steps[8]; memset(steps, 1, 8 * sizeof(bool));
if(!form.empty())
{
auto node_server_id_string = form.get("test-node-servers", "");
if(node_server_id_string != "") {
int node_server_id = 0;
if(DataTypeConverter::NUMBER_PARSE_OKAY == DataTypeConverter::strToInt(node_server_id_string, node_server_id )) {
node_server = controller::NodeServer::load(node_server_id);
}
}
node_server_id_string = form.get("test-node-servers2", "");
if(node_server_id_string != "") {
int node_server_id = 0;
if(DataTypeConverter::NUMBER_PARSE_OKAY == DataTypeConverter::strToInt(node_server_id_string, node_server_id )) {
node_server2 = controller::NodeServer::load(node_server_id);
}
}
auto topic_id_string = form.get("test-hedera-topic", "");
if(topic_id_string != "") {
int topic_id = 0;
if(DataTypeConverter::NUMBER_PARSE_OKAY == DataTypeConverter::strToInt(topic_id_string, topic_id)) {
hedera_topic = controller::HederaTopic::load(topic_id);
}
}
topic_id_string = form.get("test-hedera-topic2", "");
if(topic_id_string != "") {
int topic_id = 0;
if(DataTypeConverter::NUMBER_PARSE_OKAY == DataTypeConverter::strToInt(topic_id_string, topic_id)) {
hedera_topic2 = controller::HederaTopic::load(topic_id);
}
}
auto test_timeout_string = form.get("test-timeout", "");
if(test_timeout_string != "") {
DataTypeConverter::strToInt(test_timeout_string, hedera_timeout);
}
auto test_part_timeout_string = form.get("test-part-timeout", "");
if(test_part_timeout_string != "") {
DataTypeConverter::strToInt(test_part_timeout_string, sleep_ms_between_transactions);
}
auto submit = form.get("submit", "");
if(submit == "Run 6-Test") {
page = PAGE_RUN_4_SET_TEST;
} else if(submit == "json-rpc getTransactions") {
page = PAGE_GET_TRANSACTION_RPC_CALL;
}
std::string step_temp;
for(int i = 0; i < 8; i++) {
std::string name = "step-";
name += std::to_string(i+2);
step_temp = form.get(name, "");
if(step_temp == "1") {
steps[i] = true;
} else {
steps[i] = false;
}
}
}
auto node_servers = controller::NodeServer::load(model::table::NODE_SERVER_GRADIDO_NODE);
auto hedera_topics = controller::HederaTopic::listAll();
%><%@ include file="header_large.cpsp" %>
<%= getErrorsHtml() %>
<div class="center-form-container">
<!-- Tab links -->
<div class="tab">
<button class="tablinks <% if(PAGE_RUN_4_SET_TEST == page) { %> active <% } %>" onclick="openTab(event, 'test-4')">Test 6-Set (3 AddMember, Creation, 2 Transfer)</button>
<button class="tablinks <% if(PAGE_GET_TRANSACTION_RPC_CALL == page) { %> active <% } %>" onclick="openTab(event, 'gn-jsonrpc')" title="call via json-rpc to gradido node with getTransactions">getTransactions</button>
</div>
<div id="test-4" class="tabcontent" <% if(PAGE_RUN_4_SET_TEST == page) { %> style="display:block" <% } %>>
<div class="center-form-title">
<h3>Test 6-Set (3 AddMember, Creation, 2 Transfer)</</h3>
</div>
<div class="center-form-form">
<form method="POST" action="<%= getBaseUrl() %>/adminNodeServerTest">
<p>1. Create three new accounts and show user public keys for comparisation</p>
<p><input class="form-checkbox" type="checkbox" <% if(steps[0]) { %> checked="checked" <% } %> name="step-2" value="1"/> 2. Send a add-member transaction to hedera topic with one signature (first user)</p>
<p><input class="form-checkbox" type="checkbox" <% if(steps[1]) { %> checked="checked" <% } %> name="step-3" value="1"/> 3. Send a add-member transaction to hedera topic with two signatures (first user and second user)</p>
<p><input class="form-checkbox" type="checkbox" <% if(steps[2]) { %> checked="checked" <% } %> name="step-4" value="1"/> 4. Send a creation transaction to second user, signed by first user</p>
<p><input class="form-checkbox" type="checkbox" <% if(steps[3]) { %> checked="checked" <% } %> name="step-5" value="1"/> 5. Send a transfer transaction from second user to first user signed by second user</p>
<p><input class="form-checkbox" type="checkbox" <% if(steps[4]) { %> checked="checked" <% } %> name="step-6" value="1"/> 6. Send a add-member transaction to hedera topic 2 with one signature (third user)</p>
<p><input class="form-checkbox" type="checkbox" <% if(steps[5]) { %> checked="checked" <% } %> name="step-7" value="1"/> 7. Send a cross group transfer from second user to third user signed by second user</p>
<p><input class="form-checkbox" type="checkbox" <% if(steps[6]) { %> checked="checked" <% } %> name="step-8" value="1"/> 8. Wait x seconds to give hedera time to process transactions</p>
<p><input class="form-checkbox" type="checkbox" <% if(steps[7]) { %> checked="checked" <% } %> name="step-9" value="1"/> 9. Ask choosen node for transaction and print result</p>
<fieldset>
<legend>Group 1 </legend>
<label class="form-label" for="test-node-servers">Node Server for tests</label>
<% if(node_servers.size() == 0) { %>
<a href="<%= getBaseUrl() %>/nodes"><span class="link-title">Edit Node-Servers</span></a>
<% } %>
<select name="test-node-servers" id="test-node-servers">
<% for(auto it = node_servers.begin(); it != node_servers.end(); it++) {
auto model = (*it)->getModel();
%>
<option title="<%= model->toString() %>" value="<%= model->getID() %>" <% if(!node_server.isNull() && node_server->getModel()->getID() == model->getID()) {%>selected="selected"<% } %>><%= model->getUrlWithPort() %>, group: <%= model->getGroupId() %></option>
<% } %>
</select>
<label class="form-label" for="test-hedera-topic">Hedera Topic for tests</label>
<% if(hedera_topics.size() == 0) { %>
<a href="<%= getBaseUrl() %>/topic"><span class="link-title">Edit Hedera-Topics</span></a>
<% } %>
<select name="test-hedera-topic" id="test-hedera-topic">
<% for(auto it = hedera_topics.begin(); it != hedera_topics.end(); it++) {
auto model = (*it)->getModel();
auto hedera_account = (*it)->getAutoRenewAccount();
if(hedera_account->getModel()->getNetworkType() != ServerConfig::HEDERA_TESTNET) {
continue;
}
%>
<option title="<%= model->toString() %>" value="<%= model->getID() %>" <% if(!hedera_topic.isNull() && hedera_topic->getModel()->getID() == model->getID()) {%>selected="selected"<% } %>><%= model->getName() %>, group: <%= model->getGroupId() %></option>
<% } %>
</select>
</fieldset>
<fieldset>
<legend>Group 2 </legend>
<label class="form-label" for="test-node-servers2">Node Server for tests</label>
<% if(node_servers.size() == 0) { %>
<a href="<%= getBaseUrl() %>/nodes"><span class="link-title">Edit Node-Servers</span></a>
<% } %>
<select name="test-node-servers2" id="test-node-servers2">
<% for(auto it = node_servers.begin(); it != node_servers.end(); it++) {
auto model = (*it)->getModel();
%>
<option title="<%= model->toString() %>" value="<%= model->getID() %>" <% if(!node_server2.isNull() && node_server2->getModel()->getID() == model->getID()) {%>selected="selected"<% } %>><%= model->getUrlWithPort() %>, group: <%= model->getGroupId() %></option>
<% } %>
</select>
<label class="form-label" for="test-hedera-topic2">Hedera Topic for tests</label>
<% if(hedera_topics.size() == 0) { %>
<a href="<%= getBaseUrl() %>/topic"><span class="link-title">Edit Hedera-Topics</span></a>
<% } %>
<select name="test-hedera-topic2" id="test-hedera-topic2">
<% for(auto it = hedera_topics.begin(); it != hedera_topics.end(); it++) {
auto model = (*it)->getModel();
auto hedera_account = (*it)->getAutoRenewAccount();
if(hedera_account->getModel()->getNetworkType() != ServerConfig::HEDERA_TESTNET) {
continue;
}
%>
<option title="<%= model->toString() %>" value="<%= model->getID() %>" <% if(!hedera_topic2.isNull() && hedera_topic2->getModel()->getID() == model->getID()) {%>selected="selected"<% } %>><%= model->getName() %>, group: <%= model->getGroupId() %></option>
<% } %>
</select>
</fieldset>
<label class="form-label" for="test-timeout">Timeout waiting for hedera in seconds</label>
<input name="test-timeout" id="test-timeout" type="number" value="<%= hedera_timeout %>"> seconds
<label class="form-label" for="test-part-timeout">Timeout between transactions to prevent out-of-order</label>
<input name="test-part-timeout" id="test-part-timeout" type="number" value="<%= sleep_ms_between_transactions %>"> ms
<input class="center-form-submit form-button" type="submit" name="submit" value="Run 6-Test">
</form>
</div>
</div>
<div id="gn-jsonrpc" class="tabcontent" <% if(PAGE_GET_TRANSACTION_RPC_CALL == page) { %> style="display:block" <% } %>>
<div class="center-form-title">
<h3>Test 4-Set (2 AddMember, Creation, Transfer)</</h3>
</div>
<div class="center-form-form">
<form method="POST" action="<%= getBaseUrl() %>/adminNodeServerTest">
<label class="form-label" for="test-node-servers">Node Server to call</label>
<% if(node_servers.size() == 0) { %>
<a href="<%= getBaseUrl() %>/nodes"><span class="link-title">Edit Node-Servers</span></a>
<% } %>
<select name="test-node-servers" id="test-node-servers">
<% for(auto it = node_servers.begin(); it != node_servers.end(); it++) {
auto model = (*it)->getModel();
%>
<option title="<%= model->toString() %>" value="<%= model->getID() %>" <% if(!node_server.isNull() && node_server->getModel()->getID() == model->getID()) {%>selected="selected"<% } %>><%= model->getUrlWithPort() %>, group: <%= model->getGroupId() %></option>
<% } %>
</select>
<input class="center-form-submit form-button" type="submit" name="submit" value="json-rpc getTransactions">
</form>
</div>
</div>
<% if(PAGE_RUN_4_SET_TEST == page && !hedera_topic.isNull() && !node_server.isNull()) { %>
<ul>
<li>
<p>1. Create three new accounts and show user public keys for comparisation: </p>
<%
Profiler time2;
auto group_id = hedera_topic->getModel()->getGroupId();
auto group_id2 = hedera_topic2->getModel()->getGroupId();
auto user_group = controller::Group::load(group_id);
auto user_group2 = controller::Group::load(group_id2);
auto mnemonic_type = ServerConfig::MNEMONIC_BIP0039_SORTED_ORDER;
std::string password1 = "hsaj(2askaslASlllak3wjjeudsaj";
auto user_1 = controller::User::create("testEmail@google.de", "Max", "Mustermann", group_id);
auto passphrase_1 = Passphrase::generate(&ServerConfig::g_Mnemonic_WordLists[mnemonic_type]);
auto gradido_key_pair_1 = KeyPairEd25519::create(passphrase_1);
user_1->setGradidoKeyPair(gradido_key_pair_1);
user_1->login(password1);
std::string password2 = "uweia8saiSale,dsasA";
auto user_2 = controller::User::create("testEmail2@google.de", "MJax", "Mustrermann", group_id);
auto passphrase_2 = Passphrase::generate(&ServerConfig::g_Mnemonic_WordLists[mnemonic_type]);
auto gradido_key_pair_2 = KeyPairEd25519::create(passphrase_2);
user_2->setGradidoKeyPair(gradido_key_pair_2);
user_2->login(password2);
std::string password3 = "jaue_skaiellasealaK";
auto user_3 = controller::User::create("testEmail3@gmail.com", "Morpheus", "Miaufull", group_id2);
auto passphrase_3 = Passphrase::generate(&ServerConfig::g_Mnemonic_WordLists[mnemonic_type]);
auto gradido_key_pair_3 = KeyPairEd25519::create(passphrase_3);
user_3->setGradidoKeyPair(gradido_key_pair_3);
user_3->login(password3);
%>
<fieldset><legend><%= user_group->getModel()->getName() %></legend>
<p>User 1: <%= user_1->getPublicHex() %></p>
<p>User 2: <%= user_2->getPublicHex() %></p>
</fieldset>
<fieldset><legend><%= user_group2->getModel()->getName() %></legend>
<p>User 3: <%= user_3->getPublicHex() %></p>
</fieldset>
<p>Time: <%= time2.string() %>
</li>
<li>
<p>2. Send a add-member transaction to hedera topic with one signature (first user)</p>
<%
time2.reset();
if(!steps[0]) { %>
<p>skipped</p>
<% } else {
auto transaction1 = model::gradido::Transaction::createGroupMemberUpdate(user_1, user_group);
transaction1->getTransactionBody()->getGroupMemberUpdate()->setMinSignatureCount(1);
transaction1->sign(user_1);
auto transaction1_json = transaction1->getTransactionAsJson(true);
%>
<p><%= DataTypeConverter::replaceNewLineWithBr(transaction1_json) %></p>
<% } %>
<p>Time: <%= time2.string() %>
</li>
<li>
<p>3. Send a add-member transaction to hedera topic with two signatures (first user and second user)</p>
<%
time2.reset();
if(!steps[1]) { %>
<p>skipped</p>
<% } else {
auto transaction2 = model::gradido::Transaction::createGroupMemberUpdate(user_2, user_group);
transaction2->getTransactionBody()->getGroupMemberUpdate()->setMinSignatureCount(2);
transaction2->sign(user_2);
// wait before sending fourth transaction, gn seems to crash by more than 3 transaction at nearly the same time
Poco::Thread::sleep(sleep_ms_between_transactions);
transaction2->sign(user_1);
auto transaction2_json = transaction2->getTransactionAsJson(true);
%>
<p><%= DataTypeConverter::replaceNewLineWithBr(transaction2_json) %></p>
<% } %>
<p>Time: <%= time2.string() %>
</li>
<li>
<p>4. Send a creation transaction to second user, signed by first user</p>
<%
time2.reset();
if(!steps[2]) { %>
<p>skipped</p>
<% } else {
auto transaction3 = model::gradido::Transaction::createCreation(user_2, 10000000, Poco::DateTime(), "Test Creation");
// wait before sending fourth transaction, gn seems to crash by more than 3 transaction at nearly the same time
Poco::Thread::sleep(sleep_ms_between_transactions);
transaction3->sign(user_1);
auto transaction3_json = transaction3->getTransactionAsJson(true);
%>
<p><%= DataTypeConverter::replaceNewLineWithBr(transaction3_json) %></p>
<% } %>
<p>Time: <%= time2.string() %></p>
</li>
<li>
<p>5. Send a transfer transaction from second user to first user signed by second user</p>
<%
time2.reset();
if(!steps[3]) { %>
<p>skipped</p>
<% } else {
auto user_1_pubkey = user_1->getModel()->getPublicKeyCopy();
auto transaction4 = model::gradido::Transaction::createTransfer(user_2, user_1_pubkey, user_group, 5000000, "Test Transfer");
// wait before sending fourth transaction, gn seems to crash by more than 3 transaction at nearly the same time
Poco::Thread::sleep(sleep_ms_between_transactions);
transaction4[0]->sign(user_2);
auto transaction4_json = transaction4[0]->getTransactionAsJson(true);
%>
<p><%= DataTypeConverter::replaceNewLineWithBr(transaction4_json) %></p>
<% } %>
<p>Time: <%= time2.string() %></p>
</li>
<li>
<p>6. Send a add-member transaction to hedera topic 2 with one signature (third user)</p>
<%
time2.reset();
if(!steps[4]) { %>
<p>skipped</p>
<% } else {
auto transaction5 = model::gradido::Transaction::createGroupMemberUpdate(user_3, user_group2);
transaction5->getTransactionBody()->getGroupMemberUpdate()->setMinSignatureCount(1);
Poco::Thread::sleep(sleep_ms_between_transactions);
transaction5->sign(user_3);
auto transaction5_json = transaction5->getTransactionAsJson(true);
%>
<p><%= DataTypeConverter::replaceNewLineWithBr(transaction5_json) %></p>
<% } %>
<p>Time: <%= time2.string() %></p>
</li>
<li>
<p>7. Send a cross group transfer from second user to third user signed by second user</p>
<%
time2.reset();
if(!steps[5]) { %>
<p>skipped</p>
<% } else {
auto user_3_pubkey = user_3->getModel()->getPublicKeyCopy();
auto transaction6 = model::gradido::Transaction::createTransfer(user_2, user_3_pubkey, user_group2, 4000000, "Test Group Transfer", false);
if(!transaction6.size()) {
%>
<div class="alert alert-error" role="alert">
<i class="material-icons-outlined">report_problem</i>
<span>Error creating Transaction</span>
</div>
<%
} else {
Poco::Thread::sleep(sleep_ms_between_transactions);
transaction6[0]->sign(user_2);
auto transaction6_json = transaction6[0]->getTransactionAsJson(true);
auto paired_transaction = transaction6[0]->getPairedTransaction();
%>
<p><%= DataTypeConverter::replaceNewLineWithBr(transaction6_json) %></p>
<% if(!paired_transaction.isNull()) {
auto transaction6_2_json = paired_transaction->getTransactionAsJson(true);
%><p><%= DataTypeConverter::replaceNewLineWithBr(transaction6_2_json) %></p>
<% } %>
<% } %>
<% } %>
<p>Time: <%= time2.string() %></p>
</li>
<li>
<p>8. Wait <%= hedera_timeout %> seconds to give hedera time to process transactions</p>
<% if(!steps[6]) { %>
<p>skipped</p>
<% } else {
Poco::Thread::sleep(hedera_timeout * 1000);
} %>
</li>
<li>
<p>9. Ask choosen node for transaction and print result</p>
<% time2.reset();
if(!steps[7] || node_server.isNull()) {
%><p>skipped</p>
<% } else {
auto node_server_model = node_server->getModel();
JsonRPCRequest jsonrpc(node_server_model->getUrl(), node_server_model->getPort());
Poco::JSON::Object params;
params.set("groupAlias", user_group->getModel()->getAlias());
params.set("lastKnownSequenceNumber", 0);
auto gn_answear = jsonrpc.request("getTransactions", params);
if(!gn_answear.isNull()) {
std::stringstream ss;
Poco::JSON::Stringifier::stringify(gn_answear, ss, 4, -1, Poco::JSON_PRESERVE_KEY_ORDER);
std::string answear_string = ss.str(); %>
<%= DataTypeConverter::replaceNewLineWithBr(answear_string) %><%
}
} %>
<p>Time: <%= time2.string() %></p>
</li>
</ul>
<% } else if(PAGE_GET_TRANSACTION_RPC_CALL == page && !node_server.isNull()) {
Profiler time3;
auto node_server_model = node_server->getModel();
auto user_group = controller::Group::load(node_server_model->getGroupId());
JsonRPCRequest jsonrpc(node_server_model->getUrl(), node_server_model->getPort());
Poco::JSON::Object params;
params.set("groupAlias", user_group->getModel()->getAlias());
params.set("lastKnownSequenceNumber", 0);
auto gn_answear = jsonrpc.request("getTransactions", params);
if(!gn_answear.isNull()) {
std::stringstream ss;
Poco::JSON::Stringifier::stringify(gn_answear, ss, 4, -1, Poco::JSON_PRESERVE_KEY_ORDER);
std::string answear_string = ss.str();%>
<%= DataTypeConverter::replaceNewLineWithBr(answear_string) %><%
}
%>
<p>Time: <%= time3.string() %></p>
<% } %>
</div>
<script type="text/javascript" src="<%= ServerConfig::g_php_serverPath %>/js/tabs.js"></script>
<%@ include file="footer.cpsp" %>