60 lines
2.6 KiB
Python
60 lines
2.6 KiB
Python
import json
|
|
import logging
|
|
import re
|
|
|
|
from common import dates, endoflife, http
|
|
from common.releasedata import ProductData, config_from_argv
|
|
|
|
|
|
def extract_data(url: str, key_to_search_for: str) -> dict | None:
|
|
"""Extract JSON data from Motorola Mobility security updates page."""
|
|
html = http.fetch_html(url)
|
|
|
|
# find all script tags with no src attribute and containing a CDATA section.
|
|
all_scripts = [str(t.getText) for t in html.find_all("script", src=False)]
|
|
candidate_scripts = [s for s in all_scripts if key_to_search_for in s]
|
|
if len(candidate_scripts) != 1:
|
|
msg = f"Expected exactly one script containing {key_to_search_for}, found {len(candidate_scripts)}"
|
|
raise ValueError(msg)
|
|
|
|
# Ideally, we would use an actual JavaScript parser to find our desired content.
|
|
lines = candidate_scripts[0].split("\n")
|
|
candidate_lines = [line for line in lines if key_to_search_for in line]
|
|
if len(candidate_lines) != 1:
|
|
msg = f"Expected exactly one containing {key_to_search_for} in JS, got {len(candidate_lines)}"
|
|
raise ValueError(msg)
|
|
|
|
candidate_line = candidate_lines[0]
|
|
raw_json = re.search(r"\{.+}", candidate_line)
|
|
if not raw_json:
|
|
msg = f"Failed to find JSON in {candidate_line}"
|
|
raise ValueError(msg)
|
|
|
|
logging.debug(f"Found : {raw_json}")
|
|
return json.loads(raw_json.group(0))
|
|
|
|
config = config_from_argv()
|
|
with ProductData(config.product) as product_data:
|
|
json_data = extract_data(config.url, "guidedAssistant")
|
|
|
|
for question in json_data["j"]["guidedAssistant"]["questions"]:
|
|
if not question.get("responses") or question["responses"][0].get("text") != "Security patch details for all Motorola products":
|
|
logging.debug(f"Skipping {question}")
|
|
continue
|
|
|
|
lines = question["taglessText"].replace("\xa0", " ").split("\n")
|
|
logging.debug(lines)
|
|
|
|
product_id = question["agentText"]
|
|
label = lines[0].strip()
|
|
name = endoflife.to_identifier(label)
|
|
release = product_data.get_release(name)
|
|
release.set_field("link", f"https://en-us.support.motorola.com/app/software-security-update/g_id/7112/productid/{product_id}")
|
|
for line in lines:
|
|
if (m := re.search(r"^Device launched on (.*)$", line)):
|
|
date = dates.parse_date_or_month_year_date(m.group(1).strip()).replace(day=1)
|
|
release.set_release_date(date)
|
|
if (m := re.search(r"^Security updates will stop on (.*)$", line)):
|
|
eol = dates.parse_date_or_month_year_date(m.group(1).strip())
|
|
release.set_eol(eol)
|