def saml_login_authenticate(page): try: logs.log_info("Sending SAML response.") saml_response = page.find("input", attrs={"name": "SAMLResponse", "type": "hidden"}).get("value") data = {"SAMLResponse": saml_response} request = cur_session.post(saml_response_url, data=data) logs.log_info("Sending SAML login informations.") page_2 = BeautifulSoup(request.content, "html.parser") id_provider = page_2.find("input", attrs={"name": "identityProviderId", "type": "hidden"}).get("value") comp_id = page_2.find("input", attrs={"name": "c", "type": "hidden"}).get("value") email = page_2.find("input", attrs={"name": "email", "type": "hidden"}).get("value") session_id = page_2.find("input", attrs={"name": "sessionIndexId", "type": "hidden"}).get("value") lang = page_2.find("input", attrs={"name": "languageTag", "type": "hidden"}).get("value") signature = page_2.find("input", attrs={"name": "signature", "type": "hidden"}).get("value") data = { "identityProviderId": id_provider, "c": comp_id, "email": email, "sessionIndexId": session_id, "languageTag": lang, "signature": signature } cur_session.post(saml_login_url, data=data) return comp_id except (ValueError, Exception): logs.log_error("Error while sending the SAML login informations.") return None
def try_login(email, password, req=None): logs.log_info("Getting SAML response.") data = { "UserName": email, "Password": password, "Kmsi": "true", "AuthMethod": "FormsAuthentication" } if req is None: req = requests request = req.post(login_url, data=data) page = BeautifulSoup(request.content, "html.parser") error = page.find("label", id="errorText") if error is None: logs.log_info("Received SAML response.") return page else: logs.log_error("Error while getting SAML response.") return None
def authenticate_with_retries(): result = None tries = 0 max_tries = 3 while result is None and tries < max_tries: while open_config_file() is False and tries < max_tries: # The first execution of Configurator will create the basic config.ini file. executeConfigurator() tries += 1 logs.log_info("Retrying to open valid configs...") if tries >= max_tries: logs.log_error("Unable to read valid configs.") return login_email = config.get("Credentials", "Email") login_password = config.get("Credentials", "Password") if tries == 0: logs.log_info("Trying to login...") else: logs.log_info("Retrying to login...") login_result = try_login(login_email, login_password, cur_session) if login_result is not None: if os.path.exists(COOKIE_FILE) and DEV_MODE: result = "4146758" # Dev logs.log_info("Loading session " + result + " from cookies.") load_cookie_file() logs.log_info("Cookies loaded successfully.") else: result = saml_login_authenticate(login_result) logs.log_info("Session " + result + " created by authentification.") if DEV_MODE: save_cookie_file() logs.log_info("Cookies saved successfully.") else: executeConfigurator() tries += 1 return result
def submit_time(user_session_id, payload): formatted_session_validation_url = session_validation_url.format(user_session_id=user_session_id) request = cur_session.get(formatted_session_validation_url) validation_page = BeautifulSoup(request.content, "html.parser") if validation_page.text.strip() != "true": logs.log_error("Cannot submit the timesheet. Session expired.") else: formatted_netsuite_timesheet_url = netsuite_timesheet_url.format(user_session_id=user_session_id, date="") headers = { "User-Agent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) " "Chrome/90.0.4430.93 Safari/537.36", } data = {"submittedData": utilities.prettify_json(payload)} if DEV_MODE: logs.log_info("Payload: \n" + utilities.prettify_json(payload, True)) logs.log_warning("Dev Mode: Time is NOT submitted.") else: result = cur_session.post(formatted_netsuite_timesheet_url, headers=headers, data=data) logs.log(SMALL_SEPARATOR) if result.status_code == 200: logs.log_success("Time submitted successfully!") else: logs.log_error("Error while submitting the timesheet.")
def open_config_file(): if not os.path.exists(CONFIG_FILE): config["Credentials"] = {"Email": "", "Password": ""} config["Informations"] = { "Task": tasks.get_default_task(), "Time": "7:30", "Comment": "Standup, analyse, développement" } write_config_file() else: config.read(CONFIG_FILE) try: edit_email.insert( tk.END, utilities.decode_base64(config.get("Credentials", "Email"))) edit_password.insert( tk.END, utilities.secure_decode_base64( config.get("Credentials", "Password"))) task_id = config.get("Informations", "Task") if not tasks.is_valid_task_id(task_id): task_id = tasks.get_default_task() combo_task.current(tasks.get_task_index_by_id(task_id)) edit_time.insert(tk.END, config.get("Informations", "Time")) edit_comment.insert(tk.END, config.get("Informations", "Comment")) except configparser.NoOptionError: logs.log_error("Ini file corrupted. Try deleting the " + CONFIG_FILE + " file.") except UnicodeDecodeError: logs.log_error("Error decoding data. Try recreating the " + CONFIG_FILE + " file.") except utilities.binascii.Error: logs.log_error("Error decoding data. Try recreating the " + CONFIG_FILE + " file.")
def scrape(): if DEV_MODE: logs.log_warning("Dev mode is enabled.") user_session_id = authenticate_with_retries() if user_session_id is not None: logs.log_success("Login successful.") logs.log(SMALL_SEPARATOR) date = utilities.get_previous_working_date().strftime("%Y/%m/%d") # Dev test custom date # date = datetime.datetime(2021, 5, 3).strftime("%Y/%m/%d") logs.log_info("Getting the Netsuite timeSheet page entries on the: " + date) formatted_netsuite_timesheet_url = netsuite_timesheet_url.format(user_session_id=user_session_id, date=date) request = cur_session.get(formatted_netsuite_timesheet_url) netsuite_page = BeautifulSoup(request.content, "html.parser") # Dev: Test local pages # with open("tmp/payloads/netsuite/loggedin_landing_page_saved.html") as fp: # netsuite_page = BeautifulSoup(fp, 'html.parser') time_sheet_page = netsuite_page.find("body", {"id": "timeSheetPage"}) if time_sheet_page: logs.log_info("Finding the data in the page.") script_text = time_sheet_page.find("script", {"src": False}).string.strip() if script_text: logs.log_info("Parsing the time entries data.") time_entries = json.loads(utilities.get_js_var("timeEntries", script_text)) if time_entries: logs.log_success("Data extraction successful.") logs.log(SMALL_SEPARATOR) logs.log_info("NetsuiteBot detecting action to take...") if is_time_submitted(time_entries): logs.log_success("Time already submitted.") elif is_time_only_saved(time_entries): logs.log_info("Time already saved. Submitting time...") for entry in time_entries: time_entries[entry]["isPendingApprovalFlag"] = "T" time_entries[entry]["projectIsClosed"] = "F" submit_time(user_session_id, time_entries) else: logs.log_info("No existing time entry.") logs.log_info("Creating a new time entry. Submitting time...") key = utilities.get_json_key_by_index(time_entries, 0) time_entries[key]["task"] = config.get("Informations", "Task") time_entries[key]["hours"] = config.get("Informations", "Time") time_entries[key]["comment"] = config.get("Informations", "Comment").replace('"', '\"') time_entries[key]["timeBillId"] = -100 time_entries[key]["isPendingApprovalFlag"] = "T" time_entries[key]["projectIsClosed"] = "F" submit_time(user_session_id, time_entries) else: logs.log_error("No time entries found.") else: logs.log_error("Error while trying to parse the script.") else: error_msg = "Error while trying to load the Netsuite timeSheet page." page_title = netsuite_page.find("title").text if page_title: error_msg += "\nWe're on page titled: " + page_title logs.log_error(error_msg) else: logs.log_error("Failed to create user session id.")