Skip to content

Commit

Permalink
Merge pull request #6 from com-chain/webhook
Browse files Browse the repository at this point in the history
Webhook
  • Loading branch information
FlorianDubath authored Dec 11, 2019
2 parents c0aa877 + 96af2cb commit 84ecb5c
Show file tree
Hide file tree
Showing 6 changed files with 221 additions and 60 deletions.
97 changes: 97 additions & 0 deletions Webhook.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
<?php

$NANT_TRANSFERT = "0xa5f7c148";
$CM_TRANSFERT = "0x60ca9c4c";
$private_key_path ='../ComChain/comchainwebhook_rsa';
$public_key_url ='https://com-chain.org/comchainwebhook_rsa.pub';



function createWebhookMessage($tr_hash, $server_name, $store_id, $store_ref, $from_add,$rawtx){
$funct = $rawtx.substring(78,8);
$type_tr = ("0x".$funct == CM_TRANSFERT)? 'TransferCredit' : 'Transfer';
$dest = "0x".$rawtx.substring(110,40);
$amount = hexdec($rawtx.substring(150,64))/100.0;
$time = time();

$base_link = (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on') ? "https" : "http";
$base_link .= "://";
$base_link .= $_SERVER['HTTP_HOST'];

$link = array (
"href"=>$base_link."/api.php?hash=".$tr_hash,
"method"=>"GET"
);

$amount = array (
'sent'=> $amount,
'type'=> $type_tr,
'currency' => $server_name
);


$resources = array (
'id'=>$tr_hash,
'create_time'=> $time,
'state'=>'completed',
'store_id' => $store_id,
'reference' => $store_ref,
'links'=>[$link],

'addr_to' => $dest,
'amount'=>$amount
);
if (strlen($from_add)>0) {
$resources['addr_from']=$from_add;
}


$data = array ('id'=>$tr_hash,
'create_time'=>$time,
'resource_type'=>'sale',
'event_type'=> 'PAYMENT.SALE.COMPLETED',
'summary'=>'A sale has been completed. The payement has been processed.',
'links'=>[$link],
'resources'=>$resources
);

return $data;
}

// Sign and send message
function sendWebhook($url, $message) {
$json_message = json_encode($message);
$hash = crc32($json_message);
$sign = "";
$sign_key = openssl_pkey_get_private($private_key_path);
if (openssl_sign($hash, $sign, $sign_key)) {
$signed = base64_encode($sign);
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-type: application/json',
'COMCHAIN-TRANSMISSION-SIG:'.$signed,
'COMCHAIN-AUTH-ALGO:RSA',
'COMCHAIN-CERT-URL:'.$public_key_url));
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_HEADER, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $json_message);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);

$passed=true;
if (!$response = curl_exec( $ch )){
$passed=false;
}
curl_close($ch);

if ($passed) {
$code = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);
$passed = $code>=200 and $code<300;
}
return $passed;
} else {
return false;
}
}


?>
76 changes: 67 additions & 9 deletions api.php
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
<?php
header('Access-Control-Allow-Origin: *');
include './checkAdmin.php';
include './Webhook.php';
require_once 'libs/jsonRPCClient.php';

$gethRPC = new jsonRPCClient('http://127.0.0.1:8545');
Expand Down Expand Up @@ -78,6 +80,9 @@ function getEstimatedGas($txobj, $gethRPC){
}
return json_encode($data);
}



