Full Code of chiasmod0n/chiasmodon for AI

main 256f2045cf34 cached
7 files
65.4 KB
16.9k tokens
40 symbols
1 requests
Download .txt
Repository: chiasmod0n/chiasmodon
Branch: main
Commit: 256f2045cf34
Files: 7
Total size: 65.4 KB

Directory structure:
gitextract_3q7hvgfq/

├── Dockerfile
├── LICENSE.txt
├── README.md
├── cli/
│   └── chiasmodon_cli.py
├── pychiasmodon.py
├── requirements.txt
└── setup.py

================================================
FILE CONTENTS
================================================

================================================
FILE: Dockerfile
================================================
FROM python:3.11-alpine

COPY . .
RUN python setup.py install

ENTRYPOINT [ "python3","/cli/chiasmodon_cli.py" ]

================================================
FILE: LICENSE.txt
================================================
MIT License

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

================================================
FILE: README.md
================================================

# Chiasmodon

[![asciicast](https://asciinema.org/a/QrEtBLFMQrjU1sjRjcgTdo41m.svg)](https://asciinema.org/a/QrEtBLFMQrjU1sjRjcgTdo41m)
<p align="center">
<img src="https://badge.fury.io/py/chiasmodon.svg" />
</p>
Chiasmodon is an OSINT tool that allows users to gather information from various sources and conduct targeted searches based on domains, Google Play applications, email addresses, IP addresses, organizations, URLs, and more. It provides comprehensive scanning capabilities, customizable output formats, and additional options for enhanced data analysis and customization.


## ✨Features

- [x] **🌐Domain**: Conduct targeted searches by specifying a domain name to gather relevant information related to the domain.
- [x] **🎮Google Play Application**: Search for information related to a specific application on the Google Play Store by providing the application ID.
- [x] **✉️Email, 👤Username, 🔒Password**: Conduct searches based on email, username, or password to identify potential security risks or compromised credentials.
- [x] **🔍 IP Address**: Perform searches using an IP address to gather information such as geolocation, associated domain names, and historical data.
- [x] **🌍 CIDR**: Search for information related to a specified CIDR (Classless Inter-Domain Routing) block, including IP range details and associated networks.
- [x] **🔢 ASN**: Retrieve information about an Autonomous System Number (ASN), including its owner, associated IP ranges, and network details.
- [x] **🔌 Port**: Search for information about a specific port number, including its common usage, associated services, and potential vulnerabilities.
- [x] **🌐 ISP**: Conduct searches based on an Internet Service Provider (ISP) name to gather information about the ISP, its services, and associated IP ranges.
- [x] **🏢 Organization (ORG)**: Search for information related to a specific organization or company, including its contact details, associated domains, and network infrastructure.
- [x] **🔗 URL Path**: Perform searches based on a specific URL path to gather information about the path, its content, and potential security risks.
- [x] **📞 Phone**: Conduct searches using a phone number to gather information such as the associated owner, location, and any available public records.
- [x] **🔍Scan**: Perform a comprehensive scan on a given company domain name in one click, including finding
  - Related companies.
  - App applications.
  - Ips (`Port, Org, Isp, Asn`).
  - Subdomains.
  - Client credentials (`Email, Username, Password`).
  - Employee credentials (`Email, Username, Password`)
  - URLs (`Domain/IP, Port, Endpoint`)

- [X] **🌍Country**: Sort and filter search results by country to gain insights into the geographic distribution of the identified information.
- [x] **📋Output Customization**: Choose the desired output format (text, JSON, or CSV) and specify the filename to save the search results.
- [x] **⚙️Additional Options**: The tool offers various additional options, such as viewing different result types (credentials, URLs, subdomains, emails, passwords, usernames, or applications), setting API tokens, specifying timeouts, limiting results, and more.

## 🚀Comming soon

- **🏢Company Name**: We understand the importance of comprehensive company research. In our upcoming release, you'll be able to search by company name and access a wide range of documents associated with that company. This feature will provide you with a convenient and efficient way to gather crucial information, such as legal documents, financial reports, and other relevant records.

- **👤Face (Photo)**: Visual data is a powerful tool, and we are excited to introduce our advanced facial recognition feature. With "Search by Face (Photo)," you can upload an image containing a face and leverage cutting-edge technology to identify and match individuals across various data sources. This will allow you to gather valuable information, such as social media profiles, online presence, and potential connections, all through the power of facial recognition.

## Why Chiasmodon name ?
Chiasmodon niger is a species of deep sea fish in the family Chiasmodontidae. It is known for its ability to **swallow fish larger than itself**. and so do we. 😉
![Chiasmodon background](https://journal.voca.network/wp-content/uploads/2017/10/DTR083_1200.png)

## 🔑 Subscription
Join us today and unlock the potential of our cutting-edge OSINT tool. Contact https://t.me/Chiasmod0n on Telegram to subscribe and start harnessing the power of Chiasmodon for your domain investigations.

## ⬇️Install
```bash
$ pip install chiasmodon
```
Only for linux 👇 
```bash
$ activate-global-python-argcomplete
```
## 💻Usage
Chiasmodon provides a flexible and user-friendly command-line interface and python library. Here are some examples to demonstrate its usage:


```
usage: chiasmodon_cli.py [-h]
                         [-m {cred.username,cred.password,cred.email,cred.phone,cred.email.domain,cred.country,domain,domain.all,ip,ip.asn,ip.isp,ip.org,ip.port,ip.country,app.id,app.name,app.domain,url.path,url.port}]
                         [-vt {full,cred,url,email,phone,password,username,app,domain,ip,related,subdomain}] [-s] [-sr SCAN_RELATED]
                         [-ss SCAN_SUBDOMAINS] [-sa SCAN_APPS] [-si SCAN_IPS] [-sc SCAN_CLIENTS] [-se SCAN_EMPLOYEES] [-o OUTPUT]
                         [-ot {text,json,csv}] [-t TIMEOUT] [-l LIMIT] [-nc] [-lv] [-lm] [--init INIT] [-v]
                         query

Chiasmodon CLI

positional arguments:
  query                 query argument

options:
  -h, --help            show this help message and exit
  -m {cred.username,cred.password,cred.email,cred.phone,cred.email.domain,cred.country,domain,domain.all,ip,ip.asn,ip.isp,ip.org,ip.port,ip.country,app.id,app.name,app.domain,url.path,url.port}, --method {cred.username,cred.password,cred.email,cred.phone,cred.email.domain,cred.country,domain,domain.all,ip,ip.asn,ip.isp,ip.org,ip.port,ip.country,app.id,app.name,app.domain,url.path,url.port}
                        method to search by it,default is "domain".
  -vt {full,cred,url,email,phone,password,username,app,domain,ip,related,subdomain}, --view-type {full,cred,url,email,phone,password,username,app,domain,ip,related,subdomain}
                        type view the result default is "full".
  -s, --scan            scan the company domain (Related company, Clients, Employees, Company ASNs, Company Apps).
  -sr SCAN_RELATED, --scan-related SCAN_RELATED
                        Run related scan, default is yes, Ex: -sr no
  -ss SCAN_SUBDOMAINS, --scan-subdomains SCAN_SUBDOMAINS
                        Run subdomains scan, default is yes, Ex: -ss no
  -sa SCAN_APPS, --scan-apps SCAN_APPS
                        Run App scan, default is yes, Ex: -sa no
  -si SCAN_IPS, --scan-ips SCAN_IPS
                        Run IPs scan, default is yes, Ex: -si no
  -sc SCAN_CLIENTS, --scan-clients SCAN_CLIENTS
                        Run clients scan, default is yes, Ex: -sc no
  -se SCAN_EMPLOYEES, --scan-employees SCAN_EMPLOYEES
                        Run employees scan, default is yes, Ex: -se no
  -o OUTPUT, --output OUTPUT
                        filename to save the result
  -ot {text,json,csv}, --output-type {text,json,csv}
                        output format default is "text".
  -t TIMEOUT, --timeout TIMEOUT
                        request timeout default is 360 sec.
  -l LIMIT, --limit LIMIT
                        limit results default is 10000.
  -nc, --no-color       show result without color.
  -lv, --list-view-type
                        list view type.
  -lm, --list-methods   list methods.
  --init INIT           set the api token.
  -v, --version         version.
```

Examples:
```
# Scan company by domain
chiasmodon_cli.py example.com --scan

# Search for target domain, you will see the result for only this "example.com" 
chiasmodon_cli.py example.com 
    
# Search in target and target subdomains
chiasmodon_cli.py example.com --method domain.all

# Search for target subdomains
chiasmodon_cli.py example.com --view-type subdomain
        
# Search for all creds in United States 
chiasmodon_cli.py US --method cred.country

# Search for related companies by domain
chiasmodon_cli.py example.com --view-type related

# search for target app id 
chiasmodon_cli.py com.discord --method app.id 
    
# search for target app domain 
chiasmodon_cli.py discord.com --method app.domain
    
# search for target app name 
chiasmodon_cli.py Discord --method app.name
    
# Search for ip asn
chiasmodon_cli.py AS123 --method ip.asn

# Search for cred username
chiasmodon_cli.py someone --method cred.username

# Search for cred password
chiasmodon_cli.py example@123 --method cred.password

# Search for url endpoint
chiasmodon_cli.py /wp-login.php --method url.path

# Search for ip
chiasmodon_cli.py 1.1.1.1 --method ip

# Search for cidr
chiasmodon_cli.py xx.xx.xx.0/24 --method ip

# Search for target creds by domain emsils
chiasmodon_cli.py example.com --method cred.email.domain

# Search for target email
chiasmodon_cli.py someone@example.com --method cred.email  

# search for multiple targets: 
chiasmodon_cli.py targets.txt --method domain  --output example-creds.txt 
```

Please note that these examples represent only a fraction of the available options and use cases. Refer to the documentation for more detailed instructions and explore the full range of features provided by Chiasmodon.


## 💬 Contributions and Feedback

Contributions and feedback are welcome! If you encounter any issues or have suggestions for improvements, please submit them to the Chiasmodon GitHub repository. Your input will help us enhance the tool and make it more effective for the OSINT community.

## 📜License

Chiasmodon is released under the [MIT License](https://opensource.org/licenses/MIT). See the [LICENSE](https://github.com/chiasmodon/LICENSE.txt) file for more details.

## ⚠️Disclaimer

Chiasmodon is intended for legal and authorized use only. Users are responsible for ensuring compliance with applicable laws and regulations when using the tool. The developers of Chiasmodon disclaim any responsibility for the misuse or illegal use of the tool.

## 📢Acknowledgments

Chiasmodon is the result of collaborative efforts from a dedicated team of contributors who believe in the power of OSINT. We would like to express our gratitude to the open-source community for their valuable contributions and support.

## 🔗Chiasmodon Links

- [🐍 Python Library](https://pypi.org/project/chiasmodon)
- [📱 Mobile (APK)](https://github.com/chiasmod0n/chiasmodon-mobile)
- [🌐 Website](http://chiasmodon.online)
- [💬 Telegram](https://t.me/chiasmod0n)
- [🐦 X/Twitter](https://x.com/chiasmod0n)


## ⭐️Star History

<a href="https://star-history.com/#chiasmod0n/chiasmodon&Date">
 <picture>
   <source media="(prefers-color-scheme: dark)" srcset="https://api.star-history.com/svg?repos=chiasmod0n/chiasmodon&type=Date&theme=dark" />
   <source media="(prefers-color-scheme: light)" srcset="https://api.star-history.com/svg?repos=chiasmod0n/chiasmodon&type=Date" />
   <img alt="Star History Chart" src="https://api.star-history.com/svg?repos=chiasmod0n/chiasmodon&type=Date" />
 </picture>
</a>


================================================
FILE: cli/chiasmodon_cli.py
================================================
#!/usr/bin/python3
# PYTHON_ARGCOMPLETE_OK

import os
import sys
import argcomplete
import json
import argparse
import tldextract
from yaspin import yaspin
from pathlib import Path 
from pychiasmodon import Chiasmodon,Result,VERSION,VIEW_TYPE_LIST,T,_METHODS

ROOT_DIR = os.path.dirname(os.path.abspath(__file__))

class ULIT:
    @staticmethod
    def rFile(file:Path) -> str:
        if not file.is_file():
            print(f'{T.RED}Not found {file} file.{T.RESET}')
            return

        with open(file, 'r') as f:
            return f.read()    

    @staticmethod
    def wFile(file:Path, data:str) -> str:
        with open(file, 'w') as f:
            f.write(data)

    @staticmethod
    def rFileToJson(file:Path) -> dict:
        return json.loads(ULIT.rFile(file=file))

    @staticmethod
    def wJsonToFile(file:Path, data:dict) -> dict:
        ULIT.wFile(
            file=file,
            data=json.dumps(data)
        )

    @staticmethod
    def get_root_domain(d:str) -> str:
        domain = d.split()[0]
        x = tldextract.extract(domain)
        if not x.suffix:
            return None

        return '{}.{}'.format(x.domain, x.suffix)

class Scan(Chiasmodon):
    def __init__(self, options:argparse.Namespace) -> None:        
        self.options :argparse.Namespace=options
        self.result :list = []
        conf_file :Path = Path(ROOT_DIR, 'conf.json')
        token:str = ''
        
        if not conf_file.is_file():ULIT.wJsonToFile(conf_file, {})

        if self.options.init:
            token = self.options.init
            ULIT.wJsonToFile(conf_file, {'token':self.options.init})

        elif not conf_file.is_file():
            ULIT.wJsonToFile(conf_file, {})
            token = ''

        else:
            token = ULIT.rFileToJson(conf_file).get('token') or ''

        super().__init__(
            token=token,
            conf_file=conf_file,
            color=True if not self.options.no_color else False,
            debug=True, 
            check_token=self.options.init,
        )

        if self.options.init:
            sys.exit()
        
        self.scan_mode = True

    def scan_callback(self,beta,ys):
        self.print(beta.print(), ys)

    def proc(self):
        if not self.options.query:
            self.print(f"{T.RED}You can't run scan without company domain\nPlease use (-d or --domain) to scan the domain{T.RESET}")
            sys.exit(0)
        
        domain = ULIT.get_root_domain(self.options.query)
        if not domain:
            self.print(f"{T.RED}Wrong domain{T.RESET}",)
            sys.exit(0)

        self.output_folder = Path(domain)
        self.output_folder.mkdir(exist_ok=True, parents=True)

        self.__scan(
            domain=domain,
        )


    def __scan(self, domain):
        status = False

        print_output = f'{T.MAGENTA}>{T.RESET}{T.YELLOW} Saved output{T.RESET}: \n'
        output = {
            'related':[],
            'apps':[], 
            'client-creds':[],
            'client-usernames':[],
            'client-passwords':[],
            'client-emails':[],
            'employe-creds':[],
            'employe-usernames':[],
            'employe-passwords':[],
            'employe-emails':[],
            'subdomains':[],
            'urls':[],
            'endpoints':[],
            'ports':[],

        }
        
        if self.options.scan_related.lower() == 'yes':
            related = self.search(
                method='domain',
                query=domain,
                view_type='related',
                sort=True ,
                timeout=self.options.timeout,
                limit=1000000,
                callback_view_result=self.scan_callback,
                yaspin=yaspin,
                search_text=f'Find {T.GREEN+domain+T.RESET} related companies...',
                err_text=f'Not found related !'
            )


            if related:
                status = True
                output['related'] = [i.save_format() for i in related]
                ULIT.wFile((self.output_folder / 'related.txt'), '\n'.join(output['related'])) 
                print_output += f"\t{T.MAGENTA}-{T.RESET} {T.BLUE}{(self.output_folder / 'related.txt')}{T.RESET}\n"
            else:
                self.print(f'{T.RED}💥  Not found related !{T.RESET}')
            self.print(f'{T.MAGENTA}{"-"*30}{T.RESET}')
        if self.options.scan_subdomains.lower() == 'yes':
            subdomains = self.search(
                method='domain',
                query=domain,
                view_type='subdomain',
                sort=True ,
                timeout=self.options.timeout,
                limit=1000000,
                callback_view_result=self.scan_callback,
                yaspin=yaspin,
                search_text=f'Find {T.GREEN+domain+T.RESET} subdomains...',
                err_text=f'Not found subdomains !'
            )


            if subdomains:
                status = True
                output['subdomains'] = [i.save_format() for i in subdomains]
                ULIT.wFile((self.output_folder / 'subdomains.txt'), '\n'.join(output['subdomains'])) 
                print_output += f"\t{T.MAGENTA}-{T.RESET} {T.BLUE}{(self.output_folder / 'subdomains.txt')}{T.RESET}\n"
            self.print(f'{T.MAGENTA}{"-"*30}{T.RESET}')
            
        if self.options.scan_apps.lower() == 'yes':
            apps = self.search(
                method='app.domain',
                query=domain,
                view_type='app',
                sort=True ,
                timeout=self.options.timeout,
                limit=1000000,
                callback_view_result=self.scan_callback,
                yaspin=yaspin,
                search_text=f'Find {T.GREEN+domain+T.RESET} Apps...',
                err_text=f'Not found apps !'
            )


            if apps:
                status = True
                output['apps'] = [i.save_format() for i in apps]
                ULIT.wFile((self.output_folder / 'apps.txt'), '\n'.join(output['apps'])) 
                print_output += f"\t{T.MAGENTA}-{T.RESET} {T.BLUE}{(self.output_folder / 'apps.txt')}{T.RESET}\n"
            self.print(f'{T.MAGENTA}{"-"*30}{T.RESET}')
        if self.options.scan_ips.lower() == 'yes':
            ips = self.search(
                method='domain.all',
                query=domain,
                view_type='ip',
                sort=True ,
                timeout=self.options.timeout,
                limit=1000000,
                callback_view_result=self.scan_callback,
                yaspin=yaspin,
                search_text=f'Find {T.GREEN+domain+T.RESET} IPs...',
                err_text=f'Not found ips !'
            )


            if ips:
                status = True
                output['ips'] = [i.save_format() for i in ips]
                ULIT.wFile((self.output_folder / 'ips.txt'), '\n'.join(output['ips'])) 
                print_output += f"\t{T.MAGENTA}-{T.RESET} {T.BLUE}{(self.output_folder / 'ips.txt')}{T.RESET}\n"
                
            self.print(f'{T.MAGENTA}{"-"*30}{T.RESET}')
        if self.options.scan_clients.lower() == 'yes':
            client_creds:list[Result] = self.search(
                query=domain,
                method='domain.all',
                view_type='full',
                sort=True ,
                timeout=self.options.timeout,
                limit=1000000,
                callback_view_result=self.scan_callback,
                yaspin=yaspin,
                search_text=f'Find {T.GREEN+domain+T.RESET} client creds...',
                err_text=f'Not found clients !'
                
            )
        
            if client_creds:
                status = True
                output['client-creds'] =[i.save_format() for i in client_creds]
                ULIT.wFile((self.output_folder / 'client-creds.txt'), '\n'.join([':'.join(i) for i in output['client-creds']]))
                print_output += f"\t{T.MAGENTA}-{T.RESET} {T.BLUE}{(self.output_folder / 'client-creds.txt')}{T.RESET}\n"
                
                for i in client_creds:
                    output['client-usernames'].append(i.credUsername) if i.credUsername and not i.credEmail  and '/' not in i.credUsername and  i.credUsername not in output['client-usernames']  else None
                    output['client-passwords'].append(i.credPassword) if i.credPassword and i.credPassword not in output['client-passwords'] else None
                    output['client-emails'].append(i.credEmail) if i.credEmail  and i.credEmail not in output['client-emails'] else None
                    output['subdomains'].append(i.domain) if i.domain and i.domain not in output['subdomains'] and i.domain != domain else None
                    output['urls'].append(i.url) if i.url and i.url not in output['urls'] else None
                    output['endpoints'].append(i.urlPath) if i.urlPath and i.urlPath not in output['endpoints'] else None
                    output['ports'].append(i.urlPort) if i.urlPort and i.urlPort not in output['ports'] else None
                    
                ULIT.wFile((self.output_folder / 'client-usernames.txt'), '\n'.join(output['client-usernames']))
                print_output += f"\t{T.MAGENTA}-{T.RESET} {T.BLUE}{(self.output_folder / 'client-usernames.txt')}{T.RESET}\n"
                ULIT.wFile((self.output_folder / 'client-emails.txt'), '\n'.join(output['client-emails']))
                print_output += f"\t{T.MAGENTA}-{T.RESET} {T.BLUE}{(self.output_folder / 'client-emails.txt')}{T.RESET}\n"
                ULIT.wFile((self.output_folder / 'client-passwords.txt'), '\n'.join(output['client-passwords']))
                print_output += f"\t{T.MAGENTA}-{T.RESET} {T.BLUE}{(self.output_folder / 'client-passwords.txt')}{T.RESET}\n"
                ULIT.wFile((self.output_folder / 'endpoints.txt'), '\n'.join(output['endpoints']))
                print_output += f"\t{T.MAGENTA}-{T.RESET} {T.BLUE}{(self.output_folder / 'endpoints.txt')}{T.RESET}\n"
                ULIT.wFile((self.output_folder / 'ports.txt'), '\n'.join([f"{i}" for i in output['ports']]))
                print_output += f"\t{T.MAGENTA}-{T.RESET} {T.BLUE}{(self.output_folder / 'ports.txt')}{T.RESET}\n"
                ULIT.wFile((self.output_folder / 'subdomains.txt'), '\n'.join(output['subdomains']))
                print_output += f"\t{T.MAGENTA}-{T.RESET} {T.BLUE}{(self.output_folder / 'subdomains.txt')}{T.RESET}\n"
                ULIT.wFile((self.output_folder / 'urls.txt'), '\n'.join([f"{i}" for i in output['urls']]))
                print_output += f"\t{T.MAGENTA}-{T.RESET} {T.BLUE}{(self.output_folder / 'urls.txt')}{T.RESET}\n"


            self.print(f'{T.MAGENTA}{"-"*30}{T.RESET}')
        if self.options.scan_employees.lower() == 'yes':
            employe_creds = self.search(
                query=domain,
                method='cred.email.domain',
                view_type='full',
                sort=True,
                timeout=self.options.timeout,
                callback_view_result=self.scan_callback,
                limit=1000000,
                yaspin=yaspin,
                search_text=f'Find {T.GREEN+domain+T.RESET} employees creds...',
                err_text=f'Not found Employees!'
            )

            if employe_creds:
                status = True
                output['employe-creds'] =[i.save_format() for i in employe_creds]
                ULIT.wFile((self.output_folder / 'employe-creds.txt'), '\n'.join([':'.join(i) for i in output['employe-creds']]))
                print_output += f"\t{T.MAGENTA}-{T.RESET} {T.BLUE}{(self.output_folder / 'employe-creds.txt')}{T.RESET}\n"
                for i in employe_creds:
                    output['employe-usernames'].append(i.credUsername) if i.credUsername and not i.credEmail and '/' not in i.credUsername and i.credUsername not in output['employe-usernames']  else None
                    output['employe-passwords'].append(i.credPassword) if i.credPassword and i.credPassword not in output['employe-passwords'] else None
                    output['employe-emails'].append(i.credEmail) if i.credEmail  and i.credEmail not in output['employe-emails'] else None
                    
                ULIT.wFile((self.output_folder / 'employe-usernames.txt'), '\n'.join(output['employe-usernames']))
                print_output += f"\t{T.MAGENTA}-{T.RESET} {T.BLUE}{(self.output_folder / 'employe-usernames.txt')}{T.RESET}\n"
                ULIT.wFile((self.output_folder / 'employe-emails.txt'), '\n'.join(output['employe-emails']))
                print_output += f"\t{T.MAGENTA}-{T.RESET} {T.BLUE}{(self.output_folder / 'employe-emails.txt')}{T.RESET}\n"
                ULIT.wFile((self.output_folder / 'employe-passwords.txt'), '\n'.join(output['employe-passwords']))
                print_output += f"\t{T.MAGENTA}-{T.RESET} {T.BLUE}{(self.output_folder / 'employe-passwords.txt')}{T.RESET}\n"
        

        if status:
            ULIT.wJsonToFile((self.output_folder / 'scan.json'), output)
            print_output += f"\t{T.MAGENTA}-{T.RESET} {T.BLUE}{(self.output_folder / 'scan.json')}{T.RESET}"
            self.print(print_output)
        
class CLI(Chiasmodon):
    def __init__(self, options:argparse.Namespace) -> None:

        self.options :argparse.Namespace=options
        self.result :list = []

        conf_file :Path = Path(ROOT_DIR, 'conf.json')
        token:str = '' 
        
        if not conf_file.is_file():ULIT.wJsonToFile(conf_file, {})

        if self.options.init:
            token = self.options.init
            ULIT.wJsonToFile(conf_file, {'token':self.options.init})

        elif not conf_file.is_file():
            ULIT.wJsonToFile(conf_file, {})
            token = ''

        else:
            token = ULIT.rFileToJson(conf_file).get('token') or ''

        super().__init__(
            token=token,
            conf_file=conf_file,
            color=True if not self.options.no_color else False,
            #debug=self.options.debug, 
            debug=True, 
            check_token=self.options.init,
        )

        if self.options.init:
            sys.exit()

    def review_results(self,
                       beta:Result, 
                       ys=True,
                    ) -> None:

        if beta.save_format() not in self.result:
            self.print(beta.print(), ys=ys)
            self.result.append(beta.save_format())
        
    def save_result(self, view_type) -> None:

        if self.options.output:

            if self.options.output_type == "text":
                if self.result and view_type != 'cred':
                    self.result.remove(None) if None in self.result else None
                
                ULIT.wFile(
                    self.options.output,
                    '\n'.join([':'.join(i) if type(i) == list else i for i in self.result]) 
                )

            if self.options.output_type == "csv":
                if self.result and view_type != 'cred':
                    self.result.remove(None) if None in self.result else None
                
                ULIT.wFile(
                    self.options.output,
                    '\n'.join([','.join(['url/app_id','user/email', 'password', 'country', 'date'])]+[','.join(i) if type(i) == list else i for i in self.result])  if view_type == 'cred' else  '\n'.join([view_type]+[','.join(i) if type(i) == list else i for i in self.result]) 
                )

            if self.options.output_type == "json":
                ULIT.wJsonToFile(
                    self.options.output,
                    self.result
                )


    def proc(self):

        query = ULIT.rFile(f).splitlines() if (f:=Path(self.options.query)).is_file() else [self.options.query.strip()] 


        for i in query:
            self.search(
                query=i,
                method=self.options.method,
                view_type=self.options.view_type,
                limit=self.options.limit,
                timeout=self.options.timeout,
                sort=True,
                yaspin=yaspin,
                callback_view_result=self.review_results,
            )

        if self.options.output and self.result:
            self.save_result(self.options.view_type)
            self.print(f'{T.MAGENTA}>{T.RESET}{T.YELLOW} Saved output to {T.RESET}: {T.GREEN}{self.options.output}{T.RESET}')

      
if __name__ == "__main__":

    if len(sys.argv) == 1 or '--help' in sys.argv or '-h' in sys.argv:
        print(f"""
   🙂           🙂                 
  /|\\           /|\\               
  /\\            /\\                                                                                   
 \\___/        \\___/                 🔑
{T.BLUE}~^~^~^~^~^~^~^~^~^~^~^~^~{T.BLUE}~^~^~^~{T.GREEN}    {T.RESET}/|\\{T.GREEN}
|\\   {T.YELLOW}\\\\\\\\{T.GREEN}__     {T.MAGENTA}Chiasmodon{T.RESET} {T.RED}{VERSION}{T.GREEN}    {T.RESET}/\\{T.GREEN}
| \\_/    {T.RED}o{T.GREEN} \\    {T.CYAN}o{T.GREEN}                  {T.RESET}\\___/{T.GREEN}
> _   {T.YELLOW}(({T.GREEN} <_  {T.CYAN}oo{T.GREEN}        
| / \\__+___/        
|/     |/           

{T.MAGENTA}>{T.RESET} {T.YELLOW}Admin{T.RESET}: {T.GREEN}https://t.me/Chiasmod0n
{T.RESET}""")
    parser = argparse.ArgumentParser(description='Chiasmodon CLI',  formatter_class=argparse.RawTextHelpFormatter,)

    if '-lm' not in sys.argv and '--list-methods' not in sys.argv and '-lv' not in sys.argv and '--list-view-type' not in sys.argv and '-v' not in sys.argv and '--version' not in sys.argv and '--init' not in sys.argv:
        parser.add_argument('query', type=str,      help='query argument')

    parser.add_argument('-m','--method',        help='method to search by it,default is "domain".', choices=_METHODS, type=str, default='domain')
    parser.add_argument('-vt','--view-type',    help='type view the result default is "full".', choices=VIEW_TYPE_LIST, type=str, default='full')
    parser.add_argument('-s','--scan',          help='scan the company domain (Related company, Clients, Employees, Company ASNs, Company Apps).',action='store_true')
    parser.add_argument('-sr','--scan-related', help='Run related scan, default is yes, Ex: -sr no',type=str, default='yes')
    parser.add_argument('-ss','--scan-subdomains', help='Run subdomains scan, default is yes, Ex: -ss no',type=str, default='yes')
    parser.add_argument('-sa','--scan-apps',    help='Run App scan, default is yes, Ex: -sa no',type=str, default='yes')
    parser.add_argument('-si','--scan-ips',     help='Run IPs scan, default is yes, Ex: -si no',type=str, default='yes')
    parser.add_argument('-sc','--scan-clients', help='Run clients scan, default is yes, Ex: -sc no',type=str, default='yes')
    parser.add_argument('-se','--scan-employees',help='Run employees scan, default is yes, Ex: -se no',type=str, default='yes')
    parser.add_argument('-o','--output',        help='filename to save the result', type=str,)
    parser.add_argument('-ot','--output-type',  help='output format default is "text".', choices=['text', 'json', 'csv'], type=str, default='text')
    parser.add_argument('-t','--timeout',       help='request timeout default is 360 sec.',type=int, default=360)
    parser.add_argument('-l','--limit',         help='limit results default is 10000.',type=int, default=10000)
    parser.add_argument('-nc','--no-color',     help='show result without color.',action='store_true')
    parser.add_argument('-lv','--list-view-type',help='list view type.',action='store_true')
    parser.add_argument('-lm','--list-methods',   help='list methods.',  action='store_true')
    parser.add_argument('--init',               help='set the api token.',type=str)

    parser.add_argument('-v','--version',         help='version.',action='store_true') 

    parser.epilog  = f'''
Examples:

    # Scan company by domain
    {Path(sys.argv[0]).name} example.com --scan

    # Search for target domain, you will see the result for only this "example.com" 
    {Path(sys.argv[0]).name} example.com 
    
    # Search in target and target subdomains
    {Path(sys.argv[0]).name} example.com --method domain.all

    # Search for target subdomains
    {Path(sys.argv[0]).name} example.com --view-type subdomain
        
    # Search for all creds in United States 
    {Path(sys.argv[0]).name} US --method cred.country

    # Search for related companies by domain
    {Path(sys.argv[0]).name} example.com --view-type related

    # search for target app id 
    {Path(sys.argv[0]).name} com.discord --method app.id 
    
    # search for target app domain 
    {Path(sys.argv[0]).name} discord.com --method app.domain
    
    # search for target app name 
    {Path(sys.argv[0]).name} Discord --method app.name
    
    # Search for ip asn
    {Path(sys.argv[0]).name} AS123 --method ip.asn

    # Search for cred username
    {Path(sys.argv[0]).name} someone --method cred.username

    # Search for cred password
    {Path(sys.argv[0]).name} example@123 --method cred.password

    # Search for url endpoint
    {Path(sys.argv[0]).name} /wp-login.php --method url.path

    # Search for ip
    {Path(sys.argv[0]).name} 1.1.1.1 --method ip

    # Search for cidr
    {Path(sys.argv[0]).name} xx.xx.xx.0/24 --method ip

    # Search for target creds by domain emsils
    {Path(sys.argv[0]).name} example.com --method cred.email.domain

    # Search for target email
    {Path(sys.argv[0]).name} someone@example.com --method cred.email  

    # search for multiple targets: 
    {Path(sys.argv[0]).name} targets.txt --method domain  --output example-creds.txt 
    '''

    argcomplete.autocomplete(parser)
    args = parser.parse_args()
    if args.list_view_type:
        for i in VIEW_TYPE_LIST:
            print(i)
        sys.exit(0)

    if args.list_methods:
        for i in _METHODS:
            print(i)
        sys.exit(0)

    if args.version:
        print(VERSION)
        sys.exit(0)

    if args.scan:
        root=Scan(options=args)
        root.proc()

    else:
        root=CLI(options=args)
        root.proc()


================================================
FILE: pychiasmodon.py
================================================
import re
import os 
import sys
import time
import requests
from yaspin import Spinner 

VERSION = "3.0.2"
_API_URL = 'http://chiasmodon.online/v2/api/beta'
_API_HEADERS = {'user-agent':'cli/python'}
_VIEW_TYPE = {
    'full':[
        'cred.username',
        'cred.phone',
        'cred.password',
        'cred.email',
        'cred.email.domain',
        'cred.country',
        'domain',
        'domain.all',
        
        'ip',
        'ip.asn',
        'ip.isp',
        'ip.org',
        'ip.port',
        'ip.country',
        'app.id',
        'app.name',
        'app.domain',
        'url.path',
        'url.port',
    ],
    'cred':[
        'cred.phone',
        'cred.username',
        'cred.password',
        'cred.email',
        'cred.email.domain',
        'cred.country',
        'domain',
        'domain.all',
        
        'ip',
        'ip.asn',
        'ip.isp',
        'ip.org',
        'ip.port',
        'ip.country',
        'app.id',
        'app.name',
        'app.domain',
        'url.path',
        'url.port',
    ],
    'url':[
        'cred.username',
        'cred.password',
        'cred.phone',
        'cred.email',
        'cred.email.domain',
        'cred.country',
        'domain',
        'domain.all',
        'ip',
        'ip.asn',
        'ip.isp',
        'ip.org',
        'ip.port',
        'ip.country',
        'url.path',
        'url.port',
    ],
    'email':[
        'cred.username',
        'cred.phone',
        'cred.password',
        'cred.country',
        'cred.email.domain',
        'domain',
        'domain.all',
        'ip',
        'ip.asn',
        'ip.isp',
        'ip.org',
        'ip.port',
        'ip.country',
        'app.id',
        'app.name',
        'app.domain',
        'url.path',
        'url.port',
    ],
    'phone':[
        'cred.username',
        'cred.email',
        'cred.email.domain',
        'domain',
        'domain.all',
        'ip',
        'ip.asn',
        'ip.isp',
        'ip.org',
        'ip.port',
        'ip.country',
        'app.id',
        'app.name',
        'app.domain',
        'url.path',
        'url.port',
        'cred.country',
    ],    
    'password':[
        'cred.username',
        'cred.phone',

        'cred.email',
        'cred.email.domain',
        'domain',
        'domain.all',
        'ip',
        'ip.asn',
        'ip.isp',
        'ip.org',
        'ip.port',
        'ip.country',
        'app.id',
        'app.name',
        'app.domain',
        'url.path',
        'url.port',
        'cred.country',
    ],
    'username': [
        'cred.phone',
        'cred.password',
        'domain',
        'domain.all',
        'ip',
        'ip.asn',
        'ip.isp',
        'ip.org',
        'ip.port',
        'ip.country',
        'app.id',
        'app.name',
        'app.domain',
        'url.path',
        'url.port',
        'cred.country',
    ],
    'app':[
        'cred.phone',
        'cred.username',
        'cred.password',
        'cred.email',
        'cred.email.domain',
        'cred.country', 
        'app.domain'
    ],
    'domain':[
        'cred.username',
        'cred.phone',
        'cred.password',
        'cred.email',
        'cred.email.domain',
        'cred.country',
        'domain',
        'domain.all',
        
        'ip',
        'ip.asn',
        'ip.isp',
        'ip.org',
        'ip.port',
        'ip.country',
        'app.id',
        'app.name',
        'app.domain',
        'url.path',
        'url.port',
    ],
    'ip':[
        'cred.username',
        'cred.phone',
        'cred.password',
        'cred.email',
        'cred.email.domain',
        'domain',
        'domain.all',
        'ip.asn',
        'ip.isp',
        'ip.org',
        'ip.port',
        'ip.country',
        'app.id',
        'app.name',
        'app.domain',
        'url.path',
        'url.port',
        'cred.country',
    ],
    'related':[
        'domain',
    ],
    'subdomain':[
        'domain'
    ]
}

_METHODS = [
    # cred
    'cred.username',         # Query like -> somone
    'cred.password',         # Query like -> lol@123
    'cred.email',            # Query like -> somone@example.com
    'cred.phone',            # Query line -> xxxxxxxx # without : + or - or  space or ) or (
    'cred.email.domain',     # Query like -> example.com
    'cred.country',          # Query like -> US 

    # domain
    'domain',           # Query like -> example.com
    'domain.all',       # Query like -> example.com

    # ip
    'ip',               # Query like -> 1.1.1.1
    'ip.asn',           # Query like -> as123
    'ip.isp',           # Query like -> "isp company"
    'ip.org',           # Query like -> "org name"
    'ip.port',          # Query like -> 22
    'ip.country',       # Query like -> US
    
    # app
    'app.id',           # Query like -> com.example
    'app.name',         # Query like -> Example
    'app.domain',       # Query like -> example.com
    
    # url
    'url.path',         # Query like -> "isp company"
    'url.port',         # Query like -> 8080
]

VIEW_TYPE_LIST = list(_VIEW_TYPE.keys())

class T:
    RED      = '\033[91m'
    GREEN    = '\033[92m'
    YELLOW   = '\033[93m'
    BLUE     = '\033[94m'
    MAGENTA  = '\033[95m'
    CYAN     = '\033[96m'
    RESET    = '\033[0m'


class Chiasmodon:
    def __init__(self, token=None, color=True, debug=True,conf_file=None,check_token=True) -> None:
        self.token                 = token
        self.conf_file             = conf_file
        self.debug                 = debug
        self.err :bool             = False 
        self.msg :str              = '' 
        self.__result:list[Result] = []
        self.scan_mode             = False

        if not color:
            T.RED      = ''
            T.GREEN    = ''
            T.YELLOW   = ''
            T.BLUE     = ''
            T.MAGENTA  = ''
            T.CYAN     = ''
            T.RESET    = ''
        
        if self.token and check_token:
            if self.__check_token():
                self.print(f'{T.GREEN}Set token successfully{T.RESET}')

            else:
                try:os.remove(conf_file)
                except:pass

                self.print(f'{T.RED}{self.msg}{T.RESET}')
                return

    def proc_all_domains(self,
                query,
                view_type,
                sort,
                timeout,
                limit,
                callback_view_result,
                yaspin,
                search_text,
                err_text) -> list:
        

        domains :list = self.__proc_query(
                query=query,
                method='domain',
                view_type='subdomain',
                sort=sort,
                timeout=timeout,
                limit=limit,
                callback_view_result=None,
                yaspin=None,
                search_text=search_text,
                err_text=err_text,
        )
        self.__result :list = []
        result :list = []
        
        domains = [i.domain for i in domains]
        if query not in domains:domains.append(query)

        for domain in domains:
            result.extend(self.__proc_query(
                query=domain,
                method='domain',
                view_type=view_type,
                sort=sort,
                timeout=timeout,
                limit=limit,
                callback_view_result=callback_view_result,
                yaspin=yaspin,
                search_text=search_text.replace(query, domain),
                err_text=err_text,
            ))
            self.__result :list = []
        
        return result

    
    def filter(self,query:str,method:str):

        if 'domain' in method:
            if not re.match(r"^(?!.*\d+\.\d+\.\d+\.\d+$)[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+$", query):
                self.print(f'{T.RED}Your format query is wrong!\nThis is not domain.{T.RESET}')
                return False

        elif method == 'ip':
            if not re.match(r"\b(?:\d{1,3}\.){3}\d{1,3}\b", query):
                self.print(f'{T.RED}Your format query is wrong!\nAccept only ipv4.{T.RESET}')
                return False
        
        elif method == 'ip.asn':
            if not query.lower().startswith('as'):
                self.print(f'{T.RED}Your format query is wrong!\nThe ASN starts with AS\nLike this: AS1234.{T.RESET}')
                return False
        
        elif method in ['ip.port', 'url.port']:
            if not re.match(r":(\d+)", query):
                self.print(f'{T.RED}Your format query is wrong!\nThis is not port.{T.RESET}')
                return False
        
        elif method == 'cred.email':
            if not re.match(r'^[\w\.-]+@[\w\.-]+\.\w+$', query):
                self.print(f'{T.RED}Your format query is wrong!\nThis is not email.{T.RESET}')
                return False
        
        elif method == 'cred.country' or method == 'ip.country':
            if not len(query) == 2:
                self.print(f'{T.RED}Your format query is wrong!\nAccept only country code.{T.RESET}')
                return False
        
        elif method == 'url.path':
            if not query[0] == '/':
                self.print(f'{T.RED}Your format query is wrong!\nThe url path moset be like: /somthing{T.RESET}')
                return False
        
        return query

    def print(self,text, ys=None, ys_err=False) -> None:
        if text == None:return 
        if self.debug:
            if ys:
                if not ys_err:
                    ys.write(text)
                else:
                    ys.text = text
            else:
                print(text)

    def __check_token(self):
        if self.__request({
            'token'     : self.token,
            'version'   : VERSION,
            'method'    : 'token'
        }).get('is_active'):
            return True 

        return False 

    def __request(self, data:dict,timeout=60):

        try:
            resp = requests.post(_API_URL, data=data, headers=_API_HEADERS, timeout=timeout)
            resp.close()
            resp = resp.json()

            try:
                if resp.get('err'):
                    self.err = True 
                    self.msg = resp['msg']
            except:pass

            return resp

        except requests.exceptions.ReadTimeout:
            self.print(f"{T.RED}\nError: timeout !\nPlease try agine later.{T.RESET}")
            sys.exit()

        except requests.exceptions.InvalidJSONError:
            self.print(f"{T.RED}\nError: Server send wrong data.\nPlease try agine later.{T.RESET}")
            sys.exit()

        except Exception as e:
            self.print(f"{T.RED}\nRequest error: {e}\nPlease try agine later.{T.RESET}")
            sys.exit()


    def __proc_query(self, 
                    method:str, 
                    query:str, 
                    view_type:str, 
                    timeout:int,
                    sort:bool, 
                    limit:int,
                    yaspin:bool,
                    callback_view_result,
                    search_text='',
                    err_text=''
                    ) -> dict:
        Result.VIEW_TYPE = view_type

        result : list[Result] = []

        data = {

            'token'         :       self.token,
            'type-view'     :       view_type,
            'method'        :       method,
            'version'       :       VERSION,
            'query'         :       query,
            'get-info'      :       'yes'
        }

        if yaspin:
            with yaspin(Spinner(["🐟","🐠","🐡","🐬","🐋","🐳","🦈","🐙","🐚","🪼","🪸"], 200),text=f"Processing {query} ..." if not search_text else search_text) as sp:
                process_info = self.__request(
                    data=data,
                    timeout=timeout,
                )

            if process_info and process_info.get('count') == 0:
                if not err_text:
                    self.print(f"{T.RED}Not found result{T.RESET}", sp,ys_err=True)
                else:
                    self.print(f"{T.RED}{err_text}{T.RESET}", sp,ys_err=True)
                        

                sp.fail("💥 ")
                sp.stop()
                return result 

            else:
                sp.ok("⚓ ")

        else:
            process_info = self.__request(
                data=data,
                timeout=timeout,
            )
            if process_info and process_info.get('count') == 0:
                self.print(f"{T.RED}Not found result{T.RESET}")
                return result
            
        
        del data['get-info'] 

        if self.err:
            self.err= False
            self.print(f'{T.RED}Error: {self.msg}{T.RESET}',ys_err=True) 
            return
            
        if yaspin: 
            self.print(f"{T.YELLOW}Pages count{T.YELLOW}: {T.GREEN}{process_info['pages'] if process_info['count'] != -1 else 'unknown'}{T.RESET}")

        data['sid'] = process_info['sid']

        if yaspin:
            YS = yaspin(f'Get pages 0/{process_info["pages"]}').green.bold.shark #.on_black
            YS.start()

        else:
            YS = None
        
        for p in range(1, process_info['pages']+0x1):
            if yaspin:YS.text = f'Get pages {p}/{process_info["pages"]}'
            
            data['page'] = p

            beta_result = self.__request(
                data=data,
                timeout=timeout,
            )

            if self.err:
                self.err=False
                if yaspin:self.print(f"{T.RED}{self.msg}{T.RESET}", YS, ys_err=True);YS.fail("💥 ");YS.stop()
                return result

            for r in beta_result['data']:
                
                column :Result = Result(**r)

                if sort and column in self.__result:
                    continue
                
                if callback_view_result != None:
                    callback_view_result(beta=column, ys=YS)

                result.append(column)
                self.__result.append(column)

                if len(result) == limit:
                    if yaspin:YS.text='';YS.stop()
                    return result
                
            if beta_result['done']:
                if yaspin:YS.text='';YS.stop()
                return result

            time.sleep(0x1)

        if not result:
            if yaspin:self.print(f"{T.RED}Not found result{T.RESET}", YS,ys_err=True);YS.fail("💥 ");YS.stop()
            else:self.print(f"{T.RED}Not found result{T.RESET}")
        else:
            if yaspin:YS.text='';YS.stop()
        return result
    
    def search(self,
               query,
               method='domain',
               view_type='full',
               limit=10000,
               timeout=60,
               sort=True,
               yaspin=False,
               search_text='',
               err_text='',
               callback_view_result=None) -> dict:
        
        
        if method not in _METHODS:
            raise Exception(f"{T.RED}not found this method: {method}.{T.RESET}")
        
        if method not in _VIEW_TYPE[view_type]:
            raise Exception(f"{T.RED}{view_type} doesn't support ({method}).{T.RESET}")
        
        
        self.err = False
        self.msg = ''
        result = None

        query = self.filter(query, method)
        if query == False:
            return

        if method == "domain.all":
            result = self.proc_all_domains(
                query=query,
                view_type=view_type,
                sort=sort,
                timeout=timeout,
                limit=limit,
                callback_view_result=callback_view_result,
                yaspin=yaspin,
                search_text=search_text,
                err_text=err_text,
            )

        else:

            result = self.__proc_query(
                query=query,
                method=method,
                view_type=view_type,
                sort=sort,
                timeout=timeout,
                limit=limit,
                callback_view_result=callback_view_result,
                yaspin=yaspin,
                search_text=search_text,
                err_text=err_text,
            )

        self.__result:list = []

        return result

class Result(dict):
    VIEW_TYPE = None
    HID_PASS  = True if os.environ.get('HID_PASS') else False 
    def __init__(self,type,**kwargs) -> None:
        
        self.kwargs         = kwargs
        Type           = type 

        self.url            = None
        self.urlPort        = None
        self.urlPath        = None
        self.credEmail      = None
        self.credUsername   = None
        self.credPassword   = None
        self.credCountry    = None
        self.credDate       = None 
        self.credPhone      = None 
        self.domain         = None 
        self.ip             = None 
        self.ipAsn          = None
        self.ipIsp          = None
        self.ipOrg          = None
        self.ipPorts        = None
        self.ipCountry      = None
        self.appID          = None
        self.appName        = None 
        self.appIcon        = None 
        self.appDomain      = None 

        if Type == "login":
            if kwargs.get('url'):
                self.urlPath = kwargs['url']['path']
                self.urlPort = kwargs['url']['port']
                self.url    = self.__convert_url(kwargs['url'])
                
                if kwargs['url']['ip']:
                    self.__convert_and_set_ip(kwargs['url']['ip'])

                elif kwargs['url']['domain']:
                    self.domain = self.__convert_domain(kwargs['url']['domain'])    
                

            if kwargs.get('app'):
                self.appID   = kwargs['app']['id']
                self.appName = kwargs['app']['name']
                self.appIcon = kwargs['app']['icon']
                if kwargs['app']['domain']:
                    self.appDomain = self.__convert_domain(kwargs['app']['domain'])

            if kwargs.get('cred'):
                if kwargs['cred']['email']:
                    self.credEmail = self.__convert_email(kwargs['cred']['email'])

                self.credUsername = kwargs['cred']['username']
                self.credPassword = kwargs['cred']['password'] if not self.HID_PASS else '*'*len(kwargs['cred']['password']) 
                if kwargs['cred']['phone']:
                    self.credPhone = self.__convert_phone(kwargs['cred']['phone'])


            if kwargs.get('country'):
                self.credCountry = kwargs['country']['f']
            
            self.credDate = kwargs['date']

        elif Type == 'url':
            self.urlPath = kwargs['path']
            self.urlPort = kwargs['port']
            self.url = self.__convert_url(kwargs)

            if kwargs['ip']:
                self.url    = self.__convert_url(kwargs)
                self.__convert_and_set_ip(kwargs['ip'])

            elif kwargs['domain']:
                self.domain = self.__convert_domain(kwargs['domain'])    

        elif Type == "email":
            self.credEmail = self.__convert_email(kwargs)
        
        elif Type == "domain":
            self.domain = self.__convert_domain(kwargs)

        elif Type == 'app':
            self.appID = kwargs['id']
            self.appName = kwargs['name']
            self.appIcon = kwargs['icon']

            if kwargs['domain']:
                self.domain = self.__convert_domain(kwargs['domain'])    


        elif Type == 'ip':
            self.__convert_and_set_ip(kwargs)
    
    def __convert_phone(self,phone):
        return f"+{phone['country']['p']} {phone['number']}"

    def __convert_email(self,email):
        return f"{email['name']}@{self.__convert_domain(email['domain'])}"

    def __convert_and_set_ip(self,ip):
        self.ip         = ip['ip']
        self.ipAsn      = ip['asn']
        self.ipOrg      = ip['org']
        self.ipIsp      = ip['isp']
        self.ipPorts    = ip['ports']
        self.ipCountry  = ip['country']['f'] if ip['country'] else None

    def __convert_url(self,url:dict):
        if url['domain']:
            return f"{url['proto']}://{self.__convert_domain(url['domain'])}:{url['port']}{url['path']}" 
        elif url['ip']:
            return f"{url['proto']}://{url['ip']['ip']}:{url['port']}{url['path']}" 

        
        return None 

    def __convert_domain(self,domain:dict):
        return f"{(domain['sub']+'.') if domain['sub'] else ''}{domain['name']}{('.'+domain['suffix']) if domain['suffix']  else ''}"


    def __str__(self) -> str:
        return self.save_format()

    def __radd__(self, other):
        if isinstance(other, str):
            return   other + self.save_format() 
        else:
            return NotImplemented

    def __add__(self, other):
        if isinstance(other, str):
            return self.save_format() + other
        else:
            return NotImplemented
          
    def __getattr__(self, key):
        if key in self:
            return self[key]
        else:
            raise AttributeError(f"'Result' object has no attribute '{key}'")

    def __setattr__(self, key, value):
        self[key] = value
        
    
    def print(self,):
        c=""

        if self.VIEW_TYPE == "email" and self.credEmail:
            c+=f"{T.MAGENTA}[ {T.YELLOW}Email{T.MAGENTA} ]{T.MAGENTA}> {T.CYAN}{self.credEmail}{T.RESET}"

        if self.VIEW_TYPE == "password" and self.credPassword:
            c+=f"{T.MAGENTA}[ {T.YELLOW}Email{T.MAGENTA} ]{T.MAGENTA}> {T.CYAN}{self.credPassword}{T.RESET}"

        if self.VIEW_TYPE == "username" and self.credUsername:
            c+=f"{T.MAGENTA}[ {T.YELLOW}Email{T.MAGENTA} ]{T.MAGENTA}> {T.CYAN}{self.credUsername}{T.RESET}"
        
        if self.VIEW_TYPE == "app" and self.appID:
            if self.appID:c+=f"{T.MAGENTA}[ {T.YELLOW}APP{T.MAGENTA} ]{T.RED}{T.MAGENTA}>  {T.CYAN}{self.appID}{T.RESET}\n"
            if self.appName:c+=f"{T.MAGENTA}[ {T.YELLOW}APP{T.MAGENTA} ]{T.RED}{T.MAGENTA}> {T.RED} Name{T.RESET}{' ':10}: {T.CYAN}{self.appName}{T.RESET}\n"
            if self.appIcon:c+=f"{T.MAGENTA}[ {T.YELLOW}APP{T.MAGENTA} ]{T.RED}{T.MAGENTA}> {T.RED} Icon{T.RESET}{' ':10}: {T.CYAN}{self.appIcon}{T.RESET}\n"
            if self.appDomain:c+=f"{T.MAGENTA}[ {T.YELLOW}APP{T.MAGENTA} ]{T.MAGENTA}> {T.RED} Domain{T.RESET}{' ':8}: {T.CYAN}{self.appDomain}{T.RESET}\n"
            
        if self.VIEW_TYPE == "url" and self.url:
            if self.url:c+=f"{T.MAGENTA}[ {T.YELLOW}URL{T.MAGENTA}  ]{T.MAGENTA}>  {T.CYAN}{self.url}{T.RESET}\n"
            if self.urlPath:c+=f"{T.MAGENTA}[ {T.YELLOW}URL{T.MAGENTA}  ]{T.MAGENTA}> {T.RED} Path{T.RESET}{' ':10}: {T.CYAN}{self.urlPath}{T.RESET}\n"
            if self.urlPort:c+=f"{T.MAGENTA}[ {T.YELLOW}URL{T.MAGENTA}  ]{T.MAGENTA}> {T.RED} Port{T.RESET}{' ':10}: {T.CYAN}{self.urlPort}{T.RESET}\n"

        if self.VIEW_TYPE == "ip" and self.ip:
            if self.ip:c+=f"{T.MAGENTA}[ {T.YELLOW}IP{T.MAGENTA} ]{T.MAGENTA}>  {T.BLUE}{self.ip}{T.RESET}\n"
            if self.ipPorts:c+=f"{T.MAGENTA}[ {T.YELLOW}IP{T.MAGENTA} ]{T.RED}{T.MAGENTA}> {T.RED} Ports{T.RESET}{' ':9}: {T.CYAN}{self.ipPorts}{T.RESET}\n"
            if self.ipAsn:c+=f"{T.MAGENTA}[ {T.YELLOW}IP{T.MAGENTA} ]{T.RED}{T.MAGENTA}> {T.RED} Asn{T.RESET}{' ':11}: {T.CYAN}{self.ipAsn}{T.RESET}\n"
            if self.ipIsp:c+=f"{T.MAGENTA}[ {T.YELLOW}IP{T.MAGENTA} ]{T.RED}{T.MAGENTA}> {T.RED} Isp{T.RESET}{' ':11}: {T.CYAN}{self.ipIsp}{T.RESET}\n"
            if self.ipOrg:c+=f"{T.MAGENTA}[ {T.YELLOW}IP{T.MAGENTA} ]{T.RED}{T.MAGENTA}> {T.RED} Org{T.RESET}{' ':11}: {T.CYAN}{self.ipOrg}{T.RESET}\n"
            if self.ipCountry:c+=f"{T.MAGENTA}[ {T.YELLOW}IP{T.MAGENTA} ]{T.MAGENTA}>{T.RED}  Country{T.RESET}{' ':7}: {T.CYAN}{self.ipCountry}{T.RESET}\n"

        if self.VIEW_TYPE in ["domain", 'subdomain', 'related'] and self.domain:
            c+=f"{T.MAGENTA}[ {T.YELLOW}Domain{T.MAGENTA} ]{T.MAGENTA}> {T.CYAN}{self.domain}{T.RESET}"

        if self.VIEW_TYPE == "phone" and self.credPhone:
            return f"{T.MAGENTA}> {T.CYAN}{self.credPhone}{T.RESET}"

        if self.VIEW_TYPE == "cred":
            if self.url:c+=f"{T.MAGENTA}[ {T.YELLOW}URL{T.MAGENTA}  ]{T.MAGENTA}>  {T.BLUE}{self.url}{T.RESET}\n"
            if self.appID:c+=f"{T.MAGENTA}[ {T.YELLOW}APP{T.MAGENTA}  ]{T.RED}{T.MAGENTA}>  {T.CYAN}{self.appID}{T.RESET}\n"
            if self.credEmail:c+=f"{T.MAGENTA}[ {T.YELLOW}CRED{T.MAGENTA} ]{T.MAGENTA}> {T.RED} Email{T.RESET}{' ':9}: {T.GREEN}{self.credEmail}{T.RESET}\n"
            if self.credUsername and not self.credEmail:c+=f"{T.MAGENTA}[ {T.YELLOW}CRED{T.MAGENTA} ]{T.MAGENTA}> {T.RED} Username{T.RESET}{' ':6}: {T.GREEN}{self.credUsername}{T.RESET}\n"
            if self.credPassword:c+=f"{T.MAGENTA}[ {T.YELLOW}CRED{T.MAGENTA} ]{T.MAGENTA}> {T.RED} Password{T.RESET}{' ':6}: {T.GREEN}{self.credPassword}{T.RESET}\n"
            if self.credPhone:c+=f"{T.MAGENTA}[ {T.YELLOW}CRED{T.MAGENTA} ]{T.MAGENTA}> {T.RED} Phone{T.RESET}{' ':9}: {T.GREEN}{self.credPhone}{T.RESET}\n"
            if self.credCountry:c+=f"{T.MAGENTA}[ {T.YELLOW}CRED{T.MAGENTA} ]{T.MAGENTA}>{T.RED}  Country{T.RESET}{' ':7}: {T.CYAN}{self.credCountry}{T.RESET}\n"

        if self.VIEW_TYPE == "full":
            if self.url:c+=f"{T.MAGENTA}[ {T.YELLOW}URL{T.MAGENTA}  ]{T.MAGENTA}>  {T.BLUE}{self.url}{T.RESET}\n"
            if self.urlPath and self.urlPath != '/':c+=f"{T.MAGENTA}[ {T.YELLOW}URL{T.MAGENTA}  ]{T.MAGENTA}> {T.RED} Path{T.RESET}{' ':10}: {T.CYAN}{self.urlPath}{T.RESET}\n"
            if self.urlPort and self.urlPort not in [80, 443]:c+=f"{T.MAGENTA}[ {T.YELLOW}URL{T.MAGENTA}  ]{T.MAGENTA}> {T.RED} Port{T.RESET}{' ':10}: {T.CYAN}{self.urlPort}{T.RESET}\n"
            if self.ip:c+=f"{T.MAGENTA}[ {T.YELLOW}IP{T.MAGENTA}   ]{T.MAGENTA}>  {T.BLUE}{self.ip}{T.RESET}\n"
            if self.ipPorts:c+=f"{T.MAGENTA}[ {T.YELLOW}IP{T.MAGENTA}   ]{T.RED}{T.MAGENTA}> {T.RED} Ports{T.RESET}{' ':9}: {T.CYAN}{self.ipPorts}{T.RESET}\n"
            if self.ipAsn:c+=f"{T.MAGENTA}[ {T.YELLOW}IP{T.MAGENTA}   ]{T.RED}{T.MAGENTA}> {T.RED} Asn{T.RESET}{' ':11}: {T.CYAN}{self.ipAsn}{T.RESET}\n"
            if self.ipIsp:c+=f"{T.MAGENTA}[ {T.YELLOW}IP{T.MAGENTA}   ]{T.RED}{T.MAGENTA}> {T.RED} Isp{T.RESET}{' ':11}: {T.CYAN}{self.ipIsp}{T.RESET}\n"
            if self.ipOrg:c+=f"{T.MAGENTA}[ {T.YELLOW}IP{T.MAGENTA}   ]{T.RED}{T.MAGENTA}> {T.RED} Org{T.RESET}{' ':11}: {T.CYAN}{self.ipOrg}{T.RESET}\n"
            if self.ipCountry:c+=f"{T.MAGENTA}[ {T.YELLOW}IP{T.MAGENTA}   ]{T.MAGENTA}>{T.RED}  Country{T.RESET}{' ':7}: {T.CYAN}{self.ipCountry}{T.RESET}\n"
            
            if self.appID:c+=f"{T.MAGENTA}[ {T.YELLOW}APP{T.MAGENTA}  ]{T.RED}{T.MAGENTA}>  {T.CYAN}{self.appID}{T.RESET}\n"
            if self.appName:c+=f"{T.MAGENTA}[ {T.YELLOW}APP{T.MAGENTA}  ]{T.RED}{T.MAGENTA}> {T.RED} Name{T.RESET}{' ':10}: {T.CYAN}{self.appName}{T.RESET}\n"
            if self.appIcon:c+=f"{T.MAGENTA}[ {T.YELLOW}APP{T.MAGENTA}  ]{T.RED}{T.MAGENTA}> {T.RED} Icon{T.RESET}{' ':10}: {T.CYAN}{self.appIcon}{T.RESET}\n"
            if self.appDomain:c+=f"{T.MAGENTA}[ {T.YELLOW}APP{T.MAGENTA}  ]{T.MAGENTA}> {T.RED} Domain{T.RESET}{' ':8}: {T.CYAN}{self.appDomain}{T.RESET}\n"
            
            if self.credEmail:c+=f"{T.MAGENTA}[ {T.YELLOW}CRED{T.MAGENTA} ]{T.MAGENTA}> {T.RED} Email{T.RESET}{' ':9}: {T.GREEN}{self.credEmail}{T.RESET}\n"
            if self.credUsername and not self.credEmail:c+=f"{T.MAGENTA}[ {T.YELLOW}CRED{T.MAGENTA} ]{T.MAGENTA}> {T.RED} Username{T.RESET}{' ':6}: {T.GREEN}{self.credUsername}{T.RESET}\n"
            if self.credPassword:c+=f"{T.MAGENTA}[ {T.YELLOW}CRED{T.MAGENTA} ]{T.MAGENTA}> {T.RED} Password{T.RESET}{' ':6}: {T.GREEN}{self.credPassword}{T.RESET}\n"
            if self.credPhone:c+=f"{T.MAGENTA}[ {T.YELLOW}CRED{T.MAGENTA} ]{T.MAGENTA}> {T.RED} Phone{T.RESET}{' ':9}: {T.GREEN}{self.credPhone}{T.RESET}\n"
            if self.credCountry:c+=f"{T.MAGENTA}[ {T.YELLOW}CRED{T.MAGENTA} ]{T.MAGENTA}>{T.RED}  Country{T.RESET}{' ':7}: {T.CYAN}{self.credCountry}{T.RESET}\n"

        return c            

    def save_format(self):
        result = []
        if self.VIEW_TYPE in ['cred', 'full']:
            # 1 
            if self.url:
                result.append(self.url)
            elif self.appID:
                result.append(self.appID)
            else:
                result.append('')

            # 2
            if self.credUsername:
                result.append(self.credUsername)
            elif self.credEmail:
                result.append(self.credEmail)
            else:
                result.append('')
            
            # 3 
            if self.credPassword:
                result.append(self.credPassword)
            else:
                result.append('')
            
            # 4 
            if self.credCountry:
                result.append(self.credCountry)
            else:
                result.append('')
            
            # 5
            #if self.credDate:
            #    result.append(self.credDate)
            #else:
            #    result.append('')

            return result

        elif self.VIEW_TYPE in ['subdomain', 'related', 'domain']:
            return self.domain
        
        elif self.VIEW_TYPE == 'email':
            return self.credEmail

        elif self.VIEW_TYPE == 'phone':
            return self.credPhone

        elif self.VIEW_TYPE == 'username':
            return self.credUsername
        
        elif self.VIEW_TYPE == 'password':
            return self.credPassword
        
        
        elif self.VIEW_TYPE == 'ip':
            return self.ip
        
        elif self.VIEW_TYPE == 'app':
            return self.appID

        elif self.VIEW_TYPE == 'url':
            return self.url
        else:
            return 'null'


================================================
FILE: requirements.txt
================================================
tldextract==5.1.2
yaspin==3.0.1
argcomplete==3.3.0
requests==2.31.0

================================================
FILE: setup.py
================================================
#!/usr/bin/python3
from distutils.core import setup
from os import path
here = path.abspath(path.dirname(__file__))
with open(path.join(here, 'README.md'), encoding='utf-8') as f:
    long_description = f.read()

setup(name='chiasmodon',
      version='3.0.2',
      description='Chiasmodon is an OSINT tool that allows users to gather information from various sources and conduct targeted searches based on domains, Google Play applications, email addresses, IP addresses, organizations, URLs, and more. It provides comprehensive scanning capabilities, customizable output formats, and additional options for enhanced data analysis and customization.',
      long_description=long_description,
      long_description_content_type='text/markdown',
      author='chiasmod0n',
      keywords='intelligence osint credentials emails asn cidr bugbounty subdomains information-gathering intelligence-analysis reconnaissance attack-surface subdomain-enumeration reconnaissance-framework bugbounty-tool email-enumeration chiasmodon',
      url='https://github.com/chiasmod0n/chiasmodon',
      packages=['.'],
      scripts=['cli/chiasmodon_cli.py'],
      install_requires=['requests', 'yaspin', 'tldextract','argcomplete']
    ) 
Download .txt
gitextract_3q7hvgfq/

├── Dockerfile
├── LICENSE.txt
├── README.md
├── cli/
│   └── chiasmodon_cli.py
├── pychiasmodon.py
├── requirements.txt
└── setup.py
Download .txt
SYMBOL INDEX (40 symbols across 2 files)

FILE: cli/chiasmodon_cli.py
  class ULIT (line 16) | class ULIT:
    method rFile (line 18) | def rFile(file:Path) -> str:
    method wFile (line 27) | def wFile(file:Path, data:str) -> str:
    method rFileToJson (line 32) | def rFileToJson(file:Path) -> dict:
    method wJsonToFile (line 36) | def wJsonToFile(file:Path, data:dict) -> dict:
    method get_root_domain (line 43) | def get_root_domain(d:str) -> str:
  class Scan (line 51) | class Scan(Chiasmodon):
    method __init__ (line 52) | def __init__(self, options:argparse.Namespace) -> None:
    method scan_callback (line 84) | def scan_callback(self,beta,ys):
    method proc (line 87) | def proc(self):
    method __scan (line 105) | def __scan(self, domain):
  class CLI (line 299) | class CLI(Chiasmodon):
    method __init__ (line 300) | def __init__(self, options:argparse.Namespace) -> None:
    method review_results (line 333) | def review_results(self,
    method save_result (line 342) | def save_result(self, view_type) -> None:
    method proc (line 371) | def proc(self):

FILE: pychiasmodon.py
  class T (line 244) | class T:
  class Chiasmodon (line 254) | class Chiasmodon:
    method __init__ (line 255) | def __init__(self, token=None, color=True, debug=True,conf_file=None,c...
    method proc_all_domains (line 284) | def proc_all_domains(self,
    method filter (line 332) | def filter(self,query:str,method:str):
    method print (line 371) | def print(self,text, ys=None, ys_err=False) -> None:
    method __check_token (line 382) | def __check_token(self):
    method __request (line 392) | def __request(self, data:dict,timeout=60):
    method __proc_query (line 420) | def __proc_query(self,
    method search (line 541) | def search(self,
  class Result (line 601) | class Result(dict):
    method __init__ (line 604) | def __init__(self,type,**kwargs) -> None:
    method __convert_phone (line 695) | def __convert_phone(self,phone):
    method __convert_email (line 698) | def __convert_email(self,email):
    method __convert_and_set_ip (line 701) | def __convert_and_set_ip(self,ip):
    method __convert_url (line 709) | def __convert_url(self,url:dict):
    method __convert_domain (line 718) | def __convert_domain(self,domain:dict):
    method __str__ (line 722) | def __str__(self) -> str:
    method __radd__ (line 725) | def __radd__(self, other):
    method __add__ (line 731) | def __add__(self, other):
    method __getattr__ (line 737) | def __getattr__(self, key):
    method __setattr__ (line 743) | def __setattr__(self, key, value):
    method print (line 747) | def print(self,):
    method save_format (line 817) | def save_format(self):
Condensed preview — 7 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (71K chars).
[
  {
    "path": "Dockerfile",
    "chars": 112,
    "preview": "FROM python:3.11-alpine\n\nCOPY . .\nRUN python setup.py install\n\nENTRYPOINT [ \"python3\",\"/cli/chiasmodon_cli.py\" ]"
  },
  {
    "path": "LICENSE.txt",
    "chars": 1053,
    "preview": "MIT License\r\n\r\nPermission is hereby granted, free of charge, to any person obtaining a copy\r\nof this software and associ"
  },
  {
    "path": "README.md",
    "chars": 11473,
    "preview": "\r\n# Chiasmodon\r\n\r\n[![asciicast](https://asciinema.org/a/QrEtBLFMQrjU1sjRjcgTdo41m.svg)](https://asciinema.org/a/QrEtBLFM"
  },
  {
    "path": "cli/chiasmodon_cli.py",
    "chars": 22127,
    "preview": "#!/usr/bin/python3\n# PYTHON_ARGCOMPLETE_OK\n\nimport os\nimport sys\nimport argcomplete\nimport json\nimport argparse\nimport t"
  },
  {
    "path": "pychiasmodon.py",
    "chars": 30914,
    "preview": "import re\r\nimport os \r\nimport sys\r\nimport time\r\nimport requests\r\nfrom yaspin import Spinner \r\n\r\nVERSION = \"3.0.2\"\r\n_API_"
  },
  {
    "path": "requirements.txt",
    "chars": 70,
    "preview": "tldextract==5.1.2\r\nyaspin==3.0.1\r\nargcomplete==3.3.0\r\nrequests==2.31.0"
  },
  {
    "path": "setup.py",
    "chars": 1243,
    "preview": "#!/usr/bin/python3\r\nfrom distutils.core import setup\r\nfrom os import path\r\nhere = path.abspath(path.dirname(__file__))\r\n"
  }
]

About this extraction

This page contains the full source code of the chiasmod0n/chiasmodon GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 7 files (65.4 KB), approximately 16.9k tokens, and a symbol index with 40 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!