65 lines
2.7 KiB
Python
65 lines
2.7 KiB
Python
"""Check the public Beget release over HTTP and inspect the TLS certificate."""
|
|
from pathlib import Path
|
|
from urllib.request import build_opener, ProxyHandler, HTTPSHandler, Request
|
|
import json
|
|
import socket
|
|
import ssl
|
|
import sys
|
|
|
|
ROOT = Path(__file__).resolve().parent
|
|
PUBLIC = ROOT / 'public'
|
|
sys.path.insert(0, str(ROOT / '.deps'))
|
|
from cryptography import x509
|
|
|
|
BASE = 'https://servaki.online'
|
|
opener = build_opener(ProxyHandler({}), HTTPSHandler(context=ssl._create_unverified_context()))
|
|
|
|
|
|
def get(path):
|
|
request = Request(BASE + path, headers={'Cache-Control': 'no-cache', 'Accept-Encoding': 'identity'})
|
|
with opener.open(request, timeout=20) as response:
|
|
return response.status, response.read(), response.url
|
|
|
|
|
|
def certificate():
|
|
with socket.create_connection(('servaki.online', 443), timeout=12) as conn:
|
|
with ssl._create_unverified_context().wrap_socket(conn, server_hostname='servaki.online') as tls:
|
|
cert = x509.load_der_x509_certificate(tls.getpeercert(binary_form=True))
|
|
valid = True
|
|
try:
|
|
with socket.create_connection(('servaki.online', 443), timeout=12) as conn:
|
|
with ssl.create_default_context().wrap_socket(conn, server_hostname='servaki.online'):
|
|
pass
|
|
except ssl.SSLError:
|
|
valid = False
|
|
return valid, cert.not_valid_after_utc.isoformat()
|
|
|
|
|
|
def main():
|
|
pages = sorted(PUBLIC.rglob('*.html'))
|
|
selected = pages + [PUBLIC / 'robots.txt', PUBLIC / 'sitemap.xml']
|
|
selected += [PUBLIC / 'assets/editorial/editorial.css',
|
|
PUBLIC / 'assets/editorial/photo-networks-vpn-960.webp',
|
|
PUBLIC / 'assets/editorial/networks-vpn-480.webp']
|
|
mismatches = []
|
|
for file in selected:
|
|
rel = file.relative_to(PUBLIC).as_posix()
|
|
path = '/' if rel == 'index.html' else '/' + rel.removesuffix('index.html')
|
|
try:
|
|
status, body, final_url = get(path)
|
|
if status != 200 or body != file.read_bytes() or not final_url.startswith(BASE + '/'):
|
|
mismatches.append({'path': path, 'status': status, 'bytes': len(body)})
|
|
except Exception as error:
|
|
mismatches.append({'path': path, 'error': type(error).__name__ + ': ' + str(error)[:130]})
|
|
valid, not_after = certificate()
|
|
report = {'checked': len(selected), 'exact_matches': len(selected) - len(mismatches),
|
|
'tls_valid': valid, 'tls_not_after': not_after, 'mismatches': mismatches}
|
|
(ROOT / 'live-verification.json').write_text(json.dumps(report, ensure_ascii=False, indent=2), encoding='utf-8')
|
|
print(json.dumps(report, ensure_ascii=False))
|
|
if mismatches or not valid:
|
|
raise SystemExit(1)
|
|
|
|
|
|
if __name__ == '__main__':
|
|
main()
|