mirror of
https://github.com/IT4Change/gradido.git
synced 2025-12-13 07:45:54 +00:00
replace \r\n with \n
This commit is contained in:
parent
9946cc0e13
commit
55334799cb
@ -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'];
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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>
|
||||
*/
|
||||
|
||||
@ -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>
|
||||
*/
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
@ -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
2
gn
@ -1 +1 @@
|
||||
Subproject commit a61871987261614102b11ed58791081be1954d3c
|
||||
Subproject commit 5437e2f882c54efe4f501f7cd0d97f53806d0b74
|
||||
@ -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
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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;
|
||||
|
||||
}
|
||||
@ -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");
|
||||
|
||||
|
||||
|
||||
}
|
||||
@ -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_
|
||||
@ -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_
|
||||
@ -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;
|
||||
}
|
||||
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@ -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" %>
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user