https://github.com/pogzyb/whodap

Python RDAP utility for querying and parsing information about Domains, IPv4s, IPv6s, and AS numbers

https://github.com/pogzyb/whodap

Science Score: 23.0%

This score indicates how likely this project is to be science-related based on various indicators:

  • CITATION.cff file
  • codemeta.json file
    Found codemeta.json file
  • .zenodo.json file
  • DOI references
  • Academic publication links
  • Committers with academic emails
    1 of 4 committers (25.0%) from academic institutions
  • Institutional organization owner
  • JOSS paper metadata
  • Scientific vocabulary similarity
    Low similarity (8.5%) to scientific vocabulary

Keywords

hacktoberfest proxy python-3 rdap rdap-client rdap-servers rdap-service whois whois-information whois-lookup whoislookup
Last synced: 6 months ago · JSON representation

Repository

Python RDAP utility for querying and parsing information about Domains, IPv4s, IPv6s, and AS numbers

Basic Info
  • Host: GitHub
  • Owner: pogzyb
  • Language: Python
  • Default Branch: main
  • Homepage:
  • Size: 113 KB
Statistics
  • Stars: 27
  • Watchers: 1
  • Forks: 9
  • Open Issues: 0
  • Releases: 14
Topics
hacktoberfest proxy python-3 rdap rdap-client rdap-servers rdap-service whois whois-information whois-lookup whoislookup
Created almost 5 years ago · Last pushed 7 months ago
Metadata Files
Readme License

README.md

whodap

PyPI version example workflow codecov Code style: black

whodap | Simple RDAP Utility for Python

  • Support for asyncio HTTP requests (httpx)
  • Leverages the SimpleNamespace type for cleaner RDAP Response traversal
  • Keeps the familiar look of WHOIS via the to_whois_dict method for DNS lookups

Quickstart

```python import asyncio from pprint import pprint

import whodap

Looking up a domain name

response = whodap.lookup_domain(domain='bitcoin', tld='org')

Equivalent asyncio call

loop = asyncio.geteventloop() response = loop.rununtilcomplete(whodap.aiolookupdomain(domain='bitcoin', tld='org'))

"response" is a DomainResponse object. It contains the output from the RDAP lookup.

print(response)

Traverse the DomainResponse via "dot" notation

print(response.events) """ [{ "eventAction": "last update of RDAP database", "eventDate": "2021-04-23T21:50:03" }, { "eventAction": "registration", "eventDate": "2008-08-18T13:19:55" }, ... ] """

Retrieving the registration date from above:

print(response.events[1].eventDate) """ 2008-08-18 13:19:55 """

Don't want "dot" notation? Use to_dict to get the RDAP response as a dictionary

pprint(response.to_dict())

Use to_whois_dict for the familiar look of WHOIS output

pprint(response.towhoisdict()) """ {abuseemail: 'abuse@namecheap.com', abusephone: 'tel:+1.6613102107', adminaddress: 'P.O. Box 0823-03411, Panama, Panama, PA', adminemail: '2603423f6ed44178a3b9d728827aa19a.protect@whoisguard.com', adminfax: 'fax:+51.17057182', adminname: 'WhoisGuard Protected', adminorganization: 'WhoisGuard, Inc.', adminphone: 'tel:+507.8365503', billingaddress: None, billingemail: None, billingfax: None, billingname: None, billingorganization: None, billingphone: None, createddate: datetime.datetime(2008, 8, 18, 13, 19, 55), domainname: 'bitcoin.org', expiresdate: datetime.datetime(2029, 8, 18, 13, 19, 55), nameservers: ['dns1.registrar-servers.com', 'dns2.registrar-servers.com'], registrantaddress: 'P.O. Box 0823-03411, Panama, Panama, PA', registrantemail: '2603423f6ed44178a3b9d728827aa19a.protect@whoisguard.com', registrantfax: 'fax:+51.17057182', registrantname: 'WhoisGuard Protected', registrantorganization: None, registrantphone: 'tel:+507.8365503', registraraddress: '4600 E Washington St #305, Phoenix, Arizona, 85034', registraremail: 'support@namecheap.com', registrarfax: None, registrarname: 'NAMECHEAP INC', registrarphone: 'tel:+1.6613102107', status: ['client transfer prohibited'], technicaladdress: 'P.O. Box 0823-03411, Panama, Panama, PA', technicalemail: '2603423f6ed44178a3b9d728827aa19a.protect@whoisguard.com', technicalfax: 'fax:+51.17057182', technicalname: 'WhoisGuard Protected', technicalorganization: 'WhoisGuard, Inc.', technicalphone: 'tel:+507.8365503', updated_date: datetime.datetime(2019, 11, 24, 13, 58, 35)} """ ```

