#!python

import argparse, json
from porchpirate import porchpirate

# cooked up by
# Dominik Penner (@zer0pwn)
# &&& Jake Bolam (@xixasec)

WHITE   = '\033[37m'
BLUE    = '\033[34m'
BLACK   = "\u001b[30m"
RED     = "\u001b[31m"
YELLOW  = "\u001b[33m"
MAGENTA = "\u001b[35m"
CYAN    = "\u001b[36m"
WHITE   = "\u001b[37m"
GREEN   = "\u001b[32m"
BOLD    = '\033[1m'
END     = '\033[0m'

banner = r'''
{}                      __          _          __     
   ___  ___  ________/ /    ___  (_)______ _/ /____ 
  / _ \/ _ \/ __/ __/ _ \  / _ \/ / __/ _ `/ __/ -_)
 / .__/\___/_/  \__/_//_/ / .__/_/_/  \_,_/\__/\__/ 
/_/                      /_/                    
              by {}Mand Consulting Group{}
                 {}@zer0pwn @xixasec{}
'''.format(BOLD, BLUE, END, CYAN, END)

parser = argparse.ArgumentParser(
    description="Secret scanner for public Postman collections.",
    epilog="Usage: porch-pirate -s shopify --globals",
)
parser.add_argument('-s', help="Search term")
parser.add_argument('-p', help="Page number")
parser.add_argument('-l', help="Limit results")
parser.add_argument('-t', help="Entity type.")
parser.add_argument('-w', help="Workspace ID")
parser.add_argument('-c', help="Collection ID")
parser.add_argument('-r', help="Request ID")
parser.add_argument('-u', help="User ID")
parser.add_argument('--proxy', help="Proxy to use.")
parser.add_argument('--raw', const='all', nargs='?', help="Show raw JSON output.")
parser.add_argument('--globals', const='all', nargs='?', help="Show workspace globals.")
parser.add_argument('--collections', const='all', nargs='?', help="Show workspace collections.")
parser.add_argument('--requests', const='all', nargs='?', help="Show collection requests.")
parser.add_argument('--curl', const='all', nargs='?', help="Show curl command for request.")
parser.add_argument('--urls', const='all', nargs='?', help="Return list of URLs from a workspace.")
parser.add_argument('--dump', const='all', nargs='?', help="Dump all requests in a workspace.")
arguments = parser.parse_args()

if not arguments.raw:
    print(banner)

