Skip to content

Commit

Permalink
extend bitcoin: URI with signature data, instead of serialized format
Browse files Browse the repository at this point in the history
  • Loading branch information
ThomasV committed Jul 21, 2015
1 parent 1e66820 commit e77f0c9
Show file tree
Hide file tree
Showing 6 changed files with 54 additions and 54 deletions.
4 changes: 2 additions & 2 deletions gui/qt/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ def __init__(self, windows):
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

Expand Down Expand Up @@ -140,7 +140,7 @@ def check_qt_version(self):
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
Expand Down
78 changes: 35 additions & 43 deletions gui/qt/main_window.py
Original file line number Diff line number Diff line change
Expand Up @@ -698,26 +698,29 @@ def delete_payment_request(self, item):
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 += "&timestamp=%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))
Expand Down Expand Up @@ -745,8 +748,8 @@ def sign_payment_request(self, addr):
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):
Expand All @@ -765,29 +768,20 @@ def save_payment_request(self):
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()
Expand Down Expand Up @@ -883,8 +877,8 @@ def update_receive_tab(self):
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,'')])
Expand Down Expand Up @@ -1343,7 +1337,7 @@ def payment_request_error(self):
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:
Expand All @@ -1354,13 +1348,14 @@ def pay_from_URI(self,URI):
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):
Expand Down Expand Up @@ -1394,19 +1389,16 @@ def get_payment_request_thread():
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()
Expand Down Expand Up @@ -2215,7 +2207,7 @@ def read_tx_from_qrcode(self):
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...
Expand Down
2 changes: 1 addition & 1 deletion gui/qt/paytoedit.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ def __init__(self, win):
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

Expand Down
8 changes: 3 additions & 5 deletions lib/paymentrequest.py
Original file line number Diff line number Diff line change
Expand Up @@ -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):
Expand All @@ -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)
Expand Down
11 changes: 9 additions & 2 deletions lib/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -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()}
Expand All @@ -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


Expand Down
5 changes: 4 additions & 1 deletion plugins/email.py
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,10 @@ def send(self, addr):
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:')
Expand Down

0 comments on commit e77f0c9

Please sign in to comment.