64 lines
2.6 KiB
Python
64 lines
2.6 KiB
Python
|
|
"""Read-only HTTP smoke checks against the locally recorded server (no login)."""
|
||
|
|
import io
|
||
|
|
import json
|
||
|
|
import time
|
||
|
|
|
||
|
|
import psutil
|
||
|
|
import requests
|
||
|
|
from PIL import Image
|
||
|
|
|
||
|
|
from local_server import RUNTIME, recorded_process
|
||
|
|
|
||
|
|
|
||
|
|
def main():
|
||
|
|
proc = recorded_process()
|
||
|
|
if not proc:
|
||
|
|
raise RuntimeError('Start the local server first')
|
||
|
|
client = requests.Session()
|
||
|
|
client.trust_env = False
|
||
|
|
results = []
|
||
|
|
cases = [
|
||
|
|
('/', 302, None),
|
||
|
|
('/login', 200, None),
|
||
|
|
('/user/openCaptcha', 200, None),
|
||
|
|
('/static/lib/css/style.css', 200, None),
|
||
|
|
('/static/images/logo.png', 200, None),
|
||
|
|
('/system/openConfig', 302, None),
|
||
|
|
('/system/openConfig', 302, {'Safe': 'legacy-bypass'}),
|
||
|
|
('/inner/on_publish', 403, None),
|
||
|
|
]
|
||
|
|
for path, expected, headers in cases:
|
||
|
|
response = client.get('http://127.0.0.1:10001' + path, headers=headers,
|
||
|
|
allow_redirects=False, timeout=15)
|
||
|
|
assert response.status_code == expected, (path, response.status_code)
|
||
|
|
if expected == 302:
|
||
|
|
assert response.headers['Location'] == '/login'
|
||
|
|
if path == '/user/openCaptcha':
|
||
|
|
image = Image.open(io.BytesIO(response.content))
|
||
|
|
image.verify()
|
||
|
|
assert response.headers['Content-Type'].startswith('image/')
|
||
|
|
results.append({'path': path, 'safe_header': bool(headers), 'status': response.status_code})
|
||
|
|
client.close()
|
||
|
|
processes = [proc, *proc.children(recursive=True)]
|
||
|
|
sockets = []
|
||
|
|
for process in processes:
|
||
|
|
for conn in process.connections(kind='inet'):
|
||
|
|
if conn.status == psutil.CONN_LISTEN:
|
||
|
|
assert conn.laddr.ip == '127.0.0.1' and conn.laddr.port == 10001, conn
|
||
|
|
assert conn.type.name != 'SOCK_DGRAM', conn
|
||
|
|
if conn.raddr:
|
||
|
|
assert conn.raddr.ip in ('127.0.0.1', '::1'), conn
|
||
|
|
sockets.append({'pid': process.pid, 'local': list(conn.laddr),
|
||
|
|
'remote': list(conn.raddr), 'status': conn.status})
|
||
|
|
assert 'ffmpeg' not in process.name().lower() and 'zlm' not in process.name().lower()
|
||
|
|
assert any(item['status'] == psutil.CONN_LISTEN for item in sockets)
|
||
|
|
report = {'checked_at': time.strftime('%Y-%m-%d %H:%M:%S'), 'http': results,
|
||
|
|
'process_ids': [process.pid for process in processes], 'sockets': sockets,
|
||
|
|
'scope': 'Anonymous HTTP and current process/socket snapshot only; no real camera/model/login tested'}
|
||
|
|
(RUNTIME / 'local-verification.json').write_text(json.dumps(report, indent=2), encoding='utf-8')
|
||
|
|
print(json.dumps(report, indent=2))
|
||
|
|
|
||
|
|
|
||
|
|
if __name__ == '__main__':
|
||
|
|
main()
|