#!/usr/bin/env python

# THE BASE OF THIS FILE WAS AUTOMATICALLY GENERATED BY template.py, for more information, visit
# https://git.romanh.de/Roman/HackingScripts

import os
import io
import re
import sys
import json
import time
import base64
import requests
import subprocess
import urllib.parse
from bs4 import BeautifulSoup
from hackingscripts import util, rev_shell
from hackingscripts.fileserver import HttpFileServer
from urllib3.exceptions import InsecureRequestWarning
requests.packages.urllib3.disable_warnings(category=InsecureRequestWarning)

import struct
from candy_maps import *

IP_ADDRESS = util.get_address()
BASE_URL = "https://603f2fa6-8131-45da-b831-f0bc598e4b4a.idocker.vuln.land" if "LOCAL" not in sys.argv else "http://127.0.0.1:1337"
PROXIES = {"http": "http://127.0.0.1:8080", "https": "http://127.0.0.1:8080"}

def request(method, uri, **kwargs):
    if not uri.startswith("/") and uri != "":
        uri = "/" + uri

    client = requests
    if "session" in kwargs:
        client = kwargs["session"]
        del kwargs["session"]
    
    if "allow_redirects" not in kwargs:
        kwargs["allow_redirects"] = False
    
    if "verify" not in kwargs:
        kwargs["verify"] = False
    
    if "proxies" not in kwargs:
        kwargs["proxies"] = PROXIES

    url = BASE_URL + uri
    return client.request(method, url, **kwargs)

def get_license():
    res = request("GET", "/license")
    util.assert_status_code(res, 200)
    util.assert_content_type(res, "application/json")
    return json.loads(res.text)

def put_license(license_key):
    res = request("POST", "/license", json={"LicenseKey": license_key})
    util.assert_status_code(res, 200)
    util.assert_content_type(res, "application/json")
    util.assert_json_path(res, ".isValid", True)
    return json.loads(res.text)

def num_to_chr(num):
    assert num >= 0 and num < 32
    i = CANDY_MAP.index(num)
    assert i != -1
    return chr(i)

def compute_shuffle(arr):
    value = 0
    for i in range(24):        
        value += arr[i] + SHUFFLER[i]
    return value % 32

def arr_to_license(arr):
    license_key = ""
    for i, num in enumerate(arr):
        license_key += num_to_chr(num)
        if len(license_key) in [5, 11, 17, 23]:
            license_key += "-"

    assert len(license_key) == 29
    assert license_key[5] == '-'
    assert license_key[11] == '-'
    assert license_key[17] == '-'
    assert license_key[23] == '-'
    return license_key

def shuffle_array(byte_arr):

    shuffle_num_2 = byte_arr[24]
    assert shuffle_num_2 < 32

    for shuffle_num_1 in range(0, 32):
        shuffled_arr = list(None for i in range(25))
        for i in range(24):
            value = CANDY_MIX_HORIZONTALS[shuffle_num_2].index(byte_arr[i])
            destination = CANDY_MIX_VERTICALS[shuffle_num_1].index(i)
            shuffled_arr[destination] = value
        
        if shuffle_num_1 == compute_shuffle(shuffled_arr):
            break
    
    shuffled_arr[24] = byte_arr[24]
    return shuffled_arr


def binary_to_array(byte_arr):
    arr = []
    
    for i in range(0, 15, 5):
        num = struct.unpack(">Q", util.lpad(byte_arr[i:i+5], 8, b"\x00"))[0]
        arr.append((num >> 35) & 0x1F)
        arr.append((num >> 30) & 0x1F)
        arr.append((num >> 25) & 0x1F)
        arr.append((num >> 20) & 0x1F)
        arr.append((num >> 15) & 0x1F)
        arr.append((num >> 10) & 0x1F)
        arr.append((num >> 5) & 0x1F)
        arr.append(num & 0x1F)

    arr.append(byte_arr[-1] >> 3)
    assert len(arr) == 25
    return arr

def create_license_block(product_name, time_gen, time_exp):
    byte_arr = b""
    byte_arr += struct.pack("<I", time_exp)
    byte_arr += struct.pack("<I", time_gen)
    byte_arr += struct.pack("B", product_name) # product_name = CandyCaneMachine2000
    byte_arr += struct.pack("B", 0) # flags
    byte_arr += struct.pack("<H", 0) # count
    byte_arr += struct.pack("<H", 0) # premium
    byte_arr += struct.pack("B", 2) # product_type = Premium
    byte_arr += struct.pack("B", 0) # shuffle
    assert len(byte_arr) == 16
    return byte_arr

def generate_license_key(product_name):
    now = int(time.time())
    license_block = create_license_block(product_name, now, now + 1000)
    arr = binary_to_array(license_block)
    arr = shuffle_array(arr)
    license_key = arr_to_license(arr)
    return license_key

if __name__ == "__main__":

    key_1 = generate_license_key(0)
    flag = put_license(key_1)["flag"]
    print("[+] Flag:", flag)

    key_2 = generate_license_key(1)
    flag = put_license(key_2)["flag"]
    print("[+] Flag:", flag)

