Compare commits

...

50 Commits

Author SHA1 Message Date
Carsten Schafer
1961c26362 Merge pull request #432 from Telecominfraproject/PKI2-208-Set-cert-validation-mode-in-tmpl
Make websocket security mode configurable
2026-03-16 13:16:18 -04:00
Carsten Schafer
cae9856fed Make websocket security mode configurable
Signed-off-by: Carsten Schafer <Carsten.Schafer@kinarasystems.com>
2026-03-16 11:48:03 -04:00
Carsten Schafer
2378bd76bb Merge pull request #431 from Telecominfraproject/WIFI_15313_fix_schema_sync
WIFI-15313: fix: schema sync on max channel value
2026-02-06 07:31:45 -05:00
Ivan Chvets
87f7d116a7 fix: schema sync on max channel value
https://telecominfraproject.atlassian.net/browse/WIFI-15313
Signed-off-by: Ivan Chvets <ivan.chvets@kinarasystems.com>
2026-02-05 18:35:41 -05:00
Carsten Schafer
3e5c96202a Merge pull request #430 from Telecominfraproject/WIFI-15323-Update-build-documentation
[WIFI-15323] Update build documentation
2026-02-05 10:50:27 -05:00
Andre Courchesne
0914b4908c - Update build doc and add quick build script
Signed-off-by: Andre Courchesne <andre.courchesne@intello.com>
2026-02-03 23:34:05 -05:00
i-chvets
d68c7bdb77 Merge pull request #429 from Telecominfraproject/WIFI-15031-fix-fingerprinting-raw-mode
WIFI-15031: fix: updated config validation
2025-12-10 13:46:17 -05:00
Ivan Chvets
d2f2b8df90 fix: Updated configuration validation to fix issue with fingerprinting raw mode.
https://telecominfraproject.atlassian.net/browse/WIFI-15031
Signed-off-by: Ivan Chvets <ivan.chvets@kinarasystems.com>
2025-12-10 11:49:36 -05:00
i-chvets
dfba03bd17 Merge pull request #428 from Telecominfraproject/version_update
version: Updated version to 4.2.0 (RC1)
2025-12-05 13:11:08 -05:00
Ivan Chvets
b6f0f113e2 version: Updated version to 4.2.0 (RC1)
Signed-off-by: Ivan Chvets <ivan.chvets@kinarasystems.com>
2025-12-05 12:43:33 -05:00
i-chvets
ac04422302 Merge pull request #427 from Telecominfraproject/schema_sync
WIFI-15257: fix: Schema sync
2025-12-04 16:36:05 -05:00
Ivan Chvets
63114641a7 fix: Schema sync
https://telecominfraproject.atlassian.net/browse/WIFI-15257
Signed-off-by: Ivan Chvets <ivan.chvets@kinarasystems.com>
2025-12-04 16:08:54 -05:00
i-chvets
691d3399f8 Merge pull request #426 from Telecominfraproject/version_update
fix: Version update - release 4.1.1
2025-09-11 12:24:22 -04:00
Ivan Chvets
6542726ac3 Merge branch 'master' of github.com:Telecominfraproject/wlan-cloud-ucentralgw into version_update 2025-09-11 11:59:42 -04:00
Ivan Chvets
4bc753f8b5 fix: Version update - release 4.1.1
Signed-off-by: Ivan Chvets <ivan.chvets@kinarasystems.com>
2025-09-11 11:56:05 -04:00
i-chvets
e3a513fa6a Merge pull request #425 from Telecominfraproject/WIFI-15016_fix_schema_sync
WIFI 15016 fix: Sync schema.
2025-09-11 11:54:50 -04:00
Ivan Chvets
b151239a5c fix: Sync schema.
https://telecominfraproject.atlassian.net/browse/WIFI-15016

Signed-off-by: Ivan Chvets <ivan.chvets@kinarasystems.com>
2025-09-11 11:23:14 -04:00
Carsten Schafer
862dab38d1 Merge pull request #423 from Telecominfraproject/WIFI-14903-ssl-upgrade-via-debian-bookworm
Wifi 14903 ssl upgrade via debian bookworm
2025-09-02 13:54:50 -04:00
Carsten Schafer
ee2e9a19c0 Remove warning and fix RTTY PONG flags
Signed-off-by: Carsten Schafer <Carsten.Schafer@kinarasystems.com>
2025-09-02 13:28:11 -04:00
Carsten Schafer
8b28fa0435 Some more cleanup - remove code using deprecated functions
Signed-off-by: Carsten Schafer <Carsten.Schafer@kinarasystems.com>
2025-08-26 13:04:30 -04:00
Carsten Schafer
aeef70a121 Return PONG in response to PING
Signed-off-by: Carsten Schafer <Carsten.Schafer@kinarasystems.com>
2025-08-26 09:09:52 -04:00
Carsten Schafer
42c421ec12 Handle scenario where 3+ readable events including continuation frames all resulted in a final frame of 0 length
Signed-off-by: Carsten Schafer <Carsten.Schafer@kinarasystems.com>
2025-08-25 11:01:08 -04:00
Carsten Schafer
98bfb4b24d Fix package manager and resolver warnings
Signed-off-by: Carsten Schafer <Carsten.Schafer@kinarasystems.com>
2025-08-25 10:50:34 -04:00
Carsten Schafer
6b64089f55 Be able to more readily configure some useful settings via docker compose
Signed-off-by: Carsten Schafer <Carsten.Schafer@kinarasystems.com>
2025-08-25 10:45:23 -04:00
Carsten Schafer
1f6e42b57c Merge remote-tracking branch 'origin/master' into WIFI-14903-ssl-upgrade-via-debian-bookworm 2025-08-22 13:31:21 -04:00
Carsten Schafer
f857d61377 Merge remote-tracking branch 'origin/WIFI-14903-ssl-upgrade-via-debian-bookworm' into WIFI-14903-ssl-upgrade-via-debian-bookworm 2025-08-22 13:30:55 -04:00
Carsten Schafer
66d580d047 Work with new WS behaviour
Signed-off-by: Carsten Schafer <Carsten.Schafer@kinarasystems.com>
2025-08-22 13:30:07 -04:00
Carsten Schafer
567c671c22 Merge pull request #414 from Telecominfraproject/staging-WIFI-14588-Cloud-package-manager3
WIFI-14588: Cloud Package manager
2025-08-22 09:16:31 -04:00
Adam Capparelli
9e3735ced8 Switch to newer poco.
Signed-off-by: Adam Capparelli <adam.capparelli@alumni.utoronto.ca>
2025-08-21 13:03:58 -04:00
Carsten Schafer
18b169e517 Resolve conflict
Signed-off-by: Carsten Schafer <Carsten.Schafer@kinarasystems.com>
2025-08-21 09:38:16 -04:00
Carsten Schafer
cab0d8aee6 Remove test code
Signed-off-by: Carsten Schafer <Carsten.Schafer@kinarasystems.com>
2025-08-21 09:37:07 -04:00
Adam Capparelli
680b6a16e3 Fix more compilation errors.
Signed-off-by: Adam Capparelli <adam.capparelli@alumni.utoronto.ca>
2025-08-21 09:07:13 -04:00
Adam Capparelli
218694872f Fix some compile errors.
Signed-off-by: Adam Capparelli <adam.capparelli@alumni.utoronto.ca>
2025-08-21 08:47:39 -04:00
Carsten Schafer
6ae1eeb2ea Upgrade to debian bookworm, resolve compile issues, work around IOExceptions test
Signed-off-by: Carsten Schafer <Carsten.Schafer@kinarasystems.com>
2025-08-20 14:10:16 -04:00
Carsten Schafer
f537e701a0 Merge remote-tracking branch 'origin/master' into WIFI-14903-diagnose-ssl-err 2025-08-19 11:39:51 -04:00
Adam Capparelli
d4dfb7b620 Merge pull request #422 from Telecominfraproject/WIFI-14979-Update-owgw-built-in-schema
WIFI-14979-Update-owgw-built-in-schema: Add HaLow to wifi band enums.
2025-08-18 13:39:51 -04:00
Adam Capparelli
446cbf270f Add description to enable field.
Signed-off-by: Adam Capparelli <adam.capparelli@alumni.utoronto.ca>
2025-08-18 13:22:45 -04:00
Adam Capparelli
06ffee27b1 Add HaLow to wifi band enums.
Signed-off-by: Adam Capparelli <adam.capparelli@alumni.utoronto.ca>
2025-08-18 13:15:49 -04:00
i-chvets
fa3c325bfa Merge pull request #420 from Telecominfraproject/schema_sync
feat: Schema sync.
2025-08-14 16:35:56 -04:00
i-chvets
182a442582 Merge pull request #421 from Telecominfraproject/add_enroll_openapi
feat: Added reenroll to openapi.
2025-08-14 16:33:39 -04:00
Ivan Chvets
3b7a24ea30 feat: Added reenroll to openapi.
Signed-off-by: Ivan Chvets <ivan.chvets@kinarasystems.com>
2025-08-14 11:45:36 -04:00
Ivan Chvets
1c5909613f feat: Schema sync.
Signed-off-by: Ivan Chvets <ivan.chvets@kinarasystems.com>
2025-08-14 11:33:42 -04:00
Carsten Schafer
8e5e51a52a Correct call to poco_warning
Signed-off-by: Carsten Schafer <Carsten.Schafer@kinarasystems.com>
2025-08-11 15:49:08 -04:00
Carsten Schafer
b4699e9178 Add extra logging for SSL errors
Signed-off-by: Carsten Schafer <Carsten.Schafer@kinarasystems.com>
2025-08-11 15:35:48 -04:00
Carsten Schafer
438309714f Merge pull request #418 from Telecominfraproject/WIFI-14953-add-entire-trust-chain-for-rtty
WIFI-14953 Add entire trust chain for rtty use
2025-08-06 11:00:04 -04:00
Carsten Schafer
a9130eeb75 Read from proper client cas file
Signed-off-by: Carsten Schafer <Carsten.Schafer@kinarasystems.com>
2025-08-06 09:13:04 -04:00
Carsten Schafer
33068fca9e Declare the variable
Signed-off-by: Carsten Schafer <Carsten.Schafer@kinarasystems.com>
2025-08-05 11:15:51 -04:00
Carsten Schafer
d329151f6c Fix typo
Signed-off-by: Carsten Schafer <Carsten.Schafer@kinarasystems.com>
2025-08-05 10:46:45 -04:00
Carsten Schafer
ec846006bb Add entire trust chain for rtty use
Signed-off-by: Carsten Schafer <Carsten.Schafer@kinarasystems.com>
2025-08-05 10:24:33 -04:00
Kumiko18
bd48079a8d WIFI-14588: Cloud Package manager
1. Added independent package north/south bound API for package listing/installing/deleting
  2. Added modified openapi schema for swagger

