else:
MONOSPACE_FONT = 'monospace'
-ALIAS_REGEXP = '^(|([\w\-\.]+)@)((\w[\w\-]+\.)+[\w\-]+)$'
-
from electrum import ELECTRUM_VERSION
import re
def timer_actions(self):
self.run_hook('timer_actions')
- if self.payto_e.hasFocus():
- return
- r = unicode( self.payto_e.text() )
- if r != self.previous_payto_e:
- self.previous_payto_e = r
- r = r.strip()
- if re.match('^(|([\w\-\.]+)@)((\w[\w\-]+\.)+[\w\-]+)$', r):
- try:
- to_address = self.wallet.get_alias(r, True, self.show_message, self.question)
- except:
- return
- if to_address:
- s = r + ' <' + to_address + '>'
- self.payto_e.setText(s)
-
-
-
def update_status(self):
if self.wallet.interface and self.wallet.interface.is_connected:
if not self.wallet.up_to_date:
def address_label_clicked(self, item, column, l, column_addr, column_label):
if column == column_label and item.isSelected():
+ is_editable = item.data(0, 32).toBool()
+ if not is_editable:
+ return
addr = unicode( item.text(column_addr) )
label = unicode( item.text(column_label) )
- if label in self.wallet.aliases.keys():
- return
item.setFlags(Qt.ItemIsEditable|Qt.ItemIsSelectable | Qt.ItemIsUserCheckable | Qt.ItemIsEnabled | Qt.ItemIsDragEnabled)
l.editItem( item, column )
item.setFlags(Qt.ItemIsSelectable | Qt.ItemIsUserCheckable | Qt.ItemIsEnabled | Qt.ItemIsDragEnabled)
if column == column_label:
addr = unicode( item.text(column_addr) )
text = unicode( item.text(column_label) )
- changed = False
+ is_editable = item.data(0, 32).toBool()
+ if not is_editable:
+ return
- if text in self.wallet.aliases.keys():
- print_error("Error: This is one of your aliases")
- label = self.wallet.labels.get(addr,'')
- item.setText(column_label, QString(label))
- else:
- changed = self.set_label(addr, text)
- if changed:
- self.update_history_tab()
- self.update_completions()
+ changed = self.set_label(addr, text)
+ if changed:
+ self.update_history_tab()
+ self.update_completions()
self.current_item_changed(item)
for addr,label in self.wallet.labels.items():
if addr in self.wallet.addressbook:
l.append( label + ' <' + addr + '>')
- l = l + self.wallet.aliases.keys()
+ self.run_hook('update_completions', l)
self.completions.setStringList(l)
r = unicode( self.payto_e.text() )
r = r.strip()
- # alias
- m1 = re.match(ALIAS_REGEXP, r)
# label or alias, with address in brackets
- m2 = re.match('(.*?)\s*\<([1-9A-HJ-NP-Za-km-z]{26,})\>', r)
-
- if m1:
- to_address = self.wallet.get_alias(r, True, self.show_message, self.question)
- if not to_address:
- return
- elif m2:
- to_address = m2.group(2)
- else:
- to_address = r
+ m = re.match('(.*?)\s*\<([1-9A-HJ-NP-Za-km-z]{26,})\>', r)
+ to_address = m.group(2) if m else r
if not is_valid(to_address):
QMessageBox.warning(self, _('Error'), _('Invalid Bitcoin Address') + ':\n' + to_address, _('OK'))
def set_url(self, url):
- payto, amount, label, message, signature, identity, url = self.wallet.parse_url(url, self.show_message, self.question)
+ address, amount, label, message, signature, identity, url = util.parse_url(url)
+
+ if label and self.wallet.labels.get(address) != label:
+ if self.question('Give label "%s" to address %s ?'%(label,address)):
+ if address not in self.wallet.addressbook and not self.wallet.is_mine(address):
+ self.wallet.addressbook.append(address)
+ self.set_label(address, label)
+
+ self.run_hook('set_url', url, self.show_message, self.question)
+
self.tabs.setCurrentIndex(1)
- label = self.wallet.labels.get(payto)
- m_addr = label + ' <'+ payto+'>' if label else payto
+ label = self.wallet.labels.get(address)
+ m_addr = label + ' <'+ address +'>' if label else address
self.payto_e.setText(m_addr)
self.message_e.setText(message)
menu.exec_(self.receive_list.viewport().mapToGlobal(position))
- def payto(self, x, is_alias):
- if not x: return
- if is_alias:
- label = x
- m_addr = label
- else:
- addr = x
- label = self.wallet.labels.get(addr)
- m_addr = label + ' <' + addr + '>' if label else addr
+ def payto(self, addr):
+ if not addr: return
+ label = self.wallet.labels.get(addr)
+ m_addr = label + ' <' + addr + '>' if label else addr
self.tabs.setCurrentIndex(1)
self.payto_e.setText(m_addr)
self.amount_e.setFocus()
- def delete_contact(self, x, is_alias):
+
+ def delete_contact(self, x):
if self.question(_("Do you want to remove")+" %s "%x +_("from your list of contacts?")):
- if not is_alias and x in self.wallet.addressbook:
+ if x in self.wallet.addressbook:
self.wallet.addressbook.remove(x)
self.set_label(x, None)
- elif is_alias and x in self.wallet.aliases:
- self.wallet.aliases.pop(x)
- self.update_history_tab()
- self.update_contacts_tab()
- self.update_completions()
+ self.update_history_tab()
+ self.update_contacts_tab()
+ self.update_completions()
- def create_contact_menu(self, position):
- # fixme: this function apparently has a side effect.
- # if it is not called the menu pops up several times
- #self.contacts_list.selectedIndexes()
+ def create_contact_menu(self, position):
item = self.contacts_list.itemAt(position)
if not item: return
addr = unicode(item.text(0))
label = unicode(item.text(1))
- is_alias = label in self.wallet.aliases.keys()
- x = label if is_alias else addr
+ is_editable = item.data(0,32).toBool()
+ payto_addr = item.data(0,33).toString()
menu = QMenu()
menu.addAction(_("Copy to Clipboard"), lambda: self.app.clipboard().setText(addr))
- menu.addAction(_("Pay to"), lambda: self.payto(x, is_alias))
+ menu.addAction(_("Pay to"), lambda: self.payto(payto_addr))
menu.addAction(_("QR code"), lambda: self.show_qrcode("bitcoin:" + addr, _("Address")))
- if not is_alias:
+ if is_editable:
menu.addAction(_("Edit label"), lambda: self.edit_label(False))
- else:
- menu.addAction(_("View alias details"), lambda: self.show_contact_details(label))
- menu.addAction(_("Delete"), lambda: self.delete_contact(x,is_alias))
+ menu.addAction(_("Delete"), lambda: self.delete_contact(addr))
+
+ self.run_hook('create_contact_menu', menu, item)
menu.exec_(self.contacts_list.viewport().mapToGlobal(position))
# we use column 1 because column 0 may be hidden
l.setCurrentItem(l.topLevelItem(0),1)
- def show_contact_details(self, m):
- a = self.wallet.aliases.get(m)
- if a:
- if a[0] in self.wallet.authorities.keys():
- s = self.wallet.authorities.get(a[0])
- else:
- s = "self-signed"
- msg = _('Alias:')+' '+ m + '\n'+_('Target address:')+' '+ a[1] + '\n\n'+_('Signed by:')+' ' + s + '\n'+_('Signing address:')+' ' + a[0]
- QMessageBox.information(self, 'Alias', msg, 'OK')
def update_contacts_tab(self):
l = self.contacts_list
l.clear()
- alias_targets = []
- for alias, v in self.wallet.aliases.items():
- s, target = v
- alias_targets.append(target)
- item = QTreeWidgetItem( [ target, alias, '-'] )
- item.setBackgroundColor(0, QColor('lightgray'))
- l.addTopLevelItem(item)
-
for address in self.wallet.addressbook:
- if address in alias_targets: continue
label = self.wallet.labels.get(address,'')
n = 0
for tx in self.wallet.transactions.values():
item = QTreeWidgetItem( [ address, label, "%d"%n] )
item.setFont(0, QFont(MONOSPACE_FONT))
+ # 32 = label can be edited (bool)
+ item.setData(0,32, True)
+ # 33 = payto string
+ item.setData(0,33, address)
l.addTopLevelItem(item)
+ self.run_hook('update_contacts_tab', l)
l.setCurrentItem(l.topLevelItem(0))
+
def create_console_tab(self):
from qt_console import Console
self.console = console = Console()
self.show_message(tx_details)
elif treeview == self.contacts_treeview:
m = self.addressbook_list.get_value( self.addressbook_list.get_iter(c), 0)
- a = self.wallet.aliases.get(m)
- if a:
- if a[0] in self.wallet.authorities.keys():
- s = self.wallet.authorities.get(a[0])
- else:
- s = "self-signed"
- msg = 'Alias: '+ m + '\nTarget address: '+ a[1] + '\n\nSigned by: ' + s + '\nSigning address:' + a[0]
- self.show_message(msg)
+ #a = self.wallet.aliases.get(m)
+ #if a:
+ # if a[0] in self.wallet.authorities.keys():
+ # s = self.wallet.authorities.get(a[0])
+ # else:
+ # s = "self-signed"
+ # msg = 'Alias: '+ m + '\nTarget address: '+ a[1] + '\n\nSigned by: ' + s + '\nSigning address:' + a[0]
+ # self.show_message(msg)
def treeview_key_press(self, treeview, event):
self.show_message(tx_details)
elif treeview == self.contacts_treeview:
m = self.addressbook_list.get_value( self.addressbook_list.get_iter(c), 0)
- a = self.wallet.aliases.get(m)
- if a:
- if a[0] in self.wallet.authorities.keys():
- s = self.wallet.authorities.get(a[0])
- else:
- s = "self"
- msg = 'Alias:'+ m + '\n\nTarget: '+ a[1] + '\nSigned by: ' + s + '\nSigning address:' + a[0]
- self.show_message(msg)
+ #a = self.wallet.aliases.get(m)
+ #if a:
+ # if a[0] in self.wallet.authorities.keys():
+ # s = self.wallet.authorities.get(a[0])
+ # else:
+ # s = "self"
+ # msg = 'Alias:'+ m + '\n\nTarget: '+ a[1] + '\nSigned by: ' + s + '\nSigning address:' + a[0]
+ # self.show_message(msg)
return False
def update_sending_tab(self):
# detect addresses that are not mine in history, add them here...
self.addressbook_list.clear()
- for alias, v in self.wallet.aliases.items():
- s, target = v
- label = self.wallet.labels.get(alias)
- self.addressbook_list.append((alias, label, '-'))
+ #for alias, v in self.wallet.aliases.items():
+ # s, target = v
+ # label = self.wallet.labels.get(alias)
+ # self.addressbook_list.append((alias, label, '-'))
for address in self.wallet.addressbook:
label = self.wallet.labels.get(address)
label, is_default_label = self.wallet.get_label(tx_hash)
tooltip = tx_hash + "\n%d confirmations"%conf if tx_hash else ''
- details = self.wallet.get_tx_details(tx_hash)
+ details = self.get_tx_details(tx_hash)
self.history_list.prepend( [tx_hash, conf_icon, time_str, label, is_default_label,
format_satoshis(value,True,self.wallet.num_zeros),
if cursor: self.history_treeview.set_cursor( cursor )
+ def get_tx_details(self, tx_hash):
+ import datetime
+ if not tx_hash: return ''
+ tx = self.wallet.transactions.get(tx_hash)
+ is_mine, v, fee = self.wallet.get_tx_value(tx)
+ conf, timestamp = self.wallet.verifier.get_confirmations(tx_hash)
+
+ if timestamp:
+ time_str = datetime.datetime.fromtimestamp(timestamp).isoformat(' ')[:-3]
+ else:
+ time_str = 'pending'
+
+ inputs = map(lambda x: x.get('address'), tx.inputs)
+ outputs = map(lambda x: x.get('address'), tx.d['outputs'])
+ tx_details = "Transaction Details" +"\n\n" \
+ + "Transaction ID:\n" + tx_hash + "\n\n" \
+ + "Status: %d confirmations\n"%conf
+ if is_mine:
+ if fee:
+ tx_details += "Amount sent: %s\n"% format_satoshis(v-fee, False) \
+ + "Transaction fee: %s\n"% format_satoshis(fee, False)
+ else:
+ tx_details += "Amount sent: %s\n"% format_satoshis(v, False) \
+ + "Transaction fee: unknown\n"
+ else:
+ tx_details += "Amount received: %s\n"% format_satoshis(v, False) \
+
+ tx_details += "Date: %s\n\n"%time_str \
+ + "Inputs:\n-"+ '\n-'.join(inputs) + "\n\n" \
+ + "Outputs:\n-"+ '\n-'.join(outputs)
+
+ return tx_details
+
+
def newaddress_dialog(self, w):
-import os, sys
+import os, sys, re
import platform
import shutil
from datetime import datetime
return "about 1 year ago"
else:
return "over %d years ago" % (round(distance_in_minutes / 525600))
+
+
+
+
+# URL decode
+_ud = re.compile('%([0-9a-hA-H]{2})', re.MULTILINE)
+urldecode = lambda x: _ud.sub(lambda m: chr(int(m.group(1), 16)), x)
+
+def parse_url(url):
+ o = url[8:].split('?')
+ address = o[0]
+ if len(o)>1:
+ params = o[1].split('&')
+ else:
+ params = []
+
+ amount = label = message = signature = identity = ''
+ for p in params:
+ k,v = p.split('=')
+ uv = urldecode(v)
+ if k == 'amount': amount = uv
+ elif k == 'message': message = uv
+ elif k == 'label': label = uv
+ elif k == 'signature':
+ identity, signature = uv.split(':')
+ url = url.replace('&%s=%s'%(k,v),'')
+ else:
+ print k,v
+
+ return address, amount, label, message, signature, identity, url
+
+
+
from util import print_msg, print_error, user_dir, format_satoshis
from bitcoin import *
-# URL decode
-_ud = re.compile('%([0-9a-hA-H]{2})', re.MULTILINE)
-urldecode = lambda x: _ud.sub(lambda m: chr(int(m.group(1), 16)), x)
# AES encryption
EncodeAES = lambda secret, s: base64.b64encode(aes.encryptData(secret,s))
self.use_encryption = config.get('use_encryption', False)
self.seed = config.get('seed', '') # encrypted
self.labels = config.get('labels', {})
- self.aliases = config.get('aliases', {}) # aliases for addresses
- self.authorities = config.get('authorities', {}) # trusted addresses
self.frozen_addresses = config.get('frozen_addresses',[])
self.prioritized_addresses = config.get('prioritized_addresses',[])
- self.receipts = config.get('receipts',{}) # signed URIs
self.addressbook = config.get('contacts', [])
self.imported_keys = config.get('imported_keys',{})
self.history = config.get('addr_history',{}) # address -> list(txid, height)
return tx.get_value(addresses, self.prevout_values)
- def get_tx_details(self, tx_hash):
- import datetime
- if not tx_hash: return ''
- tx = self.transactions.get(tx_hash)
- is_mine, v, fee = self.get_tx_value(tx)
- conf, timestamp = self.verifier.get_confirmations(tx_hash)
-
- if timestamp:
- time_str = datetime.datetime.fromtimestamp(timestamp).isoformat(' ')[:-3]
- else:
- time_str = 'pending'
-
- inputs = map(lambda x: x.get('address'), tx.inputs)
- outputs = map(lambda x: x.get('address'), tx.d['outputs'])
- tx_details = "Transaction Details" +"\n\n" \
- + "Transaction ID:\n" + tx_hash + "\n\n" \
- + "Status: %d confirmations\n"%conf
- if is_mine:
- if fee:
- tx_details += "Amount sent: %s\n"% format_satoshis(v-fee, False) \
- + "Transaction fee: %s\n"% format_satoshis(fee, False)
- else:
- tx_details += "Amount sent: %s\n"% format_satoshis(v, False) \
- + "Transaction fee: unknown\n"
- else:
- tx_details += "Amount received: %s\n"% format_satoshis(v, False) \
-
- tx_details += "Date: %s\n\n"%time_str \
- + "Inputs:\n-"+ '\n-'.join(inputs) + "\n\n" \
- + "Outputs:\n-"+ '\n-'.join(outputs)
-
- r = self.receipts.get(tx_hash)
- if r:
- tx_details += "\n_______________________________________" \
- + '\n\nSigned URI: ' + r[2] \
- + "\n\nSigned by: " + r[0] \
- + '\n\nSignature: ' + r[1]
-
- return tx_details
-
def update_tx_outputs(self, tx_hash):
tx = self.transactions.get(tx_hash)
return True, out
- def read_alias(self, alias):
- # this might not be the right place for this function.
- import urllib
-
- m1 = re.match('([\w\-\.]+)@((\w[\w\-]+\.)+[\w\-]+)', alias)
- m2 = re.match('((\w[\w\-]+\.)+[\w\-]+)', alias)
- if m1:
- url = 'https://' + m1.group(2) + '/bitcoin.id/' + m1.group(1)
- elif m2:
- url = 'https://' + alias + '/bitcoin.id'
- else:
- return ''
- try:
- lines = urllib.urlopen(url).readlines()
- except:
- return ''
-
- # line 0
- line = lines[0].strip().split(':')
- if len(line) == 1:
- auth_name = None
- target = signing_addr = line[0]
- else:
- target, auth_name, signing_addr, signature = line
- msg = "alias:%s:%s:%s"%(alias,target,auth_name)
- print msg, signature
- EC_KEY.verify_message(signing_addr, signature, msg)
-
- # other lines are signed updates
- for line in lines[1:]:
- line = line.strip()
- if not line: continue
- line = line.split(':')
- previous = target
- print repr(line)
- target, signature = line
- EC_KEY.verify_message(previous, signature, "alias:%s:%s"%(alias,target))
-
- if not is_valid(target):
- raise ValueError("Invalid bitcoin address")
-
- return target, signing_addr, auth_name
def update_password(self, seed, old_password, new_password):
if new_password == '': new_password = None
self.imported_keys[k] = c
self.save()
- def get_alias(self, alias, interactive = False, show_message=None, question = None):
- try:
- target, signing_address, auth_name = self.read_alias(alias)
- except BaseException, e:
- # raise exception if verify fails (verify the chain)
- if interactive:
- show_message("Alias error: " + str(e))
- return
-
- print target, signing_address, auth_name
-
- if auth_name is None:
- a = self.aliases.get(alias)
- if not a:
- msg = "Warning: the alias '%s' is self-signed.\nThe signing address is %s.\n\nDo you want to add this alias to your list of contacts?"%(alias,signing_address)
- if interactive and question( msg ):
- self.aliases[alias] = (signing_address, target)
- else:
- target = None
- else:
- if signing_address != a[0]:
- msg = "Warning: the key of alias '%s' has changed since your last visit! It is possible that someone is trying to do something nasty!!!\nDo you accept to change your trusted key?"%alias
- if interactive and question( msg ):
- self.aliases[alias] = (signing_address, target)
- else:
- target = None
- else:
- if signing_address not in self.authorities.keys():
- msg = "The alias: '%s' links to %s\n\nWarning: this alias was signed by an unknown key.\nSigning authority: %s\nSigning address: %s\n\nDo you want to add this key to your list of trusted keys?"%(alias,target,auth_name,signing_address)
- if interactive and question( msg ):
- self.authorities[signing_address] = auth_name
- else:
- target = None
-
- if target:
- self.aliases[alias] = (signing_address, target)
-
- return target
-
-
- def parse_url(self, url, show_message, question):
- o = url[8:].split('?')
- address = o[0]
- if len(o)>1:
- params = o[1].split('&')
- else:
- params = []
-
- amount = label = message = signature = identity = ''
- for p in params:
- k,v = p.split('=')
- uv = urldecode(v)
- if k == 'amount': amount = uv
- elif k == 'message': message = uv
- elif k == 'label': label = uv
- elif k == 'signature':
- identity, signature = uv.split(':')
- url = url.replace('&%s=%s'%(k,v),'')
- else:
- print k,v
-
- if label and self.labels.get(address) != label:
- if question('Give label "%s" to address %s ?'%(label,address)):
- if address not in self.addressbook and not self.is_mine(address):
- self.addressbook.append(address)
- self.labels[address] = label
-
- if signature:
- if re.match('^(|([\w\-\.]+)@)((\w[\w\-]+\.)+[\w\-]+)$', identity):
- signing_address = self.get_alias(identity, True, show_message, question)
- elif is_valid(identity):
- signing_address = identity
- else:
- signing_address = None
- if not signing_address:
- return
- try:
- EC_KEY.verify_message(signing_address, signature, url )
- self.receipt = (signing_address, signature, url)
- except:
- show_message('Warning: the URI contains a bad signature.\nThe identity of the recipient cannot be verified.')
- address = amount = label = identity = message = ''
-
- if re.match('^(|([\w\-\.]+)@)((\w[\w\-]+\.)+[\w\-]+)$', address):
- payto_address = self.get_alias(address, True, show_message, question)
- if payto_address:
- address = address + ' <' + payto_address + '>'
-
- return address, amount, label, message, signature, identity, url
-
def freeze(self,addr):
'labels': self.labels,
'contacts': self.addressbook,
'imported_keys': self.imported_keys,
- 'aliases': self.aliases,
- 'authorities': self.authorities,
- 'receipts': self.receipts,
'num_zeros': self.num_zeros,
'frozen_addresses': self.frozen_addresses,
'prioritized_addresses': self.prioritized_addresses,
--- /dev/null
+import re
+import platform
+from decimal import Decimal
+
+from PyQt4.QtGui import *
+from PyQt4.QtCore import *
+import PyQt4.QtCore as QtCore
+import PyQt4.QtGui as QtGui
+
+from electrum_gui.qrcodewidget import QRCodeWidget
+from electrum_gui import bmp, pyqrnative
+from electrum_gui.i18n import _
+
+
+ALIAS_REGEXP = '^(|([\w\-\.]+)@)((\w[\w\-]+\.)+[\w\-]+)$'
+
+
+config = {}
+
+def get_info():
+ return 'Aliases', _('Retrieve aliases using http.')
+
+def init(self):
+ global config
+ config = self.config
+ self.aliases = config.get('aliases', {}) # aliases for addresses
+ self.authorities = config.get('authorities', {}) # trusted addresses
+ self.receipts = config.get('receipts',{}) # signed URIs
+ do_enable(self, is_enabled())
+
+def is_enabled():
+ return config.get('use_aliases') is True
+
+def is_available():
+ return True
+
+
+def toggle(gui):
+ enabled = not is_enabled()
+ config.set_key('use_aliases', enabled, True)
+ do_enable(gui, enabled)
+ return enabled
+
+
+def do_enable(gui, enabled):
+ if enabled:
+ gui.set_hook('timer_actions', timer_actions)
+ gui.set_hook('set_url', set_url_hook)
+ gui.set_hook('update_contacts_tab', update_contacts_tab_hook)
+ gui.set_hook('update_completions', update_completions_hook)
+ gui.set_hook('create_contact_menu', create_contact_menu_hook)
+ else:
+ gui.unset_hook('timer_actions', timer_actions)
+ gui.unset_hook('set_url', set_url_hook)
+ gui.unset_hook('update_contacts_tab', update_contacts_tab_hook)
+ gui.unset_hook('update_completions', update_completions_hook)
+ gui.unset_hook('create_contact_menu', create_contact_menu_hook)
+
+
+def timer_actions(self):
+ if self.payto_e.hasFocus():
+ return
+ r = unicode( self.payto_e.text() )
+ if r != self.previous_payto_e:
+ self.previous_payto_e = r
+ r = r.strip()
+ if re.match('^(|([\w\-\.]+)@)((\w[\w\-]+\.)+[\w\-]+)$', r):
+ try:
+ to_address = get_alias(self, r, True, self.show_message, self.question)
+ except:
+ return
+ if to_address:
+ s = r + ' <' + to_address + '>'
+ self.payto_e.setText(s)
+
+
+def get_alias(self, alias, interactive = False, show_message=None, question = None):
+ try:
+ target, signing_address, auth_name = read_alias(self, alias)
+ except BaseException, e:
+ # raise exception if verify fails (verify the chain)
+ if interactive:
+ show_message("Alias error: " + str(e))
+ return
+
+ print target, signing_address, auth_name
+
+ if auth_name is None:
+ a = self.aliases.get(alias)
+ if not a:
+ msg = "Warning: the alias '%s' is self-signed.\nThe signing address is %s.\n\nDo you want to add this alias to your list of contacts?"%(alias,signing_address)
+ if interactive and question( msg ):
+ self.aliases[alias] = (signing_address, target)
+ else:
+ target = None
+ else:
+ if signing_address != a[0]:
+ msg = "Warning: the key of alias '%s' has changed since your last visit! It is possible that someone is trying to do something nasty!!!\nDo you accept to change your trusted key?"%alias
+ if interactive and question( msg ):
+ self.aliases[alias] = (signing_address, target)
+ else:
+ target = None
+ else:
+ if signing_address not in self.authorities.keys():
+ msg = "The alias: '%s' links to %s\n\nWarning: this alias was signed by an unknown key.\nSigning authority: %s\nSigning address: %s\n\nDo you want to add this key to your list of trusted keys?"%(alias,target,auth_name,signing_address)
+ if interactive and question( msg ):
+ self.authorities[signing_address] = auth_name
+ else:
+ target = None
+
+ if target:
+ self.aliases[alias] = (signing_address, target)
+
+ return target
+
+
+
+def read_alias(self, alias):
+ import urllib
+
+ m1 = re.match('([\w\-\.]+)@((\w[\w\-]+\.)+[\w\-]+)', alias)
+ m2 = re.match('((\w[\w\-]+\.)+[\w\-]+)', alias)
+ if m1:
+ url = 'https://' + m1.group(2) + '/bitcoin.id/' + m1.group(1)
+ elif m2:
+ url = 'https://' + alias + '/bitcoin.id'
+ else:
+ return ''
+ try:
+ lines = urllib.urlopen(url).readlines()
+ except:
+ return ''
+
+ # line 0
+ line = lines[0].strip().split(':')
+ if len(line) == 1:
+ auth_name = None
+ target = signing_addr = line[0]
+ else:
+ target, auth_name, signing_addr, signature = line
+ msg = "alias:%s:%s:%s"%(alias,target,auth_name)
+ print msg, signature
+ EC_KEY.verify_message(signing_addr, signature, msg)
+
+ # other lines are signed updates
+ for line in lines[1:]:
+ line = line.strip()
+ if not line: continue
+ line = line.split(':')
+ previous = target
+ print repr(line)
+ target, signature = line
+ EC_KEY.verify_message(previous, signature, "alias:%s:%s"%(alias,target))
+
+ if not is_valid(target):
+ raise ValueError("Invalid bitcoin address")
+
+ return target, signing_addr, auth_name
+
+
+def set_url_hook(self, url, show_message, question):
+ payto, amount, label, message, signature, identity, url = util.parse_url(url)
+ if signature:
+ if re.match('^(|([\w\-\.]+)@)((\w[\w\-]+\.)+[\w\-]+)$', identity):
+ signing_address = get_alias(identity, True, show_message, question)
+ elif is_valid(identity):
+ signing_address = identity
+ else:
+ signing_address = None
+ if not signing_address:
+ return
+ try:
+ EC_KEY.verify_message(signing_address, signature, url )
+ self.receipt = (signing_address, signature, url)
+ except:
+ show_message('Warning: the URI contains a bad signature.\nThe identity of the recipient cannot be verified.')
+ address = amount = label = identity = message = ''
+
+ if re.match('^(|([\w\-\.]+)@)((\w[\w\-]+\.)+[\w\-]+)$', address):
+ payto_address = get_alias(address, True, show_message, question)
+ if payto_address:
+ address = address + ' <' + payto_address + '>'
+
+ return address, amount, label, message, signature, identity, url
+
+
+
+def update_contacts_tab_hook(self, l):
+ alias_targets = []
+ for alias, v in self.aliases.items():
+ s, target = v
+ alias_targets.append(target)
+ item = QTreeWidgetItem( [ target, alias, '-'] )
+ item.setBackgroundColor(0, QColor('lightgray'))
+ l.insertTopLevelItem(0,item)
+ item.setData(0,32,False)
+ item.setData(0,33,alias + ' <' + target + '>')
+
+
+
+def update_completions_hook(self, l):
+ l[:] = l + self.aliases.keys()
+
+
+def create_contact_menu_hook(self, menu, item):
+ label = unicode(item.text(1))
+ if label in self.aliases.keys():
+ addr = unicode(item.text(0))
+ label = unicode(item.text(1))
+ menu.addAction(_("View alias details"), lambda: show_contact_details(self, label))
+ menu.addAction(_("Delete alias"), lambda: delete_alias(self, label))
+
+
+def show_contact_details(self, m):
+ a = self.aliases.get(m)
+ if a:
+ if a[0] in self.authorities.keys():
+ s = self.authorities.get(a[0])
+ else:
+ s = "self-signed"
+ msg = _('Alias:')+' '+ m + '\n'+_('Target address:')+' '+ a[1] + '\n\n'+_('Signed by:')+' ' + s + '\n'+_('Signing address:')+' ' + a[0]
+ QMessageBox.information(self, 'Alias', msg, 'OK')
+
+
+def delete_alias(self, x):
+ if self.question(_("Do you want to remove")+" %s "%x +_("from your list of contacts?")):
+ if x in self.aliases:
+ self.aliases.pop(x)
+ self.update_history_tab()
+ self.update_contacts_tab()
+ self.update_completions()