Compare commits

...

79 Commits

Author SHA1 Message Date
TIP Automation User
7760230f02 Chg: update image tag in helm values to v2.8.0-RC2 2022-12-16 14:51:57 +00:00
Stephane Bourque
6223ade0f6 Merge pull request #83 from Telecominfraproject/main
https://telecominfraproject.atlassian.net/browse/WIFI-10082
2022-12-15 11:35:04 -08:00
Stephane Bourque
64e6a6f70a Merge pull request #82 from Telecominfraproject/WIFI-11974
https://telecominfraproject.atlassian.net/browse/WIFI-10082
2022-12-15 11:34:02 -08:00
stephb9959
c67367ec4d https://telecominfraproject.atlassian.net/browse/WIFI-10082
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2022-12-15 11:31:19 -08:00
stephb9959
fe3c5d7c4a https://telecominfraproject.atlassian.net/browse/WIFI-10082
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2022-12-15 11:20:15 -08:00
Stephane Bourque
da52cf5823 Merge pull request #81 from Telecominfraproject/main
https://telecominfraproject.atlassian.net/browse/WIFI-11974
2022-12-14 20:54:39 -08:00
Stephane Bourque
3c8d8697e0 Merge pull request #80 from Telecominfraproject/WIFI-11974
https://telecominfraproject.atlassian.net/browse/WIFI-11974
2022-12-14 11:53:51 -08:00
stephb9959
7b0c61ff5e https://telecominfraproject.atlassian.net/browse/WIFI-11974
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2022-12-14 11:53:23 -08:00
TIP Automation User
e9a9416332 Chg: update image tag in helm values to v2.8.0-RC1 2022-12-13 23:08:43 +00:00
Stephane Bourque
2255988b4c Merge pull request #79 from Telecominfraproject/WIFI-11867
https://telecominfraproject.atlassian.net/browse/WIFI-11867
2022-12-12 14:32:50 -08:00
stephb9959
106c9353fc https://telecominfraproject.atlassian.net/browse/WIFI-11867
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2022-12-12 14:32:12 -08:00
Johann Hoffmann
6c7fc8e310 Make firmware DB refresh interval configurable in Docker Compose and increase it (#78)
Signed-off-by: Johann Hoffmann <johann.hoffmann@mailbox.org>

Signed-off-by: Johann Hoffmann <johann.hoffmann@mailbox.org>
2022-12-09 17:40:05 +01:00
Stephane Bourque
e151b45d51 Merge pull request #77 from Telecominfraproject/WIFI-11867
https://telecominfraproject.atlassian.net/browse/WIFI-11867
2022-12-01 10:07:38 -08:00
stephb9959
1584ff1ebe https://telecominfraproject.atlassian.net/browse/WIFI-11867
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2022-12-01 10:04:16 -08:00
stephb9959
82ccb08d6b https://telecominfraproject.atlassian.net/browse/WIFI-11867
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2022-12-01 09:52:40 -08:00
stephb9959
82b184a79f https://telecominfraproject.atlassian.net/browse/WIFI-11867
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2022-12-01 09:19:54 -08:00
stephb9959
71c37edde7 https://telecominfraproject.atlassian.net/browse/WIFI-11867
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2022-12-01 09:14:59 -08:00
stephb9959
0c8fa44935 https://telecominfraproject.atlassian.net/browse/WIFI-11867
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2022-12-01 09:10:33 -08:00
stephb9959
32714f95b6 https://telecominfraproject.atlassian.net/browse/WIFI-11867
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2022-12-01 09:07:53 -08:00
Dmitry Dunaev
13cbf8c603 [WIFI-11729] Fix: doc generation error
Signed-off-by: Dmitry Dunaev <dmitry@opsfleet.com>
2022-12-01 13:21:05 +03:00
stephb9959
48c95c3101 Merge remote-tracking branch 'origin/main' 2022-11-30 22:16:24 -08:00
stephb9959
857055750f https://telecominfraproject.atlassian.net/browse/WIFI-11755
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2022-11-30 22:16:14 -08:00
Dmitry Dunaev
96b22ef09b Merge pull request #76 from Telecominfraproject/feature/wifi-11729--pages-docs
[WIFI-11729] Add: README info
2022-11-29 15:02:49 +03:00
Dmitry Dunaev
acff9afff2 [WIFI-11729] Add: README info
Signed-off-by: Dmitry Dunaev <dmitry@opsfleet.com>
2022-11-29 15:02:31 +03:00
Dmitry Dunaev
1e250be2cd Merge pull request #75 from Telecominfraproject/feature/wifi-11729--pages-docs
[WIFI-11729] Fix: OpenAPI file loc
2022-11-29 14:42:21 +03:00
Dmitry Dunaev
93a8624645 [WIFI-11729] Fix: OpenAPI file loc
Signed-off-by: Dmitry Dunaev <dmitry@opsfleet.com>
2022-11-29 14:42:05 +03:00
Dmitry Dunaev
b9bf57e1f2 Merge pull request #74 from Telecominfraproject/feature/wifi-11729--pages-docs
[WIFI-11729] Add: workflow to generate docs to GitHub pages
2022-11-29 14:40:23 +03:00
Dmitry Dunaev
f203622299 [WIFI-11729] Add: workflow to generate docs to GitHub pages
Signed-off-by: Dmitry Dunaev <dmitry@opsfleet.com>
2022-11-29 14:39:58 +03:00
stephb9959
698282658c https://telecominfraproject.atlassian.net/browse/WIFI-11755
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2022-11-27 21:32:11 -08:00
stephb9959
5baacac9bf Merge remote-tracking branch 'origin/main' 2022-11-27 14:33:34 -08:00
stephb9959
8ca4531c99 https://telecominfraproject.atlassian.net/browse/WIFI-11755
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2022-11-27 14:33:22 -08:00
Johann Hoffmann
a6e0cd453b [WIFI-11419] Patch workflows with regard to deprecated Github actions commands (#73)
* Update checkout action version and replace set-output commands

Signed-off-by: Johann Hoffmann <johann.hoffmann@mailbox.org>

* Fix output variable assignment

Signed-off-by: Johann Hoffmann <johann.hoffmann@mailbox.org>

Signed-off-by: Johann Hoffmann <johann.hoffmann@mailbox.org>
2022-11-25 15:33:25 +01:00
Johann Hoffmann
5e39f63fd2 Move ARG definition to avoid hitting build cache
Signed-off-by: Johann Hoffmann <johann.hoffmann@mailbox.org>
2022-11-22 14:16:39 +01:00
Johann Hoffmann
9b081c6924 Set vcpkg to fixed version
Signed-off-by: Johann Hoffmann <johann.hoffmann@mailbox.org>
2022-11-22 12:50:03 +01:00
stephb9959
be2150d845 https://telecominfraproject.atlassian.net/browse/WIFI-11303
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2022-11-21 09:14:45 -08:00
stephb9959
2d6f1879f5 https://telecominfraproject.atlassian.net/browse/WIFI-11303
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2022-11-21 07:40:18 -08:00
stephb9959
e870a381a8 https://telecominfraproject.atlassian.net/browse/WIFI-11303
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2022-11-18 19:54:42 -08:00
stephb9959
0cc0d0204e https://telecominfraproject.atlassian.net/browse/WIFI-11303
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2022-11-18 07:33:59 -08:00
stephb9959
498e55f933 https://telecominfraproject.atlassian.net/browse/WIFI-11303
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2022-11-18 07:24:32 -08:00
stephb9959
a9b3cb9821 https://telecominfraproject.atlassian.net/browse/WIFI-11303
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2022-11-17 21:26:50 -08:00
stephb9959
29736da681 https://telecominfraproject.atlassian.net/browse/WIFI-11303
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2022-11-17 11:40:39 -08:00
stephb9959
28f890002b https://telecominfraproject.atlassian.net/browse/WIFI-11303
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2022-11-16 23:04:36 -08:00
stephb9959
0ec0a4fd95 https://telecominfraproject.atlassian.net/browse/WIFI-11303
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2022-11-16 10:34:35 -08:00
stephb9959
6dce398ddc https://telecominfraproject.atlassian.net/browse/WIFI-11303
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2022-11-16 10:24:35 -08:00
stephb9959
eca0e8883a https://telecominfraproject.atlassian.net/browse/WIFI-11303
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2022-11-14 10:11:03 -08:00
stephb9959
43cc667a59 Merge remote-tracking branch 'origin/main' 2022-11-08 23:10:13 -08:00
stephb9959
a084230cbd https://telecominfraproject.atlassian.net/browse/WIFI-11303
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2022-11-08 23:10:02 -08:00
Dmitry Dunaev
59c5ed51c0 Merge pull request #72 from Telecominfraproject/fix/wifi-11490--git-hash
[WIFI-11490] Fix: Get Git hash command in CMakeLists
2022-11-08 14:17:21 +03:00
Dmitry Dunaev
1128fd3c23 [WIFI-11490] Fix: Get Git hash command in CMakeLists
Signed-off-by: Dmitry Dunaev <dmitry@opsfleet.com>
2022-11-08 13:42:09 +03:00
stephb9959
ee4f1fac93 https://telecominfraproject.atlassian.net/browse/WIFI-10918
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2022-11-07 15:30:28 -08:00
stephb9959
a1a600de77 https://telecominfraproject.atlassian.net/browse/WIFI-10918
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2022-11-07 14:59:41 -08:00
stephb9959
9d64c2dabd https://telecominfraproject.atlassian.net/browse/WIFI-11303
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2022-11-03 23:15:02 -07:00
stephb9959
4f6c9728ef https://telecominfraproject.atlassian.net/browse/WIFI-11303
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2022-11-03 10:25:11 -07:00
stephb9959
167933e422 https://telecominfraproject.atlassian.net/browse/WIFI-11303
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2022-11-03 10:24:11 -07:00
stephb9959
f661bb579a https://telecominfraproject.atlassian.net/browse/WIFI-11303
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2022-11-03 09:36:34 -07:00
stephb9959
1e14eb1611 https://telecominfraproject.atlassian.net/browse/WIFI-11303
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2022-11-02 22:31:59 -07:00
stephb9959
dae57a7492 Merge remote-tracking branch 'origin/main' 2022-10-31 11:19:03 -07:00
stephb9959
d30014372b https://telecominfraproject.atlassian.net/browse/WIFI-11303
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2022-10-31 11:18:55 -07:00
Dmitry Dunaev
a9f37ae30d Merge pull request #71 from Telecominfraproject/feature/wifi-9942--sqlite
[WIFI-9942] Add: sqlite package
2022-10-31 12:05:27 +03:00
Dmitry Dunaev
23bc11f26e [WIFI-9942] Add: sqlite package
Signed-off-by: Dmitry Dunaev <dmitry@opsfleet.com>
2022-10-31 12:05:08 +03:00
stephb9959
caa25f0a1e https://telecominfraproject.atlassian.net/browse/WIFI-11303
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2022-10-30 10:14:19 -07:00
stephb9959
b86e80be6d https://telecominfraproject.atlassian.net/browse/WIFI-11303
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2022-10-29 21:47:39 -07:00
stephb9959
880a14b651 Merge remote-tracking branch 'origin/main' 2022-10-27 23:41:11 -07:00
stephb9959
fa5d1b982a https://telecominfraproject.atlassian.net/browse/WIFI-11303
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2022-10-27 23:41:02 -07:00
Stephane Bourque
e803885d24 Merge pull request #70 from Telecominfraproject/WIFI-10959-switch-fmtlib-and-awssdk
[WIFI-10959] Switch fmtlib and aws to prebuilt packages in Dockerfiles
2022-10-27 12:53:59 -07:00
stephb9959
17b7e1de59 Merge remote-tracking branch 'origin/main' 2022-10-27 09:50:04 -07:00
stephb9959
15d7ae635c https://telecominfraproject.atlassian.net/browse/WIFI-11303
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2022-10-27 09:49:55 -07:00
stephb9959
244423132e https://telecominfraproject.atlassian.net/browse/WIFI-11303
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2022-10-27 09:34:02 -07:00
stephb9959
ad149a8e40 https://telecominfraproject.atlassian.net/browse/WIFI-11303
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2022-10-26 21:56:07 -07:00
stephb9959
59020f8809 https://telecominfraproject.atlassian.net/browse/WIFI-11303
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2022-10-26 21:34:01 -07:00
stephb9959
4c5dbea4fb Merge remote-tracking branch 'origin/main' 2022-10-26 15:01:05 -07:00
stephb9959
8fa42ab75d https://telecominfraproject.atlassian.net/browse/WIFI-11303
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2022-10-26 15:00:54 -07:00
Johann Hoffmann
ad1d7301a1 Switch to dynamic linkage and add overlays for system libs
Signed-off-by: Johann Hoffmann <johann.hoffmann@mailbox.org>
2022-10-20 16:11:53 +02:00
Johann Hoffmann
6ad2f0ba1b Add libfmt-dev
Signed-off-by: Johann Hoffmann <johann.hoffmann@mailbox.org>
2022-10-17 22:34:12 +02:00
Johann Hoffmann
aad7cf752a Add find_package call for zlib
Signed-off-by: Johann Hoffmann <johann.hoffmann@mailbox.org>
2022-10-17 22:34:12 +02:00
Johann Hoffmann
ff8fa5e625 Install AWS SDK and json-schema-validator with vcpkg
Signed-off-by: Johann Hoffmann <johann.hoffmann@mailbox.org>
2022-10-17 22:34:11 +02:00
Johann Hoffmann
6e38083912 Add vcpkg.json
Signed-off-by: Johann Hoffmann <johann.hoffmann@mailbox.org>
2022-10-17 22:34:11 +02:00
Dmitry Dunaev
98509fdab7 Merge pull request #69 from Telecominfraproject/security/wifi-11170--docker-image-version
[WIFI-11170] Chg: upgrade base Debian image
2022-10-11 14:59:41 +03:00
Dmitry Dunaev
2bbaf44e88 [WIFI-11170] Chg: upgrade base Debian image
Signed-off-by: Dmitry Dunaev <dmitry@opsfleet.com>
2022-10-11 14:59:24 +03:00
113 changed files with 10262 additions and 8427 deletions

View File

@@ -27,7 +27,7 @@ jobs:
DOCKER_REGISTRY_USERNAME: ucentral DOCKER_REGISTRY_USERNAME: ucentral
steps: steps:
- name: Checkout actions repo - name: Checkout actions repo
uses: actions/checkout@v2 uses: actions/checkout@v3
with: with:
repository: Telecominfraproject/.github repository: Telecominfraproject/.github
path: github path: github
@@ -58,11 +58,11 @@ jobs:
- name: Get base branch name and set as output - name: Get base branch name and set as output
id: get_base_branch id: get_base_branch
run: | run: |
echo ::set-output name=branch::$(echo ${GITHUB_BASE_REF##*/}) echo "branch=$(echo ${GITHUB_BASE_REF##*/})" >> $GITHUB_OUTPUT
echo ::set-output name=owgw_branch::$(echo ${GITHUB_BASE_REF##*/} | sed 's/main/master/g') echo "owgw_branch=$(echo ${GITHUB_BASE_REF##*/} | sed 's/main/master/g')" >> $GITHUB_OUTPUT
- name: Checkout actions repo - name: Checkout actions repo
uses: actions/checkout@v2 uses: actions/checkout@v3
with: with:
repository: Telecominfraproject/.github repository: Telecominfraproject/.github
path: github path: github
@@ -87,7 +87,7 @@ jobs:
- docker - docker
steps: steps:
- name: Checkout actions repo - name: Checkout actions repo
uses: actions/checkout@v2 uses: actions/checkout@v3
with: with:
repository: Telecominfraproject/.github repository: Telecominfraproject/.github
path: github path: github

41
.github/workflows/openapi-pages.yml vendored Normal file
View File

@@ -0,0 +1,41 @@
name: Update OpenAPI docs on GitHub Pages
on:
push:
paths:
- 'openapi/**'
branches:
- main
workflow_dispatch:
defaults:
run:
shell: bash
jobs:
docsgen:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Generate static HTML page with docs from OpenAPI definition
run: |
docker run --rm -v "${PWD}:/local" openapitools/openapi-generator-cli:v6.2.1 generate -i https://raw.githubusercontent.com/Telecominfraproject/wlan-cloud-ucentralfms/main/openapi/owfms.yaml -g html2 --skip-validate-spec -o /local/
- name: Update OpenAPI docs
run: |
mkdir tmp-docs
mv index.html tmp-docs/index.html
mkdir -p ~/.ssh
ssh-keyscan -H github.com >> ~/.ssh/known_hosts
echo https://tip-automation:${{ secrets.GIT_PUSH_PAT }}@github.com > ~/.git-credentials
git config --global credential.helper store
git config --global user.email "tip-automation@telecominfraproject.com"
git config --global user.name "TIP Automation User"
git pull
git checkout gh-pages || git checkout -b gh-pages
rm -rf docs
mv tmp-docs docs
git add docs
git commit -m'Update OpenAPI docs for GitHub pages'
git push --set-upstream origin gh-pages

View File

@@ -1,5 +1,5 @@
cmake_minimum_required(VERSION 3.13) cmake_minimum_required(VERSION 3.13)
project(owfms VERSION 2.7.0) project(owfms VERSION 2.8.0)
set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD 17)
@@ -27,12 +27,12 @@ endif()
find_package(Git QUIET) find_package(Git QUIET)
if(GIT_FOUND AND EXISTS "${PROJECT_SOURCE_DIR}/.git") if(GIT_FOUND AND EXISTS "${PROJECT_SOURCE_DIR}/.git")
execute_process(COMMAND ${GIT_EXECUTABLE} describe --always --tags execute_process(COMMAND ${GIT_EXECUTABLE} rev-parse --short HEAD
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
RESULT_VARIABLE GIT_RESULT RESULT_VARIABLE GIT_RESULT
OUTPUT_VARIABLE GIT_HASH) OUTPUT_VARIABLE GIT_HASH)
if(NOT GIT_RESULT EQUAL "0") if(NOT GIT_RESULT EQUAL "0")
message(FATAL_ERROR "git describe --always --tags failed with ${GIT_RESULT}") message(FATAL_ERROR "git rev-parse --short HEAD failed with ${GIT_RESULT}")
endif() endif()
string(REGEX REPLACE "\n$" "" GIT_HASH "${GIT_HASH}") string(REGEX REPLACE "\n$" "" GIT_HASH "${GIT_HASH}")
endif() endif()
@@ -42,8 +42,10 @@ endif()
find_package(OpenSSL REQUIRED) find_package(OpenSSL REQUIRED)
find_package(fmt REQUIRED) find_package(fmt REQUIRED)
find_package(ZLIB REQUIRED)
find_package(Poco REQUIRED COMPONENTS Crypto JWT Net Util NetSSL Data DataSQLite) find_package(Poco REQUIRED COMPONENTS Crypto JWT Net Util NetSSL Data DataSQLite)
find_package(AWSSDK REQUIRED COMPONENTS s3) find_package(AWSSDK REQUIRED COMPONENTS s3)
find_package(ZLIB REQUIRED)
if(SMALL_BUILD) if(SMALL_BUILD)
find_package(Poco REQUIRED COMPONENTS Crypto JWT Net Util NetSSL Data DataSQLite) find_package(Poco REQUIRED COMPONENTS Crypto JWT Net Util NetSSL Data DataSQLite)
@@ -75,14 +77,54 @@ add_executable( owfms
src/framework/OpenWifiTypes.h src/framework/OpenWifiTypes.h
src/framework/orm.h src/framework/orm.h
src/framework/StorageClass.h src/framework/StorageClass.h
src/framework/ow_constants.h
src/framework/MicroServiceErrorHandler.h
src/framework/WebSocketClientNotifications.h
src/framework/MicroServiceErrorHandler.h src/framework/MicroServiceErrorHandler.h
src/framework/UI_WebSocketClientServer.cpp
src/framework/UI_WebSocketClientServer.h
src/framework/UI_WebSocketClientNotifications.cpp
src/framework/UI_WebSocketClientNotifications.h
src/framework/utils.h
src/framework/utils.cpp
src/framework/AppServiceRegistry.h
src/framework/SubSystemServer.cpp
src/framework/SubSystemServer.h
src/framework/RESTAPI_utils.h
src/framework/AuthClient.cpp
src/framework/AuthClient.h
src/framework/MicroServiceNames.h
src/framework/MicroServiceFuncs.h
src/framework/OpenAPIRequests.cpp
src/framework/OpenAPIRequests.h
src/framework/MicroServiceFuncs.cpp
src/framework/ALBserver.cpp
src/framework/ALBserver.h
src/framework/KafkaManager.cpp
src/framework/KafkaManager.h
src/framework/RESTAPI_RateLimiter.h
src/framework/WebSocketLogger.h
src/framework/RESTAPI_GenericServerAccounting.h
src/framework/RESTAPI_SystemConfiguration.h
src/framework/CIDR.h
src/framework/RESTAPI_Handler.cpp
src/framework/RESTAPI_Handler.h
src/framework/RESTAPI_ExtServer.h
src/framework/RESTAPI_ExtServer.cpp
src/framework/RESTAPI_IntServer.cpp
src/framework/RESTAPI_IntServer.h
src/framework/RESTAPI_SystemCommand.h
src/framework/RESTAPI_WebSocketServer.h
src/framework/EventBusManager.cpp
src/framework/EventBusManager.h
src/framework/RESTAPI_PartHandler.h
src/framework/MicroService.cpp
src/framework/MicroServiceExtra.h
src/RESTObjects/RESTAPI_SecurityObjects.h src/RESTObjects/RESTAPI_SecurityObjects.cpp src/RESTObjects/RESTAPI_SecurityObjects.h src/RESTObjects/RESTAPI_SecurityObjects.cpp
src/RESTObjects/RESTAPI_ProvObjects.cpp src/RESTObjects/RESTAPI_ProvObjects.h
src/RESTObjects/RESTAPI_GWobjects.h src/RESTObjects/RESTAPI_GWobjects.cpp src/RESTObjects/RESTAPI_GWobjects.h src/RESTObjects/RESTAPI_GWobjects.cpp
src/RESTObjects/RESTAPI_FMSObjects.h src/RESTObjects/RESTAPI_FMSObjects.cpp src/RESTObjects/RESTAPI_FMSObjects.h src/RESTObjects/RESTAPI_FMSObjects.cpp
src/RESTObjects/RESTAPI_CertObjects.cpp src/RESTObjects/RESTAPI_CertObjects.h
src/RESTObjects/RESTAPI_OWLSobjects.cpp src/RESTObjects/RESTAPI_OWLSobjects.h
src/RESTObjects/RESTAPI_ProvObjects.cpp src/RESTObjects/RESTAPI_ProvObjects.h
src/RESTObjects/RESTAPI_AnalyticsObjects.cpp src/RESTObjects/RESTAPI_AnalyticsObjects.h
src/RESTObjects/RESTAPI_SubObjects.cpp src/RESTObjects/RESTAPI_SubObjects.h
src/RESTAPI/RESTAPI_firmwaresHandler.cpp src/RESTAPI/RESTAPI_firmwaresHandler.h src/RESTAPI/RESTAPI_firmwaresHandler.cpp src/RESTAPI/RESTAPI_firmwaresHandler.h
src/RESTAPI/RESTAPI_firmwareHandler.cpp src/RESTAPI/RESTAPI_firmwareHandler.h src/RESTAPI/RESTAPI_firmwareHandler.cpp src/RESTAPI/RESTAPI_firmwareHandler.h
src/RESTAPI/RESTAPI_historyHandler.cpp src/RESTAPI/RESTAPI_historyHandler.h src/RESTAPI/RESTAPI_historyHandler.cpp src/RESTAPI/RESTAPI_historyHandler.h
@@ -95,7 +137,6 @@ add_executable( owfms
src/Daemon.cpp src/Daemon.h src/Daemon.cpp src/Daemon.h
src/StorageService.cpp src/StorageService.h src/StorageService.cpp src/StorageService.h
src/ManifestCreator.cpp src/ManifestCreator.h src/ManifestCreator.cpp src/ManifestCreator.h
src/framework/MicroService.h
src/NewConnectionHandler.cpp src/NewConnectionHandler.h src/NewConnectionHandler.cpp src/NewConnectionHandler.h
src/LatestFirmwareCache.cpp src/LatestFirmwareCache.h src/LatestFirmwareCache.cpp src/LatestFirmwareCache.h
src/DeviceCache.cpp src/DeviceCache.h src/DeviceCache.cpp src/DeviceCache.h
@@ -105,7 +146,9 @@ add_executable( owfms
src/NewCommandHandler.cpp src/NewCommandHandler.h src/NewCommandHandler.cpp src/NewCommandHandler.h
src/storage/orm_history.cpp src/storage/orm_history.h src/storage/orm_history.cpp src/storage/orm_history.h
src/storage/orm_firmwares.cpp src/storage/orm_firmwares.h src/storage/orm_firmwares.cpp src/storage/orm_firmwares.h
src/storage/orm_deviceInfo.cpp src/storage/orm_deviceInfo.h src/RESTAPI/RESTAPI_deviceInformation_handler.cpp src/RESTAPI/RESTAPI_deviceInformation_handler.h) src/storage/orm_deviceInfo.cpp src/storage/orm_deviceInfo.h
src/RESTAPI/RESTAPI_deviceInformation_handler.cpp
src/RESTAPI/RESTAPI_deviceInformation_handler.h)
target_link_libraries( owfms PUBLIC target_link_libraries( owfms PUBLIC
${Poco_LIBRARIES} ${Poco_LIBRARIES}

View File

@@ -1,17 +1,14 @@
ARG DEBIAN_VERSION=11.4-slim ARG DEBIAN_VERSION=11.5-slim
ARG POCO_VERSION=poco-tip-v1 ARG POCO_VERSION=poco-tip-v2
ARG FMTLIB_VERSION=9.0.0
ARG CPPKAFKA_VERSION=tip-v1 ARG CPPKAFKA_VERSION=tip-v1
ARG JSON_VALIDATOR_VERSION=2.1.0
ARG AWS_SDK_VERSION=1.9.315
FROM debian:$DEBIAN_VERSION AS build-base FROM debian:$DEBIAN_VERSION AS build-base
RUN apt-get update && apt-get install --no-install-recommends -y \ RUN apt-get update && apt-get install --no-install-recommends -y \
make cmake g++ git \ make cmake g++ git curl zip unzip pkg-config \
libpq-dev libmariadb-dev libmariadbclient-dev-compat \ libpq-dev libmariadb-dev libmariadbclient-dev-compat \
librdkafka-dev libboost-all-dev libssl-dev \ librdkafka-dev libboost-all-dev libssl-dev \
zlib1g-dev nlohmann-json3-dev ca-certificates libcurl4-openssl-dev zlib1g-dev ca-certificates libcurl4-openssl-dev libfmt-dev
FROM build-base AS poco-build FROM build-base AS poco-build
@@ -27,20 +24,6 @@ RUN cmake ..
RUN cmake --build . --config Release -j8 RUN cmake --build . --config Release -j8
RUN cmake --build . --target install RUN cmake --build . --target install
FROM build-base AS fmtlib-build
ARG FMTLIB_VERSION
ADD https://api.github.com/repos/fmtlib/fmt/git/refs/tags/${FMTLIB_VERSION} version.json
RUN git clone https://github.com/fmtlib/fmt --branch ${FMTLIB_VERSION} /fmtlib
WORKDIR /fmtlib
RUN mkdir cmake-build
WORKDIR cmake-build
RUN cmake ..
RUN make
RUN make install
FROM build-base AS cppkafka-build FROM build-base AS cppkafka-build
ARG CPPKAFKA_VERSION ARG CPPKAFKA_VERSION
@@ -55,62 +38,30 @@ RUN cmake ..
RUN cmake --build . --config Release -j8 RUN cmake --build . --config Release -j8
RUN cmake --build . --target install RUN cmake --build . --target install
FROM build-base AS json-schema-validator-build
ARG JSON_VALIDATOR_VERSION
ADD https://api.github.com/repos/pboettch/json-schema-validator/git/refs/tags/${JSON_VALIDATOR_VERSION} version.json
RUN git clone https://github.com/pboettch/json-schema-validator --branch ${JSON_VALIDATOR_VERSION} /json-schema-validator
WORKDIR /json-schema-validator
RUN mkdir cmake-build
WORKDIR cmake-build
RUN cmake ..
RUN make
RUN make install
FROM build-base AS aws-sdk-cpp-build
ARG AWS_SDK_VERSION
ADD https://api.github.com/repos/aws/aws-sdk-cpp/git/refs/tags/${AWS_SDK_VERSION} version.json
RUN git clone --recurse-submodules https://github.com/aws/aws-sdk-cpp --branch ${AWS_SDK_VERSION} /aws-sdk-cpp
WORKDIR /aws-sdk-cpp
RUN mkdir cmake-build
WORKDIR cmake-build
RUN cmake .. -DBUILD_ONLY="sns;s3" \
-DCMAKE_BUILD_TYPE=Release \
-DUSE_OPENSSL=ON \
-DCPP_STANDARD=17 \
-DBUILD_SHARED_LIBS=ON \
-DCMAKE_CXX_FLAGS="-Wno-error=stringop-overflow -Wno-error=uninitialized" \
-DAUTORUN_UNIT_TESTS=OFF
RUN cmake --build . --config Release -j8
RUN cmake --build . --target install
FROM build-base AS owfms-build FROM build-base AS owfms-build
ADD CMakeLists.txt build /owfms/ ADD CMakeLists.txt build /owfms/
ADD overlays /owfms/overlays
ADD cmake /owfms/cmake ADD cmake /owfms/cmake
ADD src /owfms/src ADD src /owfms/src
ADD .git /owfms/.git ADD .git /owfms/.git
ARG VCPKG_VERSION=2022.11.14
RUN git clone --depth 1 --branch ${VCPKG_VERSION} https://github.com/microsoft/vcpkg && \
./vcpkg/bootstrap-vcpkg.sh && \
mkdir /vcpkg/custom-triplets && \
cp /vcpkg/triplets/x64-linux.cmake /vcpkg/custom-triplets/x64-linux.cmake && \
sed -i 's/set(VCPKG_LIBRARY.*/set(VCPKG_LIBRARY_LINKAGE dynamic)/g' /vcpkg/custom-triplets/x64-linux.cmake && \
./vcpkg/vcpkg install aws-sdk-cpp[s3]:x64-linux json-schema-validator:x64-linux --overlay-triplets=/vcpkg/custom-triplets --overlay-ports=/owfms/overlays
COPY --from=poco-build /usr/local/include /usr/local/include COPY --from=poco-build /usr/local/include /usr/local/include
COPY --from=poco-build /usr/local/lib /usr/local/lib COPY --from=poco-build /usr/local/lib /usr/local/lib
COPY --from=cppkafka-build /usr/local/include /usr/local/include COPY --from=cppkafka-build /usr/local/include /usr/local/include
COPY --from=cppkafka-build /usr/local/lib /usr/local/lib COPY --from=cppkafka-build /usr/local/lib /usr/local/lib
COPY --from=json-schema-validator-build /usr/local/include /usr/local/include
COPY --from=json-schema-validator-build /usr/local/lib /usr/local/lib
COPY --from=aws-sdk-cpp-build /usr/local/include /usr/local/include
COPY --from=aws-sdk-cpp-build /usr/local/lib /usr/local/lib
COPY --from=fmtlib-build /usr/local/include /usr/local/include
COPY --from=fmtlib-build /usr/local/lib /usr/local/lib
WORKDIR /owfms WORKDIR /owfms
RUN mkdir cmake-build RUN mkdir cmake-build
WORKDIR /owfms/cmake-build WORKDIR /owfms/cmake-build
RUN cmake .. RUN cmake -DCMAKE_TOOLCHAIN_FILE=/vcpkg/scripts/buildsystems/vcpkg.cmake ..
RUN cmake --build . --config Release -j8 RUN cmake --build . --config Release -j8
FROM debian:$DEBIAN_VERSION FROM debian:$DEBIAN_VERSION
@@ -127,7 +78,7 @@ RUN mkdir -p "$OWFMS_ROOT" "$OWFMS_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 libmariadb-dev-compat libpq5 postgresql-client libfmt7 sqlite3
COPY readiness_check /readiness_check COPY readiness_check /readiness_check
COPY test_scripts/curl/cli /cli COPY test_scripts/curl/cli /cli
@@ -139,11 +90,9 @@ RUN wget https://raw.githubusercontent.com/Telecominfraproject/wlan-cloud-ucentr
-O /usr/local/share/ca-certificates/restapi-ca-selfsigned.crt -O /usr/local/share/ca-certificates/restapi-ca-selfsigned.crt
COPY --from=owfms-build /owfms/cmake-build/owfms /openwifi/owfms COPY --from=owfms-build /owfms/cmake-build/owfms /openwifi/owfms
COPY --from=cppkafka-build /cppkafka/cmake-build/src/lib/* /usr/local/lib COPY --from=owfms-build /vcpkg/installed/x64-linux/lib/ /usr/local/lib/
COPY --from=poco-build /poco/cmake-build/lib/* /usr/local/lib COPY --from=cppkafka-build /cppkafka/cmake-build/src/lib/ /usr/local/lib/
COPY --from=aws-sdk-cpp-build /aws-sdk-cpp/cmake-build/aws-cpp-sdk-core/libaws-cpp-sdk-core.so /usr/local/lib COPY --from=poco-build /poco/cmake-build/lib/ /usr/local/lib/
COPY --from=aws-sdk-cpp-build /aws-sdk-cpp/cmake-build/aws-cpp-sdk-s3/libaws-cpp-sdk-s3.so /usr/local/lib
COPY --from=aws-sdk-cpp-build /aws-sdk-cpp/cmake-build/aws-cpp-sdk-sns/libaws-cpp-sdk-sns.so /usr/local/lib
RUN ldconfig RUN ldconfig

View File

@@ -5,6 +5,11 @@ The uCentralFMS is a micro-service part of the OpenWiFi ecosystem. uCentralFMS i
to facilitate the task of upgrade and maintaining the proper firmware for all the devices to facilitate the task of upgrade and maintaining the proper firmware for all the devices
used in your OpenWiFi solution. You may either [build it](#building) or use the [Docker version](#docker). used in your OpenWiFi solution. You may either [build it](#building) or use the [Docker version](#docker).
## OpenAPI
You may get static page with OpenAPI docs generated from the definition on [GitHub Page](https://telecominfraproject.github.io/wlan-cloud-ucentralfms/).
Also you may use [Swagger UI](https://petstore.swagger.io/#/) with OpenAPI definition file raw link (i.e. [latest version file](https://raw.githubusercontent.com/Telecominfraproject/wlan-cloud-ucentralfms/main/openapi/owfms.yaml)) to get interactive docs page.
## Building ## Building
In order to build the uCentralFMS, you will need to install its dependencies, which includes the following: In order to build the uCentralFMS, you will need to install its dependencies, which includes the following:
- cmake - cmake
@@ -216,4 +221,4 @@ s3.key = *******************************************
s3.retry = 60 s3.retry = 60
s3.bucket.uri = ucentral-ap-firmware.s3.amazonaws.com s3.bucket.uri = ucentral-ap-firmware.s3.amazonaws.com
``` ```

2
build
View File

@@ -1 +1 @@
18 24

View File

@@ -23,6 +23,8 @@ if [[ "$TEMPLATE_CONFIG" = 'true' ]]; then
SYSTEM_URI_PUBLIC=${SYSTEM_URI_PUBLIC:-"https://localhost:16004"} \ SYSTEM_URI_PUBLIC=${SYSTEM_URI_PUBLIC:-"https://localhost:16004"} \
SYSTEM_URI_UI=${SYSTEM_URI_UI:-"http://localhost"} \ SYSTEM_URI_UI=${SYSTEM_URI_UI:-"http://localhost"} \
SECURITY_RESTAPI_DISABLE=${SECURITY_RESTAPI_DISABLE:-"false"} \ SECURITY_RESTAPI_DISABLE=${SECURITY_RESTAPI_DISABLE:-"false"} \
FIRMWAREDB_REFRESH=${FIRMWAREDB_REFRESH:-"86400"} \
FIRMWAREDB_MAXAGE=${FIRMWAREDB_MAXAGE:-"90"} \
S3_BUCKETNAME=${S3_BUCKETNAME:-"ucentral-ap-firmware"} \ S3_BUCKETNAME=${S3_BUCKETNAME:-"ucentral-ap-firmware"} \
S3_REGION=${S3_REGION:-"us-east-1"} \ S3_REGION=${S3_REGION:-"us-east-1"} \
S3_SECRET=${S3_SECRET:-"*******************************************"} \ S3_SECRET=${S3_SECRET:-"*******************************************"} \

View File

@@ -9,7 +9,7 @@ fullnameOverride: ""
images: images:
owfms: owfms:
repository: tip-tip-wlan-cloud-ucentral.jfrog.io/owfms repository: tip-tip-wlan-cloud-ucentral.jfrog.io/owfms
tag: main tag: v2.8.0-RC2
pullPolicy: Always pullPolicy: Always
# regcred: # regcred:
# registry: tip-tip-wlan-cloud-ucentral.jfrog.io # registry: tip-tip-wlan-cloud-ucentral.jfrog.io
@@ -147,7 +147,7 @@ configProperties:
s3.region: us-east-1 s3.region: us-east-1
s3.retry: 60 s3.retry: 60
s3.bucket.uri: ucentral-ap-firmware.s3.amazonaws.com s3.bucket.uri: ucentral-ap-firmware.s3.amazonaws.com
firmwaredb.refresh: 1800 firmwaredb.refresh: 86400
# ALB # ALB
alb.enable: "true" alb.enable: "true"
alb.port: 16104 alb.port: 16104

View File

@@ -0,0 +1 @@
set(VCPKG_POLICY_EMPTY_PACKAGE enabled)

4
overlays/curl/vcpkg.json Normal file
View File

@@ -0,0 +1,4 @@
{
"name": "curl",
"version-string": "7.74.0-1.3+deb11u3"
}

View File

@@ -0,0 +1 @@
set(VCPKG_POLICY_EMPTY_PACKAGE enabled)

View File

@@ -0,0 +1,4 @@
{
"name": "openssl",
"version-string": "1.1.1n-0+deb11u3"
}

View File

@@ -0,0 +1 @@
set(VCPKG_POLICY_EMPTY_PACKAGE enabled)

4
overlays/zlib/vcpkg.json Normal file
View File

@@ -0,0 +1,4 @@
{
"name": "zlib",
"version-string": "1:1.2.11.dfsg-2+deb11u2"
}

View File

@@ -38,8 +38,8 @@ openwifi.system.commandchannel = /tmp/app.ucentralfms
openwifi.system.uri.ui = ${SYSTEM_URI_UI} openwifi.system.uri.ui = ${SYSTEM_URI_UI}
openwifi.security.restapi.disable = ${SECURITY_RESTAPI_DISABLE} openwifi.security.restapi.disable = ${SECURITY_RESTAPI_DISABLE}
firmwaredb.refresh = 1800 firmwaredb.refresh = ${FIRMWAREDB_REFRESH}
firmwaredb.maxage = 90 firmwaredb.maxage = ${FIRMWAREDB_MAXAGE}
# #
# Firmware Microservice Specific Section # Firmware Microservice Specific Section

View File

@@ -8,14 +8,19 @@
#include "LatestFirmwareCache.h" #include "LatestFirmwareCache.h"
#include "StorageService.h" #include "StorageService.h"
#include "framework/MicroServiceFuncs.h"
#include "framework/utils.h"
#include "fmt/format.h"
namespace OpenWifi { namespace OpenWifi {
int AutoUpdater::Start() { int AutoUpdater::Start() {
poco_information(Logger(),"Starting..."); poco_information(Logger(),"Starting...");
AutoUpdaterEnabled_ = MicroService::instance().ConfigGetBool("autoupdater.enabled", false); AutoUpdaterEnabled_ = MicroServiceConfigGetBool("autoupdater.enabled", false);
if(AutoUpdaterEnabled_) { if(AutoUpdaterEnabled_) {
Running_ = false; Running_ = false;
AutoUpdaterFrequency_ = MicroService::instance().ConfigGetInt("autoupdater.frequency",600); AutoUpdaterFrequency_ = MicroServiceConfigGetInt("autoupdater.frequency",600);
AutoUpdaterCallBack_ = std::make_unique<Poco::TimerCallback<AutoUpdater>>(*this, &AutoUpdater::onTimer); AutoUpdaterCallBack_ = std::make_unique<Poco::TimerCallback<AutoUpdater>>(*this, &AutoUpdater::onTimer);
Timer_.setStartInterval(5 * 60 * 1000); // first run in 5 minutes Timer_.setStartInterval(5 * 60 * 1000); // first run in 5 minutes
Timer_.setPeriodicInterval(AutoUpdaterFrequency_ * 1000); Timer_.setPeriodicInterval(AutoUpdaterFrequency_ * 1000);
@@ -50,7 +55,7 @@ namespace OpenWifi {
try { try {
poco_debug(Logger(),fmt::format("Preparing to upgrade {}",Entry.first)); poco_debug(Logger(),fmt::format("Preparing to upgrade {}",Entry.first));
auto CacheEntry = Cache_.find(Entry.first); auto CacheEntry = Cache_.find(Entry.first);
uint64_t now = OpenWifi::Now(); uint64_t now = Utils::Now();
std::string firmwareUpgrade; std::string firmwareUpgrade;
if(CacheEntry == Cache_.end() || (CacheEntry->second.LastCheck-now)>300) { if(CacheEntry == Cache_.end() || (CacheEntry->second.LastCheck-now)>300) {
// get the firmware settings for that device. // get the firmware settings for that device.

View File

@@ -2,11 +2,11 @@
// Created by stephane bourque on 2021-10-04. // Created by stephane bourque on 2021-10-04.
// //
#ifndef OWFMS_AUTOUPDATER_H #pragma once
#define OWFMS_AUTOUPDATER_H
#include "framework/MicroService.h"
#include <deque> #include <deque>
#include "framework/SubSystemServer.h"
#include "Poco/Util/Application.h" #include "Poco/Util/Application.h"
#include "Poco/Timer.h" #include "Poco/Timer.h"
@@ -55,4 +55,3 @@ namespace OpenWifi {
inline auto AutoUpdater() { return AutoUpdater::instance(); } inline auto AutoUpdater() { return AutoUpdater::instance(); }
} }
#endif //OWFMS_AUTOUPDATER_H

View File

@@ -19,6 +19,8 @@
#include "AutoUpdater.h" #include "AutoUpdater.h"
#include "NewCommandHandler.h" #include "NewCommandHandler.h"
#include "framework/UI_WebSocketClientServer.h"
namespace OpenWifi { namespace OpenWifi {
class Daemon *Daemon::instance_ = nullptr; class Daemon *Daemon::instance_ = nullptr;
@@ -37,7 +39,8 @@ namespace OpenWifi {
NewConnectionHandler(), NewConnectionHandler(),
ManifestCreator(), ManifestCreator(),
AutoUpdater(), AutoUpdater(),
NewCommandHandler() NewCommandHandler(),
UI_WebSocketClientServer()
}); });
} }
return instance_; return instance_;
@@ -45,6 +48,11 @@ namespace OpenWifi {
void Daemon::PostInitialization([[maybe_unused]] Poco::Util::Application &self) { void Daemon::PostInitialization([[maybe_unused]] Poco::Util::Application &self) {
} }
void DaemonPostInitialization(Poco::Util::Application &self) {
Daemon()->PostInitialization(self);
}
} }
int main(int argc, char **argv) { int main(int argc, char **argv) {

View File

@@ -7,6 +7,8 @@
#include "framework/MicroService.h" #include "framework/MicroService.h"
#include "framework/OpenWifiTypes.h" #include "framework/OpenWifiTypes.h"
#include "framework/MicroServiceNames.h"
#include "RESTObjects/RESTAPI_FMSObjects.h" #include "RESTObjects/RESTAPI_FMSObjects.h"
#include "Dashboard.h" #include "Dashboard.h"
@@ -30,9 +32,7 @@ namespace OpenWifi {
void PostInitialization(Poco::Util::Application &self); void PostInitialization(Poco::Util::Application &self);
static Daemon *instance(); static Daemon *instance();
inline void ResetDashboard() { DB_.Reset(); } inline DeviceDashboard & GetDashboard() { return DB_; }
inline void CreateDashboard() { DB_.Create(); }
inline const FMSObjects::DeviceReport & GetDashboard() { return DB_.Report(); }
private: private:
static Daemon *instance_; static Daemon *instance_;
@@ -40,9 +40,6 @@ namespace OpenWifi {
}; };
inline Daemon * Daemon() { return Daemon::instance(); } inline Daemon * Daemon() { return Daemon::instance(); }
inline void DaemonPostInitialization(Poco::Util::Application &self) {
Daemon()->PostInitialization(self);
}
} }
#endif //UCENTRALFWS_DAEMON_H #endif //UCENTRALFWS_DAEMON_H

View File

@@ -4,15 +4,48 @@
#include "Dashboard.h" #include "Dashboard.h"
#include "StorageService.h" #include "StorageService.h"
#include "framework/utils.h"
namespace OpenWifi { namespace OpenWifi {
void DeviceDashboard::Create() {
uint64_t Now = OpenWifi::Now();
if(LastRun_==0 || (Now-LastRun_)>120) { bool DeviceDashboard::Get(FMSObjects::DeviceReport &D, Poco::Logger & Logger) {
DB_.reset(); uint64_t Now = Utils::Now();
StorageService()->DevicesDB().GenerateDeviceReport(DB_); if(!ValidDashboard_ || LastRun_==0 || (Now-LastRun_)>120) {
LastRun_ = Now; Generate(D, Logger);
} } else {
} std::lock_guard G(DataMutex_);
D = DB_;
}
return ValidDashboard_;
};
void DeviceDashboard::Generate(FMSObjects::DeviceReport &D, Poco::Logger & Logger ) {
if (GeneratingDashboard_.load()) {
// std::cout << "Trying to generate dashboard but already being generated" << std::endl;
while(GeneratingDashboard_.load()) {
Poco::Thread::trySleep(100);
}
std::lock_guard G(DataMutex_);
D = DB_;
} else {
GeneratingDashboard_ = true;
ValidDashboard_ = false;
try {
// std::cout << "Generating dashboard." << std::endl;
poco_information(Logger, "DASHBOARD: Generating a new dashboard.");
FMSObjects::DeviceReport NewData;
StorageService()->DevicesDB().GenerateDeviceReport(NewData);
LastRun_ = Utils::Now();
NewData.snapshot = LastRun_;
D = NewData;
std::lock_guard G(DataMutex_);
DB_ = NewData;
ValidDashboard_=true;
} catch(...) {
}
GeneratingDashboard_ = false;
}
}
} }

View File

@@ -2,22 +2,26 @@
// Created by stephane bourque on 2021-07-21. // Created by stephane bourque on 2021-07-21.
// //
#ifndef UCENTRALGW_DASHBOARD_H #pragma once
#define UCENTRALGW_DASHBOARD_H
#include <mutex>
#include "framework/OpenWifiTypes.h" #include "framework/OpenWifiTypes.h"
#include "RESTObjects/RESTAPI_FMSObjects.h" #include "RESTObjects/RESTAPI_FMSObjects.h"
#include "Poco/Logger.h"
namespace OpenWifi { namespace OpenWifi {
class DeviceDashboard { class DeviceDashboard {
public: public:
void Create(); bool Get(FMSObjects::DeviceReport &D, Poco::Logger &Logger);
const FMSObjects::DeviceReport & Report() const { return DB_;}
inline void Reset() { LastRun_=0; DB_.reset(); }
private:
FMSObjects::DeviceReport DB_;
uint64_t LastRun_=0;
};
}
#endif // UCENTRALGW_DASHBOARD_H private:
std::mutex DataMutex_;
volatile std::atomic_bool GeneratingDashboard_ = false;
volatile bool ValidDashboard_ = false;
FMSObjects::DeviceReport DB_;
uint64_t LastRun_ = 0;
void Generate(FMSObjects::DeviceReport &D, Poco::Logger &Logger);
};
}

View File

@@ -2,11 +2,10 @@
// Created by stephane bourque on 2021-07-13. // Created by stephane bourque on 2021-07-13.
// //
#ifndef UCENTRALFMS_DEVICECACHE_H #pragma once
#define UCENTRALFMS_DEVICECACHE_H
#include <string> #include <string>
#include "framework/MicroService.h" #include "framework/SubSystemServer.h"
namespace OpenWifi { namespace OpenWifi {
@@ -43,6 +42,3 @@ namespace OpenWifi {
inline auto DeviceCache() { return DeviceCache::instance(); } inline auto DeviceCache() { return DeviceCache::instance(); }
} }
#endif //UCENTRALFMS_DEVICECACHE_H

View File

@@ -2,14 +2,13 @@
// Created by stephane bourque on 2021-07-26. // Created by stephane bourque on 2021-07-26.
// //
#ifndef UCENTRALFMS_FIRMWARECACHE_H #pragma once
#define UCENTRALFMS_FIRMWARECACHE_H
#include <map> #include <map>
#include <memory> #include <memory>
#include "RESTObjects/RESTAPI_FMSObjects.h" #include "RESTObjects/RESTAPI_FMSObjects.h"
#include "framework/MicroService.h" #include "framework/SubSystemServer.h"
namespace OpenWifi { namespace OpenWifi {
@@ -40,6 +39,3 @@ namespace OpenWifi {
inline auto FirmwareCache() { return FirmwareCache::instance(); } inline auto FirmwareCache() { return FirmwareCache::instance(); }
} }
#endif //UCENTRALFMS_FIRMWARECACHE_H

View File

@@ -2,16 +2,17 @@
// Created by stephane bourque on 2021-07-13. // Created by stephane bourque on 2021-07-13.
// //
#ifndef UCENTRALFMS_LATESTFIRMWARECACHE_H #pragma once
#define UCENTRALFMS_LATESTFIRMWARECACHE_H
#include "Poco/JSON/Object.h" #include "Poco/JSON/Object.h"
#include "Poco/Net/HTTPServerRequest.h" #include "Poco/Net/HTTPServerRequest.h"
#include "Poco/Net/HTTPServerResponse.h" #include "Poco/Net/HTTPServerResponse.h"
#include "Poco/JWT/Signer.h" #include "Poco/JWT/Signer.h"
#include "Poco/SHA2Engine.h" #include "Poco/SHA2Engine.h"
#include "Poco/StringTokenizer.h"
#include "RESTObjects/RESTAPI_SecurityObjects.h" #include "RESTObjects/RESTAPI_SecurityObjects.h"
#include "framework/MicroService.h" #include "framework/SubSystemServer.h"
namespace OpenWifi { namespace OpenWifi {
@@ -42,7 +43,7 @@ namespace OpenWifi {
auto Tokens = Poco::StringTokenizer(Revision,"/", Poco::StringTokenizer::TOK_TRIM); auto Tokens = Poco::StringTokenizer(Revision,"/", Poco::StringTokenizer::TOK_TRIM);
if(Tokens.count()!=2) if(Tokens.count()!=2)
return false; return false;
return (Tokens[1].substr(0,5) == "IP-v"); return (Tokens[1].substr(0,5) == "TIP-v");
} }
void DumpCache(); void DumpCache();
@@ -64,6 +65,3 @@ namespace OpenWifi {
inline auto LatestFirmwareCache() { return LatestFirmwareCache::instance(); } inline auto LatestFirmwareCache() { return LatestFirmwareCache::instance(); }
} }
#endif //UCENTRALFMS_LATESTFIRMWARECACHE_H

View File

@@ -14,6 +14,9 @@
#include "StorageService.h" #include "StorageService.h"
#include "LatestFirmwareCache.h" #include "LatestFirmwareCache.h"
#include "framework/utils.h"
#include "fmt/format.h"
namespace OpenWifi { namespace OpenWifi {
void ManifestCreator::onTimer([[maybe_unused]] Poco::Timer &timer) { void ManifestCreator::onTimer([[maybe_unused]] Poco::Timer &timer) {
@@ -29,7 +32,7 @@ namespace OpenWifi {
bool ManifestCreator::ComputeManifest(S3BucketContent &BucketContent) { bool ManifestCreator::ComputeManifest(S3BucketContent &BucketContent) {
uint64_t Limit = OpenWifi::Now() - MaxAge_, Rejected=0, Accepted=0, BadFormat=0, MissingJson=0; uint64_t Limit = Utils::Now() - MaxAge_, Rejected=0, Accepted=0, BadFormat=0, MissingJson=0;
for(auto &[Name,Entry]:BucketContent) { for(auto &[Name,Entry]:BucketContent) {
std::string C = Entry.S3ContentManifest; std::string C = Entry.S3ContentManifest;
@@ -89,10 +92,10 @@ namespace OpenWifi {
continue; continue;
if(BucketEntry.Valid && !StorageService()->FirmwaresDB().GetFirmwareByName(R,BucketEntry.Compatible,F)) { if(BucketEntry.Valid && !StorageService()->FirmwaresDB().GetFirmwareByName(R,BucketEntry.Compatible,F)) {
F.id = MicroService::instance().CreateUUID(); F.id = MicroServiceCreateUUID();
F.release = Release; F.release = Release;
F.size = BucketEntry.S3Size; F.size = BucketEntry.S3Size;
F.created = OpenWifi::Now(); F.created = Utils::Now();
F.imageDate = BucketEntry.S3TimeStamp; F.imageDate = BucketEntry.S3TimeStamp;
F.image = BucketEntry.Image; F.image = BucketEntry.Image;
F.uri = BucketEntry.URI; F.uri = BucketEntry.URI;
@@ -109,14 +112,14 @@ namespace OpenWifi {
int ManifestCreator::Start() { int ManifestCreator::Start() {
Running_ = true; Running_ = true;
S3BucketName_ = MicroService::instance().ConfigGetString("s3.bucketname"); S3BucketName_ = MicroServiceConfigGetString("s3.bucketname","");
S3Region_ = MicroService::instance().ConfigGetString("s3.region"); S3Region_ = MicroServiceConfigGetString("s3.region","");
S3Secret_ = MicroService::instance().ConfigGetString("s3.secret"); S3Secret_ = MicroServiceConfigGetString("s3.secret","");
S3Key_ = MicroService::instance().ConfigGetString("s3.key"); S3Key_ = MicroServiceConfigGetString("s3.key","");
S3Retry_ = MicroService::instance().ConfigGetInt("s3.retry",60); S3Retry_ = MicroServiceConfigGetInt("s3.retry",60);
DBRefresh_ = MicroService::instance().ConfigGetInt("firmwaredb.refresh",30*60); DBRefresh_ = MicroServiceConfigGetInt("firmwaredb.refresh",30*60);
MaxAge_ = MicroService::instance().ConfigGetInt("firmwaredb.maxage",90) * 24 * 60 * 60; MaxAge_ = MicroServiceConfigGetInt("firmwaredb.maxage",90) * 24 * 60 * 60;
AwsConfig_.enableTcpKeepAlive = true; AwsConfig_.enableTcpKeepAlive = true;
AwsConfig_.enableEndpointDiscovery = true; AwsConfig_.enableEndpointDiscovery = true;
@@ -169,7 +172,7 @@ namespace OpenWifi {
static const std::string UPGRADE("-upgrade.bin"); static const std::string UPGRADE("-upgrade.bin");
std::string URIBase = "https://"; std::string URIBase = "https://";
URIBase += MicroService::instance().ConfigGetString("s3.bucket.uri"); URIBase += MicroServiceConfigGetString("s3.bucket.uri","");
Bucket.clear(); Bucket.clear();

View File

@@ -2,14 +2,13 @@
// Created by stephane bourque on 2021-06-02. // Created by stephane bourque on 2021-06-02.
// //
#ifndef UCENTRALFWS_MANIFESTCREATOR_H #pragma once
#define UCENTRALFWS_MANIFESTCREATOR_H
#include <aws/core/Aws.h> #include <aws/core/Aws.h>
#include <aws/s3/S3Client.h> #include <aws/s3/S3Client.h>
#include <aws/core/auth/AWSCredentials.h> #include <aws/core/auth/AWSCredentials.h>
#include "framework/MicroService.h" #include "framework/SubSystemServer.h"
#include "Poco/Timer.h" #include "Poco/Timer.h"
namespace OpenWifi { namespace OpenWifi {
@@ -71,5 +70,3 @@ namespace OpenWifi {
inline auto ManifestCreator() { return ManifestCreator::instance(); }; inline auto ManifestCreator() { return ManifestCreator::instance(); };
} }
#endif //UCENTRALFWS_MANIFESTCREATOR_H

View File

@@ -5,6 +5,10 @@
#include "NewCommandHandler.h" #include "NewCommandHandler.h"
#include "StorageService.h" #include "StorageService.h"
#include "framework/KafkaManager.h"
#include "fmt/format.h"
#include "nlohmann/json.hpp"
namespace OpenWifi { namespace OpenWifi {
void NewCommandHandler::run() { void NewCommandHandler::run() {

View File

@@ -2,10 +2,9 @@
// Created by stephane bourque on 2021-11-21. // Created by stephane bourque on 2021-11-21.
// //
#ifndef OWFMS_NEWCOMMANDHANDLER_H #pragma once
#define OWFMS_NEWCOMMANDHANDLER_H
#include "framework/MicroService.h" #include "framework/SubSystemServer.h"
#include "framework/OpenWifiTypes.h" #include "framework/OpenWifiTypes.h"
namespace OpenWifi { namespace OpenWifi {
@@ -37,5 +36,3 @@ namespace OpenWifi {
inline auto NewCommandHandler() { return NewCommandHandler::instance(); }; inline auto NewCommandHandler() { return NewCommandHandler::instance(); };
} }
#endif //OWFMS_NEWCOMMANDHANDLER_H

View File

@@ -13,6 +13,9 @@
#include "DeviceCache.h" #include "DeviceCache.h"
#include "AutoUpdater.h" #include "AutoUpdater.h"
#include "framework/KafkaManager.h"
#include "fmt/format.h"
/* /*
{ "system" : { "id" : 6715803232063 , "host" : "https://localhost:17002" } , { "system" : { "id" : 6715803232063 , "host" : "https://localhost:17002" } ,
"payload" : "{"capabilities":{"compatible":"linksys_ea8300","model":"Linksys EA8300 (Dallas)","network":{"lan":["eth0"],"wan":["eth1"]},"platform":"ap","switch":{"switch0":{"enable":true,"ports":[{"device":"eth0","need_tag":false,"num":0,"want_untag":true},{"num":1,"role":"lan"},{"num":2,"role":"lan"},{"num":3,"role":"lan"},{"num":4,"role":"lan"}],"reset":true,"roles":[{"device":"eth0","ports":"1 2 3 4 0","role":"lan"}]}},"wifi":{"platform/soc/a000000.wifi":{"band":["2G"],"channels":[1,2,3,4,5,6,7,8,9,10,11],"frequencies":[2412,2417,2422,2427,2432,2437,2442,2447,2452,2457,2462],"ht_capa":6639,"htmode":["HT20","HT40","VHT20","VHT40","VHT80"],"rx_ant":3,"tx_ant":3,"vht_capa":865687986},"platform/soc/a800000.wifi":{"band":["5G"],"channels":[36,40,44,48,52,56,60,64],"frequencies":[5180,5200,5220,5240,5260,5280,5300,5320],"ht_capa":6639,"htmode":["HT20","HT40","VHT20","VHT40","VHT80"],"rx_ant":3,"tx_ant":3,"vht_capa":865687986},"soc/40000000.pci/pci0000:00/0000:00:00.0/0000:01:00.0":{"band":["5G"],"channels":[100,104,108,112,116,120,124,128,132,136,140,144,149,153,157,161,165],"frequencies":[5500,5520,5540,5560,5580,5600,5620,5640,5660,5680,5700,5720,5745,5765,5785,5805,5825],"ht_capa":6639,"htmode":["HT20","HT40","VHT20","VHT40","VHT80"],"rx_ant":3,"tx_ant":3,"vht_capa":865696178}}},"firmware":"OpenWrt 21.02-SNAPSHOT r16011+53-6fd65c6573 / TIP-devel-0825cb93","serial":"24f5a207a130","uuid":1623866223}} "payload" : "{"capabilities":{"compatible":"linksys_ea8300","model":"Linksys EA8300 (Dallas)","network":{"lan":["eth0"],"wan":["eth1"]},"platform":"ap","switch":{"switch0":{"enable":true,"ports":[{"device":"eth0","need_tag":false,"num":0,"want_untag":true},{"num":1,"role":"lan"},{"num":2,"role":"lan"},{"num":3,"role":"lan"},{"num":4,"role":"lan"}],"reset":true,"roles":[{"device":"eth0","ports":"1 2 3 4 0","role":"lan"}]}},"wifi":{"platform/soc/a000000.wifi":{"band":["2G"],"channels":[1,2,3,4,5,6,7,8,9,10,11],"frequencies":[2412,2417,2422,2427,2432,2437,2442,2447,2452,2457,2462],"ht_capa":6639,"htmode":["HT20","HT40","VHT20","VHT40","VHT80"],"rx_ant":3,"tx_ant":3,"vht_capa":865687986},"platform/soc/a800000.wifi":{"band":["5G"],"channels":[36,40,44,48,52,56,60,64],"frequencies":[5180,5200,5220,5240,5260,5280,5300,5320],"ht_capa":6639,"htmode":["HT20","HT40","VHT20","VHT40","VHT80"],"rx_ant":3,"tx_ant":3,"vht_capa":865687986},"soc/40000000.pci/pci0000:00/0000:00:00.0/0000:01:00.0":{"band":["5G"],"channels":[100,104,108,112,116,120,124,128,132,136,140,144,149,153,157,161,165],"frequencies":[5500,5520,5540,5560,5580,5600,5620,5640,5660,5680,5700,5720,5745,5765,5785,5805,5825],"ht_capa":6639,"htmode":["HT20","HT40","VHT20","VHT40","VHT80"],"rx_ant":3,"tx_ant":3,"vht_capa":865696178}}},"firmware":"OpenWrt 21.02-SNAPSHOT r16011+53-6fd65c6573 / TIP-devel-0825cb93","serial":"24f5a207a130","uuid":1623866223}}

View File

@@ -2,11 +2,9 @@
// Created by stephane bourque on 2021-07-13. // Created by stephane bourque on 2021-07-13.
// //
#ifndef UCENTRALFMS_NEWCONNECTIONHANDLER_H #pragma once
#define UCENTRALFMS_NEWCONNECTIONHANDLER_H
#include "framework/SubSystemServer.h"
#include "framework/MicroService.h"
#include "framework/OpenWifiTypes.h" #include "framework/OpenWifiTypes.h"
namespace OpenWifi { namespace OpenWifi {
@@ -40,4 +38,3 @@ namespace OpenWifi {
inline auto NewConnectionHandler() { return NewConnectionHandler::instance(); }; inline auto NewConnectionHandler() { return NewConnectionHandler::instance(); };
} }
#endif //UCENTRALFMS_NEWCONNECTIONHANDLER_H

View File

@@ -2,8 +2,7 @@
// Created by stephane bourque on 2021-10-23. // Created by stephane bourque on 2021-10-23.
// //
#include "framework/MicroService.h" #include "framework/RESTAPI_Handler.h"
#include "RESTAPI/RESTAPI_firmwareHandler.h" #include "RESTAPI/RESTAPI_firmwareHandler.h"
#include "RESTAPI/RESTAPI_firmwaresHandler.h" #include "RESTAPI/RESTAPI_firmwaresHandler.h"
#include "RESTAPI/RESTAPI_firmwareAgeHandler.h" #include "RESTAPI/RESTAPI_firmwareAgeHandler.h"
@@ -12,11 +11,13 @@
#include "RESTAPI/RESTAPI_historyHandler.h" #include "RESTAPI/RESTAPI_historyHandler.h"
#include "RESTAPI/RESTAPI_deviceReportHandler.h" #include "RESTAPI/RESTAPI_deviceReportHandler.h"
#include "RESTAPI/RESTAPI_deviceInformation_handler.h" #include "RESTAPI/RESTAPI_deviceInformation_handler.h"
#include "framework/RESTAPI_SystemCommand.h"
#include "framework/RESTAPI_WebSocketServer.h"
namespace OpenWifi { namespace OpenWifi {
Poco::Net::HTTPRequestHandler * RESTAPI_ExtRouter(const std::string &Path, RESTAPIHandler::BindingMap &Bindings, Poco::Net::HTTPRequestHandler * RESTAPI_ExtRouter(const std::string &Path, RESTAPIHandler::BindingMap &Bindings,
Poco::Logger & L, RESTAPI_GenericServer & S, uint64_t TransactionId) { Poco::Logger & L, RESTAPI_GenericServerAccounting & S, uint64_t TransactionId) {
return RESTAPI_Router< return RESTAPI_Router<
RESTAPI_firmwaresHandler, RESTAPI_firmwaresHandler,
RESTAPI_firmwareHandler, RESTAPI_firmwareHandler,
@@ -26,12 +27,13 @@ namespace OpenWifi {
RESTAPI_connectedDeviceHandler, RESTAPI_connectedDeviceHandler,
RESTAPI_historyHandler, RESTAPI_historyHandler,
RESTAPI_deviceReportHandler, RESTAPI_deviceReportHandler,
RESTAPI_deviceInformation_handler RESTAPI_deviceInformation_handler,
RESTAPI_webSocketServer
>(Path,Bindings,L, S, TransactionId); >(Path,Bindings,L, S, TransactionId);
} }
Poco::Net::HTTPRequestHandler * RESTAPI_IntRouter(const std::string &Path, RESTAPIHandler::BindingMap &Bindings, Poco::Net::HTTPRequestHandler * RESTAPI_IntRouter(const std::string &Path, RESTAPIHandler::BindingMap &Bindings,
Poco::Logger & L, RESTAPI_GenericServer & S, uint64_t TransactionId) { Poco::Logger & L, RESTAPI_GenericServerAccounting & S, uint64_t TransactionId) {
return RESTAPI_Router_I< return RESTAPI_Router_I<
RESTAPI_firmwaresHandler, RESTAPI_firmwaresHandler,
RESTAPI_firmwareHandler, RESTAPI_firmwareHandler,

View File

@@ -5,12 +5,12 @@
#ifndef UCENTRALFMS_RESTAPI_CONNECTEDDEVICEHANDLER_H #ifndef UCENTRALFMS_RESTAPI_CONNECTEDDEVICEHANDLER_H
#define UCENTRALFMS_RESTAPI_CONNECTEDDEVICEHANDLER_H #define UCENTRALFMS_RESTAPI_CONNECTEDDEVICEHANDLER_H
#include "framework/MicroService.h" #include "framework/RESTAPI_Handler.h"
namespace OpenWifi { namespace OpenWifi {
class RESTAPI_connectedDeviceHandler : public RESTAPIHandler { class RESTAPI_connectedDeviceHandler : public RESTAPIHandler {
public: public:
RESTAPI_connectedDeviceHandler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServer & Server, uint64_t TransactionId, bool Internal) RESTAPI_connectedDeviceHandler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServerAccounting & Server, uint64_t TransactionId, bool Internal)
: RESTAPIHandler(bindings, L, : RESTAPIHandler(bindings, L,
std::vector<std::string> std::vector<std::string>
{Poco::Net::HTTPRequest::HTTP_GET, {Poco::Net::HTTPRequest::HTTP_GET,

View File

@@ -6,12 +6,12 @@
#define UCENTRALFMS_RESTAPI_CONNECTEDDEVICESHANDLER_H #define UCENTRALFMS_RESTAPI_CONNECTEDDEVICESHANDLER_H
#include "framework/MicroService.h" #include "framework/RESTAPI_Handler.h"
namespace OpenWifi { namespace OpenWifi {
class RESTAPI_connectedDevicesHandler : public RESTAPIHandler { class RESTAPI_connectedDevicesHandler : public RESTAPIHandler {
public: public:
RESTAPI_connectedDevicesHandler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServer & Server, uint64_t TransactionId, bool Internal) RESTAPI_connectedDevicesHandler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServerAccounting & Server, uint64_t TransactionId, bool Internal)
: RESTAPIHandler(bindings, L, : RESTAPIHandler(bindings, L,
std::vector<std::string> std::vector<std::string>
{Poco::Net::HTTPRequest::HTTP_GET, {Poco::Net::HTTPRequest::HTTP_GET,

View File

@@ -4,12 +4,12 @@
#pragma once #pragma once
#include "framework/MicroService.h" #include "framework/RESTAPI_Handler.h"
namespace OpenWifi { namespace OpenWifi {
class RESTAPI_deviceInformation_handler : public RESTAPIHandler { class RESTAPI_deviceInformation_handler : public RESTAPIHandler {
public: public:
RESTAPI_deviceInformation_handler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServer & Server, uint64_t TransactionId, bool Internal) RESTAPI_deviceInformation_handler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServerAccounting & Server, uint64_t TransactionId, bool Internal)
: RESTAPIHandler(bindings, L, : RESTAPIHandler(bindings, L,
std::vector<std::string> std::vector<std::string>
{Poco::Net::HTTPRequest::HTTP_GET, {Poco::Net::HTTPRequest::HTTP_GET,

View File

@@ -9,9 +9,13 @@
namespace OpenWifi { namespace OpenWifi {
void RESTAPI_deviceReportHandler::DoGet() { void RESTAPI_deviceReportHandler::DoGet() {
Daemon()->CreateDashboard(); poco_information(Logger(),fmt::format("GET-DASHBOARD: {}", Requester()));
Poco::JSON::Object O; FMSObjects::DeviceReport Data;
Daemon()->GetDashboard().to_json(O); if(Daemon()->GetDashboard().Get(Data, Logger())) {
ReturnObject(O); Poco::JSON::Object Answer;
Data.to_json(Answer);
return ReturnObject(Answer);
}
return BadRequest(RESTAPI::Errors::InternalError);
} }
} }

View File

@@ -4,12 +4,12 @@
#pragma once #pragma once
#include "framework/MicroService.h" #include "framework/RESTAPI_Handler.h"
namespace OpenWifi { namespace OpenWifi {
class RESTAPI_deviceReportHandler : public RESTAPIHandler { class RESTAPI_deviceReportHandler : public RESTAPIHandler {
public: public:
RESTAPI_deviceReportHandler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServer & Server, uint64_t TransactionId, bool Internal) RESTAPI_deviceReportHandler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServerAccounting & Server, uint64_t TransactionId, bool Internal)
: RESTAPIHandler(bindings, L, : RESTAPIHandler(bindings, L,
std::vector<std::string> std::vector<std::string>
{Poco::Net::HTTPRequest::HTTP_GET, {Poco::Net::HTTPRequest::HTTP_GET,

View File

@@ -5,12 +5,12 @@
#ifndef UCENTRALFMS_RESTAPI_FIRMWAREAGEHANDLER_H #ifndef UCENTRALFMS_RESTAPI_FIRMWAREAGEHANDLER_H
#define UCENTRALFMS_RESTAPI_FIRMWAREAGEHANDLER_H #define UCENTRALFMS_RESTAPI_FIRMWAREAGEHANDLER_H
#include "framework/MicroService.h" #include "framework/RESTAPI_Handler.h"
namespace OpenWifi { namespace OpenWifi {
class RESTAPI_firmwareAgeHandler : public RESTAPIHandler { class RESTAPI_firmwareAgeHandler : public RESTAPIHandler {
public: public:
RESTAPI_firmwareAgeHandler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServer & Server, uint64_t TransactionId, bool Internal) RESTAPI_firmwareAgeHandler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServerAccounting & Server, uint64_t TransactionId, bool Internal)
: RESTAPIHandler(bindings, L, : RESTAPIHandler(bindings, L,
std::vector<std::string> std::vector<std::string>
{Poco::Net::HTTPRequest::HTTP_GET, {Poco::Net::HTTPRequest::HTTP_GET,

View File

@@ -4,9 +4,11 @@
#include "Poco/JSON/Parser.h" #include "Poco/JSON/Parser.h"
#include "RESTAPI_firmwareHandler.h" #include "RESTAPI/RESTAPI_firmwareHandler.h"
#include "StorageService.h" #include "StorageService.h"
#include "framework/ow_constants.h" #include "framework/ow_constants.h"
#include "framework/MicroServiceFuncs.h"
#include "framework/utils.h"
namespace OpenWifi { namespace OpenWifi {
void void
@@ -16,7 +18,7 @@ namespace OpenWifi {
if (!F.from_json(Obj)) { if (!F.from_json(Obj)) {
return BadRequest(RESTAPI::Errors::InvalidJSONDocument); return BadRequest(RESTAPI::Errors::InvalidJSONDocument);
} }
F.id = MicroService::instance().CreateUUID(); F.id = MicroServiceCreateUUID();
if(StorageService()->FirmwaresDB().AddFirmware(F)) { if(StorageService()->FirmwaresDB().AddFirmware(F)) {
Poco::JSON::Object Answer; Poco::JSON::Object Answer;
F.to_json(Answer); F.to_json(Answer);
@@ -78,7 +80,7 @@ namespace OpenWifi {
SecurityObjects::NoteInfoVec NIV; SecurityObjects::NoteInfoVec NIV;
NIV = RESTAPI_utils::to_object_array<SecurityObjects::NoteInfo>(Obj->get(RESTAPI::Protocol::NOTES).toString()); NIV = RESTAPI_utils::to_object_array<SecurityObjects::NoteInfo>(Obj->get(RESTAPI::Protocol::NOTES).toString());
for(auto const &i:NIV) { for(auto const &i:NIV) {
SecurityObjects::NoteInfo ii{.created=(uint64_t)OpenWifi::Now(), .createdBy=UserInfo_.userinfo.email, .note=i.note}; SecurityObjects::NoteInfo ii{.created=(uint64_t)Utils::Now(), .createdBy=UserInfo_.userinfo.email, .note=i.note};
F.notes.push_back(ii); F.notes.push_back(ii);
} }
} }

View File

@@ -5,12 +5,12 @@
#ifndef UCENTRALFWS_RESTAPI_FIRMWAREHANDLER_H #ifndef UCENTRALFWS_RESTAPI_FIRMWAREHANDLER_H
#define UCENTRALFWS_RESTAPI_FIRMWAREHANDLER_H #define UCENTRALFWS_RESTAPI_FIRMWAREHANDLER_H
#include "framework/MicroService.h" #include "framework/RESTAPI_Handler.h"
namespace OpenWifi { namespace OpenWifi {
class RESTAPI_firmwareHandler : public RESTAPIHandler { class RESTAPI_firmwareHandler : public RESTAPIHandler {
public: public:
RESTAPI_firmwareHandler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServer & Server, uint64_t TransactionId, bool Internal) RESTAPI_firmwareHandler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServerAccounting & Server, uint64_t TransactionId, bool Internal)
: RESTAPIHandler(bindings, L, : RESTAPIHandler(bindings, L,
std::vector<std::string> std::vector<std::string>
{Poco::Net::HTTPRequest::HTTP_GET, {Poco::Net::HTTPRequest::HTTP_GET,

View File

@@ -5,12 +5,12 @@
#ifndef UCENTRALFWS_RESTAPI_FIRMWARESHANDLER_H #ifndef UCENTRALFWS_RESTAPI_FIRMWARESHANDLER_H
#define UCENTRALFWS_RESTAPI_FIRMWARESHANDLER_H #define UCENTRALFWS_RESTAPI_FIRMWARESHANDLER_H
#include "framework/MicroService.h" #include "framework/RESTAPI_Handler.h"
namespace OpenWifi { namespace OpenWifi {
class RESTAPI_firmwaresHandler : public RESTAPIHandler { class RESTAPI_firmwaresHandler : public RESTAPIHandler {
public: public:
RESTAPI_firmwaresHandler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServer & Server, uint64_t TransactionId, bool Internal) RESTAPI_firmwaresHandler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServerAccounting & Server, uint64_t TransactionId, bool Internal)
: RESTAPIHandler(bindings, L, : RESTAPIHandler(bindings, L,
std::vector<std::string> std::vector<std::string>
{Poco::Net::HTTPRequest::HTTP_GET, {Poco::Net::HTTPRequest::HTTP_GET,

View File

@@ -4,12 +4,12 @@
#pragma once #pragma once
#include "framework/MicroService.h" #include "framework/RESTAPI_Handler.h"
namespace OpenWifi { namespace OpenWifi {
class RESTAPI_historyHandler : public RESTAPIHandler { class RESTAPI_historyHandler : public RESTAPIHandler {
public: public:
RESTAPI_historyHandler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServer & Server, uint64_t TransactionId, bool Internal) RESTAPI_historyHandler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServerAccounting & Server, uint64_t TransactionId, bool Internal)
: RESTAPIHandler(bindings, L, : RESTAPIHandler(bindings, L,
std::vector<std::string> std::vector<std::string>
{Poco::Net::HTTPRequest::HTTP_GET, {Poco::Net::HTTPRequest::HTTP_GET,

View File

@@ -4,7 +4,7 @@
#include "RESTAPI_AnalyticsObjects.h" #include "RESTAPI_AnalyticsObjects.h"
#include "RESTAPI_ProvObjects.h" #include "RESTAPI_ProvObjects.h"
#include "framework/MicroService.h" #include "framework/RESTAPI_utils.h"
using OpenWifi::RESTAPI_utils::field_to_json; using OpenWifi::RESTAPI_utils::field_to_json;
using OpenWifi::RESTAPI_utils::field_from_json; using OpenWifi::RESTAPI_utils::field_from_json;

View File

@@ -5,6 +5,7 @@
#pragma once #pragma once
#include "RESTAPI_ProvObjects.h" #include "RESTAPI_ProvObjects.h"
#include "framework/utils.h"
#include <vector> #include <vector>
namespace OpenWifi { namespace OpenWifi {
@@ -375,7 +376,7 @@ namespace OpenWifi {
}; };
struct WifiClientHistory { struct WifiClientHistory {
uint64_t timestamp=OpenWifi::Now(); uint64_t timestamp=Utils::Now();
std::string station_id; std::string station_id;
std::string bssid; std::string bssid;
std::string ssid; std::string ssid;

View File

@@ -3,7 +3,7 @@
// //
#include "RESTAPI_CertObjects.h" #include "RESTAPI_CertObjects.h"
#include "framework/MicroService.h" #include "framework/RESTAPI_utils.h"
using OpenWifi::RESTAPI_utils::field_to_json; using OpenWifi::RESTAPI_utils::field_to_json;
using OpenWifi::RESTAPI_utils::field_from_json; using OpenWifi::RESTAPI_utils::field_from_json;
@@ -154,6 +154,7 @@ namespace OpenWifi::CertObjects {
field_to_json(Obj,"submitted", submitted); field_to_json(Obj,"submitted", submitted);
field_to_json(Obj,"started", started); field_to_json(Obj,"started", started);
field_to_json(Obj,"completed", completed); field_to_json(Obj,"completed", completed);
field_to_json(Obj,"requesterUsername", requesterUsername);
} }
bool JobEntry::from_json(const Poco::JSON::Object::Ptr &Obj) { bool JobEntry::from_json(const Poco::JSON::Object::Ptr &Obj) {
@@ -171,6 +172,7 @@ namespace OpenWifi::CertObjects {
field_from_json(Obj,"submitted", submitted); field_from_json(Obj,"submitted", submitted);
field_from_json(Obj,"started", started); field_from_json(Obj,"started", started);
field_from_json(Obj,"completed", completed); field_from_json(Obj,"completed", completed);
field_from_json(Obj,"requesterUsername", requesterUsername);
return true; return true;
} catch (...) { } catch (...) {
} }

View File

@@ -91,6 +91,7 @@ namespace OpenWifi::CertObjects {
uint64_t submitted=0; uint64_t submitted=0;
uint64_t started=0; uint64_t started=0;
uint64_t completed=0; uint64_t completed=0;
std::string requesterUsername;
void to_json(Poco::JSON::Object &Obj) const; void to_json(Poco::JSON::Object &Obj) const;
bool from_json(const Poco::JSON::Object::Ptr &Obj); bool from_json(const Poco::JSON::Object::Ptr &Obj);

View File

@@ -3,7 +3,8 @@
// //
#include "RESTAPI_FMSObjects.h" #include "RESTAPI_FMSObjects.h"
#include "framework/MicroService.h" #include "framework/RESTAPI_utils.h"
#include "framework/utils.h"
using OpenWifi::RESTAPI_utils::field_to_json; using OpenWifi::RESTAPI_utils::field_to_json;
using OpenWifi::RESTAPI_utils::field_from_json; using OpenWifi::RESTAPI_utils::field_from_json;
@@ -233,7 +234,7 @@ namespace OpenWifi::FMSObjects {
UnknownFirmwares_.clear(); UnknownFirmwares_.clear();
totalSecondsOld_.clear(); totalSecondsOld_.clear();
numberOfDevices = 0 ; numberOfDevices = 0 ;
snapshot = OpenWifi::Now(); snapshot = Utils::Now();
} }
bool DeviceReport::from_json([[maybe_unused]] const Poco::JSON::Object::Ptr &Obj) { bool DeviceReport::from_json([[maybe_unused]] const Poco::JSON::Object::Ptr &Obj) {

View File

@@ -11,12 +11,13 @@
#include "Daemon.h" #include "Daemon.h"
#ifdef TIP_GATEWAY_SERVICE #ifdef TIP_GATEWAY_SERVICE
#include "DeviceRegistry.h" #include "AP_WS_Server.h"
#include "CapabilitiesCache.h" #include "CapabilitiesCache.h"
#endif #endif
#include "RESTAPI_GWobjects.h" #include "RESTAPI_GWobjects.h"
#include "framework/MicroService.h" #include "framework/RESTAPI_utils.h"
#include "framework/utils.h"
using OpenWifi::RESTAPI_utils::field_to_json; using OpenWifi::RESTAPI_utils::field_to_json;
using OpenWifi::RESTAPI_utils::field_from_json; using OpenWifi::RESTAPI_utils::field_from_json;
@@ -49,6 +50,10 @@ namespace OpenWifi::GWObjects {
field_to_json(Obj,"entity", entity); field_to_json(Obj,"entity", entity);
field_to_json(Obj,"modified", modified); field_to_json(Obj,"modified", modified);
field_to_json(Obj,"locale", locale); field_to_json(Obj,"locale", locale);
field_to_json(Obj,"restrictedDevice", restrictedDevice);
field_to_json(Obj,"pendingConfiguration", pendingConfiguration);
field_to_json(Obj,"pendingConfigurationCmd", pendingConfigurationCmd);
field_to_json(Obj,"restrictionDetails", restrictionDetails);
} }
void Device::to_json_with_status(Poco::JSON::Object &Obj) const { void Device::to_json_with_status(Poco::JSON::Object &Obj) const {
@@ -57,7 +62,7 @@ namespace OpenWifi::GWObjects {
#ifdef TIP_GATEWAY_SERVICE #ifdef TIP_GATEWAY_SERVICE
ConnectionState ConState; ConnectionState ConState;
if (DeviceRegistry()->GetState(SerialNumber, ConState)) { if (AP_WS_Server()->GetState(SerialNumber, ConState)) {
ConState.to_json(Obj); ConState.to_json(Obj);
} else { } else {
field_to_json(Obj,"ipAddress", ""); field_to_json(Obj,"ipAddress", "");
@@ -69,6 +74,7 @@ namespace OpenWifi::GWObjects {
field_to_json(Obj,"verifiedCertificate", "NO_CERTIFICATE"); field_to_json(Obj,"verifiedCertificate", "NO_CERTIFICATE");
field_to_json(Obj,"associations_2G", (uint64_t) 0); field_to_json(Obj,"associations_2G", (uint64_t) 0);
field_to_json(Obj,"associations_5G", (uint64_t) 0); field_to_json(Obj,"associations_5G", (uint64_t) 0);
field_to_json(Obj,"associations_6G", (uint64_t) 0);
} }
#endif #endif
} }
@@ -88,6 +94,10 @@ namespace OpenWifi::GWObjects {
field_from_json(Obj,"subscriber", subscriber); field_from_json(Obj,"subscriber", subscriber);
field_from_json(Obj,"entity", entity); field_from_json(Obj,"entity", entity);
field_from_json(Obj,"locale", locale); field_from_json(Obj,"locale", locale);
field_from_json(Obj,"restrictedDevice", restrictedDevice);
field_from_json(Obj,"pendingConfiguration", pendingConfiguration);
field_from_json(Obj,"pendingConfigurationCmd", pendingConfigurationCmd);
field_from_json(Obj,"restrictionDetails", restrictionDetails);
return true; return true;
} catch (const Poco::Exception &E) { } catch (const Poco::Exception &E) {
} }
@@ -198,6 +208,7 @@ namespace OpenWifi::GWObjects {
field_to_json(Obj,"lastContact", LastContact); field_to_json(Obj,"lastContact", LastContact);
field_to_json(Obj,"associations_2G", Associations_2G); field_to_json(Obj,"associations_2G", Associations_2G);
field_to_json(Obj,"associations_5G", Associations_5G); field_to_json(Obj,"associations_5G", Associations_5G);
field_to_json(Obj,"associations_6G", Associations_6G);
field_to_json(Obj,"webSocketClients", webSocketClients); field_to_json(Obj,"webSocketClients", webSocketClients);
field_to_json(Obj,"websocketPackets", websocketPackets); field_to_json(Obj,"websocketPackets", websocketPackets);
field_to_json(Obj,"kafkaClients", kafkaClients); field_to_json(Obj,"kafkaClients", kafkaClients);
@@ -206,7 +217,8 @@ namespace OpenWifi::GWObjects {
field_to_json(Obj,"started", started); field_to_json(Obj,"started", started);
field_to_json(Obj,"sessionId", sessionId); field_to_json(Obj,"sessionId", sessionId);
field_to_json(Obj,"connectionCompletionTime", connectionCompletionTime); field_to_json(Obj,"connectionCompletionTime", connectionCompletionTime);
field_to_json(Obj,"totalConnectionTime", OpenWifi::Now() - started); field_to_json(Obj,"totalConnectionTime", Utils::Now() - started);
field_to_json(Obj,"certificateExpiryDate", certificateExpiryDate);
switch(VerifiedCertificate) { switch(VerifiedCertificate) {
case NO_CERTIFICATE: case NO_CERTIFICATE:
@@ -225,12 +237,14 @@ namespace OpenWifi::GWObjects {
void DeviceConnectionStatistics::to_json(Poco::JSON::Object &Obj) const { void DeviceConnectionStatistics::to_json(Poco::JSON::Object &Obj) const {
field_to_json(Obj,"averageConnectionTime", averageConnectionTime); field_to_json(Obj,"averageConnectionTime", averageConnectionTime);
field_to_json(Obj,"connectedDevices", connectedDevices ); field_to_json(Obj,"connectedDevices", connectedDevices );
field_to_json(Obj,"connectingDevices", connectingDevices );
} }
bool DeviceConnectionStatistics::from_json(const Poco::JSON::Object::Ptr &Obj) { bool DeviceConnectionStatistics::from_json(const Poco::JSON::Object::Ptr &Obj) {
try { try {
field_from_json(Obj,"averageConnectionTime", averageConnectionTime); field_from_json(Obj,"averageConnectionTime", averageConnectionTime);
field_from_json(Obj,"connectedDevices", connectedDevices ); field_from_json(Obj,"connectedDevices", connectedDevices );
field_from_json(Obj,"connectingDevices", connectingDevices );
return true; return true;
} catch (const Poco::Exception &E) { } catch (const Poco::Exception &E) {
} }
@@ -283,7 +297,7 @@ namespace OpenWifi::GWObjects {
lastContact.clear(); lastContact.clear();
associations.clear(); associations.clear();
numberOfDevices = 0 ; numberOfDevices = 0 ;
snapshot = OpenWifi::Now(); snapshot = Utils::Now();
} }
void CapabilitiesModel::to_json(Poco::JSON::Object &Obj) const{ void CapabilitiesModel::to_json(Poco::JSON::Object &Obj) const{
@@ -295,9 +309,12 @@ namespace OpenWifi::GWObjects {
field_to_json(Obj,"serialNumber",serialNumber); field_to_json(Obj,"serialNumber",serialNumber);
field_to_json(Obj,"timeout",timeout); field_to_json(Obj,"timeout",timeout);
field_to_json(Obj,"type",type); field_to_json(Obj,"type",type);
field_to_json(Obj,"script",script);
field_to_json(Obj,"scriptId",scriptId); field_to_json(Obj,"scriptId",scriptId);
field_to_json(Obj,"script",script);
field_to_json(Obj,"when",when); field_to_json(Obj,"when",when);
field_to_json(Obj,"signature", signature);
field_to_json(Obj,"deferred", deferred);
field_to_json(Obj,"uri", uri);
} }
bool ScriptRequest::from_json(const Poco::JSON::Object::Ptr &Obj) { bool ScriptRequest::from_json(const Poco::JSON::Object::Ptr &Obj) {
@@ -308,6 +325,9 @@ namespace OpenWifi::GWObjects {
field_from_json(Obj,"script",script); field_from_json(Obj,"script",script);
field_from_json(Obj,"scriptId",scriptId); field_from_json(Obj,"scriptId",scriptId);
field_from_json(Obj,"when",when); field_from_json(Obj,"when",when);
field_from_json(Obj,"signature", signature);
field_from_json(Obj,"deferred", deferred);
field_from_json(Obj,"uri", uri);
return true; return true;
} catch (const Poco::Exception &E) { } catch (const Poco::Exception &E) {
} }
@@ -379,6 +399,7 @@ namespace OpenWifi::GWObjects {
field_to_json(Obj,"secret",secret); field_to_json(Obj,"secret",secret);
field_to_json(Obj,"certificate",certificate); field_to_json(Obj,"certificate",certificate);
field_to_json(Obj,"radsec",radsec); field_to_json(Obj,"radsec",radsec);
field_to_json(Obj,"allowSelfSigned",allowSelfSigned);
field_to_json(Obj,"radsecPort",radsecPort); field_to_json(Obj,"radsecPort",radsecPort);
field_to_json(Obj,"radsecSecret",radsecSecret); field_to_json(Obj,"radsecSecret",radsecSecret);
field_to_json(Obj,"radsecCacerts",radsecCacerts); field_to_json(Obj,"radsecCacerts",radsecCacerts);
@@ -397,6 +418,7 @@ namespace OpenWifi::GWObjects {
field_from_json(Obj,"secret",secret); field_from_json(Obj,"secret",secret);
field_from_json(Obj,"certificate",certificate); field_from_json(Obj,"certificate",certificate);
field_from_json(Obj,"radsec",radsec); field_from_json(Obj,"radsec",radsec);
field_from_json(Obj,"allowSelfSigned",allowSelfSigned);
field_from_json(Obj,"radsecSecret",radsecSecret); field_from_json(Obj,"radsecSecret",radsecSecret);
field_from_json(Obj,"radsecPort",radsecPort); field_from_json(Obj,"radsecPort",radsecPort);
field_from_json(Obj,"radsecCacerts",radsecCacerts); field_from_json(Obj,"radsecCacerts",radsecCacerts);
@@ -409,5 +431,117 @@ namespace OpenWifi::GWObjects {
} }
return false; return false;
} }
void ScriptEntry::to_json(Poco::JSON::Object &Obj) const {
field_to_json(Obj,"id", id);
field_to_json(Obj,"name", name);
field_to_json(Obj,"description", description);
field_to_json(Obj,"uri", uri);
field_to_json(Obj,"content", content);
field_to_json(Obj,"version", version);
field_to_json(Obj,"type", type);
field_to_json(Obj,"created", created);
field_to_json(Obj,"modified", modified);
field_to_json(Obj,"author", author);
field_to_json(Obj,"restricted", restricted);
field_to_json(Obj,"deferred", deferred);
field_to_json(Obj,"timeout", timeout);
field_to_json(Obj,"defaultUploadURI", defaultUploadURI);
}
bool ScriptEntry::from_json(const Poco::JSON::Object::Ptr &Obj) {
try {
field_from_json(Obj,"id", id);
field_from_json(Obj,"name", name);
field_from_json(Obj,"description", description);
field_from_json(Obj,"uri", uri);
field_from_json(Obj,"content", content);
field_from_json(Obj,"version", version);
field_from_json(Obj,"type", type);
field_from_json(Obj,"created", created);
field_from_json(Obj,"modified", modified);
field_from_json(Obj,"author", author);
field_from_json(Obj,"restricted", restricted);
field_from_json(Obj,"deferred", deferred);
field_from_json(Obj,"timeout", timeout);
field_from_json(Obj,"defaultUploadURI", defaultUploadURI);
return true;
} catch (const Poco::Exception &E) {
}
return false;
}
void ScriptEntryList::to_json(Poco::JSON::Object &Obj) const {
field_to_json(Obj,"scripts",scripts);
}
bool ScriptEntryList::from_json(const Poco::JSON::Object::Ptr &Obj) {
try {
field_from_json(Obj,"scripts",scripts);
return true;
} catch (const Poco::Exception &E) {
}
return false;
}
void DeviceRestrictionsKeyInfo::to_json(Poco::JSON::Object &Obj) const {
field_to_json(Obj,"vendor", vendor);
field_to_json(Obj,"algo", algo);
}
bool DeviceRestrictionsKeyInfo::from_json(const Poco::JSON::Object::Ptr &Obj) {
try {
field_from_json(Obj,"vendor", vendor);
field_from_json(Obj,"algo", algo);
return true;
} catch (const Poco::Exception &E) {
}
return false;
}
void DeviceRestrictions::to_json(Poco::JSON::Object &Obj) const {
field_to_json(Obj,"dfs", dfs);
field_to_json(Obj,"ssh", ssh);
field_to_json(Obj,"rtty", rtty);
field_to_json(Obj,"tty", tty);
field_to_json(Obj,"developer", developer);
field_to_json(Obj,"upgrade", upgrade);
field_to_json(Obj,"commands", commands);
field_to_json(Obj,"country", country);
field_to_json(Obj,"key_info", key_info);
}
bool DeviceRestrictions::from_json(const Poco::JSON::Object::Ptr &Obj) {
try {
field_from_json(Obj,"dfs", dfs);
field_from_json(Obj,"ssh", ssh);
field_from_json(Obj,"rtty", rtty);
field_from_json(Obj,"tty", tty);
field_from_json(Obj,"developer", developer);
field_from_json(Obj,"upgrade", upgrade);
field_from_json(Obj,"commands", commands);
field_from_json(Obj,"country", country);
field_from_json(Obj,"key_info", key_info);
return true;
} catch (const Poco::Exception &E) {
}
return false;
}
bool DeviceRestrictionsKeyInfo::operator!=(const OpenWifi::GWObjects::DeviceRestrictionsKeyInfo &T) const {
return (T.algo!=algo) || (T.vendor!=vendor);
}
bool DeviceRestrictions::operator!=(const OpenWifi::GWObjects::DeviceRestrictions &T) const {
return ( (T.dfs!=dfs) ||
(T.rtty!=rtty) ||
(T.upgrade!=upgrade) ||
(T.commands != commands) ||
(T.developer != developer) ||
(T.ssh !=ssh) ||
(T.key_info != key_info) ||
(T.country != country) );
}
} }

View File

@@ -28,23 +28,52 @@ namespace OpenWifi::GWObjects {
uint64_t TX = 0, RX = 0; uint64_t TX = 0, RX = 0;
uint64_t Associations_2G=0; uint64_t Associations_2G=0;
uint64_t Associations_5G=0; uint64_t Associations_5G=0;
uint64_t Associations_6G=0;
bool Connected = false; bool Connected = false;
uint64_t LastContact=0; uint64_t LastContact=0;
std::string Firmware; std::string Firmware;
CertificateValidation VerifiedCertificate = NO_CERTIFICATE; CertificateValidation VerifiedCertificate = NO_CERTIFICATE;
std::string Compatible; std::string Compatible;
uint64_t kafkaClients=0; uint64_t kafkaClients=0;
uint64_t webSocketClients=0; uint64_t webSocketClients=0;
uint64_t kafkaPackets=0; uint64_t kafkaPackets=0;
uint64_t websocketPackets=0; uint64_t websocketPackets=0;
std::string locale; std::string locale;
uint64_t started=0; uint64_t started=0;
uint64_t sessionId=0; uint64_t sessionId=0;
double connectionCompletionTime=0.0; double connectionCompletionTime=0.0;
std::uint64_t certificateExpiryDate=0;
void to_json(Poco::JSON::Object &Obj) const; void to_json(Poco::JSON::Object &Obj) const;
}; };
struct DeviceRestrictionsKeyInfo {
std::string vendor;
std::string algo;
bool operator !=(const DeviceRestrictionsKeyInfo &b) const;
void to_json(Poco::JSON::Object &Obj) const;
bool from_json(const Poco::JSON::Object::Ptr &Obj);
};
struct DeviceRestrictions {
bool dfs = false;
bool ssh = false;
bool rtty = false;
bool tty = false;
bool developer = false;
bool upgrade = false;
bool commands = false;
std::vector<std::string> country;
DeviceRestrictionsKeyInfo key_info;
bool operator !=(const DeviceRestrictions &D) const;
void to_json(Poco::JSON::Object &Obj) const;
bool from_json(const Poco::JSON::Object::Ptr &Obj);
};
struct Device { struct Device {
std::string SerialNumber; std::string SerialNumber;
std::string DeviceType; std::string DeviceType;
@@ -68,6 +97,10 @@ namespace OpenWifi::GWObjects {
std::string entity; std::string entity;
uint64_t modified=0; uint64_t modified=0;
std::string locale; std::string locale;
bool restrictedDevice=false;
std::string pendingConfiguration;
std::string pendingConfigurationCmd;
DeviceRestrictions restrictionDetails;
void to_json(Poco::JSON::Object &Obj) const; void to_json(Poco::JSON::Object &Obj) const;
void to_json_with_status(Poco::JSON::Object &Obj) const; void to_json_with_status(Poco::JSON::Object &Obj) const;
@@ -78,6 +111,8 @@ namespace OpenWifi::GWObjects {
struct DeviceConnectionStatistics { struct DeviceConnectionStatistics {
std::uint64_t connectedDevices = 0; std::uint64_t connectedDevices = 0;
std::uint64_t averageConnectionTime = 0; std::uint64_t averageConnectionTime = 0;
std::uint64_t connectingDevices = 0;
void to_json(Poco::JSON::Object &Obj) const; void to_json(Poco::JSON::Object &Obj) const;
bool from_json(const Poco::JSON::Object::Ptr &Obj); bool from_json(const Poco::JSON::Object::Ptr &Obj);
}; };
@@ -211,13 +246,44 @@ namespace OpenWifi::GWObjects {
void to_json(Poco::JSON::Object &Obj) const; void to_json(Poco::JSON::Object &Obj) const;
}; };
struct ScriptEntry {
std::string id;
std::string name;
std::string description;
std::string uri;
std::string content;
std::string version;
std::string type;
std::uint64_t created;
std::uint64_t modified;
std::string author;
Types::StringVec restricted;
bool deferred=false;
std::uint64_t timeout=30;
std::string defaultUploadURI;
void to_json(Poco::JSON::Object &Obj) const;
bool from_json(const Poco::JSON::Object::Ptr &Obj);
};
struct ScriptEntryList {
std::vector<ScriptEntry> scripts;
void to_json(Poco::JSON::Object &Obj) const;
bool from_json(const Poco::JSON::Object::Ptr &Obj);
};
struct ScriptRequest { struct ScriptRequest {
uint64_t timeout=30;
std::string serialNumber; std::string serialNumber;
uint64_t timeout=30;
std::string type; std::string type;
std::string script; std::string script;
std::string scriptId; std::string scriptId;
uint64_t when=0; std::uint64_t when;
std::string signature;
bool deferred;
std::string uri;
void to_json(Poco::JSON::Object &Obj) const; void to_json(Poco::JSON::Object &Obj) const;
bool from_json(const Poco::JSON::Object::Ptr &Obj); bool from_json(const Poco::JSON::Object::Ptr &Obj);
}; };
@@ -230,6 +296,7 @@ namespace OpenWifi::GWObjects {
std::string secret; std::string secret;
std::string certificate; std::string certificate;
bool radsec=false; bool radsec=false;
bool allowSelfSigned=false;
uint16_t radsecPort=2083; uint16_t radsecPort=2083;
std::string radsecSecret; std::string radsecSecret;
std::string radsecKey; std::string radsecKey;
@@ -271,4 +338,5 @@ namespace OpenWifi::GWObjects {
void to_json(Poco::JSON::Object &Obj) const; void to_json(Poco::JSON::Object &Obj) const;
bool from_json(const Poco::JSON::Object::Ptr &Obj); bool from_json(const Poco::JSON::Object::Ptr &Obj);
}; };
} }

View File

@@ -0,0 +1,110 @@
//
// Created by stephane bourque on 2021-08-31.
//
#include "framework/RESTAPI_utils.h"
using OpenWifi::RESTAPI_utils::field_to_json;
using OpenWifi::RESTAPI_utils::field_from_json;
using OpenWifi::RESTAPI_utils::EmbedDocument;
#include "RESTAPI_OWLSobjects.h"
// SIM -> 0x53/0x073, 0x49/0x69, 0x4d/0x6d
namespace OpenWifi::OWLSObjects {
void SimulationDetails::to_json(Poco::JSON::Object &Obj) const {
field_to_json(Obj,"id", id);
field_to_json(Obj,"name", name);
field_to_json(Obj,"gateway", gateway);
field_to_json(Obj,"certificate", certificate);
field_to_json(Obj,"key", key);
field_to_json(Obj,"macPrefix", macPrefix);
field_to_json(Obj,"deviceType", deviceType);
field_to_json(Obj,"devices", devices);
field_to_json(Obj,"healthCheckInterval", healthCheckInterval);
field_to_json(Obj,"stateInterval", stateInterval);
field_to_json(Obj,"minAssociations", minAssociations);
field_to_json(Obj,"maxAssociations", maxAssociations);
field_to_json(Obj,"minClients", minClients);
field_to_json(Obj,"maxClients", maxClients);
field_to_json(Obj,"simulationLength", simulationLength);
field_to_json(Obj,"threads", threads);
field_to_json(Obj,"clientInterval", clientInterval);
field_to_json(Obj,"keepAlive", keepAlive);
field_to_json(Obj,"reconnectInterval", reconnectInterval);
field_to_json(Obj,"concurrentDevices", concurrentDevices);
}
bool SimulationDetails::from_json(const Poco::JSON::Object::Ptr &Obj) {
try {
field_from_json(Obj,"id", id);
field_from_json(Obj,"name", name);
field_from_json(Obj,"gateway", gateway);
field_from_json(Obj,"certificate", certificate);
field_from_json(Obj,"key", key);
field_from_json(Obj,"macPrefix", macPrefix);
field_from_json(Obj,"deviceType", deviceType);
field_from_json(Obj,"devices", devices);
field_from_json(Obj,"healthCheckInterval", healthCheckInterval);
field_from_json(Obj,"stateInterval", stateInterval);
field_from_json(Obj,"minAssociations", minAssociations);
field_from_json(Obj,"maxAssociations", maxAssociations);
field_from_json(Obj,"minClients", minClients);
field_from_json(Obj,"maxClients", maxClients);
field_from_json(Obj,"simulationLength", simulationLength);
field_from_json(Obj,"threads", threads);
field_from_json(Obj,"clientInterval", clientInterval);
field_from_json(Obj,"keepAlive", keepAlive);
field_from_json(Obj,"reconnectInterval", reconnectInterval);
field_from_json(Obj,"concurrentDevices", concurrentDevices);
return true;
} catch(...) {
}
return false;
}
void SimulationDetailsList::to_json(Poco::JSON::Object &Obj) const {
field_to_json(Obj,"list", list);
}
bool SimulationDetailsList::from_json(const Poco::JSON::Object::Ptr &Obj) {
try {
field_from_json(Obj,"list", list);
return true;
} catch(...) {
}
return false;
}
void SimulationStatus::to_json(Poco::JSON::Object &Obj) const {
field_to_json(Obj,"id", id);
field_to_json(Obj,"simulationId", simulationId);
field_to_json(Obj,"state", state);
field_to_json(Obj,"tx", tx);
field_to_json(Obj,"rx", rx);
field_to_json(Obj,"msgsTx", msgsTx);
field_to_json(Obj,"msgsRx", msgsRx);
field_to_json(Obj,"liveDevices", liveDevices);
field_to_json(Obj,"timeToFullDevices", timeToFullDevices);
field_to_json(Obj,"startTime", startTime);
field_to_json(Obj,"endTime", endTime);
field_to_json(Obj,"errorDevices", errorDevices);
field_to_json(Obj,"owner", owner);
}
void Dashboard::to_json([[maybe_unused]] Poco::JSON::Object &Obj) const {
}
bool Dashboard::from_json([[maybe_unused]] const Poco::JSON::Object::Ptr &Obj) {
return true;
}
void Dashboard::reset() {
}
}

View File

@@ -0,0 +1,77 @@
//
// Created by stephane bourque on 2021-08-31.
//
#ifndef UCENTRALSIM_RESTAPI_OWLSOBJECTS_H
#define UCENTRALSIM_RESTAPI_OWLSOBJECTS_H
#include <vector>
#include "Poco/JSON/Object.h"
namespace OpenWifi::OWLSObjects {
struct SimulationDetails {
std::string id;
std::string name;
std::string gateway;
std::string certificate;
std::string key;
std::string macPrefix;
std::string deviceType;
uint64_t devices = 5;
uint64_t healthCheckInterval = 60;
uint64_t stateInterval = 60 ;
uint64_t minAssociations = 1;
uint64_t maxAssociations = 3;
uint64_t minClients = 1 ;
uint64_t maxClients = 3;
uint64_t simulationLength = 60 * 60;
uint64_t threads = 16;
uint64_t clientInterval = 1;
uint64_t keepAlive = 300;
uint64_t reconnectInterval = 30 ;
uint64_t concurrentDevices = 5;
void to_json(Poco::JSON::Object &Obj) const;
bool from_json(const Poco::JSON::Object::Ptr &Obj);
};
struct SimulationDetailsList {
std::vector<SimulationDetails> list;
void to_json(Poco::JSON::Object &Obj) const;
bool from_json(const Poco::JSON::Object::Ptr &Obj);
};
struct SimulationStatus {
std::string id;
std::string simulationId;
std::string state;
uint64_t tx;
uint64_t rx;
uint64_t msgsTx;
uint64_t msgsRx;
uint64_t liveDevices;
uint64_t timeToFullDevices;
uint64_t startTime;
uint64_t endTime;
uint64_t errorDevices;
std::string owner;
void to_json(Poco::JSON::Object &Obj) const;
};
struct Dashboard {
int O;
void to_json(Poco::JSON::Object &Obj) const;
bool from_json(const Poco::JSON::Object::Ptr &Obj);
void reset();
};
}
#endif //UCENTRALSIM_RESTAPI_OWLSOBJECTS_H

View File

@@ -8,7 +8,9 @@
#include "RESTAPI_ProvObjects.h" #include "RESTAPI_ProvObjects.h"
#include "framework/MicroService.h" #include "framework/RESTAPI_utils.h"
#include "framework/MicroServiceFuncs.h"
#include "framework/utils.h"
using OpenWifi::RESTAPI_utils::field_to_json; using OpenWifi::RESTAPI_utils::field_to_json;
using OpenWifi::RESTAPI_utils::field_from_json; using OpenWifi::RESTAPI_utils::field_from_json;
@@ -600,6 +602,7 @@ namespace OpenWifi::ProvObjects {
field_to_json( Obj, "devClass",devClass); field_to_json( Obj, "devClass",devClass);
field_to_json( Obj, "locale",locale); field_to_json( Obj, "locale",locale);
field_to_json( Obj, "realMacAddress",realMacAddress); field_to_json( Obj, "realMacAddress",realMacAddress);
field_to_json( Obj, "doNotAllowOverrides",doNotAllowOverrides);
} }
bool InventoryTag::from_json(const Poco::JSON::Object::Ptr &Obj) { bool InventoryTag::from_json(const Poco::JSON::Object::Ptr &Obj) {
@@ -621,6 +624,7 @@ namespace OpenWifi::ProvObjects {
field_from_json( Obj,"devClass",devClass); field_from_json( Obj,"devClass",devClass);
field_from_json( Obj,"locale",locale); field_from_json( Obj,"locale",locale);
field_from_json( Obj,"realMacAddress",realMacAddress); field_from_json( Obj,"realMacAddress",realMacAddress);
field_from_json( Obj, "doNotAllowOverrides",doNotAllowOverrides);
return true; return true;
} catch(...) { } catch(...) {
@@ -1091,7 +1095,7 @@ namespace OpenWifi::ProvObjects {
} }
bool UpdateObjectInfo(const Poco::JSON::Object::Ptr &O, const SecurityObjects::UserInfo &U, ObjectInfo &I) { bool UpdateObjectInfo(const Poco::JSON::Object::Ptr &O, const SecurityObjects::UserInfo &U, ObjectInfo &I) {
uint64_t Now = OpenWifi::Now(); uint64_t Now = Utils::Now();
if(O->has("name")) if(O->has("name"))
I.name = O->get("name").toString(); I.name = O->get("name").toString();
@@ -1112,7 +1116,7 @@ namespace OpenWifi::ProvObjects {
} }
bool CreateObjectInfo(const Poco::JSON::Object::Ptr &O, const SecurityObjects::UserInfo &U, ObjectInfo &I) { bool CreateObjectInfo(const Poco::JSON::Object::Ptr &O, const SecurityObjects::UserInfo &U, ObjectInfo &I) {
uint64_t Now = OpenWifi::Now(); uint64_t Now = Utils::Now();
if(O->has("name")) if(O->has("name"))
I.name = O->get("name").toString(); I.name = O->get("name").toString();
@@ -1130,14 +1134,14 @@ namespace OpenWifi::ProvObjects {
} }
I.notes = N; I.notes = N;
I.modified = I.created = Now; I.modified = I.created = Now;
I.id = MicroService::CreateUUID(); I.id = MicroServiceCreateUUID();
return true; return true;
} }
bool CreateObjectInfo([[maybe_unused]] const SecurityObjects::UserInfo &U, ObjectInfo &I) { bool CreateObjectInfo([[maybe_unused]] const SecurityObjects::UserInfo &U, ObjectInfo &I) {
I.modified = I.created = OpenWifi::Now(); I.modified = I.created = Utils::Now();
I.id = MicroService::CreateUUID(); I.id = MicroServiceCreateUUID();
return true; return true;
} }
@@ -1159,5 +1163,82 @@ namespace OpenWifi::ProvObjects {
return false; return false;
} }
void RRMAlgorithmDetails::to_json(Poco::JSON::Object &Obj) const {
field_to_json(Obj,"name",name);
field_to_json(Obj,"parameters",parameters);
}
bool RRMAlgorithmDetails::from_json(const Poco::JSON::Object::Ptr &Obj) {
try {
field_from_json(Obj,"name",name);
field_from_json(Obj,"parameters",parameters);
return true;
} catch(...) {
}
return false;
}
void RRMDetails::to_json(Poco::JSON::Object &Obj) const {
field_to_json(Obj,"vendor",vendor);
field_to_json(Obj,"schedule",schedule);
field_to_json(Obj,"algorithms",algorithms);
}
bool RRMDetails::from_json(const Poco::JSON::Object::Ptr &Obj) {
try {
field_from_json(Obj,"vendor",vendor);
field_from_json(Obj,"schedule",schedule);
field_from_json(Obj,"algorithms",algorithms);
return true;
} catch(...) {
}
return false;
}
void ConfigurationOverride::to_json(Poco::JSON::Object &Obj) const {
field_to_json(Obj,"source",source);
field_to_json(Obj,"reason",reason);
field_to_json(Obj,"parameterName",parameterName);
field_to_json(Obj,"parameterType",parameterType);
field_to_json(Obj,"parameterValue",parameterValue);
field_to_json(Obj,"modified",modified);
}
bool ConfigurationOverride::from_json(const Poco::JSON::Object::Ptr &Obj) {
try {
field_from_json(Obj,"source",source);
field_from_json(Obj,"reason",reason);
field_from_json(Obj,"parameterName",parameterName);
field_from_json(Obj,"parameterType",parameterType);
field_from_json(Obj,"parameterValue",parameterValue);
field_from_json(Obj,"modified",modified);
return true;
} catch(...) {
}
return false;
}
void ConfigurationOverrideList::to_json(Poco::JSON::Object &Obj) const {
field_to_json(Obj,"serialNumber",serialNumber);
field_to_json(Obj,"managementPolicy",managementPolicy);
field_to_json(Obj,"overrides",overrides);
}
bool ConfigurationOverrideList::from_json(const Poco::JSON::Object::Ptr &Obj) {
try {
field_from_json(Obj,"serialNumber",serialNumber);
field_from_json(Obj,"managementPolicy",managementPolicy);
field_from_json(Obj,"overrides",overrides);
return true;
} catch(...) {
}
return false;
}
} }

View File

@@ -8,8 +8,7 @@
#pragma once #pragma once
#include <string> #include "RESTObjects/RESTAPI_SecurityObjects.h"
#include "RESTAPI_SecurityObjects.h"
namespace OpenWifi::ProvObjects { namespace OpenWifi::ProvObjects {
@@ -62,6 +61,21 @@ namespace OpenWifi::ProvObjects {
}; };
typedef std::vector<ManagementPolicy> ManagementPolicyVec; typedef std::vector<ManagementPolicy> ManagementPolicyVec;
struct RRMAlgorithmDetails {
std::string name;
std::string parameters;
void to_json(Poco::JSON::Object &Obj) const;
bool from_json(const Poco::JSON::Object::Ptr &Obj);
};
struct RRMDetails {
std::string vendor;
std::string schedule;
std::vector<RRMAlgorithmDetails> algorithms;
void to_json(Poco::JSON::Object &Obj) const;
bool from_json(const Poco::JSON::Object::Ptr &Obj);
};
struct DeviceRules { struct DeviceRules {
std::string rcOnly{"inherit"}; std::string rcOnly{"inherit"};
std::string rrm{"inherit"}; std::string rrm{"inherit"};
@@ -414,6 +428,7 @@ namespace OpenWifi::ProvObjects {
std::string devClass; std::string devClass;
std::string locale; std::string locale;
std::string realMacAddress; std::string realMacAddress;
bool doNotAllowOverrides=false;
void to_json(Poco::JSON::Object &Obj) const; void to_json(Poco::JSON::Object &Obj) const;
bool from_json(const Poco::JSON::Object::Ptr &Obj); bool from_json(const Poco::JSON::Object::Ptr &Obj);
@@ -679,6 +694,27 @@ namespace OpenWifi::ProvObjects {
bool from_json(const Poco::JSON::Object::Ptr &Obj); bool from_json(const Poco::JSON::Object::Ptr &Obj);
}; };
struct ConfigurationOverride {
std::string source;
std::string reason;
std::string parameterName;
std::string parameterType;
std::string parameterValue;
std::uint64_t modified;
void to_json(Poco::JSON::Object &Obj) const;
bool from_json(const Poco::JSON::Object::Ptr &Obj);
};
struct ConfigurationOverrideList {
std::string serialNumber;
Types::UUID_t managementPolicy;
std::vector<ConfigurationOverride> overrides;
void to_json(Poco::JSON::Object &Obj) const;
bool from_json(const Poco::JSON::Object::Ptr &Obj);
};
bool UpdateObjectInfo(const Poco::JSON::Object::Ptr &O, const SecurityObjects::UserInfo &U, ObjectInfo &I); bool UpdateObjectInfo(const Poco::JSON::Object::Ptr &O, const SecurityObjects::UserInfo &U, ObjectInfo &I);
bool CreateObjectInfo(const Poco::JSON::Object::Ptr &O, const SecurityObjects::UserInfo &U, ObjectInfo &I); bool CreateObjectInfo(const Poco::JSON::Object::Ptr &O, const SecurityObjects::UserInfo &U, ObjectInfo &I);
bool CreateObjectInfo(const SecurityObjects::UserInfo &U, ObjectInfo &I); bool CreateObjectInfo(const SecurityObjects::UserInfo &U, ObjectInfo &I);

View File

@@ -9,7 +9,7 @@
#include "Poco/JSON/Parser.h" #include "Poco/JSON/Parser.h"
#include "Poco/JSON/Stringifier.h" #include "Poco/JSON/Stringifier.h"
#include "framework/MicroService.h" #include "framework/RESTAPI_utils.h"
#include "RESTAPI_SecurityObjects.h" #include "RESTAPI_SecurityObjects.h"
using OpenWifi::RESTAPI_utils::field_to_json; using OpenWifi::RESTAPI_utils::field_to_json;
@@ -433,7 +433,7 @@ namespace OpenWifi::SecurityObjects {
SecurityObjects::NoteInfoVec NIV; SecurityObjects::NoteInfoVec NIV;
NIV = RESTAPI_utils::to_object_array<SecurityObjects::NoteInfo>(Obj->get("notes").toString()); NIV = RESTAPI_utils::to_object_array<SecurityObjects::NoteInfo>(Obj->get("notes").toString());
for(auto const &i:NIV) { for(auto const &i:NIV) {
SecurityObjects::NoteInfo ii{.created=(uint64_t)OpenWifi::Now(), .createdBy=UInfo.email, .note=i.note}; SecurityObjects::NoteInfo ii{.created=(uint64_t)Utils::Now(), .createdBy=UInfo.email, .note=i.note};
Notes.push_back(ii); Notes.push_back(ii);
} }
} }
@@ -446,7 +446,7 @@ namespace OpenWifi::SecurityObjects {
bool MergeNotes(const NoteInfoVec & NewNotes, const UserInfo &UInfo, NoteInfoVec & ExistingNotes) { bool MergeNotes(const NoteInfoVec & NewNotes, const UserInfo &UInfo, NoteInfoVec & ExistingNotes) {
for(auto const &i:NewNotes) { for(auto const &i:NewNotes) {
SecurityObjects::NoteInfo ii{.created=(uint64_t)OpenWifi::Now(), .createdBy=UInfo.email, .note=i.note}; SecurityObjects::NoteInfo ii{.created=(uint64_t)Utils::Now(), .createdBy=UInfo.email, .note=i.note};
ExistingNotes.push_back(ii); ExistingNotes.push_back(ii);
} }
return true; return true;
@@ -619,5 +619,80 @@ namespace OpenWifi::SecurityObjects {
field_to_json(Obj,"login",login); field_to_json(Obj,"login",login);
field_to_json(Obj,"logout",logout); field_to_json(Obj,"logout",logout);
} }
void ApiKeyAccessRight::to_json(Poco::JSON::Object &Obj) const {
field_to_json(Obj, "service", service);
field_to_json(Obj, "access", access);
}
bool ApiKeyAccessRight::from_json(const Poco::JSON::Object::Ptr &Obj) {
try {
field_from_json(Obj, "service", service);
field_from_json(Obj, "access", access);
return true;
} catch(...) {
std::cout << "Cannot parse: Token" << std::endl;
}
return false;
}
void ApiKeyAccessRightList::to_json(Poco::JSON::Object &Obj) const {
field_to_json(Obj, "acls", acls);
}
bool ApiKeyAccessRightList::from_json(const Poco::JSON::Object::Ptr &Obj) {
try {
field_from_json(Obj, "acls", acls);
return true;
} catch(...) {
std::cout << "Cannot parse: Token" << std::endl;
}
return false;
}
void ApiKeyEntry::to_json(Poco::JSON::Object &Obj) const {
field_to_json(Obj, "id", id);
field_to_json(Obj, "userUuid", userUuid);
field_to_json(Obj, "name", name);
field_to_json(Obj, "apiKey", apiKey);
field_to_json(Obj, "salt", salt);
field_to_json(Obj, "description", description);
field_to_json(Obj, "expiresOn", expiresOn);
field_to_json(Obj, "rights", rights);
field_to_json(Obj, "lastUse", lastUse);
}
bool ApiKeyEntry::from_json(const Poco::JSON::Object::Ptr &Obj) {
try {
field_from_json(Obj, "id", id);
field_from_json(Obj, "userUuid", userUuid);
field_from_json(Obj, "name", name);
field_from_json(Obj, "apiKey", apiKey);
field_from_json(Obj, "salt", salt);
field_from_json(Obj, "description", description);
field_from_json(Obj, "expiresOn", expiresOn);
field_from_json(Obj, "rights", rights);
field_from_json(Obj, "lastUse", lastUse);
return true;
} catch(...) {
std::cout << "Cannot parse: Token" << std::endl;
}
return false;
}
void ApiKeyEntryList::to_json(Poco::JSON::Object &Obj) const {
field_to_json(Obj, "apiKeys", apiKeys);
}
bool ApiKeyEntryList::from_json(const Poco::JSON::Object::Ptr &Obj) {
try {
field_from_json(Obj, "apiKeys", apiKeys);
return true;
} catch(...) {
std::cout << "Cannot parse: Token" << std::endl;
}
return false;
}
} }

View File

@@ -14,6 +14,7 @@
#include "Poco/JSON/Object.h" #include "Poco/JSON/Object.h"
#include "Poco/Data/LOB.h" #include "Poco/Data/LOB.h"
#include "Poco/Data/LOBStream.h" #include "Poco/Data/LOBStream.h"
#include "framework/utils.h"
namespace OpenWifi { namespace OpenWifi {
uint64_t Now(); uint64_t Now();
@@ -62,7 +63,7 @@ namespace OpenWifi {
std::string UserTypeToString(USER_ROLE U); std::string UserTypeToString(USER_ROLE U);
struct NoteInfo { struct NoteInfo {
uint64_t created=0; // = OpenWifi::Now(); uint64_t created=0; // = Utils::Now();
std::string createdBy; std::string createdBy;
std::string note; std::string note;
@@ -101,7 +102,7 @@ namespace OpenWifi {
std::string uuid; std::string uuid;
std::string question; std::string question;
std::string method; std::string method;
uint64_t created = OpenWifi::Now(); uint64_t created = Utils::Now();
void to_json(Poco::JSON::Object &Obj) const; void to_json(Poco::JSON::Object &Obj) const;
bool from_json(const Poco::JSON::Object::Ptr &Obj); bool from_json(const Poco::JSON::Object::Ptr &Obj);
@@ -251,7 +252,8 @@ namespace OpenWifi {
VERIFY_EMAIL, VERIFY_EMAIL,
SUB_FORGOT_PASSWORD, SUB_FORGOT_PASSWORD,
SUB_VERIFY_EMAIL, SUB_VERIFY_EMAIL,
SUB_SIGNUP SUB_SIGNUP,
EMAIL_INVITATION
}; };
struct ActionLink { struct ActionLink {
@@ -263,7 +265,7 @@ namespace OpenWifi {
std::string locale; std::string locale;
std::string message; std::string message;
uint64_t sent=0; uint64_t sent=0;
uint64_t created=OpenWifi::Now(); uint64_t created=Utils::Now();
uint64_t expires=0; uint64_t expires=0;
uint64_t completed=0; uint64_t completed=0;
uint64_t canceled=0; uint64_t canceled=0;
@@ -323,5 +325,44 @@ namespace OpenWifi {
void to_json(Poco::JSON::Object &Obj) const; void to_json(Poco::JSON::Object &Obj) const;
}; };
struct ApiKeyAccessRight {
std::string service;
std::string access;
void to_json(Poco::JSON::Object &Obj) const;
bool from_json(const Poco::JSON::Object::Ptr &Obj);
};
struct ApiKeyAccessRightList {
std::vector<ApiKeyAccessRight> acls;
void to_json(Poco::JSON::Object &Obj) const;
bool from_json(const Poco::JSON::Object::Ptr &Obj);
};
struct ApiKeyEntry {
Types::UUID_t id;
Types::UUID_t userUuid;
std::string name;
std::string description;
std::string apiKey;
std::string salt;
std::uint64_t created;
std::uint64_t expiresOn=0;
ApiKeyAccessRightList rights;
std::uint64_t lastUse=0;
void to_json(Poco::JSON::Object &Obj) const;
bool from_json(const Poco::JSON::Object::Ptr &Obj);
};
struct ApiKeyEntryList {
std::vector<ApiKeyEntry> apiKeys;
void to_json(Poco::JSON::Object &Obj) const;
bool from_json(const Poco::JSON::Object::Ptr &Obj);
};
} }
} }

View File

@@ -3,12 +3,11 @@
// //
#include "RESTAPI_SubObjects.h" #include "RESTAPI_SubObjects.h"
#include "framework/MicroService.h" #include "framework/RESTAPI_utils.h"
using OpenWifi::RESTAPI_utils::field_to_json; using OpenWifi::RESTAPI_utils::field_to_json;
using OpenWifi::RESTAPI_utils::field_from_json; using OpenWifi::RESTAPI_utils::field_from_json;
namespace OpenWifi::SubObjects { namespace OpenWifi::SubObjects {
void HomeDeviceMode::to_json(Poco::JSON::Object &Obj) const { void HomeDeviceMode::to_json(Poco::JSON::Object &Obj) const {

View File

@@ -3,9 +3,11 @@
// //
#include "GW_SDK.h" #include "GW_SDK.h"
#include "Daemon.h"
#include "Poco/Net/HTTPResponse.h" #include "Poco/Net/HTTPResponse.h"
#include "framework/MicroServiceNames.h"
#include "framework/OpenAPIRequests.h"
namespace OpenWifi::SDK::GW { namespace OpenWifi::SDK::GW {
bool SendFirmwareUpgradeCommand( const std::string & serialNumber, const std::string & URI, [[maybe_unused]] uint64_t When ) { bool SendFirmwareUpgradeCommand( const std::string & serialNumber, const std::string & URI, [[maybe_unused]] uint64_t When ) {

View File

@@ -2,11 +2,9 @@
// Created by stephane bourque on 2021-10-05. // Created by stephane bourque on 2021-10-05.
// //
#ifndef OWFMS_GW_SDK_H #pragma once
#define OWFMS_GW_SDK_H
#include <string>
#include "framework/MicroService.h"
namespace OpenWifi::SDK::GW { namespace OpenWifi::SDK::GW {
@@ -14,4 +12,3 @@ namespace OpenWifi::SDK::GW {
}; };
#endif //OWFMS_GW_SDK_H

View File

@@ -2,7 +2,8 @@
// Created by stephane bourque on 2021-10-04. // Created by stephane bourque on 2021-10-04.
// //
#include "framework/MicroService.h" #include "framework/OpenAPIRequests.h"
#include "framework/MicroServiceNames.h"
namespace OpenWifi::SDK::Prov { namespace OpenWifi::SDK::Prov {
bool GetFirmwareOptions( const std::string & serialNumber, std::string &firmwareUpgrade, bool GetFirmwareOptions( const std::string & serialNumber, std::string &firmwareUpgrade,

View File

@@ -2,10 +2,9 @@
// Created by stephane bourque on 2021-10-04. // Created by stephane bourque on 2021-10-04.
// //
#ifndef OWFMS_PROV_SDK_H #pragma once
#define OWFMS_PROV_SDK_H
#include "framework/MicroService.h" #include <string>
namespace OpenWifi::SDK::Prov { namespace OpenWifi::SDK::Prov {
@@ -14,5 +13,3 @@ namespace OpenWifi::SDK::Prov {
}; };
#endif //OWFMS_PROV_SDK_H

View File

@@ -6,10 +6,8 @@
// Arilia Wireless Inc. // Arilia Wireless Inc.
// //
#ifndef UCENTRAL_USTORAGESERVICE_H #pragma once
#define UCENTRAL_USTORAGESERVICE_H
#include "framework/MicroService.h"
#include "framework/StorageClass.h" #include "framework/StorageClass.h"
#include "RESTObjects/RESTAPI_FMSObjects.h" #include "RESTObjects/RESTAPI_FMSObjects.h"
@@ -53,4 +51,3 @@ namespace OpenWifi {
} // namespace } // namespace
#endif //UCENTRAL_USTORAGESERVICE_H

View File

@@ -0,0 +1,77 @@
//
// Created by stephane bourque on 2022-10-25.
//
#include "ALBserver.h"
#include "framework/utils.h"
#include "framework/MicroServiceFuncs.h"
#include "fmt/format.h"
namespace OpenWifi {
void ALBRequestHandler::handleRequest([[maybe_unused]] Poco::Net::HTTPServerRequest& Request, Poco::Net::HTTPServerResponse& Response) {
Utils::SetThreadName("alb-request");
try {
if((id_ % 100) == 0) {
Logger_.debug(fmt::format("ALB-REQUEST({}): ALB Request {}.", Request.clientAddress().toString(), id_));
}
Response.setChunkedTransferEncoding(true);
Response.setContentType("text/html");
Response.setDate(Poco::Timestamp());
Response.setStatus(Poco::Net::HTTPResponse::HTTP_OK);
Response.setKeepAlive(true);
Response.set("Connection", "keep-alive");
Response.setVersion(Poco::Net::HTTPMessage::HTTP_1_1);
std::ostream &Answer = Response.send();
Answer << "process Alive and kicking!";
} catch (...) {
}
}
ALBRequestHandlerFactory::ALBRequestHandlerFactory(Poco::Logger & L):
Logger_(L) {
}
ALBRequestHandler* ALBRequestHandlerFactory::createRequestHandler(const Poco::Net::HTTPServerRequest& request) {
if (request.getURI() == "/")
return new ALBRequestHandler(Logger_, req_id_++);
else
return nullptr;
}
ALBHealthCheckServer::ALBHealthCheckServer() :
SubSystemServer("ALBHealthCheckServer", "ALB-SVR", "alb")
{
}
int ALBHealthCheckServer::Start() {
if(MicroServiceConfigGetBool("alb.enable",false)) {
poco_information(Logger(),"Starting...");
Running_=true;
Port_ = (int)MicroServiceConfigGetInt("alb.port",15015);
Poco::Net::IPAddress Addr(Poco::Net::IPAddress::wildcard(
Poco::Net::Socket::supportsIPv6() ? Poco::Net::AddressFamily::IPv6
: Poco::Net::AddressFamily::IPv4));
Poco::Net::SocketAddress SockAddr(Addr, Port_);
Poco::Net::ServerSocket ClientSocket(SockAddr, 64);
Socket_ = std::make_unique<Poco::Net::ServerSocket>(SockAddr, Port_);
auto Params = new Poco::Net::HTTPServerParams;
Params->setName("ws:alb");
Server_ = std::make_unique<Poco::Net::HTTPServer>(new ALBRequestHandlerFactory(Logger()), *Socket_, Params);
Server_->start();
}
return 0;
}
void ALBHealthCheckServer::Stop() {
poco_information(Logger(),"Stopping...");
if(Running_)
Server_->stopAll(true);
poco_information(Logger(),"Stopped...");
}
} // namespace OpenWifi

63
src/framework/ALBserver.h Normal file
View File

@@ -0,0 +1,63 @@
//
// Created by stephane bourque on 2022-10-25.
//
#pragma once
#include "framework/SubSystemServer.h"
#include "Poco/Net/HTTPRequestHandler.h"
#include "Poco/Net/HTTPServerRequest.h"
#include "Poco/Net/HTTPServerResponse.h"
#include "Poco/Net/HTTPRequestHandlerFactory.h"
#include "Poco/Net/HTTPServer.h"
namespace OpenWifi {
class ALBRequestHandler: public Poco::Net::HTTPRequestHandler {
public:
explicit ALBRequestHandler(Poco::Logger & L, uint64_t id)
: Logger_(L), id_(id) {
}
void handleRequest([[maybe_unused]] Poco::Net::HTTPServerRequest& Request, Poco::Net::HTTPServerResponse& Response) override;
private:
Poco::Logger & Logger_;
uint64_t id_;
};
class ALBRequestHandlerFactory: public Poco::Net::HTTPRequestHandlerFactory
{
public:
explicit ALBRequestHandlerFactory(Poco::Logger & L);
ALBRequestHandler* createRequestHandler(const Poco::Net::HTTPServerRequest& request) override;
private:
Poco::Logger &Logger_;
inline static std::atomic_uint64_t req_id_=1;
};
class ALBHealthCheckServer : public SubSystemServer {
public:
ALBHealthCheckServer();
static auto instance() {
static auto instance = new ALBHealthCheckServer;
return instance;
}
int Start() override;
void Stop() override;
private:
std::unique_ptr<Poco::Net::HTTPServer> Server_;
std::unique_ptr<Poco::Net::ServerSocket> Socket_;
int Port_ = 0;
mutable std::atomic_bool Running_=false;
};
inline auto ALBHealthCheckServer() { return ALBHealthCheckServer::instance(); }
} // namespace OpenWifi

View File

@@ -4,8 +4,14 @@
#pragma once #pragma once
#include "framework/MicroService.h" #include "Poco/Logger.h"
#include "Poco/JSON/Parser.h" #include "Poco/JSON/Parser.h"
#include "Poco/Net/HTTPServerRequest.h"
#include "Poco/Net/HTTPServerResponse.h"
#include "Poco/Net/HTTPSClientSession.h"
#include "Poco/URI.h"
#include "framework/MicroServiceFuncs.h"
namespace OpenWifi { namespace OpenWifi {
inline void API_Proxy( Poco::Logger &Logger, inline void API_Proxy( Poco::Logger &Logger,
@@ -15,7 +21,7 @@ namespace OpenWifi {
const char * PathRewrite, const char * PathRewrite,
uint64_t msTimeout_ = 10000 ) { uint64_t msTimeout_ = 10000 ) {
try { try {
auto Services = MicroService::instance().GetServices(ServiceType); auto Services = MicroServiceGetServices(ServiceType);
for(auto const &Svc:Services) { for(auto const &Svc:Services) {
Poco::URI SourceURI(Request->getURI()); Poco::URI SourceURI(Request->getURI());
Poco::URI DestinationURI(Svc.PrivateEndPoint); Poco::URI DestinationURI(Svc.PrivateEndPoint);
@@ -35,7 +41,7 @@ namespace OpenWifi {
ProxyRequest.add("Authorization", Request->get("Authorization")); ProxyRequest.add("Authorization", Request->get("Authorization"));
} else { } else {
ProxyRequest.add("X-API-KEY", Svc.AccessKey); ProxyRequest.add("X-API-KEY", Svc.AccessKey);
ProxyRequest.add("X-INTERNAL-NAME", MicroService::instance().PublicEndPoint()); ProxyRequest.add("X-INTERNAL-NAME", MicroServicePublicEndPoint());
} }
if(Request->getMethod() == Poco::Net::HTTPRequest::HTTP_DELETE) { if(Request->getMethod() == Poco::Net::HTTPRequest::HTTP_DELETE) {

View File

@@ -0,0 +1,102 @@
//
// Created by stephane bourque on 2022-10-25.
//
#pragma once
#include <string>
#include <fstream>
#include <iomanip>
#include <iostream>
#include "Poco/StreamCopier.h"
#include "Poco/File.h"
#include "framework/MicroServiceFuncs.h"
#include "nlohmann/json.hpp"
namespace OpenWifi {
class AppServiceRegistry {
public:
AppServiceRegistry() {
FileName = MicroServiceDataDirectory() + "/registry.json";
Poco::File F(FileName);
try {
if(F.exists()) {
std::ostringstream OS;
std::ifstream IF(FileName);
Poco::StreamCopier::copyStream(IF, OS);
Registry_ = nlohmann::json::parse(OS.str());
}
} catch (...) {
Registry_ = nlohmann::json::parse("{}");
}
}
static AppServiceRegistry & instance() {
static auto instance_= new AppServiceRegistry;
return *instance_;
}
inline ~AppServiceRegistry() {
Save();
}
inline void Save() {
std::istringstream IS( to_string(Registry_));
std::ofstream OF;
OF.open(FileName,std::ios::binary | std::ios::trunc);
Poco::StreamCopier::copyStream(IS, OF);
}
inline void Set(const char *Key, uint64_t Value ) {
Registry_[Key] = Value;
Save();
}
inline void Set(const char *Key, const std::string &Value ) {
Registry_[Key] = Value;
Save();
}
inline void Set(const char *Key, bool Value ) {
Registry_[Key] = Value;
Save();
}
inline bool Get(const char *Key, bool & Value ) {
if(Registry_[Key].is_boolean()) {
Value = Registry_[Key].get<bool>();
return true;
}
return false;
}
inline bool Get(const char *Key, uint64_t & Value ) {
if(Registry_[Key].is_number_unsigned()) {
Value = Registry_[Key].get<uint64_t>();
return true;
}
return false;
}
inline bool Get(const char *Key, std::string & Value ) {
if(Registry_[Key].is_string()) {
Value = Registry_[Key].get<std::string>();
return true;
}
return false;
}
private:
std::string FileName;
nlohmann::json Registry_;
};
inline auto AppServiceRegistry() { return AppServiceRegistry::instance(); }
}

View File

@@ -0,0 +1,129 @@
//
// Created by stephane bourque on 2022-10-25.
//
#include "Poco/Net/HTTPServerResponse.h"
#include "framework/AuthClient.h"
#include "framework/MicroServiceNames.h"
#include "framework/OpenAPIRequests.h"
#include "framework/utils.h"
#include "fmt/format.h"
namespace OpenWifi {
bool AuthClient::RetrieveTokenInformation(const std::string & SessionToken,
SecurityObjects::UserInfoAndPolicy & UInfo,
std::uint64_t TID,
bool & Expired, bool & Contacted, bool Sub) {
try {
Types::StringPairVec QueryData;
QueryData.push_back(std::make_pair("token",SessionToken));
std::string AlternateURIForLogging = fmt::format("{}?token={}", Sub ? "/api/v1/validateSubToken" : "/api/v1/validateToken", Utils::SanitizeToken(SessionToken));
OpenAPIRequestGet Req( uSERVICE_SECURITY,
Sub ? "/api/v1/validateSubToken" : "/api/v1/validateToken",
QueryData,
10000,
AlternateURIForLogging
);
Poco::JSON::Object::Ptr Response;
auto StatusCode = Req.Do(Response);
if(StatusCode==Poco::Net::HTTPServerResponse::HTTP_GATEWAY_TIMEOUT) {
Contacted = false;
return false;
}
Contacted = true;
if(StatusCode==Poco::Net::HTTPServerResponse::HTTP_OK) {
if(Response->has("tokenInfo") && Response->has("userInfo")) {
UInfo.from_json(Response);
if(IsTokenExpired(UInfo.webtoken)) {
Expired = true;
return false;
}
Expired = false;
Cache_.update(SessionToken, UInfo);
return true;
} else {
return false;
}
}
} catch (...) {
poco_error(Logger(),fmt::format("Failed to retrieve token={} for TID={}", Utils::SanitizeToken(SessionToken), TID));
}
Expired = false;
return false;
}
bool AuthClient::IsAuthorized(const std::string &SessionToken, SecurityObjects::UserInfoAndPolicy & UInfo,
std::uint64_t TID,
bool & Expired, bool & Contacted, bool Sub) {
auto User = Cache_.get(SessionToken);
if(!User.isNull()) {
if(IsTokenExpired(User->webtoken)) {
Expired = true;
Cache_.remove(SessionToken);
return false;
}
Expired = false;
UInfo = *User;
return true;
}
return RetrieveTokenInformation(SessionToken, UInfo, TID, Expired, Contacted, Sub);
}
bool AuthClient::RetrieveApiKeyInformation(const std::string & SessionToken,
SecurityObjects::UserInfoAndPolicy & UInfo,
std::uint64_t TID,
bool & Expired, bool & Contacted) {
try {
Types::StringPairVec QueryData;
QueryData.push_back(std::make_pair("apikey",SessionToken));
std::string AlternateURIForLogging = fmt::format("/api/v1/validateApiKey?apiKey={}", Utils::SanitizeToken(SessionToken));
OpenAPIRequestGet Req( uSERVICE_SECURITY,
"/api/v1/validateApiKey" ,
QueryData,
10000,
AlternateURIForLogging);
Poco::JSON::Object::Ptr Response;
auto StatusCode = Req.Do(Response);
if(StatusCode==Poco::Net::HTTPServerResponse::HTTP_GATEWAY_TIMEOUT) {
Contacted = false;
return false;
}
Contacted = true;
if(StatusCode==Poco::Net::HTTPServerResponse::HTTP_OK) {
if(Response->has("tokenInfo") && Response->has("userInfo") && Response->has("expiresOn")) {
UInfo.from_json(Response);
Expired = false;
ApiKeyCache_.update(SessionToken, ApiKeyCacheEntry{ .UserInfo = UInfo, .ExpiresOn = Response->get("expiresOn")});
return true;
} else {
return false;
}
}
} catch (...) {
poco_error(Logger(),fmt::format("Failed to retrieve api key={} for TID={}", Utils::SanitizeToken(SessionToken), TID));
}
Expired = false;
return false;
}
bool AuthClient::IsValidApiKey(const std::string &SessionToken, SecurityObjects::UserInfoAndPolicy &UInfo,
std::uint64_t TID, bool &Expired, bool &Contacted) {
auto User = ApiKeyCache_.get(SessionToken);
if (!User.isNull()) {
if(User->ExpiresOn < Utils::Now()) {
Expired = false;
UInfo = User->UserInfo;
return true;
}
ApiKeyCache_.remove(SessionToken);
}
return RetrieveApiKeyInformation(SessionToken, UInfo, TID, Expired, Contacted);
}
} // namespace OpenWifi

View File

@@ -0,0 +1,79 @@
//
// Created by stephane bourque on 2022-10-25.
//
#pragma once
#include "framework/SubSystemServer.h"
#include "RESTObjects/RESTAPI_SecurityObjects.h"
#include "Poco/ExpireLRUCache.h"
#include "framework/utils.h"
namespace OpenWifi {
class AuthClient : public SubSystemServer {
public:
explicit AuthClient() noexcept:
SubSystemServer("Authentication", "AUTH-CLNT", "authentication")
{
}
static auto instance() {
static auto instance_ = new AuthClient;
return instance_;
}
struct ApiKeyCacheEntry {
OpenWifi::SecurityObjects::UserInfoAndPolicy UserInfo;
std::uint64_t ExpiresOn;
};
inline int Start() override {
return 0;
}
inline void Stop() override {
poco_information(Logger(),"Stopping...");
std::lock_guard G(Mutex_);
Cache_.clear();
poco_information(Logger(),"Stopped...");
}
inline void RemovedCachedToken(const std::string &Token) {
Cache_.remove(Token);
ApiKeyCache_.remove(Token);
}
inline static bool IsTokenExpired(const SecurityObjects::WebToken &T) {
return ((T.expires_in_+T.created_) < Utils::Now());
}
bool RetrieveTokenInformation(const std::string & SessionToken,
SecurityObjects::UserInfoAndPolicy & UInfo,
std::uint64_t TID,
bool & Expired, bool & Contacted, bool Sub=false);
bool RetrieveApiKeyInformation(const std::string & SessionToken,
SecurityObjects::UserInfoAndPolicy & UInfo,
std::uint64_t TID,
bool & Expired, bool & Contacted);
bool IsAuthorized(const std::string &SessionToken, SecurityObjects::UserInfoAndPolicy & UInfo,
std::uint64_t TID,
bool & Expired, bool & Contacted, bool Sub = false);
bool IsValidApiKey(const std::string &SessionToken, SecurityObjects::UserInfoAndPolicy & UInfo,
std::uint64_t TID,
bool & Expired, bool & Contacted);
private:
Poco::ExpireLRUCache<std::string,OpenWifi::SecurityObjects::UserInfoAndPolicy> Cache_{512,1200000 };
Poco::ExpireLRUCache<std::string,ApiKeyCacheEntry> ApiKeyCache_{512,1200000 };
};
inline auto AuthClient() { return AuthClient::instance(); }
} // namespace OpenWifi

155
src/framework/CIDR.h Normal file
View File

@@ -0,0 +1,155 @@
//
// Created by stephane bourque on 2022-10-25.
//
#pragma once
#include <string>
#include "Poco/Net/IPAddress.h"
#include "Poco/StringTokenizer.h"
#include "framework/OpenWifiTypes.h"
namespace OpenWifi::CIDR {
static bool cidr_match(const in_addr &addr, const in_addr &net, uint8_t bits) {
if (bits == 0) {
return true;
}
return !((addr.s_addr ^ net.s_addr) & htonl(0xFFFFFFFFu << (32 - bits)));
}
static bool cidr6_match(const in6_addr &address, const in6_addr &network, uint8_t bits) {
#ifdef __linux__
const uint32_t *a = address.s6_addr32;
const uint32_t *n = network.s6_addr32;
#else
const uint32_t *a = address.__u6_addr.__u6_addr32;
const uint32_t *n = network.__u6_addr.__u6_addr32;
#endif
int bits_whole, bits_incomplete;
bits_whole = bits >> 5; // number of whole u32
bits_incomplete = bits & 0x1F; // number of bits in incomplete u32
if (bits_whole) {
if (memcmp(a, n, bits_whole << 2) != 0) {
return false;
}
}
if (bits_incomplete) {
uint32_t mask = htonl((0xFFFFFFFFu) << (32 - bits_incomplete));
if ((a[bits_whole] ^ n[bits_whole]) & mask) {
return false;
}
}
return true;
}
static bool ConvertStringToLong(const char *S, unsigned long &L) {
char *end;
L = std::strtol(S, &end, 10);
return end != S;
}
static bool CidrIPinRange(const Poco::Net::IPAddress &IP, const std::string &Range) {
Poco::StringTokenizer TimeTokens(Range, "/", Poco::StringTokenizer::TOK_TRIM);
Poco::Net::IPAddress RangeIP;
if (Poco::Net::IPAddress::tryParse(TimeTokens[0], RangeIP)) {
if (TimeTokens.count() == 2) {
if (RangeIP.family() == Poco::Net::IPAddress::IPv4) {
unsigned long MaskLength;
if (ConvertStringToLong(TimeTokens[1].c_str(), MaskLength)) {
return cidr_match(*static_cast<const in_addr *>(RangeIP.addr()),
*static_cast<const in_addr *>(IP.addr()), MaskLength);
}
} else if (RangeIP.family() == Poco::Net::IPAddress::IPv6) {
unsigned long MaskLength;
if (ConvertStringToLong(TimeTokens[1].c_str(), MaskLength)) {
return cidr6_match(*static_cast<const in6_addr *>(RangeIP.addr()),
*static_cast<const in6_addr *>(IP.addr()), MaskLength);
}
}
}
return false;
}
return false;
}
//
// Ranges can be a single IP, of IP1-IP2, of A set of IPs: IP1,IP2,IP3, or a cidr IP/24
// These can work for IPv6 too...
//
static bool ValidateRange(const std::string &R) {
auto Tokens = Poco::StringTokenizer(R, "-");
if (Tokens.count() == 2) {
Poco::Net::IPAddress a, b;
if (!Poco::Net::IPAddress::tryParse(Tokens[0], a) &&
Poco::Net::IPAddress::tryParse(Tokens[1], b))
return false;
return a.family() == b.family();
}
Tokens = Poco::StringTokenizer(R, ",");
if (Tokens.count() > 1) {
return std::all_of(Tokens.begin(), Tokens.end(), [](const std::string &A) {
Poco::Net::IPAddress a;
return Poco::Net::IPAddress::tryParse(A, a);
});
}
Tokens = Poco::StringTokenizer(R, "/");
if (Tokens.count() == 2) {
Poco::Net::IPAddress a;
if (!Poco::Net::IPAddress::tryParse(Tokens[0], a))
return false;
if (std::atoi(Tokens[1].c_str()) == 0)
return false;
return true;
}
Poco::Net::IPAddress a;
return Poco::Net::IPAddress::tryParse(R, a);
}
static bool IpInRange(const Poco::Net::IPAddress &target, const std::string &R) {
auto Tokens = Poco::StringTokenizer(R, "-");
if (Tokens.count() == 2) {
auto a = Poco::Net::IPAddress::parse(Tokens[0]);
auto b = Poco::Net::IPAddress::parse(Tokens[1]);
if (target.family() != a.family())
return false;
return (a <= target && b >= target);
}
Tokens = Poco::StringTokenizer(R, ",");
if (Tokens.count() > 1) {
return std::any_of(Tokens.begin(), Tokens.end(), [target](const std::string &Element) {
return Poco::Net::IPAddress::parse(Element) == target;
});
}
Tokens = Poco::StringTokenizer(R, "/");
if (Tokens.count() == 2) {
return CidrIPinRange(target, R);
}
return Poco::Net::IPAddress::parse(R) == target;
}
[[nodiscard]] inline bool IpInRanges(const std::string &IP, const Types::StringVec &R) {
Poco::Net::IPAddress Target;
if (!Poco::Net::IPAddress::tryParse(IP, Target))
return false;
return std::any_of(cbegin(R), cend(R),
[Target](const std::string &i) { return IpInRange(Target, i); });
}
[[nodiscard]] inline bool ValidateIpRanges(const Types::StringVec &Ranges) {
return std::all_of(cbegin(Ranges), cend(Ranges), ValidateRange);
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -5,7 +5,7 @@
#pragma once #pragma once
#include <nlohmann/json-schema.hpp> #include <nlohmann/json-schema.hpp>
#include "framework/MicroService.h" #include "framework/SubSystemServer.h"
using nlohmann::json; using nlohmann::json;
using nlohmann::json_schema::json_validator; using nlohmann::json_schema::json_validator;
@@ -32,7 +32,7 @@ namespace OpenWifi {
nlohmann::json RootSchema_; nlohmann::json RootSchema_;
ConfigurationValidator(): ConfigurationValidator():
SubSystemServer("configvalidator", "CFG-VALIDATOR", "config.validator") { SubSystemServer("ConfigValidator", "CFG-VALIDATOR", "config.validator") {
} }
}; };

View File

@@ -0,0 +1,49 @@
//
// Created by stephane bourque on 2022-10-26.
//
#include "framework/EventBusManager.h"
#include "framework/KafkaManager.h"
#include "framework/utils.h"
#include "framework/MicroServiceFuncs.h"
namespace OpenWifi {
EventBusManager::EventBusManager(Poco::Logger &L) :
Logger_(L) {
}
void EventBusManager::run() {
Running_ = true;
Utils::SetThreadName("fmwk:EventMgr");
auto Msg = MicroServiceMakeSystemEventMessage(KafkaTopics::ServiceEvents::EVENT_JOIN);
KafkaManager()->PostMessage(KafkaTopics::SERVICE_EVENTS,MicroServicePrivateEndPoint(),Msg, false);
while(Running_) {
Poco::Thread::trySleep((unsigned long)MicroServiceDaemonBusTimer());
if(!Running_)
break;
Msg = MicroServiceMakeSystemEventMessage(KafkaTopics::ServiceEvents::EVENT_KEEP_ALIVE);
KafkaManager()->PostMessage(KafkaTopics::SERVICE_EVENTS,MicroServicePrivateEndPoint(),Msg, false);
}
Msg = MicroServiceMakeSystemEventMessage(KafkaTopics::ServiceEvents::EVENT_LEAVE);
KafkaManager()->PostMessage(KafkaTopics::SERVICE_EVENTS,MicroServicePrivateEndPoint(),Msg, false);
};
void EventBusManager::Start() {
poco_information(Logger(),"Starting...");
if(KafkaManager()->Enabled()) {
Thread_.start(*this);
}
}
void EventBusManager::Stop() {
if(KafkaManager()->Enabled()) {
poco_information(Logger(),"Stopping...");
Running_ = false;
Thread_.wakeUp();
Thread_.join();
poco_information(Logger(),"Stopped...");
}
}
} // namespace OpenWifi

View File

@@ -0,0 +1,28 @@
//
// Created by stephane bourque on 2022-10-26.
//
#pragma once
#include "Poco/Runnable.h"
#include "Poco/Logger.h"
#include "Poco/Thread.h"
namespace OpenWifi {
class EventBusManager : public Poco::Runnable {
public:
explicit EventBusManager(Poco::Logger &L);
void run() final;
void Start();
void Stop();
inline Poco::Logger & Logger() { return Logger_; }
private:
mutable std::atomic_bool Running_ = false;
Poco::Thread Thread_;
Poco::Logger &Logger_;
};
} // namespace OpenWifi

View File

@@ -0,0 +1,365 @@
//
// Created by stephane bourque on 2022-10-25.
//
#include "KafkaManager.h"
#include "framework/MicroServiceFuncs.h"
#include "fmt/format.h"
namespace OpenWifi {
void KafkaLoggerFun([[maybe_unused]] cppkafka::KafkaHandleBase & handle, int level, const std::string & facility, const std::string &message) {
switch ((cppkafka::LogLevel) level) {
case cppkafka::LogLevel::LogNotice: {
poco_notice(KafkaManager()->Logger(),fmt::format("kafka-log: facility: {} message: {}",facility, message));
}
break;
case cppkafka::LogLevel::LogDebug: {
poco_debug(KafkaManager()->Logger(),fmt::format("kafka-log: facility: {} message: {}",facility, message));
}
break;
case cppkafka::LogLevel::LogInfo: {
poco_information(KafkaManager()->Logger(),fmt::format("kafka-log: facility: {} message: {}",facility, message));
}
break;
case cppkafka::LogLevel::LogWarning: {
poco_warning(KafkaManager()->Logger(), fmt::format("kafka-log: facility: {} message: {}",facility, message));
}
break;
case cppkafka::LogLevel::LogAlert:
case cppkafka::LogLevel::LogCrit: {
poco_critical(KafkaManager()->Logger(),fmt::format("kafka-log: facility: {} message: {}",facility, message));
}
break;
case cppkafka::LogLevel::LogErr:
case cppkafka::LogLevel::LogEmerg:
default: {
poco_error(KafkaManager()->Logger(),fmt::format("kafka-log: facility: {} message: {}",facility, message));
}
break;
}
}
inline void KafkaErrorFun([[maybe_unused]] cppkafka::KafkaHandleBase & handle, int error, const std::string &reason) {
poco_error(KafkaManager()->Logger(),fmt::format("kafka-error: {}, reason: {}", error, reason));
}
inline void AddKafkaSecurity(cppkafka::Configuration & Config) {
auto CA = MicroServiceConfigGetString("openwifi.kafka.ssl.ca.location","");
auto Certificate = MicroServiceConfigGetString("openwifi.kafka.ssl.certificate.location","");
auto Key = MicroServiceConfigGetString("openwifi.kafka.ssl.key.location","");
auto Password = MicroServiceConfigGetString("openwifi.kafka.ssl.key.password","");
if(CA.empty() || Certificate.empty() || Key.empty())
return;
Config.set("ssl.ca.location", CA);
Config.set("ssl.certificate.location", Certificate);
Config.set("ssl.key.location", Key);
if(!Password.empty())
Config.set("ssl.key.password", Password);
}
void KafkaManager::initialize(Poco::Util::Application & self) {
SubSystemServer::initialize(self);
KafkaEnabled_ = MicroServiceConfigGetBool("openwifi.kafka.enable",false);
}
inline void KafkaProducer::run() {
Poco::Logger &Logger_ = Poco::Logger::create("KAFKA-PRODUCER", KafkaManager()->Logger().getChannel());
poco_information(Logger_,"Starting...");
Utils::SetThreadName("Kafka:Prod");
cppkafka::Configuration Config({
{ "client.id", MicroServiceConfigGetString("openwifi.kafka.client.id", "") },
{ "metadata.broker.list", MicroServiceConfigGetString("openwifi.kafka.brokerlist", "") }
});
AddKafkaSecurity(Config);
Config.set_log_callback(KafkaLoggerFun);
Config.set_error_callback(KafkaErrorFun);
KafkaManager()->SystemInfoWrapper_ = R"lit({ "system" : { "id" : )lit" +
std::to_string(MicroServiceID()) +
R"lit( , "host" : ")lit" + MicroServicePrivateEndPoint() +
R"lit(" } , "payload" : )lit" ;
cppkafka::Producer Producer(Config);
Running_ = true;
Poco::AutoPtr<Poco::Notification> Note(Queue_.waitDequeueNotification());
while(Note && Running_) {
try {
auto Msg = dynamic_cast<KafkaMessage *>(Note.get());
if (Msg != nullptr) {
Producer.produce(
cppkafka::MessageBuilder(Msg->Topic()).key(Msg->Key()).payload(Msg->Payload()));
}
} catch (const cppkafka::HandleException &E) {
poco_warning(Logger_,fmt::format("Caught a Kafka exception (producer): {}", E.what()));
} catch( const Poco::Exception &E) {
Logger_.log(E);
} catch (...) {
poco_error(Logger_,"std::exception");
}
Note = Queue_.waitDequeueNotification();
}
poco_information(Logger_,"Stopped...");
}
inline void KafkaConsumer::run() {
Utils::SetThreadName("Kafka:Cons");
Poco::Logger &Logger_ = Poco::Logger::create("KAFKA-CONSUMER", KafkaManager()->Logger().getChannel());
poco_information(Logger_,"Starting...");
cppkafka::Configuration Config({
{ "client.id", MicroServiceConfigGetString("openwifi.kafka.client.id","") },
{ "metadata.broker.list", MicroServiceConfigGetString("openwifi.kafka.brokerlist","") },
{ "group.id", MicroServiceConfigGetString("openwifi.kafka.group.id","") },
{ "enable.auto.commit", MicroServiceConfigGetBool("openwifi.kafka.auto.commit",false) },
{ "auto.offset.reset", "latest" } ,
{ "enable.partition.eof", false }
});
AddKafkaSecurity(Config);
Config.set_log_callback(KafkaLoggerFun);
Config.set_error_callback(KafkaErrorFun);
cppkafka::TopicConfiguration topic_config = {
{ "auto.offset.reset", "smallest" }
};
// Now configure it to be the default topic config
Config.set_default_topic_configuration(topic_config);
cppkafka::Consumer Consumer(Config);
Consumer.set_assignment_callback([&](cppkafka::TopicPartitionList& partitions) {
if(!partitions.empty()) {
poco_information(Logger_,fmt::format("Partition assigned: {}...",
partitions.front().get_partition()));
}
});
Consumer.set_revocation_callback([&](const cppkafka::TopicPartitionList& partitions) {
if(!partitions.empty()) {
poco_information(Logger_,fmt::format("Partition revocation: {}...",
partitions.front().get_partition()));
}
});
bool AutoCommit = MicroServiceConfigGetBool("openwifi.kafka.auto.commit",false);
auto BatchSize = MicroServiceConfigGetInt("openwifi.kafka.consumer.batchsize",20);
Types::StringVec Topics;
KafkaManager()->Topics(Topics);
Consumer.subscribe(Topics);
Running_ = true;
while(Running_) {
try {
std::vector<cppkafka::Message> MsgVec = Consumer.poll_batch(BatchSize, std::chrono::milliseconds(100));
for(auto const &Msg:MsgVec) {
if (!Msg)
continue;
if (Msg.get_error()) {
if (!Msg.is_eof()) {
poco_error(Logger_,fmt::format("Error: {}", Msg.get_error().to_string()));
}
if(!AutoCommit)
Consumer.async_commit(Msg);
continue;
}
KafkaManager()->Dispatch(Msg.get_topic(), Msg.get_key(),Msg.get_payload() );
if (!AutoCommit)
Consumer.async_commit(Msg);
}
} catch (const cppkafka::HandleException &E) {
poco_warning(Logger_,fmt::format("Caught a Kafka exception (consumer): {}", E.what()));
} catch (const Poco::Exception &E) {
Logger_.log(E);
} catch (...) {
poco_error(Logger_,"std::exception");
}
}
Consumer.unsubscribe();
poco_information(Logger_,"Stopped...");
}
void KafkaProducer::Start() {
if(!Running_) {
Running_=true;
Worker_.start(*this);
}
}
void KafkaProducer::Stop() {
if(Running_) {
Running_=false;
Queue_.wakeUpAll();
Worker_.join();
}
}
void KafkaProducer::Produce(const std::string &Topic, const std::string &Key, const std::string &Payload) {
std::lock_guard G(Mutex_);
Queue_.enqueueNotification( new KafkaMessage(Topic,Key,Payload));
}
void KafkaConsumer::Start() {
if(!Running_) {
Running_=true;
Worker_.start(*this);
}
}
void KafkaConsumer::Stop() {
if(Running_) {
Running_=false;
Worker_.wakeUp();
Worker_.join();
}
}
void KafkaDispatcher::Start() {
if(!Running_) {
Running_=true;
Worker_.start(*this);
}
}
void KafkaDispatcher::Stop() {
if(Running_) {
Running_=false;
Queue_.wakeUpAll();
Worker_.join();
}
}
auto KafkaDispatcher::RegisterTopicWatcher(const std::string &Topic, Types::TopicNotifyFunction &F) {
std::lock_guard G(Mutex_);
auto It = Notifiers_.find(Topic);
if(It == Notifiers_.end()) {
Types::TopicNotifyFunctionList L;
L.emplace(L.end(),std::make_pair(F,FunctionId_));
Notifiers_[Topic] = std::move(L);
} else {
It->second.emplace(It->second.end(),std::make_pair(F,FunctionId_));
}
return FunctionId_++;
}
void KafkaDispatcher::UnregisterTopicWatcher(const std::string &Topic, int Id) {
std::lock_guard G(Mutex_);
auto It = Notifiers_.find(Topic);
if(It != Notifiers_.end()) {
Types::TopicNotifyFunctionList & L = It->second;
for(auto it=L.begin(); it!=L.end(); it++)
if(it->second == Id) {
L.erase(it);
break;
}
}
}
void KafkaDispatcher::Dispatch(const std::string &Topic, const std::string &Key, const std::string &Payload) {
std::lock_guard G(Mutex_);
auto It = Notifiers_.find(Topic);
if(It!=Notifiers_.end()) {
Queue_.enqueueNotification(new KafkaMessage(Topic, Key, Payload));
}
}
void KafkaDispatcher::run() {
Poco::Logger &Logger_ = Poco::Logger::create("KAFKA-DISPATCHER", KafkaManager()->Logger().getChannel());
poco_information(Logger_,"Starting...");
Poco::AutoPtr<Poco::Notification> Note(Queue_.waitDequeueNotification());
Utils::SetThreadName("kafka:dispatch");
while(Note && Running_) {
auto Msg = dynamic_cast<KafkaMessage*>(Note.get());
if(Msg!= nullptr) {
auto It = Notifiers_.find(Msg->Topic());
if (It != Notifiers_.end()) {
const auto & FL = It->second;
for(const auto &[CallbackFunc,_]:FL) {
CallbackFunc(Msg->Key(), Msg->Payload());
}
}
}
Note = Queue_.waitDequeueNotification();
}
poco_information(Logger_,"Stopped...");
}
void KafkaDispatcher::Topics(std::vector<std::string> &T) {
T.clear();
for(const auto &[TopicName,_]:Notifiers_)
T.push_back(TopicName);
}
int KafkaManager::Start() {
if(!KafkaEnabled_)
return 0;
ConsumerThr_.Start();
ProducerThr_.Start();
Dispatcher_.Start();
return 0;
}
void KafkaManager::Stop() {
if(KafkaEnabled_) {
poco_information(Logger(),"Stopping...");
Dispatcher_.Stop();
ProducerThr_.Stop();
ConsumerThr_.Stop();
poco_information(Logger(),"Stopped...");
return;
}
}
void KafkaManager::PostMessage(const std::string &topic, const std::string & key, const std::string &PayLoad, bool WrapMessage ) {
if(KafkaEnabled_) {
ProducerThr_.Produce(topic,key,WrapMessage ? WrapSystemId(PayLoad) : PayLoad);
}
}
void KafkaManager::Dispatch(const std::string &Topic, const std::string & Key, const std::string &Payload) {
Dispatcher_.Dispatch(Topic, Key, Payload);
}
[[nodiscard]] std::string KafkaManager::WrapSystemId(const std::string & PayLoad) {
return SystemInfoWrapper_ + PayLoad + "}";
}
uint64_t KafkaManager::RegisterTopicWatcher(const std::string &Topic, Types::TopicNotifyFunction &F) {
if(KafkaEnabled_) {
return Dispatcher_.RegisterTopicWatcher(Topic,F);
} else {
return 0;
}
}
void KafkaManager::UnregisterTopicWatcher(const std::string &Topic, uint64_t Id) {
if(KafkaEnabled_) {
Dispatcher_.UnregisterTopicWatcher(Topic, Id);
}
}
void KafkaManager::Topics(std::vector<std::string> &T) {
Dispatcher_.Topics(T);
}
void KafkaManager::PartitionAssignment(const cppkafka::TopicPartitionList& partitions) {
poco_information(Logger(),fmt::format("Partition assigned: {}...", partitions.front().get_partition()));
}
void KafkaManager::PartitionRevocation(const cppkafka::TopicPartitionList& partitions) {
poco_information(Logger(),fmt::format("Partition revocation: {}...",partitions.front().get_partition()));
}
} // namespace OpenWifi

View File

@@ -0,0 +1,122 @@
//
// Created by stephane bourque on 2022-10-25.
//
#pragma once
#include "Poco/Notification.h"
#include "Poco/NotificationQueue.h"
#include "framework/SubSystemServer.h"
#include "framework/OpenWifiTypes.h"
#include "framework/utils.h"
#include "framework/KafkaTopics.h"
#include "cppkafka/cppkafka.h"
namespace OpenWifi {
class KafkaMessage: public Poco::Notification {
public:
KafkaMessage( const std::string &Topic, const std::string &Key, const std::string & Payload) :
Topic_(Topic), Key_(Key), Payload_(Payload) {
}
inline const std::string & Topic() { return Topic_; }
inline const std::string & Key() { return Key_; }
inline const std::string & Payload() { return Payload_; }
private:
std::string Topic_;
std::string Key_;
std::string Payload_;
};
class KafkaProducer : public Poco::Runnable {
public:
void run () override;
void Start();
void Stop();
void Produce(const std::string &Topic, const std::string &Key, const std::string &Payload);
private:
std::recursive_mutex Mutex_;
Poco::Thread Worker_;
mutable std::atomic_bool Running_=false;
Poco::NotificationQueue Queue_;
};
class KafkaConsumer : public Poco::Runnable {
public:
void run() override;
void Start();
void Stop();
private:
std::recursive_mutex Mutex_;
Poco::Thread Worker_;
mutable std::atomic_bool Running_=false;
};
class KafkaDispatcher : public Poco::Runnable {
public:
void Start();
void Stop();
auto RegisterTopicWatcher(const std::string &Topic, Types::TopicNotifyFunction &F);
void UnregisterTopicWatcher(const std::string &Topic, int Id);
void Dispatch(const std::string &Topic, const std::string &Key, const std::string &Payload);
void run() override;
void Topics(std::vector<std::string> &T);
private:
std::recursive_mutex Mutex_;
Types::NotifyTable Notifiers_;
Poco::Thread Worker_;
mutable std::atomic_bool Running_=false;
uint64_t FunctionId_=1;
Poco::NotificationQueue Queue_;
};
class KafkaManager : public SubSystemServer {
public:
friend class KafkaConsumer;
friend class KafkaProducer;
inline void initialize(Poco::Util::Application & self) override;
static auto instance() {
static auto instance_ = new KafkaManager;
return instance_;
}
int Start() override;
void Stop() override;
void PostMessage(const std::string &topic, const std::string & key, const std::string &PayLoad, bool WrapMessage = true );
void Dispatch(const std::string &Topic, const std::string & Key, const std::string &Payload);
[[nodiscard]] std::string WrapSystemId(const std::string & PayLoad);
[[nodiscard]] inline bool Enabled() const { return KafkaEnabled_; }
uint64_t RegisterTopicWatcher(const std::string &Topic, Types::TopicNotifyFunction &F);
void UnregisterTopicWatcher(const std::string &Topic, uint64_t Id);
void Topics(std::vector<std::string> &T);
private:
bool KafkaEnabled_ = false;
std::string SystemInfoWrapper_;
KafkaProducer ProducerThr_;
KafkaConsumer ConsumerThr_;
KafkaDispatcher Dispatcher_;
void PartitionAssignment(const cppkafka::TopicPartitionList& partitions);
void PartitionRevocation(const cppkafka::TopicPartitionList& partitions);
KafkaManager() noexcept:
SubSystemServer("KafkaManager", "KAFKA-SVR", "openwifi.kafka") {
}
};
inline auto KafkaManager() { return KafkaManager::instance(); }
} // namespace OpenWifi

View File

@@ -8,6 +8,7 @@
#pragma once #pragma once
#include <string>
namespace OpenWifi::KafkaTopics { namespace OpenWifi::KafkaTopics {
static const std::string HEALTHCHECK{"healthcheck"}; static const std::string HEALTHCHECK{"healthcheck"};
static const std::string STATE{"state"}; static const std::string STATE{"state"};

View File

@@ -0,0 +1,712 @@
//
// Created by stephane bourque on 2022-10-26.
//
#include "Poco/FileChannel.h"
#include "Poco/ConsoleChannel.h"
#include "Poco/PatternFormatter.h"
#include "Poco/FormattingChannel.h"
#include "Poco/AsyncChannel.h"
#include "Poco/NullChannel.h"
#include "Poco/SplitterChannel.h"
#include "Poco/Net/HTTPStreamFactory.h"
#include "Poco/Net/HTTPSStreamFactory.h"
#include "Poco/Net/FTPSStreamFactory.h"
#include "Poco/Net/FTPStreamFactory.h"
#include "Poco/Net/SSLManager.h"
#include "Poco/JSON/JSONException.h"
#include "framework/MicroService.h"
#include "framework/MicroServiceErrorHandler.h"
#include "framework/UI_WebSocketClientServer.h"
#include "framework/MicroServiceNames.h"
#include "framework/AuthClient.h"
#include "framework/ALBserver.h"
#include "framework/KafkaManager.h"
#include "framework/RESTAPI_GenericServerAccounting.h"
#include "framework/RESTAPI_ExtServer.h"
#include "framework/RESTAPI_IntServer.h"
#include "framework/utils.h"
#include "framework/WebSocketLogger.h"
namespace OpenWifi {
void MicroService::Exit(int Reason) {
std::exit(Reason);
}
void MicroService::BusMessageReceived([[maybe_unused]] const std::string &Key, const std::string & Payload) {
std::lock_guard G(InfraMutex_);
try {
Poco::JSON::Parser P;
auto Object = P.parse(Payload).extract<Poco::JSON::Object::Ptr>();
if (Object->has(KafkaTopics::ServiceEvents::Fields::ID) &&
Object->has(KafkaTopics::ServiceEvents::Fields::EVENT)) {
uint64_t ID = Object->get(KafkaTopics::ServiceEvents::Fields::ID);
auto Event = Object->get(KafkaTopics::ServiceEvents::Fields::EVENT).toString();
if (ID != ID_) {
if( Event==KafkaTopics::ServiceEvents::EVENT_JOIN ||
Event==KafkaTopics::ServiceEvents::EVENT_KEEP_ALIVE ||
Event==KafkaTopics::ServiceEvents::EVENT_LEAVE ) {
if( Object->has(KafkaTopics::ServiceEvents::Fields::TYPE) &&
Object->has(KafkaTopics::ServiceEvents::Fields::PUBLIC) &&
Object->has(KafkaTopics::ServiceEvents::Fields::PRIVATE) &&
Object->has(KafkaTopics::ServiceEvents::Fields::VRSN) &&
Object->has(KafkaTopics::ServiceEvents::Fields::KEY)) {
auto PrivateEndPoint = Object->get(KafkaTopics::ServiceEvents::Fields::PRIVATE).toString();
if (Event == KafkaTopics::ServiceEvents::EVENT_KEEP_ALIVE && Services_.find(PrivateEndPoint) != Services_.end()) {
Services_[PrivateEndPoint].LastUpdate = Utils::Now();
} else if (Event == KafkaTopics::ServiceEvents::EVENT_LEAVE) {
Services_.erase(PrivateEndPoint);
poco_debug(logger(),fmt::format("Service {} ID={} leaving system.",Object->get(KafkaTopics::ServiceEvents::Fields::PRIVATE).toString(),ID));
} else if (Event == KafkaTopics::ServiceEvents::EVENT_JOIN || Event == KafkaTopics::ServiceEvents::EVENT_KEEP_ALIVE) {
poco_debug(logger(),fmt::format("Service {} ID={} joining system.",Object->get(KafkaTopics::ServiceEvents::Fields::PRIVATE).toString(),ID));
Services_[PrivateEndPoint] = Types::MicroServiceMeta{
.Id = ID,
.Type = Poco::toLower(Object->get(KafkaTopics::ServiceEvents::Fields::TYPE).toString()),
.PrivateEndPoint = Object->get(KafkaTopics::ServiceEvents::Fields::PRIVATE).toString(),
.PublicEndPoint = Object->get(KafkaTopics::ServiceEvents::Fields::PUBLIC).toString(),
.AccessKey = Object->get(KafkaTopics::ServiceEvents::Fields::KEY).toString(),
.Version = Object->get(KafkaTopics::ServiceEvents::Fields::VRSN).toString(),
.LastUpdate = Utils::Now() };
std::string SvcList;
for (const auto &Svc: Services_) {
if(SvcList.empty())
SvcList = Svc.second.Type;
else
SvcList += ", " + Svc.second.Type;
}
poco_information(logger(),fmt::format("Current list of microservices: {}", SvcList));
}
} else {
poco_error(logger(),fmt::format("KAFKA-MSG: invalid event '{}', missing a field.",Event));
}
} else if (Event==KafkaTopics::ServiceEvents::EVENT_REMOVE_TOKEN) {
if(Object->has(KafkaTopics::ServiceEvents::Fields::TOKEN)) {
#ifndef TIP_SECURITY_SERVICE
AuthClient()->RemovedCachedToken(Object->get(KafkaTopics::ServiceEvents::Fields::TOKEN).toString());
#endif
} else {
poco_error(logger(),fmt::format("KAFKA-MSG: invalid event '{}', missing token",Event));
}
} else {
poco_error(logger(),fmt::format("Unknown Event: {} Source: {}", Event, ID));
}
}
} else {
poco_error(logger(),"Bad bus message.");
}
auto i=Services_.begin();
auto now = Utils::Now();
for(;i!=Services_.end();) {
if((now - i->second.LastUpdate)>60) {
i = Services_.erase(i);
} else
++i;
}
} catch (const Poco::Exception &E) {
logger().log(E);
}
}
Types::MicroServiceMetaVec MicroService::GetServices(const std::string & Type) {
std::lock_guard G(InfraMutex_);
auto T = Poco::toLower(Type);
Types::MicroServiceMetaVec Res;
for(const auto &[_,ServiceRec]:Services_) {
if(ServiceRec.Type==T)
Res.push_back(ServiceRec);
}
return Res;
}
Types::MicroServiceMetaVec MicroService::GetServices() {
std::lock_guard G(InfraMutex_);
Types::MicroServiceMetaVec Res;
for(const auto &[_,ServiceRec]:Services_) {
Res.push_back(ServiceRec);
}
return Res;
}
void MicroService::LoadConfigurationFile() {
std::string Location = Poco::Environment::get(DAEMON_CONFIG_ENV_VAR,".");
ConfigFileName_ = ConfigFileName_.empty() ? Location + "/" + DAEMON_PROPERTIES_FILENAME : ConfigFileName_;
Poco::Path ConfigFile(ConfigFileName_);
if(!ConfigFile.isFile())
{
std::cerr << DAEMON_APP_NAME << ": Configuration "
<< ConfigFile.toString() << " does not seem to exist. Please set " + DAEMON_CONFIG_ENV_VAR
+ " env variable the path of the " + DAEMON_PROPERTIES_FILENAME + " file." << std::endl;
std::exit(Poco::Util::Application::EXIT_CONFIG);
}
// loadConfiguration(ConfigFile.toString());
PropConfigurationFile_ = new Poco::Util::PropertyFileConfiguration(ConfigFile.toString());
configPtr()->addWriteable(PropConfigurationFile_, PRIO_DEFAULT);
}
void MicroService::Reload() {
LoadConfigurationFile();
LoadMyConfig();
}
void MicroService::LoadMyConfig() {
NoAPISecurity_ = ConfigGetBool("openwifi.security.restapi.disable",false);
std::string KeyFile = ConfigPath("openwifi.service.key","");
if(!KeyFile.empty()) {
std::string KeyFilePassword = ConfigPath("openwifi.service.key.password", "");
AppKey_ = Poco::SharedPtr<Poco::Crypto::RSAKey>(new Poco::Crypto::RSAKey("", KeyFile, KeyFilePassword));
Cipher_ = CipherFactory_.createCipher(*AppKey_);
Signer_.setRSAKey(AppKey_);
Signer_.addAllAlgorithms();
NoBuiltInCrypto_ = false;
} else {
NoBuiltInCrypto_ = true;
}
ID_ = Utils::GetSystemId();
if(!DebugMode_)
DebugMode_ = ConfigGetBool("openwifi.system.debug",false);
MyPrivateEndPoint_ = ConfigGetString("openwifi.system.uri.private");
MyPublicEndPoint_ = ConfigGetString("openwifi.system.uri.public");
UIURI_ = ConfigGetString("openwifi.system.uri.ui");
MyHash_ = Utils::ComputeHash(MyPublicEndPoint_);
}
void MicroService::InitializeLoggingSystem() {
static auto initialized = false;
if(!initialized) {
initialized = true;
LoadConfigurationFile();
auto LoggingDestination = MicroService::instance().ConfigGetString("logging.type", "file");
auto LoggingFormat = MicroService::instance().ConfigGetString("logging.format",
"%Y-%m-%d %H:%M:%S.%i %s: [%p][thr:%I] %t");
auto UseAsyncLogs_ = MicroService::instance().ConfigGetBool("logging.asynch", true);
auto DisableWebSocketLogging = MicroService::instance().ConfigGetBool("logging.websocket",false);
if (LoggingDestination == "null") {
Poco::AutoPtr<Poco::NullChannel> DevNull(new Poco::NullChannel);
Poco::Logger::root().setChannel(DevNull);
} else if (LoggingDestination == "console") {
SetConsoleLogs(UseAsyncLogs_, DisableWebSocketLogging, LoggingFormat);
} else if (LoggingDestination == "colorconsole") {
SetColorConsoleLogs(UseAsyncLogs_, DisableWebSocketLogging, LoggingFormat);
} else if (LoggingDestination == "sql") {
SetSQLLogs(UseAsyncLogs_, DisableWebSocketLogging, LoggingFormat);
} else if (LoggingDestination == "syslog") {
SetSyslogLogs(UseAsyncLogs_, DisableWebSocketLogging, LoggingFormat);
} else {
SetFileLogs(UseAsyncLogs_, DisableWebSocketLogging, LoggingFormat, DAEMON_ROOT_ENV_VAR);
}
auto Level = Poco::Logger::parseLevel(MicroService::instance().ConfigGetString("logging.level", "debug"));
Poco::Logger::root().setLevel(Level);
if(!DisableWebSocketLogging) {
static const UI_WebSocketClientServer::NotificationTypeIdVec Notifications = {
{1, "log"}};
UI_WebSocketClientServer()->RegisterNotifications(Notifications);
}
}
}
void MicroService::SetConsoleLogs(bool UseAsync, bool DisableWebSocketLogging, const std::string & FormatterPattern) {
Poco::AutoPtr<Poco::ConsoleChannel> Console(new Poco::ConsoleChannel);
Poco::AutoPtr<Poco::PatternFormatter> Formatter(new Poco::PatternFormatter);
Formatter->setProperty("pattern", FormatterPattern);
Poco::AutoPtr<Poco::FormattingChannel> FormattingChannel(new Poco::FormattingChannel(Formatter, Console));
if(DisableWebSocketLogging) {
if(UseAsync) {
Poco::AutoPtr<Poco::AsyncChannel> Async(new Poco::AsyncChannel(FormattingChannel));
Poco::Logger::root().setChannel(Async);
} else {
Poco::Logger::root().setChannel(FormattingChannel);
}
} else {
Poco::AutoPtr<WebSocketLogger> WSLogger(new WebSocketLogger);
Poco::AutoPtr<Poco::SplitterChannel> Splitter(new Poco::SplitterChannel);
Splitter->addChannel(WSLogger);
Splitter->addChannel(FormattingChannel);
if(UseAsync) {
Poco::AutoPtr<Poco::AsyncChannel> Async(new Poco::AsyncChannel(Splitter));
Poco::Logger::root().setChannel(Async);
} else {
Poco::Logger::root().setChannel(Splitter);
}
}
Poco::Logger::root().information(fmt::format("Enabled console logs: asynch={} websocket={}",UseAsync,DisableWebSocketLogging));
}
void MicroService::SetColorConsoleLogs(bool UseAsync, bool DisableWebSocketLogging, const std::string & FormatterPattern) {
Poco::AutoPtr<Poco::ColorConsoleChannel> Console(new Poco::ColorConsoleChannel);
Poco::AutoPtr<Poco::PatternFormatter> Formatter(new Poco::PatternFormatter);
Formatter->setProperty("pattern", FormatterPattern);
Poco::AutoPtr<Poco::FormattingChannel> FormattingChannel(new Poco::FormattingChannel(Formatter, Console));
if(DisableWebSocketLogging) {
if(UseAsync) {
Poco::AutoPtr<Poco::AsyncChannel> Async(new Poco::AsyncChannel(FormattingChannel));
Poco::Logger::root().setChannel(Async);
} else {
Poco::Logger::root().setChannel(FormattingChannel);
}
} else {
Poco::AutoPtr<WebSocketLogger> WSLogger(new WebSocketLogger);
Poco::AutoPtr<Poco::SplitterChannel> Splitter(new Poco::SplitterChannel);
Splitter->addChannel(WSLogger);
Splitter->addChannel(FormattingChannel);
if(UseAsync) {
Poco::AutoPtr<Poco::AsyncChannel> Async(new Poco::AsyncChannel(Splitter));
Poco::Logger::root().setChannel(Async);
} else {
Poco::Logger::root().setChannel(Splitter);
}
}
Poco::Logger::root().information(fmt::format("Enabled color console logs: asynch={} websocket={}",UseAsync,DisableWebSocketLogging));
}
void MicroService::SetSQLLogs([[maybe_unused]] bool UseAsync,[[maybe_unused]] bool DisableWebSocketLogging,[[maybe_unused]] const std::string & FormatterPattern) {
//"CREATE TABLE T_POCO_LOG (Source VARCHAR, Name VARCHAR, ProcessId INTEGER, Thread VARCHAR, ThreadId INTEGER, Priority INTEGER, Text VARCHAR, DateTime DATE)"
}
void MicroService::SetSyslogLogs([[maybe_unused]] bool UseAsync,[[maybe_unused]] bool DisableWebSocketLogging,[[maybe_unused]] const std::string & FormatterPattern) {
}
void MicroService::SetFileLogs(bool UseAsync, bool DisableWebSocketLogging, const std::string & FormatterPattern, const std::string & root_env_var) {
std::string DefaultLogPath = fmt::format("${}/logs",root_env_var);
auto LoggingLocationDir = MicroService::instance().ConfigPath("logging.path", DefaultLogPath);
Poco::File LD(LoggingLocationDir);
try {
if(!LD.exists()) {
LD.createDirectory();
}
} catch(const Poco::Exception &E) {
std::cout << "Cannot create " << LD.path() << " Error: " << E.message() << std::endl;
}
auto LoggingLocationDirFilePattern = LoggingLocationDir + "/log";
Poco::AutoPtr<Poco::FileChannel> FileChannel(new Poco::FileChannel);
FileChannel->setProperty("rotation", "10 M");
FileChannel->setProperty("archive", "timestamp");
FileChannel->setProperty("purgeCount", "10");
FileChannel->setProperty("path", LoggingLocationDirFilePattern);
Poco::AutoPtr<Poco::PatternFormatter> Formatter(new Poco::PatternFormatter);
Formatter->setProperty("pattern", FormatterPattern);
Poco::AutoPtr<Poco::FormattingChannel> FormattingChannel(new Poco::FormattingChannel(Formatter, FileChannel));
if(DisableWebSocketLogging) {
if(UseAsync) {
Poco::AutoPtr<Poco::AsyncChannel> Async(new Poco::AsyncChannel(FormattingChannel));
Poco::Logger::root().setChannel(Async);
} else {
Poco::Logger::root().setChannel(FormattingChannel);
}
} else {
Poco::AutoPtr<WebSocketLogger> WSLogger(new WebSocketLogger);
Poco::AutoPtr<Poco::SplitterChannel> Splitter(new Poco::SplitterChannel);
Splitter->addChannel(WSLogger);
Splitter->addChannel(FormattingChannel);
if(UseAsync) {
Poco::AutoPtr<Poco::AsyncChannel> Async(new Poco::AsyncChannel(Splitter));
Poco::Logger::root().setChannel(Async);
} else {
Poco::Logger::root().setChannel(Splitter);
}
}
Poco::Logger::root().information(fmt::format("Enabled file logs: asynch={} websocket={}",UseAsync,DisableWebSocketLogging));
}
void DaemonPostInitialization(Poco::Util::Application &self);
void MicroService::initialize(Poco::Util::Application &self) {
// add the default services
LoadConfigurationFile();
InitializeLoggingSystem();
SubSystems_.push_back(KafkaManager());
SubSystems_.push_back(ALBHealthCheckServer());
SubSystems_.push_back(RESTAPI_ExtServer());
SubSystems_.push_back(RESTAPI_IntServer());
#ifndef TIP_SECURITY_SERVICE
SubSystems_.push_back(AuthClient());
#endif
Poco::Net::initializeSSL();
Poco::Net::HTTPStreamFactory::registerFactory();
Poco::Net::HTTPSStreamFactory::registerFactory();
Poco::Net::FTPStreamFactory::registerFactory();
Poco::Net::FTPSStreamFactory::registerFactory();
Poco::File DataDir(ConfigPath("openwifi.system.data"));
DataDir_ = DataDir.path();
if(!DataDir.exists()) {
try {
DataDir.createDirectory();
} catch (const Poco::Exception &E) {
logger().log(E);
}
}
WWWAssetsDir_ = ConfigPath("openwifi.restapi.wwwassets","");
if(WWWAssetsDir_.empty())
WWWAssetsDir_ = DataDir_;
LoadMyConfig();
InitializeSubSystemServers();
ServerApplication::initialize(self);
DaemonPostInitialization(self);
Types::TopicNotifyFunction F = [this](const std::string &Key,const std::string &Payload) { this->BusMessageReceived(Key, Payload); };
KafkaManager()->RegisterTopicWatcher(KafkaTopics::SERVICE_EVENTS, F);
}
void MicroService::uninitialize() {
// add your own uninitialization code here
ServerApplication::uninitialize();
}
void MicroService::reinitialize(Poco::Util::Application &self) {
ServerApplication::reinitialize(self);
// add your own reinitialization code here
}
void MicroService::defineOptions(Poco::Util::OptionSet &options) {
ServerApplication::defineOptions(options);
options.addOption(
Poco::Util::Option("help", "", "display help information on command line arguments")
.required(false)
.repeatable(false)
.callback(Poco::Util::OptionCallback<MicroService>(this, &MicroService::handleHelp)));
options.addOption(
Poco::Util::Option("file", "", "specify the configuration file")
.required(false)
.repeatable(false)
.argument("file")
.callback(Poco::Util::OptionCallback<MicroService>(this, &MicroService::handleConfig)));
options.addOption(
Poco::Util::Option("debug", "", "to run in debug, set to true")
.required(false)
.repeatable(false)
.callback(Poco::Util::OptionCallback<MicroService>(this, &MicroService::handleDebug)));
options.addOption(
Poco::Util::Option("logs", "", "specify the log directory and file (i.e. dir/file.log)")
.required(false)
.repeatable(false)
.argument("dir")
.callback(Poco::Util::OptionCallback<MicroService>(this, &MicroService::handleLogs)));
options.addOption(
Poco::Util::Option("version", "", "get the version and quit.")
.required(false)
.repeatable(false)
.callback(Poco::Util::OptionCallback<MicroService>(this, &MicroService::handleVersion)));
}
void MicroService::handleHelp([[maybe_unused]] const std::string &name, [[maybe_unused]] const std::string &value) {
HelpRequested_ = true;
displayHelp();
stopOptionsProcessing();
}
void MicroService::handleVersion([[maybe_unused]] const std::string &name, [[maybe_unused]] const std::string &value) {
HelpRequested_ = true;
std::cout << Version() << std::endl;
stopOptionsProcessing();
}
void MicroService::handleDebug([[maybe_unused]] const std::string &name, const std::string &value) {
if(value == "true")
DebugMode_ = true ;
}
void MicroService::handleLogs([[maybe_unused]] const std::string &name, const std::string &value) {
LogDir_ = value;
}
void MicroService::handleConfig([[maybe_unused]] const std::string &name, const std::string &value) {
ConfigFileName_ = value;
}
void MicroService::displayHelp() {
Poco::Util::HelpFormatter helpFormatter(options());
helpFormatter.setCommand(commandName());
helpFormatter.setUsage("OPTIONS");
helpFormatter.setHeader("A " + DAEMON_APP_NAME + " implementation for TIP.");
helpFormatter.format(std::cout);
}
void MicroService::InitializeSubSystemServers() {
for(auto i:SubSystems_) {
addSubsystem(i);
}
}
void MicroService::StartSubSystemServers() {
AddActivity("Starting");
for(auto i:SubSystems_) {
i->Start();
}
EventBusManager_ = std::make_unique<EventBusManager>(Poco::Logger::create("EventBusManager",Poco::Logger::root().getChannel(),Poco::Logger::root().getLevel()));
EventBusManager_->Start();
}
void MicroService::StopSubSystemServers() {
AddActivity("Stopping");
EventBusManager_->Stop();
for(auto i=SubSystems_.rbegin(); i!=SubSystems_.rend(); ++i) {
(*i)->Stop();
}
}
[[nodiscard]] std::string MicroService::CreateUUID() {
static std::random_device rd;
static std::mt19937_64 gen(rd());
static std::uniform_int_distribution<> dis(0, 15);
static std::uniform_int_distribution<> dis2(8, 11);
std::stringstream ss;
int i;
ss << std::hex;
for (i = 0; i < 8; i++) {
ss << dis(gen);
}
ss << "-";
for (i = 0; i < 4; i++) {
ss << dis(gen);
}
ss << "-4";
for (i = 0; i < 3; i++) {
ss << dis(gen);
}
ss << "-";
ss << dis2(gen);
for (i = 0; i < 3; i++) {
ss << dis(gen);
}
ss << "-";
for (i = 0; i < 12; i++) {
ss << dis(gen);
};
return ss.str();
}
bool MicroService::SetSubsystemLogLevel(const std::string &SubSystem, const std::string &Level) {
try {
auto P = Poco::Logger::parseLevel(Level);
auto Sub = Poco::toLower(SubSystem);
if (Sub == "all") {
for (auto i : SubSystems_) {
i->Logger().setLevel(P);
}
return true;
} else {
for (auto i : SubSystems_) {
if (Sub == Poco::toLower(i->Name())) {
i->Logger().setLevel(P);
return true;
}
}
}
} catch (const Poco::Exception & E) {
std::cerr << "Exception" << std::endl;
}
return false;
}
void MicroService::Reload(const std::string &Sub) {
for (auto i : SubSystems_) {
if (Poco::toLower(Sub) == Poco::toLower(i->Name())) {
i->reinitialize(Poco::Util::Application::instance());
return;
}
}
}
Types::StringVec MicroService::GetSubSystems() const {
Types::StringVec Result;
for(auto i:SubSystems_)
Result.push_back(Poco::toLower(i->Name()));
return Result;
}
Types::StringPairVec MicroService::GetLogLevels() {
Types::StringPairVec Result;
for(auto &i:SubSystems_) {
auto P = std::make_pair( i->Name(), Utils::LogLevelToString(i->GetLoggingLevel()));
Result.push_back(P);
}
return Result;
}
const Types::StringVec & MicroService::GetLogLevelNames() {
static Types::StringVec LevelNames{"none", "fatal", "critical", "error", "warning", "notice", "information", "debug", "trace" };
return LevelNames;
}
uint64_t MicroService::ConfigGetInt(const std::string &Key,uint64_t Default) {
return (uint64_t) config().getInt64(Key,Default);
}
uint64_t MicroService::ConfigGetInt(const std::string &Key) {
return config().getInt(Key);
}
uint64_t MicroService::ConfigGetBool(const std::string &Key,bool Default) {
return config().getBool(Key,Default);
}
uint64_t MicroService::ConfigGetBool(const std::string &Key) {
return config().getBool(Key);
}
std::string MicroService::ConfigGetString(const std::string &Key,const std::string & Default) {
return config().getString(Key, Default);
}
std::string MicroService::ConfigGetString(const std::string &Key) {
return config().getString(Key);
}
std::string MicroService::ConfigPath(const std::string &Key,const std::string & Default) {
std::string R = config().getString(Key, Default);
return Poco::Path::expand(R);
}
std::string MicroService::ConfigPath(const std::string &Key) {
std::string R = config().getString(Key);
return Poco::Path::expand(R);
}
std::string MicroService::Encrypt(const std::string &S) {
if(NoBuiltInCrypto_) {
return S;
}
return Cipher_->encryptString(S, Poco::Crypto::Cipher::Cipher::ENC_BASE64);;
}
std::string MicroService::Decrypt(const std::string &S) {
if(NoBuiltInCrypto_) {
return S;
}
return Cipher_->decryptString(S, Poco::Crypto::Cipher::Cipher::ENC_BASE64);;
}
std::string MicroService::MakeSystemEventMessage( const std::string & Type ) const {
Poco::JSON::Object Obj;
Obj.set(KafkaTopics::ServiceEvents::Fields::EVENT,Type);
Obj.set(KafkaTopics::ServiceEvents::Fields::ID,ID_);
Obj.set(KafkaTopics::ServiceEvents::Fields::TYPE,Poco::toLower(DAEMON_APP_NAME));
Obj.set(KafkaTopics::ServiceEvents::Fields::PUBLIC,MyPublicEndPoint_);
Obj.set(KafkaTopics::ServiceEvents::Fields::PRIVATE,MyPrivateEndPoint_);
Obj.set(KafkaTopics::ServiceEvents::Fields::KEY,MyHash_);
Obj.set(KafkaTopics::ServiceEvents::Fields::VRSN,Version_);
std::stringstream ResultText;
Poco::JSON::Stringifier::stringify(Obj, ResultText);
return ResultText.str();
}
[[nodiscard]] bool MicroService::IsValidAPIKEY(const Poco::Net::HTTPServerRequest &Request) {
try {
auto APIKEY = Request.get("X-API-KEY");
return APIKEY == MyHash_;
} catch (const Poco::Exception &E) {
logger().log(E);
}
return false;
}
void MicroService::SavePID() {
try {
std::ofstream O;
O.open(MicroService::instance().DataDir() + "/pidfile",std::ios::binary | std::ios::trunc);
O << Poco::Process::id();
O.close();
} catch (...)
{
std::cout << "Could not save system ID" << std::endl;
}
}
int MicroService::main([[maybe_unused]] const ArgVec &args) {
MicroServiceErrorHandler ErrorHandler(*this);
Poco::ErrorHandler::set(&ErrorHandler);
if (!HelpRequested_) {
SavePID();
Poco::Logger &logger = Poco::Logger::get(DAEMON_APP_NAME);
logger.notice(fmt::format("Starting {} version {}.",DAEMON_APP_NAME, Version()));
if(Poco::Net::Socket::supportsIPv6())
poco_information(logger,"System supports IPv6.");
else
poco_information(logger,"System does NOT support IPv6.");
if (config().getBool("application.runAsDaemon", false)) {
poco_information(logger,"Starting as a daemon.");
}
poco_information(logger,fmt::format("System ID set to {}",ID_));
StartSubSystemServers();
waitForTerminationRequest();
StopSubSystemServers();
logger.notice(fmt::format("Stopped {}...",DAEMON_APP_NAME));
}
return Application::EXIT_OK;
}
void MicroService::AddActivity(const std::string &Activity) {
if(!DataDir_.empty()) {
std::string ActivityFile{ DataDir_ + "/activity.log"};
try {
std::ofstream of(ActivityFile,std::ios_base::app | std::ios_base::out );
auto t = std::chrono::system_clock::now();
std::time_t now = std::chrono::system_clock::to_time_t(t);
of << Activity << " at " << std::ctime(&now) ;
} catch (...) {
}
}
}
[[nodiscard]] std::string MicroService::Sign(Poco::JWT::Token &T, const std::string &Algo) {
if(NoBuiltInCrypto_) {
return T.toString();
} else {
return Signer_.sign(T,Algo);
}
}
void MicroService::DeleteOverrideConfiguration() {
Poco::File F(DataDir_ + ExtraConfigurationFilename);
try {
if(F.exists())
F.remove();
} catch (...) {
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -10,6 +10,7 @@
#include "Poco/Net/NetException.h" #include "Poco/Net/NetException.h"
#include "Poco/Net/SSLException.h" #include "Poco/Net/SSLException.h"
#include "Poco/JSON/Template.h" #include "Poco/JSON/Template.h"
#include "Poco/JSON/JSONException.h"
#include "Poco/Thread.h" #include "Poco/Thread.h"
namespace OpenWifi { namespace OpenWifi {
@@ -101,6 +102,48 @@ namespace OpenWifi {
E.displayText(), E.displayText(),
E.message(), E.message(),
E.what())); E.what()));
} catch (const Poco::TimeoutException &E) {
poco_error(App_.logger(), fmt::format("Poco::TimeoutException thr_name={} thr_id={} code={} text={} msg={} what={}",
t_name, t_id, E.code(),
E.displayText(),
E.message(),
E.what()));
} catch (const Poco::NoThreadAvailableException &E) {
poco_error(App_.logger(), fmt::format("Poco::NoThreadAvailableException thr_name={} thr_id={} code={} text={} msg={} what={}",
t_name, t_id, E.code(),
E.displayText(),
E.message(),
E.what()));
} catch (const Poco::OutOfMemoryException &E) {
poco_error(App_.logger(), fmt::format("Poco::OutOfMemoryException thr_name={} thr_id={} code={} text={} msg={} what={}",
t_name, t_id, E.code(),
E.displayText(),
E.message(),
E.what()));
} catch (const Poco::BadCastException &E) {
poco_error(App_.logger(), fmt::format("Poco::BadCastException thr_name={} thr_id={} code={} text={} msg={} what={}",
t_name, t_id, E.code(),
E.displayText(),
E.message(),
E.what()));
} catch (const Poco::DataException &E) {
poco_error(App_.logger(), fmt::format("Poco::DataException thr_name={} thr_id={} code={} text={} msg={} what={}",
t_name, t_id, E.code(),
E.displayText(),
E.message(),
E.what()));
} catch (const Poco::PoolOverflowException &E) {
poco_error(App_.logger(), fmt::format("Poco::PoolOverflowException thr_name={} thr_id={} code={} text={} msg={} what={}",
t_name, t_id, E.code(),
E.displayText(),
E.message(),
E.what()));
} catch (const Poco::SystemException &E) {
poco_error(App_.logger(), fmt::format("Poco::SystemException thr_name={} thr_id={} code={} text={} msg={} what={}",
t_name, t_id, E.code(),
E.displayText(),
E.message(),
E.what()));
} catch (const Poco::RuntimeException &E) { } catch (const Poco::RuntimeException &E) {
poco_error(App_.logger(), fmt::format("Poco::RuntimeException thr_name={} thr_id={} code={} text={} msg={} what={}", poco_error(App_.logger(), fmt::format("Poco::RuntimeException thr_name={} thr_id={} code={} text={} msg={} what={}",
t_name, t_id, E.code(), t_name, t_id, E.code(),

View File

@@ -0,0 +1,132 @@
//
// Created by stephane bourque on 2022-10-26.
//
#pragma once
#include <string>
#include <map>
#include "Poco/BasicEvent.h"
#include "Poco/ExpireLRUCache.h"
namespace OpenWifi {
class ConfigurationEntry {
public:
template <typename T> explicit ConfigurationEntry(T def) :
Default_(def),
Current_(def){
}
template <typename T> explicit ConfigurationEntry(T def, T cur, const std::string &Hint="") :
Default_(def),
Current_(cur),
Hint_(Hint){
}
inline ConfigurationEntry()=default;
inline ~ConfigurationEntry()=default;
template <typename T> explicit operator T () const { return std::get<T>(Current_); }
inline ConfigurationEntry & operator=(const char *v) { Current_ = std::string(v); return *this;}
template <typename T> ConfigurationEntry & operator=(T v) { Current_ = (T) v; return *this;}
void reset() {
Current_ = Default_;
}
private:
std::variant<bool,uint64_t,std::string> Default_, Current_;
std::string Hint_;
};
inline std::string to_string(const ConfigurationEntry &v) { return (std::string) v; }
typedef std::map<std::string,ConfigurationEntry> ConfigurationMap_t;
template <typename T> class FIFO {
public:
explicit FIFO(uint32_t Size) :
Size_(Size) {
Buffer_ = new T [Size_];
}
~FIFO() {
delete [] Buffer_;
}
mutable Poco::BasicEvent<bool> Writable_;
mutable Poco::BasicEvent<bool> Readable_;
inline bool Read(T &t) {
{
std::lock_guard M(Mutex_);
if (Write_ == Read_) {
return false;
}
t = Buffer_[Read_++];
if (Read_ == Size_) {
Read_ = 0;
}
Used_--;
}
bool flag = true;
Writable_.notify(this, flag);
return true;
}
inline bool Write(const T &t) {
{
std::lock_guard M(Mutex_);
Buffer_[Write_++] = t;
if (Write_ == Size_) {
Write_ = 0;
}
Used_++;
MaxEverUsed_ = std::max(Used_,MaxEverUsed_);
}
bool flag = true;
Readable_.notify(this, flag);
return false;
}
inline bool isFull() {
std::lock_guard M(Mutex_);
return Used_==Buffer_->capacity();
}
inline auto MaxEverUser() const { return MaxEverUsed_; }
private:
std::recursive_mutex Mutex_;
uint32_t Size_=0;
uint32_t Read_=0;
uint32_t Write_=0;
uint32_t Used_=0;
uint32_t MaxEverUsed_=0;
T * Buffer_ = nullptr;
};
template <class Record, typename KeyType = std::string, int Size=256, int Expiry=60000> class RecordCache {
public:
explicit RecordCache( KeyType Record::* Q) :
MemberOffset(Q){
};
inline auto update(const Record &R) {
return Cache_.update(R.*MemberOffset, R);
}
inline auto get(const KeyType &K) {
return Cache_.get(K);
}
inline auto remove(const KeyType &K) {
return Cache_.remove(K);
}
inline auto remove(const Record &R) {
return Cache_.remove(R.*MemberOffset);
}
private:
KeyType Record::* MemberOffset;
Poco::ExpireLRUCache<KeyType,Record> Cache_{Size,Expiry};
};
}

View File

@@ -0,0 +1,121 @@
//
// Created by stephane bourque on 2022-10-25.
//
#include "framework/MicroService.h"
#include "framework/MicroServiceFuncs.h"
namespace OpenWifi {
const std::string &MicroServiceDataDirectory() { return MicroService::instance().DataDir(); }
Types::MicroServiceMetaVec MicroServiceGetServices(const std::string &Type) {
return MicroService::instance().GetServices(Type);
}
Types::MicroServiceMetaVec MicroServiceGetServices() {
return MicroService::instance().GetServices();
}
std::string MicroServicePublicEndPoint() { return MicroService::instance().PublicEndPoint(); }
std::string MicroServiceConfigGetString(const std::string &Key, const std::string &DefaultValue) {
return MicroService::instance().ConfigGetString(Key, DefaultValue);
}
bool MicroServiceConfigGetBool(const std::string &Key, bool DefaultValue) {
return MicroService::instance().ConfigGetBool(Key, DefaultValue);
}
std::uint64_t MicroServiceConfigGetInt(const std::string &Key, std::uint64_t DefaultValue) {
return MicroService::instance().ConfigGetInt(Key, DefaultValue);
}
std::string MicroServicePrivateEndPoint() { return MicroService::instance().PrivateEndPoint(); }
std::uint64_t MicroServiceID() { return MicroService::instance().ID(); }
bool MicroServiceIsValidAPIKEY(const Poco::Net::HTTPServerRequest &Request) {
return MicroService::instance().IsValidAPIKEY(Request);
}
bool MicroServiceNoAPISecurity() { return MicroService::instance().NoAPISecurity(); }
void MicroServiceLoadConfigurationFile() { MicroService::instance().LoadConfigurationFile(); }
void MicroServiceReload() { MicroService::instance().Reload(); }
void MicroServiceReload(const std::string &Type) { MicroService::instance().Reload(Type); }
const Types::StringVec MicroServiceGetLogLevelNames() {
return MicroService::instance().GetLogLevelNames();
}
const Types::StringVec MicroServiceGetSubSystems() {
return MicroService::instance().GetSubSystems();
}
Types::StringPairVec MicroServiceGetLogLevels() { return MicroService::instance().GetLogLevels(); }
bool MicroServiceSetSubsystemLogLevel(const std::string &SubSystem, const std::string &Level) {
return MicroService::instance().SetSubsystemLogLevel(SubSystem, Level);
}
void MicroServiceGetExtraConfiguration(Poco::JSON::Object &Answer) {
MicroService::instance().GetExtraConfiguration(Answer);
}
std::string MicroServiceVersion() { return MicroService::instance().Version(); }
std::uint64_t MicroServiceUptimeTotalSeconds() {
return MicroService::instance().uptime().totalSeconds();
}
std::uint64_t MicroServiceStartTimeEpochTime() {
return MicroService::instance().startTime().epochTime();
}
std::string MicroServiceGetUIURI() { return MicroService::instance().GetUIURI(); }
const SubSystemVec MicroServiceGetFullSubSystems() {
return MicroService::instance().GetFullSubSystems();
}
std::string MicroServiceCreateUUID() { return MicroService::CreateUUID(); }
std::uint64_t MicroServiceDaemonBusTimer() { return MicroService::instance().DaemonBusTimer(); }
std::string MicroServiceMakeSystemEventMessage(const std::string &Type) {
return MicroService::instance().MakeSystemEventMessage(Type);
}
Poco::ThreadPool &MicroServiceTimerPool() { return MicroService::instance().TimerPool(); }
std::string MicroServiceConfigPath(const std::string &Key,
const std::string &DefaultValue) {
return MicroService::instance().ConfigPath(Key, DefaultValue);
}
std::string MicroServiceWWWAssetsDir() {
return MicroService::instance().WWWAssetsDir();
}
std::uint64_t MicroServiceRandom(std::uint64_t Start,std::uint64_t End) {
return MicroService::instance().Random(Start, End);
}
std::uint64_t MicroServiceRandom(std::uint64_t Range) {
return MicroService::instance().Random(Range);
}
std::string MicroServiceSign(Poco::JWT::Token &T, const std::string &Algo) {
return MicroService::instance().Sign(T, Algo);
}
std::string MicroServiceGetPublicAPIEndPoint() {
return MicroService::instance().GetPublicAPIEndPoint();
}
void MicroServiceDeleteOverrideConfiguration() {
return MicroService::instance().DeleteOverrideConfiguration();
}
}

View File

@@ -0,0 +1,56 @@
//
// Created by stephane bourque on 2022-10-25.
//
#pragma once
#include <string>
#include "framework/OpenWifiTypes.h"
#include "Poco/Net/HTTPServerRequest.h"
#include "Poco/JSON/Object.h"
#include "Poco/ThreadPool.h"
#include "Poco/JWT/Token.h"
namespace OpenWifi {
class SubSystemServer;
using SubSystemVec=std::vector<SubSystemServer *>;
const std::string & MicroServiceDataDirectory();
Types::MicroServiceMetaVec MicroServiceGetServices(const std::string & Type);
Types::MicroServiceMetaVec MicroServiceGetServices();
std::string MicroServicePublicEndPoint();
std::string MicroServiceConfigGetString(const std::string &Key, const std::string &DefaultValue);
bool MicroServiceConfigGetBool(const std::string &Key, bool DefaultValue);
std::uint64_t MicroServiceConfigGetInt(const std::string &Key, std::uint64_t DefaultValue);
std::string MicroServicePrivateEndPoint();
std::uint64_t MicroServiceID();
bool MicroServiceIsValidAPIKEY(const Poco::Net::HTTPServerRequest &Request);
bool MicroServiceNoAPISecurity();
void MicroServiceLoadConfigurationFile();
void MicroServiceReload();
void MicroServiceReload(const std::string &Type);
const Types::StringVec MicroServiceGetLogLevelNames();
const Types::StringVec MicroServiceGetSubSystems();
Types::StringPairVec MicroServiceGetLogLevels();
bool MicroServiceSetSubsystemLogLevel(const std::string &SubSystem, const std::string &Level);
void MicroServiceGetExtraConfiguration(Poco::JSON::Object &Answer);
std::string MicroServiceVersion();
std::uint64_t MicroServiceUptimeTotalSeconds();
std::uint64_t MicroServiceStartTimeEpochTime();
std::string MicroServiceGetUIURI();
const SubSystemVec MicroServiceGetFullSubSystems();
std::string MicroServiceCreateUUID();
std::uint64_t MicroServiceDaemonBusTimer();
std::string MicroServiceMakeSystemEventMessage( const std::string & Type );
Poco::ThreadPool & MicroServiceTimerPool();
std::string MicroServiceConfigPath(const std::string &Key,
const std::string &DefaultValue);
std::string MicroServiceWWWAssetsDir();
std::uint64_t MicroServiceRandom(std::uint64_t Start,std::uint64_t End);
std::uint64_t MicroServiceRandom(std::uint64_t Range);
std::string MicroServiceSign(Poco::JWT::Token &T, const std::string &Algo);
std::string MicroServiceGetPublicAPIEndPoint();
void MicroServiceDeleteOverrideConfiguration();
}

View File

@@ -0,0 +1,22 @@
//
// Created by stephane bourque on 2022-10-25.
//
#pragma once
#include <string>
namespace OpenWifi {
static const std::string uSERVICE_SECURITY{"owsec"};
static const std::string uSERVICE_GATEWAY{"owgw"};
static const std::string uSERVICE_FIRMWARE{ "owfms"};
static const std::string uSERVICE_TOPOLOGY{ "owtopo"};
static const std::string uSERVICE_PROVISIONING{ "owprov"};
static const std::string uSERVICE_OWLS{ "owls"};
static const std::string uSERVICE_SUBCRIBER{ "owsub"};
static const std::string uSERVICE_INSTALLER{ "owinst"};
static const std::string uSERVICE_ANALYTICS{ "owanalytics"};
static const std::string uSERVICE_OWRRM{ "owrrm"};
}

View File

@@ -0,0 +1,289 @@
//
// Created by stephane bourque on 2022-10-25.
//
#include "OpenAPIRequests.h"
#include "Poco/Logger.h"
#include "Poco/URI.h"
#include "Poco/Net/HTTPRequest.h"
#include "Poco/Net/HTTPSClientSession.h"
#include "Poco/JSON/Parser.h"
#include "fmt/format.h"
#include "framework/MicroServiceFuncs.h"
namespace OpenWifi {
Poco::Net::HTTPServerResponse::HTTPStatus OpenAPIRequestGet::Do(Poco::JSON::Object::Ptr &ResponseObject, const std::string & BearerToken) {
try {
auto Services = MicroServiceGetServices(Type_);
for(auto const &Svc:Services) {
Poco::URI URI(Svc.PrivateEndPoint);
auto Secure = (URI.getScheme() == "https");
URI.setPath(EndPoint_);
for (const auto &qp : QueryData_)
URI.addQueryParameter(qp.first, qp.second);
std::string Path(URI.getPathAndQuery());
Poco::Net::HTTPRequest Request(Poco::Net::HTTPRequest::HTTP_GET,
Path,
Poco::Net::HTTPMessage::HTTP_1_1);
poco_debug(Poco::Logger::get("REST-CALLER-GET"), fmt::format(" {}", LoggingStr_.empty() ? URI.toString() : LoggingStr_ ) );
if(BearerToken.empty()) {
Request.add("X-API-KEY", Svc.AccessKey);
Request.add("X-INTERNAL-NAME", MicroServicePublicEndPoint());
} else {
// Authorization: Bearer ${token}
Request.add("Authorization", "Bearer " + BearerToken);
}
if(Secure) {
Poco::Net::HTTPSClientSession Session(URI.getHost(), URI.getPort());
Session.setTimeout(Poco::Timespan(msTimeout_ / 1000, msTimeout_ % 1000));
Session.sendRequest(Request);
Poco::Net::HTTPResponse Response;
std::istream &is = Session.receiveResponse(Response);
if (Response.getStatus() == Poco::Net::HTTPResponse::HTTP_OK) {
Poco::JSON::Parser P;
ResponseObject = P.parse(is).extract<Poco::JSON::Object::Ptr>();
}
return Response.getStatus();
} else {
Poco::Net::HTTPClientSession Session(URI.getHost(), URI.getPort());
Session.setTimeout(Poco::Timespan(msTimeout_ / 1000, msTimeout_ % 1000));
Session.sendRequest(Request);
Poco::Net::HTTPResponse Response;
std::istream &is = Session.receiveResponse(Response);
if (Response.getStatus() == Poco::Net::HTTPResponse::HTTP_OK) {
Poco::JSON::Parser P;
ResponseObject = P.parse(is).extract<Poco::JSON::Object::Ptr>();
}
return Response.getStatus();
}
}
}
catch (const Poco::Exception &E)
{
Poco::Logger::get("REST-CALLER-GET").log(E);
}
return Poco::Net::HTTPServerResponse::HTTP_GATEWAY_TIMEOUT;
}
Poco::Net::HTTPServerResponse::HTTPStatus OpenAPIRequestPut::Do(Poco::JSON::Object::Ptr &ResponseObject, const std::string & BearerToken) {
try {
auto Services = MicroServiceGetServices(Type_);
for(auto const &Svc:Services) {
Poco::URI URI(Svc.PrivateEndPoint);
auto Secure = (URI.getScheme() == "https");
URI.setPath(EndPoint_);
for (const auto &qp : QueryData_)
URI.addQueryParameter(qp.first, qp.second);
poco_debug(Poco::Logger::get("REST-CALLER-PUT"), fmt::format(" {}", LoggingStr_.empty() ? URI.toString() : LoggingStr_ ) );
std::string Path(URI.getPathAndQuery());
Poco::Net::HTTPRequest Request(Poco::Net::HTTPRequest::HTTP_PUT,
Path,
Poco::Net::HTTPMessage::HTTP_1_1);
std::ostringstream obody;
Poco::JSON::Stringifier::stringify(Body_,obody);
Request.setContentType("application/json");
Request.setContentLength(obody.str().size());
if(BearerToken.empty()) {
Request.add("X-API-KEY", Svc.AccessKey);
Request.add("X-INTERNAL-NAME", MicroServicePublicEndPoint());
} else {
// Authorization: Bearer ${token}
Request.add("Authorization", "Bearer " + BearerToken);
}
if(Secure) {
Poco::Net::HTTPSClientSession Session(URI.getHost(), URI.getPort());
Session.setTimeout(Poco::Timespan(msTimeout_ / 1000, msTimeout_ % 1000));
std::ostream &os = Session.sendRequest(Request);
os << obody.str();
Poco::Net::HTTPResponse Response;
std::istream &is = Session.receiveResponse(Response);
if (Response.getStatus() == Poco::Net::HTTPResponse::HTTP_OK) {
Poco::JSON::Parser P;
ResponseObject = P.parse(is).extract<Poco::JSON::Object::Ptr>();
} else {
Poco::JSON::Parser P;
ResponseObject = P.parse(is).extract<Poco::JSON::Object::Ptr>();
}
return Response.getStatus();
} else {
Poco::Net::HTTPClientSession Session(URI.getHost(), URI.getPort());
Session.setTimeout(Poco::Timespan(msTimeout_ / 1000, msTimeout_ % 1000));
std::ostream &os = Session.sendRequest(Request);
os << obody.str();
Poco::Net::HTTPResponse Response;
std::istream &is = Session.receiveResponse(Response);
if (Response.getStatus() == Poco::Net::HTTPResponse::HTTP_OK) {
Poco::JSON::Parser P;
ResponseObject = P.parse(is).extract<Poco::JSON::Object::Ptr>();
} else {
Poco::JSON::Parser P;
ResponseObject = P.parse(is).extract<Poco::JSON::Object::Ptr>();
}
return Response.getStatus();
}
}
}
catch (const Poco::Exception &E)
{
Poco::Logger::get("REST-CALLER-PUT").log(E);
}
return Poco::Net::HTTPServerResponse::HTTP_GATEWAY_TIMEOUT;
}
Poco::Net::HTTPServerResponse::HTTPStatus OpenAPIRequestPost::Do(Poco::JSON::Object::Ptr &ResponseObject, const std::string & BearerToken) {
try {
auto Services = MicroServiceGetServices(Type_);
for(auto const &Svc:Services) {
Poco::URI URI(Svc.PrivateEndPoint);
auto Secure = (URI.getScheme() == "https");
URI.setPath(EndPoint_);
for (const auto &qp : QueryData_)
URI.addQueryParameter(qp.first, qp.second);
poco_debug(Poco::Logger::get("REST-CALLER-POST"),fmt::format(" {}", LoggingStr_.empty() ? URI.toString() : LoggingStr_ ) );
std::string Path(URI.getPathAndQuery());
Poco::Net::HTTPRequest Request(Poco::Net::HTTPRequest::HTTP_POST,
Path,
Poco::Net::HTTPMessage::HTTP_1_1);
std::ostringstream obody;
Poco::JSON::Stringifier::stringify(Body_,obody);
Request.setContentType("application/json");
Request.setContentLength(obody.str().size());
if(BearerToken.empty()) {
Request.add("X-API-KEY", Svc.AccessKey);
Request.add("X-INTERNAL-NAME", MicroServicePublicEndPoint());
} else {
// Authorization: Bearer ${token}
Request.add("Authorization", "Bearer " + BearerToken);
}
if(Secure) {
Poco::Net::HTTPSClientSession Session(URI.getHost(), URI.getPort());
Session.setTimeout(Poco::Timespan(msTimeout_ / 1000, msTimeout_ % 1000));
std::ostream &os = Session.sendRequest(Request);
os << obody.str();
Poco::Net::HTTPResponse Response;
std::istream &is = Session.receiveResponse(Response);
if (Response.getStatus() == Poco::Net::HTTPResponse::HTTP_OK) {
Poco::JSON::Parser P;
ResponseObject = P.parse(is).extract<Poco::JSON::Object::Ptr>();
} else {
Poco::JSON::Parser P;
ResponseObject = P.parse(is).extract<Poco::JSON::Object::Ptr>();
}
return Response.getStatus();
} else {
Poco::Net::HTTPClientSession Session(URI.getHost(), URI.getPort());
Session.setTimeout(Poco::Timespan(msTimeout_ / 1000, msTimeout_ % 1000));
std::ostream &os = Session.sendRequest(Request);
os << obody.str();
Poco::Net::HTTPResponse Response;
std::istream &is = Session.receiveResponse(Response);
if (Response.getStatus() == Poco::Net::HTTPResponse::HTTP_OK) {
Poco::JSON::Parser P;
ResponseObject = P.parse(is).extract<Poco::JSON::Object::Ptr>();
} else {
Poco::JSON::Parser P;
ResponseObject = P.parse(is).extract<Poco::JSON::Object::Ptr>();
}
return Response.getStatus();
}
}
}
catch (const Poco::Exception &E)
{
Poco::Logger::get("REST-CALLER-POST").log(E);
}
return Poco::Net::HTTPServerResponse::HTTP_GATEWAY_TIMEOUT;
}
Poco::Net::HTTPServerResponse::HTTPStatus OpenAPIRequestDelete::Do(const std::string & BearerToken) {
try {
auto Services = MicroServiceGetServices(Type_);
for(auto const &Svc:Services) {
Poco::URI URI(Svc.PrivateEndPoint);
auto Secure = (URI.getScheme() == "https");
URI.setPath(EndPoint_);
for (const auto &qp : QueryData_)
URI.addQueryParameter(qp.first, qp.second);
poco_debug(Poco::Logger::get("REST-CALLER-DELETE"),fmt::format(" {}", LoggingStr_.empty() ? URI.toString() : LoggingStr_ ) );
std::string Path(URI.getPathAndQuery());
Poco::Net::HTTPRequest Request(Poco::Net::HTTPRequest::HTTP_DELETE,
Path,
Poco::Net::HTTPMessage::HTTP_1_1);
if(BearerToken.empty()) {
Request.add("X-API-KEY", Svc.AccessKey);
Request.add("X-INTERNAL-NAME", MicroServicePublicEndPoint());
} else {
// Authorization: Bearer ${token}
Request.add("Authorization", "Bearer " + BearerToken);
}
if(Secure) {
Poco::Net::HTTPSClientSession Session(URI.getHost(), URI.getPort());
Session.setTimeout(Poco::Timespan(msTimeout_ / 1000, msTimeout_ % 1000));
Session.sendRequest(Request);
Poco::Net::HTTPResponse Response;
Session.receiveResponse(Response);
return Response.getStatus();
} else {
Poco::Net::HTTPClientSession Session(URI.getHost(), URI.getPort());
Session.setTimeout(Poco::Timespan(msTimeout_ / 1000, msTimeout_ % 1000));
Session.sendRequest(Request);
Poco::Net::HTTPResponse Response;
Session.receiveResponse(Response);
return Response.getStatus();
}
}
}
catch (const Poco::Exception &E)
{
Poco::Logger::get("REST-CALLER-DELETE").log(E);
}
return Poco::Net::HTTPServerResponse::HTTP_GATEWAY_TIMEOUT;
}
} // namespace OpenWifi

View File

@@ -0,0 +1,110 @@
//
// Created by stephane bourque on 2022-10-25.
//
#pragma once
#include <string>
#include "Poco/JSON/Object.h"
#include "Poco/Net/HTTPServerResponse.h"
#include "framework/OpenWifiTypes.h"
namespace OpenWifi {
class OpenAPIRequestGet {
public:
explicit OpenAPIRequestGet( const std::string & Type,
const std::string & EndPoint,
const Types::StringPairVec & QueryData,
uint64_t msTimeout,
const std::string &LoggingStr=""):
Type_(Type),
EndPoint_(EndPoint),
QueryData_(QueryData),
msTimeout_(msTimeout),
LoggingStr_(LoggingStr){};
Poco::Net::HTTPServerResponse::HTTPStatus Do(Poco::JSON::Object::Ptr &ResponseObject, const std::string & BearerToken = "");
private:
std::string Type_;
std::string EndPoint_;
Types::StringPairVec QueryData_;
uint64_t msTimeout_;
std::string LoggingStr_;
};
class OpenAPIRequestPut {
public:
explicit OpenAPIRequestPut( const std::string & Type,
const std::string & EndPoint,
const Types::StringPairVec & QueryData,
const Poco::JSON::Object & Body,
uint64_t msTimeout,
const std::string &LoggingStr=""):
Type_(Type),
EndPoint_(EndPoint),
QueryData_(QueryData),
msTimeout_(msTimeout),
Body_(Body),
LoggingStr_(LoggingStr){};
Poco::Net::HTTPServerResponse::HTTPStatus Do(Poco::JSON::Object::Ptr &ResponseObject, const std::string & BearerToken = "");
private:
std::string Type_;
std::string EndPoint_;
Types::StringPairVec QueryData_;
uint64_t msTimeout_;
Poco::JSON::Object Body_;
std::string LoggingStr_;
};
class OpenAPIRequestPost {
public:
explicit OpenAPIRequestPost( const std::string & Type,
const std::string & EndPoint,
const Types::StringPairVec & QueryData,
const Poco::JSON::Object & Body,
uint64_t msTimeout,
const std::string &LoggingStr=""):
Type_(Type),
EndPoint_(EndPoint),
QueryData_(QueryData),
msTimeout_(msTimeout),
Body_(Body),
LoggingStr_(LoggingStr){};
Poco::Net::HTTPServerResponse::HTTPStatus Do(Poco::JSON::Object::Ptr &ResponseObject, const std::string & BearerToken = "");
private:
std::string Type_;
std::string EndPoint_;
Types::StringPairVec QueryData_;
uint64_t msTimeout_;
Poco::JSON::Object Body_;
std::string LoggingStr_;
};
class OpenAPIRequestDelete {
public:
explicit OpenAPIRequestDelete( const std::string & Type,
const std::string & EndPoint,
const Types::StringPairVec & QueryData,
uint64_t msTimeout,
const std::string &LoggingStr=""):
Type_(Type),
EndPoint_(EndPoint),
QueryData_(QueryData),
msTimeout_(msTimeout),
LoggingStr_(LoggingStr){};
Poco::Net::HTTPServerResponse::HTTPStatus Do(const std::string & BearerToken = "");
private:
std::string Type_;
std::string EndPoint_;
Types::StringPairVec QueryData_;
uint64_t msTimeout_;
Poco::JSON::Object Body_;
std::string LoggingStr_;
};
} // namespace OpenWifi

View File

@@ -28,6 +28,19 @@ namespace OpenWifi::Types {
typedef std::string UUID_t; typedef std::string UUID_t;
typedef std::vector<UUID_t> UUIDvec_t; typedef std::vector<UUID_t> UUIDvec_t;
typedef std::map<std::string,std::map<uint32_t,uint64_t>> Counted3DMapSII; typedef std::map<std::string,std::map<uint32_t,uint64_t>> Counted3DMapSII;
struct MicroServiceMeta {
uint64_t Id=0;
std::string Type;
std::string PrivateEndPoint;
std::string PublicEndPoint;
std::string AccessKey;
std::string Version;
uint64_t LastUpdate=0;
};
typedef std::map<std::string, MicroServiceMeta> MicroServiceMetaMap;
typedef std::vector<MicroServiceMeta> MicroServiceMetaVec;
} }
namespace OpenWifi { namespace OpenWifi {

View File

@@ -0,0 +1,27 @@
//
// Created by stephane bourque on 2022-10-25.
//
#include "framework/RESTAPI_ExtServer.h"
namespace OpenWifi {
Poco::Net::HTTPRequestHandler *ExtRequestHandlerFactory::createRequestHandler(const Poco::Net::HTTPServerRequest &Request) {
try {
Poco::URI uri(Request.getURI());
auto TID = NextTransactionId_++;
Utils::SetThreadName(fmt::format("x-rest:{}",TID).c_str());
return RESTAPI_ExtServer()->CallServer(uri.getPath(), TID);
} catch (...) {
}
return nullptr;
}
Poco::Net::HTTPRequestHandler *RESTAPI_ExtServer::CallServer(const std::string &Path, uint64_t Id) {
RESTAPIHandler::BindingMap Bindings;
Utils::SetThreadName(fmt::format("x-rest:{}",Id).c_str());
return RESTAPI_ExtRouter(Path, Bindings, Logger(), Server_, Id);
}
}

View File

@@ -0,0 +1,99 @@
//
// Created by stephane bourque on 2022-10-25.
//
#pragma once
#include "Poco/Net/HTTPServer.h"
#include "framework/SubSystemServer.h"
#include "framework/RESTAPI_Handler.h"
namespace OpenWifi {
Poco::Net::HTTPRequestHandler * RESTAPI_ExtRouter(const std::string &Path, RESTAPIHandler::BindingMap &Bindings,
Poco::Logger & L, RESTAPI_GenericServerAccounting & S, uint64_t Id);
class ExtRequestHandlerFactory : public Poco::Net::HTTPRequestHandlerFactory {
public:
ExtRequestHandlerFactory() = default;
Poco::Net::HTTPRequestHandler *createRequestHandler(const Poco::Net::HTTPServerRequest &Request) override;
private:
static inline std::atomic_uint64_t NextTransactionId_ = 1;
};
class RESTAPI_ExtServer : public SubSystemServer {
public:
static auto instance() {
static auto instance_ = new RESTAPI_ExtServer;
return instance_;
}
inline int Start() override {
poco_information(Logger(),"Starting.");
Server_.InitLogging();
for(const auto & Svr: ConfigServersList_) {
if(MicroServiceNoAPISecurity()) {
poco_information(Logger(),fmt::format("Starting: {}:{}. Security has been disabled for APIs.", Svr.Address(), Svr.Port()));
} else {
poco_information(Logger(),fmt::format("Starting: {}:{} Keyfile:{} CertFile: {}", Svr.Address(), Svr.Port(),
Svr.KeyFile(),Svr.CertFile()));
Svr.LogCert(Logger());
if (!Svr.RootCA().empty())
Svr.LogCas(Logger());
}
Poco::Net::HTTPServerParams::Ptr Params = new Poco::Net::HTTPServerParams;
Params->setKeepAlive(true);
Params->setName("ws:xrest");
std::unique_ptr<Poco::Net::HTTPServer> NewServer;
if(MicroServiceNoAPISecurity()) {
auto Sock{Svr.CreateSocket(Logger())};
NewServer = std::make_unique<Poco::Net::HTTPServer>(new ExtRequestHandlerFactory, Pool_, Sock, Params);
} else {
auto Sock{Svr.CreateSecureSocket(Logger())};
NewServer = std::make_unique<Poco::Net::HTTPServer>(new ExtRequestHandlerFactory, Pool_, Sock, Params);
};
NewServer->start();
RESTServers_.push_back(std::move(NewServer));
}
return 0;
}
inline void Stop() override {
poco_information(Logger(),"Stopping...");
for( const auto & svr : RESTServers_ )
svr->stopAll(true);
Pool_.stopAll();
Pool_.joinAll();
RESTServers_.clear();
poco_information(Logger(),"Stopped...");
}
inline void reinitialize([[maybe_unused]] Poco::Util::Application &self) override {
MicroServiceLoadConfigurationFile();
poco_information(Logger(),"Reinitializing.");
Stop();
Start();
}
Poco::Net::HTTPRequestHandler *CallServer(const std::string &Path, uint64_t Id);
const Poco::ThreadPool & Pool() { return Pool_; }
private:
std::vector<std::unique_ptr<Poco::Net::HTTPServer>> RESTServers_;
Poco::ThreadPool Pool_{"x-rest",8,128};
RESTAPI_GenericServerAccounting Server_;
RESTAPI_ExtServer() noexcept:
SubSystemServer("RESTAPI_ExtServer", "REST-XSRV", "openwifi.restapi")
{
}
};
inline auto RESTAPI_ExtServer() { return RESTAPI_ExtServer::instance(); };
}

View File

@@ -0,0 +1,75 @@
//
// Created by stephane bourque on 2022-10-25.
//
#pragma once
#include <string>
#include <array>
#include "Poco/StringTokenizer.h"
#include "Poco/String.h"
#include "Poco/Net/HTTPRequest.h"
#include "framework/MicroServiceFuncs.h"
namespace OpenWifi {
class RESTAPI_GenericServerAccounting {
public:
enum {
LOG_GET=0,
LOG_DELETE,
LOG_PUT,
LOG_POST
};
void inline SetFlags(bool External, const std::string &Methods) {
Poco::StringTokenizer Tokens(Methods,",");
auto Offset = (External ? 0 : 4);
for(const auto &i:Tokens) {
if(Poco::icompare(i,Poco::Net::HTTPRequest::HTTP_DELETE)==0)
LogFlags_[Offset+LOG_DELETE]=true;
else if(Poco::icompare(i,Poco::Net::HTTPRequest::HTTP_PUT)==0)
LogFlags_[Offset+LOG_PUT]=true;
else if(Poco::icompare(i,Poco::Net::HTTPRequest::HTTP_POST)==0)
LogFlags_[Offset+LOG_POST]=true;
else if(Poco::icompare(i,Poco::Net::HTTPRequest::HTTP_GET)==0)
LogFlags_[Offset+LOG_GET]=true;
}
}
inline void InitLogging() {
std::string Public = MicroServiceConfigGetString("apilogging.public.methods","PUT,POST,DELETE");
SetFlags(true, Public);
std::string Private = MicroServiceConfigGetString("apilogging.private.methods","PUT,POST,DELETE");
SetFlags(false, Private);
std::string PublicBadTokens = MicroServiceConfigGetString("apilogging.public.badtokens.methods","");
LogBadTokens_[0] = (Poco::icompare(PublicBadTokens,"true")==0);
std::string PrivateBadTokens = MicroServiceConfigGetString("apilogging.private.badtokens.methods","");
LogBadTokens_[1] = (Poco::icompare(PrivateBadTokens,"true")==0);
}
[[nodiscard]] inline bool LogIt(const std::string &Method, bool External) const {
auto Offset = (External ? 0 : 4);
if(Method == Poco::Net::HTTPRequest::HTTP_GET)
return LogFlags_[Offset+LOG_GET];
if(Method == Poco::Net::HTTPRequest::HTTP_POST)
return LogFlags_[Offset+LOG_POST];
if(Method == Poco::Net::HTTPRequest::HTTP_PUT)
return LogFlags_[Offset+LOG_PUT];
if(Method == Poco::Net::HTTPRequest::HTTP_DELETE)
return LogFlags_[Offset+LOG_DELETE];
return false;
};
[[nodiscard]] inline bool LogBadTokens(bool External) const {
return LogBadTokens_[ (External ? 0 : 1) ];
};
private:
std::array<bool,8> LogFlags_{false};
std::array<bool,2> LogBadTokens_{false};
};
}

View File

@@ -0,0 +1,8 @@
//
// Created by stephane bourque on 2022-10-25.
//
#include "RESTAPI_Handler.h"
namespace OpenWifi {
} // namespace OpenWifi

View File

@@ -0,0 +1,826 @@
//
// Created by stephane bourque on 2022-10-25.
//
#pragma once
#include <string>
#include <vector>
#include <map>
#include "Poco/Net/HTTPRequestHandler.h"
#include "Poco/Logger.h"
#include "Poco/JSON/Object.h"
#include "Poco/JSON/Parser.h"
#include "Poco/Net/HTTPResponse.h"
#include "Poco/Net/HTTPServerResponse.h"
#include "Poco/DeflatingStream.h"
#include "Poco/TemporaryFile.h"
#include "Poco/Net/OAuth20Credentials.h"
#include "framework/ow_constants.h"
#include "framework/RESTAPI_GenericServerAccounting.h"
#include "framework/RESTAPI_RateLimiter.h"
#include "framework/utils.h"
#include "framework/RESTAPI_utils.h"
#include "framework/AuthClient.h"
#include "RESTObjects/RESTAPI_SecurityObjects.h"
#if defined(TIP_SECURITY_SERVICE)
#include "AuthService.h"
#endif
using namespace std::chrono_literals;
namespace OpenWifi {
class RESTAPIHandler : public Poco::Net::HTTPRequestHandler {
public:
struct QueryBlock {
uint64_t StartDate = 0 , EndDate = 0 , Offset = 0 , Limit = 0, LogType = 0 ;
std::string SerialNumber, Filter;
std::vector<std::string> Select;
bool Lifetime=false, LastOnly=false, Newest=false, CountOnly=false, AdditionalInfo=false;
};
typedef std::map<std::string, std::string> BindingMap;
struct RateLimit {
int64_t Interval=1000;
int64_t MaxCalls=10;
};
RESTAPIHandler( BindingMap map,
Poco::Logger &l,
std::vector<std::string> Methods,
RESTAPI_GenericServerAccounting & Server,
uint64_t TransactionId,
bool Internal,
bool AlwaysAuthorize=true,
bool RateLimited=false,
const RateLimit & Profile = RateLimit{.Interval=1000,.MaxCalls=100},
bool SubscriberOnly=false)
: Bindings_(std::move(map)),
Logger_(l),
Methods_(std::move(Methods)),
Internal_(Internal),
RateLimited_(RateLimited),
SubOnlyService_(SubscriberOnly),
AlwaysAuthorize_(AlwaysAuthorize),
Server_(Server),
MyRates_(Profile),
TransactionId_(TransactionId)
{
}
inline bool RoleIsAuthorized([[maybe_unused]] const std::string & Path, [[maybe_unused]] const std::string & Method, [[maybe_unused]] std::string & Reason) {
return true;
}
inline void handleRequest(Poco::Net::HTTPServerRequest &RequestIn,
Poco::Net::HTTPServerResponse &ResponseIn) final {
try {
Request = &RequestIn;
Response = &ResponseIn;
// std::string th_name = "restsvr_" + std::to_string(TransactionId_);
// Utils::SetThreadName(th_name.c_str());
if(Request->getContentLength()>0) {
if(Request->getContentType().find("application/json")!=std::string::npos) {
ParsedBody_ = IncomingParser_.parse(Request->stream()).extract<Poco::JSON::Object::Ptr>();
}
}
if(RateLimited_ && RESTAPI_RateLimiter()->IsRateLimited(RequestIn,MyRates_.Interval, MyRates_.MaxCalls)) {
return UnAuthorized(RESTAPI::Errors::RATE_LIMIT_EXCEEDED);
}
if (!ContinueProcessing())
return;
bool Expired=false, Contacted=false;
if (AlwaysAuthorize_ && !IsAuthorized(Expired, Contacted, SubOnlyService_)) {
if(Expired)
return UnAuthorized(RESTAPI::Errors::EXPIRED_TOKEN);
if(Contacted)
return UnAuthorized(RESTAPI::Errors::INVALID_TOKEN);
else
return UnAuthorized(RESTAPI::Errors::SECURITY_SERVICE_UNREACHABLE);
}
std::string Reason;
if(!RoleIsAuthorized(RequestIn.getURI(), Request->getMethod(), Reason)) {
return UnAuthorized(RESTAPI::Errors::ACCESS_DENIED);
}
ParseParameters();
if (Request->getMethod() == Poco::Net::HTTPRequest::HTTP_GET)
return DoGet();
else if (Request->getMethod() == Poco::Net::HTTPRequest::HTTP_POST)
return DoPost();
else if (Request->getMethod() == Poco::Net::HTTPRequest::HTTP_DELETE)
return DoDelete();
else if (Request->getMethod() == Poco::Net::HTTPRequest::HTTP_PUT)
return DoPut();
return BadRequest(RESTAPI::Errors::UnsupportedHTTPMethod);
} catch (const Poco::Exception &E) {
Logger_.log(E);
return BadRequest(RESTAPI::Errors::InternalError);
}
}
[[nodiscard]] inline bool NeedAdditionalInfo() const { return QB_.AdditionalInfo; }
[[nodiscard]] inline const std::vector<std::string> & SelectedRecords() const { return QB_.Select; }
inline static bool ParseBindings(const std::string & Request, const std::list<std::string> & EndPoints, BindingMap &bindings) {
bindings.clear();
auto PathItems = Poco::StringTokenizer(Request, "/");
for(const auto &EndPoint:EndPoints) {
auto ParamItems = Poco::StringTokenizer(EndPoint, "/");
if (PathItems.count() != ParamItems.count())
continue;
bool Matched = true;
for (size_t i = 0; i < PathItems.count(); i++) {
if (PathItems[i] != ParamItems[i]) {
if (ParamItems[i][0] == '{') {
auto ParamName = ParamItems[i].substr(1, ParamItems[i].size() - 2);
bindings[Poco::toLower(ParamName)] = PathItems[i];
} else {
Matched = false;
break;
}
}
}
if(Matched)
return true;
}
return false;
}
inline void PrintBindings() {
for (const auto &[key, value] : Bindings_)
std::cout << "Key = " << key << " Value= " << value << std::endl;
}
inline void ParseParameters() {
Poco::URI uri(Request->getURI());
Parameters_ = uri.getQueryParameters();
InitQueryBlock();
}
inline static bool is_number(const std::string &s) {
return !s.empty() && std::all_of(s.begin(), s.end(), ::isdigit);
}
inline static bool is_bool(const std::string &s) {
if (s == "true" || s == "false")
return true;
return false;
}
[[nodiscard]] inline uint64_t GetParameter(const std::string &Name, const uint64_t Default) {
auto Hint = std::find_if(Parameters_.begin(),Parameters_.end(),[&](const std::pair<std::string,std::string> &S){ return S.first==Name; });
if(Hint==Parameters_.end() || !is_number(Hint->second))
return Default;
return std::stoull(Hint->second);
}
[[nodiscard]] inline bool GetBoolParameter(const std::string &Name, bool Default=false) {
auto Hint = std::find_if(begin(Parameters_),end(Parameters_),[&](const std::pair<std::string,std::string> &S){ return S.first==Name; });
if(Hint==end(Parameters_) || !is_bool(Hint->second))
return Default;
return Hint->second=="true";
}
[[nodiscard]] inline std::string GetParameter(const std::string &Name, const std::string &Default="") {
auto Hint = std::find_if(begin(Parameters_),end(Parameters_),[&](const std::pair<std::string,std::string> &S){ return S.first==Name; });
if(Hint==end(Parameters_))
return Default;
return Hint->second;
}
[[nodiscard]] inline bool HasParameter(const std::string &Name, std::string &Value) {
auto Hint = std::find_if(begin(Parameters_),end(Parameters_),[&](const std::pair<std::string,std::string> &S){ return S.first==Name; });
if(Hint==end(Parameters_))
return false;
Value = Hint->second;
return true;
}
[[nodiscard]] inline bool HasParameter(const std::string &Name, uint64_t & Value) {
auto Hint = std::find_if(begin(Parameters_),end(Parameters_),[&](const std::pair<std::string,std::string> &S){ return S.first==Name; });
if(Hint==end(Parameters_))
return false;
Value = std::stoull(Hint->second);
return true;
}
[[nodiscard]] inline const std::string & GetBinding(const std::string &Name, const std::string &Default="") {
auto E = Bindings_.find(Poco::toLower(Name));
if (E == Bindings_.end())
return Default;
return E->second;
}
[[nodiscard]] inline static std::string MakeList(const std::vector<std::string> &L) {
std::string Return;
for (const auto &i : L) {
if (Return.empty())
Return = i;
else
Return += ", " + i;
}
return Return;
}
static inline bool AssignIfPresent(const Poco::JSON::Object::Ptr &O, const std::string &Field, Types::UUIDvec_t & Value) {
if(O->has(Field) && O->isArray(Field)) {
auto Arr = O->getArray(Field);
for(const auto &i:*Arr)
Value.emplace_back(i.toString());
return true;
}
return false;
}
static inline bool AssignIfPresent(const Poco::JSON::Object::Ptr &O, const std::string &Field, std::string &Value) {
if(O->has(Field)) {
Value = O->get(Field).toString();
return true;
}
return false;
}
static inline bool AssignIfPresent(const Poco::JSON::Object::Ptr &O, const std::string &Field, uint64_t &Value) {
if(O->has(Field)) {
Value = O->get(Field);
return true;
}
return false;
}
static inline bool AssignIfPresent(const Poco::JSON::Object::Ptr &O, const std::string &Field, bool &Value) {
if(O->has(Field)) {
Value = O->get(Field).toString()=="true";
return true;
}
return false;
}
static inline bool AssignIfPresent(const Poco::JSON::Object::Ptr &O, const std::string &Field, double &Value) {
if(O->has(Field)) {
Value = (double) O->get(Field);
return true;
}
return false;
}
static inline bool AssignIfPresent(const Poco::JSON::Object::Ptr &O, const std::string &Field, Poco::Data::BLOB &Value) {
if(O->has(Field)) {
std::string Content = O->get(Field).toString();
auto DecodedBlob = Utils::base64decode(Content);
Value.assignRaw((const unsigned char *)&DecodedBlob[0],DecodedBlob.size());
return true;
}
return false;
}
template <typename T> bool AssignIfPresent(const Poco::JSON::Object::Ptr &O, const std::string &Field, const T &value, T & assignee) {
if(O->has(Field)) {
assignee = value;
return true;
}
return false;
}
inline void SetCommonHeaders(bool CloseConnection=false) {
Response->setVersion(Poco::Net::HTTPMessage::HTTP_1_1);
Response->setChunkedTransferEncoding(true);
Response->setContentType("application/json");
auto Origin = Request->find("Origin");
if (Origin != Request->end()) {
Response->set("Access-Control-Allow-Origin", Origin->second);
} else {
Response->set("Access-Control-Allow-Origin", "*");
}
Response->set("Vary", "Origin, Accept-Encoding");
if(CloseConnection) {
Response->set("Connection", "close");
Response->setKeepAlive(false);
} else {
Response->setKeepAlive(true);
Response->set("Connection", "Keep-Alive");
Response->set("Keep-Alive", "timeout=30, max=1000");
}
}
inline void ProcessOptions() {
Response->setVersion(Poco::Net::HTTPMessage::HTTP_1_1);
Response->setChunkedTransferEncoding(true);
auto Origin = Request->find("Origin");
if (Origin != Request->end()) {
Response->set("Access-Control-Allow-Origin", Origin->second);
} else {
Response->set("Access-Control-Allow-Origin", "*");
}
Response->set("Access-Control-Allow-Methods", MakeList(Methods_));
auto RequestHeaders = Request->find("Access-Control-Request-Headers");
if(RequestHeaders!=Request->end())
Response->set("Access-Control-Allow-Headers", RequestHeaders->second);
Response->set("Vary", "Origin, Accept-Encoding");
Response->set("Access-Control-Allow-Credentials", "true");
Response->set("Access-Control-Max-Age", "86400");
Response->set("Connection", "Keep-Alive");
Response->set("Keep-Alive", "timeout=30, max=1000");
Response->setContentLength(0);
Response->setStatus(Poco::Net::HTTPResponse::HTTP_OK);
Response->send();
}
inline void PrepareResponse(Poco::Net::HTTPResponse::HTTPStatus Status = Poco::Net::HTTPResponse::HTTP_OK,
bool CloseConnection = false) {
Response->setStatus(Status);
SetCommonHeaders(CloseConnection);
}
inline void BadRequest(const OpenWifi::RESTAPI::Errors::msg &E, const std::string & Extra="") {
PrepareResponse(Poco::Net::HTTPResponse::HTTP_BAD_REQUEST);
Poco::JSON::Object ErrorObject;
ErrorObject.set("ErrorCode",400);
ErrorObject.set("ErrorDetails",Request->getMethod());
if(Extra.empty())
ErrorObject.set("ErrorDescription",fmt::format("{}: {}",E.err_num,E.err_txt)) ;
else
ErrorObject.set("ErrorDescription",fmt::format("{}: {} ({})",E.err_num,E.err_txt, Extra)) ;
std::ostream &Answer = Response->send();
Poco::JSON::Stringifier::stringify(ErrorObject, Answer);
}
inline void InternalError(const OpenWifi::RESTAPI::Errors::msg &E) {
PrepareResponse(Poco::Net::HTTPResponse::HTTP_INTERNAL_SERVER_ERROR);
Poco::JSON::Object ErrorObject;
ErrorObject.set("ErrorCode",500);
ErrorObject.set("ErrorDetails",Request->getMethod());
ErrorObject.set("ErrorDescription",fmt::format("{}: {}",E.err_num,E.err_txt)) ;
std::ostream &Answer = Response->send();
Poco::JSON::Stringifier::stringify(ErrorObject, Answer);
}
inline void UnAuthorized(const OpenWifi::RESTAPI::Errors::msg &E) {
PrepareResponse(Poco::Net::HTTPResponse::HTTP_FORBIDDEN);
Poco::JSON::Object ErrorObject;
ErrorObject.set("ErrorCode",E.err_num);
ErrorObject.set("ErrorDetails",Request->getMethod());
ErrorObject.set("ErrorDescription",fmt::format("{}: {}",E.err_num,E.err_txt)) ;
std::ostream &Answer = Response->send();
Poco::JSON::Stringifier::stringify(ErrorObject, Answer);
}
inline void NotFound() {
PrepareResponse(Poco::Net::HTTPResponse::HTTP_NOT_FOUND);
Poco::JSON::Object ErrorObject;
ErrorObject.set("ErrorCode",404);
ErrorObject.set("ErrorDetails",Request->getMethod());
const auto & E = OpenWifi::RESTAPI::Errors::Error404;
ErrorObject.set("ErrorDescription",fmt::format("{}: {}",E.err_num,E.err_txt)) ;
std::ostream &Answer = Response->send();
Poco::JSON::Stringifier::stringify(ErrorObject, Answer);
poco_debug(Logger_,fmt::format("RES-NOTFOUND: User='{}@{}' Method='{}' Path='{}",
Requester(),
Utils::FormatIPv6(Request->clientAddress().toString()),
Request->getMethod(),
Request->getURI()));
}
inline void OK() {
PrepareResponse();
if( Request->getMethod()==Poco::Net::HTTPRequest::HTTP_DELETE ||
Request->getMethod()==Poco::Net::HTTPRequest::HTTP_OPTIONS) {
Response->send();
} else {
Poco::JSON::Object ErrorObject;
ErrorObject.set("Code", 0);
ErrorObject.set("Operation", Request->getMethod());
ErrorObject.set("Details", "Command completed.");
std::ostream &Answer = Response->send();
Poco::JSON::Stringifier::stringify(ErrorObject, Answer);
}
}
inline void SendCompressedTarFile(const std::string & FileName, const std::string & Content) {
Response->setStatus(Poco::Net::HTTPResponse::HTTPStatus::HTTP_OK);
SetCommonHeaders();
Response->set("Content-Type","application/gzip");
Response->set("Content-Disposition", "attachment; filename=" + FileName );
Response->set("Content-Transfer-Encoding","binary");
Response->set("Accept-Ranges", "bytes");
Response->set("Cache-Control", "no-store");
Response->set("Expires", "Mon, 26 Jul 2027 05:00:00 GMT");
Response->setStatus(Poco::Net::HTTPResponse::HTTP_OK);
Response->setContentLength(Content.size());
Response->setChunkedTransferEncoding(true);
std::ostream& OutputStream = Response->send();
OutputStream << Content;
}
inline void SendFile(Poco::File & File, const std::string & UUID) {
Response->setStatus(Poco::Net::HTTPResponse::HTTPStatus::HTTP_OK);
SetCommonHeaders();
Response->set("Content-Type","application/octet-stream");
Response->set("Content-Disposition", "attachment; filename=" + UUID );
Response->set("Content-Transfer-Encoding","binary");
Response->set("Accept-Ranges", "bytes");
Response->set("Cache-Control", "no-store");
Response->set("Expires", "Mon, 26 Jul 2027 05:00:00 GMT");
Response->setContentLength(File.getSize());
Response->sendFile(File.path(),"application/octet-stream");
}
inline void SendFile(Poco::File & File) {
Response->setStatus(Poco::Net::HTTPResponse::HTTPStatus::HTTP_OK);
SetCommonHeaders();
Poco::Path P(File.path());
auto MT = Utils::FindMediaType(File);
if(MT.Encoding==Utils::BINARY) {
Response->set("Content-Transfer-Encoding","binary");
Response->set("Accept-Ranges", "bytes");
}
Response->set("Cache-Control", "no-store");
Response->set("Expires", "Mon, 26 Jul 2027 05:00:00 GMT");
Response->sendFile(File.path(),MT.ContentType);
}
inline void SendFile(Poco::TemporaryFile &TempAvatar, [[maybe_unused]] const std::string &Type, const std::string & Name) {
Response->setStatus(Poco::Net::HTTPResponse::HTTPStatus::HTTP_OK);
SetCommonHeaders();
auto MT = Utils::FindMediaType(Name);
if(MT.Encoding==Utils::BINARY) {
Response->set("Content-Transfer-Encoding","binary");
Response->set("Accept-Ranges", "bytes");
}
Response->set("Content-Disposition", "attachment; filename=" + Name );
Response->set("Accept-Ranges", "bytes");
Response->set("Cache-Control", "no-store");
Response->set("Expires", "Mon, 26 Jul 2027 05:00:00 GMT");
Response->setContentLength(TempAvatar.getSize());
Response->sendFile(TempAvatar.path(),MT.ContentType);
}
inline void SendFileContent(const std::string &Content, const std::string &Type, const std::string & Name) {
Response->setStatus(Poco::Net::HTTPResponse::HTTPStatus::HTTP_OK);
SetCommonHeaders();
auto MT = Utils::FindMediaType(Name);
if(MT.Encoding==Utils::BINARY) {
Response->set("Content-Transfer-Encoding","binary");
Response->set("Accept-Ranges", "bytes");
}
Response->set("Content-Disposition", "attachment; filename=" + Name );
Response->set("Accept-Ranges", "bytes");
Response->set("Cache-Control", "no-store");
Response->set("Expires", "Mon, 26 Jul 2027 05:00:00 GMT");
Response->setContentLength(Content.size());
Response->setContentType(Type );
auto & OutputStream = Response->send();
OutputStream << Content ;
}
inline void SendHTMLFileBack(Poco::File & File,
const Types::StringPairVec & FormVars) {
Response->setStatus(Poco::Net::HTTPResponse::HTTPStatus::HTTP_OK);
SetCommonHeaders();
Response->set("Pragma", "private");
Response->set("Expires", "Mon, 26 Jul 2027 05:00:00 GMT");
std::string FormContent = Utils::LoadFile(File.path());
Utils::ReplaceVariables(FormContent, FormVars);
Response->setContentLength(FormContent.size());
Response->setChunkedTransferEncoding(true);
Response->setContentType("text/html");
std::ostream& ostr = Response->send();
ostr << FormContent;
}
inline void ReturnStatus(Poco::Net::HTTPResponse::HTTPStatus Status, bool CloseConnection=false) {
PrepareResponse(Status, CloseConnection);
if(Status == Poco::Net::HTTPResponse::HTTP_NO_CONTENT) {
Response->setContentLength(0);
Response->erase("Content-Type");
Response->setChunkedTransferEncoding(false);
}
Response->send();
}
inline bool ContinueProcessing() {
if (Request->getMethod() == Poco::Net::HTTPRequest::HTTP_OPTIONS) {
ProcessOptions();
return false;
} else if (std::find(Methods_.begin(), Methods_.end(), Request->getMethod()) == Methods_.end()) {
BadRequest(RESTAPI::Errors::UnsupportedHTTPMethod);
return false;
}
return true;
}
inline bool IsAuthorized(bool & Expired, bool & Contacted, bool SubOnly = false );
inline void ReturnObject(Poco::JSON::Object &Object) {
PrepareResponse();
if(Request!= nullptr) {
// can we compress ???
auto AcceptedEncoding = Request->find("Accept-Encoding");
if(AcceptedEncoding!=Request->end()) {
if( AcceptedEncoding->second.find("gzip")!=std::string::npos ||
AcceptedEncoding->second.find("compress")!=std::string::npos) {
Response->set("Content-Encoding", "gzip");
std::ostream &Answer = Response->send();
Poco::DeflatingOutputStream deflater(Answer, Poco::DeflatingStreamBuf::STREAM_GZIP);
Poco::JSON::Stringifier::stringify(Object, deflater);
deflater.close();
return;
}
}
}
std::ostream &Answer = Response->send();
Poco::JSON::Stringifier::stringify(Object, Answer);
}
inline void ReturnRawJSON(const std::string &json_doc) {
PrepareResponse();
if(Request!= nullptr) {
// can we compress ???
auto AcceptedEncoding = Request->find("Accept-Encoding");
if(AcceptedEncoding!=Request->end()) {
if( AcceptedEncoding->second.find("gzip")!=std::string::npos ||
AcceptedEncoding->second.find("compress")!=std::string::npos) {
Response->set("Content-Encoding", "gzip");
std::ostream &Answer = Response->send();
Poco::DeflatingOutputStream deflater(Answer, Poco::DeflatingStreamBuf::STREAM_GZIP);
deflater << json_doc;
deflater.close();
return;
}
}
}
std::ostream &Answer = Response->send();
Answer << json_doc;
}
inline void ReturnCountOnly(uint64_t Count) {
Poco::JSON::Object Answer;
Answer.set("count", Count);
ReturnObject(Answer);
}
inline bool InitQueryBlock() {
if(QueryBlockInitialized_)
return true;
QueryBlockInitialized_=true;
QB_.SerialNumber = GetParameter(RESTAPI::Protocol::SERIALNUMBER, "");
QB_.StartDate = GetParameter(RESTAPI::Protocol::STARTDATE, 0);
QB_.EndDate = GetParameter(RESTAPI::Protocol::ENDDATE, 0);
QB_.Offset = GetParameter(RESTAPI::Protocol::OFFSET, 0);
QB_.Limit = GetParameter(RESTAPI::Protocol::LIMIT, 100);
QB_.Filter = GetParameter(RESTAPI::Protocol::FILTER, "");
QB_.Lifetime = GetBoolParameter(RESTAPI::Protocol::LIFETIME,false);
QB_.LogType = GetParameter(RESTAPI::Protocol::LOGTYPE,0);
QB_.LastOnly = GetBoolParameter(RESTAPI::Protocol::LASTONLY,false);
QB_.Newest = GetBoolParameter(RESTAPI::Protocol::NEWEST,false);
QB_.CountOnly = GetBoolParameter(RESTAPI::Protocol::COUNTONLY,false);
QB_.AdditionalInfo = GetBoolParameter(RESTAPI::Protocol::WITHEXTENDEDINFO,false);
auto RawSelect = GetParameter(RESTAPI::Protocol::SELECT, "");
auto Entries = Poco::StringTokenizer(RawSelect,",");
for(const auto &i:Entries) {
QB_.Select.emplace_back(i);
}
if(QB_.Offset<1)
QB_.Offset=0;
return true;
}
[[nodiscard]] inline uint64_t Get(const char *Parameter,const Poco::JSON::Object::Ptr &Obj, uint64_t Default=0){
if(Obj->has(Parameter))
return Obj->get(Parameter);
return Default;
}
[[nodiscard]] inline std::string GetS(const char *Parameter,const Poco::JSON::Object::Ptr &Obj, const std::string & Default=""){
if(Obj->has(Parameter))
return Obj->get(Parameter).toString();
return Default;
}
[[nodiscard]] inline bool GetB(const char *Parameter,const Poco::JSON::Object::Ptr &Obj, bool Default=false){
if(Obj->has(Parameter))
return Obj->get(Parameter).toString()=="true";
return Default;
}
[[nodiscard]] inline uint64_t GetWhen(const Poco::JSON::Object::Ptr &Obj) {
return RESTAPIHandler::Get(RESTAPI::Protocol::WHEN, Obj);
}
template<typename T> void ReturnObject(const char *Name, const std::vector<T> & Objects) {
Poco::JSON::Object Answer;
RESTAPI_utils::field_to_json(Answer,Name,Objects);
ReturnObject(Answer);
}
template<typename T> void Object(const char *Name, const std::vector<T> & Objects) {
Poco::JSON::Object Answer;
RESTAPI_utils::field_to_json(Answer,Name,Objects);
ReturnObject(Answer);
}
template <typename T> void Object(const T &O) {
Poco::JSON::Object Answer;
O.to_json(Answer);
ReturnObject(Answer);
}
Poco::Logger & Logger() { return Logger_; }
virtual void DoGet() = 0 ;
virtual void DoDelete() = 0 ;
virtual void DoPost() = 0 ;
virtual void DoPut() = 0 ;
Poco::Net::HTTPServerRequest *Request= nullptr;
Poco::Net::HTTPServerResponse *Response= nullptr;
SecurityObjects::UserInfoAndPolicy UserInfo_;
QueryBlock QB_;
const std::string & Requester() const { return REST_Requester_; }
protected:
BindingMap Bindings_;
Poco::URI::QueryParameters Parameters_;
Poco::Logger &Logger_;
std::string SessionToken_;
std::vector<std::string> Methods_;
bool Internal_=false;
bool RateLimited_=false;
bool QueryBlockInitialized_=false;
bool SubOnlyService_=false;
bool AlwaysAuthorize_=true;
Poco::JSON::Parser IncomingParser_;
RESTAPI_GenericServerAccounting & Server_;
RateLimit MyRates_;
uint64_t TransactionId_;
Poco::JSON::Object::Ptr ParsedBody_;
std::string REST_Requester_;
};
#ifdef TIP_SECURITY_SERVICE
[[nodiscard]] bool AuthServiceIsAuthorized(Poco::Net::HTTPServerRequest & Request,std::string &SessionToken,
SecurityObjects::UserInfoAndPolicy & UInfo, std::uint64_t TID, bool & Expired , bool Sub );
#endif
inline bool RESTAPIHandler::IsAuthorized( bool & Expired , [[maybe_unused]] bool & Contacted , bool Sub ) {
if(Internal_ && Request->has("X-INTERNAL-NAME")) {
auto Allowed = MicroServiceIsValidAPIKEY(*Request);
Contacted = true;
if(!Allowed) {
if(Server_.LogBadTokens(false)) {
poco_debug(Logger_,fmt::format("I-REQ-DENIED({}): TID={} Method={} Path={}",
Utils::FormatIPv6(Request->clientAddress().toString()),
TransactionId_,
Request->getMethod(), Request->getURI()));
}
} else {
auto Id = Request->get("X-INTERNAL-NAME", "unknown");
REST_Requester_ = Id;
if(Server_.LogIt(Request->getMethod(),true)) {
poco_debug(Logger_,fmt::format("I-REQ-ALLOWED({}): TID={} User='{}' Method={} Path={}",
Utils::FormatIPv6(Request->clientAddress().toString()),
TransactionId_,
Id,
Request->getMethod(), Request->getURI()));
}
}
return Allowed;
} else if(!Internal_ && Request->has("X-API-KEY")) {
SessionToken_ = Request->get("X-API-KEY", "");
#ifdef TIP_SECURITY_SERVICE
std::uint64_t expiresOn;
if (AuthService()->IsValidApiKey(SessionToken_, UserInfo_.webtoken, UserInfo_.userinfo, Expired, expiresOn)) {
#else
if (AuthClient()->IsValidApiKey( SessionToken_, UserInfo_, TransactionId_, Expired, Contacted)) {
#endif
REST_Requester_ = UserInfo_.userinfo.email;
if(Server_.LogIt(Request->getMethod(),true)) {
poco_debug(Logger_,fmt::format("X-REQ-ALLOWED({}): APIKEY-ACCESS TID={} User='{}@{}' Method={} Path={}",
UserInfo_.userinfo.email,
TransactionId_,
Utils::FormatIPv6(Request->clientAddress().toString()),
Request->clientAddress().toString(),
Request->getMethod(),
Request->getURI()));
}
return true;
} else {
if(Server_.LogBadTokens(true)) {
poco_debug(Logger_,fmt::format("X-REQ-DENIED({}): TID={} Method={} Path={}",
Utils::FormatIPv6(Request->clientAddress().toString()),
TransactionId_,
Request->getMethod(),
Request->getURI()));
}
}
return false;
} else {
if (SessionToken_.empty()) {
try {
Poco::Net::OAuth20Credentials Auth(*Request);
if (Auth.getScheme() == "Bearer") {
SessionToken_ = Auth.getBearerToken();
}
} catch (const Poco::Exception &E) {
Logger_.log(E);
}
}
#ifdef TIP_SECURITY_SERVICE
if (AuthServiceIsAuthorized(*Request, SessionToken_, UserInfo_, TransactionId_, Expired, Sub)) {
#else
if (AuthClient()->IsAuthorized( SessionToken_, UserInfo_, TransactionId_, Expired, Contacted, Sub)) {
#endif
REST_Requester_ = UserInfo_.userinfo.email;
if(Server_.LogIt(Request->getMethod(),true)) {
poco_debug(Logger_,fmt::format("X-REQ-ALLOWED({}): TID={} User='{}@{}' Method={} Path={}",
UserInfo_.userinfo.email,
TransactionId_,
Utils::FormatIPv6(Request->clientAddress().toString()),
Request->clientAddress().toString(),
Request->getMethod(),
Request->getURI()));
}
return true;
} else {
if(Server_.LogBadTokens(true)) {
poco_debug(Logger_,fmt::format("X-REQ-DENIED({}): TID={} Method={} Path={}",
Utils::FormatIPv6(Request->clientAddress().toString()),
TransactionId_,
Request->getMethod(),
Request->getURI()));
}
}
return false;
}
}
class RESTAPI_UnknownRequestHandler : public RESTAPIHandler {
public:
RESTAPI_UnknownRequestHandler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServerAccounting & Server, uint64_t TransactionId, bool Internal)
: RESTAPIHandler(bindings, L, std::vector<std::string>{}, Server, TransactionId, Internal) {}
inline void DoGet() override {};
inline void DoPost() override {};
inline void DoPut() override {};
inline void DoDelete() override {};
};
template<class T>
constexpr auto test_has_PathName_method(T*)
-> decltype( T::PathName() , std::true_type{} )
{
return std::true_type{};
}
constexpr auto test_has_PathName_method(...) -> std::false_type
{
return std::false_type{};
}
template<typename T, typename... Args>
RESTAPIHandler * RESTAPI_Router(const std::string & RequestedPath, RESTAPIHandler::BindingMap &Bindings,
Poco::Logger & Logger, RESTAPI_GenericServerAccounting & Server, uint64_t TransactionId) {
static_assert(test_has_PathName_method((T*)nullptr), "Class must have a static PathName() method.");
if(RESTAPIHandler::ParseBindings(RequestedPath,T::PathName(),Bindings)) {
return new T(Bindings, Logger, Server, TransactionId, false);
}
if constexpr (sizeof...(Args) == 0) {
return new RESTAPI_UnknownRequestHandler(Bindings,Logger, Server, TransactionId, false);
} else {
return RESTAPI_Router<Args...>(RequestedPath, Bindings, Logger, Server, TransactionId);
}
}
template<typename T, typename... Args>
RESTAPIHandler * RESTAPI_Router_I(const std::string & RequestedPath, RESTAPIHandler::BindingMap &Bindings,
Poco::Logger & Logger, RESTAPI_GenericServerAccounting & Server, uint64_t TransactionId) {
static_assert(test_has_PathName_method((T*)nullptr), "Class must have a static PathName() method.");
if(RESTAPIHandler::ParseBindings(RequestedPath,T::PathName(),Bindings)) {
return new T(Bindings, Logger, Server, TransactionId, true );
}
if constexpr (sizeof...(Args) == 0) {
return new RESTAPI_UnknownRequestHandler(Bindings,Logger, Server, TransactionId, true);
} else {
return RESTAPI_Router_I<Args...>(RequestedPath, Bindings, Logger, Server, TransactionId);
}
}
} // namespace OpenWifi

View File

@@ -0,0 +1,17 @@
//
// Created by stephane bourque on 2022-10-25.
//
#include "RESTAPI_IntServer.h"
namespace OpenWifi {
Poco::Net::HTTPRequestHandler *
IntRequestHandlerFactory::createRequestHandler(const Poco::Net::HTTPServerRequest &Request) {
auto TID = NextTransactionId_++;
Utils::SetThreadName(fmt::format("i-rest:{}", TID).c_str());
Poco::URI uri(Request.getURI());
return RESTAPI_IntServer()->CallServer(uri.getPath(), TID);
}
} // namespace OpenWifi

View File

@@ -0,0 +1,104 @@
//
// Created by stephane bourque on 2022-10-25.
//
#pragma once
#include "Poco/Net/HTTPServer.h"
#include "framework/SubSystemServer.h"
#include "framework/RESTAPI_Handler.h"
namespace OpenWifi {
Poco::Net::HTTPRequestHandler * RESTAPI_IntRouter(const std::string &Path, RESTAPIHandler::BindingMap &Bindings,
Poco::Logger & L, RESTAPI_GenericServerAccounting & S, uint64_t Id);
class IntRequestHandlerFactory : public Poco::Net::HTTPRequestHandlerFactory {
public:
inline IntRequestHandlerFactory() = default;
Poco::Net::HTTPRequestHandler *createRequestHandler(const Poco::Net::HTTPServerRequest &Request) override;
private:
static inline std::atomic_uint64_t NextTransactionId_ = 1;
};
class RESTAPI_IntServer : public SubSystemServer {
public:
static auto instance() {
static auto instance_ = new RESTAPI_IntServer;
return instance_;
}
inline int Start() override {
poco_information(Logger(),"Starting.");
Server_.InitLogging();
for(const auto & Svr: ConfigServersList_) {
if(MicroServiceNoAPISecurity()) {
poco_information(Logger(),fmt::format("Starting: {}:{}. Security has been disabled for APIs.", Svr.Address(), Svr.Port()));
} else {
poco_information(Logger(),fmt::format("Starting: {}:{}. Keyfile:{} CertFile: {}", Svr.Address(), Svr.Port(),
Svr.KeyFile(),Svr.CertFile()));
Svr.LogCert(Logger());
if (!Svr.RootCA().empty())
Svr.LogCas(Logger());
}
auto Params = new Poco::Net::HTTPServerParams;
Params->setKeepAlive(true);
Params->setName("ws:irest");
std::unique_ptr<Poco::Net::HTTPServer> NewServer;
if(MicroServiceNoAPISecurity()) {
auto Sock{Svr.CreateSocket(Logger())};
NewServer = std::make_unique<Poco::Net::HTTPServer>(new IntRequestHandlerFactory, Pool_, Sock, Params);
} else {
auto Sock{Svr.CreateSecureSocket(Logger())};
NewServer = std::make_unique<Poco::Net::HTTPServer>(new IntRequestHandlerFactory, Pool_, Sock, Params);
};
NewServer->start();
RESTServers_.push_back(std::move(NewServer));
}
return 0;
}
inline void Stop() override {
poco_information(Logger(),"Stopping...");
for( const auto & svr : RESTServers_ )
svr->stopAll(true);
Pool_.stopAll();
Pool_.joinAll();
poco_information(Logger(),"Stopped...");
}
inline void reinitialize([[maybe_unused]] Poco::Util::Application &self) override {
MicroServiceLoadConfigurationFile();
poco_information(Logger(),"Reinitializing.");
Stop();
Start();
}
inline Poco::Net::HTTPRequestHandler *CallServer(const std::string &Path, uint64_t Id) {
RESTAPIHandler::BindingMap Bindings;
Utils::SetThreadName(fmt::format("i-rest:{}",Id).c_str());
return RESTAPI_IntRouter(Path, Bindings, Logger(), Server_, Id);
}
const Poco::ThreadPool & Pool() { return Pool_; }
private:
std::vector<std::unique_ptr<Poco::Net::HTTPServer>> RESTServers_;
Poco::ThreadPool Pool_{"i-rest",4,64};
RESTAPI_GenericServerAccounting Server_;
RESTAPI_IntServer() noexcept:
SubSystemServer("RESTAPI_IntServer", "REST-ISRV", "openwifi.internal.restapi")
{
}
};
inline auto RESTAPI_IntServer() { return RESTAPI_IntServer::instance(); };
} // namespace OpenWifi

View File

@@ -0,0 +1,66 @@
//
// Created by stephane bourque on 2022-10-26.
//
#pragma once
#include <string>
#include "Poco/Net/PartHandler.h"
#include "Poco/Net/MessageHeader.h"
#include "Poco/CountingStream.h"
#include "Poco/NullStream.h"
#include "Poco/StreamCopier.h"
namespace OpenWifi {
class RESTAPI_PartHandler: public Poco::Net::PartHandler {
public:
RESTAPI_PartHandler():
_length(0)
{
}
inline void handlePart(const Poco::Net::MessageHeader& header, std::istream& stream) override
{
_type = header.get("Content-Type", "(unspecified)");
if (header.has("Content-Disposition"))
{
std::string disp;
Poco::Net::NameValueCollection params;
Poco::Net::MessageHeader::splitParameters(header["Content-Disposition"], disp, params);
_name = params.get("name", "(unnamed)");
_fileName = params.get("filename", "(unnamed)");
}
Poco::CountingInputStream istr(stream);
Poco::NullOutputStream ostr;
Poco::StreamCopier::copyStream(istr, ostr);
_length = (int)istr.chars();
}
[[nodiscard]] inline int length() const
{
return _length;
}
[[nodiscard]] inline const std::string& name() const
{
return _name;
}
[[nodiscard]] inline const std::string& fileName() const
{
return _fileName;
}
[[nodiscard]] inline const std::string& contentType() const
{
return _type;
}
private:
int _length;
std::string _type;
std::string _name;
std::string _fileName;
};
}

View File

@@ -0,0 +1,75 @@
//
// Created by stephane bourque on 2022-10-25.
//
#pragma once
#include "framework/SubSystemServer.h"
#include "Poco/URI.h"
#include "Poco/Net/HTTPServerRequest.h"
#include "Poco/ExpireLRUCache.h"
#include "fmt/format.h"
namespace OpenWifi {
class RESTAPI_RateLimiter : public SubSystemServer {
public:
struct ClientCacheEntry {
int64_t Start=0;
int Count=0;
};
static auto instance() {
static auto instance_ = new RESTAPI_RateLimiter;
return instance_;
}
inline int Start() final { return 0;};
inline void Stop() final { };
inline bool IsRateLimited(const Poco::Net::HTTPServerRequest &R, int64_t Period, int64_t MaxCalls) {
Poco::URI uri(R.getURI());
auto H = str_hash(uri.getPath() + R.clientAddress().host().toString());
auto E = Cache_.get(H);
auto Now = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch()).count();
if(E.isNull()) {
Cache_.add(H,ClientCacheEntry{.Start=Now, .Count=1});
return false;
}
if((Now-E->Start)<Period) {
E->Count++;
Cache_.update(H,E);
if(E->Count > MaxCalls) {
poco_warning(Logger(),fmt::format("RATE-LIMIT-EXCEEDED: from '{}'", R.clientAddress().toString()));
return true;
}
return false;
}
E->Start = Now;
E->Count = 1;
Cache_.update(H,E);
return false;
}
inline void Clear() {
Cache_.clear();
}
private:
Poco::ExpireLRUCache<uint64_t,ClientCacheEntry> Cache_{2048};
std::hash<std::string> str_hash;
RESTAPI_RateLimiter() noexcept:
SubSystemServer("RateLimiter", "RATE-LIMITER", "rate.limiter")
{
}
};
inline auto RESTAPI_RateLimiter() { return RESTAPI_RateLimiter::instance(); }
}

View File

@@ -0,0 +1,157 @@
//
// Created by stephane bourque on 2022-10-25.
//
#pragma once
#include "framework/RESTAPI_Handler.h"
#include "Poco/Environment.h"
using namespace std::chrono_literals;
namespace OpenWifi {
class RESTAPI_system_command : public RESTAPIHandler {
public:
RESTAPI_system_command(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServerAccounting & Server, uint64_t TransactionId, bool Internal)
: RESTAPIHandler(bindings, L,
std::vector<std::string>{Poco::Net::HTTPRequest::HTTP_POST,
Poco::Net::HTTPRequest::HTTP_GET,
Poco::Net::HTTPRequest::HTTP_OPTIONS},
Server,
TransactionId,
Internal) {}
static auto PathName() { return std::list<std::string>{"/api/v1/system"};}
inline void DoGet() {
std::string Arg;
if(HasParameter("command",Arg) && Arg=="info") {
Poco::JSON::Object Answer;
Answer.set(RESTAPI::Protocol::VERSION, MicroServiceVersion());
Answer.set(RESTAPI::Protocol::UPTIME, MicroServiceUptimeTotalSeconds());
Answer.set(RESTAPI::Protocol::START, MicroServiceStartTimeEpochTime());
Answer.set(RESTAPI::Protocol::OS, Poco::Environment::osName());
Answer.set(RESTAPI::Protocol::PROCESSORS, Poco::Environment::processorCount());
Answer.set(RESTAPI::Protocol::HOSTNAME, Poco::Environment::nodeName());
Answer.set(RESTAPI::Protocol::UI, MicroServiceGetUIURI());
Poco::JSON::Array Certificates;
auto SubSystems = MicroServiceGetFullSubSystems();
std::set<std::string> CertNames;
for(const auto &i:SubSystems) {
auto Hosts=i->HostSize();
for(uint64_t j=0;j<Hosts;++j) {
auto CertFileName = i->Host(j).CertFile();
if(!CertFileName.empty()) {
Poco::File F1(CertFileName);
if(F1.exists()) {
auto InsertResult = CertNames.insert(CertFileName);
if(InsertResult.second) {
Poco::JSON::Object Inner;
Poco::Path F(CertFileName);
Inner.set("filename", F.getFileName());
Poco::Crypto::X509Certificate C(CertFileName);
auto ExpiresOn = C.expiresOn();
Inner.set("expiresOn", ExpiresOn.timestamp().epochTime());
Certificates.add(Inner);
}
}
}
}
}
Answer.set("certificates", Certificates);
return ReturnObject(Answer);
}
if(GetBoolParameter("extraConfiguration")) {
Poco::JSON::Object Answer;
MicroServiceGetExtraConfiguration(Answer);
return ReturnObject(Answer);
}
BadRequest(RESTAPI::Errors::InvalidCommand);
}
inline void DoPost() final {
const auto & Obj = ParsedBody_;
if (Obj->has(RESTAPI::Protocol::COMMAND)) {
auto Command = Poco::toLower(Obj->get(RESTAPI::Protocol::COMMAND).toString());
if (Command == RESTAPI::Protocol::SETLOGLEVEL) {
if (Obj->has(RESTAPI::Protocol::SUBSYSTEMS) &&
Obj->isArray(RESTAPI::Protocol::SUBSYSTEMS)) {
auto ParametersBlock = Obj->getArray(RESTAPI::Protocol::SUBSYSTEMS);
for (const auto &i : *ParametersBlock) {
Poco::JSON::Parser pp;
auto InnerObj = pp.parse(i).extract<Poco::JSON::Object::Ptr>();
if (InnerObj->has(RESTAPI::Protocol::TAG) &&
InnerObj->has(RESTAPI::Protocol::VALUE)) {
auto Name = GetS(RESTAPI::Protocol::TAG, InnerObj);
auto Value = GetS(RESTAPI::Protocol::VALUE, InnerObj);
MicroServiceSetSubsystemLogLevel(Name, Value);
poco_information(Logger_,
fmt::format("Setting log level for {} at {}", Name, Value));
}
}
return OK();
}
} else if (Command == RESTAPI::Protocol::GETLOGLEVELS) {
auto CurrentLogLevels = MicroServiceGetLogLevels();
Poco::JSON::Object Result;
Poco::JSON::Array Array;
for (auto &[Name, Level] : CurrentLogLevels) {
Poco::JSON::Object Pair;
Pair.set(RESTAPI::Protocol::TAG, Name);
Pair.set(RESTAPI::Protocol::VALUE, Level);
Array.add(Pair);
}
Result.set(RESTAPI::Protocol::TAGLIST, Array);
return ReturnObject(Result);
} else if (Command == RESTAPI::Protocol::GETLOGLEVELNAMES) {
Poco::JSON::Object Result;
Poco::JSON::Array LevelNamesArray;
const Types::StringVec &LevelNames = MicroServiceGetLogLevelNames();
for (const auto &i : LevelNames)
LevelNamesArray.add(i);
Result.set(RESTAPI::Protocol::LIST, LevelNamesArray);
return ReturnObject(Result);
} else if (Command == RESTAPI::Protocol::GETSUBSYSTEMNAMES) {
Poco::JSON::Object Result;
Poco::JSON::Array LevelNamesArray;
const Types::StringVec &SubSystemNames = MicroServiceGetSubSystems();
for (const auto &i : SubSystemNames)
LevelNamesArray.add(i);
Result.set(RESTAPI::Protocol::LIST, LevelNamesArray);
return ReturnObject(Result);
} else if (Command == RESTAPI::Protocol::STATS) {
} else if (Command == RESTAPI::Protocol::RELOAD) {
if (Obj->has(RESTAPI::Protocol::SUBSYSTEMS) &&
Obj->isArray(RESTAPI::Protocol::SUBSYSTEMS)) {
auto SubSystems = Obj->getArray(RESTAPI::Protocol::SUBSYSTEMS);
std::vector<std::string> Names;
for (const auto &i : *SubSystems)
Names.push_back(i.toString());
std::thread ReloadThread([Names](){
std::this_thread::sleep_for(10000ms);
for(const auto &i:Names) {
if(i=="daemon")
MicroServiceReload();
else
MicroServiceReload(i);
}
});
ReloadThread.detach();
}
return OK();
}
} else {
return BadRequest(RESTAPI::Errors::InvalidCommand);
}
BadRequest(RESTAPI::Errors::MissingOrInvalidParameters);
}
void DoPut() final {};
void DoDelete() final {};
};
}

View File

@@ -0,0 +1,52 @@
//
// Created by stephane bourque on 2022-10-31.
//
#pragma once
#include "framework/RESTAPI_Handler.h"
#include "framework/MicroServiceFuncs.h"
using namespace std::chrono_literals;
namespace OpenWifi {
class RESTAPI_system_configuration : public RESTAPIHandler {
public:
RESTAPI_system_configuration(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L,
RESTAPI_GenericServerAccounting &Server, uint64_t TransactionId,
bool Internal)
: RESTAPIHandler(bindings, L,
std::vector<std::string>{Poco::Net::HTTPRequest::HTTP_PUT,
Poco::Net::HTTPRequest::HTTP_GET,
Poco::Net::HTTPRequest::HTTP_DELETE,
Poco::Net::HTTPRequest::HTTP_OPTIONS},
Server, TransactionId, Internal) {}
static auto PathName() { return std::list<std::string>{"/api/v1/systemConfiguration"}; }
inline void DoPost() final {}
inline void DoGet() final {
return OK();
}
inline void DoPut() final{
if(UserInfo_.userinfo.userRole!=SecurityObjects::ROOT) {
return UnAuthorized(RESTAPI::Errors::ACCESS_DENIED);
}
return OK();
};
inline void DoDelete() final{
if(UserInfo_.userinfo.userRole!=SecurityObjects::ROOT) {
return UnAuthorized(RESTAPI::Errors::ACCESS_DENIED);
}
MicroServiceDeleteOverrideConfiguration();
return OK();
};
};
}

View File

@@ -0,0 +1,45 @@
//
// Created by stephane bourque on 2022-10-26.
//
#pragma once
#include "framework/RESTAPI_Handler.h"
#include "Poco/Net/WebSocket.h"
#include "framework/UI_WebSocketClientServer.h"
#include "framework/MicroServiceFuncs.h"
namespace OpenWifi {
class RESTAPI_webSocketServer : public RESTAPIHandler {
public:
inline RESTAPI_webSocketServer(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServerAccounting &Server, uint64_t TransactionId, bool Internal)
: RESTAPIHandler(bindings, L,
std::vector<std::string>{ Poco::Net::HTTPRequest::HTTP_GET,
Poco::Net::HTTPRequest::HTTP_OPTIONS},
Server, TransactionId, Internal,false) {}
static auto PathName() { return std::list<std::string>{"/api/v1/ws"};}
void DoGet() final {
try
{
if(Request->find("Upgrade") != Request->end() && Poco::icompare((*Request)["Upgrade"], "websocket") == 0) {
try
{
Poco::Net::WebSocket WS(*Request, *Response);
auto Id = MicroServiceCreateUUID();
UI_WebSocketClientServer()->NewClient(WS,Id,UserInfo_.userinfo.email, TransactionId_);
}
catch (...) {
std::cout << "Cannot create websocket client..." << std::endl;
}
}
} catch(...) {
std::cout << "Cannot upgrade connection..." << std::endl;
}
};
void DoDelete() final {};
void DoPost() final {};
void DoPut() final {};
private:
};
}

View File

@@ -0,0 +1,484 @@
//
// Created by stephane bourque on 2022-10-25.
//
#pragma once
#include <string>
#include "Poco/JSON/Object.h"
#include "Poco/JSON/Parser.h"
#include "Poco/Data/LOB.h"
#include "Poco/Net/HTTPServerRequest.h"
#include "framework/OpenWifiTypes.h"
#include "framework/utils.h"
namespace OpenWifi::RESTAPI_utils {
inline void EmbedDocument(const std::string & ObjName, Poco::JSON::Object & Obj, const std::string &ObjStr) {
std::string D = ObjStr.empty() ? "{}" : ObjStr;
Poco::JSON::Parser P;
Poco::Dynamic::Var result = P.parse(D);
const auto &DetailsObj = result.extract<Poco::JSON::Object::Ptr>();
Obj.set(ObjName, DetailsObj);
}
inline void field_to_json(Poco::JSON::Object &Obj, const char *Field, bool V) {
Obj.set(Field,V);
}
inline void field_to_json(Poco::JSON::Object &Obj, const char *Field, double V) {
Obj.set(Field,V);
}
inline void field_to_json(Poco::JSON::Object &Obj, const char *Field, float V) {
Obj.set(Field,V);
}
inline void field_to_json(Poco::JSON::Object &Obj, const char *Field, const std::string & S) {
Obj.set(Field,S);
}
inline void field_to_json(Poco::JSON::Object &Obj, const char *Field, const char * S) {
Obj.set(Field,S);
}
inline void field_to_json(Poco::JSON::Object &Obj, const char *Field, int16_t Value) {
Obj.set(Field, Value);
}
inline void field_to_json(Poco::JSON::Object &Obj, const char *Field, int32_t Value) {
Obj.set(Field, Value);
}
inline void field_to_json(Poco::JSON::Object &Obj, const char *Field, int64_t Value) {
Obj.set(Field, Value);
}
inline void field_to_json(Poco::JSON::Object &Obj, const char *Field, uint16_t Value) {
Obj.set(Field, Value);
}
inline void field_to_json(Poco::JSON::Object &Obj, const char *Field, uint32_t Value) {
Obj.set(Field, Value);
}
inline void field_to_json(Poco::JSON::Object &Obj, const char *Field, uint64_t Value) {
Obj.set(Field,Value);
}
inline void field_to_json(Poco::JSON::Object &Obj, const char *Field, const Poco::Data::BLOB &Value) {
auto Result = Utils::base64encode((const unsigned char *)Value.rawContent(),Value.size());
Obj.set(Field,Result);
}
inline void field_to_json(Poco::JSON::Object &Obj, const char *Field, const Types::StringPairVec & S) {
Poco::JSON::Array Array;
for(const auto &i:S) {
Poco::JSON::Object O;
O.set("tag",i.first);
O.set("value", i.second);
Array.add(O);
}
Obj.set(Field,Array);
}
inline void field_to_json(Poco::JSON::Object &Obj, const char *Field, const Types::StringVec &V) {
Poco::JSON::Array A;
for(const auto &i:V)
A.add(i);
Obj.set(Field,A);
}
inline void field_to_json(Poco::JSON::Object &Obj, const char *Field, const Types::TagList &V) {
Poco::JSON::Array A;
for(const auto &i:V)
A.add(i);
Obj.set(Field,A);
}
inline void field_to_json(Poco::JSON::Object &Obj, const char *Field, const Types::CountedMap &M) {
Poco::JSON::Array A;
for(const auto &[Key,Value]:M) {
Poco::JSON::Object O;
O.set("tag",Key);
O.set("value", Value);
A.add(O);
}
Obj.set(Field,A);
}
inline void field_to_json(Poco::JSON::Object &Obj, const char *Field, const Types::Counted3DMapSII &M) {
Poco::JSON::Array A;
for(const auto &[OrgName,MonthlyNumberMap]:M) {
Poco::JSON::Object OrgObject;
OrgObject.set("tag",OrgName);
Poco::JSON::Array MonthlyArray;
for(const auto &[Month,Counter]:MonthlyNumberMap) {
Poco::JSON::Object Inner;
Inner.set("value", Month);
Inner.set("counter", Counter);
MonthlyArray.add(Inner);
}
OrgObject.set("index",MonthlyArray);
A.add(OrgObject);
}
Obj.set(Field, A);
}
template<typename T> void field_to_json(Poco::JSON::Object &Obj,
const char *Field,
const T &V,
std::function<std::string(const T &)> F) {
Obj.set(Field, F(V));
}
template<class T> void field_to_json(Poco::JSON::Object &Obj, const char *Field, const std::vector<T> &Value) {
Poco::JSON::Array Arr;
for(const auto &i:Value) {
Poco::JSON::Object AO;
i.to_json(AO);
Arr.add(AO);
}
Obj.set(Field, Arr);
}
template<class T> void field_to_json(Poco::JSON::Object &Obj, const char *Field, const T &Value) {
Poco::JSON::Object Answer;
Value.to_json(Answer);
Obj.set(Field, Answer);
}
///////////////////////////
///////////////////////////
///////////////////////////
///////////////////////////
template<typename T> bool field_from_json(const Poco::JSON::Object::Ptr &Obj, const char *Field, T & V,
std::function<T(const std::string &)> F) {
if(Obj->has(Field) && !Obj->isNull(Field))
V = F(Obj->get(Field).toString());
return true;
}
inline void field_from_json(const Poco::JSON::Object::Ptr &Obj, const char *Field, std::string &S) {
if(Obj->has(Field) && !Obj->isNull(Field))
S = Obj->get(Field).toString();
}
inline void field_from_json(const Poco::JSON::Object::Ptr &Obj, const char *Field, double & Value) {
if(Obj->has(Field) && !Obj->isNull(Field))
Value = (double)Obj->get(Field);
}
inline void field_from_json(const Poco::JSON::Object::Ptr &Obj, const char *Field, float & Value) {
if(Obj->has(Field) && !Obj->isNull(Field))
Value = (float)Obj->get(Field);
}
inline void field_from_json(const Poco::JSON::Object::Ptr &Obj, const char *Field, bool &Value) {
if(Obj->has(Field) && !Obj->isNull(Field))
Value = (Obj->get(Field).toString() == "true");
}
inline void field_from_json(const Poco::JSON::Object::Ptr &Obj, const char *Field, int16_t &Value) {
if(Obj->has(Field) && !Obj->isNull(Field))
Value = (int16_t)Obj->get(Field);
}
inline void field_from_json(const Poco::JSON::Object::Ptr &Obj, const char *Field, int32_t &Value) {
if(Obj->has(Field) && !Obj->isNull(Field))
Value = (int32_t) Obj->get(Field);
}
inline void field_from_json(const Poco::JSON::Object::Ptr &Obj, const char *Field, int64_t &Value) {
if(Obj->has(Field) && !Obj->isNull(Field))
Value = (int64_t)Obj->get(Field);
}
inline void field_from_json(const Poco::JSON::Object::Ptr &Obj, const char *Field, uint16_t &Value) {
if(Obj->has(Field) && !Obj->isNull(Field))
Value = (uint16_t)Obj->get(Field);
}
inline void field_from_json(const Poco::JSON::Object::Ptr &Obj, const char *Field, uint32_t &Value) {
if(Obj->has(Field) && !Obj->isNull(Field))
Value = (uint32_t)Obj->get(Field);
}
inline void field_from_json(const Poco::JSON::Object::Ptr &Obj, const char *Field, uint64_t &Value) {
if(Obj->has(Field) && !Obj->isNull(Field))
Value = (uint64_t)Obj->get(Field);
}
inline void field_from_json(const Poco::JSON::Object::Ptr &Obj, const char *Field, Poco::Data::BLOB &Value) {
if(Obj->has(Field) && !Obj->isNull(Field)) {
auto Result = Utils::base64decode(Obj->get(Field).toString());
Value.assignRaw((const unsigned char *)&Result[0],Result.size());
}
}
inline void field_from_json(const Poco::JSON::Object::Ptr &Obj, const char *Field, Types::StringPairVec &Vec) {
if(Obj->isArray(Field) && !Obj->isNull(Field)) {
auto O = Obj->getArray(Field);
for(const auto &i:*O) {
std::string S1,S2;
auto Inner = i.extract<Poco::JSON::Object::Ptr>();
if(Inner->has("tag"))
S1 = Inner->get("tag").toString();
if(Inner->has("value"))
S2 = Inner->get("value").toString();
auto P = std::make_pair(S1,S2);
Vec.push_back(P);
}
}
}
inline void field_from_json(const Poco::JSON::Object::Ptr &Obj, const char *Field, Types::StringVec &Value) {
if(Obj->isArray(Field) && !Obj->isNull(Field)) {
Value.clear();
Poco::JSON::Array::Ptr A = Obj->getArray(Field);
for(const auto &i:*A) {
Value.push_back(i.toString());
}
}
}
inline void field_from_json(const Poco::JSON::Object::Ptr &Obj, const char *Field, Types::TagList &Value) {
if(Obj->isArray(Field) && !Obj->isNull(Field)) {
Value.clear();
Poco::JSON::Array::Ptr A = Obj->getArray(Field);
for(const auto &i:*A) {
Value.push_back(i);
}
}
}
template<class T> void field_from_json(const Poco::JSON::Object::Ptr &Obj, const char *Field, std::vector<T> &Value) {
if(Obj->isArray(Field) && !Obj->isNull(Field)) {
Poco::JSON::Array::Ptr Arr = Obj->getArray(Field);
for(auto &i:*Arr) {
auto InnerObj = i.extract<Poco::JSON::Object::Ptr>();
T NewItem;
NewItem.from_json(InnerObj);
Value.push_back(NewItem);
}
}
}
template<class T> void field_from_json(const Poco::JSON::Object::Ptr &Obj, const char *Field, T &Value) {
if(Obj->isObject(Field) && !Obj->isNull(Field)) {
Poco::JSON::Object::Ptr A = Obj->getObject(Field);
Value.from_json(A);
}
}
inline std::string to_string(const Types::TagList & ObjectArray) {
Poco::JSON::Array OutputArr;
if(ObjectArray.empty())
return "[]";
for(auto const &i:ObjectArray) {
OutputArr.add(i);
}
std::ostringstream OS;
Poco::JSON::Stringifier::stringify(OutputArr,OS, 0,0, Poco::JSON_PRESERVE_KEY_ORDER );
return OS.str();
}
inline std::string to_string(const Types::StringVec & ObjectArray) {
Poco::JSON::Array OutputArr;
if(ObjectArray.empty())
return "[]";
for(auto const &i:ObjectArray) {
OutputArr.add(i);
}
std::ostringstream OS;
Poco::JSON::Stringifier::condense(OutputArr,OS);
return OS.str();
}
inline std::string to_string(const Types::StringPairVec & ObjectArray) {
Poco::JSON::Array OutputArr;
if(ObjectArray.empty())
return "[]";
for(auto const &i:ObjectArray) {
Poco::JSON::Array InnerArray;
InnerArray.add(i.first);
InnerArray.add(i.second);
OutputArr.add(InnerArray);
}
std::ostringstream OS;
Poco::JSON::Stringifier::condense(OutputArr,OS);
return OS.str();
}
template<class T> std::string to_string(const std::vector<T> & ObjectArray) {
Poco::JSON::Array OutputArr;
if(ObjectArray.empty())
return "[]";
for(auto const &i:ObjectArray) {
Poco::JSON::Object O;
i.to_json(O);
OutputArr.add(O);
}
std::ostringstream OS;
Poco::JSON::Stringifier::condense(OutputArr,OS);
return OS.str();
}
template<class T> std::string to_string(const std::vector<std::vector<T>> & ObjectArray) {
Poco::JSON::Array OutputArr;
if(ObjectArray.empty())
return "[]";
for(auto const &i:ObjectArray) {
Poco::JSON::Array InnerArr;
for(auto const &j:i) {
if constexpr(std::is_integral<T>::value) {
InnerArr.add(j);
} if constexpr(std::is_same_v<T,std::string>) {
InnerArr.add(j);
} else {
InnerArr.add(j);
Poco::JSON::Object O;
j.to_json(O);
InnerArr.add(O);
}
}
OutputArr.add(InnerArr);
}
std::ostringstream OS;
Poco::JSON::Stringifier::condense(OutputArr,OS);
return OS.str();
}
template<class T> std::string to_string(const T & Object) {
Poco::JSON::Object OutputObj;
Object.to_json(OutputObj);
std::ostringstream OS;
Poco::JSON::Stringifier::condense(OutputObj,OS);
return OS.str();
}
inline Types::StringVec to_object_array(const std::string & ObjectString) {
Types::StringVec Result;
if(ObjectString.empty())
return Result;
try {
Poco::JSON::Parser P;
auto Object = P.parse(ObjectString).template extract<Poco::JSON::Array::Ptr>();
for (auto const &i : *Object) {
Result.push_back(i.toString());
}
} catch (...) {
}
return Result;
}
inline OpenWifi::Types::TagList to_taglist(const std::string & ObjectString) {
Types::TagList Result;
if(ObjectString.empty())
return Result;
try {
Poco::JSON::Parser P;
auto Object = P.parse(ObjectString).template extract<Poco::JSON::Array::Ptr>();
for (auto const &i : *Object) {
Result.push_back(i);
}
} catch (...) {
}
return Result;
}
inline Types::StringPairVec to_stringpair_array(const std::string &S) {
Types::StringPairVec R;
if(S.empty())
return R;
try {
Poco::JSON::Parser P;
auto Object = P.parse(S).template extract<Poco::JSON::Array::Ptr>();
for (const auto &i : *Object) {
auto InnerObject = i.template extract<Poco::JSON::Array::Ptr>();
if(InnerObject->size()==2) {
auto S1 = InnerObject->getElement<std::string>(0);
auto S2 = InnerObject->getElement<std::string>(1);
R.push_back(std::make_pair(S1,S2));
}
}
} catch (...) {
}
return R;
}
template<class T> std::vector<T> to_object_array(const std::string & ObjectString) {
std::vector<T> Result;
if(ObjectString.empty())
return Result;
try {
Poco::JSON::Parser P;
auto Object = P.parse(ObjectString).template extract<Poco::JSON::Array::Ptr>();
for (auto const &i : *Object) {
auto InnerObject = i.template extract<Poco::JSON::Object::Ptr>();
T Obj;
Obj.from_json(InnerObject);
Result.push_back(Obj);
}
} catch (...) {
}
return Result;
}
template<class T> std::vector<std::vector<T>> to_array_of_array_of_object(const std::string & ObjectString) {
std::vector<std::vector<T>> Result;
if(ObjectString.empty())
return Result;
try {
Poco::JSON::Parser P1;
auto OutterArray = P1.parse(ObjectString).template extract<Poco::JSON::Array::Ptr>();
for (auto const &i : *OutterArray) {
Poco::JSON::Parser P2;
auto InnerArray = P2.parse(i).template extract<Poco::JSON::Array::Ptr>();
std::vector<T> InnerVector;
for(auto const &j: *InnerArray) {
auto Object = j.template extract<Poco::JSON::Object::Ptr>();
T Obj;
Obj.from_json(Object);
InnerVector.push_back(Obj);
}
Result.push_back(InnerVector);
}
} catch (...) {
}
return Result;
}
template<class T> T to_object(const std::string & ObjectString) {
T Result;
if(ObjectString.empty())
return Result;
Poco::JSON::Parser P;
auto Object = P.parse(ObjectString).template extract<Poco::JSON::Object::Ptr>();
Result.from_json(Object);
return Result;
}
template<class T> bool from_request(T & Obj, Poco::Net::HTTPServerRequest &Request) {
Poco::JSON::Parser IncomingParser;
auto RawObject = IncomingParser.parse(Request.stream()).extract<Poco::JSON::Object::Ptr>();
Obj.from_json(RawObject);
return true;
}
}

View File

@@ -14,7 +14,8 @@
#include "Poco/Data/MySQL/Connector.h" #include "Poco/Data/MySQL/Connector.h"
#endif #endif
#include "framework/MicroService.h" #include "framework/SubSystemServer.h"
#include "framework/MicroServiceFuncs.h"
namespace OpenWifi { namespace OpenWifi {
enum DBType { enum DBType {
@@ -34,7 +35,7 @@ namespace OpenWifi {
std::lock_guard Guard(Mutex_); std::lock_guard Guard(Mutex_);
Logger().notice("Starting."); Logger().notice("Starting.");
std::string DBType = MicroService::instance().ConfigGetString("storage.type"); std::string DBType = MicroServiceConfigGetString("storage.type","");
if (DBType == "sqlite") { if (DBType == "sqlite") {
Setup_SQLite(); Setup_SQLite();
@@ -72,9 +73,9 @@ namespace OpenWifi {
inline int StorageClass::Setup_SQLite() { inline int StorageClass::Setup_SQLite() {
Logger().notice("SQLite StorageClass enabled."); Logger().notice("SQLite StorageClass enabled.");
dbType_ = sqlite; dbType_ = sqlite;
auto DBName = MicroService::instance().DataDir() + "/" + MicroService::instance().ConfigGetString("storage.type.sqlite.db"); auto DBName = MicroServiceDataDirectory() + "/" + MicroServiceConfigGetString("storage.type.sqlite.db","");
int NumSessions = (int) MicroService::instance().ConfigGetInt("storage.type.sqlite.maxsessions", 64); int NumSessions = (int) MicroServiceConfigGetInt("storage.type.sqlite.maxsessions", 64);
int IdleTime = (int) MicroService::instance().ConfigGetInt("storage.type.sqlite.idletime", 60); int IdleTime = (int) MicroServiceConfigGetInt("storage.type.sqlite.idletime", 60);
Poco::Data::SQLite::Connector::registerConnector(); Poco::Data::SQLite::Connector::registerConnector();
// Pool_ = std::make_unique<Poco::Data::SessionPool>(new Poco::Data::SessionPool(SQLiteConn_.name(), DBName, 8, // Pool_ = std::make_unique<Poco::Data::SessionPool>(new Poco::Data::SessionPool(SQLiteConn_.name(), DBName, 8,
@@ -87,13 +88,13 @@ namespace OpenWifi {
inline int StorageClass::Setup_MySQL() { inline int StorageClass::Setup_MySQL() {
Logger().notice("MySQL StorageClass enabled."); Logger().notice("MySQL StorageClass enabled.");
dbType_ = mysql; dbType_ = mysql;
int NumSessions = (int) MicroService::instance().ConfigGetInt("storage.type.mysql.maxsessions", 64); int NumSessions = (int) MicroServiceConfigGetInt("storage.type.mysql.maxsessions", 64);
int IdleTime = (int) MicroService::instance().ConfigGetInt("storage.type.mysql.idletime", 60); int IdleTime = (int) MicroServiceConfigGetInt("storage.type.mysql.idletime", 60);
auto Host = MicroService::instance().ConfigGetString("storage.type.mysql.host"); auto Host = MicroServiceConfigGetString("storage.type.mysql.host","");
auto Username = MicroService::instance().ConfigGetString("storage.type.mysql.username"); auto Username = MicroServiceConfigGetString("storage.type.mysql.username","");
auto Password = MicroService::instance().ConfigGetString("storage.type.mysql.password"); auto Password = MicroServiceConfigGetString("storage.type.mysql.password","");
auto Database = MicroService::instance().ConfigGetString("storage.type.mysql.database"); auto Database = MicroServiceConfigGetString("storage.type.mysql.database","");
auto Port = MicroService::instance().ConfigGetString("storage.type.mysql.port"); auto Port = MicroServiceConfigGetString("storage.type.mysql.port","");
std::string ConnectionStr = std::string ConnectionStr =
"host=" + Host + "host=" + Host +
@@ -112,14 +113,14 @@ namespace OpenWifi {
inline int StorageClass::Setup_PostgreSQL() { inline int StorageClass::Setup_PostgreSQL() {
Logger().notice("PostgreSQL StorageClass enabled."); Logger().notice("PostgreSQL StorageClass enabled.");
dbType_ = pgsql; dbType_ = pgsql;
int NumSessions = (int) MicroService::instance().ConfigGetInt("storage.type.postgresql.maxsessions", 64); int NumSessions = (int) MicroServiceConfigGetInt("storage.type.postgresql.maxsessions", 64);
int IdleTime = (int) MicroService::instance().ConfigGetInt("storage.type.postgresql.idletime", 60); int IdleTime = (int) MicroServiceConfigGetInt("storage.type.postgresql.idletime", 60);
auto Host = MicroService::instance().ConfigGetString("storage.type.postgresql.host"); auto Host = MicroServiceConfigGetString("storage.type.postgresql.host", "");
auto Username = MicroService::instance().ConfigGetString("storage.type.postgresql.username"); auto Username = MicroServiceConfigGetString("storage.type.postgresql.username", "");
auto Password = MicroService::instance().ConfigGetString("storage.type.postgresql.password"); auto Password = MicroServiceConfigGetString("storage.type.postgresql.password", "");
auto Database = MicroService::instance().ConfigGetString("storage.type.postgresql.database"); auto Database = MicroServiceConfigGetString("storage.type.postgresql.database", "");
auto Port = MicroService::instance().ConfigGetString("storage.type.postgresql.port"); auto Port = MicroServiceConfigGetString("storage.type.postgresql.port", "");
auto ConnectionTimeout = MicroService::instance().ConfigGetString("storage.type.postgresql.connectiontimeout"); auto ConnectionTimeout = MicroServiceConfigGetString("storage.type.postgresql.connectiontimeout", "");
std::string ConnectionStr = std::string ConnectionStr =
"host=" + Host + "host=" + Host +

View File

@@ -0,0 +1,320 @@
//
// Created by stephane bourque on 2022-10-25.
//
#include "fmt/format.h"
#include "framework/SubSystemServer.h"
#include "Poco/Net/SSLManager.h"
#include "Poco/DateTimeFormatter.h"
#include "Poco/DateTimeFormat.h"
#include "framework/MicroServiceFuncs.h"
namespace OpenWifi {
PropertiesFileServerEntry::PropertiesFileServerEntry(std::string Address, uint32_t port, std::string Key_file,
std::string Cert_file, std::string RootCa, std::string Issuer,
std::string ClientCas, std::string Cas,
std::string Key_file_password, std::string Name,
Poco::Net::Context::VerificationMode M,
int backlog)
: address_(std::move(Address)),
port_(port),
cert_file_(std::move(Cert_file)),
key_file_(std::move(Key_file)),
root_ca_(std::move(RootCa)),
key_file_password_(std::move(Key_file_password)),
issuer_cert_file_(std::move(Issuer)),
client_cas_(std::move(ClientCas)),
cas_(std::move(Cas)),
name_(std::move(Name)),
backlog_(backlog),
level_(M) {
};
[[nodiscard]] Poco::Net::SecureServerSocket PropertiesFileServerEntry::CreateSecureSocket(Poco::Logger &L) const {
Poco::Net::Context::Params P;
P.verificationMode = level_;
P.verificationDepth = 9;
P.loadDefaultCAs = root_ca_.empty();
P.cipherList = "ALL:!ADH:!LOW:!EXP:!MD5:@STRENGTH";
P.dhUse2048Bits = true;
P.caLocation = cas_;
auto Context = Poco::AutoPtr<Poco::Net::Context>(new Poco::Net::Context(Poco::Net::Context::TLS_SERVER_USE, P));
if(!key_file_password_.empty()) {
auto PassphraseHandler = Poco::SharedPtr<MyPrivateKeyPassphraseHandler>( new MyPrivateKeyPassphraseHandler(key_file_password_,L));
Poco::Net::SSLManager::instance().initializeServer(PassphraseHandler, nullptr,Context);
}
if (!cert_file_.empty() && !key_file_.empty()) {
Poco::Crypto::X509Certificate Cert(cert_file_);
Poco::Crypto::X509Certificate Root(root_ca_);
Context->useCertificate(Cert);
Context->addChainCertificate(Root);
Context->addCertificateAuthority(Root);
if (level_ == Poco::Net::Context::VERIFY_STRICT) {
if (issuer_cert_file_.empty()) {
L.fatal("In strict mode, you must supply ans issuer certificate");
}
if (client_cas_.empty()) {
L.fatal("In strict mode, client cas must be supplied");
}
Poco::Crypto::X509Certificate Issuing(issuer_cert_file_);
Context->addChainCertificate(Issuing);
Context->addCertificateAuthority(Issuing);
}
Poco::Crypto::RSAKey Key("", key_file_, key_file_password_);
Context->usePrivateKey(Key);
SSL_CTX *SSLCtx = Context->sslContext();
if (!SSL_CTX_check_private_key(SSLCtx)) {
L.fatal(fmt::format("Wrong Certificate({}) for Key({})", cert_file_, key_file_));
}
SSL_CTX_set_verify(SSLCtx, SSL_VERIFY_PEER, nullptr);
if (level_ == Poco::Net::Context::VERIFY_STRICT) {
SSL_CTX_set_client_CA_list(SSLCtx, SSL_load_client_CA_file(client_cas_.c_str()));
}
SSL_CTX_enable_ct(SSLCtx, SSL_CT_VALIDATION_STRICT);
SSL_CTX_dane_enable(SSLCtx);
Context->enableSessionCache();
Context->setSessionCacheSize(0);
Context->setSessionTimeout(60);
Context->enableExtendedCertificateVerification(true);
Context->disableStatelessSessionResumption();
}
if (address_ == "*") {
Poco::Net::IPAddress Addr(Poco::Net::IPAddress::wildcard(
Poco::Net::Socket::supportsIPv6() ? Poco::Net::AddressFamily::IPv6
: Poco::Net::AddressFamily::IPv4));
Poco::Net::SocketAddress SockAddr(Addr, port_);
return Poco::Net::SecureServerSocket(SockAddr, backlog_, Context);
} else {
Poco::Net::IPAddress Addr(address_);
Poco::Net::SocketAddress SockAddr(Addr, port_);
return Poco::Net::SecureServerSocket(SockAddr, backlog_, Context);
}
}
[[nodiscard]] Poco::Net::ServerSocket PropertiesFileServerEntry::CreateSocket([[maybe_unused]] Poco::Logger &L) const {
Poco::Net::Context::Params P;
if (address_ == "*") {
Poco::Net::IPAddress Addr(Poco::Net::IPAddress::wildcard(
Poco::Net::Socket::supportsIPv6() ? Poco::Net::AddressFamily::IPv6
: Poco::Net::AddressFamily::IPv4));
Poco::Net::SocketAddress SockAddr(Addr, port_);
return Poco::Net::ServerSocket(SockAddr, backlog_);
} else {
Poco::Net::IPAddress Addr(address_);
Poco::Net::SocketAddress SockAddr(Addr, port_);
return Poco::Net::ServerSocket(SockAddr, backlog_);
}
}
void PropertiesFileServerEntry::LogCertInfo(Poco::Logger &L, const Poco::Crypto::X509Certificate &C) const {
L.information("=============================================================================================");
L.information(fmt::format("> Issuer: {}", C.issuerName()));
L.information("---------------------------------------------------------------------------------------------");
L.information(fmt::format("> Common Name: {}",
C.issuerName(Poco::Crypto::X509Certificate::NID_COMMON_NAME)));
L.information(fmt::format("> Country: {}",
C.issuerName(Poco::Crypto::X509Certificate::NID_COUNTRY)));
L.information(fmt::format("> Locality: {}",
C.issuerName(Poco::Crypto::X509Certificate::NID_LOCALITY_NAME)));
L.information(fmt::format("> State/Prov: {}",
C.issuerName(Poco::Crypto::X509Certificate::NID_STATE_OR_PROVINCE)));
L.information(fmt::format("> Org name: {}",
C.issuerName(Poco::Crypto::X509Certificate::NID_ORGANIZATION_NAME)));
L.information(
fmt::format("> Org unit: {}",
C.issuerName(Poco::Crypto::X509Certificate::NID_ORGANIZATION_UNIT_NAME)));
L.information(
fmt::format("> Email: {}",
C.issuerName(Poco::Crypto::X509Certificate::NID_PKCS9_EMAIL_ADDRESS)));
L.information(fmt::format("> Serial#: {}",
C.issuerName(Poco::Crypto::X509Certificate::NID_SERIAL_NUMBER)));
L.information("---------------------------------------------------------------------------------------------");
L.information(fmt::format("> Subject: {}", C.subjectName()));
L.information("---------------------------------------------------------------------------------------------");
L.information(fmt::format("> Common Name: {}",
C.subjectName(Poco::Crypto::X509Certificate::NID_COMMON_NAME)));
L.information(fmt::format("> Country: {}",
C.subjectName(Poco::Crypto::X509Certificate::NID_COUNTRY)));
L.information(fmt::format("> Locality: {}",
C.subjectName(Poco::Crypto::X509Certificate::NID_LOCALITY_NAME)));
L.information(
fmt::format("> State/Prov: {}",
C.subjectName(Poco::Crypto::X509Certificate::NID_STATE_OR_PROVINCE)));
L.information(
fmt::format("> Org name: {}",
C.subjectName(Poco::Crypto::X509Certificate::NID_ORGANIZATION_NAME)));
L.information(
fmt::format("> Org unit: {}",
C.subjectName(Poco::Crypto::X509Certificate::NID_ORGANIZATION_UNIT_NAME)));
L.information(
fmt::format("> Email: {}",
C.subjectName(Poco::Crypto::X509Certificate::NID_PKCS9_EMAIL_ADDRESS)));
L.information(fmt::format("> Serial#: {}",
C.subjectName(Poco::Crypto::X509Certificate::NID_SERIAL_NUMBER)));
L.information("---------------------------------------------------------------------------------------------");
L.information(fmt::format("> Signature Algo: {}", C.signatureAlgorithm()));
auto From = Poco::DateTimeFormatter::format(C.validFrom(), Poco::DateTimeFormat::HTTP_FORMAT);
L.information(fmt::format("> Valid from: {}", From));
auto Expires =
Poco::DateTimeFormatter::format(C.expiresOn(), Poco::DateTimeFormat::HTTP_FORMAT);
L.information(fmt::format("> Expires on: {}", Expires));
L.information(fmt::format("> Version: {}", (int)C.version()));
L.information(fmt::format("> Serial #: {}", C.serialNumber()));
L.information("=============================================================================================");
}
void PropertiesFileServerEntry::LogCert(Poco::Logger &L) const {
try {
Poco::Crypto::X509Certificate C(cert_file_);
L.information("=============================================================================================");
L.information("=============================================================================================");
L.information(fmt::format("Certificate Filename: {}", cert_file_));
LogCertInfo(L, C);
L.information("=============================================================================================");
if (!issuer_cert_file_.empty()) {
Poco::Crypto::X509Certificate C1(issuer_cert_file_);
L.information("=============================================================================================");
L.information("=============================================================================================");
L.information(fmt::format("Issues Certificate Filename: {}", issuer_cert_file_));
LogCertInfo(L, C1);
L.information("=============================================================================================");
}
if (!client_cas_.empty()) {
std::vector<Poco::Crypto::X509Certificate> Certs =
Poco::Net::X509Certificate::readPEM(client_cas_);
L.information("=============================================================================================");
L.information("=============================================================================================");
L.information(fmt::format("Client CAs Filename: {}", client_cas_));
L.information("=============================================================================================");
auto i = 1;
for (const auto &C3 : Certs) {
L.information(fmt::format(" Index: {}", i));
L.information("=============================================================================================");
LogCertInfo(L, C3);
i++;
}
L.information("=============================================================================================");
}
} catch (const Poco::Exception &E) {
L.log(E);
}
}
void PropertiesFileServerEntry::LogCas(Poco::Logger &L) const {
try {
std::vector<Poco::Crypto::X509Certificate> Certs =
Poco::Net::X509Certificate::readPEM(root_ca_);
L.information("=============================================================================================");
L.information("=============================================================================================");
L.information(fmt::format("CA Filename: {}", root_ca_));
L.information("=============================================================================================");
auto i = 1;
for (const auto &C : Certs) {
L.information(fmt::format(" Index: {}", i));
L.information("=============================================================================================");
LogCertInfo(L, C);
i++;
}
L.information("=============================================================================================");
} catch (const Poco::Exception &E) {
L.log(E);
}
}
SubSystemServer::SubSystemServer(const std::string &Name, const std::string &LoggingPrefix,
const std::string &SubSystemConfigPrefix):
Name_(Name),
LoggerPrefix_(LoggingPrefix),
SubSystemConfigPrefix_(SubSystemConfigPrefix) {
}
void SubSystemServer::initialize([[maybe_unused]] Poco::Util::Application &self) {
auto i = 0;
bool good = true;
auto NewLevel = MicroServiceConfigGetString("logging.level." + Name_, "");
if(NewLevel.empty())
Logger_ = std::make_unique<LoggerWrapper>(Poco::Logger::create(LoggerPrefix_, Poco::Logger::root().getChannel(), Poco::Logger::root().getLevel()));
else
Logger_ = std::make_unique<LoggerWrapper>(Poco::Logger::create(LoggerPrefix_, Poco::Logger::root().getChannel(), Poco::Logger::parseLevel(NewLevel)));
ConfigServersList_.clear();
while (good) {
std::string root{SubSystemConfigPrefix_ + ".host." + std::to_string(i) + "."};
std::string address{root + "address"};
if (MicroServiceConfigGetString(address, "").empty()) {
good = false;
} else {
std::string port{root + "port"};
std::string key{root + "key"};
std::string key_password{root + "key.password"};
std::string cert{root + "cert"};
std::string name{root + "name"};
std::string backlog{root + "backlog"};
std::string rootca{root + "rootca"};
std::string issuer{root + "issuer"};
std::string clientcas(root + "clientcas");
std::string cas{root + "cas"};
std::string level{root + "security"};
Poco::Net::Context::VerificationMode M = Poco::Net::Context::VERIFY_RELAXED;
auto L = MicroServiceConfigGetString(level, "");
if (L == "strict") {
M = Poco::Net::Context::VERIFY_STRICT;
} else if (L == "none") {
M = Poco::Net::Context::VERIFY_NONE;
} else if (L == "relaxed") {
M = Poco::Net::Context::VERIFY_RELAXED;
} else if (L == "once")
M = Poco::Net::Context::VERIFY_ONCE;
PropertiesFileServerEntry entry(MicroServiceConfigGetString(address, ""),
MicroServiceConfigGetInt(port, 0),
MicroServiceConfigPath(key, ""),
MicroServiceConfigPath(cert, ""),
MicroServiceConfigPath(rootca, ""),
MicroServiceConfigPath(issuer, ""),
MicroServiceConfigPath(clientcas, ""),
MicroServiceConfigPath(cas, ""),
MicroServiceConfigGetString(key_password, ""),
MicroServiceConfigGetString(name, ""), M,
(int)MicroServiceConfigGetInt(backlog, 64));
ConfigServersList_.push_back(entry);
i++;
}
}
}
} // namespace OpenWifi

View File

@@ -0,0 +1,124 @@
//
// Created by stephane bourque on 2022-10-25.
//
#pragma once
#include <string>
#include <mutex>
#include "Poco/Util/Application.h"
#include "Poco/Net/Context.h"
#include "Poco/Net/SecureServerSocket.h"
#include "Poco/Net/PrivateKeyPassphraseHandler.h"
namespace OpenWifi {
class MyPrivateKeyPassphraseHandler : public Poco::Net::PrivateKeyPassphraseHandler {
public:
explicit MyPrivateKeyPassphraseHandler(const std::string &Password, Poco::Logger & Logger):
PrivateKeyPassphraseHandler(true),
Password_(Password),
Logger_(Logger) {
}
void onPrivateKeyRequested([[maybe_unused]] const void * pSender,std::string & privateKey) {
poco_information(Logger_,"Returning key passphrase.");
privateKey = Password_;
};
inline Poco::Logger & Logger() { return Logger_; }
private:
std::string Password_;
Poco::Logger & Logger_;
};
class PropertiesFileServerEntry {
public:
PropertiesFileServerEntry(std::string Address, uint32_t port, std::string Key_file,
std::string Cert_file, std::string RootCa, std::string Issuer,
std::string ClientCas, std::string Cas,
std::string Key_file_password = "", std::string Name = "",
Poco::Net::Context::VerificationMode M =
Poco::Net::Context::VerificationMode::VERIFY_RELAXED,
int backlog = 64);
[[nodiscard]] inline const std::string &Address() const { return address_; };
[[nodiscard]] inline uint32_t Port() const { return port_; };
[[nodiscard]] inline auto KeyFile() const { return key_file_; };
[[nodiscard]] inline auto CertFile() const { return cert_file_; };
[[nodiscard]] inline auto RootCA() const { return root_ca_; };
[[nodiscard]] inline auto KeyFilePassword() const { return key_file_password_; };
[[nodiscard]] inline auto IssuerCertFile() const { return issuer_cert_file_; };
[[nodiscard]] inline auto Name() const { return name_; };
[[nodiscard]] inline int Backlog() const { return backlog_; }
[[nodiscard]] inline auto Cas() const { return cas_; }
[[nodiscard]] Poco::Net::SecureServerSocket CreateSecureSocket(Poco::Logger &L) const;
[[nodiscard]] Poco::Net::ServerSocket CreateSocket([[maybe_unused]] Poco::Logger &L) const;
void LogCertInfo(Poco::Logger &L, const Poco::Crypto::X509Certificate &C) const;
void LogCert(Poco::Logger &L) const;
void LogCas(Poco::Logger &L) const;
private:
std::string address_;
uint32_t port_;
std::string cert_file_;
std::string key_file_;
std::string root_ca_;
std::string key_file_password_;
std::string issuer_cert_file_;
std::string client_cas_;
std::string cas_;
std::string name_;
int backlog_;
Poco::Net::Context::VerificationMode level_;
};
class SubSystemServer : public Poco::Util::Application::Subsystem {
public:
SubSystemServer(const std::string & Name, const std::string &LoggingPrefix,
const std::string & SubSystemConfigPrefix);
void initialize(Poco::Util::Application &self) override;
inline void uninitialize() override {
}
inline void reinitialize([[maybe_unused]] Poco::Util::Application &self) override {
poco_information(Logger_->L_,"Reloading of this subsystem is not supported.");
}
inline void defineOptions([[maybe_unused]] Poco::Util::OptionSet &options) override {
}
inline const std::string & Name() const { return Name_; };
inline const char * name() const override { return Name_.c_str(); }
inline const PropertiesFileServerEntry & Host(uint64_t index) { return ConfigServersList_[index]; };
inline uint64_t HostSize() const { return ConfigServersList_.size(); }
inline Poco::Logger & Logger() const { return Logger_->L_; }
inline void SetLoggingLevel(const std::string & levelName) {
Logger_->L_.setLevel(Poco::Logger::parseLevel(levelName));
}
inline int GetLoggingLevel() { return Logger_->L_.getLevel(); }
virtual int Start() = 0;
virtual void Stop() = 0;
struct LoggerWrapper {
Poco::Logger & L_;
LoggerWrapper(Poco::Logger &L) :
L_(L) {
}
};
protected:
std::recursive_mutex Mutex_;
std::vector<PropertiesFileServerEntry> ConfigServersList_;
private:
std::unique_ptr<LoggerWrapper> Logger_;
std::string Name_;
std::string LoggerPrefix_;
std::string SubSystemConfigPrefix_;
};
typedef std::vector<SubSystemServer *> SubSystemVec;
} // namespace OpenWifi

Some files were not shown because too many files have changed in this diff Show More