mirror of
				https://github.com/Telecominfraproject/wlan-cloud-ucentralgw.git
				synced 2025-11-04 04:37:46 +00:00 
			
		
		
		
	Compare commits
	
		
			61 Commits
		
	
	
		
			kv3.0.12
			...
			add_enroll
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					3b7a24ea30 | ||
| 
						 | 
					438309714f | ||
| 
						 | 
					a9130eeb75 | ||
| 
						 | 
					33068fca9e | ||
| 
						 | 
					d329151f6c | ||
| 
						 | 
					ec846006bb | ||
| 
						 | 
					242261de0a | ||
| 
						 | 
					31a4edead5 | ||
| 
						 | 
					f7b697f219 | ||
| 
						 | 
					e020da75fc | ||
| 
						 | 
					89702f56e0 | ||
| 
						 | 
					0ac97442c0 | ||
| 
						 | 
					e38b4c8a13 | ||
| 
						 | 
					9c5bbee834 | ||
| 
						 | 
					a5d1eebe6d | ||
| 
						 | 
					ee14f064c8 | ||
| 
						 | 
					dbf52c1f23 | ||
| 
						 | 
					9dc6a6bf97 | ||
| 
						 | 
					1c0556f8bf | ||
| 
						 | 
					d298139525 | ||
| 
						 | 
					a37c961f5b | ||
| 
						 | 
					75bcbd748c | ||
| 
						 | 
					b6eba2a96d | ||
| 
						 | 
					17082803d4 | ||
| 
						 | 
					26b9a96506 | ||
| 
						 | 
					5ce8dae9ec | ||
| 
						 | 
					7da135c1e5 | ||
| 
						 | 
					50ee4ba5cb | ||
| 
						 | 
					3a8109d7ad | ||
| 
						 | 
					56232966ec | ||
| 
						 | 
					1ecf98d712 | ||
| 
						 | 
					f5b60ced61 | ||
| 
						 | 
					e4d141bb8e | ||
| 
						 | 
					25b4288050 | ||
| 
						 | 
					82430c2d5d | ||
| 
						 | 
					7b68ec0536 | ||
| 
						 | 
					839f4fec44 | ||
| 
						 | 
					c4178209bb | ||
| 
						 | 
					79ab67db50 | ||
| 
						 | 
					00bc77feea | ||
| 
						 | 
					4f00d77d2b | ||
| 
						 | 
					c679d4ac40 | ||
| 
						 | 
					4a150a9fcb | ||
| 
						 | 
					83eb603f0a | ||
| 
						 | 
					38bc0f0d69 | ||
| 
						 | 
					e7362c2020 | ||
| 
						 | 
					9c9987e190 | ||
| 
						 | 
					4ac7b6ba0b | ||
| 
						 | 
					f9ee19af91 | ||
| 
						 | 
					cd2ab8660f | ||
| 
						 | 
					b9f00f6603 | ||
| 
						 | 
					596cfd49e1 | ||
| 
						 | 
					b3deba5606 | ||
| 
						 | 
					a97d49a06b | ||
| 
						 | 
					b1be0604d6 | ||
| 
						 | 
					b29f7f7dc4 | ||
| 
						 | 
					132b31b06b | ||
| 
						 | 
					3114ff8a32 | ||
| 
						 | 
					9c5aeda5dd | ||
| 
						 | 
					783ec99930 | ||
| 
						 | 
					0c661b8b93 | 
							
								
								
									
										2
									
								
								.github/workflows/ci.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								.github/workflows/ci.yml
									
									
									
									
										vendored
									
									
								
							@@ -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
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										2
									
								
								.github/workflows/release.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								.github/workflows/release.yml
									
									
									
									
										vendored
									
									
								
							@@ -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
 | 
			
		||||
 
 | 
			
		||||
@@ -1,5 +1,5 @@
 | 
			
		||||
cmake_minimum_required(VERSION 3.13)
 | 
			
		||||
project(owgw VERSION 3.1.0)
 | 
			
		||||
project(owgw VERSION 4.1.0)
 | 
			
		||||
 | 
			
		||||
set(CMAKE_CXX_STANDARD 20)
 | 
			
		||||
set(CMAKE_CXX_STANDARD_REQUIRED True)
 | 
			
		||||
 
 | 
			
		||||
@@ -1,7 +1,7 @@
 | 
			
		||||
ARG DEBIAN_VERSION=11.5-slim
 | 
			
		||||
ARG POCO_VERSION=poco-tip-v2
 | 
			
		||||
ARG CPPKAFKA_VERSION=tip-v1
 | 
			
		||||
ARG VALIJASON_VERSION=tip-v1
 | 
			
		||||
ARG VALIJASON_VERSION=tip-v1.0.2
 | 
			
		||||
ARG APP_NAME=owgw
 | 
			
		||||
ARG APP_HOME_DIR=/openwifi
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										72
									
								
								PROTOCOL.md
									
									
									
									
									
								
							
							
						
						
									
										72
									
								
								PROTOCOL.md
									
									
									
									
									
								
							@@ -306,8 +306,54 @@ The device should answer:
 | 
			
		||||
         },
 | 
			
		||||
     "id" : <same number>
 | 
			
		||||
}
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
#### Controller wants the device to apply a given fixed configuration
 | 
			
		||||
 | 
			
		||||
Controller sends this command when it requires the device to apply fixed configuration, eg. country code. The device
 | 
			
		||||
should respond with message indicating failure or success.
 | 
			
		||||
 | 
			
		||||
```json
 | 
			
		||||
{   "jsonrpc" : "2.0",
 | 
			
		||||
    "method" : "fixedconfig",
 | 
			
		||||
    "params" : {
 | 
			
		||||
        "serial" : <serial number>,
 | 
			
		||||
        "when" : Optional - <UTC time when to apply this config, 0 means immediate, this is a suggestion>
 | 
			
		||||
        "country" : "<country-code>"
 | 
			
		||||
     },
 | 
			
		||||
}
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
If AP supports compressed configuration feature by inidcating `compress_cmd=true` in its capabilities, controller
 | 
			
		||||
will send a compressed configuration message where configuration payload (i.e. contents of `params`) is compressed
 | 
			
		||||
and encoded in base64 format:
 | 
			
		||||
```json
 | 
			
		||||
{   "jsonrpc" : "2.0",
 | 
			
		||||
    "method" : "configure",
 | 
			
		||||
    "params" : {
 | 
			
		||||
        "compress_64" : "<b64 encoded zlib compressed payload>",
 | 
			
		||||
        "compress_sz" : "<size of uncompressed data in bytes>"
 | 
			
		||||
     },
 | 
			
		||||
     "id" : <some number>
 | 
			
		||||
}
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
The device should answer:
 | 
			
		||||