Exported Functions and Classes

| Object | Description | | ----------- | ----------- | | lookup_domain | Performs an RDAP query for the given Domain and TLD | | lookup_ipv4 | Performs an RDAP query for the given IPv4 address | | lookup_ipv6 | Performs an RDAP query for the given IPv6 address | | lookup_asn | Performs an RDAP query for the Autonomous System with the given Number | | aio_lookup_domain | async counterpart to lookup_domain | | aio_lookup_ipv4 | async counterpart to lookup_ipv4 | | aio_lookup_ipv6 | async counterpart to lookup_ipv6 | | aio_lookup_asn | async counterpart to lookup_asn | | DNSClient | Reusable client for RDAP DNS queries | | IPv4Client | Reusable client for RDAP IPv4 queries | | IPv6Client | Reusable client for RDAP IPv6 queries | | ASNClient | Reusable client for RDAP ASN queries |

Common Usage Patterns

  • Using the DNSClient: ```python import whodap

Initialize an instance of DNSClient using classmethods: new_client or new_aio_client

dnsclient = whodap.DNSClient.newclient() for domain, tld in [('google', 'com'), ('google', 'buzz')]: response = dns_client.lookup(domain, tld)

Equivalent asyncio call

dnsclient = await whodap.DNSClient.newaioclient() for domain, tld in [('google', 'com'), ('google', 'buzz')]: response = await dnsclient.aio_lookup(domain, tld)

Use the DNSClient contextmanagers: new_client_context or new_aio_client_context

with whodap.DNSClient.newclientcontext() as dnsclient: for domain, tld in [('google', 'com'), ('google', 'buzz')]: response = dnsclient.lookup(domain, tld)

Equivalent asyncio call

async with whodap.DNSClient.newaioclientcontext() as dnsclient: for domain, tld in [('google', 'com'), ('google', 'buzz')]: response = await dnsclient.aiolookup(domain, tld) ```

  • Configurable httpx client:

```python import asyncio

import httpx import whodap

Initialize a custom, pre-configured httpx client ...

httpxclient = httpx.Client(proxies=httpx.Proxy('https://user:pw@proxyurl.net'))

... or an async client

aiohttpxclient = httpx.AsyncClient(proxies=httpx.Proxy('http://user:pw@proxy_url.net'))

Three common methods for leveraging httpx clients are outlined below:

1) Pass the httpx client directly into the convenience functions: lookup_domain or aio_lookup_domain

Important: In this scenario, you are responsible for closing the httpx client.

In this example, the given httpx client is used as a contextmanager; ensuring it is "closed" when finished.

async with aiohttpxclient: futures = [] for domain, tld in [('google', 'com'), ('google', 'buzz')]: task = whodap.aiolookupdomain(domain, tld, httpxclient=aiohttpx_client) futures.append(task) await asyncio.gather(*futures)

2) Pass the httpxclient into the DNSClient classmethod: `newclientornewaioclient`

aiodnsclient = await whodap.DNSClient.newaioclient(aiohttpxclient) result = await aiodnsclient.aiolookup('google', 'buzz') await aiohttpx_client.aclose()

3) Pass the httpxclient into the DNSClient contextmanagers: `newclientcontextornewaioclientcontext`

This method ensures the underlying httpx_client is closed when exiting the "with" block.

async with whodap.DNSClient.newaioclientcontext(aiohttpxclient) as dnsclient: for domain, tld in [('google', 'com'), ('google', 'buzz')]: response = await dnsclient.aiolookup(domain, tld) ```

  • Using the to_whois_dict method and RDAPConformanceException ```python import logging

from whodap import lookup_domain from whodap.errors import RDAPConformanceException

logger = logging.getLogger(name)

strict = False (default)

rdapresponse = lookupdomain("example", "com") whoisformat = rdapresponse.towhoisdict() logger.info(f"whois={whois_format}")

Given a valid RDAP response, the to_whois_dict method will attempt to

convert the RDAP format into a flattened dictionary of WHOIS key/values

strict = True

try: # Unfortunately, there are instances in which the RDAP protocol is not # properly implemented by the registrar. By default, the to_whois_dict # will still attempt to parse the into the WHOIS dictionary. However, # there is no guarantee that the information will be correct or non-null. # If your applications rely on accurate information, the strict=True # parameter will raise an RDAPConformanceException when encountering # invalid or incorrectly formatted RDAP responses. rdapresponse = lookupdomain("example", "com") whoisformat = rdapresponse.towhoisdict(strict=True) except RDAPConformanceException: logger.exception("RDAP response is incorrectly formatted.") ```

