Files
MeshCore/src/helpers/CompanionChannelAlias.h
T

84 lines
3.3 KiB
C++

#pragma once
#include <stddef.h>
#include <stdint.h>
#include <string.h>
#include <helpers/RadioProfilePresets.h>
// Local labels, not part of a hashtag PSK. Keep the original app label/key.
enum class CompanionChannelKind : uint8_t { MeshCore, Radio2, Meshtext, Invalid };
struct CompanionChannelAlias {
CompanionChannelKind kind;
bool hashtag;
const char* tail;
};
inline CompanionChannelAlias parseCompanionChannelAlias(const char* name) {
if (name == nullptr) return {CompanionChannelKind::Invalid, false, ""};
const bool hashtag = name[0] == '#';
const char* tail = name + (hashtag ? 1 : 0);
CompanionChannelKind kind = CompanionChannelKind::MeshCore;
if (strncmp(tail, "r2-", 3) == 0) {
kind = CompanionChannelKind::Radio2;
tail += 3;
} else if (strncmp(tail, "mt-", 3) == 0) {
kind = CompanionChannelKind::Meshtext;
tail += 3;
}
if (kind != CompanionChannelKind::MeshCore
&& (tail[0] == 0 || tail[0] == '#' || strncmp(tail, "r2-", 3) == 0
|| strncmp(tail, "mt-", 3) == 0)) kind = CompanionChannelKind::Invalid;
return {kind, hashtag, tail};
}
// Only exact named radio2 aliases request RF setup. Ordinary channels and
// arbitrary r2 labels keep the operator's existing profile.
inline const char* companionChannelRadio2Preset(const char* name) {
if (!name) return nullptr;
if (*name == '#') ++name;
if (strncmp(name, "r2-", 3)) return nullptr;
name += 3;
// An exact preset tail also excludes every invalid/nested alias form.
return mesh::cli::radio2PresetTuple(name) ? name : nullptr;
}
inline bool companionChannelCanonicalName(const char* name, char* out, size_t size) {
if (out == nullptr) return false;
const auto alias = parseCompanionChannelAlias(name);
if (alias.kind == CompanionChannelKind::Invalid) return false;
const size_t offset = alias.hashtag ? 1 : 0;
const size_t length = strlen(alias.tail);
if (size <= offset + length) return false;
if (offset) out[0] = '#';
memcpy(out + offset, alias.tail, length + 1);
return true;
}
template <typename Hash>
bool resolveCompanionChannelKey(const char* name, uint8_t secret[32], Hash hash) {
const auto alias = parseCompanionChannelAlias(name);
if (alias.kind == CompanionChannelKind::Invalid) return false;
if (alias.kind == CompanionChannelKind::MeshCore || !alias.hashtag) return true;
for (size_t i = 16; i < 32; ++i) {
if (secret[i] != 0) return true; // Never rewrite an explicit 256-bit PSK.
}
uint8_t app_key[16];
hash(app_key, sizeof(app_key), reinterpret_cast<const uint8_t*>(name), strlen(name));
if (memcmp(secret, app_key, sizeof(app_key)) != 0) return true; // Custom PSK.
char canonical[32];
if (!companionChannelCanonicalName(name, canonical, sizeof(canonical))) return false;
hash(secret, 16, reinterpret_cast<const uint8_t*>(canonical), strlen(canonical));
return true;
}
inline int companionChannelReceivePriority(const char* name, uint8_t origin,
bool radio2_defined = true) {
const auto alias = parseCompanionChannelAlias(name);
if (alias.kind == CompanionChannelKind::Invalid) return -1;
if (radio2_defined) {
if (alias.kind == CompanionChannelKind::Meshtext) return -1;
if (alias.kind == CompanionChannelKind::Radio2) return origin == 1 ? 0 : -1;
}
return origin == 1 ? 1 : 0;
}