/* * Copyright (C) 2026 oxmc / PawletOS * SPDX-License-Identifier: Apache-2.0 */ #include "catalog.h" #include #include #include #include #include "http.h" namespace pawlet::hwupdate { namespace { std::string Escape(CURL* c, const std::string& s) { char* e = curl_easy_escape(c, s.c_str(), static_cast(s.size())); std::string out = e ? e : s; if (e) curl_free(e); return out; } std::string BuildUrl(const std::string& baseUrl, const CheckRequest& r) { CURL* c = curl_easy_init(); std::ostringstream u; u << baseUrl; // baseUrl already contains "?mode=hardware"; append remaining params. u << "&target=update"; u << "&device=" << Escape(c, r.device); u << "&pawlet_version=" << Escape(c, r.pawletVersion); u << "&hardware_id=" << Escape(c, r.hardwareId); u << "&component_id=" << Escape(c, r.componentId); if (!r.hardwareRevision.empty()) u << "&hardware_revision=" << Escape(c, r.hardwareRevision); if (!r.currentVersion.empty()) u << "¤t_version=" << Escape(c, r.currentVersion); if (!r.bootloaderVersion.empty()) u << "&bootloader_version=" << Escape(c, r.bootloaderVersion); if (c) curl_easy_cleanup(c); return u.str(); } std::optional ParseUpdate(const std::string& body) { Json::Value root; Json::CharReaderBuilder b; std::string errs; std::istringstream in(body); if (!Json::parseFromStream(b, in, &root, &errs)) { LOG(WARNING) << "hwupdate: bad update response: " << errs; return std::nullopt; } const Json::Value& u = root["update"]; if (!u.isObject()) return std::nullopt; UpdateEntry e; e.version = u.get("version", "").asString(); e.datetime = u.get("datetime", 0).asInt64(); e.filename = u.get("filename", "").asString(); e.id = u.get("id", "").asString(); e.sizeBytes = u.get("size_bytes", 0).asInt64(); e.url = u.get("url", "").asString(); e.checksumSha256 = u.get("checksum_sha256", "").asString(); e.changelogUrl = u.get("changelog_url", "").asString(); const Json::Value& inst = u["installer"]; e.installerType = inst.get("type", "").asString(); e.installerHandler = inst.get("handler", "").asString(); if (e.url.empty() || e.checksumSha256.empty() || e.installerHandler.empty()) { LOG(WARNING) << "hwupdate: update entry missing required fields"; return std::nullopt; } return e; } } // namespace std::optional CheckUpdate(const std::string& baseUrl, const CheckRequest& req) { std::string url = BuildUrl(baseUrl, req); std::string body; long code = 0; if (!http::Get(url, &body, &code)) return std::nullopt; if (code == 204) return std::nullopt; // up to date if (code != 200) { LOG(WARNING) << "hwupdate: update check http=" << code << " for " << req.componentId; return std::nullopt; } return ParseUpdate(body); } } // namespace pawlet::hwupdate