Skip to content

Commit

Permalink
fix(cpn): radio specific name and label validators (#4670)
Browse files Browse the repository at this point in the history
Only allows valid characters in names, drops invalid characters if present
  • Loading branch information
Neil Horne authored Feb 28, 2024
1 parent 3807d77 commit 57c7aca
Show file tree
Hide file tree
Showing 31 changed files with 429 additions and 140 deletions.
14 changes: 9 additions & 5 deletions companion/src/firmwares/edgetx/edgetxinterface.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
#include "yaml_ops.h"
#include "yaml_generalsettings.h"
#include "yaml_modeldata.h"
#include "labelvalidator.h"

#include <QMessageBox>

Expand Down Expand Up @@ -113,11 +114,14 @@ bool loadLabelsListFromYaml(RadioData::ModelLabels& labels,
std::string lbl = it->first.as<std::string>();
RadioData::LabelData ld;
ld.name = QString::fromStdString(lbl);
if (lbls[lbl]["selected"])
ld.selected = lbls[lbl]["selected"].as<bool>();
else
ld.selected = false;
labels.append(ld);
YamlValidateLabel(ld.name);
if (!ld.name.isEmpty()) {
if (lbls[lbl]["selected"])
ld.selected = lbls[lbl]["selected"].as<bool>();
else
ld.selected = false;
labels.append(ld);
}
}
}

Expand Down
14 changes: 13 additions & 1 deletion companion/src/firmwares/edgetx/yaml_generalsettings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,17 @@

#include <QMessageBox>

void YamlValidateNames(GeneralSettings& gs, Board::Type board)
{
for (int i = 0; i < CPN_MAX_INPUTS; i++) {
YamlValidateName(gs.inputConfig[i].name, board);
}

for (int i = 0; i < CPN_MAX_SWITCHES; i++) {
YamlValidateName(gs.switchConfig[i].name, board);
}
}

const YamlLookupTable beeperModeLut = {
{ GeneralSettings::BEEPER_QUIET, "mode_quiet" },
{ GeneralSettings::BEEPER_ALARMS_ONLY, "mode_alarms" },
Expand Down Expand Up @@ -599,7 +610,8 @@ bool convert<GeneralSettings>::decode(const Node& node, GeneralSettings& rhs)
node["labelMultiMode"] >> rhs.labelMultiMode;
node["favMultiMode"] >> rhs.favMultiMode;

// fix ups
// perform integrity checks and fix-ups
YamlValidateNames(rhs, fw->getBoard());
rhs.validateFlexSwitches();

return true;
Expand Down
56 changes: 55 additions & 1 deletion companion/src/firmwares/edgetx/yaml_modeldata.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,57 @@

SemanticVersion version; // used for data conversions

void YamlValidateLabelsNames(ModelData& model, Board::Type board)
{
YamlValidateName(model.name, board);

QStringList lst = QString(model.labels).split(',', Qt::SkipEmptyParts);

for (int i = lst.count() - 1; i >= 0; i--) {
YamlValidateLabel(lst[i]);
if (lst.at(i).isEmpty())
lst.removeAt(i);
}

strcpy(model.labels, QString(lst.join(',')).toLatin1().data());

for (int i = 0; i < CPN_MAX_CURVES; i++) {
YamlValidateName(model.curves[i].name, board);
}

for (int i = 0; i < CPN_MAX_EXPOS; i++) {
YamlValidateName(model.expoData[i].name, board);
}

for (int i = 0; i < CPN_MAX_GVARS; i++) {
YamlValidateName(model.gvarData[i].name, board);
}

for (int i = 0; i < CPN_MAX_FLIGHT_MODES; i++) {
YamlValidateName(model.flightModeData[i].name, board);
}

for (int i = 0; i < CPN_MAX_SWITCHES_FUNCTION; i++) {
YamlValidateName(model.functionSwitchNames[i], board);
}

for (int i = 0; i < CPN_MAX_INPUTS; i++) {
YamlValidateName(model.inputNames[i], board);
}

for (int i = 0; i < CPN_MAX_CHNOUT; i++) {
YamlValidateName(model.limitData[i].name, board);
}

for (int i = 0; i < CPN_MAX_MIXERS; i++) {
YamlValidateName(model.mixData[i].name, board);
}

for (int i = 0; i < CPN_MAX_SENSORS; i++) {
YamlValidateName(model.sensorData[i].label, board);
}
}

static const YamlLookupTable timerModeLut = {
{TimerData::TIMERMODE_OFF, "OFF"},
{TimerData::TIMERMODE_ON, "ON"},
Expand Down Expand Up @@ -1092,6 +1143,8 @@ bool convert<ModelData>::decode(const Node& node, ModelData& rhs)
{
if (!node.IsMap()) return false;

Board::Type board = getCurrentBoard();

unsigned int modelIds[CPN_MAX_MODULES];
memset(modelIds, 0, sizeof(modelIds));

Expand Down Expand Up @@ -1151,6 +1204,7 @@ bool convert<ModelData>::decode(const Node& node, ModelData& rhs)
node["limitData"] >> rhs.limitData;

node["inputNames"] >> rhs.inputNames;

node["expoData"] >> rhs.expoData;

node["curves"] >> rhs.curves;
Expand Down Expand Up @@ -1326,7 +1380,7 @@ bool convert<ModelData>::decode(const Node& node, ModelData& rhs)
}

// perform integrity checks and fix-ups

YamlValidateLabelsNames(rhs, board);
rhs.sortMixes(); // critical for Companion and radio that mix lines are in sequence

return true;
Expand Down
28 changes: 28 additions & 0 deletions companion/src/firmwares/edgetx/yaml_ops.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@
*/

#include "yaml_ops.h"
#include "labelvalidator.h"
#include "namevalidator.h"

SemanticVersion radioSettingsVersion;
SemanticVersion modelSettingsVersion;
Expand Down Expand Up @@ -57,6 +59,32 @@ void operator >> (const YAML::Node& node, bool& value)
}
}