function getEthCall($txobj, $gethRPC){
$data = getDefaultResponse();
try {
Expand Down Expand Up @@ -161,13 +166,13 @@ function validateShop($shop_id, $server_name){
$cluster = Cassandra::cluster('127.0.0.1') ->withCredentials("transactions_ro", "Public_transactions")->build();
$keyspace = 'comchain';
$session = $cluster->connect($keyspace);
$query = "SELECT * FROM sellers WHERE store_id = ? AND server_name = ? ";
$query = "SELECT webhook_url FROM sellers WHERE store_id = ? AND server_name = ? ";
$options = array('arguments' => array($shop_id, $server_name));
foreach ($session->execute(new Cassandra\SimpleStatement($query), $options) as $row) {
return true;
return $row['webhook_url'];
}

return false;
return "";
}


Expand All @@ -176,10 +181,14 @@ function validateShopData() {
$shop_id=$_REQUEST['shopId'];
$shop_ref=$_REQUEST['txId'];
$server_name=$_REQUEST['serverName'];
return (isset($shop_id) && isset($server_name) && isset($shop_ref) && validateShop( $shop_id, $server_name));
if (isset($shop_id) && isset($server_name) && isset($shop_ref)) {
return validateShop( $shop_id, $server_name);
} else {
return "";
}
}

function storeAdditionalData($transaction_ash) {
function storeAdditionalData($is_valid_shop, $transaction_ash, $web_hook_status) {
$shop_id=$_REQUEST['shopId'];
$shop_ref=$_REQUEST['txId'];
$delegate=$_REQUEST['delegate'];
Expand All @@ -189,7 +198,11 @@ function storeAdditionalData($transaction_ash) {
$do_insert=false;
$fields =array();
$val =array();
if (validateShopData()) {

$fields['wh_status'] = $web_hook_status;
$val[]='?';

if ($is_valid_shop) {
$fields['store_id'] = $shop_id;
$fields['store_ref'] = $shop_ref;
$val[]='?';
Expand All @@ -211,7 +224,8 @@ function storeAdditionalData($transaction_ash) {
$val[]='?';
}

if (sizeof($fields)>0) {
// Add if not only the status
if (sizeof($fields)>1) {
$fields['hash'] = $transaction_ash;
$val[]='?';
// build the query
Expand All @@ -228,16 +242,59 @@ function storeAdditionalData($transaction_ash) {

function sendRawTransaction($rawtx,$gethRPC){
$data = getDefaultResponse();

$shop_url = validateShopData();



$contract = '';
$dest = '';
$amount = 0;
$to_bal = 0;
$wh_status = 0;
try {
if (strlen($shop_url)>0) {
$config = getServerConfig($_REQUEST['serverName']);
$contract = $config->{'contract_1'};
// if so get the dest
$dest = '0x'.$rawtx.substr(110,40);
// get the sender
// TODO $sender = TransactionEcRecover($rawtx)[0];

// get the amount
$amount = hexdec($rawtx.substr(150,64));
// get the balances for dest
$to_bal = getBalance($dest, $contract);
// TODO $from_bal = getBalance($sender, $contract);
$wh_status = 1;
}

$data['data'] = getRPCResponse($gethRPC->eth_sendRawTransaction($rawtx));

if (strlen($shop_url)>0 && $amount > 0) {
// get the balances check if changes compatible the the amount
$to_bal_after = getBalance($dest, $contract);
$from_bal_after = getBalance($sender, $contract);
if ($to_bal_after - $to_bal >= $amount) { // TODO} && $from_bal - $from_bal_after >= $amount) {
// if so : send the webhook
$message = createWebhookMessage($data['data'], $_REQUEST['serverName'],
$_REQUEST['shopId'], $_REQUEST['txId'],
"", $rawtx); // TODO ""=> $sender
$res = sendWebhook($shop_url, $message);
if ($res) {
$wh_status = 3;
} else {
$wh_status = 2;
}
}
}
}
catch (exception $e) {
$data['error'] = true;
$data['msg'] = 'E1'.$e->getMessage();
}

try {
storeAdditionalData($data['data']);
storeAdditionalData(strlen($shop_url)>0, $data['data'], $wh_status);
}
catch (exception $e) {
$data['error'] = true;
Expand All @@ -246,6 +303,7 @@ function sendRawTransaction($rawtx,$gethRPC){
return json_encode($data);
}


function formatAddress($addr){
if (substr($addr, 0, 2) == "0x")
return $addr;
Expand Down
31 changes: 29 additions & 2 deletions checkAdmin.php
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ function getServerConfig($server){
return $json->{'server'};
}

function getAccType($address,$contract){
function getAccType($address, $contract){
$url = getServerAddress()."/api.php";
$ch = curl_init();
$ethCall = ['to' =>$contract,
Expand All @@ -53,7 +53,7 @@ function getAccType($address,$contract){
return substr($data,-1);
}

function getAccStatus($address,$contract){
function getAccStatus($address, $contract){
$url = getServerAddress()."/api.php";
$ch = curl_init();
$ethCall = ['to' =>$contract,
Expand All @@ -78,6 +78,33 @@ function getAccStatus($address,$contract){
return substr($data,-1);
}

function getBalance($address, $contract){
$url = getServerAddress()."/api.php";
$ch = curl_init();
$ethCall = ['to' =>$contract,
'data' => '0x70a08231000000000000000000000000'.substr($address,2)
];
$fields = ['ethCall'=>$ethCall];
$fields_string = http_build_query($fields);

curl_setopt($ch, CURLOPT_URL, $url);
// Set so curl_exec returns the result instead of outputting it.
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POST, count($fields));
curl_setopt($ch,CURLOPT_POSTFIELDS, $fields_string);

// Get the response and close the channel.
$response = curl_exec($ch);
curl_close($ch);

$json = json_decode($response);
$data= $json->{'data'};

return hexdec($data);
}



function checkSign($dat, $signature, $caller){

return $caller==personal_ecRecover($dat, $signature);
Expand Down
21 changes: 18 additions & 3 deletions ecrecover_helper.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,21 @@
require_once './Keccak.php';
use kornrunner\Keccak;


function TransactionEcRecover($rawTx) {
// get the signature, last 134 chars
$len = strlen($rawTx);
$len_data = $len - 134;
$data = substr($rawTx, 0, $len_data);
$signature = substr($rawTx, $len_data);
$v = substr($signature,0,2);
$r = substr($signature,4,64);
$s = substr($signature,70,64);
$signed = '0x'.$r.$s.$v;
return ecRecoverPublic($data, $signed);
}


function personal_ecRecover($msg, $signed) {
return personal_ecRecoverPublic($msg, $signed)[0];
}
Expand All @@ -16,7 +31,7 @@ function ecRecover($hex, $signed) {

function personal_ecRecoverPublic($msg, $signed) {
$personal_prefix_msg = "\x19Ethereum Signed Message:\n". strlen($msg). $msg;
$hex = keccak256($personal_prefix_msg);
$hex = keccak256WithPrefix($personal_prefix_msg);
return ecRecoverPublic($hex, $signed);
}

Expand Down Expand Up @@ -45,7 +60,7 @@ function ecRecoverPublic($hex, $signed) {
$publicKey = Signature::recoverPublicKey($rGmp, $sGmp, $messageGmp, $recovery);
$publicKeyString = $publicKey["x"] . $publicKey["y"];

return array('0x'. substr(keccak256(hex2bin($publicKeyString)), -40),$publicKeyString);
return array('0x'. substr(keccak256WithPrefix(hex2bin($publicKeyString)), -40),$publicKeyString);
}

function strToHex($string)
Expand All @@ -54,7 +69,7 @@ function strToHex($string)
return '0x' . array_shift($hex);
}

function keccak256($str) {
function keccak256WithPrefix($str) {
return '0x'. Keccak::hash($str, 256);
}

Expand Down
13 changes: 9 additions & 4 deletions parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,7 @@ def find_zip(libprefix):
session.execute(cqlInsertHash)

# Check if the transaction is in the pending transaction table (webshop_transactions)
cqlcommand = "SELECT hash, store_id, store_ref, delegate , message_from, message_to, toTimestamp(now()) AS stamp FROM webshop_transactions WHERE hash='{}'".format(transHash)
cqlcommand = "SELECT hash, store_id, store_ref, wh_status, delegate , message_from, message_to, toTimestamp(now()) AS stamp FROM webshop_transactions WHERE hash='{}'".format(transHash)
rows = sessioStaging.execute(cqlcommand)
additional_fields = []
additional_values = []
Expand Down Expand Up @@ -202,11 +202,16 @@ def find_zip(libprefix):
additional_fields.append('store_id')
additional_values.append("'{}'".format(row.store_id))
additional_fields.append('store_ref')
additional_values.append("'{}'".format(row.store_ref)) # check for '
additional_values.append("'{}'".format(row.store_ref))

status = row.wh_status
nb_attempt ='0'
if status>1: # 2 failed attempt / 3 success
nb_attempt ='1'
additional_fields.append('status')
additional_values.append("1") # New shop transction
additional_values.append(status) # New shop transction
additional_fields.append('tr_attempt_nb')
additional_values.append("0")
additional_values.append(nb_attempt)
additional_fields.append('tr_attempt_date')
additional_values.append("'{}'".format(row.stamp-10800000))

Expand Down
Loading

0 comments on commit 84ecb5c

Please sign in to comment.