```json
 | 
			
		||||
{   "jsonrpc" : "2.0",
 | 
			
		||||
    "result" : {
 | 
			
		||||
        "serial": <serial number>,
 | 
			
		||||
        "status": {
 | 
			
		||||
            "error": 0 or an error number,
 | 
			
		||||
            "text": <description of the error or success, eg. "Applied fixed config, rebooting">
 | 
			
		||||
        },
 | 
			
		||||
        "uuid": <UUID>
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
##### The Answer
 | 
			
		||||
The device can answer and tell the controller it has rejected certain parts of the config and potentially replaced them with
 | 
			
		||||
appropriate values. This could be used to allow a device to replace frequencies for the regions it is located in. The device 
 | 
			
		||||
@@ -834,6 +880,32 @@ The device should answer:
 | 
			
		||||
}
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
#### Controller wants the device to perform re-enrollment
 | 
			
		||||
Controller sends this command to trigger re-enrollment, i.e. update of operational certificate. Extreme care must be taken.
 | 
			
		||||
```json
 | 
			
		||||
{    "jsonrpc" : "2.0" , 
 | 
			
		||||
     "method" : "reenroll" , 
 | 
			
		||||
     "params" : {
 | 
			
		||||
        "serial" : <serial number>,
 | 
			
		||||
        "when" : Optional - <UTC time when to apply this config, 0 mean immediate, this is a suggestion>
 | 
			
		||||
     },
 | 
			
		||||
     "id" : <some number>
 | 
			
		||||
}
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
The device should answer:
 | 
			
		||||
