Clean-up string sanitation helpers (#2660)

This commit is contained in:
Oxan van Leeuwen 2021-11-10 19:42:41 +01:00 committed by GitHub
parent 92321e219a
commit 4d43396835
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 37 additions and 44 deletions

View file

@ -17,7 +17,7 @@ static const char *const TAG = "mqtt.component";
void MQTTComponent::set_retain(bool retain) { this->retain_ = retain; } void MQTTComponent::set_retain(bool retain) { this->retain_ = retain; }
std::string MQTTComponent::get_discovery_topic_(const MQTTDiscoveryInfo &discovery_info) const { std::string MQTTComponent::get_discovery_topic_(const MQTTDiscoveryInfo &discovery_info) const {
std::string sanitized_name = sanitize_string_allowlist(App.get_name(), HOSTNAME_CHARACTER_ALLOWLIST); std::string sanitized_name = str_sanitize(App.get_name());
return discovery_info.prefix + "/" + this->component_type() + "/" + sanitized_name + "/" + return discovery_info.prefix + "/" + this->component_type() + "/" + sanitized_name + "/" +
this->get_default_object_id_() + "/config"; this->get_default_object_id_() + "/config";
} }
@ -136,7 +136,7 @@ bool MQTTComponent::is_discovery_enabled() const {
} }
std::string MQTTComponent::get_default_object_id_() const { std::string MQTTComponent::get_default_object_id_() const {
return sanitize_string_allowlist(to_lowercase_underscore(this->friendly_name()), HOSTNAME_CHARACTER_ALLOWLIST); return str_sanitize(str_snake_case(this->friendly_name()));
} }
void MQTTComponent::subscribe(const std::string &topic, mqtt_callback_t callback, uint8_t qos) { void MQTTComponent::subscribe(const std::string &topic, mqtt_callback_t callback, uint8_t qos) {

View file

@ -35,7 +35,7 @@ const std::string &EntityBase::get_object_id() { return this->object_id_; }
// Calculate Object ID Hash from Entity Name // Calculate Object ID Hash from Entity Name
void EntityBase::calc_object_id_() { void EntityBase::calc_object_id_() {
this->object_id_ = sanitize_string_allowlist(to_lowercase_underscore(this->name_), HOSTNAME_CHARACTER_ALLOWLIST); this->object_id_ = str_sanitize(str_snake_case(this->name_));
// FNV-1 hash // FNV-1 hash
this->object_id_hash_ = fnv1_hash(this->object_id_); this->object_id_hash_ = fnv1_hash(this->object_id_);
} }

View file

@ -128,31 +128,6 @@ float gamma_uncorrect(float value, float gamma) {
return powf(value, 1 / gamma); return powf(value, 1 / gamma);
} }
std::string to_lowercase_underscore(std::string s) {
std::transform(s.begin(), s.end(), s.begin(), ::tolower);
std::replace(s.begin(), s.end(), ' ', '_');
return s;
}
std::string sanitize_string_allowlist(const std::string &s, const std::string &allowlist) {
std::string out(s);
out.erase(std::remove_if(out.begin(), out.end(),
[&allowlist](const char &c) { return allowlist.find(c) == std::string::npos; }),
out.end());
return out;
}
std::string sanitize_hostname(const std::string &hostname) {
std::string s = sanitize_string_allowlist(hostname, HOSTNAME_CHARACTER_ALLOWLIST);
return truncate_string(s, 63);
}
std::string truncate_string(const std::string &s, size_t length) {
if (s.length() > length)
return s.substr(0, length);
return s;
}
std::string value_accuracy_to_string(float value, int8_t accuracy_decimals) { std::string value_accuracy_to_string(float value, int8_t accuracy_decimals) {
if (accuracy_decimals < 0) { if (accuracy_decimals < 0) {
auto multiplier = powf(10.0f, accuracy_decimals); auto multiplier = powf(10.0f, accuracy_decimals);
@ -191,8 +166,6 @@ ParseOnOffState parse_on_off(const char *str, const char *on, const char *off) {
return PARSE_NONE; return PARSE_NONE;
} }
const char *const HOSTNAME_CHARACTER_ALLOWLIST = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_";
uint8_t crc8(uint8_t *data, uint8_t len) { uint8_t crc8(uint8_t *data, uint8_t len) {
uint8_t crc = 0; uint8_t crc = 0;
@ -481,4 +454,24 @@ IRAM_ATTR InterruptLock::InterruptLock() { portDISABLE_INTERRUPTS(); }
IRAM_ATTR InterruptLock::~InterruptLock() { portENABLE_INTERRUPTS(); } IRAM_ATTR InterruptLock::~InterruptLock() { portENABLE_INTERRUPTS(); }
#endif #endif
// ---------------------------------------------------------------------------------------------------------------------
std::string str_truncate(const std::string &str, size_t length) {
return str.length() > length ? str.substr(0, length) : str;
}
std::string str_snake_case(const std::string &str) {
std::string result;
result.resize(str.length());
std::transform(str.begin(), str.end(), result.begin(), ::tolower);
std::replace(result.begin(), result.end(), ' ', '_');
return result;
}
std::string str_sanitize(const std::string &str) {
std::string out;
std::copy_if(str.begin(), str.end(), std::back_inserter(out), [](const char &c) {
return c == '-' || c == '_' || (c >= '0' && c <= '9') || (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z');
});
return out;
}
} // namespace esphome } // namespace esphome

View file

@ -25,9 +25,6 @@
namespace esphome { namespace esphome {
/// The characters that are allowed in a hostname.
extern const char *const HOSTNAME_CHARACTER_ALLOWLIST;
/// Read the raw MAC address into the provided byte array (6 bytes). /// Read the raw MAC address into the provided byte array (6 bytes).
void get_mac_address_raw(uint8_t *mac); void get_mac_address_raw(uint8_t *mac);
@ -55,14 +52,6 @@ std::string to_string(double val);
std::string to_string(long double val); std::string to_string(long double val);
optional<int> parse_hex(const std::string &str, size_t start, size_t length); optional<int> parse_hex(const std::string &str, size_t start, size_t length);
optional<int> parse_hex(char chr); optional<int> parse_hex(char chr);
/// Sanitize the hostname by removing characters that are not in the allowlist and truncating it to 63 chars.
std::string sanitize_hostname(const std::string &hostname);
/// Truncate a string to a specific length
std::string truncate_string(const std::string &s, size_t length);
/// Convert the string to lowercase_underscore.
std::string to_lowercase_underscore(std::string s);
/// Compare string a to string b (ignoring case) and return whether they are equal. /// Compare string a to string b (ignoring case) and return whether they are equal.
bool str_equals_case_insensitive(const std::string &a, const std::string &b); bool str_equals_case_insensitive(const std::string &a, const std::string &b);
@ -145,9 +134,6 @@ std::string uint64_to_string(uint64_t num);
/// Convert a uint32_t to a hex string /// Convert a uint32_t to a hex string
std::string uint32_to_string(uint32_t num); std::string uint32_to_string(uint32_t num);
/// Sanitizes the input string with the allowlist.
std::string sanitize_string_allowlist(const std::string &s, const std::string &allowlist);
uint8_t reverse_bits_8(uint8_t x); uint8_t reverse_bits_8(uint8_t x);
uint16_t reverse_bits_16(uint16_t x); uint16_t reverse_bits_16(uint16_t x);
uint32_t reverse_bits_32(uint32_t x); uint32_t reverse_bits_32(uint32_t x);
@ -331,6 +317,20 @@ template<typename T, enable_if_t<std::is_unsigned<T>::value, int> = 0> constexpr
///@} ///@}
/// @name Strings
///@{
/// Truncate a string to a specific length.
std::string str_truncate(const std::string &str, size_t length);
/// Convert the string to snake case (lowercase with underscores).
std::string str_snake_case(const std::string &str);
/// Sanitizes the input string by removing all characters but alphanumerics, dashes and underscores.
std::string str_sanitize(const std::string &str);
///@}
/// @name Parsing & formatting /// @name Parsing & formatting
///@{ ///@{