class S2eModule(Module, CapBank): NAME = 's2e' DESCRIPTION = u'Épargne Salariale' MAINTAINER = u'Edouard Lambert' EMAIL = '*****@*****.**' LICENSE = 'AGPLv3+' VERSION = '1.4' CONFIG = BackendConfig( ValueBackendPassword('login', label='Identifiant', masked=False), ValueBackendPassword('password', label='Code secret', regexp='^(\d{6})$'), ValueBackendPassword('secret', label=u'Réponse secrète (optionnel)', default=''), Value('website', label='Banque', default='', choices={ 'esalia': u'Esalia', 'capeasi': u'Capeasi', 'erehsbc': u'ERE HSBC', 'bnppere': u'BNPP ERE' })) BROWSERS = { 'esalia': EsaliaBrowser, 'capeasi': CapeasiBrowser, 'erehsbc': ErehsbcBrowser, 'bnppere': BnppereBrowser, } def create_default_browser(self): self.BROWSER = self.BROWSERS[self.config['website'].get()] return self.create_browser(self.config['login'].get(), self.config['password'].get(), secret=self.config['secret'].get()) def get_account(self, _id): return find_object(self.browser.iter_accounts(), id=_id, error=AccountNotFound) def iter_accounts(self): return self.browser.iter_accounts() def iter_history(self, account): return self.browser.iter_history(account) def iter_investment(self, account): return self.browser.iter_investment(account) def iter_pocket(self, account): return self.browser.iter_pocket(account)
class LdlcModule(Module, CapBill): NAME = 'ldlc' DESCRIPTION = u'ldlc website' MAINTAINER = u'Vincent Paredes' EMAIL = '*****@*****.**' LICENSE = 'AGPLv3+' VERSION = '1.2' CONFIG = BackendConfig(Value('login', label='Email'), ValueBackendPassword('password', label='Password'), Value('website', label='Site web', default='part', choices={'pro': 'Professionnels', 'part': 'Particuliers'})) BROWSER = LdlcBrowser def create_default_browser(self): return self.create_browser(self.config['website'].get(), self.config['login'].get(), self.config['password'].get()) def iter_subscription(self): return self.browser.get_subscription_list() def get_subscription(self, _id): return find_object(self.iter_subscription(), id=_id, error=SubscriptionNotFound) def get_bill(self, _id): subid = _id.split('_')[0] subscription = self.get_subscription(subid) return find_object(self.iter_bills(subscription), id=_id, error=BillNotFound) def iter_bills(self, subscription): if not isinstance(subscription, Subscription): subscription = self.get_subscription(subscription) return self.browser.iter_bills(subscription) def download_bill(self, bill): if not isinstance(bill, Bill): bill = self.get_bill(bill) return self.browser.open(bill._url).content
class LCLModule(Module, CapBank): NAME = 'lcl' MAINTAINER = u'Romain Bignon' EMAIL = '*****@*****.**' VERSION = '1.1' DESCRIPTION = u'LCL' LICENSE = 'AGPLv3+' CONFIG = BackendConfig( ValueBackendPassword('login', label='Identifiant', masked=False), ValueBackendPassword('password', label='Code personnel'), Value('website', label='Type de compte', default='par', choices={ 'par': 'Particuliers', 'pro': 'Professionnels', 'ent': 'Entreprises', 'esp': 'Espace Pro' })) BROWSER = LCLBrowser def create_default_browser(self): # assume all `website` option choices are defined here browsers = { 'par': LCLBrowser, 'pro': LCLProBrowser, 'ent': LCLEnterpriseBrowser, 'esp': LCLEspaceProBrowser } website_value = self.config['website'] self.BROWSER = browsers.get(website_value.get(), browsers[website_value.default]) return self.create_browser(self.config['login'].get(), self.config['password'].get()) def iter_accounts(self): return self.browser.get_accounts_list() def get_account(self, _id): return find_object(self.browser.get_accounts_list(), id=_id, error=AccountNotFound) def iter_coming(self, account): transactions = list(self.browser.get_cb_operations(account)) transactions.sort(key=lambda tr: tr.rdate, reverse=True) return transactions def iter_history(self, account): transactions = list(self.browser.get_history(account)) transactions.sort(key=lambda tr: tr.rdate, reverse=True) return transactions
def handle_security(self): if self.page.doc.xpath('//span[@class="a-button-text"]'): self.page.send_code() self.otp_form = self.page.get_response_form() self.otp_url = self.url raise BrowserQuestion( Value('pin_code', label=self.page.get_otp_message() if self.page.get_otp_message() else 'Please type the OTP you received'))
class GuerrillamailModule(Module, CapMessages, CapMessagesPost): NAME = 'guerrillamail' DESCRIPTION = u'GuerrillaMail temp mailbox' MAINTAINER = u'Vincent A' EMAIL = '*****@*****.**' LICENSE = 'AGPLv3+' VERSION = '1.1' BROWSER = GuerrillamailBrowser CONFIG = BackendConfig(Value('inbox', label='Inbox', default='')) def iter_threads(self): inbox = self.config['inbox'].get() if not inbox: raise NotImplementedError() else: return [self.get_thread(inbox)] def get_thread(self, _id): t = Thread(_id) t.title = 'Mail for %s' % _id t.flags = t.IS_DISCUSSION first = True for d in self.browser.get_mails(_id): m = self.make_message(d, t) if not m.content: m.content = self.browser.get_mail_content(m.id) if first: first = False t.root = m else: m.parent = t.root m.parent.children.append(m) return t def post_message(self, m): raise NotImplementedError() def make_message(self, d, thread): m = Message(thread, d['id']) m.children = [] m.sender = d['from'] m.flags = 0 if not d.get('read', True): m.flags = m.IS_UNREAD m.title = d['subject'] m.date = d['datetime'] m.receivers = [d['to']] return m
def double_auth(self, recipient): try: form = self.get_form(id='formCache') except FormNotFound: raise AddRecipientError('form not found') self.browser.context = form['context'] self.browser.dup = form['dup'] self.browser.logged = 1 getsigninfo_data = {} getsigninfo_data['b64_jeton_transaction'] = form['context'] getsigninfo_data['action_level'] = self.get_action_level() r = self.browser.open( 'https://particuliers.secure.societegenerale.fr/sec/getsigninfo.json', data=getsigninfo_data) assert r.page.doc['commun']['statut'] == 'ok' recipient = self.get_recipient_object(recipient, get_info=True) self.browser.page = None if r.page.doc['donnees']['sign_proc'] == 'csa': send_data = {} send_data['csa_op'] = 'sign' send_data['context'] = form['context'] r = self.browser.open( 'https://particuliers.secure.societegenerale.fr/sec/csa/send.json', data=send_data) assert r.page.doc['commun']['statut'] == 'ok' raise AddRecipientStep( recipient, Value( 'code', label= u'Cette opération doit être validée par un Code Sécurité.') ) elif r.page.doc['donnees']['sign_proc'] == 'OOB': oob_data = {} oob_data['b64_jeton_transaction'] = form['context'] r = self.browser.open( 'https://particuliers.secure.societegenerale.fr/sec/oob_sendoob.json', data=oob_data) assert r.page.doc['commun']['statut'] == 'ok' self.browser.id_transaction = r.page.doc['donnees'][ 'id-transaction'] raise AddRecipientStep( recipient, ValueBool( 'pass', label= u'Valider cette opération sur votre applicaton société générale' )) else: raise AddRecipientError('sign process unknown')
def send_sms_to_user(self, recipient): """Add recipient with OTP SMS authentication""" data = {} data['csa_op'] = 'sign' data['context'] = self.context self.open(self.absurl('/sec/csa/send.json'), data=data) raise AddRecipientStep( recipient, Value( 'code', label='Cette opération doit être validée par un Code Sécurité.' ))
def new_recipient(self, recipient, **params): if 'code' in params: # for sms authentication return self.send_code(recipient, **params) # prepare commun data for all authentication method data = {} data['adresseBeneficiaire'] = '' data['iban'] = recipient.iban data['libelleBeneficiaire'] = recipient.label data['notification'] = True data['typeBeneficiaire'] = '' # provisional if self.digital_key: if 'digital_key' in params: return self.new_recipient_digital_key(recipient, data) # need to be on recipient page send sms or mobile notification # needed to get the phone number, enabling the possibility to send sms. # all users with validated phone number can receive sms code self.recipients.go(data=JSON({'type': 'TOUS'})) # check type of recipient activation type_activation = 'sms' # provisional if self.digital_key: if self.page.has_digital_key(): # force users with digital key activated to use digital key authentication type_activation = 'digital_key' if type_activation == 'sms': # post recipient data sending sms with same request data['typeEnvoi'] = 'SMS' recipient = self.add_recip.go(data=json.dumps(data), headers={ 'Content-Type': 'application/json' }).get_recipient(recipient) raise AddRecipientStep( recipient, Value('code', label='Saisissez le code reçu par SMS.')) elif type_activation == 'digital_key': # recipient validated with digital key are immediatly available recipient.enabled_date = datetime.today() raise AddRecipientStep( recipient, ValueBool( 'digital_key', label= 'Validez pour recevoir une demande sur votre application bancaire. La validation de votre bénéficiaire peut prendre plusieurs minutes.' ))
class JirafeauModule(Module, CapPaste): NAME = 'jirafeau' DESCRIPTION = u'Jirafeau-based file upload website' MAINTAINER = u'Vincent A' EMAIL = '*****@*****.**' LICENSE = 'AGPLv3+' VERSION = '1.6' CONFIG = BackendConfig(Value('base_url', label='Base Jirafeau URL', description='URL of the Jirafeau-based site to use', regexp=r'https?://.*', default='https://jirafeau.net/')) BROWSER = JirafeauBrowser def create_default_browser(self): return self.create_browser(self.config['base_url'].get()) def can_post(self, contents, title=None, public=None, max_age=None): if public or max_age not in self.browser.age_keyword: return 0 max_size, _ = self.browser.get_max_sizes() if max_size and len(b64decode(contents)) > max_size: return 0 return 1 def get_paste(self, url): d = self.browser.recognize(url) if not d: return if self.browser.exists(d['id']): return ret = JirafeauPaste(d['id']) ret.url = d['url'] return ret def new_paste(self, *args, **kwargs): return JirafeauPaste(*args, **kwargs) def post_paste(self, paste, max_age=None): d = self.browser.post(b64decode(paste.contents), paste.title, max_age) paste.id = d['id'] paste.url = d['page_url'] return paste def fill_paste(self, obj, fields): if 'contents' in fields: data = self.browser.download(obj.id) obj.contents = bin_to_b64(data) OBJECTS = {JirafeauPaste: fill_paste}
def sms_second_step(self): # <div class="form-errors"><ul><li>Vous avez atteint le nombre maximal de demandes pour aujourd'hui</li></ul></div> error = CleanText('//div[has-class("form-errors")]')(self.doc) if len(error) > 0: raise BrowserIncorrectPassword(error) form = self.get_form() self.browser.auth_token = form['flow_secureForm_instance'] form['otp_prepare[receiveCode]'] = '' form.submit() raise BrowserQuestion(Value('pin_code', label='Enter the PIN Code'))
class BoursoramaModule(Module, CapBank): NAME = 'boursorama' MAINTAINER = u'Gabriel Kerneis' EMAIL = '*****@*****.**' VERSION = '1.2' LICENSE = 'AGPLv3+' DESCRIPTION = u'Boursorama' CONFIG = BackendConfig(ValueBackendPassword('login', label='Identifiant', masked=False), ValueBackendPassword('password', label='Mot de passe'), ValueBool('enable_twofactors', label='Send validation sms', default=False), Value('device', label='Device name', regexp='\w*', default=''), Value('pin_code', label='Sms code', required=False), ) BROWSER = BoursoramaBrowser def create_default_browser(self): return self.create_browser(self.config) def iter_accounts(self): return self.browser.get_accounts_list() def get_account(self, _id): account = self.browser.get_account(_id) if account: return account else: raise AccountNotFound() def iter_history(self, account): for tr in self.browser.get_history(account): if not tr._is_coming: yield tr def iter_coming(self, account): for tr in self.browser.get_history(account): if tr._is_coming: yield tr def iter_investment(self, account): return self.browser.get_investment(account)
class MediawikiModule(Module, CapContent): NAME = 'mediawiki' MAINTAINER = u'Clément Schreiner' EMAIL = '*****@*****.**' VERSION = '1.1' LICENSE = 'AGPLv3+' DESCRIPTION = 'Wikis running MediaWiki, like Wikipedia' CONFIG = BackendConfig(Value('url', label='URL of the Mediawiki website', default='http://en.wikipedia.org/', regexp='https?://.*'), Value('apiurl', label='URL of the Mediawiki website\'s API', default='http://en.wikipedia.org/w/api.php', regexp='https?://.*'), Value('username', label='Login', default=''), ValueBackendPassword('password', label='Password', default='')) BROWSER = MediawikiBrowser def create_default_browser(self): username = self.config['username'].get() password = self.config['password'].get() if len(username) > 0 else None return self.create_browser(self.config['url'].get(), self.config['apiurl'].get(), username, password) def get_content(self, _id, revision=None): _id = _id.replace(' ', '_') content = Content(_id) page = _id rev = revision.id if revision else None with self.browser: data = self.browser.get_wiki_source(page, rev) content.content = data return content def iter_revisions(self, _id): return self.browser.iter_wiki_revisions(_id) def push_content(self, content, message=None, minor=False): self.browser.set_wiki_source(content, message, minor) def get_content_preview(self, content): return self.browser.get_wiki_preview(content)
class SocieteGeneraleModule(Module, CapBank): NAME = 'societegenerale' MAINTAINER = u'Jocelyn Jaubert' EMAIL = '*****@*****.**' VERSION = '1.1' LICENSE = 'AGPLv3+' DESCRIPTION = u'Société Générale' CONFIG = BackendConfig( ValueBackendPassword('login', label='Code client', masked=False), ValueBackendPassword('password', label='Code secret'), Value('website', label='Type de compte', default='par', choices={ 'par': 'Particuliers', 'pro': 'Professionnels', 'ent': 'Entreprises' })) def create_default_browser(self): b = { 'par': SocieteGenerale, 'pro': SGProfessionalBrowser, 'ent': SGEnterpriseBrowser } self.BROWSER = b[self.config['website'].get()] return self.create_browser(self.config['login'].get(), self.config['password'].get()) def iter_accounts(self): for account in self.browser.get_accounts_list(): yield account def get_account(self, _id): with self.browser: account = self.browser.get_account(_id) if account: return account else: raise AccountNotFound() def iter_history(self, account): with self.browser: for tr in self.browser.iter_history(account): if not tr._coming: yield tr def iter_coming(self, account): with self.browser: for tr in self.browser.iter_history(account): if tr._coming: yield tr
class ZerobinModule(Module, CapPaste): NAME = 'zerobin' DESCRIPTION = u'ZeroBin/0bin encrypted pastebin' MAINTAINER = u'Vincent A' EMAIL = '*****@*****.**' LICENSE = 'AGPLv3+' VERSION = '1.4' CONFIG = BackendConfig( Value('url', label='URL of the zerobin/0bin', regexp='https?://.*', default='https://zerobin.net'), ValueBool('discussion', label='Allow paste comments (ZeroBin only)', default=False), ) BROWSER = ZerobinBrowser def create_default_browser(self): return self.create_browser(self.config['url'].get(), self.config['discussion'].get()) def can_post(self, contents, title=None, public=None, max_age=None): """ Checks if the paste can be pasted by this backend. Some properties are considered required (public/private, max_age) while others are just bonuses (language). contents: Can be used to check encodability, maximum length, etc. title: Can be used to check length, allowed characters. Should not be required. public: True must be public, False must be private, None do not care. max_age: Maximum time to live in seconds. A score of 0 means the backend is not suitable. A score of 1 means the backend is suitable. Higher scores means it is more suitable than others with a lower score. :rtype: int :returns: score """ if public: return 0 return self.browser.can_post(contents, max_age) def get_paste(self, id): if '#' not in id: return elif id.startswith('http://') or id.startswith('https://'): if not id.startswith(self.config['url'].get()): return return self.browser.get_paste(id) def new_paste(self, *args, **kwargs): return ZeroPaste(*args, **kwargs) def post_paste(self, paste, max_age=None): self.browser.post_paste(paste, max_age)
class BPModule(Module, CapBankTransfer): NAME = 'bp' MAINTAINER = u'Nicolas Duhamel' EMAIL = '*****@*****.**' VERSION = '1.2' LICENSE = 'AGPLv3+' DESCRIPTION = u'La Banque Postale' CONFIG = BackendConfig( ValueBackendPassword('login', label='Identifiant', masked=False), ValueBackendPassword('password', label='Mot de passe', regexp='^(\d{6}|)$'), Value('website', label='Type de compte', default='par', choices={ 'par': 'Particuliers', 'pro': 'Professionnels' })) def create_default_browser(self): b = {'par': BPBrowser, 'pro': BProBrowser} self.BROWSER = b[self.config['website'].get()] return self.create_browser(self.config['login'].get(), self.config['password'].get()) def iter_accounts(self): return self.browser.get_accounts_list() def get_account(self, _id): return self.browser.get_account(_id) def iter_history(self, account): if account.type == Account.TYPE_MARKET: raise NotImplementedError() for tr in self.browser.get_history(account): if not tr._coming: yield tr def iter_coming(self, account): for tr in self.browser.get_coming(account): if tr._coming: yield tr def transfer(self, id_from, id_to, amount, reason=None): from_account = self.get_account(id_from) to_account = self.get_account(id_to) #TODO: retourner le numero du virement #TODO: support the 'reason' parameter return self.browser.make_transfer(from_account, to_account, amount)
class CmbModule(AbstractModule, CapBankTransfer, CapContact): NAME = 'cmb' MAINTAINER = u'Edouard Lambert' EMAIL = '*****@*****.**' VERSION = '2.1' DESCRIPTION = u'Crédit Mutuel de Bretagne' LICENSE = 'LGPLv3+' PARENT = 'cmso' CONFIG = BackendConfig(ValueBackendPassword('login', label='Identifiant', masked=False), ValueBackendPassword('password', label='Mot de passe'), Value('website', label='Type de compte', default='par', choices={'par': 'Particuliers', 'pro': 'Professionnels'}))
class MaterielnetModule(Module, CapDocument): NAME = 'materielnet' DESCRIPTION = 'Materiel.net' MAINTAINER = 'Edouard Lambert' EMAIL = '*****@*****.**' LICENSE = 'LGPLv3+' VERSION = '2.1' CONFIG = BackendConfig( ValueBackendPassword('login', label='Email'), ValueBackendPassword('password', label='Mot de passe'), Value('captcha_response', label='Réponse captcha', default='', required=False)) BROWSER = MaterielnetBrowser accepted_document_types = (DocumentTypes.BILL, ) def create_default_browser(self): return self.create_browser(self.config, self.config['login'].get(), self.config['password'].get()) def iter_subscription(self): return self.browser.get_subscription_list() def get_subscription(self, _id): return find_object(self.iter_subscription(), id=_id, error=SubscriptionNotFound) def get_document(self, _id): subid = _id.rsplit('_', 1)[0] subscription = self.get_subscription(subid) return find_object(self.iter_documents(subscription), id=_id, error=DocumentNotFound) def iter_documents(self, subscription): if not isinstance(subscription, Subscription): subscription = self.get_subscription(subscription) return self.browser.iter_documents(subscription) def download_document(self, document): if not isinstance(document, Document): document = self.get_document(document) if document.url is NotAvailable: return return self.browser.open(document.url).content
def setUp(self): if not self.is_backend_configured(): self.backend.config['metier'] = Value(value='informaticien') self.backend.config['place'] = Value(value='100|PAYS|01') self.backend.config['salary'] = Value(value='15000') self.backend.config['qualification'] = Value(value='9') self.backend.config['domain'] = Value(value='M18') self.backend.config['limit_data'] = Value(value='93')
def do_otp(self, mfaToken): data = { 'challengeType': 'otp', 'mfaToken': mfaToken } try: result = self.request('/api/mfa/challenge', json=data) except ClientError as e: json_response = e.response.json() # if we send more than 5 otp without success, the server will warn the user to # wait 12h before retrying, but in fact it seems that we can resend otp 5 mins later if e.response.status_code == 429: raise BrowserUnavailable(json_response['detail']) raise BrowserQuestion(Value('otp', label='Veuillez entrer le code reçu par sms au ' + result['obfuscatedPhoneNumber']))
def new_recipient(self, recipient, **params): if 'sms_password' in params: return self.end_sms_recipient(recipient, **params) self.pre_transfer( next(acc for acc in self.get_accounts_list() if acc.type in (Account.TYPE_CHECKING, Account.TYPE_SAVINGS))) # This send sms to user. self.page.go_add_recipient() self.page.check_canceled_auth() self.page.set_browser_form() raise AddRecipientStep( self.get_recipient_obj(recipient), Value('sms_password', label=self.page.get_prompt_text()))
class CanalplusBackend(BaseBackend, ICapVideo, ICapCollection): NAME = 'canalplus' MAINTAINER = u'Nicolas Duhamel' EMAIL = '*****@*****.**' VERSION = '0.e' DESCRIPTION = 'Canal Plus French TV' LICENSE = 'AGPLv3+' CONFIG = BackendConfig( Value('quality', label='Quality of videos', choices=['hd', 'sd'], default='hd')) BROWSER = CanalplusBrowser def create_default_browser(self): return self.create_browser(quality=self.config['quality'].get()) def search_videos(self, pattern, sortby=ICapVideo.SEARCH_RELEVANCE, nsfw=False, max_results=None): with self.browser: return self.browser.search_videos(pattern) def get_video(self, _id): m = re.match('https?://www\.canal-?plus\.fr/.*\?vid=(\d+)', _id) if m: _id = m.group(1) with self.browser: return self.browser.get_video(_id) def fill_video(self, video, fields): if fields != ['thumbnail']: # if we don't want only the thumbnail, we probably want also every fields with self.browser: video = self.browser.get_video(CanalplusVideo.id2url(video.id), video) if 'thumbnail' in fields and video.thumbnail: with self.browser: video.thumbnail.data = self.browser.readurl( video.thumbnail.url) return video OBJECTS = {CanalplusVideo: fill_video} def iter_resources(self, objs, split_path): if BaseVideo in objs: with self.browser: return self.browser.iter_resources(split_path)
def check_auth_methods(self): if self.mobile_confirmation.is_here(): self.page.check_bypass() if self.mobile_confirmation.is_here(): self.polling_data = self.page.get_polling_data() assert self.polling_data, "Can't proceed to polling if no polling_data" raise AppValidation(self.page.get_validation_msg()) if self.otp_validation_page.is_here(): self.otp_data = self.page.get_otp_data() assert self.otp_data, "Can't proceed to SMS handling if no otp_data" raise BrowserQuestion(Value('code', label=self.page.get_message())) self.check_otp_blocked()
class BnppereModule(AbstractModule, CapBankWealth, CapProfile): NAME = 'bnppere' DESCRIPTION = u'BNP Épargne Salariale' MAINTAINER = u'Edouard Lambert' EMAIL = '*****@*****.**' LICENSE = 'LGPLv3+' VERSION = '2.1' CONFIG = BackendConfig( ValueBackendPassword('login', label='Identifiant', masked=False), ValueBackendPassword('password', label='Code secret'), Value('otp', label=u'Code de sécurité', default='', regexp=r'^(\d{6})$'), Value('website', label='Espace Client', default='personeo', choices={ 'personeo': 'PEE, PERCO (Personeo)', 'visiogo': 'PER Entreprises (Visiogo)' })) PARENT = 's2e' def create_default_browser(self): websites = {'personeo': BnppereBrowser, 'visiogo': VisiogoBrowser} self.BROWSER = websites[self.config['website'].get()] return self.create_browser(self.config, weboob=self.weboob) def iter_accounts(self): return self.browser.iter_accounts() def iter_history(self, account): return self.browser.iter_history(account) def get_profile(self): return self.browser.get_profile()
class AloesModule(Module, CapBook): NAME = 'opacwebaloes' MAINTAINER = u'Jeremy Monnet' EMAIL = '*****@*****.**' VERSION = '1.3' DESCRIPTION = 'Aloes Library software' LICENSE = 'AGPLv3+' CONFIG = BackendConfig( Value('login', label='Account ID', regexp='^\d{1,8}\w$'), ValueBackendPassword('password', label='Password of account'), Value('baseurl', label='Base URL')) BROWSER = AloesBrowser def create_default_browser(self): return self.create_browser(self.config['baseurl'].get(), self.config['login'].get(), self.config['password'].get()) def iter_rented(self): for book in self.browser.get_rented_books_list(): yield book def iter_booked(self): for book in self.browser.get_booked_books_list(): yield book def iter_books(self): for book in self.get_booked(): yield book for book in self.get_rented(): yield book def get_book(self, _id): raise NotImplementedError() def search_books(self, _string): raise NotImplementedError()
class OnlinenetModule(Module, CapDocument): NAME = 'onlinenet' DESCRIPTION = u'Online.net' MAINTAINER = u'Edouard Lambert' EMAIL = '*****@*****.**' LICENSE = 'LGPLv3+' VERSION = '1.6' CONFIG = BackendConfig( Value('login', label='Identifiant'), ValueBackendPassword('password', label='Mot de passe')) BROWSER = OnlinenetBrowser accepted_document_types = ( DocumentTypes.BILL, DocumentTypes.OTHER, ) def create_default_browser(self): return self.create_browser(self.config['login'].get(), self.config['password'].get()) def iter_subscription(self): return self.browser.get_subscription_list() def get_subscription(self, _id): return find_object(self.iter_subscription(), id=_id, error=SubscriptionNotFound) def get_document(self, _id): subid = _id.rsplit('_', 1)[0] subscription = self.get_subscription(subid) return find_object(self.iter_documents(subscription), id=_id, error=DocumentNotFound) def iter_documents(self, subscription): if not isinstance(subscription, Subscription): subscription = self.get_subscription(subscription) return self.browser.iter_documents(subscription) def download_document(self, document): if not isinstance(document, Document): document = self.get_document(document) if document._url is NotAvailable: return return self.browser.open(document._url).content
class GanAssurancesBackend(BaseBackend, ICapBank): NAME = 'ganassurances' MAINTAINER = u'Romain Bignon' EMAIL = '*****@*****.**' VERSION = '0.h' DESCRIPTION = u'Groupama Assurances French bank website' LICENSE = 'AGPLv3+' website_choices = OrderedDict([ (k, u'%s (%s)' % (v, k)) for k, v in sorted({ 'espaceclient.groupama.fr': u'Groupama Banque', 'espaceclient.ganassurances.fr': u'Gan Assurances', }.iteritems(), key=lambda (k, v): (v, k)) ]) CONFIG = BackendConfig( Value('website', label='Which bank', choices=website_choices, default='espaceclient.ganassurances.fr'), ValueBackendPassword('login', label='Account ID', masked=False), ValueBackendPassword('password', label='Password of account')) BROWSER = GanAssurances def create_default_browser(self): return self.create_browser(self.config['website'].get(), self.config['login'].get(), self.config['password'].get()) def iter_accounts(self): with self.browser: return self.browser.get_accounts_list() def get_account(self, _id): with self.browser: account = self.browser.get_account(_id) if account: return account else: raise AccountNotFound() def iter_history(self, account): with self.browser: return self.browser.get_history(account) def iter_coming(self, account): with self.browser: return self.browser.get_coming(account)
class CmsoModule(Module, CapBankWealth, CapContact): NAME = 'cmso' MAINTAINER = u'Romain Bignon' EMAIL = '*****@*****.**' VERSION = '1.4' DESCRIPTION = u'Crédit Mutuel Sud-Ouest' LICENSE = 'AGPLv3+' CONFIG = BackendConfig( ValueBackendPassword('login', label='Identifiant', masked=False), ValueBackendPassword('password', label='Mot de passe'), Value('website', label='Type de compte', default='par', choices={ 'par': 'Particuliers', 'pro': 'Professionnels' })) BROWSER = CmsoParBrowser def create_default_browser(self): b = {'par': CmsoParBrowser, 'pro': CmsoProBrowser} self.BROWSER = b[self.config['website'].get()] return self.create_browser( "%s.%s" % (self.NAME, 'com' if self.NAME == 'cmso' else 'fr'), self.config['login'].get(), self.config['password'].get()) def get_account(self, _id): return find_object(self.browser.iter_accounts(), id=_id, error=AccountNotFound) def iter_accounts(self): return self.browser.iter_accounts() def iter_history(self, account): return self.browser.iter_history(account) def iter_coming(self, account): return self.browser.iter_coming(account) def iter_investment(self, account): return self.browser.iter_investment(account) def iter_contacts(self): if self.config['website'].get() != "par": raise NotImplementedError() return self.browser.get_advisor()
class BnpcartesentrepriseModule(Module, CapBank): NAME = 'bnpcards' DESCRIPTION = u'BNP Cartes Entreprises' MAINTAINER = u'Baptiste Delpey' EMAIL = '*****@*****.**' LICENSE = 'LGPLv3+' VERSION = '1.6' CONFIG = BackendConfig( ValueBackendPassword('login', label='Identifiant', masked=False), ValueBackendPassword('password', label='Code personnel'), Value('type', label='Profil de connexion', default='ges', choices={ '1': 'Titulaire', '2': 'Gestionnaire' })) BROWSER = ProxyBrowser def create_default_browser(self): return self.create_browser(self.config['type'].get(), self.config['login'].get(), self.config['password'].get()) def get_account(self, _id): return find_object(self.browser.iter_accounts(), id=_id, error=AccountNotFound) def iter_accounts(self): for acc in self.browser.iter_accounts(): acc._bisoftcap = { 'all': { 'softcap_day': 5, 'day_for_softcap': 100 } } yield acc def iter_coming(self, account): for tr in self.browser.get_transactions(account): if tr._coming: yield tr def iter_history(self, account): for tr in self.browser.get_transactions(account): if not tr._coming: yield tr
class CmmcModule(Module, CapBank, CapContact): NAME = 'cmmc' MAINTAINER = u'Edouard Lambert' EMAIL = '*****@*****.**' VERSION = '1.3' DESCRIPTION = u'Crédit Mutuel Massif Central' LICENSE = 'AGPLv3+' CONFIG = BackendConfig( ValueBackendPassword('login', label='Identifiant', masked=False), ValueBackendPassword('password', label='Mot de passe'), Value('website', label='Type de compte', default='pro', choices={ 'par': 'Particuliers', 'pro': 'Professionnels' })) BROWSER = CmsoParBrowser def create_default_browser(self): b = {'par': CmsoParBrowser, 'pro': CmsoProBrowser} self.BROWSER = b[self.config['website'].get()] return self.create_browser(self.weboob, "cmmc.fr", self.config['login'].get(), self.config['password'].get()) def get_account(self, _id): return find_object(self.browser.iter_accounts(), id=_id, error=AccountNotFound) def iter_accounts(self): return self.browser.iter_accounts() def iter_history(self, account): return self.browser.iter_history(account) def iter_coming(self, account): return self.browser.iter_coming(account) def iter_investment(self, account): return self.browser.iter_investment(account) def iter_contacts(self): if self.config['website'].get() != "par": raise NotImplementedError() return self.browser.get_advisor()
def new_recipient(self, recipient, **params): if 'code' in params: return self.send_code(recipient, **params) # needed to get the phone number, enabling the possibility to send sms. self.recipients.go(data=JSON({'type': 'TOUS'})) # post recipient data sending sms with same request data = {} data['adresseBeneficiaire'] = '' data['iban'] = recipient.iban data['libelleBeneficiaire'] = recipient.label data['notification'] = True data['typeBeneficiaire'] = '' data['typeEnvoi'] = 'SMS' recipient = self.add_recip.go(data=json.dumps(data), headers={'Content-Type': 'application/json'}).get_recipient(recipient) raise AddRecipientStep(recipient, Value('code', label='Saississez le code.'))