qwiklabs: use a server on localhost:12345 to manage new qw account requests

this allows to scale the automator using multiple instances of the script running separetely (e.g. in docker containers) but using a single server for accounts to prevent conficts between different instances
master
EmaMaker 2021-11-05 22:43:43 +01:00
parent b83e8449e3
commit 5fb1d0edde
16 changed files with 140 additions and 116 deletions

View File

@ -1,7 +1,7 @@
import subprocess
from utils import global_vars
import time
from qwiklabs import get_account
from qwiklabs import get_google_account
from shell import shell
from shell.gists.gists import UserBot

View File

@ -1,67 +0,0 @@
# There is a more efficient way of doing this, but i don't want to think about it rn
import time
import random
# from qwiklabs import create_account, delete_account
class QL_AccountList():
def __init__(self, account_list):
QL_AccountList.SUSPEND_TIME = 3600 #in seconds
QL_AccountList.ACTION_WAIT_TIME = 1200 #in seconds
self.account_list = account_list
self.suspended_list = {}
self.to_delete = []
self.last_action_time = time.time()
self.last_action = 0 #0 added, 1 removed
print("[QL_AccountList] New account list created! Using list from file: {} " .format(account_list))
def request_new_account(self):
with open(self.account_list, 'r') as accounts:
accounts_lines = []
#needed to strip down of \n
for line in accounts.readlines():
accounts_lines.append(line.rstrip())
while True:
account = accounts_lines[random.randint(0, len(accounts_lines)-1)]
if self.is_account_valid(account):
print("[QL_AccountList] A new account has been requested! choosen {}".format(account))
self.suspend_account(account)
return account
def suspend_account(self, account):
print("[QL_AccountList] Account {} will be suspended for the next {} seconds".format(account, QL_AccountList.SUSPEND_TIME))
self.suspended_list[account] = int(time.time())
def is_account_suspended(self, account):
return account in self.suspended_list.keys()
def is_account_valid(self, account):
return (not self.is_account_suspended(account)) and (not account in self.to_delete)
def mark_account_for_deletition(self):
print("[QL_AccountList] Account {} has been marked for deletition".format(account))
self.to_delete.append(account)
def update_account_list(self):
# Try to reintegrate suspended accounts
to_delete = []
for account in self.suspended_list.keys():
if time.time() - self.suspended_list[account] > QL_AccountList.SUSPEND_TIME:
to_delete.append(account)
for d in to_delete:
del self.suspended_list[d]
# if time.time() - self.last_action_time > QL_AccountList.ACTION_WAIT_TIME:
# # TODO: add the requesting of a proxy when doing these actions
# if last_action == 0:
# # removed an account from the "to delete" lsit
# delete_account.QL_DeleteAccount(False, to_delete[random.randint(0, len(to_delete)-1)])
# else:
# # otherwise create a new account
# create_account.QL_CreateAccount(False)

View File

