From b2639b24faa732f2eb7e1085d8ddc4bd3a226165 Mon Sep 17 00:00:00 2001 From: Rich Morgan Date: Tue, 28 Jan 2014 16:21:15 -0500 Subject: [PATCH 01/11] Corrected company name. --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 45c8361..94e5494 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,5 @@ -©2011 BIT-PAY LLC. +©2011-2014 BITPAY, INC. + Permission is hereby granted to any person obtaining a copy of this software and associated documentation for use and/or modification in association with the bitpay.com service. From 935578114abe5b36fde84440706077bd2759f5f7 Mon Sep 17 00:00:00 2001 From: Rich Morgan Date: Tue, 28 Jan 2014 16:23:07 -0500 Subject: [PATCH 02/11] Corrected company name, license & formatting --- lib/bitpay/bp_config_default.php | 29 +++++++++++++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) diff --git a/lib/bitpay/bp_config_default.php b/lib/bitpay/bp_config_default.php index 4b24c09..36f9941 100644 --- a/lib/bitpay/bp_config_default.php +++ b/lib/bitpay/bp_config_default.php @@ -1,15 +1,40 @@ From 3ce0b202d10fa55959752fff57ac37a7b580b443 Mon Sep 17 00:00:00 2001 From: Rich Morgan Date: Tue, 28 Jan 2014 16:29:34 -0500 Subject: [PATCH 03/11] Corrected company name, license & formatting --- lib/bitpay/bp_lib.php | 213 ++++++++++++++++++++++++------------------ 1 file changed, 121 insertions(+), 92 deletions(-) diff --git a/lib/bitpay/bp_lib.php b/lib/bitpay/bp_lib.php index effdd31..a46e03f 100644 --- a/lib/bitpay/bp_lib.php +++ b/lib/bitpay/bp_lib.php @@ -1,49 +1,70 @@ curl_error($curl)); - } else { - $response = json_decode($responseString, true); - if (!$response) - $response = array('error' => 'invalid json: '.$responseString); - } - curl_close($curl); - return $response; + $curl = curl_init($url); + $length = 0; + + if ($post) { + curl_setopt($curl, CURLOPT_POST, 1); + curl_setopt($curl, CURLOPT_POSTFIELDS, $post); + $length = strlen($post); + } + + $uname = base64_encode($apiKey); + $header = array( + 'Content-Type: application/json', + 'Content-Length: ' . $length, + 'Authorization: Basic ' . $uname, + ); + + curl_setopt($curl, CURLOPT_PORT, $bpconfig['port']); + curl_setopt($curl, CURLOPT_HTTPHEADER, $header); + curl_setopt($curl, CURLOPT_TIMEOUT, 10); + curl_setopt($curl, CURLOPT_HTTPAUTH, CURLAUTH_BASIC ) ; + curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, $bpconfig['ssl_verifypeer']); // verify certificate + curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, $bpconfig['ssl_verifyhost']); // check existence of CN and verify that it matches hostname + curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1); + curl_setopt($curl, CURLOPT_FORBID_REUSE, 1); + curl_setopt($curl, CURLOPT_FRESH_CONNECT, 1); + + $responseString = curl_exec($curl); + + if($responseString == false) { + $response = array('error' => curl_error($curl)); + } else { + $response = json_decode($responseString, true); + if (!$response) + $response = array('error' => 'invalid json: '.$responseString); + } + + curl_close($curl); + return $response; } + // $orderId: Used to display an orderID to the buyer. In the account summary view, this value is used to // identify a ledger entry if present. // @@ -61,71 +82,79 @@ function bpCurl($url, $apiKey, $post = false) { // If a given option is not provided here, the value of that option will default to what is found in bp_options.php // (see api documentation for information on these options). function bpCreateInvoice($orderId, $price, $posData, $options = array()) { - global $bpOptions, $bpconfig; - - $options = array_merge($bpOptions, $options); // $options override any options found in bp_options.php - - $pos = array('posData' => $posData); - if ($bpOptions['verifyPos']) - $pos['hash'] = crypt(serialize($posData), $options['apiKey']); - $options['posData'] = json_encode($pos); - - $options['orderID'] = $orderId; - $options['price'] = $price; - - $postOptions = array('orderID', 'itemDesc', 'itemCode', 'notificationEmail', 'notificationURL', 'redirectURL', - 'posData', 'price', 'currency', 'physical', 'fullNotifications', 'transactionSpeed', 'buyerName', - 'buyerAddress1', 'buyerAddress2', 'buyerCity', 'buyerState', 'buyerZip', 'buyerEmail', 'buyerPhone'); - foreach($postOptions as $o) - if (array_key_exists($o, $options)) - $post[$o] = $options[$o]; - $post = json_encode($post); - - $response = bpCurl('https://'.$bpconfig['hostAndPort'].'/api/invoice/', $options['apiKey'], $post); + global $bpOptions, $bpconfig; - return $response; + $options = array_merge($bpOptions, $options); // $options override any options found in bp_options.php + $pos = array('posData' => $posData); + + if ($bpOptions['verifyPos']) + $pos['hash'] = crypt(serialize($posData), $options['apiKey']); + + $options['posData'] = json_encode($pos); + $options['orderID'] = $orderId; + $options['price'] = $price; + + $postOptions = array('orderID', 'itemDesc', 'itemCode', 'notificationEmail', 'notificationURL', 'redirectURL', + 'posData', 'price', 'currency', 'physical', 'fullNotifications', 'transactionSpeed', 'buyerName', + 'buyerAddress1', 'buyerAddress2', 'buyerCity', 'buyerState', 'buyerZip', 'buyerEmail', 'buyerPhone'); + + foreach($postOptions as $o) + if (array_key_exists($o, $options)) + $post[$o] = $options[$o]; + + $post = json_encode($post); + + $response = bpCurl('https://'.$bpconfig['hostAndPort'].'/api/invoice/', $options['apiKey'], $post); + + return $response; } // Call from your notification handler to convert $_POST data to an object containing invoice data function bpVerifyNotification($apiKey = false) { - global $bpOptions, $bpconfig; - if (!$apiKey) - $apiKey = $bpOptions['apiKey']; - - $post = file_get_contents("php://input"); - if (!$post) - return 'No post data'; - - $json = json_decode($post, true); - - if (is_string($json)) - return $json; // error + global $bpOptions, $bpconfig; - if (!array_key_exists('posData', $json)) - return 'no posData'; - - $posData = json_decode($json['posData'], true); - if($bpOptions['verifyPos'] and $posData['hash'] != crypt(serialize($posData['posData']), $apiKey)) - return 'authentication failed (bad hash)'; - $json['posData'] = $posData['posData']; - - return $json; + if (!$apiKey) + $apiKey = $bpOptions['apiKey']; + + $post = file_get_contents("php://input"); + + if (!$post) + return 'No post data'; + + $json = json_decode($post, true); + + if (is_string($json)) + return $json; // error + + if (!array_key_exists('posData', $json)) + return 'no posData'; + + $posData = json_decode($json['posData'], true); + + if($bpOptions['verifyPos'] and $posData['hash'] != crypt(serialize($posData['posData']), $apiKey)) + return 'authentication failed (bad hash)'; + + $json['posData'] = $posData['posData']; + + return $json; } // $options can include ('apiKey') function bpGetInvoice($invoiceId, $apiKey=false) { - global $bpOptions, $bpconfig; - if (!$apiKey) - $apiKey = $bpOptions['apiKey']; + global $bpOptions, $bpconfig; - $response = bpCurl('https://'.$bpconfig['hostAndPort'].'/api/invoice/'.$invoiceId, $apiKey); - if (is_string($response)) - return $response; // error - $response['posData'] = json_decode($response['posData'], true); - $response['posData'] = $response['posData']['posData']; + if (!$apiKey) + $apiKey = $bpOptions['apiKey']; - return $response; + $response = bpCurl('https://'.$bpconfig['hostAndPort'].'/api/invoice/'.$invoiceId, $apiKey); + + if (is_string($response)) + return $response; // error + + $response['posData'] = json_decode($response['posData'], true); + $response['posData'] = $response['posData']['posData']; + + return $response; } - -?> +?> From 62905e2f43cbd7b66c0e3aeddb1750ab32e9c70d Mon Sep 17 00:00:00 2001 From: Rich Morgan Date: Tue, 28 Jan 2014 16:30:10 -0500 Subject: [PATCH 04/11] Corrected company name, license & formatting --- lib/bitpay/bp_options.php | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/lib/bitpay/bp_options.php b/lib/bitpay/bp_options.php index 11cf1ad..be28f91 100644 --- a/lib/bitpay/bp_options.php +++ b/lib/bitpay/bp_options.php @@ -1,5 +1,24 @@ Date: Tue, 28 Jan 2014 16:36:16 -0500 Subject: [PATCH 05/11] Corrected company name, license & formatting --- .../Bitpay/Bitcoins/Block/Iframe.php | 162 ++++++++++-------- 1 file changed, 90 insertions(+), 72 deletions(-) diff --git a/app/code/community/Bitpay/Bitcoins/Block/Iframe.php b/app/code/community/Bitpay/Bitcoins/Block/Iframe.php index 8110fd2..4630a62 100644 --- a/app/code/community/Bitpay/Bitcoins/Block/Iframe.php +++ b/app/code/community/Bitpay/Bitcoins/Block/Iframe.php @@ -1,76 +1,94 @@ setTemplate('bitcoins/iframe.phtml'); - parent::_construct(); - } - - public function GetQuoteId() - { - $quote = $this->getQuote(); - $quoteId = $quote->getId(); - return $quoteId; - } - - - // create an invoice and return the url so that iframe.phtml can display it - public function GetIframeUrl() - { - // are they using bitpay? - if (!($quote = Mage::getSingleton('checkout/session')->getQuote()) - or !($payment = $quote->getPayment()) - or !($instance = $payment->getMethodInstance()) - or ($instance->getCode() != 'Bitcoins')) - return 'notbitpay'; - - // fullscreen disabled? - if (Mage::getStoreConfig('payment/Bitcoins/fullscreen')) - return 'disabled'; - - include Mage::getBaseDir('lib').'/bitpay/bp_lib.php'; +/** + * ©2011,2012,2013,2014 BITPAY, INC. + * + * Permission is hereby granted to any person obtaining a copy of this software + * and associated documentation for use and/or modification in association with + * the bitpay.com service. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * Bitcoin payment plugin using the bitpay.com service. + * + */ + +class Bitpay_Bitcoins_Block_Iframe extends Mage_Checkout_Block_Onepage_Payment { + protected function _construct() { + $this->setTemplate('bitcoins/iframe.phtml'); + parent::_construct(); + } + + public function GetQuoteId() { + $quote = $this->getQuote(); + $quoteId = $quote->getId(); + return $quoteId; + } + + // create an invoice and return the url so that iframe.phtml can display it + public function GetIframeUrl() { + // are they using bitpay? + if (!($quote = Mage::getSingleton('checkout/session')->getQuote()) + or !($payment = $quote->getPayment()) + or !($instance = $payment->getMethodInstance()) + or ($instance->getCode() != 'Bitcoins')) + return 'notbitpay'; + + // fullscreen disabled? + if (Mage::getStoreConfig('payment/Bitcoins/fullscreen')) + return 'disabled'; + + include Mage::getBaseDir('lib').'/bitpay/bp_lib.php'; + + $apiKey = Mage::getStoreConfig('payment/Bitcoins/api_key'); + $speed = Mage::getStoreConfig('payment/Bitcoins/speed'); + + $quote = $this->getQuote(); + $quoteId = $quote->getId(); + + if (Mage::getModel('Bitcoins/ipn')->GetQuotePaid($quoteId)) + return 'paid'; // quote's already paid, so don't show the iframe + + + $options = array( + 'currency' => $quote->getQuoteCurrencyCode(), + 'fullNotifications' => 'true', + 'notificationURL' => Mage::getUrl('bitpay_callback'), + 'redirectURL' => Mage::getUrl('checkout/onepage/success'), + 'transactionSpeed' => $speed, + 'apiKey' => $apiKey, + ); + + // customer data + $method = Mage::getModel('Bitcoins/paymentMethod'); + $options += $method->ExtractAddress($quote->getShippingAddress()); + + // Mage doesn't round the total until saving and it can have more precision at this point which would be bad for later comparing records w/ bitpay. So round here to match what the price will be saved as: + $price = round($quote->getGrandTotal(),4); + + //serialize info about the quote to detect changes + $hash = $method->getQuoteHash($quoteId); + + Mage::log('invoicing for '.$price.' '.$quote->getQuoteCurrencyCode(), NULL, 'bitpay.log'); + + $invoice = bpCreateInvoice($quoteId, $price, array('quoteId' => $quoteId, 'quoteHash' => $hash), $options); + + Mage::log($invoice, NULL, 'bitpay.log'); + + if (array_key_exists('error', $invoice)) { + Mage::log('Error creating bitpay invoice', null, 'bitpay.log'); + Mage::log($invoice['error'], null, 'bitpay.log'); + Mage::throwException("Error creating bit-pay invoice. Please try again or use another payment option."); + return false; + } + + return $invoice['url'].'&view=iframe'; + } - $apiKey = Mage::getStoreConfig('payment/Bitcoins/api_key'); - $speed = Mage::getStoreConfig('payment/Bitcoins/speed'); - - $quote = $this->getQuote(); - $quoteId = $quote->getId(); - if (Mage::getModel('Bitcoins/ipn')->GetQuotePaid($quoteId)) - return 'paid'; // quote's already paid, so don't show the iframe - - $options = array( - 'currency' => $quote->getQuoteCurrencyCode(), - 'fullNotifications' => 'true', - 'notificationURL' => Mage::getUrl('bitpay_callback'), - 'redirectURL' => Mage::getUrl('checkout/onepage/success'), - 'transactionSpeed' => $speed, - 'apiKey' => $apiKey, - ); - - // customer data - $method = Mage::getModel('Bitcoins/paymentMethod'); - $options += $method->ExtractAddress($quote->getShippingAddress()); - - // Mage doesn't round the total until saving and it can have more precision at this point which would be bad for later comparing records w/ bitpay. So round here to match what the price will be saved as: - $price = round($quote->getGrandTotal(),4); - - //serialize info about the quote to detect changes - $hash = $method->getQuoteHash($quoteId); - - Mage::log('invoicing for '.$price.' '.$quote->getQuoteCurrencyCode(), NULL, 'bitpay.log'); - $invoice = bpCreateInvoice($quoteId, $price, array('quoteId' => $quoteId, 'quoteHash' => $hash), $options); - Mage::log($invoice, NULL, 'bitpay.log'); - - if (array_key_exists('error', $invoice)) - { - Mage::log('Error creating bitpay invoice', null, 'bitpay.log'); - Mage::log($invoice['error'], null, 'bitpay.log'); - Mage::throwException("Error creating bit-pay invoice. Please try again or use another payment option."); - return false; - } - - return $invoice['url'].'&view=iframe'; - } } From 7071a2c9785cfdcbedfa1b3c9b44336a0957b063 Mon Sep 17 00:00:00 2001 From: Rich Morgan Date: Tue, 28 Jan 2014 16:44:45 -0500 Subject: [PATCH 06/11] Corrected company name, license & formatting --- .../community/Bitpay/Bitcoins/Model/Ipn.php | 168 ++++++++++-------- 1 file changed, 90 insertions(+), 78 deletions(-) diff --git a/app/code/community/Bitpay/Bitcoins/Model/Ipn.php b/app/code/community/Bitpay/Bitcoins/Model/Ipn.php index 5fc9578..5ad9776 100644 --- a/app/code/community/Bitpay/Bitcoins/Model/Ipn.php +++ b/app/code/community/Bitpay/Bitcoins/Model/Ipn.php @@ -1,80 +1,92 @@ _init('Bitcoins/ipn'); - return parent::_construct(); - } - - function Record($invoice) - { - return $this - ->setQuoteId(isset($invoice['posData']['quoteId']) ? $invoice['posData']['quoteId'] : NULL) - ->setOrderId(isset($invoice['posData']['orderId']) ? $invoice['posData']['orderId'] : NULL) - ->setPosData(json_encode($invoice['posData'])) - ->setInvoiceId($invoice['id']) - ->setUrl($invoice['url']) - ->setStatus($invoice['status']) - ->setBtcPrice($invoice['btcPrice']) - ->setPrice($invoice['price']) - ->setCurrency($invoice['currency']) - ->setInvoiceTime(intval($invoice['invoiceTime']/1000.0)) - ->setExpirationTime(intval($invoice['expirationTime']/1000.0)) - ->setCurrentTime(intval($invoice['currentTime']/1000.0)) - ->save(); - } - - function GetStatusReceived($quoteId, $statuses) - { - if (!$quoteId) - return false; - - $quote = Mage::getModel('sales/quote')->load($quoteId, 'entity_id'); - if (!$quote) - { - Mage::log('quote not found', NULL, 'bitpay.log'); - return false; - } - - $quoteHash = Mage::getModel('Bitcoins/paymentMethod')->getQuoteHash($quoteId); - if (!$quoteHash) - { - Mage::log('Could not find quote hash for quote '.$quoteId, NULL, 'bitpay.log'); - return false; - } - - $collection = $this->getCollection()->AddFilter('quote_id', $quoteId); - foreach($collection as $i) - { - if (in_array($i->getStatus(), $statuses)) - { - // check that quote data was not updated after IPN sent - $posData = json_decode($i->getPosData()); - if (!$posData) - continue; - - if ($quoteHash == $posData->quoteHash) - return true; - } - } - - return false; - } - - function GetQuotePaid($quoteId) - { - return $this->GetStatusReceived($quoteId, array('paid', 'confirmed', 'complete')); - } - - function GetQuoteComplete($quoteId) - { - return $this->GetStatusReceived($quoteId, array('confirmed', 'complete')); - } - - - -} - -?> \ No newline at end of file +/** + * ©2011,2012,2013,2014 BITPAY, INC. + * + * Permission is hereby granted to any person obtaining a copy of this software + * and associated documentation for use and/or modification in association with + * the bitpay.com service. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * Bitcoin payment plugin using the bitpay.com service. + * + */ + +class Bitpay_Bitcoins_Model_Ipn extends Mage_Core_Model_Abstract { + + function _construct() { + $this->_init('Bitcoins/ipn'); + return parent::_construct(); + } + + function Record($invoice) { + return $this + ->setQuoteId(isset($invoice['posData']['quoteId']) ? $invoice['posData']['quoteId'] : NULL) + ->setOrderId(isset($invoice['posData']['orderId']) ? $invoice['posData']['orderId'] : NULL) + ->setPosData(json_encode($invoice['posData'])) + ->setInvoiceId($invoice['id']) + ->setUrl($invoice['url']) + ->setStatus($invoice['status']) + ->setBtcPrice($invoice['btcPrice']) + ->setPrice($invoice['price']) + ->setCurrency($invoice['currency']) + ->setInvoiceTime(intval($invoice['invoiceTime']/1000.0)) + ->setExpirationTime(intval($invoice['expirationTime']/1000.0)) + ->setCurrentTime(intval($invoice['currentTime']/1000.0)) + ->save(); + } + + function GetStatusReceived($quoteId, $statuses) { + if (!$quoteId) + return false; + + $quote = Mage::getModel('sales/quote')->load($quoteId, 'entity_id'); + + if (!$quote) { + Mage::log('quote not found', NULL, 'bitpay.log'); + return false; + } + + $quoteHash = Mage::getModel('Bitcoins/paymentMethod')->getQuoteHash($quoteId); + + if (!$quoteHash) { + Mage::log('Could not find quote hash for quote '.$quoteId, NULL, 'bitpay.log'); + return false; + } + + $collection = $this->getCollection()->AddFilter('quote_id', $quoteId); + + foreach($collection as $i) { + if (in_array($i->getStatus(), $statuses)) { + // check that quote data was not updated after IPN sent + $posData = json_decode($i->getPosData()); + + if (!$posData) + continue; + + if ($quoteHash == $posData->quoteHash) + return true; + } + } + + return false; + } + + function GetQuotePaid($quoteId) { + return $this->GetStatusReceived($quoteId, array('paid', 'confirmed', 'complete')); + } + + function GetQuoteComplete($quoteId) { + return $this->GetStatusReceived($quoteId, array('confirmed', 'complete')); + } + +} + +?> From 843769a8d66672a84ebca952eaf20c53cbe052b1 Mon Sep 17 00:00:00 2001 From: Rich Morgan Date: Tue, 28 Jan 2014 21:33:34 -0600 Subject: [PATCH 07/11] Added license info & corrected company name. --- .../Bitpay/Bitcoins/Model/Source/Speed.php | 56 ++++++++++++------- 1 file changed, 36 insertions(+), 20 deletions(-) diff --git a/app/code/community/Bitpay/Bitcoins/Model/Source/Speed.php b/app/code/community/Bitpay/Bitcoins/Model/Source/Speed.php index 76b556b..145a1c6 100644 --- a/app/code/community/Bitpay/Bitcoins/Model/Source/Speed.php +++ b/app/code/community/Bitpay/Bitcoins/Model/Source/Speed.php @@ -1,24 +1,40 @@ 'low', - 'label' => 'Low', - ), - array( - 'value' => 'medium', - 'label' => 'Medium', - ), - array( - 'value' => 'high', - 'label' => 'High', - )); - } +/** + * ©2011,2012,2013,2014 BITPAY, INC. + * + * Permission is hereby granted to any person obtaining a copy of this software + * and associated documentation for use and/or modification in association with + * the bitpay.com service. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * Bitcoin payment plugin using the bitpay.com service. + * + */ + +class Bitpay_Bitcoins_Model_Source_Speed { + public function toOptionArray() { + return array( + array( + 'value' => 'low', + 'label' => 'Low', + ), + array( + 'value' => 'medium', + 'label' => 'Medium', + ), + array( + 'value' => 'high', + 'label' => 'High', + )); + } } -?> \ No newline at end of file +?> From 8b01715d63fc7bfaa193d91ec629c29674dc1876 Mon Sep 17 00:00:00 2001 From: Rich Morgan Date: Tue, 28 Jan 2014 21:34:56 -0600 Subject: [PATCH 08/11] Added license info & corrected company name. --- .../Bitpay/Bitcoins/Model/Resource/Ipn.php | 31 ++++++++++++++----- 1 file changed, 24 insertions(+), 7 deletions(-) diff --git a/app/code/community/Bitpay/Bitcoins/Model/Resource/Ipn.php b/app/code/community/Bitpay/Bitcoins/Model/Resource/Ipn.php index eaa3571..c192d53 100644 --- a/app/code/community/Bitpay/Bitcoins/Model/Resource/Ipn.php +++ b/app/code/community/Bitpay/Bitcoins/Model/Resource/Ipn.php @@ -1,11 +1,28 @@ _init('Bitcoins/ipn', 'id'); - } +/** + * ©2011,2012,2013,2014 BITPAY, INC. + * + * Permission is hereby granted to any person obtaining a copy of this software + * and associated documentation for use and/or modification in association with + * the bitpay.com service. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * Bitcoin payment plugin using the bitpay.com service. + * + */ + +class Bitpay_Bitcoins_Model_Resource_Ipn extends Mage_Core_Model_Resource_Db_Abstract { + protected function _construct() { + $this->_init('Bitcoins/ipn', 'id'); + } } -?> \ No newline at end of file +?> From 389c4008a4aff2919451d6d6c353478d1f1a6638 Mon Sep 17 00:00:00 2001 From: Rich Morgan Date: Tue, 28 Jan 2014 21:35:41 -0600 Subject: [PATCH 09/11] Added license info & corrected company name. --- .../Model/Resource/Ipn/Collection.php | 35 ++++++++++++++----- 1 file changed, 26 insertions(+), 9 deletions(-) diff --git a/app/code/community/Bitpay/Bitcoins/Model/Resource/Ipn/Collection.php b/app/code/community/Bitpay/Bitcoins/Model/Resource/Ipn/Collection.php index 53a2063..871918b 100644 --- a/app/code/community/Bitpay/Bitcoins/Model/Resource/Ipn/Collection.php +++ b/app/code/community/Bitpay/Bitcoins/Model/Resource/Ipn/Collection.php @@ -1,11 +1,28 @@ _init('Bitcoins/ipn'); - } -} - -?> \ No newline at end of file +/** + * ©2011,2012,2013,2014 BITPAY, INC. + * + * Permission is hereby granted to any person obtaining a copy of this software + * and associated documentation for use and/or modification in association with + * the bitpay.com service. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * Bitcoin payment plugin using the bitpay.com service. + * + */ + +class Bitpay_Bitcoins_Model_Resource_Ipn_Collection extends Mage_Core_Model_Resource_Db_Collection_Abstract { + protected function _construct() { + $this->_init('Bitcoins/ipn'); + } +} + +?> From baba81fbc577a0a6ee70a3383ba2d094d07aa47e Mon Sep 17 00:00:00 2001 From: Rich Morgan Date: Tue, 28 Jan 2014 21:40:51 -0600 Subject: [PATCH 10/11] Added license, formatting & correct company name. --- .../Bitcoins/controllers/IndexController.php | 108 ++++++++++-------- 1 file changed, 62 insertions(+), 46 deletions(-) diff --git a/app/code/community/Bitpay/Bitcoins/controllers/IndexController.php b/app/code/community/Bitpay/Bitcoins/controllers/IndexController.php index 356d1b0..6c90e60 100644 --- a/app/code/community/Bitpay/Bitcoins/controllers/IndexController.php +++ b/app/code/community/Bitpay/Bitcoins/controllers/IndexController.php @@ -1,53 +1,69 @@ getRequest()->getParams(); - $quoteId = $params['quote']; - $paid = Mage::getModel('Bitcoins/ipn')->GetQuotePaid($quoteId); - print json_encode(array('paid' => $paid)); - exit(); - } - - // bitpay's IPN lands here - public function indexAction() { - require Mage::getBaseDir('lib').'/bitpay/bp_lib.php'; - - Mage::log(file_get_contents('php://input'), null, 'bitpay.log'); - - $apiKey = Mage::getStoreConfig('payment/Bitcoins/api_key'); - $invoice = bpVerifyNotification($apiKey); - - if (is_string($invoice)) - Mage::log("bitpay callback error: $invoice", null, 'bitpay.log'); - else { - // get the order - if (isset($invoice['posData']['quoteId'])) { - $quoteId = $invoice['posData']['quoteId']; - $order = Mage::getModel('sales/order')->load($quoteId, 'quote_id'); - } - else { - $orderId = $invoice['posData']['orderId']; - $order = Mage::getModel('sales/order')->loadByIncrementId($orderId); - } - - // save the ipn so that we can find it when the user clicks "Place Order" - Mage::getModel('Bitcoins/ipn')->Record($invoice); - - // update the order if it exists already - if ($order->getId()) - switch($invoice['status']) { - case 'confirmed': - case 'complete': - $method = Mage::getModel('Bitcoins/paymentMethod'); - $method->MarkOrderPaid($order); - - break; - } - } - } + public function checkForPaymentAction() { + $params = $this->getRequest()->getParams(); + $quoteId = $params['quote']; + $paid = Mage::getModel('Bitcoins/ipn')->GetQuotePaid($quoteId); + print json_encode(array('paid' => $paid)); + exit(); + } + + // bitpay's IPN lands here + public function indexAction() { + require Mage::getBaseDir('lib').'/bitpay/bp_lib.php'; + Mage::log(file_get_contents('php://input'), null, 'bitpay.log'); + $apiKey = Mage::getStoreConfig('payment/Bitcoins/api_key'); + $invoice = bpVerifyNotification($apiKey); + + if (is_string($invoice)) + Mage::log("bitpay callback error: $invoice", null, 'bitpay.log'); + else { + // get the order + if (isset($invoice['posData']['quoteId'])) { + $quoteId = $invoice['posData']['quoteId']; + $order = Mage::getModel('sales/order')->load($quoteId, 'quote_id'); + } else { + $orderId = $invoice['posData']['orderId']; + $order = Mage::getModel('sales/order')->loadByIncrementId($orderId); + } + + // save the ipn so that we can find it when the user clicks "Place Order" + Mage::getModel('Bitcoins/ipn')->Record($invoice); + + // update the order if it exists already + if ($order->getId()) + switch($invoice['status']) { + case 'confirmed': + case 'complete': + $method = Mage::getModel('Bitcoins/paymentMethod'); + $method->MarkOrderPaid($order); + break; + } + + } + + } } From 393788aba970074ab5fde4a88bca530a16870261 Mon Sep 17 00:00:00 2001 From: Rich Morgan Date: Wed, 29 Jan 2014 12:54:59 -0500 Subject: [PATCH 11/11] Corrected company name, license & formatting --- .../Bitpay/Bitcoins/Model/PaymentMethod.php | 460 +++++++++--------- 1 file changed, 231 insertions(+), 229 deletions(-) diff --git a/app/code/community/Bitpay/Bitcoins/Model/PaymentMethod.php b/app/code/community/Bitpay/Bitcoins/Model/PaymentMethod.php index d17f484..3b1b513 100644 --- a/app/code/community/Bitpay/Bitcoins/Model/PaymentMethod.php +++ b/app/code/community/Bitpay/Bitcoins/Model/PaymentMethod.php @@ -1,253 +1,255 @@ _canUseCheckout; + /** + * Can save credit card information for future processing? + */ + protected $_canSaveCc = false; + + //protected $_formBlockType = 'bitcoins/form'; + //protected $_infoBlockType = 'bitcoins/info'; + + function canUseForCurrency($currencyCode) { + $currencies = Mage::getStoreConfig('payment/Bitcoins/currencies'); + $currencies = array_map('trim', explode(',', $currencies)); + return array_search($currencyCode, $currencies) !== false; + } + + public function canUseCheckout() { + $secret = Mage::getStoreConfig('payment/Bitcoins/api_key'); + + if (!$secret or !strlen($secret)) { + Mage::log('Bitpay/Bitcoins: API key not entered', null, 'bitpay.log'); + return false; + } + + $speed = Mage::getStoreConfig('payment/Bitcoins/speed'); + + if (!$speed or !strlen($speed)) { + Mage::log('Bitpay/Bitcoins: Transaction Speed invalid', null, 'bitpay.log'); + return false; + } + + return $this->_canUseCheckout; + } + + public function authorize(Varien_Object $payment, $amount) { + if (!Mage::getStoreConfig('payment/Bitcoins/fullscreen')) + return $this->CheckForPayment($payment); + else + return $this->CreateInvoiceAndRedirect($payment, $amount); + } + + function CheckForPayment($payment) { + $quoteId = $payment->getOrder()->getQuoteId(); + $ipn = Mage::getModel('Bitcoins/ipn'); + + if (!$ipn->GetQuotePaid($quoteId)) { + Mage::throwException("Order not paid for. Please pay first and then Place your Order."); + } else if (!$ipn->GetQuoteComplete($quoteId)) { + // order status will be PAYMENT_REVIEW instead of PROCESSING + $payment->setIsTransactionPending(true); + } else { + $this->MarkOrderPaid($payment->getOrder()); } - public function authorize(Varien_Object $payment, $amount) - { - if (!Mage::getStoreConfig('payment/Bitcoins/fullscreen')) - return $this->CheckForPayment($payment); - else - return $this->CreateInvoiceAndRedirect($payment, $amount); + return $this; + } + + function MarkOrderPaid($order) { + $order->setState(Mage_Sales_Model_Order::STATE_PROCESSING, true)->save(); - } - - function CheckForPayment($payment) - { - $quoteId = $payment->getOrder()->getQuoteId(); - $ipn = Mage::getModel('Bitcoins/ipn'); - if (!$ipn->GetQuotePaid($quoteId)) - { - Mage::throwException("Order not paid for. Please pay first and then Place your Order."); - } - else if (!$ipn->GetQuoteComplete($quoteId)) - { - // order status will be PAYMENT_REVIEW instead of PROCESSING - $payment->setIsTransactionPending(true); - } - else - { - $this->MarkOrderPaid($payment->getOrder()); - } - - return $this; - } - - function MarkOrderPaid($order) - { - $order->setState(Mage_Sales_Model_Order::STATE_PROCESSING, true)->save(); - if (!count($order->getInvoiceCollection())) - { - $invoice = $order->prepareInvoice() - ->setTransactionId(1) - ->addComment('Invoiced automatically by Bitpay/Bitcoins/controllers/IndexController.php') - ->register() - ->pay(); + if (!count($order->getInvoiceCollection())) { + $invoice = $order->prepareInvoice() + ->setTransactionId(1) + ->addComment('Invoiced automatically by Bitpay/Bitcoins/controllers/IndexController.php') + ->register() + ->pay(); - $transactionSave = Mage::getModel('core/resource_transaction') - ->addObject($invoice) - ->addObject($invoice->getOrder()); - $transactionSave->save(); - } - } - - // given Mage_Core_Model_Abstract, return api-friendly address - function ExtractAddress($address) - { - $options = array(); - $options['buyerName'] = $address->getName(); - if ($address->getCompany()) - $options['buyerName'] = $options['buyerName'].' c/o '.$address->getCompany(); - $options['buyerAddress1'] = $address->getStreet1(); - $options['buyerAddress2'] = $address->getStreet2(); - $options['buyerAddress3'] = $address->getStreet3(); - $options['buyerAddress4'] = $address->getStreet4(); - $options['buyerCity'] = $address->getCity(); - $options['buyerState'] = $address->getRegionCode(); - $options['buyerZip'] = $address->getPostcode(); - $options['buyerCountry'] = $address->getCountry(); - $options['buyerEmail'] = $address->getEmail(); - $options['buyerPhone'] = $address->getTelephone(); - // trim to fit API specs - foreach(array('buyerName', 'buyerAddress1', 'buyerAddress2', 'buyerAddress3', 'buyerAddress4', 'buyerCity', 'buyerState', 'buyerZip', 'buyerCountry', 'buyerEmail', 'buyerPhone') as $f) - $options[$f] = substr($options[$f], 0, 100); - return $options; - } - - function CreateInvoiceAndRedirect($payment, $amount) - { - include Mage::getBaseDir('lib').'/bitpay/bp_lib.php'; + $transactionSave = Mage::getModel('core/resource_transaction') + ->addObject($invoice) + ->addObject($invoice->getOrder()); - $apiKey = Mage::getStoreConfig('payment/Bitcoins/api_key'); - $speed = Mage::getStoreConfig('payment/Bitcoins/speed'); + $transactionSave->save(); + } + } + + // given Mage_Core_Model_Abstract, return api-friendly address + function ExtractAddress($address) { + $options = array(); + $options['buyerName'] = $address->getName(); - $order = $payment->getOrder(); - $orderId = $order->getIncrementId(); - $options = array( - 'currency' => $order->getBaseCurrencyCode(), - 'buyerName' => $order->getCustomerFirstname().' '.$order->getCustomerLastname(), - 'fullNotifications' => 'true', - 'notificationURL' => Mage::getUrl('bitpay_callback'), - 'redirectURL' => Mage::getUrl('checkout/onepage/success'), - 'transactionSpeed' => $speed, - 'apiKey' => $apiKey, - ); - $options += $this->ExtractAddress($order->getShippingAddress()); - - $invoice = bpCreateInvoice($orderId, $amount, array('orderId' => $orderId), $options); + if ($address->getCompany()) + $options['buyerName'] = $options['buyerName'].' c/o '.$address->getCompany(); - $payment->setIsTransactionPending(true); // status will be PAYMENT_REVIEW instead of PROCESSING + $options['buyerAddress1'] = $address->getStreet1(); + $options['buyerAddress2'] = $address->getStreet2(); + $options['buyerAddress3'] = $address->getStreet3(); + $options['buyerAddress4'] = $address->getStreet4(); + $options['buyerCity'] = $address->getCity(); + $options['buyerState'] = $address->getRegionCode(); + $options['buyerZip'] = $address->getPostcode(); + $options['buyerCountry'] = $address->getCountry(); + $options['buyerEmail'] = $address->getEmail(); + $options['buyerPhone'] = $address->getTelephone(); - if (array_key_exists('error', $invoice)) - { - Mage::log('Error creating bitpay invoice', null, 'bitpay.log'); - Mage::log($invoice['error'], null, 'bitpay.log'); - Mage::throwException("Error creating bit-pay invoice. Please try again or use another payment option."); - } - else - { - $invoiceId = Mage::getModel('sales/order_invoice_api')->create($orderId, array()); - Mage::getSingleton('customer/session')->setRedirectUrl($invoice['url']); - } + // trim to fit API specs + foreach(array('buyerName', 'buyerAddress1', 'buyerAddress2', 'buyerAddress3', 'buyerAddress4', 'buyerCity', 'buyerState', 'buyerZip', 'buyerCountry', 'buyerEmail', 'buyerPhone') as $f) + $options[$f] = substr($options[$f], 0, 100); - return $this; - } + return $options; + } + + function CreateInvoiceAndRedirect($payment, $amount) { + include Mage::getBaseDir('lib').'/bitpay/bp_lib.php'; - public function getOrderPlaceRedirectUrl() - { - if (Mage::getStoreConfig('payment/Bitcoins/fullscreen')) - return Mage::getSingleton('customer/session')->getRedirectUrl(); - else - return ''; - } - - # computes a unique hash determined by the contents of the cart - public function getQuoteHash($quoteId) - { - $quote = Mage::getModel('sales/quote')->load($quoteId, 'entity_id'); - if (!$quote) - { - Mage::log('getQuoteTimestamp: quote not found', NULL, 'bitpay.log'); - return false; - } - - #encode items - $items = $quote->getAllItems(); - $latest = NULL; - $description = ''; - foreach($items as $i) - { - $description.= 'i'.$i->getItemId().'q'.$i->getQty(); + $apiKey = Mage::getStoreConfig('payment/Bitcoins/api_key'); + $speed = Mage::getStoreConfig('payment/Bitcoins/speed'); + $order = $payment->getOrder(); + $orderId = $order->getIncrementId(); - # could encode $i->getOptions() here but item ids are incremented if options are changed - } - - $hash = base64_encode(hash_hmac('sha256', $description, $quoteId)); - $hash = substr($hash, 0, 30); // fit it in posData maxlen - - Mage::log("quote $quoteId descr $description hash $hash", NULL, 'bitpay.log'); - - return $hash; - } - + $options = array( + 'currency' => $order->getBaseCurrencyCode(), + 'buyerName' => $order->getCustomerFirstname().' '.$order->getCustomerLastname(), + 'fullNotifications' => 'true', + 'notificationURL' => Mage::getUrl('bitpay_callback'), + 'redirectURL' => Mage::getUrl('checkout/onepage/success'), + 'transactionSpeed' => $speed, + 'apiKey' => $apiKey, + ); + + $options += $this->ExtractAddress($order->getShippingAddress()); + $invoice = bpCreateInvoice($orderId, $amount, array('orderId' => $orderId), $options); + $payment->setIsTransactionPending(true); // status will be PAYMENT_REVIEW instead of PROCESSING + + if (array_key_exists('error', $invoice)) { + Mage::log('Error creating bitpay invoice', null, 'bitpay.log'); + Mage::log($invoice['error'], null, 'bitpay.log'); + Mage::throwException("Error creating bit-pay invoice. Please try again or use another payment option."); + } else { + $invoiceId = Mage::getModel('sales/order_invoice_api')->create($orderId, array()); + Mage::getSingleton('customer/session')->setRedirectUrl($invoice['url']); + } + + return $this; + } + + public function getOrderPlaceRedirectUrl() { + if (Mage::getStoreConfig('payment/Bitcoins/fullscreen')) + return Mage::getSingleton('customer/session')->getRedirectUrl(); + else + return ''; + } + + // computes a unique hash determined by the contents of the cart + public function getQuoteHash($quoteId) { + $quote = Mage::getModel('sales/quote')->load($quoteId, 'entity_id'); + if (!$quote) { + Mage::log('getQuoteTimestamp: quote not found', NULL, 'bitpay.log'); + return false; + } + + // encode items + $items = $quote->getAllItems(); + $latest = NULL; + $description = ''; + + foreach($items as $i) { + $description.= 'i'.$i->getItemId().'q'.$i->getQty(); + // could encode $i->getOptions() here but item ids are incremented if options are changed + } + + $hash = base64_encode(hash_hmac('sha256', $description, $quoteId)); + $hash = substr($hash, 0, 30); // fit it in posData maxlen + + Mage::log("quote $quoteId descr $description hash $hash", NULL, 'bitpay.log'); + + return $hash; + } + } -?> +?>