boursorama two_authentication with BrowserToBeContinued instead of raw_input

This commit is contained in:
Baptiste Delpey 2015-03-06 17:27:09 +01:00 committed by Romain Bignon
commit aa721c28b8
3 changed files with 75 additions and 83 deletions

View file

@ -44,7 +44,7 @@ class Boursorama(Browser):
'b290ef629c88f0508e9cc6305421c173bd4291175e3ddedbee05ee666b34c20e'] 'b290ef629c88f0508e9cc6305421c173bd4291175e3ddedbee05ee666b34c20e']
ENCODING = None # refer to the HTML encoding ENCODING = None # refer to the HTML encoding
PAGES = { PAGES = {
'.*/connexion/securisation/index.phtml': AuthenticationPage, '.*/connexion/securisation.*': AuthenticationPage,
'.*connexion.phtml.*': LoginPage, '.*connexion.phtml.*': LoginPage,
'.*/comptes/synthese.phtml': AccountsList, '.*/comptes/synthese.phtml': AccountsList,
'.*/comptes/banque/detail/mouvements.phtml.*': AccountHistory, '.*/comptes/banque/detail/mouvements.phtml.*': AccountHistory,
@ -55,10 +55,14 @@ class Boursorama(Browser):
'.*/opcvm.phtml.*': InvestmentDetail '.*/opcvm.phtml.*': InvestmentDetail
} }
def __init__(self, device="weboob", enable_twofactors=False, __states__ = []
*args, **kwargs):
self.device = device def __init__(self, config=None, *args, **kwargs):
self.enable_twofactors = enable_twofactors self.config = config
self.auth_token = None
kwargs['get_home'] = False
kwargs['username'] = self.config['login'].get()
kwargs['password'] = self.config['password'].get()
Browser.__init__(self, *args, **kwargs) Browser.__init__(self, *args, **kwargs)
def home(self): def home(self):
@ -72,32 +76,36 @@ class Boursorama(Browser):
def handle_authentication(self): def handle_authentication(self):
if self.is_on_page(AuthenticationPage): if self.is_on_page(AuthenticationPage):
if self.enable_twofactors: if self.config['enable_twofactors'].get():
self.page.authenticate(self.device) if not self.config['pin_code'].get() or not self.auth_token:
self.page.send_sms()
else:
self.page.authenticate()
else: else:
raise BrowserIncorrectAuthenticationCode( raise BrowserIncorrectAuthenticationCode(
"""Boursorama - activate the two factor authentication in boursorama config.""" """Boursorama - activate the two factor authentication in boursorama config."""
""" You will receive SMS code but are limited in request per day (around 15)""" """ You will receive SMS code but are limited in request per day (around 15)"""
) )
def login(self): def login(self):
assert isinstance(self.device, basestring) assert isinstance(self.config['device'].get(), basestring)
assert isinstance(self.enable_twofactors, bool) assert isinstance(self.config['enable_twofactors'].get(), bool)
assert self.password.isdigit() assert self.password.isdigit()
if not self.is_on_page(LoginPage): if self.is_on_page(AuthenticationPage):
self.location('https://' + self.DOMAIN + '/connexion.phtml', no_login=True) self.handle_authentication()
else:
if not self.is_on_page(LoginPage):
self.location('https://' + self.DOMAIN + '/connexion.phtml', no_login=True)
self.page.login(self.username, self.password) self.page.login(self.username, self.password)
if self.is_on_page(LoginPage): if self.is_on_page(LoginPage):
raise BrowserIncorrectPassword() raise BrowserIncorrectPassword()
#after login, we might be redirected to the two factor #after login, we might be redirected to the two factor
#authentication page #authentication page
#print "handle authentication" self.handle_authentication()
self.handle_authentication()
self.location('/comptes/synthese.phtml', no_login=True) self.location('/comptes/synthese.phtml', no_login=True)
@ -107,6 +115,8 @@ class Boursorama(Browser):
raise BrowserIncorrectAuthenticationCode() raise BrowserIncorrectAuthenticationCode()
def get_accounts_list(self): def get_accounts_list(self):
if self.is_on_page(AuthenticationPage):
self.login()
if not self.is_on_page(AccountsList): if not self.is_on_page(AccountsList):
self.location('/comptes/synthese.phtml') self.location('/comptes/synthese.phtml')