```json
 | 
			
		||||
{     "jsonrpc" : "2.0" , 
 | 
			
		||||
      "result" : {
 | 
			
		||||
          "serial" : <serial number> ,
 | 
			
		||||
          "status" : {
 | 
			
		||||
            "error" : <0 or the value of $? from the shell running the command, 255 signifies a timeout>,
 | 
			
		||||
            "txt" : <text describing the error or success>
 | 
			
		||||
      },
 | 
			
		||||
  "id" : <same number as request>
 | 
			
		||||
}
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
#### Controller wants the device to switch to another controller
 | 
			
		||||
Controller sends this when the device should change the controller it connects to without looking up a new redirector.
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -12,7 +12,7 @@ info:
 | 
			
		||||
    url: https://www.ucentral.info/support
 | 
			
		||||
 | 
			
		||||
servers:
 | 
			
		||||
  - url: 'https://localhost:16001/api/v1'
 | 
			
		||||
  - url: 'https://localhost:16002/api/v1'
 | 
			
		||||
 | 
			
		||||
security:
 | 
			
		||||
  - bearerAuth: []
 | 
			
		||||
@@ -1576,6 +1576,15 @@ components:
 | 
			
		||||
          format: base64
 | 
			
		||||
          description: This is a base64 encoded string of the certificate bundle (the current bundle .tar.gz file from the PKI portal)
 | 
			
		||||
 | 
			
		||||
    ReenrollRequest:
 | 
			
		||||
      type: object
 | 
			
		||||
      properties:
 | 
			
		||||
        serialNumber:
 | 
			
		||||
          type: string
 | 
			
		||||
        when:
 | 
			
		||||
          type: integer
 | 
			
		||||
          format: int64
 | 
			
		||||
 | 
			
		||||
    PowerCycleRequest:
 | 
			
		||||
      type: object
 | 
			
		||||
      properties:
 | 
			
		||||
@@ -3056,6 +3065,32 @@ paths:
 | 
			
		||||
        404:
 | 
			
		||||
          $ref: '#/components/responses/NotFound'
 | 
			
		||||
 | 
			
		||||
  /device/{serialNumber}/reenroll:
 | 
			
		||||
    post:
 | 
			
		||||
      tags:
 | 
			
		||||
        - Commands
 | 
			
		||||
      summary: Reenroll operational certificate for the device.
 | 
			
		||||
      operationId: reenrollCertificate
 | 
			
		||||
      parameters:
 | 
			
		||||
        - in: path
 | 
			
		||||
          name: serialNumber
 | 
			
		||||
          schema:
 | 
			
		||||
            type: string
 | 
			
		||||
          required: true
 | 
			
		||||
      requestBody:
 | 
			
		||||
        description: Reenroll operational certificate for the device
 | 
			
		||||
        content:
 | 
			
		||||
          application/json:
 | 
			
		||||
            schema:
 | 
			
		||||
              $ref: '#/components/schemas/ReenrollRequest'
 | 
			
		||||
      responses:
 | 
			
		||||
        200:
 | 
			
		||||
          $ref: '#/components/responses/Success'
 | 
			
		||||
        403:
 | 
			
		||||
          $ref: '#/components/responses/Unauthorized'
 | 
			
		||||
        404:
 | 
			
		||||
          $ref: '#/components/responses/NotFound'
 | 
			
		||||
 | 
			
		||||
  /device/{serialNumber}/powercycle:
 | 
			
		||||
    post:
 | 
			
		||||
      tags:
 | 
			
		||||
 
 | 
			
		||||
@@ -213,6 +213,7 @@ namespace OpenWifi {
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			State_.certificateExpiryDate = PeerCert.expiresOn().timestamp().epochTime();
 | 
			
		||||
			State_.certificateIssuerName = PeerCert.issuerName();
 | 
			
		||||
 | 
			
		||||
			poco_trace(Logger_,
 | 
			
		||||
					   fmt::format("TLS-CONNECTION({}): Session={} CN={} Completed. (t={})", CId_,
 | 
			
		||||
 
 | 
			
		||||
@@ -71,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_)) {
 | 
			
		||||
			// validate certificate agains trusted chain
 | 
			
		||||
			for (const auto &cert : ClientCasCerts_) {
 | 
			
		||||
				if (Certificate.issuedBy(cert)) {
 | 
			
		||||
					return true;
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			poco_warning(
 | 
			
		||||
					Logger(),
 | 
			
		||||
					fmt::format("CERTIFICATE({}): issuer mismatch. Local='{}' Incoming='{}'",
 | 
			
		||||
								ConnectionId, IssuerCert_->issuerName(), Certificate.issuerName()));
 | 
			
		||||
				return false;
 | 
			
		||||
			}
 | 
			
		||||
			return true;
 | 
			
		||||
					fmt::format(
 | 
			
		||||
						"CERTIFICATE({}): issuer mismatch. Certificate not issued by any trusted CA",
 | 
			
		||||
						ConnectionId)
 | 
			
		||||
					);
 | 
			
		||||
		}
 | 
			
		||||
		return false;
 | 
			
		||||
	}
 | 
			
		||||
@@ -133,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);
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -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_;
 | 
			
		||||
 
 | 
			
		||||
@@ -111,7 +111,7 @@ namespace OpenWifi {
 | 
			
		||||
				i >> cache;
 | 
			
		||||
 | 
			
		||||
				for (const auto &[Type, Platform] : cache.items()) {
 | 
			
		||||
					Platforms_[Type] = Poco::toLower(to_string(Platform));
 | 
			
		||||
					Platforms_[Type] = Poco::toLower(Platform.get<std::string>());
 | 
			
		||||
				}
 | 
			
		||||
			} catch (...) {
 | 
			
		||||
			}
 | 
			
		||||
 
 | 
			
		||||
@@ -54,8 +54,8 @@ namespace OpenWifi::RESTAPI_RPC {
 | 
			
		||||
						std::chrono::milliseconds WaitTimeInMs, Poco::JSON::Object *ObjectToReturn,
 | 
			
		||||
						RESTAPIHandler *Handler, Poco::Logger &Logger, bool Deferred) {
 | 
			
		||||
 | 
			
		||||
		Logger.information(fmt::format("{},{}: New {} command. User={} Serial={}. ", Cmd.UUID,
 | 
			
		||||
									   RPCID, Cmd.Command, Cmd.SubmittedBy, Cmd.SerialNumber));
 | 
			
		||||
		Logger.information(fmt::format("{},{}: New {} command. User={} Serial={} Details={}. ", Cmd.UUID,
 | 
			
		||||
									   RPCID, Cmd.Command, Cmd.SubmittedBy, Cmd.SerialNumber, Cmd.Details));
 | 
			
		||||
		Cmd.Submitted = Utils::Now();
 | 
			
		||||
		Cmd.Executed = 0;
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -167,7 +167,11 @@ namespace OpenWifi {
 | 
			
		||||
		{APCommands::Commands::certupdate, false, true, &RESTAPI_device_commandHandler::CertUpdate, 60000ms},
 | 
			
		||||
		{APCommands::Commands::transfer, false, true, &RESTAPI_device_commandHandler::Transfer, 60000ms},
 | 
			
		||||
		{APCommands::Commands::script, false, true, &RESTAPI_device_commandHandler::Script, 60000ms},
 | 
			
		||||
		{APCommands::Commands::powercycle, false, true, &RESTAPI_device_commandHandler::PowerCycle, 60000ms}
 | 
			
		||||
		{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::reenroll, false, true, &RESTAPI_device_commandHandler::ReEnroll, 120000ms},
 | 
			
		||||
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	void RESTAPI_device_commandHandler::DoPost() {
 | 
			
		||||
@@ -691,9 +695,31 @@ namespace OpenWifi {
 | 
			
		||||
				Params.stringify(ParamStream);
 | 
			
		||||
				Cmd.Details = ParamStream.str();
 | 
			
		||||
 | 
			
		||||
				// retrieve capabilities and encode/compress parameters, if required
 | 
			
		||||
				Poco::JSON::Object ConfigParams = Params;
 | 
			
		||||
				GWObjects::Capabilities Caps;
 | 
			
		||||
				if (StorageService()->GetDeviceCapabilities(SerialNumber_, Caps)) {
 | 
			
		||||
					Poco::JSON::Object CapsJson;
 | 
			
		||||
					Caps.to_json(CapsJson);
 | 
			
		||||
					auto DeviceCaps = CapsJson.getObject(uCentralProtocol::CAPABILITIES);
 | 
			
		||||
					if (DeviceCaps->has("compress_cmd") && DeviceCaps->get("compress_cmd")) {
 | 
			
		||||
						// compressed command capability present and it is set, compress parameters
 | 
			
		||||
						Poco::JSON::Object CompressedParams;
 | 
			
		||||
						std::string CompressedBase64Data;
 | 
			
		||||
						std::uint64_t UncompressedDataLen = ParamStream.str().length();
 | 
			
		||||
						if (Utils::CompressAndEncodeBase64(ParamStream.str(), CompressedBase64Data)) {
 | 
			
		||||
							// set compressed, base 64 encoded data and length of uncompressed data
 | 
			
		||||
							CompressedParams.set(uCentralProtocol::COMPRESS_64, CompressedBase64Data);
 | 
			
		||||
							CompressedParams.set(uCentralProtocol::COMPRESS_SZ, UncompressedDataLen);
 | 
			
		||||
							ConfigParams = CompressedParams;
 | 
			
		||||
						}
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
				// AP_WS_Server()->SetPendingUUID(SerialNumber_, NewUUID);
 | 
			
		||||
				RESTAPI_RPC::WaitForCommand(CMD_RPC, APCommands::Commands::configure, true,
 | 
			
		||||
												   Cmd, Params, *Request, *Response, timeout,
 | 
			
		||||
												   Cmd, ConfigParams, *Request, *Response, timeout,
 | 
			
		||||
												   nullptr, this, Logger_);
 | 
			
		||||
 | 
			
		||||
				if(!Cmd.Executed) {
 | 
			
		||||
@@ -1548,4 +1574,123 @@ namespace OpenWifi {
 | 
			
		||||
										   Logger_);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// `fixedconfig` command is used set country propery on AP
 | 
			
		||||
	// This handler uses `fixedconfig` command definitions
 | 
			
		||||
	void RESTAPI_device_commandHandler::FixedConfig(
 | 
			
		||||
		const std::string &CMD_UUID, uint64_t CMD_RPC, std::chrono::milliseconds timeout,
 | 
			
		||||
		[[maybe_unused]] const GWObjects::DeviceRestrictions &Restrictions) {
 | 
			
		||||
		poco_debug(Logger_, fmt::format("FIXEDCONFIG({},{}): TID={} user={} serial={}", CMD_UUID, CMD_RPC,
 | 
			
		||||
										TransactionId_, Requester(), SerialNumber_));
 | 
			
		||||
		// do not allow `fixedconfig` command for simulated devices
 | 
			
		||||
		if(IsDeviceSimulated(SerialNumber_)) {
 | 
			
		||||
			CallCanceled("FIXEDCONFIG", CMD_UUID, CMD_RPC, RESTAPI::Errors::SimulatedDeviceNotSupported);
 | 
			
		||||
			return BadRequest(RESTAPI::Errors::SimulatedDeviceNotSupported);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// setup and validate fixedconfig object
 | 
			
		||||
		GWObjects::FixedConfig fixed_config;
 | 
			
		||||
		if(!fixed_config.from_json(ParsedBody_)) {
 | 
			
		||||
			return BadRequest(RESTAPI::Errors::MissingOrInvalidParameters);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// setup command message
 | 
			
		||||
		GWObjects::CommandDetails Cmd;
 | 
			
		||||
		Cmd.SerialNumber = SerialNumber_;
 | 
			
		||||
		Cmd.SubmittedBy = Requester();
 | 
			
		||||
		Cmd.UUID = CMD_UUID;
 | 
			
		||||
		Cmd.Command = uCentralProtocol::FIXEDCONFIG;
 | 
			
		||||
		std::ostringstream os;
 | 
			
		||||
		ParsedBody_->stringify(os);
 | 
			
		||||
		Cmd.Details = os.str();
 | 
			
		||||
		Cmd.RunAt = 0;
 | 
			
		||||
		Cmd.ErrorCode = 0;
 | 
			
		||||
		Cmd.WaitingForFile = 0;
 | 
			
		||||
 | 
			
		||||
		// send fixedconfig command to device and return status
 | 
			
		||||
		return RESTAPI_RPC::WaitForCommand(CMD_RPC, APCommands::Commands::fixedconfig, false, Cmd,
 | 
			
		||||
										   *ParsedBody_, *Request, *Response, timeout, nullptr, this,
 | 
			
		||||
										   Logger_);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void RESTAPI_device_commandHandler::CableDiagnostics(
 | 
			
		||||
		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("CABLEDIAGNOSTICS", CMD_UUID, CMD_RPC, RESTAPI::Errors::ACCESS_DENIED);
 | 
			
		||||
			return UnAuthorized(RESTAPI::Errors::ACCESS_DENIED);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		poco_debug(Logger_, fmt::format("CABLEDIAGNOSTICS({},{}): TID={} user={} serial={}", CMD_UUID,
 | 
			
		||||
										CMD_RPC, TransactionId_, Requester(), SerialNumber_));
 | 
			
		||||
 | 
			
		||||
		if(IsDeviceSimulated(SerialNumber_)) {
 | 
			
		||||
			CallCanceled("CABLEDIAGNOSTICS", CMD_UUID, CMD_RPC, RESTAPI::Errors::SimulatedDeviceNotSupported);
 | 
			
		||||
			return BadRequest(RESTAPI::Errors::SimulatedDeviceNotSupported);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		GWObjects::CableDiagnostics	PR;
 | 
			
		||||
		if(!PR.from_json(ParsedBody_)) {
 | 
			
		||||
			return BadRequest(RESTAPI::Errors::MissingOrInvalidParameters);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		GWObjects::CommandDetails Cmd;
 | 
			
		||||
		Cmd.SerialNumber = SerialNumber_;
 | 
			
		||||
		Cmd.SubmittedBy = Requester();
 | 
			
		||||
		Cmd.UUID = CMD_UUID;
 | 
			
		||||
		Cmd.Command = uCentralProtocol::CABLEDIAGNOSTICS;
 | 
			
		||||
		std::ostringstream os;
 | 
			
		||||
		ParsedBody_->stringify(os);
 | 
			
		||||
		Cmd.Details = os.str();
 | 
			
		||||
		Cmd.RunAt = PR.when;
 | 
			
		||||
		Cmd.ErrorCode = 0;
 | 
			
		||||
		Cmd.WaitingForFile = 0;
 | 
			
		||||
 | 
			
		||||
		return RESTAPI_RPC::WaitForCommand(CMD_RPC, APCommands::Commands::cablediagnostics, false, Cmd,
 | 
			
		||||
										   *ParsedBody_, *Request, *Response, timeout, nullptr, this,
 | 
			
		||||
										   Logger_);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void RESTAPI_device_commandHandler::ReEnroll(
 | 
			
		||||
		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("REENROLL", CMD_UUID, CMD_RPC, RESTAPI::Errors::ACCESS_DENIED);
 | 
			
		||||
			return UnAuthorized(RESTAPI::Errors::ACCESS_DENIED);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		poco_debug(Logger_, fmt::format("REENROLL({},{}): TID={} user={} serial={}", CMD_UUID,
 | 
			
		||||
										CMD_RPC, TransactionId_, Requester(), SerialNumber_));
 | 
			
		||||
 | 
			
		||||
		if(IsDeviceSimulated(SerialNumber_)) {
 | 
			
		||||
			CallCanceled("REENROLL", CMD_UUID, CMD_RPC, RESTAPI::Errors::SimulatedDeviceNotSupported);
 | 
			
		||||
			return BadRequest(RESTAPI::Errors::SimulatedDeviceNotSupported);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		GWObjects::ReEnroll PR;
 | 
			
		||||
		if(!PR.from_json(ParsedBody_)) {
 | 
			
		||||
			return BadRequest(RESTAPI::Errors::MissingOrInvalidParameters);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		GWObjects::CommandDetails Cmd;
 | 
			
		||||
		Cmd.SerialNumber = SerialNumber_;
 | 
			
		||||
		Cmd.SubmittedBy = Requester();
 | 
			
		||||
		Cmd.UUID = CMD_UUID;
 | 
			
		||||
		Cmd.Command = uCentralProtocol::REENROLL;
 | 
			
		||||
		std::ostringstream os;
 | 
			
		||||
		ParsedBody_->stringify(os);
 | 
			
		||||
		Cmd.Details = os.str();
 | 
			
		||||
		Cmd.RunAt = PR.when;
 | 
			
		||||
		Cmd.ErrorCode = 0;
 | 
			
		||||
		Cmd.WaitingForFile = 0;
 | 
			
		||||
 | 
			
		||||
		return RESTAPI_RPC::WaitForCommand(CMD_RPC, APCommands::Commands::reenroll, false, Cmd,
 | 
			
		||||
										   *ParsedBody_, *Request, *Response, timeout, nullptr, this,
 | 
			
		||||
										   Logger_);
 | 
			
		||||
	}
 | 
			
		||||
} // namespace OpenWifi
 | 
			
		||||
 
 | 
			
		||||
@@ -70,6 +70,12 @@ namespace OpenWifi {
 | 
			
		||||
					const GWObjects::DeviceRestrictions &R);
 | 
			
		||||
		void PowerCycle(const std::string &UUID, uint64_t RPC, std::chrono::milliseconds timeout,
 | 
			
		||||
					  const GWObjects::DeviceRestrictions &R);
 | 
			
		||||
		void FixedConfig(const std::string &UUID, uint64_t RPC, std::chrono::milliseconds timeout,
 | 
			
		||||
					  const GWObjects::DeviceRestrictions &R);
 | 
			
		||||
		void CableDiagnostics(const std::string &UUID, uint64_t RPC, std::chrono::milliseconds timeout,
 | 
			
		||||
					  const GWObjects::DeviceRestrictions &R);
 | 
			
		||||
		void ReEnroll(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}"};
 | 
			
		||||
 
 | 
			
		||||
@@ -22,9 +22,15 @@ namespace OpenWifi {
 | 
			
		||||
 | 
			
		||||
		std::string FileType;
 | 
			
		||||
		std::string FileContent;
 | 
			
		||||
		if (!StorageService()->GetAttachedFileContent(UUID, SerialNumber, FileContent, FileType) || FileContent.empty()) {
 | 
			
		||||
		int WaitingForFile = 0;
 | 
			
		||||
		if (!StorageService()->GetAttachedFileContent(UUID, SerialNumber, FileContent, FileType, WaitingForFile) && !WaitingForFile) {
 | 
			
		||||
			return NotFound();
 | 
			
		||||
		}
 | 
			
		||||
		else if (WaitingForFile) {
 | 
			
		||||
			// waiting for file to be uploaded, return Accepted
 | 
			
		||||
			return Accepted();
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (FileType == "pcap") {
 | 
			
		||||
			SendFileContent(FileContent, "application/vnd.tcpdump.pcap", UUID + ".pcap");
 | 
			
		||||
		}
 | 
			
		||||
 
 | 
			
		||||
@@ -297,6 +297,7 @@ namespace OpenWifi::GWObjects {
 | 
			
		||||
		field_to_json(Obj, "connectionCompletionTime", connectionCompletionTime);
 | 
			
		||||
		field_to_json(Obj, "totalConnectionTime", Utils::Now() - started);
 | 
			
		||||
		field_to_json(Obj, "certificateExpiryDate", certificateExpiryDate);
 | 
			
		||||
		field_to_json(Obj, "certificateIssuerName", certificateIssuerName);
 | 
			
		||||
		field_to_json(Obj, "connectReason", connectReason);
 | 
			
		||||
		field_to_json(Obj, "uptime", uptime);
 | 
			
		||||
        field_to_json(Obj, "compatible", Compatible);
 | 
			
		||||
@@ -358,6 +359,7 @@ namespace OpenWifi::GWObjects {
 | 
			
		||||
            field_from_json(Obj, "connectionCompletionTime", connectionCompletionTime);
 | 
			
		||||
            field_from_json(Obj, "totalConnectionTime", totalConnectionTime);
 | 
			
		||||
            field_from_json(Obj, "certificateExpiryDate", certificateExpiryDate);
 | 
			
		||||
			field_from_json(Obj, "certificateIssuerName", certificateIssuerName);
 | 
			
		||||
            field_from_json(Obj, "connectReason", connectReason);
 | 
			
		||||
            field_from_json(Obj, "uptime", uptime);
 | 
			
		||||
            field_from_json(Obj, "hasRADIUSSessions", hasRADIUSSessions );
 | 
			
		||||
@@ -799,4 +801,34 @@ namespace OpenWifi::GWObjects {
 | 
			
		||||
		return false;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	bool FixedConfig::from_json(const Poco::JSON::Object::Ptr &Obj) {
 | 
			
		||||
		try {
 | 
			
		||||
			field_from_json(Obj, "serial", serialNumber);
 | 
			
		||||
			field_from_json(Obj, "country", country);
 | 
			
		||||
			return true;
 | 
			
		||||
		} catch (const Poco::Exception &E) {
 | 
			
		||||
		}
 | 
			
		||||
		return false;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	bool CableDiagnostics::from_json(const Poco::JSON::Object::Ptr &Obj) {
 | 
			
		||||
		try {
 | 
			
		||||
			field_from_json(Obj, "serial", serialNumber);
 | 
			
		||||
			field_from_json(Obj, "when", when);
 | 
			
		||||
			field_from_json(Obj, "ports", ports);
 | 
			
		||||
			return true;
 | 
			
		||||
		} catch (const Poco::Exception &E) {
 | 
			
		||||
		}
 | 
			
		||||
		return false;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	bool ReEnroll::from_json(const Poco::JSON::Object::Ptr &Obj) {
 | 
			
		||||
		try {
 | 
			
		||||
			field_from_json(Obj, "serial", serialNumber);
 | 
			
		||||
			field_from_json(Obj, "when", when);
 | 
			
		||||
			return true;
 | 
			
		||||
		} catch (const Poco::Exception &E) {
 | 
			
		||||
		}
 | 
			
		||||
		return false;
 | 
			
		||||
	}
 | 
			
		||||
} // namespace OpenWifi::GWObjects
 | 
			
		||||
 
 | 
			
		||||
@@ -42,6 +42,7 @@ namespace OpenWifi::GWObjects {
 | 
			
		||||
		uint64_t sessionId = 0;
 | 
			
		||||
		double connectionCompletionTime = 0.0;
 | 
			
		||||
		std::uint64_t certificateExpiryDate = 0;
 | 
			
		||||
		std::string certificateIssuerName;
 | 
			
		||||
		std::uint64_t hasRADIUSSessions = 0;
 | 
			
		||||
		bool hasGPS = false;
 | 
			
		||||
		std::uint64_t sanity=0;
 | 
			
		||||
@@ -532,6 +533,25 @@ namespace OpenWifi::GWObjects {
 | 
			
		||||
		std::uint64_t 	when;
 | 
			
		||||
		std::vector<PowerCyclePort> ports;
 | 
			
		||||
 | 
			
		||||
		bool from_json(const Poco::JSON::Object::Ptr &Obj);
 | 
			
		||||
	};
 | 
			
		||||
	struct FixedConfig {
 | 
			
		||||
		std::string 	serialNumber;
 | 
			
		||||
		std::string 	country;
 | 
			
		||||
 | 
			
		||||
		bool from_json(const Poco::JSON::Object::Ptr &Obj);
 | 
			
		||||
	};
 | 
			
		||||
	struct CableDiagnostics {
 | 
			
		||||
		std::string 	serialNumber;
 | 
			
		||||
		std::uint64_t 	when;
 | 
			
		||||
		std::vector<std::string> ports;
 | 
			
		||||
 | 
			
		||||
		bool from_json(const Poco::JSON::Object::Ptr &Obj);
 | 
			
		||||
	};
 | 
			
		||||
	struct ReEnroll {
 | 
			
		||||
		std::string 	serialNumber;
 | 
			
		||||
		std::uint64_t 	when;
 | 
			
		||||
 | 
			
		||||
		bool from_json(const Poco::JSON::Object::Ptr &Obj);
 | 
			
		||||
	};
 | 
			
		||||
} // namespace OpenWifi::GWObjects
 | 
			
		||||
 
 | 
			
		||||
@@ -243,7 +243,7 @@ namespace OpenWifi {
 | 
			
		||||
									 const std::string &Type);
 | 
			
		||||
		bool CancelWaitFile(std::string &UUID, std::string &ErrorText);
 | 
			
		||||
		bool GetAttachedFileContent(std::string &UUID, const std::string &SerialNumber,
 | 
			
		||||
									std::string &FileContent, std::string &Type);
 | 
			
		||||
									std::string &FileContent, std::string &Type, int& WaitingForFile);
 | 
			
		||||
		bool RemoveAttachedFile(std::string &UUID);
 | 
			
		||||
		bool SetCommandResult(std::string &UUID, std::string &Result);
 | 
			
		||||
		bool GetNewestCommands(std::string &SerialNumber, uint64_t HowMany,
 | 
			
		||||
 
 | 
			
		||||
@@ -376,6 +376,8 @@ static std::string DefaultAPSchema = R"foo(
 | 
			
		||||
            "properties": {
 | 
			
		||||
                "port-mirror": {
 | 
			
		||||
                    "description": "Enable mirror of traffic from multiple minotor ports to a single analysis port.",
 | 
			
		||||
                    "type": "array",
 | 
			
		||||
                    "items": {
 | 
			
		||||
                        "type": "object",
 | 
			
		||||
                        "properties": {
 | 
			
		||||
                            "monitor-ports": {
 | 
			
		||||
@@ -390,6 +392,7 @@ static std::string DefaultAPSchema = R"foo(
 | 
			
		||||
                                "type": "string"
 | 
			
		||||
                            }
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                },
 | 
			
		||||
                "loop-detection": {
 | 
			
		||||
                    "description": "Enable loop detection on the L2 switches/bridge.",
 | 
			
		||||
@@ -2411,11 +2414,18 @@ static std::string DefaultAPSchema = R"foo(
 | 
			
		||||
                    "$ref": "#/$defs/interface.ssid.encryption"
 | 
			
		||||
                },
 | 
			
		||||
                "multi-psk": {
 | 
			
		||||
                    "anyOf": [
 | 
			
		||||
                        {
 | 
			
		||||
                            "type": "array",
 | 
			
		||||
                            "items": {
 | 
			
		||||
                                "$ref": "#/$defs/interface.ssid.multi-psk"
 | 
			
		||||
                            }
 | 
			
		||||
                        },
 | 
			
		||||
                        {
 | 
			
		||||
                            "type": "boolean"
 | 
			
		||||
                        }
 | 
			
		||||
                    ]
 | 
			
		||||
		},
 | 
			
		||||
                "rrm": {
 | 
			
		||||
                    "$ref": "#/$defs/interface.ssid.rrm"
 | 
			
		||||
                },
 | 
			
		||||
@@ -3942,7 +3952,9 @@ static std::string DefaultAPSchema = R"foo(
 | 
			
		||||
                            "inactive-deauth",
 | 
			
		||||
                            "key-mismatch",
 | 
			
		||||
                            "beacon-report",
 | 
			
		||||
                            "radar-detected"
 | 
			
		||||
                            "radar-detected",
 | 
			
		||||
                            "ft-finish",
 | 
			
		||||
                            "sta-authorized"
 | 
			
		||||
			 ]
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
@@ -4645,18 +4657,24 @@ static std::string DefaultSWITCHSchema = R"foo(
 | 
			
		||||
            "type": "object",
 | 
			
		||||
            "properties": {
 | 
			
		||||
                "port-mirror": {
 | 
			
		||||
                    "description": "Enable mirror of traffic from multiple minotor ports to a single analysis port.",
 | 
			
		||||
                    "type": "array",
 | 
			
		||||
                    "items": {
 | 
			
		||||
                        "type": "object",
 | 
			
		||||
                        "properties": {
 | 
			
		||||
                            "monitor-ports": {
 | 
			
		||||
                                "description": "The list of ports that we want to mirror.",
 | 
			
		||||
                                "type": "array",
 | 
			
		||||
                                "items": {
 | 
			
		||||
                                    "type": "string"
 | 
			
		||||
                                }
 | 
			
		||||
                            },
 | 
			
		||||
                            "analysis-port": {
 | 
			
		||||
                                "description": "The port that mirror'ed packets should be sent to.",
 | 
			
		||||
                                "type": "string"
 | 
			
		||||
                            }
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                },
 | 
			
		||||
                "loop-detection": {
 | 
			
		||||
                    "type": "object",
 | 
			
		||||
@@ -6603,11 +6621,18 @@ static std::string DefaultSWITCHSchema = R"foo(
 | 
			
		||||
                    "$ref": "#/$defs/interface.ssid.encryption"
 | 
			
		||||
                },
 | 
			
		||||
                "multi-psk": {
 | 
			
		||||
                    "anyOf": [
 | 
			
		||||
                        {
 | 
			
		||||
                            "type": "array",
 | 
			
		||||
                            "items": {
 | 
			
		||||
                                "$ref": "#/$defs/interface.ssid.multi-psk"
 | 
			
		||||
                            }
 | 
			
		||||
                        },
 | 
			
		||||
                        {
 | 
			
		||||
                            "type": "boolean"
 | 
			
		||||
                        }
 | 
			
		||||
                    ]
 | 
			
		||||
                },
 | 
			
		||||
                "rrm": {
 | 
			
		||||
                    "$ref": "#/$defs/interface.ssid.rrm"
 | 
			
		||||
                },
 | 
			
		||||
@@ -7897,7 +7922,9 @@ static std::string DefaultSWITCHSchema = R"foo(
 | 
			
		||||
                            "inactive-deauth",
 | 
			
		||||
                            "key-mismatch",
 | 
			
		||||
                            "beacon-report",
 | 
			
		||||
                            "radar-detected"
 | 
			
		||||
                            "radar-detected",
 | 
			
		||||
                            "ft-finish",
 | 
			
		||||
                            "sta-authorized"
 | 
			
		||||
                        ]
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
 
 | 
			
		||||
@@ -118,6 +118,10 @@ namespace OpenWifi {
 | 
			
		||||
						Producer.poll((std::chrono::milliseconds) 0);
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
				if (Queue_.size() == 0) {
 | 
			
		||||
					// message queue is empty, flush all previously sent messages
 | 
			
		||||
					Producer.flush();
 | 
			
		||||
				}
 | 
			
		||||
			} catch (const cppkafka::HandleException &E) {
 | 
			
		||||
				poco_warning(Logger_,
 | 
			
		||||
							 fmt::format("Caught a Kafka exception (producer): {}", E.what()));
 | 
			
		||||
@@ -126,10 +130,6 @@ namespace OpenWifi {
 | 
			
		||||
			} catch (...) {
 | 
			
		||||
				poco_error(Logger_, "std::exception");
 | 
			
		||||
			}
 | 
			
		||||
			if (Queue_.size() == 0) {
 | 
			
		||||
				// message queue is empty, flush all previously sent messages
 | 
			
		||||
				Producer.flush();
 | 
			
		||||
			}
 | 
			
		||||
			Note = Queue_.waitDequeueNotification();
 | 
			
		||||
		}
 | 
			
		||||
		Producer.flush();
 | 
			
		||||
 
 | 
			
		||||
@@ -431,6 +431,11 @@ namespace OpenWifi {
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		inline void Accepted() {
 | 
			
		||||
			PrepareResponse(Poco::Net::HTTPResponse::HTTP_ACCEPTED);
 | 
			
		||||
			Response->send();
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		inline void SendCompressedTarFile(const std::string &FileName, const std::string &Content) {
 | 
			
		||||
			Response->setStatus(Poco::Net::HTTPResponse::HTTPStatus::HTTP_OK);
 | 
			
		||||
			SetCommonHeaders();
 | 
			
		||||
 
 | 
			
		||||
@@ -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);
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -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_; };
 | 
			
		||||
 
 | 
			
		||||
@@ -580,6 +580,10 @@ namespace OpenWifi::RESTAPI::Protocol {
 | 
			
		||||
	static const char *INTERVAL = "interval";
 | 
			
		||||
	static const char *UI = "UI";
 | 
			
		||||
	static const char *BANDWIDTH = "bandwidth";
 | 
			
		||||
 | 
			
		||||
	static const char *FIXEDCONFIG = "fixedconfig";
 | 
			
		||||
	static const char *CABLEDIAGNOSTICS = "cable-diagnostics";
 | 
			
		||||
	static const char *REENROLL = "reenroll";
 | 
			
		||||
} // namespace OpenWifi::RESTAPI::Protocol
 | 
			
		||||
 | 
			
		||||
namespace OpenWifi::uCentralProtocol {
 | 
			
		||||
@@ -608,6 +612,7 @@ namespace OpenWifi::uCentralProtocol {
 | 
			
		||||
	static const char *CFGPENDING = "cfgpending";
 | 
			
		||||
	static const char *RECOVERY = "recovery";
 | 
			
		||||
	static const char *COMPRESS_64 = "compress_64";
 | 
			
		||||
	static const char *COMPRESS_SZ = "compress_sz";
 | 
			
		||||
	static const char *CAPABILITIES = "capabilities";
 | 
			
		||||
	static const char *REQUEST_UUID = "request_uuid";
 | 
			
		||||
	static const char *SANITY = "sanity";
 | 
			
		||||
@@ -692,6 +697,11 @@ namespace OpenWifi::uCentralProtocol {
 | 
			
		||||
	static const char *RRM = "rrm";
 | 
			
		||||
	static const char *ACTIONS = "actions";
 | 
			
		||||
 | 
			
		||||
	static const char *FIXEDCONFIG = "fixedconfig";
 | 
			
		||||
	static const char *CABLEDIAGNOSTICS = "cable-diagnostics";
 | 
			
		||||
	static const char *REENROLL = "reenroll";
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
} // namespace OpenWifi::uCentralProtocol
 | 
			
		||||
 | 
			
		||||
namespace OpenWifi::uCentralProtocol::Events {
 | 
			
		||||
@@ -788,6 +798,9 @@ namespace OpenWifi::APCommands {
 | 
			
		||||
		certupdate,
 | 
			
		||||
		transfer,
 | 
			
		||||
		powercycle,
 | 
			
		||||
		fixedconfig,
 | 
			
		||||
		cablediagnostics,
 | 
			
		||||
		reenroll,
 | 
			
		||||
		unknown
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
@@ -802,7 +815,9 @@ namespace OpenWifi::APCommands {
 | 
			
		||||
		RESTAPI::Protocol::EVENTQUEUE,	 RESTAPI::Protocol::TELEMETRY,
 | 
			
		||||
		RESTAPI::Protocol::PING,		 RESTAPI::Protocol::SCRIPT,
 | 
			
		||||
		RESTAPI::Protocol::RRM,		 	 RESTAPI::Protocol::CERTUPDATE,
 | 
			
		||||
		RESTAPI::Protocol::TRANSFER,	 RESTAPI::Protocol::POWERCYCLE
 | 
			
		||||
		RESTAPI::Protocol::TRANSFER,	 RESTAPI::Protocol::POWERCYCLE,
 | 
			
		||||
		RESTAPI::Protocol::FIXEDCONFIG,  RESTAPI::Protocol::CABLEDIAGNOSTICS,
 | 
			
		||||
		RESTAPI::Protocol::REENROLL
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	inline const char *to_string(Commands Cmd) { return uCentralAPCommands[(uint8_t)Cmd]; }
 | 
			
		||||
 
 | 
			
		||||
@@ -590,6 +590,26 @@ namespace OpenWifi::Utils {
 | 
			
		||||
		return false;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	//
 | 
			
		||||
	// Compress given data using utility function and encode it in base64 format.
 | 
			
		||||
	//
 | 
			
		||||
	bool CompressAndEncodeBase64(const std::string& UnCompressedData, std::string& CompressedBase64Data) {
 | 
			
		||||
 | 
			
		||||
		unsigned long CompressedDataSize = UnCompressedData.size();
 | 
			
		||||
		std::vector<Bytef> CompressedData(CompressedDataSize);
 | 
			
		||||
		auto status = compress(&CompressedData[0], &CompressedDataSize,
 | 
			
		||||
								(Bytef*) UnCompressedData.c_str(), UnCompressedData.size());
 | 
			
		||||
		if (status == Z_OK) {
 | 
			
		||||
			CompressedBase64Data = OpenWifi::Utils::base64encode(&CompressedData[0], CompressedDataSize);
 | 
			
		||||
		}
 | 
			
		||||
		else {
 | 
			
		||||
			// failed to compress data
 | 
			
		||||
			return false;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		return true;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	bool IsAlphaNumeric(const std::string &s) {
 | 
			
		||||
		return std::all_of(s.begin(), s.end(), [](char c) -> bool { return isalnum(c); });
 | 
			
		||||
	}
 | 
			
		||||
 
 | 
			
		||||
@@ -151,6 +151,8 @@ namespace OpenWifi::Utils {
 | 
			
		||||
	bool ExtractBase64CompressedData(const std::string &CompressedData,
 | 
			
		||||
									 std::string &UnCompressedData, uint64_t compress_sz);
 | 
			
		||||
 | 
			
		||||
	bool CompressAndEncodeBase64(const std::string& UnCompressedData, std::string& CompressedData);
 | 
			
		||||
 | 
			
		||||
	inline bool match(const char* first, const char* second)
 | 
			
		||||
	{
 | 
			
		||||
		// If we reach at the end of both strings, we are done
 | 
			
		||||
 
 | 
			
		||||
@@ -14,6 +14,7 @@
 | 
			
		||||
#include "nlohmann/json.hpp"
 | 
			
		||||
 | 
			
		||||
#include "Poco/NObserver.h"
 | 
			
		||||
#include <Poco/Net/Context.h>
 | 
			
		||||
#include "Poco/Net/SocketNotification.h"
 | 
			
		||||
#include "Poco/Net/NetException.h"
 | 
			
		||||
#include "Poco/Net/WebSocketImpl.h"
 | 
			
		||||
@@ -71,6 +72,7 @@ namespace OpenWifi {
 | 
			
		||||
				const auto &RootCas =
 | 
			
		||||
					MicroServiceConfigPath("ucentral.websocket.host.0.rootca", "");
 | 
			
		||||
				const auto &Cas = MicroServiceConfigPath("ucentral.websocket.host.0.cas", "");
 | 
			
		||||
				const auto &ClientCasFile = MicroServiceConfigPath("ucentral.websocket.host.0.clientcas", "");
 | 
			
		||||
 | 
			
		||||
				Poco::Net::Context::Params P;
 | 
			
		||||
 | 
			
		||||
@@ -86,6 +88,7 @@ namespace OpenWifi {
 | 
			
		||||
				Poco::Crypto::X509Certificate Cert(CertFileName);
 | 
			
		||||
				Poco::Crypto::X509Certificate Root(RootCaFileName);
 | 
			
		||||
				Poco::Crypto::X509Certificate Issuing(IssuerFileName);
 | 
			
		||||
                std::vector<Poco::Crypto::X509Certificate> ClientCasCerts;
 | 
			
		||||
				Poco::Crypto::RSAKey Key("", KeyFileName, KeyPassword);
 | 
			
		||||
 | 
			
		||||
				DeviceSecureContext->useCertificate(Cert);
 | 
			
		||||
@@ -93,7 +96,11 @@ namespace OpenWifi {
 | 
			
		||||
				DeviceSecureContext->addCertificateAuthority(Root);
 | 
			
		||||
				DeviceSecureContext->addChainCertificate(Issuing);
 | 
			
		||||
				DeviceSecureContext->addCertificateAuthority(Issuing);
 | 
			
		||||
				DeviceSecureContext->addCertificateAuthority(Root);
 | 
			
		||||
                ClientCasCerts = Poco::Net::X509Certificate::readPEM(ClientCasFile);
 | 
			
		||||
                for (const auto &cert : ClientCasCerts) {
 | 
			
		||||
                    DeviceSecureContext->addChainCertificate(cert);
 | 
			
		||||
                    DeviceSecureContext->addCertificateAuthority(cert);
 | 
			
		||||
                }
 | 
			
		||||
				DeviceSecureContext->enableSessionCache(true);
 | 
			
		||||
				DeviceSecureContext->setSessionCacheSize(0);
 | 
			
		||||
				DeviceSecureContext->setSessionTimeout(120);
 | 
			
		||||
 
 | 
			
		||||
@@ -644,21 +644,7 @@ namespace OpenWifi {
 | 
			
		||||
			uint64_t Size = FileContent.str().size();
 | 
			
		||||
 | 
			
		||||
			Poco::Data::Session Sess = Pool_->get();
 | 
			
		||||
			Sess.begin();
 | 
			
		||||
			Poco::Data::Statement Statement(Sess);
 | 
			
		||||
 | 
			
		||||
			std::string StatementStr;
 | 
			
		||||
 | 
			
		||||
			//	Get the existing command
 | 
			
		||||
 | 
			
		||||
			StatementStr =
 | 
			
		||||
				"UPDATE CommandList SET WaitingForFile=?, AttachDate=?, AttachSize=? WHERE UUID=?";
 | 
			
		||||
 | 
			
		||||
			Statement << ConvertParams(StatementStr), Poco::Data::Keywords::use(WaitForFile),
 | 
			
		||||
				Poco::Data::Keywords::use(Now), Poco::Data::Keywords::use(Size),
 | 
			
		||||
				Poco::Data::Keywords::use(UUID);
 | 
			
		||||
			Statement.execute();
 | 
			
		||||
			Sess.commit();
 | 
			
		||||
			if (Size < FileUploader()->MaxSize()) {
 | 
			
		||||
 | 
			
		||||
				Poco::Data::BLOB TheBlob;
 | 
			
		||||
@@ -680,7 +666,20 @@ namespace OpenWifi {
 | 
			
		||||
			} else {
 | 
			
		||||
				poco_warning(Logger(), fmt::format("File {} is too large.", UUID));
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			// update CommandList here to ensure that file us uploaded
 | 
			
		||||
                        Sess.begin();
 | 
			
		||||
                        Poco::Data::Statement Statement(Sess);
 | 
			
		||||
			std::string StatementStr;
 | 
			
		||||
			StatementStr =
 | 
			
		||||
				"UPDATE CommandList SET WaitingForFile=?, AttachDate=?, AttachSize=? WHERE UUID=?";
 | 
			
		||||
 | 
			
		||||
			Statement << ConvertParams(StatementStr), Poco::Data::Keywords::use(WaitForFile),
 | 
			
		||||
				Poco::Data::Keywords::use(Now), Poco::Data::Keywords::use(Size),
 | 
			
		||||
				Poco::Data::Keywords::use(UUID);
 | 
			
		||||
			Statement.execute();
 | 
			
		||||
			Sess.commit();
 | 
			
		||||
 | 
			
		||||
			return true;
 | 
			
		||||
		} catch (const Poco::Exception &E) {
 | 
			
		||||
			Logger().log(E);
 | 
			
		||||
@@ -689,7 +688,7 @@ namespace OpenWifi {
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	bool Storage::GetAttachedFileContent(std::string &UUID, const std::string &SerialNumber,
 | 
			
		||||
										 std::string &FileContent, std::string &Type) {
 | 
			
		||||
										 std::string &FileContent, std::string &Type, int &WaitingForFile) {
 | 
			
		||||
		try {
 | 
			
		||||
			Poco::Data::BLOB L;
 | 
			
		||||
			/*
 | 
			
		||||
@@ -702,10 +701,10 @@ namespace OpenWifi {
 | 
			
		||||
			Poco::Data::Statement Select1(Sess);
 | 
			
		||||
 | 
			
		||||
			std::string TmpSerialNumber;
 | 
			
		||||
			std::string st1{"SELECT SerialNumber, Command FROM CommandList WHERE UUID=?"};
 | 
			
		||||
			std::string st1{"SELECT SerialNumber, Command , WaitingForFile FROM CommandList WHERE UUID=?"};
 | 
			
		||||
			std::string Command;
 | 
			
		||||
			Select1 << ConvertParams(st1), Poco::Data::Keywords::into(TmpSerialNumber),
 | 
			
		||||
				Poco::Data::Keywords::into(Command), Poco::Data::Keywords::use(UUID);
 | 
			
		||||
				Poco::Data::Keywords::into(Command), Poco::Data::Keywords::into(WaitingForFile), Poco::Data::Keywords::use(UUID);
 | 
			
		||||
			Select1.execute();
 | 
			
		||||
 | 
			
		||||
			if (TmpSerialNumber != SerialNumber) {
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user