diff --git a/weboob/backends/bnporc/captcha.py b/weboob/backends/bnporc/captcha.py deleted file mode 100644 index eaa45436..00000000 --- a/weboob/backends/bnporc/captcha.py +++ /dev/null @@ -1,121 +0,0 @@ -# -*- coding: utf-8 -*- - -# Copyright(C) 2009-2011 Romain Bignon -# -# This file is part of weboob. -# -# weboob is free software: you can redistribute it and/or modify -# it under the terms of the GNU Affero General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# weboob is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Affero General Public License for more details. -# -# You should have received a copy of the GNU Affero General Public License -# along with weboob. If not, see . - - -import hashlib -import sys -import Image - -class TileError(Exception): - def __init__(self, msg, tile = None): - Exception.__init__(self, msg) - self.tile = tile - - -class Captcha(object): - def __init__(self, file): - self.inim = Image.open(file) - self.nx,self.ny = self.inim.size - self.inmat = self.inim.load() - self.map = {} - - self.tiles = [[Tile(x+5*y+1) for y in xrange(5)] for x in xrange(5)] - - def __getitem__(self, (x, y)): - return self.inmat[x % self.nx, y % self.ny] - - def all_coords(self): - for y in xrange(self.ny): - for x in xrange(self.nx): - yield x, y - - def get_codes(self, code): - s = '' - for c in code: - s += '%02d' % self.map[int(c)].id - return s - - def build_tiles(self): - y = 1 - ty = 0 - while y < self.ny: - x = 1 - tx = 0 - while x < self.nx: - tile = self.tiles[tx][ty] - for j in xrange(26): - l = [] - tile.map.append(l) - for i in xrange(26): - if self[x+i,y+j] > 20: - l.append('.') - tile.valid = True - else: - l.append(' ') - - if tile.valid: - self.map[tile.get_num()] = tile - - x += 27 - tx += 1 - - y += 27 - ty += 1 - -class Tile(object): - hash = {'4a6eff78f6c6f172b75bf9fd7fd36d5d': 0, - '70019df58ec6e96d983507de86529058': 1, - '683a3700dbd1b9019b5ad3ca39c545d3': 2, - '998935d6f4111bd586001468a9c705a7': 3, - 'a5cca8bf800fa505cf7ae5039b0cc73c': 4, - '2317a585e19c4f245cdc8acda51e4542': 5, - '956958628d014f6e6bf59d88cd254dc6': 6, - '13c35a4e7bf18e95186311876e66dd95': 7, - '736894876d76899a5cfecc745b095121': 8, - 'ff41cd68224bece411c7fc876ab05a1d': 9 - } - - def __init__(self, _id): - self.id = _id - self.valid = False - self.map = [] - - def __repr__(self): - return "" % (self.id, self.valid) - - def checksum(self): - s = '' - for pxls in self.map: - for pxl in pxls: - s += pxl - return hashlib.md5(s).hexdigest() - - def get_num(self): - sum = self.checksum() - try: - return self.hash[sum] - except KeyError: - raise TileError('Tile not found', self) - - def display(self): - for pxls in self.map: - for pxl in pxls: - sys.stdout.write(pxl) - sys.stdout.write('\n') - print self.checksum() diff --git a/weboob/backends/bnporc/pages/login.py b/weboob/backends/bnporc/pages/login.py index 66332b56..adbdf8a6 100644 --- a/weboob/backends/bnporc/pages/login.py +++ b/weboob/backends/bnporc/pages/login.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright(C) 2009-2011 Romain Bignon +# Copyright(C) 2009-2011 Romain Bignon, Pierre Mazière # # This file is part of weboob. # @@ -23,8 +23,8 @@ import urllib from logging import error from weboob.tools.browser import BasePage, BrowserUnavailable -from weboob.backends.bnporc.captcha import Captcha, TileError - +from weboob.tools.virtkeyboard import VirtKeyboard,VirtKeyboardError +import tempfile __all__ = ['LoginPage', 'ConfirmPage', 'ChangePasswordPage'] @@ -39,14 +39,45 @@ class LoginPage(BasePage): raise BrowserUnavailable(msg) def login(self, login, password): - img = Captcha(self.browser.openurl('/NSImgGrille')) + symbols={'0':'9cc4789a2cb223e8f2d5e676e90264b5', + '1':'e10b58fc085f9683052d5a63c96fc912', + '2':'04ec647e7b3414bcc069f0c54eb55a4c', + '3':'fde84fd9bac725db8463554448f1e469', + '4':'2359eea8671bf112b58264bec0294f71', + '5':'82b55b63480114f04fad8c5c4fa5673a', + '6':'e074864faeaeabb3be3d118192cd8879', + '7':'753468d88d4810206a6f0ab9c6ef1b16', + '8':'9cc4789a2cb223e8f2d5e676e90264b5', + '9':'828cf0faf86ac78e7f43208907620527' + } + + map=self.document.find("//map[@name='MapGril']") + + coords={} + for area in map.getiterator("area"): + code=area.attrib.get("onclick")[-4:-2] + area_coords=[] + for coord in area.attrib.get("coords").split(","): + area_coords.append(int(coord)) + coords[code]=tuple(area_coords) try: - img.build_tiles() - except TileError, err: + vk=VirtKeyboard(self.browser.openurl("/NSImgGrille"),coords,27) + except VirtKeyboardError,err: error("Error: %s" % err) - if err.tile: - err.tile.display() + return False + + for s in symbols.keys(): + try: + vk.get_symbol_code(symbols[s]) + except VirtKeyboardError: + if self.browser.responses_dirname is None: + self.browser.responses_dirname = \ + tempfile.mkdtemp(prefix='weboob_session_') + vk.generate_MD5(self.browser.responses_dirname) + error("Error: Symbol '%s' not found; all symbol hashes are available in %s" \ + % (s,self.browser.responses_dirname)) + return False self.browser.select_form('logincanalnet') # HACK because of fucking malformed HTML, the field isn't recognized by mechanize. @@ -54,7 +85,10 @@ class LoginPage(BasePage): self.browser.set_all_readonly(False) self.browser['ch1'] = login - self.browser['ch5'] = img.get_codes(password) + passwd='' + for c in password: + passwd+=vk.get_symbol_code(symbols[c]) + self.browser['ch5'] = passwd self.browser.submit() @@ -64,17 +98,53 @@ class ConfirmPage(BasePage): class ChangePasswordPage(BasePage): def change_password(self, current, new): - img = Captcha(self.browser.openurl('/NSImgGrille')) + symbols={'0':'9cc4789a2cb223e8f2d5e676e90264b5', + '1':'e10b58fc085f9683052d5a63c96fc912', + '2':'04ec647e7b3414bcc069f0c54eb55a4c', + '3':'fde84fd9bac725db8463554448f1e469', + '4':'2359eea8671bf112b58264bec0294f71', + '5':'82b55b63480114f04fad8c5c4fa5673a', + '6':'e074864faeaeabb3be3d118192cd8879', + '7':'753468d88d4810206a6f0ab9c6ef1b16', + '8':'9cc4789a2cb223e8f2d5e676e90264b5', + '9':'828cf0faf86ac78e7f43208907620527' + } + + map=self.document.find("//map[@name='MapGril']") + + coords={} + for area in map.getiterator("area"): + code=area.attrib.get("onclick")[-4:-2] + area_coords=[] + for coord in area.attrib.get("coords").split(","): + area_coords.append(int(coord)) + coords[code]=tuple(area_coords) try: - img.build_tiles() - except TileError, err: - error('Error: %s' % err) - if err.tile: - err.tile.display() + vk=VirtKeyboard(self.browser.openurl("/NSImgGrille"),coords,27) + except VirtKeyboardError,err: + error("Error: %s" % err) + return False - code_current = img.get_codes(current) - code_new = img.get_codes(new) + for s in symbols.keys(): + try: + vk.get_symbol_code(symbols[s]) + except VirtKeyboardError: + if self.browser.responses_dirname is None: + self.browser.responses_dirname = \ + tempfile.mkdtemp(prefix='weboob_session_') + vk.generate_MD5(self.browser.responses_dirname) + error("Error: Symbol '%s' not found; all symbol hashes are available in %s" \ + % (s,self.browser.responses_dirname)) + return False + + code_current='' + for c in current: + code_current+=vk.get_symbol_code(symbols[c]) + + code_new='' + for c in new: + code_new+=vk.get_symbol_code(symbols[c]) data = {'ch1': code_current, 'ch2': code_new,