diff --git a/LICENSE b/LICENSE index cf457637..2e6aa30c 100644 --- a/LICENSE +++ b/LICENSE @@ -1,20 +1,3 @@ -The MIT License (MIT) - Copyright (c) 2014 OutCast3k - -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. +Copyright (c) 2015 ttutdxh.nubits@gmail.com +Copyright (c) 2016 Triplex diff --git a/README.md b/README.md index dd4e44a1..bcf5522b 100644 --- a/README.md +++ b/README.md @@ -1,13 +1,11 @@ -coinbin +Cointoolkit ======= -A Open Source Browser Based Bitcoin Wallet. Version 1.2 beta by OutCast3k +A Open Source Browser Based Bitcoin Wallet. -Live version available at http://coinb.in/ or http://4zpinp6gdkjfplhk.onion +Live version available at http://triplexfw/coinbin/ -Github URL: https://github.com/OutCast3k/coinbin/ - -Coinb.in supports a number of key features such as: +Github URL: https://github.com/triplexfw/coinbin - Offline Compressed & uncompressed Address creation. - Offline Multisignature Address creation. @@ -28,4 +26,4 @@ Coinb.in supports a number of key features such as: - HD (bip32) support - Supports altcoins such as litecoin -Donate to 1CWHWkTWaq1K5hevimJia3cyinQsrgXUvg to see more development! +Donate to BTC: 1J9Lfaz9poYrNSRH1vccd9qeYxBzwZ1Pq7 or DASH: XdR8hW2ac1MtRKNpfBaCzkKJM6P23qju6N to see more development! diff --git a/css/jquery-ui-sort-only.min.css b/css/jquery-ui-sort-only.min.css new file mode 100644 index 00000000..dd15d34f --- /dev/null +++ b/css/jquery-ui-sort-only.min.css @@ -0,0 +1,6 @@ +/*! jQuery UI - v1.11.4 - 2016-01-02 +* http://jqueryui.com +* Includes: core.css, sortable.css +* Copyright jQuery Foundation and other contributors; Licensed MIT */ + +.ui-helper-hidden{display:none}.ui-helper-hidden-accessible{border:0;clip:rect(0 0 0 0);height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;width:1px}.ui-helper-reset{margin:0;padding:0;border:0;outline:0;line-height:1.3;text-decoration:none;font-size:100%;list-style:none}.ui-helper-clearfix:before,.ui-helper-clearfix:after{content:"";display:table;border-collapse:collapse}.ui-helper-clearfix:after{clear:both}.ui-helper-clearfix{min-height:0}.ui-helper-zfix{width:100%;height:100%;top:0;left:0;position:absolute;opacity:0;filter:Alpha(Opacity=0)}.ui-front{z-index:100}.ui-state-disabled{cursor:default!important}.ui-icon{display:block;text-indent:-99999px;overflow:hidden;background-repeat:no-repeat}.ui-widget-overlay{position:fixed;top:0;left:0;width:100%;height:100%}.ui-sortable-handle{-ms-touch-action:none;touch-action:none} \ No newline at end of file diff --git a/css/style.css b/css/style.css index 9cebfa22..05d8a7ea 100644 --- a/css/style.css +++ b/css/style.css @@ -24,3 +24,46 @@ body { background-color: #f5f5f5; padding-top: 20px; } + +.glyphicon-refresh-animate { + -animation: spin 1s infinite linear; + -webkit-animation: spin2 1s infinite linear; +} + +@-webkit-keyframes spin2 { + from { -webkit-transform: rotate(0deg);} + to { -webkit-transform: rotate(360deg);} +} + +@keyframes spin { + from { transform: scale(1) rotate(0deg);} + to { transform: scale(1) rotate(360deg);} +} + +#verifyTransactionData .table>tbody>tr>td { + vertical-align: middle; +} + +@media (min-width: 768px) { + .wideModal .modal-dialog { + width: 70%; + } +} + +.sig_position { + text-align: center; +} + +#multisigPubKeys .item { + margin-bottom: 5px; +} + +.glyphicon-minus:before { + content: "\2212"; + margin-left: -1px; +} + +.handle { + padding-left: 15px; + font-size: 20px; +} \ No newline at end of file diff --git a/index.html b/index.html index 9f7d4d0f..e4bb045a 100644 --- a/index.html +++ b/index.html @@ -2,19 +2,21 @@
-
+ Cointoolkit
Be your own bank, take control of your own money and start using Bitcoin today!
- +Be your own bank, take control of your own money and start using DASH today!
+Coinbin is an open source web based wallet written in javascript and released under the MIT license which means its free to use and edit.
+Cointoolkit is an open source web based wallet written in javascript and released under the MIT license which means it's free to use and edit.
We offer a fully transparent multisig solution which works seamlessly offline and with other bitcoin clients.
+This is the first tool that supports combining signatures in a multi signature transaction. Verify your first transaction, click the number of signatures and combine the other versions
You can store anything from an address to a entire transaction or a private key
+ +Any keys used you will need to manually store safely as they will be needed later to redeem the bitcoins.
- +Any keys used you will need to manually store safely as they will be needed later to redeem the coins.
+ +You can use the advanced options below to generate different kind of keys and addresses.
@@ -270,8 +310,11 @@Public keys can be generated in your browser or from your bitcoin client.
+Public keys can be generated in your browser or from your wallet.
Enter the public keys of all the participants, to create a multi signature address. Maximum of 15 allowed. Compressed and uncompressed public keys are accepted.
This script should be saved and should be shared with all the participants before a payment is made, so they may validate the authenticity of the address, it will also be used later to release the bitcoins.
+This script should be saved and should be shared with all the participants before a payment is made, so they may validate the authenticity of the address, it will also be used later to release the coins.
+ Or +Use this page to create a raw transaction
Address, WIF key or Multisig Redeem Script: @@ -454,7 +523,14 @@Indicates the timestamp of a transaction.
+ +The settings page can be used to select alternative networks of which you can retrieve your unspent outputs and broadcast a signed transaction into.
@@ -474,24 +550,30 @@Enter the address and amount you wish to make a payment to.
The transaction below has been generated and encoded. It can be broadcasted once it has been signed.
Size: 0 bytes
+ +Size: 0 bytes
+The above redeem script has been decoded
- +The above redeem script has been decoded
?
| Address | +Pubkey | +Identity (if known) | +
|---|
The above script has been decoded
-The above script has been decoded
+| Txid | N | Script | Signed? | MultiSig? | -
| + Txid + | ++ N + | ++ Amount + | ++ Script + | ++ Signed? + | ++ MultiSig? + | +
| Address | Amount | Script | +Address | +Identity (if known) | +Amount | +Script |
The above wif key has been decoded
Address:
Public key:
-Private key:
+Private key in hex:
Is compressed:
-The above public key has been encoded to its address
+The above public key has been encoded to its address
Address:
+The key has been decoded
| Index | Address | Private Key (WIF) | Extended xPub | Extended xPrv | ||
| Index | Address | Private Key (WIF) | Extended xPub | Public key (hex) | Extended xPrv |
| S# | +Address | +Pubkey | +Identity (if known) | +
|---|
Here you can see the script assembly
+ +Sorry the data is too long for the QR generator.
"); - } - } else { - var qrcode = new QRCode("qrcode"); - qrstr = "bitcoin:"+$('.address',thisbtn).val(); - } - - if(qrstr){ - qrcode.makeCode(qrstr); - } - }); - - $('input[title!=""], abbr[title!=""]').tooltip({'placement':'bottom'}); - - if (location.hash !== ''){ - $('a[href="' + location.hash + '"]').tab('show'); - } - - $(".showKey").click(function(){ - $("input[type='password']",$(this).parent().parent()).attr('type','text'); - }); - - $("#homeBtn").click(function(e){ - e.preventDefault(); - history.pushState(null, null, '#home'); - $("#header .active, #content .tab-content").removeClass("active"); - $("#home").addClass("active"); - }); - - $('a[data-toggle="tab"]').on('click', function(e) { - e.preventDefault(); - if(e.target){ - history.pushState(null, null, '#'+$(e.target).attr('href').substr(1)); - } - }); - - window.addEventListener("popstate", function(e) { - var activeTab = $('[href=' + location.hash + ']'); - if (activeTab.length) { - activeTab.tab('show'); - } else { - $('.nav-tabs a:first').tab('show'); - } - }); - - for(i=1;i<3;i++){ - $(".pubkeyAdd").click(); - } - - validateOutputAmount(); - - /* settings page code */ - - $("#coinjs_pub").val('0x'+(coinjs.pub).toString(16)); - $("#coinjs_priv").val('0x'+(coinjs.priv).toString(16)); - $("#coinjs_multisig").val('0x'+(coinjs.multisig).toString(16)); - - $("#coinjs_hdpub").val('0x'+(coinjs.hdkey.pub).toString(16)); - $("#coinjs_hdprv").val('0x'+(coinjs.hdkey.prv).toString(16)); - - $("#settingsBtn").click(function(){ - - // log out of openwallet - $("#walletLogout").click(); - - $("#statusSettings").removeClass("alert-success").removeClass("alert-danger").addClass("hidden").html(""); - $("#settings .has-error").removeClass("has-error"); - - $.each($(".coinjssetting"),function(i, o){ - if(!$(o).val().match(/^0x[0-9a-f]+$/)){ - $(o).parent().addClass("has-error"); - } - }); - - if($("#settings .has-error").length==0){ - - coinjs.pub = $("#coinjs_pub").val()*1; - coinjs.priv = $("#coinjs_priv").val()*1; - coinjs.multisig = $("#coinjs_multisig").val()*1; - - coinjs.hdkey.pub = $("#coinjs_hdpub").val()*1; - coinjs.hdkey.prv = $("#coinjs_hdprv").val()*1; - - configureBroadcast(); - configureGetUnspentTx(); - - $("#statusSettings").addClass("alert-success").removeClass("hidden").html(" Settings updates successfully").fadeOut().fadeIn(); - } else { - $("#statusSettings").addClass("alert-danger").removeClass("hidden").html("There is an error with one or more of your settings"); - } - }); - - $("#coinjs_coin").change(function(){ - - var o = ($("option:selected",this).attr("rel")).split(";"); - - // deal with broadcasting settings - if(o[5]=="false"){ - $("#coinjs_broadcast, #rawTransaction, #rawSubmitBtn, #openBtn").attr('disabled',true); - $("#coinjs_broadcast").val("coinb.in"); - } else { - $("#coinjs_broadcast").val(o[5]); - $("#coinjs_broadcast, #rawTransaction, #rawSubmitBtn, #openBtn").attr('disabled',false); - } - - // deal with unspent output settings - if(o[6]=="false"){ - $("#coinjs_utxo, #redeemFrom, #redeemFromBtn, #openBtn, .qrcodeScanner").attr('disabled',true); - $("#coinjs_utxo").val("coinb.in"); - } else { - $("#coinjs_utxo").val(o[6]); - $("#coinjs_utxo, #redeemFrom, #redeemFromBtn, #openBtn, .qrcodeScanner").attr('disabled',false); - } - - // deal with the reset - $("#coinjs_pub").val(o[0]); - $("#coinjs_priv").val(o[1]); - $("#coinjs_multisig").val(o[2]); - $("#coinjs_hdpub").val(o[3]); - $("#coinjs_hdprv").val(o[4]); - - // hide/show custom screen - if($("option:selected",this).val()=="custom"){ - $("#settingsCustom").removeClass("hidden"); - } else { - $("#settingsCustom").addClass("hidden"); - } - }); - - function configureBroadcast(){ - var host = $("#coinjs_broadcast option:selected").val(); - $("#rawSubmitBtn").unbind(""); - if(host=="blockr.io_litecoin"){ - $("#rawSubmitBtn").click(function(){ - rawSubmitBlockrio_litecoin(this) - }); - } else if(host=="blockr.io_bitcoinmainnet"){ - $("#rawSubmitBtn").click(function(){ - rawSubmitBlockrio_BitcoinMainnet(this); - }); - } else { - $("#rawSubmitBtn").click(function(){ - rawSubmitDefault(this); // revert to default - }); - } - } - - function configureGetUnspentTx(){ - $("#redeemFromBtn").attr('rel',$("#coinjs_utxo option:selected").val()); - } - - /* capture mouse movement to add entropy */ - var IE = document.all?true:false // Boolean, is browser IE? - if (!IE) document.captureEvents(Event.MOUSEMOVE) - document.onmousemove = getMouseXY; - function getMouseXY(e) { - var tempX = 0; - var tempY = 0; - if (IE) { // If browser is IE - tempX = event.clientX + document.body.scrollLeft; - tempY = event.clientY + document.body.scrollTop; - } else { - tempX = e.pageX; - tempY = e.pageY; - }; - - if (tempX < 0){tempX = 0}; - if (tempY < 0){tempY = 0}; - var xEnt = Crypto.util.bytesToHex([tempX]).slice(-2); - var yEnt = Crypto.util.bytesToHex([tempY]).slice(-2); - var addEnt = xEnt.concat(yEnt); - - if ($("#entropybucket").html().indexOf(xEnt) == -1 && $("#entropybucket").html().indexOf(yEnt) == -1) { - $("#entropybucket").html(addEnt + $("#entropybucket").html()); - }; - - if ($("#entropybucket").html().length > 128) { - $("#entropybucket").html($("#entropybucket").html().slice(0, 128)) - }; - - return true; - }; -}); diff --git a/js/cointoolkit.js b/js/cointoolkit.js new file mode 100644 index 00000000..681aa4ae --- /dev/null +++ b/js/cointoolkit.js @@ -0,0 +1,2440 @@ +$(document).ready(function() { + + if(window.location.hostname == "ttutdxh-nubits.github.io" && window.location.protocol != 'https:') { + window.location.href = "https:" + window.location.href.substring(window.location.protocol.length); + } + + var toolkit = {}; + + function updateQueryStringParameter(uri, key, value) { + var re = new RegExp("([?&])" + key + "=.*?(&|$)", "i"); + var separator = uri.indexOf('?') !== -1 ? "&" : "?"; + if (uri.match(re)) { + return uri.replace(re, '$1' + key + "=" + value + '$2'); + } + else { + return uri + separator + key + "=" + value; + } + } + + function walletBalance(){ + var tx = coinjs.transaction(); + $("#walletLoader").removeClass("hidden"); + coinjs.addressBalance($("#walletAddress").html(),function(data){ + if($(data).find("result").text()==1){ + var v = $(data).find("balance").text()/("1e"+coinjs.decimalPlaces); + $("#walletBalance").html(v+" BTC").attr('rel',v).fadeOut().fadeIn(); + } else { + $("#walletBalance").html("0.00 BTC").attr('rel',v).fadeOut().fadeIn(); + } + + $("#walletLoader").addClass("hidden"); + }); + } + + function checkBalanceLoop(){ + setTimeout(function(){ + walletBalance(); + checkBalanceLoop(); + },45000); + } + + + function scannerStart(){ + navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia || false; + if(navigator.getUserMedia){ + if (!!window.stream) { + $("video").attr('src',null); + window.stream.stop(); + } + + var videoSource = $("select#videoSource").val(); + var constraints = { + video: { + optional: [{sourceId: videoSource}] + } + }; + + navigator.getUserMedia(constraints, function(stream){ + window.stream = stream; // make stream available to console + var videoElement = document.querySelector('video'); + videoElement.src = window.URL.createObjectURL(stream); + videoElement.play(); + }, function(error){ }); + + QCodeDecoder().decodeFromCamera(document.getElementById('videoReader'), function(er,data){ + if(!er){ + var match = data.match(/^(bitcoin|nu|Nu|bcexchange|B\&C\ Exchange|ppcoin|peercoin)\:([a-z0-9]{27,34})/i); + var result = match ? match[2] : data; + $(""+$("#qrcode-scanner-callback-to").html()).val(result); + $("#qrScanClose").click(); + } + }); + } else { + $("#videoReaderError").removeClass("hidden"); + $("#videoReader, #videoSource").addClass("hidden"); + } + } + + /* function to determine what we are redeeming from */ + function redeemingFrom(string){ + var r = {}; + var decode = coinjs.addressDecode(string); + if(decode.version == coinjs.pub){ // regular address + r.addr = string; + r.from = 'address'; + r.isMultisig = false; + } else if (decode.version == coinjs.priv){ // wif key + var a = coinjs.wif2address(string); + r.addr = a['address']; + r.from = 'wif'; + r.isMultisig = false; + } else if (decode.version == coinjs.multisig){ // mulisig address + r.addr = ''; + r.from = 'multisigAddress'; + r.isMultisig = false; + } else { + var script = coinjs.script(); + var decodeRs = script.decodeRedeemScript(string); + if(decodeRs){ // redeem script + r.addr = decodeRs['address']; + r.from = 'redeemScript'; + r.decodedRs = decodeRs; + r.isMultisig = true; + } else { // something else + r.addr = ''; + r.from = 'other'; + r.isMultisig = false; + } + } + return r; + } + + /* global function to add outputs to page */ + function addOutput(tx, n, script, amount) { + if(tx){ + if($("#inputs .txId:last").val()!=""){ + $("#inputs .txidAdd:last").click(); + } + + $("#inputs .row:last input").attr('disabled',true); + + $("#inputs .txId:last").val(tx); + $("#inputs .txIdN:last").val(n); + $("#inputs .txIdAmount:last").val(amount); + $("#inputs .txIdScript:last").val(script); + } + } + + /* math to calculate the inputs and outputs */ + + function totalInputAmount(){ + $("#totalInput").html('0.00'); + $.each($("#inputs .txIdAmount"), function(i,o){ + if(isNaN($(o).val())){ + $(o).parent().addClass('has-error'); + } else { + $(o).parent().removeClass('has-error'); + var f = 0; + if(!isNaN($(o).val())){ + f += $(o).val()*1; + } + $("#totalInput").html((($("#totalInput").html()*1) + (f*1)).toFixed(coinjs.decimalPlaces)); + } + }); + totalFee(); + } + + function validateOutputAmount(){ + $("#recipients .amount").unbind(''); + $("#recipients .amount").keyup(function(){ + if(isNaN($(this).val())){ + $(this).parent().addClass('has-error'); + } else { + $(this).parent().removeClass('has-error'); + var f = 0; + $.each($("#recipients .amount"),function(i,o){ + if(!isNaN($(o).val())){ + f += $(o).val()*1; + } + }); + $("#totalOutput").html((f).toFixed(coinjs.decimalPlaces)); + } + totalFee(); + }).keyup(); + } + + function totalFee(){ + var fee = (($("#totalInput").html()*1) - ($("#totalOutput").html()*1)).toFixed(coinjs.decimalPlaces); + $("#transactionFee").val((fee>0)?fee:'0.00'); + } + + function decodeRedeemScript(){ + var script = coinjs.script(); + var decode = script.decodeRedeemScript($("#verifyScript").val()); + if(decode){ + $("#verifyRsData .multisigAddress").val(decode['address']); + $("#verifyRsData .multisigScriptHash").val(decode['scriptHash']); + $("#verifyRsData .multisigScriptHashKnown").val((known.scriptHash[decode['scriptHash']])?known.scriptHash[decode['scriptHash']].name:''); + $("#verifyRsData .signaturesRequired").html(decode['signaturesRequired']); + $("#verifyRsData table tbody").html(""); + for(var i=0;i