Skip to content

Commit

Permalink
Added demo_website
Browse files Browse the repository at this point in the history
  • Loading branch information
gavinandresen committed Apr 17, 2013
1 parent c70b18b commit 1f1f3e0
Show file tree
Hide file tree
Showing 23 changed files with 10,883 additions and 9 deletions.
19 changes: 19 additions & 0 deletions COPYING
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
Copyright (c) 2013 Bitcoin Developers

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

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.
1 change: 0 additions & 1 deletion TODO.txt
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ Arguments:
--memo="message"
--expires=timestamp
--payment_url=URL
--single_use
--out=path_to_file

--certificates is the certificate chain, farthest-from-root first.
Expand Down
5 changes: 1 addition & 4 deletions c++/paymentrequest-create.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@
// expires= : unix timestamp (integer) when this Request expires
// payment_url= : URL where a Payment message should be sent
// out= : file to write to (default: standard output)
// single_use : if specified, this will be a single-use Request
//

// Apple has deprecated OpenSSL in latest MacOS, shut up compiler warnings about it.
Expand Down Expand Up @@ -287,7 +286,7 @@ google::protobuf::uint64 BTC_to_satoshis(double btc)

int main(int argc, char **argv) {
std::list<string> expected = split("paytoaddress,amount,certificates,privatekey,memo,"
"expires,payment_url,single_use,out", ",");
"expires,payment_url,out", ",");

