async def fetch_image(self) -> Optional[OTAImage]: async with aiohttp.ClientSession() as req: LOGGER.debug("Downloading %s for %s", self.url, self.key) async with req.get(self.url) as rsp: data = await rsp.read() img, _ = parse_ota_image(data) assert img.header.key == self.key LOGGER.debug( "%s: version: %s, hw_ver: (%s, %s), OTA string: %s", img.header.key, img.header.file_version, img.header.minimum_hardware_version, img.header.maximum_hardware_version, img.header.header_string, ) LOGGER.debug( "Finished downloading %s bytes from %s for %s ver %s", self.image_size, self.url, self.key, self.version, ) return img
def test_parse_ota_hue(): data = create_hue_ota(b"test") + b"rest" img, rest = firmware.parse_ota_image(data) assert isinstance(img, firmware.HueSBLOTAImage) assert rest == b"rest" assert img.data == b"\x2A\x00\x01" + b"test" assert img.serialize() + b"rest" == data
def test_legrand_container_unwrapping(image): # Unwrapped size prefix and 1 + 16 byte suffix data = ( t.uint32_t(len(image.serialize())).serialize() + image.serialize() + b"\x01" + b"abcdabcdabcdabcd" ) with pytest.raises(ValueError): firmware.parse_ota_image(data[:-1]) with pytest.raises(ValueError): firmware.parse_ota_image(b"\xFF" + data[1:]) img, rest = firmware.parse_ota_image(data) assert not rest assert img == image
def test_parse_ota_ikea_trailing(image): data = wrap_ikea(image.serialize() + b"trailing") parsed, remaining = firmware.parse_ota_image(data) assert not remaining assert parsed.header.image_size == len(image.serialize() + b"trailing") assert parsed.subelements[0].data == b"data" + b"trailing" parsed2, remaining2 = firmware.OTAImage.deserialize(parsed.serialize()) assert not remaining2
def _fetch_image(self) -> Optional[BaseOTAImage]: """Loads full OTA Image from the file.""" try: with open(self.file_name, mode="rb") as f: data = f.read() img, _ = parse_ota_image(data) return img except (OSError, ValueError): LOGGER.debug("Couldn't load '%s' OTA image", self.file_name, exc_info=True) return None
def test_parse_ota_hue_invalid(): data = create_hue_ota(b"test") firmware.parse_ota_image(data) with pytest.raises(ValueError): firmware.parse_ota_image(data[:-1]) header, rest = firmware.OTAImageHeader.deserialize(data) assert data == header.serialize() + rest with pytest.raises(ValueError): # Three byte sequence must be the first thing after the header firmware.parse_ota_image(header.serialize() + b"\xFF" + rest[1:]) with pytest.raises(ValueError): # Only Hue is known to use these images firmware.parse_ota_image(header.replace(manufacturer_id=12).serialize() + rest)
async def fetch_image(self) -> Optional[OTAImage]: async with aiohttp.ClientSession() as req: LOGGER.debug("Downloading %s for %s", self.url, self.key) async with req.get(self.url) as rsp: data = await rsp.read() ota_image, _ = parse_ota_image(data) assert ota_image.header.key == self.key LOGGER.debug( "Finished downloading %s bytes from %s for %s ver %s", self.image_size, self.url, self.key, self.version, ) return ota_image
async def fetch_image(self) -> BaseOTAImage | None: async with aiohttp.ClientSession() as req: LOGGER.debug("Downloading %s for %s", self.url, self.key) async with req.get(self.url) as rsp: data = await rsp.read() img_tgz = io.BytesIO(data) with tarfile.open(fileobj=img_tgz) as tar: # Unpack tar for item in tar: if item.name.endswith(".ota"): f = tar.extractfile(item) if f is None: raise ValueError( f"Issue extracting {item.name} from {self.url}" ) else: file_bytes = f.read() break img, _ = parse_ota_image(file_bytes) LOGGER.debug( "%s: version: %s, hw_ver: (%s, %s), OTA string: %s", img.header.key, img.header.file_version, img.header.minimum_hardware_version, img.header.maximum_hardware_version, img.header.header_string, ) assert img.header.manufacturer_id == self.manufacturer_id # we can't check assert img.header.key == self.key because # self.key does not include any valid image_type data for salus # devices. It is not known at the point of generating the FW # list cache, so it can't be checked here (Ikea and ledvance have # this listed in the JSON, so they already know and can do this). LOGGER.debug( "Finished downloading %s bytes from %s for %s ver %s", self.image_size, self.url, self.key, self.version, ) return img
def scan_image(cls, file_name: str): """Check the header of the image.""" try: with open(file_name, mode="rb") as f: parsed_image, _ = parse_ota_image(f.read()) img = cls(file_name=file_name, header=parsed_image.header) LOGGER.debug( "%s: %s, version: %s, hw_ver: (%s, %s), OTA string: %s", img.key, img.file_name, img.version, img.header.minimum_hardware_version, img.header.maximum_hardware_version, img.header.header_string, ) return img except (OSError, ValueError): LOGGER.debug("File '%s' doesn't appear to be a OTA image", file_name, exc_info=True) return None
def test_parse_ota_ikea_truncated(data): with pytest.raises(ValueError): firmware.parse_ota_image(data)
def test_parse_ota_ikea(image): data = wrap_ikea(image.serialize()) assert firmware.parse_ota_image(data) == (image, b"")
def test_parse_ota_normal(image): assert firmware.parse_ota_image(image.serialize()) == (image, b"")