mirror of
https://github.com/agessaman/MeshCore.git
synced 2026-08-28 11:54:17 +00:00
feat(mqtt): add mesh-chaun14 and wcmesh presets
Support "{pubkey}" username sentinel so brokers can auth with the
device public key without enlarging the prefs username field.
This commit is contained in:
@@ -390,6 +390,12 @@ bool CommonCLI::handleObserverSetCmd(uint32_t sender_timestamp, const char* conf
|
||||
} else if (p && p->topic_style == MQTT_TOPIC_MESHCORE &&
|
||||
(strlen(_mqtt_prefs.mqtt_iata) == 0 || strcmp(_mqtt_prefs.mqtt_iata, "XXX") == 0)) {
|
||||
sprintf(reply, "OK - slot %d preset: %s (run 'set mqtt.iata <airport_code>' to publish)", slot + 1, preset_name);
|
||||
} else if (p && mqttPresetNeedsSlotPassword(p) &&
|
||||
_mqtt_prefs.mqtt_slot_password[slot][0] == '\0' &&
|
||||
!mqttPresetNeedsSlotUsername(p)) {
|
||||
sprintf(reply,
|
||||
"OK - slot %d preset: %s (run 'set mqtt%d.password <pass>' to connect)",
|
||||
slot + 1, preset_name, slot + 1);
|
||||
} else if (p && mqttPresetNeedsSlotCredentials(p) &&
|
||||
(_mqtt_prefs.mqtt_slot_username[slot][0] == '\0' ||
|
||||
_mqtt_prefs.mqtt_slot_password[slot][0] == '\0')) {
|
||||
|
||||
@@ -40,10 +40,32 @@ struct MQTTPresetDef {
|
||||
const char* userpass_password; // MQTT_AUTH_USERPASS: embedded password, or nullptr to use mqttN.password
|
||||
};
|
||||
|
||||
// True when preset uses MQTT_AUTH_USERPASS but credentials come from slot prefs (mqttN.username/password).
|
||||
static inline bool mqttPresetNeedsSlotCredentials(const MQTTPresetDef* preset) {
|
||||
// Sentinel: resolve MQTT username from device public-key hex at connect time.
|
||||
// Braces match topic placeholders ({device}/{iata}); never send this string to the broker.
|
||||
static const char MQTT_USERPASS_USERNAME_PUBKEY[] = "{pubkey}";
|
||||
|
||||
static inline bool mqttPresetUsesDevicePubkeyUsername(const MQTTPresetDef* preset) {
|
||||
return preset && preset->auth_type == MQTT_AUTH_USERPASS &&
|
||||
(!preset->userpass_username || !preset->userpass_password);
|
||||
preset->userpass_username &&
|
||||
strcmp(preset->userpass_username, MQTT_USERPASS_USERNAME_PUBKEY) == 0;
|
||||
}
|
||||
|
||||
// True when USERPASS username must come from mqttN.username (null embedded username).
|
||||
// "{pubkey}" is an embedded sentinel, so it does not need a slot username.
|
||||
static inline bool mqttPresetNeedsSlotUsername(const MQTTPresetDef* preset) {
|
||||
return preset && preset->auth_type == MQTT_AUTH_USERPASS &&
|
||||
!preset->userpass_username;
|
||||
}
|
||||
|
||||
// True when USERPASS password must come from mqttN.password (null embedded password).
|
||||
static inline bool mqttPresetNeedsSlotPassword(const MQTTPresetDef* preset) {
|
||||
return preset && preset->auth_type == MQTT_AUTH_USERPASS &&
|
||||
!preset->userpass_password;
|
||||
}
|
||||
|
||||
// True when preset uses MQTT_AUTH_USERPASS but at least one credential comes from slot prefs.
|
||||
static inline bool mqttPresetNeedsSlotCredentials(const MQTTPresetDef* preset) {
|
||||
return mqttPresetNeedsSlotUsername(preset) || mqttPresetNeedsSlotPassword(preset);
|
||||
}
|
||||
|
||||
// Google Trust Services - GTS Root R4 (used by LetsMesh Analyzer)
|
||||
@@ -105,7 +127,7 @@ static const char ISRG_ROOT_X1[] PROGMEM =
|
||||
"-----END CERTIFICATE-----\n";
|
||||
|
||||
// Number of built-in presets
|
||||
static const int MQTT_PRESET_COUNT = 27;
|
||||
static const int MQTT_PRESET_COUNT = 29;
|
||||
|
||||
// Built-in preset definitions (stored in flash)
|
||||
static const MQTTPresetDef MQTT_PRESETS[MQTT_PRESET_COUNT] = {
|
||||
@@ -142,6 +164,10 @@ static const MQTTPresetDef MQTT_PRESETS[MQTT_PRESET_COUNT] = {
|
||||
{ "flmesh", "wss://mcmqtt.jntconnections.com:443", "mcmqtt.jntconnections.com", GTS_ROOT_R4, MQTT_AUTH_JWT, MQTT_TOPIC_MESHCORE, 0, true, 55, nullptr, nullptr },
|
||||
{ "corecomms", "wss://mqtt.corecomms.net:443/mqtt", "mqtt.corecomms.net", GTS_ROOT_R4, MQTT_AUTH_JWT, MQTT_TOPIC_MESHCORE, 0, true, 55, nullptr, nullptr },
|
||||
{ "meshtexas", "wss://mqtt.meshtexas.org:443/mqtt", "mqtt.meshtexas.org", GTS_ROOT_R4, MQTT_AUTH_JWT, MQTT_TOPIC_MESHCORE, 0, true, 55, nullptr, nullptr },
|
||||
// Username is device pubkey hex at connect; password from mqttN.password. No TLS.
|
||||
{ "mesh-chaun14", "mqtt://mqtt.mesh.chaun14.fr:1884", nullptr, nullptr, MQTT_AUTH_USERPASS, MQTT_TOPIC_MESHCORE, 0, true, 60, MQTT_USERPASS_USERNAME_PUBKEY, nullptr },
|
||||
// LetsMesh-compatible JWT; TLS is Let's Encrypt (ISRG Root X1), not GTS.
|
||||
{ "wcmesh", "wss://mqtt.wcmesh.com:443", "mqtt.wcmesh.com", ISRG_ROOT_X1, MQTT_AUTH_JWT, MQTT_TOPIC_MESHCORE, 0, true, 55, nullptr, nullptr },
|
||||
};
|
||||
|
||||
// Find a preset by name, returns nullptr if not found
|
||||
|
||||
@@ -1395,10 +1395,19 @@ void MQTTBridge::setupSlot(int index) {
|
||||
slot.client->setCredentials(_jwt_username, slot.auth_token);
|
||||
}
|
||||
} else if (slot.preset->auth_type == MQTT_AUTH_USERPASS) {
|
||||
if (slot.preset->userpass_username && slot.preset->userpass_password) {
|
||||
slot.client->setCredentials(slot.preset->userpass_username, slot.preset->userpass_password);
|
||||
} else if (strlen(slot.username) > 0) {
|
||||
slot.client->setCredentials(slot.username, slot.password);
|
||||
const char* user = nullptr;
|
||||
const char* pass = slot.preset->userpass_password
|
||||
? slot.preset->userpass_password
|
||||
: slot.password;
|
||||
if (mqttPresetUsesDevicePubkeyUsername(slot.preset)) {
|
||||
user = _device_id; // never send "{pubkey}" literally
|
||||
} else if (slot.preset->userpass_username) {
|
||||
user = slot.preset->userpass_username;
|
||||
} else if (slot.username[0] != '\0') {
|
||||
user = slot.username;
|
||||
}
|
||||
if (user && user[0] != '\0' && pass && pass[0] != '\0') {
|
||||
slot.client->setCredentials(user, pass);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@@ -2310,15 +2319,15 @@ bool MQTTBridge::isSlotReady(int index, char* reason_buf, size_t reason_size) co
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (mqttPresetNeedsSlotCredentials(slot.preset)) {
|
||||
if (_obs->mqtt_slot_username[index][0] == '\0') {
|
||||
if (reason_buf) snprintf(reason_buf, reason_size, "set mqtt%d.username <user>", index + 1);
|
||||
return false;
|
||||
}
|
||||
if (_obs->mqtt_slot_password[index][0] == '\0') {
|
||||
if (reason_buf) snprintf(reason_buf, reason_size, "set mqtt%d.password <pass>", index + 1);
|
||||
return false;
|
||||
}
|
||||
if (mqttPresetNeedsSlotUsername(slot.preset) &&
|
||||
_obs->mqtt_slot_username[index][0] == '\0') {
|
||||
if (reason_buf) snprintf(reason_buf, reason_size, "set mqtt%d.username <user>", index + 1);
|
||||
return false;
|
||||
}
|
||||
if (mqttPresetNeedsSlotPassword(slot.preset) &&
|
||||
_obs->mqtt_slot_password[index][0] == '\0') {
|
||||
if (reason_buf) snprintf(reason_buf, reason_size, "set mqtt%d.password <pass>", index + 1);
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
// Custom slot without a topic template uses meshcore format, needs IATA
|
||||
|
||||
Reference in New Issue
Block a user