textend bitcoin: URI with signature data, instead of serialized format - electrum - Electrum Bitcoin wallet HTML git clone https://git.parazyd.org/electrum DIR Log DIR Files DIR Refs DIR Submodules --- DIR commit e77f0c98e774f1566ec7f0cb78ac41f2d462c608 DIR parent 1e668209dcbec5ccf32121e9199f3ff2bc671e81 HTML Author: ThomasV <thomasv@gitorious> Date: Tue, 21 Jul 2015 11:40:55 +0200 extend bitcoin: URI with signature data, instead of serialized format Diffstat: M gui/qt/__init__.py | 4 ++-- M gui/qt/main_window.py | 78 ++++++++++++++----------------- M gui/qt/paytoedit.py | 2 +- M lib/paymentrequest.py | 8 +++----- M lib/util.py | 11 +++++++++-- M plugins/email.py | 5 ++++- 6 files changed, 54 insertions(+), 54 deletions(-) --- DIR diff --git a/gui/qt/__init__.py b/gui/qt/__init__.py t@@ -57,7 +57,7 @@ class OpenFileEventFilter(QObject): def eventFilter(self, obj, event): if event.type() == QtCore.QEvent.FileOpen: if len(self.windows) >= 1: - self.windows[0].pay_from_URI(event.url().toEncoded()) + self.windows[0].pay_to_URI(event.url().toEncoded()) return True return False t@@ -140,7 +140,7 @@ class ElectrumGui: return int(qtVersion[0]) >= 4 and int(qtVersion[2]) >= 7 def set_url(self, uri): - self.current_window.pay_from_URI(uri) + self.current_window.pay_to_URI(uri) def run_wizard(self, storage, action): import installwizard DIR diff --git a/gui/qt/main_window.py b/gui/qt/main_window.py t@@ -698,26 +698,29 @@ class ElectrumWindow(QMainWindow): self.update_receive_tab() self.clear_receive_tab() - def get_receive_URI(self): - addr = str(self.receive_address_e.text()) - amount = self.receive_amount_e.get_amount() - message = unicode(self.receive_message_e.text()) + def get_request_URI(self, addr): + req = self.wallet.receive_requests[addr] + message = self.wallet.labels.get(addr, '') + amount = req['amount'] URI = util.create_URI(addr, amount, message) - return URI + if req.get('id') and req.get('sig'): + sig = req.get('sig').decode('hex') + sig = bitcoin.base_encode(sig, base=58) + URI += "&id=" + req['id'] + "&sig="+sig + if req.get('timestamp'): + URI += "×tamp=%d"%req.get('timestamp') + if req.get('expiration'): + URI += "&expiration=%d"%req.get('expiration') + return str(URI) def receive_list_menu(self, position): item = self.receive_list.itemAt(position) addr = str(item.text(2)) req = self.wallet.receive_requests[addr] - time, amount = req['timestamp'], req['amount'] - message = self.wallet.labels.get(addr, '') - URI = util.create_URI(addr, amount, message) menu = QMenu() - menu.addAction(_("Copy Address"), lambda: self.app.clipboard().setText(addr)) - menu.addAction(_("Copy URI"), lambda: self.app.clipboard().setText(str(URI))) - if req.get('signature'): - menu.addAction(_("Copy Signed URI"), lambda: self.view_signed_request(addr)) - menu.addAction(_("Save as BIP70 file"), lambda: self.export_payment_request(addr)) #.setEnabled(amount is not None) + menu.addAction(_("Copy Address"), lambda: self.view_and_paste(_('Address'), '', addr)) + menu.addAction(_("Copy URI"), lambda: self.view_and_paste('URI', '', self.get_request_URI(addr))) + menu.addAction(_("Save as BIP70 file"), lambda: self.export_payment_request(addr)) menu.addAction(_("Delete"), lambda: self.delete_payment_request(item)) run_hook('receive_list_menu', menu, addr) menu.exec_(self.receive_list.viewport().mapToGlobal(position)) t@@ -745,8 +748,8 @@ class ElectrumWindow(QMainWindow): return pr, requestor = paymentrequest.make_request(self.config, req, alias, alias_privkey) if requestor: - req['requestor'] = requestor - req['signature'] = pr.signature.encode('hex') + req['id'] = requestor + req['sig'] = pr.signature.encode('hex') self.wallet.add_payment_request(req, self.config) def save_payment_request(self): t@@ -765,29 +768,20 @@ class ElectrumWindow(QMainWindow): self.update_address_tab() self.save_request_button.setEnabled(False) - def view_signed_request(self, addr): - import urllib - r = self.wallet.receive_requests.get(addr) - pr = paymentrequest.serialize_request(r).SerializeToString() - pr_text = 'bitcoin:?s=' + bitcoin.base_encode(pr, base=58) + def view_and_paste(self, title, msg, data): dialog = QDialog(self) - dialog.setWindowTitle(_("Signed Request")) + dialog.setWindowTitle(title) vbox = QVBoxLayout() - pr_e = ShowQRTextEdit(text=pr_text) - pr_e.addCopyButton(self.app) - msg = ' '.join([_('The following URI contains your payment request signed with your OpenAlias key.'), - _('The signature is a proof that the payment was requested by you.')]) - l = QLabel(msg) - l.setWordWrap(True) - vbox.addWidget(l) + label = QLabel(msg) + label.setWordWrap(True) + vbox.addWidget(label) + pr_e = ShowQRTextEdit(text=data) vbox.addWidget(pr_e) - msg = _('Note: This format is experimental and may not be supported by other Bitcoin clients.') - vbox.addWidget(QLabel(msg)) vbox.addLayout(Buttons(CopyCloseButton(pr_e.text, self.app, dialog))) dialog.setLayout(vbox) + #print len(data), data dialog.exec_() - def export_payment_request(self, addr): r = self.wallet.receive_requests.get(addr) pr = paymentrequest.serialize_request(r).SerializeToString() t@@ -883,8 +877,8 @@ class ElectrumWindow(QMainWindow): message = req.get('memo', '') date = format_time(timestamp) status = req.get('status') - signature = req.get('signature') - requestor = req.get('requestor', '') + signature = req.get('sig') + requestor = req.get('id', '') amount_str = self.format_amount(amount) if amount else "" account = '' item = QTreeWidgetItem([date, account, address, '', message, amount_str, pr_tooltips.get(status,'')]) t@@ -1343,7 +1337,7 @@ class ElectrumWindow(QMainWindow): self.show_message(self.payment_request.error) self.payment_request = None - def pay_from_URI(self,URI): + def pay_to_URI(self, URI): if not URI: return try: t@@ -1354,13 +1348,14 @@ class ElectrumWindow(QMainWindow): self.tabs.setCurrentIndex(1) r = out.get('r') - s = out.get('s') - if r or s: + sig = out.get('sig') + _id = out.get('id') + if r or (_id and sig): def get_payment_request_thread(): - if s: + if _id and sig: from electrum import paymentrequest - data = bitcoin.base_decode(s, None, base=58) - self.payment_request = paymentrequest.PaymentRequest(data) + pr = paymentrequest.serialize_request(out).SerializeToString() + self.payment_request = paymentrequest.PaymentRequest(pr) else: self.payment_request = get_payment_request(r) if self.payment_request.verify(self.contacts): t@@ -1394,19 +1389,16 @@ class ElectrumWindow(QMainWindow): self.amount_e.textEdited.emit("") - def do_clear(self): self.not_enough_funds = False self.payto_e.is_pr = False for e in [self.payto_e, self.message_e, self.amount_e, self.fee_e]: e.setText('') e.setFrozen(False) - self.set_pay_from([]) self.update_status() run_hook('do_clear') - def set_frozen_state(self, addrs, freeze): self.wallet.set_frozen_state(addrs, freeze) self.update_address_tab() t@@ -2215,7 +2207,7 @@ class ElectrumWindow(QMainWindow): return # if the user scanned a bitcoin URI if data.startswith("bitcoin:"): - self.pay_from_URI(data) + self.pay_to_URI(data) return # else if the user scanned an offline signed tx # transactions are binary, but qrcode seems to return utf8... DIR diff --git a/gui/qt/paytoedit.py b/gui/qt/paytoedit.py t@@ -47,7 +47,7 @@ class PayToEdit(ScanQRTextEdit): self.errors = [] self.is_pr = False self.is_alias = False - self.scan_f = win.pay_from_URI + self.scan_f = win.pay_to_URI self.update_size() self.payto_address = None DIR diff --git a/lib/paymentrequest.py b/lib/paymentrequest.py t@@ -318,7 +318,6 @@ def sign_request_with_alias(pr, alias, alias_privkey): address = bitcoin.address_from_private_key(alias_privkey) compressed = bitcoin.is_compressed(alias_privkey) pr.signature = ec_key.sign_message(message, compressed, address) - return pr def sign_request_with_x509(pr, key_path, cert_path): t@@ -336,14 +335,13 @@ def sign_request_with_x509(pr, key_path, cert_path): hashBytes = bytearray(hashlib.sha256(msgBytes).digest()) sig = rsakey.sign(x509.PREFIX_RSA_SHA256 + hashBytes) pr.signature = bytes(sig) - return pr def serialize_request(req): pr = make_unsigned_request(req) - signature = req.get('signature') - if signature: - requestor = req.get('requestor') + signature = req.get('sig') + requestor = req.get('id') + if requestor and signature: pr.signature = signature.decode('hex') pr.pki_type = 'dnssec+btc' pr.pki_data = str(requestor) DIR diff --git a/lib/util.py b/lib/util.py t@@ -261,7 +261,7 @@ def parse_URI(uri): for k, v in pq.items(): if len(v)!=1: raise Exception('Duplicate Key', k) - if k not in ['amount', 'label', 'message', 'r', 's']: + if k not in ['amount', 'label', 'message', 'r', 'id', 'sig', 'timestamp', 'expiration']: raise BaseException('Unknown key', k) out = {k: v[0] for k, v in pq.items()} t@@ -276,9 +276,16 @@ def parse_URI(uri): amount = Decimal(m.group(1)) * pow( Decimal(10) , k) else: amount = Decimal(am) * COIN - out['amount'] = amount + out['amount'] = int(amount) if 'message' in out: out['message'] = out['message'].decode('utf8') + out['memo'] = out['message'] + if 'timestamp' in out: + out['timestamp'] = int(out['timestamp']) + out['expiration'] = int(out['expiration']) + if 'sig' in out: + out['sig'] = bitcoin.base_decode(out['sig'], None, base=58).encode('hex') + return out DIR diff --git a/plugins/email.py b/plugins/email.py t@@ -148,7 +148,10 @@ class Plugin(BasePlugin): from electrum import paymentrequest r = self.wallet.receive_requests.get(addr) message = r.get('memo', '') - pr, requestor = paymentrequest.make_request(self.config, r) + if r.get('signature'): + pr = paymentrequest.serialize_request(r) + else: + pr, requestor = paymentrequest.make_request(self.config, r) if not pr: return recipient, ok = QtGui.QInputDialog.getText(self.win, 'Send request', 'Send request to:')