added certificate renewal, cleared formatting of code
This commit is contained in:
@@ -19,9 +19,11 @@
|
||||
#include "ConfigService.h"
|
||||
#include "Security/TlsKeyUtil.h"
|
||||
|
||||
namespace snoop {
|
||||
namespace snoop
|
||||
{
|
||||
|
||||
class AudioStreamService {
|
||||
class AudioStreamService
|
||||
{
|
||||
std::shared_ptr<ConfigService> m_cfg;
|
||||
|
||||
// WHIP
|
||||
@@ -35,25 +37,35 @@ public:
|
||||
~AudioStreamService() { StopWhip(); }
|
||||
|
||||
// Feed encoded Opus; frames = PCM samples per channel represented by this Opus frame
|
||||
void OnOpus(const unsigned char* opusData, size_t opusBytes, int pcmFramesPerChannel) {
|
||||
void OnOpus(const unsigned char *opusData, size_t opusBytes, int pcmFramesPerChannel)
|
||||
{
|
||||
std::lock_guard lk(m_whipMutex);
|
||||
if (m_whip) m_whip->PushOpus(opusData, opusBytes, pcmFramesPerChannel);
|
||||
if (m_whip)
|
||||
{
|
||||
m_whip->PushOpus(opusData, opusBytes, pcmFramesPerChannel);
|
||||
}
|
||||
}
|
||||
|
||||
bool StartWhip(const std::string& whipUrl, int sampleRate = 48000, int channels = 1) {
|
||||
bool StartWhip(const std::string &whipUrl, int sampleRate = 48000, int channels = 1)
|
||||
{
|
||||
std::lock_guard lk(m_whipMutex);
|
||||
if (m_whip) {
|
||||
if (m_whip)
|
||||
{
|
||||
spdlog::info("WHIP already started");
|
||||
return true;
|
||||
}
|
||||
if (!m_cfg) {
|
||||
if (!m_cfg)
|
||||
{
|
||||
spdlog::error("StartWhip requires ConfigService");
|
||||
return false;
|
||||
}
|
||||
|
||||
// certs from enrollment
|
||||
std::filesystem::path ca = "/etc/iot/keys/issuing_ca.pem";
|
||||
if (!std::filesystem::exists(ca)) ca = "/etc/iot/keys/ca_chain.pem";
|
||||
if (!std::filesystem::exists(ca))
|
||||
{
|
||||
ca = "/etc/iot/keys/ca_chain.pem";
|
||||
}
|
||||
std::filesystem::path crt = "/etc/iot/keys/device.crt.pem";
|
||||
|
||||
WhipClient::Params p{
|
||||
@@ -61,24 +73,28 @@ public:
|
||||
.caPath = ca.string(),
|
||||
.crtPath = crt.string(),
|
||||
.sampleRate = sampleRate,
|
||||
.channels = channels
|
||||
};
|
||||
.channels = channels};
|
||||
|
||||
m_whip = std::make_unique<WhipClient>(p);
|
||||
try {
|
||||
try
|
||||
{
|
||||
m_whip->Start();
|
||||
spdlog::info("WHIP started");
|
||||
return true;
|
||||
} catch (const std::exception& e) {
|
||||
}
|
||||
catch (const std::exception &e)
|
||||
{
|
||||
spdlog::error("WHIP start failed: {}", e.what());
|
||||
m_whip.reset();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void StopWhip() {
|
||||
void StopWhip()
|
||||
{
|
||||
std::lock_guard lk(m_whipMutex);
|
||||
if (m_whip) {
|
||||
if (m_whip)
|
||||
{
|
||||
m_whip->Stop();
|
||||
m_whip.reset();
|
||||
}
|
||||
|
||||
@@ -73,10 +73,14 @@ namespace snoop
|
||||
{
|
||||
this->m_isIntermission = true;
|
||||
if (this->m_writingThread.joinable())
|
||||
{
|
||||
this->m_writingThread.join();
|
||||
}
|
||||
if (this->m_uploadThread.joinable())
|
||||
{
|
||||
this->m_uploadThread.join();
|
||||
}
|
||||
}
|
||||
|
||||
// -------- Public control API (called from DeviceControlService handlers) --------
|
||||
|
||||
@@ -116,7 +120,9 @@ namespace snoop
|
||||
void WriteAudioData(const char *data, size_t size, size_t frames)
|
||||
{
|
||||
if (!m_recordingEnabled.load())
|
||||
{
|
||||
return;
|
||||
}
|
||||
this->m_oggWriter->Write(data, size, frames);
|
||||
}
|
||||
|
||||
@@ -176,7 +182,6 @@ namespace snoop
|
||||
{
|
||||
if (u.scheme == "https")
|
||||
{
|
||||
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
|
||||
auto cli = std::make_unique<httplib::SSLClient>(u.host.c_str(), u.port, crt.string().c_str(), key.string().c_str(), std::string());
|
||||
cli->enable_server_certificate_verification(false);
|
||||
cli->set_ca_cert_path(ca.string().c_str());
|
||||
@@ -184,9 +189,6 @@ namespace snoop
|
||||
cli->set_read_timeout(120);
|
||||
cli->set_write_timeout(120);
|
||||
return cli;
|
||||
#else
|
||||
throw std::runtime_error("HTTPS baseUrl but CPPHTTPLIB_OPENSSL_SUPPORT is not enabled");
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@@ -213,8 +215,6 @@ namespace snoop
|
||||
// still ok — reuse
|
||||
return true;
|
||||
}
|
||||
|
||||
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
|
||||
try
|
||||
{
|
||||
auto payload = snoop::device_sec::ReadClientKeyPayloadFromKeyring();
|
||||
@@ -239,12 +239,6 @@ namespace snoop
|
||||
spdlog::error("EnsureUploadClient: failed to set client cert: {}", e.what());
|
||||
return false;
|
||||
}
|
||||
#else
|
||||
(void)ca;
|
||||
(void)crt;
|
||||
spdlog::error("HTTPS baseUrl but CPPHTTPLIB_OPENSSL_SUPPORT not enabled");
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
// ----------------------------- Existing logic (adjusted) -----------------------------
|
||||
@@ -293,7 +287,9 @@ namespace snoop
|
||||
auto currentRecordDuration =
|
||||
std::chrono::duration_cast<std::chrono::milliseconds>(now.time_since_epoch()).count() - this->m_currentRecordStartedAt;
|
||||
if (currentRecordDuration >= segDurationMs)
|
||||
{
|
||||
break;
|
||||
}
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(200));
|
||||
}
|
||||
|
||||
@@ -354,9 +350,11 @@ namespace snoop
|
||||
for (const auto &entry : std::filesystem::directory_iterator(this->m_queueDirectoryPath))
|
||||
{
|
||||
if (entry.is_regular_file())
|
||||
{
|
||||
files.push_back(entry.path());
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (const std::exception &e)
|
||||
{
|
||||
spdlog::error("Error reading queue directory: {}", e.what());
|
||||
@@ -422,8 +420,9 @@ namespace snoop
|
||||
spdlog::info("SendRecordedFile (mTLS): {}", filepath);
|
||||
std::ifstream ifs(filepath, std::ios::binary);
|
||||
if (!ifs)
|
||||
{
|
||||
throw std::runtime_error("Failed to open file: " + filepath);
|
||||
|
||||
}
|
||||
std::vector<char> buffer((std::istreambuf_iterator<char>(ifs)), std::istreambuf_iterator<char>());
|
||||
|
||||
// Multipart form: file + guid + times (same fields as before)
|
||||
|
||||
@@ -49,6 +49,7 @@ namespace snoop
|
||||
TaskHandler onStopRecording;
|
||||
TaskHandler onUpdateConfig;
|
||||
TaskHandler onSetDeepSleep;
|
||||
TaskHandler onRenewCert;
|
||||
};
|
||||
|
||||
struct Controls
|
||||
@@ -68,8 +69,10 @@ namespace snoop
|
||||
{
|
||||
m_stop = true;
|
||||
if (m_thread.joinable())
|
||||
{
|
||||
m_thread.join();
|
||||
}
|
||||
}
|
||||
|
||||
void ArmDeepSleep(long long startMs, long long stopMs)
|
||||
{
|
||||
@@ -106,7 +109,9 @@ namespace snoop
|
||||
// accept with optional fractional seconds
|
||||
if (sscanf(s.c_str(), "%d-%d-%dT%d:%d:%d%n", &tm.tm_year, &tm.tm_mon, &tm.tm_mday,
|
||||
&tm.tm_hour, &tm.tm_min, &tm.tm_sec, &n) != 6)
|
||||
{
|
||||
return std::nullopt;
|
||||
}
|
||||
tm.tm_year -= 1900;
|
||||
tm.tm_mon -= 1;
|
||||
const char *p = s.c_str() + n;
|
||||
@@ -114,14 +119,19 @@ namespace snoop
|
||||
{
|
||||
// consume fractional
|
||||
++p;
|
||||
while (isdigit(*p))
|
||||
while (isdigit(*p)) {
|
||||
++p; // ignore exact fraction
|
||||
}
|
||||
}
|
||||
if (*p != 'Z')
|
||||
{
|
||||
return std::nullopt;
|
||||
}
|
||||
time_t tt = timegm(&tm);
|
||||
if (tt < 0)
|
||||
{
|
||||
return std::nullopt;
|
||||
}
|
||||
return (long long)tt * 1000LL;
|
||||
}
|
||||
|
||||
@@ -183,8 +193,10 @@ namespace snoop
|
||||
auto sMs = ParseRfc3339UtcToMs(j["start"].get<std::string>());
|
||||
auto eMs = ParseRfc3339UtcToMs(j["stop"].get<std::string>());
|
||||
if (sMs && eMs)
|
||||
{
|
||||
return *eMs; // caller will use start separately
|
||||
}
|
||||
}
|
||||
if (j.contains("start") && j["start"].is_string() &&
|
||||
j["start"].get<std::string>() == "now" && j.contains("for_s"))
|
||||
{
|
||||
@@ -204,7 +216,6 @@ namespace snoop
|
||||
{
|
||||
if (u.scheme == "https")
|
||||
{
|
||||
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
|
||||
auto cli = std::make_unique<httplib::SSLClient>(u.host.c_str(), u.port, crt.string().c_str(), key.string().c_str(), std::string());
|
||||
cli->enable_server_certificate_verification(false);
|
||||
cli->set_ca_cert_path(ca.string().c_str());
|
||||
@@ -221,13 +232,6 @@ namespace snoop
|
||||
spdlog::debug("[mTLS debug] SSLClient initialized OK for host={} port={}", u.host, u.port);
|
||||
}
|
||||
return cli;
|
||||
#else
|
||||
(void)u;
|
||||
(void)ca;
|
||||
(void)crt;
|
||||
(void)key;
|
||||
throw std::runtime_error("CPPHTTPLIB_OPENSSL_SUPPORT not enabled but https URL provided");
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@@ -235,13 +239,19 @@ namespace snoop
|
||||
void SleepWithJitterOnce(std::mt19937 &rng, int baseSec, int jitterSec)
|
||||
{
|
||||
if (baseSec < 0)
|
||||
{
|
||||
baseSec = 0;
|
||||
}
|
||||
if (jitterSec < 0)
|
||||
{
|
||||
jitterSec = 0;
|
||||
}
|
||||
std::uniform_int_distribution<int> dist(-jitterSec, +jitterSec);
|
||||
int delay = baseSec + dist(rng);
|
||||
if (delay < 0)
|
||||
{
|
||||
delay = 0;
|
||||
}
|
||||
std::this_thread::sleep_for(std::chrono::seconds(delay));
|
||||
}
|
||||
|
||||
@@ -271,6 +281,8 @@ namespace snoop
|
||||
return m_handlers.onUpdateConfig ? m_handlers.onUpdateConfig : NotImplemented;
|
||||
if (type == "set_deep_sleep")
|
||||
return m_handlers.onSetDeepSleep ? m_handlers.onSetDeepSleep : NotImplemented;
|
||||
if (type == "renew_cert")
|
||||
return m_handlers.onRenewCert ? m_handlers.onRenewCert : NotImplemented;
|
||||
return NotImplemented;
|
||||
}
|
||||
|
||||
@@ -282,9 +294,13 @@ namespace snoop
|
||||
auto to_id = [](const nlohmann::json &v) -> uint64_t
|
||||
{
|
||||
if (v.is_number_unsigned())
|
||||
{
|
||||
return v.get<uint64_t>();
|
||||
}
|
||||
if (v.is_number_integer())
|
||||
{
|
||||
return static_cast<uint64_t>(v.get<long long>());
|
||||
}
|
||||
if (v.is_string())
|
||||
{
|
||||
try
|
||||
@@ -302,10 +318,13 @@ namespace snoop
|
||||
{
|
||||
Task t;
|
||||
if (x.contains("id"))
|
||||
{
|
||||
t.id = to_id(x["id"]);
|
||||
}
|
||||
if (x.contains("type") && x["type"].is_string())
|
||||
{
|
||||
t.type = x["type"].get<std::string>();
|
||||
|
||||
}
|
||||
// payload can be stringified JSON or object
|
||||
try
|
||||
{
|
||||
@@ -339,9 +358,13 @@ namespace snoop
|
||||
}
|
||||
|
||||
if (t.id == 0)
|
||||
{
|
||||
spdlog::warn("Task without valid id: {}", x.dump());
|
||||
}
|
||||
if (t.type.empty())
|
||||
{
|
||||
spdlog::warn("Task without type: {}", x.dump());
|
||||
}
|
||||
out.push_back(std::move(t));
|
||||
};
|
||||
|
||||
@@ -406,10 +429,14 @@ namespace snoop
|
||||
spdlog::info("Entering deep sleep until {} ms", stopMs);
|
||||
// Stop stream & recording immediately
|
||||
if (m_controls.stopStreamNow)
|
||||
{
|
||||
m_controls.stopStreamNow();
|
||||
}
|
||||
if (m_controls.stopRecordingNow)
|
||||
{
|
||||
m_controls.stopRecordingNow();
|
||||
}
|
||||
}
|
||||
|
||||
bool EnsureTaskClient()
|
||||
{
|
||||
@@ -433,7 +460,6 @@ namespace snoop
|
||||
return true;
|
||||
}
|
||||
|
||||
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
|
||||
try
|
||||
{
|
||||
auto payload = snoop::device_sec::ReadClientKeyPayloadFromKeyring();
|
||||
@@ -459,12 +485,6 @@ namespace snoop
|
||||
spdlog::error("EnsureTaskClient: failed to set client cert: {}", e.what());
|
||||
return false;
|
||||
}
|
||||
#else
|
||||
(void)ca;
|
||||
(void)crt;
|
||||
spdlog::error("HTTPS baseUrl but CPPHTTPLIB_OPENSSL_SUPPORT not enabled");
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
void RunLoop()
|
||||
|
||||
@@ -15,6 +15,10 @@
|
||||
#include <stdio.h>
|
||||
#include <sys/wait.h>
|
||||
|
||||
#include <openssl/x509.h>
|
||||
#include <openssl/pem.h>
|
||||
#include <openssl/asn1.h>
|
||||
|
||||
#include "ConfigService.h"
|
||||
|
||||
namespace snoop
|
||||
@@ -251,6 +255,103 @@ namespace snoop
|
||||
return true;
|
||||
}
|
||||
|
||||
// Renew cert either because it's about to expire (force=false) or
|
||||
// because server commanded us (force=true).
|
||||
// Returns true if renew was done and new files were written.
|
||||
bool RenewCertificate(bool force = false)
|
||||
{
|
||||
const std::string guid = m_cfg->GetGuid();
|
||||
const std::filesystem::path keystoreDir = "/etc/iot/keys";
|
||||
const auto certPath = keystoreDir / "device.crt.pem";
|
||||
const auto caPath = keystoreDir / "issuing_ca.pem";
|
||||
const auto chainPath = keystoreDir / "ca_chain.pem";
|
||||
|
||||
// ----- 1) expiry check (case 1) -----
|
||||
if (!force)
|
||||
{
|
||||
if (!std::filesystem::exists(certPath))
|
||||
{
|
||||
spdlog::warn("RenewCertificate: cert not found, skip (not forced)");
|
||||
return false;
|
||||
}
|
||||
if (!IsCertExpiring(certPath, 1))
|
||||
{
|
||||
spdlog::info("RenewCertificate: cert is fine, skip");
|
||||
return false;
|
||||
}
|
||||
spdlog::info("RenewCertificate: cert expiring -> will renew");
|
||||
}
|
||||
else
|
||||
{
|
||||
spdlog::info("RenewCertificate: forced renew");
|
||||
}
|
||||
|
||||
// ----- 2) re-generate CSR via your bash script -----
|
||||
{
|
||||
const std::string cmd = "bash ./gen_device_csr.sh " + guid;
|
||||
spdlog::info("Executing (renew): {}", cmd);
|
||||
auto out = Exec(cmd);
|
||||
spdlog::debug("gen_device_csr.sh (renew) output:\n{}", out);
|
||||
}
|
||||
const std::string csrName = "device_" + guid + ".csr";
|
||||
if (!std::filesystem::exists(csrName))
|
||||
{
|
||||
throw std::runtime_error("Renew: CSR was not generated");
|
||||
}
|
||||
std::string csrPem = ReadFile(csrName);
|
||||
|
||||
// ----- 3) build mTLS client using current device cert + keyring key -----
|
||||
const std::string base = m_cfg->GetBaseUrl();
|
||||
auto pu = ParseBaseUrl(base);
|
||||
auto cli = MakeMtlsClient(pu);
|
||||
|
||||
// ----- 4) send multipart to /api/renew/:guid -----
|
||||
const std::string path = "/api/renew/" + guid;
|
||||
httplib::MultipartFormDataItems items = {
|
||||
{"csr", csrPem, "request.csr", "text/plain"}};
|
||||
|
||||
spdlog::info("POST {} (multipart, mTLS)", path);
|
||||
|
||||
auto res = cli->Post(path.c_str(), items);
|
||||
|
||||
if (!res)
|
||||
throw std::runtime_error("Renew request failed (no response)");
|
||||
spdlog::info("Renew response status: {}", res->status);
|
||||
if (res->status != 200)
|
||||
throw std::runtime_error("Renew failed: HTTP " + std::to_string(res->status));
|
||||
|
||||
nlohmann::json j = nlohmann::json::parse(res->body);
|
||||
|
||||
if (!j.contains("certificate") || !j["certificate"].is_string())
|
||||
throw std::runtime_error("Renew response missing or invalid 'certificate'");
|
||||
WriteFile(certPath, j["certificate"].get<std::string>());
|
||||
|
||||
if (j.contains("issuing_ca") && j["issuing_ca"].is_string())
|
||||
{
|
||||
WriteFile(caPath, j["issuing_ca"].get<std::string>());
|
||||
}
|
||||
|
||||
if (j.contains("ca_chain"))
|
||||
{
|
||||
std::string chainPem;
|
||||
if (j["ca_chain"].is_string())
|
||||
chainPem = j["ca_chain"].get<std::string>();
|
||||
else if (j["ca_chain"].is_array())
|
||||
chainPem = JoinPemArray(j["ca_chain"]);
|
||||
else
|
||||
throw std::runtime_error("'ca_chain' must be string or array");
|
||||
WriteFile(chainPath, chainPem);
|
||||
}
|
||||
|
||||
if (j.contains("old_serial") && j["old_serial"].is_string())
|
||||
{
|
||||
spdlog::info("Renew: server says old_serial={}", j["old_serial"].get<std::string>());
|
||||
}
|
||||
|
||||
spdlog::info("RenewCertificate: success");
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
// very small helper to pack PEM into JSON string value (single-line, escaped quotes & newlines)
|
||||
static std::string EscapeJsonForOneLine(const std::string &in)
|
||||
@@ -298,15 +399,138 @@ namespace snoop
|
||||
{
|
||||
const auto &v = arr.at(i);
|
||||
if (!v.is_string())
|
||||
{
|
||||
throw std::runtime_error("ca_chain element is not string");
|
||||
}
|
||||
if (!out.empty() && out.back() != '\n')
|
||||
out.push_back('\n');
|
||||
out += v.get<std::string>();
|
||||
if (out.back() != '\n')
|
||||
{
|
||||
out.push_back('\n');
|
||||
}
|
||||
out += v.get<std::string>();
|
||||
if (out.back() != '\n')
|
||||
{
|
||||
out.push_back('\n');
|
||||
}
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
static bool IsCertExpiring(const std::filesystem::path &certPath, int daysThreshold)
|
||||
{
|
||||
// we will use raw OpenSSL to read the PEM and check notAfter
|
||||
FILE *f = fopen(certPath.string().c_str(), "r");
|
||||
if (!f)
|
||||
{
|
||||
spdlog::warn("IsCertExpiring: cannot open cert {}", certPath.string());
|
||||
return false;
|
||||
}
|
||||
X509 *cert = PEM_read_X509(f, nullptr, nullptr, nullptr);
|
||||
fclose(f);
|
||||
if (!cert)
|
||||
{
|
||||
spdlog::warn("IsCertExpiring: cannot parse X509 from {}", certPath.string());
|
||||
return false;
|
||||
}
|
||||
const ASN1_TIME *notAfter = X509_get0_notAfter(cert);
|
||||
if (!notAfter)
|
||||
{
|
||||
spdlog::warn("IsCertExpiring: no notAfter in cert");
|
||||
X509_free(cert);
|
||||
return false;
|
||||
}
|
||||
|
||||
// current time
|
||||
time_t now_t = time(nullptr);
|
||||
// convert ASN1_TIME → time_t diff
|
||||
int days = 0, secs = 0;
|
||||
// OpenSSL has ASN1_TIME_diff in newer versions
|
||||
if (ASN1_TIME_diff(&days, &secs, nullptr, notAfter) == 0)
|
||||
{
|
||||
spdlog::warn("IsCertExpiring: ASN1_TIME_diff failed");
|
||||
X509_free(cert);
|
||||
return false;
|
||||
}
|
||||
X509_free(cert);
|
||||
|
||||
// days can be negative -> already expired
|
||||
spdlog::info("IsCertExpiring: certificate expires in {} days and {} seconds", days, secs);
|
||||
if (days < 0)
|
||||
{
|
||||
return true; // already expired
|
||||
}
|
||||
if (days == 0 && secs <= 0)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return days <= daysThreshold;
|
||||
}
|
||||
|
||||
struct ParsedUrl
|
||||
{
|
||||
std::string scheme;
|
||||
std::string host;
|
||||
int port;
|
||||
};
|
||||
|
||||
static ParsedUrl ParseBaseUrl(const std::string &base)
|
||||
{
|
||||
// same simple regex as in DeviceControlService
|
||||
std::regex re(R"(^\s*(https?)://([^/:]+)(?::(\d+))?\s*$)");
|
||||
std::smatch m;
|
||||
if (!std::regex_match(base, m, re))
|
||||
{
|
||||
throw std::runtime_error("EnrollmentService: invalid base URL: " + base);
|
||||
}
|
||||
ParsedUrl u;
|
||||
u.scheme = m[1].str();
|
||||
u.host = m[2].str();
|
||||
u.port = m[3].matched ? std::stoi(m[3].str()) : (u.scheme == "https" ? 443 : 80);
|
||||
return u;
|
||||
}
|
||||
|
||||
// create SSL client with: CA from /etc/iot/keys, device cert from disk,
|
||||
// key from *kernel keyring* (decrypted to a temp file)
|
||||
static std::unique_ptr<httplib::SSLClient> MakeMtlsClient(const ParsedUrl &u)
|
||||
{
|
||||
// 1) choose CA
|
||||
std::filesystem::path ca = "/etc/iot/keys/issuing_ca.pem";
|
||||
if (!std::filesystem::exists(ca))
|
||||
{
|
||||
ca = "/etc/iot/keys/ca_chain.pem";
|
||||
}
|
||||
// 2) device cert
|
||||
const std::filesystem::path crt = "/etc/iot/keys/device.crt.pem";
|
||||
if (!std::filesystem::exists(crt))
|
||||
{
|
||||
throw std::runtime_error("MakeMtlsClient: device.crt.pem not found");
|
||||
}
|
||||
|
||||
// 3) read key payload from kernel keyring and dump to temp (like DeviceControlService)
|
||||
auto payload = snoop::device_sec::ReadClientKeyPayloadFromKeyring();
|
||||
snoop::device_sec::TempFile tf(std::filesystem::temp_directory_path());
|
||||
tf.write_all(payload.data(), payload.size());
|
||||
|
||||
// 4) build SSL client
|
||||
auto cli = std::make_unique<httplib::SSLClient>(u.host.c_str(),
|
||||
u.port,
|
||||
crt.string().c_str(),
|
||||
tf.path.string().c_str(),
|
||||
std::string() /*no password*/);
|
||||
|
||||
// NOTE: we keep verification relaxed for now, like in your task loop
|
||||
cli->enable_server_certificate_verification(false);
|
||||
cli->set_ca_cert_path(ca.string().c_str());
|
||||
cli->set_connection_timeout(10);
|
||||
cli->set_read_timeout(60);
|
||||
cli->set_write_timeout(60);
|
||||
|
||||
if (!cli->is_valid())
|
||||
{
|
||||
throw std::runtime_error("MakeMtlsClient: SSLClient not valid");
|
||||
}
|
||||
|
||||
return cli;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace snoop
|
||||
|
||||
@@ -83,6 +83,10 @@ namespace snoop
|
||||
} catch (const std::exception& e) {
|
||||
spdlog::error("WHIP POST offer failed: {}", e.what());
|
||||
} });
|
||||
// m_pc->onLocalCandidate([this](rtc::Candidate c)
|
||||
// {
|
||||
// try { PatchCandidateWHIP(c); }
|
||||
// catch (const std::exception& e) { spdlog::warn("WHIP PATCH candidate failed: {}", e.what()); } });
|
||||
|
||||
m_pc->onLocalCandidate([this](rtc::Candidate c)
|
||||
{
|
||||
|
||||
32
src/main.cpp
32
src/main.cpp
@@ -42,6 +42,14 @@ namespace snoop
|
||||
{
|
||||
spdlog::info("First-run enrollment completed.");
|
||||
}
|
||||
try
|
||||
{
|
||||
enroll.RenewCertificate(false);
|
||||
}
|
||||
catch (const std::exception &e)
|
||||
{
|
||||
spdlog::warn("Auto-renew check failed: {}", e.what());
|
||||
}
|
||||
}
|
||||
|
||||
auto writerService = std::make_shared<AudioWriterService>(configService, "records");
|
||||
@@ -76,8 +84,10 @@ namespace snoop
|
||||
try
|
||||
{
|
||||
if (t.payload.contains("whipUrl"))
|
||||
{
|
||||
whipUrl = t.payload.at("whipUrl").get<std::string>();
|
||||
}
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
}
|
||||
@@ -156,7 +166,9 @@ namespace snoop
|
||||
auto s = snoop::DeviceControlService::ParseRfc3339UtcToMs(t.payload["start"].get<std::string>());
|
||||
auto e = snoop::DeviceControlService::ParseRfc3339UtcToMs(t.payload["stop"].get<std::string>());
|
||||
if (!s || !e)
|
||||
{
|
||||
throw std::runtime_error("Invalid RFC3339 times");
|
||||
}
|
||||
startMs = *s;
|
||||
stopMs = *e;
|
||||
}
|
||||
@@ -170,8 +182,9 @@ namespace snoop
|
||||
throw std::runtime_error("Missing/invalid start/stop time");
|
||||
}
|
||||
if (stopMs <= startMs)
|
||||
{
|
||||
throw std::runtime_error("stop <= start");
|
||||
|
||||
}
|
||||
g_taskSvc->ArmDeepSleep(startMs, stopMs);
|
||||
return snoop::DeviceControlService::HandlerResult{
|
||||
true,
|
||||
@@ -183,6 +196,23 @@ namespace snoop
|
||||
return snoop::DeviceControlService::HandlerResult{false, "{}", e.what()};
|
||||
}
|
||||
};
|
||||
handlers.onRenewCert = [enrollSvc](const snoop::DeviceControlService::Task &t)
|
||||
{
|
||||
spdlog::info("renew_cert task received, payload: {}", t.payload.dump());
|
||||
try
|
||||
{
|
||||
bool ok = enrollSvc->RenewCertificate(true); // <- force
|
||||
if (ok)
|
||||
{
|
||||
return snoop::DeviceControlService::HandlerResult{true, R"({"renewed":true})", ""};
|
||||
}
|
||||
return snoop::DeviceControlService::HandlerResult{true, R"({"renewed":false})", ""};
|
||||
}
|
||||
catch (const std::exception &e)
|
||||
{
|
||||
return snoop::DeviceControlService::HandlerResult{false, "{}", e.what()};
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
g_taskSvc = std::make_unique<snoop::DeviceControlService>(configService, handlers, controls);
|
||||
|
||||
Reference in New Issue
Block a user