Review changes
This commit is contained in:
@@ -30,6 +30,19 @@ bool FontInstaller::isValidFamilyName(const char* name) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool FontInstaller::isValidFontFileName(const char* name) {
|
||||||
|
if (name == nullptr || name[0] == '\0') return false;
|
||||||
|
// Matches the cap used by the web-server manifest parser; the SD-side path buffer is 128
|
||||||
|
// bytes including the family prefix, so 60 leaves plenty of headroom.
|
||||||
|
static constexpr size_t MAX_FONT_FILE_NAME_LEN = 60;
|
||||||
|
const size_t nameLen = strlen(name);
|
||||||
|
if (nameLen > MAX_FONT_FILE_NAME_LEN) return false;
|
||||||
|
if (name[0] == '/') return false;
|
||||||
|
if (strchr(name, '\\') != nullptr) return false;
|
||||||
|
if (strstr(name, "..") != nullptr) return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
bool FontInstaller::ensureFamilyDir(const char* familyName) {
|
bool FontInstaller::ensureFamilyDir(const char* familyName) {
|
||||||
if (!isValidFamilyName(familyName)) {
|
if (!isValidFamilyName(familyName)) {
|
||||||
LOG_ERR("FONT", "Invalid family name: %s", familyName ? familyName : "<null>");
|
LOG_ERR("FONT", "Invalid family name: %s", familyName ? familyName : "<null>");
|
||||||
|
|||||||
@@ -25,6 +25,11 @@ class FontInstaller {
|
|||||||
/// Validate a family name: alphanumeric + hyphen + underscore only, no path traversal.
|
/// Validate a family name: alphanumeric + hyphen + underscore only, no path traversal.
|
||||||
static bool isValidFamilyName(const char* name);
|
static bool isValidFamilyName(const char* name);
|
||||||
|
|
||||||
|
/// Validate a font file name as it appears in a manifest entry: non-empty, length-bounded,
|
||||||
|
/// no absolute paths, no backslashes, no traversal components. Slashes are allowed for
|
||||||
|
/// "<family>/<file>"-style entries.
|
||||||
|
static bool isValidFontFileName(const char* name);
|
||||||
|
|
||||||
/// Ensure /.crosspoint/fonts/<family>/ directory exists.
|
/// Ensure /.crosspoint/fonts/<family>/ directory exists.
|
||||||
bool ensureFamilyDir(const char* familyName);
|
bool ensureFamilyDir(const char* familyName);
|
||||||
|
|
||||||
|
|||||||
@@ -130,7 +130,13 @@ bool FontDownloadActivity::fetchAndParseManifest() {
|
|||||||
family.description = fObj["description"] | "";
|
family.description = fObj["description"] | "";
|
||||||
// styles[] in the JSON is intentionally ignored — see ManifestFamily.
|
// styles[] in the JSON is intentionally ignored — see ManifestFamily.
|
||||||
|
|
||||||
|
if (!FontInstaller::isValidFamilyName(family.name.c_str())) {
|
||||||
|
LOG_ERR("FONT", "Manifest entry rejected, invalid family name: %s", family.name.c_str());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
family.totalSize = 0;
|
family.totalSize = 0;
|
||||||
|
bool fileNamesOk = true;
|
||||||
for (JsonObject fileObj : fObj["files"].as<JsonArray>()) {
|
for (JsonObject fileObj : fObj["files"].as<JsonArray>()) {
|
||||||
ManifestFile file;
|
ManifestFile file;
|
||||||
file.name = fileObj["name"] | "";
|
file.name = fileObj["name"] | "";
|
||||||
@@ -139,9 +145,15 @@ bool FontDownloadActivity::fetchAndParseManifest() {
|
|||||||
file.crc32 = fileObj["crc32"].as<uint32_t>();
|
file.crc32 = fileObj["crc32"].as<uint32_t>();
|
||||||
file.hasCrc32 = true;
|
file.hasCrc32 = true;
|
||||||
}
|
}
|
||||||
|
if (!FontInstaller::isValidFontFileName(file.name.c_str())) {
|
||||||
|
LOG_ERR("FONT", "Manifest entry rejected, invalid file name in %s: %s", family.name.c_str(), file.name.c_str());
|
||||||
|
fileNamesOk = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
family.totalSize += file.size;
|
family.totalSize += file.size;
|
||||||
family.files.push_back(std::move(file));
|
family.files.push_back(std::move(file));
|
||||||
}
|
}
|
||||||
|
if (!fileNamesOk) continue;
|
||||||
|
|
||||||
family.installed = fontInstaller_.isFamilyInstalled(family.name.c_str());
|
family.installed = fontInstaller_.isFamilyInstalled(family.name.c_str());
|
||||||
|
|
||||||
@@ -225,7 +237,8 @@ bool readU8(FsFile& f, uint8_t& v) { return f.read(&v, 1) == 1; }
|
|||||||
bool readU32(FsFile& f, uint32_t& v) {
|
bool readU32(FsFile& f, uint32_t& v) {
|
||||||
uint8_t buf[4];
|
uint8_t buf[4];
|
||||||
if (f.read(buf, 4) != 4) return false;
|
if (f.read(buf, 4) != 4) return false;
|
||||||
v = buf[0] | (buf[1] << 8) | (buf[2] << 16) | (buf[3] << 24);
|
v = static_cast<uint32_t>(buf[0]) | (static_cast<uint32_t>(buf[1]) << 8) | (static_cast<uint32_t>(buf[2]) << 16) |
|
||||||
|
(static_cast<uint32_t>(buf[3]) << 24);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
bool readStr(FsFile& f, std::string& s) {
|
bool readStr(FsFile& f, std::string& s) {
|
||||||
@@ -460,8 +473,17 @@ void FontDownloadActivity::downloadFamily(int familyIdx) {
|
|||||||
downloadingFamilyHasResumable_ = family.hasResumableDownload;
|
downloadingFamilyHasResumable_ = family.hasResumableDownload;
|
||||||
|
|
||||||
// Restore families_ regardless of success/error/abort outcome, then merge
|
// Restore families_ regardless of success/error/abort outcome, then merge
|
||||||
// back the mutations the impl made on the local family copy.
|
// back the mutations the impl made on the local family copy. Without the
|
||||||
if (restoreFamiliesFromSd() && familyIdx >= 0 && familyIdx < static_cast<int>(families_.size())) {
|
// restored manifest the activity can't render the family list, so a failed
|
||||||
|
// restore is fatal — drop to ERROR rather than continuing with empty state.
|
||||||
|
if (!restoreFamiliesFromSd()) {
|
||||||
|
RenderLock lock(*this);
|
||||||
|
state_ = ERROR;
|
||||||
|
pendingErrorAction_ = PendingFontAction::Download;
|
||||||
|
errorMessage_ = "Failed to restore manifest";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (familyIdx >= 0 && familyIdx < static_cast<int>(families_.size())) {
|
||||||
families_[familyIdx].installed = family.installed;
|
families_[familyIdx].installed = family.installed;
|
||||||
families_[familyIdx].hasUpdate = family.hasUpdate;
|
families_[familyIdx].hasUpdate = family.hasUpdate;
|
||||||
families_[familyIdx].hasResumableDownload = family.hasResumableDownload;
|
families_[familyIdx].hasResumableDownload = family.hasResumableDownload;
|
||||||
|
|||||||
Reference in New Issue
Block a user