|
|
@ -68,9 +68,20 @@ class TranslationsHeader:
|
|
|
|
except EOFError:
|
|
|
|
except EOFError:
|
|
|
|
raise DataError("Invalid header data")
|
|
|
|
raise DataError("Invalid header data")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def version_tuple(self) -> tuple[int, int, int]:
|
|
|
|
|
|
|
|
try:
|
|
|
|
|
|
|
|
version_parts = self.version.split(".")
|
|
|
|
|
|
|
|
major = int(version_parts[0])
|
|
|
|
|
|
|
|
minor = int(version_parts[1])
|
|
|
|
|
|
|
|
patch = int(version_parts[2])
|
|
|
|
|
|
|
|
return major, minor, patch
|
|
|
|
|
|
|
|
except (ValueError, IndexError):
|
|
|
|
|
|
|
|
raise DataError("Invalid header version")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
async def change_language(msg: ChangeLanguage) -> Success:
|
|
|
|
async def change_language(msg: ChangeLanguage) -> Success:
|
|
|
|
from trezor import translations
|
|
|
|
from trezor import translations, utils
|
|
|
|
|
|
|
|
from trezor.crypto.hashlib import sha256
|
|
|
|
from trezor.messages import Success
|
|
|
|
from trezor.messages import Success
|
|
|
|
|
|
|
|
|
|
|
|
data_length = msg.data_length # local_cache_attribute
|
|
|
|
data_length = msg.data_length # local_cache_attribute
|
|
|
@ -86,35 +97,47 @@ async def change_language(msg: ChangeLanguage) -> Success:
|
|
|
|
if data_length < _HEADER_SIZE:
|
|
|
|
if data_length < _HEADER_SIZE:
|
|
|
|
raise DataError("Translations too short")
|
|
|
|
raise DataError("Translations too short")
|
|
|
|
|
|
|
|
|
|
|
|
data_left = data_length
|
|
|
|
|
|
|
|
offset = 0
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# Getting and parsing the header
|
|
|
|
# Getting and parsing the header
|
|
|
|
header_data = await get_data_chunk(_HEADER_SIZE, offset)
|
|
|
|
header_data = await get_data_chunk(_HEADER_SIZE, 0)
|
|
|
|
header = TranslationsHeader.from_bytes(header_data)
|
|
|
|
header = TranslationsHeader.from_bytes(header_data)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# Verifying header information
|
|
|
|
|
|
|
|
# TODO: verify the header signature (signature of sha256(header))
|
|
|
|
if header.data_length + _HEADER_SIZE != data_length:
|
|
|
|
if header.data_length + _HEADER_SIZE != data_length:
|
|
|
|
raise DataError("Invalid header data length")
|
|
|
|
raise DataError("Invalid header data length")
|
|
|
|
|
|
|
|
# TODO: how to handle the version updates - numbers have to be bumped in cs.json and others
|
|
|
|
# TODO: verify the hash of the data (get all of them and hash them)
|
|
|
|
# (or have this logic in a separate blob-creating tool)
|
|
|
|
# TODO: verify the header signature (signature of sha256(header))
|
|
|
|
if header.version_tuple() != (
|
|
|
|
|
|
|
|
utils.VERSION_MAJOR,
|
|
|
|
|
|
|
|
utils.VERSION_MINOR,
|
|
|
|
|
|
|
|
utils.VERSION_PATCH,
|
|
|
|
|
|
|
|
):
|
|
|
|
|
|
|
|
raise DataError("Invalid translations version")
|
|
|
|
|
|
|
|
|
|
|
|
# Confirm with user and wipe old data
|
|
|
|
# Confirm with user and wipe old data
|
|
|
|
await _require_confirm_change_language(header.language)
|
|
|
|
await _require_confirm_change_language(header.language)
|
|
|
|
translations.wipe()
|
|
|
|
translations.wipe()
|
|
|
|
|
|
|
|
|
|
|
|
# Write the header
|
|
|
|
# Write the header
|
|
|
|
translations.write(header_data, offset)
|
|
|
|
translations.write(header_data, 0)
|
|
|
|
offset += len(header_data)
|
|
|
|
|
|
|
|
data_left -= len(header_data)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# Requesting the data in chunks and saving them
|
|
|
|
# Requesting the data in chunks and saving them
|
|
|
|
|
|
|
|
# Also checking the hash of the data for consistency
|
|
|
|
|
|
|
|
data_left = data_length - len(header_data)
|
|
|
|
|
|
|
|
offset = len(header_data)
|
|
|
|
|
|
|
|
hash_writer = utils.HashWriter(sha256())
|
|
|
|
while data_left > 0:
|
|
|
|
while data_left > 0:
|
|
|
|
data_chunk = await get_data_chunk(data_left, offset)
|
|
|
|
data_chunk = await get_data_chunk(data_left, offset)
|
|
|
|
translations.write(data_chunk, offset)
|
|
|
|
translations.write(data_chunk, offset)
|
|
|
|
|
|
|
|
hash_writer.write(data_chunk)
|
|
|
|
data_left -= len(data_chunk)
|
|
|
|
data_left -= len(data_chunk)
|
|
|
|
offset += len(data_chunk)
|
|
|
|
offset += len(data_chunk)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# When the data do not match the hash, wipe all the written translations
|
|
|
|
|
|
|
|
if hash_writer.get_digest() != header.data_hash:
|
|
|
|
|
|
|
|
translations.wipe()
|
|
|
|
|
|
|
|
raise DataError("Invalid data hash")
|
|
|
|
|
|
|
|
|
|
|
|
return Success(message="Language changed")
|
|
|
|
return Success(message="Language changed")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|