Contributions

  • Interested in contributing?
  • Have any questions or comments?
  • Anything that you'd like to see?
  • Anything that doesn't look right?

Please post a question or comment.

Roadmap

[alpha] 0.1.X Release: - ~~Support for RDAP "domain" queries~~ - ~~Support for RDAP "ipv4" and "ipv6" queries~~ - ~~Support for RDAP ASN queries~~ - Abstract the HTTP Client (httpx is the defacto client for now) - Add parser utils/helpers for IPv4, IPv6, and ASN Responses (if someone shows interest) - Add RDAP response validation support leveraging ICANN's tool

RDAP Resources:

Owner

  • Login: pogzyb
  • Kind: user

GitHub Events

Total
  • Release event: 1
  • Watch event: 6
  • Push event: 2
  • Pull request event: 1
  • Pull request review event: 1
  • Fork event: 2
  • Create event: 1
Last Year
  • Release event: 1
  • Watch event: 6
  • Push event: 2
  • Pull request event: 1
  • Pull request review event: 1
  • Fork event: 2
  • Create event: 1

Committers

Last synced: 8 months ago

All Time
  • Total Commits: 92
  • Total Committers: 4
  • Avg Commits per committer: 23.0
  • Development Distribution Score (DDS): 0.033
Past Year
  • Commits: 0
  • Committers: 0
  • Avg Commits per committer: 0.0
  • Development Distribution Score (DDS): 0.0
Top Committers
Name Email Commits
pogzyb p****b@u****u 89
Rahul Sharma r****h@g****m 1
Grigi n****s@g****m 1
Kyle M s****t@s****o 1
Committer Domains (Top 20 + Academic)

Issues and Pull Requests

Last synced: 6 months ago

All Time
  • Total issues: 12
  • Total pull requests: 27
  • Average time to close issues: 21 days
  • Average time to close pull requests: about 1 hour
  • Total issue authors: 5
  • Total pull request authors: 4
  • Average comments per issue: 1.08
  • Average comments per pull request: 0.67
  • Merged pull requests: 27
  • Bot issues: 0
  • Bot pull requests: 0
Past Year
  • Issues: 0
  • Pull requests: 0
  • Average time to close issues: N/A
  • Average time to close pull requests: N/A
  • Issue authors: 0
  • Pull request authors: 0
  • Average comments per issue: 0
  • Average comments per pull request: 0
  • Merged pull requests: 0
  • Bot issues: 0
  • Bot pull requests: 0
Top Authors
Issue Authors
  • pogzyb (6)
  • ninoseki (2)
  • fabaff (2)
  • whatabeautifulmemory (1)
  • Commod0re (1)
Pull Request Authors
  • pogzyb (26)
  • TirathPatel (1)
  • villain-inc (1)
  • grigi (1)
  • rahulXs (1)
Top Labels
Issue Labels
hacktoberfest (5) enhancement (3) good first issue (2)
Pull Request Labels
bug (1)

Packages

  • Total packages: 1
  • Total downloads:
    • pypi 17,831 last-month
  • Total docker downloads: 40
  • Total dependent packages: 1
  • Total dependent repositories: 7
  • Total versions: 14
  • Total maintainers: 1
pypi.org: whodap

Simple RDAP Utility for Python

  • Versions: 14
  • Dependent Packages: 1
  • Dependent Repositories: 7
  • Downloads: 17,831 Last month
  • Docker Downloads: 40
Rankings
Docker downloads count: 4.1%
Downloads: 4.3%
Dependent packages count: 4.8%
Dependent repos count: 5.5%
Average: 8.0%
Forks count: 14.2%
Stargazers count: 14.9%
Maintainers (1)
Last synced: 6 months ago

Dependencies

setup.py pypi
  • async_generator >=1.10
  • httpx >=0.20.0
.github/workflows/black-linter.yml actions
  • actions/checkout v2 composite
  • psf/black stable composite
.github/workflows/run-build-and-test.yml actions
  • actions/checkout v3 composite
  • actions/setup-python v4 composite
  • actions/upload-artifact v3 composite
  • codecov/codecov-action v2 composite
pyproject.toml pypi