mirror of
				https://github.com/Telecominfraproject/wlan-cloud-ucentralgw.git
				synced 2025-11-03 20:27:45 +00:00 
			
		
		
		
	Compare commits
	
		
			93 Commits
		
	
	
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					9e1e75b1da | ||
| 
						 | 
					7ba90a0964 | ||
| 
						 | 
					51a1b12d03 | ||
| 
						 | 
					e3e1d04b2f | ||
| 
						 | 
					862dab38d1 | ||
| 
						 | 
					ee2e9a19c0 | ||
| 
						 | 
					e59304517e | ||
| 
						 | 
					8b28fa0435 | ||
| 
						 | 
					aeef70a121 | ||
| 
						 | 
					42c421ec12 | ||
| 
						 | 
					98bfb4b24d | ||
| 
						 | 
					6b64089f55 | ||
| 
						 | 
					1f6e42b57c | ||
| 
						 | 
					f857d61377 | ||
| 
						 | 
					66d580d047 | ||
| 
						 | 
					567c671c22 | ||
| 
						 | 
					9e3735ced8 | ||
| 
						 | 
					18b169e517 | ||
| 
						 | 
					cab0d8aee6 | ||
| 
						 | 
					680b6a16e3 | ||
| 
						 | 
					218694872f | ||
| 
						 | 
					6ae1eeb2ea | ||
| 
						 | 
					f537e701a0 | ||
| 
						 | 
					d4dfb7b620 | ||
| 
						 | 
					446cbf270f | ||
| 
						 | 
					06ffee27b1 | ||
| 
						 | 
					fa3c325bfa | ||
| 
						 | 
					182a442582 | ||
| 
						 | 
					3b7a24ea30 | ||
| 
						 | 
					1c5909613f | ||
| 
						 | 
					8e5e51a52a | ||
| 
						 | 
					b4699e9178 | ||
| 
						 | 
					438309714f | ||
| 
						 | 
					a9130eeb75 | ||
| 
						 | 
					33068fca9e | ||
| 
						 | 
					d329151f6c | ||
| 
						 | 
					ec846006bb | ||
| 
						 | 
					bd48079a8d | ||
