extend bitcoin: URI with signature data, instead of serialized format
This commit is contained in:
parent
1e668209dc
commit
e77f0c98e7
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
|
|
@ -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))
|
||||
|
@ -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):
|
||||
|
@ -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()
|
||||
|
@ -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,'')])
|
||||
|
@ -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:
|
||||
|
@ -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):
|
||||
|
@ -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()
|
||||
|
@ -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...
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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):
|
||||
|
@ -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)
|
||||
|
|
11
lib/util.py
11
lib/util.py
|
@ -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()}
|
||||
|
@ -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
|
||||
|
||||
|
||||
|
|
|
@ -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:')
|
||||
|
|
Loading…
Reference in New Issue