View file

@ -41,15 +41,12 @@ class BoursoramaModule(Module, CapBank):
ValueBackendPassword('password', label='Mot de passe'), ValueBackendPassword('password', label='Mot de passe'),
ValueBool('enable_twofactors', label='Send validation sms', default=False), ValueBool('enable_twofactors', label='Send validation sms', default=False),
Value('device', label='Device name', regexp='\w*', default=''), Value('device', label='Device name', regexp='\w*', default=''),
Value('pin_code', label='Sms code', required=False),
) )
BROWSER = Boursorama BROWSER = Boursorama
def create_default_browser(self): def create_default_browser(self):
return self.create_browser( return self.create_browser(self.config)
self.config["device"].get()
, self.config["enable_twofactors"].get()
, self.config['login'].get()
, self.config['password'].get())
def iter_accounts(self): def iter_accounts(self):
for account in self.browser.get_accounts_list(): for account in self.browser.get_accounts_list():

View file

@ -17,23 +17,55 @@
# You should have received a copy of the GNU Affero General Public License # You should have received a copy of the GNU Affero General Public License
# along with weboob. If not, see <http://www.gnu.org/licenses/>. # along with weboob. If not, see <http://www.gnu.org/licenses/>.
from weboob.deprecated.browser import Page, BrowserIncorrectPassword
import urllib2
import re import re
import urllib2
from weboob.exceptions import BrowserToBeContinued
from weboob.deprecated.browser import Page, BrowserIncorrectPassword
class BrowserAuthenticationCodeMaxLimit(BrowserIncorrectPassword): class BrowserAuthenticationCodeMaxLimit(BrowserIncorrectPassword):
pass pass
class AuthenticationPage(Page): class AuthenticationPage(Page):
MAX_LIMIT = "vous avez atteint le nombre maximum "\ MAX_LIMIT = r"vous avez atteint le nombre maximum "\
"d'utilisation de l'authentification forte." "d'utilisation de l'authentification forte."
SECURE_PAGE = "https://www.boursorama.com/comptes/connexion/securisation/index.phtml"
REFERER = SECURE_PAGE
headers = {"User-Agent": "Mozilla/5.0 (Windows; U; Windows "
"NT 5.1; en-US; rv:1.9.2.8) Gecko/20100722 Firefox/3.6.8"
" GTB7.1 (.NET CLR 3.5.30729)",
"Referer": REFERER,
}
headers_ajax = {"User-Agent": "Mozilla/5.0 (Windows; U; Windows "
"NT 5.1; en-US; rv:1.9.2.8) Gecko/20100722 Firefox/3.6.8"
" GTB7.1 (.NET CLR 3.5.30729)",
"Accept": "application/json",
"X-Requested-With": "XMLHttpRequest",
"X-Request": "JSON",
"X-Brs-Xhr-Request": "true",
"X-Brs-Xhr-Schema": "DATA+OUT",
"Referer": REFERER,
}
def on_loaded(self): def on_loaded(self):
pass pass
def authenticate(self, device): def authenticate(self):
url = "https://" + self.browser.DOMAIN + "/ajax/banque/otp.phtml"
data = "authentificationforteToken=%s&authentificationforteStep=otp&alertType=10100&org=%s&otp=%s&validate=" % (self.browser.auth_token, self.REFERER, self.browser.config['pin_code'].get())
req = urllib2.Request(url, data, self.headers_ajax)
response = self.browser.open(req)
url = "%s?" % (self.SECURE_PAGE)
data = "org=/&device=%s" % (self.browser.config['device'].get())
req = urllib2.Request(url, data, headers=self.headers)
response = self.browser.open(req)
self.browser.auth_token = None
def send_sms(self):
"""This function simulates the registration of a device on """This function simulates the registration of a device on
boursorama two factor authentification web page. boursorama two factor authentification web page.
I I
@ -41,73 +73,26 @@ class AuthenticationPage(Page):
@exception BrowserAuthenticationCodeMaxLimit when daily limit is consumed @exception BrowserAuthenticationCodeMaxLimit when daily limit is consumed
@exception BrowserIncorrectAuthenticationCode when code is not correct @exception BrowserIncorrectAuthenticationCode when code is not correct
""" """
DOMAIN = self.browser.DOMAIN url = "https://%s/ajax/banque/otp.phtml?org=%s&alertType=10100" % (self.browser.DOMAIN, self.REFERER)
SECURE_PAGE = "https://www.boursorama.com/comptes/connexion/securisation/index.phtml" req = urllib2.Request(url, headers=self.headers_ajax)
REFERER = SECURE_PAGE
#print "Need to authenticate for device", device
#print "Domain information", DOMAIN
url = "https://%s/ajax/banque/otp.phtml?org=%s&alertType=10100" % (DOMAIN, REFERER)
#print url
headers = {"User-Agent": "Mozilla/5.0 (Windows; U; Windows "
"NT 5.1; en-US; rv:1.9.2.8) Gecko/20100722 Firefox/3.6.8"
" GTB7.1 (.NET CLR 3.5.30729)",
"Referer": REFERER,
}
headers_ajax = {"User-Agent": "Mozilla/5.0 (Windows; U; Windows "
"NT 5.1; en-US; rv:1.9.2.8) Gecko/20100722 Firefox/3.6.8"
" GTB7.1 (.NET CLR 3.5.30729)",
"Accept": "application/json",
"X-Requested-With": "XMLHttpRequest",
"X-Request": "JSON",
"X-Brs-Xhr-Request": "true",
"X-Brs-Xhr-Schema": "DATA+OUT",
"Referer": REFERER,
}
req = urllib2.Request(url, headers=headers_ajax)
response = self.browser.open(req) response = self.browser.open(req)
#extrat authentication token from response (in form) #extrat authentication token from response (in form)
info = response.read() info = response.read()
regex = re.compile(r"vous avez atteint le nombre maximum d'utilisation de l'authentification forte.") regex = re.compile(self.MAX_LIMIT)
r = regex.search(info) r = regex.search(info)
if r: if r:
self.logger.info("Boursorama - Vous avez atteint le nombre maximum d'utilisation de l'authentification forte") self.logger.info("Boursorama - Vous avez atteint le nombre maximum d'utilisation de l'authentification forte")
raise BrowserAuthenticationCodeMaxLimit() raise BrowserAuthenticationCodeMaxLimit()
#print "Response from initial request,", len(info), response.info()
regex = re.compile(r"name=\\\"authentificationforteToken\\\" " regex = re.compile(r"name=\\\"authentificationforteToken\\\" "
r"value=\\\"(?P<value>\w*?)\\\"") r"value=\\\"(?P<value>\w*?)\\\"")
r = regex.search(info) r = regex.search(info)
token = r.group('value') self.browser.auth_token = r.group('value')
#print "Extracted token", token
#step2 #step2
url = "https://" + DOMAIN + "/ajax/banque/otp.phtml" url = "https://" + self.browser.DOMAIN + "/ajax/banque/otp.phtml"
data = "authentificationforteToken=%s&authentificationforteStep=start&alertType=10100&org=%s&validate=" % (token, REFERER) data = "authentificationforteToken=%s&authentificationforteStep=start&alertType=10100&org=%s&validate=" % (self.browser.auth_token, self.REFERER)
req = urllib2.Request(url, data, headers_ajax) req = urllib2.Request(url, data, self.headers_ajax)
response = self.browser.open(req) response = self.browser.open(req)
#info = response.read() raise BrowserToBeContinued('pin_code')
#print "after asking to send token authentification" \
# ,len(info), response.info()
pin = raw_input('Enter the "Boursorama Banque" access code:')
#print "Pin access code: ''%s''" % (pin)
url = "https://" + DOMAIN + "/ajax/banque/otp.phtml"
data = "authentificationforteToken=%s&authentificationforteStep=otp&alertType=10100&org=%s&otp=%s&validate=" % (token, REFERER, pin)
req = urllib2.Request(url, data, headers_ajax)
response = self.browser.open(req)
#info = response.read()
#print "after pin authentification", len(info), response.info()
url = "%s?" % (SECURE_PAGE)
data = "org=/&device=%s" % (device)
req = urllib2.Request(url, data, headers=headers)
response = self.browser.open(req)
#result = response.read()
#print response, "\n", response.info()