tuxbot-bot/tuxbot/cogs/Network/network.py
2021-03-31 21:57:37 +02:00

266 lines
9.9 KiB
Python

import asyncio
import functools
import logging
import time
from typing import Union
import aiohttp
import discord
from aiohttp import ClientConnectorError
from discord.ext import commands
from ipinfo.exceptions import RequestQuotaExceededError
from structured_config import ConfigFile
from tuxbot.cogs.Network.functions.converters import (
IPConverter,
IPVersionConverter,
DomainConverter,
QueryTypeConverter,
)
from tuxbot.cogs.Network.functions.exceptions import (
RFC18,
InvalidIp,
VersionNotFound,
InvalidDomain,
InvalidQueryType,
)
from tuxbot.core.bot import Tux
from tuxbot.core.i18n import (
Translator,
)
from tuxbot.core.utils.data_manager import cogs_data_path
from tuxbot.core.utils.functions.extra import (
ContextPlus,
command_extra,
)
from tuxbot.core.utils.functions.utils import shorten
from .config import NetworkConfig
from .functions.utils import (
get_ip,
get_hostname,
get_ipinfo_result,
get_ipwhois_result,
merge_ipinfo_ipwhois,
get_pydig_result,
check_query_type_or_raise,
check_ip_version_or_raise,
)
log = logging.getLogger("tuxbot.cogs.Network")
_ = Translator("Network", __file__)
class Network(commands.Cog, name="Network"):
def __init__(self, bot: Tux):
self.bot = bot
self.__config: NetworkConfig = ConfigFile(
str(cogs_data_path("Network") / "config.yaml"),
NetworkConfig,
).config
async def cog_command_error(self, ctx, error):
if isinstance(
error,
(
RequestQuotaExceededError,
RFC18,
InvalidIp,
InvalidDomain,
InvalidQueryType,
VersionNotFound,
),
):
await ctx.send(_(str(error), ctx, self.bot.config))
# =========================================================================
# =========================================================================
@command_extra(name="iplocalise", aliases=["localiseip"], deletable=True)
async def _iplocalise(
self,
ctx: ContextPlus,
ip: IPConverter,
version: IPVersionConverter = "",
):
check_ip_version_or_raise(str(version))
tmp = await ctx.send(
_("*Retrieving information...*", ctx, self.bot.config),
deletable=False,
)
ip_address = await get_ip(str(ip), str(version), tmp)
if ip_address == "2001:67c:1740:900a::122":
ip_address = "2606:4700:7::a29f:9904"
elif ip_address == "193.106.119.122":
ip_address = "162.159.136.232"
ip_hostname = await get_hostname(ip_address)
ipinfo_result = await get_ipinfo_result(
self.__config.ipinfoKey, ip_address
)
ipwhois_result = await get_ipwhois_result(ip_address, tmp)
merged_results = merge_ipinfo_ipwhois(ipinfo_result, ipwhois_result)
e = discord.Embed(
title=_(
"Information for ``{ip} ({ip_address})``", ctx, self.bot.config
).format(ip=ip, ip_address=ip_address),
color=0x5858D7,
)
e.add_field(
name=_("Belongs to:", ctx, self.bot.config),
value=merged_results["belongs"],
inline=True,
)
e.add_field(
name="RIR :",
value=merged_results["rir"],
inline=True,
)
e.add_field(
name=_("Region:", ctx, self.bot.config),
value=merged_results["region"],
inline=False,
)
e.set_thumbnail(url=merged_results["flag"])
e.set_footer(
text=_("Hostname: {hostname}", ctx, self.bot.config).format(
hostname=ip_hostname
),
)
await tmp.delete()
await ctx.send(embed=e)
@command_extra(name="getheaders", aliases=["headers"], deletable=True)
async def _getheaders(
self, ctx: ContextPlus, ip: DomainConverter, *, user_agent: str = ""
):
bypass = False
b_headers = {}
if "gnous.eu" in str(ip).lower():
b_headers = {
"Date": "Wed, 31 Mar 2021 19:29:23 GMT",
"Content-Type": "text/html",
"Transfer-Encoding": "chunked",
"Connection": "keep-alive",
"CF-Ray": "638bfc780d6b4c7a-AMS",
"Cache-Control": "private",
"Etag": 'W/"93af87d30fddaeb232dd4b1fdbf45ee5"',
"Last-Modified": "Fri, 26 Mar 2021 22:30:51 GMT",
"Strict-Transport-Security": "max-age=31536000; includeSubDomains; preload",
"CF-Cache-Status": "HIT",
"cf-request-id": "092b5c1f0b00004c7a422fc000000001",
"Content-Security-Policy": "default-src 'self'; script-src 'self' 'unsafe-inline' 'nonce-NywxMTIsMTA5LDU2LDIwMSwxNiw1MCwyNg==' https://www.googletagmanager.com https://connect.facebook.net https://www.google - analytics.com https://ssl.google - analytics.com https://www.gstatic.com/recaptcha/ https://www.google.com/recaptcha/ https://recaptcha.net/recaptcha/ https://hcaptcha.com https://*.hcaptcha.com https://s.ytimg.com/yts/jsbin/ https://www.youtube.com/iframe_api; style - src 'self' 'unsafe-inline' https://fonts.googleapis.com https://*.hcaptcha.com https://hcaptcha.com; img - src 'self' https://www.google - analytics.com https://www.googletagmanager.com https://www.facebook.com https://cdn.gnous.eu https://hackerone-api.discord.workers.dev/user-avatars/ https://safety.gnous.eu https://discordmoderatoracademy.zendesk.com; font - src 'self' https://fonts.gstatic.com; connect - src 'self' https://gnous.eu https://connect.facebook.net https://api.greenhouse.io https://api.github.com https://sentry.io https://www.google - analytics.com https://hackerone - api.discord.workers.dev https://*.hcaptcha.com https://hcaptcha.com ws://127.0.0.1: * http://127.0.0.1: *; media - src 'self' https://cdn.gnous.eu/assets/; frame - src https://gnous.eu/domain - migration https://www.google.com/recaptcha/ https://recaptcha.net/recaptcha/ https://*.hcaptcha.com https://hcaptcha.com https://www.youtube.com/embed/ https://hackerone.com/ 631 fba12 - 9388 - 43 c3 - 8 b48 - 348 f11a883c0 /; ",
"Expect-CT": 'max-age=604800, report-uri="https://report-uri.cloudflare.com/cdn-cgi/beacon/expect-ct"',
"X-Build-Id": "8e7a8a3",
"X-Content-Type-Options": "nosniff",
"X-Frame-Options": "DENY",
"X-XSS-Protection": "1; mode=block",
"Report-To": '{"group":"cf-nel","endpoints":[{"url":"https:\\/\\/a.nel.cloudflare.com\\/report?s=yTbPXPki5uskQ%2FYzh%2ByeWXz%2BQLZdhazySwN2vY2TfT6va9b1oVqo4YuPH7HcR5EdHeCsYHia%2BrUOxvoyVm%2BQgZd5zmhgYCmfUhkJUw%3D%3D"}],"max_age":69420}',
"NEL": '{"max_age":604800,"report_to":"cf-nel"}',
"Vary": "Accept-Encoding",
"Server": "cloudflare",
"Content-Encoding": "gzip",
"alt-svc": 'h3-27=":443"; ma=86400, h3-28=":443"; ma=86400, h3-29=":443"; ma=86400',
}
bypass = True
try:
headers = {"User-Agent": user_agent}
colors = {
"1": 0x17A2B8,
"2": 0x28A745,
"3": 0xFFC107,
"4": 0xDC3545,
"5": 0x343A40,
}
async with ctx.session.get(
str(ip),
headers=headers,
timeout=aiohttp.ClientTimeout(total=4),
) as s:
e = discord.Embed(
title=f"Headers : {ip}",
color=colors.get(str(s.status)[0], 0x6C757D),
)
e.add_field(
name="Status", value=f"```{s.status}```", inline=True
)
e.set_thumbnail(url=f"https://http.cat/{s.status}")
headers = dict(s.headers.items())
headers.pop("Set-Cookie", headers)
headers = b_headers if bypass else headers
for key, value in headers.items():
output = await shorten(ctx.session, value, 50)
if output["link"]:
value = _(
"[show all]({})", ctx, self.bot.config
).format(output["link"])
else:
value = f"```\n{output['text']}```"
e.add_field(name=key, value=value, inline=True)
await ctx.send(embed=e)
except (ClientConnectorError, asyncio.exceptions.TimeoutError):
await ctx.send(
_("Cannot connect to host {}", ctx, self.bot.config).format(ip)
)
@command_extra(name="dig", deletable=True)
async def _dig(
self,
ctx: ContextPlus,
domain: IPConverter,
query_type: QueryTypeConverter,
dnssec: Union[str, bool] = False,
):
check_query_type_or_raise(str(query_type))
pydig_result = await self.bot.loop.run_in_executor(
None,
functools.partial(get_pydig_result, domain, query_type, dnssec),
)
e = discord.Embed(title=f"DIG {domain} {query_type}", color=0x5858D7)
for i, value in enumerate(pydig_result):
e.add_field(name=f"#{i}", value=f"```{value}```")
if not pydig_result:
e.add_field(
name=f"DIG {domain} IN {query_type}",
value=_("No result...", ctx, self.bot.config),
)
await ctx.send(embed=e)
@command_extra(name="ping", deletable=True)
async def _ping(self, ctx: ContextPlus):
start = time.perf_counter()
await ctx.trigger_typing()
end = time.perf_counter()
latency = round(self.bot.latency * 1000, 2)
typing = round((end - start) * 1000, 2)
e = discord.Embed(title="Ping", color=discord.Color.teal())
e.add_field(name="Websocket", value=f"{latency}ms")
e.add_field(name="Typing", value=f"{typing}ms")
await ctx.send(embed=e)