Signed-off-by: Kumiko18 <alex18_huang@accton.com>
2025-07-25 01:58:37 +00:00
31 changed files with 1226 additions and 300 deletions

4
.gitignore vendored
View File

@@ -29,4 +29,6 @@ helm/charts/*
!helm/charts/.gitkeep
/portal-test/
/src/ow_version.h
.vscode/*
# Build dependencies temporary folder
.build-deps/

View File

@@ -1,11 +1,36 @@
# Building from source
In order to build OWGW, you will need to install its dependencies, which includes the following:
## Quick Build (Recommended - Using Container)
The easiest way to build OWGW is using the provided build script that creates a Debian Bookworm container with all dependencies:
```bash
./build-ucentralgw.sh
```
This script will:
- Build all dependencies (POCO, cppkafka, valijson) in a Debian Bookworm container
- Store dependency builds in `.build-deps/` (gitignored, cached for faster rebuilds)
- Build the OWGW binary and place it in `./cmake-build/owgw`
- Work entirely within the repository - no system-wide installation needed
**Requirements:**
- Docker installed and running
- Git
**Clean rebuild (if needed):**
```bash
rm -rf .build-deps/build-cache
./build-ucentralgw.sh
```
## Manual Build from Source
If you prefer to build manually without Docker, you will need to install the following dependencies:
- cmake
- boost
- POCO 1.10.1 or later
- a C++17 compiler
- openssl
- libpq-dev (PortgreSQL development libraries)
- libpq-dev (PostgreSQL development libraries)
- mysql-client (MySQL client)
- librdkafka
- cppkafka
@@ -20,7 +45,7 @@ These instructions have proven to work on Ubuntu 20.4.
```bash
sudo apt install git cmake g++ libssl-dev libmariadb-dev \
libpq-dev libaprutil1-dev apache2-dev libboost-all-dev \
librdkafka-dev // default-libmysqlclient-dev \
librdkafka-dev default-libmysqlclient-dev \
nlohmann-json-dev
git clone https://github.com/Telecominfraproject/wlan-cloud-lib-poco --branch poco-tip-v1 poco

View File

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

View File

@@ -1,5 +1,5 @@
ARG DEBIAN_VERSION=11.5-slim
ARG POCO_VERSION=poco-tip-v2
ARG DEBIAN_VERSION=bookworm
ARG POCO_VERSION=poco-tip-v4-tag
ARG CPPKAFKA_VERSION=tip-v1
ARG VALIJASON_VERSION=tip-v1.0.2
ARG APP_NAME=owgw
@@ -100,7 +100,7 @@ RUN mkdir -p $APP_ROOT $APP_CONFIG && \
RUN apt-get update && apt-get install --no-install-recommends -y \
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 test_scripts/curl/cli /cli

243
build-ucentralgw.sh Executable file
View File

@@ -0,0 +1,243 @@
#!/bin/bash
# Script to build wlan-cloud-ucentralgw project in a Debian Bookworm container
# Dependencies are built in a temporary folder within the repo
set -e
# Configuration
POCO_VERSION="poco-tip-v4-tag"
CPPKAFKA_VERSION="tip-v1"
VALIJSON_VERSION="tip-v1.0.2"
DEBIAN_VERSION="bookworm"
TEMP_BUILD_DIR=".build-deps"
OUTPUT_DIR="./cmake-build"
BINARY_NAME="owgw"
CONTAINER_NAME="ucentralgw-builder-$$"
IMAGE_NAME="ucentralgw-build-env:${DEBIAN_VERSION}"
# Colors for output
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
RED='\033[0;31m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
echo -e "${GREEN}=== Building wlan-cloud-ucentralgw in Debian ${DEBIAN_VERSION} container ===${NC}"
# Check if Docker is available
if ! command -v docker >/dev/null 2>&1; then
echo -e "${RED}Error: Docker is not installed or not in PATH${NC}"
exit 1
fi
# Create temporary build directory structure
echo -e "${YELLOW}Creating temporary build directory: ${TEMP_BUILD_DIR}${NC}"
mkdir -p "${TEMP_BUILD_DIR}"
mkdir -p "${OUTPUT_DIR}"
# Create Dockerfile for build environment
echo -e "${YELLOW}Creating build environment Dockerfile...${NC}"
cat > "${TEMP_BUILD_DIR}/Dockerfile.build" <<EOF
FROM debian:${DEBIAN_VERSION}
# Install build dependencies
RUN apt-get update && apt-get install --no-install-recommends -y \\
make cmake g++ git \\
libpq-dev libmariadb-dev libmariadbclient-dev-compat \\
librdkafka-dev libboost-all-dev libssl-dev \\
zlib1g-dev nlohmann-json3-dev ca-certificates libfmt-dev
# Set working directory
WORKDIR /build
# Copy build script into container
COPY build-in-container.sh /build/
RUN chmod +x /build/build-in-container.sh
# Entry point
ENTRYPOINT ["/build/build-in-container.sh"]
EOF
# Create the build script that runs inside the container
echo -e "${YELLOW}Creating in-container build script...${NC}"
cat > "${TEMP_BUILD_DIR}/build-in-container.sh" <<'EOFSCRIPT'
#!/bin/bash
set -e
POCO_VERSION="poco-tip-v4-tag"
CPPKAFKA_VERSION="tip-v1"
VALIJSON_VERSION="tip-v1.0.2"
BUILD_DIR="/build/deps"
INSTALL_PREFIX="/build/install"
REPO_DIR="/repo"
OUTPUT_DIR="/repo/cmake-build"
# Number of parallel jobs
JOBS=$(nproc 2>/dev/null || echo 4)
echo "=== Building dependencies in container ==="
echo "Using ${JOBS} parallel jobs"
# Function to build a dependency
build_dependency() {
local name=$1
local repo=$2
local branch=$3
local build_dir="${BUILD_DIR}/${name}"
echo "Building ${name}..."
if [ ! -d "${build_dir}" ]; then
echo "Cloning ${name} from ${repo} (branch: ${branch})"
git clone --depth 1 --branch "${branch}" "${repo}" "${build_dir}"
fi
mkdir -p "${build_dir}/cmake-build"
cd "${build_dir}/cmake-build"
echo "Configuring ${name}..."
if [ "${name}" = "poco" ]; then
# POCO needs special configuration to enable all required components
cmake -DCMAKE_INSTALL_PREFIX="${INSTALL_PREFIX}" \
-DENABLE_JSON=ON \
-DENABLE_CRYPTO=ON \
-DENABLE_JWT=ON \
-DENABLE_NET=ON \
-DENABLE_NETSSL=ON \
-DENABLE_UTIL=ON \
-DENABLE_DATA=ON \
-DENABLE_DATA_SQLITE=ON \
-DENABLE_DATA_POSTGRESQL=ON \
-DENABLE_DATA_MYSQL=ON \
..
else
cmake -DCMAKE_INSTALL_PREFIX="${INSTALL_PREFIX}" ..
fi
echo "Building ${name}..."
cmake --build . --config Release -j${JOBS}
echo "Installing ${name}..."
cmake --build . --target install
# For POCO, create symlinks if needed and show what was installed
if [ "${name}" = "poco" ]; then
echo "POCO libraries installed:"
find "${INSTALL_PREFIX}/lib" -name "libPoco*" -type f || true
# Run ldconfig to update library cache
cd "${INSTALL_PREFIX}/lib"
# Create missing symlinks if needed
for lib in libPocoJSON.so libPocoCrypto.so libPocoNet.so libPocoNetSSL.so libPocoUtil.so libPocoFoundation.so libPocoData.so libPocoDataSQLite.so libPocoDataPostgreSQL.so libPocoDataMySQL.so libPocoJWT.so; do
if [ ! -e "${lib}" ]; then
# Find versioned library and create symlink
versioned=$(find . -maxdepth 1 -name "${lib}.*" | head -n 1)
if [ -n "$versioned" ]; then
echo "Creating symlink: ${lib} -> ${versioned}"
ln -sf "$(basename ${versioned})" "${lib}"
fi
fi
done
fi
echo "${name} built successfully"
}
# Create directories
mkdir -p "${BUILD_DIR}"
mkdir -p "${INSTALL_PREFIX}"
# Build POCO
build_dependency \
"poco" \
"https://github.com/Telecominfraproject/wlan-cloud-lib-poco" \
"${POCO_VERSION}"
# Build cppkafka
build_dependency \
"cppkafka" \
"https://github.com/Telecominfraproject/wlan-cloud-lib-cppkafka" \
"${CPPKAFKA_VERSION}"
# Build valijson
build_dependency \
"valijson" \
"https://github.com/Telecominfraproject/wlan-cloud-lib-valijson" \
"${VALIJSON_VERSION}"
# Build the main application
echo "=== Building owgw ==="
cd "${REPO_DIR}"
# Configure git to trust the repository directory (needed for mounted volumes)
git config --global --add safe.directory /repo
# Clean the build directory to avoid CMake cache conflicts
if [ -d "${OUTPUT_DIR}" ]; then
echo "Cleaning existing build directory..."
rm -rf "${OUTPUT_DIR}"
fi
mkdir -p "${OUTPUT_DIR}"
cd "${OUTPUT_DIR}"
echo "Configuring owgw..."
export CMAKE_PREFIX_PATH="${INSTALL_PREFIX}"
export PKG_CONFIG_PATH="${INSTALL_PREFIX}/lib/pkgconfig:${PKG_CONFIG_PATH}"
export LD_LIBRARY_PATH="${INSTALL_PREFIX}/lib:${LD_LIBRARY_PATH}"
# Debug: show what libraries are available
echo "Installed libraries in ${INSTALL_PREFIX}/lib:"
ls -la "${INSTALL_PREFIX}/lib" || true
cmake \
-DCMAKE_PREFIX_PATH="${INSTALL_PREFIX}" \
-DCMAKE_LIBRARY_PATH="${INSTALL_PREFIX}/lib" \
-DPoco_DIR="${INSTALL_PREFIX}/lib/cmake/Poco" \
-DCppKafka_DIR="${INSTALL_PREFIX}/lib/cmake/CppKafka" \
..
echo "Building owgw..."
echo "Library search paths:"
echo " LD_LIBRARY_PATH=${LD_LIBRARY_PATH}"
echo " CMAKE_PREFIX_PATH=${CMAKE_PREFIX_PATH}"
# Build with explicit library path
LIBRARY_PATH="${INSTALL_PREFIX}/lib:${LIBRARY_PATH}" \
cmake --build . --config Release -j${JOBS}
echo "=== Build completed successfully ==="
EOFSCRIPT
# Build the Docker image
echo -e "${YELLOW}Building Docker image (this may take a while on first run)...${NC}"
docker build \
-t "${IMAGE_NAME}" \
-f "${TEMP_BUILD_DIR}/Dockerfile.build" \
"${TEMP_BUILD_DIR}"
# Run the build in the container
echo -e "${YELLOW}Running build in container...${NC}"
docker run --rm \
--name "${CONTAINER_NAME}" \
-v "$(pwd):/repo" \
-v "$(pwd)/${TEMP_BUILD_DIR}/build-cache:/build/deps" \
"${IMAGE_NAME}"
echo -e "${GREEN}=== Build completed successfully! ===${NC}"
echo -e "${GREEN}Binary location: ${OUTPUT_DIR}/${BINARY_NAME}${NC}"
echo ""
echo "To run the binary, you'll need the dependencies installed or use the container."
echo ""
echo "To clean up build dependencies:"
echo -e "${YELLOW} rm -rf ${TEMP_BUILD_DIR}${NC}"
echo ""
echo "To remove the Docker image:"
echo -e "${YELLOW} docker rmi ${IMAGE_NAME}${NC}"
echo ""
echo "Note: The temporary build directory (${TEMP_BUILD_DIR}) is excluded from git."
exit 0

View File

@@ -14,6 +14,7 @@ if [[ "$TEMPLATE_CONFIG" = 'true' ]]; then
WEBSOCKET_HOST_CAS=${WEBSOCKET_HOST_CAS:-"\${APP_ROOT}/certs/cas"} \
WEBSOCKET_HOST_PORT=${WEBSOCKET_HOST_PORT:-"15002"} \
WEBSOCKET_HOST_KEY_PASSWORD=${WEBSOCKET_HOST_KEY_PASSWORD:-"mypassword"} \
WEBSOCKET_HOST_SECURITY=${WEBSOCKET_HOST_SECURITY:-"strict"} \
RESTAPI_HOST_ROOTCA=${RESTAPI_HOST_ROOTCA:-"\${APP_ROOT}/certs/restapi-ca.pem"} \
RESTAPI_HOST_PORT=${RESTAPI_HOST_PORT:-"16002"} \
RESTAPI_HOST_CERT=${RESTAPI_HOST_CERT:-"\${APP_ROOT}/certs/restapi-cert.pem"} \
@@ -32,6 +33,7 @@ if [[ "$TEMPLATE_CONFIG" = 'true' ]]; then
FILEUPLOADER_HOST_KEY_PASSWORD=${FILEUPLOADER_HOST_KEY_PASSWORD:-"mypassword"} \
FILEUPLOADER_PATH=${FILEUPLOADER_PATH:-"\${APP_ROOT}/uploads"} \
FILEUPLOADER_URI=${FILEUPLOADER_URI:-"https://localhost:16003"} \
FILEUPLOADER_MAXSIZE=${FILEUPLOADER_MAXSIZE:-"10000"} \
SERVICE_KEY=${SERVICE_KEY:-"\${APP_ROOT}/certs/restapi-key.pem"} \
SERVICE_KEY_PASSWORD=${SERVICE_KEY_PASSWORD:-"mypassword"} \
SYSTEM_DATA=${SYSTEM_DATA:-"\${APP_ROOT}/data"} \
@@ -76,6 +78,7 @@ if [[ "$TEMPLATE_CONFIG" = 'true' ]]; then
CERTIFICATES_ALLOWMISMATCH=${CERTIFICATES_ALLOWMISMATCH:-"false"} \
IPINFO_DEFAULT_COUNTRY=${IPINFO_DEFAULT_COUNTRY:-"US"} \
DEVICE_SESSION_TIMEOUT=${DEVICE_SESSION_TIMEOUT:-"600"} \
LOGGING_LEVEL=${LOGGING_LEVEL:-"information"} \
envsubst < /"${APP_NAME}".properties.tmpl > "${APP_CONFIG}"/"${APP_NAME}".properties
fi

View File

@@ -1576,6 +1576,15 @@ components:
format: base64
description: This is a base64 encoded string of the certificate bundle (the current bundle .tar.gz file from the PKI portal)
ReenrollRequest:
type: object
properties:
serialNumber:
type: string
when:
type: integer
format: int64
PowerCycleRequest:
type: object
properties:
@@ -1600,6 +1609,74 @@ components:
maximum: 60000
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:
/devices:
get:
@@ -3056,6 +3133,32 @@ paths:
404:
$ref: '#/components/responses/NotFound'
/device/{serialNumber}/reenroll:
post:
tags:
- Commands
summary: Reenroll operational certificate for the device.
operationId: reenrollCertificate
parameters:
- in: path
name: serialNumber
schema:
type: string
required: true
requestBody:
description: Reenroll operational certificate for the device
content:
application/json:
schema:
$ref: '#/components/schemas/ReenrollRequest'
responses:
200:
$ref: '#/components/responses/Success'
403:
$ref: '#/components/responses/Unauthorized'
404:
$ref: '#/components/responses/NotFound'
/device/{serialNumber}/powercycle:
post:
tags:
@@ -3084,6 +3187,98 @@ paths:
404:
$ref: '#/components/responses/NotFound'
/device/{serialNumber}/package:
get:
tags:
- Commands
summary: Get package installed on the remote device.
operationId: getDevicePackages
parameters:
- in: path
name: serialNumber
schema:
type: string
required: true
- 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:
get:
tags:

View File

@@ -12,7 +12,7 @@ ucentral.websocket.host.0.clientcas = ${WEBSOCKET_HOST_CLIENTCAS}
ucentral.websocket.host.0.cas = ${WEBSOCKET_HOST_CAS}
ucentral.websocket.host.0.address = *
ucentral.websocket.host.0.port = ${WEBSOCKET_HOST_PORT}
ucentral.websocket.host.0.security = strict
ucentral.websocket.host.0.security = ${WEBSOCKET_HOST_SECURITY}
ucentral.websocket.host.0.key.password = ${WEBSOCKET_HOST_KEY_PASSWORD}
ucentral.websocket.maxreactors = 20
@@ -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.password = ${FILEUPLOADER_HOST_KEY_PASSWORD}
openwifi.fileuploader.path = ${FILEUPLOADER_PATH}
openwifi.fileuploader.maxsize = 10000
# maxsize in KB
openwifi.fileuploader.maxsize = ${FILEUPLOADER_MAXSIZE}
openwifi.fileuploader.uri = ${FILEUPLOADER_URI}
#
@@ -182,4 +183,4 @@ archiver.db.3.keep = 7
########################################################################
logging.type = console
logging.path = $OWGW_ROOT/logs
logging.level = information
logging.level = ${LOGGING_LEVEL}

View File

@@ -7,6 +7,7 @@
#include <Poco/Net/Context.h>
#include <Poco/Net/HTTPServerRequestImpl.h>
#include <Poco/Net/HTTPServerResponseImpl.h>
#include <Poco/JSON/JSONException.h>
#include <Poco/Net/NetException.h>
#include <Poco/Net/SSLException.h>
#include <Poco/Net/SecureStreamSocketImpl.h>
@@ -39,7 +40,7 @@ namespace OpenWifi {
Poco::Net::HTTPServerResponse &response,
uint64_t session_id, Poco::Logger &L,
std::pair<std::shared_ptr<Poco::Net::SocketReactor>, std::shared_ptr<LockedDbSession>> R)
: Logger_(L) {
: Logger_(L), IncomingFrame_(0) {
Reactor_ = R.first;
DbSession_ = R.second;
@@ -54,6 +55,7 @@ namespace OpenWifi {
WS_->setNoDelay(false);
WS_->setKeepAlive(true);
WS_->setBlocking(false);
IncomingFrame_.resize(0);
uuid_ = MicroServiceRandom(std::numeric_limits<std::uint64_t>::max()-1);
AP_WS_Server()->IncrementConnectionCount();
@@ -600,36 +602,95 @@ namespace OpenWifi {
EndConnection();
}
void AP_WS_Connection::ProcessIncomingFrame() {
Poco::Buffer<char> IncomingFrame(0);
void AP_WS_Connection::ProcessWSFinalPayload() {
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;
int flags = 0;
int IncomingSize = 0;
bool KillConnection=false;
try {
int Op, flags;
auto IncomingSize = WS_->receiveFrame(IncomingFrame, flags);
IncomingSize = WS_->receiveFrame(CurrentFrame, flags);
int Op;
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_,
fmt::format("DISCONNECT({}): device has disconnected. Session={}",
CId_, State_.sessionId));
return EndConnection();
}
IncomingFrame.append(0);
State_.RX += IncomingSize;
AP_WS_Server()->AddRX(IncomingSize);
if (IncomingSize > 0) {
State_.RX += IncomingSize;
AP_WS_Server()->AddRX(IncomingSize);
IncomingFrame_.append(CurrentFrame);
}
State_.MessageCount++;
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) {
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,
(int)Poco::Net::WebSocket::FRAME_OP_PONG |
(int)Poco::Net::WebSocket::FRAME_FLAG_FIN);
(int)Poco::Net::WebSocket::FRAME_FLAG_FIN);
if (KafkaManager()->Enabled()) {
Poco::JSON::Object PingObject;
@@ -643,49 +704,32 @@ namespace OpenWifi {
PingDetails.set("locale", State_.locale);
PingObject.set(uCentralProtocol::PING, PingDetails);
poco_trace(Logger_,fmt::format("Sending PING for {}", SerialNumber_));
KafkaManager()->PostMessage(KafkaTopics::CONNECTION, SerialNumber_,PingObject);
KafkaManager()->PostMessage(KafkaTopics::CONNECTION, SerialNumber_,
PingObject);
}
return;
} break;
case Poco::Net::WebSocket::FRAME_OP_PONG: {
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;
case Poco::Net::WebSocket::FRAME_OP_TEXT: {
poco_trace(Logger_,
fmt::format("FRAME({}): Frame received (length={}, flags={}). Msg={}",
CId_, IncomingSize, flags, IncomingFrame.begin()));
Poco::JSON::Parser parser;
auto ParsedMessage = parser.parse(IncomingFrame.begin());
auto IncomingJSON = ParsedMessage.extract<Poco::JSON::Object::Ptr>();
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_++;
}
fmt::format("TEXT({}): Frame received (len={}, flags={}). Msg={}",
CId_, IncomingSize, flags,
CurrentFrame.begin() == nullptr ? "" : CurrentFrame.begin()));
} break;
case Poco::Net::WebSocket::FRAME_OP_CLOSE: {
@@ -701,25 +745,31 @@ namespace OpenWifi {
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) {
poco_warning(Logger_,
fmt::format("ConnectionResetException({}): Text:{} Payload:{} Session:{}",
CId_, E.displayText(),
IncomingFrame.begin() == nullptr ? "" : IncomingFrame.begin(),
CurrentFrame.begin() == nullptr ? "" : CurrentFrame.begin(),
State_.sessionId));
KillConnection=true;
} catch (const Poco::JSON::JSONException &E) {
poco_warning(Logger_,
fmt::format("JSONException({}): Text:{} Payload:{} Session:{}", CId_,
E.displayText(),
IncomingFrame.begin() == nullptr ? "" : IncomingFrame.begin(),
CurrentFrame.begin() == nullptr ? "" : CurrentFrame.begin(),
State_.sessionId));
KillConnection=true;
} catch (const Poco::Net::WebSocketException &E) {
poco_warning(Logger_,
fmt::format("WebSocketException({}): Text:{} Payload:{} Session:{}", CId_,
E.displayText(),
IncomingFrame.begin() == nullptr ? "" : IncomingFrame.begin(),
CurrentFrame.begin() == nullptr ? "" : CurrentFrame.begin(),
State_.sessionId));
KillConnection=true;
} catch (const Poco::Net::SSLConnectionUnexpectedlyClosedException &E) {
@@ -728,42 +778,42 @@ namespace OpenWifi {
fmt::format(
"SSLConnectionUnexpectedlyClosedException({}): Text:{} Payload:{} Session:{}",
CId_, E.displayText(),
IncomingFrame.begin() == nullptr ? "" : IncomingFrame.begin(),
CurrentFrame.begin() == nullptr ? "" : CurrentFrame.begin(),
State_.sessionId));
KillConnection=true;
} catch (const Poco::Net::SSLException &E) {
poco_warning(Logger_,
fmt::format("SSLException({}): Text:{} Payload:{} Session:{}", CId_,
E.displayText(),
IncomingFrame.begin() == nullptr ? "" : IncomingFrame.begin(),
CurrentFrame.begin() == nullptr ? "" : CurrentFrame.begin(),
State_.sessionId));
KillConnection=true;
} catch (const Poco::Net::NetException &E) {
poco_warning(Logger_,
fmt::format("NetException({}): Text:{} Payload:{} Session:{}", CId_,
E.displayText(),
IncomingFrame.begin() == nullptr ? "" : IncomingFrame.begin(),
CurrentFrame.begin() == nullptr ? "" : CurrentFrame.begin(),
State_.sessionId));
KillConnection=true;
} catch (const Poco::IOException &E) {
poco_warning(Logger_,
fmt::format("IOException({}): Text:{} Payload:{} Session:{}", CId_,
E.displayText(),
IncomingFrame.begin() == nullptr ? "" : IncomingFrame.begin(),
CurrentFrame.begin() == nullptr ? "" : CurrentFrame.begin(),
State_.sessionId));
KillConnection=true;
} catch (const Poco::Exception &E) {
poco_warning(Logger_,
fmt::format("Exception({}): Text:{} Payload:{} Session:{}", CId_,
E.displayText(),
IncomingFrame.begin() == nullptr ? "" : IncomingFrame.begin(),
CurrentFrame.begin() == nullptr ? "" : CurrentFrame.begin(),
State_.sessionId));
KillConnection=true;
} catch (const std::exception &E) {
poco_warning(Logger_,
fmt::format("std::exception({}): Text:{} Payload:{} Session:{}", CId_,
E.what(),
IncomingFrame.begin() == nullptr ? "" : IncomingFrame.begin(),
CurrentFrame.begin() == nullptr ? "" : CurrentFrame.begin(),
State_.sessionId));
KillConnection=true;
} catch (...) {
@@ -776,7 +826,9 @@ namespace OpenWifi {
if (!KillConnection && Errors_ < 10)
return;
poco_warning(Logger_, fmt::format("DISCONNECTING({}): ConnectionException: {} Errors: {}", CId_, KillConnection, Errors_ ));
poco_warning(Logger_,
fmt::format("DISCONNECTING({}): ConnectionException: {} Errors: {}",
CId_, KillConnection, Errors_ ));
EndConnection();
}
@@ -921,4 +973,4 @@ namespace OpenWifi {
}
}
} // namespace OpenWifi
} // namespace OpenWifi

View File

@@ -22,7 +22,7 @@
namespace OpenWifi {
class AP_WS_Connection {
static constexpr int BufSize = 256000;
static constexpr int BufSize = 512000;
public:
explicit AP_WS_Connection(Poco::Net::HTTPServerRequest &request,
@@ -33,6 +33,7 @@ namespace OpenWifi {
void EndConnection();
void ProcessJSONRPCEvent(Poco::JSON::Object::Ptr &Doc);
void ProcessJSONRPCResult(Poco::JSON::Object::Ptr Doc);
void ProcessWSFinalPayload();
void ProcessIncomingFrame();
void ProcessIncomingRadiusData(const Poco::JSON::Object::Ptr &Doc);
@@ -145,6 +146,7 @@ namespace OpenWifi {
std::uint64_t uuid_=0;
bool Simulated_=false;
std::atomic_uint64_t LastContact_=0;
Poco::Buffer<char> IncomingFrame_;
static inline std::atomic_uint64_t ConcurrentStartingDevices_ = 0;
@@ -175,4 +177,4 @@ namespace OpenWifi {
};
} // namespace OpenWifi
} // namespace OpenWifi

View File

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

View File

@@ -120,7 +120,6 @@ namespace OpenWifi {
P.verificationDepth = 9;
P.loadDefaultCAs = Svr.RootCA().empty();
P.cipherList = "ALL:!ADH:!LOW:!EXP:!MD5:@STRENGTH";
P.dhUse2048Bits = true;
P.caLocation = Svr.Cas();
auto Context = Poco::AutoPtr<Poco::Net::Context>(
@@ -795,4 +794,4 @@ namespace OpenWifi {
return false;
}
} // namespace OpenWifi
} // namespace OpenWifi

View File

@@ -315,4 +315,4 @@ namespace OpenWifi {
poco_notice(Logger(), "Stopped...");
}
} // namespace OpenWifi
} // namespace OpenWifi

View File

@@ -91,6 +91,31 @@ namespace OpenWifi {
TransactionId_, UUID, RPC, Poco::Thread::current()->id()));
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 &param : 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:
return BadRequest(RESTAPI::Errors::InvalidCommand);
}
@@ -128,6 +153,21 @@ namespace OpenWifi {
return DeleteChecks();
case APCommands::Commands::statistics:
return DeleteStatistics();
case APCommands::Commands::package: {
GWObjects::DeviceRestrictions Restrictions;
if (!AP_WS_Server()->Connected(SerialNumberInt_, Restrictions)) {
CallCanceled(Command_.c_str(), RESTAPI::Errors::DeviceNotConnected);
return BadRequest(RESTAPI::Errors::DeviceNotConnected);
}
auto UUID = MicroServiceCreateUUID();
auto RPC = CommandManager()->Next_RPC_ID();
poco_debug(
Logger_,
fmt::format(
"Command RTTY TID={} can proceed. Identified as {} and RPCID as {}. thr_id={}",
TransactionId_, UUID, RPC, Poco::Thread::current()->id()));
return DeletePackages(UUID, RPC, 300000ms, Restrictions);
}
default:
return BadRequest(RESTAPI::Errors::InvalidCommand);
}
@@ -171,7 +211,7 @@ namespace OpenWifi {
{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() {
@@ -409,6 +449,210 @@ namespace OpenWifi {
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(
const std::string &CMD_UUID, uint64_t CMD_RPC, std::chrono::milliseconds timeout,
[[maybe_unused]] const GWObjects::DeviceRestrictions &Restrictions) {

View File

@@ -33,6 +33,13 @@ namespace OpenWifi {
void GetStatus();
void GetChecks();
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);
@@ -76,6 +83,8 @@ namespace OpenWifi {
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() {
return std::list<std::string>{"/api/v1/device/{serialNumber}/{command}"};

View File

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

View File

@@ -552,6 +552,51 @@ namespace OpenWifi::GWObjects {
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);
};
} // namespace OpenWifi::GWObjects

View File

@@ -120,14 +120,16 @@ namespace OpenWifi {
Poco::Buffer<char> IncomingFrame(0);
try {
int Op, flags;
int IncomingSize;
int Op, flags, IncomingSize;
IncomingSize = WS_->receiveFrame(IncomingFrame, flags);
Op = flags & Poco::Net::WebSocket::FRAME_OP_BITMASK;
if (IncomingSize == 0 && flags == 0 && Op == 0) {
poco_information(
Logger(),
if (IncomingSize == -1) {
poco_trace(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_));
MustDisconnect = true;
} else {
@@ -136,12 +138,14 @@ namespace OpenWifi {
fmt::format("TELEMETRY-WS-PING({}): received. PONG sent back.", CId_));
WS_->sendFrame("", 0,
(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) {
poco_information(
Logger(),
poco_information(Logger(),
fmt::format("TELEMETRY-DISCONNECT({}): device wants to disconnect.", CId_));
MustDisconnect = true;
} else if (Op == Poco::Net::WebSocket::FRAME_OP_CONT) {
poco_information(Logger(),
fmt::format("TELEMETRY-CONT({}): rx {} bytes.", CId_, IncomingSize));
}
}
} catch (...) {
@@ -154,4 +158,4 @@ namespace OpenWifi {
SendTelemetryShutdown();
}
} // namespace OpenWifi
} // namespace OpenWifi

View File

@@ -276,7 +276,8 @@ static std::string DefaultAPSchema = R"foo(
"sae-mixed",
"wpa3",
"wpa3-192",
"wpa3-mixed"
"wpa3-mixed",
"mpsk-radius"
],
"examples": [
"psk2"
@@ -376,21 +377,18 @@ static std::string DefaultAPSchema = R"foo(
"properties": {
"port-mirror": {
"description": "Enable mirror of traffic from multiple minotor ports to a single analysis port.",
"type": "array",
"items": {
"type": "object",
"properties": {
"monitor-ports": {
"description": "The list of ports that we want to mirror.",
"type": "array",
"items": {
"type": "string"
}
},
"analysis-port": {
"description": "The port that mirror'ed packets should be sent to.",
"type": "object",
"properties": {
"monitor-ports": {
"description": "The list of ports that we want to mirror.",
"type": "array",
"items": {
"type": "string"
}
},
"analysis-port": {
"description": "The port that mirror'ed packets should be sent to.",
"type": "string"
}
}
},
@@ -552,7 +550,8 @@ static std::string DefaultAPSchema = R"foo(
"5G",
"5G-lower",
"5G-upper",
"6G"
"6G",
"HaLow"
]
},
"bandwidth": {
@@ -569,7 +568,7 @@ static std::string DefaultAPSchema = R"foo(
"oneOf": [
{
"type": "integer",
"maximum": 196,
"maximum": 233,
"minimum": 1
},
{
@@ -583,7 +582,7 @@ static std::string DefaultAPSchema = R"foo(
"type": "array",
"items": {
"type": "integer",
"maximum": 196,
"maximum": 233,
"minimum": 1
}
},
@@ -625,6 +624,10 @@ static std::string DefaultAPSchema = R"foo(
],
"default": 80
},
"enable": {
"description": "Specifies radio is enabled/disabled.",
"type": "boolean"
},
"require-mode": {
"description": "Stations that do no fulfill these HT modes will be rejected.",
"type": "string",
@@ -2309,7 +2312,8 @@ static std::string DefaultAPSchema = R"foo(
"5G",
"5G-lower",
"5G-upper",
"6G"
"6G",
"HaLow"
]
}
},
@@ -2413,6 +2417,11 @@ static std::string DefaultAPSchema = R"foo(
"encryption": {
"$ref": "#/$defs/interface.ssid.encryption"
},
"enhanced-mpsk": {
"description": "Optionally disable MPSK",
"type": "boolean",
"default": true
},
"multi-psk": {
"anyOf": [
{
@@ -3742,7 +3751,8 @@ static std::string DefaultAPSchema = R"foo(
"5G",
"5G-lower",
"5G-upper",
"6G"
"6G",
"HaLow"
]
}
},
@@ -3777,7 +3787,7 @@ static std::string DefaultAPSchema = R"foo(
"enum": [
"polled",
"final",
"raw-data"
"raw"
],
"default": "final"
},
@@ -4443,7 +4453,8 @@ static std::string DefaultSWITCHSchema = R"foo(
"sae-mixed",
"wpa3",
"wpa3-192",
"wpa3-mixed"
"wpa3-mixed",
"mpsk-radius"
],
"examples": [
"psk2"
@@ -4658,21 +4669,18 @@ static std::string DefaultSWITCHSchema = R"foo(
"properties": {
"port-mirror": {
"description": "Enable mirror of traffic from multiple minotor ports to a single analysis port.",
"type": "array",
"items": {
"type": "object",
"properties": {
"monitor-ports": {
"description": "The list of ports that we want to mirror.",
"type": "array",
"items": {
"type": "string"
}
},
"analysis-port": {
"description": "The port that mirror'ed packets should be sent to.",
"type": "object",
"properties": {
"monitor-ports": {
"description": "The list of ports that we want to mirror.",
"type": "array",
"items": {
"type": "string"
}
},
"analysis-port": {
"description": "The port that mirror'ed packets should be sent to.",
"type": "string"
}
}
},
@@ -4892,7 +4900,8 @@ static std::string DefaultSWITCHSchema = R"foo(
"5G",
"5G-lower",
"5G-upper",
"6G"
"6G",
"HaLow"
]
},
"bandwidth": {
@@ -4907,7 +4916,7 @@ static std::string DefaultSWITCHSchema = R"foo(
"oneOf": [
{
"type": "integer",
"maximum": 196,
"maximum": 233,
"minimum": 1
},
{
@@ -4920,7 +4929,7 @@ static std::string DefaultSWITCHSchema = R"foo(
"type": "array",
"items": {
"type": "integer",
"maximum": 196,
"maximum": 233,
"minimum": 1
}
},
@@ -4958,6 +4967,10 @@ static std::string DefaultSWITCHSchema = R"foo(
],
"default": 80
},
"enable": {
"description": "Specifies radio is enabled/disabled.",
"type": "boolean"
},
"require-mode": {
"type": "string",
"enum": [
@@ -6530,7 +6543,8 @@ static std::string DefaultSWITCHSchema = R"foo(
"5G",
"5G-lower",
"5G-upper",
"6G"
"6G",
"HaLow"
]
}
},
@@ -6620,6 +6634,11 @@ static std::string DefaultSWITCHSchema = R"foo(
"encryption": {
"$ref": "#/$defs/interface.ssid.encryption"
},
"enhanced-mpsk": {
"description": "Optionally disable MPSK",
"type": "boolean",
"default": true
},
"multi-psk": {
"anyOf": [
{
@@ -7753,7 +7772,8 @@ static std::string DefaultSWITCHSchema = R"foo(
"5G",
"5G-lower",
"5G-upper",
"6G"
"6G",
"HaLow"
]
}
},

View File

@@ -845,4 +845,4 @@ namespace OpenWifi {
}
}
} // namespace OpenWifi
} // namespace OpenWifi

View File

@@ -14,6 +14,7 @@
#include <iostream>
#include <random>
#include <vector>
#include <optional>
// 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/PropertyFileConfiguration.h"
#include "Poco/Util/ServerApplication.h"
#include "Poco/ThreadPool.h"
#include "framework/OpenWifiTypes.h"

View File

@@ -5,6 +5,7 @@
#pragma once
#include <string>
#include <optional>
#include "framework/OpenWifiTypes.h"

View File

@@ -35,7 +35,6 @@ namespace OpenWifi {
P.verificationDepth = 9;
P.loadDefaultCAs = root_ca_.empty();
P.cipherList = "ALL:!ADH:!LOW:!EXP:!MD5:@STRENGTH";
P.dhUse2048Bits = true;
P.caLocation = cas_;
// P.securityLevel =
@@ -344,4 +343,4 @@ namespace OpenWifi {
}
}
} // namespace OpenWifi
} // namespace OpenWifi

View File

@@ -210,10 +210,16 @@ namespace OpenWifi {
n = Client->second->WS_->receiveFrame(IncomingFrame, flags);
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) {
poco_debug(Logger(),
fmt::format("CLOSE({}): {} UI Client is closing WS connection.",
Client->second->Id_, Client->second->UserName_));
fmt::format("CLOSE({}): {} UI Client is closing WS connection.",
Client->second->Id_, Client->second->UserName_));
return EndConnection(Client);
}
@@ -221,7 +227,7 @@ namespace OpenWifi {
case Poco::Net::WebSocket::FRAME_OP_PING: {
Client->second->WS_->sendFrame("", 0,
(int)Poco::Net::WebSocket::FRAME_OP_PONG |
(int)Poco::Net::WebSocket::FRAME_FLAG_FIN);
(int)Poco::Net::WebSocket::FRAME_FLAG_FIN);
} break;
case Poco::Net::WebSocket::FRAME_OP_PONG: {
} break;
@@ -231,6 +237,11 @@ namespace OpenWifi {
Client->second->Id_, Client->second->UserName_));
return EndConnection(Client);
} 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: {
constexpr const char *DropMessagesCommand = "drop-notifications";
IncomingFrame.append(0);
@@ -319,4 +330,4 @@ namespace OpenWifi {
}
}
} // namespace OpenWifi
} // namespace OpenWifi

View File

@@ -433,6 +433,10 @@ namespace OpenWifi::RESTAPI::Errors {
static const struct msg InvalidRRMAction { 1192, "Invalid RRM Action." };
static const struct msg InvalidPackageURL { 1193, "Invalid URL, must start with http:// or https://." };
static const struct msg FailedToDownload { 1194, "Failed to download package." };
static const struct msg FailedToDecompress { 1195, "Failed to decompress package data."};
static const struct msg SimulationDoesNotExist {
7000, "Simulation Instance ID does not exist."
};
@@ -550,6 +554,10 @@ namespace OpenWifi::RESTAPI::Protocol {
static const char *DEBUG = "debug";
static const char *SCRIPT = "script";
static const char *TIMEOUT = "timeout";
static const char *PACKAGE = "package";
static const char *PACKAGES = "packages";
static const char *PACKAGEINST = "packageInstall";
static const char *PACKAGEDEL = "packageDelete";
static const char *NEWPASSWORD = "newPassword";
static const char *USERS = "users";
@@ -669,6 +677,9 @@ namespace OpenWifi::uCentralProtocol {
static const char *SIGNATURE = "signature";
static const char *INFO = "info";
static const char *DATE = "date";
static const char *PACKAGE = "package";
static const char *PACKAGES = "packages";
static const char *CATEGORY = "category";
static const char *SERIALNUMBER = "serialNumber";
static const char *COMPATIBLE = "compatible";
@@ -701,7 +712,7 @@ namespace OpenWifi::uCentralProtocol {
static const char *CABLEDIAGNOSTICS = "cable-diagnostics";
static const char *REENROLL = "reenroll";
static const char *OPERATION = "op";
} // namespace OpenWifi::uCentralProtocol
namespace OpenWifi::uCentralProtocol::Events {
@@ -736,7 +747,7 @@ namespace OpenWifi::uCentralProtocol::Events {
ET_EVENT,
ET_WIFISCAN,
ET_ALARM,
ET_REBOOTLOG
ET_REBOOTLOG,
};
inline EVENT_MSG EventFromString(const std::string &Method) {
@@ -801,6 +812,7 @@ namespace OpenWifi::APCommands {
fixedconfig,
cablediagnostics,
reenroll,
package,
unknown
};
@@ -817,7 +829,7 @@ namespace OpenWifi::APCommands {
RESTAPI::Protocol::RRM, RESTAPI::Protocol::CERTUPDATE,
RESTAPI::Protocol::TRANSFER, RESTAPI::Protocol::POWERCYCLE,
RESTAPI::Protocol::FIXEDCONFIG, RESTAPI::Protocol::CABLEDIAGNOSTICS,
RESTAPI::Protocol::REENROLL
RESTAPI::Protocol::REENROLL, RESTAPI::Protocol::PACKAGE
};
inline const char *to_string(Commands Cmd) { return uCentralAPCommands[(uint8_t)Cmd]; }

View File

@@ -888,78 +888,15 @@ namespace OpenWifi::Utils {
return password;
}
// 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> naptrRecords;
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;
}
/*
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
#47 3.825 /owgw/src/framework/utils.cpp: In function 'std::vector<OpenWifi::Utils::NAPTRRecord> OpenWifi::Utils::getNAPTRRecords(const std::string&)':
#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]
std::vector<SrvRecord> getSRVRecords(const std::string& domain) {
std::vector<SrvRecord> srvRecords;
// 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;
}
#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]
*/
} // namespace OpenWifi::Utils