@ -0,0 +1,98 @@
''' 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 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"))
print("[AccountServer] Received a request for a new account, choose", account)
elif command[0] == "remacc":
del suspended_dict[command[1]]
todelete_list.append(command[1])
clientsocket.close()
print("[AccountServer] Received a request to delete", account, "adding to list!")
if __name__ == "__main__":
socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
socket.bind(("localhost", 12345))
socket.listen(5)
with Manager() as manager:
available = open('src/qwiklabs/account_server/qwiklabs_available_accounts.txt', 'r+')
suspended = open('src/qwiklabs/account_server/qwiklabs_suspended.txt', 'r+')
todelete = open('src/qwiklabs/account_server/qwiklabs_todelete.txt', 'r+')
# 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:
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)
print("Unsuspend", account, "as enough time as passed")
for account in tounsuspend:
del suspended_dict[account]
#update list
if time.time() - last_update_time > 5:
last_update_time = time.time()
#print("Cyclic update of files")
available = open('src/qwiklabs/account_server/qwiklabs_available_accounts.txt', 'r+')
suspended = open('src/qwiklabs/account_server/qwiklabs_suspended.txt', 'r+')
todelete = open('src/qwiklabs/account_server/qwiklabs_todelete.txt', 'r+')
#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()

View File

@ -0,0 +1,13 @@
import socket
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(("localhost", 12345))
s.send(b"givacc")
print(s.recv(1024))
s.close()
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(("localhost", 12345))
s.send(b"remacc|06prgzamm96@esiix.com")
print(s.recv(1024))
s.close()

View File

@ -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

View File

@ -0,0 +1 @@
{}

View File

@ -0,0 +1 @@
06prgzamm96@esiix.com

View File

@ -19,4 +19,4 @@ fi
sleep 5
#Now start the actual bot, we're in a safe environment
DISPLAY=:2 python src/qwiklabs/get_account.py $2
DISPLAY=:2 python src/qwiklabs/get_google_account.py $2

View File

@ -177,7 +177,7 @@ def get_google_account():
if global_vars.TEST_QWIKLABS_ACCOUNT is False:
print("[QL_GetAccount] Using TEST Qwiklabs account to get it")
account = global_vars.ql_list.request_new_account()
account = socket_request_new_account()
subprocess.call(['bash','-c', "src/qwiklabs/get_account.sh {} {} ".format(str(global_vars.PROXY), account)])
else:
@ -207,44 +207,12 @@ def get_google_account():
return email, password, gshell_link, driver
# def get_google_account():
# from utils import global_vars
# import subprocess
# if not global_vars.TEST_ACCOUNT:
# print("[QL_GetAccount] Getting new google account..." )
# account = global_vars.ql_list.request_new_account()
# res = subprocess.check_output(['bash','-c', "src/qwiklabs/get_account.sh {} {} ".format(str(global_vars.PROXY), account)]).decode('utf-8')
# if res == 'False' or 'False' in res:
# res = bool(res)
# # Maybe if we failed there was a connection issue, so ping qwiklabs.com to check
# # If ping is successful the account is out of quota
# if global_vars.PROXY is False:
# r = requests.get("https://qwiklabs.com")
# else :
# proxyDict = {
# "socksVersion" : 5,
# "socks" : global_vars.PROXY
# }
# r = requests.get("https://qwiklabs.com", proxies=proxyDict)
# # ping was unsuccessful, delete the account
# if r.stats_code == 200:
# print("[QL_GetAccount] Something went wrong, trying again")
# return get_google_account()
# else:
# global_vars.account_list.mark_account_for_deletition(account)
# else:
# res = tuple(res.rsplit())
# print("[QL_GetGAccount] {}".format(res))
# return res
# else:
# print("[QL_GetAccount] Using Test Account {}".format(global_vars.TEST_ACCOUNT) )
# return global_vars.TEST_ACCOUNT
# Assumes the account server is already running on localhost:12345
def socket_request_new_account():
import socket
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(("localhost", 12345))
s.send(b"givacc")
account = s.recv(1024).decode("utf-8")
s.close()
return account

View File

@ -8,7 +8,7 @@ Specs:
'''
# text.get_attribute("value") return the text content of a text field
from qwiklabs.get_account import get_google_account
from qwiklabs.get_google_account import get_google_account
from utils import global_vars, browser_manager
import random

View File

@ -1,10 +1,6 @@
from qwiklabs import account_list
PROXY = False
ql_list = account_list.QL_AccountList('/home/emamaker/Documents/Projects/GColabAutomator/GColabAutomator-v2/src/qwiklabs_available_accounts.txt')
TEST_ACCOUNT = False
# email, password, gcloud shell link
# TEST_ACCOUNT = ('student-01-474fc01a4ea5@qwiklabs.net', 'PkR9NJR4ms5D', 'https://accounts.google.com/AddSession?service=accountsettings&sarp=1&continue=https%3A%2F%2Fconsole.cloud.google.com%2Fhome%2Fdashboard%3Fproject%3Dqwiklabs-gcp-03-676b378e29e0#Email=student-01-474fc01a4ea5@qwiklabs.net')
TEST_QWIKLABS_ACCOUNT = False
# TEST_QWIKLABS_ACCOUNT = "i3z8qtab@xojxe.com"