| 
						 | 
					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:
 | 
					jobs:
 | 
				
			||||||
  docker:
 | 
					  docker:
 | 
				
			||||||
    runs-on: ubuntu-20.04
 | 
					    runs-on: ubuntu-latest
 | 
				
			||||||
    env:
 | 
					    env:
 | 
				
			||||||
      DOCKER_REGISTRY_URL: tip-tip-wlan-cloud-ucentral.jfrog.io
 | 
					      DOCKER_REGISTRY_URL: tip-tip-wlan-cloud-ucentral.jfrog.io
 | 
				
			||||||
      DOCKER_REGISTRY_USERNAME: ucentral
 | 
					      DOCKER_REGISTRY_USERNAME: ucentral
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										2
									
								
								.github/workflows/release.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								.github/workflows/release.yml
									
									
									
									
										vendored
									
									
								
							@@ -11,7 +11,7 @@ defaults:
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
jobs:
 | 
					jobs:
 | 
				
			||||||
  helm-package:
 | 
					  helm-package:
 | 
				
			||||||
    runs-on: ubuntu-20.04
 | 
					    runs-on: ubuntu-latest
 | 
				
			||||||
    env:
 | 
					    env:
 | 
				
			||||||
      HELM_REPO_URL: https://tip.jfrog.io/artifactory/tip-wlan-cloud-ucentral-helm/
 | 
					      HELM_REPO_URL: https://tip.jfrog.io/artifactory/tip-wlan-cloud-ucentral-helm/
 | 
				
			||||||
      HELM_REPO_USERNAME: ucentral
 | 
					      HELM_REPO_USERNAME: ucentral
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										2
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							@@ -29,4 +29,4 @@ helm/charts/*
 | 
				
			|||||||
!helm/charts/.gitkeep
 | 
					!helm/charts/.gitkeep
 | 
				
			||||||
/portal-test/
 | 
					/portal-test/
 | 
				
			||||||
/src/ow_version.h
 | 
					/src/ow_version.h
 | 
				
			||||||
 | 
					.vscode/*
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,5 +1,5 @@
 | 
				
			|||||||
cmake_minimum_required(VERSION 3.13)
 | 
					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 20)
 | 
				
			||||||
set(CMAKE_CXX_STANDARD_REQUIRED True)
 | 
					set(CMAKE_CXX_STANDARD_REQUIRED True)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,7 +1,7 @@
 | 
				
			|||||||
ARG DEBIAN_VERSION=11.5-slim
 | 
					ARG DEBIAN_VERSION=bookworm
 | 
				
			||||||
ARG POCO_VERSION=poco-tip-v2
 | 
					ARG POCO_VERSION=poco-tip-v4-tag
 | 
				
			||||||
ARG CPPKAFKA_VERSION=tip-v1
 | 
					ARG CPPKAFKA_VERSION=tip-v1
 | 
				
			||||||
ARG VALIJASON_VERSION=tip-v1
 | 
					ARG VALIJASON_VERSION=tip-v1.0.2
 | 
				
			||||||
ARG APP_NAME=owgw
 | 
					ARG APP_NAME=owgw
 | 
				
			||||||
ARG APP_HOME_DIR=/openwifi
 | 
					ARG APP_HOME_DIR=/openwifi
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -100,7 +100,7 @@ RUN mkdir -p $APP_ROOT $APP_CONFIG && \
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
RUN apt-get update && apt-get install --no-install-recommends -y \
 | 
					RUN apt-get update && apt-get install --no-install-recommends -y \
 | 
				
			||||||
    librdkafka++1 gosu gettext ca-certificates bash jq curl wget \
 | 
					    librdkafka++1 gosu gettext ca-certificates bash jq curl wget \
 | 
				
			||||||
    libmariadb-dev-compat libpq5 unixodbc postgresql-client libfmt7 sqlite3
 | 
					    libmariadb-dev-compat libpq5 unixodbc postgresql-client libfmt9 sqlite3
 | 
				
			||||||
 | 
					
 | 
				
			||||||
COPY readiness_check /readiness_check
 | 
					COPY readiness_check /readiness_check
 | 
				
			||||||
COPY test_scripts/curl/cli /cli
 | 
					COPY test_scripts/curl/cli /cli
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										72
									
								
								PROTOCOL.md
									
									
									
									
									
								
							
							
						
						
									
										72
									
								
								PROTOCOL.md
									
									
									
									
									
								
							@@ -306,8 +306,54 @@ The device should answer:
 | 
				
			|||||||
         },
 | 
					         },
 | 
				
			||||||
     "id" : <same number>
 | 
					     "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 Answer
 | 
				
			||||||
The device can answer and tell the controller it has rejected certain parts of the config and potentially replaced them with
 | 
					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 
 | 
					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 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.
 | 
					Controller sends this when the device should change the controller it connects to without looking up a new redirector.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -32,6 +32,7 @@ if [[ "$TEMPLATE_CONFIG" = 'true' ]]; then
 | 
				
			|||||||
    FILEUPLOADER_HOST_KEY_PASSWORD=${FILEUPLOADER_HOST_KEY_PASSWORD:-"mypassword"} \
 | 
					    FILEUPLOADER_HOST_KEY_PASSWORD=${FILEUPLOADER_HOST_KEY_PASSWORD:-"mypassword"} \
 | 
				
			||||||
    FILEUPLOADER_PATH=${FILEUPLOADER_PATH:-"\${APP_ROOT}/uploads"} \
 | 
					    FILEUPLOADER_PATH=${FILEUPLOADER_PATH:-"\${APP_ROOT}/uploads"} \
 | 
				
			||||||
    FILEUPLOADER_URI=${FILEUPLOADER_URI:-"https://localhost:16003"} \
 | 
					    FILEUPLOADER_URI=${FILEUPLOADER_URI:-"https://localhost:16003"} \
 | 
				
			||||||
 | 
					    FILEUPLOADER_MAXSIZE=${FILEUPLOADER_MAXSIZE:-"10000"} \
 | 
				
			||||||
    SERVICE_KEY=${SERVICE_KEY:-"\${APP_ROOT}/certs/restapi-key.pem"} \
 | 
					    SERVICE_KEY=${SERVICE_KEY:-"\${APP_ROOT}/certs/restapi-key.pem"} \
 | 
				
			||||||
    SERVICE_KEY_PASSWORD=${SERVICE_KEY_PASSWORD:-"mypassword"} \
 | 
					    SERVICE_KEY_PASSWORD=${SERVICE_KEY_PASSWORD:-"mypassword"} \
 | 
				
			||||||
    SYSTEM_DATA=${SYSTEM_DATA:-"\${APP_ROOT}/data"} \
 | 
					    SYSTEM_DATA=${SYSTEM_DATA:-"\${APP_ROOT}/data"} \
 | 
				
			||||||
@@ -76,6 +77,7 @@ if [[ "$TEMPLATE_CONFIG" = 'true' ]]; then
 | 
				
			|||||||
    CERTIFICATES_ALLOWMISMATCH=${CERTIFICATES_ALLOWMISMATCH:-"false"} \
 | 
					    CERTIFICATES_ALLOWMISMATCH=${CERTIFICATES_ALLOWMISMATCH:-"false"} \
 | 
				
			||||||
    IPINFO_DEFAULT_COUNTRY=${IPINFO_DEFAULT_COUNTRY:-"US"} \
 | 
					    IPINFO_DEFAULT_COUNTRY=${IPINFO_DEFAULT_COUNTRY:-"US"} \
 | 
				
			||||||
    DEVICE_SESSION_TIMEOUT=${DEVICE_SESSION_TIMEOUT:-"600"} \
 | 
					    DEVICE_SESSION_TIMEOUT=${DEVICE_SESSION_TIMEOUT:-"600"} \
 | 
				
			||||||
 | 
					    LOGGING_LEVEL=${LOGGING_LEVEL:-"information"} \
 | 
				
			||||||
    envsubst < /"${APP_NAME}".properties.tmpl > "${APP_CONFIG}"/"${APP_NAME}".properties
 | 
					    envsubst < /"${APP_NAME}".properties.tmpl > "${APP_CONFIG}"/"${APP_NAME}".properties
 | 
				
			||||||
fi
 | 
					fi
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -9,7 +9,7 @@ fullnameOverride: ""
 | 
				
			|||||||
images:
 | 
					images:
 | 
				
			||||||
  owgw:
 | 
					  owgw:
 | 
				
			||||||
    repository: tip-tip-wlan-cloud-ucentral.jfrog.io/owgw
 | 
					    repository: tip-tip-wlan-cloud-ucentral.jfrog.io/owgw
 | 
				
			||||||
    tag: master
 | 
					    tag: v4.1.0
 | 
				
			||||||
    pullPolicy: Always
 | 
					    pullPolicy: Always
 | 
				
			||||||
#    regcred:
 | 
					#    regcred:
 | 
				
			||||||
#      registry: tip-tip-wlan-cloud-ucentral.jfrog.io
 | 
					#      registry: tip-tip-wlan-cloud-ucentral.jfrog.io
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -12,7 +12,7 @@ info:
 | 
				
			|||||||
    url: https://www.ucentral.info/support
 | 
					    url: https://www.ucentral.info/support
 | 
				
			||||||
 | 
					
 | 
				
			||||||
servers:
 | 
					servers:
 | 
				
			||||||
  - url: 'https://localhost:16001/api/v1'
 | 
					  - url: 'https://localhost:16002/api/v1'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
security:
 | 
					security:
 | 
				
			||||||
  - bearerAuth: []
 | 
					  - bearerAuth: []
 | 
				
			||||||
@@ -1576,6 +1576,15 @@ components:
 | 
				
			|||||||
          format: base64
 | 
					          format: base64
 | 
				
			||||||
          description: This is a base64 encoded string of the certificate bundle (the current bundle .tar.gz file from the PKI portal)
 | 
					          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:
 | 
					    PowerCycleRequest:
 | 
				
			||||||
      type: object
 | 
					      type: object
 | 
				
			||||||
      properties:
 | 
					      properties:
 | 
				
			||||||
@@ -1600,6 +1609,74 @@ components:
 | 
				
			|||||||
                maximum: 60000
 | 
					                maximum: 60000
 | 
				
			||||||
                description: off time in milliseconds
 | 
					                description: off time in milliseconds
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    PackageGetResponse:
 | 
				
			||||||
 | 
					      type: object
 | 
				
			||||||
 | 
					      properties:
 | 
				
			||||||
 | 
					        serial:
 | 
				
			||||||
 | 
					          type: string
 | 
				
			||||||
 | 
					        status:
 | 
				
			||||||
 | 
					          type: object
 | 
				
			||||||
 | 
					          properties:
 | 
				
			||||||
 | 
					            package:
 | 
				
			||||||
 | 
					              type: string
 | 
				
			||||||
 | 
					            text:
 | 
				
			||||||
 | 
					              type: string
 | 
				
			||||||
 | 
					        uuid:
 | 
				
			||||||
 | 
					          type: number
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    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:
 | 
					paths:
 | 
				
			||||||
  /devices:
 | 
					  /devices:
 | 
				
			||||||
    get:
 | 
					    get:
 | 
				
			||||||
@@ -3056,6 +3133,32 @@ paths:
 | 
				
			|||||||
        404:
 | 
					        404:
 | 
				
			||||||
          $ref: '#/components/responses/NotFound'
 | 
					          $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:
 | 
					  /device/{serialNumber}/powercycle:
 | 
				
			||||||
    post:
 | 
					    post:
 | 
				
			||||||
      tags:
 | 
					      tags:
 | 
				
			||||||
@@ -3084,6 +3187,98 @@ paths:
 | 
				
			|||||||
        404:
 | 
					        404:
 | 
				
			||||||
          $ref: '#/components/responses/NotFound'
 | 
					          $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
 | 
				
			||||||
 | 
					        - in: query
 | 
				
			||||||
 | 
					          name: pkgName
 | 
				
			||||||
 | 
					          schema:
 | 
				
			||||||
 | 
					            type: string
 | 
				
			||||||
 | 
					          required: true
 | 
				
			||||||
 | 
					          description: The name or identifier of the package to retrieve.
 | 
				
			||||||
 | 
					      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:
 | 
					  /ouis:
 | 
				
			||||||
    get:
 | 
					    get:
 | 
				
			||||||
      tags:
 | 
					      tags:
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -52,7 +52,8 @@ openwifi.fileuploader.host.0.cert = ${FILEUPLOADER_HOST_CERT}
 | 
				
			|||||||
openwifi.fileuploader.host.0.key = ${FILEUPLOADER_HOST_KEY}
 | 
					openwifi.fileuploader.host.0.key = ${FILEUPLOADER_HOST_KEY}
 | 
				
			||||||
openwifi.fileuploader.host.0.key.password = ${FILEUPLOADER_HOST_KEY_PASSWORD}
 | 
					openwifi.fileuploader.host.0.key.password = ${FILEUPLOADER_HOST_KEY_PASSWORD}
 | 
				
			||||||
openwifi.fileuploader.path = ${FILEUPLOADER_PATH}
 | 
					openwifi.fileuploader.path = ${FILEUPLOADER_PATH}
 | 
				
			||||||
openwifi.fileuploader.maxsize = 10000
 | 
					# maxsize in KB
 | 
				
			||||||
 | 
					openwifi.fileuploader.maxsize = ${FILEUPLOADER_MAXSIZE}
 | 
				
			||||||
openwifi.fileuploader.uri = ${FILEUPLOADER_URI}
 | 
					openwifi.fileuploader.uri = ${FILEUPLOADER_URI}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#
 | 
					#
 | 
				
			||||||
@@ -182,4 +183,4 @@ archiver.db.3.keep = 7
 | 
				
			|||||||
########################################################################
 | 
					########################################################################
 | 
				
			||||||
logging.type = console
 | 
					logging.type = console
 | 
				
			||||||
logging.path = $OWGW_ROOT/logs
 | 
					logging.path = $OWGW_ROOT/logs
 | 
				
			||||||
logging.level = information
 | 
					logging.level = ${LOGGING_LEVEL}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -7,6 +7,7 @@
 | 
				
			|||||||
#include <Poco/Net/Context.h>
 | 
					#include <Poco/Net/Context.h>
 | 
				
			||||||
#include <Poco/Net/HTTPServerRequestImpl.h>
 | 
					#include <Poco/Net/HTTPServerRequestImpl.h>
 | 
				
			||||||
#include <Poco/Net/HTTPServerResponseImpl.h>
 | 
					#include <Poco/Net/HTTPServerResponseImpl.h>
 | 
				
			||||||
 | 
					#include <Poco/JSON/JSONException.h>
 | 
				
			||||||
#include <Poco/Net/NetException.h>
 | 
					#include <Poco/Net/NetException.h>
 | 
				
			||||||
#include <Poco/Net/SSLException.h>
 | 
					#include <Poco/Net/SSLException.h>
 | 
				
			||||||
#include <Poco/Net/SecureStreamSocketImpl.h>
 | 
					#include <Poco/Net/SecureStreamSocketImpl.h>
 | 
				
			||||||
@@ -39,7 +40,7 @@ namespace OpenWifi {
 | 
				
			|||||||
									   Poco::Net::HTTPServerResponse &response,
 | 
														   Poco::Net::HTTPServerResponse &response,
 | 
				
			||||||
									   uint64_t session_id, Poco::Logger &L,
 | 
														   uint64_t session_id, Poco::Logger &L,
 | 
				
			||||||
									   std::pair<std::shared_ptr<Poco::Net::SocketReactor>, std::shared_ptr<LockedDbSession>> R)
 | 
														   std::pair<std::shared_ptr<Poco::Net::SocketReactor>, std::shared_ptr<LockedDbSession>> R)
 | 
				
			||||||
		: Logger_(L) {
 | 
							: Logger_(L), IncomingFrame_(0) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		Reactor_ = R.first;
 | 
							Reactor_ = R.first;
 | 
				
			||||||
		DbSession_ = R.second;
 | 
							DbSession_ = R.second;
 | 
				
			||||||
@@ -54,6 +55,7 @@ namespace OpenWifi {
 | 
				
			|||||||
		WS_->setNoDelay(false);
 | 
							WS_->setNoDelay(false);
 | 
				
			||||||
		WS_->setKeepAlive(true);
 | 
							WS_->setKeepAlive(true);
 | 
				
			||||||
		WS_->setBlocking(false);
 | 
							WS_->setBlocking(false);
 | 
				
			||||||
 | 
							IncomingFrame_.resize(0);
 | 
				
			||||||
		uuid_ = MicroServiceRandom(std::numeric_limits<std::uint64_t>::max()-1);
 | 
							uuid_ = MicroServiceRandom(std::numeric_limits<std::uint64_t>::max()-1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		AP_WS_Server()->IncrementConnectionCount();
 | 
							AP_WS_Server()->IncrementConnectionCount();
 | 
				
			||||||
@@ -213,6 +215,7 @@ namespace OpenWifi {
 | 
				
			|||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			State_.certificateExpiryDate = PeerCert.expiresOn().timestamp().epochTime();
 | 
								State_.certificateExpiryDate = PeerCert.expiresOn().timestamp().epochTime();
 | 
				
			||||||
 | 
								State_.certificateIssuerName = PeerCert.issuerName();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			poco_trace(Logger_,
 | 
								poco_trace(Logger_,
 | 
				
			||||||
					   fmt::format("TLS-CONNECTION({}): Session={} CN={} Completed. (t={})", CId_,
 | 
										   fmt::format("TLS-CONNECTION({}): Session={} CN={} Completed. (t={})", CId_,
 | 
				
			||||||
@@ -599,33 +602,92 @@ namespace OpenWifi {
 | 
				
			|||||||
		EndConnection();
 | 
							EndConnection();
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	void AP_WS_Connection::ProcessIncomingFrame() {
 | 
						void AP_WS_Connection::ProcessWSFinalPayload() {
 | 
				
			||||||
		Poco::Buffer<char> IncomingFrame(0);
 | 
							auto IncomingSize = IncomingFrame_.size();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (IncomingSize == 0) {
 | 
				
			||||||
 | 
								poco_debug(Logger_,
 | 
				
			||||||
 | 
											 fmt::format("ProcessWSFrame({}): Final Acc. Frame received but empty",
 | 
				
			||||||
 | 
														 CId_));
 | 
				
			||||||
 | 
								return;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							IncomingFrame_.append(0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							poco_trace(Logger_,
 | 
				
			||||||
 | 
									   fmt::format("ProcessWSFrame({}): Final Acc. Frame received (len={}, Msg={}",
 | 
				
			||||||
 | 
												   CId_, IncomingSize, IncomingFrame_.begin()));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							Poco::JSON::Parser parser;
 | 
				
			||||||
 | 
							auto ParsedMessage = parser.parse(IncomingFrame_.begin());
 | 
				
			||||||
 | 
							auto IncomingJSON = ParsedMessage.extract<Poco::JSON::Object::Ptr>();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (IncomingJSON->has(uCentralProtocol::JSONRPC)) {
 | 
				
			||||||
 | 
								if (IncomingJSON->has(uCentralProtocol::METHOD) &&
 | 
				
			||||||
 | 
									IncomingJSON->has(uCentralProtocol::PARAMS)) {
 | 
				
			||||||
 | 
									ProcessJSONRPCEvent(IncomingJSON);
 | 
				
			||||||
 | 
								} else if (IncomingJSON->has(uCentralProtocol::RESULT) &&
 | 
				
			||||||
 | 
										   IncomingJSON->has(uCentralProtocol::ID)) {
 | 
				
			||||||
 | 
									poco_trace(Logger_, fmt::format("RPC-RESULT({}): payload: {}", CId_,
 | 
				
			||||||
 | 
																	IncomingFrame_.begin()));
 | 
				
			||||||
 | 
									ProcessJSONRPCResult(IncomingJSON);
 | 
				
			||||||
 | 
								} else {
 | 
				
			||||||
 | 
									poco_warning(
 | 
				
			||||||
 | 
										Logger_,
 | 
				
			||||||
 | 
										fmt::format("INVALID-PAYLOAD({}): Payload is not JSON-RPC 2.0: {}",
 | 
				
			||||||
 | 
													CId_, IncomingFrame_.begin()));
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							} else if (IncomingJSON->has(uCentralProtocol::RADIUS)) {
 | 
				
			||||||
 | 
								ProcessIncomingRadiusData(IncomingJSON);
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								std::ostringstream iS;
 | 
				
			||||||
 | 
								IncomingJSON->stringify(iS);
 | 
				
			||||||
 | 
								poco_warning(
 | 
				
			||||||
 | 
									Logger_,
 | 
				
			||||||
 | 
									fmt::format("FRAME({}): illegal transaction header, missing 'jsonrpc': {}",
 | 
				
			||||||
 | 
												CId_, iS.str()));
 | 
				
			||||||
 | 
								Errors_++;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							IncomingFrame_.clear();
 | 
				
			||||||
 | 
							IncomingFrame_.resize(0);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						void AP_WS_Connection::ProcessIncomingFrame() {
 | 
				
			||||||
 | 
							Poco::Buffer<char> CurrentFrame(0);
 | 
				
			||||||
		bool KillConnection = false;
 | 
							bool KillConnection = false;
 | 
				
			||||||
 | 
							int flags = 0;
 | 
				
			||||||
 | 
							int IncomingSize = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		try {
 | 
							try {
 | 
				
			||||||
			int 	Op, flags;
 | 
								IncomingSize = WS_->receiveFrame(CurrentFrame, flags);
 | 
				
			||||||
			auto IncomingSize = WS_->receiveFrame(IncomingFrame, flags);
 | 
								int Op;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			Op = flags & Poco::Net::WebSocket::FRAME_OP_BITMASK;
 | 
								Op = flags & Poco::Net::WebSocket::FRAME_OP_BITMASK;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			if (IncomingSize == 0 && flags == 0 && Op == 0) {
 | 
								if (IncomingSize < 0 && flags == 0) {
 | 
				
			||||||
 | 
									poco_trace(Logger_,
 | 
				
			||||||
 | 
										fmt::format("EMPTY({}): Non-blocking try-again empty frame (len={}, flags={})",
 | 
				
			||||||
 | 
												   CId_, IncomingSize, flags));
 | 
				
			||||||
 | 
					            } else if (IncomingSize == 0 && flags == 0) {
 | 
				
			||||||
				poco_information(Logger_,
 | 
									poco_information(Logger_,
 | 
				
			||||||
								 fmt::format("DISCONNECT({}): device has disconnected. Session={}",
 | 
													 fmt::format("DISCONNECT({}): device has disconnected. Session={}",
 | 
				
			||||||
											 CId_, State_.sessionId));
 | 
																 CId_, State_.sessionId));
 | 
				
			||||||
				return EndConnection();
 | 
									return EndConnection();
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			IncomingFrame.append(0);
 | 
								if (IncomingSize > 0) {
 | 
				
			||||||
 | 
					 | 
				
			||||||
				State_.RX += IncomingSize;
 | 
									State_.RX += IncomingSize;
 | 
				
			||||||
				AP_WS_Server()->AddRX(IncomingSize);
 | 
									AP_WS_Server()->AddRX(IncomingSize);
 | 
				
			||||||
 | 
									IncomingFrame_.append(CurrentFrame);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
			State_.MessageCount++;
 | 
								State_.MessageCount++;
 | 
				
			||||||
			State_.LastContact = Utils::Now();
 | 
								State_.LastContact = Utils::Now();
 | 
				
			||||||
 | 
								poco_trace(Logger_,
 | 
				
			||||||
 | 
										   fmt::format("FRAME({}): Frame rx (op={} len={}, flags={}, acc.len={})",
 | 
				
			||||||
 | 
													   CId_, Op, IncomingSize, flags, IncomingFrame_.size()));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			switch (Op) {
 | 
								switch (Op) {
 | 
				
			||||||
				case Poco::Net::WebSocket::FRAME_OP_PING: {
 | 
									case Poco::Net::WebSocket::FRAME_OP_PING: {
 | 
				
			||||||
					poco_trace(Logger_, fmt::format("WS-PING({}): received. PONG sent back.", CId_));
 | 
										poco_trace(Logger_, fmt::format("PING({}): received. PONG sent back.", CId_));
 | 
				
			||||||
					WS_->sendFrame("", 0,
 | 
										WS_->sendFrame("", 0,
 | 
				
			||||||
								   (int)Poco::Net::WebSocket::FRAME_OP_PONG |
 | 
													   (int)Poco::Net::WebSocket::FRAME_OP_PONG |
 | 
				
			||||||
								   (int)Poco::Net::WebSocket::FRAME_FLAG_FIN);
 | 
													   (int)Poco::Net::WebSocket::FRAME_FLAG_FIN);
 | 
				
			||||||
@@ -642,49 +704,32 @@ namespace OpenWifi {
 | 
				
			|||||||
						PingDetails.set("locale", State_.locale);
 | 
											PingDetails.set("locale", State_.locale);
 | 
				
			||||||
						PingObject.set(uCentralProtocol::PING, PingDetails);
 | 
											PingObject.set(uCentralProtocol::PING, PingDetails);
 | 
				
			||||||
						poco_trace(Logger_,fmt::format("Sending PING for {}", SerialNumber_));
 | 
											poco_trace(Logger_,fmt::format("Sending PING for {}", SerialNumber_));
 | 
				
			||||||
						KafkaManager()->PostMessage(KafkaTopics::CONNECTION, SerialNumber_,PingObject);
 | 
											KafkaManager()->PostMessage(KafkaTopics::CONNECTION, SerialNumber_,
 | 
				
			||||||
 | 
																		PingObject);
 | 
				
			||||||
					}
 | 
										}
 | 
				
			||||||
 | 
										return;
 | 
				
			||||||
				} break;
 | 
									} break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				case Poco::Net::WebSocket::FRAME_OP_PONG: {
 | 
									case Poco::Net::WebSocket::FRAME_OP_PONG: {
 | 
				
			||||||
					poco_trace(Logger_, fmt::format("PONG({}): received and ignored.", CId_));
 | 
										poco_trace(Logger_, fmt::format("PONG({}): received and ignored.", CId_));
 | 
				
			||||||
 | 
										return;
 | 
				
			||||||
 | 
									} break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									case Poco::Net::WebSocket::FRAME_OP_CONT: {
 | 
				
			||||||
 | 
										poco_trace(Logger_, fmt::format("CONTINUATION({}): registered.", CId_));
 | 
				
			||||||
 | 
									} break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									case Poco::Net::WebSocket::FRAME_OP_BINARY: {
 | 
				
			||||||
 | 
										poco_trace(Logger_, fmt::format("BINARY({}): Invalid frame type.", CId_));
 | 
				
			||||||
 | 
										KillConnection=true;
 | 
				
			||||||
 | 
										return;
 | 
				
			||||||
				} break;
 | 
									} break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				case Poco::Net::WebSocket::FRAME_OP_TEXT: {
 | 
									case Poco::Net::WebSocket::FRAME_OP_TEXT: {
 | 
				
			||||||
					poco_trace(Logger_,
 | 
										poco_trace(Logger_,
 | 
				
			||||||
							   fmt::format("FRAME({}): Frame received (length={}, flags={}). Msg={}",
 | 
												   fmt::format("TEXT({}): Frame received (len={}, flags={}). Msg={}",
 | 
				
			||||||
										   CId_, IncomingSize, flags, IncomingFrame.begin()));
 | 
															   CId_, IncomingSize, flags,
 | 
				
			||||||
 | 
															   CurrentFrame.begin() == nullptr ? "" : CurrentFrame.begin()));
 | 
				
			||||||
					Poco::JSON::Parser parser;
 | 
					 | 
				
			||||||
					auto ParsedMessage = parser.parse(IncomingFrame.begin());
 | 
					 | 
				
			||||||
					auto IncomingJSON = ParsedMessage.extract<Poco::JSON::Object::Ptr>();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
					if (IncomingJSON->has(uCentralProtocol::JSONRPC)) {
 | 
					 | 
				
			||||||
						if (IncomingJSON->has(uCentralProtocol::METHOD) &&
 | 
					 | 
				
			||||||
							IncomingJSON->has(uCentralProtocol::PARAMS)) {
 | 
					 | 
				
			||||||
							ProcessJSONRPCEvent(IncomingJSON);
 | 
					 | 
				
			||||||
						} else if (IncomingJSON->has(uCentralProtocol::RESULT) &&
 | 
					 | 
				
			||||||
								   IncomingJSON->has(uCentralProtocol::ID)) {
 | 
					 | 
				
			||||||
							poco_trace(Logger_, fmt::format("RPC-RESULT({}): payload: {}", CId_,
 | 
					 | 
				
			||||||
															IncomingFrame.begin()));
 | 
					 | 
				
			||||||
							ProcessJSONRPCResult(IncomingJSON);
 | 
					 | 
				
			||||||
						} else {
 | 
					 | 
				
			||||||
							poco_warning(
 | 
					 | 
				
			||||||
								Logger_,
 | 
					 | 
				
			||||||
								fmt::format("INVALID-PAYLOAD({}): Payload is not JSON-RPC 2.0: {}",
 | 
					 | 
				
			||||||
											CId_, IncomingFrame.begin()));
 | 
					 | 
				
			||||||
						}
 | 
					 | 
				
			||||||
					} else if (IncomingJSON->has(uCentralProtocol::RADIUS)) {
 | 
					 | 
				
			||||||
						ProcessIncomingRadiusData(IncomingJSON);
 | 
					 | 
				
			||||||
					} else {
 | 
					 | 
				
			||||||
						std::ostringstream iS;
 | 
					 | 
				
			||||||
						IncomingJSON->stringify(iS);
 | 
					 | 
				
			||||||
						poco_warning(
 | 
					 | 
				
			||||||
							Logger_,
 | 
					 | 
				
			||||||
							fmt::format("FRAME({}): illegal transaction header, missing 'jsonrpc': {}",
 | 
					 | 
				
			||||||
										CId_, iS.str()));
 | 
					 | 
				
			||||||
						Errors_++;
 | 
					 | 
				
			||||||
					}
 | 
					 | 
				
			||||||
				} break;
 | 
									} break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				case Poco::Net::WebSocket::FRAME_OP_CLOSE: {
 | 
									case Poco::Net::WebSocket::FRAME_OP_CLOSE: {
 | 
				
			||||||
@@ -700,25 +745,31 @@ namespace OpenWifi {
 | 
				
			|||||||
					return;
 | 
										return;
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								// Check for final frame and process accumulated payload
 | 
				
			||||||
 | 
								if (!KillConnection && (flags & Poco::Net::WebSocket::FRAME_FLAG_FIN) != 0) {
 | 
				
			||||||
 | 
									ProcessWSFinalPayload();
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		} catch (const Poco::Net::ConnectionResetException &E) {
 | 
							} catch (const Poco::Net::ConnectionResetException &E) {
 | 
				
			||||||
			poco_warning(Logger_,
 | 
								poco_warning(Logger_,
 | 
				
			||||||
						 fmt::format("ConnectionResetException({}): Text:{} Payload:{} Session:{}",
 | 
											 fmt::format("ConnectionResetException({}): Text:{} Payload:{} Session:{}",
 | 
				
			||||||
									 CId_, E.displayText(),
 | 
														 CId_, E.displayText(),
 | 
				
			||||||
									 IncomingFrame.begin() == nullptr ? "" : IncomingFrame.begin(),
 | 
														 CurrentFrame.begin() == nullptr ? "" : CurrentFrame.begin(),
 | 
				
			||||||
									 State_.sessionId));
 | 
														 State_.sessionId));
 | 
				
			||||||
			KillConnection=true;
 | 
								KillConnection=true;
 | 
				
			||||||
		} catch (const Poco::JSON::JSONException &E) {
 | 
							} catch (const Poco::JSON::JSONException &E) {
 | 
				
			||||||
			poco_warning(Logger_,
 | 
								poco_warning(Logger_,
 | 
				
			||||||
						 fmt::format("JSONException({}): Text:{} Payload:{} Session:{}", CId_,
 | 
											 fmt::format("JSONException({}): Text:{} Payload:{} Session:{}", CId_,
 | 
				
			||||||
									 E.displayText(),
 | 
														 E.displayText(),
 | 
				
			||||||
									 IncomingFrame.begin() == nullptr ? "" : IncomingFrame.begin(),
 | 
														 CurrentFrame.begin() == nullptr ? "" : CurrentFrame.begin(),
 | 
				
			||||||
									 State_.sessionId));
 | 
														 State_.sessionId));
 | 
				
			||||||
			KillConnection=true;
 | 
								KillConnection=true;
 | 
				
			||||||
		} catch (const Poco::Net::WebSocketException &E) {
 | 
							} catch (const Poco::Net::WebSocketException &E) {
 | 
				
			||||||
			poco_warning(Logger_,
 | 
								poco_warning(Logger_,
 | 
				
			||||||
						 fmt::format("WebSocketException({}): Text:{} Payload:{} Session:{}", CId_,
 | 
											 fmt::format("WebSocketException({}): Text:{} Payload:{} Session:{}", CId_,
 | 
				
			||||||
									 E.displayText(),
 | 
														 E.displayText(),
 | 
				
			||||||
									 IncomingFrame.begin() == nullptr ? "" : IncomingFrame.begin(),
 | 
														 CurrentFrame.begin() == nullptr ? "" : CurrentFrame.begin(),
 | 
				
			||||||
									 State_.sessionId));
 | 
														 State_.sessionId));
 | 
				
			||||||
			KillConnection=true;
 | 
								KillConnection=true;
 | 
				
			||||||
		} catch (const Poco::Net::SSLConnectionUnexpectedlyClosedException &E) {
 | 
							} catch (const Poco::Net::SSLConnectionUnexpectedlyClosedException &E) {
 | 
				
			||||||
@@ -727,42 +778,42 @@ namespace OpenWifi {
 | 
				
			|||||||
				fmt::format(
 | 
									fmt::format(
 | 
				
			||||||
					"SSLConnectionUnexpectedlyClosedException({}): Text:{} Payload:{} Session:{}",
 | 
										"SSLConnectionUnexpectedlyClosedException({}): Text:{} Payload:{} Session:{}",
 | 
				
			||||||
					CId_, E.displayText(),
 | 
										CId_, E.displayText(),
 | 
				
			||||||
					IncomingFrame.begin() == nullptr ? "" : IncomingFrame.begin(),
 | 
										CurrentFrame.begin() == nullptr ? "" : CurrentFrame.begin(),
 | 
				
			||||||
					State_.sessionId));
 | 
										State_.sessionId));
 | 
				
			||||||
			KillConnection=true;
 | 
								KillConnection=true;
 | 
				
			||||||
		} catch (const Poco::Net::SSLException &E) {
 | 
							} catch (const Poco::Net::SSLException &E) {
 | 
				
			||||||
			poco_warning(Logger_,
 | 
								poco_warning(Logger_,
 | 
				
			||||||
						 fmt::format("SSLException({}): Text:{} Payload:{} Session:{}", CId_,
 | 
											 fmt::format("SSLException({}): Text:{} Payload:{} Session:{}", CId_,
 | 
				
			||||||
									 E.displayText(),
 | 
														 E.displayText(),
 | 
				
			||||||
									 IncomingFrame.begin() == nullptr ? "" : IncomingFrame.begin(),
 | 
														 CurrentFrame.begin() == nullptr ? "" : CurrentFrame.begin(),
 | 
				
			||||||
									 State_.sessionId));
 | 
														 State_.sessionId));
 | 
				
			||||||
			KillConnection=true;
 | 
								KillConnection=true;
 | 
				
			||||||
		} catch (const Poco::Net::NetException &E) {
 | 
							} catch (const Poco::Net::NetException &E) {
 | 
				
			||||||
			poco_warning(Logger_,
 | 
								poco_warning(Logger_,
 | 
				
			||||||
						 fmt::format("NetException({}): Text:{} Payload:{} Session:{}", CId_,
 | 
											 fmt::format("NetException({}): Text:{} Payload:{} Session:{}", CId_,
 | 
				
			||||||
									 E.displayText(),
 | 
														 E.displayText(),
 | 
				
			||||||
									 IncomingFrame.begin() == nullptr ? "" : IncomingFrame.begin(),
 | 
														 CurrentFrame.begin() == nullptr ? "" : CurrentFrame.begin(),
 | 
				
			||||||
									 State_.sessionId));
 | 
														 State_.sessionId));
 | 
				
			||||||
			KillConnection=true;
 | 
								KillConnection=true;
 | 
				
			||||||
		} catch (const Poco::IOException &E) {
 | 
							} catch (const Poco::IOException &E) {
 | 
				
			||||||
			poco_warning(Logger_,
 | 
								poco_warning(Logger_,
 | 
				
			||||||
						 fmt::format("IOException({}): Text:{} Payload:{} Session:{}", CId_,
 | 
											 fmt::format("IOException({}): Text:{} Payload:{} Session:{}", CId_,
 | 
				
			||||||
									 E.displayText(),
 | 
														 E.displayText(),
 | 
				
			||||||
									 IncomingFrame.begin() == nullptr ? "" : IncomingFrame.begin(),
 | 
														 CurrentFrame.begin() == nullptr ? "" : CurrentFrame.begin(),
 | 
				
			||||||
									 State_.sessionId));
 | 
														 State_.sessionId));
 | 
				
			||||||
			KillConnection=true;
 | 
								KillConnection=true;
 | 
				
			||||||
		} catch (const Poco::Exception &E) {
 | 
							} catch (const Poco::Exception &E) {
 | 
				
			||||||
			poco_warning(Logger_,
 | 
								poco_warning(Logger_,
 | 
				
			||||||
						 fmt::format("Exception({}): Text:{} Payload:{} Session:{}", CId_,
 | 
											 fmt::format("Exception({}): Text:{} Payload:{} Session:{}", CId_,
 | 
				
			||||||
									 E.displayText(),
 | 
														 E.displayText(),
 | 
				
			||||||
									 IncomingFrame.begin() == nullptr ? "" : IncomingFrame.begin(),
 | 
														 CurrentFrame.begin() == nullptr ? "" : CurrentFrame.begin(),
 | 
				
			||||||
									 State_.sessionId));
 | 
														 State_.sessionId));
 | 
				
			||||||
			KillConnection=true;
 | 
								KillConnection=true;
 | 
				
			||||||
		} catch (const std::exception &E) {
 | 
							} catch (const std::exception &E) {
 | 
				
			||||||
			poco_warning(Logger_,
 | 
								poco_warning(Logger_,
 | 
				
			||||||
						 fmt::format("std::exception({}): Text:{} Payload:{} Session:{}", CId_,
 | 
											 fmt::format("std::exception({}): Text:{} Payload:{} Session:{}", CId_,
 | 
				
			||||||
									 E.what(),
 | 
														 E.what(),
 | 
				
			||||||
									 IncomingFrame.begin() == nullptr ? "" : IncomingFrame.begin(),
 | 
														 CurrentFrame.begin() == nullptr ? "" : CurrentFrame.begin(),
 | 
				
			||||||
									 State_.sessionId));
 | 
														 State_.sessionId));
 | 
				
			||||||
			KillConnection=true;
 | 
								KillConnection=true;
 | 
				
			||||||
		} catch (...) {
 | 
							} catch (...) {
 | 
				
			||||||
@@ -775,7 +826,9 @@ namespace OpenWifi {
 | 
				
			|||||||
		if (!KillConnection && Errors_ < 10)
 | 
							if (!KillConnection && Errors_ < 10)
 | 
				
			||||||
			return;
 | 
								return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		poco_warning(Logger_, fmt::format("DISCONNECTING({}): ConnectionException: {} Errors: {}", CId_, KillConnection, Errors_ ));
 | 
							poco_warning(Logger_,
 | 
				
			||||||
 | 
									fmt::format("DISCONNECTING({}): ConnectionException: {} Errors: {}",
 | 
				
			||||||
 | 
												CId_, KillConnection, Errors_ ));
 | 
				
			||||||
		EndConnection();
 | 
							EndConnection();
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -22,7 +22,7 @@
 | 
				
			|||||||
namespace OpenWifi {
 | 
					namespace OpenWifi {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	class AP_WS_Connection {
 | 
						class AP_WS_Connection {
 | 
				
			||||||
		static constexpr int BufSize = 256000;
 | 
							static constexpr int BufSize = 512000;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	  public:
 | 
						  public:
 | 
				
			||||||
		explicit AP_WS_Connection(Poco::Net::HTTPServerRequest &request,
 | 
							explicit AP_WS_Connection(Poco::Net::HTTPServerRequest &request,
 | 
				
			||||||
@@ -33,6 +33,7 @@ namespace OpenWifi {
 | 
				
			|||||||
		void EndConnection();
 | 
							void EndConnection();
 | 
				
			||||||
		void ProcessJSONRPCEvent(Poco::JSON::Object::Ptr &Doc);
 | 
							void ProcessJSONRPCEvent(Poco::JSON::Object::Ptr &Doc);
 | 
				
			||||||
		void ProcessJSONRPCResult(Poco::JSON::Object::Ptr Doc);
 | 
							void ProcessJSONRPCResult(Poco::JSON::Object::Ptr Doc);
 | 
				
			||||||
 | 
					        void ProcessWSFinalPayload();
 | 
				
			||||||
		void ProcessIncomingFrame();
 | 
							void ProcessIncomingFrame();
 | 
				
			||||||
		void ProcessIncomingRadiusData(const Poco::JSON::Object::Ptr &Doc);
 | 
							void ProcessIncomingRadiusData(const Poco::JSON::Object::Ptr &Doc);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -145,6 +146,7 @@ namespace OpenWifi {
 | 
				
			|||||||
		std::uint64_t 	uuid_=0;
 | 
							std::uint64_t 	uuid_=0;
 | 
				
			||||||
		bool	Simulated_=false;
 | 
							bool	Simulated_=false;
 | 
				
			||||||
		std::atomic_uint64_t 	LastContact_=0;
 | 
							std::atomic_uint64_t 	LastContact_=0;
 | 
				
			||||||
 | 
							Poco::Buffer<char> IncomingFrame_;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		static inline std::atomic_uint64_t ConcurrentStartingDevices_ = 0;
 | 
							static inline std::atomic_uint64_t ConcurrentStartingDevices_ = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -71,14 +71,18 @@ namespace OpenWifi {
 | 
				
			|||||||
	bool AP_WS_Server::ValidateCertificate(const std::string &ConnectionId,
 | 
						bool AP_WS_Server::ValidateCertificate(const std::string &ConnectionId,
 | 
				
			||||||
										   const Poco::Crypto::X509Certificate &Certificate) {
 | 
															   const Poco::Crypto::X509Certificate &Certificate) {
 | 
				
			||||||
		if (IsCertOk()) {
 | 
							if (IsCertOk()) {
 | 
				
			||||||
			if (!Certificate.issuedBy(*IssuerCert_)) {
 | 
								// validate certificate agains trusted chain
 | 
				
			||||||
 | 
								for (const auto &cert : ClientCasCerts_) {
 | 
				
			||||||
 | 
									if (Certificate.issuedBy(cert)) {
 | 
				
			||||||
 | 
										return true;
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
			poco_warning(
 | 
								poco_warning(
 | 
				
			||||||
					Logger(),
 | 
										Logger(),
 | 
				
			||||||
					fmt::format("CERTIFICATE({}): issuer mismatch. Local='{}' Incoming='{}'",
 | 
										fmt::format(
 | 
				
			||||||
								ConnectionId, IssuerCert_->issuerName(), Certificate.issuerName()));
 | 
											"CERTIFICATE({}): issuer mismatch. Certificate not issued by any trusted CA",
 | 
				
			||||||
				return false;
 | 
											ConnectionId)
 | 
				
			||||||
			}
 | 
										);
 | 
				
			||||||
			return true;
 | 
					 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		return false;
 | 
							return false;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -116,7 +120,6 @@ namespace OpenWifi {
 | 
				
			|||||||
			P.verificationDepth = 9;
 | 
								P.verificationDepth = 9;
 | 
				
			||||||
			P.loadDefaultCAs = Svr.RootCA().empty();
 | 
								P.loadDefaultCAs = Svr.RootCA().empty();
 | 
				
			||||||
			P.cipherList = "ALL:!ADH:!LOW:!EXP:!MD5:@STRENGTH";
 | 
								P.cipherList = "ALL:!ADH:!LOW:!EXP:!MD5:@STRENGTH";
 | 
				
			||||||
			P.dhUse2048Bits = true;
 | 
					 | 
				
			||||||
			P.caLocation = Svr.Cas();
 | 
								P.caLocation = Svr.Cas();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			auto Context = Poco::AutoPtr<Poco::Net::Context>(
 | 
								auto Context = Poco::AutoPtr<Poco::Net::Context>(
 | 
				
			||||||
@@ -133,6 +136,13 @@ namespace OpenWifi {
 | 
				
			|||||||
			Context->addChainCertificate(Issuing);
 | 
								Context->addChainCertificate(Issuing);
 | 
				
			||||||
			Context->addCertificateAuthority(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());
 | 
								Poco::Crypto::RSAKey Key("", Svr.KeyFile(), Svr.KeyFilePassword());
 | 
				
			||||||
			Context->usePrivateKey(Key);
 | 
								Context->usePrivateKey(Key);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -223,6 +223,7 @@ namespace OpenWifi {
 | 
				
			|||||||
		mutable std::array<std::mutex,MACHashMax>		SerialNumbersMutex_;
 | 
							mutable std::array<std::mutex,MACHashMax>		SerialNumbersMutex_;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		std::unique_ptr<Poco::Crypto::X509Certificate> IssuerCert_;
 | 
							std::unique_ptr<Poco::Crypto::X509Certificate> IssuerCert_;
 | 
				
			||||||
 | 
							std::vector<Poco::Crypto::X509Certificate> ClientCasCerts_;
 | 
				
			||||||
		std::list<std::unique_ptr<Poco::Net::HTTPServer>> WebServers_;
 | 
							std::list<std::unique_ptr<Poco::Net::HTTPServer>> WebServers_;
 | 
				
			||||||
		Poco::ThreadPool DeviceConnectionPool_{"ws:dev-pool", 4, 256};
 | 
							Poco::ThreadPool DeviceConnectionPool_{"ws:dev-pool", 4, 256};
 | 
				
			||||||
		Poco::Net::SocketReactor Reactor_;
 | 
							Poco::Net::SocketReactor Reactor_;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -111,7 +111,7 @@ namespace OpenWifi {
 | 
				
			|||||||
				i >> cache;
 | 
									i >> cache;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				for (const auto &[Type, Platform] : cache.items()) {
 | 
									for (const auto &[Type, Platform] : cache.items()) {
 | 
				
			||||||
					Platforms_[Type] = Poco::toLower(to_string(Platform));
 | 
										Platforms_[Type] = Poco::toLower(Platform.get<std::string>());
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
			} catch (...) {
 | 
								} catch (...) {
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -54,8 +54,8 @@ namespace OpenWifi::RESTAPI_RPC {
 | 
				
			|||||||
						std::chrono::milliseconds WaitTimeInMs, Poco::JSON::Object *ObjectToReturn,
 | 
											std::chrono::milliseconds WaitTimeInMs, Poco::JSON::Object *ObjectToReturn,
 | 
				
			||||||
						RESTAPIHandler *Handler, Poco::Logger &Logger, bool Deferred) {
 | 
											RESTAPIHandler *Handler, Poco::Logger &Logger, bool Deferred) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		Logger.information(fmt::format("{},{}: New {} command. User={} Serial={}. ", Cmd.UUID,
 | 
							Logger.information(fmt::format("{},{}: New {} command. User={} Serial={} Details={}. ", Cmd.UUID,
 | 
				
			||||||
									   RPCID, Cmd.Command, Cmd.SubmittedBy, Cmd.SerialNumber));
 | 
														   RPCID, Cmd.Command, Cmd.SubmittedBy, Cmd.SerialNumber, Cmd.Details));
 | 
				
			||||||
		Cmd.Submitted = Utils::Now();
 | 
							Cmd.Submitted = Utils::Now();
 | 
				
			||||||
		Cmd.Executed = 0;
 | 
							Cmd.Executed = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -91,6 +91,31 @@ namespace OpenWifi {
 | 
				
			|||||||
					TransactionId_, UUID, RPC, Poco::Thread::current()->id()));
 | 
										TransactionId_, UUID, RPC, Poco::Thread::current()->id()));
 | 
				
			||||||
			return Rtty(UUID, RPC, 60000ms, Restrictions);
 | 
								return Rtty(UUID, RPC, 60000ms, Restrictions);
 | 
				
			||||||
		};
 | 
							};
 | 
				
			||||||
 | 
							case APCommands::Commands::package:{
 | 
				
			||||||
 | 
								GWObjects::DeviceRestrictions Restrictions;
 | 
				
			||||||
 | 
								std::string pkg_name = "";
 | 
				
			||||||
 | 
								if (!AP_WS_Server()->Connected(SerialNumberInt_, Restrictions)) {
 | 
				
			||||||
 | 
									CallCanceled(Command_.c_str(), RESTAPI::Errors::DeviceNotConnected);
 | 
				
			||||||
 | 
									return BadRequest(RESTAPI::Errors::DeviceNotConnected);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								Poco::URI uri(Request->getURI());
 | 
				
			||||||
 | 
								for (const auto ¶m : uri.getQueryParameters()) {
 | 
				
			||||||
 | 
									if (param.first == "pkgName") {
 | 
				
			||||||
 | 
										pkg_name = param.second;
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								if (pkg_name.empty()) {
 | 
				
			||||||
 | 
									return BadRequest(RESTAPI::Errors::MissingOrInvalidParameters);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								auto UUID = MicroServiceCreateUUID();
 | 
				
			||||||
 | 
								auto RPC = CommandManager()->Next_RPC_ID();
 | 
				
			||||||
 | 
								poco_debug(
 | 
				
			||||||
 | 
									Logger_,
 | 
				
			||||||
 | 
									fmt::format(
 | 
				
			||||||
 | 
										"Command Package TID={} can proceed. Identified as {} and RPCID as {}. thr_id={}",
 | 
				
			||||||
 | 
										TransactionId_, UUID, RPC, Poco::Thread::current()->id()));
 | 
				
			||||||
 | 
								return GetPackages(UUID, RPC, pkg_name, 300000ms, Restrictions);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
		default:
 | 
							default:
 | 
				
			||||||
			return BadRequest(RESTAPI::Errors::InvalidCommand);
 | 
								return BadRequest(RESTAPI::Errors::InvalidCommand);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
@@ -128,6 +153,21 @@ namespace OpenWifi {
 | 
				
			|||||||
			return DeleteChecks();
 | 
								return DeleteChecks();
 | 
				
			||||||
		case APCommands::Commands::statistics:
 | 
							case APCommands::Commands::statistics:
 | 
				
			||||||
			return DeleteStatistics();
 | 
								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:
 | 
							default:
 | 
				
			||||||
			return BadRequest(RESTAPI::Errors::InvalidCommand);
 | 
								return BadRequest(RESTAPI::Errors::InvalidCommand);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
@@ -167,7 +207,11 @@ namespace OpenWifi {
 | 
				
			|||||||
		{APCommands::Commands::certupdate, false, true, &RESTAPI_device_commandHandler::CertUpdate, 60000ms},
 | 
							{APCommands::Commands::certupdate, false, true, &RESTAPI_device_commandHandler::CertUpdate, 60000ms},
 | 
				
			||||||
		{APCommands::Commands::transfer, false, true, &RESTAPI_device_commandHandler::Transfer, 60000ms},
 | 
							{APCommands::Commands::transfer, false, true, &RESTAPI_device_commandHandler::Transfer, 60000ms},
 | 
				
			||||||
		{APCommands::Commands::script, false, true, &RESTAPI_device_commandHandler::Script, 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},
 | 
				
			||||||
 | 
							{APCommands::Commands::package, false, true, &RESTAPI_device_commandHandler::PackageInstall, 120000ms},
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	void RESTAPI_device_commandHandler::DoPost() {
 | 
						void RESTAPI_device_commandHandler::DoPost() {
 | 
				
			||||||
@@ -405,6 +449,210 @@ namespace OpenWifi {
 | 
				
			|||||||
		BadRequest(RESTAPI::Errors::NoRecordsDeleted);
 | 
							BadRequest(RESTAPI::Errors::NoRecordsDeleted);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						void RESTAPI_device_commandHandler::GetPackages(const std::string &CMD_UUID, uint64_t CMD_RPC,
 | 
				
			||||||
 | 
							const std::string pkg_name,
 | 
				
			||||||
 | 
							[[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_);
 | 
				
			||||||
 | 
							Params.set(uCentralProtocol::PACKAGE, pkg_name);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							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(
 | 
						void RESTAPI_device_commandHandler::Ping(
 | 
				
			||||||
		const std::string &CMD_UUID, uint64_t CMD_RPC, std::chrono::milliseconds timeout,
 | 
							const std::string &CMD_UUID, uint64_t CMD_RPC, std::chrono::milliseconds timeout,
 | 
				
			||||||
		[[maybe_unused]] const GWObjects::DeviceRestrictions &Restrictions) {
 | 
							[[maybe_unused]] const GWObjects::DeviceRestrictions &Restrictions) {
 | 
				
			||||||
@@ -691,9 +939,31 @@ namespace OpenWifi {
 | 
				
			|||||||
				Params.stringify(ParamStream);
 | 
									Params.stringify(ParamStream);
 | 
				
			||||||
				Cmd.Details = ParamStream.str();
 | 
									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);
 | 
									// AP_WS_Server()->SetPendingUUID(SerialNumber_, NewUUID);
 | 
				
			||||||
				RESTAPI_RPC::WaitForCommand(CMD_RPC, APCommands::Commands::configure, true,
 | 
									RESTAPI_RPC::WaitForCommand(CMD_RPC, APCommands::Commands::configure, true,
 | 
				
			||||||
												   Cmd, Params, *Request, *Response, timeout,
 | 
																	   Cmd, ConfigParams, *Request, *Response, timeout,
 | 
				
			||||||
												   nullptr, this, Logger_);
 | 
																	   nullptr, this, Logger_);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				if(!Cmd.Executed) {
 | 
									if(!Cmd.Executed) {
 | 
				
			||||||
@@ -1548,4 +1818,123 @@ namespace OpenWifi {
 | 
				
			|||||||
										   Logger_);
 | 
															   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
 | 
					} // namespace OpenWifi
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -33,6 +33,13 @@ namespace OpenWifi {
 | 
				
			|||||||
		void GetStatus();
 | 
							void GetStatus();
 | 
				
			||||||
		void GetChecks();
 | 
							void GetChecks();
 | 
				
			||||||
		void DeleteChecks();
 | 
							void DeleteChecks();
 | 
				
			||||||
 | 
							void GetPackages(const std::string &UUID, uint64_t RPC,
 | 
				
			||||||
 | 
											 std::string pkg_name,
 | 
				
			||||||
 | 
											 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);
 | 
							bool IsDeviceSimulated(std::string &Serial);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -70,6 +77,14 @@ namespace OpenWifi {
 | 
				
			|||||||
					const GWObjects::DeviceRestrictions &R);
 | 
										const GWObjects::DeviceRestrictions &R);
 | 
				
			||||||
		void PowerCycle(const std::string &UUID, uint64_t RPC, std::chrono::milliseconds timeout,
 | 
							void PowerCycle(const std::string &UUID, uint64_t RPC, std::chrono::milliseconds timeout,
 | 
				
			||||||
					  const GWObjects::DeviceRestrictions &R);
 | 
										  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);
 | 
				
			||||||
 | 
							void PackageInstall(const std::string &UUID, uint64_t RPC, std::chrono::milliseconds timeout,
 | 
				
			||||||
 | 
										  const GWObjects::DeviceRestrictions &R);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		static auto PathName() {
 | 
							static auto PathName() {
 | 
				
			||||||
			return std::list<std::string>{"/api/v1/device/{serialNumber}/{command}"};
 | 
								return std::list<std::string>{"/api/v1/device/{serialNumber}/{command}"};
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -22,9 +22,15 @@ namespace OpenWifi {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
		std::string FileType;
 | 
							std::string FileType;
 | 
				
			||||||
		std::string FileContent;
 | 
							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();
 | 
								return NotFound();
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
							else if (WaitingForFile) {
 | 
				
			||||||
 | 
								// waiting for file to be uploaded, return Accepted
 | 
				
			||||||
 | 
								return Accepted();
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (FileType == "pcap") {
 | 
							if (FileType == "pcap") {
 | 
				
			||||||
			SendFileContent(FileContent, "application/vnd.tcpdump.pcap", UUID + ".pcap");
 | 
								SendFileContent(FileContent, "application/vnd.tcpdump.pcap", UUID + ".pcap");
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -12,9 +12,9 @@
 | 
				
			|||||||
#include "Daemon.h"
 | 
					#include "Daemon.h"
 | 
				
			||||||
#ifdef TIP_GATEWAY_SERVICE
 | 
					#ifdef TIP_GATEWAY_SERVICE
 | 
				
			||||||
#include "AP_WS_Server.h"
 | 
					#include "AP_WS_Server.h"
 | 
				
			||||||
#include "StorageService.h"
 | 
					 | 
				
			||||||
#include "CapabilitiesCache.h"
 | 
					#include "CapabilitiesCache.h"
 | 
				
			||||||
#include "RADIUSSessionTracker.h"
 | 
					#include "RADIUSSessionTracker.h"
 | 
				
			||||||
 | 
					#include "StorageService.h"
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "RESTAPI_GWobjects.h"
 | 
					#include "RESTAPI_GWobjects.h"
 | 
				
			||||||
@@ -31,7 +31,8 @@ namespace OpenWifi::GWObjects {
 | 
				
			|||||||
		field_to_json(Obj, "serialNumber", SerialNumber);
 | 
							field_to_json(Obj, "serialNumber", SerialNumber);
 | 
				
			||||||
#ifdef TIP_GATEWAY_SERVICE
 | 
					#ifdef TIP_GATEWAY_SERVICE
 | 
				
			||||||
		field_to_json(Obj, "deviceType", StorageService()->GetPlatform(SerialNumber));
 | 
							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
 | 
					#endif
 | 
				
			||||||
		field_to_json(Obj, "macAddress", MACAddress);
 | 
							field_to_json(Obj, "macAddress", MACAddress);
 | 
				
			||||||
		field_to_json(Obj, "manufacturer", Manufacturer);
 | 
							field_to_json(Obj, "manufacturer", Manufacturer);
 | 
				
			||||||
@@ -179,7 +180,6 @@ namespace OpenWifi::GWObjects {
 | 
				
			|||||||
			field_from_json(Obj, "recorded", Recorded);
 | 
								field_from_json(Obj, "recorded", Recorded);
 | 
				
			||||||
			return true;
 | 
								return true;
 | 
				
			||||||
		} catch (...) {
 | 
							} catch (...) {
 | 
				
			||||||
 | 
					 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		return false;
 | 
							return false;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -275,7 +275,8 @@ namespace OpenWifi::GWObjects {
 | 
				
			|||||||
		return false;
 | 
							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, "ipAddress", Address);
 | 
				
			||||||
		field_to_json(Obj, "txBytes", TX);
 | 
							field_to_json(Obj, "txBytes", TX);
 | 
				
			||||||
		field_to_json(Obj, "rxBytes", RX);
 | 
							field_to_json(Obj, "rxBytes", RX);
 | 
				
			||||||
@@ -297,6 +298,7 @@ namespace OpenWifi::GWObjects {
 | 
				
			|||||||
		field_to_json(Obj, "connectionCompletionTime", connectionCompletionTime);
 | 
							field_to_json(Obj, "connectionCompletionTime", connectionCompletionTime);
 | 
				
			||||||
		field_to_json(Obj, "totalConnectionTime", Utils::Now() - started);
 | 
							field_to_json(Obj, "totalConnectionTime", Utils::Now() - started);
 | 
				
			||||||
		field_to_json(Obj, "certificateExpiryDate", certificateExpiryDate);
 | 
							field_to_json(Obj, "certificateExpiryDate", certificateExpiryDate);
 | 
				
			||||||
 | 
							field_to_json(Obj, "certificateIssuerName", certificateIssuerName);
 | 
				
			||||||
		field_to_json(Obj, "connectReason", connectReason);
 | 
							field_to_json(Obj, "connectReason", connectReason);
 | 
				
			||||||
		field_to_json(Obj, "uptime", uptime);
 | 
							field_to_json(Obj, "uptime", uptime);
 | 
				
			||||||
		field_to_json(Obj, "compatible", Compatible);
 | 
							field_to_json(Obj, "compatible", Compatible);
 | 
				
			||||||
@@ -358,6 +360,7 @@ namespace OpenWifi::GWObjects {
 | 
				
			|||||||
			field_from_json(Obj, "connectionCompletionTime", connectionCompletionTime);
 | 
								field_from_json(Obj, "connectionCompletionTime", connectionCompletionTime);
 | 
				
			||||||
			field_from_json(Obj, "totalConnectionTime", totalConnectionTime);
 | 
								field_from_json(Obj, "totalConnectionTime", totalConnectionTime);
 | 
				
			||||||
			field_from_json(Obj, "certificateExpiryDate", certificateExpiryDate);
 | 
								field_from_json(Obj, "certificateExpiryDate", certificateExpiryDate);
 | 
				
			||||||
 | 
								field_from_json(Obj, "certificateIssuerName", certificateIssuerName);
 | 
				
			||||||
			field_from_json(Obj, "connectReason", connectReason);
 | 
								field_from_json(Obj, "connectReason", connectReason);
 | 
				
			||||||
			field_from_json(Obj, "uptime", uptime);
 | 
								field_from_json(Obj, "uptime", uptime);
 | 
				
			||||||
			field_from_json(Obj, "hasRADIUSSessions", hasRADIUSSessions);
 | 
								field_from_json(Obj, "hasRADIUSSessions", hasRADIUSSessions);
 | 
				
			||||||
@@ -799,4 +802,123 @@ namespace OpenWifi::GWObjects {
 | 
				
			|||||||
		return false;
 | 
							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;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						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);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						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
 | 
					} // namespace OpenWifi::GWObjects
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -42,6 +42,7 @@ namespace OpenWifi::GWObjects {
 | 
				
			|||||||
		uint64_t sessionId = 0;
 | 
							uint64_t sessionId = 0;
 | 
				
			||||||
		double connectionCompletionTime = 0.0;
 | 
							double connectionCompletionTime = 0.0;
 | 
				
			||||||
		std::uint64_t certificateExpiryDate = 0;
 | 
							std::uint64_t certificateExpiryDate = 0;
 | 
				
			||||||
 | 
							std::string certificateIssuerName;
 | 
				
			||||||
		std::uint64_t hasRADIUSSessions = 0;
 | 
							std::uint64_t hasRADIUSSessions = 0;
 | 
				
			||||||
		bool hasGPS = false;
 | 
							bool hasGPS = false;
 | 
				
			||||||
		std::uint64_t sanity=0;
 | 
							std::uint64_t sanity=0;
 | 
				
			||||||
@@ -532,6 +533,70 @@ namespace OpenWifi::GWObjects {
 | 
				
			|||||||
		std::uint64_t 	when;
 | 
							std::uint64_t 	when;
 | 
				
			||||||
		std::vector<PowerCyclePort> ports;
 | 
							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);
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
						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);
 | 
							bool from_json(const Poco::JSON::Object::Ptr &Obj);
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
} // namespace OpenWifi::GWObjects
 | 
					} // namespace OpenWifi::GWObjects
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -243,7 +243,7 @@ namespace OpenWifi {
 | 
				
			|||||||
									 const std::string &Type);
 | 
														 const std::string &Type);
 | 
				
			||||||
		bool CancelWaitFile(std::string &UUID, std::string &ErrorText);
 | 
							bool CancelWaitFile(std::string &UUID, std::string &ErrorText);
 | 
				
			||||||
		bool GetAttachedFileContent(std::string &UUID, const std::string &SerialNumber,
 | 
							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 RemoveAttachedFile(std::string &UUID);
 | 
				
			||||||
		bool SetCommandResult(std::string &UUID, std::string &Result);
 | 
							bool SetCommandResult(std::string &UUID, std::string &Result);
 | 
				
			||||||
		bool GetNewestCommands(std::string &SerialNumber, uint64_t HowMany,
 | 
							bool GetNewestCommands(std::string &SerialNumber, uint64_t HowMany,
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -120,14 +120,16 @@ namespace OpenWifi {
 | 
				
			|||||||
		Poco::Buffer<char> IncomingFrame(0);
 | 
							Poco::Buffer<char> IncomingFrame(0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		try {
 | 
							try {
 | 
				
			||||||
			int Op, flags;
 | 
								int Op, flags, IncomingSize;
 | 
				
			||||||
			int IncomingSize;
 | 
					
 | 
				
			||||||
			IncomingSize = WS_->receiveFrame(IncomingFrame, flags);
 | 
								IncomingSize = WS_->receiveFrame(IncomingFrame, flags);
 | 
				
			||||||
			Op = flags & Poco::Net::WebSocket::FRAME_OP_BITMASK;
 | 
								Op = flags & Poco::Net::WebSocket::FRAME_OP_BITMASK;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			if (IncomingSize == 0 && flags == 0 && Op == 0) {
 | 
								if (IncomingSize == -1) {
 | 
				
			||||||
				poco_information(
 | 
									poco_trace(Logger(),
 | 
				
			||||||
					Logger(),
 | 
										fmt::format("TELEMETRY-EMPTY({}): Empty frame, non-blocking try-again.", CId_));
 | 
				
			||||||
 | 
								} else if (IncomingSize == 0 && flags == 0 && Op == 0) {
 | 
				
			||||||
 | 
									poco_information(Logger(),
 | 
				
			||||||
					fmt::format("TELEMETRY-DISCONNECT({}): device has disconnected.", CId_));
 | 
										fmt::format("TELEMETRY-DISCONNECT({}): device has disconnected.", CId_));
 | 
				
			||||||
				MustDisconnect = true;
 | 
									MustDisconnect = true;
 | 
				
			||||||
			} else {
 | 
								} else {
 | 
				
			||||||
@@ -138,10 +140,12 @@ namespace OpenWifi {
 | 
				
			|||||||
								   (int)Poco::Net::WebSocket::FRAME_OP_PONG |
 | 
													   (int)Poco::Net::WebSocket::FRAME_OP_PONG |
 | 
				
			||||||
								   (int)Poco::Net::WebSocket::FRAME_FLAG_FIN);
 | 
													   (int)Poco::Net::WebSocket::FRAME_FLAG_FIN);
 | 
				
			||||||
				} else if (Op == Poco::Net::WebSocket::FRAME_OP_CLOSE) {
 | 
									} else if (Op == Poco::Net::WebSocket::FRAME_OP_CLOSE) {
 | 
				
			||||||
					poco_information(
 | 
										poco_information(Logger(),
 | 
				
			||||||
						Logger(),
 | 
					 | 
				
			||||||
						fmt::format("TELEMETRY-DISCONNECT({}): device wants to disconnect.", CId_));
 | 
											fmt::format("TELEMETRY-DISCONNECT({}): device wants to disconnect.", CId_));
 | 
				
			||||||
					MustDisconnect = true;
 | 
										MustDisconnect = true;
 | 
				
			||||||
 | 
									} else if (Op == Poco::Net::WebSocket::FRAME_OP_CONT) {
 | 
				
			||||||
 | 
										poco_information(Logger(),
 | 
				
			||||||
 | 
											fmt::format("TELEMETRY-CONT({}): rx {} bytes.", CId_, IncomingSize));
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		} catch (...) {
 | 
							} catch (...) {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -376,6 +376,8 @@ static std::string DefaultAPSchema = R"foo(
 | 
				
			|||||||
            "properties": {
 | 
					            "properties": {
 | 
				
			||||||
                "port-mirror": {
 | 
					                "port-mirror": {
 | 
				
			||||||
                    "description": "Enable mirror of traffic from multiple minotor ports to a single analysis port.",
 | 
					                    "description": "Enable mirror of traffic from multiple minotor ports to a single analysis port.",
 | 
				
			||||||
 | 
					                    "type": "array",
 | 
				
			||||||
 | 
					                    "items": {
 | 
				
			||||||
                        "type": "object",
 | 
					                        "type": "object",
 | 
				
			||||||
                        "properties": {
 | 
					                        "properties": {
 | 
				
			||||||
                            "monitor-ports": {
 | 
					                            "monitor-ports": {
 | 
				
			||||||
@@ -390,6 +392,7 @@ static std::string DefaultAPSchema = R"foo(
 | 
				
			|||||||
                                "type": "string"
 | 
					                                "type": "string"
 | 
				
			||||||
                            }
 | 
					                            }
 | 
				
			||||||
                        }
 | 
					                        }
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
                },
 | 
					                },
 | 
				
			||||||
                "loop-detection": {
 | 
					                "loop-detection": {
 | 
				
			||||||
                    "description": "Enable loop detection on the L2 switches/bridge.",
 | 
					                    "description": "Enable loop detection on the L2 switches/bridge.",
 | 
				
			||||||
@@ -549,7 +552,8 @@ static std::string DefaultAPSchema = R"foo(
 | 
				
			|||||||
                        "5G",
 | 
					                        "5G",
 | 
				
			||||||
                        "5G-lower",
 | 
					                        "5G-lower",
 | 
				
			||||||
                        "5G-upper",
 | 
					                        "5G-upper",
 | 
				
			||||||
                        "6G"
 | 
					                        "6G",
 | 
				
			||||||
 | 
					                        "HaLow"
 | 
				
			||||||
                    ]
 | 
					                    ]
 | 
				
			||||||
                },
 | 
					                },
 | 
				
			||||||
                "bandwidth": {
 | 
					                "bandwidth": {
 | 
				
			||||||
@@ -622,6 +626,10 @@ static std::string DefaultAPSchema = R"foo(
 | 
				
			|||||||
                    ],
 | 
					                    ],
 | 
				
			||||||
                    "default": 80
 | 
					                    "default": 80
 | 
				
			||||||
                },
 | 
					                },
 | 
				
			||||||
 | 
					                "enable": {
 | 
				
			||||||
 | 
					                    "description": "Specifies radio is enabled/disabled.",
 | 
				
			||||||
 | 
					                    "type": "boolean"
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
                "require-mode": {
 | 
					                "require-mode": {
 | 
				
			||||||
                    "description": "Stations that do no fulfill these HT modes will be rejected.",
 | 
					                    "description": "Stations that do no fulfill these HT modes will be rejected.",
 | 
				
			||||||
                    "type": "string",
 | 
					                    "type": "string",
 | 
				
			||||||
@@ -2306,7 +2314,8 @@ static std::string DefaultAPSchema = R"foo(
 | 
				
			|||||||
                            "5G",
 | 
					                            "5G",
 | 
				
			||||||
                            "5G-lower",
 | 
					                            "5G-lower",
 | 
				
			||||||
                            "5G-upper",
 | 
					                            "5G-upper",
 | 
				
			||||||
                            "6G"
 | 
					                            "6G",
 | 
				
			||||||
 | 
					                            "HaLow"
 | 
				
			||||||
                        ]
 | 
					                        ]
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
                },
 | 
					                },
 | 
				
			||||||
@@ -2411,11 +2420,18 @@ static std::string DefaultAPSchema = R"foo(
 | 
				
			|||||||
                    "$ref": "#/$defs/interface.ssid.encryption"
 | 
					                    "$ref": "#/$defs/interface.ssid.encryption"
 | 
				
			||||||
                },
 | 
					                },
 | 
				
			||||||
                "multi-psk": {
 | 
					                "multi-psk": {
 | 
				
			||||||
 | 
					                    "anyOf": [
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
                            "type": "array",
 | 
					                            "type": "array",
 | 
				
			||||||
                            "items": {
 | 
					                            "items": {
 | 
				
			||||||
                                "$ref": "#/$defs/interface.ssid.multi-psk"
 | 
					                                "$ref": "#/$defs/interface.ssid.multi-psk"
 | 
				
			||||||
                            }
 | 
					                            }
 | 
				
			||||||
                        },
 | 
					                        },
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                            "type": "boolean"
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                    ]
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
                "rrm": {
 | 
					                "rrm": {
 | 
				
			||||||
                    "$ref": "#/$defs/interface.ssid.rrm"
 | 
					                    "$ref": "#/$defs/interface.ssid.rrm"
 | 
				
			||||||
                },
 | 
					                },
 | 
				
			||||||
@@ -3732,7 +3748,8 @@ static std::string DefaultAPSchema = R"foo(
 | 
				
			|||||||
                            "5G",
 | 
					                            "5G",
 | 
				
			||||||
                            "5G-lower",
 | 
					                            "5G-lower",
 | 
				
			||||||
                            "5G-upper",
 | 
					                            "5G-upper",
 | 
				
			||||||
                            "6G"
 | 
					                            "6G",
 | 
				
			||||||
 | 
					                            "HaLow"
 | 
				
			||||||
                        ]
 | 
					                        ]
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
                },
 | 
					                },
 | 
				
			||||||
@@ -3942,7 +3959,9 @@ static std::string DefaultAPSchema = R"foo(
 | 
				
			|||||||
                            "inactive-deauth",
 | 
					                            "inactive-deauth",
 | 
				
			||||||
                            "key-mismatch",
 | 
					                            "key-mismatch",
 | 
				
			||||||
                            "beacon-report",
 | 
					                            "beacon-report",
 | 
				
			||||||
                            "radar-detected"
 | 
					                            "radar-detected",
 | 
				
			||||||
 | 
					                            "ft-finish",
 | 
				
			||||||
 | 
					                            "sta-authorized"
 | 
				
			||||||
			 ]
 | 
								 ]
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
@@ -4645,18 +4664,24 @@ static std::string DefaultSWITCHSchema = R"foo(
 | 
				
			|||||||
            "type": "object",
 | 
					            "type": "object",
 | 
				
			||||||
            "properties": {
 | 
					            "properties": {
 | 
				
			||||||
                "port-mirror": {
 | 
					                "port-mirror": {
 | 
				
			||||||
 | 
					                    "description": "Enable mirror of traffic from multiple minotor ports to a single analysis port.",
 | 
				
			||||||
 | 
					                    "type": "array",
 | 
				
			||||||
 | 
					                    "items": {
 | 
				
			||||||
                        "type": "object",
 | 
					                        "type": "object",
 | 
				
			||||||
                        "properties": {
 | 
					                        "properties": {
 | 
				
			||||||
                            "monitor-ports": {
 | 
					                            "monitor-ports": {
 | 
				
			||||||
 | 
					                                "description": "The list of ports that we want to mirror.",
 | 
				
			||||||
                                "type": "array",
 | 
					                                "type": "array",
 | 
				
			||||||
                                "items": {
 | 
					                                "items": {
 | 
				
			||||||
                                    "type": "string"
 | 
					                                    "type": "string"
 | 
				
			||||||
                                }
 | 
					                                }
 | 
				
			||||||
                            },
 | 
					                            },
 | 
				
			||||||
                            "analysis-port": {
 | 
					                            "analysis-port": {
 | 
				
			||||||
 | 
					                                "description": "The port that mirror'ed packets should be sent to.",
 | 
				
			||||||
                                "type": "string"
 | 
					                                "type": "string"
 | 
				
			||||||
                            }
 | 
					                            }
 | 
				
			||||||
                        }
 | 
					                        }
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
                },
 | 
					                },
 | 
				
			||||||
                "loop-detection": {
 | 
					                "loop-detection": {
 | 
				
			||||||
                    "type": "object",
 | 
					                    "type": "object",
 | 
				
			||||||
@@ -4874,7 +4899,8 @@ static std::string DefaultSWITCHSchema = R"foo(
 | 
				
			|||||||
                        "5G",
 | 
					                        "5G",
 | 
				
			||||||
                        "5G-lower",
 | 
					                        "5G-lower",
 | 
				
			||||||
                        "5G-upper",
 | 
					                        "5G-upper",
 | 
				
			||||||
                        "6G"
 | 
					                        "6G",
 | 
				
			||||||
 | 
					                        "HaLow"
 | 
				
			||||||
                    ]
 | 
					                    ]
 | 
				
			||||||
                },
 | 
					                },
 | 
				
			||||||
                "bandwidth": {
 | 
					                "bandwidth": {
 | 
				
			||||||
@@ -4940,6 +4966,10 @@ static std::string DefaultSWITCHSchema = R"foo(
 | 
				
			|||||||
                    ],
 | 
					                    ],
 | 
				
			||||||
                    "default": 80
 | 
					                    "default": 80
 | 
				
			||||||
                },
 | 
					                },
 | 
				
			||||||
 | 
					                "enable": {
 | 
				
			||||||
 | 
					                    "description": "Specifies radio is enabled/disabled.",
 | 
				
			||||||
 | 
					                    "type": "boolean"
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
                "require-mode": {
 | 
					                "require-mode": {
 | 
				
			||||||
                    "type": "string",
 | 
					                    "type": "string",
 | 
				
			||||||
                    "enum": [
 | 
					                    "enum": [
 | 
				
			||||||
@@ -6512,7 +6542,8 @@ static std::string DefaultSWITCHSchema = R"foo(
 | 
				
			|||||||
                            "5G",
 | 
					                            "5G",
 | 
				
			||||||
                            "5G-lower",
 | 
					                            "5G-lower",
 | 
				
			||||||
                            "5G-upper",
 | 
					                            "5G-upper",
 | 
				
			||||||
                            "6G"
 | 
					                            "6G",
 | 
				
			||||||
 | 
					                            "HaLow"
 | 
				
			||||||
                        ]
 | 
					                        ]
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
                },
 | 
					                },
 | 
				
			||||||
@@ -6603,11 +6634,18 @@ static std::string DefaultSWITCHSchema = R"foo(
 | 
				
			|||||||
                    "$ref": "#/$defs/interface.ssid.encryption"
 | 
					                    "$ref": "#/$defs/interface.ssid.encryption"
 | 
				
			||||||
                },
 | 
					                },
 | 
				
			||||||
                "multi-psk": {
 | 
					                "multi-psk": {
 | 
				
			||||||
 | 
					                    "anyOf": [
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
                            "type": "array",
 | 
					                            "type": "array",
 | 
				
			||||||
                            "items": {
 | 
					                            "items": {
 | 
				
			||||||
                                "$ref": "#/$defs/interface.ssid.multi-psk"
 | 
					                                "$ref": "#/$defs/interface.ssid.multi-psk"
 | 
				
			||||||
                            }
 | 
					                            }
 | 
				
			||||||
                        },
 | 
					                        },
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                            "type": "boolean"
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                    ]
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
                "rrm": {
 | 
					                "rrm": {
 | 
				
			||||||
                    "$ref": "#/$defs/interface.ssid.rrm"
 | 
					                    "$ref": "#/$defs/interface.ssid.rrm"
 | 
				
			||||||
                },
 | 
					                },
 | 
				
			||||||
@@ -7728,7 +7766,8 @@ static std::string DefaultSWITCHSchema = R"foo(
 | 
				
			|||||||
                            "5G",
 | 
					                            "5G",
 | 
				
			||||||
                            "5G-lower",
 | 
					                            "5G-lower",
 | 
				
			||||||
                            "5G-upper",
 | 
					                            "5G-upper",
 | 
				
			||||||
                            "6G"
 | 
					                            "6G",
 | 
				
			||||||
 | 
					                            "HaLow"
 | 
				
			||||||
                        ]
 | 
					                        ]
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
                },
 | 
					                },
 | 
				
			||||||
@@ -7897,7 +7936,9 @@ static std::string DefaultSWITCHSchema = R"foo(
 | 
				
			|||||||
                            "inactive-deauth",
 | 
					                            "inactive-deauth",
 | 
				
			||||||
                            "key-mismatch",
 | 
					                            "key-mismatch",
 | 
				
			||||||
                            "beacon-report",
 | 
					                            "beacon-report",
 | 
				
			||||||
                            "radar-detected"
 | 
					                            "radar-detected",
 | 
				
			||||||
 | 
					                            "ft-finish",
 | 
				
			||||||
 | 
					                            "sta-authorized"
 | 
				
			||||||
                        ]
 | 
					                        ]
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -118,6 +118,10 @@ namespace OpenWifi {
 | 
				
			|||||||
						Producer.poll((std::chrono::milliseconds) 0);
 | 
											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) {
 | 
								} catch (const cppkafka::HandleException &E) {
 | 
				
			||||||
				poco_warning(Logger_,
 | 
									poco_warning(Logger_,
 | 
				
			||||||
							 fmt::format("Caught a Kafka exception (producer): {}", E.what()));
 | 
												 fmt::format("Caught a Kafka exception (producer): {}", E.what()));
 | 
				
			||||||
@@ -126,10 +130,6 @@ namespace OpenWifi {
 | 
				
			|||||||
			} catch (...) {
 | 
								} catch (...) {
 | 
				
			||||||
				poco_error(Logger_, "std::exception");
 | 
									poco_error(Logger_, "std::exception");
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			if (Queue_.size() == 0) {
 | 
					 | 
				
			||||||
				// message queue is empty, flush all previously sent messages
 | 
					 | 
				
			||||||
				Producer.flush();
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
			Note = Queue_.waitDequeueNotification();
 | 
								Note = Queue_.waitDequeueNotification();
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		Producer.flush();
 | 
							Producer.flush();
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -14,6 +14,7 @@
 | 
				
			|||||||
#include <iostream>
 | 
					#include <iostream>
 | 
				
			||||||
#include <random>
 | 
					#include <random>
 | 
				
			||||||
#include <vector>
 | 
					#include <vector>
 | 
				
			||||||
 | 
					#include <optional>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// This must be defined for poco_debug and poco_trace macros to function.
 | 
					// This must be defined for poco_debug and poco_trace macros to function.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -40,6 +41,7 @@ namespace OpenWifi {
 | 
				
			|||||||
#include "Poco/Util/OptionSet.h"
 | 
					#include "Poco/Util/OptionSet.h"
 | 
				
			||||||
#include "Poco/Util/PropertyFileConfiguration.h"
 | 
					#include "Poco/Util/PropertyFileConfiguration.h"
 | 
				
			||||||
#include "Poco/Util/ServerApplication.h"
 | 
					#include "Poco/Util/ServerApplication.h"
 | 
				
			||||||
 | 
					#include "Poco/ThreadPool.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "framework/OpenWifiTypes.h"
 | 
					#include "framework/OpenWifiTypes.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -5,6 +5,7 @@
 | 
				
			|||||||
#pragma once
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <string>
 | 
					#include <string>
 | 
				
			||||||
 | 
					#include <optional>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "framework/OpenWifiTypes.h"
 | 
					#include "framework/OpenWifiTypes.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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) {
 | 
							inline void SendCompressedTarFile(const std::string &FileName, const std::string &Content) {
 | 
				
			||||||
			Response->setStatus(Poco::Net::HTTPResponse::HTTPStatus::HTTP_OK);
 | 
								Response->setStatus(Poco::Net::HTTPResponse::HTTPStatus::HTTP_OK);
 | 
				
			||||||
			SetCommonHeaders();
 | 
								SetCommonHeaders();
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -35,7 +35,6 @@ namespace OpenWifi {
 | 
				
			|||||||
		P.verificationDepth = 9;
 | 
							P.verificationDepth = 9;
 | 
				
			||||||
		P.loadDefaultCAs = root_ca_.empty();
 | 
							P.loadDefaultCAs = root_ca_.empty();
 | 
				
			||||||
		P.cipherList = "ALL:!ADH:!LOW:!EXP:!MD5:@STRENGTH";
 | 
							P.cipherList = "ALL:!ADH:!LOW:!EXP:!MD5:@STRENGTH";
 | 
				
			||||||
		P.dhUse2048Bits = true;
 | 
					 | 
				
			||||||
		P.caLocation = cas_;
 | 
							P.caLocation = cas_;
 | 
				
			||||||
        // P.securityLevel =
 | 
					        // P.securityLevel =
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -68,6 +67,16 @@ namespace OpenWifi {
 | 
				
			|||||||
				Context->addCertificateAuthority(Issuing);
 | 
									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_);
 | 
								Poco::Crypto::RSAKey Key("", key_file_, key_file_password_);
 | 
				
			||||||
			Context->usePrivateKey(Key);
 | 
								Context->usePrivateKey(Key);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -45,6 +45,7 @@ namespace OpenWifi {
 | 
				
			|||||||
		[[nodiscard]] inline auto KeyFile() const { return key_file_; };
 | 
							[[nodiscard]] inline auto KeyFile() const { return key_file_; };
 | 
				
			||||||
		[[nodiscard]] inline auto CertFile() const { return cert_file_; };
 | 
							[[nodiscard]] inline auto CertFile() const { return cert_file_; };
 | 
				
			||||||
		[[nodiscard]] inline auto RootCA() const { return root_ca_; };
 | 
							[[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 KeyFilePassword() const { return key_file_password_; };
 | 
				
			||||||
		[[nodiscard]] inline auto IssuerCertFile() const { return issuer_cert_file_; };
 | 
							[[nodiscard]] inline auto IssuerCertFile() const { return issuer_cert_file_; };
 | 
				
			||||||
		[[nodiscard]] inline auto Name() const { return name_; };
 | 
							[[nodiscard]] inline auto Name() const { return name_; };
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -210,6 +210,12 @@ namespace OpenWifi {
 | 
				
			|||||||
			n = Client->second->WS_->receiveFrame(IncomingFrame, flags);
 | 
								n = Client->second->WS_->receiveFrame(IncomingFrame, flags);
 | 
				
			||||||
			auto Op = flags & Poco::Net::WebSocket::FRAME_OP_BITMASK;
 | 
								auto Op = flags & Poco::Net::WebSocket::FRAME_OP_BITMASK;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (n == -1) {
 | 
				
			||||||
 | 
									poco_warning(Logger(),
 | 
				
			||||||
 | 
										fmt::format("UI-EMPTY({}): {} Empty Frame flags {}.",
 | 
				
			||||||
 | 
													Client->second->Id_, Client->second->UserName_, flags));
 | 
				
			||||||
 | 
									return;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
			if (n == 0) {
 | 
								if (n == 0) {
 | 
				
			||||||
				poco_debug(Logger(),
 | 
									poco_debug(Logger(),
 | 
				
			||||||
					fmt::format("CLOSE({}): {} UI Client is closing WS connection.",
 | 
										fmt::format("CLOSE({}): {} UI Client is closing WS connection.",
 | 
				
			||||||
@@ -231,6 +237,11 @@ namespace OpenWifi {
 | 
				
			|||||||
									   Client->second->Id_, Client->second->UserName_));
 | 
														   Client->second->Id_, Client->second->UserName_));
 | 
				
			||||||
				return EndConnection(Client);
 | 
									return EndConnection(Client);
 | 
				
			||||||
			} break;
 | 
								} break;
 | 
				
			||||||
 | 
								case Poco::Net::WebSocket::FRAME_OP_CONT: {
 | 
				
			||||||
 | 
									poco_warning(Logger(),
 | 
				
			||||||
 | 
												 fmt::format("CONT({}): {} Unexpected CONT Frame - Ignoring.",
 | 
				
			||||||
 | 
															 Client->second->Id_, Client->second->UserName_));
 | 
				
			||||||
 | 
								} break;
 | 
				
			||||||
			case Poco::Net::WebSocket::FRAME_OP_TEXT: {
 | 
								case Poco::Net::WebSocket::FRAME_OP_TEXT: {
 | 
				
			||||||
				constexpr const char *DropMessagesCommand = "drop-notifications";
 | 
									constexpr const char *DropMessagesCommand = "drop-notifications";
 | 
				
			||||||
				IncomingFrame.append(0);
 | 
									IncomingFrame.append(0);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -433,6 +433,10 @@ namespace OpenWifi::RESTAPI::Errors {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	static const struct msg InvalidRRMAction { 1192, "Invalid RRM Action." };
 | 
						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 FailedToDecompress { 1195, "Failed to decompress package data."};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    static const struct msg SimulationDoesNotExist {
 | 
					    static const struct msg SimulationDoesNotExist {
 | 
				
			||||||
        7000, "Simulation Instance ID does not exist."
 | 
					        7000, "Simulation Instance ID does not exist."
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
@@ -550,6 +554,10 @@ namespace OpenWifi::RESTAPI::Protocol {
 | 
				
			|||||||
	static const char *DEBUG = "debug";
 | 
						static const char *DEBUG = "debug";
 | 
				
			||||||
	static const char *SCRIPT = "script";
 | 
						static const char *SCRIPT = "script";
 | 
				
			||||||
	static const char *TIMEOUT = "timeout";
 | 
						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 *NEWPASSWORD = "newPassword";
 | 
				
			||||||
	static const char *USERS = "users";
 | 
						static const char *USERS = "users";
 | 
				
			||||||
@@ -580,6 +588,10 @@ namespace OpenWifi::RESTAPI::Protocol {
 | 
				
			|||||||
	static const char *INTERVAL = "interval";
 | 
						static const char *INTERVAL = "interval";
 | 
				
			||||||
	static const char *UI = "UI";
 | 
						static const char *UI = "UI";
 | 
				
			||||||
	static const char *BANDWIDTH = "bandwidth";
 | 
						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::RESTAPI::Protocol
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace OpenWifi::uCentralProtocol {
 | 
					namespace OpenWifi::uCentralProtocol {
 | 
				
			||||||
@@ -608,6 +620,7 @@ namespace OpenWifi::uCentralProtocol {
 | 
				
			|||||||
	static const char *CFGPENDING = "cfgpending";
 | 
						static const char *CFGPENDING = "cfgpending";
 | 
				
			||||||
	static const char *RECOVERY = "recovery";
 | 
						static const char *RECOVERY = "recovery";
 | 
				
			||||||
	static const char *COMPRESS_64 = "compress_64";
 | 
						static const char *COMPRESS_64 = "compress_64";
 | 
				
			||||||
 | 
						static const char *COMPRESS_SZ = "compress_sz";
 | 
				
			||||||
	static const char *CAPABILITIES = "capabilities";
 | 
						static const char *CAPABILITIES = "capabilities";
 | 
				
			||||||
	static const char *REQUEST_UUID = "request_uuid";
 | 
						static const char *REQUEST_UUID = "request_uuid";
 | 
				
			||||||
	static const char *SANITY = "sanity";
 | 
						static const char *SANITY = "sanity";
 | 
				
			||||||
@@ -664,6 +677,9 @@ namespace OpenWifi::uCentralProtocol {
 | 
				
			|||||||
	static const char *SIGNATURE = "signature";
 | 
						static const char *SIGNATURE = "signature";
 | 
				
			||||||
	static const char *INFO = "info";
 | 
						static const char *INFO = "info";
 | 
				
			||||||
	static const char *DATE = "date";
 | 
						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 *SERIALNUMBER = "serialNumber";
 | 
				
			||||||
	static const char *COMPATIBLE = "compatible";
 | 
						static const char *COMPATIBLE = "compatible";
 | 
				
			||||||
@@ -692,6 +708,11 @@ namespace OpenWifi::uCentralProtocol {
 | 
				
			|||||||
	static const char *RRM = "rrm";
 | 
						static const char *RRM = "rrm";
 | 
				
			||||||
	static const char *ACTIONS = "actions";
 | 
						static const char *ACTIONS = "actions";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						static const char *FIXEDCONFIG = "fixedconfig";
 | 
				
			||||||
 | 
						static const char *CABLEDIAGNOSTICS = "cable-diagnostics";
 | 
				
			||||||
 | 
						static const char *REENROLL = "reenroll";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						static const char *OPERATION = "op";
 | 
				
			||||||
} // namespace OpenWifi::uCentralProtocol
 | 
					} // namespace OpenWifi::uCentralProtocol
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace OpenWifi::uCentralProtocol::Events {
 | 
					namespace OpenWifi::uCentralProtocol::Events {
 | 
				
			||||||
@@ -726,7 +747,7 @@ namespace OpenWifi::uCentralProtocol::Events {
 | 
				
			|||||||
		ET_EVENT,
 | 
							ET_EVENT,
 | 
				
			||||||
		ET_WIFISCAN,
 | 
							ET_WIFISCAN,
 | 
				
			||||||
		ET_ALARM,
 | 
							ET_ALARM,
 | 
				
			||||||
		ET_REBOOTLOG
 | 
							ET_REBOOTLOG,
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	inline EVENT_MSG EventFromString(const std::string &Method) {
 | 
						inline EVENT_MSG EventFromString(const std::string &Method) {
 | 
				
			||||||
@@ -788,6 +809,10 @@ namespace OpenWifi::APCommands {
 | 
				
			|||||||
		certupdate,
 | 
							certupdate,
 | 
				
			||||||
		transfer,
 | 
							transfer,
 | 
				
			||||||
		powercycle,
 | 
							powercycle,
 | 
				
			||||||
 | 
							fixedconfig,
 | 
				
			||||||
 | 
							cablediagnostics,
 | 
				
			||||||
 | 
							reenroll,
 | 
				
			||||||
 | 
							package,
 | 
				
			||||||
		unknown
 | 
							unknown
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -802,7 +827,9 @@ namespace OpenWifi::APCommands {
 | 
				
			|||||||
		RESTAPI::Protocol::EVENTQUEUE,	 RESTAPI::Protocol::TELEMETRY,
 | 
							RESTAPI::Protocol::EVENTQUEUE,	 RESTAPI::Protocol::TELEMETRY,
 | 
				
			||||||
		RESTAPI::Protocol::PING,		 RESTAPI::Protocol::SCRIPT,
 | 
							RESTAPI::Protocol::PING,		 RESTAPI::Protocol::SCRIPT,
 | 
				
			||||||
		RESTAPI::Protocol::RRM,		 	 RESTAPI::Protocol::CERTUPDATE,
 | 
							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,	 RESTAPI::Protocol::PACKAGE
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	inline const char *to_string(Commands Cmd) { return uCentralAPCommands[(uint8_t)Cmd]; }
 | 
						inline const char *to_string(Commands Cmd) { return uCentralAPCommands[(uint8_t)Cmd]; }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -590,6 +590,26 @@ namespace OpenWifi::Utils {
 | 
				
			|||||||
		return false;
 | 
							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) {
 | 
						bool IsAlphaNumeric(const std::string &s) {
 | 
				
			||||||
		return std::all_of(s.begin(), s.end(), [](char c) -> bool { return isalnum(c); });
 | 
							return std::all_of(s.begin(), s.end(), [](char c) -> bool { return isalnum(c); });
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -868,78 +888,15 @@ namespace OpenWifi::Utils {
 | 
				
			|||||||
        return password;
 | 
					        return password;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/*
 | 
				
			||||||
 | 
						 Note that these 2 functions aren't used. They have been removed due to this deprecation warning:
 | 
				
			||||||
	// Function to query NAPTR records for a domain and return them in a vector
 | 
						// Function to query NAPTR records for a domain and return them in a vector
 | 
				
			||||||
    std::vector<NAPTRRecord> getNAPTRRecords(const std::string& domain) {
 | 
						 #47 3.825 /owgw/src/framework/utils.cpp: In function 'std::vector<OpenWifi::Utils::NAPTRRecord> OpenWifi::Utils::getNAPTRRecords(const std::string&)':
 | 
				
			||||||
        std::vector<NAPTRRecord> naptrRecords;
 | 
					#47 3.825 /owgw/src/framework/utils.cpp:915:28: warning: 'int ns_sprintrr(const ns_msg*, const ns_rr*, const char*, const char*, char*, size_t)' is deprecated [-Wdeprecated-declarations]
 | 
				
			||||||
 | 
					 | 
				
			||||||
        unsigned char buf[4096];
 | 
					 | 
				
			||||||
        ns_msg handle;
 | 
					 | 
				
			||||||
        ns_initparse(buf, NS_PACKETSZ, &handle);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        // Query NAPTR records for the given domain
 | 
					 | 
				
			||||||
        int response = res_query(domain.c_str(), ns_c_in, ns_t_naptr, buf, sizeof(buf));
 | 
					 | 
				
			||||||
        if (response < 0) {
 | 
					 | 
				
			||||||
            return naptrRecords;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if(ns_initparse(buf, response, &handle) < 0) {
 | 
					 | 
				
			||||||
            return naptrRecords;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        // Iterate through the DNS response and extract NAPTR records
 | 
					 | 
				
			||||||
        int count = ns_msg_count(handle, ns_s_an);
 | 
					 | 
				
			||||||
        for (int i = 0; i < count; ++i) {
 | 
					 | 
				
			||||||
            ns_rr rr;
 | 
					 | 
				
			||||||
            if (ns_parserr(&handle, ns_s_an, i, &rr) == 0) {
 | 
					 | 
				
			||||||
                char rdata[256];
 | 
					 | 
				
			||||||
                ns_sprintrr(&handle, &rr, nullptr, nullptr, rdata, sizeof(rdata));
 | 
					 | 
				
			||||||
                NAPTRRecord record;
 | 
					 | 
				
			||||||
                std::istringstream os(rdata);
 | 
					 | 
				
			||||||
                os  >> record.name >> record.ttl >> record.rclass >> record.rtype >> record.order >> record.preference >> record.flags
 | 
					 | 
				
			||||||
                    >> record.service >> record.regexp >>  record.replacement;
 | 
					 | 
				
			||||||
                naptrRecords.push_back(record);
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        return naptrRecords;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    std::vector<SrvRecord> getSRVRecords(const std::string& domain) {
 | 
					    std::vector<SrvRecord> getSRVRecords(const std::string& domain) {
 | 
				
			||||||
        std::vector<SrvRecord> srvRecords;
 | 
					    #47 3.833 /owgw/src/framework/utils.cpp: In function 'std::vector<OpenWifi::Utils::SrvRecord> OpenWifi::Utils::getSRVRecords(const std::string&)':
 | 
				
			||||||
 | 
					    #47 3.833 /owgw/src/framework/utils.cpp:952:28: warning: 'int ns_sprintrr(const ns_msg*, const ns_rr*, const char*, const char*, char*, size_t)' is deprecated [-Wdeprecated-declarations]
 | 
				
			||||||
        // Buffer to hold the DNS response
 | 
						*/
 | 
				
			||||||
        unsigned char buf[4096];
 | 
					 | 
				
			||||||
        ns_msg handle;
 | 
					 | 
				
			||||||
        ns_initparse(buf, NS_PACKETSZ, &handle);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        // Query NAPTR records for the given domain
 | 
					 | 
				
			||||||
        int response = res_query(domain.c_str(), ns_c_in, ns_t_srv, buf, sizeof(buf));
 | 
					 | 
				
			||||||
        if (response < 0) {
 | 
					 | 
				
			||||||
            std::cerr << "DNS query failed for " << domain << ": " << hstrerror(h_errno) << std::endl;
 | 
					 | 
				
			||||||
            return srvRecords;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if(ns_initparse(buf, response, &handle) < 0) {
 | 
					 | 
				
			||||||
            return srvRecords;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        // Iterate through the DNS response and extract NAPTR records
 | 
					 | 
				
			||||||
        int count = ns_msg_count(handle, ns_s_an);
 | 
					 | 
				
			||||||
        for (int i = 0; i < count; ++i) {
 | 
					 | 
				
			||||||
            ns_rr rr;
 | 
					 | 
				
			||||||
            if (ns_parserr(&handle, ns_s_an, i, &rr) == 0) {
 | 
					 | 
				
			||||||
                char rdata[256];
 | 
					 | 
				
			||||||
                ns_sprintrr(&handle, &rr, nullptr, nullptr, rdata, sizeof(rdata));
 | 
					 | 
				
			||||||
                SrvRecord record;
 | 
					 | 
				
			||||||
                std::istringstream os(rdata);
 | 
					 | 
				
			||||||
                os  >>  record.name >> record.ttl >> record.rclass >> record.rtype >> record.pref >> record.weight >>
 | 
					 | 
				
			||||||
                    record.port >> record.srvname ;
 | 
					 | 
				
			||||||
                srvRecords.push_back(record);
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        return srvRecords;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
} // namespace OpenWifi::Utils
 | 
					} // namespace OpenWifi::Utils
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -151,6 +151,8 @@ namespace OpenWifi::Utils {
 | 
				
			|||||||
	bool ExtractBase64CompressedData(const std::string &CompressedData,
 | 
						bool ExtractBase64CompressedData(const std::string &CompressedData,
 | 
				
			||||||
									 std::string &UnCompressedData, uint64_t compress_sz);
 | 
														 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)
 | 
						inline bool match(const char* first, const char* second)
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		// If we reach at the end of both strings, we are done
 | 
							// If we reach at the end of both strings, we are done
 | 
				
			||||||
@@ -296,8 +298,10 @@ namespace OpenWifi::Utils {
 | 
				
			|||||||
        std::string     replacement;
 | 
					        std::string     replacement;
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// removed due to deprecation: see utils.cpp
 | 
				
			||||||
    // Function to query NAPTR records for a domain and return them in a vector
 | 
					    // Function to query NAPTR records for a domain and return them in a vector
 | 
				
			||||||
    std::vector<NAPTRRecord> getNAPTRRecords(const std::string& domain);
 | 
					    //std::vector<NAPTRRecord> getNAPTRRecords(const std::string& domain);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    struct SrvRecord {
 | 
					    struct SrvRecord {
 | 
				
			||||||
        std::string     name;
 | 
					        std::string     name;
 | 
				
			||||||
        std::string     ttl;
 | 
					        std::string     ttl;
 | 
				
			||||||
@@ -309,7 +313,8 @@ namespace OpenWifi::Utils {
 | 
				
			|||||||
        std::string     srvname;
 | 
					        std::string     srvname;
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    std::vector<SrvRecord> getSRVRecords(const std::string& domain);
 | 
						// removed due to deprecation: see utils.cpp
 | 
				
			||||||
 | 
					    // std::vector<SrvRecord> getSRVRecords(const std::string& domain);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    struct HostNameServerResult{
 | 
					    struct HostNameServerResult{
 | 
				
			||||||
        std::string     Hostname;
 | 
					        std::string     Hostname;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -14,6 +14,7 @@
 | 
				
			|||||||
#include "nlohmann/json.hpp"
 | 
					#include "nlohmann/json.hpp"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "Poco/NObserver.h"
 | 
					#include "Poco/NObserver.h"
 | 
				
			||||||
 | 
					#include <Poco/Net/Context.h>
 | 
				
			||||||
#include "Poco/Net/SocketNotification.h"
 | 
					#include "Poco/Net/SocketNotification.h"
 | 
				
			||||||
#include "Poco/Net/NetException.h"
 | 
					#include "Poco/Net/NetException.h"
 | 
				
			||||||
#include "Poco/Net/WebSocketImpl.h"
 | 
					#include "Poco/Net/WebSocketImpl.h"
 | 
				
			||||||
@@ -71,6 +72,7 @@ namespace OpenWifi {
 | 
				
			|||||||
				const auto &RootCas =
 | 
									const auto &RootCas =
 | 
				
			||||||
					MicroServiceConfigPath("ucentral.websocket.host.0.rootca", "");
 | 
										MicroServiceConfigPath("ucentral.websocket.host.0.rootca", "");
 | 
				
			||||||
				const auto &Cas = MicroServiceConfigPath("ucentral.websocket.host.0.cas", "");
 | 
									const auto &Cas = MicroServiceConfigPath("ucentral.websocket.host.0.cas", "");
 | 
				
			||||||
 | 
									const auto &ClientCasFile = MicroServiceConfigPath("ucentral.websocket.host.0.clientcas", "");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				Poco::Net::Context::Params P;
 | 
									Poco::Net::Context::Params P;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -86,6 +88,7 @@ namespace OpenWifi {
 | 
				
			|||||||
				Poco::Crypto::X509Certificate Cert(CertFileName);
 | 
									Poco::Crypto::X509Certificate Cert(CertFileName);
 | 
				
			||||||
				Poco::Crypto::X509Certificate Root(RootCaFileName);
 | 
									Poco::Crypto::X509Certificate Root(RootCaFileName);
 | 
				
			||||||
				Poco::Crypto::X509Certificate Issuing(IssuerFileName);
 | 
									Poco::Crypto::X509Certificate Issuing(IssuerFileName);
 | 
				
			||||||
 | 
					                std::vector<Poco::Crypto::X509Certificate> ClientCasCerts;
 | 
				
			||||||
				Poco::Crypto::RSAKey Key("", KeyFileName, KeyPassword);
 | 
									Poco::Crypto::RSAKey Key("", KeyFileName, KeyPassword);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				DeviceSecureContext->useCertificate(Cert);
 | 
									DeviceSecureContext->useCertificate(Cert);
 | 
				
			||||||
@@ -93,7 +96,11 @@ namespace OpenWifi {
 | 
				
			|||||||
				DeviceSecureContext->addCertificateAuthority(Root);
 | 
									DeviceSecureContext->addCertificateAuthority(Root);
 | 
				
			||||||
				DeviceSecureContext->addChainCertificate(Issuing);
 | 
									DeviceSecureContext->addChainCertificate(Issuing);
 | 
				
			||||||
				DeviceSecureContext->addCertificateAuthority(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->enableSessionCache(true);
 | 
				
			||||||
				DeviceSecureContext->setSessionCacheSize(0);
 | 
									DeviceSecureContext->setSessionCacheSize(0);
 | 
				
			||||||
				DeviceSecureContext->setSessionTimeout(120);
 | 
									DeviceSecureContext->setSessionTimeout(120);
 | 
				
			||||||
@@ -573,13 +580,15 @@ namespace OpenWifi {
 | 
				
			|||||||
		try {
 | 
							try {
 | 
				
			||||||
			Client = Clients_.find(pNf->socket().impl()->sockfd());
 | 
								Client = Clients_.find(pNf->socket().impl()->sockfd());
 | 
				
			||||||
			if (Client == end(Clients_)) {
 | 
								if (Client == end(Clients_)) {
 | 
				
			||||||
				poco_warning(Logger(), fmt::format("Cannot find client socket: {}",
 | 
									poco_warning(Logger(),
 | 
				
			||||||
 | 
										fmt::format("Cannot find client socket: {}",
 | 
				
			||||||
								pNf->socket().impl()->sockfd()));
 | 
													pNf->socket().impl()->sockfd()));
 | 
				
			||||||
				return;
 | 
									return;
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			Connection = Client->second;
 | 
								Connection = Client->second;
 | 
				
			||||||
			if(Connection->WSSocket_==nullptr || Connection->WSSocket_->impl()==nullptr) {
 | 
								if(Connection->WSSocket_==nullptr || Connection->WSSocket_->impl()==nullptr) {
 | 
				
			||||||
				poco_warning(Logger(), fmt::format("WebSocket is no valid: {}",
 | 
									poco_warning(Logger(),
 | 
				
			||||||
 | 
										fmt::format("WebSocket is not valid: {}",
 | 
				
			||||||
							    Connection->SerialNumber_));
 | 
												    Connection->SerialNumber_));
 | 
				
			||||||
				return;
 | 
									return;
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
@@ -589,6 +598,14 @@ namespace OpenWifi {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
			auto ReceivedBytes = Connection->WSSocket_->receiveFrame(FrameBuffer, sizeof(FrameBuffer), flags);
 | 
								auto ReceivedBytes = Connection->WSSocket_->receiveFrame(FrameBuffer, sizeof(FrameBuffer), flags);
 | 
				
			||||||
			auto Op = flags & Poco::Net::WebSocket::FRAME_OP_BITMASK;
 | 
								auto Op = flags & Poco::Net::WebSocket::FRAME_OP_BITMASK;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (ReceivedBytes == -1) {
 | 
				
			||||||
 | 
									poco_trace(Logger(),
 | 
				
			||||||
 | 
										fmt::format("WS-EMPTY{}: Non-blocking try-again empty Frame: flags {}",
 | 
				
			||||||
 | 
													Connection->SerialNumber_, flags));
 | 
				
			||||||
 | 
									return;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			switch (Op) {
 | 
								switch (Op) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			case Poco::Net::WebSocket::FRAME_OP_PING: {
 | 
								case Poco::Net::WebSocket::FRAME_OP_PING: {
 | 
				
			||||||
@@ -596,8 +613,10 @@ namespace OpenWifi {
 | 
				
			|||||||
				    (int)Poco::Net::WebSocket::FRAME_OP_PONG |
 | 
									    (int)Poco::Net::WebSocket::FRAME_OP_PONG |
 | 
				
			||||||
					(int)Poco::Net::WebSocket::FRAME_FLAG_FIN);
 | 
										(int)Poco::Net::WebSocket::FRAME_FLAG_FIN);
 | 
				
			||||||
			} break;
 | 
								} break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			case Poco::Net::WebSocket::FRAME_OP_PONG: {
 | 
								case Poco::Net::WebSocket::FRAME_OP_PONG: {
 | 
				
			||||||
			} break;
 | 
								} break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			case Poco::Net::WebSocket::FRAME_OP_TEXT: {
 | 
								case Poco::Net::WebSocket::FRAME_OP_TEXT: {
 | 
				
			||||||
				if (ReceivedBytes == 0) {
 | 
									if (ReceivedBytes == 0) {
 | 
				
			||||||
					EndConnection(Connection,__func__,__LINE__);
 | 
										EndConnection(Connection,__func__,__LINE__);
 | 
				
			||||||
@@ -624,6 +643,7 @@ namespace OpenWifi {
 | 
				
			|||||||
					}
 | 
										}
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
			} break;
 | 
								} break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			case Poco::Net::WebSocket::FRAME_OP_BINARY: {
 | 
								case Poco::Net::WebSocket::FRAME_OP_BINARY: {
 | 
				
			||||||
				if (ReceivedBytes == 0) {
 | 
									if (ReceivedBytes == 0) {
 | 
				
			||||||
					EndConnection(Connection,__func__,__LINE__);
 | 
										EndConnection(Connection,__func__,__LINE__);
 | 
				
			||||||
@@ -637,6 +657,15 @@ namespace OpenWifi {
 | 
				
			|||||||
					}
 | 
										}
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
			} break;
 | 
								} break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								case Poco::Net::WebSocket::FRAME_OP_CONT: {
 | 
				
			||||||
 | 
									// may have to handle this, but not sure whether it's a continuation for text or
 | 
				
			||||||
 | 
									// binary, seems to be a hole in the protocol.
 | 
				
			||||||
 | 
									poco_warning(Logger(),
 | 
				
			||||||
 | 
												 fmt::format("CONT Frame {} received, ignoring for now.",
 | 
				
			||||||
 | 
															 ReceivedBytes));
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			case Poco::Net::WebSocket::FRAME_OP_CLOSE: {
 | 
								case Poco::Net::WebSocket::FRAME_OP_CLOSE: {
 | 
				
			||||||
				EndConnection(Connection,__func__,__LINE__);
 | 
									EndConnection(Connection,__func__,__LINE__);
 | 
				
			||||||
				return;
 | 
									return;
 | 
				
			||||||
@@ -682,8 +711,8 @@ namespace OpenWifi {
 | 
				
			|||||||
		if (Connection->WSSocket_ != nullptr && Connection->WSSocket_->impl()!= nullptr) {
 | 
							if (Connection->WSSocket_ != nullptr && Connection->WSSocket_->impl()!= nullptr) {
 | 
				
			||||||
			try {
 | 
								try {
 | 
				
			||||||
				Connection->WSSocket_->sendFrame(Buf, len,
 | 
									Connection->WSSocket_->sendFrame(Buf, len,
 | 
				
			||||||
												 Poco::Net::WebSocket::FRAME_FLAG_FIN |
 | 
																	 (int) Poco::Net::WebSocket::FRAME_FLAG_FIN |
 | 
				
			||||||
													 Poco::Net::WebSocket::FRAME_OP_BINARY);
 | 
																	 (int) Poco::Net::WebSocket::FRAME_OP_BINARY);
 | 
				
			||||||
				return;
 | 
									return;
 | 
				
			||||||
			} catch (...) {
 | 
								} catch (...) {
 | 
				
			||||||
				poco_error(Logger(), "SendData shutdown.");
 | 
									poco_error(Logger(), "SendData shutdown.");
 | 
				
			||||||
@@ -985,8 +1014,9 @@ namespace OpenWifi {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	bool RTTYS_server::SendToClient(Poco::Net::WebSocket &WebSocket, const u_char *Buf, int len) {
 | 
						bool RTTYS_server::SendToClient(Poco::Net::WebSocket &WebSocket, const u_char *Buf, int len) {
 | 
				
			||||||
		WebSocket.sendFrame(
 | 
							WebSocket.sendFrame(Buf, len,
 | 
				
			||||||
			Buf, len, Poco::Net::WebSocket::FRAME_FLAG_FIN | Poco::Net::WebSocket::FRAME_OP_BINARY);
 | 
												(int) Poco::Net::WebSocket::FRAME_FLAG_FIN |
 | 
				
			||||||
 | 
												(int) Poco::Net::WebSocket::FRAME_OP_BINARY);
 | 
				
			||||||
		return true;
 | 
							return true;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -644,21 +644,7 @@ namespace OpenWifi {
 | 
				
			|||||||
			uint64_t Size = FileContent.str().size();
 | 
								uint64_t Size = FileContent.str().size();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			Poco::Data::Session Sess = Pool_->get();
 | 
								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()) {
 | 
								if (Size < FileUploader()->MaxSize()) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				Poco::Data::BLOB TheBlob;
 | 
									Poco::Data::BLOB TheBlob;
 | 
				
			||||||
@@ -678,9 +664,24 @@ namespace OpenWifi {
 | 
				
			|||||||
				Insert.execute();
 | 
									Insert.execute();
 | 
				
			||||||
				Sess.commit();
 | 
									Sess.commit();
 | 
				
			||||||
			} else {
 | 
								} else {
 | 
				
			||||||
				poco_warning(Logger(), fmt::format("File {} is too large.", UUID));
 | 
									poco_warning(Logger(),
 | 
				
			||||||
 | 
										fmt::format("File {} is too large ({} >= {} max bytes).",
 | 
				
			||||||
 | 
											UUID, Size, FileUploader()->MaxSize()));
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								// 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();
 | 
								Sess.commit();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			return true;
 | 
								return true;
 | 
				
			||||||
		} catch (const Poco::Exception &E) {
 | 
							} catch (const Poco::Exception &E) {
 | 
				
			||||||
			Logger().log(E);
 | 
								Logger().log(E);
 | 
				
			||||||
@@ -689,7 +690,7 @@ namespace OpenWifi {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	bool Storage::GetAttachedFileContent(std::string &UUID, const std::string &SerialNumber,
 | 
						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 {
 | 
							try {
 | 
				
			||||||
			Poco::Data::BLOB L;
 | 
								Poco::Data::BLOB L;
 | 
				
			||||||
			/*
 | 
								/*
 | 
				
			||||||
@@ -702,10 +703,10 @@ namespace OpenWifi {
 | 
				
			|||||||
			Poco::Data::Statement Select1(Sess);
 | 
								Poco::Data::Statement Select1(Sess);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			std::string TmpSerialNumber;
 | 
								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;
 | 
								std::string Command;
 | 
				
			||||||
			Select1 << ConvertParams(st1), Poco::Data::Keywords::into(TmpSerialNumber),
 | 
								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();
 | 
								Select1.execute();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			if (TmpSerialNumber != SerialNumber) {
 | 
								if (TmpSerialNumber != SerialNumber) {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -204,13 +204,12 @@ namespace OpenWifi {
 | 
				
			|||||||
			std::string whereClause = "";
 | 
								std::string whereClause = "";
 | 
				
			||||||
			if (!platform.empty()) {
 | 
								if (!platform.empty()) {
 | 
				
			||||||
				if (includeProvisioned == false) {
 | 
									if (includeProvisioned == false) {
 | 
				
			||||||
 | 
										//whereClause = fmt::format("WHERE entity='' and venue='' and DeviceType='" + platform + "'");
 | 
				
			||||||
					whereClause = fmt::format("WHERE entity='' and venue='' and DeviceType='" + platform + "'");
 | 
										whereClause = fmt::format("WHERE entity='' and venue='' and DeviceType='{}'", platform);
 | 
				
			||||||
				} else {
 | 
									} else {
 | 
				
			||||||
					whereClause = fmt::format("WHERE DeviceType='" + platform + "'");
 | 
										//whereClause = fmt::format("WHERE DeviceType='" + platform + "'");
 | 
				
			||||||
 | 
										whereClause = fmt::format("WHERE DeviceType='{}'", platform);
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
			
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
				//st = "SELECT SerialNumber From Devices WHERE DeviceType='" + platform + "' ";
 | 
									//st = "SELECT SerialNumber From Devices WHERE DeviceType='" + platform + "' ";
 | 
				
			||||||
			} else {
 | 
								} else {
 | 
				
			||||||
				if (includeProvisioned == false) {
 | 
									if (includeProvisioned == false) {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -49,8 +49,7 @@ namespace OpenWifi {
 | 
				
			|||||||
						"Data TEXT, "
 | 
											"Data TEXT, "
 | 
				
			||||||
						"Recorded BIGINT, "
 | 
											"Recorded BIGINT, "
 | 
				
			||||||
						"INDEX StatSerial0 (SerialNumber)), ",
 | 
											"INDEX StatSerial0 (SerialNumber)), ",
 | 
				
			||||||
						"INDEX StatSerial (SerialNumber ASC, Recorded ASC))",
 | 
										"INDEX StatSerial (SerialNumber ASC, Recorded ASC))", Poco::Data::Keywords::now;
 | 
				
			||||||
					Poco::Data::Keywords::now;
 | 
					 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			return 0;
 | 
								return 0;
 | 
				
			||||||
		} catch (const Poco::Exception &E) {
 | 
							} catch (const Poco::Exception &E) {
 | 
				
			||||||
@@ -154,8 +153,7 @@ namespace OpenWifi {
 | 
				
			|||||||
				"alter table devices add column lastRecordedContact bigint",
 | 
									"alter table devices add column lastRecordedContact bigint",
 | 
				
			||||||
				"alter table devices add column simulated boolean",
 | 
									"alter table devices add column simulated boolean",
 | 
				
			||||||
				"alter table devices add column certificateExpiryDate bigint",
 | 
									"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) {
 | 
								for (const auto &i : Script) {
 | 
				
			||||||
				try {
 | 
									try {
 | 
				
			||||||
@@ -279,9 +277,7 @@ namespace OpenWifi {
 | 
				
			|||||||
					Poco::Data::Keywords::now;
 | 
										Poco::Data::Keywords::now;
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			std::vector<std::string> Script{
 | 
								std::vector<std::string> Script{"alter table DefaultConfigs add column Platform text"};
 | 
				
			||||||
				"alter table DefaultConfigs add column Platform text"
 | 
					 | 
				
			||||||
			};
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
			for (const auto &i : Script) {
 | 
								for (const auto &i : Script) {
 | 
				
			||||||
				try {
 | 
									try {
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user