if(arguments.s):
    if arguments.l:
        limit = arguments.l
    else:
        limit = 100
    if arguments.p:
        page = arguments.p
    else:
        page = None
    if arguments.proxy:
        proxyconfig = arguments.proxy
    else:
        proxyconfig = None
    porchpirate = porchpirate(proxy=proxyconfig)
    if arguments.t:
        entity_type = arguments.t
    else:
        entity_type = None

    search_stats = json.loads(porchpirate.search_stats(arguments.s))
    search_results_count = search_stats['data']['all']
    api_results = search_stats['data']['api']
    team_results = search_stats['data']['team']
    collection_results = search_stats['data']['collection']
    workspace_results = search_stats['data']['workspace']
    request_results = search_stats['data']['request']
    flow_results = search_stats['data']['flow']

    print(f"{BOLD}{GREEN}[+]{END} Query returned {GREEN}{search_results_count}{END} search results.{END}\n")
    if request_results != 0:
        print(f"{BOLD}- Requests:{END}{GREEN}{request_results}{END}")
    if workspace_results != 0:
        print(f"{BOLD}- Workspaces:{END}{GREEN}{workspace_results}{END}")
    if collection_results != 0:
        print(f"{BOLD}- Collections:{END}{GREEN}{collection_results}{END}")
    if team_results != 0:
        print(f"{BOLD}- Teams:{END}{GREEN}{team_results}{END}")
    if api_results != 0:
        print(f"{BOLD}- APIs:{END}{GREEN}{api_results}{END}")
    if flow_results != 0:
        print(f"{BOLD}- Flows:{END}{GREEN}{flow_results}{END}")
    print()

    search = json.loads(porchpirate.search(arguments.s, indice=entity_type, page=page, limit=limit))
    if(arguments.globals):
        findings = []
        unique_findings = []
        for result in search['data']:
            try:
                workspace = result['document']['workspaces']
                for w in workspace:
                    findings.append({
                        'id': w['id'],
                        'name': w['name']
                    })
            except:
                pass

        seen_findings = set()
        for obj in findings:
            if obj['name'] not in seen_findings:
                unique_findings.append(obj)
                seen_findings.add(obj['name'])
        number_of_findings = len(unique_findings)
        print(f"{BOLD}{GREEN}[+]{END} Found {number_of_findings} unique workspaces. Checking globals...{END}")
        for finding in unique_findings:
            print(f"{YELLOW}[*]{END} Querying global variables in {CYAN}{finding['id']}{END}")
            globalsfindings = {
                'name': finding['name'],
                'search_data': search['data'],
                'finding': json.loads(porchpirate.workspace_globals(finding['id']))
            }
            porchpirate._show_formatted_globals_findings(globalsfindings)

    if(arguments.dump):
        workspaces = []
        for result in search['data']:
            try:
                workspace = result['document']['workspaces']
                for w in workspace:
                    if w['id'] not in workspaces:
                        workspaces.append(w['id'])
            except:
                pass
        for w in workspaces:
            try:
                print(f"\n{YELLOW}[*]{END} Querying workspace ID {CYAN}{w}{END}\n")
                workspace = json.loads(porchpirate.workspace(w))
                collections = json.loads(porchpirate.collections(w))
                for collection in collections['data']:
                    requests = collection['requests']
                    for r in requests:
                        request_data = json.loads(porchpirate.request(r['id']))
                        try:
                            porchpirate._show_formatted_request(request_data['data'], r['id'])
                        except:
                            pass
            # skip to next workspace on ctrl-c
            except KeyboardInterrupt:     
                continue

    # this might be the ugliest snippet in the whole script
    # im so sorry
    if(arguments.urls):
        workspaces = []
        for result in search['data']:
            try:
                workspace = result['document']['workspaces']
                for w in workspace:
                    if w['id'] not in workspaces:
                        workspaces.append(w['id'])
            except:
                pass
        for w in workspaces:
            try:
                print(f"\n{YELLOW}[*]{END} Querying workspace ID {CYAN}{w}{END}\n")
                workspace = json.loads(porchpirate.workspace(w))
                collections = json.loads(porchpirate.collections(w))
                for collection in collections['data']:
                    requests = collection['requests']
                    try:
                        for r in requests:
                            request_data = json.loads(porchpirate.request(r['id']))
                            url = request_data['data']['url']
                            print(f"{BOLD}- URL: {END}{YELLOW}{url}{END}")
                    except:
                        pass
            except KeyboardInterrupt:     
                continue
        exit()

    if(arguments.raw):
        print(json.dumps(search))

    elif(arguments.s and not arguments.globals and not arguments.dump):
        porchpirate._show_formatted_search_results(search)