void YamlValidateLabel(QString &input)
{
LabelValidator *lv = new LabelValidator();

if (!lv->isValid(input)) {
lv->fixup(input);
input = input.trimmed();
}

delete lv;
}

void YamlValidateName(char *input, Board::Type board)
{
NameValidator *nv = new NameValidator(board);
QString in(input);

if (!nv->isValid(in)) {
nv->fixup(in);
in = in.trimmed();
}

strcpy(input, in.toLatin1().data());
delete nv;
}

namespace YAML {

std::string LookupValue(const YamlLookupTable& lut, const int& value)
Expand Down
7 changes: 6 additions & 1 deletion companion/src/firmwares/edgetx/yaml_ops.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,11 @@
#pragma once

#include <yaml-cpp/yaml.h>
#include "helpers.h"
#include "boards.h"

#include <algorithm>
#include <QString>
#include "helpers.h"

typedef std::pair<int, std::string> YamlLookupTableElmt;
typedef std::vector<YamlLookupTableElmt> YamlLookupTable;
Expand Down Expand Up @@ -122,6 +124,9 @@ void operator>>(const YAML::Node& node, T (&value)[N])
}
}

void YamlValidateName(char *input, Board::Type board);
void YamlValidateLabel(QString &input);

namespace YAML {

std::string LookupValue(const YamlLookupTable& lut, const int& value);
Expand Down
5 changes: 5 additions & 0 deletions companion/src/firmwares/generalsettings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
#include "eeprominterface.h"
#include "radiodataconversionstate.h"
#include "compounditemmodels.h"
#include "yaml_ops.h"

const uint8_t chout_ar[] = { // First number is 0..23 -> template setup, Second is relevant channel out
1,2,3,4 , 1,2,4,3 , 1,3,2,4 , 1,3,4,2 , 1,4,2,3 , 1,4,3,2,
Expand Down Expand Up @@ -836,13 +837,15 @@ bool GeneralSettings::convertLegacyConfiguration(Board::Type board)
{
for (int i = 0; i < CPN_MAX_STICKS && i < Boards::getCapability(board, Board::Sticks); i++) {
inputConfig[i].type = Board::AIT_STICK;
YamlValidateName(stickName[i], board);
strncpy(inputConfig[i].name, stickName[i], HARDWARE_NAME_LEN);
}

for (int i = 0; i < CPN_MAX_POTS && i < Boards::getCapability(board, Board::Pots); i++) {
int idx = Boards::getInputPotIndex(i, board);
if (idx >= 0) {
inputConfig[idx].type = Board::AIT_FLEX;
YamlValidateName(potName[i], board);
strncpy(inputConfig[idx].name, potName[i], HARDWARE_NAME_LEN);
int ft = std::stoi(DataHelpers::getStringTagMappingTag(potTypesConversionTable, potConfig[i]));
if (ft > -1)
Expand All @@ -854,6 +857,7 @@ bool GeneralSettings::convertLegacyConfiguration(Board::Type board)
int idx = Boards::getInputSliderIndex(i, board);
if (idx >= 0) {
inputConfig[idx].type = Board::AIT_FLEX;
YamlValidateName(sliderName[i], board);
strncpy(inputConfig[idx].name, sliderName[i], HARDWARE_NAME_LEN);
int ft = std::stoi(DataHelpers::getStringTagMappingTag(sliderTypesConversionTable, sliderConfig[i]));
if (ft > -1)
Expand All @@ -869,6 +873,7 @@ bool GeneralSettings::convertLegacyConfiguration(Board::Type board)

for (int i = 0; i < CPN_MAX_SWITCHES && i < Boards::getCapability(board, Board::Switches); i++) {
switchConfig[i].type = (Board::SwitchType)swtchConfig[i];
YamlValidateName(swtchName[i], board);
strncpy(switchConfig[i].name, swtchName[i], HARDWARE_NAME_LEN);
}

Expand Down
7 changes: 2 additions & 5 deletions companion/src/firmwares/modeldata.h
Original file line number Diff line number Diff line change
Expand Up @@ -46,10 +46,6 @@ class AbstractStaticItemModel;
constexpr char AIM_MODELDATA_TRAINERMODE[] {"modeldata.trainermode"};
constexpr char AIM_MODELDATA_FUNCSWITCHCONFIG[] {"modeldata.funcswitchconfig"};
constexpr char AIM_MODELDATA_FUNCSWITCHSTART[] {"modeldata.funcswitchstart"};
constexpr int LABEL_LENGTH=16;

#define CHAR_FOR_NAMES " ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_-."
#define CHAR_FOR_NAMES_REGEX "[ A-Za-z0-9_.-,\"]*"

class RSSIAlarmData {
public:
Expand Down Expand Up @@ -87,6 +83,7 @@ enum TrainerMode {
TRAINER_MODE_LAST = TRAINER_MODE_MULTI
};

#define MODEL_NAME_LEN 15
#define INPUT_NAME_LEN 4
#define CPN_MAX_BITMAP_LEN 14

Expand Down Expand Up @@ -125,7 +122,7 @@ class ModelData {

char semver[8 + 1];
bool used;
char name[15+1];
char name[MODEL_NAME_LEN + 1];
char filename[16+1];
char labels[100];
int modelIndex; // Companion only, temporary index position managed by data model.
Expand Down
21 changes: 10 additions & 11 deletions companion/src/firmwares/radiodata.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -109,8 +109,8 @@ void RadioData::convert(RadioDataConversionState & cstate)
void RadioData::addLabel(QString label)
{
label = unEscapeCSV(label);
// Truncate possible UTF-8 to 16char maximum
QByteArray output = label.toUtf8();
// Truncate possible UTF-8 to 16 char maximum
QByteArray output = label.toLatin1();
if (output.size() > LABEL_LENGTH) {
int truncateAt = 0;
for (int i = LABEL_LENGTH; i > 0; i--) {
Expand All @@ -135,12 +135,12 @@ bool RadioData::deleteLabel(QString label)

// Remove labels in the models
for(auto& model : models) {
QStringList modelLabels = fromCSV(QString::fromUtf8(model.labels));
QStringList modelLabels = fromCSV(QString::fromLatin1(model.labels));
if (modelLabels.indexOf(label) >= 0) {
deleted = true;
modelLabels.removeAll(label);
}
strcpy(model.labels, toCSV(modelLabels).toUtf8().data());
strcpy(model.labels, toCSV(modelLabels).toLatin1().data());
}

// Remove the label from the global list
Expand Down Expand Up @@ -186,8 +186,8 @@ bool RadioData::renameLabel(QString from, QString to)
if (ind != -1) {
modelLabels.replace(ind, csvTo);
QString outputcsv = QString(modelLabels.join(','));
if (outputcsv.toUtf8().size() < (int)sizeof(model.labels)) {
strcpy(model.labels, outputcsv.toUtf8().data());
if (outputcsv.toLatin1().size() < (int)sizeof(model.labels)) {
strcpy(model.labels, outputcsv.toLatin1().data());
} else { // Shouldn't ever get here, from check above
success = false;
throw std::length_error(model.name);
Expand Down Expand Up @@ -231,10 +231,10 @@ bool RadioData::addLabelToModel(int index, QString label)
char *modelLabelCsv = models[index].labels;
// Make sure it will fit
if (strlen(modelLabelCsv) + label.size() + 1 < sizeof(models[index].labels)-1) {
QStringList modelLabels = QString::fromUtf8(modelLabelCsv).split(',', Qt::SkipEmptyParts);
QStringList modelLabels = QString::fromLatin1(modelLabelCsv).split(',', Qt::SkipEmptyParts);
if (modelLabels.indexOf(label) == -1) {
modelLabels.append(label);
strcpy(models[index].labels, QString(modelLabels.join(',')).toUtf8().data());
strcpy(models[index].labels, QString(modelLabels.join(',')).toLatin1().data());
return true;
}
}
Expand All @@ -246,10 +246,10 @@ bool RadioData::removeLabelFromModel(int index, QString label)
{
if ((unsigned int)index >= models.size()) return false;

QStringList lbls = fromCSV(QString::fromUtf8(models[index].labels));
QStringList lbls = fromCSV(QString::fromLatin1(models[index].labels));
if (lbls.indexOf(label) >= 0) {
lbls.removeAll(label);
strcpy(models[index].labels, toCSV(lbls).toUtf8().data());
strcpy(models[index].labels, toCSV(lbls).toLatin1().data());
return true;
}
return false;
Expand Down Expand Up @@ -342,4 +342,3 @@ AbstractStaticItemModel * RadioData::modelSortOrderItemModel()
mdl->loadItemList();
return mdl;
}

2 changes: 2 additions & 0 deletions companion/src/firmwares/radiodata.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
// identiying names of static abstract item models
constexpr char AIM_RADIO_MODEL_SORT_ORDER[] {"radio.modelsortorder"};

constexpr int LABEL_LENGTH = 16;

class RadioDataConversionState;
class AbstractStaticItemModel;

Expand Down
4 changes: 2 additions & 2 deletions companion/src/generaledit/generalsetup.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
#include "compounditemmodels.h"
#include "filtereditemmodels.h"
#include "autocombobox.h"
#include "namevalidator.h"

GeneralSetupPanel::GeneralSetupPanel(QWidget * parent, GeneralSettings & generalSettings, Firmware * firmware):
GeneralPanel(parent, generalSettings, firmware),
Expand Down Expand Up @@ -287,8 +288,7 @@ ui(new Ui::GeneralSetup)
ui->pwrOnDelay->hide();
}

QRegExp rx(CHAR_FOR_NAMES_REGEX);
ui->registrationId->setValidator(new QRegExpValidator(rx, this));
ui->registrationId->setValidator(new NameValidator(board, this));
ui->registrationId->setMaxLength(REGISTRATION_ID_LEN);

setValues();
Expand Down
Loading

0 comments on commit 57c7aca

Please sign in to comment.