@ -1,4 +1,5 @@
from electrum . util import print_error
from electrum . util import print_error
from electrum_gui . i18n import _
import httplib , urllib
import httplib , urllib
import hashlib
import hashlib
import json
import json
@ -14,83 +15,136 @@ import PyQt4.QtCore as QtCore
import PyQt4 . QtGui as QtGui
import PyQt4 . QtGui as QtGui
target_host = ' labelectrum.herokuapp.com '
target_host = ' labelectrum.herokuapp.com '
config = { }
def is_available ( ) :
return True
def auth_token ( ) :
global config
return config . get ( " plugin_label_api_key " )
def init ( gui ) :
def init ( gui ) :
""" If you want to give this a spin create a account at the target_host url and put it in your user dir config
""" If you want to give this a spin create a account at the target_host url and put it in your user dir config
file with the label_api_key . """
file with the label_api_key . """
global auth_token
global config
auth_token = gui . config . get ( " label_api_key " )
config = gui . config
if not auth_token :
return
if config . get ( ' plugin_label_enabled ' ) :
gui . set_hook ( ' create_settings_tab ' , add_settings_tab )
gui . set_hook ( ' close_settings_dialog ' , close_settings_dialog )
if not auth_token ( ) :
return
cloud_wallet = CloudWallet ( gui . wallet )
cloud_wallet = CloudWallet ( gui . wallet )
gui . set_hook ( ' create_settings_tab ' , add_settings_tab )
gui . set_hook ( ' set_label ' , set_label )
gui . set_hook ( ' label_changed ' , label_changed )
cloud_wallet . full_pull ( )
def wallet_id ( wallet ) :
cloud_wallet . full_pull ( )
return hashlib . sha256 ( str ( wallet . get_master_public_key ( ) ) ) . digest ( ) . encode ( ' hex ' )
def wallet_id ( ) :
global config
return hashlib . sha256 ( str ( config . get ( " master_public_key " ) ) ) . digest ( ) . encode ( ' hex ' )
def set_label ( item , label , changed ) :
if not changed :
return
def label_changed ( gui , item , label ) :
print " Label changed! Item: %s Label: %s label " % ( item , label )
print " Label changed! Item: %s Label: %s label " % ( item , label )
global auth_token , target_host
global target_host
hashed = hashlib . sha256 ( item ) . digest ( ) . encode ( ' hex ' )
hashed = hashlib . sha256 ( item ) . digest ( ) . encode ( ' hex ' )
bundle = { " label " : { " external_id " : hashed , " text " : label } }
bundle = { " label " : { " external_id " : hashed , " text " : label } }
params = json . dumps ( bundle )
params = json . dumps ( bundle )
connection = httplib . HTTPConnection ( target_host )
connection = httplib . HTTPConnection ( target_host )
wallet = wallet_id ( gui . wallet )
connection . request ( " POST " , ( " /api/wallets/ %s /labels.json?auth_token= %s " % ( wallet_id ( ) , auth_token ( ) ) ) , params , { ' Content-Type ' : ' application/json ' } )
connection . request ( " POST " , ( " /api/wallets/ %s /labels.json?auth_token= %s " % ( wallet , auth_token ) ) , params , { ' Content-Type ' : ' application/json ' } )
response = connection . getresponse ( )
response = connection . getresponse ( )
if response . reason == httplib . responses [ httplib . NOT_FOUND ] :
if response . reason == httplib . responses [ httplib . NOT_FOUND ] :
return
return
response = json . loads ( response . read ( ) )
response = json . loads ( response . read ( ) )
def close_settings_dialog ( gui ) :
global config
# When you enable the plugin for the first time this won't exist.
if is_enabled ( ) :
if hasattr ( gui , ' auth_token_edit ' ) :
config . set_key ( " plugin_label_api_key " , str ( gui . auth_token_edit . text ( ) ) )
else :
QMessageBox . information ( None , _ ( " Cloud plugin loaded " ) , _ ( " Please open the settings again to configure the label-cloud plugin. " ) )
def add_settings_tab ( gui , tabs ) :
def add_settings_tab ( gui , tabs ) :
cloud_tab = QWidget ( )
def check_for_api_key ( api_key ) :
layout = QGridLayout ( cloud_tab )
global config
layout . addWidget ( QLabel ( " API Key: " ) , 0 , 0 )
if api_key and len ( api_key ) > 12 :
layout . addWidget ( QLineEdit ( auth_token ) , 0 , 2 )
config . set_key ( " plugin_label_api_key " , str ( gui . auth_token_edit . text ( ) ) )
upload . setEnabled ( True )
download . setEnabled ( True )
else :
upload . setEnabled ( False )
download . setEnabled ( False )
cloud_tab = QWidget ( )
layout = QGridLayout ( cloud_tab )
layout . addWidget ( QLabel ( " API Key: " ) , 0 , 0 )
layout . addWidget ( QLabel ( " Label sync options: " ) , 1 , 0 )
# TODO: I need to add it to the Electrum GUI here so I can retrieve it later when the settings dialog is closed, is there a better way to do this?
gui . auth_token_edit = QLineEdit ( auth_token ( ) )
gui . auth_token_edit . textChanged . connect ( check_for_api_key )
upload = QPushButton ( " Force upload " )
layout . addWidget ( gui . auth_token_edit , 0 , 1 , 1 , 2 )
upload . clicked . connect ( lambda : full_push ( gui . wallet ) )
layout . addWidget ( QLabel ( " Label cloud options: " ) , 1 , 0 )
layout . addWidget ( upload , 1 , 1 )
download = QPushButton ( " Force download " )
up load = QPushButton ( " Force up load " )
download . clicked . connect ( lambda : full_pull ( gui . wallet ) )
up load. clicked . connect ( lambda : full_push ( gui . wallet ) )
layout . addWidget ( down load, 1 , 2 )
layout . addWidget ( up load, 1 , 1 )
tabs . addTab ( cloud_tab , " Label cloud " )
download = QPushButton ( " Force download " )
download . clicked . connect ( lambda : full_pull ( gui . wallet ) )
layout . addWidget ( download , 1 , 2 )
gui . cloud_tab = cloud_tab
check_for_api_key ( auth_token ( ) )
tabs . addTab ( cloud_tab , " Label cloud " )
def full_push ( wallet ) :
def full_push ( wallet ) :
cloud_wallet = CloudWallet ( wallet )
cloud_wallet = CloudWallet ( wallet )
cloud_wallet . full_push ( )
cloud_wallet . full_push ( )
print " Labels pushed "
QMessageBox . information ( None , _ ( " Labels synced " ) , _ ( " Yo ur label s have b een uploa ded. " ) )
def full_pull ( wallet ) :
def full_pull ( wallet ) :
cloud_wallet = CloudWallet ( wallet )
cloud_wallet = CloudWallet ( wallet )
cloud_wallet . full_pull ( True )
cloud_wallet . full_pull ( True )
print " Labels pulled, please restart your client "
QMessageBox . information ( None , _ ( " Labels synced " ) , _ ( " Your labels have been synced, please restart Electrum for the changes to take effect. " ) )
def show ( ) :
def show ( ) :
print ' showing '
print ' showing '
def get_info ( ) :
def get_info ( ) :
return ' Label sync ' , " Syncs your labels with LabElectrum . Labels are not encrypted, transactions and addresses are however. This code might increase the load of your wallet with a few micoseconds as it will sync labels on each startup. "
return ' Label sync ' , " Syncs your labels with ' the cloud ' . Labels are not encrypted, transactions and addresses are however. This code might increase the load of your wallet with a few micoseconds as it will sync labels on each startup."
def is_enabled ( ) :
def is_enabled ( ) :
return True
return config . get ( ' plugin_label_enabled ' ) is True
def toggle ( gui ) :
def toggle ( gui ) :
return is_enabled ( )
if not is_enabled ( ) :
enabled = True
else :
enabled = False
gui . unset_hook ( ' create_settings_tab ' , add_settings_tab )
gui . unset_hook ( ' close_settings_dialog ' , close_settings_dialog )
config . set_key ( ' plugin_label_enabled ' , enabled , True )
if enabled :
init ( gui )
return enabled
# This can probably be refactored into plain top level methods instead of a class
# This can probably be refactored into plain top level methods instead of a class
class CloudWallet ( ) :
class CloudWallet ( ) :
def __init__ ( self , wallet ) :
def __init__ ( self , wallet ) :
self . mpk = hashlib . sha256 ( str ( wallet . get_master_public_key ( ) ) ) . digest ( ) . encode ( ' hex ' )
self . labels = wallet . labels
self . labels = wallet . labels
self . transactions = wallet . transactions
self . transactions = wallet . transactions
@ -101,11 +155,10 @@ class CloudWallet():
self . addresses = addresses
self . addresses = addresses
def full_pull ( self , force = False ) :
def full_pull ( self , force = False ) :
global target_host , auth_token
global target_host
connection = httplib . HTTPConnection ( target_host )
connection = httplib . HTTPConnection ( target_host )
connection . request ( " GET " , ( " /api/wallets/ %s /labels.json?auth_token= %s " % ( self . mpk , auth_token ) ) , " " , { ' Content-Type ' : ' application/json ' } )
connection . request ( " GET " , ( " /api/wallets/ %s /labels.json?auth_token= %s " % ( wallet_id ( ) , auth_token ( ) ) ) , " " , { ' Content-Type ' : ' application/json ' } )
response = connection . getresponse ( )
response = connection . getresponse ( )
if response . reason == httplib . responses [ httplib . NOT_FOUND ] :
if response . reason == httplib . responses [ httplib . NOT_FOUND ] :
return
return
@ -114,6 +167,10 @@ class CloudWallet():
except ValueError as e :
except ValueError as e :
return
return
if " error " in response :
QMessageBox . warning ( None , _ ( " Error " ) , _ ( " Could not sync labels: %s " % response [ " error " ] ) )
return
for label in response :
for label in response :
for key in self . addresses :
for key in self . addresses :
target_hashed = hashlib . sha256 ( key ) . digest ( ) . encode ( ' hex ' )
target_hashed = hashlib . sha256 ( key ) . digest ( ) . encode ( ' hex ' )
@ -127,7 +184,7 @@ class CloudWallet():
self . labels [ key ] = label [ " text " ]
self . labels [ key ] = label [ " text " ]
def full_push ( self ) :
def full_push ( self ) :
global target_host , auth_token
global target_host
bundle = { " labels " : { } }
bundle = { " labels " : { } }
for key , value in self . labels . iteritems ( ) :
for key , value in self . labels . iteritems ( ) :
@ -136,10 +193,16 @@ class CloudWallet():
params = json . dumps ( bundle )
params = json . dumps ( bundle )
connection = httplib . HTTPConnection ( target_host )
connection = httplib . HTTPConnection ( target_host )
connection . request ( " POST " , ( " /api/wallets/ %s /labels/batch.json?auth_token= %s " % ( self . mpk , auth_token ) ) , params , { ' Content-Type ' : ' application/json ' } )
connection . request ( " POST " , ( " /api/wallets/ %s /labels/batch.json?auth_token= %s " % ( wallet_id ( ) , auth_token ( ) ) ) , params , { ' Content-Type ' : ' application/json ' } )
response = connection . getresponse ( )
response = connection . getresponse ( )
if response . reason == httplib . responses [ httplib . NOT_FOUND ] :
if response . reason == httplib . responses [ httplib . NOT_FOUND ] :
return
return
response = json . loads ( response . read ( ) )
try :
print response
response = json . loads ( response . read ( ) )
except ValueError as e :
return
if " error " in response :
QMessageBox . warning ( None , _ ( " Error " ) , _ ( " Could not sync labels: %s " % response [ " error " ] ) )
return