if(arguments.w):
    if(arguments.globals):
        if arguments.proxy:
            proxyconfig = arguments.proxy
        else:
            proxyconfig = None
        porchpirate = porchpirate(proxy=proxyconfig)
        workspace = json.loads(porchpirate.workspace(arguments.w))
        globals = json.loads(porchpirate.workspace_globals(arguments.w))
        workspace['globals'] = []
        workspace['globals'].append(globals)
        try:
            environments = workspace['data']['dependencies']['environments']
            for environment in environments:
                environment_globals = json.loads(porchpirate.environment(environment))
                workspace['globals'].append(environment_globals)
        except:
            pass
        if(arguments.raw):
            print(json.dumps(globals))
        else:
            porchpirate._show_formatted_workspace(workspace)
    if arguments.collections:
        if arguments.proxy:
            proxyconfig = arguments.proxy
        else:
            proxyconfig = None
        porchpirate = porchpirate(proxy=proxyconfig)
        collections = json.loads(porchpirate.collections(arguments.w))
        if(arguments.raw):
            print(json.dumps(globals))
        else:
            porchpirate._show_formatted_collections(collections)
    if(arguments.dump):
        if arguments.proxy:
            proxyconfig = arguments.proxy
        else:
            proxyconfig = None
        porchpirate = porchpirate(proxy=proxyconfig)
        collections = json.loads(porchpirate.collections(arguments.w))
        try:
            for collection in collections['data']:
                requests = collection['requests']
                for r in requests:
                    request_data = json.loads(porchpirate.request(r['id']))
                    try:
                        porchpirate._show_formatted_request(request_data['data'], r['id'])
                    except:
                        pass
        except:
            pass
    if(arguments.urls):
        if arguments.proxy:
            proxyconfig = arguments.proxy
        else:
            proxyconfig = None
        porchpirate = porchpirate(proxy=proxyconfig)
        collections = json.loads(porchpirate.collections(arguments.w))
        try:
            for collection in collections['data']:
                requests = collection['requests']
                for r in requests:
                    request_data = json.loads(porchpirate.request(r['id']))
                    try:
                        url = request_data['data']['url']
                        print(f"{BOLD}- URL: {END}{YELLOW}{url}{END}")
                    except:
                        pass
        except:
            pass
    if(arguments.raw):
        if arguments.proxy:
            proxyconfig = arguments.proxy
        else:
            proxyconfig = None
        porchpirate = porchpirate(proxy=proxyconfig)
        workspace = json.loads(porchpirate.workspace(arguments.w))
        print(json.dumps(workspace))
    if(arguments.requests):
        if arguments.proxy:
            proxyconfig = arguments.proxy
        else:
            proxyconfig = None
        porchpirate = porchpirate(proxy=proxyconfig)
        collections = json.loads(porchpirate.collections(arguments.w))
        try:
            for collection in collections['data']:
                requests = collection['requests']
                try:
                    for request in requests:
                        print(f"{BOLD}- Request: {END}{YELLOW}{request['name']}{END}")
                except:
                    pass
        except:
            print(f"{BOLD}{RED}[-]{END} Workspace not found.{END}")
    else:
        try:
            if arguments.proxy:
                proxyconfig = arguments.proxy
            else:
                proxyconfig = None
            porchpirate = porchpirate(proxy=proxyconfig)
            workspace = json.loads(porchpirate.workspace(arguments.w))
            globals = json.loads(porchpirate.workspace_globals(arguments.w))
            workspace['globals'] = []
            workspace['globals'].append(globals)
            try:
                environments = workspace['data']['dependencies']['environments']
                for environment in environments:
                    environment_globals = json.loads(porchpirate.environment(environment))
                    workspace['globals'].append(environment_globals)
            except:
                pass
            if(arguments.raw):
                print(json.dumps(workspace))
                print(json.dumps(workspace['globals']))
            else:
                try:
                    porchpirate._show_formatted_workspace(workspace)
                except:
                    print(f"{BOLD}{RED}[-]{END} Workspace not found.{END}")
        except:
            pass

if(arguments.c):
    if arguments.proxy:
        proxyconfig = arguments.proxy
    else:
        proxyconfig = None
    p = porchpirate(proxy=proxyconfig)
    collection = json.loads(p.collection(arguments.c))
    if arguments.raw:
        print(json.dumps(collection))
    elif arguments.requests:
        request = json.loads(p.request(arguments.requests))['data']
        print(request)
    else:
        p._show_formatted_collection(collection)

if(arguments.r):
    if arguments.proxy:
        proxyconfig = arguments.proxy
    else:
        proxyconfig = None
    p = porchpirate(proxy=proxyconfig)
    request = json.loads(p.request(arguments.r))['data']
    if arguments.raw:
        print(json.dumps(request))
        exit()
    if arguments.curl:
        curl = p.build_curl_request(request)
        print(curl)
    else:
        p._show_formatted_request(request, arguments.r)

if(arguments.u):
    if arguments.proxy:
        proxyconfig = arguments.proxy
    else:
        proxyconfig = None
    p = porchpirate(proxy=proxyconfig)

    if arguments.u.isnumeric():
        # User ID logic
        pass

    user_profile = json.loads(p.profile(arguments.u))

    if arguments.raw:
        print(json.dumps(user_profile))

    if('error' in user_profile):
        print(f"{BOLD}{RED}[-]{END} User not found.{END}")
    elif user_profile['entity_type'] == 'team':
        team_id = user_profile['entity_id']
        team_members = user_profile['info']['members']
        team_collections = json.loads(p.team_collections(team_id))
        team_workspaces = json.loads(p.team_workspaces(team_id))
        if arguments.raw:
            print(json.dumps(team_collections))
            print(json.dumps(team_workspaces))
            print(json.dumps(team_members))
        else:
             p._show_formatted_team(user_profile, team_collections, team_workspaces, team_members)
    else:
        user_id = user_profile['entity_id']
        user_collections = json.loads(p.user_collections(user_id))
        user_workspaces = json.loads(p.user_workspaces(user_id))
        if arguments.raw:
            print(json.dumps(user_collections))
            print(json.dumps(user_workspaces))
        else:
            p._show_formatted_user(user_profile, user_collections, user_workspaces)

if not arguments.s and not arguments.w and not arguments.c and not arguments.r and not arguments.u:
    parser.print_help()