View File

@@ -298,8 +298,10 @@ namespace OpenWifi::Utils {
std::string replacement;
};
// Function to query NAPTR records for a domain and return them in a vector
std::vector<NAPTRRecord> getNAPTRRecords(const std::string& domain);
// removed due to deprecation: see utils.cpp
// Function to query NAPTR records for a domain and return them in a vector
//std::vector<NAPTRRecord> getNAPTRRecords(const std::string& domain);
struct SrvRecord {
std::string name;
std::string ttl;
@@ -311,7 +313,8 @@ namespace OpenWifi::Utils {
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{
std::string Hostname;

View File

@@ -14,6 +14,7 @@
#include "nlohmann/json.hpp"
#include "Poco/NObserver.h"
#include <Poco/Net/Context.h>
#include "Poco/Net/SocketNotification.h"
#include "Poco/Net/NetException.h"
#include "Poco/Net/WebSocketImpl.h"
@@ -71,6 +72,7 @@ namespace OpenWifi {
const auto &RootCas =
MicroServiceConfigPath("ucentral.websocket.host.0.rootca", "");
const auto &Cas = MicroServiceConfigPath("ucentral.websocket.host.0.cas", "");
const auto &ClientCasFile = MicroServiceConfigPath("ucentral.websocket.host.0.clientcas", "");
Poco::Net::Context::Params P;
@@ -86,6 +88,7 @@ namespace OpenWifi {
Poco::Crypto::X509Certificate Cert(CertFileName);
Poco::Crypto::X509Certificate Root(RootCaFileName);
Poco::Crypto::X509Certificate Issuing(IssuerFileName);
std::vector<Poco::Crypto::X509Certificate> ClientCasCerts;
Poco::Crypto::RSAKey Key("", KeyFileName, KeyPassword);
DeviceSecureContext->useCertificate(Cert);
@@ -93,7 +96,11 @@ namespace OpenWifi {
DeviceSecureContext->addCertificateAuthority(Root);
DeviceSecureContext->addChainCertificate(Issuing);
DeviceSecureContext->addCertificateAuthority(Issuing);
DeviceSecureContext->addCertificateAuthority(Root);
ClientCasCerts = Poco::Net::X509Certificate::readPEM(ClientCasFile);
for (const auto &cert : ClientCasCerts) {
DeviceSecureContext->addChainCertificate(cert);
DeviceSecureContext->addCertificateAuthority(cert);
}
DeviceSecureContext->enableSessionCache(true);
DeviceSecureContext->setSessionCacheSize(0);
DeviceSecureContext->setSessionTimeout(120);
@@ -573,14 +580,16 @@ namespace OpenWifi {
try {
Client = Clients_.find(pNf->socket().impl()->sockfd());
if (Client == end(Clients_)) {
poco_warning(Logger(), fmt::format("Cannot find client socket: {}",
pNf->socket().impl()->sockfd()));
poco_warning(Logger(),
fmt::format("Cannot find client socket: {}",
pNf->socket().impl()->sockfd()));
return;
}
Connection = Client->second;
if(Connection->WSSocket_==nullptr || Connection->WSSocket_->impl()==nullptr) {
poco_warning(Logger(), fmt::format("WebSocket is no valid: {}",
Connection->SerialNumber_));
poco_warning(Logger(),
fmt::format("WebSocket is not valid: {}",
Connection->SerialNumber_));
return;
}
@@ -589,15 +598,25 @@ namespace OpenWifi {
auto ReceivedBytes = Connection->WSSocket_->receiveFrame(FrameBuffer, sizeof(FrameBuffer), flags);
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) {
case Poco::Net::WebSocket::FRAME_OP_PING: {
Connection->WSSocket_->sendFrame("", 0,
(int)Poco::Net::WebSocket::FRAME_OP_PONG |
(int)Poco::Net::WebSocket::FRAME_FLAG_FIN);
(int)Poco::Net::WebSocket::FRAME_OP_PONG |
(int)Poco::Net::WebSocket::FRAME_FLAG_FIN);
} break;
case Poco::Net::WebSocket::FRAME_OP_PONG: {
} break;
case Poco::Net::WebSocket::FRAME_OP_TEXT: {
if (ReceivedBytes == 0) {
EndConnection(Connection,__func__,__LINE__);
@@ -624,19 +643,29 @@ namespace OpenWifi {
}
}
} break;
case Poco::Net::WebSocket::FRAME_OP_BINARY: {
if (ReceivedBytes == 0) {
EndConnection(Connection,__func__,__LINE__);
return;
} else {
poco_trace(Logger(),
fmt::format("Sending {} key strokes to device.", ReceivedBytes));
fmt::format("Sending {} key strokes to device.", ReceivedBytes));
if (!RTTYS_server().KeyStrokes(Connection, FrameBuffer, ReceivedBytes)) {
EndConnection(Connection,__func__,__LINE__);
return;
}
}
} 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: {
EndConnection(Connection,__func__,__LINE__);
return;
@@ -682,8 +711,8 @@ namespace OpenWifi {
if (Connection->WSSocket_ != nullptr && Connection->WSSocket_->impl()!= nullptr) {
try {
Connection->WSSocket_->sendFrame(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;
} catch (...) {
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) {
WebSocket.sendFrame(
Buf, len, Poco::Net::WebSocket::FRAME_FLAG_FIN | Poco::Net::WebSocket::FRAME_OP_BINARY);
WebSocket.sendFrame(Buf, len,
(int) Poco::Net::WebSocket::FRAME_FLAG_FIN |
(int) Poco::Net::WebSocket::FRAME_OP_BINARY);
return true;
}
@@ -1117,4 +1147,4 @@ namespace OpenWifi {
RTTYS_EndPoint::~RTTYS_EndPoint() {
}
} // namespace OpenWifi
} // namespace OpenWifi

View File

@@ -664,12 +664,14 @@ namespace OpenWifi {
Insert.execute();
Sess.commit();
} 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);
Sess.begin();
Poco::Data::Statement Statement(Sess);
std::string StatementStr;
StatementStr =
"UPDATE CommandList SET WaitingForFile=?, AttachDate=?, AttachSize=? WHERE UUID=?";

View File

@@ -202,15 +202,14 @@ namespace OpenWifi {
std::string st;
std::string whereClause = "";
if(!platform.empty()) {
if (!platform.empty()) {
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 {
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 + "' ";
} else {
if (includeProvisioned == false) {
@@ -218,7 +217,7 @@ namespace OpenWifi {
}
//st = "SELECT SerialNumber From Devices ";
}
st = fmt::format("SELECT SerialNumber From Devices {}", whereClause);
if (orderBy.empty())
@@ -896,9 +895,9 @@ namespace OpenWifi {
if (includeProvisioned == false) {
whereClause = fmt::format("WHERE DeviceType='{}' and entity='' and venue=''",platform);
} else {
whereClause = fmt::format("WHERE DeviceType='{}'", platform);
whereClause = fmt::format("WHERE DeviceType='{}'", platform);
}
}
st =
@@ -907,7 +906,7 @@ namespace OpenWifi {
ComputeRange(From, HowMany));
//Logger().information(fmt::format(" GetDevices st is {} ", st));
Select << ConvertParams(st), Poco::Data::Keywords::into(Records);
Select.execute();

View File

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