/**
* Array indexes for raw package array
*/
- const INDEX_PACKAGE_SENDER = 0;
- const INDEX_PACKAGE_RECIPIENT = 1;
- const INDEX_PACKAGE_CONTENT = 2;
- const INDEX_PACKAGE_STATUS = 3;
- const INDEX_PACKAGE_SIGNATURE = 4;
+ const INDEX_PACKAGE_SENDER = 0;
+ const INDEX_PACKAGE_RECIPIENT = 1;
+ const INDEX_PACKAGE_CONTENT = 2;
+ const INDEX_PACKAGE_STATUS = 3;
+ const INDEX_PACKAGE_HASH = 4;
+ const INDEX_PACKAGE_PRIVATE_KEY_HASH = 5;
/**
- * Size of the decoded data array ('status' is not included)
+ * Size of the decoded data array
*/
- const DECODED_DATA_ARRAY_SIZE = 4;
+ const DECODED_DATA_ARRAY_SIZE = 6;
/**
* Named array elements for decoded package content
*/
- const PACKAGE_CONTENT_EXTENSION = 'compressor';
- const PACKAGE_CONTENT_MESSAGE = 'message';
- const PACKAGE_CONTENT_TAGS = 'tags';
- const PACKAGE_CONTENT_CHECKSUM = 'checksum';
+ const PACKAGE_CONTENT_EXTENSION = 'compressor';
+ const PACKAGE_CONTENT_MESSAGE = 'message';
+ const PACKAGE_CONTENT_TAGS = 'tags';
+ const PACKAGE_CONTENT_CHECKSUM = 'checksum';
+ const PACKAGE_CONTENT_SENDER = 'sender';
+ const PACKAGE_CONTENT_HASH = 'hash';
+ const PACKAGE_CONTENT_PRIVATE_KEY_HASH = 'pkhash';
/**
* Named array elements for package data
*/
- const PACKAGE_DATA_SENDER = 'sender';
- const PACKAGE_DATA_RECIPIENT = 'recipient';
- const PACKAGE_DATA_CONTENT = 'content';
- const PACKAGE_DATA_STATUS = 'status';
- const PACKAGE_DATA_SIGNATURE = 'signature';
+ const PACKAGE_DATA_SENDER = 'sender';
+ const PACKAGE_DATA_RECIPIENT = 'recipient';
+ const PACKAGE_DATA_CONTENT = 'content';
+ const PACKAGE_DATA_STATUS = 'status';
+ const PACKAGE_DATA_HASH = 'hash';
+ const PACKAGE_DATA_PRIVATE_KEY_HASH = 'pkhash';
/**
* All package status
/**
* Constants for message data array
*/
- const MESSAGE_ARRAY_DATA = 'message_data';
- const MESSAGE_ARRAY_TYPE = 'message_type';
+ const MESSAGE_ARRAY_DATA = 'message_data';
+ const MESSAGE_ARRAY_TYPE = 'message_type';
+ const MESSAGE_ARRAY_SENDER = 'message_sender';
+ const MESSAGE_ARRAY_HASH = 'message_hash';
+ const MESSAGE_ARRAY_TAGS = 'message_tags';
/**
* Generic answer status field
), $forceReInit);
}
+ /**
+ * Determines private key hash from given session id
+ *
+ * @param $decodedData Array with decoded data
+ * @return $hash Private key's hash
+ */
+ private function determineSenderPrivateKeyHash (array $decodedData) {
+ // Get DHT instance
+ $dhtInstance = DhtObjectFactory::createDhtInstance('node');
+
+ // Ask DHT for session id
+ $senderData = $dhtInstance->findNodeLocalBySessionId($decodedData[self::PACKAGE_CONTENT_SENDER]);
+
+ // Is an entry found?
+ if (count($senderData) > 0) {
+ // Make sure the element 'private_key_hash' is there
+ /* NOISY-DEBUG */ self::createDebugInstance(__CLASS__)->debugOutput('NETWORK-PACKAGE[' . __METHOD__ . ':' . __LINE__ . ']: senderData=' . print_r($senderData, TRUE));
+ assert(isset($senderData[NodeDistributedHashTableDatabaseWrapper::DB_COLUMN_PRIVATE_KEY_HASH]));
+
+ // Return it
+ return $senderData[NodeDistributedHashTableDatabaseWrapper::DB_COLUMN_PRIVATE_KEY_HASH];
+ } // END - if
+
+ // Make sure the requested element is there
+ //* DEBUG-DIE */ die('decodedData=' . print_r($decodedData, TRUE));
+ assert(isset($decodedData[self::PACKAGE_CONTENT_PRIVATE_KEY_HASH]));
+
+ // There is no DHT entry so, accept the hash from decoded data
+ return $decodedData[self::PACKAGE_CONTENT_PRIVATE_KEY_HASH];
+ }
+
/**
* "Getter" for hash from given content
*
// Pop the entry (it should be it)
$nextData = $this->getStackInstance()->popNamed($stackerName);
- // Compare both signatures
- assert($nextData[self::PACKAGE_DATA_SIGNATURE] == $packageData[self::PACKAGE_DATA_SIGNATURE]);
+ // Compare both hashes
+ assert($nextData[self::PACKAGE_DATA_HASH] == $packageData[self::PACKAGE_DATA_HASH]);
// Temporary set the new status
$packageData[self::PACKAGE_DATA_STATUS] = $newStatus;
}
/**
- * Generates a signature for given raw package content and sender id
+ * Generates a secure hash for given raw package content and sender id
*
* @param $content Raw package data
- * @param $senderId Sender id to generate a signature for
- * @return $signature Signature as BASE64-encoded string
+ * @param $senderId Sender id to generate a hash for
+ * @return $hash Hash as hex-encoded string
*/
- private function generatePackageSignature ($content, $senderId) {
- // Hash content and sender id together, use md5() as last algo
- $hash = md5($this->getCryptoInstance()->hashString($senderId . $content, $this->getPrivateKey(), FALSE));
+ private function generatePackageHash ($content, $senderId) {
+ // Debug message
+ //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput('NETWORK-PACKAGE[' . __METHOD__ . ':' . __LINE__ . ']: content()=' . strlen($content) . ',senderId=' . $senderId . ' - CALLED!');
- // Encrypt the content again with the hash as a key
- $encryptedContent = $this->getCryptoInstance()->encryptString($content, $hash);
+ // Is the feature enabled?
+ if (!FrameworkFeature::isFeatureAvailable('hubcoin_reward')) {
+ // Feature is not enabled
+ //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput('NETWORK-PACKAGE[' . __METHOD__ . ':' . __LINE__ . ']: Feature "hubcoin_reward" not available, not generating package hash. Returning NULL ...');
+ return NULL;
+ } // END - if
- // Encode it with BASE64
- $signature = base64_encode($encryptedContent);
+ // Fake array
+ $data = array(
+ self::PACKAGE_CONTENT_SENDER => $senderId,
+ self::PACKAGE_CONTENT_MESSAGE => $content,
+ self::PACKAGE_CONTENT_PRIVATE_KEY_HASH => ''
+ );
+
+ // Hash content and sender id together, use scrypt
+ //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput('NETWORK-PACKAGE[' . __METHOD__ . ':' . __LINE__ . ']: senderId=' . $senderId . ',content()=' . strlen($content));
+ $hash = FrameworkFeature::callFeature('hubcoin_reward', 'generateHash', array($senderId . ':' . $content . ':' . $this->determineSenderPrivateKeyHash($data)));
+
+ // Debug message
+ //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput('NETWORK-PACKAGE[' . __METHOD__ . ':' . __LINE__ . ']: hash=' . $hash . ' - EXIT!');
// Return it
- return $signature;
+ return $hash;
}
/**
- * Checks whether the signature of given package data is 'valid', here that
+ * Checks whether the hash of given package data is 'valid', here that
* means it is the same or not.
*
* @param $decodedArray An array with 'decoded' (explode() was mostly called) data
- * @return $isSignatureValid Whether the signature is valid
- * @todo Unfinished area, signatures are currently NOT fully supported
+ * @return $isHashValid Whether the hash is valid
+ * @todo Unfinished area, hashes are currently NOT fully supported
*/
- private function isPackageSignatureValid (array $decodedArray) {
- // Generate the signature of comparing it
- $signature = $this->generatePackageSignature($decodedArray[self::INDEX_PACKAGE_CONTENT], $decodedArray[self::INDEX_PACKAGE_SENDER]);
+ private function isPackageHashValid (array $decodedArray) {
+ // Debug message
+ //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput('NETWORK-PACKAGE[' . __METHOD__ . ':' . __LINE__ . ']: decodedArray=' . print_r($decodedArray, TRUE) . ' - CALLED!');
+
+ // Make sure the required array elements are there
+ assert(isset($decodedArray[self::PACKAGE_CONTENT_SENDER]));
+ assert(isset($decodedArray[self::PACKAGE_CONTENT_MESSAGE]));
+ assert(isset($decodedArray[self::PACKAGE_CONTENT_HASH]));
+
+ // Is the feature enabled?
+ if (!FrameworkFeature::isFeatureAvailable('hubcoin_reward')) {
+ // Feature is not enabled, so hashes are always valid
+ //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput('NETWORK-PACKAGE[' . __METHOD__ . ':' . __LINE__ . ']: Feature "hubcoin_reward" not available, not checking hash. Returning TRUE ...');
+ return TRUE;
+ } // END - if
- // Is it the same?
- //$isSignatureValid =
- exit(__METHOD__ . ': signature=' . $signature . chr(10) . ',decodedArray=' . print_r($decodedArray, TRUE));
+ // Check validity
+ //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput('NETWORK-PACKAGE[' . __METHOD__ . ':' . __LINE__ . ']: senderId=' . $decodedArray[self::PACKAGE_CONTENT_SENDER] . ',message()=' . strlen($decodedArray[self::PACKAGE_CONTENT_MESSAGE]) . '),hash=' . $decodedArray[self::PACKAGE_CONTENT_HASH]);
+ //* DEBUG-DIE: */ die(__METHOD__ . ': decodedArray=' . print_r($decodedArray, TRUE));
+ $isHashValid = FrameworkFeature::callFeature('hubcoin_reward', 'checkHash', array($decodedArray[self::PACKAGE_CONTENT_SENDER] . ':' . $decodedArray[self::PACKAGE_CONTENT_MESSAGE] . ':' . $this->determineSenderPrivateKeyHash($decodedArray), $decodedArray[self::PACKAGE_CONTENT_HASH]));
+
+ // Return it
+ //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput('NETWORK-PACKAGE[' . __METHOD__ . ':' . __LINE__ . ']: isHashValid=' . intval($isHashValid) . ' - EXIT!');
+ return $isHashValid;
}
/**
//* DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput('content(' . strlen($content) . ')=' . $content);
// ... and compress it
- $content = $this->getCompressorInstance()->compressStream($content);
+ $compressed = $this->getCompressorInstance()->compressStream($content);
// Add magic in front of it and hash behind it, including BASE64 encoding
$packageContent = sprintf(self::PACKAGE_MASK,
$this->getCompressorInstance()->getCompressorExtension(),
// - separator
self::PACKAGE_MASK_SEPARATOR,
- // 2.) Raw package content, encoded with BASE64
- base64_encode($content),
+ // 2.) Compressed raw package content, encoded with BASE64
+ base64_encode($compressed),
// - separator
self::PACKAGE_MASK_SEPARATOR,
// 3.) Tags
// - separator
self::PACKAGE_MASK_SEPARATOR,
// 4.) Checksum
- $this->getHashFromContent($content)
+ $this->getHashFromContent($compressed)
);
// Debug message
// Now prepare the temporary array and push it on the 'undeclared' stack
$this->getStackInstance()->pushNamed(self::STACKER_NAME_UNDECLARED, array(
- self::PACKAGE_DATA_SENDER => $this->getSessionId(),
- self::PACKAGE_DATA_RECIPIENT => $helperInstance->getRecipientType(),
- self::PACKAGE_DATA_CONTENT => $packageContent,
- self::PACKAGE_DATA_STATUS => self::PACKAGE_STATUS_NEW,
- self::PACKAGE_DATA_SIGNATURE => $this->generatePackageSignature($packageContent, $this->getSessionId())
+ self::PACKAGE_DATA_SENDER => $this->getSessionId(),
+ self::PACKAGE_DATA_RECIPIENT => $helperInstance->getRecipientType(),
+ self::PACKAGE_DATA_CONTENT => $packageContent,
+ self::PACKAGE_DATA_STATUS => self::PACKAGE_STATUS_NEW,
+ self::PACKAGE_DATA_HASH => $this->generatePackageHash($content, $this->getSessionId()),
+ self::PACKAGE_DATA_PRIVATE_KEY_HASH => $this->getPrivateKeyHash(),
));
// Debug message
// And remove it finally
$this->getStackInstance()->popNamed(self::STACKER_NAME_DECLARED);
- } catch (InvalidStateException $e) {
+ } catch (UnexpectedStateException $e) {
// The state is not excepected (shall be 'connected')
self::createDebugInstance(__CLASS__)->debugOutput('NETWORK-PACKAGE[' . __METHOD__ . ':' . __LINE__ . ']: Caught ' . $e->__toString() . ',message=' . $e->getMessage());
*/
public function accept (Visitor $visitorInstance) {
// Debug message
- /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput('NETWORK-PACKAGE[' . __METHOD__ . ':' . __LINE__ . ']: ' . $visitorInstance->__toString() . ' has visited - CALLED!');
+ //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput('NETWORK-PACKAGE[' . __METHOD__ . ':' . __LINE__ . ']: ' . $visitorInstance->__toString() . ' has visited - CALLED!');
// Visit the package
$visitorInstance->visitNetworkPackage($this);
$this->getAssemblerInstance()->accept($visitorInstance);
// Debug message
- /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput('NETWORK-PACKAGE[' . __METHOD__ . ':' . __LINE__ . ']: ' . $visitorInstance->__toString() . ' has visited - EXIT!');
+ //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput('NETWORK-PACKAGE[' . __METHOD__ . ':' . __LINE__ . ']: ' . $visitorInstance->__toString() . ' has visited - EXIT!');
}
/**
// Assert on count (should be always 3)
assert(count($decodedArray) == self::DECODED_DATA_ARRAY_SIZE);
- // Generate the signature of comparing it
/*
- * @todo Unsupported feature of "signed" messages commented out
- if (!$this->isPackageSignatureValid($decodedArray)) {
- // Is not valid, so throw an exception here
- exit(__METHOD__ . ':INVALID SIG! UNDER CONSTRUCTION!' . chr(10));
- } // END - if
- */
-
- /*
- * Create 'decodedData' array with all assoziative array elements,
- * except signature.
+ * Create 'decodedData' array with all assoziative array elements.
*/
$decodedData = array(
- self::PACKAGE_DATA_SENDER => $decodedArray[self::INDEX_PACKAGE_SENDER],
- self::PACKAGE_DATA_RECIPIENT => $decodedArray[self::INDEX_PACKAGE_RECIPIENT],
- self::PACKAGE_DATA_CONTENT => $decodedArray[self::INDEX_PACKAGE_CONTENT],
- self::PACKAGE_DATA_STATUS => self::PACKAGE_STATUS_DECODED
+ self::PACKAGE_DATA_SENDER => $decodedArray[self::INDEX_PACKAGE_SENDER],
+ self::PACKAGE_DATA_RECIPIENT => $decodedArray[self::INDEX_PACKAGE_RECIPIENT],
+ self::PACKAGE_DATA_CONTENT => $decodedArray[self::INDEX_PACKAGE_CONTENT],
+ self::PACKAGE_DATA_STATUS => self::PACKAGE_STATUS_DECODED,
+ self::PACKAGE_DATA_HASH => $decodedArray[self::INDEX_PACKAGE_HASH],
+ self::PACKAGE_DATA_PRIVATE_KEY_HASH => $decodedArray[self::INDEX_PACKAGE_PRIVATE_KEY_HASH]
);
// And return it
*/
$decodedContent = array(
// Compressor's extension used to compress the data
- self::PACKAGE_CONTENT_EXTENSION => $decodedContent[self::INDEX_COMPRESSOR_EXTENSION],
+ self::PACKAGE_CONTENT_EXTENSION => $decodedContent[self::INDEX_COMPRESSOR_EXTENSION],
// Package data (aka "message") in BASE64-decoded form but still compressed
- self::PACKAGE_CONTENT_MESSAGE => base64_decode($decodedContent[self::INDEX_PACKAGE_DATA]),
+ self::PACKAGE_CONTENT_MESSAGE => base64_decode($decodedContent[self::INDEX_PACKAGE_DATA]),
// Tags as an indexed array for "tagging" the message
- self::PACKAGE_CONTENT_TAGS => explode(self::PACKAGE_TAGS_SEPARATOR, $decodedContent[self::INDEX_TAGS]),
+ self::PACKAGE_CONTENT_TAGS => explode(self::PACKAGE_TAGS_SEPARATOR, $decodedContent[self::INDEX_TAGS]),
// Checksum of the _decoded_ data
- self::PACKAGE_CONTENT_CHECKSUM => $decodedContent[self::INDEX_CHECKSUM]
+ self::PACKAGE_CONTENT_CHECKSUM => $decodedContent[self::INDEX_CHECKSUM],
+ // Sender's id
+ self::PACKAGE_CONTENT_SENDER => $decodedData[self::PACKAGE_DATA_SENDER],
+ // Hash from decoded raw data
+ self::PACKAGE_CONTENT_HASH => $decodedData[self::PACKAGE_DATA_HASH],
+ // Hash of private key
+ self::PACKAGE_CONTENT_PRIVATE_KEY_HASH => $decodedData[self::PACKAGE_DATA_PRIVATE_KEY_HASH]
);
// Is the checksum valid?
* @todo Implement verification of all sent tags here?
*/
public function handleNewlyArrivedMessage () {
+ // Make sure there is at least one message
+ assert($this->isNewMessageArrived());
+
// Get it from the stacker, it is the full array with the decoded message
$decodedContent = $this->getStackInstance()->popNamed(self::STACKER_NAME_NEW_MESSAGE);
+ // Generate the hash of comparing it
+ if (!$this->isPackageHashValid($decodedContent)) {
+ // Is not valid, so throw an exception here
+ exit(__METHOD__ . ':INVALID HASH! UNDER CONSTRUCTION!' . chr(10));
+ } // END - if
+
// Now get a filter chain back from factory with given tags array
$chainInstance = PackageFilterChainFactory::createChainByTagsArray($decodedContent[self::PACKAGE_CONTENT_TAGS]);
* Process the message through all filters, note that all other
* elements from $decodedContent are no longer needed.
*/
- $chainInstance->processMessage($decodedContent[self::PACKAGE_CONTENT_MESSAGE], $this);
+ $chainInstance->processMessage($decodedContent, $this);
+
+ /*
+ * Post-processing of message data (this won't remote the message from
+ * the stack).
+ */
+ $chainInstance->postProcessMessage($this);
}
/**
// Handle message data
$handlerInstance->handleMessageData($messageArray[self::MESSAGE_ARRAY_DATA], $this);
+
+ // Post-handling of message data
+ $handlerInstance->postHandleMessageData($messageArray, $this);
+ }
+
+ /**
+ * Feeds the hash and sender (as recipient for the 'sender' reward) to the
+ * miner's queue, unless the message is not a "reward claim" message as this
+ * leads to an endless loop. You may wish to run the miner to get some
+ * reward ("Hubcoins") for "mining" this hash.
+ *
+ * @param $messageData Array with message data
+ * @return void
+ * @todo ~10% done?
+ */
+ public function feedHashToMiner (array $messageData) {
+ // Is the feature enabled?
+ if (!FrameworkFeature::isFeatureAvailable('hubcoin_reward')) {
+ /*
+ * Feature is not enabled, don't feed the hash to the miner as it
+ *may be invalid.
+ */
+ return;
+ } // END - if
+
+ // Make sure the required elements are there
+ assert(isset($messageData[self::MESSAGE_ARRAY_SENDER]));
+ assert(isset($messageData[self::MESSAGE_ARRAY_HASH]));
+ assert(isset($messageData[self::MESSAGE_ARRAY_TAGS]));
+
+ // Debug message
+ /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput('NETWORK-PACKAGE[' . __METHOD__ . ':' . __LINE__ . ']: messageData=' . print_r($messageData, TRUE));
+
+ // Resolve session id ('sender' is a session id) into node id
+ $nodeId = HubTools::resolveNodeIdBySessionId($messageData[self::MESSAGE_ARRAY_SENDER]);
+
+ // Is 'claim_reward' the message type?
+ if (in_array('claim_reward', $messageData[self::MESSAGE_ARRAY_TAGS])) {
+ /*
+ * Then don't feed this message to the miner as this causes an
+ * endless loop of mining.
+ */
+ return;
+ } // END - if
+
+ $this->partialStub('@TODO nodeId=' . $nodeId . ',messageData=' . print_r($messageData, TRUE));
}
}