diff --git a/modules/hsbc/backend.py b/modules/hsbc/backend.py
index 4900dd84..c3dee1ca 100644
--- a/modules/hsbc/backend.py
+++ b/modules/hsbc/backend.py
@@ -20,6 +20,7 @@
from weboob.capabilities.bank import ICapBank, AccountNotFound
+from weboob.capabilities.base import find_object
from weboob.tools.backend import BaseBackend, BackendConfig
from weboob.tools.value import ValueBackendPassword, Value
@@ -51,12 +52,7 @@ class HSBCBackend(BaseBackend, ICapBank):
yield account
def get_account(self, _id):
- with self.browser:
- account = self.browser.get_account(_id)
- if account:
- return account
- else:
- raise AccountNotFound()
+ return find_object(self.browser.get_accounts_list(), id=_id, error=AccountNotFound)
def iter_history(self, account):
for tr in self.browser.get_history(account):
diff --git a/modules/hsbc/browser.py b/modules/hsbc/browser.py
index 256ceeed..5a10b184 100644
--- a/modules/hsbc/browser.py
+++ b/modules/hsbc/browser.py
@@ -18,6 +18,7 @@
# along with weboob. If not, see .
+import ssl
from datetime import timedelta
from weboob.tools.date import LinearDateGuesser
@@ -30,22 +31,30 @@ __all__ = ['HSBC']
class HSBC(LoginBrowser):
- VERIFY = False
BASEURL = 'https://client.hsbc.fr'
- CERTHASH = '48d84a782728eeeb622e9ff721688365e24f555ae1aec49b3be33831c7fe24e6'
- connection = URL('https://www.hsbc.fr/1/2/hsbc-france/particuliers/connexion', LoginPage)
- login = URL('https://www.hsbc.fr/1/*', LoginPage)
- cptPage = URL('/cgi-bin/emcgi.*\&CPT_IdPrestation.*',
- '/cgi-bin/emcgi.*\&Ass_IdPrestation.*',
- CPTOperationPage)
- cbPage = URL('/cgi-bin/emcgi.*\&CB_IdPrestation.*',
- CBOperationPage)
- accounts = URL('/cgi-bin/emcgi', AccountsPage)
+
+ connection = URL(r'https://www.hsbc.fr/1/2/hsbc-france/particuliers/connexion', LoginPage)
+ login = URL(r'https://www.hsbc.fr/1/*', LoginPage)
+ cptPage = URL(r'/cgi-bin/emcgi.*\&CPT_IdPrestation.*',
+ r'/cgi-bin/emcgi.*\&Ass_IdPrestation.*',
+ CPTOperationPage)
+ cbPage = URL(r'/cgi-bin/emcgi.*\&CB_IdPrestation.*',
+ CBOperationPage)
+ accounts = URL(r'/cgi-bin/emcgi', AccountsPage)
def __init__(self, username, password, secret, *args, **kwargs):
self.secret = secret
LoginBrowser.__init__(self, username, password, *args, **kwargs)
+ def prepare_request(self, req):
+ preq = super(HSBC, self).prepare_request(req)
+
+ conn = self.session.adapters['https://'].get_connection(preq.url)
+ conn.ssl_version = ssl.PROTOCOL_TLSv1
+
+ return preq
+
+
def home(self):
return self.login.go()
@@ -58,7 +67,7 @@ class HSBC(LoginBrowser):
raise BrowserIncorrectPassword()
self.location(no_secure_key_link)
- self.page.login_w_secure(self.login, self.password, self.secret)
+ self.page.login_w_secure(self.password, self.secret)
self.page.useless_form()
home_url = self.page.get_frame()
@@ -90,7 +99,7 @@ class HSBC(LoginBrowser):
if self.cbPage.is_here():
guesser = LinearDateGuesser(date_max_bump=timedelta(45))
- return self.pagination(lambda: self.page.get_history(date_guesser=guesser))
+ return self.page.get_history(date_guesser=guesser)
else:
return self._get_history()
diff --git a/modules/hsbc/pages.py b/modules/hsbc/pages.py
index 459b9e36..ac06123b 100644
--- a/modules/hsbc/pages.py
+++ b/modules/hsbc/pages.py
@@ -20,25 +20,26 @@
from urlparse import urlparse, parse_qs
import re
-from weboob.tools.browser2.page import HTMLPage, method, ListElement, ItemElement, SkipItem, LoggedPage
-from weboob.tools.browser2.filters import Filter, Env, CleanText, CleanDecimal, Link, Field, DateGuesser, TableCell
from weboob.capabilities import NotAvailable
from weboob.capabilities.bank import Account
from weboob.tools.capabilities.bank.transactions import FrenchTransaction
-class Transaction(FrenchTransaction):
- PATTERNS = [(re.compile('^VIR(EMENT)? (?P.*)'), FrenchTransaction.TYPE_TRANSFER),
- (re.compile('^PRLV (?P.*)'), FrenchTransaction.TYPE_ORDER),
- (re.compile('^(?P.*) CARTE \d+ PAIEMENT CB\s+(?P\d{2})(?P\d{2}) ?(.*)$'),
- FrenchTransaction.TYPE_CARD),
- (re.compile('^RETRAIT DAB (?P\d{2})(?P\d{2}) (?P.*) CARTE [\*\d]+'),
- FrenchTransaction.TYPE_WITHDRAWAL),
- (re.compile('^CHEQUE( (?P.*))?$'), FrenchTransaction.TYPE_CHECK),
- (re.compile('^(F )?COTIS\.? (?P.*)'),FrenchTransaction.TYPE_BANK),
- (re.compile('^(REMISE|REM CHQ) (?P.*)'),FrenchTransaction.TYPE_DEPOSIT),
- ]
+from weboob.tools.browser import BrowserIncorrectPassword
+from weboob.tools.browser2.page import HTMLPage, method, ListElement, ItemElement, SkipItem, LoggedPage, pagination
+from weboob.tools.browser2.filters import Filter, Env, CleanText, CleanDecimal, Link, Field, DateGuesser, TableCell
- _is_coming = False
+
+class Transaction(FrenchTransaction):
+ PATTERNS = [(re.compile(r'^VIR(EMENT)? (?P.*)'), FrenchTransaction.TYPE_TRANSFER),
+ (re.compile(r'^PRLV (?P.*)'), FrenchTransaction.TYPE_ORDER),
+ (re.compile(r'^CB (?P.*)\s+(?P\d+)/(?P\d+)\s*(?P.*)'),
+ FrenchTransaction.TYPE_CARD),
+ (re.compile(r'^DAB (?P\d{2})/(?P\d{2}) ((?P\d{2})H(?P\d{2}) )?(?P.*?)( CB N°.*)?$'),
+ FrenchTransaction.TYPE_WITHDRAWAL),
+ (re.compile(r'^CHEQUE$'), FrenchTransaction.TYPE_CHECK),
+ (re.compile(r'^COTIS\.? (?P.*)'), FrenchTransaction.TYPE_BANK),
+ (re.compile(r'^REMISE (?P.*)'), FrenchTransaction.TYPE_DEPOSIT),
+ ]
class AccountsPage(LoggedPage, HTMLPage):
def get_frame(self):
@@ -114,6 +115,7 @@ class Pagination(object):
class CBOperationPage(LoggedPage, HTMLPage):
+ @pagination
@method
class get_history(Pagination, Transaction.TransactionsElement):
head_xpath = '//table//tr/th'
@@ -127,18 +129,22 @@ class CBOperationPage(LoggedPage, HTMLPage):
class CPTOperationPage(LoggedPage, HTMLPage):
def get_history(self):
- for script in self.doc.xpath('//script'):
- if script.text is None or script.text.find('\nCL(0') < 0:
- continue
+ for script in self.doc.xpath('//script'):
+ if script.text is None or script.text.find('\nCL(0') < 0:
+ continue
- for m in re.finditer(r"CL\((\d+),'(.+)','(.+)','(.+)','([\d -\.,]+)',('([\d -\.,]+)',)?'\d+','\d+','[\w\s]+'\);", script.text, flags=re.MULTILINE):
- op = Transaction(m.group(1))
- op.parse(date=m.group(3), raw=re.sub(u'[ ]+', u' ', m.group(4).replace(u'\n', u' ')))
- op.set_amount(m.group(5))
- op._coming = (re.match('\d+/\d+/\d+', m.group(2)) is None)
- yield op
+ for m in re.finditer(r"CL\((\d+),'(.+)','(.+)','(.+)','([\d -\.,]+)',('([\d -\.,]+)',)?'\d+','\d+','[\w\s]+'\);", script.text, flags=re.MULTILINE):
+ op = Transaction(m.group(1))
+ op.parse(date=m.group(3), raw=re.sub(u'[ ]+', u' ', m.group(4).replace(u'\n', u' ')))
+ op.set_amount(m.group(5))
+ op._coming = (re.match(r'\d+/\d+/\d+', m.group(2)) is None)
+ yield op
class LoginPage(HTMLPage):
+ def on_load(self):
+ for message in self.doc.getroot().cssselect('div.csPanelErrors, div.csPanelAlert'):
+ raise BrowserIncorrectPassword(CleanText('.')(message))
+
def login(self, login):
form = self.get_form(nr=2)
form['userid'] = login
@@ -152,12 +158,15 @@ class LoginPage(HTMLPage):
else:
return a.attrib['href']
- def login_w_secure(self, login, password, secret):
+ def login_w_secure(self, password, secret):
form = self.get_form(nr=0)
form['memorableAnswer'] = secret
inputs = self.doc.xpath(u'//input[starts-with(@id, "keyrcc_password_first")]')
split_pass = u''
- for i,inpu in enumerate(inputs):
+ if len(password) != len(inputs):
+ raise BrowserIncorrectPassword('Your password must be %d chars long' % len(inputs))
+
+ for i, inpu in enumerate(inputs):
#The good field are 1,2,3 and the bad one are 11,12,21,23,24,31 and so one
if int(inpu.attrib['id'].split('first')[1]) < 10:
split_pass += password[i]