Compare commits

..

9 Commits

Author SHA1 Message Date
Kumiko18
e34dea6275 WIFI-14588 Cloud Package Manager
Modify api GET /device/<serial>/package
      1. Package information is no longer embedded into `connect` message
      2. Modify api GET /device/<serial>/package to retrieve package information from APs directly

Signed-off-by: Kumiko18 <alex18_huang@accton.com>
2025-07-14 06:08:55 +00:00
Kumiko18
2b2eca69fa WIFI-14588: Cloud Package manager
1. Added package north/south bound API for package listing/installing/deleting
  2. Added modified openapi schema for swagger

Signed-off-by: Kumiko18 <alex18_huang@accton.com>
2025-06-24 06:47:22 +00:00
i-chvets
a5d1eebe6d Merge pull request #405 from Telecominfraproject/version_update
WIFI-14521: fix: Version update - release 4.0.0
2025-04-24 16:56:09 -04:00
Ivan Chvets
ee14f064c8 Merge branch 'master' of github.com:Telecominfraproject/wlan-cloud-ucentralgw into version_update 2025-04-24 16:36:14 -04:00
i-chvets
dbf52c1f23 Merge pull request #406 from Telecominfraproject/WIFI-14521-ci-changes
WIFI-14521 Update to ubuntu-latest for GH runner
2025-04-24 16:18:31 -04:00
Carsten Schafer
9dc6a6bf97 Update to ubuntu-latest for GH runner
Signed-off-by: Carsten Schafer <Carsten.Schafer@kinarasystems.com>
2025-04-24 15:30:49 -04:00
Ivan Chvets
1c0556f8bf fix: Version update - release 4.0.0
Signed-off-by: Ivan Chvets <ivan.chvets@kinarasystems.com>
2025-04-24 14:09:12 -04:00
i-chvets
d298139525 Merge pull request #403 from Telecominfraproject/wifi-14521_feat_use_clientcas_for_validation
WIFI-14521: feat: Added processing of clientcas
2025-04-09 11:50:04 -04:00
Ivan Chvets
a37c961f5b feat: Added processing of clientcas
https://telecominfraproject.atlassian.net/browse/WIFI-14521

Summary of changes:
- Updated code to add certificates from clientcas to trust chain and
  validate client certificates against it.

Signed-off-by: Ivan Chvets <ivan.chvets@kinarasystems.com>
2025-04-09 10:30:52 -04:00
21 changed files with 697 additions and 111 deletions

View File

@@ -21,7 +21,7 @@ defaults:
jobs:
docker:
runs-on: ubuntu-20.04
runs-on: ubuntu-latest
env:
DOCKER_REGISTRY_URL: tip-tip-wlan-cloud-ucentral.jfrog.io
DOCKER_REGISTRY_USERNAME: ucentral

View File

@@ -11,7 +11,7 @@ defaults:
jobs:
helm-package:
runs-on: ubuntu-20.04
runs-on: ubuntu-latest
env:
HELM_REPO_URL: https://tip.jfrog.io/artifactory/tip-wlan-cloud-ucentral-helm/
HELM_REPO_USERNAME: ucentral

2
.gitignore vendored
View File

