# Copyright(C) 2017 Tony Malto # # flake8: compatible # # This file is part of a woob module. # # This woob module is free software: you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This woob module 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 Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public License # along with this woob module. If not, see . from woob.browser import LoginBrowser, URL, need_login from woob.capabilities.bank import Account from woob.browser.exceptions import ServerError from woob.exceptions import BrowserIncorrectPassword, ActionNeeded from .pages import ( LoginPage, AccountsPage, TransactionsInvestmentsPage, AllTransactionsPage, DocumentsSignaturePage, RedirectToUserAgreementPage, UserAgreementPage, RedirectionPage, AuthCodePage, ) class GmfBrowser(LoginBrowser): BASEURL = 'https://mon-espace-societaire.gmf.fr' login_post = URL(r'/connexion/CAP-US_AccesEC/api/accounts/authentication', LoginPage) auth_page = URL(r'https://coveauth.gmf.fr/coveauth-server/oauth2/authorization',) redirection_page = URL(r'/homepage\?code=(?P.+)&state=.*', RedirectionPage) auth_code_page = URL(r'/cap-mx-espacesocietaire-internet/api/users/authorizationCode', AuthCodePage) redirect_to_user_agreement = URL('^$', RedirectToUserAgreementPage) user_agreement = URL(r'/restreint/pages/securite/IC9.faces', UserAgreementPage) accounts = URL(r'/cap-mx-espacesocietaire-internet/api/prestation', AccountsPage) transactions_investments = URL( r'https://espace-assure.gmf.fr/pointentree/contratvie/detailsContrats', TransactionsInvestmentsPage ) all_transactions = URL( r'https://espace-assure.gmf.fr/pages/contratvie/detailscontrats/.*\.faces', AllTransactionsPage ) documents_signature = URL(r'/public/pages/authentification/.*\.faces', DocumentsSignaturePage) def __init__(self, config, *args, **kwargs): kwargs['username'] = config['login'].get() kwargs['password'] = config['password'].get() super().__init__(*args, **kwargs) self.config = config def do_login(self): try: self.login_post.go( json={ 'id': self.username, 'motDePasse': self.password, }, params={'marque': 'GMF'} ) except ServerError as e: if e.response.status_code == 502: # When credentials are incorrect we get a 502 without any error message raise BrowserIncorrectPassword() status = self.page.get_status() if status == 'M': raise ActionNeeded( '''Pour garantir la sécurité de votre espace client, votre compte nécessite une mise à jour. Veuillez vous connecter sur votre portail internet.''' ) id = self.page.get_id() self.auth_page.go( data={ 'username': id, 'password': self.password, 'client_id': 'acces-ec-gmf-PROD', 'state': 'eyJwIjoiU1RBVEUifQ==', 'profile': 'accesec', 'population': '51', 'ttl': '240', 'response_type': 'code', 'redirect_uri': f'{self.BASEURL}/homepage', } ) if not self.redirection_page.is_here(): raise AssertionError('Should be on redirection page') # csrf token is needed for accounts page code = self.page.params['code'] self.auth_code_page.go(json={'code': code}) self.session.headers['covea-csrf-token'] = self.page.get_csrf_token() @need_login def iter_accounts(self): self.accounts.go() return self.page.iter_accounts() @need_login def iter_history(self, account): self.accounts.stay_or_go() data = self.page.get_details_page_form_data(account) self.transactions_investments.go(data=data) self.page.show_all_transactions() return self.page.iter_history() @need_login def iter_investment(self, account): self.accounts.stay_or_go() data = self.page.get_details_page_form_data(account) self.transactions_investments.go(data=data) if self.page.has_investments(): return self.page.iter_investments() elif account.label == 'Epargne Compte Libre Croissance' and account.type == Account.TYPE_LIFE_INSURANCE: # This type of life insurance is very specific and contains only one invest of type 'Fond en euros' with no more information available on detail page. return self.page.create_investment(account) return []