def evernote_login_password( auth_user: Optional[str], auth_password: Optional[str], backend: str, network_retry_count: int, ) -> str: auth_user, auth_password = prompt_credentials(auth_user, auth_password) auth_client = get_auth_client( backend=backend, network_retry_count=network_retry_count ) try: auth_res = auth_client.login(auth_user, auth_password) except EvernoteAuthError as e: raise ProgramTerminatedError(e) if auth_res.secondFactorRequired: auth_res = handle_two_factor_auth( auth_client, auth_res.authenticationToken, auth_res.secondFactorDeliveryHint, ) return str(auth_res.authenticationToken)
def sync( database: str, max_chunk_results: int, max_download_workers: int, network_retry_count: int, ) -> None: storage = get_storage(database) raise_on_old_database_version(storage) backend = storage.config.get_config_value("backend") auth_token = storage.config.get_config_value("auth_token") note_client = get_sync_client(auth_token, backend, network_retry_count, max_chunk_results) note_synchronizer = NoteSynchronizer(note_client, storage, max_download_workers) try: note_synchronizer.sync() except WrongAuthUserError as e: raise ProgramTerminatedError( f"Current user of this database is {e.local_user}, not {e.remote_user}!" " Each user must use a different database file.") logger.info("Synchronization completed!")
def get_sync_client( auth_token: str, backend: str, network_error_retry_count: int, max_chunk_results: int, ) -> EvernoteClientSync: logger.info(f"Authorizing auth token, {backend} backend...") client = EvernoteClientSync( token=auth_token, backend=backend, network_error_retry_count=network_error_retry_count, max_chunk_results=max_chunk_results, ) try: client.verify_token() except EvernoteAuthError as e: raise ProgramTerminatedError(e) token_expiration = get_token_expiration_date(auth_token) logger.info(f"Successfully authenticated as {client.user}!") logger.info(f"Current login will expire at {token_expiration}.") return client
def test_cli_program_error(mocker, caplog): cli_mock = mocker.patch("evernote_backup.cli.cli") cli_mock.side_effect = ProgramTerminatedError("test") with pytest.raises(SystemExit): cli_module.main() assert caplog.messages[0] == "test"
def handle_two_factor_auth(auth_client: EvernoteClientAuth, token: str, delivery_hint: str) -> AuthenticationResult: ota_code = prompt_ota(delivery_hint) try: return auth_client.two_factor_auth(token, ota_code) except EvernoteAuthError as e: raise ProgramTerminatedError(e)
def get_storage(database_path: Path) -> SqliteStorage: logger.info("Reading database {0}...".format(database_path.name)) try: return SqliteStorage(database_path) except FileNotFoundError: raise ProgramTerminatedError( f"Database file {database_path} does not exist." f" Initialize database first!" )
def prompt_ota(delivery_hint: str) -> str: if not is_output_to_terminal(): raise ProgramTerminatedError( "Two-factor authentication requires user input!") one_time_hint = "" if delivery_hint: one_time_hint = " ({0})".format(delivery_hint) return str(click.prompt(f"Enter one-time code{one_time_hint}"))
def prompt_credentials( user: Optional[str], password: Optional[str], ) -> Tuple[str, str]: if not is_output_to_terminal() and not all([user, password]): raise ProgramTerminatedError("--user and --password are required!") if not user: user = str(click.prompt("Username or Email")) if not password: password = str(click.prompt("Password", hide_input=True)) return user, password
def export( database: str, single_notes: bool, include_trash: bool, output_path: str, ) -> None: storage = get_storage(database) raise_on_old_database_version(storage) exporter = NoteExporter(storage, output_path) try: exporter.export_notebooks(single_notes, include_trash) except NothingToExportError: raise ProgramTerminatedError( "Database is empty, nothing to export." " Execute sync command to populate database first!") logger.info("All notes have been exported!")
def reauth( database: Path, auth_user: Optional[str], auth_password: Optional[str], auth_is_oauth: bool, auth_oauth_port: int, auth_oauth_host: str, auth_token: Optional[str], network_retry_count: int, ) -> None: storage = get_storage(database) raise_on_old_database_version(storage) backend = storage.config.get_config_value("backend") if not auth_token: auth_token = get_auth_token( auth_user, auth_password, auth_is_oauth, auth_oauth_port, auth_oauth_host, backend, network_retry_count, ) note_client = get_sync_client(auth_token, backend, network_retry_count, 1) local_user = storage.config.get_config_value("user") if local_user != note_client.user: raise ProgramTerminatedError( f"Current user of this database is {local_user}, not {note_client.user}!" " Each user must use a different database file.") storage.config.set_config_value("auth_token", auth_token) logger.info(f"Successfully refreshed auth token for {local_user}!")
def raise_on_existing_database(database_path: Path) -> None: if database_path.exists(): raise ProgramTerminatedError( "Database already exists." " Use --force option to overwrite existing database file." )
def raise_on_old_database_version(storage: SqliteStorage) -> None: try: storage.check_version() except DatabaseResyncRequiredError: raise ProgramTerminatedError( "The database version has been updated. Full resync is required.")