first commit
This commit is contained in:
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
84
.venv/lib/python3.12/site-packages/hetzner/util/addr.py
Normal file
84
.venv/lib/python3.12/site-packages/hetzner/util/addr.py
Normal file
@@ -0,0 +1,84 @@
|
||||
import socket
|
||||
import struct
|
||||
|
||||
|
||||
def parse_ipv4(addr):
|
||||
"""
|
||||
Return a numeric representation of the given IPv4 address.
|
||||
"""
|
||||
binary_ip = socket.inet_pton(socket.AF_INET, addr)
|
||||
return struct.unpack('!L', binary_ip)[0]
|
||||
|
||||
|
||||
def parse_ipv6(addr):
|
||||
"""
|
||||
Return a numeric representation of the given IPv6 address.
|
||||
"""
|
||||
binary_ip = socket.inet_pton(socket.AF_INET6, addr)
|
||||
high, low = struct.unpack('!QQ', binary_ip)
|
||||
return high << 64 | low
|
||||
|
||||
|
||||
def parse_ipaddr(addr, is_ipv6=None):
|
||||
"""
|
||||
Parse IP address and return a tuple consisting of a boolean indicating
|
||||
whether the given address is an IPv6 address and the numeric representation
|
||||
of the address.
|
||||
|
||||
If is_ipv6 is either True or False, the specific address type is enforced
|
||||
and only the parsed address is returned instead of a tuple.
|
||||
"""
|
||||
if is_ipv6 is None:
|
||||
try:
|
||||
return False, parse_ipv4(addr)
|
||||
except socket.error:
|
||||
return True, parse_ipv6(addr)
|
||||
elif is_ipv6:
|
||||
return parse_ipv6(addr)
|
||||
else:
|
||||
return parse_ipv4(addr)
|
||||
|
||||
|
||||
def get_ipv4_range(numeric_netaddr, prefix_len):
|
||||
"""
|
||||
Return the smallest and biggest possible IPv4 address of the specified
|
||||
network address (in numeric representation) and prefix length.
|
||||
"""
|
||||
mask_inverted = 32 - prefix_len
|
||||
mask_bin = 0xffffffff >> mask_inverted << mask_inverted
|
||||
range_start = numeric_netaddr & mask_bin
|
||||
range_end = range_start | (1 << mask_inverted) - 1
|
||||
return range_start, range_end
|
||||
|
||||
|
||||
def get_ipv6_range(numeric_netaddr, prefix_len):
|
||||
"""
|
||||
Return the smallest and biggest possible IPv6 address of the specified
|
||||
network address (in numeric representation) and prefix length.
|
||||
"""
|
||||
mask_bin_full = 0xffffffffffffffffffffffffffffffff
|
||||
mask_inverted = 128 - prefix_len
|
||||
mask_bin = mask_bin_full >> mask_inverted << mask_inverted
|
||||
range_start = numeric_netaddr & mask_bin
|
||||
range_end = range_start | (1 << mask_inverted) - 1
|
||||
return range_start, range_end
|
||||
|
||||
|
||||
def ipv4_bin2addr(numeric_addr):
|
||||
"""
|
||||
Convert a numeric representation of the given IPv4 address into quad-dotted
|
||||
notation.
|
||||
"""
|
||||
packed = struct.pack('!L', numeric_addr)
|
||||
return socket.inet_ntop(socket.AF_INET, packed)
|
||||
|
||||
|
||||
def ipv6_bin2addr(numeric_addr):
|
||||
"""
|
||||
Convert a numeric representation of the given IPv6 address into a shortened
|
||||
hexadecimal notiation separated by colons.
|
||||
"""
|
||||
high = numeric_addr >> 64
|
||||
low = numeric_addr & 0xffffffffffffffff
|
||||
packed = struct.pack('!QQ', high, low)
|
||||
return socket.inet_ntop(socket.AF_INET6, packed)
|
||||
70
.venv/lib/python3.12/site-packages/hetzner/util/http.py
Normal file
70
.venv/lib/python3.12/site-packages/hetzner/util/http.py
Normal file
@@ -0,0 +1,70 @@
|
||||
import os
|
||||
import ssl
|
||||
import socket
|
||||
|
||||
from tempfile import NamedTemporaryFile
|
||||
|
||||
try:
|
||||
from httplib import HTTPSConnection
|
||||
except ImportError:
|
||||
from http.client import HTTPSConnection
|
||||
|
||||
|
||||
class ValidatedHTTPSConnection(HTTPSConnection):
|
||||
CA_ROOT_CERT_FALLBACK = '''
|
||||
DigiCert Global Root G2
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIDjjCCAnagAwIBAgIQAzrx5qcRqaC7KGSxHQn65TANBgkqhkiG9w0BAQsFADBh
|
||||
MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
|
||||
d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBH
|
||||
MjAeFw0xMzA4MDExMjAwMDBaFw0zODAxMTUxMjAwMDBaMGExCzAJBgNVBAYTAlVT
|
||||
MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j
|
||||
b20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IEcyMIIBIjANBgkqhkiG
|
||||
9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuzfNNNx7a8myaJCtSnX/RrohCgiN9RlUyfuI
|
||||
2/Ou8jqJkTx65qsGGmvPrC3oXgkkRLpimn7Wo6h+4FR1IAWsULecYxpsMNzaHxmx
|
||||
1x7e/dfgy5SDN67sH0NO3Xss0r0upS/kqbitOtSZpLYl6ZtrAGCSYP9PIUkY92eQ
|
||||
q2EGnI/yuum06ZIya7XzV+hdG82MHauVBJVJ8zUtluNJbd134/tJS7SsVQepj5Wz
|
||||
tCO7TG1F8PapspUwtP1MVYwnSlcUfIKdzXOS0xZKBgyMUNGPHgm+F6HmIcr9g+UQ
|
||||
vIOlCsRnKPZzFBQ9RnbDhxSJITRNrw9FDKZJobq7nMWxM4MphQIDAQABo0IwQDAP
|
||||
BgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBhjAdBgNVHQ4EFgQUTiJUIBiV
|
||||
5uNu5g/6+rkS7QYXjzkwDQYJKoZIhvcNAQELBQADggEBAGBnKJRvDkhj6zHd6mcY
|
||||
1Yl9PMWLSn/pvtsrF9+wX3N3KjITOYFnQoQj8kVnNeyIv/iPsGEMNKSuIEyExtv4
|
||||
NeF22d+mQrvHRAiGfzZ0JFrabA0UWTW98kndth/Jsw1HKj2ZL7tcu7XUIOGZX1NG
|
||||
Fdtom/DzMNU+MeKNhJ7jitralj41E6Vf8PlwUHBHQRFXGU7Aj64GxJUTFy8bJZ91
|
||||
8rGOmaFvE7FBcf6IKshPECBV1/MUReXgRPTqh5Uykw7+U0b6LJ3/iyK5S9kJRaTe
|
||||
pLiaWN0bfVKfjllDiIGknibVb63dDcY3fe0Dkhvld1927jyNxF1WW6LZZm6zNTfl
|
||||
MrY=
|
||||
-----END CERTIFICATE-----
|
||||
'''
|
||||
|
||||
def get_ca_cert_bundle(self):
|
||||
via_env = os.getenv('SSL_CERT_FILE')
|
||||
if via_env is not None and os.path.exists(via_env):
|
||||
return via_env
|
||||
probe_paths = [
|
||||
"/etc/ssl/certs/ca-certificates.crt",
|
||||
"/etc/ssl/certs/ca-bundle.crt",
|
||||
"/etc/pki/tls/certs/ca-bundle.crt",
|
||||
]
|
||||
for path in probe_paths:
|
||||
if os.path.exists(path):
|
||||
return path
|
||||
return None
|
||||
|
||||
def connect(self):
|
||||
sock = socket.create_connection((self.host, self.port),
|
||||
self.timeout,
|
||||
self.source_address)
|
||||
bundle = cafile = self.get_ca_cert_bundle()
|
||||
if bundle is None:
|
||||
ca_certs = NamedTemporaryFile()
|
||||
ca_certs.write('\n'.join(
|
||||
map(str.strip, self.CA_ROOT_CERT_FALLBACK.splitlines())
|
||||
).encode('ascii'))
|
||||
ca_certs.flush()
|
||||
cafile = ca_certs.name
|
||||
self.sock = ssl.wrap_socket(sock, self.key_file, self.cert_file,
|
||||
cert_reqs=ssl.CERT_REQUIRED,
|
||||
ca_certs=cafile)
|
||||
if bundle is None:
|
||||
ca_certs.close()
|
||||
19
.venv/lib/python3.12/site-packages/hetzner/util/scraping.py
Normal file
19
.venv/lib/python3.12/site-packages/hetzner/util/scraping.py
Normal file
@@ -0,0 +1,19 @@
|
||||
try:
|
||||
from HTMLParser import HTMLParser
|
||||
except ImportError:
|
||||
from html.parser import HTMLParser
|
||||
|
||||
|
||||
class CSRFParser(HTMLParser):
|
||||
def __init__(self, field_name):
|
||||
HTMLParser.__init__(self)
|
||||
self.field_name = field_name
|
||||
self.csrf_token = None
|
||||
|
||||
def handle_starttag(self, tag, attrs):
|
||||
if tag != 'input':
|
||||
return
|
||||
attrdict = dict(attrs)
|
||||
if attrdict.get('name', '') == self.field_name:
|
||||
self.csrf_token = attrdict.get('value', None)
|
||||
handle_startendtag = handle_starttag
|
||||
Reference in New Issue
Block a user