mirror of
https://github.com/BigBodyCobain/Shadowbroker.git
synced 2026-08-03 02:33:37 +02:00
v0.9.6: InfoNet hashchain, Wormhole gate encryption, mesh reputation, 16 community contributors
Gate messages now propagate via the Infonet hashchain as encrypted blobs — every node syncs them through normal chain sync while only Gate members with MLS keys can decrypt. Added mesh reputation system, peer push workers, voluntary Wormhole opt-in for node participation, fork recovery, killwormhole scripts, obfuscated terminology, and hardened the self-updater to protect encryption keys and chain state during updates. New features: Shodan search, train tracking, Sentinel Hub imagery, 8 new intelligence layers, CCTV expansion to 11,000+ cameras across 6 countries, Mesh Terminal CLI, prediction markets, desktop-shell scaffold, and comprehensive mesh test suite (215 frontend + backend tests passing). Community contributors: @wa1id, @AlborzNazari, @adust09, @Xpirix, @imqdcr, @csysp, @suranyami, @chr0n1x, @johan-martensson, @singularfailure, @smithbh, @OrfeoTerkuci, @deuza, @tm-const, @Elhard1, @ttulttul
This commit is contained in:
@@ -0,0 +1,113 @@
|
||||
"""
|
||||
PSK Reporter fetcher — pulls recent digital mode signal reports (FT8, WSPR, etc.)
|
||||
from the global PSK Reporter network. No API key required.
|
||||
|
||||
Docs: https://pskreporter.info/pskdev.html
|
||||
"""
|
||||
|
||||
import logging
|
||||
import xml.etree.ElementTree as ET
|
||||
|
||||
import requests
|
||||
from cachetools import TTLCache, cached
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
_cache = TTLCache(maxsize=1, ttl=600) # 10-minute cache
|
||||
|
||||
_ENDPOINT = "https://retrieve.pskreporter.info/query"
|
||||
|
||||
|
||||
def maidenhead_to_latlon(locator: str) -> tuple[float, float] | None:
|
||||
"""Convert a 4-or-6 character Maidenhead grid locator to (lat, lon)."""
|
||||
loc = locator.strip().upper()
|
||||
if len(loc) < 4:
|
||||
return None
|
||||
try:
|
||||
lon = (ord(loc[0]) - ord("A")) * 20 - 180
|
||||
lat = (ord(loc[1]) - ord("A")) * 10 - 90
|
||||
lon += int(loc[2]) * 2
|
||||
lat += int(loc[3])
|
||||
if len(loc) >= 6:
|
||||
lon += (ord(loc[4]) - ord("A")) * (2 / 24)
|
||||
lat += (ord(loc[5]) - ord("A")) * (1 / 24)
|
||||
# center of sub-square
|
||||
lon += 1 / 24
|
||||
lat += 1 / 48
|
||||
else:
|
||||
# center of grid square
|
||||
lon += 1
|
||||
lat += 0.5
|
||||
if abs(lat) > 90 or abs(lon) > 180:
|
||||
return None
|
||||
return round(lat, 4), round(lon, 4)
|
||||
except (IndexError, ValueError):
|
||||
return None
|
||||
|
||||
|
||||
@cached(_cache)
|
||||
def fetch_psk_reporter_spots() -> list[dict]:
|
||||
"""Fetch recent FT8 reception reports from PSK Reporter."""
|
||||
try:
|
||||
resp = requests.get(
|
||||
_ENDPOINT,
|
||||
params={
|
||||
"mode": "FT8",
|
||||
"flowStartSeconds": -900, # last 15 minutes
|
||||
"rronly": 1, # reception reports only
|
||||
"noactive": 1, # exclude active monitor noise
|
||||
"rptlimit": 5000, # cap payload size
|
||||
},
|
||||
timeout=30,
|
||||
headers={"Accept": "application/xml"},
|
||||
)
|
||||
resp.raise_for_status()
|
||||
|
||||
root = ET.fromstring(resp.content)
|
||||
|
||||
# PSK Reporter XML uses namespaces
|
||||
ns = ""
|
||||
if root.tag.startswith("{"):
|
||||
ns = root.tag.split("}")[0] + "}"
|
||||
|
||||
spots: list[dict] = []
|
||||
for rec in root.iter(f"{ns}receptionReport"):
|
||||
receiver_loc = rec.get("receiverLocator", "")
|
||||
sender_loc = rec.get("senderLocator", "")
|
||||
|
||||
# Prefer receiver location (where the signal was heard)
|
||||
loc_str = receiver_loc or sender_loc
|
||||
if not loc_str:
|
||||
continue
|
||||
coords = maidenhead_to_latlon(loc_str)
|
||||
if coords is None:
|
||||
continue
|
||||
lat, lon = coords
|
||||
|
||||
try:
|
||||
freq = int(rec.get("frequency", "0"))
|
||||
except (ValueError, TypeError):
|
||||
freq = 0
|
||||
|
||||
try:
|
||||
snr = int(rec.get("sNR", "0"))
|
||||
except (ValueError, TypeError):
|
||||
snr = 0
|
||||
|
||||
spots.append({
|
||||
"lat": lat,
|
||||
"lon": lon,
|
||||
"sender": (rec.get("senderCallsign") or "")[:20],
|
||||
"receiver": (rec.get("receiverCallsign") or "")[:20],
|
||||
"frequency": freq,
|
||||
"mode": (rec.get("mode") or "FT8")[:10],
|
||||
"snr": snr,
|
||||
"time": rec.get("flowStartSeconds", ""),
|
||||
})
|
||||
|
||||
logger.info("PSK Reporter: fetched %d spots", len(spots))
|
||||
return spots
|
||||
|
||||
except (requests.RequestException, ET.ParseError, Exception) as e:
|
||||
logger.error("PSK Reporter fetch error: %s", e)
|
||||
return []
|
||||
Reference in New Issue
Block a user