map<string,string> params;
if (!parse_command_line(argc, argv, expected, params)) {
Expand Down Expand Up @@ -329,8 +328,6 @@ int main(int argc, char **argv) {
else
std::cerr << "Invalid expires, ignoring: " << params["expires"] << "\n";
}
if (params.count("single_use"))
details.set_single_use(true);
if (params.count("payment_url"))
details.set_payment_url(params["payment_url"]);

Expand Down
25 changes: 25 additions & 0 deletions php/demo_website/README.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
Source code for PHP website that generates PaymentRequests and
handles the whole PaymentRequest->Payment->PaymentACK payment
flow.

Requirements:

Recent version of PHP 5 that includes:
+ memcache
+ openssl
DrSlump's ProtoBuf support for PHP
https://github.com/drslump/Protobuf-PHP

What is here:

createpaymentrequest.php : Main page: logic for creating a PaymentRequest
form.html.inc : HTML for createpaymentrequest.php

If a bitcoin: URI is produced, then the request= parameter will point to:
f.php : just serves up a generated PaymentRequest from memcache

If a payment_url is part of the payment request, then it is set to:
payACK.php : receives a Payment message and responds with PayACK

include/
Supporting PHP code.
198 changes: 198 additions & 0 deletions php/demo_website/createpaymentrequest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,198 @@
<?php
//
// Create-a-payment-request test form.
//
// Requires:
// PHP5.3 or later
// openssl
// bcmath
// memcached
// http://drslump.github.com/Protobuf-PHP/
//

// Protocol buffer stuff:
require_once 'DrSlump/Protobuf.php';
\DrSlump\Protobuf::autoload();
require_once 'include/paymentrequest.php';

// Certificate handling stuff:
require_once 'include/certificates.php';

// Form-handling stuff:
require_once 'include/fillInFormValues.php';
require_once 'include/validateForm.php';
require_once 'include/urls.php';

// Bitcoin address stuff:
require_once 'include/base58.php';

function setField($params, $name, $callable)
{
if (isset($params[$name]))
call_user_func($callable, $params[$name]);
}

function mySecret($memcache)
{
$secret = $memcache->get('secret');
if ($secret === FALSE) {
$secret = openssl_random_pseudo_bytes(16);
$memcache->set('secret', $secret);
}
return $secret;
}

function createPaymentRequest($params)
{
$memcache = new Memcache;
$memcache->connect('localhost', 11211) or die ("Could not connect to memcache");

// $params contains:
// merchant / address123 / amount123 / time / expires / memo
// payment_url / ACK_message
$codec = new \DrSlump\Protobuf\Codec\Binary();

$details = new \payments\PaymentDetails();
$details->setTime(time() + (int)$params['time']);
if ($params['expires'] != "never") {
$details->setExpires(time() + (int)$params['expires']);
}
setField($params, 'memo', array($details, 'setMemo'));

$testnet = false;
$totalAmount = 0;
for ($i = 1; $i <= 3; $i++) {
$field = "address".$i;
if (!empty($params[$field])) {
$output = new \payments\Output();
$r = address_to_script($params["address".$i]);
if ($r[0]) $testnet = true;
$output->setScript($r[1]);
$output->setAmount($params["amount".$i]*1.0e8);
$totalAmount += $params["amount".$i];

$details->addOutputs($output);
}
}
if ($testnet) {
$details->setNetwork("test");
}
if (isset($params['payment_url'])) {
/* Generate a unique id for this request: */
$id = uniqid(mySecret($memcache));
/* ... store it in merchant data: */
$details->setMerchantData($id);

$ackURL = AbsoluteURL('')."payACK.php";
$details->setPaymentUrl($ackURL);

if (isset($params['ACK_message'])) {
$memcache->set($id, $params['ACK_message'], 0, 60*60*24);
}
else {
$memcache->set($id, '', 0, 60*60*24);
}
}

$paymentRequest = new \payments\PaymentRequest();
$serialized = $details->serialize($codec);
$paymentRequest->setSerializedPaymentDetails($serialized);

// Signed?
if ($params['merchant'] != "None") {

// TODO: memcache serialized $certChain to avoid constant lookups:
$certChain = new \payments\X509Certificates();
// TODO: more than one .crt...
$leafCert = file_get_contents("/home/gavin/.certs/bitcoincore.crt");
$certs = fetch_chain($leafCert);
foreach ($certs as $cert) {
$certChain->addCertificate($cert);
}

$paymentRequest->setPkiType("x509+sha1");
$paymentRequest->setPkiData($certChain->serialize($codec));

$priv_key = file_get_contents("/home/gavin/.certs/bitcoincore.key");
$pkeyid = openssl_get_privatekey($priv_key);

$paymentRequest->setSignature("");
$dataToSign = $paymentRequest->serialize($codec);

$signature = "";
$result = openssl_sign($dataToSign, $signature, $pkeyid, OPENSSL_ALGO_SHA1);
if ($signature === FALSE) return "ERROR: signing failed.\n";
$paymentRequest->setSignature($signature);

}

$data = $paymentRequest->serialize($codec);

if (isset($params['produce_uri']))
{
$urlParams = array();

if ($totalAmount > 0)
$urlParams['amount'] = $totalAmount;

$hash = hash('ripemd128', $data);
$memcache->set($hash, $data, FALSE, 60*60*24); /* cache for 24 hours */

// f.php is fetch payment request from memcache:
$urlParams['request'] = AbsoluteURL('')."f.php?h=".$hash;

$url = AddArgsToURL("bitcoin:".$params["address1"], $urlParams);

return MakeAnchor("CLICK TO PAY", $url);
}

header('Content-Type: application/x-bitcoinpaymentrequest');
$filename = "r".(string)time().".bitcoinpaymentrequest";
header('Content-Disposition: inline; filename='.$filename);
header('Content-Transfer-Encoding: binary');
header('Expires: 0');
header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
header('Pragma: public');
header('Content-Length: ' . (string)strlen($data));

echo $data;

exit(0);
}

ob_start();
include "form.html.inc";
$html = ob_get_contents();
ob_end_clean();

$request = (get_magic_quotes_gpc() ? array_map('stripslashes', $_REQUEST) : $_REQUEST);

$validationData['address1'] = array('isRequired', 'type' => 'btcaddress');
$validationData['amount1'] = array('isRequired', 'type' => 'btcamount');
$validationData['address2'] = array('type' => 'btcaddress');
$validationData['amount2'] = array('type' => 'btcamount');
$validationData['address3'] = array('type' => 'btcaddress');
$validationData['amount3'] = array('type' => 'btcamount');

if (isset($request['submit'])) {
$formErrors = validateForm($request, $validationData);

if (count($formErrors) == 0) {
$info = createPaymentRequest($request);
$html = preg_replace('/<p class="result">[^<]*/', '<p class="result">'.$info, $html);

// Normally there would be code here to process the form
// and redirect to a thank you page...
// ... but for this example, we just always re-display the form.
// $info = "No errors; got these values:".
// nl2br(htmlspecialchars(print_r($request, 1)));
// $html = preg_replace('/<body>/', "<body><p>$info</p>", $html);
}
}
else {
$formErrors = array();
}

echo fillInFormValues($html, $request, $formErrors);

?>
Loading

0 comments on commit 1f1f3e0

Please sign in to comment.