forked from bitpay/i-made-this
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathapp.js
174 lines (146 loc) · 5.71 KB
/
app.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
'use strict';
var bitcore;
angular.module('iMadeThis', ['ngFileUpload', 'monospaced.qrcode'])
.run( function run () {
bitcore = require('bitcore-lib');
})
.controller('MyCtrl', ['$scope', 'Upload', '$http', '$interval',
function ($scope, Upload, $http, $interval) {
var bitcoreServiceBasePath = 'http://localhost:3001/stampingservice';
var pendingFileHashes = {};
var file; // represents the uploaded file
var fileHash; // a hash of the uploaded file
var pollInterval; // $interval promise that needs to be canceled if user exits stamping mode
var privateKey; // the private key of the generated address
function hashFile(file, cb){
Upload.base64DataUrl(file).then(function(urls){
var Buffer = bitcore.deps.Buffer;
var data = new Buffer(urls, 'base64');
var hash = bitcore.crypto.Hash.sha256sha256(data);
var hashString = hash.toString('hex');
return cb(hashString);
});
}
function isFileInBlockchain(fileHashString){
// Asks bitcore-node if the hash of the uploaded file has been timestamped in the bockchain before
$http.get(bitcoreServiceBasePath + '/hash/' + fileHashString)
.success(gotFile)
.error(didNotGetFile);
function gotFile(data, statusCode){
$scope.previousTimestamps = data;
$scope.previousTimestamps = $scope.previousTimestamps.map(function(ts){
ts.date = new Date(ts.timestamp*1000);
return ts;
});
}
function didNotGetFile(data, statusCode){
if(statusCode === 404){
if(pendingFileHashes[fileHash]){
$scope.pendingTimestamp = pendingFileHashes[fileHash];
}
}
}
}
$scope.$watch('files', function () {
// Wait for the user to upload a file
if($scope.files && $scope.files[0]){
file = $scope.files[0];
var typeToks = file.type.split('/');
var nameToks = file.name.split('.');
var ext = nameToks[nameToks.length - 1];
$scope.fileType = typeToks[0];
$scope.fileExtension = ext;
hashFile(file, function(fileHashString){
fileHash = fileHashString;
console.log('fileHash', fileHash);
isFileInBlockchain(fileHash);
});
}
});
$scope.cancel = function(){
// Returns app to zero-state
delete $scope.files;
$scope.stampSuccess = false;
$scope.previousTimestamps = [];
$scope.pendingTimestamp = null;
$scope.cancelStamp();
};
$scope.cancelStamp = function(){
// Exits stamping mode for the current file
$scope.stamping = false;
$interval.cancel(pollInterval);
};
$scope.stampFile = function(){
// Generates a BTC address to be displayed by the qrcode so
// that the user can send the app enough BTC for timestamping
$scope.stamping = true;
privateKey = new bitcore.PrivateKey();
var publicKey = new bitcore.PublicKey(privateKey);
$scope.address = new bitcore.Address(publicKey, bitcore.Networks.testnet).toString();
monitorAddress($scope.address, function(unspentOutputs){
timeStampFile(unspentOutputs, privateKey);
});
};
function monitorAddress(address, cb){
// Asks bitcore-node whether the input BTC address has received funds from the user
function gotAddressInfo(data, statusCode){
if(data.length){
var unspentOutput = data[0];
$interval.cancel(pollInterval);
cb(unspentOutput);
}
}
pollInterval = $interval(function(){
console.log('monitorAddress interval called for address:', address);
$http.get(bitcoreServiceBasePath + '/address/' + address)
.success(gotAddressInfo);
}, 1000);
}
function timeStampFile(unspentOutput, privateKey){
// Uses the BTC received from the user to create a new transaction object
// that includes the hash of the uploaded file
var UnspentOutput = bitcore.Transaction.UnspentOutput;
var Transaction = bitcore.Transaction;
var unspent2 = UnspentOutput(unspentOutput);
// Let's create a transaction that sends all recieved BTC to a miner
// (no coins will go to a change address)
var transaction2 = Transaction();
transaction2
.from(unspent2)
.fee(50000);
// Append the hash of the file to the transaction
transaction2.addOutput(new Transaction.Output({
script: bitcore.Script.buildDataOut(fileHash, 'hex'),
satoshis: 0
}));
// Sign transaction with the original private key that generated
// the address to which the user sent BTC
transaction2.sign(privateKey);
$scope.transactionId = transaction2.id;
var serializedTransaction = transaction2.uncheckedSerialize();
sendTransaction(serializedTransaction);
}
function sendTransaction(serializedTransaction){
// Asks bitcore-node to broadcast the timestamped transaction
$http.get(bitcoreServiceBasePath + '/send/' + serializedTransaction)
.success(sentTransaction);
function sentTransaction(){
$scope.stampSuccess = true;
pendingFileHashes[fileHash] = {date: new Date()};
}
}
$scope.openTransactionInBrowser = function(transactionId){
require('shell').openExternal('https://test-insight.bitpay.com/tx/' + transactionId);
};
// Prevent files that are dragged into the electron browser window
// from being loaded into the browser if we are not in the preliminary
// upload state
window.addEventListener("dragover",function(e){
e = e || event;
e.preventDefault();
},false);
window.addEventListener("drop",function(e){
e = e || event;
e.preventDefault();
},false);
}]);