Possibly useful Python functions
- dns_dict.py : DNS[
host] returns randomized ipaddress from system DNS, honoring TTL - totp.py : A zero dependency TOTP token generator
- snake_camel.py : convert between snake_case, camelCase, and PascalCase
| """DNS[<host>] returns randomized ipaddress from system DNS, honoring TTL""" | |
| # /// script | |
| # requires-python = ">=3" | |
| # dependencies = [ | |
| # "dnspython", | |
| # ] | |
| # /// | |
| __all__ = [ | |
| "DNS", | |
| ] | |
| import ipaddress | |
| import random | |
| import time | |
| import dns.resolver | |
| NX_EXPIRE = 5 * 60 | |
| def dns_query(host): | |
| try: | |
| query = dns.resolver.resolve(host) | |
| expiration = query.expiration | |
| addresses = tuple(ipaddress.ip_address(_.address) for _ in query) | |
| except dns.resolver.NXDOMAIN: | |
| expiration = time.time() + NX_EXPIRE | |
| addresses = () | |
| return int(expiration), addresses | |
| class DNS(dict): | |
| def __init__(self, hosts=None): | |
| hosts = hosts if hosts else () | |
| data = {host: dns_query(host) for host in hosts} | |
| super().__init__(data) | |
| def __getitem__(self, host): | |
| try: | |
| expiration, addresses = dict.__getitem__(self, host) | |
| if expiration <= int(time.time()): | |
| raise ValueError("DNS query expired") | |
| except (ValueError, KeyError): | |
| expiration, addresses = dns_query(host) | |
| self[host] = expiration, addresses | |
| address = random.choice(addresses) if addresses else None | |
| return address | |
| if __name__ == "__main__": | |
| dns_cache = DNS(["google.com", "bing.com"]) | |
| print(dns_cache["microsoft.com"]) | |
| print(dns_cache["bing.com"]) | |
| print("DNS cache:", dns_cache) |
| # /// script | |
| # requires-python = ">=3" | |
| # dependencies = [] | |
| # /// | |
| __all__ = ["snake_to_camel", "snake_to_pascal", "case_to_snake"] | |
| def snake_to_camel(value: str) -> str: | |
| """convert snake_case into camelCase | |
| FIXME: ignores duplicate '_' | |
| >>> snake_to_camel('identifier_for_object') | |
| 'identifierForObject' | |
| """ | |
| new_value, *parts = value.split("_") | |
| return "".join((new_value, *(part.capitalize() for part in parts))) | |
| def snake_to_pascal(value: str) -> str: | |
| """convert snake_case into PascalCase | |
| >>> snake_to_pascal('identifier_for_object') | |
| 'IdentifierForObject' | |
| """ | |
| first, *rest = snake_to_camel(value) | |
| return "".join((first.capitalize(), *rest)) | |
| def case_to_snake(value: str) -> str: | |
| """convert camelCase or PascalCase into snake_case or _snake_case | |
| >>> case_to_snake('IdentifierForObject') | |
| '_identifier_for_object' | |
| >>> case_to_snake('identifierForObject') | |
| 'identifier_for_object' | |
| """ | |
| first, *rest = snake_to_camel(value) | |
| return "".join( | |
| (char if not char.isupper() else f"_{char.lower()}") for char in value | |
| ) | |
| if __name__ == "__main__": | |
| import doctest | |
| doctest.testmod() |
| """A zero dependency TOTP token generator. | |
| RFC4226 and RFC6238 | |
| otpauth://totp/$LABEL?secret=$SECRET | |
| """ | |
| # /// script | |
| # requires-python = ">=3" | |
| # /// | |
| __all__ = [ | |
| "hotp", | |
| ] | |
| import base64 | |
| import hashlib | |
| import hmac | |
| import time | |
| def count_now(timestep=30, epoch=0): | |
| """RFC6238 aka TOTP: the counter is based on time""" | |
| timestamp = int(time.time()) | |
| counter = (timestamp - epoch) // timestep | |
| return bytes.fromhex(format(counter, "016x")) | |
| def hotp(secret, count=None, digits=6, constructor=hashlib.sha1): | |
| """RFC4226 aka HOTP""" | |
| if count is None: | |
| count = count_now() | |
| key = base64.b32decode(secret) | |
| hmac_sha1 = hmac.new(key, count, constructor) | |
| hash_ = hmac_sha1.digest() | |
| offset = hash_[-1] & 0xF | |
| data = hash_[offset : offset + 4] | |
| otp = int(data.hex(), 16) | |
| result = otp & 0x7FFFFFFF | |
| return "{:06d}".format(result)[-digits:] | |
| if __name__ == "__main__": | |
| # shared secret | |
| secret = "JBSWY3DPEHPK3PXP" | |
| print(hotp(secret)) | |
| secret = "L7DYDYMB5ZXHGHPJUW77QXXY6AY4ZTW7DZWNPV3YQOVXFX6HN4VNNDJQGIDJFDKY" | |
| print(hotp(secret)) |