accountserver: port for exclusive use inside a docker container
parent
ecf5be5515
commit
36c8424b34
|
@ -0,0 +1,7 @@
|
|||
# syntax=docker/dockerfile:1
|
||||
|
||||
FROM python:3.10-bullseye
|
||||
WORKDIR /code
|
||||
EXPOSE 12345
|
||||
COPY ./code/account_server.py ./account_server.py
|
||||
CMD [ "python3", "-u", "/code/account_server.py"]
|
|
@ -0,0 +1,14 @@
|
|||
06prgzamm96@esiix.com
|
||||
jhv8mtemi@esiix.com
|
||||
6bgfngq6@yoggm.com
|
||||
fohxil@xojxe.com
|
||||
b4d0o0y5pg@esiix.com
|
||||
i3z8qtab@xojxe.com
|
||||
l5wbup@1secmail.com
|
||||
ryysw0@1secmail.net
|
||||
m5l7868ar@wwjmp.com
|
||||
ue8oqa0lf0j@1secmail.net
|
||||
17k2l9@1secmail.com
|
||||
c5xm6j@1secmail.net
|
||||
mud0ud@esiix.com
|
||||
t788egrvdp@wwjmp.com
|
|
@ -0,0 +1,112 @@
|
|||
''' This file needs to be run outside of the GShellAutomator script
|
||||
Starts a TCP server on localhost, to which GSA asks for accounts and reports problems
|
||||
Command list:
|
||||
givacc: Client is requesting a qwiklabs account to use. Take one from the available list and return it, then put it in the suspended list
|
||||
remacc: Client reported the account is not working anymore, and it needs to be delete (TODO: make this script test is the account is really unusable)
|
||||
'''
|
||||
|
||||
import time
|
||||
import json
|
||||
import socket
|
||||
import random
|
||||
import threading
|
||||
|
||||
from multiprocessing import Process, Manager
|
||||
|
||||
def qwprint(*s):
|
||||
msg = ''.join(a + " " for a in s)
|
||||
print("[QWAccountServer]", msg)
|
||||
|
||||
def handle_clients(available_list, suspended_dict, todelete_list):
|
||||
while True:
|
||||
(clientsocket, address) = socket.accept()
|
||||
command = clientsocket.recv(1024).decode("utf-8").split("|")
|
||||
|
||||
if command[0] != "":
|
||||
if command[0] == "givacc":
|
||||
account_valid = False
|
||||
while not account_valid:
|
||||
account = available_list[random.randint(0, len(available_list)-1)]
|
||||
if (not account in suspended_dict.keys() ) and (not account in todelete_list):
|
||||
account_valid = True
|
||||
suspended_dict[account] = time.time()
|
||||
|
||||
clientsocket.send(account.encode("utf-8"))
|
||||
|
||||
qwprint("Received a request for a new account, choose", account)
|
||||
|
||||
elif command[0] == "remacc":
|
||||
if command[1]in suspended_dict:
|
||||
del suspended_dict[command[1]]
|
||||
|
||||
todelete_list.append(command[1])
|
||||
clientsocket.close()
|
||||
|
||||
qwprint("Received a request to delete", command[1], "adding to list!")
|
||||
|
||||
def openfiles():
|
||||
available = open('/account_data/qwiklabs_available_accounts.txt', 'r+')
|
||||
suspended = open('/account_data/qwiklabs_suspended.txt', 'r+')
|
||||
todelete = open('/account_data/qwiklabs_todelete.txt', 'r+')
|
||||
|
||||
return available, suspended, todelete
|
||||
|
||||
if __name__ == "__main__":
|
||||
qwprint("Starting QWAccountServer")
|
||||
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as socket:
|
||||
socket.bind(("0.0.0.0", 12345))
|
||||
socket.listen(5)
|
||||
|
||||
with Manager() as manager:
|
||||
available, suspended, todelete = openfiles()
|
||||
|
||||
# create the list from the files
|
||||
available_list = manager.list([line.strip() for line in available.readlines()])
|
||||
try:
|
||||
suspended_dict = manager.dict(json.loads(suspended.read()))
|
||||
except:
|
||||
suspended_dict = manager.dict({})
|
||||
|
||||
todelete_list = manager.list([line.strip() for line in todelete.readlines()])
|
||||
|
||||
p = Process(target=handle_clients, args=(available_list, suspended_dict, todelete_list))
|
||||
p.start()
|
||||
|
||||
last_update_time = time.time()
|
||||
while True:
|
||||
|
||||
try:
|
||||
tounsuspend = []
|
||||
for account in suspended_dict:
|
||||
if time.time()-suspended_dict[account] > 3600: #time is stored in seconds, so this is 3600 after an hour os first being suspened
|
||||
tounsuspend.append(account)
|
||||
qwprint("Unsuspend " + account+ " as enough time as passed")
|
||||
|
||||
for account in tounsuspend:
|
||||
del suspended_dict[account]
|
||||
except:
|
||||
pass
|
||||
|
||||
#update list
|
||||
if time.time() - last_update_time > 5:
|
||||
qwprint("Cyclic update of files")
|
||||
last_update_time = time.time()
|
||||
|
||||
available, suspended, todelete = openfiles()
|
||||
|
||||
#clear files, update with data loaded from the program
|
||||
available.truncate(0)
|
||||
suspended.truncate(0)
|
||||
todelete.truncate(0)
|
||||
|
||||
#put data in there
|
||||
available.writelines([(l + "\n") for l in available_list])
|
||||
suspended.write(json.dumps(dict(suspended_dict)))
|
||||
todelete.writelines([(l + "\n") for l in todelete_list])
|
||||
|
||||
#close files for it to take effect
|
||||
available.close()
|
||||
suspended.close()
|
||||
todelete.close()
|
||||
# else:
|
||||
# print("no time to update", str(time.time() - last_update_time))
|
|
@ -0,0 +1,16 @@
|
|||
import socket
|
||||
|
||||
acc = ""
|
||||
|
||||
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
|
||||
s.connect(("0.0.0.0", 12345))
|
||||
s.send(b"givacc")
|
||||
acc = s.recv(1024)
|
||||
print(acc)
|
||||
s.close()
|
||||
|
||||
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
|
||||
s.connect(("0.0.0.0", 12345))
|
||||
s.send(b"remacc|t788egrvdp@wwjmp.com")
|
||||
print(s.recv(1024))
|
||||
s.close()
|
|
@ -0,0 +1,193 @@
|
|||
from utils import browser_manager
|
||||
from selenium.webdriver.common.by import By
|
||||
import time
|
||||
from selenium.webdriver.common.alert import Alert, Command
|
||||
from selenium.webdriver.common.keys import Keys
|
||||
import requests
|
||||
|
||||
import os
|
||||
import urllib
|
||||
|
||||
# recaptcha libraries
|
||||
import pydub
|
||||
import speech_recognition as sr
|
||||
|
||||
from bs4 import BeautifulSoup
|
||||
from utils.global_vars import PROXY
|
||||
|
||||
class QL_CreateAccount:
|
||||
|
||||
def create_account(self):
|
||||
self.info = RandomNameGenerator(self.proxy).get_person_info()
|
||||
|
||||
self.driver = browser_manager.start_browser()
|
||||
self.temp_mail = TempMail()
|
||||
|
||||
self.temp_mail_address = self.temp_mail.get_new_temp_mail()
|
||||
|
||||
self.sign_up()
|
||||
self.accept_eula()
|
||||
|
||||
print("Account created!".format(self.info, self.temp_mail_address))
|
||||
|
||||
def sign_up(self):
|
||||
print("[+] Creating a new account for with mail [{}:{}]".format(self.info, self.temp_mail_address))
|
||||
|
||||
self.driver.get("https://www.qwiklabs.com/users/sign_up")
|
||||
time.sleep(1.5)
|
||||
|
||||
#accept goddamn cookies
|
||||
browser_manager.clickButton(self.driver, By.XPATH, '/html/body/div[2]/div/button')
|
||||
time.sleep(2)
|
||||
|
||||
browser_manager.inputText(self.driver, By.CSS_SELECTOR, "#user_first_name", self.info[0], after_delay=1.5)
|
||||
browser_manager.inputText(self.driver, By.CSS_SELECTOR, "#user_last_name", self.info[1], after_delay=1.5)
|
||||
browser_manager.inputText(self.driver, By.CSS_SELECTOR, "#user_email", self.temp_mail_address, after_delay=1.5)
|
||||
browser_manager.inputText(self.driver, By.CSS_SELECTOR, "#user_company_name", self.info[2], after_delay=1.5)
|
||||
browser_manager.inputText(self.driver, By.CSS_SELECTOR, "#user_password", "hellogoodbye", after_delay=1.5)
|
||||
browser_manager.inputText(self.driver, By.CSS_SELECTOR, "#user_password_confirmation", "hellogoodbye", after_delay=1.5)
|
||||
time.sleep(10)
|
||||
|
||||
self.resolve_captcha('/html/body/div[1]/div[1]/div[2]/form[2]/div[8]/div/div/iframe', "recaptcha-checkbox", "/html/body/div[4]/div[4]", "recaptcha-audio-button")
|
||||
|
||||
time.sleep(5)
|
||||
self.driver.find_element_by_xpath('/html/body/div[1]/div[1]/div[2]/form[2]/div[9]/button').click()
|
||||
|
||||
def resolve_captcha(self, frame1_xpath, checkbox_classname, frame2_container_xpath, audio_id):
|
||||
# switch to recaptcha frame
|
||||
# frames = self.driver.find_elements_by_tag_name("iframe")
|
||||
# self.driver.switch_to.frame(frames[0])
|
||||
self.driver.switch_to.frame(self.driver.find_element_by_xpath(frame1_xpath))
|
||||
|
||||
browser_manager.delay(self.driver)
|
||||
|
||||
# click on checkbox to activate recaptcha
|
||||
self.driver.find_element_by_class_name(checkbox_classname).click()
|
||||
|
||||
# switch to recaptcha audio control frame
|
||||
self.driver.switch_to.default_content()
|
||||
frame2_container = browser_manager.waitForElement(self.driver, By.XPATH, frame2_container_xpath)
|
||||
|
||||
# Sometimes the captcha gets accepted right away
|
||||
if frame2_container is False:
|
||||
return
|
||||
|
||||
frames = frame2_container.find_elements_by_tag_name("iframe")
|
||||
self.driver.switch_to.frame(frames[0])
|
||||
browser_manager.delay(self.driver)
|
||||
|
||||
# click on audio challenge
|
||||
self.driver.find_element_by_id(audio_id).click()
|
||||
|
||||
# switch to recaptcha audio challenge frame
|
||||
self.driver.switch_to.default_content()
|
||||
frames = self.driver.find_elements_by_tag_name("iframe")
|
||||
self.driver.switch_to.frame(frames[-1])
|
||||
browser_manager.delay(self.driver)
|
||||
|
||||
# get the mp3 audio file
|
||||
src = self.driver.find_element_by_id("audio-source").get_attribute("src")
|
||||
print("[INFO] Audio src: %s" % src)
|
||||
|
||||
# download the mp3 audio file from the source
|
||||
urllib.request.urlretrieve(src, os.path.normpath(os.getcwd() + "\\sample.mp3"))
|
||||
browser_manager.delay(self.driver)
|
||||
|
||||
# load downloaded mp3 audio file as .wav
|
||||
try:
|
||||
sound = pydub.AudioSegment.from_mp3(os.path.normpath(os.getcwd() + "\\sample.mp3"))
|
||||
sound.export(os.path.normpath(os.getcwd() + "\\sample.wav"), format="wav")
|
||||
sample_audio = sr.AudioFile(os.path.normpath(os.getcwd() + "\\sample.wav"))
|
||||
except Exception:
|
||||
print("[ERR] Please run program as administrator or download ffmpeg manually, "
|
||||
"http://blog.gregzaal.com/how-to-install-ffmpeg-on-windows/")
|
||||
|
||||
# translate audio to text with google voice recognition
|
||||
r = sr.Recognizer()
|
||||
with sample_audio as source:
|
||||
audio = r.record(source)
|
||||
key = r.recognize_google(audio)
|
||||
print("[INFO] Recaptcha Passcode: %s" % key)
|
||||
|
||||
# key in results and submit
|
||||
self.driver.find_element_by_id("audio-response").send_keys(key.lower())
|
||||
self.driver.find_element_by_id("audio-response").send_keys(Keys.ENTER)
|
||||
self.driver.switch_to.default_content()
|
||||
browser_manager.delay(self.driver)
|
||||
# self.driver.find_element_by_id("recaptcha-verify-button").click()
|
||||
# browser_manager.delay(self.driver)
|
||||
|
||||
def accept_eula(self):
|
||||
self.driver.get(self.temp_mail.get_confirmation_link())
|
||||
|
||||
time.sleep(5)
|
||||
|
||||
#insert password
|
||||
browser_manager.inputText(self.driver, By.CSS_SELECTOR, "#user_password", "hellogoodbye", after_delay=1.5)
|
||||
browser_manager.clickButton(self.driver, By.XPATH, "/html/body/div[2]/div[1]/div[2]/form/div[4]/button")
|
||||
time.sleep(10)
|
||||
|
||||
browser_manager.clickButton(self.driver, By.XPATH, '/html/body/div[2]/div/button')
|
||||
time.sleep(2)
|
||||
|
||||
self.resolve_captcha('/html/body/div[1]/form/div/div/div/div/div/iframe', "recaptcha-checkbox", "/html/body/div[4]/div[4]", "recaptcha-audio-button")
|
||||
time.sleep(5)
|
||||
browser_manager.clickButton(self.driver, By.XPATH, '/html/body/div[1]/form/input[5]')
|
||||
|
||||
time.sleep(1000)
|
||||
|
||||
class RandomNameGenerator():
|
||||
def __init__(self):
|
||||
self.proxyDict = {
|
||||
"socks" : PROXY,
|
||||
"socksVersion" : 5
|
||||
}
|
||||
|
||||
def get_person_info(self):
|
||||
if PROXY:
|
||||
r = requests.get('https://randomuser.me/api', proxies=self.proxyDict)
|
||||
else:
|
||||
r = requests.get('https://randomuser.me/api')
|
||||
|
||||
firstname = r.json()['results'][0]['name']['first']
|
||||
lastname = r.json()['results'][0]['name']['last']
|
||||
#use city as company
|
||||
company = r.json()['results'][0]['location']['city']
|
||||
return (firstname, lastname, company)
|
||||
|
||||
# get a temp mail from https://www.1secmail.com/api/ and handle it using requests
|
||||
class TempMail:
|
||||
def __init__(self):
|
||||
self.proxyDict = {
|
||||
"socks" : PROXY,
|
||||
"socksVersion" : 5
|
||||
}
|
||||
|
||||
# Open a new tab, head over to temp-mail.org, click the delete button and get a new temp mail
|
||||
def get_new_temp_mail(self):
|
||||
self.email = requests.get('https://www.1secmail.com/api/v1/?action=genRandomMailbox', proxies=self.proxyDict).json()[0]
|
||||
return self.email
|
||||
|
||||
# Wait for qwiklabs confirmation email to arrive, click it
|
||||
def get_confirmation_link(self):
|
||||
arrived = False
|
||||
while arrived == False:
|
||||
print('Waiting for confirmation email')
|
||||
fetched_msg = requests.get('https://www.1secmail.com/api/v1/?action=getMessages&login=' + self.email.split('@')[0] + '&domain='+self.email.split('@')[1], proxies=self.proxyDict)
|
||||
arrived = fetched_msg.text != '[]'
|
||||
time.sleep(2)
|
||||
|
||||
print('Email arrived')
|
||||
msg_id = fetched_msg.json()[0]['id']
|
||||
email = requests.get('https://www.1secmail.com/api/v1/?action=readMessage&login=' + self.email.split('@')[0] + '&domain='+self.email.split('@')[1] + '&id=' + str(msg_id))
|
||||
body = email.json()['body']
|
||||
|
||||
soup = BeautifulSoup(body, 'html.parser')
|
||||
|
||||
a = ""
|
||||
for link in soup.find_all('a'):
|
||||
if 'confirmation' in link.get('href'):
|
||||
a = link.get('href')
|
||||
print("Here's the confirmation link " + a)
|
||||
|
||||
return a
|
|
@ -0,0 +1,72 @@
|
|||
from utils import browser_manager
|
||||
from selenium.webdriver.common.by import By
|
||||
import time
|
||||
from selenium.webdriver.common.alert import Alert
|
||||
from selenium.webdriver.common.alert import Command
|
||||
|
||||
class QL_DeleteAccount:
|
||||
def __init__(self, account):
|
||||
self.account = account
|
||||
|
||||
def delete_account(self):
|
||||
self.driver = browser_manager.start_browser()
|
||||
self.sign_in()
|
||||
self.delete()
|
||||
|
||||
def sign_in(self):
|
||||
print("[+] Signing in using account [{}:{}]".format(self.account[0], self.account[1]))
|
||||
|
||||
self.driver.get("https://www.qwiklabs.com/users/sign_in")
|
||||
time.sleep(1.5)
|
||||
|
||||
#accept goddamn cookies
|
||||
browser_manager.clickButton(self.driver, By.XPATH, '/html/body/div[2]/div/button')
|
||||
time.sleep(2)
|
||||
|
||||
browser_manager.inputText(self.driver, By.CSS_SELECTOR, "#user_email", self.account[0])
|
||||
time.sleep(1.5)
|
||||
browser_manager.inputText(self.driver, By.CSS_SELECTOR, "#user_password", self.account[1])
|
||||
time.sleep(1.5)
|
||||
browser_manager.clickButton(self.driver, By.CSS_SELECTOR, "#new_user > div.form-actions > button")
|
||||
time.sleep(5)
|
||||
|
||||
def delete(self):
|
||||
|
||||
# Click on profile icon, it's under a shadow-dom element
|
||||
root1 = self.driver.find_element_by_css_selector("#my_account")
|
||||
shadow = browser_manager.expand_shadow_element(self.driver, root1)
|
||||
profile = shadow.find_element_by_css_selector('.ql-icon-button')
|
||||
profile.click()
|
||||
|
||||
time.sleep(2)
|
||||
|
||||
# head over to settings
|
||||
settings = self.driver.find_element_by_css_selector('#settings')
|
||||
settings.click()
|
||||
time.sleep(2)
|
||||
|
||||
#accept goddamn cookies
|
||||
browser_manager.clickButton(self.driver, By.XPATH, '/html/body/div[2]/div/button')
|
||||
time.sleep(2)
|
||||
|
||||
# select 'security' tab
|
||||
root1 = browser_manager.waitForElement(self.driver, By.XPATH, '/html/body/ql-drawer-container/ql-drawer/ql-sidenav/ql-sidenav-item[4]')
|
||||
shadow = browser_manager.expand_shadow_element(self.driver, root1)
|
||||
root1.click()
|
||||
time.sleep(2)
|
||||
|
||||
# button = shadow.find_element_by_css_selector('.sidenav-item')
|
||||
# button.click()
|
||||
|
||||
browser_manager.clickButton(self.driver, By.XPATH, '/html/body/ql-drawer-container/ql-drawer-content/main/div[3]/div[2]/div/a')
|
||||
time.sleep(5)
|
||||
|
||||
#delete history
|
||||
browser_manager.clickButton(self.driver, By.CSS_SELECTOR, '#delete_account_history_are_you_sure > div > div > div > a:nth-child(2)')
|
||||
time.sleep(8)
|
||||
|
||||
# finally accept the deletition of the account
|
||||
al = self.driver.switch_to.alert
|
||||
al.accept()
|
||||
|
||||
print("Account {} deleted!".format(self.account))
|
|
@ -0,0 +1,8 @@
|
|||
services:
|
||||
accountserver:
|
||||
build: .
|
||||
ports:
|
||||
- "12345:12345"
|
||||
volumes:
|
||||
- ./code:/code
|
||||
- ./account_data:/account_data
|
|
@ -0,0 +1,4 @@
|
|||
#!/bin/bash
|
||||
|
||||
#sudo docker compose up
|
||||
sudo docker compose up --build
|
Loading…
Reference in New Issue