Skip to content

Instantly share code, notes, and snippets.

@ariankordi
Created November 6, 2023 05:14
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ariankordi/bae839598cd20680a5b2f85cd565336e to your computer and use it in GitHub Desktop.
Save ariankordi/bae839598cd20680a5b2f85cd565336e to your computer and use it in GitHub Desktop.
EllisProtect™ Technology wipes Tom Ellis off the face of the earth. No context is provided.
from selenium import webdriver
# import the service so a custom executable path can be specified
from selenium.webdriver.chrome.service import Service
from shutil import which
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
import selenium.common.exceptions
import traceback
import re
import time
import os
from sys import argv
# for notify-send
from subprocess import Popen
# Initialize global variables
previous_chat_url = None
# names of removed pages will be stored here
names = []
# match names based on misspellings of "ellis"
# alongside other names and keywords
# "facebook user" = banned user
ellis_misspellings_pattern = re.compile(
r'(?:[E3]+[lIi1!]+[lIi1!]+[s5]+)|' # Matches ellis (with various misspellings)
r'(?:Facebook\suser)|' # "Facebook user"
r'(?:musk)|' # (Elon) Musk
r'(?:kardashian)|' # Kardashian
r'(?:timberlake)|' # Timberlake
r'(?:fan)|' # fan
r'(?:page)', # page
re.IGNORECASE
)
# detect flukes across the ENTIRE page at the end, canNOT be erroneous...
fluke_pattern = re.compile(
r'(?:ellis)|' # Matches ellis (with various misspellings)
r'(?:musk)|' # (Elon) Musk
r'(?:kardashian)|' # Kardashian
r'(?:timberlake)', # Timberlake
re.IGNORECASE
)
# Configure Chrome profile to disable image loading
options = webdriver.ChromeOptions()
# if is true then will print all chats uhhhhhh
debug = False
try:
# if there's any second argument then disable headless
if argv[1]:
print('\033[1mDEBUG MODE ENABLED:\033[0m browser will not run headless. it will also stick around. if you get an error next time you run this it\'s probably because the chromium didn\'t launch because there is already one open. ok?')
# makes the browser hang around for testing
options.add_experimental_option("detach", True)
debug = True
except IndexError:
options.add_argument("--headless") # Comment this line if you want to see the browser in action
pass
# optimization to disable images
# (ublock should also do this additionally disabling fonts & trackers)
options.add_argument('--blink-settings=imagesEnabled=false')
options.add_argument("--enable-gpu")
options.add_argument("--ozone-platform-hint=auto")
options.add_argument("--ignore-gpu-blocklist")
options.add_argument("--use-vulkan")
options.add_argument("--enable-raw-draw")
options.add_argument("--enable-gpu-rasterization")
options.add_argument("--enable-gpu-compositing")
options.add_argument("--password-store=basic")
# make sure we can find a home directory. otherwise, Just Book It!
assert 'HOME' in os.environ
# Specify and set the path to the Chrome user profile in the user home .config
options.add_argument(f"--user-data-dir={os.environ['HOME']}/.config/FUCK KING FACE BOOK")
# test timeouts with this profile
#options.add_argument("--user-data-dir=/dev/shm/tezt")
service = Service(executable_path=which('chromedriver'))
# Initialize the WebDriver with the custom profile
driver = webdriver.Chrome(options=options, service=service)
print('opening webdriver...')
# the window size can probably be smaller
# but this is important otherwise it will not load at all
driver.set_window_size(1366, 768)
# Open Facebook Messenger
driver.get("https://www.messenger.com")
print('navigated to messenger.com')
# Wait for chats to load
try:
WebDriverWait(driver, 60).until(
EC.presence_of_element_located((By.CSS_SELECTOR, 'div[aria-label="Chats"]'))
)
except selenium.common.exceptions.TimeoutException as e:
# chat was not able to load..!!! now notify me
Popen(['notify-send', '-u', 'critical', 'EllisProtect™ Fault!!', 'Was not able to load chats. OH NO! Inspect the systemd logs.'])
raise e
print('chats loaded, matching...')
# Find chats containing "Ellis" (or its misspellings)
#chat_entries = driver.find_elements(By.CSS_SELECTOR, 'a[role=link] div[class=""] > span[dir=auto] > span')
# above broke oct 8, this is a lot more vague but it should work
chat_entries = driver.find_elements(By.CSS_SELECTOR, 'a[role=link] span[dir=auto]')
matching_chats = []
#matching_chats = [chat for chat in chat_entries if ellis_misspellings_pattern.search(chat.text)]
for chat in chat_entries:
does_match = ellis_misspellings_pattern.search(chat.text)
if debug:
print(f'"{chat.text}" {("does" if does_match else "does NOT")} match')
if does_match:
matching_chats.append(chat)
# Iterate through matching chats
# TODO: use enumerate, and make it so that at the end it will re-search the chat list and add to the array
for chat in matching_chats:
try:
# Click on the chat
chat.click()
print('clicked on a matching chat, trying to see when change finished...')
# poll to find out when the page transitions
# by checking the user's href at the top of the page
# should be 2 seconds max, 0.1 * 20
for _ in range(20):
# also retry on some exceptions
try:
chat_url_button = driver.find_element(By.CSS_SELECTOR, '[role="main"] a[role="link"][tabindex="0"][aria-label]')
current_chat_url = chat_url_button.get_attribute('href')
if current_chat_url != previous_chat_url:
previous_chat_url = current_chat_url
page_name = chat_url_button.get_attribute('aria-label')
print(f"successfully navigated to: \033[1m{page_name}\033[0m")
names.append(page_name)
break
time.sleep(0.1)
# retry if there's a stale element or no element found
except (selenium.common.exceptions.StaleElementReferenceException, selenium.common.exceptions.NoSuchElementException):
continue
# Check if "Conversation information" section is open
conversation_info_section = driver.find_elements(By.CSS_SELECTOR, 'div[style="transform: translateX(0%) translateZ(1px);"]')
if not conversation_info_section:
# Click on the "Conversation information" (dot dot dot) button if it doesn't exist
print('clicking on ellipsis button...')
WebDriverWait(driver, 3).until(
EC.presence_of_element_located((By.CSS_SELECTOR, '[aria-label="Conversation information"]'))
).click()
print('waiting for sidebar to load after Conversation information was clicked...')
# Wait for the sidebar to load
WebDriverWait(driver, 3).until(
EC.presence_of_element_located((By.CSS_SELECTOR, 'div[style="transform: translateX(0%) translateZ(1px);"]'))
)
print('checking for Privacy & Support section...')
# Check if Privacy & Support section exists
privacy_support_section = driver.find_elements(By.CSS_SELECTOR, '#privacy_support_section')
if not privacy_support_section:
# Click on the Privacy & Support dropdown if it doesn't exist
privacy_support_dropdown = driver.find_elements(By.CSS_SELECTOR, 'div[role="list"] > div [role="button"]')
for dropdown_item in privacy_support_dropdown:
if "Privacy" in dropdown_item.text:
dropdown_item.click()
break
# Wait for the Privacy & Support section to load
print('waiting for Privacy & support section')
WebDriverWait(driver, 3).until(
EC.presence_of_element_located((By.CSS_SELECTOR, '#privacy_support_section'))
)
print('looking for block button')
# Search for and click on the "Block" button
block_button = driver.find_elements(By.CSS_SELECTOR, '#privacy_support_section [role="button"]')
the_button = None
for button in block_button:
# detect Block or Unblock
if "lock" in button.text:
the_button = button
break
# this ugly definition is due to wanting to continue the outer loop
if the_button:
if "Unblock" in the_button.text:
# TODO: sometimes is wrong
print('person is already blocked! moving along...')
#continue
else:
# kinda messy to include literally the rest of the logic in here
# but this is all that involves clicking...
# ... the block button and dealing with the dialog
the_button.click()
print('clicked it.')
print('now waiting for dialog (or its block button)')
# Wait for the confirmation dialog to load
# make it a short wait bc this is the wait that happpens if they are already blocked
confirmation_dialog = WebDriverWait(driver, 6).until(
EC.presence_of_element_located((By.CSS_SELECTOR, '[role="dialog"]'))
)
print('waiting for Block messages and calls button')
# click Block messages and calls button
block_button = WebDriverWait(driver, 3).until(
EC.presence_of_element_located((By.CSS_SELECTOR, '[role="dialog"] [role=button]:not([aria-label=Close]):first-child'))
)
if block_button:
block_button.click()
print('waiting for block confirm button')
# Wait for and click the "Block" button in the confirmation dialog
block_confirm_button = WebDriverWait(driver, 3).until(
EC.presence_of_element_located((By.CSS_SELECTOR, '[role="dialog"] [aria-label="Block"]:first-child'))
)
if block_confirm_button:
# make sure it is interactable
for _ in range(9):
if block_confirm_button.is_displayed() and block_confirm_button.is_enabled():
block_confirm_button.click()
break
time.sleep(0.3)
print('closing dialog, loop will repeat')
# wait for and click close button for first dialog (either one work)
close_button = WebDriverWait(driver, 3).until(
# invisible element
EC.presence_of_element_located((By.CSS_SELECTOR, '[role="dialog"] div[aria-hidden="true"] [aria-label="Close"]'))
#EC.presence_of_element_located((By.CSS_SELECTOR, '[role="dialog"] div:not(aria-hidden) > div > div > div > div > [aria-label="Close"]'))
)
if close_button:
#close_button.click()
# for whatever reason selenium is super BITCHy about wanting to close this. so...
# close the hidden close button as a matter of fact
driver.execute_script("document.querySelector('[role=\"dialog\"] div[aria-hidden=\"true\"] [aria-label=\"Close\"]').click()")
print('closed block dialog, now going to look for menu button')
# find chat menu button, three dots alongside name
#menu_button = chat.find_element(By.XPATH, '../../../../../../../../../../../../../../../..//div[@aria-label="Menu"]')
#menu_button.click()
# returns not interactable so have to use this js method instead...
driver.execute_script("arguments[0].parentElement.parentElement.parentElement.parentElement.parentElement.parentElement.parentElement.parentElement.parentElement.parentElement.parentElement.querySelector('[aria-label=\"Menu\"]').click()", chat)
# click archive button in the menu we just opened
archive_button = driver.find_elements(By.CSS_SELECTOR, 'div[role="menuitem"]')
for button in archive_button:
# detect Block or Unblock
if "Archive" in button.text:
print('found and clicking archive button')
button.click()
break
# skip if some sort of timeoutexception happened
#except (selenium.common.exceptions.TimeoutException, selenium.common.exceptions.ElementNotInteractableException):
except Exception as e:
Popen(['notify-send', 'EllisProtect™ Non-Critical', f'Exception {type(e)} was caught, you should probably check it out.'])
traceback.print_exc()
continue
# check len by end (or actually TODO see if i should use a manual counter instead)
if len(matching_chats):
s_plural = ('s' if len(matching_chats) > 1 else '')
names_list = ', '.join(names)
print('\033[91mtsk tsk tsk! looks like she has ' + str(len(matching_chats)) + ' chat' + s_plural + ' with tom ellis!\n' + names_list + '\033[0m')
Popen(['notify-send', 'EllisProtect™ Detection Results', f'Removed {len(matching_chats)} chat{s_plural} with: {names_list}.'])
# sleep to let stuff post before exiting
time.sleep(3)
else:
# NO MATCHING CHATS??? check the entire page once again
# to make sure that it is not a fluke.
search_entire_page = fluke_pattern.search(driver.page_source)
if search_entire_page:
Popen(['notify-send', '-u', 'critical', 'EllisProtect™ CRITICAL FAULT!!', 'What the hell? Tom Ellis was detected but couldn\'t be removed. Time to debug the script!!'])
print('\033[91mWHAT THE FEVC???\033[0m no ellis found in any chats but also it was found on the entire page so hmmmMMMMMMMMMMMMMMMMMMMMMMM. here:', search_entire_page)
else:
# ok, all may be clear...
print('\033[92mall clear!\033[0m')
#except Exception as e:
# print(f"An error occurred: {str(e)}")
#finally:
# # Close the WebDriver (it should do this automatically regardless)
# driver.quit()
"""
* load fb messenger, messenger.com
* probably use a custom chrome profile here
* choose not to load images with the chrome config bc they're unneeded and it would save bandwidth
* should probably check if it doesn't load right and show a notify-send
* wait for chats to load: div[aria-label=Chats]
* search for "ellis" in all chats
* regex:
const ellisMisspellingsPattern = /[E3]+[l|I|i|1|!]+[l|I|i|1|!]+[s|5]+/i;
Array.from(document.querySelectorAll('a[role=link] div[class=\'\'] > span[dir=auto] > span')).filter(e => {
return e.textContent.match(ellisMisspellingsPattern);
});
* for each chat entry...
* click on it (click on the respective conversation)
* wait until after you have navigated to a new URL... (TBD):
* click on this: [aria-label="Conversation information"] (dot dot dot)
* track that this was already set in a variable and skip it next time
* wait for the whole sidebar to load: div[style="transform: translateX(0%) translateZ(1px);"]
* search for and click on the Privacy & support dropdown:
Array.from(document.querySelectorAll('div[role=list] > div [role=button]')).filter(e => {
return e.textContent.contains('Privacy');
})[0].click();
* track this and skip it next time too
* wait for privacy support section to load: #privacy_support_section (yay, easy!)
* wait for block button, then click it:
Array.from(document.querySelectorAll('#privacy_support_section [role=button]')).filter(e => {
return e.textContent.contains('Block');
})[0].click()
//* wait for the box to pop up: [role=dialog]
// * you may have to add a selector for the
* wait for and then click the block button: [role=dialog] [role=button]:not([aria-label=Close]):first-child
* may be unreliable, matches ALL buttons, and just clicks the first one. the first one SHOULD be "block messages and calls" if you are friends with them
* wait for and then click the confirmation block button: [aria-label=Block]
* click this [role=dialog] [aria-label=Close]
* move on to next list entry
"""
[Unit]
Description=ellisprotect wipes tom ellis off the face of the earth
[Service]
Type=oneshot
WorkingDirectory=/home/arian/Downloads
ExecStart=/usr/bin/python3 ellisprotect.py
[Unit]
Description=run ellisprotect every x hours?
[Timer]
#OnCalendar=*:0/2
OnCalendar=0/3:00:00
RandomizedDelaySec=1h
Persistent=true
[Install]
WantedBy=timers.target
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment