trm coinbase plugin until fixed - electrum - Electrum Bitcoin wallet HTML git clone https://git.parazyd.org/electrum DIR Log DIR Files DIR Refs DIR Submodules --- DIR commit 8d207aa074c55ce31410d65369e5febd888332d5 DIR parent 9483eadc7eea9aac166256d968d7094fbee4aea0 HTML Author: ThomasV <thomasv@gitorious> Date: Wed, 8 Jan 2014 12:11:40 +0100 rm coinbase plugin until fixed Diffstat: D plugins/coinbase_buyback.py | 307 ------------------------------- 1 file changed, 0 insertions(+), 307 deletions(-) --- DIR diff --git a/plugins/coinbase_buyback.py b/plugins/coinbase_buyback.py t@@ -1,307 +0,0 @@ -import PyQt4 -import sys - -import PyQt4.QtCore as QtCore -import urllib -import re -import time -import os -import httplib2 -import datetime -import json -import string - -from urllib import urlencode - -from PyQt4.QtGui import * -from PyQt4.QtCore import * -from PyQt4.QtWebKit import QWebView - -from electrum import BasePlugin -from electrum.i18n import _, set_language -from electrum.util import user_dir -from electrum.util import appdata_dir -from electrum.util import format_satoshis -from electrum_gui.qt import ElectrumGui - -SATOSHIS_PER_BTC = float(100000000) -COINBASE_ENDPOINT = 'https://coinbase.com' -CERTS_PATH = appdata_dir() + '/certs/ca-coinbase.crt' -SCOPE = 'buy' -REDIRECT_URI = 'urn:ietf:wg:oauth:2.0:oob' -TOKEN_URI = 'https://coinbase.com/oauth/token' -CLIENT_ID = '0a930a48b5a6ea10fb9f7a9fec3d093a6c9062ef8a7eeab20681274feabdab06' -CLIENT_SECRET = 'f515989e8819f1822b3ac7a7ef7e57f755c9b12aee8f22de6b340a99fd0fd617' -# Expiry is stored in RFC3339 UTC format -EXPIRY_FORMAT = '%Y-%m-%dT%H:%M:%SZ' - -class Plugin(BasePlugin): - - def fullname(self): return 'Coinbase BuyBack' - - def description(self): return 'After sending bitcoin, prompt the user with the option to rebuy them via Coinbase.\n\nMarcell Ortutay, 1FNGQvm29tKM7y3niq63RKi7Qbg7oZ3jrB' - - def __init__(self, gui, name): - BasePlugin.__init__(self, gui, name) - self._is_available = self._init() - - def _init(self): - return True - - def is_available(self): - return self._is_available - - def enable(self): - return BasePlugin.enable(self) - - def receive_tx(self, tx, wallet): - domain = wallet.get_account_addresses(None) - is_relevant, is_send, v, fee = tx.get_value(domain, wallet.prevout_values) - if isinstance(self.gui, ElectrumGui): - try: - web = propose_rebuy_qt(abs(v)) - except OAuth2Exception as e: - rm_local_oauth_credentials() - # TODO(ortutay): android flow - - -def propose_rebuy_qt(amount): - web = QWebView() - box = QMessageBox() - box.setFixedSize(200, 200) - - credentials = read_local_oauth_credentials() - questionText = _('Rebuy ') + format_satoshis(amount) + _(' BTC?') - if credentials: - credentials.refresh() - if credentials and not credentials.invalid: - credentials.store_locally() - totalPrice = get_coinbase_total_price(credentials, amount) - questionText += _('\n(Price: ') + totalPrice + _(')') - - if not question(box, questionText): - return - - if credentials: - do_buy(credentials, amount) - else: - do_oauth_flow(web, amount) - return web - -def do_buy(credentials, amount): - h = httplib2.Http(ca_certs=CERTS_PATH) - h = credentials.authorize(h) - params = { - 'qty': float(amount)/SATOSHIS_PER_BTC, - 'agree_btc_amount_varies': False - } - resp, content = h.request( - COINBASE_ENDPOINT + '/api/v1/buys', 'POST', urlencode(params)) - if resp['status'] != '200': - message(_('Error, could not buy bitcoin')) - return - content = json.loads(content) - if content['success']: - message(_('Success!\n') + content['transfer']['description']) - else: - if content['errors']: - message(_('Error: ') + string.join(content['errors'], '\n')) - else: - message(_('Error, could not buy bitcoin')) - -def get_coinbase_total_price(credentials, amount): - h = httplib2.Http(ca_certs=CERTS_PATH) - params={'qty': amount/SATOSHIS_PER_BTC} - resp, content = h.request(COINBASE_ENDPOINT + '/api/v1/prices/buy?' + urlencode(params),'GET') - content = json.loads(content) - if resp['status'] != '200': - return 'unavailable' - return '$' + content['total']['amount'] - -def do_oauth_flow(web, amount): - # QT expects un-escaped URL - auth_uri = step1_get_authorize_url() - web.load(QUrl(auth_uri)) - web.setFixedSize(500, 700) - web.show() - web.titleChanged.connect(lambda(title): complete_oauth_flow(title, web, amount) if re.search('^[a-z0-9]+$', title) else False) - -def complete_oauth_flow(token, web, amount): - web.close() - http = httplib2.Http(ca_certs=CERTS_PATH) - credentials = step2_exchange(str(token), http) - credentials.store_locally() - do_buy(credentials, amount) - -def token_path(): - dir = user_dir() + '/coinbase_buyback' - if not os.access(dir, os.F_OK): - os.mkdir(dir) - return dir + '/token' - -def read_local_oauth_credentials(): - if not os.access(token_path(), os.F_OK): - return None - f = open(token_path(), 'r') - data = f.read() - f.close() - try: - credentials = Credentials.from_json(data) - return credentials - except Exception as e: - return None - -def rm_local_oauth_credentials(): - os.remove(token_path()) - -def step1_get_authorize_url(): - return ('https://coinbase.com/oauth/authorize' - + '?scope=' + SCOPE - + '&redirect_uri=' + REDIRECT_URI - + '&response_type=code' - + '&client_id=' + CLIENT_ID - + '&access_type=offline') - -def step2_exchange(code, http): - body = urllib.urlencode({ - 'grant_type': 'authorization_code', - 'client_id': CLIENT_ID, - 'client_secret': CLIENT_SECRET, - 'code': code, - 'redirect_uri': REDIRECT_URI, - 'scope': SCOPE, - }) - headers = { - 'content-type': 'application/x-www-form-urlencoded', - } - - resp, content = http.request(TOKEN_URI, method='POST', body=body, - headers=headers) - if resp.status == 200: - d = json.loads(content) - access_token = d['access_token'] - refresh_token = d.get('refresh_token', None) - token_expiry = None - if 'expires_in' in d: - token_expiry = datetime.datetime.utcnow() + datetime.timedelta( - seconds=int(d['expires_in'])) - return Credentials(access_token, refresh_token, token_expiry) - else: - raise OAuth2Exception(content) - -class OAuth2Exception(Exception): - """An error related to OAuth2""" - -class Credentials(object): - def __init__(self, access_token, refresh_token, token_expiry): - self.access_token = access_token - self.refresh_token = refresh_token - self.token_expiry = token_expiry - - # Indicates a failed refresh - self.invalid = False - - def to_json(self): - token_expiry = self.token_expiry - if (token_expiry and isinstance(token_expiry, datetime.datetime)): - token_expiry = token_expiry.strftime(EXPIRY_FORMAT) - - d = { - 'access_token': self.access_token, - 'refresh_token': self.refresh_token, - 'token_expiry': token_expiry, - } - return json.dumps(d) - - def store_locally(self): - f = open(token_path(), 'w') - f.write(self.to_json()) - f.close() - - @classmethod - def from_json(cls, s): - data = json.loads(s) - if ('token_expiry' in data - and not isinstance(data['token_expiry'], datetime.datetime)): - try: - data['token_expiry'] = datetime.datetime.strptime( - data['token_expiry'], EXPIRY_FORMAT) - except: - data['token_expiry'] = None - retval = Credentials( - data['access_token'], - data['refresh_token'], - data['token_expiry']) - return retval - - def apply(self, headers): - headers['Authorization'] = 'Bearer ' + self.access_token - - def authorize(self, http): - request_orig = http.request - - # The closure that will replace 'httplib2.Http.request'. - def new_request(uri, method='GET', body=None, headers=None, - redirections=httplib2.DEFAULT_MAX_REDIRECTS, - connection_type=None): - headers = {} - if headers is None: - headers = {} - self.apply(headers) - - resp, content = request_orig(uri, method, body, headers, - redirections, connection_type) - if resp.status == 401: - self._refresh(request_orig) - self.store_locally() - self.apply(headers) - return request_orig(uri, method, body, headers, - redirections, connection_type) - else: - return (resp, content) - - http.request = new_request - setattr(http.request, 'credentials', self) - return http - - def refresh(self): - h = httplib2.Http(ca_certs=CERTS_PATH) - try: - self._refresh(h.request) - except OAuth2Exception as e: - rm_local_oauth_credentials() - self.invalid = True - raise e - - def _refresh(self, http_request): - body = urllib.urlencode({ - 'grant_type': 'refresh_token', - 'refresh_token': self.refresh_token, - 'client_id': CLIENT_ID, - 'client_secret': CLIENT_SECRET, - }) - headers = { - 'content-type': 'application/x-www-form-urlencoded', - } - resp, content = http_request( - TOKEN_URI, method='POST', body=body, headers=headers) - if resp.status == 200: - d = json.loads(content) - self.token_response = d - self.access_token = d['access_token'] - self.refresh_token = d.get('refresh_token', self.refresh_token) - if 'expires_in' in d: - self.token_expiry = datetime.timedelta( - seconds=int(d['expires_in'])) + datetime.datetime.utcnow() - else: - raise OAuth2Exception('Refresh failed, ' + content) - -def message(msg): - box = QMessageBox() - box.setFixedSize(200, 200) - return QMessageBox.information(box, _('Message'), msg) - -def question(widget, msg): - return (QMessageBox.question( - widget, _('Message'), msg, QMessageBox.Yes | QMessageBox.No, QMessageBox.No) - == QMessageBox.Yes)