mirror of
https://github.com/ByteWelder/Tactility.git
synced 2026-08-17 23:55:04 +00:00
App metadata filtering in app-module
This commit is contained in:
parent
623ed9414c
commit
e75016f5cf
@ -13,6 +13,8 @@ extern "C" {
|
||||
#define APP_METADATA_APP_ID_LENGTH 32
|
||||
#define APP_METADATA_APP_NAME_LENGTH 32
|
||||
#define APP_METADATA_APP_VERSION_NAME_LENGTH 16
|
||||
#define APP_METADATA_REQUIRES_DEVICE_ARCH_LENGTH 32
|
||||
#define APP_METADATA_REQUIRES_DEVICE_ID_LENGTH 64
|
||||
|
||||
struct AppMetadata {
|
||||
|
||||
@ -42,6 +44,20 @@ struct AppMetadata {
|
||||
|
||||
/** The technical version (must be incremented with new releases of the app) */
|
||||
uint64_t app_version_code;
|
||||
|
||||
/**
|
||||
* Comma-separated list of MCU architectures the app is restricted to (e.g. "esp32s3,esp32p4"),
|
||||
* matching ESP-IDF target names. Empty means unrestricted.
|
||||
* Must be NULL-terminated.
|
||||
*/
|
||||
char requires_device_arch[APP_METADATA_REQUIRES_DEVICE_ARCH_LENGTH + 1];
|
||||
|
||||
/**
|
||||
* Comma-separated list of device ids the app is restricted to (e.g. "m5stack-tab5"), matching
|
||||
* the folder names under Devices/. Empty means unrestricted.
|
||||
* Must be NULL-terminated.
|
||||
*/
|
||||
char requires_device_id[APP_METADATA_REQUIRES_DEVICE_ID_LENGTH + 1];
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@ -18,6 +18,12 @@ bool app_metadata_is_valid_name(const std::string& name);
|
||||
bool app_metadata_is_valid_version_name(const std::string& version);
|
||||
bool app_metadata_is_valid_version_code(const std::string& version);
|
||||
|
||||
/** Validates a comma-separated list of MCU architecture names (alphanumeric items only). */
|
||||
bool app_metadata_is_valid_device_arch_list(const std::string& value);
|
||||
|
||||
/** Validates a comma-separated list of device ids (alphanumeric + '-' items, matching Devices/<id> folder names). */
|
||||
bool app_metadata_is_valid_device_id_list(const std::string& value);
|
||||
|
||||
/** Copies @a value into @a dest (a fixed-size buffer of @a dest_size bytes, including the NULL
|
||||
* terminator) if it fits.
|
||||
* @retval false @a value doesn't fit in @a dest_size bytes - @a dest is left untouched */
|
||||
|
||||
@ -37,6 +37,26 @@ bool validate_string(const std::string& value, bool (*is_valid_char)(char)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
/** Validates a comma-separated list: non-empty, no leading/trailing/double commas (which would
|
||||
* produce an empty item), and every item passing @a is_valid_item_char. */
|
||||
bool validate_csv_list(const std::string& value, bool (*is_valid_item_char)(char)) {
|
||||
if (value.empty()) {
|
||||
return false;
|
||||
}
|
||||
size_t start = 0;
|
||||
while (true) {
|
||||
auto comma = value.find(',', start);
|
||||
auto end = comma == std::string::npos ? value.size() : comma;
|
||||
if (end == start || !validate_string(value.substr(start, end - start), is_valid_item_char)) {
|
||||
return false;
|
||||
}
|
||||
if (comma == std::string::npos) {
|
||||
return true;
|
||||
}
|
||||
start = comma + 1;
|
||||
}
|
||||
}
|
||||
|
||||
/** manifest.properties format: "key=value" lines, "[section]" lines prefix every following key
|
||||
* until the next section, "#" lines are comments, blank lines are skipped. Deliberately a local,
|
||||
* minimal re-implementation rather than depending on Tactility's file::loadPropertiesFile() -
|
||||
@ -130,6 +150,18 @@ bool app_metadata_is_valid_version_code(const std::string& version) {
|
||||
});
|
||||
}
|
||||
|
||||
bool app_metadata_is_valid_device_arch_list(const std::string& value) {
|
||||
return validate_csv_list(value, [](char c) {
|
||||
return std::isalnum(static_cast<unsigned char>(c)) != 0;
|
||||
});
|
||||
}
|
||||
|
||||
bool app_metadata_is_valid_device_id_list(const std::string& value) {
|
||||
return validate_csv_list(value, [](char c) {
|
||||
return std::isalnum(static_cast<unsigned char>(c)) != 0 || c == '-';
|
||||
});
|
||||
}
|
||||
|
||||
bool app_metadata_copy_bounded(char* dest, size_t dest_size, const std::string& value) {
|
||||
if (value.size() >= dest_size) {
|
||||
return false;
|
||||
@ -141,6 +173,10 @@ bool app_metadata_copy_bounded(char* dest, size_t dest_size, const std::string&
|
||||
error_t app_metadata_parse(const char* path, struct AppMetadata* out_metadata) {
|
||||
LOG_I(TAG, "Parsing manifest %s", path);
|
||||
|
||||
// Both requires.* fields are optional in V2 and unwritten by V1; zeroing here (rather than
|
||||
// relying on the caller) guarantees they read back as empty ("unrestricted") either way.
|
||||
*out_metadata = {};
|
||||
|
||||
std::map<std::string, std::string> properties;
|
||||
std::string first_line;
|
||||
if (!load_properties(path, properties, first_line)) {
|
||||
|
||||
@ -99,5 +99,33 @@ bool app_metadata_parse_v2(const std::map<std::string, std::string>& properties,
|
||||
return false;
|
||||
}
|
||||
|
||||
// requires (optional; if present, must be a non-empty comma-separated list)
|
||||
|
||||
auto device_arch_iterator = properties.find("requires.device.arch");
|
||||
if (device_arch_iterator != properties.end()) {
|
||||
const std::string& device_arch = device_arch_iterator->second;
|
||||
if (!app_metadata_is_valid_device_arch_list(device_arch)) {
|
||||
LOG_E(TAG, "Invalid requires.device.arch");
|
||||
return false;
|
||||
}
|
||||
if (!app_metadata_copy_bounded(out_metadata.requires_device_arch, sizeof(out_metadata.requires_device_arch), device_arch)) {
|
||||
LOG_E(TAG, "requires.device.arch too long");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
auto device_id_iterator = properties.find("requires.device.id");
|
||||
if (device_id_iterator != properties.end()) {
|
||||
const std::string& device_id = device_id_iterator->second;
|
||||
if (!app_metadata_is_valid_device_id_list(device_id)) {
|
||||
LOG_E(TAG, "Invalid requires.device.id");
|
||||
return false;
|
||||
}
|
||||
if (!app_metadata_copy_bounded(out_metadata.requires_device_id, sizeof(out_metadata.requires_device_id), device_id)) {
|
||||
LOG_E(TAG, "requires.device.id too long");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user