@@ -29,4 +29,4 @@ helm/charts/*
!helm/charts/.gitkeep
/portal-test/
/src/ow_version.h
.vscode/*

View File

@@ -1,5 +1,5 @@
cmake_minimum_required(VERSION 3.13)
project(owgw VERSION 3.2.1)
project(owgw VERSION 4.0.0)
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED True)

View File

@@ -1600,6 +1600,73 @@ components:
maximum: 60000
description: off time in milliseconds
PackageGetResponse:
type: object
properties:
packages:
type: array
items:
type: object
properties:
name:
type: string
version:
type: string
serialNumber:
type: string
PackageInstallRequest:
type: object
properties:
serialNumber:
type: string
packages:
type: array
items:
type: object
properties:
name:
type: string
url:
type: string
PackageInstallResponse:
type: object
properties:
serial:
type: string
status:
type: object
properties:
error:
type: number
packages:
type: array
items:
type: object
properties:
name:
type: string
result:
type: string
text:
type: string
uuid:
type: number
PackageRemoveRequest:
type: object
properties:
serialNumber:
type: string
packages:
type: array
items:
type: object
properties:
name:
type: string
paths:
/devices:
get:
@@ -3084,6 +3151,92 @@ paths:
404:
$ref: '#/components/responses/NotFound'
/device/{serialNumber}/package:
get:
tags:
- Commands
summary: Get package installed on the remote device.
operationId: getDevicePackages
parameters:
- in: path
name: serialNumber
schema:
type: string
required: true
responses:
200:
description: Successful command execution
content:
application/json:
schema:
$ref: '#/components/schemas/PackageGetResponse'
403:
$ref: '#/components/responses/Unauthorized'
404:
$ref: '#/components/responses/NotFound'
post:
tags:
- Commands
summary: Install IPK files to remote device.
operationId: postDevicePackages
parameters:
- in: path
name: serialNumber
schema:
type: string
required: true
requestBody:
description: Packages to be installed
content:
application/json:
schema:
$ref: '#/components/schemas/PackageInstallRequest'
responses:
200:
description: Successful command execution
content:
application/json:
schema:
$ref: '#/components/schemas/PackageInstallResponse'
400:
$ref: '#/components/responses/BadRequest'
403:
$ref: '#/components/responses/Unauthorized'
404:
$ref: '#/components/responses/NotFound'
delete:
tags:
- Commands
summary: Remove install packages from remote device.
operationId: deleteDevicePackages
parameters:
- in: path
name: serialNumber
schema:
type: string
required: true
requestBody:
description: Packages to be removed
content:
application/json:
schema:
$ref: '#/components/schemas/PackageRemoveRequest'
responses:
200:
content:
application/json:
schema:
$ref: '#/components/schemas/PackageInstallResponse'
400:
$ref: '#/components/responses/BadRequest'
403:
$ref: '#/components/responses/Unauthorized'
404:
$ref: '#/components/responses/NotFound'
/ouis:
get:
tags:

View File

@@ -561,14 +561,14 @@ namespace OpenWifi {
void AP_WS_Connection::OnSocketShutdown(
[[maybe_unused]] const Poco::AutoPtr<Poco::Net::ShutdownNotification> &pNf) {
poco_trace(Logger_, fmt::format("SOCKET-SHUTDOWN({}): Closing.", CId_));
std::lock_guard G(ConnectionMutex_);
// std::lock_guard G(ConnectionMutex_);
return EndConnection();
}
void AP_WS_Connection::OnSocketError(
[[maybe_unused]] const Poco::AutoPtr<Poco::Net::ErrorNotification> &pNf) {
poco_trace(Logger_, fmt::format("SOCKET-ERROR({}): Closing.", CId_));
std::lock_guard G(ConnectionMutex_);
// std::lock_guard G(ConnectionMutex_);
return EndConnection();
}
@@ -652,10 +652,9 @@ namespace OpenWifi {
case Poco::Net::WebSocket::FRAME_OP_TEXT: {
poco_trace(Logger_,
fmt::format("FRAME({}): Frame received (length={}, flags={}). Msg={}",
CId_, IncomingSize, flags, IncomingFrame.begin()));
fmt::format("FRAME({}): Frame received (length={}, flags={}). Msg={}",
CId_, IncomingSize, flags, IncomingFrame.begin()));
Poco::JSON::Parser parser;
auto ParsedMessage = parser.parse(IncomingFrame.begin());
auto IncomingJSON = ParsedMessage.extract<Poco::JSON::Object::Ptr>();

View File

@@ -168,6 +168,9 @@ namespace OpenWifi {
void Process_wifiscan(Poco::JSON::Object::Ptr ParamsObj);
void Process_alarm(Poco::JSON::Object::Ptr ParamsObj);
void Process_rebootLog(Poco::JSON::Object::Ptr ParamsObj);
void Process_packagelist(Poco::JSON::Object::Ptr ParamsObj);
void Process_packageinstall(Poco::JSON::Object::Ptr ParamsObj);
void Process_packageremove(Poco::JSON::Object::Ptr ParamsObj);
inline void SetLastHealthCheck(const GWObjects::HealthCheck &H) {
RawLastHealthcheck_ = H;

View File

@@ -105,7 +105,7 @@ namespace OpenWifi {
Restrictions_.developer = Capabilities->getValue<bool>("developer");
}
if(Capabilities->has("secure-rtty")) {
if (Capabilities->has("secure-rtty")) {
RTTYMustBeSecure_ = Capabilities->getValue<bool>("secure-rtty");
}

View File

@@ -57,9 +57,8 @@ namespace OpenWifi {
if (request.find("Upgrade") != request.end() &&
Poco::icompare(request["Upgrade"], "websocket") == 0) {
Utils::SetThreadName("ws:conn-init");
//session_id_++;
auto new_session_id = session_id_.fetch_add(1, std::memory_order_seq_cst) + 1;
return new AP_WS_RequestHandler(Logger_, new_session_id);
session_id_++;
return new AP_WS_RequestHandler(Logger_, session_id_);
} else {
return nullptr;
}
@@ -72,14 +71,18 @@ namespace OpenWifi {
bool AP_WS_Server::ValidateCertificate(const std::string &ConnectionId,
const Poco::Crypto::X509Certificate &Certificate) {
if (IsCertOk()) {
if (!Certificate.issuedBy(*IssuerCert_)) {
poco_warning(
Logger(),
fmt::format("CERTIFICATE({}): issuer mismatch. Local='{}' Incoming='{}'",
ConnectionId, IssuerCert_->issuerName(), Certificate.issuerName()));
return false;
// validate certificate agains trusted chain
for (const auto &cert : ClientCasCerts_) {
if (Certificate.issuedBy(cert)) {
return true;
}
}
return true;
poco_warning(
Logger(),
fmt::format(
"CERTIFICATE({}): issuer mismatch. Certificate not issued by any trusted CA",
ConnectionId)
);
}
return false;
}
@@ -134,6 +137,13 @@ namespace OpenWifi {
Context->addChainCertificate(Issuing);
Context->addCertificateAuthority(Issuing);
// add certificates from clientcas to trust chain
ClientCasCerts_ = Poco::Net::X509Certificate::readPEM(Svr.ClientCas());
for (const auto &cert : ClientCasCerts_) {
Context->addChainCertificate(cert);
Context->addCertificateAuthority(cert);
}
Poco::Crypto::RSAKey Key("", Svr.KeyFile(), Svr.KeyFilePassword());
Context->usePrivateKey(Key);
@@ -515,27 +525,10 @@ namespace OpenWifi {
Connection = SessionHint->second;
Sessions_[sessionHash].erase(SessionHint);
}
std::atomic_bool duplicate_session = false;
{
auto deviceHash = MACHash::Hash(SerialNumber);
std::lock_guard DeviceLock(SerialNumbersMutex_[deviceHash]);
auto DeviceHint = SerialNumbers_[deviceHash].find(SerialNumber);
if (DeviceHint == SerialNumbers_[deviceHash].end()) {
// No duplicate connection go ahead and add new connection
SerialNumbers_[deviceHash][SerialNumber] = Connection;
}
else {
// Mark a duplicate session
duplicate_session = true;
poco_information(Logger(), fmt::format("[session ID: {}] Found a duplicate connection for device serial: {}", session_id, Utils::IntToSerialNumber(SerialNumber)));
}
}
if (duplicate_session.load()){
// This is only called if we have a duplicate session
// We remove the new incoming session that we just added a few lines above, forcing the destructor for this new session while not impacting the pointers to the old session.
std::lock_guard SessionLock(SessionMutex_[sessionHash]);
Sessions_[sessionHash].erase(session_id);
}
auto deviceHash = MACHash::Hash(SerialNumber);
std::lock_guard DeviceLock(SerialNumbersMutex_[deviceHash]);
SerialNumbers_[deviceHash][SerialNumber] = Connection;
}
bool AP_WS_Server::EndSession(uint64_t session_id, uint64_t SerialNumber) {

View File

@@ -223,6 +223,7 @@ namespace OpenWifi {
mutable std::array<std::mutex,MACHashMax> SerialNumbersMutex_;
std::unique_ptr<Poco::Crypto::X509Certificate> IssuerCert_;
std::vector<Poco::Crypto::X509Certificate> ClientCasCerts_;
std::list<std::unique_ptr<Poco::Net::HTTPServer>> WebServers_;
Poco::ThreadPool DeviceConnectionPool_{"ws:dev-pool", 4, 256};
Poco::Net::SocketReactor Reactor_;

View File

@@ -91,6 +91,21 @@ namespace OpenWifi {
TransactionId_, UUID, RPC, Poco::Thread::current()->id()));
return Rtty(UUID, RPC, 60000ms, Restrictions);
};
case APCommands::Commands::package:{
GWObjects::DeviceRestrictions Restrictions;
if (!AP_WS_Server()->Connected(SerialNumberInt_, Restrictions)) {
CallCanceled(Command_.c_str(), RESTAPI::Errors::DeviceNotConnected);
return BadRequest(RESTAPI::Errors::DeviceNotConnected);
}
auto UUID = MicroServiceCreateUUID();
auto RPC = CommandManager()->Next_RPC_ID();
poco_debug(
Logger_,
fmt::format(
"Command RTTY TID={} can proceed. Identified as {} and RPCID as {}. thr_id={}",
TransactionId_, UUID, RPC, Poco::Thread::current()->id()));
return GetPackages(UUID, RPC, 300000ms, Restrictions);
}
default:
return BadRequest(RESTAPI::Errors::InvalidCommand);
}
@@ -128,6 +143,21 @@ namespace OpenWifi {
return DeleteChecks();
case APCommands::Commands::statistics:
return DeleteStatistics();
case APCommands::Commands::package: {
GWObjects::DeviceRestrictions Restrictions;
if (!AP_WS_Server()->Connected(SerialNumberInt_, Restrictions)) {
CallCanceled(Command_.c_str(), RESTAPI::Errors::DeviceNotConnected);
return BadRequest(RESTAPI::Errors::DeviceNotConnected);
}
auto UUID = MicroServiceCreateUUID();
auto RPC = CommandManager()->Next_RPC_ID();
poco_debug(
Logger_,
fmt::format(
"Command RTTY TID={} can proceed. Identified as {} and RPCID as {}. thr_id={}",
TransactionId_, UUID, RPC, Poco::Thread::current()->id()));
return DeletePackages(UUID, RPC, 300000ms, Restrictions);
}
default:
return BadRequest(RESTAPI::Errors::InvalidCommand);
}
@@ -170,7 +200,7 @@ namespace OpenWifi {
{APCommands::Commands::powercycle, false, true, &RESTAPI_device_commandHandler::PowerCycle, 60000ms},
{APCommands::Commands::fixedconfig, false, true, &RESTAPI_device_commandHandler::FixedConfig, 120000ms},
{APCommands::Commands::cablediagnostics, false, true, &RESTAPI_device_commandHandler::CableDiagnostics, 120000ms},
{APCommands::Commands::package, false, true, &RESTAPI_device_commandHandler::PackageInstall, 120000ms},
};
void RESTAPI_device_commandHandler::DoPost() {
@@ -408,6 +438,214 @@ namespace OpenWifi {
BadRequest(RESTAPI::Errors::NoRecordsDeleted);
}
void RESTAPI_device_commandHandler::GetPackages(const std::string &CMD_UUID, uint64_t CMD_RPC,
[[maybe_unused]] std::chrono::milliseconds timeout,
[[maybe_unused]] const GWObjects::DeviceRestrictions &Restrictions) {
poco_debug(Logger_, fmt::format("GET-PACKAGES({},{}): TID={} user={} serial={}. thr_id={}",
TransactionId_, Requester(), SerialNumber_,
Poco::Thread::current()->id()));
if (IsDeviceSimulated(SerialNumber_)) {
return BadRequest(RESTAPI::Errors::SimulatedDeviceNotSupported);
}
Poco::JSON::Object Params;
Params.set(uCentralProtocol::OPERATION, "list");
Params.set(uCentralProtocol::SERIAL, SerialNumber_);
std::ostringstream os2;
Params.stringify(os2);
poco_information(Logger_, fmt::format("GET_OBJECT: {} for device {}", os2.str(), SerialNumber_));
std::stringstream ParamStream;
Params.stringify(ParamStream);
GWObjects::CommandDetails Cmd;
Cmd.SerialNumber = SerialNumber_;
Cmd.UUID = CMD_UUID;
Cmd.SubmittedBy = Requester();
Cmd.Command = uCentralProtocol::PACKAGE;
Cmd.RunAt = 0;
Cmd.Details = ParamStream.str();
RESTAPI_RPC::WaitForCommand(CMD_RPC, APCommands::Commands::package, false, Cmd, Params,
*Request, *Response, timeout, nullptr, nullptr, Logger_);
Poco::JSON::Object O, P;
Cmd.to_json(O);
Poco::Dynamic::Var resultsVar = O.get("results");
Poco::JSON::Object::Ptr resultsObj = resultsVar.extract<Poco::JSON::Object::Ptr>();
return ReturnObject(*resultsObj);
}
void RESTAPI_device_commandHandler::PackageInstall(
const std::string &CMD_UUID, uint64_t CMD_RPC,
[[maybe_unused]] std::chrono::milliseconds timeout,
[[maybe_unused]] const GWObjects::DeviceRestrictions &Restrictions) {
if (UserInfo_.userinfo.userRole != SecurityObjects::ROOT &&
UserInfo_.userinfo.userRole != SecurityObjects::ADMIN) {
CallCanceled("INSTALLPACKAGE", CMD_UUID, CMD_RPC, RESTAPI::Errors::ACCESS_DENIED);
return UnAuthorized(RESTAPI::Errors::ACCESS_DENIED);
}
poco_debug(Logger_, fmt::format("INSTALL-PACKAGES({},{}): TID={} user={} serial={}", CMD_UUID,
CMD_RPC, TransactionId_, Requester(), SerialNumber_));
if (IsDeviceSimulated(SerialNumber_)) {
CallCanceled("INSTALL-PACKAGES", CMD_UUID, CMD_RPC, RESTAPI::Errors::SimulatedDeviceNotSupported);
return BadRequest(RESTAPI::Errors::SimulatedDeviceNotSupported);
}
const auto &Obj = ParsedBody_;
if (!Obj->has(RESTAPI::Protocol::SERIALNUMBER)) {
return BadRequest(RESTAPI::Errors::MissingOrInvalidParameters);
}
auto SNum = Obj->get(RESTAPI::Protocol::SERIALNUMBER).toString();
if (SerialNumber_ != SNum) {
CallCanceled("INSTALL-PACKAGES", CMD_UUID, CMD_RPC, RESTAPI::Errors::SerialNumberMismatch);
return BadRequest(RESTAPI::Errors::SerialNumberMismatch);
}
std::ostringstream os;
ParsedBody_->stringify(os);
poco_information(Logger_, fmt::format("INSTALL_OBJECT: {} for device {}", os.str(), SerialNumber_));
GWObjects::PackageInstall PI;
if (!PI.from_json(ParsedBody_)) {
return BadRequest(RESTAPI::Errors::MissingOrInvalidParameters);
}
Poco::JSON::Array::Ptr ArrayObj = Poco::SharedPtr<Poco::JSON::Array>(new Poco::JSON::Array);
for (const auto &i : PI.pkgs) {
Poco::JSON::Object::Ptr Obj =
Poco::SharedPtr<Poco::JSON::Object>(new Poco::JSON::Object);
i.to_json(*Obj);
ArrayObj->add(Obj);
}
Poco::JSON::Object Params;
Params.set(uCentralProtocol::OPERATION, "install");
Params.set(uCentralProtocol::SERIAL, SerialNumber_);
Params.set(uCentralProtocol::PACKAGES, ArrayObj);
std::ostringstream os2;
Params.stringify(os2);
poco_information(Logger_, fmt::format("INSTALL_OBJECT2: {} for device {}", os2.str(), SerialNumber_));
std::stringstream ParamStream;
Params.stringify(ParamStream);
GWObjects::CommandDetails Cmd;
Cmd.SerialNumber = SerialNumber_;
Cmd.UUID = CMD_UUID;
Cmd.SubmittedBy = Requester();
Cmd.Command = uCentralProtocol::PACKAGE;
Cmd.RunAt = 0;
Cmd.Details = ParamStream.str();
RESTAPI_RPC::WaitForCommand(CMD_RPC, APCommands::Commands::package, false, Cmd, Params,
*Request, *Response, timeout, nullptr, nullptr, Logger_);
Poco::JSON::Object O, P;
Cmd.to_json(O);
Poco::Dynamic::Var resultsVar = O.get("results");
Poco::JSON::Object::Ptr resultsObj = resultsVar.extract<Poco::JSON::Object::Ptr>();
return ReturnObject(*resultsObj);
}
void RESTAPI_device_commandHandler::DeletePackages(
const std::string &CMD_UUID, uint64_t CMD_RPC,
[[maybe_unused]] std::chrono::milliseconds timeout,
[[maybe_unused]] const GWObjects::DeviceRestrictions &Restrictions) {
if (UserInfo_.userinfo.userRole != SecurityObjects::ROOT &&
UserInfo_.userinfo.userRole != SecurityObjects::ADMIN) {
CallCanceled("DELETE-PACKAGES", CMD_UUID, CMD_RPC, RESTAPI::Errors::ACCESS_DENIED);
return UnAuthorized(RESTAPI::Errors::ACCESS_DENIED);
}
poco_debug(Logger_, fmt::format("DELETE-PACKAGES({},{}): TID={} user={} serial={}", CMD_UUID,
CMD_RPC, TransactionId_, Requester(), SerialNumber_));
if (IsDeviceSimulated(SerialNumber_)) {
CallCanceled("DELETE-PACKAGES", CMD_UUID, CMD_RPC, RESTAPI::Errors::SimulatedDeviceNotSupported);
return BadRequest(RESTAPI::Errors::SimulatedDeviceNotSupported);
}
const auto &Obj = ParsedBody_;
if (!Obj->has(RESTAPI::Protocol::SERIALNUMBER)) {
return BadRequest(RESTAPI::Errors::MissingOrInvalidParameters);
}
auto SNum = Obj->get(RESTAPI::Protocol::SERIALNUMBER).toString();
if (SerialNumber_ != SNum) {
CallCanceled("DELETE-PACKAGES", CMD_UUID, CMD_RPC, RESTAPI::Errors::SerialNumberMismatch);
return BadRequest(RESTAPI::Errors::SerialNumberMismatch);
}
std::ostringstream os;
ParsedBody_->stringify(os);
poco_information(Logger_, fmt::format("DELETE_OBJECT: {} for device {}", os.str(), SerialNumber_));
GWObjects::PackageRemove PR;
if (!PR.from_json(ParsedBody_)) {
return BadRequest(RESTAPI::Errors::MissingOrInvalidParameters);
}
Poco::JSON::Array::Ptr ArrayObj = Poco::SharedPtr<Poco::JSON::Array>(new Poco::JSON::Array);
for (const auto &i : PR.pkgs) {
Poco::JSON::Object::Ptr Obj =
Poco::SharedPtr<Poco::JSON::Object>(new Poco::JSON::Object);
i.to_json(*Obj);
ArrayObj->add(Obj);
}
Poco::JSON::Object Params;
Params.set(uCentralProtocol::OPERATION, "delete");
Params.set(uCentralProtocol::SERIAL, SerialNumber_);
Params.set(uCentralProtocol::PACKAGES, ArrayObj);
std::ostringstream os2;
Params.stringify(os2);
poco_information(Logger_, fmt::format("DELETE_OBJECT2: {} for device {}", os2.str(), SerialNumber_));
std::stringstream ParamStream;
Params.stringify(ParamStream);
GWObjects::CommandDetails Cmd;
Cmd.SerialNumber = SerialNumber_;
Cmd.UUID = CMD_UUID;
Cmd.SubmittedBy = Requester();
Cmd.Command = uCentralProtocol::PACKAGE;
Cmd.RunAt = 0;
Cmd.Details = ParamStream.str();
RESTAPI_RPC::WaitForCommand(CMD_RPC, APCommands::Commands::package, false, Cmd, Params,
*Request, *Response, timeout, nullptr, nullptr, Logger_);
Poco::JSON::Object O, P;
Cmd.to_json(O);
Poco::Dynamic::Var resultsVar = O.get("results");
Poco::JSON::Object::Ptr resultsObj = resultsVar.extract<Poco::JSON::Object::Ptr>();
return ReturnObject(*resultsObj);
}
void RESTAPI_device_commandHandler::Ping(
const std::string &CMD_UUID, uint64_t CMD_RPC, std::chrono::milliseconds timeout,
[[maybe_unused]] const GWObjects::DeviceRestrictions &Restrictions) {

View File

@@ -33,6 +33,10 @@ namespace OpenWifi {
void GetStatus();
void GetChecks();
void DeleteChecks();
void GetPackages(const std::string &UUID, uint64_t RPC, std::chrono::milliseconds timeout,
const GWObjects::DeviceRestrictions &R);
void DeletePackages(const std::string &UUID, uint64_t RPC, std::chrono::milliseconds timeout,
const GWObjects::DeviceRestrictions &R);
bool IsDeviceSimulated(std::string &Serial);
@@ -74,6 +78,8 @@ namespace OpenWifi {
const GWObjects::DeviceRestrictions &R);
void CableDiagnostics(const std::string &UUID, uint64_t RPC, std::chrono::milliseconds timeout,
const GWObjects::DeviceRestrictions &R);
void PackageInstall(const std::string &UUID, uint64_t RPC, std::chrono::milliseconds timeout,
const GWObjects::DeviceRestrictions &R);
static auto PathName() {
return std::list<std::string>{"/api/v1/device/{serialNumber}/{command}"};

View File

@@ -12,9 +12,9 @@
#include "Daemon.h"
#ifdef TIP_GATEWAY_SERVICE
#include "AP_WS_Server.h"
#include "StorageService.h"
#include "CapabilitiesCache.h"
#include "RADIUSSessionTracker.h"
#include "StorageService.h"
#endif
#include "RESTAPI_GWobjects.h"
@@ -31,7 +31,8 @@ namespace OpenWifi::GWObjects {
field_to_json(Obj, "serialNumber", SerialNumber);
#ifdef TIP_GATEWAY_SERVICE
field_to_json(Obj, "deviceType", StorageService()->GetPlatform(SerialNumber));
field_to_json(Obj, "blackListed", StorageService()->IsBlackListed(Utils::MACToInt(SerialNumber)));
field_to_json(Obj, "blackListed",
StorageService()->IsBlackListed(Utils::MACToInt(SerialNumber)));
#endif
field_to_json(Obj, "macAddress", MACAddress);
field_to_json(Obj, "manufacturer", Manufacturer);
@@ -70,12 +71,12 @@ namespace OpenWifi::GWObjects {
#ifdef TIP_GATEWAY_SERVICE
ConnectionState ConState;
#ifdef USE_MEDUSA_CLIENT
auto Res = GS()->GetState(SerialNumber);
if (Res.has_value()) {
Res.value().to_json(SerialNumber,Obj);
auto Res = GS()->GetState(SerialNumber);
if (Res.has_value()) {
Res.value().to_json(SerialNumber, Obj);
#else
if (AP_WS_Server()->GetState(SerialNumber, ConState)) {
ConState.to_json(SerialNumber,Obj);
if (AP_WS_Server()->GetState(SerialNumber, ConState)) {
ConState.to_json(SerialNumber, Obj);
#endif
} else {
field_to_json(Obj, "ipAddress", "");
@@ -172,17 +173,16 @@ namespace OpenWifi::GWObjects {
field_to_json(Obj, "recorded", Recorded);
}
bool HealthCheck::from_json(const Poco::JSON::Object::Ptr &Obj) {
try {
field_from_json(Obj, "UUID", UUID);
field_from_json(Obj, "sanity", Sanity);
field_from_json(Obj, "recorded", Recorded);
return true;
} catch(...) {
}
return false;
}
bool HealthCheck::from_json(const Poco::JSON::Object::Ptr &Obj) {
try {
field_from_json(Obj, "UUID", UUID);
field_from_json(Obj, "sanity", Sanity);
field_from_json(Obj, "recorded", Recorded);
return true;
} catch (...) {
}
return false;
}
void DefaultFirmware::to_json(Poco::JSON::Object &Obj) const {
field_to_json(Obj, "deviceType", deviceType);
@@ -275,7 +275,8 @@ namespace OpenWifi::GWObjects {
return false;
}
void ConnectionState::to_json([[maybe_unused]] const std::string &SerialNumber, Poco::JSON::Object &Obj) {
void ConnectionState::to_json([[maybe_unused]] const std::string &SerialNumber,
Poco::JSON::Object &Obj) {
field_to_json(Obj, "ipAddress", Address);
field_to_json(Obj, "txBytes", TX);
field_to_json(Obj, "rxBytes", RX);
@@ -299,12 +300,12 @@ namespace OpenWifi::GWObjects {
field_to_json(Obj, "certificateExpiryDate", certificateExpiryDate);
field_to_json(Obj, "connectReason", connectReason);
field_to_json(Obj, "uptime", uptime);
field_to_json(Obj, "compatible", Compatible);
field_to_json(Obj, "compatible", Compatible);
#ifdef TIP_GATEWAY_SERVICE
hasRADIUSSessions = RADIUSSessionTracker()->HasSessions(SerialNumber);
#endif
field_to_json(Obj, "hasRADIUSSessions", hasRADIUSSessions );
field_to_json(Obj, "hasRADIUSSessions", hasRADIUSSessions);
field_to_json(Obj, "hasGPS", hasGPS);
field_to_json(Obj, "sanity", sanity);
field_to_json(Obj, "memoryUsed", memoryUsed);
@@ -334,44 +335,44 @@ namespace OpenWifi::GWObjects {
}
}
bool ConnectionState::from_json(const Poco::JSON::Object::Ptr &Obj) {
try {
field_from_json(Obj, "compatible", Compatible);
field_from_json(Obj, "ipAddress", Address);
field_from_json(Obj, "txBytes", TX);
field_from_json(Obj, "rxBytes", RX);
field_from_json(Obj, "messageCount", MessageCount);
field_from_json(Obj, "UUID", UUID);
field_from_json(Obj, "connected", Connected);
field_from_json(Obj, "firmware", Firmware);
field_from_json(Obj, "lastContact", LastContact);
field_from_json(Obj, "associations_2G", Associations_2G);
field_from_json(Obj, "associations_5G", Associations_5G);
field_from_json(Obj, "associations_6G", Associations_6G);
field_from_json(Obj, "webSocketClients", webSocketClients);
field_from_json(Obj, "websocketPackets", websocketPackets);
field_from_json(Obj, "kafkaClients", kafkaClients);
field_from_json(Obj, "kafkaPackets", kafkaPackets);
field_from_json(Obj, "locale", locale);
field_from_json(Obj, "started", started);
field_from_json(Obj, "sessionId", sessionId);
field_from_json(Obj, "connectionCompletionTime", connectionCompletionTime);
field_from_json(Obj, "totalConnectionTime", totalConnectionTime);
field_from_json(Obj, "certificateExpiryDate", certificateExpiryDate);
field_from_json(Obj, "connectReason", connectReason);
field_from_json(Obj, "uptime", uptime);
field_from_json(Obj, "hasRADIUSSessions", hasRADIUSSessions );
field_from_json(Obj, "hasGPS", hasGPS);
field_from_json(Obj, "sanity", sanity);
field_from_json(Obj, "memoryUsed", memoryUsed);
field_from_json(Obj, "sanity", sanity);
field_from_json(Obj, "load", load);
field_from_json(Obj, "temperature", temperature);
return true;
} catch(const Poco::Exception &E) {
}
return false;
}
bool ConnectionState::from_json(const Poco::JSON::Object::Ptr &Obj) {
try {
field_from_json(Obj, "compatible", Compatible);
field_from_json(Obj, "ipAddress", Address);
field_from_json(Obj, "txBytes", TX);
field_from_json(Obj, "rxBytes", RX);
field_from_json(Obj, "messageCount", MessageCount);
field_from_json(Obj, "UUID", UUID);
field_from_json(Obj, "connected", Connected);
field_from_json(Obj, "firmware", Firmware);
field_from_json(Obj, "lastContact", LastContact);
field_from_json(Obj, "associations_2G", Associations_2G);
field_from_json(Obj, "associations_5G", Associations_5G);
field_from_json(Obj, "associations_6G", Associations_6G);
field_from_json(Obj, "webSocketClients", webSocketClients);
field_from_json(Obj, "websocketPackets", websocketPackets);
field_from_json(Obj, "kafkaClients", kafkaClients);
field_from_json(Obj, "kafkaPackets", kafkaPackets);
field_from_json(Obj, "locale", locale);
field_from_json(Obj, "started", started);
field_from_json(Obj, "sessionId", sessionId);
field_from_json(Obj, "connectionCompletionTime", connectionCompletionTime);
field_from_json(Obj, "totalConnectionTime", totalConnectionTime);
field_from_json(Obj, "certificateExpiryDate", certificateExpiryDate);
field_from_json(Obj, "connectReason", connectReason);
field_from_json(Obj, "uptime", uptime);
field_from_json(Obj, "hasRADIUSSessions", hasRADIUSSessions);
field_from_json(Obj, "hasGPS", hasGPS);
field_from_json(Obj, "sanity", sanity);
field_from_json(Obj, "memoryUsed", memoryUsed);
field_from_json(Obj, "sanity", sanity);
field_from_json(Obj, "load", load);
field_from_json(Obj, "temperature", temperature);
return true;
} catch (const Poco::Exception &E) {
}
return false;
}
void DeviceConnectionStatistics::to_json(Poco::JSON::Object &Obj) const {
field_to_json(Obj, "averageConnectionTime", averageConnectionTime);
@@ -819,4 +820,105 @@ namespace OpenWifi::GWObjects {
}
return false;
}
bool PackageInfo::from_json(const Poco::JSON::Object::Ptr &Obj) {
try {
field_from_json(Obj, "name", name);
field_from_json(Obj, "version", version);
return true;
} catch (const Poco::Exception &E) {
}
return false;
}
void PackageInfo::to_json(Poco::JSON::Object &Obj) const {
field_to_json(Obj, "name", name);
field_to_json(Obj, "version", version);
}
bool PackageList::from_json(const Poco::JSON::Array::Ptr &Obj) {
try {
std::ostringstream oss;
Poco::JSON::Stringifier::stringify(Obj, oss);
packageStringArray = oss.str();
return true;
} catch (const Poco::Exception &E) {
}
return false;
}
void PackageList::to_json(Poco::JSON::Object &Obj) const {
Obj.set("serialNumber", serialNumber);
Poco::JSON::Array packageJsonArray;
for (const auto &pkg : packageArray) {
Poco::JSON::Object pkgObj;
pkg.to_json(pkgObj);
packageJsonArray.add(pkgObj);
}
Obj.set("packageArray", packageJsonArray);
Obj.set("FirstUpdate", Poco::UInt64(FirstUpdate));
Obj.set("LastUpdate", Poco::UInt64(LastUpdate));
}
bool ToBeInstalled::from_json(const Poco::JSON::Object::Ptr &Obj) {
try {
field_from_json(Obj, "name", name);
field_from_json(Obj, "url", url);
Poco::URI uri(url);
std::string scheme = uri.getScheme();
if (scheme != "http" && scheme != "https") {
return false;
}
return true;
} catch (const Poco::Exception &E) {
}
return false;
}
void ToBeInstalled::to_json(Poco::JSON::Object &Obj) const {
Obj.set("name", name);
Obj.set("url", url);
}
bool PackageInstall::from_json(const Poco::JSON::Object::Ptr &Obj) {
try {
field_from_json(Obj, "serialNumber", serialNumber);
field_from_json(Obj, "when", when);
field_from_json(Obj, "packages", pkgs);
return true;
} catch (const Poco::Exception &E) {
}
return false;
}
bool ToBeRemoved::from_json(const Poco::JSON::Object::Ptr &Obj) {
try {
field_from_json(Obj, "name", name);
return true;
} catch (const Poco::Exception &E) {
}
return false;
}
void ToBeRemoved::to_json(Poco::JSON::Object &Obj) const {
Obj.set("name", name);
}
bool PackageRemove::from_json(const Poco::JSON::Object::Ptr &Obj) {
try {
field_from_json(Obj, "serialNumber", serialNumber);
field_from_json(Obj, "packages", pkgs);
return true;
} catch (const Poco::Exception &E) {
}
return false;
}
} // namespace OpenWifi::GWObjects

View File

@@ -545,6 +545,51 @@ namespace OpenWifi::GWObjects {
std::uint64_t when;
std::vector<std::string> ports;
bool from_json(const Poco::JSON::Object::Ptr &Obj);
};
struct PackageInfo {
std::string name;
std::string version;
bool from_json(const Poco::JSON::Object::Ptr &Obj);
void to_json(Poco::JSON::Object &Obj) const;
};
struct PackageList {
std::string serialNumber;
std::vector<PackageInfo> packageArray;
uint64_t FirstUpdate = 0;
uint64_t LastUpdate = 0;
std::string packageStringArray;
bool from_json(const Poco::JSON::Array::Ptr &Obj);
void to_json(Poco::JSON::Object &Obj) const;
};
struct ToBeInstalled {
std::string name;
std::string url;
bool from_json(const Poco::JSON::Object::Ptr &Obj);
void to_json(Poco::JSON::Object &Obj) const;
};
struct PackageInstall {
std::string serialNumber;
std::uint64_t when;
std::vector<ToBeInstalled> pkgs;
bool from_json(const Poco::JSON::Object::Ptr &Obj);
void to_json(Poco::JSON::Object &Obj) const;
};
struct ToBeRemoved {
std::string name;
bool from_json(const Poco::JSON::Object::Ptr &Obj);
void to_json(Poco::JSON::Object &Obj) const;
};
struct PackageRemove {
std::string serialNumber;
std::uint64_t when;
std::vector<ToBeRemoved> pkgs;
bool from_json(const Poco::JSON::Object::Ptr &Obj);
};
} // namespace OpenWifi::GWObjects

View File

@@ -293,6 +293,7 @@ namespace OpenWifi {
int Create_BlackList();
int Create_FileUploads();
int Create_DefaultFirmwares();
int Create_Packages();
bool AnalyzeCommands(Types::CountedMap &R);
bool AnalyzeDevices(GWObjects::Dashboard &D);

View File

@@ -68,6 +68,16 @@ namespace OpenWifi {
Context->addCertificateAuthority(Issuing);
}
if (!client_cas_.empty()) {
// add certificates specified in clientcas
std::vector<Poco::Crypto::X509Certificate> Certs =
Poco::Net::X509Certificate::readPEM(client_cas_);
for (const auto &cert : Certs) {
Context->addChainCertificate(cert);
Context->addCertificateAuthority(cert);
}
}
Poco::Crypto::RSAKey Key("", key_file_, key_file_password_);
Context->usePrivateKey(Key);

View File

@@ -45,6 +45,7 @@ namespace OpenWifi {
[[nodiscard]] inline auto KeyFile() const { return key_file_; };
[[nodiscard]] inline auto CertFile() const { return cert_file_; };
[[nodiscard]] inline auto RootCA() const { return root_ca_; };
[[nodiscard]] inline auto ClientCas() const { return client_cas_; };
[[nodiscard]] inline auto KeyFilePassword() const { return key_file_password_; };
[[nodiscard]] inline auto IssuerCertFile() const { return issuer_cert_file_; };
[[nodiscard]] inline auto Name() const { return name_; };

View File

@@ -433,6 +433,9 @@ namespace OpenWifi::RESTAPI::Errors {
static const struct msg InvalidRRMAction { 1192, "Invalid RRM Action." };
static const struct msg InvalidPackageURL { 1193, "Invalid URL, must start with http:// or https://." };
static const struct msg FailedToDownload { 1194, "Failed to download package." };
static const struct msg SimulationDoesNotExist {
7000, "Simulation Instance ID does not exist."
};
@@ -550,6 +553,10 @@ namespace OpenWifi::RESTAPI::Protocol {
static const char *DEBUG = "debug";
static const char *SCRIPT = "script";
static const char *TIMEOUT = "timeout";
static const char *PACKAGE = "package";
static const char *PACKAGES = "packages";
static const char *PACKAGEINST = "packageInstall";
static const char *PACKAGEDEL = "packageDelete";
static const char *NEWPASSWORD = "newPassword";
static const char *USERS = "users";
@@ -668,6 +675,9 @@ namespace OpenWifi::uCentralProtocol {
static const char *SIGNATURE = "signature";
static const char *INFO = "info";
static const char *DATE = "date";
static const char *PACKAGE = "package";
static const char *PACKAGES = "packages";
static const char *CATEGORY = "category";
static const char *SERIALNUMBER = "serialNumber";
static const char *COMPATIBLE = "compatible";
@@ -699,6 +709,10 @@ namespace OpenWifi::uCentralProtocol {
static const char *FIXEDCONFIG = "fixedconfig";
static const char *CABLEDIAGNOSTICS = "cable-diagnostics";
static const char *OPERATION = "op";
static const char *PACKAGEINST = "pkginst";
static const char *PACKAGEDEL = "pkgdel";
} // namespace OpenWifi::uCentralProtocol
namespace OpenWifi::uCentralProtocol::Events {
@@ -733,7 +747,8 @@ namespace OpenWifi::uCentralProtocol::Events {
ET_EVENT,
ET_WIFISCAN,
ET_ALARM,
ET_REBOOTLOG
ET_REBOOTLOG,
ET_PACKAGE
};
inline EVENT_MSG EventFromString(const std::string &Method) {
@@ -767,6 +782,8 @@ namespace OpenWifi::uCentralProtocol::Events {
return ET_ALARM;
else if (strcmp(REBOOTLOG, Method.c_str()) == 0)
return ET_REBOOTLOG;
else if (strcmp(PACKAGE, Method.c_str()) == 0)
return ET_PACKAGE;
return ET_UNKNOWN;
};
} // namespace OpenWifi::uCentralProtocol::Events
@@ -797,6 +814,7 @@ namespace OpenWifi::APCommands {
powercycle,
fixedconfig,
cablediagnostics,
package,
unknown
};
@@ -812,7 +830,8 @@ namespace OpenWifi::APCommands {
RESTAPI::Protocol::PING, RESTAPI::Protocol::SCRIPT,
RESTAPI::Protocol::RRM, RESTAPI::Protocol::CERTUPDATE,
RESTAPI::Protocol::TRANSFER, RESTAPI::Protocol::POWERCYCLE,
RESTAPI::Protocol::FIXEDCONFIG, RESTAPI::Protocol::CABLEDIAGNOSTICS
RESTAPI::Protocol::FIXEDCONFIG, RESTAPI::Protocol::CABLEDIAGNOSTICS,
RESTAPI::Protocol::PACKAGE
};
inline const char *to_string(Commands Cmd) { return uCentralAPCommands[(uint8_t)Cmd]; }

View File

@@ -49,8 +49,7 @@ namespace OpenWifi {
"Data TEXT, "
"Recorded BIGINT, "
"INDEX StatSerial0 (SerialNumber)), ",
"INDEX StatSerial (SerialNumber ASC, Recorded ASC))",
Poco::Data::Keywords::now;
"INDEX StatSerial (SerialNumber ASC, Recorded ASC))", Poco::Data::Keywords::now;
}
return 0;
} catch (const Poco::Exception &E) {
@@ -154,8 +153,7 @@ namespace OpenWifi {
"alter table devices add column lastRecordedContact bigint",
"alter table devices add column simulated boolean",
"alter table devices add column certificateExpiryDate bigint",
"alter table devices add column connectReason TEXT"
};
"alter table devices add column connectReason TEXT"};
for (const auto &i : Script) {
try {
@@ -279,9 +277,7 @@ namespace OpenWifi {
Poco::Data::Keywords::now;
}
std::vector<std::string> Script{
"alter table DefaultConfigs add column Platform text"
};
std::vector<std::string> Script{"alter table DefaultConfigs add column Platform text"};
for (const auto &i : Script) {
try {

View File

@@ -34,7 +34,7 @@ password=${OWSEC_PASSWORD}
if [[ "${FLAGS}" == "" ]]
then
FLAGS="-s"
FLAGS="-s -k"
fi
token=""

19
verbosity.json Normal file
View File

@@ -0,0 +1,19 @@
[
{
"serialNumber": "xxxxx",
"packages": "akiho - 98-10-16-71a3b533e-1 \n erichi - 98-12-06-98e79a27f-1 \n ucrun - 2022-02-19-05be6abeb-1 \n vxlan - 7 ..."
},
{
"serialNumber": "xxxxx",
"packages": [
{
"packageName": "akiho",
"version": "98-10-16-71a3b533e-1"
},
{
"packageName": "erichi",
"version": "98-12-06-98e79a27f-1"
}
]
}
]